@@ -264,33 +264,56 @@ def determine_timestamp(sor, eor, splitinfo, cycle, ntf, HBF_per_timeframe = 256
264264 Determines the timestamp and production offset variable based
265265 on the global properties of the production (MC split, etc) and the properties
266266 of the run. ntf is the number of timeframes per MC job
267+
268+ Args:
269+ sor: int
270+ start-of-run in milliseconds since epoch
271+ eor: int
272+ end-of-run in milliseconds since epoch
273+ splitinfo: tuple (int, int)
274+ splitinfo[0]: split ID of this job
275+ splitinfo[1]: total number of jobs to split into
276+ cycle: int
277+ cycle of this productions. Typically a run is not entirely filled by and anchored simulation
278+ but only a proportion of events is simulated.
279+ With increasing number of cycles, the data run is covered more and more.
280+ ntf: int
281+ number of timeframes
282+ HBF_per_timeframe: int
283+ number of orbits per timeframe
284+ Returns:
285+ int: timestamp in milliseconds
286+ int: production offset aka "which timeslot in this production to simulate"
267287 """
268288 totaljobs = splitinfo [1 ]
269289 thisjobID = splitinfo [0 ]
270- print (f"Start-of-run : { sor } " )
271- print (f"End-of-run : { eor } " )
272- time_length_inmus = 1000 * (eor - sor ) # time length in micro seconds
273- timestamp_delta = time_length_inmus / totaljobs
290+ # length of this run in micro seconds, since we use the orbit duration in micro seconds
291+ time_length_inmus = 1000 * (eor - sor )
274292
293+ # figure out how many timeframes fit into this run range
294+ # take the number of orbits per timeframe and multiply by orbit duration to calculate how many timeframes fit into this run
275295 ntimeframes = time_length_inmus / (HBF_per_timeframe * LHCOrbitMUS )
276- norbits = time_length_inmus / LHCOrbitMUS
296+ # also calculate how many orbits fit into the run range
277297 print (f"This run has space for { ntimeframes } timeframes" )
278- print (f"This run has { norbits } orbits" )
279298
280- # ntimeframes is the total number of timeframes possible
281- # if we have totaljobs number of jobs
282- maxtimeframesperjob = ntimeframes // totaljobs
283- orbitsperjob = norbits // totaljobs
299+ # figure out how many timeframes can maximally be covered by one job
300+ maxtimeframesperjob = ntimeframes / totaljobs
284301 print (f"Each job can do { maxtimeframesperjob } maximally at a prod split of { totaljobs } " )
285- print (f"With each job doing { ntf } timeframes, this corresponds to a filling rate of " , ntf / maxtimeframesperjob )
302+ print (f"With each job doing { ntf } timeframes, this corresponds to a filling rate of { ntf / maxtimeframesperjob } " )
286303 # filling rate should be smaller than 100%
287304 assert (ntf <= maxtimeframesperjob )
288305
289- maxcycles = maxtimeframesperjob // ntf
290- print (f"We can do this amount of cycle iterations to achieve 100%: " , maxcycles )
306+ # each cycle populates more and more run range. The maximum number of cycles to populate the run fully is:
307+ maxcycles = maxtimeframesperjob / ntf
308+ print (f"We can do this amount of cycle iterations to achieve 100%: { maxcycles } " )
291309
310+ # overall, we have maxcycles * totaljobs slots to fill the run range with ntf timeframes per slot
311+ # figure out in which slot to simulate
292312 production_offset = int (thisjobID * maxcycles ) + cycle
313+ # add the time difference of this slot to start-of-run to get the final timestamp
293314 timestamp_of_production = sor + production_offset * ntf * HBF_per_timeframe * LHCOrbitMUS / 1000
315+ # this is a closure test. If we had prefect floating point precision everywhere, it wouldn't fail.
316+ # But since we don't have that and there are some int casts as well, better check again.
294317 assert (timestamp_of_production >= sor )
295318 assert (timestamp_of_production <= eor )
296319 return int (timestamp_of_production ), production_offset
@@ -328,16 +351,17 @@ def main():
328351 exit (1 )
329352
330353 first_orbit = ctp_scalers .getOrbitLimit ().first
354+ # SOR and EOR values in milliseconds
331355 sor = ctp_scalers .getTimeLimit ().first
332356 eor = ctp_scalers .getTimeLimit ().second
333357
334358 if args .use_rct_info :
335359 first_orbit = GLOparams ["FirstOrbit" ]
360+ # SOR and EOR values in milliseconds
336361 sor = GLOparams ["SOR" ]
337362 eor = GLOparams ["EOR" ]
338363
339- # determine timestamp, and production offset for the final
340- # MC job to run
364+ # determine timestamp, and production offset for the final MC job to run
341365 timestamp , prod_offset = determine_timestamp (sor , eor , [args .split_id - 1 , args .prod_split ], args .cycle , args .tf , GLOparams ["OrbitsPerTF" ])
342366
343367 # this is anchored to
@@ -346,13 +370,8 @@ def main():
346370 print ("Determined timestamp to be : " , timestamp )
347371 print ("Determined offset to be : " , prod_offset )
348372
349- currentorbit = first_orbit + prod_offset * GLOparams ["OrbitsPerTF" ] # orbit number at production start
350- currenttime = sor + prod_offset * GLOparams ["OrbitsPerTF" ] * LHCOrbitMUS // 1000 # timestamp in milliseconds
351-
352- print ("Production put at time : " + str (currenttime ))
353-
354373 # retrieve the GRPHCIF object
355- grplhcif = retrieve_GRPLHCIF (ccdbreader , int (currenttime ))
374+ grplhcif = retrieve_GRPLHCIF (ccdbreader , int (timestamp ))
356375 eCM = grplhcif .getSqrtS ()
357376 A1 = grplhcif .getAtomicNumberB1 ()
358377 A2 = grplhcif .getAtomicNumberB2 ()
@@ -390,8 +409,9 @@ def main():
390409 effTrigger = 28.0 # this is ZDC
391410 else :
392411 effTrigger = 0.759
393-
394- rate = retrieve_MinBias_CTPScaler_Rate (ctp_scalers , currenttime / 1000. , effTrigger , grplhcif .getBunchFilling ().getNBunches (), ColSystem )
412+
413+ # time needs to be converted to seconds ==> timestamp / 1000
414+ rate = retrieve_MinBias_CTPScaler_Rate (ctp_scalers , timestamp / 1000. , effTrigger , grplhcif .getBunchFilling ().getNBunches (), ColSystem )
395415
396416 if rate != None :
397417 # if the rate calculation was successful we will use it, otherwise we fall back to some rate given as part
0 commit comments