Skip to content

Commit 228739a

Browse files
committed
Two improvements for the MC anchoring service
1) Greater flexibility to set the timeframe length in orbits. The `--orbitsPerTF` options now, * either takes a precise integer number * or a comma-separated string of triples f:t:o which denote to use `o` orbits when the interaction rate falls between `f` (inclusive) and `t` (exclusive) example: `--orbitsPerTF 0:10000:32,10001:10000000:8` will apply 32 orbit-sizes timeframes when the interaction rate is below 10kHz, otherwise 8 orbits. This improvement caused a larger refactoring of the code, because we now need to query the interaction rate twice. 2) Improvements in the bad-data exlusion treatment: * We now report the global fraction of run-space excluded by the list * We now determine each line, wether the treatment is in orbits or in timestamps
1 parent c072ec3 commit 228739a

File tree

1 file changed

+111
-63
lines changed

1 file changed

+111
-63
lines changed

MC/bin/o2dpg_sim_workflow_anchored.py

Lines changed: 111 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,35 @@ def retrieve_Aggregated_RunInfos(run_number):
119119
"detList" : detList}
120120

121121

122+
def parse_orbits_per_tf(orbitsPerTF, intRate):
123+
"""
124+
Function to determine the number of orbits per TF to be used as
125+
a function of interaction rate.
126+
"""
127+
if intRate == None or intRate < 0:
128+
return -1
129+
130+
# Check if the argument is a single integer, in which case we just use it
131+
if orbitsPerTF.isdigit():
132+
return int(orbitsPerTF)
133+
134+
# Otherwise we assume that the argument is a string of the form
135+
# a1:b1:o1,a2:b2:o2,...
136+
# where we apply orbit o2 if the intRate falls between a2 <= intRate < b2.
137+
ranges = orbitsPerTF.split(',')
138+
for entry in ranges:
139+
try:
140+
a, b, x = map(int, entry.split(':'))
141+
if a <= intRate < b:
142+
return x
143+
except ValueError:
144+
raise ValueError(f"Invalid format in entry: {entry}")
145+
146+
# if we didn't find a valid range we return -1 which means
147+
# that the orbit number will be determined from GRPECS
148+
return -1
149+
150+
122151
def retrieve_params_fromGRPECS_and_OrbitReset(ccdbreader, run_number, run_start, run_end):
123152
"""
124153
Retrieves start of run (sor), end of run (eor) and other global parameters from the GRPECS object,
@@ -212,11 +241,28 @@ def retrieve_CTPScalers(ccdbreader, run_number, timestamp=None):
212241
return ctpscaler
213242
return None
214243

215-
def retrieve_MinBias_CTPScaler_Rate(ctpscaler, finaltime, trig_eff, NBunches, ColSystem):
244+
def retrieve_MinBias_CTPScaler_Rate(ctpscaler, finaltime, trig_eff_arg, NBunches, ColSystem, eCM):
216245
"""
217-
retrieves the CTP scalers object for a given timestamp and run_number
218-
and calculates the interation rate to be applied in Monte Carlo digitizers
246+
retrieves the CTP scalers object for a given timestamp
247+
and calculates the interation rate to be applied in Monte Carlo digitizers.
248+
Uses trig_eff_arg when positive, otherwise calculates the effTrigger.
219249
"""
250+
251+
# determine first of all the trigger efficiency
252+
effTrigger = trig_eff_arg
253+
if effTrigger < 0:
254+
if ColSystem == "pp":
255+
if eCM < 1000:
256+
effTrigger = 0.68
257+
elif eCM < 6000:
258+
effTrigger = 0.737
259+
else:
260+
effTrigger = 0.759
261+
elif ColSystem == "PbPb":
262+
effTrigger = 28.0 # this is ZDC
263+
else:
264+
effTrigger = 0.759
265+
220266
# this is the default for pp
221267
ctpclass = 0 # <---- we take the scaler for FT0
222268
ctptype = 1
@@ -226,9 +272,6 @@ def retrieve_MinBias_CTPScaler_Rate(ctpscaler, finaltime, trig_eff, NBunches, Co
226272
ctptype = 7
227273
print("Fetching rate with time " + str(finaltime) + " class " + str(ctpclass) + " type " + str(ctptype))
228274
rate = ctpscaler.getRateGivenT(finaltime, ctpclass, ctptype)
229-
#if ColSystem == "PbPb":
230-
# rate.first = rate.first / 28.
231-
# rate.second = rate.second / 28.
232275

233276
print("Global rate " + str(rate.first) + " local rate " + str(rate.second))
234277
ctp_local_rate_raw = None
@@ -237,7 +280,7 @@ def retrieve_MinBias_CTPScaler_Rate(ctpscaler, finaltime, trig_eff, NBunches, Co
237280
if rate.first >= 0:
238281
# calculate true rate (input from Chiara Zampolli) using number of bunches
239282
coll_bunches = NBunches
240-
mu = - math.log(1. - rate.second / 11245 / coll_bunches) / trig_eff
283+
mu = - math.log(1. - rate.second / 11245 / coll_bunches) / effTrigger
241284
finalRate = coll_bunches * mu * 11245
242285
return finalRate, ctp_local_rate_raw
243286

@@ -303,7 +346,7 @@ def determine_timestamp(sor, eor, splitinfo, cycle, ntf, HBF_per_timeframe = 256
303346
return int(timestamp_of_production), production_offset
304347

305348

306-
def exclude_timestamp(ts, orbit, run, filename):
349+
def exclude_timestamp(ts, orbit, run, filename, global_run_params):
307350
"""
308351
Checks if timestamp ts (or orbit) falls within a bad data period.
309352
Returns true if this timestamp should be excluded; false otherwise
@@ -352,18 +395,25 @@ def parse_file(filename):
352395
if len(exclude_list) == 0:
353396
return False
354397

355-
data_is_in_orbits = exclude_list[0][0] < 1514761200000
356-
357-
if data_is_in_orbits:
358-
for orbitspan in exclude_list:
359-
if orbitspan[0] <= orbit and orbit <= orbitspan[1]:
360-
return True
361-
else:
362-
for timespan in exclude_list:
363-
if timespan[0] <= ts and ts <= timespan[1]:
364-
return True
365-
366-
return False
398+
timeframelength_intime = global_run_params["EOR"] - global_run_params["SOR"]
399+
timeframelength_inorbits = global_run_params["LastOrbit"] - global_run_params["FirstOrbit"]
400+
total_excluded_fraction = 0
401+
excluded = False
402+
for exclusion_entry in exclude_list:
403+
#
404+
data_is_in_orbits = exclusion_entry[0] < 1514761200000
405+
print ("Checking data", exclusion_entry)
406+
if data_is_in_orbits:
407+
total_excluded_fraction = total_excluded_fraction + (exclusion_entry[1] - exclusion_entry[0]) / (1.*timeframelength_inorbits)
408+
if exclusion_entry[0] <= orbit and orbit <= exclusion_entry[1]:
409+
excluded = True
410+
else:
411+
total_excluded_fraction = total_excluded_fraction + (exclusion_entry[1] - exclusion_entry[0]) / (1.*timeframelength_intime)
412+
if exclusion_entry[0] <= ts and ts <= exclusion_entry[1]:
413+
excluded = True
414+
415+
print(f"This run as globally {total_excluded_fraction} of it's data marked to be exluded")
416+
return excluded
367417

368418
def main():
369419
parser = argparse.ArgumentParser(description='Creates an O2DPG simulation workflow, anchored to a given LHC run. The workflows are time anchored at regular positions within a run as a function of production size, split-id and cycle.')
@@ -375,10 +425,10 @@ def main():
375425
parser.add_argument("--split-id", type=int, help="The split id of this job within the whole production --prod-split)", default=0)
376426
parser.add_argument("-tf", type=int, help="number of timeframes per job", default=1)
377427
parser.add_argument("--ccdb-IRate", type=bool, help="whether to try fetching IRate from CCDB/CTP", default=True)
378-
parser.add_argument("--trig-eff", type=float, dest="trig_eff", help="Trigger eff needed for IR", default=-1.0)
428+
parser.add_argument("--trig-eff", type=float, dest="trig_eff", help="Trigger eff needed for IR (default is automatic mode)", default=-1.0)
379429
parser.add_argument("--run-time-span-file", type=str, dest="run_span_file", help="Run-time-span-file for exclusions of timestamps (bad data periods etc.)", default="")
380430
parser.add_argument("--invert-irframe-selection", action='store_true', help="Inverts the logic of --run-time-span-file")
381-
parser.add_argument("--orbitsPerTF", type=int, help="Force a certain orbits-per-timeframe number; Automatically taken from CCDB if not given.", default=-1)
431+
parser.add_argument("--orbitsPerTF", type=str, help="Force a certain orbits-per-timeframe number; Automatically taken from CCDB if not given.", default="")
382432
parser.add_argument('forward', nargs=argparse.REMAINDER) # forward args passed to actual workflow creation
383433
args = parser.parse_args()
384434
print (args)
@@ -394,31 +444,20 @@ def main():
394444
run_start = GLOparams["SOR"]
395445
run_end = GLOparams["EOR"]
396446

397-
# overwrite with some external choices
398-
if args.orbitsPerTF!=-1:
399-
print("Adjusting orbitsPerTF from " + str(GLOparams["OrbitsPerTF"]) + " to " + str(args.orbitsPerTF))
400-
GLOparams["OrbitsPerTF"] = args.orbitsPerTF
401-
402-
# determine timestamp, and production offset for the final MC job to run
403-
timestamp, prod_offset = determine_timestamp(run_start, run_end, [args.split_id - 1, args.prod_split], args.cycle, args.tf, GLOparams["OrbitsPerTF"])
404-
# determine orbit corresponding to timestamp
405-
orbit = GLOparams["FirstOrbit"] + (timestamp - GLOparams["SOR"]) / LHCOrbitMUS
406-
407-
# check if timestamp is to be excluded
408-
job_is_exluded = exclude_timestamp(timestamp, orbit, args.run_number, args.run_span_file)
409-
# possibly invert the selection
410-
if args.invert_irframe_selection:
411-
job_is_exluded = not job_is_exluded
447+
mid_run_timestamp = (run_start + run_end) // 2
412448

413-
# this is anchored to
414-
print ("Determined start-of-run to be: ", run_start)
415-
print ("Determined end-of-run to be: ", run_end)
416-
print ("Determined timestamp to be : ", timestamp)
417-
print ("Determined offset to be : ", prod_offset)
449+
# --------
450+
# fetch other important global properties needed further below
451+
# --------
452+
ctp_scalers = retrieve_CTPScalers(ccdbreader, args.run_number, timestamp=mid_run_timestamp)
453+
if ctp_scalers is None:
454+
print(f"ERROR: Cannot retrive scalers for run number {args.run_number}")
455+
exit (1)
418456

457+
# retrieve the GRPHCIF object (using mid-run timestamp)
458+
grplhcif = retrieve_GRPLHCIF(ccdbreader, int(mid_run_timestamp))
419459

420-
# retrieve the GRPHCIF object
421-
grplhcif = retrieve_GRPLHCIF(ccdbreader, int(timestamp))
460+
# determine some fundamental physics quantities
422461
eCM = grplhcif.getSqrtS()
423462
A1 = grplhcif.getAtomicNumberB1()
424463
A2 = grplhcif.getAtomicNumberB2()
@@ -438,31 +477,40 @@ def main():
438477

439478
print ("Collision system ", ColSystem)
440479

480+
# possibly overwrite the orbitsPerTF with some external choices
481+
if args.orbitsPerTF!="":
482+
# we actually need the interaction rate for this calculation
483+
# let's use the one provided from IR.txt (async reco) as quick way to make the decision
484+
run_rate, _ = retrieve_MinBias_CTPScaler_Rate(ctp_scalers, mid_run_timestamp/1000., args.trig_eff, grplhcif.getBunchFilling().getNBunches(), ColSystem, eCM)
485+
determined_orbits = parse_orbits_per_tf(args.orbitsPerTF, run_rate)
486+
if determined_orbits != -1:
487+
print("Adjusting orbitsPerTF from " + str(GLOparams["OrbitsPerTF"]) + " to " + str(determined_orbits))
488+
GLOparams["OrbitsPerTF"] = determined_orbits
489+
490+
# determine timestamp, and production offset for the final MC job to run
491+
timestamp, prod_offset = determine_timestamp(run_start, run_end, [args.split_id - 1, args.prod_split], args.cycle, args.tf, GLOparams["OrbitsPerTF"])
492+
# determine orbit corresponding to timestamp
493+
orbit = GLOparams["FirstOrbit"] + (timestamp - GLOparams["SOR"]) / LHCOrbitMUS
494+
495+
# check if timestamp is to be excluded
496+
job_is_exluded = exclude_timestamp(timestamp, orbit, args.run_number, args.run_span_file, GLOparams)
497+
# possibly invert the selection
498+
if args.invert_irframe_selection:
499+
job_is_exluded = not job_is_exluded
500+
501+
# this is anchored to
502+
print ("Determined start-of-run to be: ", run_start)
503+
print ("Determined end-of-run to be: ", run_end)
504+
print ("Determined timestamp to be : ", timestamp)
505+
print ("Determined offset to be : ", prod_offset)
506+
441507
forwardargs = " ".join([ a for a in args.forward if a != '--' ])
442508
# retrieve interaction rate
443509
rate = None
444510
ctp_local_rate_raw = None
445511

446512
if args.ccdb_IRate == True:
447-
effTrigger = args.trig_eff
448-
if effTrigger < 0:
449-
if ColSystem == "pp":
450-
if eCM < 1000:
451-
effTrigger = 0.68
452-
elif eCM < 6000:
453-
effTrigger = 0.737
454-
else:
455-
effTrigger = 0.759
456-
elif ColSystem == "PbPb":
457-
effTrigger = 28.0 # this is ZDC
458-
else:
459-
effTrigger = 0.759
460-
ctp_scalers = retrieve_CTPScalers(ccdbreader, args.run_number)
461-
if ctp_scalers is None:
462-
print(f"ERROR: Cannot retrive scalers for run number {args.run_number}")
463-
exit (1)
464-
# time needs to be converted to seconds ==> timestamp / 1000
465-
rate, ctp_local_rate_raw = retrieve_MinBias_CTPScaler_Rate(ctp_scalers, timestamp/1000., effTrigger, grplhcif.getBunchFilling().getNBunches(), ColSystem)
513+
rate, ctp_local_rate_raw = retrieve_MinBias_CTPScaler_Rate(ctp_scalers, timestamp/1000., args.trig_eff, grplhcif.getBunchFilling().getNBunches(), ColSystem, eCM)
466514

467515
if rate != None:
468516
# if the rate calculation was successful we will use it, otherwise we fall back to some rate given as part

0 commit comments

Comments
 (0)