BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSEventAction.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) BDSIM Collaboration, 2001 - 2026.
3
4This file is part of BDSIM.
5
6BDSIM is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published
8by the Free Software Foundation version 3 of the License.
9
10BDSIM is distributed in the hope that it will be useful, but
11WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
17*/
18#include "BDSAuxiliaryNavigator.hh"
19#include "BDSDebug.hh"
20#include "BDSEventAction.hh"
21#include "BDSEventInfo.hh"
22#include "BDSGlobalConstants.hh"
23#include "BDSHitEnergyDeposition.hh"
24#include "BDSHitEnergyDepositionExtra.hh"
25#include "BDSHitEnergyDepositionGlobal.hh"
26#include "BDSHitSampler.hh"
27#include "BDSHitThinThing.hh"
28#include "BDSOutput.hh"
29#include "BDSModulator.hh"
30#include "BDSNavigatorPlacements.hh"
31#include "BDSSamplerRegistry.hh"
32#include "BDSSamplerPlacementRecord.hh"
33#include "BDSSDApertureImpacts.hh"
34#include "BDSSDCollimator.hh"
35#include "BDSSDEnergyDeposition.hh"
36#include "BDSSDEnergyDepositionGlobal.hh"
37#include "BDSSDManager.hh"
38#include "BDSSDSampler.hh"
39#include "BDSSDSamplerCylinder.hh"
40#include "BDSSDSamplerSphere.hh"
41#include "BDSSDTerminator.hh"
42#include "BDSSDThinThing.hh"
43#include "BDSSDVolumeExit.hh"
44#include "BDSStackingAction.hh"
45#include "BDSTrajectoriesToStore.hh"
46#include "BDSTrajectory.hh"
47#include "BDSTrajectoryFilter.hh"
48#include "BDSTrajectoryPointHit.hh"
49#include "BDSTrajectoryPrimary.hh"
50#include "BDSUtilities.hh"
51#include "BDSWrapperMuonSplitting.hh"
52
53#include "globals.hh" // geant4 types / globals
54#include "G4Event.hh"
55#include "G4EventManager.hh"
56#include "G4HCofThisEvent.hh"
57#include "G4PrimaryVertex.hh"
58#include "G4PrimaryParticle.hh"
59#include "G4PropagatorInField.hh"
60#include "G4Run.hh"
61#include "G4SDManager.hh"
62#include "G4StackManager.hh"
63#include "G4THitsMap.hh"
64#include "G4TrajectoryContainer.hh"
65#include "G4TrajectoryPoint.hh"
66#include "G4TransportationManager.hh"
67
68#include <algorithm>
69#include <bitset>
70#include <chrono>
71#include <ctime>
72#include <map>
73#include <string>
74#include <vector>
75
76using namespace std::chrono;
77
78G4bool FireLaserCompton; // bool to ensure that Laserwire can only occur once in an event
79
80BDSEventAction::BDSEventAction(BDSOutput* outputIn):
81 output(outputIn),
82 samplerCollID_plane(-1),
83 samplerCollID_cylin(-1),
84 samplerCollID_sphere(-1),
85 eCounterID(-1),
86 eCounterFullID(-1),
87 eCounterVacuumID(-1),
88 eCounterTunnelID(-1),
89 eCounterWorldID(-1),
90 eCounterWorldContentsID(-1),
91 worldExitCollID(-1),
92 collimatorCollID(-1),
93 apertureCollID(-1),
94 thinThingCollID(-1),
95 startTime(0),
96 stopTime(0),
97 starts(0),
98 stops(0),
99 cpuStartTime(std::clock_t()),
100 primaryAbsorbedInCollimator(false),
101 currentEventIndex(0),
102 eventInfo(nullptr),
103 nTracks(0)
104{
106 verboseEventBDSIM = globals->VerboseEventBDSIM();
107 verboseEventStart = globals->VerboseEventStart();
108 verboseEventStop = BDS::VerboseEventStop(verboseEventStart, globals->VerboseEventContinueFor());
109 storeTrajectory = globals->StoreTrajectory();
110 storeTrajectoryAll = globals->StoreTrajectoryAll();
111 storeTrajectorySecondary = globals->StoreTrajectorySecondaryParticles();
112 trajectoryFilterLogicAND = globals->TrajectoryFilterLogicAND();
113 trajectoryEnergyThreshold = globals->StoreTrajectoryEnergyThreshold();
114 trajectoryCutZ = globals->TrajCutGTZ();
115 trajectoryCutR = globals->TrajCutLTR();
116 trajConnect = globals->TrajConnect();
117 trajParticleNameToStore = globals->StoreTrajectoryParticle();
118 trajParticleIDToStore = globals->StoreTrajectoryParticleID();
119 trajDepth = globals->StoreTrajectoryDepth();
120 trajSRangeToStore = globals->StoreTrajectoryELossSRange();
121 trajFiltersSet = globals->TrajectoryFiltersSet();
122 printModulo = globals->PrintModuloEvents();
123
124 // particleID to store in integer vector
125 std::stringstream iss(trajParticleIDToStore);
126 G4int i;
127 while (iss >> i)
128 {trajParticleIDIntToStore.push_back(i);}
129}
130
131BDSEventAction::~BDSEventAction()
132{;}
133
134void BDSEventAction::BeginOfEventAction(const G4Event* evt)
135{
136#ifdef BDSDEBUG
137 G4cout << __METHOD_NAME__ << "processing begin of event action" << G4endl;
138#endif
140 nTracks = 0;
142 BDSStackingAction::energyKilled = 0;
143 primaryAbsorbedInCollimator = false; // reset flag
144 currentEventIndex = evt->GetEventID();
145
146 BDSModulator::SetEventIndex(currentEventIndex);
147
148 // reset navigators to ensure no mis-navigating and that events are truly independent
149 BDSAuxiliaryNavigator::ResetNavigatorStates();
150 BDSNavigatorPlacements::ResetNavigatorStates();
151 // make further attempts to clear Geant4's tracking history between events to make them
152 // truly independent.
153 G4Navigator* trackingNavigator = G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking();
154 trackingNavigator->ResetStackAndState();
155 G4TransportationManager* tm = G4TransportationManager::GetTransportationManager();
156 int i = 0;
157 for (auto it = tm->GetActiveNavigatorsIterator(); i < (int)tm->GetNoActiveNavigators(); it++)
158 {(*it)->ResetStackAndState(); i++;}
159 tm->GetPropagatorInField()->ClearPropagatorState(); // <- this one really makes a difference
160
161 // Unfortunately the interfaces to G4TransportationManager aren't great which makes this a bit
162 // pedantic. Also, the GetNavigator creates an exception if it doesn't find what it's looking
163 // for rather than just return a nullptr
164 G4bool samplerWorldExists = false;
165 std::vector<G4VPhysicalVolume*>::iterator worldIterator = tm->GetWorldsIterator();
166 for (G4int iw = 0; iw < (G4int)tm->GetNoWorlds(); iw++)
167 {
168 samplerWorldExists = samplerWorldExists || (*worldIterator)->GetName() == "SamplerWorld_main";
169 worldIterator++;
170 }
171 if (samplerWorldExists)
172 {
173 auto swtracker = tm->GetNavigator("SamplerWorld_main");
174 if (swtracker)
175 {swtracker->ResetStackAndState();}
176 }
177 fpEventManager->GetStackManager()->clear();
178
179 // update reference to event info
180 eventInfo = static_cast<BDSEventInfo*>(evt->GetUserInformation());
181
182 // number feedback
183 G4int currentEventID = evt->GetEventID();
184 BDSSDTerminator::eventNumber = currentEventID; // update static member of terminator
185 eventInfo->SetIndex(currentEventID);
186 if (currentEventID % printModulo == 0)
187 {G4cout << "---> Begin of event: " << currentEventID << G4endl;}
188 if (verboseEventBDSIM) // always print this out
189 {G4cout << __METHOD_NAME__ << "event #" << currentEventID << G4endl;}
190
191 // cache hit collection IDs for quicker access
192 if (samplerCollID_plane < 0)
193 { // if one is -1 then all need initialised.
194 G4SDManager* g4SDMan = G4SDManager::GetSDMpointer();
195 BDSSDManager* bdsSDMan = BDSSDManager::Instance();
196 samplerCollID_plane = g4SDMan->GetCollectionID(bdsSDMan->SamplerPlane()->GetName());
197 samplerCollID_cylin = g4SDMan->GetCollectionID(bdsSDMan->SamplerCylinder()->GetName());
198 samplerCollID_sphere = g4SDMan->GetCollectionID(bdsSDMan->SamplerSphere()->GetName());
199 eCounterID = g4SDMan->GetCollectionID(bdsSDMan->EnergyDeposition()->GetName());
200 eCounterFullID = g4SDMan->GetCollectionID(bdsSDMan->EnergyDepositionFull()->GetName());
201 eCounterVacuumID = g4SDMan->GetCollectionID(bdsSDMan->EnergyDepositionVacuum()->GetName());
202 eCounterTunnelID = g4SDMan->GetCollectionID(bdsSDMan->EnergyDepositionTunnel()->GetName());
203 eCounterWorldID = g4SDMan->GetCollectionID(bdsSDMan->EnergyDepositionWorld()->GetName());
204 eCounterWorldContentsID = g4SDMan->GetCollectionID(bdsSDMan->EnergyDepositionWorldContents()->GetName());
205 worldExitCollID = g4SDMan->GetCollectionID(bdsSDMan->WorldExit()->GetName());
206 collimatorCollID = g4SDMan->GetCollectionID(bdsSDMan->Collimator()->GetName());
207 apertureCollID = g4SDMan->GetCollectionID(bdsSDMan->ApertureImpacts()->GetName());
208 thinThingCollID = g4SDMan->GetCollectionID(bdsSDMan->ThinThing()->GetName());
209 const std::vector<G4String>& scorerNames = bdsSDMan->PrimitiveScorerNamesComplete();
210 for (const auto& name : scorerNames)
211 {scorerCollectionIDs[name] = g4SDMan->GetCollectionID(name);}
212 const std::vector<G4String>& extraSamplerWithFilterNames = bdsSDMan->ExtraSamplerWithFilterNamesComplete();
213 for (const auto& name : extraSamplerWithFilterNames)
214 {extraSamplerCollectionIDs[name] = g4SDMan->GetCollectionID(name);}
215 const std::vector<G4String>& extraSamplerCylinderWithFilterNames = bdsSDMan->ExtraSamplerCylinderWithFilterNamesComplete();
216 for (const auto& name : extraSamplerCylinderWithFilterNames)
217 {extraSamplerCylinderCollectionIDs[name] = g4SDMan->GetCollectionID(name);}
218 const std::vector<G4String>& extraSamplerSphereWithFilterNames = bdsSDMan->ExtraSamplerSphereWithFilterNamesComplete();
219 for (const auto& name : extraSamplerSphereWithFilterNames)
220 {extraSamplerCollectionIDs[name] = g4SDMan->GetCollectionID(name);}
221 }
222 FireLaserCompton=true;
223
224 cpuStartTime = std::clock();
225 // get the current time - last thing before we hand off to geant4
226 startTime = time(nullptr);
228 eventInfo->SetStopTime(startTime); // initialise to duration of 0
229
230 milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
231 starts = (G4double)ms.count()/1000.0;
232}
233
234void BDSEventAction::EndOfEventAction(const G4Event* evt)
235{
236 //G4cout << "BDSWrapperMuonSplitting::nCallsThisEvent> " << BDSWrapperMuonSplitting::nCallsThisEvent << G4endl;
237 auto flagsCache(G4cout.flags());
238 // Get event number information
239 G4int event_number = evt->GetEventID();
240 G4bool verboseThisEvent = verboseEventBDSIM && BDS::VerboseThisEvent(event_number, verboseEventStart, verboseEventStop);
241#ifdef BDSDEBUG
242 verboseThisEvent = true; // force on for debug mode
243#endif
244 const G4int nChar = 50; // for print out
245 if (verboseThisEvent)
246 {G4cout << __METHOD_NAME__ << "processing end of event"<<G4endl;}
247 eventInfo->SetIndex(event_number);
248
249 // Record if event was aborted - ie whether it's usable for analyses.
250 eventInfo->SetAborted(evt->IsAborted());
252
253 // Calculate the elapsed CPU time for the event.
254 auto cpuEndTime = std::clock();
255 G4float durationCPU = static_cast<G4float>(cpuEndTime - cpuStartTime) / CLOCKS_PER_SEC;
256 eventInfo->SetDurationCPU(durationCPU);
257
258 // Get the current wall time
259 stopTime = time(nullptr);
261
262 // Timing information (wall)
263 milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
264 stops = (G4double)ms.count()/1000.0;
266
267 G4double memoryUsedMb = BDS::GetMemoryUsage();
268 eventInfo->SetMemoryUsage(memoryUsedMb);
269
270 // cache if primary was absorbed in a collimator
272
273 // feedback
274 if (verboseThisEvent)
275 {eventInfo->Print();}
276
277 // Get the hits collection of this event - all hits from different SDs.
278 G4HCofThisEvent* HCE = evt->GetHCofThisEvent();
279
280 // samplers
281 typedef BDSHitsCollectionSampler shc;
282 std::vector<shc*> allSamplerHits;
283 shc* SampHC = HCE ? dynamic_cast<shc*>(HCE->GetHC(samplerCollID_plane)) : nullptr;
284 if (SampHC)
285 {allSamplerHits.push_back(SampHC);}
286 if (HCE)
287 {
288 for (const auto& nameIndex : extraSamplerCollectionIDs)
289 {allSamplerHits.push_back(dynamic_cast<shc*>(HCE->GetHC(nameIndex.second)));}
290 }
292 std::vector<shcc*> allSamplerCylinderHits;
293 shcc* hitsCylinder = HCE ? dynamic_cast<shcc*>(HCE->GetHC(samplerCollID_cylin)) : nullptr;
294 if (hitsCylinder)
295 {allSamplerCylinderHits.push_back(hitsCylinder);}
296 if (HCE)
297 {
298 for (const auto& nameIndex : extraSamplerCylinderCollectionIDs)
299 {allSamplerCylinderHits.push_back(dynamic_cast<shcc*>(HCE->GetHC(nameIndex.second)));}
300 }
302 std::vector<shcs*> allSamplerSphereHits;
303 shcs* hitsSphere = HCE ? dynamic_cast<shcs*>(HCE->GetHC(samplerCollID_sphere)) : nullptr;
304 if (hitsSphere)
305 {allSamplerSphereHits.push_back(hitsSphere);}
306 if (HCE)
307 {
308 for (const auto& nameIndex : extraSamplerSphereCollectionIDs)
309 {allSamplerSphereHits.push_back(dynamic_cast<shcs*>(HCE->GetHC(nameIndex.second)));}
310 }
311
312 // energy deposition collections - eloss, tunnel hits
314 echc* eCounterHits = HCE ? dynamic_cast<echc*>(HCE->GetHC(eCounterID)) : nullptr;
315 echc* eCounterFullHits = HCE ? dynamic_cast<echc*>(HCE->GetHC(eCounterFullID)) : nullptr;
316 echc* eCounterVacuumHits = HCE ? dynamic_cast<echc*>(HCE->GetHC(eCounterVacuumID)) : nullptr;
317 echc* eCounterTunnelHits = HCE ? dynamic_cast<echc*>(HCE->GetHC(eCounterTunnelID)) : nullptr;
318
319 // world exit hits
321 ecghc* eCounterWorldHits = HCE ? dynamic_cast<ecghc*>(HCE->GetHC(eCounterWorldID)) : nullptr;
322 ecghc* eCounterWorldContentsHits = HCE ? dynamic_cast<ecghc*>(HCE->GetHC(eCounterWorldContentsID)) : nullptr;
323 ecghc* worldExitHits = HCE ? dynamic_cast<ecghc*>(HCE->GetHC(worldExitCollID)) : nullptr;
324
325 // aperture hits
327 aihc* apertureImpactHits = HCE ? dynamic_cast<aihc*>(HCE->GetHC(apertureCollID)) : nullptr;
328
329 // thin thing hits
330 typedef BDSHitsCollectionThinThing tthc;
331 tthc* thinThingHits = HCE ? dynamic_cast<tthc*>(HCE->GetHC(thinThingCollID)) : nullptr;
332
333 std::map<G4String, G4THitsMap<G4double>*> scorerHits;
334 if (HCE)
335 {
336 for (const auto& nameIndex : scorerCollectionIDs)
337 {scorerHits[nameIndex.first] = dynamic_cast<G4THitsMap<G4double>*>(HCE->GetHC(nameIndex.second));}
338 }
339 // primary hit something? we infer this by seeing if there are any energy
340 // deposition hits at all - if there are, the primary must have 'hit' something.
341 // we don't check the world energy hits here because the hits could be from
342 // intended transport through air in part of the machine (a gap). similarly, there
343 // could be ionisation of the vacuum gas without a real impact so we don't check
344 // the vacuum energy deposition
345 if (eCounterHits)
346 {
347 if (verboseThisEvent)
348 {G4cout << std::left << std::setw(nChar) << "Energy deposition hits: " << eCounterHits->entries() << G4endl;}
349 if (eCounterHits->entries() > 0)
351 }
352 if (eCounterFullHits)
353 {
354 if (verboseThisEvent)
355 {G4cout << std::left << std::setw(nChar) << "Energy deposition full hits: " << eCounterFullHits->entries() << G4endl;}
356 if (eCounterFullHits->entries() > 0)
358 }
359 if (eCounterTunnelHits)
360 {
361 if (verboseThisEvent)
362 {G4cout << std::left << std::setw(nChar) << "Tunnel energy deposition hits: " << eCounterTunnelHits->entries() << G4endl;}
363 if (eCounterTunnelHits->entries() > 0)
365 }
366
367 // collimator hits if any
368 typedef BDSHitsCollectionCollimator chc;
369 chc* collimatorHits = HCE ? dynamic_cast<chc*>(HCE->GetHC(collimatorCollID)) : nullptr;
370
371 if (verboseThisEvent)
372 {
373 if (eCounterVacuumHits)
374 {G4cout << std::left << std::setw(nChar) << "Vacuum energy deposition hits: " << eCounterVacuumHits->entries() << G4endl;}
375 if (eCounterWorldHits)
376 {G4cout << std::left << std::setw(nChar) << "World energy deposition hits: " << eCounterWorldHits->entries() << G4endl;}
377 if (eCounterWorldContentsHits)
378 {G4cout << std::left << std::setw(nChar) << "World contents energy deposition hits: " << eCounterWorldContentsHits->entries() << G4endl;}
379 if (worldExitHits)
380 {G4cout << std::left << std::setw(nChar) << "World exit hits: " << worldExitHits->entries() << G4endl;}
381 if (collimatorHits)
382 {G4cout << std::left << std::setw(nChar) << "Collimator hits: " << collimatorHits->entries() << G4endl;}
383 }
384
385 // primary hits and losses
386 std::vector<const BDSTrajectoryPointHit*> primaryHits;
387 std::vector<const BDSTrajectoryPointHit*> primaryLosses;
388 G4TrajectoryContainer* trajCont = evt->GetTrajectoryContainer();
389 if (trajCont)
390 {
391 if (verboseThisEvent)
392 {G4cout << std::left << std::setw(nChar) << "Trajectories: " << trajCont->size() << G4endl;}
393 for (auto p : primaryTrajectoriesCache)
394 {primaryLosses.push_back(new BDSTrajectoryPointHit(p.second, p.second->LastPoint()));}
395 }
396 std::vector<const BDSTrajectoryPrimary*> primaryTrajectories;
397 for (auto kv : primaryTrajectoriesCache)
398 {primaryTrajectories.push_back(kv.second);}
399 primaryHits = BDSHitThinThing::ResolvePossibleEarlierThinHits(primaryTrajectories, thinThingHits);
400
401 BDSTrajectoriesToStore* interestingTrajectories = IdentifyTrajectoriesForStorage(evt,
402 verboseEventBDSIM || verboseThisEvent,
403 eCounterHits,
404 eCounterFullHits,
405 allSamplerHits,
406 nChar);
407
409 evt->GetPrimaryVertex(),
410 allSamplerHits,
411 allSamplerCylinderHits,
412 allSamplerSphereHits,
413 nullptr,
414 eCounterHits,
415 eCounterFullHits,
416 eCounterVacuumHits,
417 eCounterTunnelHits,
418 eCounterWorldHits,
419 eCounterWorldContentsHits,
420 worldExitHits,
421 primaryHits,
422 primaryLosses,
423 interestingTrajectories,
424 collimatorHits,
425 apertureImpactHits,
426 scorerHits,
427 BDSGlobalConstants::Instance()->TurnsTaken());
428
429 // if events per ntuples not set (default 0) - only write out at end
430 G4int evntsPerNtuple = BDSGlobalConstants::Instance()->NumberOfEventsPerNtuple();
431 if (evntsPerNtuple>0 && (event_number+1)%evntsPerNtuple == 0)
432 {
433 // note the timing information will be wrong here as the run hasn't finished but
434 // the file is bridged. There's no good way around this just now as this class
435 // can't access the timing information stored in BDSRunAction
437 }
438
439 if (verboseThisEvent)
440 {
441 G4cout << __METHOD_NAME__ << "end of event action done" << G4endl;
442 G4cout << "Energy deposition pool size: " << BDSAllocatorEnergyDeposition.GetAllocatedSize() << G4endl;
443 G4cout << "Energy deposition extra pool size: " << BDSAllocatorEnergyDepositionExtra.GetAllocatedSize() << G4endl;
444 G4cout << "Collimator hits pool size: " << BDSAllocatorCollimator.GetAllocatedSize() << G4endl;
445 G4cout << "Trajectory pool size: " << bdsTrajectoryAllocator.GetAllocatedSize() << G4endl;
446 G4cout << "Trajectory point pool size bdsim: " << bdsTrajectoryPointAllocator.GetAllocatedSize() << G4endl;
447#if G4VERSION_NUMBER > 1049
448 G4cout << "Trajectory point pool size: " << aTrajectoryPointAllocator()->GetAllocatedSize() << G4endl;
449#else
450 G4cout << "Trajectory point pool size: " << aTrajectoryPointAllocator->GetAllocatedSize() << G4endl;
451#endif
452 G4cout << "Trajectory point primary pool size: " << bdsTrajectoryPrimaryAllocator.GetAllocatedSize() << G4endl;
453 }
454
455 delete interestingTrajectories;
456 for (auto& p : primaryLosses)
457 {delete p;}
458 for (auto& p : primaryHits)
459 {delete p;}
460
461 G4cout.flags(flagsCache);
462}
463
465 G4bool verbose,
467 BDSHitsCollectionEnergyDeposition* eCounterFullHits,
468 const std::vector<BDSHitsCollectionSampler*>& allSamplerHits,
469 G4int nChar) const
470{
471 auto flagsCache(G4cout.flags());
472 G4TrajectoryContainer* trajCont = evt->GetTrajectoryContainer();
473
474 // Save interesting trajectories
475 std::map<BDSTrajectory*, bool> interestingTraj;
476 std::map<BDSTrajectory*, std::bitset<BDS::NTrajectoryFilters> > trajectoryFilters;
477
478 if (storeTrajectory && trajCont)
479 {
480 // cast all trajectories to BDSTrajectory once
481 TrajectoryVector* trajVec = trajCont->GetVector();
482 std::vector<BDSTrajectory*> trajVecBDS;
483 trajVecBDS.reserve(trajVec->size());
484 std::transform(trajVec->begin(), trajVec->end(), std::back_inserter(trajVecBDS),
485 [](G4VTrajectory* a) { return static_cast<BDSTrajectory*>(a); });
486
487 // build trackID map
488 std::map<int, BDSTrajectory*> trackIDToTrajectory;
489 for (auto* tr : trajVecBDS)
490 {trackIDToTrajectory[tr->GetTrackID()] = tr;}
491 trackIDToTrajectory[0] = nullptr; // primary has no parent
492
493#ifdef BDSDEBUG
494 for (auto* tr : trajVecBDS)
495 {G4cout << tr->GetTrackID() << " " << tr->GetParentID() << G4endl;}
496#endif
497
498 // build depth map
499 std::map<BDSTrajectory*, int> depthMap;
500 for (auto* tr : trajVecBDS)
501 {
502 G4int depth = 0;
503 BDSTrajectory* ct = tr;
504 // recurse up to a primary trackID and count the number of parents
505 while (ct->GetParentID() != 0)
506 {
507 ct = trackIDToTrajectory[ct->GetParentID()];
508 depth++;
509 }
510 depthMap[tr] = depth;
511 tr->SetDepth(depth);
512 tr->SetParent(trackIDToTrajectory[tr->GetParentID()]);
513 }
514
515 // loop over trajectories and determine if it should be stored
516 // keep tallies of how many will and won't be stored
517 G4int nYes = 0;
518 G4int nNo = 0;
519 for (auto* tr : trajVecBDS)
520 {
521 std::bitset<BDS::NTrajectoryFilters> filters;
522 G4int parentID = tr->GetParentID();
523
524 // always store primaries
525 if (parentID == 0)
526 {filters[BDSTrajectoryFilter::primary] = true;}
527 else
528 {
529 if (storeTrajectorySecondary)
530 {filters[BDSTrajectoryFilter::secondary] = true;}
531 }
532
533 // check on energy (if energy threshold is not negative)
534 if (trajectoryEnergyThreshold >= 0 && tr->GetInitialKineticEnergy() > trajectoryEnergyThreshold)
535 {filters[BDSTrajectoryFilter::energyThreshold] = true;}
536
537 // check on particle if not empty string
538 if (!trajParticleNameToStore.empty() || !trajParticleIDToStore.empty())
539 {
540 G4String particleName = tr->GetParticleName();
541 G4int particleID = tr->GetPDGEncoding();
542 G4String particleIDStr = G4String(std::to_string(particleID));
543 std::size_t found1 = trajParticleNameToStore.find(particleName);
544 bool found2 = (std::find(trajParticleIDIntToStore.begin(), trajParticleIDIntToStore.end(), particleID)
545 != trajParticleIDIntToStore.end());
546 if ((found1 != std::string::npos) || found2)
547 {filters[BDSTrajectoryFilter::particle] = true;}
548 }
549
550 // check on trajectory tree depth (trajDepth = 0 means only primaries)
551 if (depthMap[tr] <= trajDepth || storeTrajectoryAll) // all means to infinite trajDepth really
552 {filters[BDSTrajectoryFilter::depth] = true;}
553
554 // check on coordinates (and TODO momentum)
555 // clear out trajectories that don't reach point TrajCutGTZ or greater than TrajCutLTR
556 BDSTrajectoryPoint* trajEndPoint = static_cast<BDSTrajectoryPoint*>(tr->GetPoint(tr->GetPointEntries() - 1));
557
558 // end point greater than some Z
559 if (trajEndPoint->GetPosition().z() > trajectoryCutZ)
560 {filters[BDSTrajectoryFilter::minimumZ] = true;}
561
562 // less than maximum R
563 if (trajEndPoint->PostPosR() < trajectoryCutR)
564 {filters[BDSTrajectoryFilter::maximumR] = true;}
565
566 filters.any() ? nYes++ : nNo++;
567 interestingTraj.insert(std::pair<BDSTrajectory*, bool>(tr, filters.any()));
568 trajectoryFilters.insert(std::pair<BDSTrajectory*, std::bitset<BDS::NTrajectoryFilters> >(tr, filters));
569 }
570
571 // loop over energy hits to connect trajectories
572 if (!trajSRangeToStore.empty())
573 {
574 if (eCounterHits)
575 {
576 G4int nHits = (G4int)eCounterHits->entries();
578 for (G4int i = 0; i < nHits; i++)
579 {
580 hit = (*eCounterHits)[i];
581 double dS = hit->GetSHit();
582 for (const auto& v : trajSRangeToStore)
583 {
584 if (dS >= v.first && dS <= v.second)
585 {
586 BDSTrajectory* trajToStore = trackIDToTrajectory[hit->GetTrackID()];
587 if (!interestingTraj[trajToStore])
588 {// was marked as not storing - update counters
589 nYes++;
590 nNo--;
591 }
592 interestingTraj[trajToStore] = true;
593 trajectoryFilters[trajToStore][BDSTrajectoryFilter::elossSRange] = true;
594 break;
595 }
596 }
597 }
598 }
599 if (eCounterFullHits)
600 {
601 G4int nHits = (G4int)eCounterFullHits->entries();
603 for (G4int i = 0; i < nHits; i++)
604 {
605 hit = (*eCounterFullHits)[i];
606 double dS = hit->GetSHit();
607 for (const auto& v : trajSRangeToStore)
608 {
609 if (dS >= v.first && dS <= v.second)
610 {
611 BDSTrajectory* trajToStore = trackIDToTrajectory[hit->GetTrackID()];
612 if (!interestingTraj[trajToStore])
613 {// was marked as not storing - update counters
614 nYes++;
615 nNo--;
616 }
617 interestingTraj[trajToStore] = true;
618 trajectoryFilters[trajToStore][BDSTrajectoryFilter::elossSRange] = true;
619 break;
620 }
621 }
622 }
623 }
624 }
625
626 // loop over samplers to connect trajectories
627 for (const auto& SampHC : allSamplerHits)
628 {
629 if (!trajectorySamplerID.empty() && SampHC)
630 {
631 for (G4int i = 0; i < (G4int)SampHC->entries(); i++)
632 {
633 G4int samplerIndex = (*SampHC)[i]->samplerID;
635 if (std::find(trajectorySamplerID.begin(), trajectorySamplerID.end(), samplerIndex) !=
637 {
638 BDSTrajectory* trajToStore = trackIDToTrajectory[(*SampHC)[i]->trackID];
639 if (!interestingTraj[trajToStore])
640 {// was marked as not storing - update counters
641 nYes++;
642 nNo--;
643 }
644 interestingTraj[trajToStore] = true;
645 trajectoryFilters[trajToStore][BDSTrajectoryFilter::sampler] = true;
646 }
647 }
648 }
649 }
650
651 // If we're using AND logic (default OR) with the filters, loop over and update whether
652 // we should really store the trajectory or not. Importantly, we do this before the connect
653 // trajectory step as that flags yet more trajectories (that connect each one) back to the
654 // primary
656 {
657 for (auto& trajFlag : interestingTraj)
658 {
659 if (trajFlag.second) // if we're going to store it check the logic
660 {
661 // Use bit-wise AND ('&') on the filters matched for this trajectory with the
662 // filters set. If count of 1s the same, then trajectory should be stored,
663 // therefore if not the same, it should be set to false.
664 auto filterMatch = trajectoryFilters[trajFlag.first] & trajFiltersSet;
665 if (filterMatch.count() != trajFiltersSet.count())
666 {trajFlag.second = false;}
667 }
668 }
669 }
670
671 // Connect trajectory graphs
672 if (trajConnect && trackIDToTrajectory.size() > 1)
673 {
674 for (auto i : interestingTraj)
675 {
676 if (i.second)
677 {ConnectTrajectory(interestingTraj, i.first, trajectoryFilters);}
678 }
679 }
680 // Output interesting trajectories
681 if (verbose)
682 {G4cout << std::left << std::setw(nChar) << "Trajectories for storage: " << nYes << " out of " << nYes + nNo << G4endl;}
683 trajVecBDS.clear(); // does not delete the pointers as just casts
684 }
685 G4cout.flags(flagsCache);
686 return new BDSTrajectoriesToStore(interestingTraj, trajectoryFilters);
687}
688
689void BDSEventAction::ConnectTrajectory(std::map<BDSTrajectory*, bool>& interestingTraj,
690 BDSTrajectory* trajectoryToConnect,
691 std::map<BDSTrajectory*, std::bitset<BDS::NTrajectoryFilters> >& trajectoryFilters) const
692{
693 BDSTrajectory* parentTrajectory = trajectoryToConnect->GetParent();
694 if (parentTrajectory)
695 {
696 interestingTraj[parentTrajectory] = true;
697 trajectoryFilters[parentTrajectory][BDSTrajectoryFilter::connect] = true;
698 ConnectTrajectory(interestingTraj, parentTrajectory, trajectoryFilters);
699 }
700 else
701 {return;}
702}
703
705{
706 G4int trackID = trajectoryIn->GetTrackID();
707 if (primaryTrajectoriesCache.find(trackID) == primaryTrajectoriesCache.end())
708 {primaryTrajectoriesCache[trackID] = trajectoryIn;}
709}
G4String trajParticleIDToStore
Cache of variable from global constants.
void ConnectTrajectory(std::map< BDSTrajectory *, bool > &interestingTraj, BDSTrajectory *trajectoryToConnect, std::map< BDSTrajectory *, std::bitset< BDS::NTrajectoryFilters > > &trajectoryFilters) const
G4int eCounterVacuumID
Collection ID for the vacuum energy deposition hits.
G4bool primaryAbsorbedInCollimator
Whether primary stopped in a collimator.
G4double trajectoryCutZ
Cache of variable from global constants.
G4int collimatorCollID
Collection ID for the collimator hits.
G4int eCounterFullID
Collection ID for general energy deposition full hits.
G4int worldExitCollID
Collection ID for the world exit hits.
G4int thinThingCollID
Collection ID for the thin thing hits.
std::vector< std::pair< double, double > > trajSRangeToStore
Cache of variable from global constants.
G4bool storeTrajectory
Cache of whether to store trajectories or not.
G4bool trajectoryFilterLogicAND
Cache of variable from global constants.
G4int eCounterWorldID
Collection ID for the world energy deposition hits.
std::bitset< BDS::NTrajectoryFilters > trajFiltersSet
Cache of variable from global constants.
std::vector< int > trajParticleIDIntToStore
Cache of variable from global constants.
G4int samplerCollID_cylin
Collection ID for cylindrical sampler hits.
std::map< G4String, G4int > extraSamplerCylinderCollectionIDs
Collection IDs for extra samplers.
G4int eCounterWorldContentsID
Collection ID for the world energy deposition hits.
BDSOutput * output
Cache of output instance. Not owned by this class.
BDSTrajectoriesToStore * IdentifyTrajectoriesForStorage(const G4Event *evt, G4bool verboseThisEvent, BDSHitsCollectionEnergyDeposition *eCounterHits, BDSHitsCollectionEnergyDeposition *eCounterFullHits, const std::vector< BDSHitsCollectionSampler * > &allSamplerHits, G4int nChar=50) const
Sift through all trajectories (if any) and mark for storage.
G4int samplerCollID_plane
Collection ID for plane sampler hits.
long long int nTracks
Accumulated number of tracks for the event.
std::map< G4String, G4int > extraSamplerSphereCollectionIDs
Collection IDs for extra samplers.
time_t startTime
Time at the start of the event.
std::map< G4String, G4int > scorerCollectionIDs
Collection IDs for all scorers.
G4bool trajConnect
Cache of variable from global constants.
BDSEventInfo * eventInfo
G4int apertureCollID
Collection ID for the aperture hits.
std::vector< int > trajectorySamplerID
Cache of variable from global constants.
std::map< G4String, G4int > extraSamplerCollectionIDs
Collection IDs for extra samplers.
G4double trajectoryCutR
Cache of variable from global constants.
G4String trajParticleNameToStore
Cache of variable from global constants.
G4double stops
Precise stop time in seconds.
std::clock_t cpuStartTime
CPU time at the start of the event.
G4int trajDepth
Cache of variable from global constants.
std::map< G4int, const BDSTrajectoryPrimary * > primaryTrajectoriesCache
G4int eCounterID
Collection ID for general energy deposition hits.
void RegisterPrimaryTrajectory(const BDSTrajectoryPrimary *trajectoryIn)
Append this trajectory to vector of primaries we keep to avoid sifting at the end of event.
G4int samplerCollID_sphere
Collection ID for spherical sampler hits.
G4bool storeTrajectoryAll
Store all trajectories irrespective of filters.
time_t stopTime
Time at the end of the event.
G4double starts
Precise start time in seconds.
G4int eCounterTunnelID
Collection ID for the tunnel energy deposition hits.
G4double trajectoryEnergyThreshold
Cache of variable from global constants.
Interface to store event information use G4 hooks.
void SetPrimaryAbsorbedInCollimator(G4bool absorbed)
Setters.
void SetNTracks(long long int nTracks)
Setters.
void SetStopTime(const time_t &stopTimeIn)
Setters.
void SetMemoryUsage(G4double memoryUsageMbIn)
Setters.
void SetPrimaryHitMachine(G4bool hitIn)
Setters.
void SetStartTime(const time_t &startTimeIn)
Setters.
void SetIndex(G4int indexIn)
Setters.
void SetAborted(G4bool abortedIn)
Setters.
void SetDurationCPU(G4float durationCPUIn)
Setters.
void SetDurationWall(G4float durationWallIn)
Setters.
A class that holds global options and constants.
static BDSGlobalConstants * Instance()
Access method.
Information recorded for a single piece of energy deposition.
G4int GetTrackID() const
Accessor for extra piece of information.
static void SetEventIndex(G4int eventIndexIn)
Setter for the static counter so we can trace where it's used.
Output base class that defines interface for all output types.
Definition BDSOutput.hh:72
void CloseAndOpenNewFile()
Close a file and open a new one.
Definition BDSOutput.cc:373
void FillEvent(const BDSEventInfo *info, const G4PrimaryVertex *vertex, const std::vector< BDSHitsCollectionSampler * > &samplerHitsPlane, const std::vector< BDSHitsCollectionSamplerCylinder * > &samplerHitsCylinder, const std::vector< BDSHitsCollectionSamplerSphere * > &samplerHitsSphere, const BDSHitsCollectionSamplerLink *samplerHitsLink, const BDSHitsCollectionEnergyDeposition *energyLoss, const BDSHitsCollectionEnergyDeposition *energyLossFull, const BDSHitsCollectionEnergyDeposition *energyLossVacuum, const BDSHitsCollectionEnergyDeposition *energyLossTunnel, const BDSHitsCollectionEnergyDepositionGlobal *energyLossWorld, const BDSHitsCollectionEnergyDepositionGlobal *energyLossWorldContents, const BDSHitsCollectionEnergyDepositionGlobal *worldExitHits, const std::vector< const BDSTrajectoryPointHit * > &primaryHits, const std::vector< const BDSTrajectoryPointHit * > &primaryLosses, const BDSTrajectoriesToStore *trajectories, const BDSHitsCollectionCollimator *collimatorHits, const BDSHitsCollectionApertureImpacts *apertureImpactHits, const std::map< G4String, G4THitsMap< G4double > * > &scorerHitsMap, const G4int turnsTaken)
Copy event information from Geant4 simulation structures to output structures.
Definition BDSOutput.cc:298
A singleton class that holds all required sensitive detector class instances.
BDSSDEnergyDeposition * EnergyDeposition() const
SD for general energy deposition.
BDSSDVolumeExit * WorldExit() const
SD for world exit hits.
BDSSDEnergyDeposition * EnergyDepositionTunnel() const
SD for tunnel energy counter.
const std::vector< G4String > & ExtraSamplerCylinderWithFilterNamesComplete() const
Access a vector of names of extra samplers so we can identify the hits collections.
const std::vector< G4String > & ExtraSamplerSphereWithFilterNamesComplete() const
Access a vector of names of extra samplers so we can identify the hits collections.
BDSSDEnergyDeposition * EnergyDepositionFull() const
SD for general energy deposition but always include extra half of information.
BDSSDCollimator * Collimator() const
SD for collimator impact locations.
BDSSDThinThing * ThinThing() const
BDSSDApertureImpacts * ApertureImpacts() const
SD for aperture impact hits.
BDSSDSamplerCylinder * SamplerCylinder() const
SD for samplers (cylinder type).
const std::vector< G4String > & PrimitiveScorerNamesComplete() const
Access a vector the full primitive scorer names as registered.
BDSSDSampler * SamplerPlane() const
SD for samplers (plane type). See also SamplerPlaneWithFilter below.
BDSSDSamplerSphere * SamplerSphere() const
SD for samplers (sphere type).
BDSSDEnergyDepositionGlobal * EnergyDepositionWorldContents() const
SD for energy deposition in things that were already placed in the externally provided world.
BDSSDEnergyDepositionGlobal * EnergyDepositionWorld() const
SD for energy deposition in the world volume.
BDSSDEnergyDeposition * EnergyDepositionVacuum() const
SD for energy deposition in vacuum volumes.
const std::vector< G4String > & ExtraSamplerWithFilterNamesComplete() const
Access a vector of names of extra samplers so we can identify the hits collections.
static G4int eventNumber
Externally accessible counter for event number. Set in BeginOfEventAction.
Information about a registered sampler.
static BDSSamplerRegistry * Instance()
Accessor for registry.
const BDSSamplerPlacementRecord & GetInfo(G4int index) const
Accessor.
Double map of trajectories to bitset of which filters matched whether to store them.
A summary trajectory object of a loss point.
A Point in a trajectory with extra information.
G4double PostPosR() const
Return the transverse local radius in x,y.
Trajectory information for only the primary.
Trajectory information from track including last scatter etc.
static G4int nCallsThisEvent
Counter for understanding occurence.
G4double GetMemoryUsage()
Get the current memory usage.
G4bool VerboseThisEvent(G4int eventIndex, G4int eventStart, G4int eventStop)
Logic of whether this event should be verbose or not. Code here so it's not duplicated.
G4int VerboseEventStop(G4int verboseEventStart, G4int verboseEventContinueFor)
STL namespace.