12from geometry
import check_components
13from L1trigger
import add_trigger_simulation
14from pxd
import add_pxd_simulation
15from svd
import add_svd_simulation
16from svd
import add_svd_reconstruction
17from tracking
import add_tracking_for_PXDDataReduction_simulation, add_roiFinder
20def check_simulation(path):
21 """Check if the minimum number of modules required for simulation are in
22 the path and in the correct order"""
23 required = ['Gearbox', 'Geometry', 'FullSim']
26 # make a list of all required modules in the path
27 for module in path.modules():
28 module_type = module.type()
29 # if required add to list of found modules
30 if module_type in required:
31 # unless it is already in there
32 if module_type in found:
33 b2.B2ERROR(f"Duplicate module in path: {module_type}")
35 found.append(module.type())
37 if len(required) != len(found):
38 # Apparently at least one module is missing
41 b2.B2ERROR(f"No '{r}' module found but needed for simulation")
42 # We have all modules but do they have the correct order?
43 elif required != found:
44 b2.B2ERROR(f"Simulation modules in wrong order. Should be '{', '.join(required)}' but is '{', '.join(found)}'")
47def add_PXDDataReduction(
50 pxd_unfiltered_digits='pxd_unfiltered_digits',
53 usePXDDataReduction=True,
54 save_slow_pions_in_mc=False,
55 save_all_charged_particles_in_mc=False):
57 This function adds the standard simulation modules to a path.
58 @param pxd_unfiltered_digits: the name of the StoreArray containing the input PXDDigits
59 @param overrideDB: override settings from the DB with the value set in 'usePXDDataReduction'
60 @param usePXDDataReduction: if 'overrideDB==True', override settings from the DB
61 @param doCleanup: if 'doCleanup=True' temporary datastore objects are emptied
62 @param save_slow_pions_in_mc: if True, additional Regions of Interest on the PXD are created to save the PXDDigits
63 of slow pions from D* -> D pi^{\\pm} decays using the MCSlowPionPXDROICreator based on MC truth information
67 # svd_cluster = '__ROIsvdClusters'
68 add_svd_reconstruction(path, isROIsimulation=True)
71 svd_reco_tracks = '__ROIsvdRecoTracks'
73 add_tracking_for_PXDDataReduction_simulation(path, components, svd_cluster='__ROIsvdClusters')
75 add_roiFinder(path, svd_reco_tracks)
77 if save_slow_pions_in_mc or save_all_charged_particles_in_mc:
78 path.add_module('MCPXDROICreator',
79 PXDDigitsName=pxd_unfiltered_digits,
81 createROIForSlowPionsOnly=save_slow_pions_in_mc,
82 createROIForAll=save_all_charged_particles_in_mc)
84 # Filtering of PXDDigits
85 pxd_digifilter = b2.register_module('PXDdigiFilter')
86 pxd_digifilter.param('ROIidsName', 'ROIs')
87 pxd_digifilter.param('PXDDigitsName', pxd_unfiltered_digits)
88 pxd_digifilter.param('PXDDigitsInsideROIName', 'PXDDigits')
89 pxd_digifilter.param('overrideDB', overrideDB)
90 pxd_digifilter.param('usePXDDataReduction', usePXDDataReduction) # only used for overrideDB=True
91 path.add_module(pxd_digifilter)
93 # empty the StoreArrays which were used for the PXDDatareduction as those are not needed anymore
95 StoreArrays_to_clean = ['ROIs', '__ROIsvdRecoDigits', '__ROIsvdClusters', '__ROIsvdRecoTracks',
96 'SPTrackCands__ROI', 'SpacePoints__ROI',
97 # till here it are StoreArrays, the following are relations and Datastore objects
98 'SegmentNetwork__ROI', 'PXDInterceptsToROIs',
99 'RecoHitInformationsTo__ROIsvdClusters',
100 'SpacePoints__ROITo__ROIsvdClusters', '__ROIsvdClustersToMCParticles',
101 '__ROIsvdRecoDigitsToMCParticles',
102 '__ROIsvdClustersTo__ROIsvdRecoDigits', '__ROIsvdClustersToSVDTrueHits',
103 '__ROIsvdClustersTo__ROIsvdRecoTracks', '__ROIsvdRecoTracksToPXDIntercepts',
104 '__ROIsvdRecoTracksToRecoHitInformations',
105 '__ROIsvdRecoTracksToSPTrackCands__ROI']
107 # not only prune the pxd_unfiltered_digits, but also their relations to
108 # MCParticles, PXDDigits (the filtered ones), and PXDTrueHits
109 # Only prune the unfiltered PXD if their name is not 'PXDDigits', otherwise all PXDDigits would be lost
110 if pxd_unfiltered_digits != 'PXDDigits':
111 unfiltered_pxd_digits_arrays = [pxd_unfiltered_digits,
112 f'{pxd_unfiltered_digits}ToMCParticles',
113 f'{pxd_unfiltered_digits}ToPXDDigits',
114 f'{pxd_unfiltered_digits}ToPXDTrueHits']
115 StoreArrays_to_clean += unfiltered_pxd_digits_arrays
117 datastore_cleaner = b2.register_module('PruneDataStore')
118 datastore_cleaner.param('keepMatchedEntries', False)
119 datastore_cleaner.param('matchEntries', StoreArrays_to_clean)
120 path.add_module(datastore_cleaner)
128 forceSetPXDDataReduction=False,
129 usePXDDataReduction=True,
130 cleanupPXDDataReduction=True,
131 generate_2nd_cdc_hits=False,
132 simulateT0jitter=True,
135 usePXDGatedMode=False,
136 skipExperimentCheckForBG=False,
137 save_slow_pions_in_mc=False,
138 save_all_charged_particles_in_mc=False):
140 This function adds the standard simulation modules to a path.
141 @param forceSetPXDDataReduction: override settings from the DB with the value set in 'usePXDDataReduction'
142 @param usePXDDataReduction: if 'forceSetPXDDataReduction==True', override settings from the DB
143 @param cleanupPXDDataReduction: if True the datastore objects used by PXDDataReduction are emptied
144 @param simulateT0jitter: if True simulate L1 trigger jitter
145 @param isCosmics: if True the filling pattern is removed from L1 jitter simulation
146 @param FilterEvents: if True only the events that pass the L1 trigger will survive simulation, the other are discarded.
147 Make sure you do need to filter events before you set the value to True.
148 @param skipExperimentCheckForBG: If True, skip the check on the experiment number consistency between the basf2
149 process and the beam background files. Note that this check should be skipped only by experts.
150 @param save_slow_pions_in_mc: if True, additional Regions of Interest on the PXD are created to save the PXDDigits
151 of slow pions from D* -> D pi^{\\pm} decays using the MCSlowPionPXDROICreator based on MC truth information
152 @param save_all_charged_particles_in_mc: if True, additional Regions of Interest on the PXD are created to save the PXDDigits
153 of all charged primary MCParticles that traverse PXD
156 path.add_module('StatisticsSummary').set_name('Sum_PreSimulation')
159 check_components(components)
161 # background mixing or overlay input before process forking
162 if bkgfiles is not None:
164 bkginput = b2.register_module('BGOverlayInput')
165 bkginput.param('inputFileNames', bkgfiles)
166 bkginput.param('skipExperimentCheck', skipExperimentCheckForBG)
167 path.add_module(bkginput)
169 bkgmixer = b2.register_module('BeamBkgMixer')
170 bkgmixer.param('backgroundFiles', bkgfiles)
172 bkgmixer.param('components', components)
173 path.add_module(bkgmixer)
175 if components is None or 'PXD' in components:
176 # PXD is sensitive to hits in intervall -20us to +20us
177 bkgmixer.param('minTimePXD', -20000.0)
178 bkgmixer.param('maxTimePXD', 20000.0)
179 # Emulate injection vetos for PXD
180 pxd_veto_emulator = b2.register_module('PXDInjectionVetoEmulator')
181 path.add_module(pxd_veto_emulator)
183 # geometry parameter database
184 if 'Gearbox' not in path:
185 gearbox = b2.register_module('Gearbox')
186 path.add_module(gearbox)
189 if 'Geometry' not in path:
190 path.add_module('Geometry', useDB=True)
191 if components is not None:
192 b2.B2WARNING("Custom detector components specified: Will still build full geometry")
194 # event T0 jitter simulation
195 if simulateT0jitter and 'EventT0Generator' not in path:
196 eventt0 = b2.register_module('EventT0Generator')
197 eventt0.param("isCosmics", isCosmics)
198 path.add_module(eventt0)
200 # create EventLevelTriggerTimeInfo if it doesn't exist in BG Overlay
201 if 'SimulateEventLevelTriggerTimeInfo' not in path:
202 eventleveltriggertimeinfo = b2.register_module('SimulateEventLevelTriggerTimeInfo')
203 path.add_module(eventleveltriggertimeinfo)
205 # detector simulation
206 if 'FullSim' not in path:
207 g4sim = b2.register_module('FullSim')
208 path.add_module(g4sim)
210 check_simulation(path)
212 # no checks are performed for BeamBkgMixer and the Digitizers as they are
213 # not necessary for running simulation jobs and it should be possible to
214 # have them in the path more than once
217 if components is None or 'CDC' in components:
218 cdc_digitizer = b2.register_module('CDCDigitizer')
219 cdc_digitizer.param("Output2ndHit", generate_2nd_cdc_hits)
220 path.add_module(cdc_digitizer)
223 if components is None or 'TOP' in components:
224 top_digitizer = b2.register_module('TOPDigitizer')
225 path.add_module(top_digitizer)
228 if components is None or 'ARICH' in components:
229 arich_digitizer = b2.register_module('ARICHDigitizer')
230 path.add_module(arich_digitizer)
233 if components is None or 'ECL' in components:
234 ecl_digitizer = b2.register_module('ECLDigitizer')
235 if bkgfiles is not None:
236 ecl_digitizer.param('Background', 1)
237 path.add_module(ecl_digitizer)
240 if components is None or 'KLM' in components:
241 klm_digitizer = b2.register_module('KLMDigitizer')
242 path.add_module(klm_digitizer)
244 # BG Overlay for CDC, TOP, ARICH and KLM (for ECL it's done in ECLDigitizer)
245 if bkgfiles is not None and bkgOverlay:
246 m = path.add_module('BGOverlayExecutor', components=['CDC', 'TOP', 'ARICH', 'KLM'])
247 m.set_name('BGOverlayExecutor_CDC...KLM')
249 if components is None or 'TRG' in components:
250 if bkgfiles is not None and bkgOverlay:
251 # BG Overlay for CDCTRG. That for KLMTRG is already covered by BG Overlay
252 # for KLM. ECL and ECLTRG are already covered independently.
253 m = path.add_module('BGOverlayExecutor', components=['CDC'], CDCHitsName='CDCHits4Trg')
254 m.set_name('BGOverlayExecutor_TRGCDC')
255 add_trigger_simulation(path, simulateT0jitter=simulateT0jitter, FilterEvents=FilterEvents)
257 # SVD digitization, BG Overlay, sorting and zero suppression
258 if components is None or 'SVD' in components:
259 add_svd_simulation(path)
260 if bkgfiles is not None and bkgOverlay:
261 m = path.add_module('BGOverlayExecutor', components=['SVD'])
262 m.set_name('BGOverlayExecutor_SVD')
263 path.add_module('SVDShaperDigitSorter')
264 path.add_module('SVDZeroSuppressionEmulator')
266 # PXD digitization, BG overlay, sorting and data reduction
267 if components is None or 'PXD' in components:
268 if forceSetPXDDataReduction:
270 if usePXDDataReduction:
271 pxd_digits_name = 'pxd_unfiltered_digits'
272 add_pxd_simulation(path, digitsName=pxd_digits_name)
273 if bkgfiles is not None and bkgOverlay:
274 m = path.add_module('BGOverlayExecutor', components=['PXD'], PXDDigitsName=pxd_digits_name)
275 m.set_name('BGOverlayExecutor_PXD')
276 path.add_module('PXDDigitSorter', digits=pxd_digits_name)
277 if usePXDDataReduction:
278 add_PXDDataReduction(
282 doCleanup=cleanupPXDDataReduction,
283 overrideDB=forceSetPXDDataReduction,
284 usePXDDataReduction=usePXDDataReduction,
285 save_slow_pions_in_mc=save_slow_pions_in_mc,
286 save_all_charged_particles_in_mc=save_all_charged_particles_in_mc)
288 # use DB conditional module to decide whether ROI finding should be activated
289 path_disableROI_Sim = b2.create_path()
290 add_pxd_simulation(path_disableROI_Sim, digitsName='PXDDigits')
291 if bkgfiles is not None and bkgOverlay:
292 m = path_disableROI_Sim.add_module('BGOverlayExecutor', components=['PXD'], PXDDigitsName='PXDDigits')
293 m.set_name('BGOverlayExecutor_PXD')
294 path_disableROI_Sim.add_module('PXDDigitSorter', digits='PXDDigits')
296 path_enableROI_Sim = b2.create_path()
297 add_pxd_simulation(path_enableROI_Sim, digitsName='pxd_unfiltered_digits')
298 if bkgfiles is not None and bkgOverlay:
299 m = path_enableROI_Sim.add_module('BGOverlayExecutor', components=['PXD'], PXDDigitsName='pxd_unfiltered_digits')
300 m.set_name('BGOverlayExecutor_PXD')
301 path_enableROI_Sim.add_module('PXDDigitSorter', digits='pxd_unfiltered_digits')
302 add_PXDDataReduction(
305 pxd_unfiltered_digits='pxd_unfiltered_digits',
306 doCleanup=cleanupPXDDataReduction,
307 save_slow_pions_in_mc=save_slow_pions_in_mc,
308 save_all_charged_particles_in_mc=save_all_charged_particles_in_mc)
310 roi_condition_module_Sim = path.add_module('ROIfindingConditionFromDB')
311 roi_condition_module_Sim.if_true(path_enableROI_Sim, b2.AfterConditionPath.CONTINUE)
312 roi_condition_module_Sim.if_false(path_disableROI_Sim, b2.AfterConditionPath.CONTINUE)
315 path.add_module('StatisticsSummary').set_name('Sum_Simulation')