Belle II Software  release-08-01-10
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 
24 using namespace Belle2;
25 using 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 
42 void 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 
58 void 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
84  MCParticleGraph::GraphParticle& currParticle = TrackInfo::getInfo(*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 
143 void TrackingAction::PostUserTrackingAction(const G4Track* track)
144 {
145  G4StepPoint* postStep = track->GetStep()->GetPostStepPoint();
146 
147  // Get particle of the current track
148  try {
149  MCParticleGraph::GraphParticle& currParticle = TrackInfo::getInfo(*track);
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
224  if (m_storeTrajectories) {
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.