Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-01 07:56:24

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2023 - 2025, Simon Gardner
0003 
0004 #include <DD4hep/Handle.h>
0005 #include <DD4hep/IDDescriptor.h>
0006 #include <DD4hep/Objects.h>
0007 #include <DD4hep/Readout.h>
0008 #include <DD4hep/detail/SegmentationsInterna.h>
0009 #include <DDSegmentation/BitFieldCoder.h>
0010 #include <JANA/JException.h>
0011 #include <Math/GenVector/Cartesian3D.h>
0012 #include <Math/GenVector/DisplacementVector3D.h>
0013 #include <ROOT/RVec.hxx>
0014 #include <algorithms/geo.h>
0015 #include <edm4eic/Cov3f.h>
0016 #include <edm4hep/Vector2f.h>
0017 #include <fmt/core.h>
0018 #include <cstddef>
0019 #include <gsl/pointers>
0020 
0021 #include "algorithms/fardetectors/FarDetectorTrackerCluster.h"
0022 #include "algorithms/fardetectors/FarDetectorTrackerClusterConfig.h"
0023 
0024 namespace eicrecon {
0025 
0026 void FarDetectorTrackerCluster::init() {
0027 
0028   m_detector = algorithms::GeoSvc::instance().detector();
0029 
0030   if (m_cfg.readout.empty()) {
0031     throw JException("Readout is empty");
0032   }
0033   try {
0034     m_seg    = m_detector->readout(m_cfg.readout).segmentation();
0035     m_id_dec = m_detector->readout(m_cfg.readout).idSpec().decoder();
0036     if (!m_cfg.x_field.empty()) {
0037       m_x_idx = m_id_dec->index(m_cfg.x_field);
0038       debug("Find layer field {}, index = {}", m_cfg.x_field, m_x_idx);
0039     }
0040     if (!m_cfg.y_field.empty()) {
0041       m_y_idx = m_id_dec->index(m_cfg.y_field);
0042       debug("Find layer field {}, index = {}", m_cfg.y_field, m_y_idx);
0043     }
0044   } catch (...) {
0045     error("Failed to load ID decoder for {}", m_cfg.readout);
0046     throw JException("Failed to load ID decoder");
0047   }
0048 }
0049 
0050 void FarDetectorTrackerCluster::process(const FarDetectorTrackerCluster::Input& input,
0051                                         const FarDetectorTrackerCluster::Output& output) const {
0052 
0053   const auto [inputHitsCollections] = input;
0054   auto [outputClustersCollection]   = output;
0055 
0056   // Loop over input and output collections - Any collection should only contain hits from a single
0057   // surface
0058   for (std::size_t i = 0; i < inputHitsCollections.size(); i++) {
0059     auto inputHits = inputHitsCollections[i];
0060     if (inputHits->empty()) {
0061       continue;
0062     }
0063     auto outputClusters = outputClustersCollection[i];
0064 
0065     // Make clusters
0066     ClusterHits(*inputHits, *outputClusters);
0067   }
0068 }
0069 
0070 // Create vector of Measurement2D from list of hits
0071 void FarDetectorTrackerCluster::ClusterHits(
0072     const edm4eic::TrackerHitCollection& inputHits,
0073     edm4eic::Measurement2DCollection& outputClusters) const {
0074 
0075   ROOT::VecOps::RVec<unsigned long> id;
0076   ROOT::VecOps::RVec<int> x;
0077   ROOT::VecOps::RVec<int> y;
0078   ROOT::VecOps::RVec<float> e;
0079   ROOT::VecOps::RVec<float> t;
0080 
0081   // Gather detector id positions
0082   for (const auto& hit : inputHits) {
0083     auto cellID = hit.getCellID();
0084     id.push_back(cellID);
0085     x.push_back(m_id_dec->get(cellID, m_x_idx));
0086     y.push_back(m_id_dec->get(cellID, m_y_idx));
0087     e.push_back(hit.getEdep());
0088     t.push_back(hit.getTime());
0089   }
0090 
0091   // Set up clustering variables
0092   ROOT::VecOps::RVec<bool> available(id.size(), 1);
0093   auto indices = Enumerate(id);
0094 
0095   // Loop while there are unclustered hits
0096   while (ROOT::VecOps::Any(available)) {
0097 
0098     dd4hep::Position localPos = {0, 0, 0};
0099     float weightSum           = 0;
0100 
0101     float t0      = 0;
0102     auto maxIndex = ROOT::VecOps::ArgMax(e * available);
0103 
0104     available[maxIndex] = 0;
0105 
0106     ROOT::VecOps::RVec<unsigned long> clusterList = {maxIndex};
0107     ROOT::VecOps::RVec<float> clusterT;
0108     ROOT::VecOps::RVec<float> clusterW;
0109 
0110     // Create cluster
0111     auto cluster = outputClusters->create();
0112 
0113     // Loop over hits, adding neighbouring hits as relevant
0114     while (!clusterList.empty()) {
0115 
0116       // Takes first remaining hit in cluster list
0117       auto index = clusterList[0];
0118 
0119       // Finds neighbours of cluster within time limit
0120       auto filter = available * (abs(x - x[index]) <= 1) * (abs(y - y[index]) <= 1) *
0121                     (abs(t - t[index]) < m_cfg.hit_time_limit);
0122 
0123       // Adds the found hits to the cluster
0124       clusterList = Concatenate(clusterList, indices[filter]);
0125 
0126       // Removes the found hits from the list of still available hits
0127       available = available * (!filter);
0128 
0129       // Removes current hit from remaining found cluster hits
0130       clusterList.erase(clusterList.begin());
0131 
0132       // TODO - See if now a single detector element is expected a better function is available.
0133       auto pos = m_seg->position(id[index]);
0134 
0135       // Weighted position
0136       float weight =
0137           e[index]; // TODO - Calculate appropriate weighting based on sensor charge sharing
0138       weightSum += weight;
0139       localPos += pos * weight;
0140 
0141       // Time
0142       clusterT.push_back(t[index]);
0143 
0144       // Adds hit and weight to Measurement2D contribution
0145       cluster.addToHits(inputHits[index]);
0146       clusterW.push_back(e[index]);
0147     }
0148 
0149     // Finalise position
0150     localPos /= weightSum;
0151 
0152     edm4hep::Vector2f xyPos = {static_cast<float>(localPos.x()), static_cast<float>(localPos.y())};
0153 
0154     // Finalise time
0155     t0 = Mean(clusterT);
0156 
0157     // Normalize weights then add to cluster
0158     clusterW /= weightSum;
0159 
0160     for (auto& w : clusterW) {
0161       cluster.addToWeights(w);
0162     }
0163 
0164     edm4eic::Cov3f covariance;
0165 
0166     cluster.setSurface(id[maxIndex]);
0167     cluster.setLoc(xyPos);
0168     cluster.setTime(t0);
0169     cluster.setCovariance(covariance);
0170   }
0171 }
0172 
0173 } // namespace eicrecon