Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-12-18 09:20:29

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 
0340         if (aTrack->GetTrackID() == m_SaveTrackId)
0341         {
0342           std::cout << GetName() << ": Bad step status combination for the same track " << std::endl;
0343           std::cout << "prestep status: " << PHG4StepStatusDecode::GetStepStatus(prePoint->GetStepStatus())
0344                     << ", poststep status: " << PHG4StepStatusDecode::GetStepStatus(postPoint->GetStepStatus())
0345                     << ", last pre step status: " << PHG4StepStatusDecode::GetStepStatus(m_SavePreStepStatus)
0346                     << ", last post step status: " << PHG4StepStatusDecode::GetStepStatus(m_SavePostStepStatus) << std::endl;
0347           std::cout << "last track: " << m_SaveTrackId
0348                     << ", current trackid: " << aTrack->GetTrackID() << std::endl;
0349           std::cout << "phys pre vol: " << volume->GetName()
0350                     << " post vol : " << touchpost->GetVolume()->GetName() << std::endl;
0351           std::cout << " previous phys pre vol: " << m_SaveVolPre->GetName()
0352                     << " previous phys post vol: " << m_SaveVolPost->GetName() << std::endl;
0353           gSystem->Exit(1);
0354         }
0355       }
0356       else
0357       {
0358         std::cout << GetName() << ": New Hit for  " << std::endl;
0359         std::cout << "prestep status: " << PHG4StepStatusDecode::GetStepStatus(prePoint->GetStepStatus())
0360                   << ", poststep status: " << PHG4StepStatusDecode::GetStepStatus(postPoint->GetStepStatus())
0361                   << ", last pre step status: " << PHG4StepStatusDecode::GetStepStatus(m_SavePreStepStatus)
0362                   << ", last post step status: " << PHG4StepStatusDecode::GetStepStatus(m_SavePostStepStatus) << std::endl;
0363         std::cout << "last track: " << m_SaveTrackId
0364                   << ", current trackid: " << aTrack->GetTrackID() << std::endl;
0365         std::cout << "phys pre vol: " << volume->GetName()
0366                   << " post vol : " << touchpost->GetVolume()->GetName() << std::endl;
0367         std::cout << " previous phys pre vol: " << m_SaveVolPre->GetName()
0368                   << " previous phys post vol: " << m_SaveVolPost->GetName() << std::endl;
0369       }
0370       [[fallthrough]];
0371     case fGeomBoundary:
0372     case fUndefined:
0373       // if previous hit was saved, hit pointer was set to nullptr
0374       // and we have to make a new one
0375       if (!m_Hit)
0376       {
0377         m_Hit = new PHG4Hitv1();
0378       }
0379       // here we set the entrance values in cm
0380       m_Hit->set_x(0, prePoint->GetPosition().x() / cm);
0381       m_Hit->set_y(0, prePoint->GetPosition().y() / cm);
0382       m_Hit->set_z(0, prePoint->GetPosition().z() / cm);
0383       // time in ns
0384       m_Hit->set_t(0, prePoint->GetGlobalTime() / nanosecond);
0385       // set and save the track ID
0386       m_Hit->set_trkid(aTrack->GetTrackID());
0387       m_SaveTrackId = aTrack->GetTrackID();
0388       // set the initial energy deposit
0389       m_Hit->set_edep(0);
0390       if (whichactive > 0)  // return of IsInIHCalDetector, > 0 hit in scintillator, < 0 hit in absorber
0391       {
0392         m_Hit->set_sector(sector_id);   // the slat id
0393         m_Hit->set_scint_id(tower_id);  // the slat id
0394         m_Hit->set_eion(0);             // only implemented for v5 otherwise empty
0395         m_Hit->set_raw_light_yield(0);  //  for scintillator only, initialize light yields
0396         m_Hit->set_light_yield(0);      // for scintillator only, initialize light yields
0397         // Now save the container we want to add this hit to
0398         m_SaveHitContainer = m_HitContainer;
0399       }
0400       else
0401       {
0402         m_SaveHitContainer = m_AbsorberHitContainer;
0403       }
0404       if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
0405       {
0406         if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
0407         {
0408           m_Hit->set_trkid(pp->GetUserTrackId());
0409           m_Hit->set_shower_id(pp->GetShower()->get_id());
0410           m_SaveShower = pp->GetShower();
0411         }
0412       }
0413       break;
0414     default:
0415       break;
0416     }
0417     // some sanity checks for inconsistencies
0418     // check if this hit was created, if not print out last post step status
0419     if (!m_Hit || !std::isfinite(m_Hit->get_x(0)))
0420     {
0421       std::cout << GetName() << ": hit was not created" << std::endl;
0422       std::cout << "prestep status: " << PHG4StepStatusDecode::GetStepStatus(prePoint->GetStepStatus())
0423                 << ", poststep status: " << PHG4StepStatusDecode::GetStepStatus(postPoint->GetStepStatus())
0424                 << ", last pre step status: " << PHG4StepStatusDecode::GetStepStatus(m_SavePreStepStatus)
0425                 << ", last post step status: " << PHG4StepStatusDecode::GetStepStatus(m_SavePostStepStatus) << std::endl;
0426       std::cout << "last track: " << m_SaveTrackId
0427                 << ", current trackid: " << aTrack->GetTrackID() << std::endl;
0428       std::cout << "phys pre vol: " << volume->GetName()
0429                 << " post vol : " << touchpost->GetVolume()->GetName() << std::endl;
0430       std::cout << " previous phys pre vol: " << m_SaveVolPre->GetName()
0431                 << " previous phys post vol: " << m_SaveVolPost->GetName() << std::endl;
0432       gSystem->Exit(1);
0433     }
0434     // check if track id matches the initial one when the hit was created
0435     if (aTrack->GetTrackID() != m_SaveTrackId)
0436     {
0437       std::cout << GetName() << ": hits do not belong to the same track" << std::endl;
0438       std::cout << "saved track: " << m_SaveTrackId
0439                 << ", current trackid: " << aTrack->GetTrackID()
0440                 << ", prestep status: " << prePoint->GetStepStatus()
0441                 << ", previous post step status: " << m_SavePostStepStatus
0442                 << std::endl;
0443 
0444       gSystem->Exit(1);
0445     }
0446     m_SavePreStepStatus = prePoint->GetStepStatus();
0447     m_SavePostStepStatus = postPoint->GetStepStatus();
0448     m_SaveVolPre = volume;
0449     m_SaveVolPost = touchpost->GetVolume();
0450     // here we just update the exit values, it will be overwritten
0451     // for every step until we leave the volume or the particle
0452     // ceases to exist
0453     m_Hit->set_x(1, postPoint->GetPosition().x() / cm);
0454     m_Hit->set_y(1, postPoint->GetPosition().y() / cm);
0455     m_Hit->set_z(1, postPoint->GetPosition().z() / cm);
0456 
0457     m_Hit->set_t(1, postPoint->GetGlobalTime() / nanosecond);
0458 
0459     // sum up the energy to get total deposited
0460     m_Hit->set_edep(m_Hit->get_edep() + edep);
0461     if (whichactive > 0)  // return of IsInIHCalDetector, > 0 hit in scintillator, < 0 hit in absorber
0462     {
0463       m_Hit->set_eion(m_Hit->get_eion() + eion);
0464       light_yield = eion;
0465       if (m_LightScintModelFlag)
0466       {
0467         light_yield = GetVisibleEnergyDeposition(aStep);                         // for scintillator only, calculate light yields
0468         m_Hit->set_raw_light_yield(m_Hit->get_raw_light_yield() + light_yield);  // save raw Birks light yield
0469         if (m_MapCorrHist)
0470         {
0471           const G4TouchableHandle& theTouchable = prePoint->GetTouchableHandle();
0472           const G4ThreeVector& worldPosition = postPoint->GetPosition();
0473           G4ThreeVector localPosition = theTouchable->GetHistory()->GetTopTransform().TransformPoint(worldPosition);
0474           float lx = localPosition.x() / cm;
0475           float ly = localPosition.y() / cm;
0476 
0477           // adjust to tilemap coordinates
0478           int lcx = (int) (5.0 * lx) + 1;
0479           int lcy = (int) (5.0 * (ly + 2.0)) + 1;
0480 
0481           if ((lcy >= 1) && (lcy <= m_MapCorrHist->GetNbinsY()) &&
0482               (lcx >= 1) && (lcx <= m_MapCorrHist->GetNbinsX()))
0483           {
0484             light_yield *= m_MapCorrHist->GetBinContent(lcx, lcy);
0485           }
0486           else
0487           {
0488             light_yield = 0.0;
0489           }
0490         }
0491         else
0492         {
0493           light_yield = light_yield * GetLightCorrection(postPoint->GetPosition().x(), postPoint->GetPosition().y());
0494         }
0495       }
0496       m_Hit->set_light_yield(m_Hit->get_light_yield() + light_yield);
0497     }
0498     if (geantino)
0499     {
0500       m_Hit->set_edep(-1);  // only energy=0 g4hits get dropped, this way geantinos survive the g4hit compression
0501       m_Hit->set_eion(-1);
0502     }
0503     if (edep > 0)
0504     {
0505       if (G4VUserTrackInformation* p = aTrack->GetUserInformation())
0506       {
0507         if (PHG4TrackUserInfoV1* pp = dynamic_cast<PHG4TrackUserInfoV1*>(p))
0508         {
0509           pp->SetKeep(1);  // we want to keep the track
0510         }
0511       }
0512     }
0513 
0514     // if any of these conditions is true this is the last step in
0515     // this volume and we need to save the hit
0516     // postPoint->GetStepStatus() == fGeomBoundary: track leaves this volume
0517     // postPoint->GetStepStatus() == fWorldBoundary: track leaves this world
0518     // (happens when your detector goes outside world volume)
0519     // postPoint->GetStepStatus() == fAtRestDoItProc: track stops (typically
0520     // aTrack->GetTrackStatus() == fStopAndKill is also set)
0521     // aTrack->GetTrackStatus() == fStopAndKill: track ends
0522     if (postPoint->GetStepStatus() == fGeomBoundary ||
0523         postPoint->GetStepStatus() == fWorldBoundary ||
0524         postPoint->GetStepStatus() == fAtRestDoItProc ||
0525         aTrack->GetTrackStatus() == fStopAndKill)
0526     {
0527       // save only hits with energy deposit (or -1 for geantino)
0528       if (m_Hit->get_edep() != 0)
0529       {
0530         m_SaveHitContainer->AddHit(layer_id, m_Hit);
0531 
0532         if (m_SaveShower)
0533         {
0534           m_SaveShower->add_g4hit_id(m_SaveHitContainer->GetID(), m_Hit->get_hit_id());
0535         }
0536         // ownership has been transferred to container, set to null
0537         // so we will create a new hit for the next track
0538         m_Hit = nullptr;
0539       }
0540       else
0541       {
0542         // if this hit has no energy deposit, just reset it for reuse
0543         // this means we have to delete it in the dtor. If this was
0544         // the last hit we processed the memory is still allocated
0545         m_Hit->Reset();
0546       }
0547     }
0548     // return true to indicate the hit was used
0549     return true;
0550   }
0551 
0552   return false;
0553 }
0554 
0555 //____________________________________________________________________________..
0556 void PHG4IHCalSteppingAction::SetInterfacePointers(PHCompositeNode* topNode)
0557 {
0558   m_HitContainer = findNode::getClass<PHG4HitContainer>(topNode, m_HitNodeName);
0559   m_AbsorberHitContainer = findNode::getClass<PHG4HitContainer>(topNode, m_AbsorberNodeName);
0560 
0561   // if we do not find the node it's messed up.
0562   if (!m_HitContainer)
0563   {
0564     std::cout << "PHG4IHCalSteppingAction::SetTopNode - unable to find " << m_HitNodeName << std::endl;
0565   }
0566   if (!m_AbsorberHitContainer)
0567   {
0568     if (Verbosity() > 1)
0569     {
0570       std::cout << "PHG4IHcalSteppingAction::SetTopNode - unable to find " << m_AbsorberNodeName << std::endl;
0571     }
0572   }
0573 }
0574 
0575 void PHG4IHCalSteppingAction::SetHitNodeName(const std::string& type, const std::string& name)
0576 {
0577   if (type == "G4HIT")
0578   {
0579     m_HitNodeName = name;
0580     return;
0581   }
0582   if (type == "G4HIT_ABSORBER")
0583   {
0584     m_AbsorberNodeName = name;
0585     return;
0586   }
0587   std::cout << "Invalid output hit node type " << type << std::endl;
0588   gSystem->Exit(1);
0589   return;
0590 }
0591 
0592 void PHG4IHCalSteppingAction::CreateNodeTree(PHCompositeNode* topNode)
0593 {
0594   PHNodeIterator nodeItr(topNode);
0595   PHCompositeNode* dst_node = dynamic_cast<PHCompositeNode*>(
0596       nodeItr.findFirst("PHCompositeNode", "DST"));
0597   if (!dst_node)
0598   {
0599     std::cout << "PHComposite node created: DST" << std::endl;
0600     dst_node = new PHCompositeNode("DST");
0601     topNode->addNode(dst_node);
0602   }
0603   PHNodeIterator dstiter(dst_node);
0604   PHCompositeNode* DetNode = dynamic_cast<PHCompositeNode*>(dstiter.findFirst("PHCompositeNode", m_Detector->SuperDetector()));
0605   if (!DetNode)
0606   {
0607     DetNode = new PHCompositeNode(m_Detector->SuperDetector());
0608     dst_node->addNode(DetNode);
0609   }
0610   m_CaloInfoContainer = new TowerInfoContainerv1(TowerInfoContainer::DETECTOR::HCAL);
0611   PHIODataNode<PHObject>* towerNode = new PHIODataNode<PHObject>(m_CaloInfoContainer, "TOWERINFO_SIM_" + m_Detector->SuperDetector(), "PHObject");
0612   DetNode->addNode(towerNode);
0613 }