Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHG4MvtxSteppingAction.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHG4MvtxSteppingAction.cc
2 
3 #include "PHG4MvtxDetector.h"
4 
5 #include <g4main/PHG4Hit.h>
7 #include <g4main/PHG4Hitv1.h>
8 #include <g4main/PHG4Shower.h>
9 #include <g4main/PHG4SteppingAction.h> // for PHG4SteppingAction
11 
12 #include <phparameter/PHParameters.h>
13 #include <phparameter/PHParametersContainer.h>
14 
15 #include <phool/getClass.h>
16 #include <phool/phool.h> // for PHWHERE
17 
18 #include <TSystem.h>
19 
20 #include <Geant4/G4NavigationHistory.hh>
21 #include <Geant4/G4ParticleDefinition.hh> // for G4ParticleDefinition
22 #include <Geant4/G4ReferenceCountedHandle.hh> // for G4ReferenceCountedHandle
23 #include <Geant4/G4Step.hh>
24 #include <Geant4/G4StepPoint.hh> // for G4StepPoint
25 #include <Geant4/G4StepStatus.hh> // for fGeomBoundary, fAtRest...
26 #include <Geant4/G4String.hh> // for G4String
27 #include <Geant4/G4SystemOfUnits.hh>
28 #include <Geant4/G4ThreeVector.hh> // for G4ThreeVector
29 #include <Geant4/G4TouchableHandle.hh> // for G4TouchableHandle
30 #include <Geant4/G4Track.hh> // for G4Track
31 #include <Geant4/G4TrackStatus.hh> // for fStopAndKill
32 #include <Geant4/G4Types.hh> // for G4double
33 #include <Geant4/G4VPhysicalVolume.hh> // for G4VPhysicalVolume
34 #include <Geant4/G4VTouchable.hh> // for G4VTouchable
35 #include <Geant4/G4VUserTrackInformation.hh> // for G4VUserTrackInformation
36 
37 #include <boost/tokenizer.hpp>
38 // this is an ugly hack, the gcc optimizer has a bug which
39 // triggers the uninitialized variable warning which
40 // stops compilation because of our -Werror
41 #include <boost/version.hpp> // to get BOOST_VERSION
42 #if (__GNUC__ == 4 && __GNUC_MINOR__ == 4 && BOOST_VERSION == 105700)
43 #pragma GCC diagnostic ignored "-Wuninitialized"
44 #pragma message "ignoring bogus gcc warning in boost header lexical_cast.hpp"
45 #include <boost/lexical_cast.hpp>
46 #pragma GCC diagnostic warning "-Wuninitialized"
47 #else
48 #include <boost/lexical_cast.hpp>
49 #endif
50 
51 #include <cstdlib> // for exit
52 #include <iostream>
53 #include <string> // for operator<<, basic_string
54 
55 class PHCompositeNode;
56 
57 //____________________________________________________________________________..
59  : PHG4SteppingAction(detector->GetName())
60  , m_Detector(detector)
61 {
62  PHParametersContainer::ConstRange begin_end = paramscont->GetAllParameters();
63 
64  for (auto iter = begin_end.first; iter != begin_end.second; ++iter)
65  {
66  if (iter->first >= 0)
67  {
68  const PHParameters* params = paramscont->GetParameters(iter->first);
69  if (params->get_int_param("supportactive"))
70  {
72  }
73  if (params->get_int_param("blackhole"))
74  {
75  m_BlackHoleFlag = 1;
76  }
77  }
78  }
79 }
80 
81 //____________________________________________________________________________..
83 {
84  // if the last hit was a zero energie deposit hit, it is just reset
85  // and the memory is still allocated, so we need to delete it here
86  // if the last hit was saved, hit is a nullptr pointer which are
87  // legal to delete (it results in a no operation)
88  delete m_Hit;
89 }
90 
91 //____________________________________________________________________________..
92 bool PHG4MvtxSteppingAction::UserSteppingAction(const G4Step* aStep, bool /*was_used*/)
93 {
94  G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle();
95  // get volume of the current step
96  G4VPhysicalVolume* sensor_volume = touch->GetVolume();
97 
98  // PHG4MvtxDetector->IsInMvtx(volume)
99  // returns
100  // 0 if outside of Mvtx
101  // 1 if inside sensor
102 
103  // This checks if the volume is a sensor (doesn't tell us unique layer)
104  // PHG4MvtxDetector->IsSensor(volume)
105  // returns
106  // 1 if volume is a sensor
107  // -1 if volume is support structure
108  // 0 if not in mvtx
109  int whichactive = m_Detector->IsSensor(sensor_volume);
110 
111  if (!whichactive)
112  {
113  return false;
114  }
115 
116  // This tells us if the volume belongs to the right stave for this layer
117  // From the GDML file the 3rd volume up should be the half-stave
118  // PHG4MvtxTelescopeDetector_->IsInMvtx(volume)
119  // returns
120  // 1 if in ladder belonging to this layer
121  // 0 if not
122  int layer_id = -9999;
123  int stave_id = -9999;
124  // declare active volume variables
125  int half_stave_number = -1;
126  int module_number = -1;
127  int chip_number = -1;
128  if (whichactive < 0)
129  {
130  layer_id = 0;
131  }
132  if (whichactive > 0)
133  {
134  // std::cout << std::endl << " In UserSteppingAction for layer " << layer_id << std::endl;
135  G4VPhysicalVolume* vstave = touch->GetVolume(3);
136  int whichlayer = m_Detector->IsInMvtx(vstave, layer_id, stave_id);
137  if (layer_id < 0 || stave_id < 0)
138  {
139  std::cout << PHWHERE << "invalid Mvtx's layer (" << layer_id << ") or stave (" << stave_id << ") index " << std::endl;
140  exit(1);
141  }
142 
143  if (!whichlayer)
144  {
145  return false;
146  }
147 
148  if (Verbosity() > 5)
149  {
150  // make sure we know where we are!
151  G4VPhysicalVolume* vtest = touch->GetVolume();
152  std::cout << "Entering PHG4MvtxSteppingAction::UserSteppingAction for volume " << vtest->GetName() << std::endl;
153  G4VPhysicalVolume* vtest1 = touch->GetVolume(1);
154  std::cout << "Entering PHG4MvtxSteppingAction::UserSteppingAction for volume 1 up " << vtest1->GetName() << std::endl;
155  G4VPhysicalVolume* vtest2 = touch->GetVolume(2);
156  std::cout << "Entering PHG4MvtxSteppingAction::UserSteppingAction for volume 2 up " << vtest2->GetName() << std::endl;
157  G4VPhysicalVolume* vtest3 = touch->GetVolume(3);
158  std::cout << "Entering PHG4MvtxSteppingAction::UserSteppingAction for volume 3 up " << vtest3->GetName() << std::endl;
159  G4VPhysicalVolume* vtest4 = touch->GetVolume(4);
160  std::cout << "Entering PHG4MvtxSteppingAction::UserSteppingAction for volume 4 up " << vtest4->GetName() << std::endl;
161  }
162 
163  //=======================================================================
164  // We want the location of the hit
165  // Here we will record in the hit object:
166  // The stave, half-stave, module and chip numbers
167  // The energy deposited
168  // The entry point and exit point in world coordinates
169  // The entry point and exit point in local (sensor) coordinates
170  // The pixel number will be derived later from the entry and exit points in the sensor local coordinates
171  //=======================================================================
172 
173  if (Verbosity() > 0)
174  {
175  std::cout << std::endl
176  << " UserSteppingAction: layer " << layer_id;
177  }
178  boost::char_separator<char> sep("_");
179  boost::tokenizer<boost::char_separator<char> >::const_iterator tokeniter;
180 
181  // OLD ITS.gdml: chip number is from "ITSUChip[layer number]_[chip number]
182  // NEW: chip number is from "MVTXChip_[chip number]
183  G4VPhysicalVolume* v1 = touch->GetVolume(1);
184  boost::tokenizer<boost::char_separator<char> > tok1(v1->GetName(), sep);
185  tokeniter = tok1.begin();
186  ++tokeniter;
187  chip_number = boost::lexical_cast<int>(*tokeniter);
188  if (Verbosity() > 0)
189  {
190  std::cout << " chip " << chip_number;
191  }
192  G4VPhysicalVolume* v2 = touch->GetVolume(2);
193  boost::tokenizer<boost::char_separator<char> > tok2(v2->GetName(), sep);
194  tokeniter = tok2.begin();
195  ++tokeniter;
196  module_number = boost::lexical_cast<int>(*tokeniter);
197  if (Verbosity() > 0)
198  {
199  std::cout << " module " << module_number;
200  }
201 
202  // The stave number is the imprint number from the assembly volume imprint
203  // The assembly volume history string format is (e.g.):
204  // av_13_impr_4_ITSUHalfStave6_pv_1
205  // where "impr_4" says stave number 4
206  // and where "ITSUHalfStave6_pv_1" says hald stave number 1 in layer number 6
207 
208  G4VPhysicalVolume* v3 = touch->GetVolume(3);
209  boost::tokenizer<boost::char_separator<char> > tok3(v3->GetName(), sep);
210  tokeniter = tok3.begin();
211  ++tokeniter;
212  ++tokeniter;
213  ++tokeniter;
214  // stave_number = boost::lexical_cast<int>(*tokeniter) - 1; // starts counting imprints at 1, we count staves from 0!
215  if (Verbosity() > 0)
216  {
217  std::cout << " stave " << stave_id;
218  }
219  ++tokeniter;
220  ++tokeniter;
221  ++tokeniter;
222  half_stave_number = boost::lexical_cast<int>(*tokeniter);
223  if (Verbosity() > 0)
224  {
225  std::cout << " half_stave " << half_stave_number;
226  }
227  }
228  // FYI: doing string compares inside a stepping action sounds like a recipe
229  // for failure inside a heavy ion event... we'll wait and see how badly
230  // this profiles. -MPM
231 
232  // Now we want to collect information about the hit
233 
234  G4double edep = aStep->GetTotalEnergyDeposit() / GeV;
235  const G4Track* aTrack = aStep->GetTrack();
236  if (Verbosity() > 0)
237  {
238  std::cout << " edep = " << edep << std::endl;
239  }
240 
241  // if this cylinder stops everything, just put all kinetic energy into edep
242  if (m_Detector->IsBlackHole(layer_id))
243  {
244  edep = aTrack->GetKineticEnergy() / GeV;
245  G4Track* killtrack = const_cast<G4Track*>(aTrack);
246  killtrack->SetTrackStatus(fStopAndKill);
247  }
248 
249  if (whichactive < 0 && !m_SupportActiveFlag)
250  {
251  return false;
252  }
253  // test if we are active
254  if (m_Detector->IsActive(layer_id))
255  {
256  bool geantino = false;
257  // the check for the pdg code speeds things up, I do not want to make
258  // an expensive string compare for every track when we know
259  // geantino or chargedgeantino has pid=0
260  if (aTrack->GetParticleDefinition()->GetPDGEncoding() == 0 &&
261  aTrack->GetParticleDefinition()->GetParticleName().find("geantino") != std::string::npos)
262  {
263  geantino = true;
264  }
265 
266  G4ThreeVector worldPosition; // localPosition;
267  G4TouchableHandle theTouchable;
268 
269  G4StepPoint* prePoint = aStep->GetPreStepPoint();
270  G4StepPoint* postPoint = aStep->GetPostStepPoint();
271 
272  if (Verbosity() > 0)
273  {
274  G4ParticleDefinition* def = aTrack->GetDefinition();
275  std::cout << " Particle: " << def->GetParticleName() << std::endl;
276  }
277 
278  switch (prePoint->GetStepStatus())
279  {
280  case fGeomBoundary:
281  case fUndefined:
282  if (!m_Hit)
283  {
284  m_Hit = new PHG4Hitv1();
285  }
286  m_Hit->set_layer((unsigned int) layer_id);
287  if (whichactive > 0)
288  {
289  // set the index values needed to locate the sensor strip
294 
295  worldPosition = prePoint->GetPosition();
296 
297  if (Verbosity() > 0)
298  {
299  theTouchable = prePoint->GetTouchableHandle();
300  std::cout << "entering: depth = " << theTouchable->GetHistory()->GetDepth() << std::endl;
301  G4VPhysicalVolume* vol1 = theTouchable->GetVolume();
302  std::cout << "entering volume name = " << vol1->GetName() << std::endl;
303  }
304 
305  /*
306  localPosition = theTouchable->GetHistory()->GetTopTransform().TransformPoint(worldPosition);
307  */
308 
309  // Store the local coordinates for the entry point
310  StoreLocalCoordinate(m_Hit, aStep, true, false);
312  }
313  else
314  {
315  std::cout << "adding support hit" << std::endl;
317  }
318  // Store the entrance values in cm in world coordinates
319  m_Hit->set_x(0, prePoint->GetPosition().x() / cm);
320  m_Hit->set_y(0, prePoint->GetPosition().y() / cm);
321  m_Hit->set_z(0, prePoint->GetPosition().z() / cm);
322 
323  m_Hit->set_px(0, prePoint->GetMomentum().x() / GeV);
324  m_Hit->set_py(0, prePoint->GetMomentum().y() / GeV);
325  m_Hit->set_pz(0, prePoint->GetMomentum().z() / GeV);
326 
327  // time in ns
328  m_Hit->set_t(0, prePoint->GetGlobalTime() / nanosecond);
329  // set the track ID
330  m_Hit->set_trkid(aTrack->GetTrackID());
331  if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
332  {
333  if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
334  {
335  m_Hit->set_trkid(pp->GetUserTrackId());
336  m_Hit->set_shower_id(pp->GetShower()->get_id());
337  m_SaveShower = pp->GetShower();
338  }
339  }
340  // set the initial energy deposit
341  m_Hit->set_edep(0);
342 
343  // Now add the hit
344  // m_Hit->print();
345  // m_HitContainer->AddHit(layer_id, m_Hit);
346  break;
347  default:
348  break;
349  }
350 
351  // here we just update the exit values, it will be overwritten
352  // for every step until we leave the volume or the particle
353  // ceases to exist
354 
355  /*
356  // Note that the after you reach the boundary the touchable for the postPoint points to the next volume, not the sensor!
357  // This was given to me as the way to get back to the sensor volume, but it does not work
358  theTouchable = postPoint->GetTouchableHandle();
359  localPosition = history->GetTransform(history->GetDepth() - 1).TransformPoint(worldPosition);
360  std::cout << "Exit local coords: x " << localPosition.x() / cm << " y " << localPosition.y() / cm << " z " << localPosition.z() / cm << std::endl;
361  */
362 
363  /*
364  // Use the prePoint from the final step for now, until I understand how to get the exit point in the sensor volume coordinates
365  //======================================================================================
366  theTouchable = prePoint->GetTouchableHandle();
367  vol2 = theTouchable->GetVolume();
368  if(Verbosity() > 0)
369  std::cout << "exiting volume name = " << vol2->GetName() << std::endl;
370  worldPosition = prePoint->GetPosition();
371  if(Verbosity() > 0)
372  std::cout << "Exit world coords prePoint: x " << worldPosition.x() / cm << " y " << worldPosition.y() / cm << " z " << worldPosition.z() / cm << std::endl;
373 
374  // This is for consistency with the local coord position, the world coordinate exit position is correct
375  m_Hit->set_x( 1, prePoint->GetPosition().x() / cm );
376  m_Hit->set_y( 1, prePoint->GetPosition().y() / cm );
377  m_Hit->set_z( 1, prePoint->GetPosition().z() / cm );
378 
379  const G4NavigationHistory *history = theTouchable->GetHistory();
380  //std::cout << "exiting: depth = " << history->GetDepth() << " volume name = " << history->GetVolume(history->GetDepth())->GetName() << std::endl;
381  localPosition = history->GetTransform(history->GetDepth()).TransformPoint(worldPosition);
382 
383  m_Hit->set_local_x(1, localPosition.x() / cm);
384  m_Hit->set_local_y(1, localPosition.y() / cm);
385  m_Hit->set_local_z(1, localPosition.z() / cm);
386  */
387 
388  if (whichactive > 0)
389  {
390  // Store the local coordinates for the exit point
391  StoreLocalCoordinate(m_Hit, aStep, false, true);
392  }
393 
394  // Store world coordinates for the exit point
395  m_Hit->set_x(1, postPoint->GetPosition().x() / cm);
396  m_Hit->set_y(1, postPoint->GetPosition().y() / cm);
397  m_Hit->set_z(1, postPoint->GetPosition().z() / cm);
398 
399  m_Hit->set_px(1, postPoint->GetMomentum().x() / GeV);
400  m_Hit->set_py(1, postPoint->GetMomentum().y() / GeV);
401  m_Hit->set_pz(1, postPoint->GetMomentum().z() / GeV);
402 
403  m_Hit->set_t(1, postPoint->GetGlobalTime() / nanosecond);
404  // sum up the energy to get total deposited
405  m_Hit->set_edep(m_Hit->get_edep() + edep);
406  if (geantino)
407  {
408  m_Hit->set_edep(-1); // only energy=0 g4hits get dropped, this way geantinos survive the g4hit compression
409  }
410  if (edep > 0)
411  {
412  if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
413  {
414  if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
415  {
416  pp->SetKeep(1); // we want to keep the track
417  }
418  }
419  }
420 
421  if (Verbosity() > 0)
422  {
423  G4StepPoint* prePointA = aStep->GetPreStepPoint();
424  G4StepPoint* postPointA = aStep->GetPostStepPoint();
425  std::cout << "----- PHg4MvtxSteppingAction::UserSteppingAction - active volume = " << sensor_volume->GetName() << std::endl;
426  std::cout << " layer = " << layer_id << std::endl;
427  std::cout << " stave number = " << stave_id << " half_stave_number = " << half_stave_number << std::endl;
428  std::cout << " module number = " << module_number << std::endl;
429  std::cout << " chip number = " << chip_number << std::endl;
430  std::cout << " prepoint x position " << prePointA->GetPosition().x() / cm << std::endl;
431  std::cout << " prepoint y position " << prePointA->GetPosition().y() / cm << std::endl;
432  std::cout << " prepoint z position " << prePointA->GetPosition().z() / cm << std::endl;
433  std::cout << " postpoint x position " << postPointA->GetPosition().x() / cm << std::endl;
434  std::cout << " postpoint y position " << postPointA->GetPosition().y() / cm << std::endl;
435  std::cout << " postpoint z position " << postPointA->GetPosition().z() / cm << std::endl;
436  std::cout << " edep " << edep << std::endl;
437  }
438 
439  if (Verbosity() > 0)
440  {
441  std::cout << " stepping action found hit:" << std::endl;
442  m_Hit->print();
443  std::cout << std::endl
444  << std::endl;
445  }
446 
447  // if any of these conditions is true this is the last step in
448  // this volume and we need to save the hit
449  // postPoint->GetStepStatus() == fGeomBoundary: track leaves this volume
450  // postPoint->GetStepStatus() == fWorldBoundary: track leaves this world
451  // (happens when your detector goes outside world volume)
452  // postPoint->GetStepStatus() == fAtRestDoItProc: track stops (typically
453  // aTrack->GetTrackStatus() == fStopAndKill is also set)
454  // aTrack->GetTrackStatus() == fStopAndKill: track ends
455  if (postPoint->GetStepStatus() == fGeomBoundary ||
456  postPoint->GetStepStatus() == fWorldBoundary ||
457  postPoint->GetStepStatus() == fAtRestDoItProc ||
458  aTrack->GetTrackStatus() == fStopAndKill)
459  {
460  // save only hits with energy deposit (or -1 for geantino)
461  if (m_Hit->get_edep())
462  {
463  m_SaveHitContainer->AddHit(layer_id, m_Hit);
464  if (m_SaveShower)
465  {
467  }
468  // ownership has been transferred to container, set to null
469  // so we will create a new hit for the next track
470  m_Hit = nullptr;
471  }
472  else
473  {
474  // if this hit has no energy deposit, just reset it for reuse
475  // this means we have to delete it in the dtor. If this was
476  // the last hit we processed the memory is still allocated
477  m_Hit->Reset();
478  }
479  }
480 
481  // return true to indicate the hit was used
482  return true;
483  }
484  else
485  {
486  return false;
487  }
488 
489  return false;
490 }
491 
492 //____________________________________________________________________________..
494 {
495  m_HitContainer = findNode::getClass<PHG4HitContainer>(topNode, m_HitNodeName);
496  m_SupportHitContainer = findNode::getClass<PHG4HitContainer>(topNode, m_SupportNodeName);
497 
498  // if we do not find the node it's messed up.
499  if (!m_HitContainer)
500  {
501  if (!m_BlackHoleFlag) // not messed up if we have a black hole
502  {
503  std::cout << "PHG4MvtxSteppingAction::SetTopNode - unable to find " << m_HitNodeName << std::endl;
504  gSystem->Exit(1);
505  }
506  }
507  if (!m_SupportHitContainer)
508  {
509  if (Verbosity() > 0)
510  {
511  std::cout << "PHG4MvtxSteppingAction::SetTopNode - unable to find " << m_SupportNodeName << std::endl;
512  }
513  }
514 }
515 
517 {
518  if (type == "G4HIT")
519  {
521  return;
522  }
523  else if (type == "G4HIT_SUPPORT")
524  {
526  return;
527  }
528  std::cout << "Invalid output hit node type " << type << std::endl;
529  gSystem->Exit(1);
530  return;
531 }