diff --git a/source/event/include/G4EventManager.hh b/source/event/include/G4EventManager.hh index 623861bb172f11e4f66785a0de78482ec5152670..a38eebf01d11d46aac5c4d880f6c2c3cc8cbf929 100644 --- a/source/event/include/G4EventManager.hh +++ b/source/event/include/G4EventManager.hh @@ -88,6 +88,10 @@ class G4EventManager // object has valid primary vertices/particles, they will be added to // the given "trackvector" input. + void StackTracks(G4TrackVector* trackVector, G4bool IDhasAlreadySet= false); + // Helper function to stack a vector of tracks for processing in the + // current event. + inline const G4Event* GetConstCurrentEvent() { return currentEvent; } inline G4Event* GetNonconstCurrentEvent() @@ -156,7 +160,6 @@ class G4EventManager private: void DoProcessing(G4Event* anEvent); - void StackTracks(G4TrackVector* trackVector, G4bool IDhasAlreadySet= false); private: diff --git a/source/event/src/G4EventManager.cc b/source/event/src/G4EventManager.cc index 6032d47956be296f870a52160066c64ff196ebc2..6cce554cb3d045c952c2ccb0fcc3a956c1783305 100644 --- a/source/event/src/G4EventManager.cc +++ b/source/event/src/G4EventManager.cc @@ -32,6 +32,8 @@ #include "G4ios.hh" #include "G4EvManMessenger.hh" #include "G4Event.hh" +#include "G4ParticleDefinition.hh" +#include "G4VTrackingManager.hh" #include "G4UserEventAction.hh" #include "G4UserStackingAction.hh" #include "G4SDManager.hh" @@ -43,6 +45,7 @@ #include "G4Profiler.hh" #include "G4TiMemory.hh" +#include <unordered_set> #include "G4GlobalFastSimulationManager.hh" G4ThreadLocal G4EventManager* G4EventManager::fpEventManager = nullptr; @@ -107,7 +110,7 @@ void G4EventManager::DoProcessing(G4Event* anEvent) G4Navigator* navigator = G4TransportationManager::GetTransportationManager() ->GetNavigatorForTracking(); navigator->LocateGlobalPointAndSetup(center,0,false); - + G4Track* track = nullptr; G4TrackStatus istop = fAlive; @@ -158,6 +161,7 @@ void G4EventManager::DoProcessing(G4Event* anEvent) } #endif + std::unordered_set<G4VTrackingManager *> trackingManagersToFlush; do { @@ -166,6 +170,29 @@ void G4EventManager::DoProcessing(G4Event* anEvent) while( (track=trackContainer->PopNextTrack(&previousTrajectory)) != nullptr ) { // Loop checking 12.28.2015 M.Asai + const G4ParticleDefinition* partDef = track->GetParticleDefinition(); + G4VTrackingManager* particleTrackingManager = partDef->GetTrackingManager(); + + if (particleTrackingManager != nullptr) + { +#ifdef G4VERBOSE + if ( verboseLevel > 1 ) + { + G4cout << "Track " << track << " (trackID " << track->GetTrackID() + << ", parentID " << track->GetParentID() + << ") is handed over to custom TrackingManager." << G4endl; + } +#endif + + particleTrackingManager->HandOverOneTrack(track); + // The particle's tracking manager may either track immediately or + // defer processing until FlushEvent is called. Thus, we must neither + // check the track's status nor stack secondaries. + + // Remember this tracking manager to later call FlushEvent. + trackingManagersToFlush.insert(particleTrackingManager); + + } else { #ifdef G4VERBOSE if ( verboseLevel > 1 ) { @@ -243,10 +270,18 @@ void G4EventManager::DoProcessing(G4Event* anEvent) } delete track; break; + } } } - G4GlobalFastSimulationManager::GetGlobalFastSimulationManager()->Flush(); + // Flush all tracking managers, which may have deferred processing until now. + for (G4VTrackingManager *tm : trackingManagersToFlush) + { + tm->FlushEvent(); + } + trackingManagersToFlush.clear(); + + G4GlobalFastSimulationManager::GetGlobalFastSimulationManager()->Flush(); } while (trackContainer->GetNUrgentTrack() > 0); diff --git a/source/particles/management/include/G4PDefManager.hh b/source/particles/management/include/G4PDefManager.hh index 5b1283b5fcfa146732d0d7bc5d1c29a53eddc823..f7c6914a11a2e9922524b73691580a4b0e777455 100644 --- a/source/particles/management/include/G4PDefManager.hh +++ b/source/particles/management/include/G4PDefManager.hh @@ -64,6 +64,7 @@ #include "G4AutoLock.hh" class G4ProcessManager; +class G4VTrackingManager; class G4PDefData { @@ -76,6 +77,7 @@ class G4PDefData void initialize(); G4ProcessManager* theProcessManager = nullptr; + G4VTrackingManager* theTrackingManager = nullptr; }; class G4PDefManager diff --git a/source/particles/management/include/G4ParticleDefinition.hh b/source/particles/management/include/G4ParticleDefinition.hh index cd618658338732c7ae5fd1145003d2f845ef9289..ad2ea0b2c72c9d053c5b06067bf74d723235f2f4 100644 --- a/source/particles/management/include/G4ParticleDefinition.hh +++ b/source/particles/management/include/G4ParticleDefinition.hh @@ -53,6 +53,7 @@ class G4ProcessManager; class G4DecayTable; class G4ParticleTable; class G4ParticlePropertyTable; +class G4VTrackingManager; using G4ParticleDefinitionSubInstanceManager = G4PDefManager; @@ -162,6 +163,11 @@ class G4ParticleDefinition // Set/Get Process Manager // !! Process Manager can be modified !! + G4VTrackingManager* GetTrackingManager() const; + void SetTrackingManager(G4VTrackingManager* aTrackingManager); + // Set/Get Tracking Manager; nullptr means the default + // !! Tracking Manager can be modified !! + inline G4ParticleTable* GetParticleTable() const; // Get pointer to the particle table diff --git a/source/particles/management/src/G4PDefManager.cc b/source/particles/management/src/G4PDefManager.cc index 9d0ac4073690859fee03e77c7703b2d592e96561..584d43e09e741ce82035454f6e1f62944a3c80d2 100644 --- a/source/particles/management/src/G4PDefManager.cc +++ b/source/particles/management/src/G4PDefManager.cc @@ -39,6 +39,7 @@ void G4PDefData::initialize() { theProcessManager = nullptr; + theTrackingManager = nullptr; } G4int& G4PDefManager::slavetotalspace() diff --git a/source/particles/management/src/G4ParticleDefinition.cc b/source/particles/management/src/G4ParticleDefinition.cc index d34510ad985f605627cdca271249688abf61c448..ffd5cfd6091fd24ae94d3f8a847d57076da5f456 100644 --- a/source/particles/management/src/G4ParticleDefinition.cc +++ b/source/particles/management/src/G4ParticleDefinition.cc @@ -53,6 +53,7 @@ G4PDefManager G4ParticleDefinition::subInstanceManager; // in the class G4PDefData. // #define G4MT_pmanager ((subInstanceManager.offset()[g4particleDefinitionInstanceID]).theProcessManager) +#define G4MT_tmanager ((subInstanceManager.offset()[g4particleDefinitionInstanceID]).theTrackingManager) // -------------------------------------------------------------------- G4ParticleDefinition::G4ParticleDefinition( @@ -240,6 +241,13 @@ G4ProcessManager* G4ParticleDefinition::GetProcessManager() const return G4MT_pmanager; } +// -------------------------------------------------------------------- +G4VTrackingManager* G4ParticleDefinition::GetTrackingManager() const +{ + if(g4particleDefinitionInstanceID<0) return nullptr; + return G4MT_tmanager; +} + // -------------------------------------------------------------------- G4int G4ParticleDefinition::FillQuarkContents() { @@ -474,3 +482,22 @@ void G4ParticleDefinition::SetProcessManager(G4ProcessManager* aProcessManager) } G4MT_pmanager = aProcessManager; } + +// -------------------------------------------------------------------- +void G4ParticleDefinition::SetTrackingManager(G4VTrackingManager* aTrackingManager) +{ + if(g4particleDefinitionInstanceID<0 && !isGeneralIon) + { + if(G4Threading::G4GetThreadId() >= 0) + { + G4ExceptionDescription ed; + ed << "TrackingManager is being set to " << theParticleName + << " without proper initialization of TLS pointer vector.\n" + << "This operation is thread-unsafe."; + G4Exception("G4ParticleDefintion::SetTrackingManager", + "PART10118", JustWarning, ed); + } + SetParticleDefinitionID(); + } + G4MT_tmanager = aTrackingManager; +} diff --git a/source/run/include/G4VUserPhysicsList.hh b/source/run/include/G4VUserPhysicsList.hh index 538cc7a281368838e6c9994accbd5a9da795f329..61a8832a26556028297ddaccd23456e3c134e1a0 100644 --- a/source/run/include/G4VUserPhysicsList.hh +++ b/source/run/include/G4VUserPhysicsList.hh @@ -328,6 +328,10 @@ class G4VUserPhysicsList // this routine is invoked from RunManager void RemoveProcessManager(); + void RemoveTrackingManager(); + // Remove and delete TrackingManagers for all particles in the + // Particle Table. + public: // with description // add process manager for particles created on-the-fly void AddProcessManager(G4ParticleDefinition* newParticle, diff --git a/source/run/src/G4VUserPhysicsList.cc b/source/run/src/G4VUserPhysicsList.cc index cc3e1aec59dda0ecbf03eadeef142b9287a350af..209ef809f9b92feb081b1efb94757dc82443078d 100644 --- a/source/run/src/G4VUserPhysicsList.cc +++ b/source/run/src/G4VUserPhysicsList.cc @@ -49,9 +49,6 @@ // To initialize thread specific data // ------------------------------------------------------------ -#include <fstream> -#include <iomanip> - #include "G4PhysicsListHelper.hh" #include "G4VUserPhysicsList.hh" @@ -72,9 +69,14 @@ #include "G4UImanager.hh" #include "G4UnitsTable.hh" #include "G4UserPhysicsListMessenger.hh" +#include "G4VTrackingManager.hh" #include "G4ios.hh" #include "globals.hh" +#include <fstream> +#include <iomanip> +#include <unordered_set> + // This static member is thread local. For each thread, it holds the array // size of G4VUPLData instances. // @@ -158,6 +160,7 @@ void G4VUserPhysicsList::InitializeWorker() void G4VUserPhysicsList::TerminateWorker() { RemoveProcessManager(); + RemoveTrackingManager(); delete G4MT_theMessenger; G4MT_theMessenger = nullptr; } @@ -170,6 +173,7 @@ G4VUserPhysicsList::~G4VUserPhysicsList() G4MT_theMessenger = 0; } RemoveProcessManager(); + RemoveTrackingManager(); // invoke DeleteAllParticle theParticleTable->DeleteAllParticles(); @@ -368,6 +372,39 @@ void G4VUserPhysicsList::RemoveProcessManager() // G4VUserPhysicsList::InitializeProcessManager" << G4endl; } +// -------------------------------------------------------------------- +void G4VUserPhysicsList::RemoveTrackingManager() +{ + // One tracking manager may be registered for multiple particles, make sure + // to delete every object only once. + std::unordered_set<G4VTrackingManager *> trackingManagers; + + // loop over all particles in G4ParticleTable + theParticleIterator->reset(); + while((*theParticleIterator)()) + { + G4ParticleDefinition* particle = theParticleIterator->value(); + if (auto *trackingManager = particle->GetTrackingManager()) + { +#ifdef G4VERBOSE + if(verboseLevel > 2) + { + G4cout << "G4VUserPhysicsList::RemoveTrackingManager: "; + G4cout << "remove TrackingManager from "; + G4cout << particle->GetParticleName() << G4endl; + } +#endif + trackingManagers.insert(trackingManager); + particle->SetTrackingManager(nullptr); + } + } + + for (G4VTrackingManager *tm : trackingManagers) + { + delete tm; + } +} + //////////////////////////////////////////////////////// void G4VUserPhysicsList::SetCuts() { @@ -656,6 +693,18 @@ void G4VUserPhysicsList::BuildPhysicsTable() // Change in order to share physics tables for two kind of process. void G4VUserPhysicsList::BuildPhysicsTable(G4ParticleDefinition* particle) { + if (auto *trackingManager = particle->GetTrackingManager()) + { + if(verboseLevel > 2) + { + G4cout << "G4VUserPhysicsList::BuildPhysicsTable " + << "Calculate Physics Table for " << particle->GetParticleName() + << " via custom TrackingManager" << G4endl; + } + trackingManager->BuildPhysicsTable(*particle); + return; + } + if(!(particle->GetMasterProcessManager())) { G4cout @@ -786,6 +835,12 @@ void G4VUserPhysicsList::BuildPhysicsTable(G4ParticleDefinition* particle) /////////////////////////////////////////////////////////////// void G4VUserPhysicsList::PreparePhysicsTable(G4ParticleDefinition* particle) { + if (auto *trackingManager = particle->GetTrackingManager()) + { + trackingManager->PreparePhysicsTable(*particle); + return; + } + if(!(particle->GetMasterProcessManager())) { //// G4cout << "#### G4VUserPhysicsList::BuildPhysicsTable() - diff --git a/source/tracking/include/G4VTrackingManager.hh b/source/tracking/include/G4VTrackingManager.hh new file mode 100644 index 0000000000000000000000000000000000000000..823d01f03eb80709f917c7ecf7931e3d4bb242ad --- /dev/null +++ b/source/tracking/include/G4VTrackingManager.hh @@ -0,0 +1,71 @@ +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// G4VTrackingManager +// +// Class description: +// +// Interface class for implementing a custom tracking manager that is +// specialized for stepping one or a small number of particle types. +// +// Original author: Jonas Hahnfeld, 2021 + +#ifndef G4VTrackingManager_hh +#define G4VTrackingManager_hh 1 + +class G4ParticleDefinition; +class G4Track; + +//////////////////////// +class G4VTrackingManager +//////////////////////// +{ + + public: + virtual ~G4VTrackingManager() {} + + virtual void BuildPhysicsTable(const G4ParticleDefinition&) {} + // Messaged by the Particle definition whenever cross-section tables have + // to be rebuilt (i.e. if new materials have been defined). + + virtual void PreparePhysicsTable(const G4ParticleDefinition&) {} + // Messaged by the Particle definition whenever cross-section tables have + // to be prepared for rebuild (i.e. if new materials have been defined). + + virtual void HandOverOneTrack(G4Track* aTrack) = 0; + // Invoking this function, a G4Track given by the argument will be + // handed over to this tracking manager. It may be tracked immediately + // or processing may be deferred to a later time, at the latest when + // calling FlushEvent(). + + virtual void FlushEvent() {} + // Signal that all tracks in the current event have been finished and + // this manager should process all tracks that may have been deferred. + // When called via this method, the tracking manager may stack new + // secondaries which will be tracked afterwards. + +}; + +#endif diff --git a/source/tracking/sources.cmake b/source/tracking/sources.cmake index c25b1812666a8a5fecee4dea5deb756a2cc1971f..64df988056d50872fed03e1674b6d0b15e39eac1 100644 --- a/source/tracking/sources.cmake +++ b/source/tracking/sources.cmake @@ -26,6 +26,7 @@ geant4_define_module(NAME G4tracking G4UserTrackingAction.hh G4MultiTrackingAction.hh G4VSteppingVerbose.hh + G4VTrackingManager.hh G4VTrajectory.hh G4VTrajectoryPoint.hh trkgdefs.hh