Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:20:44

0001 #include "PHG4Prototype2InnerHcalSteppingAction.h"
0002 
0003 #include "PHG4Prototype2InnerHcalDetector.h"
0004 
0005 #include <phparameter/PHParameters.h>
0006 
0007 #include <g4main/PHG4Hit.h>
0008 #include <g4main/PHG4HitContainer.h>
0009 #include <g4main/PHG4Hitv1.h>
0010 #include <g4main/PHG4Shower.h>
0011 #include <g4main/PHG4SteppingAction.h>         // for PHG4SteppingAction
0012 #include <g4main/PHG4TrackUserInfoV1.h>
0013 
0014 #include <phool/getClass.h>
0015 
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 <cmath>                               // for isfinite, sqrt
0033 #include <iostream>
0034 #include <string>                              // for string, operator+, ope...
0035 
0036 class PHCompositeNode;
0037 
0038 //#define TESTSINGLESLAT
0039 #ifdef TESTSINGLESLAT
0040 static const int nrow = 4;
0041 static const int nslat = 9;
0042 #endif
0043 
0044 using namespace std;
0045 //____________________________________________________________________________..
0046 PHG4Prototype2InnerHcalSteppingAction::PHG4Prototype2InnerHcalSteppingAction(PHG4Prototype2InnerHcalDetector* detector, const PHParameters* parameters)
0047   : PHG4SteppingAction(detector->GetName())
0048   , m_Detector(detector)
0049   , m_HitContainer(nullptr)
0050   , m_AbsorberHitContainer(nullptr)
0051   , m_Hit(nullptr)
0052   , m_Params(parameters)
0053   , m_SaveHitContainer(nullptr)
0054   , m_SaveShower(nullptr)
0055   , m_AbsorberTruthFlag(m_Params->get_int_param("absorbertruth"))
0056   , m_IsActiveFlag(m_Params->get_int_param("active"))
0057   , m_IsBlackHoleFlag(m_Params->get_int_param("blackhole"))
0058   , m_LightScintModelFlag(m_Params->get_int_param("light_scint_model"))
0059   , m_LightBalanceInnerCorr(m_Params->get_double_param("light_balance_inner_corr"))
0060   , m_LightBalanceInnerRadius(m_Params->get_double_param("light_balance_inner_radius") * cm)
0061   , m_LightBalanceOuterCorr(m_Params->get_double_param("light_balance_outer_corr"))
0062   , m_LightBalanceOuterRadius(m_Params->get_double_param("light_balance_outer_radius") * cm)
0063 {
0064 }
0065 
0066 PHG4Prototype2InnerHcalSteppingAction::~PHG4Prototype2InnerHcalSteppingAction()
0067 {
0068   // if the last hit was a zero energie deposit hit, it is just reset
0069   // and the memory is still allocated, so we need to delete it here
0070   // if the last hit was saved, hit is a nullptr pointer which are
0071   // legal to delete (it results in a no operation)
0072   delete m_Hit;
0073 }
0074 
0075 //____________________________________________________________________________..
0076 bool PHG4Prototype2InnerHcalSteppingAction::UserSteppingAction(const G4Step* aStep, bool)
0077 {
0078   G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle();
0079   // get volume of the current step
0080   G4VPhysicalVolume* volume = touch->GetVolume();
0081 
0082   // m_Detector->IsInPrototype2InnerHcal(volume)
0083   // returns
0084   //  0 is outside of Prototype2InnerHcal
0085   //  1 is inside scintillator
0086   // -1 is steel absorber
0087 
0088   int whichactive = m_Detector->IsInPrototype2InnerHcal(volume);
0089 
0090   if (!whichactive)
0091   {
0092     return false;
0093   }
0094   int row_id = -1;
0095   int slat_id = -1;
0096   if (whichactive > 0)  // scintillator
0097   {
0098     slat_id = volume->GetCopyNo();
0099     // the row id comes from saved info in the detector construction
0100     G4VPhysicalVolume* mothervolume = touch->GetVolume(1);
0101     row_id = m_Detector->get_scinti_row_id(mothervolume->GetName());
0102     // cout << "mother volume: " <<  mothervolume->GetName()
0103     //       << ", volume name " << volume->GetName() << ", row: " << row_id
0104     //   << ", column: " << slat_id << endl;
0105 #ifdef TESTSINGLESLAT
0106     if (row_id != nrow)
0107     {
0108       return false;
0109     }
0110     if (slat_id != nslat)
0111     {
0112       return false;
0113     }
0114 #endif
0115   }
0116   else
0117   {
0118     // the row id comes from saved info in the detector construction
0119     row_id = m_Detector->get_steel_plate_id(volume->GetName());
0120 #ifdef TESTSINGLESLAT
0121     return false;
0122 #endif
0123   }
0124   // collect energy and track length step by step
0125   G4double edep = aStep->GetTotalEnergyDeposit() / GeV;
0126   G4double eion = (aStep->GetTotalEnergyDeposit() - aStep->GetNonIonizingEnergyDeposit()) / GeV;
0127   G4double light_yield = 0;
0128   const G4Track* aTrack = aStep->GetTrack();
0129 
0130   // if this block stops everything, just put all kinetic energy into edep
0131   if (m_IsBlackHoleFlag)
0132   {
0133     edep = aTrack->GetKineticEnergy() / GeV;
0134     G4Track* killtrack = const_cast<G4Track*>(aTrack);
0135     killtrack->SetTrackStatus(fStopAndKill);
0136   }
0137   int layer_id = m_Detector->get_Layer();
0138   // make sure we are in a volume
0139   if (m_IsActiveFlag)
0140   {
0141     bool geantino = false;
0142 
0143     // the check for the pdg code speeds things up, I do not want to make
0144     // an expensive string compare for every track when we know
0145     // geantino or chargedgeantino has pid=0
0146     if (aTrack->GetParticleDefinition()->GetPDGEncoding() == 0 &&
0147         aTrack->GetParticleDefinition()->GetParticleName().find("geantino") != string::npos)
0148     {
0149       geantino = true;
0150     }
0151     G4StepPoint* prePoint = aStep->GetPreStepPoint();
0152     G4StepPoint* postPoint = aStep->GetPostStepPoint();
0153     //       cout << "track id " << aTrack->GetTrackID() << endl;
0154     //       cout << "time prepoint: " << prePoint->GetGlobalTime() << endl;
0155     //       cout << "time postpoint: " << postPoint->GetGlobalTime() << endl;
0156     switch (prePoint->GetStepStatus())
0157     {
0158     case fGeomBoundary:
0159     case fUndefined:
0160       if (!m_Hit)
0161       {
0162         m_Hit = new PHG4Hitv1();
0163       }
0164       m_Hit->set_row(row_id);
0165       if (whichactive > 0)  // only for scintillators
0166       {
0167         m_Hit->set_scint_id(slat_id);  // the slat id in the mother volume (or steel plate id), the column
0168       }
0169       //here we set the entrance values in cm
0170       m_Hit->set_x(0, prePoint->GetPosition().x() / cm);
0171       m_Hit->set_y(0, prePoint->GetPosition().y() / cm);
0172       m_Hit->set_z(0, prePoint->GetPosition().z() / cm);
0173       // time in ns
0174       m_Hit->set_t(0, prePoint->GetGlobalTime() / nanosecond);
0175       //set the track ID
0176       m_Hit->set_trkid(aTrack->GetTrackID());
0177       if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
0178       {
0179         if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
0180         {
0181           m_Hit->set_trkid(pp->GetUserTrackId());
0182           m_Hit->set_shower_id(pp->GetShower()->get_id());
0183         }
0184       }
0185 
0186       //set the initial energy deposit
0187       m_Hit->set_edep(0);
0188 
0189       m_Hit->set_hit_type(0);
0190       if ((aTrack->GetParticleDefinition()->GetParticleName().find("e+") != string::npos) ||
0191           (aTrack->GetParticleDefinition()->GetParticleName().find("e-") != string::npos))
0192         m_Hit->set_hit_type(1);
0193 
0194       if (whichactive > 0)  // return of IsInPrototype2InnerHcalDetector, > 0 hit in scintillator, < 0 hit in absorber
0195       {
0196         m_SaveHitContainer = m_HitContainer;
0197         m_Hit->set_light_yield(0);  // for scintillator only, initialize light yields
0198         m_Hit->set_eion(0);
0199       }
0200       else
0201       {
0202         m_SaveHitContainer = m_AbsorberHitContainer;
0203       }
0204 
0205       if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
0206       {
0207         if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
0208         {
0209           m_Hit->set_trkid(pp->GetUserTrackId());
0210           m_Hit->set_shower_id(pp->GetShower()->get_id());
0211           m_SaveShower = pp->GetShower();
0212         }
0213       }
0214       break;
0215     default:
0216       break;
0217     }
0218     // here we just update the exit values, it will be overwritten
0219     // for every step until we leave the volume or the particle
0220     // ceases to exist
0221     m_Hit->set_x(1, postPoint->GetPosition().x() / cm);
0222     m_Hit->set_y(1, postPoint->GetPosition().y() / cm);
0223     m_Hit->set_z(1, postPoint->GetPosition().z() / cm);
0224 
0225     m_Hit->set_t(1, postPoint->GetGlobalTime() / nanosecond);
0226 
0227     if (whichactive > 0)  // return of IsInPrototype2InnerHcalDetector, > 0 hit in scintillator, < 0 hit in absorber
0228     {
0229       m_Hit->set_eion(m_Hit->get_eion() + eion);
0230       light_yield = eion;
0231       if (m_LightScintModelFlag)
0232       {
0233         light_yield = GetVisibleEnergyDeposition(aStep);  // for scintillator only, calculate light yields
0234       }
0235       if (isfinite(m_LightBalanceOuterRadius) &&
0236           isfinite(m_LightBalanceInnerRadius) &&
0237           isfinite(m_LightBalanceOuterCorr) &&
0238           isfinite(m_LightBalanceInnerCorr))
0239       {
0240         double r = sqrt(postPoint->GetPosition().x() * postPoint->GetPosition().x() + postPoint->GetPosition().y() * postPoint->GetPosition().y());
0241         double cor = GetLightCorrection(r);
0242         light_yield = light_yield * cor;
0243       }
0244       m_Hit->set_light_yield(m_Hit->get_light_yield() + light_yield);
0245     }
0246 
0247     //sum up the energy to get total deposited
0248     m_Hit->set_edep(m_Hit->get_edep() + edep);
0249     if (geantino)
0250     {
0251       m_Hit->set_edep(-1);  // only energy=0 g4hits get dropped, this way geantinos survive the g4hit compression
0252       if (whichactive > 0)  // add light yield for scintillators
0253       {
0254         m_Hit->set_light_yield(-1);
0255         m_Hit->set_eion(-1);
0256       }
0257     }
0258     if (edep > 0 && (whichactive > 0 || m_AbsorberTruthFlag > 0))
0259     {
0260       if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
0261       {
0262         if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
0263         {
0264           pp->SetKeep(1);  // we want to keep the track
0265         }
0266       }
0267     }
0268     // if any of these conditions is true this is the last step in
0269     // this volume and we need to save the hit
0270     // postPoint->GetStepStatus() == fGeomBoundary: track leaves this volume
0271     // postPoint->GetStepStatus() == fWorldBoundary: track leaves this world
0272     // (happens when your detector goes outside world volume)
0273     // postPoint->GetStepStatus() == fAtRestDoItProc: track stops (typically
0274     // aTrack->GetTrackStatus() == fStopAndKill is also set)
0275     // aTrack->GetTrackStatus() == fStopAndKill: track ends
0276     if (postPoint->GetStepStatus() == fGeomBoundary ||
0277         postPoint->GetStepStatus() == fWorldBoundary ||
0278         postPoint->GetStepStatus() == fAtRestDoItProc ||
0279         aTrack->GetTrackStatus() == fStopAndKill)
0280     {
0281       // save only hits with energy deposit (or -1 for geantino)
0282       if (m_Hit->get_edep())
0283       {
0284         m_SaveHitContainer->AddHit(layer_id, m_Hit);
0285         if (m_SaveShower)
0286         {
0287           m_SaveShower->add_g4hit_id(m_SaveHitContainer->GetID(), m_Hit->get_hit_id());
0288         }
0289         // ownership has been transferred to container, set to null
0290         // so we will create a new hit for the next track
0291         m_Hit = nullptr;
0292       }
0293       else
0294       {
0295         // if this hit has no energy deposit, just reset it for reuse
0296         // this means we have to delete it in the dtor. If this was
0297         // the last hit we processed the memory is still allocated
0298         m_Hit->Reset();
0299       }
0300     }
0301 
0302     //       m_Hit->identify();
0303     // return true to indicate the hit was used
0304     return true;
0305   }
0306   else
0307   {
0308     return false;
0309   }
0310 }
0311 
0312 //____________________________________________________________________________..
0313 void PHG4Prototype2InnerHcalSteppingAction::SetInterfacePointers(PHCompositeNode* topNode)
0314 {
0315   string hitnodename;
0316   string absorbernodename;
0317   if (m_Detector->SuperDetector() != "NONE")
0318   {
0319     hitnodename = "G4HIT_" + m_Detector->SuperDetector();
0320     absorbernodename = "G4HIT_ABSORBER_" + m_Detector->SuperDetector();
0321   }
0322   else
0323   {
0324     hitnodename = "G4HIT_" + m_Detector->GetName();
0325     absorbernodename = "G4HIT_ABSORBER_" + m_Detector->GetName();
0326   }
0327 
0328   //now look for the map and grab a pointer to it.
0329   m_HitContainer = findNode::getClass<PHG4HitContainer>(topNode, hitnodename.c_str());
0330   m_AbsorberHitContainer = findNode::getClass<PHG4HitContainer>(topNode, absorbernodename.c_str());
0331 
0332   // if we do not find the node it's messed up.
0333   if (!m_HitContainer)
0334   {
0335     std::cout << "PHG4Prototype2InnerHcalSteppingAction::SetTopNode - unable to find " << hitnodename << std::endl;
0336   }
0337   if (!m_AbsorberHitContainer)
0338   {
0339     if (Verbosity() > 1)
0340     {
0341       cout << "PHG4HcalSteppingAction::SetTopNode - unable to find " << absorbernodename << endl;
0342     }
0343   }
0344 }
0345 
0346 double
0347 PHG4Prototype2InnerHcalSteppingAction::GetLightCorrection(const double r) const
0348 {
0349   double m = (m_LightBalanceOuterCorr - m_LightBalanceInnerCorr) / (m_LightBalanceOuterRadius - m_LightBalanceInnerRadius);
0350   double b = m_LightBalanceInnerCorr - m * m_LightBalanceInnerRadius;
0351   double value = m * r + b;
0352   if (value > 1.0) return 1.0;
0353   if (value < 0.0) return 0.0;
0354 
0355   return value;
0356 }