Belle II Software  release-06-00-14
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, 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 SVDSimpleClusterizer modules.
191  They should output to different datastore objects.
192 
193  returns:
194  pybasf2.Path
195  """
196  # Set-up re-processing path
197  path = b2.create_path()
198 
199  # Read from file only what is needed
200  if not isMC:
201  path.add_module("RootInput", branchNames=HLT_INPUT_OBJECTS)
202  else:
203  path.add_module("RootInput")
204 
205  # unpack raw data to do the tracking
206  if not isMC:
207  raw.add_unpackers(path, components=['PXD', 'SVD', 'CDC'])
208  else:
209  path.add_module("Gearbox")
210  path.add_module("Geometry")
211 
212  # proceed only if we acquired 6-sample strips
213  skim6SampleEvents = b2.register_module("SVD6SampleEventSkim")
214  path.add_module(skim6SampleEvents)
215  emptypath = b2.create_path()
216  skim6SampleEvents.if_false(emptypath)
217 
218  if not isMC:
219  # run tracking reconstruction
220  add_tracking_reconstruction(path)
221  path = remove_module(path, "V0Finder")
222  if not is_validation:
223  b2.set_module_parameters(path, 'SVDClusterizer', returnClusterRawTime=True)
224 
225  # repeat svd reconstruction using only SVDShaperDigitsFromTracks
226  path.add_module("SVDShaperDigitsFromTracks")
227 
228  for cluster in clusterizers:
229  path.add_module(cluster)
230 
231  path = remove_module(path, "SVDMissingAPVsClusterCreator")
232 
233  return path
234 
235 
236 def get_calibrations(input_data, **kwargs):
237 
238  file_to_iov_physics = input_data["hadron_calib"]
239  expert_config = kwargs.get("expert_config")
240  max_events_per_run = expert_config["max_events_per_run"] # Maximum number of events selected per each run
241  isMC = expert_config["isMC"]
242 
243  reduced_file_to_iov_physics = filter_by_max_events_per_run(file_to_iov_physics,
244  max_events_per_run, random_select=True)
245  good_input_files = list(reduced_file_to_iov_physics.keys())
246 
247  b2.B2INFO(f"Total number of files used as input = {len(good_input_files)}")
248 
249  exps = [i.exp_low for i in reduced_file_to_iov_physics.values()]
250  runs = sorted([i.run_low for i in reduced_file_to_iov_physics.values()])
251 
252  firstRun = runs[0]
253  lastRun = runs[-1]
254  expNum = exps[0]
255 
256  if not len(good_input_files):
257  print("No good input files found! Check that the input files have entries != 0!")
258  sys.exit(1)
259 
260  cog6_suffix = "_CoG6"
261  cog3_suffix = "_CoG3"
262  els3_suffix = "_ELS3"
263 
264  calType = "Prompt"
265  if isMC:
266  calType = "MC"
267  unique_id_cog6 = f"SVDCoGTimeCalibrations_{calType}_{now.isoformat()}_INFO:_3rdOrderPol_TBindep_" \
268  f"Exp{expNum}_runsFrom{firstRun}to{lastRun}"
269  print(f"\nUniqueID_CoG6:\n{unique_id_cog6}")
270 
271  unique_id_cog3 = f"SVD3SampleCoGTimeCalibrations_{calType}_{now.isoformat()}_INFO:_3rdOrderPol_TBindep_" \
272  f"Exp{expNum}_runsFrom{firstRun}to{lastRun}"
273  print(f"\nUniqueID_CoG3:\n{unique_id_cog3}")
274 
275  unique_id_els3 = f"SVD3SampleELSTimeCalibrations_{calType}_{now.isoformat()}_INFO:_TBindep_" \
276  f"Exp{expNum}_runsFrom{firstRun}to{lastRun}"
277  print(f"\nUniqueID_ELS3:\n{unique_id_els3}")
278 
279  requested_iov = kwargs.get("requested_iov", None)
280  output_iov = IoV(requested_iov.exp_low, requested_iov.run_low, -1, -1)
281 
282 
285 
286  cog6 = create_svd_clusterizer(
287  name=f"ClusterReconstruction{cog6_suffix}",
288  clusters=f"SVDClustersFromTracks{cog6_suffix}",
289  reco_digits=NEW_RECO_DIGITS_NAME,
290  shaper_digits=NEW_SHAPER_DIGITS_NAME,
291  time_algorithm="CoG6",
292  get_3sample_raw_time=True)
293 
294  cog3 = create_svd_clusterizer(
295  name=f"ClusterReconstruction{cog3_suffix}",
296  clusters=f"SVDClustersFromTracks{cog3_suffix}",
297  reco_digits=NEW_RECO_DIGITS_NAME,
298  shaper_digits=NEW_SHAPER_DIGITS_NAME,
299  time_algorithm="CoG3",
300  get_3sample_raw_time=True)
301 
302  els3 = create_svd_clusterizer(
303  name=f"ClusterReconstruction{els3_suffix}",
304  clusters=f"SVDClustersFromTracks{els3_suffix}",
305  reco_digits=NEW_RECO_DIGITS_NAME,
306  shaper_digits=NEW_SHAPER_DIGITS_NAME,
307  time_algorithm="ELS3",
308  get_3sample_raw_time=True)
309 
310 
313  eventInfo = "SVDEventInfo"
314  if isMC:
315  eventInfo = "SVDEventInfoSim"
316 
317  coll_cog6 = create_collector(
318  name=f"SVDTimeCalibrationCollector{cog6_suffix}",
319  clusters=f"SVDClustersFromTracks{cog6_suffix}",
320  event_info=eventInfo,
321  event_t0="EventT0")
322 
323  algo_cog6 = create_algorithm(
324  unique_id_cog6,
325  prefix=coll_cog6.name(),
326  min_entries=10000)
327 
328  coll_cog3 = create_collector(
329  name=f"SVDTimeCalibrationCollector{cog3_suffix}",
330  clusters=f"SVDClustersFromTracks{cog3_suffix}",
331  event_info=eventInfo,
332  rawBinWidth=1,
333  event_t0="EventT0")
334 
335  algo_cog3 = create_algorithm(
336  unique_id_cog3,
337  prefix=coll_cog3.name(),
338  min_entries=10000)
339 
340  coll_els3 = create_collector(
341  name=f"SVDTimeCalibrationCollector{els3_suffix}",
342  clusters=f"SVDClustersFromTracks{els3_suffix}",
343  event_info=eventInfo,
344  event_t0="EventT0")
345 
346  algo_els3 = create_algorithm(
347  unique_id_els3,
348  prefix=coll_els3.name(),
349  min_entries=10000)
350 
351 
355 
356  pre_collector_path = create_pre_collector_path(
357  clusterizers=[cog6, cog3, els3],
358  isMC=isMC)
359  pre_collector_path.add_module(coll_cog6)
360  pre_collector_path.add_module(coll_cog3)
361  # We leave the coll_els3 to be the one "managed" by the CAF
362 
363  # calibration setup
364  calibration = Calibration("SVDTime",
365  collector=coll_els3, # The other collectors are in the pre_collector_path itself
366  algorithms=[algo_cog3, algo_cog6, algo_els3],
367  input_files=good_input_files,
368  pre_collector_path=pre_collector_path)
369 
370  calibration.strategies = strategies.SequentialBoundaries
371 
372  for algorithm in calibration.algorithms:
373  algorithm.params = {"iov_coverage": output_iov}
374 
375 
378 
379  val_cog6 = create_svd_clusterizer(
380  name=f"ClusterReconstruction{cog6_suffix}",
381  clusters=f"SVDClusters{cog6_suffix}",
382  time_algorithm="CoG6")
383 
384  val_cog6_onTracks = create_svd_clusterizer(
385  name=f"ClusterReconstruction{cog6_suffix}_onTracks",
386  clusters=f"SVDClusters{cog6_suffix}_onTracks",
387  reco_digits=NEW_RECO_DIGITS_NAME,
388  shaper_digits=NEW_SHAPER_DIGITS_NAME,
389  time_algorithm="CoG6")
390 
391  val_cog3 = create_svd_clusterizer(
392  name=f"ClusterReconstruction{cog3_suffix}",
393  clusters=f"SVDClusters{cog3_suffix}",
394  time_algorithm="CoG3")
395 
396  val_cog3_onTracks = create_svd_clusterizer(
397  name=f"ClusterReconstruction{cog3_suffix}_onTracks",
398  clusters=f"SVDClusters{cog3_suffix}_onTracks",
399  reco_digits=NEW_RECO_DIGITS_NAME,
400  shaper_digits=NEW_SHAPER_DIGITS_NAME,
401  time_algorithm="CoG3")
402 
403  val_els3 = create_svd_clusterizer(
404  name=f"ClusterReconstruction{els3_suffix}",
405  clusters=f"SVDClusters{els3_suffix}",
406  time_algorithm="ELS3")
407 
408  val_els3_onTracks = create_svd_clusterizer(
409  name=f"ClusterReconstruction{els3_suffix}_onTracks",
410  clusters=f"SVDClusters{els3_suffix}_onTracks",
411  reco_digits=NEW_RECO_DIGITS_NAME,
412  shaper_digits=NEW_SHAPER_DIGITS_NAME,
413  time_algorithm="ELS3")
414 
415  val_coll_cog6 = create_validation_collector(
416  name=f"SVDTimeValidationCollector{cog6_suffix}",
417  clusters=f"SVDClusters{cog6_suffix}",
418  clusters_onTracks=f"SVDClusters{cog6_suffix}_onTracks",
419  event_info=eventInfo,
420  event_t0="EventT0")
421 
422  val_algo_cog6 = create_validation_algorithm(
423  prefix=val_coll_cog6.name(),
424  min_entries=10000)
425 
426  val_coll_cog3 = create_validation_collector(
427  name=f"SVDTimeValidationCollector{cog3_suffix}",
428  clusters=f"SVDClusters{cog3_suffix}",
429  clusters_onTracks=f"SVDClusters{cog3_suffix}_onTracks",
430  event_info=eventInfo,
431  event_t0="EventT0")
432 
433  val_algo_cog3 = create_validation_algorithm(
434  prefix=val_coll_cog3.name(),
435  min_entries=10000)
436 
437  val_coll_els3 = create_validation_collector(
438  name=f"SVDTimeValidationCollector{els3_suffix}",
439  clusters=f"SVDClusters{els3_suffix}",
440  clusters_onTracks=f"SVDClusters{els3_suffix}_onTracks",
441  event_info=eventInfo,
442  event_t0="EventT0")
443 
444  val_algo_els3 = create_validation_algorithm(
445  prefix=val_coll_els3.name(),
446  min_entries=10000)
447 
448  val_pre_collector_path = create_pre_collector_path(
449  clusterizers=[val_cog6, val_cog6_onTracks,
450  val_cog3, val_cog3_onTracks,
451  val_els3, val_els3_onTracks],
452  isMC=isMC, is_validation=True)
453  val_pre_collector_path.add_module(val_coll_cog6)
454  val_pre_collector_path.add_module(val_coll_cog3)
455 
456  val_calibration = Calibration("SVDTimeValidation",
457  collector=val_coll_els3,
458  algorithms=[val_algo_cog3, val_algo_cog6,
459  val_algo_els3],
460  input_files=good_input_files,
461  pre_collector_path=val_pre_collector_path)
462 
463  val_calibration.strategies = strategies.SequentialRunByRun
464 
465  for algorithm in val_calibration.algorithms:
466  algorithm.params = {"iov_coverage": output_iov}
467 
468  val_calibration.depends_on(calibration)
469 
470  return [calibration, val_calibration]