Belle II Software  release-08-01-10
simulation.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 import basf2 as b2
13 from geometry import check_components
14 from L1trigger import add_trigger_simulation
15 from pxd import add_pxd_simulation
16 from svd import add_svd_simulation
17 from svd import add_svd_reconstruction
18 from tracking import add_tracking_for_PXDDataReduction_simulation, add_roiFinder
19 
20 
21 def check_simulation(path):
22  """Check if the minimum number of modules required for simulation are in
23  the path and in the correct order"""
24  required = ['Gearbox', 'Geometry', 'FullSim']
25  found = []
26 
27  # make a list of all required modules in the path
28  for module in path.modules():
29  module_type = module.type()
30  # if required add to list of found modules
31  if module_type in required:
32  # unless it is already in there
33  if module_type in found:
34  b2.B2ERROR("Duplicate module in path: %s" % module_type)
35  else:
36  found.append(module.type())
37 
38  if len(required) != len(found):
39  # Apparently at least one module is missing
40  for r in required:
41  if r not in found:
42  b2.B2ERROR("No '%s' module found but needed for simulation" % r)
43  # We have all modules but do they have the correct order?
44  elif required != found:
45  b2.B2ERROR("Simulation modules in wrong order. Should be '%s' but is '%s'"
46  % (", ".join(required), ", ".join(found)))
47 
48 
49 def add_PXDDataReduction(path, components, pxd_unfiltered_digits='pxd_unfiltered_digits',
50  doCleanup=True, overrideDB=False, usePXDDataReduction=True, save_slow_pions_in_mc=False):
51  """
52  This function adds the standard simulation modules to a path.
53  @param pxd_unfiltered_digits: the name of the StoreArray containing the input PXDDigits
54  @param overrideDB: override settings from the DB with the value set in 'usePXDDataReduction'
55  @param usePXDDataReduction: if 'overrideDB==True', override settings from the DB
56  @param doCleanup: if 'doCleanup=True' temporary datastore objects are emptied
57  @param save_slow_pions_in_mc: if True, additional Regions of Interest on the PXD are created to save the PXDDigits
58  of slow pions from D* -> D pi^{\\pm} decays using the MCSlowPionPXDROICreator based on MC truth information
59  """
60 
61  # SVD reconstruction
62  # svd_cluster = '__ROIsvdClusters'
63  add_svd_reconstruction(path, isROIsimulation=True)
64 
65  # SVD tracking
66  svd_reco_tracks = '__ROIsvdRecoTracks'
67 
68  add_tracking_for_PXDDataReduction_simulation(path, components, svd_cluster='__ROIsvdClusters')
69 
70  add_roiFinder(path, svd_reco_tracks)
71 
72  if save_slow_pions_in_mc:
73  path.add_module('MCSlowPionPXDROICreator', PXDDigitsName=pxd_unfiltered_digits, ROIsName='ROIs')
74 
75  # Filtering of PXDDigits
76  pxd_digifilter = b2.register_module('PXDdigiFilter')
77  pxd_digifilter.param('ROIidsName', 'ROIs')
78  pxd_digifilter.param('PXDDigitsName', pxd_unfiltered_digits)
79  pxd_digifilter.param('PXDDigitsInsideROIName', 'PXDDigits')
80  pxd_digifilter.param('overrideDB', overrideDB)
81  pxd_digifilter.param('usePXDDataReduction', usePXDDataReduction) # only used for overrideDB=True
82  path.add_module(pxd_digifilter)
83 
84  # empty the StoreArrays which were used for the PXDDatareduction as those are not needed anymore
85  if doCleanup:
86  datastore_cleaner = b2.register_module('PruneDataStore')
87  datastore_cleaner.param('keepMatchedEntries', False)
88  datastore_cleaner.param('matchEntries', ['ROIs', '__ROIsvdRecoDigits', '__ROIsvdClusters', '__ROIsvdRecoTracks',
89  'SPTrackCands__ROI', 'SpacePoints__ROI', pxd_unfiltered_digits,
90  # till here it are StoreArrays, the following are relations and Datastore objects
91  'SegmentNetwork__ROI', 'PXDInterceptsToROIs',
92  'RecoHitInformationsTo__ROIsvdClusters',
93  'SpacePoints__ROITo__ROIsvdClusters', '__ROIsvdClustersToMCParticles',
94  '__ROIsvdRecoDigitsToMCParticles',
95  '__ROIsvdClustersTo__ROIsvdRecoDigits', '__ROIsvdClustersToSVDTrueHits',
96  '__ROIsvdClustersTo__ROIsvdRecoTracks', '__ROIsvdRecoTracksToPXDIntercepts',
97  '__ROIsvdRecoTracksToRecoHitInformations',
98  '__ROIsvdRecoTracksToSPTrackCands__ROI',
99  # not only prune the pxd_unfiltered_digits, but also their relations to
100  # MCParticles, PXDDigits (the filtered ones), and PXDTrueHits
101  f'{pxd_unfiltered_digits}ToMCParticles',
102  f'{pxd_unfiltered_digits}ToPXDDigits',
103  f'{pxd_unfiltered_digits}ToPXDTrueHits'])
104  path.add_module(datastore_cleaner)
105 
106 
107 def add_simulation(
108  path,
109  components=None,
110  bkgfiles=None,
111  bkgOverlay=True,
112  forceSetPXDDataReduction=False,
113  usePXDDataReduction=True,
114  cleanupPXDDataReduction=True,
115  generate_2nd_cdc_hits=False,
116  simulateT0jitter=True,
117  isCosmics=False,
118  FilterEvents=False,
119  usePXDGatedMode=False,
120  skipExperimentCheckForBG=False,
121  save_slow_pions_in_mc=False):
122  """
123  This function adds the standard simulation modules to a path.
124  @param forceSetPXDDataReduction: override settings from the DB with the value set in 'usePXDDataReduction'
125  @param usePXDDataReduction: if 'forceSetPXDDataReduction==True', override settings from the DB
126  @param cleanupPXDDataReduction: if True the datastore objects used by PXDDataReduction are emptied
127  @param simulateT0jitter: if True simulate L1 trigger jitter
128  @param isCosmics: if True the filling pattern is removed from L1 jitter simulation
129  @param FilterEvents: if True only the events that pass the L1 trigger will survive simulation, the other are discarded.
130  Make sure you do need to filter events before you set the value to True.
131  @param skipExperimentCheckForBG: If True, skip the check on the experiment number consistency between the basf2
132  process and the beam background files. Note that this check should be skipped only by experts.
133  @param save_slow_pions_in_mc: if True, additional Regions of Interest on the PXD are created to save the PXDDigits
134  of slow pions from D* -> D pi^{\\pm} decays using the MCSlowPionPXDROICreator based on MC truth information
135  """
136 
137  # Check compoments.
138  check_components(components)
139 
140  # background mixing or overlay input before process forking
141  if bkgfiles is not None:
142  if bkgOverlay:
143  bkginput = b2.register_module('BGOverlayInput')
144  bkginput.param('inputFileNames', bkgfiles)
145  bkginput.param('skipExperimentCheck', skipExperimentCheckForBG)
146  path.add_module(bkginput)
147  else:
148  bkgmixer = b2.register_module('BeamBkgMixer')
149  bkgmixer.param('backgroundFiles', bkgfiles)
150  if components:
151  bkgmixer.param('components', components)
152  path.add_module(bkgmixer)
153  if usePXDGatedMode:
154  if components is None or 'PXD' in components:
155  # PXD is sensitive to hits in intervall -20us to +20us
156  bkgmixer.param('minTimePXD', -20000.0)
157  bkgmixer.param('maxTimePXD', 20000.0)
158  # Emulate injection vetos for PXD
159  pxd_veto_emulator = b2.register_module('PXDInjectionVetoEmulator')
160  path.add_module(pxd_veto_emulator)
161 
162  # geometry parameter database
163  if 'Gearbox' not in path:
164  gearbox = b2.register_module('Gearbox')
165  path.add_module(gearbox)
166 
167  # detector geometry
168  if 'Geometry' not in path:
169  path.add_module('Geometry', useDB=True)
170  if components is not None:
171  b2.B2WARNING("Custom detector components specified: Will still build full geometry")
172 
173  # event T0 jitter simulation
174  if simulateT0jitter and 'EventT0Generator' not in path:
175  eventt0 = b2.register_module('EventT0Generator')
176  eventt0.param("isCosmics", isCosmics)
177  path.add_module(eventt0)
178 
179  # create EventLevelTriggerTimeInfo if it doesn't exist in BG Overlay
180  if 'SimulateEventLevelTriggerTimeInfo' not in path:
181  eventleveltriggertimeinfo = b2.register_module('SimulateEventLevelTriggerTimeInfo')
182  path.add_module(eventleveltriggertimeinfo)
183 
184  # detector simulation
185  if 'FullSim' not in path:
186  g4sim = b2.register_module('FullSim')
187  path.add_module(g4sim)
188 
189  check_simulation(path)
190 
191  # no checks are performed for BeamBkgMixer and the Digitizers as they are
192  # not necessary for running simulation jobs and it should be possible to
193  # have them in the path more than once
194 
195  # CDC digitization
196  if components is None or 'CDC' in components:
197  cdc_digitizer = b2.register_module('CDCDigitizer')
198  cdc_digitizer.param("Output2ndHit", generate_2nd_cdc_hits)
199  path.add_module(cdc_digitizer)
200 
201  # TOP digitization
202  if components is None or 'TOP' in components:
203  top_digitizer = b2.register_module('TOPDigitizer')
204  path.add_module(top_digitizer)
205 
206  # ARICH digitization
207  if components is None or 'ARICH' in components:
208  arich_digitizer = b2.register_module('ARICHDigitizer')
209  path.add_module(arich_digitizer)
210 
211  # ECL digitization
212  if components is None or 'ECL' in components:
213  ecl_digitizer = b2.register_module('ECLDigitizer')
214  if bkgfiles is not None:
215  ecl_digitizer.param('Background', 1)
216  path.add_module(ecl_digitizer)
217 
218  # KLM digitization
219  if components is None or 'KLM' in components:
220  klm_digitizer = b2.register_module('KLMDigitizer')
221  path.add_module(klm_digitizer)
222 
223  # BG Overlay for CDC, TOP, ARICH and KLM (for ECL it's done in ECLDigitizer)
224  if bkgfiles is not None and bkgOverlay:
225  m = path.add_module('BGOverlayExecutor', components=['CDC', 'TOP', 'ARICH', 'KLM'])
226  m.set_name('BGOverlayExecutor_CDC...KLM')
227 
228  if components is None or 'TRG' in components:
229  add_trigger_simulation(path, simulateT0jitter=simulateT0jitter, FilterEvents=FilterEvents)
230 
231  # SVD digitization, BG Overlay, sorting and zero suppression
232  if components is None or 'SVD' in components:
233  add_svd_simulation(path)
234  if bkgfiles is not None and bkgOverlay:
235  m = path.add_module('BGOverlayExecutor', components=['SVD'])
236  m.set_name('BGOverlayExecutor_SVD')
237  path.add_module('SVDShaperDigitSorter')
238  path.add_module('SVDZeroSuppressionEmulator')
239 
240  # PXD digitization, BG overlay, sorting and data reduction
241  if components is None or 'PXD' in components:
242  if forceSetPXDDataReduction:
243  pxd_digits_name = ''
244  if usePXDDataReduction:
245  pxd_digits_name = 'pxd_unfiltered_digits'
246  add_pxd_simulation(path, digitsName=pxd_digits_name)
247  if bkgfiles is not None and bkgOverlay:
248  m = path.add_module('BGOverlayExecutor', components=['PXD'], PXDDigitsName=pxd_digits_name)
249  m.set_name('BGOverlayExecutor_PXD')
250  path.add_module('PXDDigitSorter', digits=pxd_digits_name)
251  if usePXDDataReduction:
252  add_PXDDataReduction(
253  path,
254  components,
255  pxd_digits_name,
256  doCleanup=cleanupPXDDataReduction,
257  overrideDB=forceSetPXDDataReduction,
258  usePXDDataReduction=usePXDDataReduction,
259  save_slow_pions_in_mc=save_slow_pions_in_mc)
260  else:
261  # use DB conditional module to decide whether ROI finding should be activated
262  path_disableROI_Sim = b2.create_path()
263  add_pxd_simulation(path_disableROI_Sim, digitsName='PXDDigits')
264  if bkgfiles is not None and bkgOverlay:
265  m = path_disableROI_Sim.add_module('BGOverlayExecutor', components=['PXD'], PXDDigitsName='PXDDigits')
266  m.set_name('BGOverlayExecutor_PXD')
267  path_disableROI_Sim.add_module('PXDDigitSorter', digits='PXDDigits')
268 
269  path_enableROI_Sim = b2.create_path()
270  add_pxd_simulation(path_enableROI_Sim, digitsName='pxd_unfiltered_digits')
271  if bkgfiles is not None and bkgOverlay:
272  m = path_enableROI_Sim.add_module('BGOverlayExecutor', components=['PXD'], PXDDigitsName='pxd_unfiltered_digits')
273  m.set_name('BGOverlayExecutor_PXD')
274  path_enableROI_Sim.add_module('PXDDigitSorter', digits='pxd_unfiltered_digits')
275  add_PXDDataReduction(
276  path_enableROI_Sim,
277  components,
278  pxd_unfiltered_digits='pxd_unfiltered_digits',
279  doCleanup=cleanupPXDDataReduction,
280  save_slow_pions_in_mc=save_slow_pions_in_mc)
281 
282  roi_condition_module_Sim = path.add_module('ROIfindingConditionFromDB')
283  roi_condition_module_Sim.if_true(path_enableROI_Sim, b2.AfterConditionPath.CONTINUE)
284  roi_condition_module_Sim.if_false(path_disableROI_Sim, b2.AfterConditionPath.CONTINUE)
285 
286  # statistics summary
287  path.add_module('StatisticsSummary').set_name('Sum_Simulation')