Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:19:18

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