Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-09-27 07:02:58

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2023 - 2024, 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/VolumeManager.h>
0009 #include <DD4hep/detail/SegmentationsInterna.h>
0010 #include <DDSegmentation/BitFieldCoder.h>
0011 #include <Evaluator/DD4hepUnits.h>
0012 #include <JANA/JException.h>
0013 #include <Math/GenVector/Cartesian3D.h>
0014 #include <Math/GenVector/DisplacementVector3D.h>
0015 #include <ROOT/RVec.hxx>
0016 #include <algorithms/geo.h>
0017 #include <edm4hep/Vector3d.h>
0018 #include <fmt/core.h>
0019 #include <gsl/pointers>
0020 #include <sys/types.h>
0021 
0022 #include "algorithms/fardetectors/FarDetectorTrackerCluster.h"
0023 #include "algorithms/fardetectors/FarDetectorTrackerClusterConfig.h"
0024 
0025 namespace eicrecon {
0026 
0027 void FarDetectorTrackerCluster::init() {
0028 
0029   m_detector         = algorithms::GeoSvc::instance().detector();
0030   m_cellid_converter = algorithms::GeoSvc::instance().cellIDPositionConverter();
0031 
0032   if (m_cfg.readout.empty()) {
0033     throw JException("Readout is empty");
0034   }
0035   try {
0036     m_seg    = m_detector->readout(m_cfg.readout).segmentation();
0037     m_id_dec = m_detector->readout(m_cfg.readout).idSpec().decoder();
0038     if (!m_cfg.x_field.empty()) {
0039       m_x_idx = m_id_dec->index(m_cfg.x_field);
0040       debug("Find layer field {}, index = {}", m_cfg.x_field, m_x_idx);
0041     }
0042     if (!m_cfg.y_field.empty()) {
0043       m_y_idx = m_id_dec->index(m_cfg.y_field);
0044       debug("Find layer field {}, index = {}", m_cfg.y_field, m_y_idx);
0045     }
0046   } catch (...) {
0047     error("Failed to load ID decoder for {}", m_cfg.readout);
0048     throw JException("Failed to load ID decoder");
0049   }
0050 }
0051 
0052 void FarDetectorTrackerCluster::process(const FarDetectorTrackerCluster::Input& input,
0053                                         const FarDetectorTrackerCluster::Output& output) const {
0054 
0055   const auto [inputHitsCollections] = input;
0056   auto [outputClustersCollection]   = output;
0057 
0058   // Loop over input and output collections - Any collection should only contain hits from a single
0059   // surface
0060   for (size_t i = 0; i < inputHitsCollections.size(); i++) {
0061     auto inputHits = inputHitsCollections[i];
0062     if (inputHits->size() == 0)
0063       continue;
0064     auto outputClusters = outputClustersCollection[i];
0065 
0066     // Make clusters
0067     auto clusters = ClusterHits(*inputHits);
0068 
0069     // Create TrackerHits from 2D cluster positions
0070     ConvertClusters(clusters, *outputClusters);
0071   }
0072 }
0073 
0074 // Create vector of FDTrackerCluster from list of hits
0075 std::vector<FDTrackerCluster>
0076 FarDetectorTrackerCluster::ClusterHits(const edm4eic::RawTrackerHitCollection& inputHits) const {
0077 
0078   std::vector<FDTrackerCluster> clusters;
0079 
0080   ROOT::VecOps::RVec<unsigned long> id;
0081   ROOT::VecOps::RVec<int> x;
0082   ROOT::VecOps::RVec<int> y;
0083   ROOT::VecOps::RVec<float> e;
0084   ROOT::VecOps::RVec<float> t;
0085 
0086   // Gather detector id positions
0087   for (const auto& hit : inputHits) {
0088     auto cellID = hit.getCellID();
0089     id.push_back(cellID);
0090     x.push_back(m_id_dec->get(cellID, m_x_idx));
0091     y.push_back(m_id_dec->get(cellID, m_y_idx));
0092     e.push_back(hit.getCharge());
0093     t.push_back(hit.getTimeStamp());
0094   }
0095 
0096   // Set up clustering variables
0097   ROOT::VecOps::RVec<bool> available(id.size(), 1);
0098   auto indices = Enumerate(id);
0099 
0100   // Loop while there are unclustered hits
0101   while (ROOT::VecOps::Any(available)) {
0102 
0103     dd4hep::Position localPos = {0, 0, 0};
0104     float weightSum           = 0;
0105 
0106     float esum    = 0;
0107     float t0      = 0;
0108     float tError  = 0;
0109     auto maxIndex = ROOT::VecOps::ArgMax(e * available);
0110 
0111     available[maxIndex] = 0;
0112 
0113     ROOT::VecOps::RVec<unsigned long> clusterList = {maxIndex};
0114     ROOT::VecOps::RVec<float> clusterT;
0115     std::vector<podio::ObjectID> clusterHits;
0116 
0117     // Loop over hits, adding neighbouring hits as relevant
0118     while (clusterList.size()) {
0119 
0120       // Takes first remaining hit in cluster list
0121       auto index = clusterList[0];
0122 
0123       // Finds neighbours of cluster within time limit
0124       auto filter = available * (abs(x - x[index]) <= 1) * (abs(y - y[index]) <= 1) *
0125                     (abs(t - t[index]) < m_cfg.hit_time_limit);
0126 
0127       // Adds the found hits to the cluster
0128       clusterList = Concatenate(clusterList, indices[filter]);
0129 
0130       // Removes the found hits from the list of still available hits
0131       available = available * (!filter);
0132 
0133       // Removes current hit from remaining found cluster hits
0134       clusterList.erase(clusterList.begin());
0135 
0136       // Adds raw hit to TrackerHit contribution
0137       clusterHits.push_back((inputHits)[index].getObjectID());
0138 
0139       // Energy
0140       auto hitE = e[index];
0141       esum += hitE;
0142       // TODO - See if now a single detector element is expected a better function is available.
0143       auto pos = m_seg->position(id[index]);
0144 
0145       // Weighted position
0146       float weight = hitE; // TODO - Calculate appropriate weighting based on sensor charge sharing
0147       weightSum += weight;
0148       localPos += pos * weight;
0149 
0150       // Time
0151       clusterT.push_back(t[index]);
0152     }
0153 
0154     // Finalise position
0155     localPos /= weightSum;
0156 
0157     // Finalise time
0158     t0     = Mean(clusterT);
0159     tError = StdDev(clusterT); // TODO fold detector timing resolution into error
0160 
0161     // Create cluster
0162     clusters.push_back(FDTrackerCluster{.cellID    = id[maxIndex],
0163                                         .x         = localPos.x(),
0164                                         .y         = localPos.y(),
0165                                         .energy    = esum,
0166                                         .time      = t0,
0167                                         .timeError = tError,
0168                                         .rawHits   = clusterHits});
0169   }
0170 
0171   return clusters;
0172 }
0173 
0174 // Convert to global coordinates and create TrackerHits
0175 void FarDetectorTrackerCluster::ConvertClusters(
0176     const std::vector<FDTrackerCluster>& clusters,
0177     edm4hep::TrackerHitCollection& outputClusters) const {
0178 
0179   // Get context of first hit
0180   const dd4hep::VolumeManagerContext* context = m_cellid_converter->findContext(clusters[0].cellID);
0181 
0182   for (auto cluster : clusters) {
0183     auto hitPos = outputClusters.create();
0184 
0185     auto globalPos = context->localToWorld({cluster.x, cluster.y, 0});
0186 
0187     // Set cluster members
0188     hitPos.setCellID(cluster.cellID);
0189     hitPos.setPosition(edm4hep::Vector3d(globalPos.x() / dd4hep::mm, globalPos.y() / dd4hep::mm,
0190                                          globalPos.z() / dd4hep::mm));
0191     hitPos.setEDep(cluster.energy);
0192     hitPos.setTime(cluster.time);
0193 
0194     // Add raw hits to cluster
0195     for (auto hit : cluster.rawHits) {
0196       hitPos.addToRawHits(hit);
0197     }
0198   }
0199 }
0200 
0201 } // namespace eicrecon