Belle II Software development
caf_ecl_time_crystalCrate.py
1
8
9"""ECL timing calibration that performs the crystal and crate calibrations,
10 merges the relevant crystal payloads, and makes validation plots. It is the
11 main script for executing the ECL timing calibrations."""
12
13from prompt import CalibrationSettings, INPUT_DATA_FILTERS
14from reconstruction import prepare_cdst_analysis, prepare_user_cdst_analysis
15from caf.utils import IoV, ExpRun
16import copy
17
18
25
26
30settings = CalibrationSettings(
31 name="ECL crystal and crate time calibrations and validations",
32 expert_username="hearty",
33 subsystem="ecl",
34 description=__doc__,
35 input_data_formats=["cdst"],
36 input_data_names=["bhabha_all_calib", "hadron_calib"],
37 input_data_filters={"bhabha_all_calib": [INPUT_DATA_FILTERS["Data Tag"]["bhabha_all_calib"],
38 INPUT_DATA_FILTERS["Beam Energy"]["4S"],
39 INPUT_DATA_FILTERS["Beam Energy"]["Continuum"],
40 INPUT_DATA_FILTERS["Beam Energy"]["Scan"],
41 INPUT_DATA_FILTERS["Data Quality Tag"]["Good"],
42 INPUT_DATA_FILTERS["Run Type"]["physics"],
43 INPUT_DATA_FILTERS["Magnet"]["On"]],
44 "hadron_calib": [INPUT_DATA_FILTERS["Data Tag"]["hadron_calib"],
45 INPUT_DATA_FILTERS["Beam Energy"]["4S"],
46 INPUT_DATA_FILTERS["Beam Energy"]["Continuum"],
47 INPUT_DATA_FILTERS["Beam Energy"]["Scan"],
48 INPUT_DATA_FILTERS["Data Quality Tag"]["Good"],
49 INPUT_DATA_FILTERS["Run Type"]["physics"],
50 INPUT_DATA_FILTERS["Magnet"]["On"]]},
51 depends_on=[],
52 expert_config={"numCrysCrateIterations": 1,
53 "maxNumberEvents": 50000000,
54 "payload_boundaries": [],
55 "t0_bhabhaToHadron_correction": 0},
56 produced_payloads=["ECLCrateTimeOffset", "ECLCrystalTimeOffset"])
57
58
59
68
69
70def 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 SVD 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 = t0_bhabhaToHadron_correction # Correct for the SVD t0 bias in ns
229 # ====================================================
230
231 col_bhabha = register_module('ECLBhabhaTCollector')
232 col_bhabha.param('timeAbsMax', 250)
233 col_bhabha.param('minCrystal', 1)
234 col_bhabha.param('maxCrystal', 8736)
235 col_bhabha.param('saveTree', False)
236 col_bhabha.param('skipTrgSel', False)
237 col_bhabha.param('hadronEventT0_TO_bhabhaEventT0_correction', t0BiasCorrection)
238
239 eclTCol = Collection(collector=col_bhabha,
240 input_files=input_files_bhabha,
241 pre_collector_path=rec_path_bhabha)
242
243 eclTCol_crys = Collection(collector=col_bhabha,
244 input_files=input_files_bhabha_crystal,
245 pre_collector_path=rec_path_bhabha)
246
247
249 print("Set up the base for the crate calibration algorithm")
250
251 eclTAlgCrates = Belle2.ECL.eclBhabhaTAlgorithm()
252
253 # Define the CAF algorithm arguments
254 # Set the cellIDLo to be larger than cellIDHi so that no crystal
255 # calibrations will be performed.
256 eclTAlgCrates.cellIDLo = 3
257 eclTAlgCrates.cellIDHi = 2
258 eclTAlgCrates.debugOutput = True
259 eclTAlgCrates.meanCleanRebinFactor = 3
260 eclTAlgCrates.meanCleanCutMinFactor = 0.3
261 eclTAlgCrates.debugFilenameBase = "eclBhabhaTAlgorithm"
262
263
265 print("Set up the base for the crystal calibration algorithm")
266
267 eclTAlgCrystals = Belle2.ECL.eclBhabhaTAlgorithm()
268
269 # Define the CAF algorithm arguments
270 # Set the crateIDLo to be larger than crateIDHi so that no crate
271 # calibrations will be performed. More variables set later in code....
272 eclTAlgCrystals.crateIDLo = 3
273 eclTAlgCrystals.crateIDHi = 2
274 eclTAlgCrystals.debugOutput = True
275 eclTAlgCrystals.meanCleanRebinFactor = 3
276 eclTAlgCrystals.meanCleanCutMinFactor = 0.3
277 eclTAlgCrystals.debugFilenameBase = "eclBhabhaTAlgorithm"
278
279 # Make two versions of these algorithms that differ only in whether
280 # or not the previous bucket's payload information is saved
281 # to a temporary payload for comparison purposes at each
282 # iteration.
283 eclTAlgCrystals_saveNotReadPrevPayload = copy.deepcopy(eclTAlgCrystals)
284 eclTAlgCrystals_readNotSavePrevPayload = copy.deepcopy(eclTAlgCrystals)
285
286 eclTAlgCrystals_saveNotReadPrevPayload.savePrevCrysPayload = True
287 eclTAlgCrystals_saveNotReadPrevPayload.readPrevCrysPayload = False
288
289 eclTAlgCrystals_readNotSavePrevPayload.savePrevCrysPayload = False
290 eclTAlgCrystals_readNotSavePrevPayload.readPrevCrysPayload = True
291
292
294 print("Set up the base for the crystal merger algorithm")
295
297 merging_alg.readPrevCrysPayload = True
298
299
305
306 if numCrysCrateIterations <= 0:
307 print("numCrysCrateIterations NEEDS TO BE > 0 !!!")
308 elif numCrysCrateIterations > 0:
309
311
312 from caf.framework import Calibration
313 print("Performing ", numCrysCrateIterations, " iterations of crate and crystal calibrations.")
314
315 crysCalibBaseName = "ECLcrystalTimeCalibration_physics_"
316 crateCalibBaseName = "ECLcrateTimeCalibration_physics_"
317 mergeCalibBaseName = "ecl_t_merge_"
318
319 calibs = []
320
321 # --------------------------------------------------------------
322 # Loop over all the iterations to set up the crate and crystal
323 # calibrations.
324
325 for i in range(numCrysCrateIterations):
326 crysCalibName = crysCalibBaseName + str(i)
327 crateCalibName = crateCalibBaseName + str(i)
328 mergeCalibName = mergeCalibBaseName + str(i)
329
330 print("iteration = ", i)
331 print("crysCalibName = ", crysCalibName)
332 print("crateCalibName = ", crateCalibName)
333
334
336 cal_crates_i = Calibration(crateCalibName)
337 cal_crates_i.add_collection(name="bhabha", collection=eclTCol)
338 cal_crates_i.algorithms = [eclTAlgCrates]
339 cal_crates_i.save_payloads = False
340 cal_crates_i.strategies = SimpleRunByRun
341 cal_crates_i.backend_args = {"request_memory": "4 GB"}
342
343
345
346 cal_crystals_i = Calibration(crysCalibName)
347 cal_crystals_i.add_collection(name="bhabha", collection=eclTCol_crys)
348 cal_crystals_i.backend_args = {"request_memory": "4 GB"}
349
350 # If this is the first iteration then save the previous crystal payload
351 # values to a temporary storage payload. If this is not the first iteration
352 # then read in the previous stored payload and plot the change in the crystal
353 if i == 0:
354 cal_crystals_i.algorithms = [eclTAlgCrystals_saveNotReadPrevPayload]
355 print("crystal algorithm: save previous payload for comparison purposes but do not read it")
356 print("eclTAlgCrystals_saveNotReadPrevPayload.savePrevCrysPayload = ",
357 eclTAlgCrystals_saveNotReadPrevPayload.savePrevCrysPayload)
358 print("eclTAlgCrystals_saveNotReadPrevPayload.readPrevCrysPayload = ",
359 eclTAlgCrystals_saveNotReadPrevPayload.readPrevCrysPayload)
360 else:
361 cal_crystals_i.algorithms = [eclTAlgCrystals_readNotSavePrevPayload]
362 print("crystal algorithm: do not save previous payload but do read it in for comparison purposes")
363 print("eclTAlgCrystals_readNotSavePrevPayload.savePrevCrysPayload = ",
364 eclTAlgCrystals_readNotSavePrevPayload.savePrevCrysPayload)
365 print("eclTAlgCrystals_readNotSavePrevPayload.readPrevCrysPayload = ",
366 eclTAlgCrystals_readNotSavePrevPayload.readPrevCrysPayload)
367
368 cal_crystals_i.save_payloads = False
369
370 # If payload boundaries are set use SequentialBoundaries
371 # otherwise use SingleIOV
372 if payload_boundaries:
373 cal_crystals_i.strategies = SequentialBoundaries
374 else:
375 cal_crystals_i.strategies = SingleIOV
376
377
379
380 cal_ecl_merge_i = Calibration(name=mergeCalibName, collector="DummyCollector",
381 input_files=input_files_bhabha_1perRun)
382
383 # Read in the previous crystal payload values for comparison
384 cal_ecl_merge_i.algorithms = [merging_alg]
385 print("merge algorithm: read previous payload for comparison purposes")
386 print("merging_alg.readPrevCrysPayload = ", merging_alg.readPrevCrysPayload)
387
388 cal_ecl_merge_i.save_payloads = False
389 ecl_merge_pre_path_i = basf2.create_path()
390 prepare_cdst_analysis(ecl_merge_pre_path_i, components=['SVD', 'CDC', 'ECL', 'KLM'])
391 ecl_merge_pre_path_i.pre_collector_path = ecl_merge_pre_path_i
392
393 # If payload boundaries are set use SequentialBoundaries
394 # otherwise use SingleIOV
395 if payload_boundaries:
396 cal_ecl_merge_i.strategies = SequentialBoundaries
397 else:
398 cal_ecl_merge_i.strategies = SingleIOV
399
400 # Modify the iov for each of the calibration algorithms
401 for algorithm in cal_crystals_i.algorithms:
402 # The payload of the final crystal calibration iteration
403 # is given the user's iov.
404 if i == numCrysCrateIterations - 1:
405 # Set payload iov information for SequentialBoundaries
406 # and SingleIOV strategies.
407 if payload_boundaries:
408 algorithm.params = {"iov_coverage": output_iov,
409 "payload_boundaries": payload_boundaries}
410
411 print("Set iov for final crystals alg - SequentialBoundaries")
412 else:
413 algorithm.params = {"apply_iov": output_iov}
414 print("Set iov for final crystals alg - SingleIOV ")
415 # Force the output iovs to be open for the intermediate
416 # step calibrations.
417 else:
418 if payload_boundaries:
419 algorithm.params = {"iov_coverage": intermediate_iov,
420 "payload_boundaries": payload_boundaries}
421 print("Set iov for intermediate crystals alg - SequentialBoundaries")
422 else:
423 algorithm.params = {"apply_iov": intermediate_iov}
424 print("Set iov for intermediate crystals alg - SingleIOV ")
425
426 # Modify the iov for each of the payload merging algorithms
427 for algorithm in cal_ecl_merge_i.algorithms:
428 # The payload of the final crystal calibration iteration
429 # is given the user's iov.
430 if i == numCrysCrateIterations - 1:
431 # Set payload iov information for SequentialBoundaries
432 # and SingleIOV strategies.
433 if payload_boundaries:
434 algorithm.params = {"iov_coverage": output_iov,
435 "payload_boundaries": payload_boundaries}
436
437 print("Set iov for final merging alg - SequentialBoundaries")
438 else:
439 algorithm.params = {"apply_iov": output_iov}
440 print("Set iov for final merging alg - SingleIOV ")
441 # Force the output iovs to be open for the intermediate
442 # step calibrations.
443 else:
444 if payload_boundaries:
445 algorithm.params = {"iov_coverage": intermediate_iov,
446 "payload_boundaries": payload_boundaries}
447 print("Set iov for intermediate merging alg - SequentialBoundaries")
448 else:
449 algorithm.params = {"apply_iov": intermediate_iov}
450 print("Set iov for intermediate merging alg - SingleIOV ")
451
452 # Fill the calibs array with all the "calibrations" that will be run
453 calibs = np.append(calibs, [cal_crates_i, cal_crystals_i, cal_ecl_merge_i])
454
455 # Make sure that the final paylaods get saved.
456 calibs[len(calibs) - 3].save_payloads = True # crates
457 calibs[len(calibs) - 1].save_payloads = True # crystals
458
459
464
465
468 root_input = register_module('RootInput')
469 rec_path_bhabha_val = create_path()
470 rec_path_bhabha_val.add_module(root_input)
471 if 'Gearbox' not in rec_path_bhabha_val:
472 rec_path_bhabha_val.add_module('Gearbox')
473 if 'Geometry' not in rec_path_bhabha_val:
474 rec_path_bhabha_val.add_module('Geometry', useDB=True)
475
476 # exclude PXD and PID; not needed
477 prepare_user_cdst_analysis(rec_path_bhabha_val, components=['SVD', 'CDC', 'ECL', 'KLM'])
478 col_bhabha_val = register_module('eclBhabhaTimeCalibrationValidationCollector')
479 col_bhabha_val.param('timeAbsMax', 70)
480 col_bhabha_val.param('saveTree', False)
481 col_bhabha_val.param('skipTrgSel', False)
482
483 eclValTCol = Collection(collector=col_bhabha_val,
484 input_files=input_files_bhabha_crystal,
485 pre_collector_path=rec_path_bhabha_val)
486
487
489
490 # Give the collector name to the algorithm since one algorithm
491 # is used to analyse the results from several possible collectors
492 eclValTAlgBhabha = Belle2.ECL.eclTValidationAlgorithm("eclBhabhaTimeCalibrationValidationCollector")
493
494 # Define the CAF algorithm arguments
495 eclValTAlgBhabha.meanCleanRebinFactor = 3
496 eclValTAlgBhabha.meanCleanCutMinFactor = 0.4
497 eclValTAlgBhabha.clusterTimesFractionWindow_maxtime = 1.5
498 eclValTAlgBhabha.debugFilenameBase = "eclBhabhaTValidationAlgorithm"
499
500
502
503 from caf.framework import Calibration
504
505 valid_cal_bhabha = Calibration("ECLcrystalTimeCalValidation_bhabhaPhysics")
506 valid_cal_bhabha.add_collection(name="bhabha", collection=eclValTCol)
507 valid_cal_bhabha.save_payloads = False
508 valid_cal_bhabha.backend_args = {"request_memory": "4 GB"}
509
510 # Make a second version of this algorithm that differs only in
511 # that it is instructed to read the previous crystal payload.
512 # The version where we don't read in the previous payload
513 # is left over from a previous code version
514 eclValTAlgBhabha_readPrevPayload = copy.deepcopy(eclValTAlgBhabha)
515 eclValTAlgBhabha_readPrevPayload.readPrevCrysPayload = True
516
517 valid_cal_bhabha.algorithms = [eclValTAlgBhabha_readPrevPayload]
518 print("bhabha validation: read previous payload for comparison purposes")
519 print("eclValTAlgBhabha_readPrevPayload.readPrevCrysPayload = ",
520 eclValTAlgBhabha_readPrevPayload.readPrevCrysPayload)
521
522 # If payload boundaries are set use SequentialBoundaries
523 # otherwise use SingleIOV
524 if payload_boundaries:
525 valid_cal_bhabha.strategies = SequentialBoundaries
526 else:
527 valid_cal_bhabha.strategies = SingleIOV
528
529 for algorithm in valid_cal_bhabha.algorithms:
530 # Set payload iov information for SequentialBoundaries
531 # and SingleIOV strategies.
532 if payload_boundaries:
533 algorithm.params = {"iov_coverage": output_iov,
534 "payload_boundaries": payload_boundaries}
535
536 print("Set iov for bhabha validation alg - SequentialBoundaries")
537 else:
538 algorithm.params = {"apply_iov": output_iov}
539 print("Set iov for bhabha validation alg - SingleIOV")
540
541
544 root_input = register_module('RootInput')
545 rec_path_hadron_val = create_path()
546 rec_path_hadron_val.add_module(root_input)
547 if 'Gearbox' not in rec_path_hadron_val:
548 rec_path_hadron_val.add_module('Gearbox')
549 if 'Geometry' not in rec_path_hadron_val:
550 rec_path_hadron_val.add_module('Geometry', useDB=True)
551
552 # exclude PXD and PID; not needed
553 prepare_user_cdst_analysis(rec_path_hadron_val, components=['SVD', 'CDC', 'ECL', 'KLM'])
554 col_hadron_val = register_module('eclHadronTimeCalibrationValidationCollector')
555 col_hadron_val.param('timeAbsMax', 70)
556 col_hadron_val.param('saveTree', False)
557
558 eclValTCol = Collection(collector=col_hadron_val,
559 input_files=input_files_hadron,
560 pre_collector_path=rec_path_hadron_val)
561
562
564
565 # Give the collector name to the algorithm since one algorithm
566 # is used to analyse the results from several possible collectors
567 eclValTAlgHadronic = Belle2.ECL.eclTValidationAlgorithm("eclHadronTimeCalibrationValidationCollector")
568
569 # Define the CAF algorithm arguments
570 eclValTAlgHadronic.meanCleanRebinFactor = 3
571 eclValTAlgHadronic.meanCleanCutMinFactor = 0.4
572 eclValTAlgHadronic.clusterTimesFractionWindow_maxtime = 8
573 eclValTAlgHadronic.debugFilenameBase = "eclHadronTValidationAlgorithm"
574
575
577
578 from caf.framework import Calibration
579
580 valid_cal_hadron = Calibration("ECLcrystalTimeCalValidation_hadronPhysics")
581 valid_cal_hadron.add_collection(name="hadron", collection=eclValTCol)
582 valid_cal_hadron.save_payloads = False
583 valid_cal_hadron.backend_args = {"request_memory": "4 GB"}
584
585 # Make a second version of this algorithm that differs only in
586 # that it is instructed to read the previous crystal payload
587 eclValTAlgHadron_readPrevPayload = copy.deepcopy(eclValTAlgHadronic)
588 eclValTAlgHadron_readPrevPayload.readPrevCrysPayload = True
589
590 # Make a second version of this algorithm that differs only in
591 # that it is instructed to read the previous crystal payload.
592 # The version where we don't read in the previous payload
593 # is left over from a previous code version
594 valid_cal_hadron.algorithms = [eclValTAlgHadron_readPrevPayload]
595 print("hadron validation: read previous payload for comparison purposes")
596 print("eclValTAlgHadron_readPrevPayload.readPrevCrysPayload = ",
597 eclValTAlgHadron_readPrevPayload.readPrevCrysPayload)
598
599 # If payload boundaries are set use SequentialBoundaries
600 # otherwise use SingleIOV
601 if payload_boundaries:
602 valid_cal_hadron.strategies = SequentialBoundaries
603 else:
604 valid_cal_hadron.strategies = SingleIOV
605
606 for algorithm in valid_cal_hadron.algorithms:
607 # Set payload iov information for SequentialBoundaries
608 # and SingleIOV strategies.
609 if payload_boundaries:
610 algorithm.params = {"iov_coverage": output_iov,
611 "payload_boundaries": payload_boundaries}
612
613 print("Set iov for hadron validation alg - SequentialBoundaries")
614 else:
615 algorithm.params = {"apply_iov": output_iov}
616 print("Set iov for hadron validation alg - SingleIOV")
617
618
621
622 # Set up the collector but with only one event per file
623 root_input = register_module('RootInput', entrySequences=[f'0:{1}'])
624
625 rec_path_bhabha_plotting = create_path()
626 rec_path_bhabha_plotting.add_module(root_input)
627 if 'Gearbox' not in rec_path_bhabha_plotting:
628 rec_path_bhabha_plotting.add_module('Gearbox')
629 if 'Geometry' not in rec_path_bhabha_plotting:
630 rec_path_bhabha_plotting.add_module('Geometry', useDB=True)
631
632 prepare_cdst_analysis(rec_path_bhabha_plotting, components=['SVD', 'CDC', 'ECL', 'KLM'])
633
634 col_bhabha_plotting = register_module('eclTimeShiftsPlottingCollector')
635 eclTCol = Collection(collector=col_bhabha_plotting,
636 input_files=input_files_plotting,
637 pre_collector_path=rec_path_bhabha_plotting)
638
639 # Set up the plotting. Use the two files with the collector to
640 # determine the run range to plot. The plotting is done in the
641 # algorithm
642
644 tShifts_alg.debugFilenameBase = "eclTimeShiftsAlgorithm"
645
646 # +-30ns range allows for unexpectedly large jumps
647 tShifts_alg.crysCrateShift_min = -30 # in ns
648 tShifts_alg.crysCrateShift_max = 30 # in ns
649
650 # Make the algorithm loop over the runs, not just the collector
651 # tShifts_alg.algorithmReadPayloads = True
652
653 cal_ecl_timeShifts = Calibration(name="ecl_t_shifts", algorithms=[tShifts_alg],
654 input_files=input_files_plotting)
655 cal_ecl_timeShifts.add_collection(name="bhabha", collection=eclTCol)
656
657 cal_ecl_timeShifts.save_payloads = False
658
659 # If payload boundaries are set use SequentialBoundaries
660 # otherwise use SingleIOV
661 if payload_boundaries:
662 cal_ecl_timeShifts.strategies = SequentialBoundaries
663 else:
664 cal_ecl_timeShifts.strategies = SingleIOV
665
666 for algorithm in cal_ecl_timeShifts.algorithms:
667 # Set payload iov information for SequentialBoundaries
668 # and SingleIOV strategies.
669 if payload_boundaries:
670 algorithm.params = {"iov_coverage": output_iov,
671 "payload_boundaries": payload_boundaries}
672
673 print("Set iov for crate time plotting alg - SequentialBoundaries")
674 else:
675 algorithm.params = {"apply_iov": output_iov}
676 print("Set iov for crate time plotting alg - SingleIOV")
677
678
683
684 # Make the crate and crytsal calibrations and the cerge crystal
685 # process occur in the order loaded into the array.
686 for i in range(len(calibs) - 1):
687 calibs[i + 1].depends_on(calibs[i])
688
689 # The validations and plotting can run independently of each other
690 # but rely on the last calibration step
691 valid_cal_bhabha.depends_on(calibs[len(calibs) - 1])
692 valid_cal_hadron.depends_on(calibs[len(calibs) - 1])
693 cal_ecl_timeShifts.depends_on(calibs[len(calibs) - 1])
694
695
697
698 calibs = np.append(calibs, [valid_cal_bhabha, valid_cal_hadron, cal_ecl_timeShifts])
699
700 print("##############")
701 print("List of calibrations:")
702 for c in calibs:
703 print(" ", c.name, " depends on ", c.dependencies, ", save payloads = ", c.save_payloads)
704 print("##############")
705
706 # You must return all calibrations you want to run in the prompt process, even if it's only one
707 # Calibrations will be executed in this order as a result of the dependencies defined by the "dependes_on(...)".
708 return calibs
709
710
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.