Belle II Software development
caf_ecl_E.py
1
8
9"""ECL single crystal energy calibration using three control samples."""
10
11from prompt import CalibrationSettings, INPUT_DATA_FILTERS
12
13# --------------------------------------------------------------
14# ..Tell the automated script some required details
15settings = CalibrationSettings(
16 name="ecl_energy",
17 expert_username="hearty",
18 subsystem="ecl",
19 description=__doc__,
20 input_data_formats=["cdst"],
21 input_data_names=[
22 "bhabha_all_calib",
23 "gamma_gamma_calib",
24 "mumu_tight_or_highm_calib"],
25 input_data_filters={
26 "bhabha_all_calib": [
27 INPUT_DATA_FILTERS["Data Tag"]["bhabha_all_calib"],
28 INPUT_DATA_FILTERS["Data Quality Tag"]["Good Or Recoverable"],
29 INPUT_DATA_FILTERS["Beam Energy"]["4S"],
30 INPUT_DATA_FILTERS["Run Type"]["physics"],
31 INPUT_DATA_FILTERS["Magnet"]["On"]],
32 "gamma_gamma_calib": [
33 INPUT_DATA_FILTERS["Data Tag"]["gamma_gamma_calib"],
34 INPUT_DATA_FILTERS["Data Quality Tag"]["Good Or Recoverable"],
35 INPUT_DATA_FILTERS["Beam Energy"]["4S"],
36 INPUT_DATA_FILTERS["Run Type"]["physics"],
37 INPUT_DATA_FILTERS["Magnet"]["On"]],
38 "mumu_tight_or_highm_calib": [
39 INPUT_DATA_FILTERS["Data Tag"]["mumu_tight_or_highm_calib"],
40 INPUT_DATA_FILTERS["Data Quality Tag"]["Good Or Recoverable"],
41 INPUT_DATA_FILTERS["Beam Energy"]["4S"],
42 INPUT_DATA_FILTERS["Run Type"]["physics"],
43 INPUT_DATA_FILTERS["Magnet"]["On"]]},
44 depends_on=[],
45 expert_config={"eCmsScale": 1.0, # Ecms/10.58, typically 0.9943 for offpeak
46 "ee5x5_min_entries": 100},
47 produced_payloads=["ECLCrystalEnergy", "ECLExpMuMuE", "ECLCrystalEnergyMuMu", "ECLExpGammaGammaE",
48 "ECLCrystalEnergyGammaGamma", "ECLExpee5x5E", "ECLCrystalEnergyee5x5", "ECLeedPhiData",
49 "ECLeedPhiMC"])
50
51# --------------------------------------------------------------
52# ..Raise clustering seed threshold in ECLCRFinder
53
54
55def touch_CRFinder(path, new_seed):
56 import basf2
57 """
58 Speed up ECL clustering by increasing seed threshold
59 """
60 new_path = basf2.create_path()
61 found = False
62 for m in path.modules():
63 if str(m) != "ECLCRFinder": # search module by name
64 new_path.add_module(m)
65 else:
66 crfinder = basf2.register_module('ECLCRFinder')
67 crfinder.param('energyCut0', new_seed)
68 basf2.print_params(crfinder)
69 new_path.add_module(crfinder)
70 found = True
71 if not found:
72 raise KeyError("Could not find ECLCRFinder in path")
73 return new_path
74
75# --------------------------------------------------------------
76# ..Raise threshold in ECLWaveformFit
77
78
79def touch_WaveformFit(path, energy_threshold):
80 import basf2
81 """
82 Speed up ECL reconstruction by increasing energy threshold
83 """
84 new_path = basf2.create_path()
85 found = False
86 for m in path.modules():
87 if str(m) != "ECLWaveformFit": # search module by name
88 new_path.add_module(m)
89 else:
90 waveformfit = basf2.register_module('ECLWaveformFit')
91 waveformfit.param('EnergyThreshold', energy_threshold)
92 basf2.print_params(waveformfit)
93 new_path.add_module(waveformfit)
94 found = True
95 if not found:
96 raise KeyError("Could not find ECLWaveformFit in path")
97 return new_path
98
99# --------------------------------------------------------------
100# ..The calibration functions
101
102
103def get_calibrations(input_data, **kwargs):
104 import basf2
105 from ROOT import Belle2
106 from caf.utils import IoV
107 from caf.framework import Calibration
108 from reconstruction import prepare_cdst_analysis
109
110 # --------------------------------------------------------------
111 # ..Bhabha
112
113 # ..Input data
114 file_to_iov_bhabha = input_data["bhabha_all_calib"]
115 input_files_bhabha = list(file_to_iov_bhabha.keys())
116
117 # ..Algorithm
118 algo_ee5x5 = Belle2.ECL.eclee5x5Algorithm()
119 expert_config = kwargs.get("expert_config")
120 ee5x5minEntries = expert_config["ee5x5_min_entries"]
121 algo_ee5x5.setMinEntries(ee5x5minEntries)
122 algo_ee5x5.setPayloadName("ECLCrystalEnergy5x5")
123 algo_ee5x5.setStoreConst(True)
124
125 # ..The calibration
126 eclee5x5_collector = basf2.register_module("eclee5x5Collector")
127 eclee5x5_collector.param("thetaLabMinDeg", 17.)
128 eclee5x5_collector.param("thetaLabMaxDeg", 150.)
129 eclee5x5_collector.param("minE0", 0.45)
130 eclee5x5_collector.param("minE1", 0.40)
131 eclee5x5_collector.param("maxdThetaSum", 2.)
132 eclee5x5_collector.param("dPhiScale", 1.)
133 eclee5x5_collector.param("maxTime", 10.)
134 eclee5x5_collector.param("useCalDigits", False)
135 eclee5x5_collector.param("requireL1", False)
136 eclee5x5_collector.param("granularity", "all")
137
138 # ..Adjust the expected energies for offpeak calibration
139 eCmsScale = expert_config["eCmsScale"]
140 eclee5x5_collector.param("expectedEnergyScale", eCmsScale)
141
142 cal_ecl_ee5x5 = Calibration("ecl_ee5x5",
143 collector=eclee5x5_collector,
144 algorithms=[algo_ee5x5],
145 input_files=input_files_bhabha
146 )
147 cal_ecl_ee5x5.backend_args = {"request_memory": "4 GB"}
148
149 # ..Add prepare_cdst_analysis to pre_collector_path
150 ee5x5_pre_path = basf2.create_path()
151 prepare_cdst_analysis(ee5x5_pre_path, components=['ECL'])
152 new_threshold = 1.0 # GeV
153 ee5x5_pre_path = touch_CRFinder(ee5x5_pre_path, new_threshold)
154 waveform_threshold = 99. # GeV
155 ee5x5_pre_path = touch_WaveformFit(ee5x5_pre_path, waveform_threshold)
156 cal_ecl_ee5x5.pre_collector_path = ee5x5_pre_path
157
158 # --------------------------------------------------------------
159 # ..gamma gamma
160
161 # ..Input data
162 file_to_iov_gamma_gamma = input_data["gamma_gamma_calib"]
163 input_files_gamma_gamma = list(file_to_iov_gamma_gamma.keys())
164
165 # ..Algorithm
166 algo_gamma_gamma = Belle2.ECL.eclGammaGammaEAlgorithm()
167 algo_gamma_gamma.setOutputName("eclGammaGammaE_algorithm.root")
168 algo_gamma_gamma.setCellIDLo(1)
169 algo_gamma_gamma.setCellIDHi(8736)
170 algo_gamma_gamma.setMinEntries(150)
171 algo_gamma_gamma.setMaxIterations(10)
172 algo_gamma_gamma.setTRatioMin(0.45)
173 algo_gamma_gamma.setTRatioMax(0.70)
174 algo_gamma_gamma.setTRatioMinHiStat(0.70)
175 algo_gamma_gamma.setTRatioMaxHiStat(0.95)
176 algo_gamma_gamma.setUpperEdgeThresh(0.02)
177 algo_gamma_gamma.setPerformFits(True)
178 algo_gamma_gamma.setFindExpValues(False)
179 algo_gamma_gamma.setStoreConst(0)
180
181 # ..The calibration
182 eclGammaGamma_collector = basf2.register_module("eclGammaGammaECollector")
183 eclGammaGamma_collector.param("granularity", "all")
184 eclGammaGamma_collector.param("thetaLabMinDeg", 0.)
185 eclGammaGamma_collector.param("thetaLabMaxDeg", 180.)
186 eclGammaGamma_collector.param("minPairMass", 9.)
187 eclGammaGamma_collector.param("mindPhi", 179.)
188 eclGammaGamma_collector.param("maxTime", 999.)
189 eclGammaGamma_collector.param("measureTrueEnergy", False)
190 eclGammaGamma_collector.param("requireL1", False)
191
192 # ..Adjust the expected energies for offpeak calibration
193 eclGammaGamma_collector.param("expectedEnergyScale", eCmsScale)
194
195 cal_ecl_gamma_gamma = Calibration("ecl_gamma_gamma",
196 collector=eclGammaGamma_collector,
197 algorithms=[algo_gamma_gamma],
198 input_files=input_files_gamma_gamma
199 )
200
201 # ..Add prepare_cdst_analysis to pre_collector_path
202 gamma_gamma_pre_path = basf2.create_path()
203 prepare_cdst_analysis(gamma_gamma_pre_path, components=['ECL'])
204 new_threshold = 1.0 # GeV
205 gamma_gamma_pre_path = touch_CRFinder(gamma_gamma_pre_path, new_threshold)
206 waveform_threshold = 99. # GeV
207 gamma_gamma_pre_path = touch_WaveformFit(gamma_gamma_pre_path, waveform_threshold)
208 cal_ecl_gamma_gamma.pre_collector_path = gamma_gamma_pre_path
209
210 # --------------------------------------------------------------
211 # ..muon pair
212
213 # ..Input data
214 file_to_iov_mu_mu = input_data["mumu_tight_or_highm_calib"]
215 input_files_mu_mu = list(file_to_iov_mu_mu.keys())
216
217 # ..Algorithm
218 algo_mu_mu = Belle2.ECL.eclMuMuEAlgorithm()
219 algo_mu_mu.cellIDLo = 1
220 algo_mu_mu.cellIDHi = 8736
221 algo_mu_mu.minEntries = 150
222 algo_mu_mu.nToRebin = 1000
223 algo_mu_mu.tRatioMin = 0.05
224 algo_mu_mu.tRatioMax = 0.40
225 algo_mu_mu.lowerEdgeThresh = 0.10
226 algo_mu_mu.performFits = True
227 algo_mu_mu.findExpValues = False
228 algo_mu_mu.storeConst = 0
229
230 # ..The calibration
231 eclmumu_collector = basf2.register_module("eclMuMuECollector")
232 eclmumu_collector.param("granularity", "all")
233 eclmumu_collector.param("minPairMass", 9.0)
234 eclmumu_collector.param("minTrackLength", 30.)
235 eclmumu_collector.param("MaxNeighbourE", 0.010)
236 eclmumu_collector.param("thetaLabMinDeg", 17.)
237 eclmumu_collector.param("thetaLabMaxDeg", 150.)
238 eclmumu_collector.param("measureTrueEnergy", False)
239 eclmumu_collector.param("requireL1", False)
240 cal_ecl_mu_mu = Calibration(name="ecl_mu_mu", collector=eclmumu_collector, algorithms=algo_mu_mu, input_files=input_files_mu_mu)
241
242 # ..Need to include track extrapolation in the path before collector
243 ext_path = basf2.create_path()
244 prepare_cdst_analysis(ext_path, components=['ECL'])
245 ext_path.add_module("Ext", pdgCodes=[13])
246 new_threshold = 0.1 # GeV
247 ext_path = touch_CRFinder(ext_path, new_threshold)
248 waveform_threshold = 99. # GeV
249 ext_path = touch_WaveformFit(ext_path, waveform_threshold)
250 cal_ecl_mu_mu.pre_collector_path = ext_path
251
252 # --------------------------------------------------------------
253 # Include a merging Calibration that doesn't require input data but instead creates the final
254 # payload from the previous calibration payloads.
255
256 # We use a dummy collector that barely outputs any data and we set the input files to a single file so
257 # we spawn only one very fast job.
258 # It doesn't matter which input file we choose as the output is never used.
259
261 cal_ecl_merge = Calibration(name="ecl_merge", collector="DummyCollector", algorithms=[merging_alg],
262 input_files=input_files_mu_mu[:1])
263
264 # The important part is that we depend on all 3 previous calibrations
265 cal_ecl_merge.depends_on(cal_ecl_ee5x5)
266 cal_ecl_merge.depends_on(cal_ecl_gamma_gamma)
267 cal_ecl_merge.depends_on(cal_ecl_mu_mu)
268
269 # ..Uses cdst data so it requires prepare_cdst_analysis
270 ecl_merge_pre_path = basf2.create_path()
271 prepare_cdst_analysis(ecl_merge_pre_path, components=['ECL'])
272 new_threshold = 0.15 # GeV
273 ecl_merge_pre_path = touch_CRFinder(ecl_merge_pre_path, new_threshold)
274 waveform_threshold = 99. # GeV
275 ecl_merge_pre_path = touch_WaveformFit(ecl_merge_pre_path, waveform_threshold)
276 ecl_merge_pre_path.pre_collector_path = ecl_merge_pre_path
277
278 # --------------------------------------------------------------
279 # ..Force the output iovs to be open
280 requested_iov = kwargs.get("requested_iov", None)
281 output_iov = IoV(requested_iov.exp_low, requested_iov.run_low, -1, -1)
282 for algorithm in cal_ecl_ee5x5.algorithms:
283 algorithm.params = {"apply_iov": output_iov}
284 for algorithm in cal_ecl_gamma_gamma.algorithms:
285 algorithm.params = {"apply_iov": output_iov}
286 for algorithm in cal_ecl_mu_mu.algorithms:
287 algorithm.params = {"apply_iov": output_iov}
288 for algorithm in cal_ecl_merge.algorithms:
289 algorithm.params = {"apply_iov": output_iov}
290
291 # --------------------------------------------------------------
292 # ..Return the calibrations
293 return [cal_ecl_ee5x5, cal_ecl_gamma_gamma, cal_ecl_mu_mu, cal_ecl_merge]
Calibrate ecl crystals using gamma pair events.
Calibrate ecl crystals using previously created payloads.
Calibrate ecl crystals using muon pair events.
Calibrate ecl crystals using Bhabha events.