Skip to content

Commit 4cb6921

Browse files
authored
Merge pull request #4 from marinang/userinterface
Add user interface and other new goodies!
2 parents 94d6f13 + 4a809f2 commit 4cb6921

39 files changed

+2016
-798
lines changed

Diff for: .gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
/EvtTypes
22
*.pyc
3+
/._simjobs_
4+
__pycache__
5+
*.egg-info
6+
/build
7+
/bin
8+
/dist

Diff for: LaunchProduction.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@
2525
parser.add_argument('evttype', metavar='<evttype>', help="EvtType of the processus to generate.", type=str)
2626
parser.add_argument('nevents', metavar='<nevents>', help="Number of events to produce.", type=int)
2727
parser.add_argument('year', metavar='<year>', help="Year to simulate.", type=int, choices=[2011,2012,2015,2016,2017])
28-
parser.add_argument('--polarity', metavar='<polarity>', help="Magnet conditions to simulate.", default='', choices=['MagUp','MagDown'])
28+
parser.add_argument('--polarity', metavar='<polarity>', help="Magnet conditions to simulate.", choices=['MagUp','MagDown'])
2929
parser.add_argument('--simcond', metavar='<simcond>', help="Simulation condition.", default='Sim09c', choices=['Sim09b','Sim09c'])
30-
parser.add_argument('--stripping', metavar='<stripping>', help="Version of the stripping.", type=str, default='')
30+
parser.add_argument('--stripping', metavar='<stripping>', help="Version of the stripping.", type=str)
3131
parser.add_argument('--turbo', help="Do the Turbo step.", action='store_true')
3232
parser.add_argument('--mudst', help="Create a muDST output instead of DST ouptut.", action='store_true')
3333
parser.add_argument('--neventsjob', metavar='<neventsjob>', help="Number of events per job.", type=int, default=50)
3434
parser.add_argument('--runnumber', metavar='<runnumber>', help="Run number for Gauss.", type=int, default=baserunnumber())
3535
parser.add_argument('--decfiles', metavar='<decfiles>', help="Version of the DecFiles package.", type=str, default='v30r5')
3636
parser.add_argument('--infiles', metavar='<infiles>', help="External files to provide for generation, i.e LHE or HepMC files.", type=str, default='')
3737

38-
parser.add_argument('--cpu', metavar='<cpu>', help="Number of CPUs per simulation job.", type=int, default=4140)
38+
parser.add_argument('--cpu', metavar='<cpu>', help="Number of CPUs per simulation job.", type=int)
3939

4040
#options to control slurm job submission #
4141
#ideally you would run with these options in a screen session #
@@ -46,7 +46,10 @@
4646
parser.add_argument('--npendingjobs', metavar='<npendingjobs>', help="(Slurm option) Maximum number of pending jobs for the user.", type=int)
4747
parser.add_argument('--nfreenodes', metavar='<nfreenodes>', help="(Slurm option) Number of nodes to be free of user's simulation jobs.", type=int)
4848
parser.add_argument('--subtime', metavar='<subtime>', help="(Slurm option) Time interval when the jobs are sent.", nargs='+', type=int, default=[0, 23])
49-
49+
50+
#lxplus options
51+
parser.add_argument('--toeos', help="Move the jobs outputs to EOS when finished.", action='store_true')
52+
5053
opts = parser.parse_args()
5154

5255
opts = vars(opts).copy()

Diff for: MANIFEST.IN

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Include the license ifile
2+
include LICENSE
3+
4+
# Include the MANIFEST itself
5+
include MANIFEST.in

Diff for: MoveJobs.py

+73-43
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,29 @@
55
from pyparsing import *
66
import shutil
77
import time
8+
from subprocess import Popen, PIPE
89

910
jobdir = os.getenv("SIMOUTPUT")
1011
if jobdir is None :
1112
jobdir = os.getenv("HOME")+"/SimulationJobs"
13+
eosdir = os.getenv("EOS_SIMOUTPUT")
14+
15+
def silentrm( path ):
16+
17+
P = Popen(['rm','-rf',path], stdout=PIPE, stderr=PIPE)
18+
_, _ = P.communicate()
19+
20+
def MoveFinishedJobs( Options ):
1221

13-
def MoveFinishedJobs( Path, Options ):
22+
if Options["toeos"]:
23+
dir_ = eosdir
24+
os.system("xrdfs root://eoslhcb.cern.ch/ mkdir -p {0}/{evttype}/{year}/{simcond}/MagUp/xml".format( dir_, **Options))
25+
os.system("xrdfs root://eoslhcb.cern.ch/ mkdir -p {0}/{evttype}/{year}/{simcond}/MagDown/xml".format( dir_,**Options))
26+
proddir_ = jobdir
27+
else:
28+
dir_ = jobdir
29+
os.system("mkdir -p {0}/{evttype}/{year}/{simcond}/MagUp/xml".format( dir_, **Options))
30+
os.system("mkdir -p {0}/{evttype}/{year}/{simcond}/MagDown/xml".format( dir_,**Options))
1431

1532
Completed = []
1633

@@ -38,35 +55,11 @@ def IsCompleted( DST, nEvents ):
3855
return True
3956
else:
4057
return False
41-
42-
def IsCompleted_1( Directory ):
43-
44-
def getstatus( status, line ):
45-
line = line.replace( status + ":", "")
46-
line = line.replace( " ", "")
47-
line = line.replace( "\n", "")
48-
49-
if line == "True":
50-
return True
51-
elif line == "False":
52-
return False
53-
54-
status_file = "{0}/status".format( Directory )
58+
59+
Path = dir_ + "/simProd_{evttype}_{simcond}/".format( **Options )
5560

56-
if os.path.isfile( status_file ):
57-
58-
status_file = open( status_file, "r")
59-
status = status_file.readlines()
60-
61-
submitted = getstatus("submitted", status[0])
62-
running = getstatus("running", status[1])
63-
completed = getstatus("completed", status[2])
64-
failed = getstatus("failed", status[3])
65-
66-
return submitted and not running and completed and not failed
67-
68-
else:
69-
return False
61+
if Options["toeos"]:
62+
Path_prod = proddir_ + "/simProd_{evttype}_{simcond}/".format( **Options )
7063

7164
number = Word(nums+".")
7265
text = Word(alphas+nums)
@@ -75,50 +68,87 @@ def getstatus( status, line ):
7568
expr = number.setResultsName("year") + Suppress(underscore) + text.setResultsName("polarity") + Suppress(underscore) + number.setResultsName("nevents") + Suppress(text)
7669
expr += Suppress(underscore) + Suppress(Literal("s")) + text.setResultsName("stripping") + Suppress(underscore) + text.setResultsName("runnumber")
7770

78-
directories = glob.glob(Path + "{0}_*".format( Options.year ) )
71+
directories = glob.glob(Path + "{year}_*".format( **Options ) )
7972

8073
for d in directories:
8174

8275
subjobdir = d.replace( Path, "")
8376
parsed = expr.parseString(subjobdir)
8477

78+
if Options["toeos"]:
79+
production_dir = Path_prod + subjobdir
80+
81+
if len(os.listdir(d)) < 1:
82+
silentrm(d)
83+
if Options["toeos"]:
84+
silentrm(production_dir)
85+
continue
86+
8587
nEvents = parsed.nevents
8688

8789
dst = "{0}/{1}_events.dst".format( d, nEvents )
8890

8991
xml = d + "/GeneratorLog.xml"
92+
93+
completed = IsCompleted( dst, parsed.nevents )
94+
finished = IsFinished( d )
9095

91-
if ( IsCompleted( dst, parsed.nevents ) and IsFinished( d ) ) or IsCompleted_1( d ):
96+
if completed and finished:
9297
newdst = "{0}evts_s{1}_{2}.dst".format( parsed.nevents, parsed.stripping, parsed.runnumber )
9398
newxml = "{0}.xml".format( parsed.runnumber )
9499

95100
print(dst)
96101

97-
shutil.move( dst, "{0}/{1}/{2}/{3}/{4}/{5}".format( jobdir, Options.evttype, Options.year, Options.simcond, parsed.polarity, newdst ) )
98-
shutil.move( xml, "{0}/{1}/{2}/{3}/{4}/xml/{5}".format( jobdir, Options.evttype, Options.year, Options.simcond, parsed.polarity, newxml ) )
102+
if Options["toeos"]:
103+
os.system("xrdfs root://eoslhcb.cern.ch/ mv {0} {1}/{evttype}/{year}/{simcond}/{2}/{3}".format( dst, dir_, parsed.polarity, newdst, **Options ))
104+
os.system("xrdfs root://eoslhcb.cern.ch/ mv {0} {1}/{evttype}/{year}/{simcond}/{2}/xml/{3}".format( xml, dir_, parsed.polarity, newxml, **Options ))
105+
106+
if os.path.isdir(production_dir):
107+
silentrm(production_dir)
108+
109+
else:
110+
shutil.move( dst, "{0}/{evttype}/{year}/{simcond}/{1}/{2}".format( dir_, parsed.polarity, newdst, **Options ) )
111+
shutil.move( xml, "{0}/{{evttype}/{year}/{simcond}/{1}/xml/{2}".format( dir_, parsed.polarity, newxml , **Options ) )
112+
113+
silentrm(d)
99114

100-
os.system("rm -rf " + d)
115+
elif not completed and finished:
116+
if os.path.isfile(dst):
117+
os.remove(dst)
118+
if os.path.isfile(xml):
119+
os.remove(xml)
120+
silentrm(d)
101121

122+
if Options["toeos"] and os.path.isdir(production_dir):
123+
silentrm(production_dir)
102124

125+
if Options["toeos"]:
126+
directories = glob.glob(Path_prod + "{year}_*".format( **Options ) )
127+
128+
for d in directories:
129+
130+
subjobdir = d.replace( Path_prod, "")
131+
parsed = expr.parseString(subjobdir)
132+
133+
finished = IsFinished( d )
134+
135+
if len(os.listdir(d)) < 1 or finished:
136+
silentrm(d)
137+
103138
if __name__ == "__main__" :
104139

105140
parser = argparse.ArgumentParser(description='')
106141

107142
parser.add_argument('evttype', metavar='<evttype>', help="EvtType of the processus to generate.", type=str)
108143
parser.add_argument('year', metavar='<year>', help="Year to simulate.", type=int, choices=[2011,2012,2015,2016,2017])
109-
parser.add_argument('--simcond', metavar='<simcond>', help="Simulation condition.", default='Sim09c', choices=['Sim09b','Sim09c','Sim09c_LLP','Sim09c_HNL'])
144+
parser.add_argument('--simcond', metavar='<simcond>', help="Simulation condition.", default='Sim09c', choices=['Sim09b','Sim09c'])
145+
parser.add_argument('--toeos', help="If jobs were moved to eos.", action='store_true')
110146

111147
opts = parser.parse_args()
112-
evttype = opts.evttype
113-
simcond = opts.simcond
114-
year = opts.year
115-
116-
jobspath = jobdir + "/simProd_{0}_{1}/".format( evttype, simcond )
117148

118-
os.system("mkdir -p {0}/{1}/{2}/{3}/MagUp/xml".format( jobdir, evttype, year, simcond))
119-
os.system("mkdir -p {0}/{1}/{2}/{3}/MagDown/xml".format( jobdir, evttype, year, simcond))
149+
opts = vars(opts).copy()
120150

121-
MoveFinishedJobs( jobspath, opts)
151+
MoveFinishedJobs( opts )
122152

123153

124154

Diff for: README.md

+65-26
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
# Simulation production
22

3-
Mini framework to send simulation jobs into lxplus or a slurm batch system (with access to cvmfs)!
3+
Mini framework to send LHCb simulation jobs on a batch system (LSF or Slurm)!
4+
5+
## Installation
6+
7+
To install the module do
8+
9+
`$ python setup.py install (--user)`.
10+
11+
You will be asked to enter some directories where you want to find your simulated samples.
12+
13+
## Usage
14+
15+
To launch the module just type `$ simprod`.
16+
17+
<p align="center">
18+
<img width="600" height="200" src="https://github.com/marinang/SimulationProduction/blob/userinterface/etc/begin_interface.png">
19+
</p>
420

521
You need to to know:
622

@@ -10,50 +26,73 @@ You need to to know:
1026

1127
* Number of events you want to produce.
1228

13-
Description of simulation setups can be found [here](https://github.com/marinang/SimulationProduction/tree/master/simjob/setup).
14-
15-
Before launching make sure to set the environnement variable _$SIMOUTPUT_ to the path of where you want to save the outputs of the jobs. This can be done using the _setup.sh_ script or adding this variable to your _.bashrc_.
29+
Description of simulation setups can be found [here](https://github.com/marinang/SimulationProduction/tree/master/simjob/setup). To start a new simulation job do:
30+
31+
`$ j = SimulationJob( evttype=EVTTYPE, year=YEAR, nevents=NEVENTS)`
32+
33+
`$ j.prepare()`
1634

17-
The script to launch jobs is **LaunchProduction.py**, usage: python LaunchProduction.py EvtType Year #Events
35+
`$ j.send()`
1836

19-
optional arguments:
37+
<p align="center">
38+
<img width="750" height="300" src="https://github.com/marinang/SimulationProduction/blob/userinterface/etc/submission.png">
39+
</p>
2040

21-
* --polarity: Magnet conditions to simulate (MagUp or MagDown, default: half MagUp, half MagDown).
2241

23-
* --neventsjob: Number of events per jobs (default: 50).
42+
### Options
2443

25-
* --runnumber: Run number for Gauss.
44+
Your have other options by default that you can change:
2645

27-
* --simcond: Simulation condition (Sim09b, Sim09c, default: Sim09c).
46+
* polarity: Magnet conditions to simulate [MagUp or MagDown, default: half MagUp, half MagDown].
2847

29-
* --stripping: Version of the stripping (default = '').
48+
* neventsjob: Number of events per jobs [default: 50].
3049

31-
* --turbo: Run the Turbo step (output has never been tested).
50+
* runnumber: Run number for simulation in Gauss.
3251

33-
* --mudst: Produce a muDST output.
52+
* simcond: Simulation condition [Sim09b, Sim09c, default: Sim09c].
3453

35-
* --decfiles: Version of the DecFiles package (default = v30r5).
54+
* stripping: Version of the stripping (default = '').
3655

37-
* --infiles: External files to provide for generation (for example LHE or HepMC files).
56+
* turbo: Run the Turbo step (output not test).
3857

39-
* --cpu: Number of CPUs per simulation job.
58+
* mudst: Produce a muDST output.
59+
60+
* decfiles: Version of the DecFiles package (default = v30r5)
61+
62+
* infiles: External files to provide for generation (for example LHE or HepMC files).
63+
64+
* cpu: Number of CPU memory (in MB) per simulation job.
4065

41-
If you wish to modify any option related to an EvtType prior to launch submission, the **GetEvtType.py** script will copy every option file that are in _EvtType.py_ to a directory called _EvtTypes_. It takes the EvtType as argument.
66+
These argument are all available at instantiation of a SimulationJob but also as property, i.e:
67+
68+
`$ j = SimulationJob( evttype=EVTTYPE, year=YEAR, nevents=NEVENTS, neventsjob=NEVENTSJOB)`
69+
70+
is equivalent to
4271

43-
If you wish to send jobs on a **Slurm** batch system you can add the following options for **LaunchProduction.py**.
72+
`$ j = SimulationJob( evttype=EVTTYPE, year=YEAR, nevents=NEVENTS)`
4473

45-
* --time: Maximum running time per simulation job in hours.
74+
### Slurm options
4675

47-
* --nsimjobs: Maximum number of simultaneous simulation jobs running.
76+
You have additionnal options for slurm batch system with default values designed for EPFL usage.
77+
78+
* time: Maximum running time per simulation job in hours.
79+
80+
* nsimjobs: Maximum number of simultaneous simulation jobs running.
4881

49-
* --nsimuserjobs: Maximum number of simultaneous simulation jobs running for the user.
82+
* nsimuserjobs: Maximum number of simultaneous simulation jobs running for the user.
5083

51-
* --nuserjobs: Maximum number of simultaneous jobs running for the user.
84+
* nuserjobs: Maximum number of simultaneous jobs running for the user.
5285

53-
* --npendingjobs: Maximum number of pending jobs for the user.
86+
* npendingjobs: Maximum number of pending jobs for the user.
5487

55-
* --nfreenodes: Number of nodes to be free of user's simulation jobs.
88+
* nfreenodes: Number of nodes to be free of user's simulation jobs.
5689

57-
* --subtime: Time interval when the jobs are sent (e.g. 16 18 means from 4pm to 6pm).
90+
* subtime: Time interval when the jobs are sent (e.g. 16 18 means from 4pm to 6pm).
91+
92+
## Monitoring
93+
94+
Just after the lauching the program type `jobs` and you can see the status of submitted jobs:
5895

59-
Note you would use these options in a **screen** session, usage: screen python LaunchProduction.py ....
96+
<p align="center">
97+
<img width="540" height="500" src="https://github.com/marinang/SimulationProduction/blob/userinterface/etc/monitor.png">
98+
</p>

Diff for: etc/begin_interface.png

115 KB
Loading

Diff for: etc/monitor.png

594 KB
Loading

Diff for: etc/submission.png

273 KB
Loading

0 commit comments

Comments
 (0)