Belle II Software development
TrackingAction.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <simulation/kernel/TrackingAction.h>
10#include <simulation/kernel/UserInfo.h>
11#include <simulation/kernel/SensitiveDetectorBase.h>
12#include <framework/logging/Logger.h>
13#include <framework/gearbox/Unit.h>
14
15#include <G4TrackingManager.hh>
16#include <G4Track.hh>
17#include <G4ParticleDefinition.hh>
18#include <G4ParticleTypes.hh>
19#include <G4EmProcessSubType.hh>
20#include <G4DecayProcessType.hh>
21#include <G4Event.hh>
22#include <G4ParticleTable.hh>
23
24using namespace Belle2;
25using namespace Belle2::Simulation;
26
28 G4UserTrackingAction(), m_mcParticleGraph(mcParticleGraph),
29 m_ignoreOpticalPhotons(false),
30 m_ignoreSecondaries(false), m_secondariesEnergyCut(0.0),
31 m_ignoreBremsstrahlungPhotons(false), m_bremsstrahlungPhotonsEnergyCut(0.0),
32 m_ignorePairConversions(false), m_pairConversionsEnergyCut(0.0),
33 m_storeTrajectories(false), m_distanceTolerance(0),
34 m_storeMCTrajectories(), m_relMCTrajectories(StoreArray<MCParticle>(), m_storeMCTrajectories)
35{
36}
37
39{
40}
41
42void TrackingAction::setStoreTrajectories(int store, double distanceTolerance)
43{
44 m_storeTrajectories = store;
45 m_distanceTolerance = distanceTolerance;
46 if (store) {
47 // registration of store arrays and relations
48 m_storeMCTrajectories.registerInDataStore();
49 StoreArray<MCParticle> mcParticles;
51
52 // additional registration of MCParticle relation
53 // (note: m_relMCTrajectories is already defined by TrackingAction::TrackingAction)
55 }
56}
57
58void TrackingAction::PreUserTrackingAction(const G4Track* track)
59{
60 //We only want to do the following for new tracks, not for suspended and reactivated ones"
61 if (track->GetCurrentStepNumber() > 0) return;
62
63 const G4DynamicParticle* dynamicParticle = track->GetDynamicParticle();
64
65 try {
66 //Check if the dynamic particle has a primary particle attached.
67 //If the answer is yes, the UserInfo of the primary particle is recycled as the UserInfo of the track.
68 const bool isPrimary = dynamicParticle->GetPrimaryParticle() != nullptr;
69 bool neutral_llp = false;
70 if (isPrimary) {
71 const G4PrimaryParticle* primaryParticle = dynamicParticle->GetPrimaryParticle();
72 if (primaryParticle->GetUserInformation() != nullptr) {
73 const_cast<G4Track*>(track)->SetUserInformation(new TrackInfo(ParticleInfo::getInfo(*primaryParticle)));
74 //check for neutral long-lived primary particle
75 if (primaryParticle->GetParticleDefinition() == G4ParticleTable::GetParticleTable()->FindParticle("LongLivedNeutralParticle")) {
76 neutral_llp = true;
77 }
78 } else {
79 B2WARNING(track->GetDefinition()->GetPDGEncoding() << " has no MCParticle user information !");
80 }
81 }
82
83 //Get particle of current track
85
86 G4ThreeVector dpMom = dynamicParticle->GetMomentum() / CLHEP::MeV * Unit::MeV;
87 currParticle.setTrackID(track->GetTrackID());
88 // If the particle is a primary particle with simulated parents update the
89 // production vertex and time to the real values from Geant4. As convention
90 // we set NaN as production time in the MCParticleGenerator if the particle
91 // wasn't directly placed with a primary vertex in Geant4.
92 if (!isPrimary or std::isnan(currParticle.getProductionTime())) {
93 G4ThreeVector trVtxPos = track->GetVertexPosition() / CLHEP::mm * Unit::mm;
94 currParticle.setProductionTime(track->GetGlobalTime()); // Time does not need a conversion factor
95 currParticle.setProductionVertex(trVtxPos.x(), trVtxPos.y(), trVtxPos.z());
96 }
97
98 //Set the Values of the particle which are already known
99 if (!neutral_llp) {
100 currParticle.setPDG(dynamicParticle->GetPDGcode());
101 currParticle.setMass(dynamicParticle->GetMass() / CLHEP::MeV * Unit::MeV);
102 currParticle.setEnergy(dynamicParticle->GetTotalEnergy() / CLHEP::MeV * Unit::MeV);
103 currParticle.setMomentum(dpMom.x(), dpMom.y(), dpMom.z());
104 }
105
106 //Primary or secondary particle?
107 if (isPrimary) {
108 //Primary particle
109 currParticle.setSecondaryPhysicsProcess(0);
110 currParticle.setIgnore(false); //Store the generator info in the MCParticles block.
111
112 } else if (track->GetCreatorProcess() != nullptr) {
113 //Secondary particle
114 const int& processSubType = track->GetCreatorProcess()->GetProcessSubType();
115 currParticle.setSecondaryPhysicsProcess(processSubType); //Store the physics process type.
116
117 //Decay-in-flight
118 if (processSubType >= static_cast<int>(DECAY) && processSubType <= static_cast<int>(DECAY_External))
119 currParticle.setIgnore(false); //Store the generator info in the MCParticles block.
120
121 } else {
122 //Unknown origin. This could be a bug originated from Geant4.
123 currParticle.setSecondaryPhysicsProcess(-1);
124 }
125
126 //Either we store all the trajectories
127 if (m_storeTrajectories > 2 ||
128 //Or only the primary ones
129 (m_storeTrajectories == 1 && isPrimary) ||
130 //Or all except optical photons
131 (m_storeTrajectories == 2 && track->GetDefinition() != G4OpticalPhoton::OpticalPhotonDefinition())) {
132 TrackInfo& info = dynamic_cast<TrackInfo&>(*track->GetUserInformation());
133 m_relMCTrajectories.add(track->GetTrackID(), m_storeMCTrajectories.getEntries());
134 info.setTrajectory(m_storeMCTrajectories.appendNew());
135 }
136
137 } catch (CouldNotFindUserInfo& exc) {
138 B2FATAL(exc.what());
139 }
140}
141
142
144{
145 G4StepPoint* postStep = track->GetStep()->GetPostStepPoint();
146
147 // Get particle of the current track
148 try {
150
151 // Add particle and decay Information to all the secondaries
152 for (G4Track* daughterTrack : *fpTrackingManager->GimmeSecondaries()) {
153
154 // Add the particle to the particle graph and as UserInfo to the track
155 // if it is a secondary particle created by Geant4.
156 if (daughterTrack->GetDynamicParticle()->GetPrimaryParticle() == NULL &&
157 daughterTrack->GetUserInformation() == NULL) {
159 const_cast<G4Track*>(daughterTrack)->SetUserInformation(new TrackInfo(daughterParticle));
160
161 currParticle.decaysInto(daughterParticle); //Add the decay history
162
163 // Optical photons and secondaries: steering of output to MCParticles
164 if (daughterTrack->GetDefinition() == G4OpticalPhoton::OpticalPhotonDefinition()) {
165
166 // Optical photons
167 if (m_ignoreOpticalPhotons) daughterParticle.setIgnore();
168 // to apply quantum efficiency only once, if optical photon is a daugher of optical photon
169 if (track->GetDefinition() == G4OpticalPhoton::OpticalPhotonDefinition()) {
170 TrackInfo* currInfo = dynamic_cast<TrackInfo*>(track->GetUserInformation());
171 TrackInfo* daughterInfo = dynamic_cast<TrackInfo*>(daughterTrack->GetUserInformation());
172 daughterInfo->setStatus(currInfo->getStatus());
173 daughterInfo->setFraction(currInfo->getFraction());
174 }
175
176 } else if (daughterTrack->GetCreatorProcess()->GetProcessSubType() == fBremsstrahlung) {
177
178 // Bremsstrahlung photons
179 // Do not store the generator info in the final MCParticles block
180 // if the ignore flag is set or its energy is too low in [MeV].
181 if (m_ignoreBremsstrahlungPhotons || daughterTrack->GetKineticEnergy() < m_bremsstrahlungPhotonsEnergyCut)
182 daughterParticle.setIgnore();
183
184 } else if (daughterTrack->GetCreatorProcess()->GetProcessSubType() == fGammaConversion) {
185
186 // e+ or e- created by gamma conversion to pairs
187 // Do not store the generator info in the final MCParticles block
188 // if the ignore flag is set or kinetic energy is too low in [MeV].
189 if (m_ignorePairConversions || daughterTrack->GetKineticEnergy() < m_pairConversionsEnergyCut)
190 daughterParticle.setIgnore();
191
192 } else {
193
194 // Do not store the generator info in the final MCParticles block
195 // if the ignore flag is set or its kinetic energy is too low in [MeV].
196 if (m_ignoreSecondaries || daughterTrack->GetKineticEnergy() < m_secondariesEnergyCut)
197 daughterParticle.setIgnore();
198
199 //B2INFO("Secondary Physics Process: " << daughterTrack->GetCreatorProcess()->GetProcessSubType());
200 }
201
202 }
203 }
204 //If the track is just suspended we can return here: the rest should be filled once the track is done
205 if (track->GetTrackStatus() == fSuspend) return;
206
207 //Check if particle left the detector/simulation volume.
208 if (postStep->GetStepStatus() == fWorldBoundary) {
210 }
211
212 //Check if particle was stopped in the detector/simulation volume
213 if (track->GetKineticEnergy() <= 0.0) {
215 }
216
217 //Set the values for the particle
218 G4ThreeVector decVtx = postStep->GetPosition() / CLHEP::mm * Unit::mm;
219 currParticle.setDecayVertex(decVtx.x(), decVtx.y(), decVtx.z());
220 currParticle.setDecayTime(postStep->GetGlobalTime()); // Time does not need a conversion factor
221 currParticle.setValidVertex(true);
222
223 //Check if we can remove some points from the trajectory
225 MCParticleTrajectory* tr = dynamic_cast<TrackInfo*>(track->GetUserInformation())->getTrajectory();
226 if (tr) {
228 }
229 }
230 } catch (CouldNotFindUserInfo& exc) {
231 B2FATAL(exc.what());
232 }
233}
Class to represent Particle data in graph.
void decaysInto(GraphParticle &daughter)
Tells the graph that this particle decays into daughter.
void setTrackID(int trackID)
Set the track ID for the particle.
void setIgnore(bool ignore=true)
Set or remove the ignore flag.
Class to build, validate and sort a particle decay chain.
Class to save the full simulated trajectory of a particle.
void simplify(float distanceTolerance)
Simplify the trajectory using the Ramer-Douglas-Peuker algorithm.
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
@ c_LeftDetector
bit 2: Particle left the detector (the simulation volume).
Definition: MCParticle.h:51
@ c_StoppedInDetector
bit 3: Particle was stopped in the detector (the simulation volume).
Definition: MCParticle.h:53
void setDecayTime(float time)
Set decay time.
Definition: MCParticle.h:390
void setMass(float mass)
Set particle mass.
Definition: MCParticle.h:366
void setDecayVertex(const ROOT::Math::XYZVector &vertex)
Set decay vertex.
Definition: MCParticle.h:447
void addStatus(unsigned short int bitmask)
Add bitmask to current status.
Definition: MCParticle.h:353
void setEnergy(float energy)
Set energy.
Definition: MCParticle.h:372
void setValidVertex(bool valid)
Set indication wether vertex and time information is valid or just default.
Definition: MCParticle.h:378
void setProductionVertex(const ROOT::Math::XYZVector &vertex)
Set production vertex position.
Definition: MCParticle.h:396
void setSecondaryPhysicsProcess(int physicsProcess)
Sets the physics process type of a secondary particle.
Definition: MCParticle.h:468
void setPDG(int pdg)
Set PDG code of the particle.
Definition: MCParticle.h:335
float getProductionTime() const
Return production time in ns.
Definition: MCParticle.h:159
void setMomentum(const ROOT::Math::XYZVector &momentum)
Set particle momentum.
Definition: MCParticle.h:417
void setProductionTime(float time)
Set production time.
Definition: MCParticle.h:384
@ c_negativeWeight
Flip the sign of the weight to become negative if the original element got re-attributed.
Definition: RelationArray.h:79
void add(index_type from, index_type to, weight_type weight=1.0)
Add a new element to the relation.
static void registerMCParticleRelation(const std::string &name, RelationArray::EConsolidationAction ignoreAction=RelationArray::c_negativeWeight)
Register an relation involving MCParticles.
virtual ~TrackingAction()
Destructor.
bool m_ignoreSecondaries
do not store secondaries in MCParticles
MCParticleGraph & m_mcParticleGraph
Reference to the MCParticle graph which is updated by the tracking action.
TrackingAction(MCParticleGraph &mcParticleGraph)
Constructor.
double m_pairConversionsEnergyCut
kinetic energy cut for stored e+ or e- from pair conversions [MeV]
void setStoreTrajectories(int store, double distanceTolerance)
Sets the trajectory option to enable storing of the simulated particle trajectories.
RelationArray m_relMCTrajectories
RelationArry for the relation between MCParticles and Trajectories.
StoreArray< MCParticleTrajectory > m_storeMCTrajectories
Store array for the Trajectories.
double m_distanceTolerance
distance tolerance to merge trajectory points
void PreUserTrackingAction(const G4Track *track)
Checks if the particle associated to the track is already in the MCParticle list.
double m_secondariesEnergyCut
kinetic energy cut for stored secondaries [MeV]
void PostUserTrackingAction(const G4Track *track)
Updates the data of the MCParticle associated with the Geant4 track.
bool m_ignorePairConversions
do not store e+ or e- from pair conversions in MCparticles
bool m_ignoreBremsstrahlungPhotons
do not store bremsstrahlung photons in MCParticles
bool m_ignoreOpticalPhotons
do not store optical photons in MCParticles
double m_bremsstrahlungPhotonsEnergyCut
kinetic energy cut for stored bremsstrahlung photons [MeV]
int m_storeTrajectories
Store trajectories for 0=none, 1=primary or 2=all particles.
UserInfo class which is used to attach additional information to Geant4 particles and tracks.
Definition: UserInfo.h:36
void setFraction(double fraction)
Store optical photon propagation fraction (used for performance speed-ups)
Definition: UserInfo.h:83
void setStatus(int status)
Set status of optical photon (used for performance speed-ups)
Definition: UserInfo.h:77
double getFraction()
Get optical photon propagation fraction (used for performance speed-ups) status=0: fraction=1 status=...
Definition: UserInfo.h:68
static Payload getInfo(Carrier &obj)
Static function to just return UserInformation attached to the obj of type Carrier.
Definition: UserInfo.h:100
int getStatus()
Get status of optical photon (used for performance speed-ups) 0 initial 1 prescaled in StackingAction...
Definition: UserInfo.h:59
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
Definition: StoreArray.h:140
static const double mm
[millimeters]
Definition: Unit.h:70
static const double MeV
[megaelectronvolt]
Definition: Unit.h:114
GraphParticle & addParticle()
Add new particle to the graph.
Abstract base class for different kinds of events.