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