File indexing completed on 2025-08-05 08:09:44
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Digitization/DigitizationConfigurator.hpp"
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/TrackParametrization.hpp"
0013 #include "Acts/Surfaces/AnnulusBounds.hpp"
0014 #include "Acts/Surfaces/DiscTrapezoidBounds.hpp"
0015 #include "Acts/Surfaces/RadialBounds.hpp"
0016 #include "Acts/Surfaces/RectangleBounds.hpp"
0017 #include "Acts/Surfaces/Surface.hpp"
0018 #include "Acts/Surfaces/SurfaceBounds.hpp"
0019 #include "Acts/Surfaces/TrapezoidBounds.hpp"
0020 #include "Acts/Utilities/BinUtility.hpp"
0021 #include "Acts/Utilities/BinningType.hpp"
0022 #include "Acts/Utilities/Zip.hpp"
0023 #include "ActsExamples/Digitization/SmearingConfig.hpp"
0024 #include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp"
0025
0026 #include <algorithm>
0027 #include <cmath>
0028 #include <memory>
0029
0030 namespace {
0031
0032
0033
0034 bool digiConfigMaybeEqual(ActsExamples::DigiComponentsConfig &a,
0035 ActsExamples::DigiComponentsConfig &b) {
0036
0037 for (const auto &[as, bs] :
0038 Acts::zip(a.smearingDigiConfig, b.smearingDigiConfig)) {
0039 if (as.index != bs.index) {
0040 return false;
0041 }
0042 }
0043
0044 const auto &ag = a.geometricDigiConfig;
0045 const auto &bg = b.geometricDigiConfig;
0046 return (ag.indices == bg.indices && ag.segmentation == bg.segmentation &&
0047 ag.thickness == bg.thickness && ag.threshold == bg.threshold &&
0048 ag.digital == bg.digital);
0049 }
0050 }
0051
0052 void ActsExamples::DigitizationConfigurator::operator()(
0053 const Acts::Surface *surface) {
0054 if (surface->associatedDetectorElement() != nullptr) {
0055 Acts::GeometryIdentifier geoId = surface->geometryId();
0056 auto dInputConfig = inputDigiComponents.find((geoId));
0057 if (dInputConfig != inputDigiComponents.end()) {
0058
0059 DigiComponentsConfig dOutputConfig;
0060 dOutputConfig.smearingDigiConfig = dInputConfig->smearingDigiConfig;
0061
0062 if (!dInputConfig->geometricDigiConfig.indices.empty()) {
0063
0064 dOutputConfig.geometricDigiConfig.indices =
0065 dInputConfig->geometricDigiConfig.indices;
0066 dOutputConfig.geometricDigiConfig.thickness =
0067 dInputConfig->geometricDigiConfig.thickness;
0068 dOutputConfig.geometricDigiConfig.chargeSmearer =
0069 dInputConfig->geometricDigiConfig.chargeSmearer;
0070 dOutputConfig.geometricDigiConfig.digital =
0071 dInputConfig->geometricDigiConfig.digital;
0072
0073 const Acts::SurfaceBounds &sBounds = surface->bounds();
0074 auto boundValues = sBounds.values();
0075
0076 const auto &inputSegmentation =
0077 dInputConfig->geometricDigiConfig.segmentation;
0078 Acts::BinUtility outputSegmentation;
0079
0080 switch (sBounds.type()) {
0081
0082 case Acts::SurfaceBounds::eRectangle: {
0083 if (inputSegmentation.binningData()[0].binvalue == Acts::binX) {
0084 Acts::ActsScalar minX = boundValues[Acts::RectangleBounds::eMinX];
0085 Acts::ActsScalar maxX = boundValues[Acts::RectangleBounds::eMaxX];
0086 unsigned int nBins = static_cast<unsigned int>(std::round(
0087 (maxX - minX) / inputSegmentation.binningData()[0].step));
0088 outputSegmentation +=
0089 Acts::BinUtility(nBins, minX, maxX, Acts::open, Acts::binX);
0090 }
0091 if (inputSegmentation.binningData()[0].binvalue == Acts::binY ||
0092 inputSegmentation.dimensions() == 2) {
0093 unsigned int accessBin =
0094 inputSegmentation.dimensions() == 2 ? 1 : 0;
0095 Acts::ActsScalar minY = boundValues[Acts::RectangleBounds::eMinY];
0096 Acts::ActsScalar maxY = boundValues[Acts::RectangleBounds::eMaxY];
0097 unsigned int nBins = static_cast<unsigned int>(
0098 std::round((maxY - minY) /
0099 inputSegmentation.binningData()[accessBin].step));
0100 outputSegmentation +=
0101 Acts::BinUtility(nBins, minY, maxY, Acts::open, Acts::binY);
0102 }
0103 } break;
0104
0105
0106 case Acts::SurfaceBounds::eTrapezoid: {
0107 if (inputSegmentation.binningData()[0].binvalue == Acts::binX) {
0108 Acts::ActsScalar maxX = std::max(
0109 boundValues[Acts::TrapezoidBounds::eHalfLengthXnegY],
0110 boundValues[Acts::TrapezoidBounds::eHalfLengthXposY]);
0111 unsigned int nBins = static_cast<unsigned int>(std::round(
0112 2 * maxX / inputSegmentation.binningData()[0].step));
0113 outputSegmentation +=
0114 Acts::BinUtility(nBins, -maxX, maxX, Acts::open, Acts::binX);
0115 }
0116 if (inputSegmentation.binningData()[0].binvalue == Acts::binY ||
0117 inputSegmentation.dimensions() == 2) {
0118 unsigned int accessBin =
0119 inputSegmentation.dimensions() == 2 ? 1 : 0;
0120 Acts::ActsScalar maxY =
0121 boundValues[Acts::TrapezoidBounds::eHalfLengthY];
0122 unsigned int nBins = static_cast<unsigned int>(
0123 std::round((2 * maxY) /
0124 inputSegmentation.binningData()[accessBin].step));
0125 outputSegmentation +=
0126 Acts::BinUtility(nBins, -maxY, maxY, Acts::open, Acts::binY);
0127 }
0128 } break;
0129
0130
0131 case Acts::SurfaceBounds::eAnnulus: {
0132 if (inputSegmentation.binningData()[0].binvalue == Acts::binR) {
0133 Acts::ActsScalar minR = boundValues[Acts::AnnulusBounds::eMinR];
0134 Acts::ActsScalar maxR = boundValues[Acts::AnnulusBounds::eMaxR];
0135 unsigned int nBins = static_cast<unsigned int>(std::round(
0136 (maxR - minR) / inputSegmentation.binningData()[0].step));
0137 outputSegmentation +=
0138 Acts::BinUtility(nBins, minR, maxR, Acts::open, Acts::binR);
0139 }
0140 if (inputSegmentation.binningData()[0].binvalue == Acts::binPhi ||
0141 inputSegmentation.dimensions() == 2) {
0142 unsigned int accessBin =
0143 inputSegmentation.dimensions() == 2 ? 1 : 0;
0144 Acts::ActsScalar averagePhi =
0145 boundValues[Acts::AnnulusBounds::eAveragePhi];
0146 Acts::ActsScalar minPhi =
0147 averagePhi - boundValues[Acts::AnnulusBounds::eMinPhiRel];
0148 Acts::ActsScalar maxPhi =
0149 averagePhi + boundValues[Acts::AnnulusBounds::eMaxPhiRel];
0150 unsigned int nBins = static_cast<unsigned int>(
0151 std::round((maxPhi - minPhi) /
0152 inputSegmentation.binningData()[accessBin].step));
0153 outputSegmentation += Acts::BinUtility(nBins, minPhi, maxPhi,
0154 Acts::open, Acts::binPhi);
0155 }
0156
0157 } break;
0158
0159
0160 case Acts::SurfaceBounds::eDiscTrapezoid: {
0161 Acts::ActsScalar minR =
0162 boundValues[Acts::DiscTrapezoidBounds::eMinR];
0163 Acts::ActsScalar maxR =
0164 boundValues[Acts::DiscTrapezoidBounds::eMaxR];
0165
0166 if (inputSegmentation.binningData()[0].binvalue == Acts::binR) {
0167 unsigned int nBins = static_cast<unsigned int>(std::round(
0168 (maxR - minR) / inputSegmentation.binningData()[0].step));
0169 outputSegmentation +=
0170 Acts::BinUtility(nBins, minR, maxR, Acts::open, Acts::binR);
0171 }
0172 if (inputSegmentation.binningData()[0].binvalue == Acts::binPhi ||
0173 inputSegmentation.dimensions() == 2) {
0174 unsigned int accessBin =
0175 inputSegmentation.dimensions() == 2 ? 1 : 0;
0176 Acts::ActsScalar hxMinR =
0177 boundValues[Acts::DiscTrapezoidBounds::eHalfLengthXminR];
0178 Acts::ActsScalar hxMaxR =
0179 boundValues[Acts::DiscTrapezoidBounds::eHalfLengthXmaxR];
0180
0181 Acts::ActsScalar averagePhi =
0182 boundValues[Acts::DiscTrapezoidBounds::eAveragePhi];
0183 Acts::ActsScalar alphaMinR = std::atan2(minR, hxMinR);
0184 Acts::ActsScalar alphaMaxR = std::atan2(maxR, hxMaxR);
0185 Acts::ActsScalar alpha = std::max(alphaMinR, alphaMaxR);
0186 unsigned int nBins = static_cast<unsigned int>(std::round(
0187 2 * alpha / inputSegmentation.binningData()[accessBin].step));
0188 outputSegmentation += Acts::BinUtility(nBins, averagePhi - alpha,
0189 averagePhi + alpha,
0190 Acts::open, Acts::binPhi);
0191 }
0192
0193 } break;
0194
0195 case Acts::SurfaceBounds::eDisc: {
0196 if (inputSegmentation.binningData()[0].binvalue == Acts::binR) {
0197 Acts::ActsScalar minR = boundValues[Acts::RadialBounds::eMinR];
0198 Acts::ActsScalar maxR = boundValues[Acts::RadialBounds::eMaxR];
0199 unsigned int nBins = static_cast<unsigned int>(std::round(
0200 (maxR - minR) / inputSegmentation.binningData()[0].step));
0201 outputSegmentation +=
0202 Acts::BinUtility(nBins, minR, maxR, Acts::open, Acts::binR);
0203 }
0204 if (inputSegmentation.binningData()[0].binvalue == Acts::binPhi ||
0205 inputSegmentation.dimensions() == 2) {
0206 unsigned int accessBin =
0207 inputSegmentation.dimensions() == 2 ? 1 : 0;
0208
0209 Acts::ActsScalar averagePhi =
0210 boundValues[Acts::RadialBounds::eAveragePhi];
0211 Acts::ActsScalar halfPhiSector =
0212 boundValues[Acts::RadialBounds::eHalfPhiSector];
0213 Acts::ActsScalar minPhi = averagePhi - halfPhiSector;
0214 Acts::ActsScalar maxPhi = averagePhi + halfPhiSector;
0215
0216 unsigned int nBins = static_cast<unsigned int>(
0217 std::round((maxPhi - minPhi) /
0218 inputSegmentation.binningData()[accessBin].step));
0219 outputSegmentation += Acts::BinUtility(nBins, minPhi, maxPhi,
0220 Acts::open, Acts::binPhi);
0221 }
0222
0223 } break;
0224
0225 default:
0226 break;
0227 }
0228
0229 dOutputConfig.geometricDigiConfig.segmentation = outputSegmentation;
0230 }
0231
0232
0233 if (compactify) {
0234
0235
0236 Acts::GeometryIdentifier volGeoId =
0237 Acts::GeometryIdentifier().setVolume(geoId.volume());
0238
0239 auto volRep = volumeLayerComponents.find(volGeoId);
0240 if (volRep != volumeLayerComponents.end() &&
0241 digiConfigMaybeEqual(dOutputConfig, volRep->second)) {
0242
0243 return;
0244 } else {
0245 volumeLayerComponents[volGeoId] = dOutputConfig;
0246 outputDigiComponents.push_back({volGeoId, dOutputConfig});
0247 }
0248
0249
0250 Acts::GeometryIdentifier volLayGeoId =
0251 Acts::GeometryIdentifier(volGeoId).setLayer(geoId.layer());
0252 auto volLayRep = volumeLayerComponents.find(volLayGeoId);
0253
0254 if (volLayRep != volumeLayerComponents.end() &&
0255 digiConfigMaybeEqual(dOutputConfig, volLayRep->second)) {
0256 return;
0257 } else {
0258 volumeLayerComponents[volLayGeoId] = dOutputConfig;
0259 outputDigiComponents.push_back({volLayGeoId, dOutputConfig});
0260 }
0261 }
0262
0263
0264 outputDigiComponents.push_back({geoId, dOutputConfig});
0265 }
0266 }
0267 }