Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-12-17 09:22:07

0001 #include "PHG4EICMvtxSteppingAction.h"
0002 
0003 #include "PHG4EICMvtxDetector.h"
0004 
0005 #include <g4main/PHG4Hit.h>
0006 #include <g4main/PHG4HitContainer.h>
0007 #include <g4main/PHG4Hitv1.h>
0008 #include <g4main/PHG4Shower.h>
0009 #include <g4main/PHG4SteppingAction.h>  // for PHG4SteppingAction
0010 #include <g4main/PHG4TrackUserInfoV1.h>
0011 
0012 #include <phool/getClass.h>
0013 #include <phool/phool.h>  // for PHWHERE
0014 
0015 #include <Geant4/G4NavigationHistory.hh>
0016 #include <Geant4/G4ParticleDefinition.hh>      // for G4ParticleDefinition
0017 #include <Geant4/G4ReferenceCountedHandle.hh>  // for G4ReferenceCountedHandle
0018 #include <Geant4/G4Step.hh>
0019 #include <Geant4/G4StepPoint.hh>   // for G4StepPoint
0020 #include <Geant4/G4StepStatus.hh>  // for fGeomBoundary, fAtRest...
0021 #include <Geant4/G4String.hh>      // for G4String
0022 #include <Geant4/G4SystemOfUnits.hh>
0023 #include <Geant4/G4ThreeVector.hh>            // for G4ThreeVector
0024 #include <Geant4/G4TouchableHandle.hh>        // for G4TouchableHandle
0025 #include <Geant4/G4Track.hh>                  // for G4Track
0026 #include <Geant4/G4TrackStatus.hh>            // for fStopAndKill
0027 #include <Geant4/G4Types.hh>                  // for G4double
0028 #include <Geant4/G4VPhysicalVolume.hh>        // for G4VPhysicalVolume
0029 #include <Geant4/G4VTouchable.hh>             // for G4VTouchable
0030 #include <Geant4/G4VUserTrackInformation.hh>  // for G4VUserTrackInformation
0031 
0032 #include <boost/tokenizer.hpp>
0033 // this is an ugly hack, the gcc optimizer has a bug which
0034 // triggers the uninitialized variable warning which
0035 // stops compilation because of our -Werror
0036 #include <boost/version.hpp>  // to get BOOST_VERSION
0037 #if (__GNUC__ == 4 && __GNUC_MINOR__ == 4 && BOOST_VERSION == 105700)
0038 #pragma GCC diagnostic ignored "-Wuninitialized"
0039 #pragma message "ignoring bogus gcc warning in boost header lexical_cast.hpp"
0040 #include <boost/lexical_cast.hpp>
0041 #pragma GCC diagnostic warning "-Wuninitialized"
0042 #else
0043 #include <boost/lexical_cast.hpp>
0044 #endif
0045 
0046 #include <cstdlib>  // for exit
0047 #include <iostream>
0048 #include <string>  // for operator<<, basic_string
0049 
0050 class PHCompositeNode;
0051 
0052 //____________________________________________________________________________..
0053 PHG4EICMvtxSteppingAction::PHG4EICMvtxSteppingAction(PHG4EICMvtxDetector* detector)
0054   : PHG4SteppingAction(detector->GetName())
0055   , m_Detector(detector)
0056   , m_HitContainer(nullptr)
0057   , m_AbsorberhitContainer(nullptr)
0058   , m_Hit(nullptr)
0059   , m_SaveShower(nullptr)
0060 {
0061 }
0062 
0063 //____________________________________________________________________________..
0064 PHG4EICMvtxSteppingAction::~PHG4EICMvtxSteppingAction()
0065 {
0066   // if the last hit was a zero energie deposit hit, it is just reset
0067   // and the memory is still allocated, so we need to delete it here
0068   // if the last hit was saved, hit is a nullptr pointer which are
0069   // legal to delete (it results in a no operation)
0070   delete m_Hit;
0071 }
0072 
0073 //____________________________________________________________________________..
0074 bool PHG4EICMvtxSteppingAction::UserSteppingAction(const G4Step* aStep, bool /*was_used*/)
0075 {
0076   G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle();
0077   // get volume of the current step
0078   G4VPhysicalVolume* sensor_volume = touch->GetVolume();
0079 
0080   // PHG4MvtxDetector->IsInMvtx(volume)
0081   // returns
0082   //  0 if outside of Mvtx
0083   //  1 if inside sensor
0084 
0085   // This checks if the volume is a sensor (doesn't tell us unique layer)
0086   // PHG4MvtxDetector->IsSensor(volume)
0087   // returns
0088   //  1 if volume is a sensor
0089   //  0 if not
0090   int whichactive = m_Detector->IsSensor(sensor_volume);
0091 
0092   if (!whichactive)
0093   {
0094     return false;
0095   }
0096 
0097   // This tells us if the volume belongs to the right stave for this layer
0098   // From the GDML file the 3rd volume up should be the half-stave
0099   // PHG4MvtxTelescopeDetector_->IsInMvtx(volume)
0100   // returns
0101   //  1 if in ladder belonging to this layer
0102   //  0 if not
0103   int layer_id = -9999;
0104   int stave_id = -9999;
0105   // std::cout << std::endl << "  In UserSteppingAction for layer " << layer_id << std::endl;
0106   G4VPhysicalVolume* vstave = touch->GetVolume(3);
0107   whichactive = m_Detector->IsInMvtx(vstave, layer_id, stave_id);
0108   if (layer_id < 0 || stave_id < 0)
0109   {
0110     std::cout << PHWHERE << "invalid Mvtx's layer (" << layer_id << ") or stave (" << stave_id << ") index " << std::endl;
0111     exit(1);
0112   }
0113 
0114   if (!whichactive)
0115   {
0116     return false;
0117   }
0118 
0119   if (Verbosity() > 5)
0120   {
0121     // make sure we know where we are!
0122     G4VPhysicalVolume* vtest = touch->GetVolume();
0123     std::cout << "Entering PHG4MvtxSteppingAction::UserSteppingAction for volume " << vtest->GetName() << std::endl;
0124     G4VPhysicalVolume* vtest1 = touch->GetVolume(1);
0125     std::cout << "Entering PHG4MvtxSteppingAction::UserSteppingAction for volume 1 up " << vtest1->GetName() << std::endl;
0126     G4VPhysicalVolume* vtest2 = touch->GetVolume(2);
0127     std::cout << "Entering PHG4MvtxSteppingAction::UserSteppingAction for volume 2 up " << vtest2->GetName() << std::endl;
0128     G4VPhysicalVolume* vtest3 = touch->GetVolume(3);
0129     std::cout << "Entering PHG4MvtxSteppingAction::UserSteppingAction for volume 3 up " << vtest3->GetName() << std::endl;
0130     G4VPhysicalVolume* vtest4 = touch->GetVolume(4);
0131     std::cout << "Entering PHG4MvtxSteppingAction::UserSteppingAction for volume 4 up " << vtest4->GetName() << std::endl;
0132   }
0133 
0134   //=======================================================================
0135   // We want the location of the hit
0136   // Here we will record in the hit object:
0137   //   The stave, half-stave, module and chip numbers
0138   //   The energy deposited
0139   //   The entry point and exit point in world coordinates
0140   //   The entry point and exit point in local (sensor) coordinates
0141   // The pixel number will be derived later from the entry and exit points in the sensor local coordinates
0142   //=======================================================================
0143 
0144   // int stave_number = -1; // stave_number from stave map values
0145   int half_stave_number = -1;
0146   int module_number = -1;
0147   int chip_number = -1;
0148 
0149   if (Verbosity() > 0)
0150   {
0151     std::cout << std::endl
0152               << "  UserSteppingAction: layer " << layer_id;
0153   }
0154   boost::char_separator<char> sep("_");
0155   boost::tokenizer<boost::char_separator<char> >::const_iterator tokeniter;
0156 
0157   // OLD ITS.gdml: chip number is from  "ITSUChip[layer number]_[chip number]
0158   // NEW: chip number is from  "MVTXChip_[chip number]
0159   G4VPhysicalVolume* v1 = touch->GetVolume(1);
0160   boost::tokenizer<boost::char_separator<char> > tok1(v1->GetName(), sep);
0161   tokeniter = tok1.begin();
0162   ++tokeniter;
0163   chip_number = boost::lexical_cast<int>(*tokeniter);
0164   if (Verbosity() > 0)
0165   {
0166     std::cout << " chip  " << chip_number;
0167   }
0168   G4VPhysicalVolume* v2 = touch->GetVolume(2);
0169   boost::tokenizer<boost::char_separator<char> > tok2(v2->GetName(), sep);
0170   tokeniter = tok2.begin();
0171   ++tokeniter;
0172   module_number = boost::lexical_cast<int>(*tokeniter);
0173   if (Verbosity() > 0)
0174   {
0175     std::cout << " module " << module_number;
0176   }
0177 
0178   // The stave number  is the imprint number from the assembly volume imprint
0179   // The assembly volume history string format is (e.g.):
0180   // av_13_impr_4_ITSUHalfStave6_pv_1
0181   // where "impr_4" says stave number 4
0182   // and where "ITSUHalfStave6_pv_1" says hald stave number 1 in layer number 6
0183 
0184   G4VPhysicalVolume* v3 = touch->GetVolume(3);
0185   boost::tokenizer<boost::char_separator<char> > tok3(v3->GetName(), sep);
0186   tokeniter = tok3.begin();
0187   ++tokeniter;
0188   ++tokeniter;
0189   ++tokeniter;
0190   // stave_number = boost::lexical_cast<int>(*tokeniter) - 1;  // starts counting imprints at 1, we count staves from 0!
0191   if (Verbosity() > 0)
0192   {
0193     std::cout << " stave " << stave_id;
0194   }
0195   ++tokeniter;
0196   ++tokeniter;
0197   ++tokeniter;
0198   half_stave_number = boost::lexical_cast<int>(*tokeniter);
0199   if (Verbosity() > 0)
0200   {
0201     std::cout << " half_stave " << half_stave_number;
0202   }
0203 
0204   // FYI: doing string compares inside a stepping action sounds like a recipe
0205   // for failure inside a heavy ion event... we'll wait and see how badly
0206   // this profiles. -MPM
0207 
0208   // Now we want to collect information about the hit
0209 
0210   G4double edep = aStep->GetTotalEnergyDeposit() / GeV;
0211   const G4Track* aTrack = aStep->GetTrack();
0212   if (Verbosity() > 0)
0213   {
0214     std::cout << " edep = " << edep << std::endl;
0215   }
0216 
0217   // if this cylinder stops everything, just put all kinetic energy into edep
0218   if (m_Detector->IsBlackHole(layer_id))
0219   {
0220     edep = aTrack->GetKineticEnergy() / GeV;
0221     G4Track* killtrack = const_cast<G4Track*>(aTrack);
0222     killtrack->SetTrackStatus(fStopAndKill);
0223   }
0224 
0225   // test if we are active
0226   if (m_Detector->IsActive(layer_id))
0227   {
0228     bool geantino = false;
0229     // the check for the pdg code speeds things up, I do not want to make
0230     // an expensive string compare for every track when we know
0231     // geantino or chargedgeantino has pid=0
0232     if (aTrack->GetParticleDefinition()->GetPDGEncoding() == 0 &&
0233         aTrack->GetParticleDefinition()->GetParticleName().find("geantino") != std::string::npos)
0234     {
0235       geantino = true;
0236     }
0237 
0238     G4ThreeVector worldPosition;  // localPosition;
0239     G4TouchableHandle theTouchable;
0240 
0241     G4StepPoint* prePoint = aStep->GetPreStepPoint();
0242     G4StepPoint* postPoint = aStep->GetPostStepPoint();
0243 
0244     if (Verbosity() > 0)
0245     {
0246       G4ParticleDefinition* def = aTrack->GetDefinition();
0247       std::cout << " Particle: " << def->GetParticleName() << std::endl;
0248     }
0249 
0250     switch (prePoint->GetStepStatus())
0251     {
0252     case fGeomBoundary:
0253     case fUndefined:
0254       if (!m_Hit)
0255       {
0256         m_Hit = new PHG4Hitv1();
0257       }
0258       m_Hit->set_layer((unsigned int) layer_id);
0259 
0260       // set the index values needed to locate the sensor strip
0261       m_Hit->set_property(PHG4Hit::prop_stave_index, stave_id);
0262       m_Hit->set_property(PHG4Hit::prop_half_stave_index, half_stave_number);
0263       m_Hit->set_property(PHG4Hit::prop_module_index, module_number);
0264       m_Hit->set_property(PHG4Hit::prop_chip_index, chip_number);
0265 
0266       worldPosition = prePoint->GetPosition();
0267 
0268       if (Verbosity() > 0)
0269       {
0270         theTouchable = prePoint->GetTouchableHandle();
0271         std::cout << "entering: depth = " << theTouchable->GetHistory()->GetDepth() << std::endl;
0272         G4VPhysicalVolume* vol1 = theTouchable->GetVolume();
0273         std::cout << "entering volume name = " << vol1->GetName() << std::endl;
0274       }
0275 
0276       /*
0277           localPosition = theTouchable->GetHistory()->GetTopTransform().TransformPoint(worldPosition);
0278           */
0279 
0280       // Store the local coordinates for the entry point
0281       StoreLocalCoordinate(m_Hit, aStep, true, false);
0282 
0283       // Store the entrance values in cm in world coordinates
0284       m_Hit->set_x(0, prePoint->GetPosition().x() / cm);
0285       m_Hit->set_y(0, prePoint->GetPosition().y() / cm);
0286       m_Hit->set_z(0, prePoint->GetPosition().z() / cm);
0287 
0288       m_Hit->set_px(0, prePoint->GetMomentum().x() / GeV);
0289       m_Hit->set_py(0, prePoint->GetMomentum().y() / GeV);
0290       m_Hit->set_pz(0, prePoint->GetMomentum().z() / GeV);
0291 
0292       // time in ns
0293       m_Hit->set_t(0, prePoint->GetGlobalTime() / nanosecond);
0294       // set the track ID
0295       m_Hit->set_trkid(aTrack->GetTrackID());
0296       if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
0297       {
0298         if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
0299         {
0300           m_Hit->set_trkid(pp->GetUserTrackId());
0301           m_Hit->set_shower_id(pp->GetShower()->get_id());
0302           m_SaveShower = pp->GetShower();
0303         }
0304       }
0305       // set the initial energy deposit
0306       m_Hit->set_edep(0);
0307 
0308       // Now add the hit
0309       //      m_Hit->print();
0310       // m_HitContainer->AddHit(layer_id, m_Hit);
0311       break;
0312     default:
0313       break;
0314     }
0315 
0316     // here we just update the exit values, it will be overwritten
0317     // for every step until we leave the volume or the particle
0318     // ceases to exist
0319 
0320     /*
0321       // Note that the after you reach the boundary the touchable for the postPoint points to the next volume, not the sensor!
0322       // This was given to me as the way to get back to the sensor volume, but it does not work
0323       theTouchable = postPoint->GetTouchableHandle();
0324       localPosition = history->GetTransform(history->GetDepth() - 1).TransformPoint(worldPosition);
0325       std::cout << "Exit local coords: x " <<  localPosition.x() / cm << " y " <<  localPosition.y() / cm << " z " <<  localPosition.z() / cm << std::endl;
0326       */
0327 
0328     /*
0329       // Use the prePoint from the final step  for now, until I understand how to get the exit point in the sensor volume coordinates
0330       //======================================================================================
0331       theTouchable = prePoint->GetTouchableHandle();
0332       vol2 = theTouchable->GetVolume();
0333       if(Verbosity() > 0)
0334         std::cout << "exiting volume name = " << vol2->GetName() << std::endl;
0335       worldPosition = prePoint->GetPosition();
0336       if(Verbosity() > 0)
0337         std::cout << "Exit world coords prePoint: x " <<  worldPosition.x() / cm << " y " <<  worldPosition.y() / cm << " z " <<  worldPosition.z() / cm << std::endl;
0338 
0339       // This is for consistency with the local coord position, the world coordinate exit position is correct
0340       m_Hit->set_x( 1, prePoint->GetPosition().x() / cm );
0341       m_Hit->set_y( 1, prePoint->GetPosition().y() / cm );
0342       m_Hit->set_z( 1, prePoint->GetPosition().z() / cm );
0343 
0344       const G4NavigationHistory *history = theTouchable->GetHistory();
0345       //std::cout << "exiting: depth = " << history->GetDepth() <<  " volume name = " << history->GetVolume(history->GetDepth())->GetName() << std::endl;
0346       localPosition = history->GetTransform(history->GetDepth()).TransformPoint(worldPosition);
0347 
0348       m_Hit->set_local_x(1, localPosition.x() / cm);
0349       m_Hit->set_local_y(1, localPosition.y() / cm);
0350       m_Hit->set_local_z(1, localPosition.z() / cm);
0351       */
0352 
0353     // Store the local coordinates for the exit point
0354     StoreLocalCoordinate(m_Hit, aStep, false, true);
0355 
0356     // Store world coordinates for the exit point
0357     m_Hit->set_x(1, postPoint->GetPosition().x() / cm);
0358     m_Hit->set_y(1, postPoint->GetPosition().y() / cm);
0359     m_Hit->set_z(1, postPoint->GetPosition().z() / cm);
0360 
0361     m_Hit->set_px(1, postPoint->GetMomentum().x() / GeV);
0362     m_Hit->set_py(1, postPoint->GetMomentum().y() / GeV);
0363     m_Hit->set_pz(1, postPoint->GetMomentum().z() / GeV);
0364 
0365     m_Hit->set_t(1, postPoint->GetGlobalTime() / nanosecond);
0366     // sum up the energy to get total deposited
0367     m_Hit->set_edep(m_Hit->get_edep() + edep);
0368     if (geantino)
0369     {
0370       m_Hit->set_edep(-1);  // only energy=0 g4hits get dropped, this way geantinos survive the g4hit compression
0371     }
0372     if (edep > 0)
0373     {
0374       if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
0375       {
0376         if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
0377         {
0378           pp->SetKeep(1);  // we want to keep the track
0379         }
0380       }
0381     }
0382 
0383     if (Verbosity() > 0)
0384     {
0385       G4StepPoint* prePointA = aStep->GetPreStepPoint();
0386       G4StepPoint* postPointA = aStep->GetPostStepPoint();
0387       std::cout << "----- PHg4MvtxSteppingAction::UserSteppingAction - active volume = " << sensor_volume->GetName() << std::endl;
0388       std::cout << "       layer = " << layer_id << std::endl;
0389       std::cout << "       stave number = " << stave_id << " half_stave_number = " << half_stave_number << std::endl;
0390       std::cout << "       module number  = " << module_number << std::endl;
0391       std::cout << "       chip number = " << chip_number << std::endl;
0392       std::cout << "       prepoint x position " << prePointA->GetPosition().x() / cm << std::endl;
0393       std::cout << "       prepoint y position " << prePointA->GetPosition().y() / cm << std::endl;
0394       std::cout << "       prepoint z position " << prePointA->GetPosition().z() / cm << std::endl;
0395       std::cout << "       postpoint x position " << postPointA->GetPosition().x() / cm << std::endl;
0396       std::cout << "       postpoint y position " << postPointA->GetPosition().y() / cm << std::endl;
0397       std::cout << "       postpoint z position " << postPointA->GetPosition().z() / cm << std::endl;
0398       std::cout << "       edep " << edep << std::endl;
0399     }
0400 
0401     if (Verbosity() > 0)
0402     {
0403       std::cout << "  stepping action found hit:" << std::endl;
0404       m_Hit->print();
0405       std::cout << std::endl
0406                 << std::endl;
0407     }
0408 
0409     // if any of these conditions is true this is the last step in
0410     // this volume and we need to save the hit
0411     // postPoint->GetStepStatus() == fGeomBoundary: track leaves this volume
0412     // postPoint->GetStepStatus() == fWorldBoundary: track leaves this world
0413     // (happens when your detector goes outside world volume)
0414     // postPoint->GetStepStatus() == fAtRestDoItProc: track stops (typically
0415     // aTrack->GetTrackStatus() == fStopAndKill is also set)
0416     // aTrack->GetTrackStatus() == fStopAndKill: track ends
0417     if (postPoint->GetStepStatus() == fGeomBoundary ||
0418         postPoint->GetStepStatus() == fWorldBoundary ||
0419         postPoint->GetStepStatus() == fAtRestDoItProc ||
0420         aTrack->GetTrackStatus() == fStopAndKill)
0421     {
0422       // save only hits with energy deposit (or -1 for geantino)
0423       if (m_Hit->get_edep())
0424       {
0425         m_HitContainer->AddHit(layer_id, m_Hit);
0426         if (m_SaveShower)
0427         {
0428           m_SaveShower->add_g4hit_id(m_HitContainer->GetID(), m_Hit->get_hit_id());
0429         }
0430         // ownership has been transferred to container, set to null
0431         // so we will create a new hit for the next track
0432         m_Hit = nullptr;
0433       }
0434       else
0435       {
0436         // if this hit has no energy deposit, just reset it for reuse
0437         // this means we have to delete it in the dtor. If this was
0438         // the last hit we processed the memory is still allocated
0439         m_Hit->Reset();
0440       }
0441     }
0442 
0443     // return true to indicate the hit was used
0444     return true;
0445   }
0446 
0447   return false;
0448 
0449   return false;
0450 }
0451 
0452 //____________________________________________________________________________..
0453 void PHG4EICMvtxSteppingAction::SetInterfacePointers(PHCompositeNode* topNode)
0454 {
0455   std::string hitnodename;
0456   std::string absorbernodename;
0457   if (m_Detector->SuperDetector() != "NONE")
0458   {
0459     hitnodename = "G4HIT_" + m_Detector->SuperDetector();
0460     absorbernodename = "G4HIT_ABSORBER_" + m_Detector->SuperDetector();
0461   }
0462   else
0463   {
0464     hitnodename = "G4HIT_" + m_Detector->GetName();
0465     absorbernodename = "G4HIT_ABSORBER_" + m_Detector->GetName();
0466   }
0467 
0468   // now look for the map and grab a pointer to it.
0469   m_HitContainer = findNode::getClass<PHG4HitContainer>(topNode, hitnodename);
0470   m_AbsorberhitContainer = findNode::getClass<PHG4HitContainer>(topNode, absorbernodename);
0471 
0472   // if we do not find the node it's messed up.
0473   if (!m_HitContainer)
0474   {
0475     std::cout << "PHG4MvtxSteppingAction::SetTopNode - unable to find " << hitnodename << std::endl;
0476   }
0477   if (!m_AbsorberhitContainer)
0478   {
0479     if (Verbosity() > 0)
0480     {
0481       std::cout << "PHG4MvtxSteppingAction::SetTopNode - unable to find " << absorbernodename << std::endl;
0482     }
0483   }
0484 }