Belle II Software  release-06-02-00
caf_ecl_time_crystalCrate.py
1 # -*- coding: utf-8 -*-
2 
3 
10 
11 """ECL timing calibration that performs the crystal and crate calibrations,
12  merges the relevant crystal payloads, and makes validation plots. It is the
13  main script for executing the ECL timing calibrations."""
14 
15 from prompt import CalibrationSettings, INPUT_DATA_FILTERS
16 from reconstruction import prepare_cdst_analysis, prepare_user_cdst_analysis
17 from caf.utils import IoV, ExpRun
18 import copy
19 
20 
27 
28 
32 settings = CalibrationSettings(
33  name="ECL crystal and crate time calibrations and validations",
34  expert_username="hearty",
35  description=__doc__,
36  input_data_formats=["cdst"],
37  input_data_names=["bhabha_all_calib", "hadron_calib"],
38  input_data_filters={"bhabha_all_calib": [INPUT_DATA_FILTERS["Data Tag"]["bhabha_all_calib"],
39  INPUT_DATA_FILTERS["Beam Energy"]["4S"],
40  INPUT_DATA_FILTERS["Beam Energy"]["Continuum"],
41  INPUT_DATA_FILTERS["Beam Energy"]["Scan"],
42  INPUT_DATA_FILTERS["Data Quality Tag"]["Good"],
43  INPUT_DATA_FILTERS["Run Type"]["physics"],
44  INPUT_DATA_FILTERS["Magnet"]["On"]],
45  "hadron_calib": [INPUT_DATA_FILTERS["Data Tag"]["hadron_calib"],
46  INPUT_DATA_FILTERS["Beam Energy"]["4S"],
47  INPUT_DATA_FILTERS["Beam Energy"]["Continuum"],
48  INPUT_DATA_FILTERS["Beam Energy"]["Scan"],
49  INPUT_DATA_FILTERS["Data Quality Tag"]["Good"],
50  INPUT_DATA_FILTERS["Run Type"]["physics"],
51  INPUT_DATA_FILTERS["Magnet"]["On"]]},
52  depends_on=[],
53  expert_config={"numCrysCrateIterations": 1,
54  "maxNumberEvents": 50000000,
55  "payload_boundaries": [],
56  "t0_bhabhaToHadron_correction": 0})
57 
58 
59 
68 
69 
70 def get_calibrations(input_data, **kwargs):
71  """
72  Parameters:
73  input_data (dict): Should contain every name from the 'input_data_names' variable as a key.
74  Each value is a dictionary with {"/path/to/file_e1_r5.root": IoV(1,5,1,5), ...}. Useful for
75  assigning to calibration.files_to_iov
76 
77  **kwargs: Configuration options to be sent in. Since this may change we use kwargs as a way to help prevent
78  backwards compatibility problems. But you could use the correct arguments in b2caf-prompt-run for this
79  release explicitly if you want to.
80 
81  Currently only kwargs["output_iov"] is used. This is the output IoV range that your payloads should
82  correspond to. Generally your highest ExpRun payload should be open ended e.g. IoV(3,4,-1,-1)
83 
84  Returns:
85  list(caf.framework.Calibration): All of the calibration objects we want to assign to the CAF process
86  """
87  import basf2
88  # Set up config options
89 
90  # Extract expert config variables input from command line (or from
91  # the calibrations submission website via the command line).
92  expert_config = kwargs.get("expert_config")
93 
94  # Determine how many iterations of the crystal calibrations and
95  # crate calibrations to perform.
96  numCrysCrateIterations = expert_config["numCrysCrateIterations"]
97  print("expert_config: numCrysCrateIterations = ", numCrysCrateIterations)
98 
99  # Set the maximum number of events to include per crystal calibration
100  # NOTE: THIS IS NOT QUITE RIGHT SINCE THIS MAXIMUM DOESN'T WORK WITH
101  # THE sequentialBoundaries SET UP FOR SEPARATE RUN NUMBER REGIONS FOR
102  # CRYSTAL CALIBRATIONS !! BUT THIS WILL WORK WELL IF THERE IS ONLY ONE
103  # RUN RANGE REGION FOR THE CRYSTAL CALIBRATIONS.
104  maxNumEventsCrystalCalib = expert_config["maxNumberEvents"]
105  print("expert_config: maxNumEventsCrystalCalib = ", maxNumEventsCrystalCalib)
106 
107  # Determine how large of an offset should be applied to correct for
108  # differences in the CDC event t0 in bhabha and hadronic events
109  t0_bhabhaToHadron_correction = expert_config["t0_bhabhaToHadron_correction"]
110  print("expert_config: t0_bhabhaToHadron_correction = ", t0_bhabhaToHadron_correction)
111 
112  from caf.strategies import SimpleRunByRun, SingleIOV, SequentialBoundaries
113  import numpy as np
114 
115  # Determine the user defined calibration boundaries. Most useful
116  # for when multiple experiments are processed at the same time.
117  # Useful for the crystal calibrations but not for the crate
118  # calibrations, which are done run-by-run.
119  payload_boundaries = [] # Introduce empty list of payload boundaries.
120  payload_boundaries.extend([ExpRun(*boundary) for boundary in expert_config["payload_boundaries"]])
121  basf2.B2INFO(f"Expert set payload boundaries are: {expert_config['payload_boundaries']}")
122  print("payload_boundaries = ", payload_boundaries)
123 
124  # In this script we want to use one sources of input data.
125  # Get the input files from the input_data variable
126  # The input data should be the bhabha skim for the calibrations
127  # and the hadron skim for the validations.
128  file_to_iov_bhabha = input_data["bhabha_all_calib"]
129  file_to_iov_hadron = input_data["hadron_calib"]
130 
131  # Set the maximum limits on the number of files/events per run.
132  # If I decided to remove the limit on the number of files per run, it is just easier
133  # to set it to a large number in case we want to introduce it later.
134  # Also, keeping it allows the crystal calibrations code to look like the
135  # crates calibration code even though they don't use the same list of input files.
136  max_files_per_run_calibration = 26
137  max_files_per_run_validation = 4
138  max_events_per_run_plotting = 1
139 
140  setMaxEventsPerCrystalCalib = True
141  max_events_per_crystalCalib = 50000000
142  if (maxNumEventsCrystalCalib == -1):
143  setMaxEventsPerCrystalCalib = False
144  elif (maxNumEventsCrystalCalib > 0):
145  max_events_per_crystalCalib = maxNumEventsCrystalCalib
146 
147  print("max_events_per_crystalCalib = ", max_events_per_crystalCalib)
148 
149  # We filter addition files if there are more than [max_files_per_run] files per run.
150  # The input data files are sorted alphabetically by b2caf-prompt-run
151  # already. This procedure respects that ordering
152  from prompt.utils import filter_by_max_files_per_run
153 
154  # We filter addition files if there are more than [max_events_per_run] events per run.
155  # For plotting after the calibrations
156  from prompt.utils import filter_by_max_events_per_run
157 
158  # We filter addition files if there are more than [max_events_per_calibration] events per crystal calibration.
159  # For doing the crystal calibrations
160  from prompt.utils import filter_by_select_max_events_from_files
161 
162  reduced_file_to_iov_bhabha = filter_by_max_files_per_run(file_to_iov_bhabha, max_files_per_run_calibration)
163  input_files_bhabha = list(reduced_file_to_iov_bhabha.keys())
164  basf2.B2INFO(f"Total number of bhabha files actually used as input for crates = {len(input_files_bhabha)}")
165 
166  reduced_file_to_iov_bhabha_1perRun = filter_by_max_files_per_run(file_to_iov_bhabha, 1)
167  input_files_bhabha_1perRun = list(reduced_file_to_iov_bhabha_1perRun.keys())
168  basf2.B2INFO(f"Total number of bhabha files actually used for dummy collectors = {len(input_files_bhabha_1perRun)}")
169 
170  input_files_bhabha_full = list(file_to_iov_bhabha.keys())
171  basf2.B2INFO(f"Total number of bhabha files as input = {len(input_files_bhabha_full)}")
172 
173  if (setMaxEventsPerCrystalCalib):
174  temp_input_files_bhabha_full = input_files_bhabha_full.copy()
175  input_files_bhabha_crystal_maxEvents = filter_by_select_max_events_from_files(
176  temp_input_files_bhabha_full, max_events_per_crystalCalib)
177  basf2.B2INFO("Total number of bhabha files that could be used as input for crystal calibration ...")
178  basf2.B2INFO(f"(ignoring payload boundaries) if a max # events is used = {len(input_files_bhabha_crystal_maxEvents)}")
179 
180  if not input_files_bhabha_crystal_maxEvents:
181  input_files_bhabha_crystal_maxEvents = input_files_bhabha_full.copy()
182  print("Number of events < maximum so set the input files list equal to the full list of input bhabha files.")
183 
184  input_files_bhabha_crystal = input_files_bhabha_full.copy()
185  if (setMaxEventsPerCrystalCalib):
186  input_files_bhabha_crystal = input_files_bhabha_crystal_maxEvents.copy()
187  print("List of input files slimmed for crystals.")
188  else:
189  print("User requested max number of events filter to not be used so all bhabha input files being used for crystals")
190 
191  basf2.B2INFO(f"Total number of bhabha files being used for crystal calibration = {len(input_files_bhabha_crystal)}")
192 
193  reduced_file_to_iov_hadron = filter_by_max_files_per_run(file_to_iov_hadron, max_files_per_run_validation)
194  input_files_hadron = list(reduced_file_to_iov_hadron.keys())
195  basf2.B2INFO(f"Total number of hadron files actually used as input = {len(input_files_hadron)}")
196 
197  # For plotting the sum of the crate and crystal calibration
198  # constants after the calibrations are made. To be used to
199  # monitor crate time jumps.
200  reduced_file_to_iov_plotting = filter_by_max_events_per_run(file_to_iov_bhabha, max_events_per_run_plotting)
201  input_files_plotting = list(reduced_file_to_iov_plotting.keys())
202 
203  # Interval of validity for the calibrations
204  intermediate_iov = IoV(0, 0, -1, -1)
205  requested_iov = kwargs.get("requested_iov", None)
206  output_iov = IoV(requested_iov.exp_low, requested_iov.run_low, -1, -1)
207 
208 
209  from basf2 import register_module, create_path
210  from ROOT import Belle2
211  from caf.framework import Collection
212 
213 
215  print("Set up the base for the collectors for the calibrations")
216 
217  root_input = register_module('RootInput')
218  rec_path_bhabha = create_path()
219  rec_path_bhabha.add_module(root_input)
220  if 'Gearbox' not in rec_path_bhabha:
221  rec_path_bhabha.add_module('Gearbox')
222  if 'Geometry' not in rec_path_bhabha:
223  rec_path_bhabha.add_module('Geometry', useDB=True)
224 
225  prepare_cdst_analysis(rec_path_bhabha, components=['SVD', 'CDC', 'ECL', 'KLM'])
226 
227  # ====================================================
228  # t0BiasCorrection = -0.9 # Correct for the CDC t0 bias in ns
229  t0BiasCorrection = t0_bhabhaToHadron_correction # Correct for the CDC t0 bias in ns
230  # ====================================================
231 
232  col_bhabha = register_module('ECLBhabhaTCollector')
233  col_bhabha.param('timeAbsMax', 250)
234  col_bhabha.param('minCrystal', 1)
235  col_bhabha.param('maxCrystal', 8736)
236  col_bhabha.param('saveTree', False)
237  col_bhabha.param('skipTrgSel', False)
238  col_bhabha.param('hadronEventT0_TO_bhabhaEventT0_correction', t0BiasCorrection)
239 
240  eclTCol = Collection(collector=col_bhabha,
241  input_files=input_files_bhabha,
242  pre_collector_path=rec_path_bhabha)
243 
244  eclTCol_crys = Collection(collector=col_bhabha,
245  input_files=input_files_bhabha_crystal,
246  pre_collector_path=rec_path_bhabha)
247 
248 
250  print("Set up the base for the crate calibration algorithm")
251 
252  eclTAlgCrates = Belle2.ECL.eclBhabhaTAlgorithm()
253 
254  # Define the CAF algorithm arguments
255  # Set the cellIDLo to be larger than cellIDHi so that no crystal
256  # calibrations will be performed.
257  eclTAlgCrates.cellIDLo = 3
258  eclTAlgCrates.cellIDHi = 2
259  eclTAlgCrates.debugOutput = True
260  eclTAlgCrates.meanCleanRebinFactor = 3
261  eclTAlgCrates.meanCleanCutMinFactor = 0.3
262  eclTAlgCrates.debugFilenameBase = "eclBhabhaTAlgorithm"
263 
264 
266  print("Set up the base for the crystal calibration algorithm")
267 
268  eclTAlgCrystals = Belle2.ECL.eclBhabhaTAlgorithm()
269 
270  # Define the CAF algorithm arguments
271  # Set the crateIDLo to be larger than crateIDHi so that no crate
272  # calibrations will be performed. More variables set later in code....
273  eclTAlgCrystals.crateIDLo = 3
274  eclTAlgCrystals.crateIDHi = 2
275  eclTAlgCrystals.debugOutput = True
276  eclTAlgCrystals.meanCleanRebinFactor = 3
277  eclTAlgCrystals.meanCleanCutMinFactor = 0.3
278  eclTAlgCrystals.debugFilenameBase = "eclBhabhaTAlgorithm"
279 
280  # Make two versions of these algorithms that differ only in whether
281  # or not the previous bucket's payload information is saved
282  # to a temporary payload for comparison purposes at each
283  # iteration.
284  eclTAlgCrystals_saveNotReadPrevPayload = copy.deepcopy(eclTAlgCrystals)
285  eclTAlgCrystals_readNotSavePrevPayload = copy.deepcopy(eclTAlgCrystals)
286 
287  eclTAlgCrystals_saveNotReadPrevPayload.savePrevCrysPayload = True
288  eclTAlgCrystals_saveNotReadPrevPayload.readPrevCrysPayload = False
289 
290  eclTAlgCrystals_readNotSavePrevPayload.savePrevCrysPayload = False
291  eclTAlgCrystals_readNotSavePrevPayload.readPrevCrysPayload = True
292 
293 
295  print("Set up the base for the crystal merger algorithm")
296 
298  merging_alg.readPrevCrysPayload = True
299 
300 
306 
307  if numCrysCrateIterations <= 0:
308  print("numCrysCrateIterations NEEDS TO BE > 0 !!!")
309  elif numCrysCrateIterations > 0:
310 
312 
313  from caf.framework import Calibration
314  print("Performing ", numCrysCrateIterations, " iterations of crate and crystal calibrations.")
315 
316  crysCalibBaseName = "ECLcrystalTimeCalibration_physics_"
317  crateCalibBaseName = "ECLcrateTimeCalibration_physics_"
318  mergeCalibBaseName = "ecl_t_merge_"
319 
320  calibs = []
321 
322  # --------------------------------------------------------------
323  # Loop over all the iterations to set up the crate and crystal
324  # calibrations.
325 
326  for i in range(numCrysCrateIterations):
327  crysCalibName = crysCalibBaseName + str(i)
328  crateCalibName = crateCalibBaseName + str(i)
329  mergeCalibName = mergeCalibBaseName + str(i)
330 
331  print("iteration = ", i)
332  print("crysCalibName = ", crysCalibName)
333  print("crateCalibName = ", crateCalibName)
334 
335 
337  cal_crates_i = Calibration(crateCalibName)
338  cal_crates_i.add_collection(name="bhabha", collection=eclTCol)
339  cal_crates_i.algorithms = [eclTAlgCrates]
340  cal_crates_i.save_payloads = False
341  cal_crates_i.strategies = SimpleRunByRun
342  cal_crates_i.backend_args = {"request_memory": "4 GB"}
343 
344 
346 
347  cal_crystals_i = Calibration(crysCalibName)
348  cal_crystals_i.add_collection(name="bhabha", collection=eclTCol_crys)
349  cal_crystals_i.backend_args = {"request_memory": "4 GB"}
350 
351  # If this is the first iteration then save the previous crystal payload
352  # values to a temporary storage payload. If this is not the first iteration
353  # then read in the previous stored payload and plot the change in the crystal
354  if i == 0:
355  cal_crystals_i.algorithms = [eclTAlgCrystals_saveNotReadPrevPayload]
356  print("crystal algorithm: save previous payload for comparison purposes but do not read it")
357  print("eclTAlgCrystals_saveNotReadPrevPayload.savePrevCrysPayload = ",
358  eclTAlgCrystals_saveNotReadPrevPayload.savePrevCrysPayload)
359  print("eclTAlgCrystals_saveNotReadPrevPayload.readPrevCrysPayload = ",
360  eclTAlgCrystals_saveNotReadPrevPayload.readPrevCrysPayload)
361  else:
362  cal_crystals_i.algorithms = [eclTAlgCrystals_readNotSavePrevPayload]
363  print("crystal algorithm: do not save previous payload but do read it in for comparison purposes")
364  print("eclTAlgCrystals_readNotSavePrevPayload.savePrevCrysPayload = ",
365  eclTAlgCrystals_readNotSavePrevPayload.savePrevCrysPayload)
366  print("eclTAlgCrystals_readNotSavePrevPayload.readPrevCrysPayload = ",
367  eclTAlgCrystals_readNotSavePrevPayload.readPrevCrysPayload)
368 
369  cal_crystals_i.save_payloads = False
370 
371  # If payload boundaries are set use SequentialBoundaries
372  # otherwise use SingleIOV
373  if payload_boundaries:
374  cal_crystals_i.strategies = SequentialBoundaries
375  else:
376  cal_crystals_i.strategies = SingleIOV
377 
378 
380 
381  cal_ecl_merge_i = Calibration(name=mergeCalibName, collector="DummyCollector",
382  input_files=input_files_bhabha_1perRun)
383 
384  # Read in the previous crystal payload values for comparision
385  cal_ecl_merge_i.algorithms = [merging_alg]
386  print("merge algorithm: read previous payload for comparison purposes")
387  print("merging_alg.readPrevCrysPayload = ", merging_alg.readPrevCrysPayload)
388 
389  cal_ecl_merge_i.save_payloads = False
390  ecl_merge_pre_path_i = basf2.create_path()
391  prepare_cdst_analysis(ecl_merge_pre_path_i, components=['SVD', 'CDC', 'ECL', 'KLM'])
392  ecl_merge_pre_path_i.pre_collector_path = ecl_merge_pre_path_i
393 
394  # If payload boundaries are set use SequentialBoundaries
395  # otherwise use SingleIOV
396  if payload_boundaries:
397  cal_ecl_merge_i.strategies = SequentialBoundaries
398  else:
399  cal_ecl_merge_i.strategies = SingleIOV
400 
401  # Modify the iov for each of the calibration algorithms
402  for algorithm in cal_crystals_i.algorithms:
403  # The payload of the final crystal calibration iteration
404  # is given the user's iov.
405  if i == numCrysCrateIterations - 1:
406  # Set payload iov information for SequentialBoundaries
407  # and SingleIOV strategies.
408  if payload_boundaries:
409  algorithm.params = {"iov_coverage": output_iov,
410  "payload_boundaries": payload_boundaries}
411 
412  print("Set iov for final crystals alg - SequentialBoundaries")
413  else:
414  algorithm.params = {"apply_iov": output_iov}
415  print("Set iov for final crystals alg - SingleIOV ")
416  # Force the output iovs to be open for the intermediate
417  # step calibrations.
418  else:
419  if payload_boundaries:
420  algorithm.params = {"iov_coverage": intermediate_iov,
421  "payload_boundaries": payload_boundaries}
422  print("Set iov for intermediate crystals alg - SequentialBoundaries")
423  else:
424  algorithm.params = {"apply_iov": intermediate_iov}
425  print("Set iov for intermediate crystals alg - SingleIOV ")
426 
427  # Modify the iov for each of the payload merging algorithms
428  for algorithm in cal_ecl_merge_i.algorithms:
429  # The payload of the final crystal calibration iteration
430  # is given the user's iov.
431  if i == numCrysCrateIterations - 1:
432  # Set payload iov information for SequentialBoundaries
433  # and SingleIOV strategies.
434  if payload_boundaries:
435  algorithm.params = {"iov_coverage": output_iov,
436  "payload_boundaries": payload_boundaries}
437 
438  print("Set iov for final merging alg - SequentialBoundaries")
439  else:
440  algorithm.params = {"apply_iov": output_iov}
441  print("Set iov for final merging alg - SingleIOV ")
442  # Force the output iovs to be open for the intermediate
443  # step calibrations.
444  else:
445  if payload_boundaries:
446  algorithm.params = {"iov_coverage": intermediate_iov,
447  "payload_boundaries": payload_boundaries}
448  print("Set iov for intermediate merging alg - SequentialBoundaries")
449  else:
450  algorithm.params = {"apply_iov": intermediate_iov}
451  print("Set iov for intermediate merging alg - SingleIOV ")
452 
453  # Fill the calibs array with all the "calibrations" that will be run
454  calibs = np.append(calibs, [cal_crates_i, cal_crystals_i, cal_ecl_merge_i])
455 
456  # Make sure that the final paylaods get saved.
457  calibs[len(calibs) - 3].save_payloads = True # crates
458  calibs[len(calibs) - 1].save_payloads = True # crystals
459 
460 
465 
466 
469  root_input = register_module('RootInput')
470  rec_path_bhabha_val = create_path()
471  rec_path_bhabha_val.add_module(root_input)
472  if 'Gearbox' not in rec_path_bhabha_val:
473  rec_path_bhabha_val.add_module('Gearbox')
474  if 'Geometry' not in rec_path_bhabha_val:
475  rec_path_bhabha_val.add_module('Geometry', useDB=True)
476 
477  # exclude PXD and PID, so only CDC and ECL used for eventT0
478  prepare_user_cdst_analysis(rec_path_bhabha_val, components=['SVD', 'CDC', 'ECL', 'KLM'])
479  col_bhabha_val = register_module('eclBhabhaTimeCalibrationValidationCollector')
480  col_bhabha_val.param('timeAbsMax', 70)
481  col_bhabha_val.param('saveTree', False)
482  col_bhabha_val.param('skipTrgSel', False)
483 
484  eclValTCol = Collection(collector=col_bhabha_val,
485  input_files=input_files_bhabha_crystal,
486  pre_collector_path=rec_path_bhabha_val)
487 
488 
490 
491  # Give the collector name to the algorithm since one algorithm
492  # is used to analyse the results from several possible collectors
493  eclValTAlgBhabha = Belle2.ECL.eclTValidationAlgorithm("eclBhabhaTimeCalibrationValidationCollector")
494 
495  # Define the CAF algorithm arguments
496  eclValTAlgBhabha.meanCleanRebinFactor = 3
497  eclValTAlgBhabha.meanCleanCutMinFactor = 0.4
498  eclValTAlgBhabha.clusterTimesFractionWindow_maxtime = 1.5
499  eclValTAlgBhabha.debugFilenameBase = "eclBhabhaTValidationAlgorithm"
500 
501 
503 
504  from caf.framework import Calibration
505 
506  valid_cal_bhabha = Calibration("ECLcrystalTimeCalValidation_bhabhaPhysics")
507  valid_cal_bhabha.add_collection(name="bhabha", collection=eclValTCol)
508  valid_cal_bhabha.save_payloads = False
509  valid_cal_bhabha.backend_args = {"request_memory": "4 GB"}
510 
511  # Make a second version of this algorithm that differs only in
512  # that it is instructed to read the previous crystal payload.
513  # The version where we don't read in the previous payload
514  # is left over from a previous code version
515  eclValTAlgBhabha_readPrevPayload = copy.deepcopy(eclValTAlgBhabha)
516  eclValTAlgBhabha_readPrevPayload.readPrevCrysPayload = True
517 
518  valid_cal_bhabha.algorithms = [eclValTAlgBhabha_readPrevPayload]
519  print("bhabha validation: read previous payload for comparison purposes")
520  print("eclValTAlgBhabha_readPrevPayload.readPrevCrysPayload = ",
521  eclValTAlgBhabha_readPrevPayload.readPrevCrysPayload)
522 
523  # If payload boundaries are set use SequentialBoundaries
524  # otherwise use SingleIOV
525  if payload_boundaries:
526  valid_cal_bhabha.strategies = SequentialBoundaries
527  else:
528  valid_cal_bhabha.strategies = SingleIOV
529 
530  for algorithm in valid_cal_bhabha.algorithms:
531  # Set payload iov information for SequentialBoundaries
532  # and SingleIOV strategies.
533  if payload_boundaries:
534  algorithm.params = {"iov_coverage": output_iov,
535  "payload_boundaries": payload_boundaries}
536 
537  print("Set iov for bhabha validation alg - SequentialBoundaries")
538  else:
539  algorithm.params = {"apply_iov": output_iov}
540  print("Set iov for bhabha validation alg - SingleIOV")
541 
542 
545  root_input = register_module('RootInput')
546  rec_path_hadron_val = create_path()
547  rec_path_hadron_val.add_module(root_input)
548  if 'Gearbox' not in rec_path_hadron_val:
549  rec_path_hadron_val.add_module('Gearbox')
550  if 'Geometry' not in rec_path_hadron_val:
551  rec_path_hadron_val.add_module('Geometry', useDB=True)
552 
553  # exclude PXD and PID, so only CDC and ECL used for eventT0
554  prepare_user_cdst_analysis(rec_path_hadron_val, components=['SVD', 'CDC', 'ECL', 'KLM'])
555  col_hadron_val = register_module('eclHadronTimeCalibrationValidationCollector')
556  col_hadron_val.param('timeAbsMax', 70)
557  col_hadron_val.param('saveTree', False)
558 
559  eclValTCol = Collection(collector=col_hadron_val,
560  input_files=input_files_hadron,
561  pre_collector_path=rec_path_hadron_val)
562 
563 
565 
566  # Give the collector name to the algorithm since one algorithm
567  # is used to analyse the results from several possible collectors
568  eclValTAlgHadronic = Belle2.ECL.eclTValidationAlgorithm("eclHadronTimeCalibrationValidationCollector")
569 
570  # Define the CAF algorithm arguments
571  eclValTAlgHadronic.meanCleanRebinFactor = 3
572  eclValTAlgHadronic.meanCleanCutMinFactor = 0.4
573  eclValTAlgHadronic.clusterTimesFractionWindow_maxtime = 8
574  eclValTAlgHadronic.debugFilenameBase = "eclHadronTValidationAlgorithm"
575 
576 
578 
579  from caf.framework import Calibration
580 
581  valid_cal_hadron = Calibration("ECLcrystalTimeCalValidation_hadronPhysics")
582  valid_cal_hadron.add_collection(name="hadron", collection=eclValTCol)
583  valid_cal_hadron.save_payloads = False
584  valid_cal_hadron.backend_args = {"request_memory": "4 GB"}
585 
586  # Make a second version of this algorithm that differs only in
587  # that it is instructed to read the previous crystal payload
588  eclValTAlgHadron_readPrevPayload = copy.deepcopy(eclValTAlgHadronic)
589  eclValTAlgHadron_readPrevPayload.readPrevCrysPayload = True
590 
591  # Make a second version of this algorithm that differs only in
592  # that it is instructed to read the previous crystal payload.
593  # The version where we don't read in the previous payload
594  # is left over from a previous code version
595  valid_cal_hadron.algorithms = [eclValTAlgHadron_readPrevPayload]
596  print("hadron validation: read previous payload for comparison purposes")
597  print("eclValTAlgHadron_readPrevPayload.readPrevCrysPayload = ",
598  eclValTAlgHadron_readPrevPayload.readPrevCrysPayload)
599 
600  # If payload boundaries are set use SequentialBoundaries
601  # otherwise use SingleIOV
602  if payload_boundaries:
603  valid_cal_hadron.strategies = SequentialBoundaries
604  else:
605  valid_cal_hadron.strategies = SingleIOV
606 
607  for algorithm in valid_cal_hadron.algorithms:
608  # Set payload iov information for SequentialBoundaries
609  # and SingleIOV strategies.
610  if payload_boundaries:
611  algorithm.params = {"iov_coverage": output_iov,
612  "payload_boundaries": payload_boundaries}
613 
614  print("Set iov for hadron validation alg - SequentialBoundaries")
615  else:
616  algorithm.params = {"apply_iov": output_iov}
617  print("Set iov for hadron validation alg - SingleIOV")
618 
619 
622 
623  # Set up the collector but with only one event per file
624  root_input = register_module('RootInput', entrySequences=['0:{}'.format(1)])
625 
626  rec_path_bhabha_plotting = create_path()
627  rec_path_bhabha_plotting.add_module(root_input)
628  if 'Gearbox' not in rec_path_bhabha_plotting:
629  rec_path_bhabha_plotting.add_module('Gearbox')
630  if 'Geometry' not in rec_path_bhabha_plotting:
631  rec_path_bhabha_plotting.add_module('Geometry', useDB=True)
632 
633  prepare_cdst_analysis(rec_path_bhabha_plotting, components=['SVD', 'CDC', 'ECL', 'KLM'])
634 
635  col_bhabha_plotting = register_module('eclTimeShiftsPlottingCollector')
636  eclTCol = Collection(collector=col_bhabha_plotting,
637  input_files=input_files_plotting,
638  pre_collector_path=rec_path_bhabha_plotting)
639 
640  # Set up the plotting. Use the two files with the collector to
641  # determine the run range to plot. The plotting is done in the
642  # algorithm
643 
644  tShifts_alg = Belle2.ECL.eclTimeShiftsAlgorithm()
645  tShifts_alg.debugFilenameBase = "eclTimeShiftsAlgorithm"
646 
647  # +-30ns range allows for unexpectedly large jumps
648  tShifts_alg.crysCrateShift_min = -30 # in ns
649  tShifts_alg.crysCrateShift_max = 30 # in ns
650 
651  # Make the algorithm loop over the runs, not just the collector
652  # tShifts_alg.algorithmReadPayloads = True
653 
654  cal_ecl_timeShifts = Calibration(name="ecl_t_shifts", algorithms=[tShifts_alg],
655  input_files=input_files_plotting)
656  cal_ecl_timeShifts.add_collection(name="bhabha", collection=eclTCol)
657 
658  cal_ecl_timeShifts.save_payloads = False
659 
660  # If payload boundaries are set use SequentialBoundaries
661  # otherwise use SingleIOV
662  if payload_boundaries:
663  cal_ecl_timeShifts.strategies = SequentialBoundaries
664  else:
665  cal_ecl_timeShifts.strategies = SingleIOV
666 
667  for algorithm in cal_ecl_timeShifts.algorithms:
668  # Set payload iov information for SequentialBoundaries
669  # and SingleIOV strategies.
670  if payload_boundaries:
671  algorithm.params = {"iov_coverage": output_iov,
672  "payload_boundaries": payload_boundaries}
673 
674  print("Set iov for crate time plotting alg - SequentialBoundaries")
675  else:
676  algorithm.params = {"apply_iov": output_iov}
677  print("Set iov for crate time plotting alg - SingleIOV")
678 
679 
684 
685  # Make the crate and crytsal calibrations and the cerge crystal
686  # process occur in the order loaded into the array.
687  for i in range(len(calibs) - 1):
688  calibs[i + 1].depends_on(calibs[i])
689 
690  # The validations and plotting can run independently of each other
691  # but rely on the last calibration step
692  valid_cal_bhabha.depends_on(calibs[len(calibs) - 1])
693  valid_cal_hadron.depends_on(calibs[len(calibs) - 1])
694  cal_ecl_timeShifts.depends_on(calibs[len(calibs) - 1])
695 
696 
698 
699  calibs = np.append(calibs, [valid_cal_bhabha, valid_cal_hadron, cal_ecl_timeShifts])
700 
701  print("##############")
702  print("List of calibrations:")
703  for c in calibs:
704  print(" ", c.name, " depends on ", c.dependencies, ", save payloads = ", c.save_payloads)
705  print("##############")
706 
707  # You must return all calibrations you want to run in the prompt process, even if it's only one
708  # Calibrations will be executed in this order as a result of the dependencies defined by the "dependes_on(...)".
709  return calibs
710 
711 
Calibrate ecl crystals using bhabha events.
Calibrate ecl crystals using previously created payloads.
Validate the ecl timing calibrations using a hadronic event selection.
Calibrate ecl crystals using previously created payloads.