Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:17:54

0001 /**
0002  * @file mvtx/MvtxClusterizer.cc
0003  * @author D. McGlinchey
0004  * @date June 2018
0005  * @brief Implementation of MvtxClusterizer
0006  */
0007 #include "MvtxClusterizer.h"
0008 #include "CylinderGeom_Mvtx.h"
0009 
0010 #include <g4detectors/PHG4CylinderGeom.h>
0011 #include <g4detectors/PHG4CylinderGeomContainer.h>
0012 
0013 #include <trackbase/ClusHitsVerbosev1.h>
0014 #include <trackbase/MvtxDefs.h>
0015 #include <trackbase/TrkrClusterContainerv4.h>
0016 #include <trackbase/TrkrClusterHitAssocv3.h>
0017 #include <trackbase/TrkrClusterv3.h>
0018 #include <trackbase/TrkrClusterv4.h>
0019 #include <trackbase/TrkrClusterv5.h>
0020 #include <trackbase/TrkrDefs.h>  // for hitkey, getLayer
0021 #include <trackbase/TrkrHitSet.h>
0022 #include <trackbase/TrkrHitSetContainer.h>
0023 #include <trackbase/TrkrHitv2.h>
0024 
0025 #include <trackbase/RawHit.h>
0026 #include <trackbase/RawHitSet.h>
0027 #include <trackbase/RawHitSetContainer.h>
0028 
0029 #include <fun4all/Fun4AllReturnCodes.h>
0030 #include <fun4all/SubsysReco.h>  // for SubsysReco
0031 
0032 #include <phool/PHCompositeNode.h>
0033 #include <phool/PHIODataNode.h>
0034 #include <phool/PHNode.h>  // for PHNode
0035 #include <phool/PHNodeIterator.h>
0036 #include <phool/PHObject.h>  // for PHObject
0037 #include <phool/getClass.h>
0038 #include <phool/phool.h>  // for PHWHERE
0039 
0040 #include <TMatrixFfwd.h>    // for TMatrixF
0041 #include <TMatrixT.h>       // for TMatrixT, operator*
0042 #include <TMatrixTUtils.h>  // for TMatrixTRow
0043 #include <TVector3.h>
0044 
0045 #pragma GCC diagnostic push
0046 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
0047 #include <boost/graph/adjacency_list.hpp>
0048 #pragma GCC diagnostic pop
0049 
0050 #include <boost/graph/connected_components.hpp>
0051 
0052 #include <array>
0053 #include <cmath>
0054 #include <cstdlib>  // for exit
0055 #include <iostream>
0056 #include <map>  // for multimap<>::iterator
0057 #include <set>  // for set, set<>::iterator
0058 #include <string>
0059 #include <vector>  // for vector
0060 
0061 namespace
0062 {
0063 
0064   /// convenience square method
0065   template <class T>
0066   inline constexpr T square(const T &x)
0067   {
0068     return x * x;
0069   }
0070 }  // namespace
0071 
0072 bool MvtxClusterizer::are_adjacent(
0073     const std::pair<TrkrDefs::hitkey, TrkrHit *> &lhs,
0074     const std::pair<TrkrDefs::hitkey, TrkrHit *> &rhs)
0075 {
0076   if (GetZClustering())
0077   {
0078     return
0079 
0080       // column adjacent
0081       ( (MvtxDefs::getCol(lhs.first) > MvtxDefs::getCol(rhs.first)) ?
0082       MvtxDefs::getCol(lhs.first)<=MvtxDefs::getCol(rhs.first)+1:
0083       MvtxDefs::getCol(rhs.first)<=MvtxDefs::getCol(lhs.first)+1) &&
0084 
0085       // row adjacent
0086       ( (MvtxDefs::getRow(lhs.first) > MvtxDefs::getRow(rhs.first)) ?
0087       MvtxDefs::getRow(lhs.first)<=MvtxDefs::getRow(rhs.first)+1:
0088       MvtxDefs::getRow(rhs.first)<=MvtxDefs::getRow(lhs.first)+1);
0089 
0090   } else {
0091 
0092     return
0093       // column identical
0094       MvtxDefs::getCol(rhs.first)==MvtxDefs::getCol(lhs.first) &&
0095 
0096       // row adjacent
0097       ( (MvtxDefs::getRow(lhs.first) > MvtxDefs::getRow(rhs.first)) ?
0098       MvtxDefs::getRow(lhs.first)<=MvtxDefs::getRow(rhs.first)+1:
0099       MvtxDefs::getRow(rhs.first)<=MvtxDefs::getRow(lhs.first)+1);
0100 
0101   }
0102 }
0103 
0104 bool MvtxClusterizer::are_adjacent(RawHit *lhs, RawHit *rhs)
0105 {
0106   if (GetZClustering())
0107   {
0108     return
0109 
0110       // phi adjacent (== column)
0111       ((lhs->getPhiBin() > rhs->getPhiBin()) ?
0112       lhs->getPhiBin() <= rhs->getPhiBin()+1:
0113       rhs->getPhiBin() <= lhs->getPhiBin()+1) &&
0114 
0115       // time adjacent (== row)
0116       ((lhs->getTBin() > rhs->getTBin()) ?
0117       lhs->getTBin() <= rhs->getTBin()+1:
0118       rhs->getTBin() <= lhs->getTBin()+1);
0119 
0120   } else {
0121 
0122     return
0123 
0124       // phi identical (== column)
0125       lhs->getPhiBin() == rhs->getPhiBin() &&
0126 
0127       // time adjacent (== row)
0128       ((lhs->getTBin() >  rhs->getTBin()) ?
0129       lhs->getTBin() <= rhs->getTBin()+1:
0130       rhs->getTBin() <= lhs->getTBin()+1);
0131 
0132   }
0133 }
0134 
0135 MvtxClusterizer::MvtxClusterizer(const std::string &name)
0136   : SubsysReco(name)
0137 {
0138 }
0139 
0140 int MvtxClusterizer::InitRun(PHCompositeNode *topNode)
0141 {
0142   //-----------------
0143   // Add Cluster Node
0144   //-----------------
0145 
0146   PHNodeIterator iter(topNode);
0147 
0148   // Looking for the DST node
0149   PHCompositeNode *dstNode =
0150       dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
0151   if (!dstNode)
0152   {
0153     std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl;
0154     return Fun4AllReturnCodes::ABORTRUN;
0155   }
0156   PHNodeIterator iter_dst(dstNode);
0157 
0158   // Create the SVX node if required
0159   PHCompositeNode *svxNode = dynamic_cast<PHCompositeNode *>(
0160       iter_dst.findFirst("PHCompositeNode", "TRKR"));
0161   if (!svxNode)
0162   {
0163     svxNode = new PHCompositeNode("TRKR");
0164     dstNode->addNode(svxNode);
0165   }
0166 
0167   // Create the Cluster node if required
0168   auto trkrclusters =
0169       findNode::getClass<TrkrClusterContainer>(dstNode, "TRKR_CLUSTER");
0170   if (!trkrclusters)
0171   {
0172     PHNodeIterator dstiter(dstNode);
0173     PHCompositeNode *DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
0174     if (!DetNode)
0175     {
0176       DetNode = new PHCompositeNode("TRKR");
0177       dstNode->addNode(DetNode);
0178     }
0179 
0180     trkrclusters = new TrkrClusterContainerv4;
0181     PHIODataNode<PHObject> *TrkrClusterContainerNode =
0182         new PHIODataNode<PHObject>(trkrclusters, "TRKR_CLUSTER", "PHObject");
0183     DetNode->addNode(TrkrClusterContainerNode);
0184   }
0185 
0186   auto clusterhitassoc =
0187       findNode::getClass<TrkrClusterHitAssoc>(topNode, "TRKR_CLUSTERHITASSOC");
0188   if (!clusterhitassoc)
0189   {
0190     PHNodeIterator dstiter(dstNode);
0191     PHCompositeNode *DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
0192     if (!DetNode)
0193     {
0194       DetNode = new PHCompositeNode("TRKR");
0195       dstNode->addNode(DetNode);
0196     }
0197 
0198     clusterhitassoc = new TrkrClusterHitAssocv3;
0199     PHIODataNode<PHObject> *newNode = new PHIODataNode<PHObject>(clusterhitassoc, "TRKR_CLUSTERHITASSOC", "PHObject");
0200     DetNode->addNode(newNode);
0201   }
0202 
0203   // Get the cluster hits verbose node, if required
0204   if (record_ClusHitsVerbose)
0205   {
0206     // get the node
0207     mClusHitsVerbose = findNode::getClass<ClusHitsVerbose>(topNode, "Trkr_SvtxClusHitsVerbose");
0208     if (!mClusHitsVerbose)
0209     {
0210       PHNodeIterator dstiter(dstNode);
0211       auto DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
0212       if (!DetNode)
0213       {
0214         DetNode = new PHCompositeNode("TRKR");
0215         dstNode->addNode(DetNode);
0216       }
0217       mClusHitsVerbose = new ClusHitsVerbosev1();
0218       auto newNode = new PHIODataNode<PHObject>(mClusHitsVerbose, "Trkr_SvtxClusHitsVerbose", "PHObject");
0219       DetNode->addNode(newNode);
0220     }
0221   }
0222 
0223   //----------------
0224   // Report Settings
0225   //----------------
0226 
0227   if (Verbosity() > 0)
0228   {
0229     std::cout << "====================== MvtxClusterizer::InitRun() "
0230             "====================="
0231          << std::endl;
0232     std::cout << " Z-dimension Clustering = " << std::boolalpha << m_makeZClustering
0233          << std::noboolalpha << std::endl;
0234     std::cout << "=================================================================="
0235             "========="
0236          << std::endl;
0237   }
0238 
0239   return Fun4AllReturnCodes::EVENT_OK;
0240 }
0241 
0242 int MvtxClusterizer::process_event(PHCompositeNode *topNode)
0243 {
0244   // get node containing the digitized hits
0245   if (!do_read_raw)
0246   {
0247     m_hits = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
0248     if (!m_hits)
0249     {
0250       std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl;
0251       return Fun4AllReturnCodes::ABORTRUN;
0252     }
0253   }
0254   else
0255   {
0256     // get node containing the digitized hits
0257     m_rawhits =
0258         findNode::getClass<RawHitSetContainer>(topNode, "TRKR_RAWHITSET");
0259     if (!m_rawhits)
0260     {
0261       std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl;
0262       return Fun4AllReturnCodes::ABORTRUN;
0263     }
0264   }
0265 
0266   // get node for clusters
0267   m_clusterlist =
0268       findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
0269   if (!m_clusterlist)
0270   {
0271     std::cout << PHWHERE << " ERROR: Can't find TRKR_CLUSTER." << std::endl;
0272     return Fun4AllReturnCodes::ABORTRUN;
0273   }
0274 
0275   // get node for cluster hit associations
0276   m_clusterhitassoc =
0277       findNode::getClass<TrkrClusterHitAssoc>(topNode, "TRKR_CLUSTERHITASSOC");
0278   if (!m_clusterhitassoc)
0279   {
0280     std::cout << PHWHERE << " ERROR: Can't find TRKR_CLUSTERHITASSOC" << std::endl;
0281     return Fun4AllReturnCodes::ABORTRUN;
0282   }
0283 
0284   // reset MVTX clusters and cluster associations
0285   const auto hitsetkeys = m_clusterlist->getHitSetKeys(TrkrDefs::mvtxId);
0286   for( const auto& hitsetkey:hitsetkeys)
0287   {
0288     m_clusterlist->removeClusters(hitsetkey);
0289     m_clusterhitassoc->removeAssocs(hitsetkey);
0290   }
0291 
0292   // run clustering
0293   if (!do_read_raw)
0294   {
0295     ClusterMvtx(topNode);
0296   }
0297   else
0298   {
0299     ClusterMvtxRaw(topNode);
0300   }
0301   PrintClusters(topNode);
0302 
0303   // done
0304   return Fun4AllReturnCodes::EVENT_OK;
0305 }
0306 
0307 void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode)
0308 {
0309   if (Verbosity() > 0)
0310   {
0311     std::cout << "Entering MvtxClusterizer::ClusterMvtx " << std::endl;
0312   }
0313 
0314   PHG4CylinderGeomContainer *geom_container =
0315       findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERGEOM_MVTX");
0316   if (!geom_container)
0317   {
0318     return;
0319   }
0320 
0321   //-----------
0322   // Clustering
0323   //-----------
0324 
0325   // loop over each MvtxHitSet object (chip)
0326   TrkrHitSetContainer::ConstRange hitsetrange =
0327       m_hits->getHitSets(TrkrDefs::TrkrId::mvtxId);
0328   for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first;
0329        hitsetitr != hitsetrange.second; ++hitsetitr)
0330   {
0331     TrkrHitSet *hitset = hitsetitr->second;
0332 
0333     if (Verbosity() > 0)
0334     {
0335       unsigned int layer = TrkrDefs::getLayer(hitsetitr->first);
0336       unsigned int stave = MvtxDefs::getStaveId(hitsetitr->first);
0337       unsigned int chip = MvtxDefs::getChipId(hitsetitr->first);
0338       unsigned int strobe = MvtxDefs::getStrobeId(hitsetitr->first);
0339       std::cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first
0340            << " layer " << layer << " stave " << stave << " chip " << chip
0341            << " strobe " << strobe << std::endl;
0342     }
0343 
0344     if (Verbosity() > 2)
0345     {
0346       hitset->identify();
0347     }
0348 
0349     // fill a vector of hits to make things easier
0350     std::vector<std::pair<TrkrDefs::hitkey, TrkrHit *> > hitvec;
0351 
0352     TrkrHitSet::ConstRange hitrangei = hitset->getHits();
0353     for (TrkrHitSet::ConstIterator hitr = hitrangei.first;
0354          hitr != hitrangei.second; ++hitr)
0355     {
0356       hitvec.emplace_back(hitr->first, hitr->second);
0357     }
0358     if (Verbosity() > 2)
0359     {
0360       std::cout << "hitvec.size(): " << hitvec.size() << std::endl;
0361     }
0362 
0363     if (Verbosity() > 0)
0364     {
0365       for (auto &hit : hitvec)
0366       {
0367         auto hitkey = hit.first;
0368         auto row = MvtxDefs::getRow(hitkey);
0369         auto col = MvtxDefs::getCol(hitkey);
0370         std::cout << "      hitkey " << hitkey << " row " << row << " col "
0371                   << col << std::endl;
0372       }
0373     }
0374 
0375     // do the clustering
0376     using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS>;
0377     Graph G;
0378 
0379     // loop over hits in this chip
0380     for (unsigned int i = 0; i < hitvec.size(); i++)
0381     {
0382       for (unsigned int j = 0; j < hitvec.size(); j++)
0383       {
0384         if (are_adjacent(hitvec[i], hitvec[j]))
0385         {
0386           add_edge(i, j, G);
0387         }
0388       }
0389     }
0390 
0391     // Find the connections between the vertices of the graph (vertices are the
0392     // rawhits,
0393     // connections are made when they are adjacent to one another)
0394     std::vector<int> component(num_vertices(G));
0395 
0396     // this is the actual clustering, performed by boost
0397     boost::connected_components(G, &component[0]);
0398 
0399     // Loop over the components(hits) compiling a list of the
0400     // unique connected groups (ie. clusters).
0401     std::set<int> cluster_ids;  // unique components
0402     std::multimap<int, std::pair<TrkrDefs::hitkey, TrkrHit *> > clusters;
0403     for (unsigned int i = 0; i < component.size(); i++)
0404     {
0405       cluster_ids.insert(component[i]);
0406       clusters.insert(make_pair(component[i], hitvec[i]));
0407     }
0408     for (const auto& clusid:cluster_ids)
0409     {
0410       auto clusrange = clusters.equal_range(clusid);
0411       auto ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid);
0412 
0413       // determine the size of the cluster in phi and z
0414       std::set<int> phibins;
0415       std::set<int> zbins;
0416       std::map<int, unsigned int> m_phi, m_z;  // Note, there are no "cut" bins for Svtx Clusters
0417 
0418       // determine the cluster position...
0419       double locxsum = 0.;
0420       double loczsum = 0.;
0421       const unsigned int nhits =
0422           std::distance(clusrange.first, clusrange.second);
0423 
0424       double locclusx = std::numeric_limits<double>::quiet_NaN();
0425       double locclusz = std::numeric_limits<double>::quiet_NaN();
0426 
0427       // we need the geometry object for this layer to get the global positions
0428       int layer = TrkrDefs::getLayer(ckey);
0429       auto layergeom = dynamic_cast<CylinderGeom_Mvtx *>(geom_container->GetLayerGeom(layer));
0430       if (!layergeom)
0431       {
0432         exit(1);
0433       }
0434 
0435       for (auto mapiter = clusrange.first; mapiter != clusrange.second;
0436            ++mapiter)
0437       {
0438         // size
0439         const auto energy = (mapiter->second).second->getAdc();
0440         int col = MvtxDefs::getCol((mapiter->second).first);
0441         int row = MvtxDefs::getRow((mapiter->second).first);
0442         zbins.insert(col);
0443         phibins.insert(row);
0444 
0445         if (mClusHitsVerbose)
0446         {
0447           auto pnew = m_phi.try_emplace(row, energy);
0448           if (!pnew.second)
0449           {
0450             pnew.first->second += energy;
0451           }
0452 
0453           pnew = m_z.try_emplace(col, energy);
0454           if (!pnew.second)
0455           {
0456             pnew.first->second += energy;
0457           }
0458         }
0459 
0460         // get local coordinates, in stae reference frame, for hit
0461         auto local_coords = layergeom->get_local_coords_from_pixel(row, col);
0462 
0463         /*
0464           manually offset position along y (thickness of the sensor),
0465           to account for effective hit position in the sensor, resulting from
0466           diffusion.
0467           Effective position corresponds to 1um above the middle of the sensor
0468         */
0469         local_coords.SetY(1e-4);
0470 
0471         // update cluster position
0472         locxsum += local_coords.X();
0473         loczsum += local_coords.Z();
0474         // add the association between this cluster key and this hitkey to the
0475         // table
0476         m_clusterhitassoc->addAssoc(ckey, mapiter->second.first);
0477 
0478       }  // mapiter
0479 
0480       if (mClusHitsVerbose)
0481       {
0482         if (Verbosity() > 10)
0483         {
0484           for (auto &hit : m_phi)
0485           {
0486             std::cout << " m_phi(" << hit.first << " : " << hit.second << ") "
0487                       << std::endl;
0488           }
0489         }
0490         for (auto &hit : m_phi)
0491         {
0492           mClusHitsVerbose->addPhiHit(hit.first, (float) hit.second);
0493         }
0494         for (auto &hit : m_z)
0495         {
0496           mClusHitsVerbose->addZHit(hit.first, (float) hit.second);
0497         }
0498         mClusHitsVerbose->push_hits(ckey);
0499       }
0500 
0501       // This is the local position
0502       locclusx = locxsum / nhits;
0503       locclusz = loczsum / nhits;
0504 
0505       const double pitch = layergeom->get_pixel_x();
0506       const double length = layergeom->get_pixel_z();
0507       const double phisize = phibins.size() * pitch;
0508       const double zsize = zbins.size() * length;
0509 
0510       static const double invsqrt12 = 1. / std::sqrt(12);
0511 
0512       // scale factors (phi direction)
0513       /*
0514         they corresponds to clusters of size (2,2), (2,3), (3,2) and (3,3) in
0515         phi and z
0516         other clusters, which are very few and pathological, get a scale factor
0517         of 1
0518         These scale factors are applied to produce cluster pulls with width
0519         unity
0520       */
0521 
0522       double phierror = pitch * invsqrt12;
0523 
0524       static constexpr std::array<double, 7> scalefactors_phi = {
0525           {0.36, 0.6, 0.37, 0.49, 0.4, 0.37, 0.33}};
0526 
0527       if ((phibins.size() == 1 && zbins.size() == 1) ||
0528           (phibins.size() == 2 && zbins.size() == 2))
0529       {
0530         phierror *= scalefactors_phi[0];
0531       }
0532       else if ((phibins.size() == 2 && zbins.size() == 1) ||
0533                (phibins.size() == 2 && zbins.size() == 3))
0534       {
0535         phierror *= scalefactors_phi[1];
0536       }
0537       else if ((phibins.size() == 1 && zbins.size() == 2) ||
0538                (phibins.size() == 3 && zbins.size() == 2))
0539       {
0540         phierror *= scalefactors_phi[2];
0541       }
0542       else if (phibins.size() == 3 && zbins.size() == 3)
0543       {
0544         phierror *= scalefactors_phi[3];
0545       }
0546 
0547       // scale factors (z direction)
0548       /*
0549         they corresponds to clusters of size (2,2), (2,3), (3,2) and (3,3) in z
0550         and phi
0551         other clusters, which are very few and pathological, get a scale factor
0552         of 1
0553       */
0554       static constexpr std::array<double, 4> scalefactors_z = {
0555           {0.47, 0.48, 0.71, 0.55}};
0556       double zerror = length * invsqrt12;
0557       if (zbins.size() == 2 && phibins.size() == 2)
0558       {
0559         zerror *= scalefactors_z[0];
0560       }
0561       else if (zbins.size() == 2 && phibins.size() == 3)
0562       {
0563         zerror *= scalefactors_z[1];
0564       }
0565       else if (zbins.size() == 3 && phibins.size() == 2)
0566       {
0567         zerror *= scalefactors_z[2];
0568       }
0569       else if (zbins.size() == 3 && phibins.size() == 3)
0570       {
0571         zerror *= scalefactors_z[3];
0572       }
0573 
0574       if (Verbosity() > 0)
0575       {
0576         std::cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer
0577              << " rad " << layergeom->get_radius() << " phibins "
0578              << phibins.size() << " pitch " << pitch << " phisize " << phisize
0579              << " zbins " << zbins.size() << " length " << length << " zsize "
0580              << zsize << " local x " << locclusx << " local y " << locclusz
0581              << std::endl;
0582       }
0583 
0584       auto clus = std::make_unique<TrkrClusterv5>();
0585       clus->setAdc(nhits);
0586       clus->setMaxAdc(1);
0587       clus->setLocalX(locclusx);
0588       clus->setLocalY(locclusz);
0589       clus->setPhiError(phierror);
0590       clus->setZError(zerror);
0591       clus->setPhiSize(phibins.size());
0592       clus->setZSize(zbins.size());
0593       // All silicon surfaces have a 1-1 map to hitsetkey.
0594       // So set subsurface key to 0
0595       clus->setSubSurfKey(0);
0596 
0597       if (Verbosity() > 2)
0598       {
0599         clus->identify();
0600       }
0601 
0602       if (zbins.size() <= 127)
0603       {
0604         m_clusterlist->addClusterSpecifyKey(ckey, clus.release());
0605       }
0606 
0607     }  // clusitr loop
0608   }    // loop over hitsets
0609 
0610   if (Verbosity() > 1)
0611   {
0612     // check that the associations were written correctly
0613     m_clusterhitassoc->identify();
0614   }
0615 
0616   return;
0617 }
0618 
0619 void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode)
0620 {
0621   if (Verbosity() > 0)
0622   {
0623     std::cout << "Entering MvtxClusterizer::ClusterMvtx " << std::endl;
0624   }
0625 
0626   PHG4CylinderGeomContainer *geom_container =
0627       findNode::getClass<PHG4CylinderGeomContainer>(topNode,
0628                                                     "CYLINDERGEOM_MVTX");
0629   if (!geom_container)
0630   {
0631     return;
0632   }
0633 
0634   //-----------
0635   // Clustering
0636   //-----------
0637 
0638   // loop over each MvtxHitSet object (chip)
0639   RawHitSetContainer::ConstRange hitsetrange =
0640       m_rawhits->getHitSets(TrkrDefs::TrkrId::mvtxId);
0641   for (RawHitSetContainer::ConstIterator hitsetitr = hitsetrange.first;
0642        hitsetitr != hitsetrange.second; ++hitsetitr)
0643   {
0644     RawHitSet *hitset = hitsetitr->second;
0645 
0646     if (Verbosity() > 0)
0647     {
0648       unsigned int layer = TrkrDefs::getLayer(hitsetitr->first);
0649       unsigned int stave = MvtxDefs::getStaveId(hitsetitr->first);
0650       unsigned int chip = MvtxDefs::getChipId(hitsetitr->first);
0651       unsigned int strobe = MvtxDefs::getStrobeId(hitsetitr->first);
0652       std::cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first
0653            << " layer " << layer << " stave " << stave << " chip " << chip
0654            << " strobe " << strobe << std::endl;
0655     }
0656 
0657     if (Verbosity() > 2)
0658     {
0659       hitset->identify();
0660     }
0661 
0662     // fill a vector of hits to make things easier
0663     std::vector<RawHit *> hitvec;
0664 
0665     RawHitSet::ConstRange hitrangei = hitset->getHits();
0666     for (RawHitSet::ConstIterator hitr = hitrangei.first;
0667          hitr != hitrangei.second; ++hitr)
0668     {
0669       hitvec.push_back((*hitr));
0670     }
0671     if (Verbosity() > 2)
0672     {
0673       std::cout << "hitvec.size(): " << hitvec.size() << std::endl;
0674     }
0675 
0676     // do the clustering
0677     using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS>;
0678     Graph G;
0679 
0680     // loop over hits in this chip
0681     for (unsigned int i = 0; i < hitvec.size(); i++)
0682     {
0683       for (unsigned int j = 0; j < hitvec.size(); j++)
0684       {
0685         if (are_adjacent(hitvec[i], hitvec[j]))
0686         {
0687           add_edge(i, j, G);
0688         }
0689       }
0690     }
0691 
0692     // Find the connections between the vertices of the graph (vertices are the
0693     // rawhits,
0694     // connections are made when they are adjacent to one another)
0695     std::vector<int> component(num_vertices(G));
0696 
0697     // this is the actual clustering, performed by boost
0698     boost::connected_components(G, &component[0]);
0699 
0700     // Loop over the components(hits) compiling a list of the
0701     // unique connected groups (ie. clusters).
0702     std::set<int> cluster_ids;  // unique components
0703 
0704     std::multimap<int, RawHit *> clusters;
0705     for (unsigned int i = 0; i < component.size(); i++)
0706     {
0707       cluster_ids.insert(component[i]);
0708       clusters.emplace(component[i], hitvec[i]);
0709     }
0710     //    std::cout << "found cluster #: "<< clusters.size()<< std::endl;
0711     // loop over the componenets and make clusters
0712     for( const auto& clusid:cluster_ids)
0713     {
0714       auto clusrange = clusters.equal_range(clusid);
0715 
0716       // make the cluster directly in the node tree
0717       auto ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid);
0718 
0719       // determine the size of the cluster in phi and z
0720       std::set<int> phibins;
0721       std::set<int> zbins;
0722 
0723       // determine the cluster position...
0724       double locxsum = 0.;
0725       double loczsum = 0.;
0726       const unsigned int nhits =
0727           std::distance(clusrange.first, clusrange.second);
0728 
0729       double locclusx = NAN;
0730       double locclusz = NAN;
0731 
0732       // we need the geometry object for this layer to get the global positions
0733       int layer = TrkrDefs::getLayer(ckey);
0734       auto layergeom = dynamic_cast<CylinderGeom_Mvtx *>(
0735           geom_container->GetLayerGeom(layer));
0736       if (!layergeom)
0737       {
0738         exit(1);
0739       }
0740 
0741       for (auto mapiter = clusrange.first; mapiter != clusrange.second;
0742            ++mapiter)
0743       {
0744         // size
0745         int col = (mapiter->second)->getPhiBin();
0746         int row = (mapiter->second)->getTBin();
0747         zbins.insert(col);
0748         phibins.insert(row);
0749 
0750         // get local coordinates, in stae reference frame, for hit
0751         auto local_coords = layergeom->get_local_coords_from_pixel(row, col);
0752 
0753         /*
0754           manually offset position along y (thickness of the sensor),
0755           to account for effective hit position in the sensor, resulting from
0756           diffusion.
0757           Effective position corresponds to 1um above the middle of the sensor
0758         */
0759         local_coords.SetY(1e-4);
0760 
0761         // update cluster position
0762         locxsum += local_coords.X();
0763         loczsum += local_coords.Z();
0764         // add the association between this cluster key and this hitkey to the
0765         // table
0766         //        m_clusterhitassoc->addAssoc(ckey, mapiter->second.first);
0767 
0768       }  // mapiter
0769 
0770       // This is the local position
0771       locclusx = locxsum / nhits;
0772       locclusz = loczsum / nhits;
0773 
0774       const double pitch = layergeom->get_pixel_x();
0775       //    std::cout << " pitch: " <<  pitch << std::endl;
0776       const double length = layergeom->get_pixel_z();
0777       //    std::cout << " length: " << length << std::endl;
0778       const double phisize = phibins.size() * pitch;
0779       const double zsize = zbins.size() * length;
0780 
0781       static const double invsqrt12 = 1. / std::sqrt(12);
0782 
0783       // scale factors (phi direction)
0784       /*
0785         they corresponds to clusters of size (2,2), (2,3), (3,2) and (3,3) in
0786         phi and z
0787         other clusters, which are very few and pathological, get a scale factor
0788         of 1
0789         These scale factors are applied to produce cluster pulls with width
0790         unity
0791       */
0792 
0793       double phierror = pitch * invsqrt12;
0794 
0795       static constexpr std::array<double, 7> scalefactors_phi = {
0796           {0.36, 0.6, 0.37, 0.49, 0.4, 0.37, 0.33}};
0797       if ((phibins.size() == 1 && zbins.size() == 1) ||
0798           (phibins.size() == 2 && zbins.size() == 2))
0799       {
0800         phierror *= scalefactors_phi[0];
0801       }
0802       else if ((phibins.size() == 2 && zbins.size() == 1) ||
0803                (phibins.size() == 2 && zbins.size() == 3))
0804       {
0805         phierror *= scalefactors_phi[1];
0806       }
0807       else if ((phibins.size() == 1 && zbins.size() == 2) ||
0808                (phibins.size() == 3 && zbins.size() == 2))
0809       {
0810         phierror *= scalefactors_phi[2];
0811       }
0812       else if (phibins.size() == 3 && zbins.size() == 3)
0813       {
0814         phierror *= scalefactors_phi[3];
0815       }
0816 
0817       // scale factors (z direction)
0818       /*
0819         they corresponds to clusters of size (2,2), (2,3), (3,2) and (3,3) in z
0820         and phi
0821         other clusters, which are very few and pathological, get a scale factor
0822         of 1
0823       */
0824       static constexpr std::array<double, 4> scalefactors_z = {
0825           {0.47, 0.48, 0.71, 0.55}};
0826       double zerror = length * invsqrt12;
0827 
0828       if (zbins.size() == 2 && phibins.size() == 2)
0829       {
0830         zerror *= scalefactors_z[0];
0831       }
0832       else if (zbins.size() == 2 && phibins.size() == 3)
0833       {
0834         zerror *= scalefactors_z[1];
0835       }
0836       else if (zbins.size() == 3 && phibins.size() == 2)
0837       {
0838         zerror *= scalefactors_z[2];
0839       }
0840       else if (zbins.size() == 3 && phibins.size() == 3)
0841       {
0842         zerror *= scalefactors_z[3];
0843       }
0844 
0845       if (Verbosity() > 0)
0846       {
0847         std::cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer
0848              << " rad " << layergeom->get_radius() << " phibins "
0849              << phibins.size() << " pitch " << pitch << " phisize " << phisize
0850              << " zbins " << zbins.size() << " length " << length << " zsize "
0851              << zsize << " local x " << locclusx << " local y " << locclusz
0852              << std::endl;
0853       }
0854 
0855       auto clus = std::make_unique<TrkrClusterv5>();
0856       clus->setAdc(nhits);
0857       clus->setMaxAdc(1);
0858       clus->setLocalX(locclusx);
0859       clus->setLocalY(locclusz);
0860       clus->setPhiError(phierror);
0861       clus->setZError(zerror);
0862       clus->setPhiSize(phibins.size());
0863       clus->setZSize(zbins.size());
0864       // All silicon surfaces have a 1-1 map to hitsetkey.
0865       // So set subsurface key to 0
0866       clus->setSubSurfKey(0);
0867 
0868       if (Verbosity() > 2)
0869       {
0870         clus->identify();
0871       }
0872 
0873       if (zbins.size() <= 127)
0874       {
0875         m_clusterlist->addClusterSpecifyKey(ckey, clus.release());
0876       }
0877     }  // clusitr loop
0878   }    // loop over hitsets
0879 
0880   if (Verbosity() > 1)
0881   {
0882     // check that the associations were written correctly
0883     m_clusterhitassoc->identify();
0884   }
0885 
0886   return;
0887 }
0888 
0889 void MvtxClusterizer::PrintClusters(PHCompositeNode *topNode)
0890 {
0891   if (Verbosity() > 0)
0892   {
0893     TrkrClusterContainer *clusterlist =
0894         findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
0895     if (!clusterlist)
0896     {
0897       return;
0898     }
0899 
0900     std::cout << "================= After MvtxClusterizer::process_event() "
0901             "===================="
0902          << std::endl;
0903 
0904     std::cout << " There are " << clusterlist->size()
0905          << " clusters recorded: " << std::endl;
0906 
0907     if (Verbosity() > 3)
0908     {
0909       clusterlist->identify();
0910     }
0911 
0912     std::cout << "=================================================================="
0913             "========="
0914          << std::endl;
0915   }
0916 
0917   return;
0918 }