BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
BDSEventAction.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) Royal Holloway,
3University of London 2001 - 2022.
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 "BDSAuxiliaryNavigator.hh"
20#include "BDSDebug.hh"
21#include "BDSEventAction.hh"
22#include "BDSEventInfo.hh"
23#include "BDSGlobalConstants.hh"
24#include "BDSHitEnergyDeposition.hh"
25#include "BDSHitEnergyDepositionExtra.hh"
26#include "BDSHitEnergyDepositionGlobal.hh"
27#include "BDSHitSampler.hh"
28#include "BDSHitThinThing.hh"
29#include "BDSOutput.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 "BDSTrajectoryPrimary.hh"
49#include "BDSUtilities.hh"
50#include "BDSWrapperMuonSplitting.hh"
51
52#include "globals.hh" // geant4 types / globals
53#include "G4Event.hh"
54#include "G4EventManager.hh"
55#include "G4HCofThisEvent.hh"
56#include "G4PrimaryVertex.hh"
57#include "G4PrimaryParticle.hh"
58#include "G4PropagatorInField.hh"
59#include "G4Run.hh"
60#include "G4SDManager.hh"
61#include "G4StackManager.hh"
62#include "G4THitsMap.hh"
63#include "G4TrajectoryContainer.hh"
64#include "G4TrajectoryPoint.hh"
65#include "BDSTrajectoryPointHit.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 seedStateAtStart(""),
102 currentEventIndex(0),
103 eventInfo(nullptr),
104 nTracks(0)
105{
107 verboseEventBDSIM = globals->VerboseEventBDSIM();
108 verboseEventStart = globals->VerboseEventStart();
109 verboseEventStop = BDS::VerboseEventStop(verboseEventStart, globals->VerboseEventContinueFor());
110 storeTrajectory = globals->StoreTrajectory();
111 storeTrajectoryAll = globals->StoreTrajectoryAll();
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 // reset navigators to ensure no mis-navigating and that events are truly independent
147 BDSAuxiliaryNavigator::ResetNavigatorStates();
148 BDSNavigatorPlacements::ResetNavigatorStates();
149 // make further attempts to clear Geant4's tracking history between events to make them
150 // truly independent.
151 G4Navigator* trackingNavigator = G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking();
152 trackingNavigator->ResetStackAndState();
153 G4TransportationManager* tm = G4TransportationManager::GetTransportationManager();
154 int i = 0;
155 for (auto it = tm->GetActiveNavigatorsIterator(); i < (int)tm->GetNoActiveNavigators(); it++)
156 {(*it)->ResetStackAndState(); i++;}
157 tm->GetPropagatorInField()->ClearPropagatorState(); // <- this one really makes a difference
158
159 // Unfortunately the interfaces to G4TransportationManager aren't great which makes this a bit
160 // pedantic. Also, the GetNavigator creates an exception if it doesn't find what it's looking
161 // for rather than just return a nullptr
162 G4bool samplerWorldExists = false;
163 std::vector<G4VPhysicalVolume*>::iterator worldIterator = tm->GetWorldsIterator();
164 for (G4int iw = 0; iw < (G4int)tm->GetNoWorlds(); iw++)
165 {
166 samplerWorldExists = samplerWorldExists || (*worldIterator)->GetName() == "SamplerWorld_main";
167 worldIterator++;
168 }
169 if (samplerWorldExists)
170 {
171 auto swtracker = tm->GetNavigator("SamplerWorld_main");
172 if (swtracker)
173 {swtracker->ResetStackAndState();}
174 }
175 fpEventManager->GetStackManager()->clear();
176
177 // update reference to event info
178 eventInfo = static_cast<BDSEventInfo*>(evt->GetUserInformation());
179
180 // number feedback
181 G4int event_number = evt->GetEventID();
182 BDSSDTerminator::eventNumber = event_number; // update static member of terminator
183 eventInfo->SetIndex(event_number);
184 if (event_number%printModulo == 0)
185 {G4cout << "---> Begin of event: " << event_number << G4endl;}
186 if (verboseEventBDSIM) // always print this out
187 {G4cout << __METHOD_NAME__ << "event #" << event_number << G4endl;}
188
189 // cache hit collection IDs for quicker access
190 if (samplerCollID_plane < 0)
191 { // if one is -1 then all need initialised.
192 G4SDManager* g4SDMan = G4SDManager::GetSDMpointer();
193 BDSSDManager* bdsSDMan = BDSSDManager::Instance();
194 samplerCollID_plane = g4SDMan->GetCollectionID(bdsSDMan->SamplerPlane()->GetName());
195 samplerCollID_cylin = g4SDMan->GetCollectionID(bdsSDMan->SamplerCylinder()->GetName());
196 samplerCollID_sphere = g4SDMan->GetCollectionID(bdsSDMan->SamplerSphere()->GetName());
197 eCounterID = g4SDMan->GetCollectionID(bdsSDMan->EnergyDeposition()->GetName());
198 eCounterFullID = g4SDMan->GetCollectionID(bdsSDMan->EnergyDepositionFull()->GetName());
199 eCounterVacuumID = g4SDMan->GetCollectionID(bdsSDMan->EnergyDepositionVacuum()->GetName());
200 eCounterTunnelID = g4SDMan->GetCollectionID(bdsSDMan->EnergyDepositionTunnel()->GetName());
201 eCounterWorldID = g4SDMan->GetCollectionID(bdsSDMan->EnergyDepositionWorld()->GetName());
202 eCounterWorldContentsID = g4SDMan->GetCollectionID(bdsSDMan->EnergyDepositionWorldContents()->GetName());
203 worldExitCollID = g4SDMan->GetCollectionID(bdsSDMan->WorldExit()->GetName());
204 collimatorCollID = g4SDMan->GetCollectionID(bdsSDMan->Collimator()->GetName());
205 apertureCollID = g4SDMan->GetCollectionID(bdsSDMan->ApertureImpacts()->GetName());
206 thinThingCollID = g4SDMan->GetCollectionID(bdsSDMan->ThinThing()->GetName());
207 const std::vector<G4String>& scorerNames = bdsSDMan->PrimitiveScorerNamesComplete();
208 for (const auto& name : scorerNames)
209 {scorerCollectionIDs[name] = g4SDMan->GetCollectionID(name);}
210 const std::vector<G4String>& extraSamplerWithFilterNames = bdsSDMan->ExtraSamplerWithFilterNamesComplete();
211 for (const auto& name : extraSamplerWithFilterNames)
212 {extraSamplerCollectionIDs[name] = g4SDMan->GetCollectionID(name);}
213 const std::vector<G4String>& extraSamplerCylinderWithFilterNames = bdsSDMan->ExtraSamplerCylinderWithFilterNamesComplete();
214 for (const auto& name : extraSamplerCylinderWithFilterNames)
215 {extraSamplerCylinderCollectionIDs[name] = g4SDMan->GetCollectionID(name);}
216 const std::vector<G4String>& extraSamplerSphereWithFilterNames = bdsSDMan->ExtraSamplerSphereWithFilterNamesComplete();
217 for (const auto& name : extraSamplerSphereWithFilterNames)
218 {extraSamplerCollectionIDs[name] = g4SDMan->GetCollectionID(name);}
219 }
220 FireLaserCompton=true;
221
222 cpuStartTime = std::clock();
223 // get the current time - last thing before we hand off to geant4
224 startTime = time(nullptr);
226 eventInfo->SetStopTime(startTime); // initialise to duration of 0
227
228 milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
229 starts = (G4double)ms.count()/1000.0;
230}
231
232void BDSEventAction::EndOfEventAction(const G4Event* evt)
233{
234 //G4cout << "BDSWrapperMuonSplitting::nCallsThisEvent> " << BDSWrapperMuonSplitting::nCallsThisEvent << G4endl;
235 auto flagsCache(G4cout.flags());
236 // Get event number information
237 G4int event_number = evt->GetEventID();
238 G4bool verboseThisEvent = verboseEventBDSIM && BDS::VerboseThisEvent(event_number, verboseEventStart, verboseEventStop);
239#ifdef BDSDEBUG
240 verboseThisEvent = true; // force on for debug mode
241#endif
242 const G4int nChar = 50; // for print out
243 if (verboseThisEvent)
244 {G4cout << __METHOD_NAME__ << "processing end of event"<<G4endl;}
245 eventInfo->SetIndex(event_number);
246
247 // Record if event was aborted - ie whether it's usable for analyses.
248 eventInfo->SetAborted(evt->IsAborted());
250
251 // Calculate the elapsed CPU time for the event.
252 auto cpuEndTime = std::clock();
253 G4float durationCPU = static_cast<G4float>(cpuEndTime - cpuStartTime) / CLOCKS_PER_SEC;
254 eventInfo->SetDurationCPU(durationCPU);
255
256 // Get the current wall time
257 stopTime = time(nullptr);
259
260 // Timing information (wall)
261 milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
262 stops = (G4double)ms.count()/1000.0;
264
265 G4double memoryUsedMb = BDS::GetMemoryUsage();
266 eventInfo->SetMemoryUsage(memoryUsedMb);
267
268 // cache if primary was absorbed in a collimator
270
271 // feedback
272 if (verboseThisEvent)
273 {eventInfo->Print();}
274
275 // Get the hits collection of this event - all hits from different SDs.
276 G4HCofThisEvent* HCE = evt->GetHCofThisEvent();
277
278 // samplers
279 typedef BDSHitsCollectionSampler shc;
280 std::vector<shc*> allSamplerHits;
281 shc* SampHC = HCE ? dynamic_cast<shc*>(HCE->GetHC(samplerCollID_plane)) : nullptr;
282 if (SampHC)
283 {allSamplerHits.push_back(SampHC);}
284 if (HCE)
285 {
286 for (const auto& nameIndex : extraSamplerCollectionIDs)
287 {allSamplerHits.push_back(dynamic_cast<shc*>(HCE->GetHC(nameIndex.second)));}
288 }
290 std::vector<shcc*> allSamplerCylinderHits;
291 shcc* hitsCylinder = HCE ? dynamic_cast<shcc*>(HCE->GetHC(samplerCollID_cylin)) : nullptr;
292 if (hitsCylinder)
293 {allSamplerCylinderHits.push_back(hitsCylinder);}
294 if (HCE)
295 {
296 for (const auto& nameIndex : extraSamplerCylinderCollectionIDs)
297 {allSamplerCylinderHits.push_back(dynamic_cast<shcc*>(HCE->GetHC(nameIndex.second)));}
298 }
300 std::vector<shcs*> allSamplerSphereHits;
301 shcs* hitsSphere = HCE ? dynamic_cast<shcs*>(HCE->GetHC(samplerCollID_sphere)) : nullptr;
302 if (hitsSphere)
303 {allSamplerSphereHits.push_back(hitsSphere);}
304 if (HCE)
305 {
306 for (const auto& nameIndex : extraSamplerSphereCollectionIDs)
307 {allSamplerSphereHits.push_back(dynamic_cast<shcs*>(HCE->GetHC(nameIndex.second)));}
308 }
309
310 // energy deposition collections - eloss, tunnel hits
312 echc* eCounterHits = HCE ? dynamic_cast<echc*>(HCE->GetHC(eCounterID)) : nullptr;
313 echc* eCounterFullHits = HCE ? dynamic_cast<echc*>(HCE->GetHC(eCounterFullID)) : nullptr;
314 echc* eCounterVacuumHits = HCE ? dynamic_cast<echc*>(HCE->GetHC(eCounterVacuumID)) : nullptr;
315 echc* eCounterTunnelHits = HCE ? dynamic_cast<echc*>(HCE->GetHC(eCounterTunnelID)) : nullptr;
316
317 // world exit hits
319 ecghc* eCounterWorldHits = HCE ? dynamic_cast<ecghc*>(HCE->GetHC(eCounterWorldID)) : nullptr;
320 ecghc* eCounterWorldContentsHits = HCE ? dynamic_cast<ecghc*>(HCE->GetHC(eCounterWorldContentsID)) : nullptr;
321 ecghc* worldExitHits = HCE ? dynamic_cast<ecghc*>(HCE->GetHC(worldExitCollID)) : nullptr;
322
323 // aperture hits
325 aihc* apertureImpactHits = HCE ? dynamic_cast<aihc*>(HCE->GetHC(apertureCollID)) : nullptr;
326
327 // thin thing hits
328 typedef BDSHitsCollectionThinThing tthc;
329 tthc* thinThingHits = HCE ? dynamic_cast<tthc*>(HCE->GetHC(thinThingCollID)) : nullptr;
330
331 std::map<G4String, G4THitsMap<G4double>*> scorerHits;
332 if (HCE)
333 {
334 for (const auto& nameIndex : scorerCollectionIDs)
335 {scorerHits[nameIndex.first] = dynamic_cast<G4THitsMap<G4double>*>(HCE->GetHC(nameIndex.second));}
336 }
337 // primary hit something? we infer this by seeing if there are any energy
338 // deposition hits at all - if there are, the primary must have 'hit' something.
339 // we don't check the world energy hits here because the hits could be from
340 // intended transport through air in part of the machine (a gap). similarly, there
341 // could be ionisation of the vacuum gas without a real impact so we don't check
342 // the vacuum energy deposition
343 if (eCounterHits)
344 {
345 if (verboseThisEvent)
346 {G4cout << std::left << std::setw(nChar) << "Energy deposition hits: " << eCounterHits->entries() << G4endl;}
347 if (eCounterHits->entries() > 0)
349 }
350 if (eCounterFullHits)
351 {
352 if (verboseThisEvent)
353 {G4cout << std::left << std::setw(nChar) << "Energy deposition full hits: " << eCounterFullHits->entries() << G4endl;}
354 if (eCounterFullHits->entries() > 0)
356 }
357 if (eCounterTunnelHits)
358 {
359 if (verboseThisEvent)
360 {G4cout << std::left << std::setw(nChar) << "Tunnel energy deposition hits: " << eCounterTunnelHits->entries() << G4endl;}
361 if (eCounterTunnelHits->entries() > 0)
363 }
364
365 // collimator hits if any
366 typedef BDSHitsCollectionCollimator chc;
367 chc* collimatorHits = HCE ? dynamic_cast<chc*>(HCE->GetHC(collimatorCollID)) : nullptr;
368
369 if (verboseThisEvent)
370 {
371 if (eCounterVacuumHits)
372 {G4cout << std::left << std::setw(nChar) << "Vacuum energy deposition hits: " << eCounterVacuumHits->entries() << G4endl;}
373 if (eCounterWorldHits)
374 {G4cout << std::left << std::setw(nChar) << "World energy deposition hits: " << eCounterWorldHits->entries() << G4endl;}
375 if (eCounterWorldContentsHits)
376 {G4cout << std::left << std::setw(nChar) << "World contents energy deposition hits: " << eCounterWorldContentsHits->entries() << G4endl;}
377 if (worldExitHits)
378 {G4cout << std::left << std::setw(nChar) << "World exit hits: " << worldExitHits->entries() << G4endl;}
379 if (collimatorHits)
380 {G4cout << std::left << std::setw(nChar) << "Collimator hits: " << collimatorHits->entries() << G4endl;}
381 }
382
383 // primary hits and losses
384 std::vector<const BDSTrajectoryPointHit*> primaryHits;
385 std::vector<const BDSTrajectoryPointHit*> primaryLosses;
386 G4TrajectoryContainer* trajCont = evt->GetTrajectoryContainer();
387 if (trajCont)
388 {
389 if (verboseThisEvent)
390 {G4cout << std::left << std::setw(nChar) << "Trajectories: " << trajCont->size() << G4endl;}
391 for (auto p : primaryTrajectoriesCache)
392 {primaryLosses.push_back(new BDSTrajectoryPointHit(p.second, p.second->LastPoint()));}
393 }
394 std::vector<const BDSTrajectoryPrimary*> primaryTrajectories;
395 for (auto kv : primaryTrajectoriesCache)
396 {primaryTrajectories.push_back(kv.second);}
397 primaryHits = BDSHitThinThing::ResolvePossibleEarlierThinHits(primaryTrajectories, thinThingHits);
398
399 BDSTrajectoriesToStore* interestingTrajectories = IdentifyTrajectoriesForStorage(evt,
400 verboseEventBDSIM || verboseThisEvent,
401 eCounterHits,
402 eCounterFullHits,
403 allSamplerHits,
404 nChar);
405
407 evt->GetPrimaryVertex(),
408 allSamplerHits,
409 allSamplerCylinderHits,
410 allSamplerSphereHits,
411 nullptr,
412 eCounterHits,
413 eCounterFullHits,
414 eCounterVacuumHits,
415 eCounterTunnelHits,
416 eCounterWorldHits,
417 eCounterWorldContentsHits,
418 worldExitHits,
419 primaryHits,
420 primaryLosses,
421 interestingTrajectories,
422 collimatorHits,
423 apertureImpactHits,
424 scorerHits,
425 BDSGlobalConstants::Instance()->TurnsTaken());
426
427 // if events per ntuples not set (default 0) - only write out at end
428 G4int evntsPerNtuple = BDSGlobalConstants::Instance()->NumberOfEventsPerNtuple();
429 if (evntsPerNtuple>0 && (event_number+1)%evntsPerNtuple == 0)
430 {
431 // note the timing information will be wrong here as the run hasn't finished but
432 // the file is bridged. There's no good way around this just now as this class
433 // can't access the timing information stored in BDSRunAction
435 }
436
437 if (verboseThisEvent)
438 {
439 G4cout << __METHOD_NAME__ << "end of event action done" << G4endl;
440 G4cout << "Energy deposition pool size: " << BDSAllocatorEnergyDeposition.GetAllocatedSize() << G4endl;
441 G4cout << "Energy deposition extra pool size: " << BDSAllocatorEnergyDepositionExtra.GetAllocatedSize() << G4endl;
442 G4cout << "Collimator hits pool size: " << BDSAllocatorCollimator.GetAllocatedSize() << G4endl;
443 G4cout << "Trajectory pool size: " << bdsTrajectoryAllocator.GetAllocatedSize() << G4endl;
444 G4cout << "Trajectory point pool size bdsim: " << bdsTrajectoryPointAllocator.GetAllocatedSize() << G4endl;
445#if G4VERSION_NUMBER > 1049
446 G4cout << "Trajectory point pool size: " << aTrajectoryPointAllocator()->GetAllocatedSize() << G4endl;
447#else
448 G4cout << "Trajectory point pool size: " << aTrajectoryPointAllocator->GetAllocatedSize() << G4endl;
449#endif
450 G4cout << "Trajectory point primary pool size: " << bdsTrajectoryPrimaryAllocator.GetAllocatedSize() << G4endl;
451 }
452
453 delete interestingTrajectories;
454 for (auto& p : primaryLosses)
455 {delete p;}
456 for (auto& p : primaryHits)
457 {delete p;}
458
459 G4cout.flags(flagsCache);
460}
461
463 G4bool verbose,
465 BDSHitsCollectionEnergyDeposition* eCounterFullHits,
466 const std::vector<BDSHitsCollectionSampler*>& allSamplerHits,
467 G4int nChar) const
468{
469 auto flagsCache(G4cout.flags());
470 G4TrajectoryContainer* trajCont = evt->GetTrajectoryContainer();
471
472 // Save interesting trajectories
473 std::map<BDSTrajectory*, bool> interestingTraj;
474 std::map<BDSTrajectory*, std::bitset<BDS::NTrajectoryFilters> > trajectoryFilters;
475
476 if (storeTrajectory && trajCont)
477 {
478 TrajectoryVector* trajVec = trajCont->GetVector();
479
480 // build trackID map, depth map
481 std::map<int, BDSTrajectory*> trackIDMap;
482 std::map<BDSTrajectory*, int> depthMap;
483 for (auto iT1 : *trajVec)
484 {
485 BDSTrajectory* traj = static_cast<BDSTrajectory*>(iT1);
486
487 // fill track ID map
488 trackIDMap[traj->GetTrackID()] = traj;
489
490 // fill depth map
491 G4int depth = traj->GetParentID() == 0 ? 0 : depthMap.at(trackIDMap.at(traj->GetParentID())) + 1;
492 traj->SetDepth(depth);
493 if (traj->GetParentID() == 0)
494 {depthMap[traj] = 0;}
495 else
496 {depthMap[traj] = depthMap.at(trackIDMap.at(traj->GetParentID())) + 1;}
497 }
498
499 // fill parent pointer - this can only be done once the map in the previous loop has been made
500 for (auto iT1 : *trajVec)
501 {
502 BDSTrajectory* traj = static_cast<BDSTrajectory*>(iT1);
503 // the parent ID may be 0 and therefore it may not be in the map but the [] operator
504 // will default-construct it giving therefore a nullptr
505 traj->SetParent(trackIDMap[iT1->GetParentID()]);
506 }
507
508 // loop over trajectories and determine if it should be stored
509 // keep tallies of how many will and won't be stored
510 G4int nYes = 0;
511 G4int nNo = 0;
512 for (auto iT1 : *trajVec)
513 {
514 std::bitset<BDS::NTrajectoryFilters> filters;
515
516 BDSTrajectory* traj = static_cast<BDSTrajectory*>(iT1);
517 G4int parentID = traj->GetParentID();
518
519 // always store primaries
520 if (parentID == 0)
521 {filters[BDSTrajectoryFilter::primary] = true;}
522
523 // check on energy (if energy threshold is not negative)
524 if (trajectoryEnergyThreshold >= 0 &&
525 traj->GetInitialKineticEnergy() > trajectoryEnergyThreshold)
526 {filters[BDSTrajectoryFilter::energyThreshold] = true;}
527
528 // check on particle if not empty string
529 if (!trajParticleNameToStore.empty() || !trajParticleIDToStore.empty())
530 {
531 G4String particleName = traj->GetParticleName();
532 G4int particleID = traj->GetPDGEncoding();
533 G4String particleIDStr = G4String(std::to_string(particleID));
534 std::size_t found1 = trajParticleNameToStore.find(particleName);
535 bool found2 = (std::find(trajParticleIDIntToStore.begin(), trajParticleIDIntToStore.end(), particleID)
536 != trajParticleIDIntToStore.end());
537 if ((found1 != std::string::npos) || found2)
538 {filters[BDSTrajectoryFilter::particle] = true;}
539 }
540
541 // check on trajectory tree depth (trajDepth = 0 means only primaries)
542 if (depthMap[traj] <= trajDepth || storeTrajectoryAll) // all means to infinite trajDepth really
543 {filters[BDSTrajectoryFilter::depth] = true;}
544
545 // check on coordinates (and TODO momentum)
546 // clear out trajectories that don't reach point TrajCutGTZ or greater than TrajCutLTR
547 BDSTrajectoryPoint* trajEndPoint = static_cast<BDSTrajectoryPoint*>(traj->GetPoint(traj->GetPointEntries() - 1));
548
549 // end point greater than some Z
550 if (trajEndPoint->GetPosition().z() > trajectoryCutZ)
551 {filters[BDSTrajectoryFilter::minimumZ] = true;}
552
553 // less than maximum R
554 if (trajEndPoint->PostPosR() < trajectoryCutR)
555 {filters[BDSTrajectoryFilter::maximumR] = true;}
556
557 filters.any() ? nYes++ : nNo++;
558 interestingTraj.insert(std::pair<BDSTrajectory*, bool>(traj, filters.any()));
559 trajectoryFilters.insert(std::pair<BDSTrajectory*, std::bitset<BDS::NTrajectoryFilters> >(traj, filters));
560 }
561
562 // loop over energy hits to connect trajectories
563 if (!trajSRangeToStore.empty())
564 {
565 if (eCounterHits)
566 {
567 G4int nHits = (G4int)eCounterHits->entries();
569 for (G4int i = 0; i < nHits; i++)
570 {
571 hit = (*eCounterHits)[i];
572 double dS = hit->GetSHit();
573 for (const auto& v : trajSRangeToStore)
574 {
575 if ( dS >= v.first && dS <= v.second)
576 {
577 BDSTrajectory* trajToStore = trackIDMap[hit->GetTrackID()];
578 if (!interestingTraj[trajToStore])
579 {// was marked as not storing - update counters
580 nYes++;
581 nNo--;
582 }
583 interestingTraj[trajToStore] = true;
584 trajectoryFilters[trajToStore][BDSTrajectoryFilter::elossSRange] = true;
585 break;
586 }
587 }
588 }
589 }
590 if (eCounterFullHits)
591 {
592 G4int nHits = (G4int)eCounterFullHits->entries();
594 for (G4int i = 0; i < nHits; i++)
595 {
596 hit = (*eCounterFullHits)[i];
597 double dS = hit->GetSHit();
598 for (const auto& v : trajSRangeToStore)
599 {
600 if ( dS >= v.first && dS <= v.second)
601 {
602 BDSTrajectory* trajToStore = trackIDMap[hit->GetTrackID()];
603 if (!interestingTraj[trajToStore])
604 {// was marked as not storing - update counters
605 nYes++;
606 nNo--;
607 }
608 interestingTraj[trajToStore] = true;
609 trajectoryFilters[trajToStore][BDSTrajectoryFilter::elossSRange] = true;
610 break;
611 }
612 }
613 }
614 }
615 }
616
617 // loop over samplers to connect trajectories
618 for (const auto& SampHC : allSamplerHits)
619 {
620 if (!trajectorySamplerID.empty() && SampHC)
621 {
622 for (G4int i = 0; i < (G4int)SampHC->entries(); i++)
623 {
624 G4int samplerIndex = (*SampHC)[i]->samplerID;
626 if (std::find(trajectorySamplerID.begin(), trajectorySamplerID.end(), samplerIndex) !=
628 {
629 BDSTrajectory* trajToStore = trackIDMap[(*SampHC)[i]->trackID];
630 if (!interestingTraj[trajToStore])
631 {// was marked as not storing - update counters
632 nYes++;
633 nNo--;
634 }
635 interestingTraj[trajToStore] = true;
636 trajectoryFilters[trajToStore][BDSTrajectoryFilter::sampler] = true;
637 }
638 }
639 }
640 }
641
642 // If we're using AND logic (default OR) with the filters, loop over and update whether
643 // we should really store the trajectory or not. Importantly, we do this before the connect
644 // trajectory step as that flags yet more trajectories (that connect each one) back to the
645 // primary
647 {
648 for (auto& trajFlag : interestingTraj)
649 {
650 if (trajFlag.second) // if we're going to store it check the logic
651 {
652 // use bit-wise AND filters matched for this trajectory with filters set
653 // if count of 1s the same, then trajectory should be stored, therefore if
654 // not the same, it should be set to false.
655 auto filterMatch = trajectoryFilters[trajFlag.first] & trajFiltersSet;
656 if (filterMatch.count() != trajFiltersSet.count())
657 {trajFlag.second = false;}
658 }
659 }
660 }
661
662 // Connect trajectory graphs
663 if (trajConnect && trackIDMap.size() > 1)
664 {
665 for (auto i : interestingTraj)
666 if (i.second)
667 {ConnectTrajectory(interestingTraj, i.first, trajectoryFilters);}
668 }
669 // Output interesting trajectories
670 if (verbose)
671 {G4cout << std::left << std::setw(nChar) << "Trajectories for storage: " << nYes << " out of " << nYes + nNo << G4endl;}
672 }
673 G4cout.flags(flagsCache);
674 return new BDSTrajectoriesToStore(interestingTraj, trajectoryFilters);
675}
676
677void BDSEventAction::ConnectTrajectory(std::map<BDSTrajectory*, bool>& interestingTraj,
678 BDSTrajectory* trajectoryToConnect,
679 std::map<BDSTrajectory*, std::bitset<BDS::NTrajectoryFilters> >& trajectoryFilters) const
680{
681 BDSTrajectory* parentTrajectory = trajectoryToConnect->GetParent();
682 if (parentTrajectory)
683 {
684 interestingTraj[parentTrajectory] = true;
685 trajectoryFilters[parentTrajectory][BDSTrajectoryFilter::connect] = true;
686 ConnectTrajectory(interestingTraj, parentTrajectory, trajectoryFilters);
687 }
688 else
689 {return;}
690}
691
693{
694 G4int trackID = trajectoryIn->GetTrackID();
695 if (primaryTrajectoriesCache.find(trackID) == primaryTrajectoriesCache.end())
696 {primaryTrajectoriesCache[trackID] = trajectoryIn;}
697}
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.
Definition: BDSEventInfo.hh:42
void SetPrimaryAbsorbedInCollimator(G4bool absorbed)
Setters.
Definition: BDSEventInfo.hh:59
void SetNTracks(long long int nTracks)
Setters.
Definition: BDSEventInfo.hh:60
void SetStopTime(const time_t &stopTimeIn)
Setters.
Definition: BDSEventInfo.hh:51
void SetMemoryUsage(G4double memoryUsageMbIn)
Setters.
Definition: BDSEventInfo.hh:58
void SetPrimaryHitMachine(G4bool hitIn)
Setters.
Definition: BDSEventInfo.hh:57
void SetStartTime(const time_t &startTimeIn)
Setters.
Definition: BDSEventInfo.hh:50
void SetIndex(G4int indexIn)
Setters.
Definition: BDSEventInfo.hh:55
void SetAborted(G4bool abortedIn)
Setters.
Definition: BDSEventInfo.hh:56
void SetDurationCPU(G4float durationCPUIn)
Setters.
Definition: BDSEventInfo.hh:53
void SetDurationWall(G4float durationWallIn)
Setters.
Definition: BDSEventInfo.hh:52
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.
Output base class that defines interface for all output types.
Definition: BDSOutput.hh:73
void CloseAndOpenNewFile()
Close a file and open a new one.
Definition: BDSOutput.cc:364
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:289
A singleton class that holds all required sensitive detector class instances.
Definition: BDSSDManager.hh:68
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).
Definition: BDSSDManager.hh:89
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.
Definition: BDSSDManager.hh:86
BDSSDSamplerSphere * SamplerSphere() const
SD for samplers (sphere type).
Definition: BDSSDManager.hh:92
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.
virtual int GetPointEntries() const
Get number of trajectory points in this trajectory.
virtual G4VTrajectoryPoint * GetPoint(G4int i) const
Access a point - use this class's container.
void SetParent(BDSTrajectory *parentIn)
Record the parent trajectory.
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)