// // ******************************************************************** // * 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. * // ******************************************************************** // // G4StackManager class implementation // // Author: Makoto Asai, 1996 // Adding sub-event parallelism // 23/Aug/2023 // -------------------------------------------------------------------- #include "G4StackManager.hh" #include "G4StackingMessenger.hh" #include "G4VTrajectory.hh" #include "G4Event.hh" #include "G4ios.hh" #include "G4ParticleDefinition.hh" #include "G4VProcess.hh" // Needed for temporal service // #include "G4ParticleTable.hh" #include "G4ProcessManager.hh" #include "G4ProcessVector.hh" G4StackManager::G4StackManager() { theMessenger = new G4StackingMessenger(this); #ifdef G4_USESMARTSTACK urgentStack = new G4SmartTrackStack; // G4cout << "+++ G4StackManager uses G4SmartTrackStack. +++" << G4endl; #else urgentStack = new G4TrackStack(5000); // G4cout << "+++ G4StackManager uses ordinary G4TrackStack. +++" << G4endl; #endif waitingStack = new G4TrackStack(1000); postponeStack = new G4TrackStack(1000); } G4StackManager::~G4StackManager() { delete userStackingAction; #ifdef G4VERBOSE if(verboseLevel>0) { G4cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << G4endl; G4cout << " Maximum number of tracks in the urgent stack : " << urgentStack->GetMaxNTrack() << G4endl; G4cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << G4endl; } #endif delete urgentStack; delete waitingStack; delete postponeStack; delete theMessenger; if(numberOfAdditionalWaitingStacks>0) { for(G4int i=0; iGetParticleDefinition(); if(pd->GetParticleDefinitionID() < 0) { G4ExceptionDescription ED; ED << "A track without proper process manager is pushed \ into the track stack.\n" << " Particle name : " << pd->GetParticleName() << " -- "; if(newTrack->GetParentID()==0) { ED << "created by a primary particle generator."; } else { const G4VProcess* vp = newTrack->GetCreatorProcess(); if(vp != nullptr) { ED << "created by " << vp->GetProcessName() << "."; } else { ED << "creaded by unknown process."; } } G4Exception("G4StackManager::PushOneTrack","Event10051", FatalException,ED); delete newTrack; return GetNUrgentTrack(); } DefineDefaultClassification( newTrack ); G4ClassificationOfNewTrack classification = fDefaultClassification; if(userStackingAction!=nullptr) { classification = userStackingAction->ClassifyNewTrack( newTrack ); if(classification != fDefaultClassification) { if(fExceptionSeverity!=G4ExceptionSeverity::IgnoreTheIssue) { G4ExceptionDescription ed; ed << "UserStackingAction has changed the track classification from " << fDefaultClassification << " to " << classification << ". "; G4Exception("G4StackManager::PushOneTrack","Event10052", fExceptionSeverity,ed); } } } if(newTrack->GetTrackStatus() == fSuspendAndWait && classification > 0) // to avoid this track sent to Waiting stack again { newTrack->SetTrackStatus( fSuspend ); } #ifdef G4VERBOSE if( verboseLevel > 1 ) { G4cout << "### Storing a track (" << newTrack->GetParticleDefinition()->GetParticleName() << ",trackID=" << newTrack->GetTrackID() << ",parentID=" << newTrack->GetParentID() << ") "; if(newTrack->GetParentID()==0) { G4cout << "created by a primary particle generator "; } else { const G4VProcess* vp = newTrack->GetCreatorProcess(); if(vp != nullptr) { G4cout << "created by " << vp->GetProcessName() << " "; } else { G4cout << "creaded by unknown process "; } } G4cout << "into stack #" << classification << G4endl; } #endif G4StackedTrack newStackedTrack( newTrack, newTrajectory ); SortOut(newStackedTrack,classification); return GetNUrgentTrack(); } G4Track* G4StackManager::PopNextTrack(G4VTrajectory** newTrajectory) { #ifdef G4VERBOSE if( verboseLevel > 1 ) { G4cout << "### pop requested out of " << GetNUrgentTrack() << " stacked tracks." << G4endl; } #endif while( GetNUrgentTrack() == 0 ) { #ifdef G4VERBOSE if( verboseLevel > 1 ) { G4cout << "### " << GetNWaitingTrack() << " waiting tracks are re-classified to" << G4endl; } #endif waitingStack->TransferTo(urgentStack); if(numberOfAdditionalWaitingStacks>0) { for(G4int i=0; iTransferTo(waitingStack); } else { additionalWaitingStacks[i]->TransferTo(additionalWaitingStacks[i-1]); } } } if(userStackingAction != nullptr) { userStackingAction->NewStage(); } #ifdef G4VERBOSE if( verboseLevel > 1 ) G4cout << " " << GetNUrgentTrack() << " urgent tracks and " << GetNWaitingTrack() << " waiting tracks." << G4endl; #endif if( ( GetNUrgentTrack()==0 ) && ( GetNWaitingTrack()==0 ) ) return nullptr; } G4StackedTrack selectedStackedTrack = urgentStack->PopFromStack(); G4Track * selectedTrack = selectedStackedTrack.GetTrack(); *newTrajectory = selectedStackedTrack.GetTrajectory(); #ifdef G4VERBOSE if( verboseLevel > 2 ) { G4cout << "Selected G4StackedTrack : " << &selectedStackedTrack << " with G4Track " << selectedStackedTrack.GetTrack() << " (trackID " << selectedStackedTrack.GetTrack()->GetTrackID() << ", parentID " << selectedStackedTrack.GetTrack()->GetParentID() << ")" << G4endl; } #endif return selectedTrack; } void G4StackManager::ReClassify() { G4StackedTrack aStackedTrack; G4TrackStack tmpStack; if( userStackingAction == nullptr ) return; if( GetNUrgentTrack() == 0 ) return; urgentStack->TransferTo(&tmpStack); while( tmpStack.GetNTrack() > 0 ) { aStackedTrack=tmpStack.PopFromStack(); DefineDefaultClassification( aStackedTrack.GetTrack() ); G4ClassificationOfNewTrack classification = fDefaultClassification; if(userStackingAction!=nullptr) { classification = userStackingAction->ClassifyNewTrack( aStackedTrack.GetTrack() ); if(classification != fDefaultClassification) { if(fExceptionSeverity!=G4ExceptionSeverity::IgnoreTheIssue) { G4ExceptionDescription ed; ed << "UserStackingAction has changed the track classification from " << fDefaultClassification << " to " << classification << ". "; G4Exception("G4StackManager::PushOneTrack","Event10052", fExceptionSeverity,ed); } } } if(aStackedTrack.GetTrack()->GetTrackStatus() == fSuspendAndWait && classification > 0) // to avoid this track sent to Waiting stack again { aStackedTrack.GetTrack()->SetTrackStatus( fSuspend ); } SortOut(aStackedTrack,classification); } } G4int G4StackManager::PrepareNewEvent(G4Event* currentEvent) { if(userStackingAction != nullptr) { userStackingAction->PrepareNewEvent(); } // Set the urgentStack in a defined state. Not doing it would // affect reproducibility // urgentStack->clearAndDestroy(); G4int n_passedFromPrevious = 0; if( GetNPostponedTrack() > 0 ) { #ifdef G4VERBOSE if( verboseLevel > 1 ) { G4cout << GetNPostponedTrack() << " postponed tracked are now shifted to the stack." << G4endl; } #endif G4StackedTrack aStackedTrack; G4TrackStack tmpStack; postponeStack->TransferTo(&tmpStack); while( tmpStack.GetNTrack() > 0 ) { aStackedTrack=tmpStack.PopFromStack(); G4Track* aTrack = aStackedTrack.GetTrack(); DefineDefaultClassification( aTrack ); G4ClassificationOfNewTrack classification = fDefaultClassification; if(userStackingAction!=nullptr) { classification = userStackingAction->ClassifyNewTrack( aTrack ); if(classification != fDefaultClassification) { if(fExceptionSeverity!=G4ExceptionSeverity::IgnoreTheIssue) { G4ExceptionDescription ed; ed << "UserStackingAction has changed the track classification from " << fDefaultClassification << " to " << classification << ". "; G4Exception("G4StackManager::PushOneTrack","Event10052", fExceptionSeverity,ed); } } } if(classification!=fKill) { aTrack->SetParentID(-1); aTrack->SetTrackID(-(++n_passedFromPrevious)); } else if(aTrack->GetTrackStatus() == fSuspendAndWait && classification > 0) // to avoid this track sent to Waiting stack again { aTrack->SetTrackStatus( fSuspend ); } SortOut(aStackedTrack,classification); } } // Reset sub-event stacks for a new event for(auto& ses : subEvtStackMap) { ses.second->PrepareNewEvent(currentEvent); } return n_passedFromPrevious; } void G4StackManager::SortOut(G4StackedTrack& aStackedTrack, G4ClassificationOfNewTrack classification) { if(classification==fKill) // delete the without stacking { G4Track* newTrack = aStackedTrack.GetTrack(); G4VTrajectory* newTrajectory = aStackedTrack.GetTrajectory(); #ifdef G4VERBOSE if( verboseLevel > 1 ) { G4cout << " ---> G4Track " << newTrack << " (trackID " << newTrack->GetTrackID() << ", parentID " << newTrack->GetParentID() << ") is not to be stored." << G4endl; } #endif delete newTrack; delete newTrajectory; } else { switch (classification) { case fUrgent: urgentStack->PushToStack( aStackedTrack ); break; case fWaiting: waitingStack->PushToStack( aStackedTrack ); break; case fPostpone: postponeStack->PushToStack( aStackedTrack ); break; default: if(classification < 100) { // pushing to additional waiting stack G4int i = classification - 10; if(i<1 || i>numberOfAdditionalWaitingStacks) { G4ExceptionDescription ED; ED << "invalid classification " << classification << G4endl; G4Exception("G4StackManager::SortOut", "Event0051", FatalException,ED); } else { additionalWaitingStacks[i-1]->PushToStack( aStackedTrack ); } } else { // pushing to sub-event stack G4int ty = classification - 100; auto ses = subEvtStackMap.find(ty); if(ses==subEvtStackMap.end()) { G4ExceptionDescription ED; ED << "invalid classification " << classification << G4endl; G4Exception("G4StackManager::SortOut", "Event0051", FatalException,ED); } else { ses->second->PushToStack( aStackedTrack ); } } break; } } } void G4StackManager::SetNumberOfAdditionalWaitingStacks(G4int iAdd) { if(iAdd > numberOfAdditionalWaitingStacks) { for(G4int i=numberOfAdditionalWaitingStacks; iiAdd; --i) { delete additionalWaitingStacks[i]; } } } void G4StackManager:: TransferStackedTracks(G4ClassificationOfNewTrack origin, G4ClassificationOfNewTrack destination) { if(origin==destination) return; if(origin==fKill) return; G4TrackStack* originStack = nullptr; switch(origin) { case fUrgent: originStack = nullptr; break; case fWaiting: originStack = waitingStack; break; case fPostpone: originStack = postponeStack; break; default: G4int i = origin - 10; if(i<=numberOfAdditionalWaitingStacks) { originStack = additionalWaitingStacks[i-1]; } else { G4ExceptionDescription ED; ED << "Invalid origin stack ID " << origin; G4Exception("G4StackManager::TransferStackedTracks","Stack0911", FatalException, ED); } break; } if(destination==fKill) { if(originStack != nullptr) { originStack->clearAndDestroy(); } else { urgentStack->clearAndDestroy(); } } else { G4TrackStack* targetStack = nullptr; switch(destination) { case fUrgent: targetStack = nullptr; break; case fWaiting: targetStack = waitingStack; break; case fPostpone: targetStack = postponeStack; break; default: G4int i = destination - 10; if(i<=numberOfAdditionalWaitingStacks) { targetStack = additionalWaitingStacks[i-1]; } else { G4ExceptionDescription ED; ED << "Invalid origin stack ID " << origin; G4Exception("G4StackManager::TransferStackedTracks","Stack0911", FatalException, ED); } break; } if(originStack != nullptr) { if(targetStack != nullptr) { originStack->TransferTo(targetStack); } else { originStack->TransferTo(urgentStack); } } else { urgentStack->TransferTo(targetStack); } } return; } void G4StackManager:: TransferOneStackedTrack(G4ClassificationOfNewTrack origin, G4ClassificationOfNewTrack destination) { if(origin==destination) return; if(origin==fKill) return; G4TrackStack* originStack = nullptr; switch(origin) { case fUrgent: originStack = nullptr; break; case fWaiting: originStack = waitingStack; break; case fPostpone: originStack = postponeStack; break; default: G4int i = origin - 10; if(i<=numberOfAdditionalWaitingStacks) { originStack = additionalWaitingStacks[i-1]; } else { G4ExceptionDescription ED; ED << "Invalid origin stack ID " << origin; G4Exception("G4StackManager::TransferStackedTracks","Stack0911", FatalException, ED); } break; } G4StackedTrack aStackedTrack; if(destination==fKill) { if( originStack != nullptr && (originStack->GetNTrack() != 0u) ) { aStackedTrack = originStack->PopFromStack(); delete aStackedTrack.GetTrack(); delete aStackedTrack.GetTrajectory(); } else if (urgentStack->GetNTrack() != 0u ) { aStackedTrack = urgentStack->PopFromStack(); delete aStackedTrack.GetTrack(); delete aStackedTrack.GetTrajectory(); } } else { G4TrackStack* targetStack = nullptr; switch(destination) { case fUrgent: targetStack = nullptr; break; case fWaiting: targetStack = waitingStack; break; case fPostpone: targetStack = postponeStack; break; default: G4int i = destination - 10; if(i<=numberOfAdditionalWaitingStacks) { targetStack = additionalWaitingStacks[i-1]; } else { G4ExceptionDescription ED; ED << "Invalid destination stack ID " << destination; G4Exception("G4StackManager::TransferStackedTracks","Stack0911", FatalException, ED); } break; } if((originStack != nullptr) && (originStack->GetNTrack() != 0u)) { aStackedTrack = originStack->PopFromStack(); if(targetStack != nullptr) { targetStack->PushToStack(aStackedTrack); } else { urgentStack->PushToStack(aStackedTrack); } } else if(urgentStack->GetNTrack() != 0u) { aStackedTrack = urgentStack->PopFromStack(); if(targetStack != nullptr) { targetStack->PushToStack(aStackedTrack); } else { urgentStack->PushToStack(aStackedTrack); } } } return; } void G4StackManager::clear() { ClearUrgentStack(); ClearWaitingStack(); for(G4int i=1; i<=numberOfAdditionalWaitingStacks; ++i) { ClearWaitingStack(i); } } void G4StackManager::ClearUrgentStack() { urgentStack->clearAndDestroy(); } void G4StackManager::ClearWaitingStack(G4int i) { if(i==0) { waitingStack->clearAndDestroy(); } else { if(i<=numberOfAdditionalWaitingStacks) { additionalWaitingStacks[i-1]->clearAndDestroy(); } } } void G4StackManager::ClearPostponeStack() { postponeStack->clearAndDestroy(); } G4int G4StackManager::GetNTotalTrack() const { std::size_t n = urgentStack->GetNTrack() + waitingStack->GetNTrack() + postponeStack->GetNTrack(); for(G4int i=1; i<=numberOfAdditionalWaitingStacks; ++i) { n += additionalWaitingStacks[i-1]->GetNTrack(); } return G4int(n); } G4int G4StackManager::GetNUrgentTrack() const { return (G4int)urgentStack->GetNTrack(); } G4int G4StackManager::GetNWaitingTrack(int i) const { if(i==0) { return (G4int)waitingStack->GetNTrack(); } if(i<=numberOfAdditionalWaitingStacks) { return (G4int)additionalWaitingStacks[i-1]->GetNTrack(); } return 0; } G4int G4StackManager::GetNPostponedTrack() const { return (G4int)postponeStack->GetNTrack(); } void G4StackManager::SetVerboseLevel( G4int const value ) { verboseLevel = value; for(auto& sets : subEvtStackMap) { sets.second->SetVerboseLevel(value); } } void G4StackManager::SetUserStackingAction(G4UserStackingAction* value) { userStackingAction = value; if(userStackingAction != nullptr) { userStackingAction->SetStackManager(this); } } void G4StackManager::DefineDefaultClassification(const G4Track* aTrack) { fDefaultClassification = fUrgent; fExceptionSeverity = G4ExceptionSeverity::IgnoreTheIssue; if(defClassPartDef.size()>0) { auto pdm = defClassPartDef.find(aTrack->GetParticleDefinition()); if(pdm!=defClassPartDef.end()) { fDefaultClassification = pdm->second.first; fExceptionSeverity = pdm->second.second; } } else if(defClassTrackStatus.size()>0) { auto tsm = defClassTrackStatus.find(aTrack->GetTrackStatus()); if(tsm!=defClassTrackStatus.end()) { fDefaultClassification = tsm->second.first; fExceptionSeverity = tsm->second.second; } } else if( aTrack->GetTrackStatus() == fSuspendAndWait ) { fDefaultClassification = fWaiting; } else if( aTrack->GetTrackStatus() == fPostponeToNextEvent ) { fDefaultClassification = fPostpone; } } void G4StackManager::SetDefaultClassification(G4TrackStatus ts, G4ClassificationOfNewTrack val, G4ExceptionSeverity es) { auto tsm = defClassTrackStatus.find(ts); if(tsm==defClassTrackStatus.end()) { defClassTrackStatus[ts] = std::pair(val,es); } else { if(tsm->second.first!=val) { // alternating default classification G4ExceptionDescription ed; ed << "Default classification for track status " << ts << " is changed from " << tsm->second.first << " to " << val << "."; G4Exception("G4StackManager::SetDefaultClassification", "Event11051",JustWarning,ed); tsm->second.first = val; } // Change severity if needed. if(tsm->second.second>es) tsm->second.second = es; } } void G4StackManager::SetDefaultClassification(const G4ParticleDefinition* pd, G4ClassificationOfNewTrack val, G4ExceptionSeverity es) { auto pdm = defClassPartDef.find(pd); if(pdm==defClassPartDef.end()) { defClassPartDef[pd] = std::pair(val,es); } else { if(pdm->second.first!=val) { // alternating default classification G4ExceptionDescription ed; ed << "Default classification for particle " << pd->GetParticleName() << " is changed from " << pdm->second.first << " to " << val << "."; G4Exception("G4StackManager::SetDefaultClassification", "Event11052", JustWarning,ed); pdm->second.first = val; } // Change severity if needed. if(pdm->second.second>es) pdm->second.second = es; } } void G4StackManager::RegisterSubEventType(G4int ty, G4int maxEnt) { if(subEvtStackMap.find(ty)==subEvtStackMap.end()) { subEvtStackMap[ty] = new G4SubEventTrackStack(ty,maxEnt); subEvtTypes.push_back(ty); #ifdef G4VERBOSE subEvtStackMap[ty]->SetVerboseLevel(verboseLevel); if( verboseLevel > 0 ) { G4cout << " ---> New sub-event stack for sub-event type " << ty << " is created. Classification id for this stack is " << subEvtTypes.size() + 99 << "." << G4endl; } } else { if( verboseLevel > 1 ) { G4cout << " ---> Sub-event stack for sub-event type " << ty << " already registered." << G4endl; } #endif } } void G4StackManager::ReleaseSubEvent(G4int ty) { auto ses = subEvtStackMap.find(ty); if(ses==subEvtStackMap.end()) { G4ExceptionDescription ED; ED << "Un-registered sub-event type " << ty << " requested."; G4Exception("G4StackManager::PopSubEvent", "SubEvt8001", FatalException,ED); return; // NOLINT: Required to silence Coverity, which does not recognize G4Exception as exit point } ses->second->ReleaseSubEvent(); }