Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-12-17 09:21:59

0001 #include "PHG4InttHitReco.h"
0002 
0003 #include <intt/CylinderGeomIntt.h>
0004 
0005 #include <g4detectors/PHG4CylinderGeom.h>  // for PHG4CylinderGeom
0006 #include <g4detectors/PHG4CylinderGeomContainer.h>
0007 
0008 #include <g4tracking/TrkrTruthTrack.h>
0009 #include <g4tracking/TrkrTruthTrackContainerv1.h>
0010 
0011 #include <trackbase/ClusHitsVerbosev1.h>
0012 #include <trackbase/InttDefs.h>
0013 #include <trackbase/TrkrClusterContainer.h>
0014 #include <trackbase/TrkrClusterContainerv4.h>
0015 #include <trackbase/TrkrClusterv4.h>
0016 #include <trackbase/TrkrDefs.h>
0017 #include <trackbase/TrkrHit.h>  // for TrkrHit
0018 #include <trackbase/TrkrHitSet.h>
0019 #include <trackbase/TrkrHitSetContainer.h>
0020 #include <trackbase/TrkrHitSetContainerv1.h>
0021 #include <trackbase/TrkrHitTruthAssoc.h>
0022 #include <trackbase/TrkrHitTruthAssocv1.h>
0023 #include <trackbase/TrkrHitv2.h>  // for TrkrHit
0024 
0025 #include <phparameter/PHParameterInterface.h>  // for PHParameterInterface
0026 
0027 #include <g4main/PHG4Hit.h>
0028 #include <g4main/PHG4HitContainer.h>
0029 #include <g4main/PHG4TruthInfoContainer.h>
0030 #include <g4main/PHG4Utils.h>
0031 
0032 #include <cdbobjects/CDBTTree.h>
0033 
0034 #include <ffamodules/CDBInterface.h>
0035 
0036 #include <fun4all/Fun4AllReturnCodes.h>
0037 #include <fun4all/SubsysReco.h>  // for SubsysReco
0038 
0039 #include <phool/PHCompositeNode.h>
0040 #include <phool/PHIODataNode.h>
0041 #include <phool/PHNode.h>  // for PHNode
0042 #include <phool/PHNodeIterator.h>
0043 #include <phool/PHObject.h>  // for PHObject
0044 #include <phool/getClass.h>
0045 #include <phool/phool.h>  // for PHWHERE
0046 #include <phool/sphenix_constants.h>
0047 
0048 #include <TSystem.h>
0049 
0050 #include <algorithm>
0051 #include <cassert>
0052 #include <cmath>
0053 #include <cstdlib>
0054 #include <iostream>
0055 #include <filesystem>
0056 #include <map>      // for _Rb_tree_const_it...
0057 #include <memory>   // for allocator_traits<...
0058 #include <set>
0059 #include <utility>  // for pair, swap, make_...
0060 #include <vector>   // for vector
0061 
0062 // update to make sure to clusterize clusters in loopers
0063 
0064 PHG4InttHitReco::PHG4InttHitReco(const std::string &name)
0065   : SubsysReco(name)
0066   , PHParameterInterface(name)
0067   , m_Detector("INTT")
0068   , m_Tmin(NAN)
0069   , m_Tmax(NAN)
0070   , m_crossingPeriod(NAN)
0071   , m_LocalOutVec(gsl_vector_alloc(3)), m_PathVec(gsl_vector_alloc(3)), m_SegmentVec(gsl_vector_alloc(3)), m_truth_hits{new TrkrHitSetContainerv1}
0072 {
0073   InitializeParameters();
0074 
0075   m_HitNodeName = "G4HIT_" + m_Detector;
0076   m_CellNodeName = "G4CELL_" + m_Detector;
0077   m_GeoNodeName = "CYLINDERGEOM_" + m_Detector;
0078   
0079   
0080   
0081 }
0082 
0083 PHG4InttHitReco::~PHG4InttHitReco()
0084 {
0085   gsl_vector_free(m_LocalOutVec);
0086   gsl_vector_free(m_PathVec);
0087   gsl_vector_free(m_SegmentVec);
0088   delete m_truth_hits;
0089 }
0090 
0091 int PHG4InttHitReco::InitRun(PHCompositeNode *topNode)
0092 {
0093   PHNodeIterator iter(topNode);
0094 
0095   // Looking for the DST node
0096   PHCompositeNode *dstNode;
0097   dstNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
0098   if (!dstNode)
0099   {
0100     std::cout << PHWHERE << "DST Node missing, exiting." << std::endl;
0101     gSystem->Exit(1);
0102     exit(1);
0103   }
0104 
0105   PHCompositeNode *runNode;
0106   runNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
0107   if (!runNode)
0108   {
0109     std::cout << Name() << "RUN Node missing, exiting." << std::endl;
0110     gSystem->Exit(1);
0111     exit(1);
0112   }
0113   PHCompositeNode *parNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "PAR"));
0114   if (!parNode)
0115   {
0116     std::cout << Name() << "PAR Node missing, exiting." << std::endl;
0117     gSystem->Exit(1);
0118     exit(1);
0119   }
0120   std::string paramnodename = "G4CELLPARAM_" + m_Detector;
0121 
0122   PHNodeIterator runiter(runNode);
0123   PHCompositeNode *RunDetNode = dynamic_cast<PHCompositeNode *>(runiter.findFirst("PHCompositeNode", m_Detector));
0124   if (!RunDetNode)
0125   {
0126     RunDetNode = new PHCompositeNode(m_Detector);
0127     runNode->addNode(RunDetNode);
0128   }
0129 
0130   PHG4HitContainer *g4hit = findNode::getClass<PHG4HitContainer>(topNode, m_HitNodeName);
0131   if (!g4hit)
0132   {
0133     std::cout << "Could not locate g4 hit node " << m_HitNodeName << std::endl;
0134     exit(1);
0135   }
0136 
0137   auto *hitsetcontainer = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
0138   if (!hitsetcontainer)
0139   {
0140     PHNodeIterator dstiter(dstNode);
0141     PHCompositeNode *DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
0142     if (!DetNode)
0143     {
0144       DetNode = new PHCompositeNode("TRKR");
0145       dstNode->addNode(DetNode);
0146     }
0147 
0148     hitsetcontainer = new TrkrHitSetContainerv1;
0149     PHIODataNode<PHObject> *newNode = new PHIODataNode<PHObject>(hitsetcontainer, "TRKR_HITSET", "PHObject");
0150     DetNode->addNode(newNode);
0151   }
0152 
0153   auto *hittruthassoc = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
0154   if (!hittruthassoc)
0155   {
0156     PHNodeIterator dstiter(dstNode);
0157     PHCompositeNode *DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
0158     if (!DetNode)
0159     {
0160       DetNode = new PHCompositeNode("TRKR");
0161       dstNode->addNode(DetNode);
0162     }
0163 
0164     hittruthassoc = new TrkrHitTruthAssocv1;
0165     PHIODataNode<PHObject> *newNode = new PHIODataNode<PHObject>(hittruthassoc, "TRKR_HITTRUTHASSOC", "PHObject");
0166     DetNode->addNode(newNode);
0167   }
0168 
0169   PHG4CylinderGeomContainer *geo = findNode::getClass<PHG4CylinderGeomContainer>(topNode, m_GeoNodeName);
0170   if (!geo)
0171   {
0172     std::cout << "Could not locate geometry node " << m_GeoNodeName << std::endl;
0173     exit(1);
0174   }
0175 
0176   if (Verbosity() > 0)
0177   {
0178     geo->identify();
0179   }
0180 
0181   UpdateParametersWithMacro();
0182   SaveToNodeTree(RunDetNode, paramnodename);
0183   // save this to the parNode for use
0184   PHNodeIterator parIter(parNode);
0185   PHCompositeNode *ParDetNode = dynamic_cast<PHCompositeNode *>(parIter.findFirst("PHCompositeNode", m_Detector));
0186   if (!ParDetNode)
0187   {
0188     ParDetNode = new PHCompositeNode(m_Detector);
0189     parNode->addNode(ParDetNode);
0190   }
0191   PutOnParNode(ParDetNode, m_GeoNodeName);
0192   m_Tmin = get_double_param("tmin");
0193   m_Tmax = get_double_param("tmax");
0194   m_crossingPeriod = get_double_param("beam_crossing_period");
0195 
0196   // get the nodes for the truth clustering
0197   m_truthtracks = findNode::getClass<TrkrTruthTrackContainer>(topNode, "TRKR_TRUTHTRACKCONTAINER");
0198   if (!m_truthtracks)
0199   {
0200     PHNodeIterator dstiter(dstNode);
0201     m_truthtracks = new TrkrTruthTrackContainerv1();
0202     auto *newNode = new PHIODataNode<PHObject>(m_truthtracks, "TRKR_TRUTHTRACKCONTAINER", "PHObject");
0203     dstNode->addNode(newNode);
0204   }
0205 
0206   m_truthclusters = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_TRUTHCLUSTERCONTAINER");
0207   if (!m_truthclusters)
0208   {
0209     m_truthclusters = new TrkrClusterContainerv4;
0210     auto *newNode = new PHIODataNode<PHObject>(m_truthclusters, "TRKR_TRUTHCLUSTERCONTAINER", "PHObject");
0211     dstNode->addNode(newNode);
0212   }
0213 
0214   m_truthinfo = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
0215   if (!m_truthinfo)
0216   {
0217     std::cout << PHWHERE << " PHG4TruthInfoContainer node not found on node tree" << std::endl;
0218     assert(m_truthinfo);
0219   }
0220 
0221   // get cluster hits verbose (the hit and energy) information
0222   if (record_ClusHitsVerbose)
0223   {
0224     // get the node
0225     mClusHitsVerbose = findNode::getClass<ClusHitsVerbosev1>(topNode, "Trkr_TruthClusHitsVerbose");
0226     if (!mClusHitsVerbose)
0227     {
0228       PHNodeIterator dstiter(dstNode);
0229       auto *DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
0230       if (!DetNode)
0231       {
0232         DetNode = new PHCompositeNode("TRKR");
0233         dstNode->addNode(DetNode);
0234       }
0235       mClusHitsVerbose = new ClusHitsVerbosev1();
0236       auto *newNode = new PHIODataNode<PHObject>(mClusHitsVerbose, "Trkr_TruthClusHitsVerbose", "PHObject");
0237       DetNode->addNode(newNode);
0238     }
0239   }
0240 
0241   //Check for the hot channel map file
0242   bool m_useLocalHitMaskFile = m_localHotStripFileName.empty() ? false : true;
0243   std::string hotStripFile;
0244   if (m_useLocalHitMaskFile)
0245   {
0246     hotStripFile = m_localHotStripFileName;
0247   }
0248   else // use CDB file
0249   {
0250     hotStripFile = std::filesystem::exists(m_hotStripFileName) ? m_hotStripFileName : CDBInterface::instance()->getUrl(m_hotStripFileName);
0251   }
0252 
0253   std::cout << "PHG4InttHitReco::InitRun - Use local hot channel map file: " << m_useLocalHitMaskFile << std::endl
0254             << "PHG4InttHitReco::InitRun - Hot channel map file: " << hotStripFile << std::endl;
0255 
0256   if (std::filesystem::exists(hotStripFile))
0257   {
0258     CDBTTree cdbttree(hotStripFile);
0259     cdbttree.LoadCalibrations();
0260 
0261     m_HotChannelSet.clear();
0262     uint64_t N = cdbttree.GetSingleIntValue("size");
0263     for (uint64_t n = 0; n < N; ++n)
0264     {
0265       //C++ designated initializers only available with -std=c++20
0266       //Just going to build the struct normally
0267       InttNameSpace::RawData_s rawHotChannel;
0268       rawHotChannel.felix_server = cdbttree.GetIntValue(n, "felix_server");
0269       rawHotChannel.felix_channel = cdbttree.GetIntValue(n, "felix_channel");
0270       rawHotChannel.chip = cdbttree.GetIntValue(n, "chip");
0271       rawHotChannel.channel = cdbttree.GetIntValue(n, "channel");
0272 
0273       m_HotChannelSet.insert(rawHotChannel);
0274     }
0275   }
0276 
0277   if (Verbosity() > 0)
0278   {
0279     std::cout<<"INTT simulation BadChannelMap : size = "<<m_HotChannelSet.size()<<"  ";
0280     std::cout<<(( !m_HotChannelSet.empty() ) ? "Hot channel map loaded " : "Hot channel map is not loaded");
0281     std::cout<<std::endl;
0282   }
0283 
0284   return Fun4AllReturnCodes::EVENT_OK;
0285 }
0286 
0287 int PHG4InttHitReco::process_event(PHCompositeNode *topNode)
0288 {
0289   PHG4HitContainer *g4hit = findNode::getClass<PHG4HitContainer>(topNode, m_HitNodeName);
0290   if (!g4hit)
0291   {
0292     std::cout << "Could not locate g4 hit node " << m_HitNodeName << std::endl;
0293     exit(1);
0294   }
0295 
0296   // Get the TrkrHitSetContainer node
0297   auto *hitsetcontainer = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
0298   if (!hitsetcontainer)
0299   {
0300     std::cout << "Could not locate TRKR_HITSET node, quit! " << std::endl;
0301     exit(1);
0302   }
0303 
0304   // Get the TrkrHitTruthAssoc node
0305   auto *hittruthassoc = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
0306   if (!hittruthassoc)
0307   {
0308     std::cout << "Could not locate TRKR_HITTRUTHASSOC node, quit! " << std::endl;
0309     exit(1);
0310   }
0311 
0312   PHG4CylinderGeomContainer *geo = findNode::getClass<PHG4CylinderGeomContainer>(topNode, m_GeoNodeName);
0313   if (!geo)
0314   {
0315     std::cout << "Could not locate geometry node " << m_GeoNodeName << std::endl;
0316     exit(1);
0317   }
0318   // loop over all of the layers in the hit container
0319   // we need the geometry object for this layer
0320   if (Verbosity() > 2)
0321   {
0322     std::cout << " PHG4InttHitReco: Loop over hits" << std::endl;
0323   }
0324   PHG4HitContainer::ConstRange hit_begin_end = g4hit->getHits();
0325 
0326   for (PHG4HitContainer::ConstIterator hiter = hit_begin_end.first; hiter != hit_begin_end.second; ++hiter)
0327   {
0328     const int sphxlayer = hiter->second->get_detid();
0329     CylinderGeomIntt *layergeom = dynamic_cast<CylinderGeomIntt *>(geo->GetLayerGeom(sphxlayer));
0330 
0331     // checking ADC timing integration window cut
0332     // uses default values for now
0333     // these should depend on layer radius
0334     if (hiter->second->get_t(0) > m_Tmax)
0335     {
0336       continue;
0337     }
0338     if (hiter->second->get_t(1) < m_Tmin)
0339     {
0340       continue;
0341     }
0342 
0343     truthcheck_g4hit(hiter->second, topNode);
0344 
0345     float time = (hiter->second->get_t(0) + hiter->second->get_t(1)) / 2.0;
0346 
0347     // I made this (small) diffusion up for now, we will get actual values for the Intt later
0348     double diffusion_width = 5.0e-04;  // diffusion radius 5 microns, in cm
0349 
0350     const int ladder_z_index = hiter->second->get_ladder_z_index();
0351     const int ladder_phi_index = hiter->second->get_ladder_phi_index();
0352 
0353     // What we have is a hit in the sensor. We have not yet assigned the strip(s) that were hit, we do that here
0354     //========================================================================
0355 
0356     // initialize them. In case find_strip_index_values does not set them we can pick this up
0357     int strip_y_index_in = -99999;
0358     int strip_z_index_in = -99999;
0359     int strip_y_index_out = -99999;
0360     int strip_z_index_out = -99999;
0361 
0362     layergeom->find_strip_index_values(ladder_z_index, hiter->second->get_local_y(0), hiter->second->get_local_z(0), strip_y_index_in, strip_z_index_in);
0363     layergeom->find_strip_index_values(ladder_z_index, hiter->second->get_local_y(1), hiter->second->get_local_z(1), strip_y_index_out, strip_z_index_out);
0364     if (strip_y_index_in == -99999 ||
0365         strip_z_index_in == -99999 ||
0366         strip_y_index_out == -99999 ||
0367         strip_z_index_out == -99999)
0368     {
0369       std::cout << "setting of strip indices failed" << std::endl;
0370       std::cout << "strip_y_index_in: " << strip_y_index_in << std::endl;
0371       std::cout << "strip_z_index_in: " << strip_z_index_in << std::endl;
0372       std::cout << "strip_y_index_out: " << strip_y_index_out << std::endl;
0373       std::cout << "strip_z_index_out: " << strip_y_index_out << std::endl;
0374       gSystem->Exit(1);
0375       exit(1);
0376     }
0377     if (Verbosity() > 5)
0378     {
0379       // check to see if we get back the positions from these strip index values
0380       double check_location[3] = {-1, -1, -1};
0381       layergeom->find_strip_center_localcoords(ladder_z_index, strip_y_index_in, strip_z_index_in, check_location);
0382       std::cout << " G4 entry location = " << hiter->second->get_local_x(0) << "  " << hiter->second->get_local_y(0) << "  " << hiter->second->get_local_z(0) << std::endl;
0383       std::cout << " Check entry location = " << check_location[0] << "  " << check_location[1] << "  " << check_location[2] << std::endl;
0384       layergeom->find_strip_center_localcoords(ladder_z_index, strip_y_index_out, strip_z_index_out, check_location);
0385       std::cout << " G4 exit location = " << hiter->second->get_local_x(1) << " " << hiter->second->get_local_y(1) << "  " << hiter->second->get_local_z(1) << std::endl;
0386       std::cout << " Check exit location = " << check_location[0] << "  " << check_location[1] << "  " << check_location[2] << std::endl;
0387     }
0388 
0389     // Now we find how many strips were crossed by this track, and divide the energy between them
0390     int minstrip_z = strip_z_index_in;
0391     int maxstrip_z = strip_z_index_out;
0392     if (minstrip_z > maxstrip_z)
0393     {
0394       std::swap(minstrip_z, maxstrip_z);
0395     }
0396 
0397     int minstrip_y = strip_y_index_in;
0398     int maxstrip_y = strip_y_index_out;
0399     if (minstrip_y > maxstrip_y)
0400     {
0401       std::swap(minstrip_y, maxstrip_y);
0402     }
0403 
0404     // Use an algorithm similar to the one for the MVTX pixels, since it facilitates adding charge diffusion
0405     // for now we assume small charge diffusion
0406     std::vector<int> vybin;
0407     std::vector<int> vzbin;
0408     // std::vector<double> vlen;
0409     std::vector<std::pair<double, double> > venergy;
0410 
0411     //====================================================
0412     // Beginning of charge sharing implementation
0413     //    Find tracklet line inside sensor
0414     //    Divide tracklet line into n segments (vary n until answer stabilizes)
0415     //    Find centroid of each segment
0416     //    Diffuse charge at each centroid
0417     //    Apportion charge between neighboring pixels
0418     //    Add the pixel energy contributions from different track segments together
0419     //====================================================
0420 
0421     // skip this hit if it involves an unreasonable  number of pixels
0422     // this skips it if either the xbin or ybin range traversed is greater than 8 (for 8 adding two pixels at each end makes the range 12)
0423     if (maxstrip_y - minstrip_y > 12 || maxstrip_z - minstrip_z > 12)
0424     {
0425       continue;
0426     }
0427     // this hit is skipped above if this dimensioning would be exceeded
0428     double stripenergy[13][13] = {};  // init to 0
0429     double stripeion[13][13] = {};    // init to 0
0430 
0431     int nsegments = 10;
0432     // Loop over track segments and diffuse charge at each segment location, collect energy in pixels
0433     // Get the entry point of the hit in sensor local coordinates
0434     gsl_vector_set(m_PathVec, 0, hiter->second->get_local_x(0));
0435     gsl_vector_set(m_PathVec, 1, hiter->second->get_local_y(0));
0436     gsl_vector_set(m_PathVec, 2, hiter->second->get_local_z(0));
0437     gsl_vector_set(m_LocalOutVec, 0, hiter->second->get_local_x(1));
0438     gsl_vector_set(m_LocalOutVec, 1, hiter->second->get_local_y(1));
0439     gsl_vector_set(m_LocalOutVec, 2, hiter->second->get_local_z(1));
0440     gsl_vector_sub(m_PathVec, m_LocalOutVec);
0441     for (int i = 0; i < nsegments; i++)
0442     {
0443       // Find the tracklet segment location
0444       // If there are n segments of equal length, we want 2*n intervals
0445       // The 1st segment is centered at interval 1, the 2nd at interval 3, the nth at interval 2n -1
0446       double interval = 2 * (double) i + 1;
0447       double frac = interval / (double) (2 * nsegments);
0448       gsl_vector_memcpy(m_SegmentVec, m_PathVec);
0449       gsl_vector_scale(m_SegmentVec, frac);
0450       gsl_vector_add(m_SegmentVec, m_LocalOutVec);
0451       // Caculate the charge diffusion over this drift distance
0452       // increases from diffusion width_min to diffusion_width_max
0453       double diffusion_radius = diffusion_width;
0454 
0455       if (Verbosity() > 5)
0456       {
0457         std::cout << " segment " << i
0458                   << " interval " << interval
0459                   << " frac " << frac
0460                   << " local_in.X " << hiter->second->get_local_x(0)
0461                   << " local_in.Z " << hiter->second->get_local_z(0)
0462                   << " local_in.Y " << hiter->second->get_local_y(0)
0463                   << " pathvec.X " << gsl_vector_get(m_PathVec, 0)
0464                   << " pathvec.Z " << gsl_vector_get(m_PathVec, 2)
0465                   << " pathvec.Y " << gsl_vector_get(m_PathVec, 1)
0466                   << " segvec.X " << gsl_vector_get(m_SegmentVec, 0)
0467                   << " segvec.Z " << gsl_vector_get(m_SegmentVec, 2)
0468                   << " segvec.Y " << gsl_vector_get(m_SegmentVec, 1) << std::endl
0469                   << " diffusion_radius " << diffusion_radius
0470                   << std::endl;
0471       }
0472 
0473       // Now find the area of overlap of the diffusion circle with each pixel and apportion the energy
0474       for (int iz = minstrip_z; iz <= maxstrip_z; iz++)
0475       {
0476         for (int iy = minstrip_y; iy <= maxstrip_y; iy++)
0477         {
0478           // Find the pixel corners for this pixel number
0479           double location[3] = {-1, -1, -1};
0480           layergeom->find_strip_center_localcoords(ladder_z_index, iy, iz, location);
0481           // note that (y1,z1) is the top left corner, (y2,z2) is the bottom right corner of the pixel - circle_rectangle_intersection expects this ordering
0482           int type = (ladder_z_index == 0 || ladder_z_index == 2) ? 0 : 1; // ladder ID 0 and 2 are type-A (1.6 cm), ladder ID 1 and 3 are type-B (2.0 cm)
0483           double y1 = location[1] - layergeom->get_strip_y_spacing() / 2.0;
0484           double y2 = location[1] + layergeom->get_strip_y_spacing() / 2.0;
0485           double z1 = location[2] + layergeom->get_strip_z_spacing(type) / 2.0;
0486           double z2 = location[2] - layergeom->get_strip_z_spacing(type) / 2.0;
0487 
0488           if (Verbosity() > 5)
0489           {
0490             std::cout << PHWHERE << " ladder_z_index " << ladder_z_index  << " strip size in z (from CylinderGeomIntt) " << fabs(z1 - z2) << " strip size in y (from CylinderGeomIntt) " << fabs(y1 - y2) << std::endl;
0491           }
0492 
0493           // here m_SegmentVec.1 (Y) and m_SegmentVec.2 (Z) are the center of the circle, and diffusion_radius is the circle radius
0494           // circle_rectangle_intersection returns the overlap area of the circle and the pixel. It is very fast if there is no overlap.
0495           double striparea_frac = PHG4Utils::circle_rectangle_intersection(y1, z1, y2, z2, gsl_vector_get(m_SegmentVec, 1), gsl_vector_get(m_SegmentVec, 2), diffusion_radius) / (M_PI * (diffusion_radius * diffusion_radius));
0496           // assume that the energy is deposited uniformly along the tracklet length, so that this segment gets the fraction 1/nsegments of the energy
0497           stripenergy[iy - minstrip_y][iz - minstrip_z] += striparea_frac * hiter->second->get_edep() / (float) nsegments;
0498           if (hiter->second->has_property(PHG4Hit::prop_eion))
0499           {
0500             stripeion[iy - minstrip_y][iz - minstrip_z] += striparea_frac * hiter->second->get_eion() / (float) nsegments;
0501           }
0502           if (Verbosity() > 5)
0503           {
0504             std::cout << "    strip y index " << iy << " strip z index  " << iz
0505                       << " strip area fraction of circle " << striparea_frac << " accumulated pixel energy " << stripenergy[iy - minstrip_y][iz - minstrip_z]
0506                       << std::endl;
0507           }
0508         }
0509       }
0510     }  // end loop over segments
0511     // now we have the energy deposited in each pixel, summed over all tracklet segments. We make a vector of all pixels with non-zero energy deposited
0512 
0513     for (int iz = minstrip_z; iz <= maxstrip_z; iz++)
0514     {
0515       for (int iy = minstrip_y; iy <= maxstrip_y; iy++)
0516       {
0517         if (stripenergy[iy - minstrip_y][iz - minstrip_z] > 0.0)
0518         {
0519           vybin.push_back(iy);
0520           vzbin.push_back(iz);
0521           std::pair<double, double> tmppair = std::make_pair(stripenergy[iy - minstrip_y][iz - minstrip_z], stripeion[iy - minstrip_y][iz - minstrip_z]);
0522           venergy.push_back(tmppair);
0523           if (Verbosity() > 1)
0524           {
0525             std::cout << " Added ybin " << iy << " zbin " << iz << " to vectors with energy " << stripenergy[iy - minstrip_y][iz - minstrip_z] << std::endl;
0526           }
0527         }
0528       }
0529     }
0530 
0531     //===================================
0532     // End of charge sharing implementation
0533     //===================================
0534 
0535     InttNameSpace::RawData_s raw;
0536     InttNameSpace::Offline_s ofl;
0537 
0538     for (unsigned int i1 = 0; i1 < vybin.size(); i1++)  // loop over all fired cells
0539     {
0540       // We add the Intt TrkrHitsets directly to the node using hitsetcontainer
0541 
0542       // Get the hit crossing
0543       int crossing = (int) (round(time / m_crossingPeriod));
0544       // crossing has to fit into 5 bits
0545       crossing = std::max(crossing, -512);
0546       crossing = std::min(crossing, 511);
0547       // We need to create the TrkrHitSet if not already made - each TrkrHitSet should correspond to a sensor for the Intt ?
0548       // The hitset key includes the layer, the ladder_z_index (sensors numbered 0-3) and  ladder_phi_index (azimuthal location of ladder) for this hit
0549       TrkrDefs::hitsetkey hitsetkey = InttDefs::genHitSetKey(sphxlayer, ladder_z_index, ladder_phi_index, crossing);
0550 
0551       // Use existing hitset or add new one if needed
0552       TrkrHitSetContainer::Iterator hitsetit = hitsetcontainer->findOrAddHitSet(hitsetkey);
0553 
0554       // generate the key for this hit
0555       TrkrDefs::hitkey hitkey = InttDefs::genHitKey(vzbin[i1], vybin[i1]);
0556       // See if this hit already exists and is not a raw hit
0557       ofl.layer = sphxlayer;
0558       ofl.ladder_z = ladder_z_index;
0559       ofl.ladder_phi = ladder_phi_index;
0560       ofl.strip_x = vybin[i1]; //vzbin is the col
0561       ofl.strip_y = vzbin[i1]; //vybin is the row
0562       raw = InttNameSpace::ToRawData(ofl);
0563 
0564       double hit_energy = venergy[i1].first * TrkrDefs::InttEnergyScaleup;
0565       addtruthhitset(hitsetkey, hitkey, hit_energy);
0566 
0567       if (m_HotChannelSet.contains(raw))
0568       { //We still want the truth hit
0569         continue;
0570       }
0571 
0572       TrkrHit *hit = hitsetit->second->getHit(hitkey);
0573       if (!hit)
0574       {
0575         // Otherwise, create a new one
0576         hit = new TrkrHitv2();
0577         hitsetit->second->addHitSpecificKey(hitkey, hit);
0578       }
0579 
0580       // Either way, add the energy to it
0581       if (Verbosity() > 2)
0582       {
0583         std::cout << "add energy " << venergy[i1].first << " to intthit " << std::endl;
0584       }
0585 
0586       hit->addEnergy(hit_energy);
0587 
0588       // Add this hit to the association map
0589       hittruthassoc->addAssoc(hitsetkey, hitkey, hiter->first);
0590 
0591       if (Verbosity() > 2)
0592       {
0593         std::cout << "PHG4InttHitReco: added hit wirh hitsetkey " << hitsetkey << " hitkey " << hitkey << " g4hitkey " << hiter->first << " energy " << hit->getEnergy() << std::endl;
0594       }
0595     }
0596   }  // end loop over g4hits
0597 
0598   // print the list of entries in the association table
0599   if (Verbosity() > 0)
0600   {
0601     std::cout << "From PHG4InttHitReco: " << std::endl;
0602     hitsetcontainer->identify();
0603     hittruthassoc->identify();
0604   }
0605 
0606   if (m_is_emb)
0607   {
0608     cluster_truthhits(topNode);  // the last track was truth -- make it's clusters
0609     prior_g4hit = nullptr;
0610   }
0611 
0612   end_event_truthcluster(topNode);
0613   return Fun4AllReturnCodes::EVENT_OK;
0614 }  // end process_event
0615 
0616 void PHG4InttHitReco::SetDefaultParameters()
0617 {
0618   // if we ever need separate timing windows, don't patch around here!
0619   // use PHParameterContainerInterface which
0620   // provides for multiple layers/detector types
0621   set_default_double_param("tmax", 7020.0);  // max upper time window for extended readout
0622   set_default_double_param("tmin", -20.0);   // min lower time window for extended readout
0623   set_default_double_param("beam_crossing_period", sphenix_constants::time_between_crossings);
0624 
0625   return;
0626 }
0627 
0628 void PHG4InttHitReco::truthcheck_g4hit(PHG4Hit *g4hit, PHCompositeNode *topNode)
0629 {
0630   if (g4hit == nullptr)
0631   {
0632     return;
0633   }
0634   int new_trkid = g4hit->get_trkid();
0635 
0636   bool is_new_track = (new_trkid != m_trkid);
0637   if (Verbosity() > 5)
0638   {
0639     std::cout << PHWHERE << std::endl
0640               << " -> Checking status of PHG4Hit. Track id(" << new_trkid << ")" << std::endl;
0641   }
0642   if (!is_new_track)
0643   {
0644     // check to see if it is an embedded track that meets the looper condition:
0645     if (m_is_emb)
0646     {
0647       if (prior_g4hit != nullptr && (std::abs(prior_g4hit->get_x(0) - g4hit->get_x(0)) > max_g4hitstep || std::abs(prior_g4hit->get_y(0) - g4hit->get_y(0)) > max_g4hitstep))
0648       {
0649         // this is a looper track -- cluster hits up to this point already
0650         cluster_truthhits(topNode);
0651       }
0652       prior_g4hit = g4hit;
0653     }
0654     return;
0655   }
0656   // <- STATUS: this is a new track
0657   if (Verbosity() > 2)
0658   {
0659     std::cout << PHWHERE << std::endl
0660               << " -> Found new embedded track with id: " << new_trkid << std::endl;
0661   }
0662   if (m_is_emb)
0663   {
0664     // cluster the old track
0665     cluster_truthhits(topNode);  // cluster m_truth_hits and add m_current_track
0666     m_current_track = nullptr;
0667     prior_g4hit = nullptr;
0668   }
0669   m_trkid = new_trkid;
0670   m_is_emb = m_truthinfo->isEmbeded(m_trkid);
0671   if (m_is_emb)
0672   {
0673     m_current_track = m_truthtracks->getTruthTrack(m_trkid, m_truthinfo);
0674     prior_g4hit = g4hit;
0675   }
0676 }
0677 
0678 void PHG4InttHitReco::end_event_truthcluster(PHCompositeNode *topNode)
0679 {
0680   if (m_is_emb)
0681   {
0682     cluster_truthhits(topNode);  // cluster m_truth_hits and add m_current_track
0683     m_current_track = nullptr;
0684     m_trkid = -1;
0685     m_is_emb = false;
0686   }
0687   m_hitsetkey_cnt.clear();
0688 }
0689 
0690 void PHG4InttHitReco::addtruthhitset(
0691     TrkrDefs::hitsetkey hitsetkey,
0692     TrkrDefs::hitkey hitkey,
0693     float neffelectrons)
0694 {
0695   if (!m_is_emb)
0696   {
0697     return;
0698   }
0699   TrkrHitSetContainer::Iterator hitsetit = m_truth_hits->findOrAddHitSet(hitsetkey);
0700   // See if this hit already exists
0701   TrkrHit *hit = nullptr;
0702   hit = hitsetit->second->getHit(hitkey);
0703   if (!hit)
0704   {
0705     // create a new one
0706     hit = new TrkrHitv2();
0707     hitsetit->second->addHitSpecificKey(hitkey, hit);
0708   }
0709   // Either way, add the energy to it  -- adc values will be added at digitization
0710   hit->addEnergy(neffelectrons);
0711 }
0712 
0713 void PHG4InttHitReco::cluster_truthhits(PHCompositeNode *topNode)
0714 {
0715   // -----------------------------------------------
0716   // Digitize, adapted from g4intt/PHG4InttDigitizer
0717   // -----------------------------------------------
0718   //
0719   // Note: not using digitization, because as currently implemented, the SvtxTrack clusters
0720   // don't use the adc weighting from the digitization code anyway.
0721   //
0722   // don't use the dead map for truth tracks
0723   /* TrkrHitSetContainer::ConstRange hitset_range = m_truth_hits->getHitSets(TrkrDefs::TrkrId::inttId); */
0724   /* for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; */
0725   /*      hitset_iter != hitset_range.second; */
0726   /*      ++hitset_iter) */
0727   /* { */
0728   /*   // we have an itrator to one TrkrHitSet for the intt from the trkrHitSetContainer */
0729   /*   // get the hitset key so we can find the layer */
0730   /*   TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; */
0731   /*   const int layer = TrkrDefs::getLayer(hitsetkey); */
0732   /*   const int ladder_phi = InttDefs::getLadderPhiId(hitsetkey); */
0733   /*   const int ladder_z = InttDefs::getLadderZId(hitsetkey); */
0734 
0735   /*   if (Verbosity() > 1) */
0736   /*   { */
0737   /*     std::cout << "PHG4InttDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << std::endl; */
0738   /*   } */
0739   /*   // get all of the hits from this hitset */
0740   /*   TrkrHitSet *hitset = hitset_iter->second; */
0741   /*   TrkrHitSet::ConstRange hit_range = hitset->getHits(); */
0742   /*   /1* std::set<TrkrDefs::hitkey> dead_hits;  // hits on dead channel *1/ // no dead channels implemented */
0743   /*   for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; */
0744   /*        hit_iter != hit_range.second; */
0745   /*        ++hit_iter) */
0746   /*   { */
0747   /*     // ++m_nCells; // not really used by PHG4InttDigitizer */
0748 
0749   /*     TrkrHit *hit = hit_iter->second; */
0750   /*     TrkrDefs::hitkey hitkey = hit_iter->first; */
0751   /*     int strip_col = InttDefs::getCol(hitkey);  // strip z index */
0752   /*     int strip_row = InttDefs::getRow(hitkey);  // strip phi index */
0753 
0754   /*     // FIXME need energy scales here */
0755   /*     if (_energy_scale.count(layer) > 1) */
0756   /*     { */
0757   /*       assert(!"Error: _energy_scale has two or more keys."); */
0758   /*     } */
0759   /*     const float mip_e = _energy_scale[layer]; */
0760 
0761   /*     std::vector<std::pair<double, double> > vadcrange = _max_fphx_adc[layer]; */
0762 
0763   /*     int adc = 0; */
0764   /*     for (unsigned int irange = 0; irange < vadcrange.size(); ++irange) */
0765   /*     { */
0766   /*       if (hit->getEnergy() / TrkrDefs::InttEnergyScaleup >= vadcrange[irange].first * */
0767   /*           (double) mip_e && hit->getEnergy() / TrkrDefs::InttEnergyScaleup */
0768   /*           < vadcrange[irange].second * (double) mip_e) */
0769   /*       { */
0770   /*         adc = (unsigned short) irange; */
0771   /*       } */
0772   /*     } */
0773   /*     hit->setAdc(adc); */
0774 
0775   /*     if (Verbosity() > 2) */
0776   /*     { */
0777   /*       std::cout << "PHG4InttDigitizer: found hit with layer " << layer << " ladder_z " << ladder_z << " ladder_phi " << ladder_phi */
0778   /*                 << " strip_col " << strip_col << " strip_row " << strip_row << " adc " << hit->getAdc() << std::endl; */
0779   /*     } */
0780   /*   }  // end loop over hits in this hitset */
0781 
0782   /* // remove hits on dead channel in TRKR_HITSET and TRKR_HITTRUTHASSOC */
0783   /* for (const auto &key : dead_hits) */
0784   /* { */
0785   /*   if (Verbosity() > 2) */
0786   /*   { */
0787   /*     std::cout << " PHG4InttDigitizer: remove hit with key: " << key << std::endl; */
0788   /*   } */
0789   /*   hitset->removeHit(key); */
0790   /* } */
0791   /* }  // end loop over hitsets */
0792 
0793   // -----------------------------------------------
0794   // Cluster, adapted from intt/InttClusterizer
0795   // -----------------------------------------------
0796   if (Verbosity() > 1)
0797   {
0798     std::cout << "Clustering truth clusters" << std::endl;
0799   }
0800 
0801   //-----------
0802   // Clustering
0803   //-----------
0804   // get the geometry node
0805   PHG4CylinderGeomContainer *geom_container = findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERGEOM_INTT");
0806   if (!geom_container)
0807   {
0808     return;
0809   }
0810 
0811   // loop over the InttHitSet objects
0812   TrkrHitSetContainer::ConstRange hitsetrange =
0813       m_truth_hits->getHitSets(TrkrDefs::TrkrId::inttId);  // from TruthClusterizerBase
0814 
0815   for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first;
0816        hitsetitr != hitsetrange.second; ++hitsetitr)
0817   {
0818     // Each hitset contains only hits that are clusterizable - i.e. belong to a single sensor
0819     TrkrHitSet *hitset = hitsetitr->second;
0820     TrkrDefs::hitsetkey hitsetkey = hitset->getHitSetKey();
0821 
0822     // cluster this hitset; all pixels in it are, by definition, part of the same clusters
0823 
0824     if (Verbosity() > 1)
0825     {
0826       std::cout << "InttClusterizer found hitsetkey " << hitsetitr->first << std::endl;
0827     }
0828     if (Verbosity() > 2)
0829     {
0830       hitset->identify();
0831     }
0832 
0833     // we have a single hitset, get the info that identifies the sensor
0834 
0835     if (Verbosity() > 2)
0836     {
0837       std::cout << "Filling cluster with hitsetkey " << ((int) hitsetkey) << std::endl;
0838     }
0839 
0840     // get the bunch crossing number from the hitsetkey
0841     /* short int crossing = InttDefs::getTimeBucketId(hitset->getHitSetKey()); */
0842 
0843     // determine the size of the cluster in phi and z, useful for track fitting the cluster
0844     std::set<int> phibins;
0845     std::set<int> zbins;
0846 
0847     // determine the cluster position...
0848     double xlocalsum = 0.0;
0849     double ylocalsum = 0.0;
0850     double zlocalsum = 0.0;
0851     unsigned int clus_adc = 0.0;
0852     unsigned nhits = 0;
0853 
0854     // aggregate the adc values
0855     double sum_adc{0};
0856     TrkrHitSet::ConstRange hitrangei = hitset->getHits();
0857     for (auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit)
0858     {
0859       sum_adc += ihit->second->getAdc();
0860     }
0861 
0862     // tune this energy threshold in the same maner of the MVTX, namely to get the same kind of pixel sizes
0863     // as the SvtxTrack clusters
0864     /* const double threshold = sum_adc * m_truth_pixelthreshold; */
0865     const double threshold = sum_adc * m_pixel_thresholdrat;       // FIXME -- tune this as needed
0866     std::map<int, unsigned int> m_iphi;
0867     std::map<int, unsigned int> m_it;
0868     std::map<int, unsigned int> m_iphiCut;
0869     std::map<int, unsigned int> m_itCut;  // FIXME
0870 
0871     int layer = TrkrDefs::getLayer(hitsetkey);
0872     CylinderGeomIntt *geom = dynamic_cast<CylinderGeomIntt *>(geom_container->GetLayerGeom(layer));
0873 
0874     int ladder_z_index = InttDefs::getLadderZId(hitsetkey);
0875 
0876     for (auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit)
0877     {
0878       int col = InttDefs::getCol(ihit->first);
0879       int row = InttDefs::getRow(ihit->first);
0880       auto adc = ihit->second->getAdc();
0881 
0882       if (mClusHitsVerbose)
0883       {
0884         std::map<int, unsigned int> &m_phi = (adc < threshold) ? m_iphiCut : m_iphi;
0885         std::map<int, unsigned int> &m_z = (adc < threshold) ? m_itCut : m_it;
0886 
0887         auto pnew = m_phi.try_emplace(row, adc);
0888         if (!pnew.second)
0889         {
0890           pnew.first->second += adc;
0891         }
0892 
0893         pnew = m_z.try_emplace(col, adc);
0894         if (!pnew.second)
0895         {
0896           pnew.first->second += adc;
0897         }
0898       }
0899       if (adc < threshold)
0900       {
0901         continue;
0902       }
0903 
0904       clus_adc += adc;
0905       zbins.insert(col);
0906       phibins.insert(row);
0907 
0908       // now get the positions from the geometry
0909       double local_hit_location[3] = {0., 0., 0.};
0910 
0911       geom->find_strip_center_localcoords(ladder_z_index, row, col, local_hit_location); //NOLINT(readability-suspicious-call-argument)
0912 
0913       xlocalsum += local_hit_location[0];
0914       ylocalsum += local_hit_location[1];
0915       zlocalsum += local_hit_location[2];
0916 
0917       ++nhits;
0918 
0919       if (Verbosity() > 6)
0920       {
0921         std::cout << "  From  geometry object: hit x " << local_hit_location[0]
0922                   << " hit y " << local_hit_location[1] << " hit z " << local_hit_location[2] << std::endl;
0923         std::cout << "     nhits " << nhits << " clusx  = " << xlocalsum / nhits << " clusy "
0924                   << ylocalsum / nhits << " clusz " << zlocalsum / nhits << std::endl;
0925       }
0926       // NOTE:
0927       /* if (_make_e_weights[layer]) */  // these values are all false by default
0928       /* if ( false ) // the current implementation of the code does not weight by adc values */
0929       /*              // therefore the default here is to use use adc to cut the outliers and nothing else */
0930       /* { */
0931       /*   xlocalsum += local_hit_location[0] * (double) hit_adc; */
0932       /*   ylocalsum += local_hit_location[1] * (double) hit_adc; */
0933       /*   zlocalsum += local_hit_location[2] * (double) hit_adc; */
0934       /* } */
0935       /* else */
0936       /* { */
0937       /* } */
0938       /* if(hit_adc > clus_maxadc) clus_maxadc = hit_adc; */  // FIXME: do we want this value to be set?
0939       /* clus_energy += hit_adc; */
0940     }
0941     if (mClusHitsVerbose)
0942     {
0943       if (Verbosity() > 10)
0944       {
0945         for (auto &hit : m_iphi)
0946         {
0947           std::cout << " m_phi(" << hit.first << " : " << hit.second << ") " << std::endl;
0948         }
0949       }
0950       for (auto &hit : m_iphi)
0951       {
0952         mClusHitsVerbose->addPhiHit(hit.first, (float) hit.second);
0953       }
0954       for (auto &hit : m_it)
0955       {
0956         mClusHitsVerbose->addZHit(hit.first, (float) hit.second);
0957       }
0958       for (auto &hit : m_iphiCut)
0959       {
0960         mClusHitsVerbose->addPhiCutHit(hit.first, (float) hit.second);
0961       }
0962       for (auto &hit : m_itCut)
0963       {
0964         mClusHitsVerbose->addZCutHit(hit.first, (float) hit.second);
0965       }
0966     }
0967 
0968     // add this cluster-hit association to the association map of (clusterkey,hitkey)
0969     if (Verbosity() > 2)
0970     {
0971       std::cout << "  nhits = " << nhits << std::endl;
0972     }
0973 
0974     /* static const float invsqrt12 = 1./sqrt(12); */
0975     // scale factors (phi direction)
0976     /*
0977        they corresponds to clusters of size 1 and 2 in phi
0978        other clusters, which are very few and pathological, get a scale factor of 1
0979        These scale factors are applied to produce cluster pulls with width unity
0980        */
0981 
0982     /* float phierror = pitch * invsqrt12; */
0983 
0984     /* static constexpr std::array<double, 3> scalefactors_phi = {{ 0.85, 0.4, 0.33 }}; */
0985     /* if( phibins.size() == 1 && layer < 5) phierror*=scalefactors_phi[0]; */
0986     /* else if( phibins.size() == 2 && layer < 5) phierror*=scalefactors_phi[1]; */
0987     /* else if( phibins.size() == 2 && layer > 4) phierror*=scalefactors_phi[2]; */
0988     /* // z error. All clusters have a z-size of 1. */
0989     /* const float zerror = length * invsqrt12; */
0990     if (nhits == 0)
0991     {
0992       continue;
0993     }
0994 
0995     double cluslocaly = ylocalsum / nhits;
0996     double cluslocalz = zlocalsum / nhits;
0997 
0998     // if (_make_e_weights[layer]) // FIXME: this is always false for now
0999     /* { */
1000     /*   cluslocaly = ylocalsum / (double) clus_adc; */
1001     /*   cluslocalz = zlocalsum / (double) clus_adc; */
1002     /* } */
1003     /* else */
1004     /* { */
1005     /* } */
1006     if (m_cluster_version == 4)
1007     {
1008       auto clus = std::make_unique<TrkrClusterv4>();
1009       clus->setAdc(clus_adc);
1010       clus->setPhiSize(phibins.size());
1011       clus->setZSize(1);
1012 
1013       if (Verbosity() > 10)
1014       {
1015         clus->identify();
1016       }
1017 
1018       clus->setLocalX(cluslocaly);
1019       clus->setLocalY(cluslocalz);
1020       // silicon has a 1-1 map between hitsetkey and surfaces. So set to 0
1021       clus->setSubSurfKey(0);
1022 
1023       m_hitsetkey_cnt.try_emplace(hitsetkey, 0);
1024       unsigned int &cnt = m_hitsetkey_cnt[hitsetkey];
1025       TrkrDefs::cluskey ckey = TrkrDefs::genClusKey(hitsetkey, cnt);
1026       m_truthclusters->addClusterSpecifyKey(ckey, clus.release());
1027       m_current_track->addCluster(ckey);
1028       if (mClusHitsVerbose)
1029       {
1030         mClusHitsVerbose->push_hits(ckey);
1031         if (Verbosity() > 10)
1032         {
1033           std::cout << " ClusHitsVerbose.size (in INTT): "
1034                     << mClusHitsVerbose->getMap().size() << std::endl;
1035         }
1036       }
1037       ++cnt;
1038     }  // end loop over hitsets
1039   }
1040 
1041   m_truth_hits->Reset();
1042   prior_g4hit = nullptr;
1043   return;
1044 }