Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-23 09:22:46

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 // TrackingManagerHelper
0027 //
0028 // Class description:
0029 //
0030 // Helper class for reducing the effort required to implement a custom tracking
0031 // manager. It implements a stepping loop that calls user actions as the generic
0032 // tracking and stepping managers do, and it implements navigation for charged
0033 // particles in energy-preserving fields and for neutral particles.
0034 //
0035 // Original author: Jonas Hahnfeld, 2021
0036 
0037 #include "G4EventManager.hh"
0038 #include "G4Field.hh"
0039 #include "G4FieldManager.hh"
0040 #include "G4FieldManagerStore.hh"
0041 #include "G4GeometryTolerance.hh"
0042 #include "G4LogicalVolume.hh"
0043 #include "G4Navigator.hh"
0044 #include "G4PropagatorInField.hh"
0045 #include "G4Region.hh"
0046 #include "G4SafetyHelper.hh"
0047 #include "G4Step.hh"
0048 #include "G4StepPoint.hh"
0049 #include "G4TouchableHandle.hh"
0050 #include "G4TouchableHistory.hh"
0051 #include "G4Track.hh"
0052 #include "G4TrackVector.hh"
0053 #include "G4TransportationManager.hh"
0054 #include "G4UserSteppingAction.hh"
0055 #include "G4UserTrackingAction.hh"
0056 #include "G4VPhysicalVolume.hh"
0057 #include "G4VSensitiveDetector.hh"
0058 
0059 template <typename PhysicsImpl, typename NavigationImpl>
0060 void TrackingManagerHelper::TrackParticle(
0061   G4Track* aTrack, PhysicsImpl& physics, NavigationImpl& navigation)
0062 {
0063   // Prepare for calling the user action.
0064   auto* evtMgr = G4EventManager::GetEventManager();
0065   auto* userTrackingAction = evtMgr->GetUserTrackingAction();
0066   auto* userSteppingAction = evtMgr->GetUserSteppingAction();
0067 
0068   // Locate the track in geometry.
0069   {
0070     auto* transMgr = G4TransportationManager::GetTransportationManager();
0071     auto* linearNavigator = transMgr->GetNavigatorForTracking();
0072 
0073     const G4ThreeVector& pos = aTrack->GetPosition();
0074     const G4ThreeVector& dir = aTrack->GetMomentumDirection();
0075 
0076     // Do not assign directly, doesn't work if the handle is empty.
0077     G4TouchableHandle touchableHandle;
0078     if (aTrack->GetTouchableHandle()) {
0079       touchableHandle = aTrack->GetTouchableHandle();
0080       // FIXME: This assumes we only ever have G4TouchableHistorys!
0081       auto* touchableHistory = (G4TouchableHistory*)touchableHandle();
0082       G4VPhysicalVolume* oldTopVolume = touchableHandle->GetVolume();
0083       G4VPhysicalVolume* newTopVolume =
0084         linearNavigator->ResetHierarchyAndLocate(pos, dir, *touchableHistory);
0085       // TODO: WHY?!
0086       if (newTopVolume != oldTopVolume || oldTopVolume->GetRegularStructureId() == 1) {
0087         touchableHandle = linearNavigator->CreateTouchableHistory();
0088         aTrack->SetTouchableHandle(touchableHandle);
0089       }
0090     }
0091     else {
0092       linearNavigator->LocateGlobalPointAndSetup(pos, &dir, false, false);
0093       touchableHandle = linearNavigator->CreateTouchableHistory();
0094       aTrack->SetTouchableHandle(touchableHandle);
0095     }
0096     aTrack->SetNextTouchableHandle(touchableHandle);
0097   }
0098 
0099   // Prepare data structures used while tracking.
0100   G4Step step;
0101   step.NewSecondaryVector();
0102   G4StepPoint& preStepPoint = *step.GetPreStepPoint();
0103   step.InitializeStep(aTrack);
0104   aTrack->SetStep(&step);
0105   G4TrackVector secondaries;
0106 
0107   // Start of tracking: Inform user and processes.
0108   if (userTrackingAction) {
0109     userTrackingAction->PreUserTrackingAction(aTrack);
0110   }
0111 
0112   physics.StartTracking(aTrack);
0113 
0114   while (aTrack->GetTrackStatus() == fAlive) {
0115     // Beginning of this step: Prepare data structures.
0116     aTrack->IncrementCurrentStepNumber();
0117 
0118     step.CopyPostToPreStepPoint();
0119     step.ResetTotalEnergyDeposit();
0120     aTrack->SetTouchableHandle(aTrack->GetNextTouchableHandle());
0121 
0122     auto* lvol = aTrack->GetTouchable()->GetVolume()->GetLogicalVolume();
0123     preStepPoint.SetMaterial(lvol->GetMaterial());
0124     preStepPoint.SetMaterialCutsCouple(lvol->GetMaterialCutsCouple());
0125 
0126     // Query step lengths from pyhsics and geometry, decide on limit.
0127     G4double physicalStep = physics.GetPhysicalInteractionLength(*aTrack);
0128     G4double geometryStep = navigation.MakeStep(*aTrack, step, physicalStep);
0129 
0130     bool geometryLimitedStep = geometryStep < physicalStep;
0131     G4double finalStep = geometryLimitedStep ? geometryStep : physicalStep;
0132 
0133     step.SetStepLength(finalStep);
0134     aTrack->SetStepLength(finalStep);
0135 
0136     // Call AlongStepDoIt in every step.
0137     physics.AlongStepDoIt(*aTrack, step, secondaries);
0138     step.UpdateTrack();
0139 
0140     if (aTrack->GetTrackStatus() == fAlive && aTrack->GetKineticEnergy() < DBL_MIN) {
0141       if (physics.HasAtRestProcesses()) {
0142         aTrack->SetTrackStatus(fStopButAlive);
0143       }
0144       else {
0145         aTrack->SetTrackStatus(fStopAndKill);
0146       }
0147     }
0148 
0149     navigation.FinishStep(*aTrack, step);
0150 
0151     // Check if the track left the world.
0152     if (aTrack->GetNextVolume() == nullptr) {
0153       aTrack->SetTrackStatus(fStopAndKill);
0154     }
0155 
0156     // The check should rather check for == fAlive and avoid calling
0157     // PostStepDoIt for fStopButAlive, but the generic stepping loop
0158     // does it like this...
0159     if (aTrack->GetTrackStatus() != fStopAndKill) {
0160       physics.PostStepDoIt(*aTrack, step, secondaries);
0161     }
0162 
0163     // Need to get the true step length, not the geometry step length!
0164     aTrack->AddTrackLength(step.GetStepLength());
0165 
0166     // End of this step: Call sensitive detector and stepping actions.
0167     if (step.GetControlFlag() != AvoidHitInvocation) {
0168       auto* sensitive = lvol->GetSensitiveDetector();
0169       if (sensitive) {
0170         sensitive->Hit(&step);
0171       }
0172     }
0173 
0174     if (userSteppingAction) {
0175       userSteppingAction->UserSteppingAction(&step);
0176     }
0177 
0178     auto* regionalAction = lvol->GetRegion()->GetRegionalSteppingAction();
0179     if (regionalAction) {
0180       regionalAction->UserSteppingAction(&step);
0181     }
0182   }
0183 
0184   if (aTrack->GetTrackStatus() == fStopButAlive && aTrack->GetNextVolume() != nullptr) {
0185     // Do one final step.
0186     aTrack->IncrementCurrentStepNumber();
0187 
0188     step.CopyPostToPreStepPoint();
0189     step.ResetTotalEnergyDeposit();
0190 
0191     physics.AtRestDoIt(*aTrack, step, secondaries);
0192 
0193     // End of this step: Call sensitive detector and stepping actions.
0194     auto* lvol = aTrack->GetTouchable()->GetVolume()->GetLogicalVolume();
0195     if (step.GetControlFlag() != AvoidHitInvocation) {
0196       auto sensitive = lvol->GetSensitiveDetector();
0197       if (sensitive) {
0198         sensitive->Hit(&step);
0199       }
0200     }
0201 
0202     if (userSteppingAction) {
0203       userSteppingAction->UserSteppingAction(&step);
0204     }
0205 
0206     auto* regionalAction = lvol->GetRegion()->GetRegionalSteppingAction();
0207     if (regionalAction) {
0208       regionalAction->UserSteppingAction(&step);
0209     }
0210   }
0211 
0212   // End of tracking: Inform processes and user.
0213   physics.EndTracking();
0214 
0215   if (userTrackingAction) {
0216     userTrackingAction->PostUserTrackingAction(aTrack);
0217   }
0218 
0219   evtMgr->StackTracks(&secondaries);
0220 
0221   step.DeleteSecondaryVector();
0222 }
0223 
0224 template <typename PhysicsImpl>
0225 void TrackingManagerHelper::TrackChargedParticle(G4Track* aTrack, PhysicsImpl& physics)
0226 {
0227   class ChargedNavigation final : public Navigation
0228   {
0229    public:
0230     ChargedNavigation()
0231     {
0232       auto* transMgr = G4TransportationManager::GetTransportationManager();
0233       fLinearNavigator = transMgr->GetNavigatorForTracking();
0234       fFieldPropagator = transMgr->GetPropagatorInField();
0235       fSafetyHelper = transMgr->GetSafetyHelper();
0236       kCarTolerance = 0.5 * G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
0237 
0238       // Reset sstate of field propagator and all chord finders.
0239       fFieldPropagator->ClearPropagatorState();
0240 
0241       auto* fieldMgrStore = G4FieldManagerStore::GetInstance();
0242       fieldMgrStore->ClearAllChordFindersState();
0243     }
0244 
0245     G4double MakeStep(G4Track& track, G4Step& step, G4double physicalStep) override
0246     {
0247       G4ThreeVector pos = track.GetPosition();
0248       G4ThreeVector dir = track.GetMomentumDirection();
0249       G4StepPoint& postStepPoint = *step.GetPostStepPoint();
0250 
0251       bool fieldExertsForce = false;
0252       if (auto* fieldMgr = fFieldPropagator->FindAndSetFieldManager(track.GetVolume())) {
0253         fieldMgr->ConfigureForTrack(&track);
0254         if (const G4Field* ptrField = fieldMgr->GetDetectorField()) {
0255           fieldExertsForce = true;
0256         }
0257       }
0258 
0259       G4double endpointDistance;
0260       G4double safety = 0.0;
0261       // Setting a fallback value for safety is required in case of where very
0262       // short steps where the field propagator returns immediately without
0263       // calling geometry.
0264       const G4double shiftSquare = (pos - fSafetyOrigin).mag2();
0265       if (shiftSquare < sqr(fSafety)) {
0266         safety = fSafety - std::sqrt(shiftSquare);
0267       }
0268 
0269       if (fieldExertsForce) {
0270         const G4DynamicParticle* pParticle = track.GetDynamicParticle();
0271         const G4double particleCharge = pParticle->GetCharge();
0272         const G4double particleMass = pParticle->GetMass();
0273         const G4double magneticMoment = pParticle->GetMagneticMoment();
0274         const G4ThreeVector particleSpin = pParticle->GetPolarization();
0275         const G4double kineticEnergy = pParticle->GetKineticEnergy();
0276         const auto pParticleDef = pParticle->GetDefinition();
0277         const auto particlePDGSpin = pParticleDef->GetPDGSpin();
0278         const auto particlePDGMagM = pParticleDef->GetPDGMagneticMoment();
0279 
0280         auto equationOfMotion = fFieldPropagator->GetCurrentEquationOfMotion();
0281         equationOfMotion->SetChargeMomentumMass(
0282           G4ChargeState(particleCharge, magneticMoment, particlePDGSpin),
0283           pParticle->GetTotalMomentum(), particleMass);
0284 
0285         const G4ThreeVector startPosition = pos;
0286         const G4ThreeVector startDirection = dir;
0287         G4FieldTrack aFieldTrack(startPosition,
0288           track.GetGlobalTime(),  // Lab.
0289           dir, kineticEnergy, particleMass, particleCharge, particleSpin, particlePDGMagM,
0290           0.0,  // Length along track
0291           particlePDGSpin);
0292 
0293         // Do the Transport in the field (non recti-linear)
0294         //
0295         fGeometryLimitedStep = false;
0296         const G4double lengthAlongCurve = fFieldPropagator->ComputeStep(
0297           aFieldTrack, physicalStep, safety, track.GetVolume(), kineticEnergy < 250.0);
0298         if (lengthAlongCurve < physicalStep) {
0299           physicalStep = lengthAlongCurve;
0300           fGeometryLimitedStep = true;
0301         }
0302         fSafetyHelper->SetCurrentSafety(safety, pos);
0303         fSafetyOrigin = pos;
0304         fSafety = safety;
0305 
0306         if (fFieldPropagator->IsParticleLooping()) {
0307           track.SetTrackStatus(fStopAndKill);
0308         }
0309 
0310         pos = aFieldTrack.GetPosition();
0311         dir = aFieldTrack.GetMomentumDir();
0312 
0313         postStepPoint.SetPosition(pos);
0314         postStepPoint.SetMomentumDirection(dir);
0315 
0316         endpointDistance = (startPosition - pos).mag();
0317       }
0318       else {
0319         fGeometryLimitedStep = false;
0320         G4double linearStepLength = fLinearNavigator->ComputeStep(pos, dir, physicalStep, safety);
0321         if (linearStepLength < physicalStep) {
0322           physicalStep = linearStepLength;
0323           fGeometryLimitedStep = true;
0324         }
0325         fSafetyHelper->SetCurrentSafety(safety, pos);
0326         fSafetyOrigin = pos;
0327         fSafety = safety;
0328 
0329         // Update the position.
0330         pos += physicalStep * dir;
0331         postStepPoint.SetPosition(pos);
0332 
0333         endpointDistance = physicalStep;
0334       }
0335 
0336       // Update global, local, and proper time.
0337       double velocity = track.GetVelocity();
0338       double deltaTime = 0;
0339       if (velocity > 0) {
0340         deltaTime = physicalStep / velocity;
0341       }
0342 
0343       postStepPoint.AddGlobalTime(deltaTime);
0344       postStepPoint.AddLocalTime(deltaTime);
0345 
0346       double restMass = track.GetDynamicParticle()->GetMass();
0347       double deltaProperTime = deltaTime * (restMass / track.GetTotalEnergy());
0348       postStepPoint.AddProperTime(deltaProperTime);
0349 
0350       // Compute safety, including the call to safetyHelper, but don't set the
0351       // safety in the post-step point to mimick the generic stepping loop.
0352       if (safety > physicalStep) {
0353         safety -= physicalStep;
0354       }
0355       else if (safety < endpointDistance) {
0356         safety = fLinearNavigator->ComputeSafety(pos);
0357         fSafetyHelper->SetCurrentSafety(safety, pos);
0358         fSafetyOrigin = pos;
0359         fSafety = safety;
0360       }
0361       else {
0362         safety = 0;
0363       }
0364       if (safety < kCarTolerance) {
0365         fPostStepSafety = kCarTolerance;
0366       }
0367       else {
0368         fPostStepSafety = safety;
0369       }
0370 
0371       return physicalStep;
0372     }
0373 
0374     void FinishStep(G4Track& track, G4Step& step) override
0375     {
0376       // Now set the safety that was computed in MakeStep.
0377       G4StepPoint& postStepPoint = *step.GetPostStepPoint();
0378       postStepPoint.SetSafety(fPostStepSafety);
0379 
0380       G4TouchableHandle touchableHandle = track.GetTouchableHandle();
0381       const G4ThreeVector& pos = track.GetPosition();
0382       if (fGeometryLimitedStep) {
0383         // Relocate the particle.
0384         fLinearNavigator->SetGeometricallyLimitedStep();
0385         fLinearNavigator->LocateGlobalPointAndUpdateTouchableHandle(
0386           pos, track.GetMomentumDirection(), touchableHandle, true);
0387         const G4VPhysicalVolume* newVolume = touchableHandle->GetVolume();
0388         if (newVolume == nullptr) {
0389           postStepPoint.SetStepStatus(fWorldBoundary);
0390         }
0391         else {
0392           postStepPoint.SetStepStatus(fGeomBoundary);
0393         }
0394       }
0395       else {
0396         // Move the Navigator's location.
0397         fLinearNavigator->LocateGlobalPointWithinVolume(pos);
0398       }
0399 
0400       postStepPoint.SetTouchableHandle(touchableHandle);
0401       track.SetNextTouchableHandle(touchableHandle);
0402     }
0403 
0404    private:
0405     G4Navigator* fLinearNavigator;
0406     G4PropagatorInField* fFieldPropagator;
0407     G4SafetyHelper* fSafetyHelper;
0408     G4ThreeVector fSafetyOrigin;
0409     G4double fSafety = 0;
0410     G4double fPostStepSafety = 0;
0411     G4double kCarTolerance;
0412     G4bool fGeometryLimitedStep;
0413   };
0414 
0415   ChargedNavigation navigation;
0416   TrackParticle(aTrack, physics, navigation);
0417 }
0418 
0419 template <typename PhysicsImpl>
0420 void TrackingManagerHelper::TrackNeutralParticle(G4Track* aTrack, PhysicsImpl& physics)
0421 {
0422   class NeutralNavigation final : public Navigation
0423   {
0424    public:
0425     NeutralNavigation()
0426     {
0427       auto* transMgr = G4TransportationManager::GetTransportationManager();
0428       fLinearNavigator = transMgr->GetNavigatorForTracking();
0429       fSafetyHelper = transMgr->GetSafetyHelper();
0430       kCarTolerance = 0.5 * G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
0431     }
0432 
0433     G4double MakeStep(G4Track& track, G4Step& step, G4double physicalStep) override
0434     {
0435       G4ThreeVector pos = track.GetPosition();
0436       G4ThreeVector dir = track.GetMomentumDirection();
0437       G4StepPoint& postStepPoint = *step.GetPostStepPoint();
0438 
0439       G4double safety = 0.0;
0440       const G4double shiftSquare = (pos - fSafetyOrigin).mag2();
0441       if (shiftSquare < sqr(fSafety)) {
0442         safety = fSafety - std::sqrt(shiftSquare);
0443       }
0444 
0445       fGeometryLimitedStep = false;
0446       G4double linearStepLength = fLinearNavigator->ComputeStep(pos, dir, physicalStep, safety);
0447       if (linearStepLength < physicalStep) {
0448         physicalStep = linearStepLength;
0449         fGeometryLimitedStep = true;
0450       }
0451       fSafetyHelper->SetCurrentSafety(safety, pos);
0452       fSafetyOrigin = pos;
0453       fSafety = safety;
0454 
0455       // Update the position.
0456       pos += physicalStep * dir;
0457       postStepPoint.SetPosition(pos);
0458 
0459       // Update global, local, and proper time.
0460       double velocity = track.GetVelocity();
0461       double deltaTime = 0;
0462       if (velocity > 0) {
0463         deltaTime = physicalStep / velocity;
0464       }
0465       postStepPoint.AddGlobalTime(deltaTime);
0466       postStepPoint.AddLocalTime(deltaTime);
0467 
0468       double restMass = track.GetDynamicParticle()->GetMass();
0469       double deltaProperTime = deltaTime * (restMass / track.GetTotalEnergy());
0470       postStepPoint.AddProperTime(deltaProperTime);
0471 
0472       // Compute safety, but don't set the safety in the post-step point to
0473       // mimick the generic stepping loop.
0474       if (safety > physicalStep) {
0475         safety -= physicalStep;
0476       }
0477       else {
0478         safety = 0;
0479       }
0480       if (safety < kCarTolerance) {
0481         fPostStepSafety = kCarTolerance;
0482       }
0483       else {
0484         fPostStepSafety = safety;
0485       }
0486 
0487       return physicalStep;
0488     }
0489 
0490     void FinishStep(G4Track& track, G4Step& step) override
0491     {
0492       // Now set the safety that was computed in MakeStep.
0493       G4StepPoint& postStepPoint = *step.GetPostStepPoint();
0494       postStepPoint.SetSafety(fPostStepSafety);
0495 
0496       G4TouchableHandle touchableHandle = track.GetTouchableHandle();
0497       const G4ThreeVector& pos = track.GetPosition();
0498       if (fGeometryLimitedStep) {
0499         // Relocate the particle.
0500         fLinearNavigator->SetGeometricallyLimitedStep();
0501         fLinearNavigator->LocateGlobalPointAndUpdateTouchableHandle(
0502           pos, track.GetMomentumDirection(), touchableHandle, true);
0503         const G4VPhysicalVolume* newVolume = touchableHandle->GetVolume();
0504         if (newVolume == nullptr) {
0505           postStepPoint.SetStepStatus(fWorldBoundary);
0506         }
0507         else {
0508           postStepPoint.SetStepStatus(fGeomBoundary);
0509         }
0510       }
0511       else {
0512         // Move the Navigator's location.
0513         fLinearNavigator->LocateGlobalPointWithinVolume(pos);
0514       }
0515 
0516       postStepPoint.SetTouchableHandle(touchableHandle);
0517       track.SetNextTouchableHandle(touchableHandle);
0518     }
0519 
0520    private:
0521     G4Navigator* fLinearNavigator;
0522     G4SafetyHelper* fSafetyHelper;
0523     G4ThreeVector fSafetyOrigin;
0524     G4double fSafety = 0;
0525     G4double fPostStepSafety = 0;
0526     G4double kCarTolerance;
0527     G4bool fGeometryLimitedStep;
0528   };
0529 
0530   NeutralNavigation navigation;
0531   TrackParticle(aTrack, physics, navigation);
0532 }