Belle II Software  release-06-02-00
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
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):
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  """
58 
59  # SVD reconstruction
60  # svd_cluster = '__ROIsvdClusters'
61  add_svd_reconstruction(path, isROIsimulation=True)
62 
63  # SVD tracking
64  svd_reco_tracks = '__ROIsvdRecoTracks'
65 
66  add_tracking_for_PXDDataReduction_simulation(path, components, svd_cluster='__ROIsvdClusters')
67 
68  add_roiFinder(path, svd_reco_tracks)
69 
70  # Filtering of PXDDigits
71  pxd_digifilter = b2.register_module('PXDdigiFilter')
72  pxd_digifilter.param('ROIidsName', 'ROIs')
73  pxd_digifilter.param('PXDDigitsName', pxd_unfiltered_digits)
74  pxd_digifilter.param('PXDDigitsInsideROIName', 'PXDDigits')
75  pxd_digifilter.param('overrideDB', overrideDB)
76  pxd_digifilter.param('usePXDDataReduction', usePXDDataReduction) # only used for overrideDB=True
77  path.add_module(pxd_digifilter)
78 
79  # empty the StoreArrays which were used for the PXDDatareduction as those are not needed anymore
80  if doCleanup:
81  datastore_cleaner = b2.register_module('PruneDataStore')
82  datastore_cleaner.param('keepMatchedEntries', False)
83  datastore_cleaner.param('matchEntries', ['ROIs', '__ROIsvdRecoDigits', '__ROIsvdClusters', '__ROIsvdRecoTracks',
84  'SPTrackCands__ROI', 'SpacePoints__ROI', pxd_unfiltered_digits,
85  # till here it are StoreArrays, the following are relations and Datastore objects
86  'SegmentNetwork__ROI', 'PXDInterceptsToROIs',
87  'RecoHitInformationsTo__ROIsvdClusters',
88  'SpacePoints__ROITo__ROIsvdClusters', '__ROIsvdClustersToMCParticles',
89  '__ROIsvdRecoDigitsToMCParticles',
90  '__ROIsvdClustersTo__ROIsvdRecoDigits', '__ROIsvdClustersToSVDTrueHits',
91  '__ROIsvdClustersTo__ROIsvdRecoTracks', '__ROIsvdRecoTracksToPXDIntercepts',
92  '__ROIsvdRecoTracksToRecoHitInformations',
93  '__ROIsvdRecoTracksToSPTrackCands__ROI'])
94  path.add_module(datastore_cleaner)
95 
96 
97 def add_roiFinder(path, reco_tracks):
98  """
99  Add the ROI finding to the path creating ROIs out of reco tracks by extrapolating them to the PXD volume.
100  :param path: Where to add the module to.
101  :param reco_tracks: Which tracks to use in the extrapolation step.
102  """
103 
104  pxdDataRed = b2.register_module('PXDROIFinder')
105  param_pxdDataRed = {
106  'recoTrackListName': reco_tracks,
107  'PXDInterceptListName': 'PXDIntercepts',
108  'ROIListName': 'ROIs',
109  'tolerancePhi': 0.15,
110  'toleranceZ': 0.5,
111  'sigmaSystU': 0.02,
112  'sigmaSystV': 0.02,
113  'numSigmaTotU': 10,
114  'numSigmaTotV': 10,
115  'maxWidthU': 0.5,
116  'maxWidthV': 0.5,
117  }
118  pxdDataRed.param(param_pxdDataRed)
119  path.add_module(pxdDataRed)
120 
121 
122 def add_simulation(
123  path,
124  components=None,
125  bkgfiles=None,
126  bkgOverlay=True,
127  forceSetPXDDataReduction=False,
128  usePXDDataReduction=True,
129  cleanupPXDDataReduction=True,
130  generate_2nd_cdc_hits=False,
131  simulateT0jitter=True,
132  isCosmics=False,
133  FilterEvents=False,
134  usePXDGatedMode=False,
135  skipExperimentCheckForBG=False):
136  """
137  This function adds the standard simulation modules to a path.
138  @param forceSetPXDDataReduction: override settings from the DB with the value set in 'usePXDDataReduction'
139  @param usePXDDataReduction: if 'forceSetPXDDataReduction==True', override settings from the DB
140  @param cleanupPXDDataReduction: if True the datastore objects used by PXDDataReduction are emptied
141  @param simulateT0jitter: if True simulate L1 trigger jitter
142  @param isCosmics: if True the filling pattern is removed from L1 jitter simulation
143  @param FilterEvents: if True only the events that pass the L1 trigger will survive simulation, the other are discarded.
144  Make sure you do need to filter events before you set the value to True.
145  @param skipExperimentCheckForBG: If True, skip the check on the experiment number consistency between the basf2
146  process and the beam background files. Note that this check should be skipped only by experts.
147  """
148 
149  # Check compoments.
150  check_components(components)
151 
152  # background mixing or overlay input before process forking
153  if bkgfiles is not None:
154  if bkgOverlay:
155  bkginput = b2.register_module('BGOverlayInput')
156  bkginput.param('inputFileNames', bkgfiles)
157  bkginput.param('skipExperimentCheck', skipExperimentCheckForBG)
158  path.add_module(bkginput)
159  else:
160  bkgmixer = b2.register_module('BeamBkgMixer')
161  bkgmixer.param('backgroundFiles', bkgfiles)
162  if components:
163  bkgmixer.param('components', components)
164  path.add_module(bkgmixer)
165  if usePXDGatedMode:
166  if components is None or 'PXD' in components:
167  # PXD is sensitive to hits in intervall -20us to +20us
168  bkgmixer.param('minTimePXD', -20000.0)
169  bkgmixer.param('maxTimePXD', 20000.0)
170  # Emulate injection vetos for PXD
171  pxd_veto_emulator = b2.register_module('PXDInjectionVetoEmulator')
172  path.add_module(pxd_veto_emulator)
173 
174  # geometry parameter database
175  if 'Gearbox' not in path:
176  gearbox = b2.register_module('Gearbox')
177  path.add_module(gearbox)
178 
179  # detector geometry
180  if 'Geometry' not in path:
181  path.add_module('Geometry', useDB=True)
182  if components is not None:
183  b2.B2WARNING("Custom detector components specified: Will still build full geometry")
184 
185  # event T0 jitter simulation
186  if simulateT0jitter and 'EventT0Generator' not in path:
187  eventt0 = b2.register_module('EventT0Generator')
188  eventt0.param("isCosmics", isCosmics)
189  path.add_module(eventt0)
190 
191  # create EventLevelTriggerTimeInfo if it doesn't exist in BG Overlay
192  if 'SimulateEventLevelTriggerTimeInfo' not in path:
193  eventleveltriggertimeinfo = b2.register_module('SimulateEventLevelTriggerTimeInfo')
194  path.add_module(eventleveltriggertimeinfo)
195 
196  # detector simulation
197  if 'FullSim' not in path:
198  g4sim = b2.register_module('FullSim')
199  path.add_module(g4sim)
200 
201  check_simulation(path)
202 
203  # no checks are performed for BeamBkgMixer and the Digitizers as they are
204  # not necessary for running simulation jobs and it should be possible to
205  # have them in the path more than once
206 
207  # CDC digitization
208  if components is None or 'CDC' in components:
209  cdc_digitizer = b2.register_module('CDCDigitizer')
210  cdc_digitizer.param("Output2ndHit", generate_2nd_cdc_hits)
211  path.add_module(cdc_digitizer)
212 
213  # TOP digitization
214  if components is None or 'TOP' in components:
215  top_digitizer = b2.register_module('TOPDigitizer')
216  path.add_module(top_digitizer)
217 
218  # ARICH digitization
219  if components is None or 'ARICH' in components:
220  arich_digitizer = b2.register_module('ARICHDigitizer')
221  path.add_module(arich_digitizer)
222 
223  # ECL digitization
224  if components is None or 'ECL' in components:
225  ecl_digitizer = b2.register_module('ECLDigitizer')
226  if bkgfiles is not None:
227  ecl_digitizer.param('Background', 1)
228  path.add_module(ecl_digitizer)
229 
230  # KLM digitization
231  if components is None or 'KLM' in components:
232  klm_digitizer = b2.register_module('KLMDigitizer')
233  path.add_module(klm_digitizer)
234 
235  # BG Overlay for CDC, TOP, ARICH and KLM (for ECL it's done in ECLDigitizer)
236  if bkgfiles is not None and bkgOverlay:
237  m = path.add_module('BGOverlayExecutor', components=['CDC', 'TOP', 'ARICH', 'KLM'])
238  m.set_name('BGOverlayExecutor_CDC...KLM')
239 
240  if components is None or 'TRG' in components:
241  add_trigger_simulation(path, simulateT0jitter=simulateT0jitter, FilterEvents=FilterEvents)
242 
243  # SVD digitization, BG Overlay, sorting and zero suppression
244  if components is None or 'SVD' in components:
245  add_svd_simulation(path)
246  if bkgfiles is not None and bkgOverlay:
247  m = path.add_module('BGOverlayExecutor', components=['SVD'])
248  m.set_name('BGOverlayExecutor_SVD')
249  path.add_module('SVDShaperDigitSorter')
250  path.add_module('SVDZeroSuppressionEmulator')
251 
252  # PXD digitization, BG overlay, sorting and data reduction
253  if components is None or 'PXD' in components:
254  if forceSetPXDDataReduction:
255  pxd_digits_name = ''
256  if usePXDDataReduction:
257  pxd_digits_name = 'pxd_unfiltered_digits'
258  add_pxd_simulation(path, digitsName=pxd_digits_name)
259  if bkgfiles is not None and bkgOverlay:
260  m = path.add_module('BGOverlayExecutor', components=['PXD'], PXDDigitsName=pxd_digits_name)
261  m.set_name('BGOverlayExecutor_PXD')
262  path.add_module('PXDDigitSorter', digits=pxd_digits_name)
263  if usePXDDataReduction:
264  add_PXDDataReduction(path, components, pxd_digits_name, doCleanup=cleanupPXDDataReduction,
265  overrideDB=forceSetPXDDataReduction, usePXDDataReduction=usePXDDataReduction)
266  else:
267  # use DB conditional module to decide whether ROI finding should be activated
268  path_disableROI_Sim = b2.create_path()
269  add_pxd_simulation(path_disableROI_Sim, digitsName='PXDDigits')
270  if bkgfiles is not None and bkgOverlay:
271  m = path_disableROI_Sim.add_module('BGOverlayExecutor', components=['PXD'], PXDDigitsName='PXDDigits')
272  m.set_name('BGOverlayExecutor_PXD')
273  path_disableROI_Sim.add_module('PXDDigitSorter', digits='PXDDigits')
274 
275  path_enableROI_Sim = b2.create_path()
276  add_pxd_simulation(path_enableROI_Sim, digitsName='pxd_unfiltered_digits')
277  if bkgfiles is not None and bkgOverlay:
278  m = path_enableROI_Sim.add_module('BGOverlayExecutor', components=['PXD'], PXDDigitsName='pxd_unfiltered_digits')
279  m.set_name('BGOverlayExecutor_PXD')
280  path_enableROI_Sim.add_module('PXDDigitSorter', digits='pxd_unfiltered_digits')
281  add_PXDDataReduction(
282  path_enableROI_Sim,
283  components,
284  pxd_unfiltered_digits='pxd_unfiltered_digits',
285  doCleanup=cleanupPXDDataReduction)
286 
287  roi_condition_module_Sim = path.add_module('ROIfindingConditionFromDB')
288  roi_condition_module_Sim.if_true(path_enableROI_Sim, b2.AfterConditionPath.CONTINUE)
289  roi_condition_module_Sim.if_false(path_disableROI_Sim, b2.AfterConditionPath.CONTINUE)
290 
291  # statistics summary
292  path.add_module('StatisticsSummary').set_name('Sum_Simulation')