File indexing completed on 2025-06-08 07:53:22
0001
0002
0003
0004
0005
0006 #include <DD4hep/Alignments.h>
0007 #include <DD4hep/DetElement.h>
0008 #include <DD4hep/Handle.h>
0009 #include <DD4hep/Objects.h>
0010 #include <DD4hep/Readout.h>
0011 #include <DD4hep/Segmentations.h>
0012 #include <DD4hep/Shapes.h>
0013 #include <DD4hep/VolumeManager.h>
0014 #include <DD4hep/detail/SegmentationsInterna.h>
0015 #include <DDSegmentation/MultiSegmentation.h>
0016 #include <DDSegmentation/Segmentation.h>
0017 #include <Evaluator/DD4hepUnits.h>
0018 #include <Math/GenVector/Cartesian3D.h>
0019 #include <Math/GenVector/DisplacementVector3D.h>
0020 #include <RtypesCore.h>
0021 #include <TGeoBBox.h>
0022 #include <TGeoMatrix.h>
0023 #include <algorithms/geo.h>
0024 #include <edm4hep/Vector3d.h>
0025 #include <fmt/core.h>
0026 #include <cmath>
0027 #include <gsl/pointers>
0028 #include <set>
0029 #include <stdexcept>
0030 #include <typeinfo>
0031 #include <utility>
0032
0033 #include "DD4hep/Detector.h"
0034 #include "SiliconChargeSharing.h"
0035 #include "algorithms/digi/SiliconChargeSharingConfig.h"
0036
0037 namespace eicrecon {
0038
0039 void SiliconChargeSharing::init() {
0040 m_converter = algorithms::GeoSvc::instance().cellIDPositionConverter();
0041 m_seg = algorithms::GeoSvc::instance().detector()->readout(m_cfg.readout).segmentation();
0042 }
0043
0044 void SiliconChargeSharing::process(const SiliconChargeSharing::Input& input,
0045 const SiliconChargeSharing::Output& output) const {
0046 const auto [simhits] = input;
0047 auto [sharedHits] = output;
0048
0049 for (const auto& hit : *simhits) {
0050
0051 auto cellID = hit.getCellID();
0052
0053 const auto* element = &m_converter->findContext(cellID)->element;
0054
0055
0056 auto [transformIt, transformInserted] =
0057 m_transform_map.try_emplace(element, &element->nominal().worldTransformation());
0058 auto [segmentationIt, segmentationInserted] =
0059 m_segmentation_map.try_emplace(element, getLocalSegmentation(cellID));
0060
0061
0062
0063 try {
0064 dd4hep::Box box = element->solid();
0065 m_xy_range_map.try_emplace(element, box->GetDX(), box->GetDY());
0066 } catch (const std::bad_cast& e) {
0067 error("Failed to cast solid to Box: {}", e.what());
0068 }
0069
0070 auto edep = hit.getEDep();
0071 auto globalHitPos = hit.getPosition();
0072 auto hitPos =
0073 global2Local(dd4hep::Position(globalHitPos.x * dd4hep::mm, globalHitPos.y * dd4hep::mm,
0074 globalHitPos.z * dd4hep::mm),
0075 transformIt->second);
0076
0077 std::unordered_set<dd4hep::rec::CellID> tested_cells;
0078 std::unordered_map<dd4hep::rec::CellID, float> cell_charge;
0079
0080
0081
0082 findAllNeighborsInSensor(cellID, tested_cells, edep, hitPos, segmentationIt->second,
0083 m_xy_range_map[element], hit, sharedHits);
0084
0085 }
0086 }
0087
0088
0089 void SiliconChargeSharing::findAllNeighborsInSensor(
0090 const dd4hep::rec::CellID testCellID, std::unordered_set<dd4hep::rec::CellID>& tested_cells,
0091 const float edep, const dd4hep::Position hitPos,
0092 const dd4hep::DDSegmentation::CartesianGridXY* segmentation,
0093 const std::pair<double, double>& xy_range, const edm4hep::SimTrackerHit& hit,
0094 edm4hep::SimTrackerHitCollection* sharedHits) const {
0095
0096
0097 tested_cells.insert(testCellID);
0098
0099 auto localPos = cell2LocalPosition(testCellID);
0100
0101
0102 if (std::abs(localPos.x()) > xy_range.first || std::abs(localPos.y()) > xy_range.second) {
0103 return;
0104 }
0105
0106
0107 auto xDimension = segmentation->gridSizeX();
0108 auto yDimension = segmentation->gridSizeY();
0109
0110 float edepCell = energyAtCell(xDimension, yDimension, localPos, hitPos, edep);
0111 if (edepCell <= m_cfg.min_edep) {
0112 return;
0113 }
0114
0115
0116 auto globalCellPos = m_converter->position(testCellID);
0117
0118 edm4hep::MutableSimTrackerHit shared_hit = hit.clone();
0119 shared_hit.setCellID(testCellID);
0120 shared_hit.setEDep(edepCell);
0121 shared_hit.setPosition({globalCellPos.x() / dd4hep::mm, globalCellPos.y() / dd4hep::mm,
0122 globalCellPos.z() / dd4hep::mm});
0123 sharedHits->push_back(shared_hit);
0124
0125
0126 std::set<dd4hep::rec::CellID> testCellNeighbours;
0127 segmentation->neighbours(testCellID, testCellNeighbours);
0128
0129 for (const auto& neighbourCell : testCellNeighbours) {
0130 if (tested_cells.find(neighbourCell) == tested_cells.end()) {
0131 findAllNeighborsInSensor(neighbourCell, tested_cells, edep, hitPos, segmentation, xy_range,
0132 hit, sharedHits);
0133 }
0134 }
0135 }
0136
0137
0138 float SiliconChargeSharing::integralGaus(float mean, float sd, float low_lim, float up_lim) {
0139
0140
0141 float up = mean > up_lim ? -0.5 : 0.5;
0142 float low = mean > low_lim ? -0.5 : 0.5;
0143 if (sd > 0) {
0144 up = -0.5 * std::erf(std::sqrt(2) * (mean - up_lim) / sd);
0145 low = -0.5 * std::erf(std::sqrt(2) * (mean - low_lim) / sd);
0146 }
0147 return up - low;
0148 }
0149
0150
0151 dd4hep::Position SiliconChargeSharing::cell2LocalPosition(const dd4hep::rec::CellID& cell) const {
0152 auto position = m_seg->position(cell);
0153 return position;
0154 }
0155
0156
0157 dd4hep::Position SiliconChargeSharing::global2Local(const dd4hep::Position& globalPosition,
0158 const TGeoHMatrix* transform) {
0159
0160 double g[3];
0161 double l[3];
0162
0163 globalPosition.GetCoordinates(static_cast<Double_t*>(g));
0164 transform->MasterToLocal(static_cast<const Double_t*>(g), static_cast<Double_t*>(l));
0165 dd4hep::Position localPosition;
0166 localPosition.SetCoordinates(static_cast<const Double_t*>(l));
0167 return localPosition;
0168 }
0169
0170
0171 float SiliconChargeSharing::energyAtCell(const double xDimension, const double yDimension,
0172 const dd4hep::Position localPos,
0173 const dd4hep::Position hitPos, const float edep) const {
0174 float energy = edep *
0175 integralGaus(hitPos.x(), m_cfg.sigma_sharingx, localPos.x() - 0.5 * xDimension,
0176 localPos.x() + 0.5 * xDimension) *
0177 integralGaus(hitPos.y(), m_cfg.sigma_sharingy, localPos.y() - 0.5 * yDimension,
0178 localPos.y() + 0.5 * yDimension);
0179 return energy;
0180 }
0181
0182
0183 const dd4hep::DDSegmentation::CartesianGridXY*
0184 SiliconChargeSharing::getLocalSegmentation(const dd4hep::rec::CellID& cellID) const {
0185
0186 auto segmentation_type = m_seg.type();
0187 const dd4hep::DDSegmentation::Segmentation* segmentation = m_seg.segmentation();
0188
0189 while (segmentation_type == "MultiSegmentation") {
0190 const auto* multi_segmentation =
0191 dynamic_cast<const dd4hep::DDSegmentation::MultiSegmentation*>(segmentation);
0192 segmentation = &multi_segmentation->subsegmentation(cellID);
0193 segmentation_type = segmentation->type();
0194 }
0195
0196
0197 const auto* cartesianGrid =
0198 dynamic_cast<const dd4hep::DDSegmentation::CartesianGridXY*>(segmentation);
0199 if (cartesianGrid == nullptr) {
0200 throw std::runtime_error("Segmentation is not of type CartesianGridXY");
0201 }
0202
0203 return cartesianGrid;
0204 }
0205
0206 }