EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EicRootSteppingAction.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file EicRootSteppingAction.cc
1 
2 #include <cmath>
3 #include <iostream>
4 #include <string>
5 
6 #include <TSystem.h>
7 
8 #include <Geant4/G4ParticleDefinition.hh>
9 #include <Geant4/G4ReferenceCountedHandle.hh>
10 #include <Geant4/G4Step.hh>
11 #include <Geant4/G4StepPoint.hh>
12 #include <Geant4/G4StepStatus.hh>
13 #include <Geant4/G4String.hh>
14 #include <Geant4/G4SystemOfUnits.hh>
15 #include <Geant4/G4ThreeVector.hh>
16 #include <Geant4/G4TouchableHandle.hh>
17 #include <Geant4/G4Track.hh>
18 #include <Geant4/G4TrackStatus.hh>
19 #include <Geant4/G4Types.hh>
20 #include <Geant4/G4VPhysicalVolume.hh>
21 #include <Geant4/G4VTouchable.hh>
22 #include <Geant4/G4VUserTrackInformation.hh>
23 
24 #include <phparameter/PHParameters.h>
25 
27 
28 #include <g4main/PHG4Hit.h>
30 #include <g4main/PHG4Hitv1.h>
31 #include <g4main/PHG4Shower.h>
34 
35 #include <phool/getClass.h>
36 
37 #include "EicRootSteppingAction.h"
38 #include "EicRootDetector.h"
39 
40 using namespace std;
41 
42 //____________________________________________________________________________..
44  : PHG4SteppingAction(detector->GetName())
45  , m_Detector(detector)
46  , m_Params(parameters)
47  , m_HitContainer(nullptr)
48  , m_AbsorberHitContainer(nullptr)
49  , m_Hit(nullptr)
50  , m_SaveHitContainer(nullptr)
51  , m_SaveVolPre(nullptr)
52  , m_SaveVolPost(nullptr)
53  , m_SaveTrackId(-1)
54  , m_SavePreStepStatus(-1)
55  , m_SavePostStepStatus(-1)
56  , m_BlackHoleFlag(m_Params->get_int_param("blackhole"))
57  , m_EdepSum(0)
58 {
59 }
60 
61 //____________________________________________________________________________..
63 {
64  // if the last hit was a zero energie deposit hit, it is just reset
65  // and the memory is still allocated, so we need to delete it here
66  // if the last hit was saved, hit is a nullptr pointer which are
67  // legal to delete (it results in a no operation)
68  delete m_Hit;
69 }
70 
71 //____________________________________________________________________________..
72 // This is the implementation of the G4 UserSteppingAction
73 bool GdmlImportDetectorSteppingAction::UserSteppingAction(const G4Step *aStep, bool was_used)
74 {
75  G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle();
76  G4TouchableHandle touchpost = aStep->GetPostStepPoint()->GetTouchableHandle();
77  // get volume of the current step
78  G4VPhysicalVolume *volume = touch->GetVolume();
79  // IsInDetector(volume) returns
80  // == 0 outside of detector
81  // > 0 for hits in active volume
82  // < 0 for hits in passive material
83  int whichactive = m_Detector->IsInDetector(volume);
84  if (!whichactive)
85  {
86  return false;
87  }
88  // collect energy and track length step by step
89  G4double edep = aStep->GetTotalEnergyDeposit() / GeV;
90  const G4Track *aTrack = aStep->GetTrack();
91  // if this detector stops everything, just put all kinetic energy into edep
92  if (m_BlackHoleFlag)
93  {
94  edep = aTrack->GetKineticEnergy() / GeV;
95  G4Track *killtrack = const_cast<G4Track *>(aTrack);
96  killtrack->SetTrackStatus(fStopAndKill);
97  }
98 
99  // Subtract '1' back, so the layer count starts from 0;
100  int detector_id = whichactive - 1;
101 
102  // cout << "Name: " << volume->GetName() << endl;
103  // cout << "det id: " << whichactive << endl;
104  bool geantino = false;
105  // the check for the pdg code speeds things up, I do not want to make
106  // an expensive string compare for every track when we know
107  // geantino or chargedgeantino has pid=0
108  if (aTrack->GetParticleDefinition()->GetPDGEncoding() == 0 &&
109  aTrack->GetParticleDefinition()->GetParticleName().find("geantino") !=
110  string::npos) // this also accounts for "chargedgeantino"
111  {
112  geantino = true;
113  }
114  G4StepPoint *prePoint = aStep->GetPreStepPoint();
115  G4StepPoint *postPoint = aStep->GetPostStepPoint();
116 
117  // Here we have to decide if we need to create a new hit. Normally this should
118  // only be neccessary if a G4 Track enters a new volume or is freshly created
119  // For this we look at the step status of the prePoint (beginning of the G4 Step).
120  // This should be either fGeomBoundary (G4 Track crosses into volume) or
121  // fUndefined (G4 Track newly created)
122  // Sadly over the years with different G4 versions we have observed cases where
123  // G4 produces "impossible hits" which we try to catch here
124  // These errors were always rare and it is not clear if they still exist but we
125  // still check for them for safety. We can reproduce G4 runs identically (if given
126  // the sequence of random number seeds you find in the log), the printouts help
127  // us giving the G4 support information about those failures
128  //
129  switch (prePoint->GetStepStatus())
130  {
131  case fPostStepDoItProc:
132  if (m_SavePostStepStatus != fGeomBoundary)
133  {
134  // this is the okay case, fPostStepDoItProc called in a volume, not first thing inside
135  // a new volume, just proceed here
136  break;
137  }
138  else
139  {
140  // this is an impossible G4 Step print out diagnostic to help debug, not sure if
141  // this is still with us
142  cout << GetName() << ": New Hit for " << endl;
143  cout << "prestep status: "
144  << PHG4StepStatusDecode::GetStepStatus(prePoint->GetStepStatus())
145  << ", poststep status: "
146  << PHG4StepStatusDecode::GetStepStatus(postPoint->GetStepStatus())
147  << ", last pre step status: "
149  << ", last post step status: "
151  cout << "last track: " << m_SaveTrackId
152  << ", current trackid: " << aTrack->GetTrackID() << endl;
153  cout << "phys pre vol: " << volume->GetName()
154  << " post vol : " << touchpost->GetVolume()->GetName() << endl;
155  cout << " previous phys pre vol: " << m_SaveVolPre->GetName()
156  << " previous phys post vol: " << m_SaveVolPost->GetName() << endl;
157  }
158  // These are the normal cases
159  case fGeomBoundary:
160  case fUndefined:
161  if (!m_Hit)
162  {
163  m_Hit = new PHG4Hitv1();
164  }
165  m_Hit->set_layer(detector_id);
166  // here we set the entrance values in cm
167  m_Hit->set_x(0, prePoint->GetPosition().x() / cm);
168  m_Hit->set_y(0, prePoint->GetPosition().y() / cm);
169  m_Hit->set_z(0, prePoint->GetPosition().z() / cm);
170  // time in ns
171  m_Hit->set_t(0, prePoint->GetGlobalTime() / nanosecond);
172  // set the track ID
173  m_Hit->set_trkid(aTrack->GetTrackID());
174  m_SaveTrackId = aTrack->GetTrackID();
175  // set the initial energy deposit
176  m_EdepSum = 0;
177  // implement your own here://
178  // add the properties you are interested in via set_XXX methods
179  // you can find existing set methods in $OFFLINE_MAIN/include/g4main/PHG4Hit.h
180  // this is initialization of your value. This is not needed you can just set the final
181  // value at the last step in this volume later one
182  if (whichactive > 0)
183  {
184  m_SaveHitContainer = m_Detector->get_hitcontainer();//detector_id);
185  }
186  else
187  {
188  // all absorber hits go into one node
189  assert(0);
190  //+m_SaveHitContainer = m_Detector->get_hitcontainer(-1);
191  }
192  // this is for the tracking of the truth info
193  if (G4VUserTrackInformation *p = aTrack->GetUserInformation())
194  {
195  if (PHG4TrackUserInfoV1 *pp = dynamic_cast<PHG4TrackUserInfoV1 *>(p))
196  {
197  m_Hit->set_trkid(pp->GetUserTrackId());
198  pp->GetShower()->add_g4hit_id(m_SaveHitContainer->GetID(), m_Hit->get_hit_id());
199  }
200  }
201  break;
202  default:
203  break;
204  }
205 
206  // This section is called for every step
207  // some sanity checks for inconsistencies (aka bugs) we have seen over the years
208  // check if this hit was created, if not print out last post step status
209  if (!m_Hit || !isfinite(m_Hit->get_x(0)))
210  {
211  cout << GetName() << ": hit was not created" << endl;
212  cout << "prestep status: "
213  << PHG4StepStatusDecode::GetStepStatus(prePoint->GetStepStatus())
214  << ", poststep status: "
215  << PHG4StepStatusDecode::GetStepStatus(postPoint->GetStepStatus())
216  << ", last pre step status: "
218  << ", last post step status: "
220  cout << "last track: " << m_SaveTrackId
221  << ", current trackid: " << aTrack->GetTrackID() << endl;
222  cout << "phys pre vol: " << volume->GetName()
223  << " post vol : " << touchpost->GetVolume()->GetName() << endl;
224  cout << " previous phys pre vol: " << m_SaveVolPre->GetName()
225  << " previous phys post vol: " << m_SaveVolPost->GetName() << endl;
226  // This is fatal - a hit from nowhere. This needs to be looked at and fixed
227  gSystem->Exit(1);
228  }
229  // check if track id matches the initial one when the hit was created
230  if (aTrack->GetTrackID() != m_SaveTrackId)
231  {
232  cout << GetName() << ": hits do not belong to the same track" << endl;
233  cout << "saved track: " << m_SaveTrackId
234  << ", current trackid: " << aTrack->GetTrackID()
235  << ", prestep status: " << prePoint->GetStepStatus()
236  << ", previous post step status: " << m_SavePostStepStatus << endl;
237  // This is fatal - a hit from nowhere. This needs to be looked at and fixed
238  gSystem->Exit(1);
239  }
240 
241  // We need to cache a few things from one step to the next
242  // to identify impossible hits and subsequent debugging printout
243  m_SavePreStepStatus = prePoint->GetStepStatus();
244  m_SavePostStepStatus = postPoint->GetStepStatus();
246  m_SaveVolPost = touchpost->GetVolume();
247  // here we just update the exit values, it will be overwritten
248  // for every step until we leave the volume or the particle
249  // ceases to exist
250  // sum up the energy to get total deposited
251  m_EdepSum += edep;
252  // if any of these conditions is true this is the last step in
253  // this volume and we need to save the hit
254  // postPoint->GetStepStatus() == fGeomBoundary: track leaves this volume
255  // postPoint->GetStepStatus() == fWorldBoundary: track leaves this world
256  // (happens when your detector goes outside world volume)
257  // postPoint->GetStepStatus() == fAtRestDoItProc: track stops (typically
258  // aTrack->GetTrackStatus() == fStopAndKill is also set)
259  // aTrack->GetTrackStatus() == fStopAndKill: track ends
260  if (postPoint->GetStepStatus() == fGeomBoundary ||
261  postPoint->GetStepStatus() == fWorldBoundary ||
262  postPoint->GetStepStatus() == fAtRestDoItProc ||
263  aTrack->GetTrackStatus() == fStopAndKill)
264  {
265  // save only hits with energy deposit (or geantino)
266  if (m_EdepSum > 0 || geantino)
267  {
268  // update values at exit coordinates and set keep flag
269  // of track to keep
270  m_Hit->set_x(1, postPoint->GetPosition().x() / cm);
271  m_Hit->set_y(1, postPoint->GetPosition().y() / cm);
272  m_Hit->set_z(1, postPoint->GetPosition().z() / cm);
273  m_Hit->set_t(1, postPoint->GetGlobalTime() / nanosecond);
274  if (G4VUserTrackInformation *p = aTrack->GetUserInformation())
275  {
276  if (PHG4TrackUserInfoV1 *pp = dynamic_cast<PHG4TrackUserInfoV1 *>(p))
277  {
278  pp->SetKeep(1); // we want to keep the track
279  }
280  }
281  if (geantino)
282  {
283  //implement your own here://
284  // if you want to do something special for geantinos (normally you do not)
285  m_Hit->set_edep(-1); // only energy=0 g4hits get dropped, this way
286  // geantinos survive the g4hit compression
287  }
288  else
289  {
291  }
292  //printf("Adding hit!\n");
293  m_SaveHitContainer->AddHit(detector_id, m_Hit);
294  // ownership has been transferred to container, set to null
295  // so we will create a new hit for the next track
296  m_Hit = nullptr;
297  }
298  else
299  {
300  // if this hit has no energy deposit, just reset it for reuse
301  // this means we have to delete it in the dtor. If this was
302  // the last hit we processed the memory is still allocated
303  m_Hit->Reset();
304  }
305  }
306  // return true to indicate the hit was used
307  return true;
308 }