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