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."""
13from prompt
import CalibrationSettings, INPUT_DATA_FILTERS
14from reconstruction
import prepare_cdst_analysis, prepare_user_cdst_analysis
15from caf.utils
import IoV, ExpRun
30settings = CalibrationSettings(
31 name=
"ECL crystal and crate time calibrations and validations",
32 expert_username=
"hearty",
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"]]},
52 expert_config={
"numCrysCrateIterations": 1,
53 "maxNumberEvents": 50000000,
54 "payload_boundaries": [],
55 "t0_bhabhaToHadron_correction": 0},
56 produced_payloads=[
"ECLCrateTimeOffset",
"ECLCrystalTimeOffset"])
70def get_calibrations(input_data, **kwargs):
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
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.
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)
85 list(caf.framework.Calibration): All of the calibration objects we want to assign to the CAF process
92 expert_config = kwargs.get(
"expert_config")
96 numCrysCrateIterations = expert_config[
"numCrysCrateIterations"]
97 print(
"expert_config: numCrysCrateIterations = ", numCrysCrateIterations)
104 maxNumEventsCrystalCalib = expert_config[
"maxNumberEvents"]
105 print(
"expert_config: maxNumEventsCrystalCalib = ", maxNumEventsCrystalCalib)
109 t0_bhabhaToHadron_correction = expert_config[
"t0_bhabhaToHadron_correction"]
110 print(
"expert_config: t0_bhabhaToHadron_correction = ", t0_bhabhaToHadron_correction)
112 from caf.strategies
import SimpleRunByRun, SingleIOV, SequentialBoundaries
119 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)
128 file_to_iov_bhabha = input_data[
"bhabha_all_calib"]
129 file_to_iov_hadron = input_data[
"hadron_calib"]
136 max_files_per_run_calibration = 26
137 max_files_per_run_validation = 4
138 max_events_per_run_plotting = 1
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
147 print(
"max_events_per_crystalCalib = ", max_events_per_crystalCalib)
160 from prompt.utils import filter_by_select_max_events_from_files
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)}")
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)}")
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)}")
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)}")
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.")
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.")
189 print(
"User requested max number of events filter to not be used so all bhabha input files being used for crystals")
191 basf2.B2INFO(f
"Total number of bhabha files being used for crystal calibration = {len(input_files_bhabha_crystal)}")
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)}")
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())
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)
209 from basf2
import register_module, create_path
210 from ROOT
import Belle2
211 from caf.framework
import Collection
215 print(
"Set up the base for the collectors for the calibrations")
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)
225 prepare_cdst_analysis(rec_path_bhabha, components=[
'SVD',
'CDC',
'ECL',
'KLM'])
228 t0BiasCorrection = t0_bhabhaToHadron_correction
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)
240 input_files=input_files_bhabha,
241 pre_collector_path=rec_path_bhabha)
243 eclTCol_crys =
Collection(collector=col_bhabha,
244 input_files=input_files_bhabha_crystal,
245 pre_collector_path=rec_path_bhabha)
249 print(
"Set up the base for the crate calibration algorithm")
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"
265 print(
"Set up the base for the crystal calibration algorithm")
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"
283 eclTAlgCrystals_saveNotReadPrevPayload = copy.deepcopy(eclTAlgCrystals)
284 eclTAlgCrystals_readNotSavePrevPayload = copy.deepcopy(eclTAlgCrystals)
286 eclTAlgCrystals_saveNotReadPrevPayload.savePrevCrysPayload =
True
287 eclTAlgCrystals_saveNotReadPrevPayload.readPrevCrysPayload =
False
289 eclTAlgCrystals_readNotSavePrevPayload.savePrevCrysPayload =
False
290 eclTAlgCrystals_readNotSavePrevPayload.readPrevCrysPayload =
True
294 print(
"Set up the base for the crystal merger algorithm")
297 merging_alg.readPrevCrysPayload =
True
306 if numCrysCrateIterations <= 0:
307 print(
"numCrysCrateIterations NEEDS TO BE > 0 !!!")
308 elif numCrysCrateIterations > 0:
312 from caf.framework
import Calibration
313 print(
"Performing ", numCrysCrateIterations,
" iterations of crate and crystal calibrations.")
315 crysCalibBaseName =
"ECLcrystalTimeCalibration_physics_"
316 crateCalibBaseName =
"ECLcrateTimeCalibration_physics_"
317 mergeCalibBaseName =
"ecl_t_merge_"
325 for i
in range(numCrysCrateIterations):
326 crysCalibName = crysCalibBaseName + str(i)
327 crateCalibName = crateCalibBaseName + str(i)
328 mergeCalibName = mergeCalibBaseName + str(i)
330 print(
"iteration = ", i)
331 print(
"crysCalibName = ", crysCalibName)
332 print(
"crateCalibName = ", crateCalibName)
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"}
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"}
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)
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)
368 cal_crystals_i.save_payloads =
False
372 if payload_boundaries:
373 cal_crystals_i.strategies = SequentialBoundaries
375 cal_crystals_i.strategies = SingleIOV
380 cal_ecl_merge_i = Calibration(name=mergeCalibName, collector=
"DummyCollector",
381 input_files=input_files_bhabha_1perRun)
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)
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
395 if payload_boundaries:
396 cal_ecl_merge_i.strategies = SequentialBoundaries
398 cal_ecl_merge_i.strategies = SingleIOV
401 for algorithm
in cal_crystals_i.algorithms:
404 if i == numCrysCrateIterations - 1:
407 if payload_boundaries:
408 algorithm.params = {
"iov_coverage": output_iov,
409 "payload_boundaries": payload_boundaries}
411 print(
"Set iov for final crystals alg - SequentialBoundaries")
413 algorithm.params = {
"apply_iov": output_iov}
414 print(
"Set iov for final crystals alg - SingleIOV ")
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")
423 algorithm.params = {
"apply_iov": intermediate_iov}
424 print(
"Set iov for intermediate crystals alg - SingleIOV ")
427 for algorithm
in cal_ecl_merge_i.algorithms:
430 if i == numCrysCrateIterations - 1:
433 if payload_boundaries:
434 algorithm.params = {
"iov_coverage": output_iov,
435 "payload_boundaries": payload_boundaries}
437 print(
"Set iov for final merging alg - SequentialBoundaries")
439 algorithm.params = {
"apply_iov": output_iov}
440 print(
"Set iov for final merging alg - SingleIOV ")
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")
449 algorithm.params = {
"apply_iov": intermediate_iov}
450 print(
"Set iov for intermediate merging alg - SingleIOV ")
453 calibs = np.append(calibs, [cal_crates_i, cal_crystals_i, cal_ecl_merge_i])
456 calibs[len(calibs) - 3].save_payloads =
True
457 calibs[len(calibs) - 1].save_payloads =
True
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)
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)
483 eclValTCol =
Collection(collector=col_bhabha_val,
484 input_files=input_files_bhabha_crystal,
485 pre_collector_path=rec_path_bhabha_val)
495 eclValTAlgBhabha.meanCleanRebinFactor = 3
496 eclValTAlgBhabha.meanCleanCutMinFactor = 0.4
497 eclValTAlgBhabha.clusterTimesFractionWindow_maxtime = 1.5
498 eclValTAlgBhabha.debugFilenameBase =
"eclBhabhaTValidationAlgorithm"
503 from caf.framework
import Calibration
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"}
514 eclValTAlgBhabha_readPrevPayload = copy.deepcopy(eclValTAlgBhabha)
515 eclValTAlgBhabha_readPrevPayload.readPrevCrysPayload =
True
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)
524 if payload_boundaries:
525 valid_cal_bhabha.strategies = SequentialBoundaries
527 valid_cal_bhabha.strategies = SingleIOV
529 for algorithm
in valid_cal_bhabha.algorithms:
532 if payload_boundaries:
533 algorithm.params = {
"iov_coverage": output_iov,
534 "payload_boundaries": payload_boundaries}
536 print(
"Set iov for bhabha validation alg - SequentialBoundaries")
538 algorithm.params = {
"apply_iov": output_iov}
539 print(
"Set iov for bhabha validation alg - SingleIOV")
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)
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)
558 eclValTCol =
Collection(collector=col_hadron_val,
559 input_files=input_files_hadron,
560 pre_collector_path=rec_path_hadron_val)
570 eclValTAlgHadronic.meanCleanRebinFactor = 3
571 eclValTAlgHadronic.meanCleanCutMinFactor = 0.4
572 eclValTAlgHadronic.clusterTimesFractionWindow_maxtime = 8
573 eclValTAlgHadronic.debugFilenameBase =
"eclHadronTValidationAlgorithm"
578 from caf.framework
import Calibration
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"}
587 eclValTAlgHadron_readPrevPayload = copy.deepcopy(eclValTAlgHadronic)
588 eclValTAlgHadron_readPrevPayload.readPrevCrysPayload =
True
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)
601 if payload_boundaries:
602 valid_cal_hadron.strategies = SequentialBoundaries
604 valid_cal_hadron.strategies = SingleIOV
606 for algorithm
in valid_cal_hadron.algorithms:
609 if payload_boundaries:
610 algorithm.params = {
"iov_coverage": output_iov,
611 "payload_boundaries": payload_boundaries}
613 print(
"Set iov for hadron validation alg - SequentialBoundaries")
615 algorithm.params = {
"apply_iov": output_iov}
616 print(
"Set iov for hadron validation alg - SingleIOV")
623 root_input = register_module(
'RootInput', entrySequences=[f
'0:{1}'])
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)
632 prepare_cdst_analysis(rec_path_bhabha_plotting, components=[
'SVD',
'CDC',
'ECL',
'KLM'])
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)
644 tShifts_alg.debugFilenameBase =
"eclTimeShiftsAlgorithm"
647 tShifts_alg.crysCrateShift_min = -30
648 tShifts_alg.crysCrateShift_max = 30
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)
657 cal_ecl_timeShifts.save_payloads =
False
661 if payload_boundaries:
662 cal_ecl_timeShifts.strategies = SequentialBoundaries
664 cal_ecl_timeShifts.strategies = SingleIOV
666 for algorithm
in cal_ecl_timeShifts.algorithms:
669 if payload_boundaries:
670 algorithm.params = {
"iov_coverage": output_iov,
671 "payload_boundaries": payload_boundaries}
673 print(
"Set iov for crate time plotting alg - SequentialBoundaries")
675 algorithm.params = {
"apply_iov": output_iov}
676 print(
"Set iov for crate time plotting alg - SingleIOV")
686 for i
in range(len(calibs) - 1):
687 calibs[i + 1].depends_on(calibs[i])
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])
698 calibs = np.append(calibs, [valid_cal_bhabha, valid_cal_hadron, cal_ecl_timeShifts])
700 print(
"##############")
701 print(
"List of calibrations:")
703 print(
" ", c.name,
" depends on ", c.dependencies,
", save payloads = ", c.save_payloads)
704 print(
"##############")
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.