11#!/usr/bin/env python3
22
33#
4- # A script producing a consistent MC->RECO->AOD workflow
5- # It aims to handle the different MC possible configurations
4+ # A script producing a consistent MC->RECO->AOD workflow
5+ # It aims to handle the different MC possible configurations
66# It just creates a workflow.json txt file, to execute the workflow one must execute right after
7- # ${O2DPG_ROOT}/MC/bin/o2_dpg_workflow_runner.py -f workflow.json
7+ # ${O2DPG_ROOT}/MC/bin/o2_dpg_workflow_runner.py -f workflow.json
88#
99# Execution examples:
1010# - pp PYTHIA jets, 2 events, triggered on high pT decay photons on all barrel calorimeters acceptance, eCMS 13 TeV
1515# - pp PYTHIA ccbar events embedded into heavy-ion environment, 2 PYTHIA events into 1 bkg event, beams energy 2.510
1616# ./o2dpg_sim_workflow.py -e TGeant3 -nb 1 -ns 2 -j 8 -tf 1 -mod "--skipModules ZDC" \
1717# -col pp -eA 2.510 -proc "ccbar" --embedding
18- #
18+ #
1919
2020import sys
2121import importlib .util
2222import argparse
2323from os import environ , mkdir
2424from os .path import join , dirname , isdir
25+ import random
2526import json
2627import itertools
2728import time
7980parser .add_argument ('-j' ,help = 'number of workers (if applicable)' , default = 8 , type = int )
8081parser .add_argument ('-mod' ,help = 'Active modules (deprecated)' , default = '--skipModules ZDC' )
8182parser .add_argument ('--with-ZDC' , action = 'store_true' , help = 'Enable ZDC in workflow' )
82- parser .add_argument ('-seed' ,help = 'random seed number' , default = 0 )
83+ parser .add_argument ('-seed' ,help = 'random seed number' , default = None )
8384parser .add_argument ('-o' ,help = 'output workflow file' , default = 'workflow.json' )
8485parser .add_argument ('--noIPC' ,help = 'disable shared memory in DPL' )
8586
125126QUALITYCONTROL_ROOT = environ .get ('QUALITYCONTROL_ROOT' )
126127O2PHYSICS_ROOT = environ .get ('O2PHYSICS_ROOT' )
127128
128- if O2DPG_ROOT == None :
129+ if O2DPG_ROOT == None :
129130 print ('Error: This needs O2DPG loaded' )
130131# exit(1)
131132
132- if O2_ROOT == None :
133+ if O2_ROOT == None :
133134 print ('Error: This needs O2 loaded' )
134135# exit(1)
135136
@@ -184,7 +185,7 @@ def addWhenActive(detID, needslist, appendstring):
184185 if isActive (detID ):
185186 needslist .append (appendstring )
186187
187- # ----------- START WORKFLOW CONSTRUCTION -----------------------------
188+ # ----------- START WORKFLOW CONSTRUCTION -----------------------------
188189
189190# set the time
190191if args .timestamp == - 1 :
@@ -197,7 +198,10 @@ def addWhenActive(detID, needslist, appendstring):
197198MODULES = "--skipModules ZDC" if not args .with_ZDC else ""
198199SIMENGINE = args .e
199200BFIELD = args .field
200- RNDSEED = args .seed # 0 means random seed ! Should we set different seed for Bkg and signal?
201+ RNDSEED = args .seed # typically the argument should be the jobid, but if we get None the current time is used for the initialisation
202+ random .seed (RNDSEED )
203+ print ("Using initialisation seed: " , RNDSEED )
204+ SIMSEED = random .randint (1 , 900000000 - NTIMEFRAMES - 1 ) # PYTHIA maximum seed is 900M for some reason
201205
202206workflow = {}
203207workflow ['stages' ] = []
@@ -282,9 +286,10 @@ def getDPL_global_options(bigshm=False):
282286 BKG_CONFIG_task = createTask (name = 'genbkgconf' )
283287 BKG_CONFIG_task ['cmd' ] = 'echo "placeholder / dummy task"'
284288 if GENBKG == 'pythia8' :
289+ print ('Background generator seed: ' , SIMSEED )
285290 BKG_CONFIG_task ['cmd' ] = '${O2DPG_ROOT}/MC/config/common/pythia8/utils/mkpy8cfg.py \
286291 --output=pythia8bkg.cfg \
287- --seed='+ str (RNDSEED )+ ' \
292+ --seed='+ str (SIMSEED )+ ' \
288293 --idA='+ str (PDGABKG )+ ' \
289294 --idB='+ str (PDGBBKG )+ ' \
290295 --eCM='+ str (ECMSBKG )+ ' \
@@ -366,6 +371,9 @@ def getDPL_global_options(bigshm=False):
366371
367372# loop over timeframes
368373for tf in range (1 , NTIMEFRAMES + 1 ):
374+ TFSEED = SIMSEED + tf
375+ print ("Timeframe " + str (tf ) + " seed: " , TFSEED )
376+
369377 timeframeworkdir = 'tf' + str (tf )
370378
371379 # ---- transport task -------
@@ -395,7 +403,7 @@ def getDPL_global_options(bigshm=False):
395403 WEIGHTPOW = float (args .weightPow )
396404 PTHATMIN = float (args .ptHatMin )
397405 PTHATMAX = float (args .ptHatMax )
398-
406+
399407 # translate here collision type to PDG
400408 COLTYPE = args .col
401409
@@ -439,7 +447,7 @@ def getDPL_global_options(bigshm=False):
439447 if GENERATOR == 'pythia8' and PROCESS != '' :
440448 SGN_CONFIG_task ['cmd' ] = '${O2DPG_ROOT}/MC/config/common/pythia8/utils/mkpy8cfg.py \
441449 --output=pythia8.cfg \
442- --seed='+ str (RNDSEED )+ ' \
450+ --seed='+ str (TFSEED )+ ' \
443451 --idA='+ str (PDGA )+ ' \
444452 --idB='+ str (PDGB )+ ' \
445453 --eCM='+ str (ECMS )+ ' \
@@ -469,7 +477,7 @@ def getDPL_global_options(bigshm=False):
469477 # -----------------
470478 signalprefix = 'sgn_' + str (tf )
471479 signalneeds = [ SGN_CONFIG_task ['name' ] ]
472-
480+
473481 # add embedIntoFile only if embeddPattern does contain a '@'
474482 embeddinto = "--embedIntoFile ../bkg_MCHeader.root" if (doembedding & ("@" in args .embeddPattern )) else ""
475483 #embeddinto= "--embedIntoFile ../bkg_MCHeader.root" if doembedding else ""
@@ -479,7 +487,7 @@ def getDPL_global_options(bigshm=False):
479487 else :
480488 signalneeds = signalneeds + [ BKG_HEADER_task ['name' ] ]
481489 SGNtask = createTask (name = 'sgnsim_' + str (tf ), needs = signalneeds , tf = tf , cwd = 'tf' + str (tf ), lab = ["GEANT" ], relative_cpu = 5 / 8 , n_workers = NWORKERS , mem = '2000' )
482- SGNtask ['cmd' ]= '${O2_ROOT}/bin/o2-sim -e ' + str (SIMENGINE ) + ' ' + str (MODULES ) + ' -n ' + str (NSIGEVENTS ) \
490+ SGNtask ['cmd' ]= '${O2_ROOT}/bin/o2-sim -e ' + str (SIMENGINE ) + ' ' + str (MODULES ) + ' -n ' + str (NSIGEVENTS ) + ' --seed ' + str ( TFSEED ) \
483491 + ' --field ' + str (BFIELD ) + ' -j ' + str (NWORKERS ) + ' -g ' + str (GENERATOR ) \
484492 + ' ' + str (TRIGGER ) + ' ' + str (CONFKEY ) + ' ' + str (INIFILE ) \
485493 + ' -o ' + signalprefix + ' ' + embeddinto + ' --timestamp ' + str (args .timestamp )
@@ -511,7 +519,7 @@ def getDPL_global_options(bigshm=False):
511519 # digitization steps
512520 # ------------------
513521 CONTEXTFILE = 'collisioncontext.root'
514-
522+
515523 # Determine interation rate
516524 # it should be taken from CDB, meanwhile some default values
517525 INTRATE = int (args .interactionRate )
@@ -742,7 +750,7 @@ def getDigiTaskName(det):
742750 TRDTRACKINGtask = createTask (name = 'trdreco_' + str (tf ), needs = [TRDDigitask ['name' ], ITSTPCMATCHtask ['name' ], TPCRECOtask ['name' ], ITSRECOtask ['name' ]], tf = tf , cwd = timeframeworkdir , lab = ["RECO" ], cpu = '1' , mem = '2000' )
743751 TRDTRACKINGtask ['cmd' ] = '${O2_ROOT}/bin/o2-trd-tracklet-transformer ' + getDPL_global_options () + putConfigValues ()
744752 workflow ['stages' ].append (TRDTRACKINGtask )
745-
753+
746754 # FIXME This is so far a workaround to avoud a race condition for trdcalibratedtracklets.root
747755 TRDTRACKINGtask2 = createTask (name = 'trdreco2_' + str (tf ), needs = [TRDTRACKINGtask ['name' ],MATBUD_DOWNLOADER_TASK ['name' ]], tf = tf , cwd = timeframeworkdir , lab = ["RECO" ], cpu = '1' , mem = '2000' )
748756 TRDTRACKINGtask2 ['cmd' ] = '${O2_ROOT}/bin/o2-trd-global-tracking ' + getDPL_global_options (bigshm = True ) \
@@ -806,7 +814,7 @@ def getDigiTaskName(det):
806814 PHSRECOtask = createTask (name = 'phsreco_' + str (tf ), needs = [getDigiTaskName ("PHS" )], tf = tf , cwd = timeframeworkdir , lab = ["RECO" ], mem = '1500' )
807815 PHSRECOtask ['cmd' ] = '${O2_ROOT}/bin/o2-phos-reco-workflow ' + getDPL_global_options () + putConfigValues ()
808816 workflow ['stages' ].append (PHSRECOtask )
809-
817+
810818 CPVRECOtask = createTask (name = 'cpvreco_' + str (tf ), needs = [getDigiTaskName ("CPV" )], tf = tf , cwd = timeframeworkdir , lab = ["RECO" ], mem = '1500' )
811819 CPVRECOtask ['cmd' ] = '${O2_ROOT}/bin/o2-cpv-reco-workflow ' + getDPL_global_options () + putConfigValues ()
812820 workflow ['stages' ].append (CPVRECOtask )
@@ -816,7 +824,7 @@ def getDigiTaskName(det):
816824 ZDCRECOtask ['cmd' ] = '${O2_ROOT}/bin/o2-zdc-digits-reco ' + getDPL_global_options () + putConfigValues ()
817825 workflow ['stages' ].append (ZDCRECOtask )
818826
819- ## forward matching
827+ ## forward matching
820828 MCHMIDMATCHtask = createTask (name = 'mchmidMatch_' + str (tf ), needs = [MCHRECOtask ['name' ], MIDRECOtask ['name' ]], tf = tf , cwd = timeframeworkdir , lab = ["RECO" ], mem = '1500' )
821829 MCHMIDMATCHtask ['cmd' ] = '${O2_ROOT}/bin/o2-muon-tracks-matcher-workflow ' + getDPL_global_options ()
822830 workflow ['stages' ].append (MCHMIDMATCHtask )
@@ -860,7 +868,7 @@ def getDigiTaskName(det):
860868
861869 def addQCPerTF (taskName , needs , readerCommand , configFilePath , objectsFile = '' ):
862870 task = createTask (name = taskName + '_local' + str (tf ), needs = needs , tf = tf , cwd = timeframeworkdir , lab = ["QC" ], cpu = 1 , mem = '2000' )
863- objectsFile = objectsFile if len (objectsFile ) > 0 else taskName + '.root'
871+ objectsFile = objectsFile if len (objectsFile ) > 0 else taskName + '.root'
864872 # the --local-batch argument will make QC Tasks store their results in a file and merge with any existing objects
865873 task ['cmd' ] = f'{ readerCommand } | o2-qc --config { configFilePath } ' + \
866874 f' --local-batch ../{ qcdir } /{ objectsFile } ' + \
@@ -869,9 +877,9 @@ def addQCPerTF(taskName, needs, readerCommand, configFilePath, objectsFile=''):
869877 # Prevents this task from being run for multiple TimeFrames at the same time, thus trying to modify the same file.
870878 task ['semaphore' ] = objectsFile
871879 workflow ['stages' ].append (task )
872-
880+
873881 ### MFT
874-
882+
875883 # to be enabled once MFT Digits should run 5 times with different configurations
876884 for flp in range (5 ):
877885 addQCPerTF (taskName = 'mftDigitsQC' + str (flp ),
@@ -957,7 +965,7 @@ def addQCPerTF(taskName, needs, readerCommand, configFilePath, objectsFile=''):
957965 needs = [ITSRECOtask ['name' ]],
958966 readerCommand = 'o2-global-track-cluster-reader --track-types "ITS" --cluster-types "ITS"' ,
959967 configFilePath = 'json://${O2DPG_ROOT}/MC/config/QC/json/its-mc-tracks-qc.json' )
960-
968+
961969 #secondary vertexer
962970 svfinder_threads = ' --threads 1 '
963971 svfinder_cpu = 1
@@ -973,7 +981,7 @@ def addQCPerTF(taskName, needs, readerCommand, configFilePath, objectsFile=''):
973981 # -----------
974982 # produce AOD
975983 # -----------
976- aodneeds = [PVFINDERtask ['name' ], SVFINDERtask ['name' ], TOFRECOtask ['name' ],
984+ aodneeds = [PVFINDERtask ['name' ], SVFINDERtask ['name' ], TOFRECOtask ['name' ],
977985 FV0RECOtask ['name' ]]
978986 if isActive ('FV0' ):
979987 aodneeds += [ FV0RECOtask ['name' ] ]
@@ -1008,7 +1016,7 @@ def addQCPerTF(taskName, needs, readerCommand, configFilePath, objectsFile=''):
10081016 if args .run_anchored == False :
10091017 AODtask ['cmd' ] += ' --aod-timeframe-id ${ALIEN_PROC_ID}' + aod_df_id
10101018 AODtask ['cmd' ] += ' ' + getDPL_global_options (bigshm = True )
1011- AODtask ['cmd' ] += ' --info-sources ' + anchorConfig .get ("o2-aod-producer-workflow-options" ,{}).get ("info-sources" ,str (aodinfosources ))
1019+ AODtask ['cmd' ] += ' --info-sources ' + anchorConfig .get ("o2-aod-producer-workflow-options" ,{}).get ("info-sources" ,str (aodinfosources ))
10121020 AODtask ['cmd' ] += ' --lpmp-prod-tag ${ALIEN_JDL_LPMPRODUCTIONTAG:-unknown}'
10131021 AODtask ['cmd' ] += ' --anchor-pass ${ALIEN_JDL_LPMANCHORPASSNAME:-unknown}'
10141022 AODtask ['cmd' ] += ' --anchor-prod ${ALIEN_JDL_MCANCHOR:-unknown}'
0 commit comments