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