Belle II Software  release-06-02-00
caf_svd_time.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
11 '''
12 Script to perform the svd time calibration with the CoG6, CoG3 and ELS3 algorithms
13 '''
14 
15 import sys
16 import datetime
17 import random
18 
19 from ROOT.Belle2 import SVDCoGTimeCalibrationAlgorithm
20 from ROOT.Belle2 import SVD3SampleCoGTimeCalibrationAlgorithm
21 from ROOT.Belle2 import SVD3SampleELSTimeCalibrationAlgorithm
22 from ROOT.Belle2 import SVDTimeValidationAlgorithm
23 
24 import basf2 as b2
25 
26 import rawdata as raw
27 from softwaretrigger.constants import HLT_INPUT_OBJECTS
28 from tracking import add_tracking_reconstruction
29 
30 from caf.framework import Calibration
31 from caf import strategies
32 from caf.utils import IoV
33 from prompt import CalibrationSettings, INPUT_DATA_FILTERS
34 from prompt.utils import filter_by_max_events_per_run
35 
36 b2.set_log_level(b2.LogLevel.INFO)
37 
38 random.seed(42)
39 
40 now = datetime.datetime.now()
41 
42 settings = CalibrationSettings(name="caf_svd_time",
43  expert_username="gdujany",
44  description=__doc__,
45  input_data_formats=["raw"],
46  input_data_names=["hadron_calib"],
47  input_data_filters={"hadron_calib": [INPUT_DATA_FILTERS["Data Tag"]["hadron_calib"],
48  INPUT_DATA_FILTERS["Beam Energy"]["4S"],
49  INPUT_DATA_FILTERS["Beam Energy"]["Continuum"],
50  INPUT_DATA_FILTERS["Run Type"]["physics"],
51  INPUT_DATA_FILTERS["Magnet"]["On"]]},
52  depends_on=[],
53  expert_config={
54  "max_events_per_run": 10000,
55  "isMC": False,
56  })
57 
58 
60 
61 
62 def remove_module(path, name):
63 
64  new_path = b2.create_path()
65  for m in path.modules():
66  if name != m.name():
67  new_path.add_module(m)
68  return new_path
69 
70 
71 
72 NEW_RECO_DIGITS_NAME = "SVDRecoDigitsFromTracks"
73 NEW_SHAPER_DIGITS_NAME = "SVDShaperDigitsFromTracks"
74 
75 
76 def create_collector(name="SVDTimeCalibrationCollector",
77  clusters="SVDClustersFromTracks",
78  event_info="SVDEventInfo",
79  event_t0="EventT0",
80  rawBinWidth=2,
81  granularity="run"):
82  """
83  Simply creates a SVDTimeCalibrationCollector module with some options.
84 
85  Returns:
86  pybasf2.Module
87  """
88 
89  collector = b2.register_module("SVDTimeCalibrationCollector")
90  collector.set_name(name)
91  collector.param("SVDClustersFromTracksName", clusters)
92  collector.param("SVDEventInfoName", event_info)
93  collector.param("EventT0Name", event_t0)
94  collector.param("granularity", granularity)
95  collector.param("RawCoGBinWidth", rawBinWidth)
96 
97  return collector
98 
99 
100 def create_validation_collector(name="SVDTimeValidationCollector",
101  clusters="SVDClusters",
102  clusters_onTracks="SVDClustersOnTracks",
103  event_info="SVDEventInfo",
104  event_t0="EventT0",
105  granularity="run"):
106  """
107  Simply creates a SVDTimeCalibrationCollector module with some options.
108 
109  Returns:
110  pybasf2.Module
111  """
112 
113  collector = b2.register_module("SVDTimeValidationCollector")
114  collector.set_name(name)
115  collector.param("SVDClustersName", clusters)
116  collector.param("SVDClustersOnTracksName", clusters_onTracks)
117  collector.param("SVDEventInfoName", event_info)
118  collector.param("EventT0Name", event_t0)
119  collector.param("granularity", granularity)
120 
121  return collector
122 
123 
124 def create_algorithm(unique_id, prefix="", min_entries=10000):
125  """
126  Simply creates a SVDCoGTimeCalibrationAlgorithm class with some options.
127 
128  Returns:
129  ROOT.Belle2.SVDCoGTimeCalibrationAlgorithm
130  """
131  if "CoG6" in prefix:
132  algorithm = SVDCoGTimeCalibrationAlgorithm(unique_id)
133  if "CoG3" in prefix:
134  algorithm = SVD3SampleCoGTimeCalibrationAlgorithm(unique_id)
135  if "ELS3" in prefix:
136  algorithm = SVD3SampleELSTimeCalibrationAlgorithm(unique_id)
137  if prefix:
138  algorithm.setPrefix(prefix)
139  algorithm.setMinEntries(min_entries)
140 
141  return algorithm
142 
143 
144 def create_validation_algorithm(prefix="", min_entries=10000):
145  """
146  Simply creates a SVDCoGTimeValidationAlgorithm class with some options.
147 
148  Returns:
149  ROOT.Belle2.SVDCoGTimeValidationAlgorithm
150  """
151  algorithm = SVDTimeValidationAlgorithm()
152  if prefix:
153  algorithm.setPrefix(prefix)
154  algorithm.setMinEntries(min_entries)
155 
156  return algorithm
157 
158 
159 def create_svd_clusterizer(name="ClusterReconstruction",
160  clusters="SVDClustersFromTracks",
161  reco_digits=None,
162  shaper_digits=None,
163  time_algorithm="CoG6",
164  get_3sample_raw_time=False):
165  """
166  Simply creates a SVDClusterizer module with some options.
167 
168  Returns:
169  pybasf2.Module
170  """
171 
172  cluster = b2.register_module("SVDClusterizer")
173  cluster.set_name(name)
174  cluster.param("Clusters", clusters)
175  if shaper_digits is not None:
176  cluster.param("ShaperDigits", shaper_digits)
177  cluster.param("timeAlgorithm6Samples", time_algorithm)
178  cluster.param("useDB", False)
179  if get_3sample_raw_time:
180  cluster.param("returnClusterRawTime", True)
181  return cluster
182 
183 
184 def create_pre_collector_path(clusterizers, isMC=False, max_events_per_run=10000, is_validation=False):
185  """
186  Create a basf2 path that runs a common reconstruction path and also runs several SVDSimpleClusterizer
187  modules with different configurations. This way they re-use the same reconstructed objects.
188 
189  Parameters:
190  clusterizers (list[pybasf2.Module]): All the differently configured
191  SVDSimpleClusterizer modules. They should output to different datastore objects.
192  max_events_per_run (int, optional): Max events read per run. Defaults to 10000.
193  is_validation (bool, optional): Is used to produce the validation plots. Defaults to False.
194 
195  returns:
196  pybasf2.Path
197  """
198  # Set-up re-processing path
199  path = b2.create_path()
200 
201  # Read from file only what is needed
202  if not isMC:
203  path.add_module("RootInput", branchNames=HLT_INPUT_OBJECTS, entrySequences=[f'0:{max_events_per_run}'])
204  else:
205  path.add_module("RootInput")
206 
207  # unpack raw data to do the tracking
208  if not isMC:
209  raw.add_unpackers(path, components=['PXD', 'SVD', 'CDC'])
210  else:
211  path.add_module("Gearbox")
212  path.add_module("Geometry")
213 
214  # proceed only if we acquired 6-sample strips
215  skim6SampleEvents = b2.register_module("SVD6SampleEventSkim")
216  path.add_module(skim6SampleEvents)
217  emptypath = b2.create_path()
218  skim6SampleEvents.if_false(emptypath)
219 
220  if not isMC:
221  # run tracking reconstruction
222  add_tracking_reconstruction(path)
223  path = remove_module(path, "V0Finder")
224  if not is_validation:
225  b2.set_module_parameters(path, 'SVDClusterizer', returnClusterRawTime=True)
226 
227  # repeat svd reconstruction using only SVDShaperDigitsFromTracks
228  path.add_module("SVDShaperDigitsFromTracks")
229 
230  for cluster in clusterizers:
231  path.add_module(cluster)
232 
233  path = remove_module(path, "SVDMissingAPVsClusterCreator")
234 
235  return path
236 
237 
238 def get_calibrations(input_data, **kwargs):
239 
240  file_to_iov_physics = input_data["hadron_calib"]
241  expert_config = kwargs.get("expert_config")
242  max_events_per_run = expert_config["max_events_per_run"] # Maximum number of events selected per each run
243  isMC = expert_config["isMC"]
244 
245  reduced_file_to_iov_physics = filter_by_max_events_per_run(file_to_iov_physics,
246  max_events_per_run, random_select=True)
247  good_input_files = list(reduced_file_to_iov_physics.keys())
248 
249  b2.B2INFO(f"Total number of files used as input = {len(good_input_files)}")
250 
251  exps = [i.exp_low for i in reduced_file_to_iov_physics.values()]
252  runs = sorted([i.run_low for i in reduced_file_to_iov_physics.values()])
253 
254  firstRun = runs[0]
255  lastRun = runs[-1]
256  expNum = exps[0]
257 
258  if not len(good_input_files):
259  print("No good input files found! Check that the input files have entries != 0!")
260  sys.exit(1)
261 
262  cog6_suffix = "_CoG6"
263  cog3_suffix = "_CoG3"
264  els3_suffix = "_ELS3"
265 
266  calType = "Prompt"
267  if isMC:
268  calType = "MC"
269  unique_id_cog6 = f"SVDCoGTimeCalibrations_{calType}_{now.isoformat()}_INFO:_3rdOrderPol_TBindep_" \
270  f"Exp{expNum}_runsFrom{firstRun}to{lastRun}"
271  print(f"\nUniqueID_CoG6:\n{unique_id_cog6}")
272 
273  unique_id_cog3 = f"SVD3SampleCoGTimeCalibrations_{calType}_{now.isoformat()}_INFO:_3rdOrderPol_TBindep_" \
274  f"Exp{expNum}_runsFrom{firstRun}to{lastRun}"
275  print(f"\nUniqueID_CoG3:\n{unique_id_cog3}")
276 
277  unique_id_els3 = f"SVD3SampleELSTimeCalibrations_{calType}_{now.isoformat()}_INFO:_TBindep_" \
278  f"Exp{expNum}_runsFrom{firstRun}to{lastRun}"
279  print(f"\nUniqueID_ELS3:\n{unique_id_els3}")
280 
281  requested_iov = kwargs.get("requested_iov", None)
282  output_iov = IoV(requested_iov.exp_low, requested_iov.run_low, -1, -1)
283 
284 
287 
288  cog6 = create_svd_clusterizer(
289  name=f"ClusterReconstruction{cog6_suffix}",
290  clusters=f"SVDClustersFromTracks{cog6_suffix}",
291  reco_digits=NEW_RECO_DIGITS_NAME,
292  shaper_digits=NEW_SHAPER_DIGITS_NAME,
293  time_algorithm="CoG6",
294  get_3sample_raw_time=True)
295 
296  cog3 = create_svd_clusterizer(
297  name=f"ClusterReconstruction{cog3_suffix}",
298  clusters=f"SVDClustersFromTracks{cog3_suffix}",
299  reco_digits=NEW_RECO_DIGITS_NAME,
300  shaper_digits=NEW_SHAPER_DIGITS_NAME,
301  time_algorithm="CoG3",
302  get_3sample_raw_time=True)
303 
304  els3 = create_svd_clusterizer(
305  name=f"ClusterReconstruction{els3_suffix}",
306  clusters=f"SVDClustersFromTracks{els3_suffix}",
307  reco_digits=NEW_RECO_DIGITS_NAME,
308  shaper_digits=NEW_SHAPER_DIGITS_NAME,
309  time_algorithm="ELS3",
310  get_3sample_raw_time=True)
311 
312 
315  eventInfo = "SVDEventInfo"
316  if isMC:
317  eventInfo = "SVDEventInfoSim"
318 
319  coll_cog6 = create_collector(
320  name=f"SVDTimeCalibrationCollector{cog6_suffix}",
321  clusters=f"SVDClustersFromTracks{cog6_suffix}",
322  event_info=eventInfo,
323  event_t0="EventT0")
324 
325  algo_cog6 = create_algorithm(
326  unique_id_cog6,
327  prefix=coll_cog6.name(),
328  min_entries=10000)
329 
330  coll_cog3 = create_collector(
331  name=f"SVDTimeCalibrationCollector{cog3_suffix}",
332  clusters=f"SVDClustersFromTracks{cog3_suffix}",
333  event_info=eventInfo,
334  rawBinWidth=1,
335  event_t0="EventT0")
336 
337  algo_cog3 = create_algorithm(
338  unique_id_cog3,
339  prefix=coll_cog3.name(),
340  min_entries=10000)
341 
342  coll_els3 = create_collector(
343  name=f"SVDTimeCalibrationCollector{els3_suffix}",
344  clusters=f"SVDClustersFromTracks{els3_suffix}",
345  event_info=eventInfo,
346  event_t0="EventT0")
347 
348  algo_els3 = create_algorithm(
349  unique_id_els3,
350  prefix=coll_els3.name(),
351  min_entries=10000)
352 
353 
357 
358  pre_collector_path = create_pre_collector_path(
359  clusterizers=[cog6, cog3, els3],
360  isMC=isMC, max_events_per_run=max_events_per_run)
361  pre_collector_path.add_module(coll_cog6)
362  pre_collector_path.add_module(coll_cog3)
363  # We leave the coll_els3 to be the one "managed" by the CAF
364 
365  # calibration setup
366  calibration = Calibration("SVDTime",
367  collector=coll_els3, # The other collectors are in the pre_collector_path itself
368  algorithms=[algo_cog3, algo_cog6, algo_els3],
369  input_files=good_input_files,
370  pre_collector_path=pre_collector_path)
371 
372  calibration.strategies = strategies.SequentialBoundaries
373 
374  for algorithm in calibration.algorithms:
375  algorithm.params = {"iov_coverage": output_iov}
376 
377 
380 
381  val_cog6 = create_svd_clusterizer(
382  name=f"ClusterReconstruction{cog6_suffix}",
383  clusters=f"SVDClusters{cog6_suffix}",
384  time_algorithm="CoG6")
385 
386  val_cog6_onTracks = create_svd_clusterizer(
387  name=f"ClusterReconstruction{cog6_suffix}_onTracks",
388  clusters=f"SVDClusters{cog6_suffix}_onTracks",
389  reco_digits=NEW_RECO_DIGITS_NAME,
390  shaper_digits=NEW_SHAPER_DIGITS_NAME,
391  time_algorithm="CoG6")
392 
393  val_cog3 = create_svd_clusterizer(
394  name=f"ClusterReconstruction{cog3_suffix}",
395  clusters=f"SVDClusters{cog3_suffix}",
396  time_algorithm="CoG3")
397 
398  val_cog3_onTracks = create_svd_clusterizer(
399  name=f"ClusterReconstruction{cog3_suffix}_onTracks",
400  clusters=f"SVDClusters{cog3_suffix}_onTracks",
401  reco_digits=NEW_RECO_DIGITS_NAME,
402  shaper_digits=NEW_SHAPER_DIGITS_NAME,
403  time_algorithm="CoG3")
404 
405  val_els3 = create_svd_clusterizer(
406  name=f"ClusterReconstruction{els3_suffix}",
407  clusters=f"SVDClusters{els3_suffix}",
408  time_algorithm="ELS3")
409 
410  val_els3_onTracks = create_svd_clusterizer(
411  name=f"ClusterReconstruction{els3_suffix}_onTracks",
412  clusters=f"SVDClusters{els3_suffix}_onTracks",
413  reco_digits=NEW_RECO_DIGITS_NAME,
414  shaper_digits=NEW_SHAPER_DIGITS_NAME,
415  time_algorithm="ELS3")
416 
417  val_coll_cog6 = create_validation_collector(
418  name=f"SVDTimeValidationCollector{cog6_suffix}",
419  clusters=f"SVDClusters{cog6_suffix}",
420  clusters_onTracks=f"SVDClusters{cog6_suffix}_onTracks",
421  event_info=eventInfo,
422  event_t0="EventT0")
423 
424  val_algo_cog6 = create_validation_algorithm(
425  prefix=val_coll_cog6.name(),
426  min_entries=10000)
427 
428  val_coll_cog3 = create_validation_collector(
429  name=f"SVDTimeValidationCollector{cog3_suffix}",
430  clusters=f"SVDClusters{cog3_suffix}",
431  clusters_onTracks=f"SVDClusters{cog3_suffix}_onTracks",
432  event_info=eventInfo,
433  event_t0="EventT0")
434 
435  val_algo_cog3 = create_validation_algorithm(
436  prefix=val_coll_cog3.name(),
437  min_entries=10000)
438 
439  val_coll_els3 = create_validation_collector(
440  name=f"SVDTimeValidationCollector{els3_suffix}",
441  clusters=f"SVDClusters{els3_suffix}",
442  clusters_onTracks=f"SVDClusters{els3_suffix}_onTracks",
443  event_info=eventInfo,
444  event_t0="EventT0")
445 
446  val_algo_els3 = create_validation_algorithm(
447  prefix=val_coll_els3.name(),
448  min_entries=10000)
449 
450  val_pre_collector_path = create_pre_collector_path(
451  clusterizers=[val_cog6, val_cog6_onTracks,
452  val_cog3, val_cog3_onTracks,
453  val_els3, val_els3_onTracks],
454  isMC=isMC, max_events_per_run=max_events_per_run, is_validation=True)
455  val_pre_collector_path.add_module(val_coll_cog6)
456  val_pre_collector_path.add_module(val_coll_cog3)
457 
458  val_calibration = Calibration("SVDTimeValidation",
459  collector=val_coll_els3,
460  algorithms=[val_algo_cog3, val_algo_cog6,
461  val_algo_els3],
462  input_files=good_input_files,
463  pre_collector_path=val_pre_collector_path)
464 
465  val_calibration.strategies = strategies.SequentialRunByRun
466 
467  for algorithm in val_calibration.algorithms:
468  algorithm.params = {"iov_coverage": output_iov}
469 
470  val_calibration.depends_on(calibration)
471 
472  return [calibration, val_calibration]