BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSSDManager.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) Royal Holloway,
3University of London 2001 - 2023.
4
5This file is part of BDSIM.
6
7BDSIM is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published
9by the Free Software Foundation version 3 of the License.
10
11BDSIM is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
18*/
19#include "BDSDebug.hh"
20#include "BDSException.hh"
21#include "BDSGlobalConstants.hh"
22#include "BDSMultiSensitiveDetectorOrdered.hh"
23#include "BDSSensitiveDetector.hh" // for inheritance
24#include "BDSSDApertureImpacts.hh"
25#include "BDSSDCollimator.hh"
26#include "BDSSDEnergyDeposition.hh"
27#include "BDSSDEnergyDepositionGlobal.hh"
28#include "BDSSDFilterIon.hh"
29#include "BDSSDFilterOr.hh"
30#include "BDSSDFilterPDGIDSet.hh"
31#include "BDSSDFilterPrimary.hh"
32#include "BDSSDManager.hh"
33#include "BDSSDSampler.hh"
34#include "BDSSDSamplerCylinder.hh"
35#include "BDSSDSamplerSphere.hh"
36#include "BDSSDSamplerLink.hh"
37#include "BDSSDThinThing.hh"
38#include "BDSSDType.hh"
39#include "BDSSDTerminator.hh"
40#include "BDSSDVolumeExit.hh"
41
42#include "G4SDKineticEnergyFilter.hh"
43#include "G4SDManager.hh"
44#include "G4Version.hh"
45
46#if G4VERSION_NUMBER > 1029
47#include "G4MultiSensitiveDetector.hh"
48#endif
49
50#include <map>
51#include <string>
52#include <vector>
53
54class BDSLinkRegistry;
55
56BDSSDManager* BDSSDManager::instance = nullptr;
57
58BDSSDManager* BDSSDManager::Instance()
59{
60 if (!instance)
61 {instance = new BDSSDManager();}
62 return instance;
63}
64
65BDSSDManager::~BDSSDManager()
66{
67 // no need to delete SDs as they are all registered in G4SDManager
68 instance = nullptr;
69
70 for (auto& kv : filters)
71 {delete kv.second;}
72 for (auto& kv : extraSamplerFilters)
73 {delete kv.second;}
74}
75
77{
79 storeCollimatorHitsAll = g->StoreCollimatorHitsAll();
80 storeCollimatorHitsIons = g->StoreCollimatorHitsIons();
81 collimatorHitsMinimumKE = g->CollimatorHitsMinimumKE();
82 generateApertureImpacts = g->StoreApertureImpacts() || g->StoreApertureImpactsHistograms();
83 storeApertureImpactsAll = g->StoreApertureImpactsAll();
84 storeApertureImpactsIons = g->StoreApertureImpactsIons();
85 apertureImpactsMinimumKE = g->ApertureImpactsMinimumKE();
86 generateELossHits = g->StoreELoss() || g->StoreELossHistograms();
87 generateELossVacuumHits = g->StoreELossVacuum() || g->StoreELossVacuumHistograms();
88 generateELossTunnelHits = g->StoreELossTunnel() || g->StoreELossTunnelHistograms();
89
90 G4bool killedParticleMassAddedToEloss = g->KilledParticlesMassAddedToEloss();
91
92 generateELossWorldContents = g->UseImportanceSampling() || g->StoreELossWorldContents() || g->StoreELossWorldContentsIntegral();
93
94 storeELossWorld = g->StoreELossWorld() || g->StoreELossWorldIntegral();
95 storeELossExtras = g->StoreELossTurn()
96 || g->StoreELossLinks()
97 || g->StoreELossLocal()
98 || g->StoreELossGlobal()
99 || g->StoreELossTime()
100 || g->StoreELossStepLength()
101 || g->StoreELossPreStepKineticEnergy()
102 || g->StoreELossModelID()
103 || g->StoreTrajectory() // if we store trajectories, we need the edep track id
104 || g->StoreELossPhysicsProcesses();
107 || g->StoreCollimatorInfo()
108 || g->StoreCollimatorHits()
109 || g->StoreCollimatorHitsLinks();
110
111 filters["primary"] = new BDSSDFilterPrimary("primary");
112 filters["ion"] = new BDSSDFilterIon("ion");
113 BDSSDFilterOr* primaryOrIon = new BDSSDFilterOr("primary_or_ion");
114 primaryOrIon->RegisterFilter(filters["primary"]);
115 primaryOrIon->RegisterFilter(filters["ion"]);
116 filters["primary_or_ion"] = primaryOrIon;
117
118 // aperture impact specifc filters
119 filters["aper_min_ke"] = new G4SDKineticEnergyFilter("aper_min_ke", apertureImpactsMinimumKE);
120 BDSSDFilterOr* primaryIonAperMinKE = new BDSSDFilterOr("primary_or_ion_aper_min_ke");
121 primaryIonAperMinKE->RegisterFilter(filters["primary_or_ion"]);
122 primaryIonAperMinKE->RegisterFilter(filters["aper_min_ke"]);
123 filters["primary_or_ion_aper_min_ke"] = primaryIonAperMinKE;
124 BDSSDFilterOr* primaryAperMinKE = new BDSSDFilterOr("primary_aper_min_ke");
125 primaryAperMinKE->RegisterFilter(filters["primary"]);
126 primaryAperMinKE->RegisterFilter(filters["aper_min_ke"]);
127
128 // collimator impact specific filters
129 filters["coll_min_ke"] = new G4SDKineticEnergyFilter("coll_min_ke", collimatorHitsMinimumKE);
130 BDSSDFilterOr* primaryIonCollMinKE = new BDSSDFilterOr("primary_or_ion_coll_min_ke");
131 primaryIonCollMinKE->RegisterFilter(filters["primary_or_ion"]);
132 primaryIonCollMinKE->RegisterFilter(filters["coll_min_ke"]);
133 filters["primary_or_ion_coll_min_ke"] = primaryIonCollMinKE;
134 BDSSDFilterOr* primaryCollMinKE = new BDSSDFilterOr("primary_coll_min_ke");
135 primaryCollMinKE->RegisterFilter(filters["primary"]);
136 primaryCollMinKE->RegisterFilter(filters["coll_min_ke"]);
137
138 G4SDManager* SDMan = G4SDManager::GetSDMpointer();
139
140 samplerPlane = new BDSSDSampler("plane");
141 SDMan->AddNewDetector(samplerPlane);
142
143 samplerCylinder = new BDSSDSamplerCylinder("cylinder");
144 SDMan->AddNewDetector(samplerCylinder);
145
146 samplerSphere = new BDSSDSamplerSphere("sphere");
147 SDMan->AddNewDetector(samplerSphere);
148
149 samplerLink = new BDSSDSamplerLink("link");
150 SDMan->AddNewDetector(samplerLink);
151
152 // Terminator sd to measure how many times that primary has passed through the terminator
153 terminator = new BDSSDTerminator("terminator");
154 SDMan->AddNewDetector(terminator);
155
156 energyDeposition = new BDSSDEnergyDeposition("general", storeELossExtras, killedParticleMassAddedToEloss);
157 SDMan->AddNewDetector(energyDeposition);
158
159 energyDepositionFull = new BDSSDEnergyDeposition("general_full", true, killedParticleMassAddedToEloss);
160 SDMan->AddNewDetector(energyDepositionFull);
161
162 energyDepositionVacuum = new BDSSDEnergyDeposition("vacuum", storeELossExtras, killedParticleMassAddedToEloss);
163 SDMan->AddNewDetector(energyDepositionVacuum);
164
165 energyDepositionTunnel = new BDSSDEnergyDeposition("tunnel", storeELossExtras, killedParticleMassAddedToEloss);
166 SDMan->AddNewDetector(energyDepositionTunnel);
167
168 energyDepositionWorld = new BDSSDEnergyDepositionGlobal("worldLoss", killedParticleMassAddedToEloss);
169 SDMan->AddNewDetector(energyDepositionWorld);
170
171 energyDepositionWorldContents = new BDSSDEnergyDepositionGlobal("worldLoss_contents", killedParticleMassAddedToEloss);
172 SDMan->AddNewDetector(energyDepositionWorldContents);
173
174 worldExit = new BDSSDVolumeExit("worldExit", true);
175 SDMan->AddNewDetector(worldExit);
176
177 apertureImpacts = new BDSSDApertureImpacts("aperture");
178 // set up a filter for the collimator sensitive detector - always store primary hits
179 G4VSDFilter* filterA = nullptr;
180 G4bool applyApertureImpactsKEFilter = apertureImpactsMinimumKE > 0;
181 if (storeApertureImpactsAll && applyApertureImpactsKEFilter)
182 {filterA = filters["aper_min_ke"];}
184 {filterA = nullptr;} // no filter -> store all
185 else if (storeApertureImpactsIons && applyApertureImpactsKEFilter) // primaries plus ion fragments
186 {filterA = filters["primary_or_ion_aper_min_ke"];}
188 {filterA = filters["primary_or_ion"];}
189 else if (applyApertureImpactsKEFilter)
190 {filterA = filters["primary_aper_min_ke"];} // primaries + KE filter
191 else
192 {filterA = filters["primary"];} // just primaries
193 apertureImpacts->SetFilter(filterA);
194 SDMan->AddNewDetector(apertureImpacts);
195
196#if G4VERSION_NUMBER > 1029
197 // only multiple SDs since 10.3
198 G4MultiSensitiveDetector* wcsd = new G4MultiSensitiveDetector("world_complete");
199 SDMan->AddNewDetector(wcsd);
200 wcsd->AddSD(energyDepositionWorld);
201 wcsd->AddSD(worldExit);
202 worldCompleteSD = wcsd;
203
204 G4MultiSensitiveDetector* acsd = new G4MultiSensitiveDetector("aperture_complete");
205 SDMan->AddNewDetector(acsd);
206 acsd->AddSD(energyDeposition);
207 acsd->AddSD(apertureImpacts);
208 apertureCompleteSD = acsd;
209#endif
210
211 collimatorSD = new BDSSDCollimator("collimator");
212 collimatorCompleteSD = new BDSMultiSensitiveDetectorOrdered("collimator_complete");
213 collimatorCompleteSD->AddSD(energyDepositionFull); // always generate full edep hits
214 collimatorCompleteSD->AddSD(collimatorSD);
215 // set up a filter for the collimator sensitive detector - always store primary hits
216 G4VSDFilter* filter = nullptr;
217 G4bool applyCollimatorHitsKEFilter = collimatorHitsMinimumKE > 0;
218 if (storeCollimatorHitsAll && applyCollimatorHitsKEFilter)
219 {filter = filters["coll_min_ke"];}
220 else if (storeCollimatorHitsAll)
221 {filter = nullptr;} // no filter -> store all
222 else if (storeCollimatorHitsIons && applyCollimatorHitsKEFilter) // primaries plus ion fragments
223 {filter = filters["primary_or_ion_coll_min_ke"];}
225 {filter = filters["primary_or_ion"];}
226 else if (applyCollimatorHitsKEFilter)
227 {filter = filters["primary_coll_min_ke"];} // primaries + KE filter
228 else
229 {filter = filters["primary"];} // just primaries
230
231 // we only want to attach the filter to the collimator SD and not the energy counter SD
232 // via the 'complete' SD. i.e. we always want energy deposition but collimator hits by
233 // the filter.
234 collimatorSD->SetFilter(filter);
235 SDMan->AddNewDetector(collimatorSD);
236 SDMan->AddNewDetector(collimatorCompleteSD);
237
238 // thin things
239 thinThingSD = new BDSSDThinThing("thinthing_general", g->StoreTrajectoryOptions());
240 thinThingSD->SetFilter(filters["primary"]);
241 SDMan->AddNewDetector(thinThingSD);
242
243 // wire scanner wires SD
244 wireCompleteSD = new BDSMultiSensitiveDetectorOrdered("wire_complete");
245 wireCompleteSD->AddSD(energyDepositionFull);
246 wireCompleteSD->AddSD(thinThingSD);
247}
248
249G4VSensitiveDetector* BDSSDManager::SensitiveDetector(const BDSSDType sdType,
250 G4bool applyOptions) const
251{
252 G4VSensitiveDetector* result = nullptr;
253 switch (sdType.underlying())
254 {
255 case BDSSDType::samplerplane:
256 {result = samplerPlane; break;}
257 case BDSSDType::samplercylinder:
258 {result = samplerCylinder; break;}
259 case BDSSDType::samplerlink:
260 {result = samplerLink; break;}
261 case BDSSDType::terminator:
262 {result = terminator; break;}
263 case BDSSDType::energydep:
264 {
265 if (applyOptions)
266 {result = generateELossHits ? energyDeposition : nullptr;}
267 else
268 {result = energyDeposition;}
269 break;
270 }
271 case BDSSDType::energydepvacuum:
272 {
273 if (applyOptions)
274 {result = generateELossVacuumHits ? energyDepositionVacuum : nullptr;}
275 else
276 {result = energyDepositionVacuum;}
277 break;
278 }
279 case BDSSDType::energydeptunnel:
280 {
281 if (applyOptions)
282 {result = generateELossTunnelHits ? energyDepositionTunnel : nullptr;}
283 else
284 {result = energyDepositionTunnel;}
285 break;
286 }
287 case BDSSDType::energydepworld:
288 {
289 if (applyOptions)
290 {result = storeELossWorld ? energyDepositionWorld : nullptr;}
291 else
292 {result = energyDepositionWorld;}
293 break;
294 }
295 case BDSSDType::worldexit:
296 {result = worldExit; break;}
297 case BDSSDType::worldcomplete:
298#if G4VERSION_NUMBER > 1029
299 {result = worldCompleteSD; break;}
300#else
301 {result = nullptr; break;}
302#endif
303 case BDSSDType::energydepworldcontents:
304 {
305 if (applyOptions)
307 else
309 break;
310 }
311 case BDSSDType::collimator:
312 {result = collimatorSD; break;}
313 case BDSSDType::collimatorcomplete:
314 {
315 if (applyOptions)
316 {// if we're not going to store collimator specific information, just use
317 // regular energy deposition hits to save memory (collimator hits require
318 // full energy deposition hits, plus use extra memory themselves).
320 {result = collimatorCompleteSD;}
321 else
322 {result = energyDeposition;}
323 }
324 else
325 {result = collimatorCompleteSD;}
326 break;
327 }
328 case BDSSDType::apertureimpacts:
329 {
330 if (applyOptions)
331 {result = generateApertureImpacts ? apertureImpacts : nullptr;}
332 else
333 {result = apertureImpacts;}
334 break;
335 }
336 case BDSSDType::aperturecomplete:
337 {
338#if G4VERSION_NUMBER > 1029
339 if (applyOptions)
340 {
342 {result = apertureCompleteSD;}
344 {result = apertureImpacts;}
345 }
346 else
347 {result = apertureCompleteSD;}
348 break;
349#else
350 if (applyOptions)
351 {result = generateApertureImpacts ? apertureImpacts : nullptr;}
352 else
353 {result = apertureImpacts;}
354 break;
355#endif
356 }
357 case BDSSDType::thinthing:
358 {result = thinThingSD; break;}
359 case BDSSDType::wirecomplete:
360 {
361 if (applyOptions)
362 {
363 result = generateELossHits
364 ? static_cast<G4VSensitiveDetector*>(wireCompleteSD)
365 : static_cast<G4VSensitiveDetector*>(thinThingSD);
366 }
367 else
368 {result = wireCompleteSD;}
369 break;
370 }
371 default:
372 {result = nullptr; break;}
373 }
374 return result;
375}
376
378 G4double unit)
379{
380 primitiveScorerNamesComplete.emplace_back(nameIn);
381
382 G4String primitivePartOnly = nameIn; // copy of full name
383 auto search = nameIn.rfind("/");
384 if (search != std::string::npos)
385 {primitivePartOnly = nameIn.substr(search+1);}
386 primitiveScorerNames.push_back(primitivePartOnly);
387 primitiveScorerNameToUnit[primitivePartOnly] = unit;
388}
389
390void BDSSDManager::RegisterPrimitiveScorerNames(const std::vector<G4String>& namesIn,
391 const std::vector<G4double>* units)
392{
393 if (units)
394 {
395 if (units->size() != namesIn.size())
396 {throw BDSException(__METHOD_NAME__, "mismatching size of names and units.");}
397 for (G4int i = 0; i < (G4int)namesIn.size(); i++)
398 {RegisterPrimitiveScorerName(namesIn[i], (*units)[i]);}
399 }
400 else
401 {
402 for (const auto& name : namesIn)
404 }
405}
406
408{
409 if (samplerLink)
410 {samplerLink->SetLinkRegistry(registry);}
411}
412
413void BDSSDManager::ConstructSamplerSDsForParticleSets(const std::map<int, std::set<int>>& samplerFilterIDtoPDGSetIn)
414{
415 G4SDManager* SDMan = G4SDManager::GetSDMpointer();
416
417 // we construct one of each sampler type per filter set as we don't know
418 // from the parser how they'll be used. very small overhead.
419
420 // plane sampler SDs
421 for (const auto& IDAndSet : samplerFilterIDtoPDGSetIn)
422 {
423 G4String samplerName = "plane_with_PDG_set_" + std::to_string(IDAndSet.first);
424 auto aSampler = new BDSSDSampler(samplerName);
425 extraSamplerWithFilterNamesComplete.emplace_back(samplerName);
426 auto filter = new BDSSDFilterPDGIDSet("pdgid_set_number_"+std::to_string(IDAndSet.first), IDAndSet.second);
427 aSampler->SetFilter(filter);
428 extraSamplersWithFilters[(G4int)IDAndSet.first] = aSampler;
429 extraSamplerFilters[(G4int)IDAndSet.first] = filter; // keep a map of them for deleting later
430 SDMan->AddNewDetector(aSampler);
431 }
432 // cylindrical sampler SDs
433 for (const auto& IDAndSet : samplerFilterIDtoPDGSetIn)
434 {
435 G4String samplerName = "cylinder_with_PDG_set_" + std::to_string(IDAndSet.first);
436 auto aSampler = new BDSSDSamplerCylinder(samplerName);
437 extraSamplerCylinderWithFilterNamesComplete.emplace_back(samplerName);
438 // filter already exists - reuse
439 aSampler->SetFilter(extraSamplerFilters[(G4int)IDAndSet.first] );
440 extraSamplerCylindersWithFilters[(G4int)IDAndSet.first] = aSampler;
441 SDMan->AddNewDetector(aSampler);
442 }
443 // spherical sampler SDs
444 for (const auto& IDAndSet : samplerFilterIDtoPDGSetIn)
445 {
446 G4String samplerName = "sphere_with_PDG_set_" + std::to_string(IDAndSet.first);
447 auto aSampler = new BDSSDSamplerSphere(samplerName);
448 extraSamplerSphereWithFilterNamesComplete.emplace_back(samplerName);
449 // filter already exists - reuse
450 aSampler->SetFilter(extraSamplerFilters[(G4int)IDAndSet.first] );
451 extraSamplerSpheresWithFilters[(G4int)IDAndSet.first] = aSampler;
452 SDMan->AddNewDetector(aSampler);
453 }
454}
455
457{
458 auto search = extraSamplersWithFilters.find(ID);
459 return search != extraSamplersWithFilters.end() ? search->second : nullptr;
460}
461
463{
464 auto search = extraSamplerCylindersWithFilters.find(ID);
465 return search != extraSamplerCylindersWithFilters.end() ? search->second : nullptr;
466}
467
469{
470 auto search = extraSamplerSpheresWithFilters.find(ID);
471 return search != extraSamplerSpheresWithFilters.end() ? search->second : nullptr;
472}
General exception with possible name of object and message.
Definition: BDSException.hh:35
A class that holds global options and constants.
static BDSGlobalConstants * Instance()
Access method.
BDS::TrajectoryOptions StoreTrajectoryOptions() const
options that require some implementation.
G4bool UseImportanceSampling() const
Is importance sampling being used.
Registry / map of components for tracker linkage.
Modified G4MultiSensitiveDetector that retains order and passes hits in sequence.
Generates BDSHitsEnergyDepositions from step information - uses curvilinear coords.
The sensitive detector class that provides sensitivity to collimators instances.
Generates BDSHitsEnergyDepositionGlobal from step information.
Generates BDSHitsEnergyDepositions from step information - uses curvilinear coords.
Filter for only ions.
Filter that applies OR to a vector of filters.
void RegisterFilter(G4VSDFilter *filterIn)
Register the filter.
Filter for a set of PDG IDs (ints).
Filter for only primary particles.
A singleton class that holds all required sensitive detector class instances.
Definition: BDSSDManager.hh:68
G4double collimatorHitsMinimumKE
Cache of global constant option.
BDSSDManager()
Private default constructor for singleton.
Definition: BDSSDManager.cc:76
BDSSDSamplerSphere * samplerSphere
SD instance.
G4bool storeCollimatorHitsAll
Cache of global constant option.
std::map< G4String, G4VSDFilter * > filters
Map of all filters used. This class owns a single instance of each.
BDSSDTerminator * terminator
SD instance.
BDSSDSamplerCylinder * SamplerCylinderWithFilter(G4int ID) const
Access the relevant SD for a given particle filter set ID. It will return nullptr if the ID is invali...
G4bool generateCollimatorHits
Cache of global constant option.
BDSSDVolumeExit * worldExit
SD instance.
G4bool generateELossVacuumHits
Cache of global constant option.
BDSSDEnergyDepositionGlobal * energyDepositionWorldContents
SD instance.
void RegisterPrimitiveScorerName(const G4String &nameIn, G4double unit=1.0)
BDSSDApertureImpacts * apertureImpacts
SD instance.
void ConstructSamplerSDsForParticleSets(const std::map< int, std::set< int > > &samplerFilterIDtoPDGSetIn)
G4bool generateELossWorldContents
Cache of global constant option.
G4bool generateELossTunnelHits
Cache of global constant option.
BDSSDSamplerLink * samplerLink
SD instance.
G4bool storeELossWorld
Cache of global constant option.
BDSSDSamplerSphere * SamplerSphereWithFilter(G4int ID) const
Access the relevant SD for a given particle filter set ID. It will return nullptr if the ID is invali...
BDSSDEnergyDeposition * energyDeposition
SD instance.
void RegisterPrimitiveScorerNames(const std::vector< G4String > &namesIn, const std::vector< G4double > *units=nullptr)
Loop over a vector and apply above single name function.
G4VSensitiveDetector * worldCompleteSD
SD instance.
G4bool storeApertureImpactsIons
Cache of global constant option.
G4VSensitiveDetector * apertureCompleteSD
SD instance.
G4bool storeApertureImpactsAll
Cache of global constant option.
BDSSDEnergyDeposition * energyDepositionTunnel
SD instance.
BDSSDSampler * samplerPlane
SD instance.
G4bool generateELossHits
Cache of global constant option.
G4VSensitiveDetector * SensitiveDetector(const BDSSDType sdType, G4bool applyOptions=false) const
BDSSDSamplerCylinder * samplerCylinder
SD instance.
std::map< G4String, G4double > primitiveScorerNameToUnit
Map of primitive scorer names to units.
BDSSDSampler * SamplerPlaneWithFilter(G4int ID) const
Access the relevant SD for a given particle filter set ID. It will return nullptr if the ID is invali...
G4bool generateApertureImpacts
Cache of global constant option.
G4bool storeCollimatorHitsIons
Cache of global constant option.
BDSSDEnergyDeposition * energyDepositionFull
SD instance.
G4double apertureImpactsMinimumKE
Cache of global constant option.
std::vector< G4String > primitiveScorerNamesComplete
Vector of complete (including mesh name) primitive scorer names.
G4bool storeELossExtras
Cache of global constant option.
std::vector< G4String > primitiveScorerNames
Just the primitive scorer part of the name.
void SetLinkRegistry(BDSLinkRegistry *registry)
If samplerLink member exists, set the registry to look up links for that SD.
BDSSDEnergyDepositionGlobal * energyDepositionWorld
SD instance.
BDSSDEnergyDeposition * energyDepositionVacuum
SD instance.
The sensitive detector class that provides sensitivity to BDSSamplerCylinder instances.
The sensitive detector class that provides sensitivity to BDSSamplerSphere instances.
The sensitive detector class that provides sensitivity to BDSSampler instances.
Definition: BDSSDSampler.hh:44
Sensitivity that measures primary particle turns for terminator.
The sensitive detector class that provides sensitivity to record thin thing hits.
Generates BDSHitEnergyDepositionGlobals if a particle is leaving a volume.
Improve type-safety of native enum data type in C++.
type underlying() const
return underlying value (can be used in switch statement)