Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-08 08:29:54

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 /// \file EmStandardPhysicsTrackingManager.cc
0027 /// \brief Implementation of the EmStandardPhysicsTrackingManager class
0028 ///
0029 /// Implementation of a custom tracking manager for e-/e+ and gamma, using
0030 /// the same processes as defined in G4EmStandardPhysics.
0031 ///
0032 /// Original author: Jonas Hahnfeld, 2021
0033 
0034 #include "EmStandardPhysicsTrackingManager.hh"
0035 
0036 #include "TrackingManagerHelper.hh"
0037 
0038 #include "G4ComptonScattering.hh"
0039 #include "G4CoulombScattering.hh"
0040 #include "G4Electron.hh"
0041 #include "G4EmParameters.hh"
0042 #include "G4Gamma.hh"
0043 #include "G4GammaConversion.hh"
0044 #include "G4KleinNishinaModel.hh"
0045 #include "G4LivermorePhotoElectricModel.hh"
0046 #include "G4LivermorePolarizedRayleighModel.hh"
0047 #include "G4PhotoElectricAngularGeneratorPolarized.hh"
0048 #include "G4PhotoElectricEffect.hh"
0049 #include "G4Positron.hh"
0050 #include "G4RayleighScattering.hh"
0051 #include "G4SystemOfUnits.hh"
0052 #include "G4UrbanMscModel.hh"
0053 #include "G4WentzelVIModel.hh"
0054 #include "G4eBremsstrahlung.hh"
0055 #include "G4eCoulombScatteringModel.hh"
0056 #include "G4eIonisation.hh"
0057 #include "G4eMultipleScattering.hh"
0058 #include "G4eplusAnnihilation.hh"
0059 
0060 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0061 
0062 EmStandardPhysicsTrackingManager* EmStandardPhysicsTrackingManager::fMasterTrackingManager =
0063   nullptr;
0064 
0065 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0066 
0067 EmStandardPhysicsTrackingManager::EmStandardPhysicsTrackingManager()
0068 {
0069   G4EmParameters* param = G4EmParameters::Instance();
0070   G4double highEnergyLimit = param->MscEnergyLimit();
0071   G4bool polar = param->EnablePolarisation();
0072 
0073   // e-
0074   {
0075     G4eMultipleScattering* msc = new G4eMultipleScattering;
0076     G4UrbanMscModel* msc1 = new G4UrbanMscModel;
0077     G4WentzelVIModel* msc2 = new G4WentzelVIModel;
0078     msc1->SetHighEnergyLimit(highEnergyLimit);
0079     msc2->SetLowEnergyLimit(highEnergyLimit);
0080     msc->SetEmModel(msc1);
0081     msc->SetEmModel(msc2);
0082     fElectronProcs.msc = msc;
0083 
0084     fElectronProcs.ioni = new G4eIonisation;
0085     fElectronProcs.brems = new G4eBremsstrahlung;
0086 
0087     G4CoulombScattering* ss = new G4CoulombScattering;
0088     G4eCoulombScatteringModel* ssm = new G4eCoulombScatteringModel;
0089     ssm->SetLowEnergyLimit(highEnergyLimit);
0090     ssm->SetActivationLowEnergyLimit(highEnergyLimit);
0091     ss->SetEmModel(ssm);
0092     ss->SetMinKinEnergy(highEnergyLimit);
0093     fElectronProcs.ss = ss;
0094   }
0095 
0096   // e+
0097   {
0098     G4eMultipleScattering* msc = new G4eMultipleScattering;
0099     G4UrbanMscModel* msc1 = new G4UrbanMscModel;
0100     G4WentzelVIModel* msc2 = new G4WentzelVIModel;
0101     msc1->SetHighEnergyLimit(highEnergyLimit);
0102     msc2->SetLowEnergyLimit(highEnergyLimit);
0103     msc->SetEmModel(msc1);
0104     msc->SetEmModel(msc2);
0105     fPositronProcs.msc = msc;
0106 
0107     fPositronProcs.ioni = new G4eIonisation;
0108     fPositronProcs.brems = new G4eBremsstrahlung;
0109     fPositronProcs.annihilation = new G4eplusAnnihilation;
0110 
0111     G4CoulombScattering* ss = new G4CoulombScattering;
0112     G4eCoulombScatteringModel* ssm = new G4eCoulombScatteringModel;
0113     ssm->SetLowEnergyLimit(highEnergyLimit);
0114     ssm->SetActivationLowEnergyLimit(highEnergyLimit);
0115     ss->SetEmModel(ssm);
0116     ss->SetMinKinEnergy(highEnergyLimit);
0117     fPositronProcs.ss = ss;
0118   }
0119 
0120   {
0121     G4PhotoElectricEffect* pe = new G4PhotoElectricEffect;
0122     G4VEmModel* peModel = new G4LivermorePhotoElectricModel;
0123     if (polar) {
0124       peModel->SetAngularDistribution(new G4PhotoElectricAngularGeneratorPolarized);
0125     }
0126     pe->SetEmModel(peModel);
0127     fGammaProcs.pe = pe;
0128 
0129     G4ComptonScattering* cs = new G4ComptonScattering;
0130     if (polar) {
0131       cs->SetEmModel(new G4KleinNishinaModel);
0132     }
0133     fGammaProcs.compton = cs;
0134 
0135     fGammaProcs.conversion = new G4GammaConversion;
0136 
0137     G4RayleighScattering* rl = new G4RayleighScattering;
0138     if (polar) {
0139       rl->SetEmModel(new G4LivermorePolarizedRayleighModel);
0140     }
0141     fGammaProcs.rayleigh = rl;
0142   }
0143 
0144   if (fMasterTrackingManager == nullptr) {
0145     fMasterTrackingManager = this;
0146   }
0147   else {
0148     fElectronProcs.msc->SetMasterProcess(fMasterTrackingManager->fElectronProcs.msc);
0149     fElectronProcs.ss->SetMasterProcess(fMasterTrackingManager->fElectronProcs.ss);
0150     fElectronProcs.ioni->SetMasterProcess(fMasterTrackingManager->fElectronProcs.ioni);
0151     fElectronProcs.brems->SetMasterProcess(fMasterTrackingManager->fElectronProcs.brems);
0152 
0153     fPositronProcs.msc->SetMasterProcess(fMasterTrackingManager->fPositronProcs.msc);
0154     fPositronProcs.ss->SetMasterProcess(fMasterTrackingManager->fPositronProcs.ss);
0155     fPositronProcs.ioni->SetMasterProcess(fMasterTrackingManager->fPositronProcs.ioni);
0156     fPositronProcs.brems->SetMasterProcess(fMasterTrackingManager->fPositronProcs.brems);
0157     fPositronProcs.annihilation->SetMasterProcess(
0158       fMasterTrackingManager->fPositronProcs.annihilation);
0159 
0160     fGammaProcs.pe->SetMasterProcess(fMasterTrackingManager->fGammaProcs.pe);
0161     fGammaProcs.compton->SetMasterProcess(fMasterTrackingManager->fGammaProcs.compton);
0162     fGammaProcs.conversion->SetMasterProcess(fMasterTrackingManager->fGammaProcs.conversion);
0163     fGammaProcs.rayleigh->SetMasterProcess(fMasterTrackingManager->fGammaProcs.rayleigh);
0164   }
0165 }
0166 
0167 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0168 
0169 EmStandardPhysicsTrackingManager::~EmStandardPhysicsTrackingManager()
0170 {
0171   if (fMasterTrackingManager == this) {
0172     fMasterTrackingManager = nullptr;
0173   }
0174 }
0175 
0176 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0177 
0178 void EmStandardPhysicsTrackingManager::BuildPhysicsTable(const G4ParticleDefinition& part)
0179 {
0180   if (&part == G4Electron::Definition()) {
0181     fElectronProcs.msc->BuildPhysicsTable(part);
0182     fElectronProcs.ioni->BuildPhysicsTable(part);
0183     fElectronProcs.brems->BuildPhysicsTable(part);
0184     fElectronProcs.ss->BuildPhysicsTable(part);
0185   }
0186   else if (&part == G4Positron::Definition()) {
0187     fPositronProcs.msc->BuildPhysicsTable(part);
0188     fPositronProcs.ioni->BuildPhysicsTable(part);
0189     fPositronProcs.brems->BuildPhysicsTable(part);
0190     fPositronProcs.annihilation->BuildPhysicsTable(part);
0191     fPositronProcs.ss->BuildPhysicsTable(part);
0192   }
0193   else if (&part == G4Gamma::Definition()) {
0194     fGammaProcs.pe->BuildPhysicsTable(part);
0195     fGammaProcs.compton->BuildPhysicsTable(part);
0196     fGammaProcs.conversion->BuildPhysicsTable(part);
0197     fGammaProcs.rayleigh->BuildPhysicsTable(part);
0198   }
0199 }
0200 
0201 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0202 
0203 void EmStandardPhysicsTrackingManager::PreparePhysicsTable(const G4ParticleDefinition& part)
0204 {
0205   if (&part == G4Electron::Definition()) {
0206     fElectronProcs.msc->PreparePhysicsTable(part);
0207     fElectronProcs.ioni->PreparePhysicsTable(part);
0208     fElectronProcs.brems->PreparePhysicsTable(part);
0209     fElectronProcs.ss->PreparePhysicsTable(part);
0210   }
0211   else if (&part == G4Positron::Definition()) {
0212     fPositronProcs.msc->PreparePhysicsTable(part);
0213     fPositronProcs.ioni->PreparePhysicsTable(part);
0214     fPositronProcs.brems->PreparePhysicsTable(part);
0215     fPositronProcs.annihilation->PreparePhysicsTable(part);
0216     fPositronProcs.ss->PreparePhysicsTable(part);
0217   }
0218   else if (&part == G4Gamma::Definition()) {
0219     fGammaProcs.pe->PreparePhysicsTable(part);
0220     fGammaProcs.compton->PreparePhysicsTable(part);
0221     fGammaProcs.conversion->PreparePhysicsTable(part);
0222     fGammaProcs.rayleigh->PreparePhysicsTable(part);
0223   }
0224 }
0225 
0226 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0227 
0228 void EmStandardPhysicsTrackingManager::TrackElectron(G4Track* aTrack)
0229 {
0230   class ElectronPhysics final : public TrackingManagerHelper::Physics
0231   {
0232     public:
0233       ElectronPhysics(EmStandardPhysicsTrackingManager& mgr) : fMgr(mgr) {}
0234 
0235       void StartTracking(G4Track* aTrack) override
0236       {
0237         auto& electronProcs = fMgr.fElectronProcs;
0238 
0239         electronProcs.msc->StartTracking(aTrack);
0240         electronProcs.ioni->StartTracking(aTrack);
0241         electronProcs.brems->StartTracking(aTrack);
0242         electronProcs.ss->StartTracking(aTrack);
0243 
0244         fPreviousStepLength = 0;
0245       }
0246       void EndTracking() override
0247       {
0248         auto& electronProcs = fMgr.fElectronProcs;
0249 
0250         electronProcs.msc->EndTracking();
0251         electronProcs.ioni->EndTracking();
0252         electronProcs.brems->EndTracking();
0253         electronProcs.ss->EndTracking();
0254       }
0255 
0256       G4double GetPhysicalInteractionLength(const G4Track& track) override
0257       {
0258         auto& electronProcs = fMgr.fElectronProcs;
0259         G4double physIntLength, proposedSafety = DBL_MAX;
0260         G4ForceCondition condition;
0261         G4GPILSelection selection;
0262 
0263         fProposedStep = DBL_MAX;
0264         fSelected = -1;
0265 
0266         physIntLength = electronProcs.ss->PostStepGPIL(track, fPreviousStepLength, &condition);
0267         if (physIntLength < fProposedStep) {
0268           fProposedStep = physIntLength;
0269           fSelected = 0;
0270         }
0271 
0272         physIntLength = electronProcs.brems->PostStepGPIL(track, fPreviousStepLength, &condition);
0273         if (physIntLength < fProposedStep) {
0274           fProposedStep = physIntLength;
0275           fSelected = 1;
0276         }
0277 
0278         physIntLength = electronProcs.ioni->PostStepGPIL(track, fPreviousStepLength, &condition);
0279         if (physIntLength < fProposedStep) {
0280           fProposedStep = physIntLength;
0281           fSelected = 2;
0282         }
0283 
0284         physIntLength = electronProcs.ioni->AlongStepGPIL(track, fPreviousStepLength, fProposedStep,
0285                                                           proposedSafety, &selection);
0286         if (physIntLength < fProposedStep) {
0287           fProposedStep = physIntLength;
0288           fSelected = -1;
0289         }
0290 
0291         physIntLength = electronProcs.msc->AlongStepGPIL(track, fPreviousStepLength, fProposedStep,
0292                                                          proposedSafety, &selection);
0293         if (physIntLength < fProposedStep) {
0294           fProposedStep = physIntLength;
0295           // Check if MSC actually wants to win, in most cases it only limits the
0296           // step size.
0297           if (selection == CandidateForSelection) {
0298             fSelected = -1;
0299           }
0300         }
0301 
0302         return fProposedStep;
0303       }
0304 
0305       void AlongStepDoIt(G4Track& track, G4Step& step, G4TrackVector&) override
0306       {
0307         if (step.GetStepLength() == fProposedStep) {
0308           step.GetPostStepPoint()->SetStepStatus(fAlongStepDoItProc);
0309         }
0310         else {
0311           // Remember that the step was limited by geometry.
0312           fSelected = -1;
0313         }
0314         auto& electronProcs = fMgr.fElectronProcs;
0315         G4VParticleChange* particleChange;
0316 
0317         particleChange = electronProcs.msc->AlongStepDoIt(track, step);
0318         particleChange->UpdateStepForAlongStep(&step);
0319         track.SetTrackStatus(particleChange->GetTrackStatus());
0320         particleChange->Clear();
0321 
0322         particleChange = electronProcs.ioni->AlongStepDoIt(track, step);
0323         particleChange->UpdateStepForAlongStep(&step);
0324         track.SetTrackStatus(particleChange->GetTrackStatus());
0325         particleChange->Clear();
0326 
0327         fPreviousStepLength = step.GetStepLength();
0328       }
0329 
0330       void PostStepDoIt(G4Track& track, G4Step& step, G4TrackVector& secondaries) override
0331       {
0332         if (fSelected < 0) {
0333           return;
0334         }
0335         step.GetPostStepPoint()->SetStepStatus(fPostStepDoItProc);
0336 
0337         auto& electronProcs = fMgr.fElectronProcs;
0338         G4VProcess* process = nullptr;
0339         G4VParticleChange* particleChange = nullptr;
0340 
0341         switch (fSelected) {
0342           case 0:
0343             process = electronProcs.ss;
0344             particleChange = electronProcs.ss->PostStepDoIt(track, step);
0345             break;
0346           case 1:
0347             process = electronProcs.brems;
0348             particleChange = electronProcs.brems->PostStepDoIt(track, step);
0349             break;
0350           case 2:
0351             process = electronProcs.ioni;
0352             particleChange = electronProcs.ioni->PostStepDoIt(track, step);
0353             break;
0354         }
0355 
0356         particleChange->UpdateStepForPostStep(&step);
0357         step.UpdateTrack();
0358 
0359         G4int numSecondaries = particleChange->GetNumberOfSecondaries();
0360         for (G4int i = 0; i < numSecondaries; ++i) {
0361           G4Track* secondary = particleChange->GetSecondary(i);
0362           secondary->SetParentID(track.GetTrackID());
0363           secondary->SetCreatorProcess(process);
0364           secondaries.push_back(secondary);
0365         }
0366 
0367         track.SetTrackStatus(particleChange->GetTrackStatus());
0368         particleChange->Clear();
0369       }
0370 
0371     private:
0372       EmStandardPhysicsTrackingManager& fMgr;
0373       G4double fPreviousStepLength;
0374       G4double fProposedStep;
0375       G4int fSelected;
0376   };
0377 
0378   ElectronPhysics physics(*this);
0379   TrackingManagerHelper::TrackChargedParticle(aTrack, physics);
0380 }
0381 
0382 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0383 
0384 void EmStandardPhysicsTrackingManager::TrackPositron(G4Track* aTrack)
0385 {
0386   class PositronPhysics final : public TrackingManagerHelper::Physics
0387   {
0388     public:
0389       PositronPhysics(EmStandardPhysicsTrackingManager& mgr) : fMgr(mgr) {}
0390 
0391       void StartTracking(G4Track* aTrack) override
0392       {
0393         auto& positronProcs = fMgr.fPositronProcs;
0394 
0395         positronProcs.msc->StartTracking(aTrack);
0396         positronProcs.ioni->StartTracking(aTrack);
0397         positronProcs.brems->StartTracking(aTrack);
0398         positronProcs.annihilation->StartTracking(aTrack);
0399         positronProcs.ss->StartTracking(aTrack);
0400 
0401         fPreviousStepLength = 0;
0402       }
0403       void EndTracking() override
0404       {
0405         auto& positronProcs = fMgr.fPositronProcs;
0406 
0407         positronProcs.msc->EndTracking();
0408         positronProcs.ioni->EndTracking();
0409         positronProcs.brems->EndTracking();
0410         positronProcs.annihilation->EndTracking();
0411         positronProcs.ss->EndTracking();
0412       }
0413 
0414       G4double GetPhysicalInteractionLength(const G4Track& track) override
0415       {
0416         auto& positronProcs = fMgr.fPositronProcs;
0417         G4double physIntLength, proposedSafety = DBL_MAX;
0418         G4ForceCondition condition;
0419         G4GPILSelection selection;
0420 
0421         fProposedStep = DBL_MAX;
0422         fSelected = -1;
0423 
0424         physIntLength = positronProcs.ss->PostStepGPIL(track, fPreviousStepLength, &condition);
0425         if (physIntLength < fProposedStep) {
0426           fProposedStep = physIntLength;
0427           fSelected = 0;
0428         }
0429 
0430         physIntLength =
0431           positronProcs.annihilation->PostStepGPIL(track, fPreviousStepLength, &condition);
0432         if (physIntLength < fProposedStep) {
0433           fProposedStep = physIntLength;
0434           fSelected = 1;
0435         }
0436 
0437         physIntLength = positronProcs.brems->PostStepGPIL(track, fPreviousStepLength, &condition);
0438         if (physIntLength < fProposedStep) {
0439           fProposedStep = physIntLength;
0440           fSelected = 2;
0441         }
0442 
0443         physIntLength = positronProcs.ioni->PostStepGPIL(track, fPreviousStepLength, &condition);
0444         if (physIntLength < fProposedStep) {
0445           fProposedStep = physIntLength;
0446           fSelected = 3;
0447         }
0448 
0449         physIntLength = positronProcs.ioni->AlongStepGPIL(track, fPreviousStepLength, fProposedStep,
0450                                                           proposedSafety, &selection);
0451         if (physIntLength < fProposedStep) {
0452           fProposedStep = physIntLength;
0453           fSelected = -1;
0454         }
0455 
0456         physIntLength = positronProcs.msc->AlongStepGPIL(track, fPreviousStepLength, fProposedStep,
0457                                                          proposedSafety, &selection);
0458         if (physIntLength < fProposedStep) {
0459           fProposedStep = physIntLength;
0460           // Check if MSC actually wants to win, in most cases it only limits the
0461           // step size.
0462           if (selection == CandidateForSelection) {
0463             fSelected = -1;
0464           }
0465         }
0466 
0467         return fProposedStep;
0468       }
0469 
0470       void AlongStepDoIt(G4Track& track, G4Step& step, G4TrackVector&) override
0471       {
0472         if (step.GetStepLength() == fProposedStep) {
0473           step.GetPostStepPoint()->SetStepStatus(fAlongStepDoItProc);
0474         }
0475         else {
0476           // Remember that the step was limited by geometry.
0477           fSelected = -1;
0478         }
0479         auto& positronProcs = fMgr.fPositronProcs;
0480         G4VParticleChange* particleChange;
0481 
0482         particleChange = positronProcs.msc->AlongStepDoIt(track, step);
0483         particleChange->UpdateStepForAlongStep(&step);
0484         track.SetTrackStatus(particleChange->GetTrackStatus());
0485         particleChange->Clear();
0486 
0487         particleChange = positronProcs.ioni->AlongStepDoIt(track, step);
0488         particleChange->UpdateStepForAlongStep(&step);
0489         track.SetTrackStatus(particleChange->GetTrackStatus());
0490         particleChange->Clear();
0491 
0492         fPreviousStepLength = step.GetStepLength();
0493       }
0494 
0495       void PostStepDoIt(G4Track& track, G4Step& step, G4TrackVector& secondaries) override
0496       {
0497         if (fSelected < 0) {
0498           return;
0499         }
0500         step.GetPostStepPoint()->SetStepStatus(fPostStepDoItProc);
0501 
0502         auto& positronProcs = fMgr.fPositronProcs;
0503         G4VProcess* process = nullptr;
0504         G4VParticleChange* particleChange = nullptr;
0505 
0506         switch (fSelected) {
0507           case 0:
0508             process = positronProcs.ss;
0509             particleChange = positronProcs.ss->PostStepDoIt(track, step);
0510             break;
0511           case 1:
0512             process = positronProcs.annihilation;
0513             particleChange = positronProcs.annihilation->PostStepDoIt(track, step);
0514             break;
0515           case 2:
0516             process = positronProcs.brems;
0517             particleChange = positronProcs.brems->PostStepDoIt(track, step);
0518             break;
0519           case 3:
0520             process = positronProcs.ioni;
0521             particleChange = positronProcs.ioni->PostStepDoIt(track, step);
0522             break;
0523         }
0524 
0525         particleChange->UpdateStepForPostStep(&step);
0526         step.UpdateTrack();
0527 
0528         G4int numSecondaries = particleChange->GetNumberOfSecondaries();
0529         for (G4int i = 0; i < numSecondaries; ++i) {
0530           G4Track* secondary = particleChange->GetSecondary(i);
0531           secondary->SetParentID(track.GetTrackID());
0532           secondary->SetCreatorProcess(process);
0533           secondaries.push_back(secondary);
0534         }
0535 
0536         track.SetTrackStatus(particleChange->GetTrackStatus());
0537         particleChange->Clear();
0538       }
0539 
0540       G4bool HasAtRestProcesses() override { return true; }
0541 
0542       void AtRestDoIt(G4Track& track, G4Step& step, G4TrackVector& secondaries) override
0543       {
0544         auto& positronProcs = fMgr.fPositronProcs;
0545         // Annihilate the positron at rest.
0546         G4VParticleChange* particleChange = positronProcs.annihilation->AtRestDoIt(track, step);
0547         particleChange->UpdateStepForAtRest(&step);
0548         step.UpdateTrack();
0549 
0550         G4int numSecondaries = particleChange->GetNumberOfSecondaries();
0551         for (G4int i = 0; i < numSecondaries; ++i) {
0552           G4Track* secondary = particleChange->GetSecondary(i);
0553           secondary->SetParentID(track.GetTrackID());
0554           secondary->SetCreatorProcess(positronProcs.annihilation);
0555           secondaries.push_back(secondary);
0556         }
0557 
0558         track.SetTrackStatus(particleChange->GetTrackStatus());
0559         particleChange->Clear();
0560       }
0561 
0562     private:
0563       EmStandardPhysicsTrackingManager& fMgr;
0564       G4double fPreviousStepLength;
0565       G4double fProposedStep;
0566       G4int fSelected;
0567   };
0568 
0569   PositronPhysics physics(*this);
0570   TrackingManagerHelper::TrackChargedParticle(aTrack, physics);
0571 }
0572 
0573 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0574 
0575 void EmStandardPhysicsTrackingManager::TrackGamma(G4Track* aTrack)
0576 {
0577   class GammaPhysics final : public TrackingManagerHelper::Physics
0578   {
0579     public:
0580       GammaPhysics(EmStandardPhysicsTrackingManager& mgr) : fMgr(mgr) {}
0581 
0582       void StartTracking(G4Track* aTrack) override
0583       {
0584         auto& gammaProcs = fMgr.fGammaProcs;
0585 
0586         gammaProcs.pe->StartTracking(aTrack);
0587         gammaProcs.compton->StartTracking(aTrack);
0588         gammaProcs.conversion->StartTracking(aTrack);
0589         gammaProcs.rayleigh->StartTracking(aTrack);
0590 
0591         fPreviousStepLength = 0;
0592       }
0593       void EndTracking() override
0594       {
0595         auto& gammaProcs = fMgr.fGammaProcs;
0596 
0597         gammaProcs.pe->EndTracking();
0598         gammaProcs.compton->EndTracking();
0599         gammaProcs.conversion->EndTracking();
0600         gammaProcs.rayleigh->EndTracking();
0601       }
0602 
0603       G4double GetPhysicalInteractionLength(const G4Track& track) override
0604       {
0605         auto& gammaProcs = fMgr.fGammaProcs;
0606         G4double physIntLength;
0607         G4ForceCondition condition;
0608 
0609         fProposedStep = DBL_MAX;
0610         fSelected = -1;
0611 
0612         physIntLength = gammaProcs.rayleigh->PostStepGPIL(track, fPreviousStepLength, &condition);
0613         if (physIntLength < fProposedStep) {
0614           fProposedStep = physIntLength;
0615           fSelected = 0;
0616         }
0617 
0618         physIntLength = gammaProcs.conversion->PostStepGPIL(track, fPreviousStepLength, &condition);
0619         if (physIntLength < fProposedStep) {
0620           fProposedStep = physIntLength;
0621           fSelected = 1;
0622         }
0623 
0624         physIntLength = gammaProcs.compton->PostStepGPIL(track, fPreviousStepLength, &condition);
0625         if (physIntLength < fProposedStep) {
0626           fProposedStep = physIntLength;
0627           fSelected = 2;
0628         }
0629 
0630         physIntLength = gammaProcs.pe->PostStepGPIL(track, fPreviousStepLength, &condition);
0631         if (physIntLength < fProposedStep) {
0632           fProposedStep = physIntLength;
0633           fSelected = 3;
0634         }
0635 
0636         return fProposedStep;
0637       }
0638 
0639       void AlongStepDoIt(G4Track&, G4Step& step, G4TrackVector&) override
0640       {
0641         if (step.GetStepLength() == fProposedStep) {
0642           step.GetPostStepPoint()->SetStepStatus(fAlongStepDoItProc);
0643         }
0644         else {
0645           // Remember that the step was limited by geometry.
0646           fSelected = -1;
0647         }
0648         fPreviousStepLength = step.GetStepLength();
0649       }
0650 
0651       void PostStepDoIt(G4Track& track, G4Step& step, G4TrackVector& secondaries) override
0652       {
0653         if (fSelected < 0) {
0654           return;
0655         }
0656         step.GetPostStepPoint()->SetStepStatus(fPostStepDoItProc);
0657 
0658         auto& gammaProcs = fMgr.fGammaProcs;
0659         G4VProcess* process = nullptr;
0660         G4VParticleChange* particleChange = nullptr;
0661 
0662         switch (fSelected) {
0663           case 0:
0664             process = gammaProcs.rayleigh;
0665             particleChange = gammaProcs.rayleigh->PostStepDoIt(track, step);
0666             break;
0667           case 1:
0668             process = gammaProcs.conversion;
0669             particleChange = gammaProcs.conversion->PostStepDoIt(track, step);
0670             break;
0671           case 2:
0672             process = gammaProcs.compton;
0673             particleChange = gammaProcs.compton->PostStepDoIt(track, step);
0674             break;
0675           case 3:
0676             process = gammaProcs.pe;
0677             particleChange = gammaProcs.pe->PostStepDoIt(track, step);
0678             break;
0679         }
0680 
0681         particleChange->UpdateStepForPostStep(&step);
0682         step.UpdateTrack();
0683 
0684         G4int numSecondaries = particleChange->GetNumberOfSecondaries();
0685         for (G4int i = 0; i < numSecondaries; ++i) {
0686           G4Track* secondary = particleChange->GetSecondary(i);
0687           secondary->SetParentID(track.GetTrackID());
0688           secondary->SetCreatorProcess(process);
0689           secondaries.push_back(secondary);
0690         }
0691 
0692         track.SetTrackStatus(particleChange->GetTrackStatus());
0693         particleChange->Clear();
0694       }
0695 
0696     private:
0697       EmStandardPhysicsTrackingManager& fMgr;
0698       G4double fPreviousStepLength;
0699       G4double fProposedStep;
0700       G4int fSelected;
0701   };
0702 
0703   GammaPhysics physics(*this);
0704   TrackingManagerHelper::TrackNeutralParticle(aTrack, physics);
0705 }
0706 
0707 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0708 
0709 void EmStandardPhysicsTrackingManager::HandOverOneTrack(G4Track* aTrack)
0710 {
0711   const G4ParticleDefinition* part = aTrack->GetParticleDefinition();
0712 
0713   if (part == G4Electron::Definition()) {
0714     TrackElectron(aTrack);
0715   }
0716   else if (part == G4Positron::Definition()) {
0717     TrackPositron(aTrack);
0718   }
0719   else if (part == G4Gamma::Definition()) {
0720     TrackGamma(aTrack);
0721   }
0722 
0723   aTrack->SetTrackStatus(fStopAndKill);
0724   delete aTrack;
0725 }
0726 
0727 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......