Back to home page

sPhenix code displayed by LXR

 
 

    


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

0001 #include "PHG4IHCalSteppingAction.h"
0002 
0003 #include "PHG4IHCalDetector.h"
0004 
0005 #include <g4detectors/PHG4StepStatusDecode.h>
0006 
0007 #include <phparameter/PHParameters.h>
0008 
0009 #include <calobase/TowerInfo.h>
0010 #include <calobase/TowerInfoContainer.h>
0011 #include <calobase/TowerInfoContainerv1.h>
0012 #include <calobase/TowerInfoDefs.h>
0013 
0014 #include <g4main/PHG4Hit.h>
0015 #include <g4main/PHG4HitContainer.h>
0016 #include <g4main/PHG4Hitv1.h>
0017 #include <g4main/PHG4Shower.h>
0018 #include <g4main/PHG4SteppingAction.h>  // for PHG4SteppingAction
0019 #include <g4main/PHG4TrackUserInfoV1.h>
0020 
0021 #include <ffamodules/CDBInterface.h>
0022 
0023 #include <fun4all/Fun4AllReturnCodes.h>
0024 
0025 #include <phool/PHCompositeNode.h>
0026 #include <phool/PHIODataNode.h>    // for PHIODataNode
0027 #include <phool/PHNode.h>          // for PHNode
0028 #include <phool/PHNodeIterator.h>  // for PHNodeIterator
0029 #include <phool/PHObject.h>        // for PHObject
0030 #include <phool/getClass.h>
0031 #include <phool/phool.h>
0032 
0033 // Root headers
0034 #include <TFile.h>
0035 #include <TH2.h>
0036 #include <TSystem.h>
0037 
0038 #include <Geant4/G4NavigationHistory.hh>
0039 #include <Geant4/G4ParticleDefinition.hh>      // for G4ParticleDefinition
0040 #include <Geant4/G4ReferenceCountedHandle.hh>  // for G4ReferenceCountedHandle
0041 #include <Geant4/G4Step.hh>
0042 #include <Geant4/G4StepPoint.hh>   // for G4StepPoint
0043 #include <Geant4/G4StepStatus.hh>  // for fGeomBoundary, fAtRest...
0044 #include <Geant4/G4String.hh>      // for G4String
0045 #include <Geant4/G4SystemOfUnits.hh>
0046 #include <Geant4/G4ThreeVector.hh>            // for G4ThreeVector
0047 #include <Geant4/G4TouchableHandle.hh>        // for G4TouchableHandle
0048 #include <Geant4/G4Track.hh>                  // for G4Track
0049 #include <Geant4/G4TrackStatus.hh>            // for fStopAndKill
0050 #include <Geant4/G4Types.hh>                  // for G4double
0051 #include <Geant4/G4VPhysicalVolume.hh>        // for G4VPhysicalVolume
0052 #include <Geant4/G4VTouchable.hh>             // for G4VTouchable
0053 #include <Geant4/G4VUserTrackInformation.hh>  // for G4VUserTrackInformation
0054 
0055 #include <cmath>  // for isfinite
0056 #include <exception>
0057 #include <filesystem>
0058 #include <iostream>
0059 #include <string>  // for operator<<, operator+
0060 #include <tuple>
0061 
0062 //____________________________________________________________________________..
0063 PHG4IHCalSteppingAction::PHG4IHCalSteppingAction(PHG4IHCalDetector* detector, PHParameters* parameters)
0064   : PHG4SteppingAction(detector->GetName())
0065   , m_Detector(detector)
0066   , m_Params(parameters)
0067   , m_IsActive(m_Params->get_int_param("active"))
0068   , m_IsBlackHole(m_Params->get_int_param("blackhole"))
0069   , m_LightScintModelFlag(m_Params->get_int_param("light_scint_model"))
0070   , m_doG4Hit(m_Params->get_int_param("saveg4hit"))
0071   , m_tmin(m_Params->get_double_param("tmin"))
0072   , m_tmax(m_Params->get_double_param("tmax"))
0073   , m_dt(m_Params->get_double_param("dt"))
0074 {
0075   SetLightCorrection(m_Params->get_double_param("light_balance_inner_radius") * cm,
0076                      m_Params->get_double_param("light_balance_inner_corr"),
0077                      m_Params->get_double_param("light_balance_outer_radius") * cm,
0078                      m_Params->get_double_param("light_balance_outer_corr"));
0079 
0080   std::string mapfile = m_Params->get_string_param("MapFileName");
0081   if (std::filesystem::path(mapfile).extension() != ".root")
0082   {
0083     mapfile = CDBInterface::instance()->getUrl(mapfile);
0084     m_Params->set_string_param("MapFileName", mapfile);
0085   }
0086 }
0087 
0088 PHG4IHCalSteppingAction::~PHG4IHCalSteppingAction()
0089 {
0090   // if the last hit was a zero energie deposit hit, it is just reset
0091   // and the memory is still allocated, so we need to delete it here
0092   // if the last hit was saved, hit is a nullptr pointer which are
0093   // legal to delete (it results in a no operation)
0094   delete m_Hit;
0095   // since we have a copy in memory of this one - we need to delete it
0096   delete m_MapCorrHist;
0097 }
0098 
0099 //____________________________________________________________________________..
0100 int PHG4IHCalSteppingAction::InitWithNode(PHCompositeNode* topNode)
0101 {
0102   if (m_LightScintModelFlag)
0103   {
0104     std::string ihcalmapname(m_Params->get_string_param("MapFileName"));
0105     if (ihcalmapname.empty())
0106     {
0107       return 0;
0108     }
0109     if (!std::filesystem::exists(m_Params->get_string_param("MapFileName")))
0110     {
0111       std::cout << PHWHERE << " Could not locate " << m_Params->get_string_param("MapFileName") << std::endl;
0112       std::cout << "use empty filename to ignore mapfile" << std::endl;
0113       gSystem->Exit(1);
0114     }
0115     TFile* file = TFile::Open(ihcalmapname.c_str());
0116     file->GetObject(m_Params->get_string_param("MapHistoName").c_str(), m_MapCorrHist);
0117     if (!m_MapCorrHist)
0118     {
0119       std::cout << "ERROR: could not find Histogram " << m_Params->get_string_param("MapHistoName") << " in " << m_Params->get_string_param("MapFileName") << std::endl;
0120       gSystem->Exit(1);
0121     }
0122     m_MapCorrHist->SetDirectory(nullptr);  // rootism: this needs to be set otherwise histo vanished when closing the file
0123     file->Close();
0124     delete file;
0125   }
0126   if (!m_doG4Hit)
0127   {
0128     try
0129     {
0130       CreateNodeTree(topNode);
0131     }
0132     catch (std::exception& e)
0133     {
0134       std::cout << e.what() << std::endl;
0135       return Fun4AllReturnCodes::ABORTRUN;
0136     }
0137     if (Verbosity() > 1)
0138     {
0139       topNode->print();
0140     }
0141   }
0142 
0143   return 0;
0144 }
0145 
0146 //____________________________________________________________________________..
0147 bool PHG4IHCalSteppingAction::NoHitSteppingAction(const G4Step* aStep)
0148 {
0149   G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle();
0150   G4TouchableHandle touchpost = aStep->GetPostStepPoint()->GetTouchableHandle();
0151   // get volume of the current step
0152   G4VPhysicalVolume* volume = touch->GetVolume();
0153 
0154   // m_Detector->IsInIHCal(volume)
0155   // returns
0156   //  0 is outside of IHCal
0157   //  1 is inside scintillator
0158   // -1 is steel absorber
0159 
0160   int whichactive = m_Detector->IsInIHCal(volume);
0161 
0162   if (!whichactive)
0163   {
0164     return false;
0165   }
0166   int layer_id = -1;
0167   int tower_id = -1;
0168   // int sector_id = -1;
0169   if (whichactive > 0)  // scintillator
0170   {
0171     std::tuple<int, int, int> layer_tower = m_Detector->GetLayerTowerId(volume);
0172     // sector_id = std::get<0>(layer_tower);
0173     layer_id = std::get<1>(layer_tower);
0174     tower_id = std::get<2>(layer_tower);
0175 
0176     //    std::cout<<"******** Inner HCal\t"<<volume->GetName()<<"\t"<<layer_id<<"\t"<<tower_id<<std::endl;
0177   }
0178   else
0179   {
0180     // absorber hit, do nothing
0181     return false;
0182   }
0183 
0184   if (!m_IsActive)
0185   {
0186     return false;
0187   }
0188 
0189   G4StepPoint* prePoint = aStep->GetPreStepPoint();
0190   G4StepPoint* postPoint = aStep->GetPostStepPoint();
0191   // time window cut
0192   double pretime = prePoint->GetGlobalTime() / nanosecond;
0193   double posttime = postPoint->GetGlobalTime() / nanosecond;
0194   if (posttime < m_tmin || pretime > m_tmax)
0195   {
0196     return false;
0197   }
0198   if ((posttime - pretime) > m_dt)
0199   {
0200     return false;
0201   }
0202   G4double eion = (aStep->GetTotalEnergyDeposit() - aStep->GetNonIonizingEnergyDeposit()) / GeV;
0203   const G4Track* aTrack = aStep->GetTrack();
0204   // we only need visible energy here
0205   double light_yield = eion;
0206 
0207   // correct evis using light map
0208   if (m_LightScintModelFlag)
0209   {
0210     light_yield = GetVisibleEnergyDeposition(aStep);
0211     if (m_MapCorrHist)
0212     {
0213       const G4TouchableHandle& theTouchable = prePoint->GetTouchableHandle();
0214       const G4ThreeVector& worldPosition = postPoint->GetPosition();
0215       G4ThreeVector localPosition = theTouchable->GetHistory()->GetTopTransform().TransformPoint(worldPosition);
0216       float lx = localPosition.x() / cm;
0217       float ly = localPosition.y() / cm;
0218 
0219       // adjust to tilemap coordinates
0220       int lcx = (int) (5.0 * lx) + 1;
0221       int lcy = (int) (5.0 * (ly + 2.0)) + 1;
0222 
0223       if ((lcy >= 1) && (lcy <= m_MapCorrHist->GetNbinsY()) &&
0224           (lcx >= 1) && (lcx <= m_MapCorrHist->GetNbinsX()))
0225       {
0226         light_yield *= m_MapCorrHist->GetBinContent(lcx, lcy);
0227       }
0228       else
0229       {
0230         light_yield = 0.0;
0231       }
0232     }
0233     else
0234     {
0235       light_yield = light_yield * GetLightCorrection(postPoint->GetPosition().x(), postPoint->GetPosition().y());
0236     }
0237   }
0238   // find the tower index for this step, tower_id is ieta, layer_id/4 is iphi
0239   unsigned int ieta = tower_id;
0240   unsigned int iphi = (unsigned int) layer_id / 4;
0241   unsigned int tower_key = TowerInfoDefs::encode_hcal(ieta, iphi);
0242   m_CaloInfoContainer->get_tower_at_key(tower_key)->set_energy(m_CaloInfoContainer->get_tower_at_key(tower_key)->get_energy() + light_yield);
0243   // set keep for the track
0244   if (light_yield > 0)
0245   {
0246     if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
0247     {
0248       if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
0249       {
0250         pp->SetKeep(1);  // we want to keep the track
0251       }
0252     }
0253   }
0254 
0255   return true;
0256 }
0257 //____________________________________________________________________________..
0258 bool PHG4IHCalSteppingAction::UserSteppingAction(const G4Step* aStep, bool /*was_used*/)
0259 {
0260   if ((!m_doG4Hit) && (!m_IsBlackHole))
0261   {
0262     return NoHitSteppingAction(aStep);
0263   }
0264 
0265   G4TouchableHandle touch = aStep->GetPreStepPoint()->GetTouchableHandle();
0266   G4TouchableHandle touchpost = aStep->GetPostStepPoint()->GetTouchableHandle();
0267   // get volume of the current step
0268   G4VPhysicalVolume* volume = touch->GetVolume();
0269 
0270   // m_Detector->IsInIHCal(volume)
0271   // returns
0272   //  0 is outside of IHCal
0273   //  1 is inside scintillator
0274   // -1 is steel absorber
0275 
0276   int whichactive = m_Detector->IsInIHCal(volume);
0277 
0278   if (!whichactive)
0279   {
0280     return false;
0281   }
0282   int layer_id = -1;
0283   int tower_id = -1;
0284   int sector_id = -1;
0285   if (whichactive > 0)  // scintillator
0286   {
0287     std::tuple<int, int, int> layer_tower = m_Detector->GetLayerTowerId(volume);
0288     sector_id = std::get<0>(layer_tower);
0289     layer_id = std::get<1>(layer_tower);
0290     tower_id = std::get<2>(layer_tower);
0291 
0292     //    std::cout<<"******** Inner HCal\t"<<volume->GetName()<<"\t"<<layer_id<<"\t"<<tower_id<<std::endl;
0293   }
0294   else
0295   {
0296     layer_id = m_Detector->GetSectorId(volume);  // absorber sector id
0297   }
0298   // collect energy and track length step by step
0299   G4double edep = aStep->GetTotalEnergyDeposit() / GeV;
0300   G4double eion = (aStep->GetTotalEnergyDeposit() - aStep->GetNonIonizingEnergyDeposit()) / GeV;
0301   double light_yield = 0;
0302   const G4Track* aTrack = aStep->GetTrack();
0303 
0304   // if this block stops everything, just put all kinetic energy into edep
0305   if (m_IsBlackHole)
0306   {
0307     edep = aTrack->GetKineticEnergy() / GeV;
0308     G4Track* killtrack = const_cast<G4Track*>(aTrack);
0309     killtrack->SetTrackStatus(fStopAndKill);
0310   }
0311 
0312   // make sure we are in a volume
0313   if (m_IsActive)
0314   {
0315     bool geantino = false;
0316 
0317     // the check for the pdg code speeds things up, I do not want to make
0318     // an expensive string compare for every track when we know
0319     // geantino or chargedgeantino has pid=0
0320     if (aTrack->GetParticleDefinition()->GetPDGEncoding() == 0 &&
0321         aTrack->GetParticleDefinition()->GetParticleName().find("geantino") != std::string::npos)
0322     {
0323       geantino = true;
0324     }
0325     G4StepPoint* prePoint = aStep->GetPreStepPoint();
0326     G4StepPoint* postPoint = aStep->GetPostStepPoint();
0327     //       std::cout << "track id " << aTrack->GetTrackID() << std::endl;
0328     //       std::cout << "time prepoint: " << prePoint->GetGlobalTime() << std::endl;
0329     //       std::cout << "time postpoint: " << postPoint->GetGlobalTime() << std::endl;
0330     switch (prePoint->GetStepStatus())
0331     {
0332     case fPostStepDoItProc:
0333       if (m_SavePostStepStatus != fGeomBoundary)
0334       {
0335         if (m_SavePostStepStatus != fAtRestDoItProc)
0336         {
0337           break;
0338         }
0339         else
0340         {
0341           if (aTrack->GetTrackID() == m_SaveTrackId)
0342           {
0343             std::cout << GetName() << ": Bad step status combination for the same track " << std::endl;
0344             std::cout << "prestep status: " << PHG4StepStatusDecode::GetStepStatus(prePoint->GetStepStatus())
0345                       << ", poststep status: " << PHG4StepStatusDecode::GetStepStatus(postPoint->GetStepStatus())
0346                       << ", last pre step status: " << PHG4StepStatusDecode::GetStepStatus(m_SavePreStepStatus)
0347                       << ", last post step status: " << PHG4StepStatusDecode::GetStepStatus(m_SavePostStepStatus) << std::endl;
0348             std::cout << "last track: " << m_SaveTrackId
0349                       << ", current trackid: " << aTrack->GetTrackID() << std::endl;
0350             std::cout << "phys pre vol: " << volume->GetName()
0351                       << " post vol : " << touchpost->GetVolume()->GetName() << std::endl;
0352             std::cout << " previous phys pre vol: " << m_SaveVolPre->GetName()
0353                       << " previous phys post vol: " << m_SaveVolPost->GetName() << std::endl;
0354             gSystem->Exit(1);
0355           }
0356         }
0357       }
0358       else
0359       {
0360         std::cout << GetName() << ": New Hit for  " << std::endl;
0361         std::cout << "prestep status: " << PHG4StepStatusDecode::GetStepStatus(prePoint->GetStepStatus())
0362                   << ", poststep status: " << PHG4StepStatusDecode::GetStepStatus(postPoint->GetStepStatus())
0363                   << ", last pre step status: " << PHG4StepStatusDecode::GetStepStatus(m_SavePreStepStatus)
0364                   << ", last post step status: " << PHG4StepStatusDecode::GetStepStatus(m_SavePostStepStatus) << std::endl;
0365         std::cout << "last track: " << m_SaveTrackId
0366                   << ", current trackid: " << aTrack->GetTrackID() << std::endl;
0367         std::cout << "phys pre vol: " << volume->GetName()
0368                   << " post vol : " << touchpost->GetVolume()->GetName() << std::endl;
0369         std::cout << " previous phys pre vol: " << m_SaveVolPre->GetName()
0370                   << " previous phys post vol: " << m_SaveVolPost->GetName() << std::endl;
0371       }
0372       [[fallthrough]];
0373     case fGeomBoundary:
0374     case fUndefined:
0375       // if previous hit was saved, hit pointer was set to nullptr
0376       // and we have to make a new one
0377       if (!m_Hit)
0378       {
0379         m_Hit = new PHG4Hitv1();
0380       }
0381       // here we set the entrance values in cm
0382       m_Hit->set_x(0, prePoint->GetPosition().x() / cm);
0383       m_Hit->set_y(0, prePoint->GetPosition().y() / cm);
0384       m_Hit->set_z(0, prePoint->GetPosition().z() / cm);
0385       // time in ns
0386       m_Hit->set_t(0, prePoint->GetGlobalTime() / nanosecond);
0387       // set and save the track ID
0388       m_Hit->set_trkid(aTrack->GetTrackID());
0389       m_SaveTrackId = aTrack->GetTrackID();
0390       // set the initial energy deposit
0391       m_Hit->set_edep(0);
0392       if (whichactive > 0)  // return of IsInIHCalDetector, > 0 hit in scintillator, < 0 hit in absorber
0393       {
0394         m_Hit->set_sector(sector_id);   // the slat id
0395         m_Hit->set_scint_id(tower_id);  // the slat id
0396         m_Hit->set_eion(0);             // only implemented for v5 otherwise empty
0397         m_Hit->set_raw_light_yield(0);  //  for scintillator only, initialize light yields
0398         m_Hit->set_light_yield(0);      // for scintillator only, initialize light yields
0399         // Now save the container we want to add this hit to
0400         m_SaveHitContainer = m_HitContainer;
0401       }
0402       else
0403       {
0404         m_SaveHitContainer = m_AbsorberHitContainer;
0405       }
0406       if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
0407       {
0408         if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
0409         {
0410           m_Hit->set_trkid(pp->GetUserTrackId());
0411           m_Hit->set_shower_id(pp->GetShower()->get_id());
0412           m_SaveShower = pp->GetShower();
0413         }
0414       }
0415       break;
0416     default:
0417       break;
0418     }
0419     // some sanity checks for inconsistencies
0420     // check if this hit was created, if not print out last post step status
0421     if (!m_Hit || !std::isfinite(m_Hit->get_x(0)))
0422     {
0423       std::cout << GetName() << ": hit was not created" << std::endl;
0424       std::cout << "prestep status: " << PHG4StepStatusDecode::GetStepStatus(prePoint->GetStepStatus())
0425                 << ", poststep status: " << PHG4StepStatusDecode::GetStepStatus(postPoint->GetStepStatus())
0426                 << ", last pre step status: " << PHG4StepStatusDecode::GetStepStatus(m_SavePreStepStatus)
0427                 << ", last post step status: " << PHG4StepStatusDecode::GetStepStatus(m_SavePostStepStatus) << std::endl;
0428       std::cout << "last track: " << m_SaveTrackId
0429                 << ", current trackid: " << aTrack->GetTrackID() << std::endl;
0430       std::cout << "phys pre vol: " << volume->GetName()
0431                 << " post vol : " << touchpost->GetVolume()->GetName() << std::endl;
0432       std::cout << " previous phys pre vol: " << m_SaveVolPre->GetName()
0433                 << " previous phys post vol: " << m_SaveVolPost->GetName() << std::endl;
0434       gSystem->Exit(1);
0435     }
0436     // check if track id matches the initial one when the hit was created
0437     if (aTrack->GetTrackID() != m_SaveTrackId)
0438     {
0439       std::cout << GetName() << ": hits do not belong to the same track" << std::endl;
0440       std::cout << "saved track: " << m_SaveTrackId
0441                 << ", current trackid: " << aTrack->GetTrackID()
0442                 << ", prestep status: " << prePoint->GetStepStatus()
0443                 << ", previous post step status: " << m_SavePostStepStatus
0444                 << std::endl;
0445 
0446       gSystem->Exit(1);
0447     }
0448     m_SavePreStepStatus = prePoint->GetStepStatus();
0449     m_SavePostStepStatus = postPoint->GetStepStatus();
0450     m_SaveVolPre = volume;
0451     m_SaveVolPost = touchpost->GetVolume();
0452     // here we just update the exit values, it will be overwritten
0453     // for every step until we leave the volume or the particle
0454     // ceases to exist
0455     m_Hit->set_x(1, postPoint->GetPosition().x() / cm);
0456     m_Hit->set_y(1, postPoint->GetPosition().y() / cm);
0457     m_Hit->set_z(1, postPoint->GetPosition().z() / cm);
0458 
0459     m_Hit->set_t(1, postPoint->GetGlobalTime() / nanosecond);
0460 
0461     // sum up the energy to get total deposited
0462     m_Hit->set_edep(m_Hit->get_edep() + edep);
0463     if (whichactive > 0)  // return of IsInIHCalDetector, > 0 hit in scintillator, < 0 hit in absorber
0464     {
0465       m_Hit->set_eion(m_Hit->get_eion() + eion);
0466       light_yield = eion;
0467       if (m_LightScintModelFlag)
0468       {
0469         light_yield = GetVisibleEnergyDeposition(aStep);                         // for scintillator only, calculate light yields
0470         m_Hit->set_raw_light_yield(m_Hit->get_raw_light_yield() + light_yield);  // save raw Birks light yield
0471         if (m_MapCorrHist)
0472         {
0473           const G4TouchableHandle& theTouchable = prePoint->GetTouchableHandle();
0474           const G4ThreeVector& worldPosition = postPoint->GetPosition();
0475           G4ThreeVector localPosition = theTouchable->GetHistory()->GetTopTransform().TransformPoint(worldPosition);
0476           float lx = localPosition.x() / cm;
0477           float ly = localPosition.y() / cm;
0478 
0479           // adjust to tilemap coordinates
0480           int lcx = (int) (5.0 * lx) + 1;
0481           int lcy = (int) (5.0 * (ly + 2.0)) + 1;
0482 
0483           if ((lcy >= 1) && (lcy <= m_MapCorrHist->GetNbinsY()) &&
0484               (lcx >= 1) && (lcx <= m_MapCorrHist->GetNbinsX()))
0485           {
0486             light_yield *= m_MapCorrHist->GetBinContent(lcx, lcy);
0487           }
0488           else
0489           {
0490             light_yield = 0.0;
0491           }
0492         }
0493         else
0494         {
0495           light_yield = light_yield * GetLightCorrection(postPoint->GetPosition().x(), postPoint->GetPosition().y());
0496         }
0497       }
0498       m_Hit->set_light_yield(m_Hit->get_light_yield() + light_yield);
0499     }
0500     if (geantino)
0501     {
0502       m_Hit->set_edep(-1);  // only energy=0 g4hits get dropped, this way geantinos survive the g4hit compression
0503       m_Hit->set_eion(-1);
0504     }
0505     if (edep > 0)
0506     {
0507       if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
0508       {
0509         if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
0510         {
0511           pp->SetKeep(1);  // we want to keep the track
0512         }
0513       }
0514     }
0515 
0516     // if any of these conditions is true this is the last step in
0517     // this volume and we need to save the hit
0518     // postPoint->GetStepStatus() == fGeomBoundary: track leaves this volume
0519     // postPoint->GetStepStatus() == fWorldBoundary: track leaves this world
0520     // (happens when your detector goes outside world volume)
0521     // postPoint->GetStepStatus() == fAtRestDoItProc: track stops (typically
0522     // aTrack->GetTrackStatus() == fStopAndKill is also set)
0523     // aTrack->GetTrackStatus() == fStopAndKill: track ends
0524     if (postPoint->GetStepStatus() == fGeomBoundary ||
0525         postPoint->GetStepStatus() == fWorldBoundary ||
0526         postPoint->GetStepStatus() == fAtRestDoItProc ||
0527         aTrack->GetTrackStatus() == fStopAndKill)
0528     {
0529       // save only hits with energy deposit (or -1 for geantino)
0530       if (m_Hit->get_edep() != 0)
0531       {
0532         m_SaveHitContainer->AddHit(layer_id, m_Hit);
0533 
0534         if (m_SaveShower)
0535         {
0536           m_SaveShower->add_g4hit_id(m_SaveHitContainer->GetID(), m_Hit->get_hit_id());
0537         }
0538         // ownership has been transferred to container, set to null
0539         // so we will create a new hit for the next track
0540         m_Hit = nullptr;
0541       }
0542       else
0543       {
0544         // if this hit has no energy deposit, just reset it for reuse
0545         // this means we have to delete it in the dtor. If this was
0546         // the last hit we processed the memory is still allocated
0547         m_Hit->Reset();
0548       }
0549     }
0550     // return true to indicate the hit was used
0551     return true;
0552   }
0553   else
0554   {
0555     return false;
0556   }
0557 }
0558 
0559 //____________________________________________________________________________..
0560 void PHG4IHCalSteppingAction::SetInterfacePointers(PHCompositeNode* topNode)
0561 {
0562   m_HitContainer = findNode::getClass<PHG4HitContainer>(topNode, m_HitNodeName);
0563   m_AbsorberHitContainer = findNode::getClass<PHG4HitContainer>(topNode, m_AbsorberNodeName);
0564 
0565   // if we do not find the node it's messed up.
0566   if (!m_HitContainer)
0567   {
0568     std::cout << "PHG4IHCalSteppingAction::SetTopNode - unable to find " << m_HitNodeName << std::endl;
0569   }
0570   if (!m_AbsorberHitContainer)
0571   {
0572     if (Verbosity() > 1)
0573     {
0574       std::cout << "PHG4IHcalSteppingAction::SetTopNode - unable to find " << m_AbsorberNodeName << std::endl;
0575     }
0576   }
0577 }
0578 
0579 void PHG4IHCalSteppingAction::SetHitNodeName(const std::string& type, const std::string& name)
0580 {
0581   if (type == "G4HIT")
0582   {
0583     m_HitNodeName = name;
0584     return;
0585   }
0586   else if (type == "G4HIT_ABSORBER")
0587   {
0588     m_AbsorberNodeName = name;
0589     return;
0590   }
0591   std::cout << "Invalid output hit node type " << type << std::endl;
0592   gSystem->Exit(1);
0593   return;
0594 }
0595 
0596 void PHG4IHCalSteppingAction::CreateNodeTree(PHCompositeNode* topNode)
0597 {
0598   PHNodeIterator nodeItr(topNode);
0599   PHCompositeNode* dst_node = dynamic_cast<PHCompositeNode*>(
0600       nodeItr.findFirst("PHCompositeNode", "DST"));
0601   if (!dst_node)
0602   {
0603     std::cout << "PHComposite node created: DST" << std::endl;
0604     dst_node = new PHCompositeNode("DST");
0605     topNode->addNode(dst_node);
0606   }
0607   PHNodeIterator dstiter(dst_node);
0608   PHCompositeNode* DetNode = dynamic_cast<PHCompositeNode*>(dstiter.findFirst("PHCompositeNode", m_Detector->SuperDetector()));
0609   if (!DetNode)
0610   {
0611     DetNode = new PHCompositeNode(m_Detector->SuperDetector());
0612     dst_node->addNode(DetNode);
0613   }
0614   m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::HCAL);
0615   PHIODataNode<PHObject>* towerNode = new PHIODataNode<PHObject>(m_CaloInfoContainer, "TOWERINFO_SIM_" + m_Detector->SuperDetector(), "PHObject");
0616   DetNode->addNode(towerNode);
0617 }