Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:18:14

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