Belle II Software  release-05-01-25
caf_cdc.py
1 # -*- coding: utf-8 -*-
2 
3 """CDC tracking calibration. Performs the T0 determination using HLT skimmed raw data."""
4 
5 from prompt import CalibrationSettings
6 from prompt.utils import events_in_basf2_file, ExpRun
7 import basf2
8 from random import choice
9 from caf.framework import Calibration
10 from caf import strategies
11 
12 
13 
14 settings = CalibrationSettings(name="CDC Tracking",
15  expert_username="eberthol",
16  description=__doc__,
17  input_data_formats=["raw"],
18  input_data_names=["hlt_mumu", "hlt_hadron", "Bcosmics"],
19  depends_on=[],
20  expert_config={
21  "max_files_per_run": 100000,
22  "min_events_per_file": 1,
23  "max_events_per_calibration": 200000,
24  "max_events_per_calibration_for_xt_sr": 1000000,
25  "max_events_per_file": 5000,
26  "max_events_per_file_hadron": 2500,
27  "payload_boundaries": [],
28  "request_memory": 4
29  })
30 
31 
32 def select_files(all_input_files, min_events, max_processed_events_per_file):
33  basf2.B2INFO("Attempting to choose a good subset of files")
34  # Let's iterate, taking a sample of files from the total (no repeats or replacement) until we get enough events
35  total_events = 0
36  chosen_files = []
37  while total_events < min_events:
38  # If the set is empty we must have used all available files. Here we break and continue. But you may want to
39  # raise an Error...
40  if not all_input_files:
41  break
42  # Randomly select a file
43  new_file_choice = choice(all_input_files)
44  # Remove it from the list so it can't be chosen again
45  all_input_files.remove(new_file_choice)
46  # Find the number of events in the file
47  total_events_in_file = events_in_basf2_file(new_file_choice)
48  if not total_events_in_file:
49  # Uh Oh! Zero event file, skip it
50  continue
51  events_contributed = 0
52  if total_events_in_file < max_processed_events_per_file:
53  # The file contains less than the max amount we have set (entrySequences)
54  events_contributed = total_events_in_file
55  else:
56  events_contributed = max_processed_events_per_file
57  chosen_files.append(new_file_choice)
58  total_events += events_contributed
59 
60  basf2.B2INFO(f"Total chosen files = {len(chosen_files)}")
61  basf2.B2INFO(f"Total events in chosen files = {total_events}")
62  if total_events < min_events:
63  raise ValueError(
64  f"There weren't enough files events selected when max_processed_events_per_file={max_processed_events_per_file}")
65  return chosen_files
66 
67 
68 
71 
72 
73 def get_calibrations(input_data, **kwargs):
74  import basf2
75  from prompt.utils import filter_by_max_files_per_run
76  # Gets the input files and IoV objects associated with the files.
77  file_to_iov_mumu = input_data["hlt_mumu"]
78  file_to_iov_hadron = input_data["hlt_hadron"]
79  file_to_iov_Bcosmics = input_data["Bcosmics"]
80 
81  # read expert_config values
82  expert_config = kwargs.get("expert_config")
83  max_files_per_run = expert_config["max_files_per_run"]
84  min_events_per_file = expert_config["min_events_per_file"]
85  max_events_per_calibration = expert_config["max_events_per_calibration"] # for t0, tw calib.
86  max_events_per_calibration_for_xt_sr = expert_config["max_events_per_calibration_for_xt_sr"] # for xt, sr calib.
87  max_events_per_file = expert_config["max_events_per_file"]
88  max_events_per_file_hadron = expert_config["max_events_per_file_hadron"]
89  payload_boundaries = []
90  payload_boundaries.extend([ExpRun(*boundary) for boundary in expert_config["payload_boundaries"]])
91  basf2.B2INFO(f"Payload boundaries from expert_config: {payload_boundaries}")
92 
93  reduced_file_to_iov_mumu = filter_by_max_files_per_run(file_to_iov_mumu, max_files_per_run, min_events_per_file)
94  input_files_mumu = list(reduced_file_to_iov_mumu.keys())
95  basf2.B2INFO(f"Total number of hlt_mumu files actually used as input = {len(input_files_mumu)}")
96  chosen_files_mumu = select_files(input_files_mumu[:], max_events_per_calibration, max_events_per_file)
97  chosen_files_mumu_for_xt_sr = select_files(input_files_mumu[:], max_events_per_calibration_for_xt_sr, max_events_per_file)
98 
99  reduced_file_to_iov_hadron = filter_by_max_files_per_run(file_to_iov_hadron, max_files_per_run, min_events_per_file)
100  input_files_hadron = list(reduced_file_to_iov_hadron.keys())
101  basf2.B2INFO(f"Total number of hlt_hadron files actually used as input = {len(input_files_hadron)}")
102  chosen_files_hadron = select_files(input_files_hadron[:], max_events_per_calibration, max_events_per_file_hadron)
103  chosen_files_hadron_for_xt_sr = select_files(input_files_hadron[:],
104  max_events_per_calibration_for_xt_sr, max_events_per_file_hadron)
105 
106  reduced_file_to_iov_Bcosmics = filter_by_max_files_per_run(file_to_iov_Bcosmics, max_files_per_run, min_events_per_file)
107  input_files_Bcosmics = list(reduced_file_to_iov_Bcosmics.keys())
108  basf2.B2INFO(f"Total number of Bcosmics files actually used as input = {len(input_files_Bcosmics)}")
109  chosen_files_Bcosmics = select_files(input_files_Bcosmics[:], max_events_per_calibration, max_events_per_file)
110  chosen_files_Bcosmics_for_xt_sr = select_files(
111  input_files_Bcosmics[:],
112  max_events_per_calibration_for_xt_sr,
113  max_events_per_file)
114 
115  input_file_dict = {
116  "hlt_mumu": chosen_files_mumu_for_xt_sr,
117  "hlt_hadron": chosen_files_hadron_for_xt_sr,
118  "Bcosmics": chosen_files_Bcosmics_for_xt_sr
119  }
120 
121  chosen_file_dict = {
122  "hlt_mumu": chosen_files_mumu,
123  "hlt_hadron": chosen_files_hadron,
124  "Bcosmics": chosen_files_Bcosmics
125  }
126 
127  # Get the overall IoV we want to cover, including the end values
128  requested_iov = kwargs.get("requested_iov", None)
129 
130  from caf.utils import IoV
131  # The actual IoV we want for any prompt request is open-ended
132  output_iov = IoV(requested_iov.exp_low, requested_iov.run_low, -1, -1)
133 
134  # for SingleIOV stratrgy, it's better to set the granularity to 'all' so that the collector jobs will run faster
135  collector_granularity = 'all'
136  if payload_boundaries:
137  basf2.B2INFO('Found payload_boundaries: set collector granularity to run')
138  collector_granularity = 'run'
139 
140  # t0
141  cal0 = CDCCalibration(name='tz0',
142  algorithms=[tz_algo()],
143  input_file_dict=chosen_file_dict,
144  max_iterations=4,
145  max_events=max_events_per_file,
146  collector_granularity=collector_granularity
147  )
148 
149  # tw
150  cal1 = CDCCalibration(name='tw0',
151  algorithms=[tw_algo()],
152  input_file_dict=chosen_file_dict,
153  max_iterations=2,
154  max_events=max_events_per_file,
155  collector_granularity=collector_granularity,
156  dependencies=[cal0]
157  )
158 
159  cal2 = CDCCalibration(name='tz1',
160  algorithms=[tz_algo()],
161  input_file_dict=chosen_file_dict,
162  max_iterations=4,
163  max_events=max_events_per_file,
164  collector_granularity=collector_granularity,
165  dependencies=[cal1]
166  )
167 
168  # xt
169  cal3 = CDCCalibration(name='xt0',
170  algorithms=[xt_algo()],
171  input_file_dict=input_file_dict,
172  max_iterations=1,
173  collector_granularity=collector_granularity,
174  dependencies=[cal2]
175  )
176 
177  # space resolution
178  cal4 = CDCCalibration(name='sr0',
179  algorithms=[sr_algo()],
180  input_file_dict=input_file_dict,
181  max_iterations=1,
182  collector_granularity=collector_granularity,
183  dependencies=[cal3]
184  )
185  # t0
186  cal5 = CDCCalibration(name='tz2',
187  algorithms=[tz_algo()],
188  input_file_dict=chosen_file_dict,
189  max_iterations=4,
190  max_events=max_events_per_file,
191  collector_granularity=collector_granularity,
192  dependencies=[cal4]
193  )
194 
195  if payload_boundaries:
196  basf2.B2INFO(f"Found payload_boundaries: calibration strategies set to SequentialBoundaries.")
197  cal0.strategies = strategies.SequentialBoundaries
198  for algorithm in cal0.algorithms:
199  algorithm.params = {"iov_coverage": output_iov, "payload_boundaries": payload_boundaries}
200  for algorithm in cal1.algorithms:
201  algorithm.params = {"iov_coverage": output_iov, "payload_boundaries": payload_boundaries}
202  for algorithm in cal2.algorithms:
203  algorithm.params = {"iov_coverage": output_iov, "payload_boundaries": payload_boundaries}
204  for algorithm in cal3.algorithms:
205  algorithm.params = {"iov_coverage": output_iov, "payload_boundaries": payload_boundaries}
206  for algorithm in cal4.algorithms:
207  algorithm.params = {"iov_coverage": output_iov, "payload_boundaries": payload_boundaries}
208  for algorithm in cal5.algorithms:
209  algorithm.params = {"iov_coverage": output_iov, "payload_boundaries": payload_boundaries}
210  else:
211  # Force the output payload IoV to be correct.
212  # It may be different if you are using another strategy like SequentialRunByRun
213  for algorithm in cal0.algorithms:
214  algorithm.params = {"apply_iov": output_iov}
215  for algorithm in cal1.algorithms:
216  algorithm.params = {"apply_iov": output_iov}
217  for algorithm in cal2.algorithms:
218  algorithm.params = {"apply_iov": output_iov}
219  for algorithm in cal3.algorithms:
220  algorithm.params = {"apply_iov": output_iov}
221  for algorithm in cal4.algorithms:
222  algorithm.params = {"apply_iov": output_iov}
223  for algorithm in cal5.algorithms:
224  algorithm.params = {"apply_iov": output_iov}
225 
226  return [cal0, cal1, cal2, cal3, cal4, cal5]
227 
228 
229 
230 
231 def pre_collector(max_events=None):
232  """
233  Define pre collection (reconstruction in our purpose).
234  Probably, we need only CDC and ECL data.
235  Parameters:
236  max_events [int] : number of events to be processed.
237  All events by Default.
238  Returns:
239  path : path for pre collection
240  """
241  from basf2 import create_path, register_module
242  from softwaretrigger.constants import HLT_INPUT_OBJECTS
243  reco_path = create_path()
244  if max_events is None:
245  root_input = register_module(
246  'RootInput',
247  branchNames=HLT_INPUT_OBJECTS
248  )
249  else:
250  root_input = register_module(
251  'RootInput',
252  branchNames=HLT_INPUT_OBJECTS,
253  entrySequences=[
254  '0:{}'.format(max_events)])
255  reco_path.add_module(root_input)
256 
257  gearbox = register_module('Gearbox')
258  reco_path.add_module(gearbox)
259  reco_path.add_module('Geometry', useDB=True)
260 
261  from rawdata import add_unpackers
262  # unpack raw data
263  add_unpackers(reco_path)
264 
265  from reconstruction import add_reconstruction
266  add_reconstruction(reco_path,
267  add_trigger_calculation=False,
268  trackFitHypotheses=[211, 13],
269  pruneTracks=False)
270 
271  return reco_path
272 
273 
274 def pre_collector_cr(max_events=None):
275  """
276  Define pre collection (reconstruction in our purpose).
277  Probably, we need only CDC and ECL data.
278  Parameters:
279  max_events [int] : number of events to be processed.
280  All events by Default.
281  Returns:
282  path : path for pre collection
283  """
284  from basf2 import create_path, register_module
285  from softwaretrigger.constants import HLT_INPUT_OBJECTS
286  reco_path = create_path()
287  if max_events is None:
288  root_input = register_module(
289  'RootInput',
290  branchNames=HLT_INPUT_OBJECTS
291  )
292  else:
293  root_input = register_module(
294  'RootInput',
295  branchNames=HLT_INPUT_OBJECTS,
296  entrySequences=[
297  '0:{}'.format(max_events)])
298  reco_path.add_module(root_input)
299 
300  gearbox = register_module('Gearbox')
301  reco_path.add_module(gearbox)
302  reco_path.add_module('Geometry', useDB=True)
303 
304  from rawdata import add_unpackers
305  # unpack raw data
306  add_unpackers(reco_path)
307 
308  from reconstruction import add_cosmics_reconstruction
309  add_cosmics_reconstruction(reco_path,
310  components=['CDC', 'ECL'],
311  merge_tracks=False,
312  pruneTracks=False,
313  data_taking_period='normal'
314  )
315  return reco_path
316 
317 
318 def collector(bField=True, is_cosmic=False, granularity='all'):
319  """
320  Create a cdc calibration collector
321  Parameters:
322  bField [bool] : True if B field is on, else False
323  isCosmic [bool] : True if cosmic events,
324  else (collision) False.
325  Returns:
326  collector : collector module
327  """
328  from basf2 import register_module
329  col = register_module('CDCCalibrationCollector',
330  granularity=granularity,
331  calExpectedDriftTime=True,
332  eventT0Extraction=True,
333  bField=bField,
334  isCosmic=is_cosmic
335  )
336  return col
337 
338 
339 def tz_algo():
340  """
341  Create a T0 calibration algorithm.
342  Returns:
343  algo : T0 algorithm
344  """
345  from ROOT import Belle2
347  algo.storeHisto(True)
348  algo.setMaxMeanDt(0.5)
349  algo.setMaxRMSDt(0.1)
350  algo.setMinimumNDF(20)
351  return algo
352 
353 
354 def tw_algo():
355  """
356  Create a time walk calibration algorithm.
357  Returns:
358  algo : TW algorithm
359  """
360  from ROOT import Belle2
362  algo.setStoreHisto(True)
363  algo.setMode(1)
364  return algo
365 
366 
367 def xt_algo():
368  """
369  Create a XT calibration algorithm.
370  Parameters:
371  prefix : prefixed name for algorithm,
372  which should be consistent with one of collector..
373  Returns:
374  algo : XT algorithm
375  """
376  from ROOT import Belle2
378  algo.setStoreHisto(True)
379  algo.setLRSeparate(True)
380  algo.setThreshold(0.55)
381  return algo
382 
383 
384 def sr_algo():
385  """
386  Create a Spacial resolution calibration algorithm.
387  Parameters:
388  prefix : prefixed name for algorithm,
389  which should be consistent with one of collector..
390  Returns:
391  algo : Spacial algorithm
392  """
393  from ROOT import Belle2
395  algo.setStoreHisto(True)
396  algo.setThreshold(0.4)
397  return algo
398 
399 
401  '''
402  CDCCalibration is a specialized calibration class for cdc.
403  Since collector is same in all elements, no need to specify it.
404  '''
405 
406  def __init__(self,
407  name,
408  algorithms,
409  input_file_dict,
410  max_iterations=5,
411  dependencies=None,
412  max_events=5000,
413  collector_granularity='All'):
414  for algo in algorithms:
415  algo.setHistFileName(name)
416 
417  super().__init__(name=name,
418  algorithms=algorithms
419  )
420 
421  from caf.framework import Collection
422 
423  for skim_type, file_list in input_file_dict.items():
424  if skim_type is "Bcosmics":
425  collection = Collection(collector=collector(granularity=collector_granularity),
426  input_files=file_list,
427  pre_collector_path=pre_collector_cr(max_events=max_events),
428  )
429  else:
430  collection = Collection(collector=collector(granularity=collector_granularity),
431  input_files=file_list,
432  pre_collector_path=pre_collector(max_events=max_events),
433  )
434  self.add_collection(name=skim_type, collection=collection)
435 
436  self.max_iterations = max_iterations
437 
438  if dependencies is not None:
439  for dep in dependencies:
440  self.depends_on(dep)
prompt.utils
Definition: utils.py:1
Belle2::CDC::XTCalibrationAlgorithm
Class to perform xt calibration for drift chamber.
Definition: XTCalibrationAlgorithm.h:61
caf_cdc.CDCCalibration.max_iterations
max_iterations
Definition: caf_cdc.py:429
Belle2::CDC::T0CalibrationAlgorithm
Class for T0 Correction .
Definition: T0CalibrationAlgorithm.h:34
softwaretrigger.constants
Definition: constants.py:1
Belle2::CDC::TimeWalkCalibrationAlgorithm
Class for Time walk calibration.
Definition: TimeWalkCalibrationAlgorithm.h:37
strategies.SequentialBoundaries
Definition: strategies.py:648
caf_cdc.CDCCalibration
Definition: caf_cdc.py:400
collector
Definition: collector.py:1
Collection
Definition: Collection.py:1
Calibration
Definition: Calibration.py:1
Belle2::CDC::SpaceResolutionCalibrationAlgorithm
Class for Space resolution calibration.
Definition: SpaceResolutionCalibrationAlgorithm.h:38