Belle II Software  release-05-01-25
caf_cdc_mp2.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
7 import basf2
8 from random import choice
9 
10 
11 
12 settings = CalibrationSettings(name="CDC T0 Calibration with MP2",
13  expert_username="uchida",
14  description=__doc__,
15  input_data_formats=["raw"],
16  input_data_names=["hlt_mumu", "hlt_hadron"],
17  depends_on=[])
18 
19 
20 def fix_tw_param():
21  from ROOT import Belle2
22  result = []
23  bad_boards = [0, 35, 37, 77, 97, 115, 133, 193, 204, 218, 247]
24  for ib in range(300):
25  if ib in bad_boards:
26  label0 = Belle2.GlobalLabel()
27  label0.construct(Belle2.CDCTimeWalks.getGlobalUniqueID(), ib, 0)
28  result.append(label0.label())
29  label1 = Belle2.GlobalLabel()
30  label1.construct(Belle2.CDCTimeWalks.getGlobalUniqueID(), ib, 1)
31  result.append(label1.label())
32  return result
33 
34 
35 def select_files(all_input_files, min_events, max_processed_events_per_file):
36  basf2.B2INFO("Attempting to choose a good subset of files")
37  # Let's iterate, taking a sample of files from the total (no repeats or replacement) until we get enough events
38  total_events = 0
39  chosen_files = []
40  while total_events < min_events:
41  # If the set is empty we must have used all available files. Here we break and continue. But you may want to
42  # raise an Error...
43  if not all_input_files:
44  break
45  # Randomly select a file
46  new_file_choice = choice(all_input_files)
47  # Remove it from the list so it can't be chosen again
48  all_input_files.remove(new_file_choice)
49  # Find the number of events in the file
50  total_events_in_file = events_in_basf2_file(new_file_choice)
51  if not total_events_in_file:
52  # Uh Oh! Zero event file, skip it
53  continue
54  events_contributed = 0
55  if total_events_in_file < max_processed_events_per_file:
56  # The file contains less than the max amount we have set (entrySequences)
57  events_contributed = total_events_in_file
58  else:
59  events_contributed = max_processed_events_per_file
60  chosen_files.append(new_file_choice)
61  total_events += events_contributed
62 
63  basf2.B2INFO(f"Total chosen files = {len(chosen_files)}")
64  basf2.B2INFO(f"Total events in chosen files = {total_events}")
65  if total_events < min_events:
66  raise ValueError(
67  f"There weren't enough files events selected when max_processed_events_per_file={max_processed_events_per_file}")
68  return chosen_files
69 
70 
71 
74 
75 
76 def get_calibrations(input_data, **kwargs):
77  import basf2
78  from prompt.utils import filter_by_max_files_per_run
79  import alignment
81  # Gets the input files and IoV objects associated with the files.
82  file_to_iov_mumu = input_data["hlt_mumu"]
83  file_to_iov_hadron = input_data["hlt_hadron"]
84  file_to_iov_Bcosmics = input_data["Bcosmics"]
85 
86  max_files_per_run = 10
87  min_events_per_file = 1000
88 
89  max_events_per_calibration = 50000
90  max_events_per_calibration_xt = 1000000
91  max_events_per_file = 2000
92  max_events_per_file_had = 1000
93 
94  reduced_file_to_iov_mumu = filter_by_max_files_per_run(file_to_iov_mumu, max_files_per_run, min_events_per_file)
95  input_files_mumu = list(reduced_file_to_iov_mumu.keys())
96  chosen_files_mumu = select_files(input_files_mumu[:], max_events_per_calibration, max_events_per_file)
97  chosen_files_mumu_xt = select_files(input_files_mumu[:], max_events_per_calibration_xt, max_events_per_file)
98  basf2.B2INFO(f"Total number of hlt_mumu files actually used as input = {len(input_files_mumu)}")
99 
100  reduced_file_to_iov_hadron = filter_by_max_files_per_run(file_to_iov_hadron, max_files_per_run, min_events_per_file)
101  input_files_hadron = list(reduced_file_to_iov_hadron.keys())
102  chosen_files_hadron = select_files(input_files_hadron[:], max_events_per_calibration, max_events_per_file_had)
103  chosen_files_hadron_xt = select_files(input_files_hadron[:], max_events_per_calibration_xt, max_events_per_file_had)
104  basf2.B2INFO(f"Total number of hlt_hadron files actually used as input = {len(input_files_hadron)}")
105 
106  # Get the overall IoV we want to cover, including the end values
107  requested_iov = kwargs.get("requested_iov", None)
108 
109  from caf.utils import IoV
110  # The actuall IoV we want for any prompt request is open-ended
111  output_iov = IoV(requested_iov.exp_low, requested_iov.run_low, -1, -1)
112  import millepede_calibration as mp2
113  # Calibrate time zero and time walk simultaneously.
114  cal1 = mp2.create(
115  name='tzw0',
116  dbobjects=['CDCTimeZeros', 'CDCTimeWalks'],
117  collections=[
118  mp2.make_collection('hlt_mumu', path=pre_collector(), tracks=['RecoTracks']),
119  mp2.make_collection('hlt_hadron', path=pre_collector(), tracks=['RecoTracks'])],
120  files=dict(hlt_mumu=chosen_files_mumu, hlt_hadron=chosen_files_hadron),
121  tags=None,
122  timedep=[],
123  constraints=[alignment.constraints.Constraints(basf2.find_file('cdc/data/cdc-T0-constraints.txt'))],
124  fixed=fix_tw_param(),
125  commands=['method inversion 1 0.1',
126  'threads 25 1',
127  'chiscut 30. 6.',
128  'entries 100',
129  'scaleerrors 1. 1.'],
130  params=dict(minPValue=0., externalIterations=0),
131  min_entries=10000)
132 
133  basf2.set_module_parameters(cal1.collections['hlt_mumu'].pre_collector_path,
134  'RootInput', entrySequences=[f'0:{max_events_per_file}'])
135  basf2.set_module_parameters(cal1.collections['hlt_hadron'].pre_collector_path,
136  'RootInput', entrySequences=[f'0:{max_events_per_file_had}'])
137  cal1.max_iterations = 5
138 
139  # Calibration of XT is separated from tz/tw. in future, it will be simultaniously calibrated...
140  cal2 = mp2.create(
141  name='xt0',
142  dbobjects=['CDCXtRelations'],
143  collections=[
144  mp2.make_collection('hlt_mumu', path=pre_collector(), tracks=['RecoTracks']),
145  mp2.make_collection('hlt_hadron', path=pre_collector(), tracks=['RecoTracks'])],
146  files=dict(hlt_mumu=chosen_files_mumu_xt, hlt_hadron=chosen_files_hadron_xt),
147  tags=None,
148  timedep=[],
149  constraints=[],
150  fixed=[],
151  commands=['method sparseMINRES-QLP 3 0.01',
152  'threads 25 1',
153  'chiscut 30. 6.',
154  'entries 100',
155  'scaleerrors 1. 1.'],
156  params=dict(minPValue=0., externalIterations=0),
157  min_entries=10000)
158 
159  basf2.set_module_parameters(cal2.collections['hlt_mumu'].pre_collector_path,
160  'RootInput', entrySequences=[f'0:{max_events_per_file}'])
161  basf2.set_module_parameters(cal2.collections['hlt_hadron'].pre_collector_path,
162  'RootInput', entrySequences=[f'0:{max_events_per_file_had}'])
163  cal2.max_iterations = 2
164  # Force the output payload IoV to be correct.
165  # It may be different if you are using another strategy like SequentialRunByRun
166  for algorithm in cal1.algorithms:
167  algorithm.params = {"apply_iov": output_iov}
168  for algorithm in cal2.algorithms:
169  algorithm.params = {"apply_iov": output_iov}
170 
171  return [cal1, cal2]
172 
173 
174 
175 
176 def pre_collector(max_events=None):
177  """
178  Define pre collection (reconstruction in our purpose).
179  Probably, we need only CDC and ECL data.
180  Parameters:
181  max_events [int] : number of events to be processed.
182  All events by Default.
183  Returns:
184  path : path for pre collection
185  """
186  from basf2 import create_path, register_module
187  import modularAnalysis as ana
188  reco_path = create_path()
189  if max_events is None:
190  root_input = register_module('RootInput')
191  else:
192  root_input = register_module('RootInput',
193  entrySequences=['0:{}'.format(max_events)]
194  )
195  reco_path.add_module(root_input)
196 
197  gearbox = register_module('Gearbox')
198  reco_path.add_module(gearbox)
199  reco_path.add_module('Geometry', useDB=True)
200 
201  from rawdata import add_unpackers
202  # unpack raw data
203  add_unpackers(reco_path)
204 
205  from reconstruction import add_reconstruction
206  add_reconstruction(reco_path,
207  components=['PXD', 'SVD', 'CDC', 'ECL'],
208  add_trigger_calculation=False,
209  trackFitHypotheses=[211, 13],
210  pruneTracks=False)
211 
212  ana.fillParticleList('mu+:qed', 'muonID > 0.1 and useCMSFrame(p) > 2.', writeOut=True, path=reco_path)
213  ana.reconstructDecay('Z0:mumu -> mu-:qed mu+:qed', '', writeOut=True, path=reco_path)
214  return reco_path
215 
216 
217 def pre_collector_cr(max_events=None):
218  """
219  Define pre collection (reconstruction in our purpose).
220  Probably, we need only CDC and ECL data.
221  Parameters:
222  max_events [int] : number of events to be processed.
223  All events by Default.
224  Returns:
225  path : path for pre collection
226  """
227  from basf2 import create_path, register_module
228  reco_path = create_path()
229  if max_events is None:
230  root_input = register_module('RootInput')
231  else:
232  root_input = register_module('RootInput',
233  entrySequences=['0:{}'.format(max_events)]
234  )
235  reco_path.add_module(root_input)
236 
237  gearbox = register_module('Gearbox')
238  reco_path.add_module(gearbox)
239  reco_path.add_module('Geometry', useDB=True)
240 
241  from rawdata import add_unpackers
242  # unpack raw data
243  add_unpackers(reco_path)
244 
245  from reconstruction import add_cosmics_reconstruction
246  add_cosmics_reconstruction(reco_path,
247  components=['CDC', 'ECL'],
248  merge_tracks=False,
249  pruneTracks=False,
250  data_taking_period='normal'
251  )
252  return reco_path
253 
254 
255 def collector(bField=True, is_cosmic=False):
256  """
257  Create a cdc calibration collector
258  Parameters:
259  bField [bool] : True if B field is on, else False
260  isCosmic [bool] : True if cosmic events,
261  else (collision) False.
262  Returns:
263  collector : collector module
264  """
265  from basf2 import register_module
266  col = register_module('CDCCalibrationCollector',
267  granularity='all',
268  calExpectedDriftTime=True,
269  eventT0Extraction=True,
270  bField=bField,
271  isCosmic=is_cosmic
272  )
273  return col
274 
275 
276 def tz_algo():
277  """
278  Create a T0 calibration algorithm.
279  Returns:
280  algo : T0 algorithm
281  """
282  from ROOT import Belle2
284  algo.storeHisto(True)
285  algo.setMaxMeanDt(0.5)
286  algo.setMaxRMSDt(0.1)
287  algo.setMinimumNDF(20)
288  return algo
289 
290 
291 def tw_algo():
292  """
293  Create a time walk calibration algorithm.
294  Returns:
295  algo : TW algorithm
296  """
297  from ROOT import Belle2
299  algo.setStoreHisto(True)
300  algo.setMode(1)
301  return algo
302 
303 
304 def xt_algo():
305  """
306  Create a XT calibration algorithm.
307  Parameters:
308  prefix : prefixed name for algorithm,
309  which should be consistent with one of collector..
310  Returns:
311  algo : XT algorithm
312  """
313  from ROOT import Belle2
315  algo.setStoreHisto(True)
316  algo.setLRSeparate(True)
317  algo.setThreshold(0.55)
318  return algo
319 
320 
321 def sr_algo():
322  """
323  Create a Spacial resolution calibration algorithm.
324  Parameters:
325  prefix : prefixed name for algorithm,
326  which should be consistent with one of collector..
327  Returns:
328  algo : Spacial algorithm
329  """
330  from ROOT import Belle2
332  algo.setStoreHisto(True)
333  algo.setThreshold(0.4)
334  return algo
prompt.utils
Definition: utils.py:1
Belle2::CDC::XTCalibrationAlgorithm
Class to perform xt calibration for drift chamber.
Definition: XTCalibrationAlgorithm.h:61
Belle2::CDC::T0CalibrationAlgorithm
Class for T0 Correction .
Definition: T0CalibrationAlgorithm.h:34
Belle2::GlobalLabel
Class to convert to/from global labels for Millepede II to/from detector & parameter identificators.
Definition: GlobalLabel.h:51
alignment.constraints.Constraints
Definition: constraints.py:54
Belle2::CDC::TimeWalkCalibrationAlgorithm
Class for Time walk calibration.
Definition: TimeWalkCalibrationAlgorithm.h:37
alignment.constraints
Definition: constraints.py:1
collector
Definition: collector.py:1
Belle2::CDC::SpaceResolutionCalibrationAlgorithm
Class for Space resolution calibration.
Definition: SpaceResolutionCalibrationAlgorithm.h:38
Belle2::CDCTimeWalks::getGlobalUniqueID
static unsigned short getGlobalUniqueID()
Get global unique id.
Definition: CDCTimeWalks.h:165