Skip to content

Commit 7188d08

Browse files
wiechulasawenzel
andauthored
TPC: Add possibility to simulate distortions (#1507)
Co-authored-by: Sandro Wenzel <sandro.wenzel@cern.ch>
1 parent 02d071a commit 7188d08

File tree

2 files changed

+71
-19
lines changed

2 files changed

+71
-19
lines changed

MC/bin/o2dpg_sim_workflow.py

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@
136136
parser.add_argument('--mft-reco-full', action='store_true', help='enables complete mft reco instead of simplified misaligned version')
137137
parser.add_argument('--mft-assessment-full', action='store_true', help='enables complete assessment of mft reco')
138138

139+
# TPC options
140+
parser.add_argument('--tpc-distortion-type', default=0, type=int, help='Simulate distortions in the TPC (0=no distortions, 1=distortions without scaling, 2=distortions with CTP scaling)')
141+
parser.add_argument('--ctp-scaler', default=0, type=float, help='CTP raw scaler value used for distortion simulation')
139142
# Global Forward reconstruction configuration
140143
parser.add_argument('--fwdmatching-assessment-full', action='store_true', help='enables complete assessment of global forward reco')
141144
parser.add_argument('--fwdmatching-4-param', action='store_true', help='excludes q/pt from matching parameters')
@@ -520,7 +523,6 @@ def getDPL_global_options(bigshm=False, ccdbbackend=True):
520523
'${O2_ROOT}/bin/o2-ccdb-downloadccdbfile --host http://alice-ccdb.cern.ch -p TPC/Calib/CorrectionMap --timestamp 1 --created-not-after ' + str(args.condition_not_after) + ' -d ${ALICEO2_CCDB_LOCALCACHE} ; }'
521524
workflow['stages'].append(TPC_SPACECHARGE_DOWNLOADER_TASK)
522525

523-
524526
# query initial configKey args for signal transport; mainly used to setup generators
525527
simInitialConfigKeys = create_geant_config(args, args.confKey)
526528

@@ -672,19 +674,18 @@ def getDPL_global_options(bigshm=False, ccdbbackend=True):
672674
--ptHatMax='+str(PTHATMAX)
673675
if WEIGHTPOW > 0:
674676
SGN_CONFIG_task['cmd'] = SGN_CONFIG_task['cmd'] + ' --weightPow=' + str(WEIGHTPOW)
675-
676677
# if we configure pythia8 here --> we also need to adjust the configuration
677678
# TODO: we need a proper config container/manager so as to combine these local configs with external configs etc.
678679
args.confKey = args.confKey + ";GeneratorPythia8.config=pythia8.cfg"
679680

680681
# elif GENERATOR == 'extgen': what do we do if generator is not pythia8?
681682
# NOTE: Generator setup might be handled in a different file or different files (one per
682683
# possible generator)
684+
683685
workflow['stages'].append(SGN_CONFIG_task)
684686

685687
# determine final conf key for signal simulation
686688
CONFKEY = constructConfigKeyArg(create_geant_config(args, args.confKey))
687-
688689
# -----------------
689690
# transport signals
690691
# -----------------
@@ -865,25 +866,46 @@ def putConfigValuesNew(listOfMainKeys=[], localCF = {}):
865866

866867
workflow['stages'].append(ContextTask)
867868

869+
# ===| TPC digi part |===
870+
CTPSCALER = args.ctp_scaler
871+
tpcDistortionType=args.tpc_distortion_type
872+
print(f"TPC distortion simulation: type = {tpcDistortionType}, CTP scaler value {CTPSCALER}");
868873
tpcdigineeds=[ContextTask['name'], LinkGRPFileTask['name'], TPC_SPACECHARGE_DOWNLOADER_TASK['name']]
869874
if usebkgcache:
870875
tpcdigineeds += [ BKG_HITDOWNLOADER_TASKS['TPC']['name'] ]
871876

877+
tpcLocalCF={"DigiParams.maxOrbitsToDigitize" : str(orbitsPerTF), "DigiParams.seed" : str(TFSEED)}
878+
879+
# handle distortions and scaling using MC maps
880+
# this assumes the lumi inside the maps is stored in FT0 (pp) scalers
881+
# in case of PbPb the conversion factor ZDC ->FT0 (pp) must be taken into account in the scalers
882+
if tpcDistortionType == 2 and CTPSCALER <= 0:
883+
print('Warning: lumi scaling requested, but no ctp scaler value set. Full map will be applied at face value.')
884+
tpcDistortionType=1
885+
886+
lumiInstFactor=1
887+
if COLTYPE == 'PbPb':
888+
lumiInstFactor=2.414
889+
890+
if tpcDistortionType == 2:
891+
tpcLocalCF['TPCCorrMap.lumiInst'] = str(CTPSCALER * lumiInstFactor)
872892
tpcdigimem = 12000 if havePbPb else 9000
873893
TPCDigitask=createTask(name='tpcdigi_'+str(tf), needs=tpcdigineeds,
874894
tf=tf, cwd=timeframeworkdir, lab=["DIGI"], cpu=NWORKERS_TF, mem=str(tpcdigimem))
875895
TPCDigitask['cmd'] = ('','ln -nfs ../bkg_HitsTPC.root . ;')[doembedding]
876896
TPCDigitask['cmd'] += '${O2_ROOT}/bin/o2-sim-digitizer-workflow ' + getDPL_global_options() + ' -n ' + str(args.ns) + simsoption \
877897
+ ' --onlyDet TPC --TPCuseCCDB --interactionRate ' + str(INTRATE) + ' --tpc-lanes ' + str(NWORKERS_TF) \
878898
+ ' --incontext ' + str(CONTEXTFILE) + ' --disable-write-ini --early-forward-policy always --forceSelectedDets ' \
899+
+ ' --tpc-distortion-type ' + str(tpcDistortionType) \
879900
+ putConfigValuesNew(["TPCGasParam","TPCGEMParam","TPCEleParam","TPCITCorr","TPCDetParam"],
880-
localCF={"DigiParams.maxOrbitsToDigitize" : str(orbitsPerTF), "DigiParams.seed" : str(TFSEED)})
901+
localCF=tpcLocalCF)
881902
TPCDigitask['cmd'] += (' --tpc-chunked-writer','')[args.no_tpc_digitchunking]
882903
TPCDigitask['cmd'] += ('',' --disable-mc')[args.no_mc_labels]
883904
# we add any other extra command line options (power user customization) with an environment variable
884905
if environ.get('O2DPG_TPC_DIGIT_EXTRA') != None:
885906
TPCDigitask['cmd'] += ' ' + environ['O2DPG_TPC_DIGIT_EXTRA']
886907
workflow['stages'].append(TPCDigitask)
908+
# END TPC digi part
887909

888910
trddigineeds = [ContextTask['name']]
889911
if usebkgcache:
@@ -1001,13 +1023,36 @@ def getDigiTaskName(det):
10011023
workflow['stages'].append(tpcclus)
10021024
tpcreconeeds.append(tpcclus['name'])
10031025

1026+
# ===| TPC reco |===
1027+
tpcLocalCFreco=dict()
1028+
1029+
# handle distortion corrections and scaling using MC maps
1030+
# this assumes the lumi inside the maps is stored in FT0 (pp) scalers
1031+
# in case of PbPb the conversion factor ZDC ->FT0 (pp) must be set
1032+
tpc_corr_options_mc=''
1033+
1034+
if tpcDistortionType == 0: # disable distortion corrections
1035+
tpc_corr_options_mc=' --corrmap-lumi-mode 0 '
1036+
tpcLocalCFreco['TPCCorrMap.lumiMean'] = '-1';
1037+
elif tpcDistortionType == 1: # disable scaling
1038+
tpc_corr_options_mc=' --corrmap-lumi-mode 2 '
1039+
tpcLocalCFreco['TPCCorrMap.lumiInst'] = str(CTPSCALER)
1040+
tpcLocalCFreco['TPCCorrMap.lumiMean'] = str(CTPSCALER)
1041+
elif tpcDistortionType == 2: # full scaling with CTP values
1042+
if COLTYPE == 'PbPb':
1043+
tpcLocalCFreco['TPCCorrMap.lumiInstFactor'] = str(lumiInstFactor)
1044+
tpc_corr_options_mc=' --corrmap-lumi-mode 2 '
1045+
tpcLocalCFreco['TPCCorrMap.lumiInst'] = str(CTPSCALER)
1046+
1047+
# TODO: Is this still used?
10041048
tpc_corr_scaling_options = anchorConfig.get('tpc-corr-scaling','')
10051049
TPCRECOtask=createTask(name='tpcreco_'+str(tf), needs=tpcreconeeds, tf=tf, cwd=timeframeworkdir, lab=["RECO"], relative_cpu=3/8, mem='16000')
10061050
TPCRECOtask['cmd'] = '${O2_ROOT}/bin/o2-tpc-reco-workflow ' + getDPL_global_options(bigshm=True) + ' --input-type clusters --output-type tracks,send-clusters-per-sector ' \
1007-
+ putConfigValuesNew(["GPU_global","TPCGasParam", "TPCCorrMap", "GPU_rec_tpc", "trackTuneParams"], {"GPU_proc.ompThreads":NWORKERS_TF}) + ('',' --disable-mc')[args.no_mc_labels] \
1008-
+ tpc_corr_scaling_options
1051+
+ putConfigValuesNew(["GPU_global","TPCGasParam", "TPCCorrMap", "GPU_rec_tpc", "trackTuneParams"], {"GPU_proc.ompThreads":NWORKERS_TF} | tpcLocalCFreco) + ('',' --disable-mc')[args.no_mc_labels] \
1052+
+ tpc_corr_scaling_options + tpc_corr_options_mc
10091053
workflow['stages'].append(TPCRECOtask)
10101054

1055+
# END TPC reco
10111056

10121057
ITSMemEstimate = 12000 if havePbPb else 2000 # PbPb has much large mem requirement for now (in worst case)
10131058
ITSRECOtask=createTask(name='itsreco_'+str(tf), needs=[getDigiTaskName("ITS")],
@@ -1025,8 +1070,8 @@ def getDigiTaskName(det):
10251070

10261071
ITSTPCMATCHtask=createTask(name='itstpcMatch_'+str(tf), needs=[TPCRECOtask['name'], ITSRECOtask['name'], FT0RECOtask['name']], tf=tf, cwd=timeframeworkdir, lab=["RECO"], mem='8000', relative_cpu=3/8)
10271072
ITSTPCMATCHtask['cmd'] = '${O2_ROOT}/bin/o2-tpcits-match-workflow ' + getDPL_global_options(bigshm=True) + ' --tpc-track-reader \"tpctracks.root\" --tpc-native-cluster-reader \"--infile tpc-native-clusters.root\" --use-ft0' \
1028-
+ putConfigValuesNew(['MFTClustererParam', 'ITSCATrackerParam', 'tpcitsMatch', 'TPCGasParam', 'TPCCorrMap', 'ITSClustererParam', 'GPU_rec_tpc', 'trackTuneParams', 'ft0tag'], {"NameConf.mDirMatLUT" : ".."}) \
1029-
+ tpc_corr_scaling_options
1073+
+ putConfigValuesNew(['MFTClustererParam', 'ITSCATrackerParam', 'tpcitsMatch', 'TPCGasParam', 'TPCCorrMap', 'ITSClustererParam', 'GPU_rec_tpc', 'trackTuneParams', 'ft0tag'], {"NameConf.mDirMatLUT" : ".."} | tpcLocalCFreco) \
1074+
+ tpc_corr_scaling_options + tpc_corr_options_mc
10301075
workflow['stages'].append(ITSTPCMATCHtask)
10311076

10321077
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')
@@ -1041,11 +1086,10 @@ def getDigiTaskName(det):
10411086
'ITSCATrackerParam',
10421087
'trackTuneParams',
10431088
'GPU_rec_tpc',
1044-
'ft0tag',
10451089
'TPCGasParam',
1046-
'TPCCorrMap'], {"NameConf.mDirMatLUT" : ".."}) \
1090+
'TPCCorrMap'], {"NameConf.mDirMatLUT" : ".."} | tpcLocalCFreco) \
10471091
+ " --track-sources " + trd_track_sources \
1048-
+ tpc_corr_scaling_options
1092+
+ tpc_corr_scaling_options + tpc_corr_options_mc
10491093
workflow['stages'].append(TRDTRACKINGtask2)
10501094

10511095
TOFRECOtask = createTask(name='tofmatch_'+str(tf), needs=[ITSTPCMATCHtask['name'], getDigiTaskName("TOF")], tf=tf, cwd=timeframeworkdir, lab=["RECO"], mem='1500')
@@ -1063,9 +1107,9 @@ def getDigiTaskName(det):
10631107
'ITSCATrackerParam',
10641108
'MFTClustererParam',
10651109
'GPU_rec_tpc',
1066-
'trackTuneParams']) \
1110+
'trackTuneParams'], tpcLocalCFreco) \
10671111
+ " --track-sources " + toftracksrcdefault + (' --combine-devices','')[args.no_combine_dpl_devices] \
1068-
+ tpc_corr_scaling_options
1112+
+ tpc_corr_scaling_options + tpc_corr_options_mc
10691113
workflow['stages'].append(TOFTPCMATCHERtask)
10701114

10711115
# MFT reco: needing access to kinematics (when assessment enabled)
@@ -1342,7 +1386,8 @@ def addQCPerTF(taskName, needs, readerCommand, configFilePath, objectsFile=''):
13421386
SVFINDERtask = createTask(name='svfinder_'+str(tf), needs=[PVFINDERtask['name'], FT0FV0EMCCTPDIGItask['name']], tf=tf, cwd=timeframeworkdir, lab=["RECO"], cpu=svfinder_cpu, mem='5000')
13431387
SVFINDERtask = createTask(name='svfinder_'+str(tf), needs=[PVFINDERtask['name']], tf=tf, cwd=timeframeworkdir, lab=["RECO"], cpu=svfinder_cpu, mem='5000')
13441388
SVFINDERtask['cmd'] = '${O2_ROOT}/bin/o2-secondary-vertexing-workflow '
1345-
SVFINDERtask['cmd'] += getDPL_global_options(bigshm=True) + svfinder_threads + putConfigValuesNew(['svertexer', 'TPCCorrMap'], {"NameConf.mDirMatLUT" : ".."})
1389+
SVFINDERtask['cmd'] += getDPL_global_options(bigshm=True) + svfinder_threads + putConfigValuesNew(['svertexer', 'TPCCorrMap'], {"NameConf.mDirMatLUT" : ".."} | tpcLocalCFreco) \
1390+
+ tpc_corr_scaling_options + tpc_corr_options_mc
13461391
# Take None as default, we only add more if nothing from anchorConfig
13471392
svfinder_sources = anchorConfig.get('o2-secondary-vertexing-workflow-options', {}). get('vertexing-sources', 'ITS-TPC,TPC-TRD,ITS-TPC-TRD,TPC-TOF,ITS-TPC-TOF,TPC-TRD-TOF,ITS-TPC-TRD-TOF,MFT-MCH,MCH-MID,ITS,MFT,TPC,TOF,FT0,MID,EMC,PHS,CPV,ZDC,FDD,HMP,FV0,TRD,MCH,CTP')
13481393
SVFINDERtask['cmd'] += ' --vertexing-sources ' + svfinder_sources + (' --combine-source-devices','')[args.no_combine_dpl_devices]

MC/bin/o2dpg_sim_workflow_anchored.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,29 +202,31 @@ def retrieve_MinBias_CTPScaler_Rate(ctpscaler, finaltime, trig_eff, NBunches, Co
202202
if ColSystem == "PbPb":
203203
ctpclass = 25 # <--- we take scalers for ZDC
204204
ctptype = 7
205-
print("Fetching rate with class " + str(ctpclass) + " type " + str(ctptype))
205+
print("Fetching rate with time " + str(finaltime) + " class " + str(ctpclass) + " type " + str(ctptype))
206206
rate = ctpscaler.getRateGivenT(finaltime, ctpclass, ctptype)
207207
#if ColSystem == "PbPb":
208208
# rate.first = rate.first / 28.
209209
# rate.second = rate.second / 28.
210210

211211
print("Global rate " + str(rate.first) + " local rate " + str(rate.second))
212+
ctp_local_rate_raw = None
213+
if rate.second >= 0:
214+
ctp_local_rate_raw = rate.second
212215
if rate.first >= 0:
213216
# calculate true rate (input from Chiara Zampolli) using number of bunches
214217
coll_bunches = NBunches
215218
mu = - math.log(1. - rate.second / 11245 / coll_bunches) / trig_eff
216219
finalRate = coll_bunches * mu * 11245
217-
return finalRate
220+
return finalRate, ctp_local_rate_raw
218221

219222
print (f"[ERROR]: Could not determine interaction rate; Some (external) default used")
220-
return None
223+
return None, None
221224

222225
def determine_timestamp(sor, eor, splitinfo, cycle, ntf, HBF_per_timeframe = 256):
223226
"""
224227
Determines the timestamp and production offset variable based
225228
on the global properties of the production (MC split, etc) and the properties
226229
of the run. ntf is the number of timeframes per MC job
227-
228230
Args:
229231
sor: int
230232
start-of-run in milliseconds since epoch
@@ -291,6 +293,7 @@ def main():
291293
parser.add_argument("--trig-eff", type=float, dest="trig_eff", help="Trigger eff needed for IR", default=-1.0)
292294
parser.add_argument('forward', nargs=argparse.REMAINDER) # forward args passed to actual workflow creation
293295
args = parser.parse_args()
296+
print (args)
294297

295298
# split id should not be larger than production id
296299
assert(args.split_id <= args.prod_split)
@@ -316,6 +319,7 @@ def main():
316319
print ("Determined timestamp to be : ", timestamp)
317320
print ("Determined offset to be : ", prod_offset)
318321

322+
319323
# retrieve the GRPHCIF object
320324
grplhcif = retrieve_GRPLHCIF(ccdbreader, int(timestamp))
321325
eCM = grplhcif.getSqrtS()
@@ -340,6 +344,7 @@ def main():
340344
forwardargs = " ".join([ a for a in args.forward if a != '--' ])
341345
# retrieve interaction rate
342346
rate = None
347+
ctp_local_rate_raw = None
343348

344349
if args.ccdb_IRate == True:
345350
effTrigger = args.trig_eff
@@ -360,7 +365,7 @@ def main():
360365
print(f"ERROR: Cannot retrive scalers for run number {args.run_number}")
361366
exit (1)
362367
# time needs to be converted to seconds ==> timestamp / 1000
363-
rate = retrieve_MinBias_CTPScaler_Rate(ctp_scalers, timestamp/1000., effTrigger, grplhcif.getBunchFilling().getNBunches(), ColSystem)
368+
rate, ctp_local_rate_raw = retrieve_MinBias_CTPScaler_Rate(ctp_scalers, timestamp/1000., effTrigger, grplhcif.getBunchFilling().getNBunches(), ColSystem)
364369

365370
if rate != None:
366371
# if the rate calculation was successful we will use it, otherwise we fall back to some rate given as part
@@ -370,6 +375,8 @@ def main():
370375
# Use re.sub() to replace the pattern with an empty string
371376
forwardargs = re.sub(pattern, " ", forwardargs)
372377
forwardargs += ' -interactionRate ' + str(int(rate))
378+
if ctp_local_rate_raw != None:
379+
forwardargs += ' --ctp-scaler ' + str(ctp_local_rate_raw)
373380

374381
# we finally pass forward to the unanchored MC workflow creation
375382
# TODO: this needs to be done in a pythonic way clearly

0 commit comments

Comments
 (0)