pre-assign secondary track IDs in ProcessSecondariesFromParticleChange

Add G4EventManager::ReserveNextTrackID() to atomically increment and
return the next track ID counter. Call it from G4SteppingManager::
ProcessSecondariesFromParticleChange() so that each secondary has its
track ID set before UserSteppingAction fires. G4EventManager::StackTracks
is updated to skip re-assignment when GetTrackID() != 0 (pre-assigned).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 10:25:01 +02:00
parent 41f2dd7996
commit e7827c9b07
3 changed files with 21 additions and 2 deletions
+4
View File
@@ -59,6 +59,10 @@ class G4EventManager
static G4EventManager* GetEventManager(); static G4EventManager* GetEventManager();
// This method returns the singleton pointer of G4EventManager. // This method returns the singleton pointer of G4EventManager.
G4int ReserveNextTrackID();
// Pre-assign the next sequential track ID to a secondary being born inside
// G4SteppingManager, so that its ID is available in UserSteppingAction.
G4EventManager(); G4EventManager();
~G4EventManager(); ~G4EventManager();
+12 -2
View File
@@ -401,6 +401,11 @@ G4int G4EventManager::StoreSubEvent(G4Event* evt, G4int& subEvtType, G4SubEvent*
return evt->StoreSubEvent(subEvtType,se); return evt->StoreSubEvent(subEvtType,se);
} }
G4int G4EventManager::ReserveNextTrackID()
{
return ++trackIDCounter;
}
void G4EventManager::StackTracks(G4TrackVector* trackVector, void G4EventManager::StackTracks(G4TrackVector* trackVector,
G4bool IDhasAlreadySet) G4bool IDhasAlreadySet)
{ {
@@ -409,9 +414,13 @@ void G4EventManager::StackTracks(G4TrackVector* trackVector,
if( trackVector->empty() ) return; if( trackVector->empty() ) return;
for( auto newTrack : *trackVector ) for( auto newTrack : *trackVector )
{ {
++trackIDCounter; if(IDhasAlreadySet)
if(!IDhasAlreadySet)
{ {
++trackIDCounter; // advance counter for primaries whose IDs are set externally
}
else if(newTrack->GetTrackID() == 0)
{
++trackIDCounter; // normal secondary: assign as usual
newTrack->SetTrackID( trackIDCounter ); newTrack->SetTrackID( trackIDCounter );
if(newTrack->GetDynamicParticle()->GetPrimaryParticle() != nullptr) if(newTrack->GetDynamicParticle()->GetPrimaryParticle() != nullptr)
{ {
@@ -420,6 +429,7 @@ void G4EventManager::StackTracks(G4TrackVector* trackVector,
pp->SetTrackID(trackIDCounter); pp->SetTrackID(trackIDCounter);
} }
} }
// else: ID was pre-assigned by ReserveNextTrackID() in G4SteppingManager — skip
newTrack->SetOriginTouchableHandle(newTrack->GetTouchableHandle()); newTrack->SetOriginTouchableHandle(newTrack->GetTouchableHandle());
trackContainer->PushOneTrack( newTrack ); trackContainer->PushOneTrack( newTrack );
#ifdef G4VERBOSE #ifdef G4VERBOSE
+5
View File
@@ -32,6 +32,7 @@
// -------------------------------------------------------------------- // --------------------------------------------------------------------
#include "G4SteppingManager.hh" #include "G4SteppingManager.hh"
#include "G4EventManager.hh"
#include "G4ForceCondition.hh" #include "G4ForceCondition.hh"
#include "G4GPILSelection.hh" #include "G4GPILSelection.hh"
@@ -600,6 +601,10 @@ G4int G4SteppingManager::ProcessSecondariesFromParticleChange()
// Set the process pointer which created this track // Set the process pointer which created this track
tempSecondaryTrack->SetCreatorProcess(creatorProcess); tempSecondaryTrack->SetCreatorProcess(creatorProcess);
// Pre-assign track ID so it is visible in UserSteppingAction via
// GetSecondaryInCurrentStep(); G4EventManager::StackTracks skips re-assignment.
tempSecondaryTrack->SetTrackID(G4EventManager::GetEventManager()->ReserveNextTrackID());
// If this 2ndry particle has 'zero' kinetic energy, make sure // If this 2ndry particle has 'zero' kinetic energy, make sure
// it invokes a rest process at the beginning of the tracking // it invokes a rest process at the beginning of the tracking
// //