File indexing completed on 2026-11-11 09:33:56
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Io/Root/RootAthenaDumpReader.hpp"
0010
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "Acts/EventData/SourceLink.hpp"
0013 #include "Acts/Geometry/GeometryIdentifier.hpp"
0014 #include "Acts/Geometry/TrackingGeometry.hpp"
0015 #include "Acts/Utilities/Zip.hpp"
0016 #include "ActsExamples/Digitization/MeasurementCreation.hpp"
0017 #include "ActsExamples/EventData/Cluster.hpp"
0018 #include "ActsExamples/EventData/IndexSourceLink.hpp"
0019 #include "ActsExamples/EventData/SimParticle.hpp"
0020 #include "ActsExamples/EventData/SpacePoint.hpp"
0021
0022 #include <algorithm>
0023 #include <numeric>
0024
0025 #include <TChain.h>
0026 #include <boost/container/static_vector.hpp>
0027
0028 using namespace Acts::UnitLiterals;
0029
0030 namespace ActsExamples {
0031
0032 namespace {
0033
0034
0035
0036
0037 inline auto particleVectorToSet(std::vector<SimParticle>& particles) {
0038 using namespace ActsExamples;
0039 auto cmp = [](const auto& a, const auto& b) {
0040 return a.particleId() == b.particleId();
0041 };
0042
0043 std::ranges::sort(particles, detail::CompareParticleId{});
0044 particles.erase(std::unique(particles.begin(), particles.end(), cmp),
0045 particles.end());
0046
0047 return SimParticleContainer(boost::container::ordered_unique_range_t{},
0048 particles.begin(), particles.end());
0049 }
0050
0051 }
0052
0053 enum SpacePointType { ePixel = 1, eStrip = 2 };
0054
0055 RootAthenaDumpReader::RootAthenaDumpReader(
0056 const RootAthenaDumpReader::Config& config, Acts::Logging::Level level)
0057 : IReader(),
0058 m_cfg(config),
0059 m_logger(Acts::getDefaultLogger(name(), level)) {
0060 if (m_cfg.inputfiles.empty()) {
0061 throw std::invalid_argument("Empty input file list");
0062 }
0063 if (m_cfg.treename.empty()) {
0064 throw std::invalid_argument("Missing tree name");
0065 }
0066
0067 m_inputchain = std::make_shared<TChain>(m_cfg.treename.c_str());
0068
0069 m_outputPixelSpacePoints.initialize(m_cfg.outputPixelSpacePoints);
0070 m_outputStripSpacePoints.initialize(m_cfg.outputStripSpacePoints);
0071 m_outputSpacePoints.initialize(m_cfg.outputSpacePoints);
0072 if (!m_cfg.onlySpacePoints) {
0073 m_outputMeasurements.initialize(m_cfg.outputMeasurements);
0074 m_outputMeasurementSubset.initialize(m_cfg.outputMeasurementSubset);
0075 m_outputClusters.initialize(m_cfg.outputClusters);
0076 if (!m_cfg.noTruth) {
0077 m_outputParticles.initialize(m_cfg.outputParticles);
0078 m_outputMeasParticleMap.initialize(m_cfg.outputMeasurementParticlesMap);
0079 m_outputParticleMeasMap.initialize(m_cfg.outputParticleMeasurementsMap);
0080 }
0081 }
0082
0083 if (m_inputchain->GetBranch("SPtopStripDirection") == nullptr) {
0084 ACTS_INFO("Additional SP strip features not available");
0085 m_haveStripFeatures = false;
0086 }
0087
0088 if (m_inputchain->GetBranch("CLetas") == nullptr) {
0089 ACTS_INFO("Cluster cell data (CLetas/CLphis/CLtots) not available");
0090 m_haveCellData = false;
0091 }
0092
0093
0094 m_inputchain->SetBranchAddress("run_number", &run_number);
0095 m_inputchain->SetBranchAddress("event_number", &event_number);
0096 m_inputchain->SetBranchAddress("nSE", &nSE);
0097 m_inputchain->SetBranchAddress("SEID", SEID);
0098
0099
0100 m_inputchain->SetBranchAddress("nCL", &nCL);
0101 m_inputchain->SetBranchAddress("CLindex", CLindex);
0102 m_inputchain->SetBranchAddress("CLhardware", &CLhardware.get());
0103 m_inputchain->SetBranchAddress("CLx", CLx);
0104 m_inputchain->SetBranchAddress("CLy", CLy);
0105 m_inputchain->SetBranchAddress("CLz", CLz);
0106 m_inputchain->SetBranchAddress("CLbarrel_endcap", CLbarrel_endcap);
0107 m_inputchain->SetBranchAddress("CLlayer_disk", CLlayer_disk);
0108 m_inputchain->SetBranchAddress("CLeta_module", CLeta_module);
0109 m_inputchain->SetBranchAddress("CLphi_module", CLphi_module);
0110 m_inputchain->SetBranchAddress("CLside", CLside);
0111 m_inputchain->SetBranchAddress("CLmoduleID", CLmoduleID);
0112 if (m_haveCellData) {
0113 m_inputchain->SetBranchAddress("CLphis", &CLphis.get());
0114 m_inputchain->SetBranchAddress("CLetas", &CLetas.get());
0115 m_inputchain->SetBranchAddress("CLtots", &CLtots.get());
0116 }
0117 m_inputchain->SetBranchAddress("CLloc_direction1", CLloc_direction1);
0118 m_inputchain->SetBranchAddress("CLloc_direction2", CLloc_direction2);
0119 m_inputchain->SetBranchAddress("CLloc_direction3", CLloc_direction3);
0120 m_inputchain->SetBranchAddress("CLJan_loc_direction1", CLJan_loc_direction1);
0121 m_inputchain->SetBranchAddress("CLJan_loc_direction2", CLJan_loc_direction2);
0122 m_inputchain->SetBranchAddress("CLJan_loc_direction3", CLJan_loc_direction3);
0123 m_inputchain->SetBranchAddress("CLpixel_count", CLpixel_count);
0124 m_inputchain->SetBranchAddress("CLcharge_count", CLcharge_count);
0125 m_inputchain->SetBranchAddress("CLloc_eta", CLloc_eta);
0126 m_inputchain->SetBranchAddress("CLloc_phi", CLloc_phi);
0127 m_inputchain->SetBranchAddress("CLglob_eta", CLglob_eta);
0128 m_inputchain->SetBranchAddress("CLglob_phi", CLglob_phi);
0129 m_inputchain->SetBranchAddress("CLeta_angle", CLeta_angle);
0130 m_inputchain->SetBranchAddress("CLphi_angle", CLphi_angle);
0131 m_inputchain->SetBranchAddress("CLnorm_x", CLnorm_x);
0132 m_inputchain->SetBranchAddress("CLnorm_y", CLnorm_y);
0133 m_inputchain->SetBranchAddress("CLnorm_z", CLnorm_z);
0134 m_inputchain->SetBranchAddress("CLlocal_cov", &CLlocal_cov.get());
0135 if (!m_cfg.noTruth) {
0136 m_inputchain->SetBranchAddress("CLparticleLink_eventIndex",
0137 &CLparticleLink_eventIndex.get());
0138 m_inputchain->SetBranchAddress("CLparticleLink_barcode",
0139 &CLparticleLink_barcode.get());
0140 m_inputchain->SetBranchAddress("CLbarcodesLinked", &CLbarcodesLinked.get());
0141 m_inputchain->SetBranchAddress("CLparticle_charge",
0142 &CLparticle_charge.get());
0143 }
0144
0145
0146 if (!m_cfg.noTruth) {
0147 m_inputchain->SetBranchAddress("nPartEVT", &nPartEVT);
0148 m_inputchain->SetBranchAddress("Part_event_number", Part_event_number);
0149 m_inputchain->SetBranchAddress("Part_barcode", Part_barcode);
0150 m_inputchain->SetBranchAddress("Part_px", Part_px);
0151 m_inputchain->SetBranchAddress("Part_py", Part_py);
0152 m_inputchain->SetBranchAddress("Part_pz", Part_pz);
0153 m_inputchain->SetBranchAddress("Part_pt", Part_pt);
0154 m_inputchain->SetBranchAddress("Part_eta", Part_eta);
0155 m_inputchain->SetBranchAddress("Part_vx", Part_vx);
0156 m_inputchain->SetBranchAddress("Part_vy", Part_vy);
0157 m_inputchain->SetBranchAddress("Part_vz", Part_vz);
0158 m_inputchain->SetBranchAddress("Part_radius", Part_radius);
0159 m_inputchain->SetBranchAddress("Part_status", Part_status);
0160 m_inputchain->SetBranchAddress("Part_charge", Part_charge);
0161 m_inputchain->SetBranchAddress("Part_pdg_id", Part_pdg_id);
0162 m_inputchain->SetBranchAddress("Part_passed", Part_passed);
0163 m_inputchain->SetBranchAddress("Part_vProdNin", Part_vProdNin);
0164 m_inputchain->SetBranchAddress("Part_vProdNout", Part_vProdNout);
0165 m_inputchain->SetBranchAddress("Part_vProdStatus", Part_vProdStatus);
0166 m_inputchain->SetBranchAddress("Part_vProdBarcode", Part_vProdBarcode);
0167 m_inputchain->SetBranchAddress("Part_vParentID", &Part_vParentID.get());
0168 m_inputchain->SetBranchAddress("Part_vParentBarcode",
0169 &Part_vParentBarcode.get());
0170 }
0171
0172
0173 m_inputchain->SetBranchAddress("nSP", &nSP);
0174 m_inputchain->SetBranchAddress("SPindex", SPindex);
0175 m_inputchain->SetBranchAddress("SPx", SPx);
0176 m_inputchain->SetBranchAddress("SPy", SPy);
0177 m_inputchain->SetBranchAddress("SPz", SPz);
0178 m_inputchain->SetBranchAddress("SPCL1_index", SPCL1_index);
0179 m_inputchain->SetBranchAddress("SPCL2_index", SPCL2_index);
0180 m_inputchain->SetBranchAddress("SPisOverlap", SPisOverlap);
0181 if (m_haveStripFeatures) {
0182 m_inputchain->SetBranchAddress("SPradius", SPradius);
0183 m_inputchain->SetBranchAddress("SPcovr", SPcovr);
0184 m_inputchain->SetBranchAddress("SPcovz", SPcovz);
0185 m_inputchain->SetBranchAddress("SPhl_topstrip", SPhl_topstrip);
0186 m_inputchain->SetBranchAddress("SPhl_botstrip", SPhl_botstrip);
0187 m_inputchain->SetBranchAddress("SPtopStripDirection",
0188 &SPtopStripDirection.get());
0189 m_inputchain->SetBranchAddress("SPbottomStripDirection",
0190 &SPbottomStripDirection.get());
0191 m_inputchain->SetBranchAddress("SPstripCenterDistance",
0192 &SPstripCenterDistance.get());
0193 m_inputchain->SetBranchAddress("SPtopStripCenterPosition",
0194 &SPtopStripCenterPosition.get());
0195 }
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237 for (const auto& file : m_cfg.inputfiles) {
0238 ACTS_DEBUG("Adding file '" << file << "' to tree " << m_cfg.treename);
0239 m_inputchain->Add(file.c_str());
0240 }
0241
0242 m_events = m_inputchain->GetEntries();
0243
0244 ACTS_DEBUG("End of constructor. In total available events=" << m_events);
0245 }
0246
0247 SimParticleContainer RootAthenaDumpReader::readParticles() const {
0248 std::vector<SimParticle> particles;
0249 particles.reserve(nPartEVT);
0250
0251 for (auto ip = 0; ip < nPartEVT; ++ip) {
0252 if (m_cfg.onlyPassedParticles && !static_cast<bool>(Part_passed[ip])) {
0253 continue;
0254 }
0255
0256 SimBarcode dummyBarcode =
0257 SimBarcode()
0258 .withVertexPrimary(
0259 static_cast<SimBarcode::PrimaryVertexId>(Part_event_number[ip]))
0260 .withVertexSecondary(static_cast<SimBarcode::SecondaryVertexId>(
0261 Part_barcode[ip] < s_maxBarcodeForPrimary ? 0 : 1))
0262 .withParticle(
0263 static_cast<SimBarcode::ParticleId>(Part_barcode[ip]));
0264 SimParticleState particle(dummyBarcode,
0265 static_cast<Acts::PdgParticle>(Part_pdg_id[ip]));
0266
0267 Acts::Vector3 p = Acts::Vector3{Part_px[ip], Part_py[ip], Part_pz[ip]} *
0268 Acts::UnitConstants::MeV;
0269 particle.setAbsoluteMomentum(p.norm());
0270
0271 particle.setDirection(p.normalized());
0272
0273 auto x = Acts::Vector4{Part_vx[ip], Part_vy[ip], Part_vz[ip], 0.0};
0274 particle.setPosition4(x);
0275
0276 particles.push_back(SimParticle(particle, particle));
0277 }
0278
0279 ACTS_DEBUG("Created " << particles.size() << " particles");
0280 auto before = particles.size();
0281
0282 auto particlesSet = particleVectorToSet(particles);
0283
0284 if (particlesSet.size() < before) {
0285 ACTS_WARNING("Particle IDs not unique for " << before - particles.size()
0286 << " particles!");
0287 }
0288
0289 return particlesSet;
0290 }
0291
0292 std::tuple<ClusterContainer, MeasurementContainer, MeasurementParticlesMap,
0293 std::unordered_map<int, std::size_t>>
0294 RootAthenaDumpReader::readMeasurements(
0295 SimParticleContainer& particles, const Acts::GeometryContext& gctx) const {
0296 ClusterContainer clusters;
0297 clusters.reserve(nCL);
0298
0299 MeasurementContainer measurements;
0300 measurements.reserve(nCL);
0301
0302 std::size_t nTotalTotZero = 0;
0303
0304 const auto prevParticlesSize = particles.size();
0305 MeasurementParticlesMap measPartMap;
0306
0307
0308 std::unordered_map<int, std::size_t> imIdxMap;
0309 imIdxMap.reserve(nCL);
0310
0311 for (int im = 0; im < nCL; im++) {
0312 if (!(CLhardware->at(im) == "PIXEL" || CLhardware->at(im) == "STRIP")) {
0313 ACTS_ERROR("hardware is neither 'PIXEL' or 'STRIP', skip particle");
0314 continue;
0315 }
0316 ACTS_VERBOSE("Cluster " << im << ": " << CLhardware->at(im));
0317
0318 auto type = (CLhardware->at(im) == "PIXEL") ? ePixel : eStrip;
0319
0320
0321
0322 Cluster cluster;
0323 if (m_cfg.readCellData && m_haveCellData) {
0324 const auto& etas = CLetas->at(im);
0325 const auto& phis = CLetas->at(im);
0326 const auto& tots = CLtots->at(im);
0327
0328 const auto totalTot = std::accumulate(tots.begin(), tots.end(), 0);
0329
0330 const auto [minEta, maxEta] =
0331 std::minmax_element(etas.begin(), etas.end());
0332 const auto [minPhi, maxPhi] =
0333 std::minmax_element(phis.begin(), phis.end());
0334
0335 cluster.channels.reserve(etas.size());
0336
0337 cluster.sizeLoc0 = *maxEta - *minEta;
0338 cluster.sizeLoc1 = *maxPhi - *minPhi;
0339
0340 if (totalTot == 0.0) {
0341 ACTS_VERBOSE(
0342 "total time over threshold is 0, set all activations to 0");
0343 nTotalTotZero++;
0344 }
0345
0346 for (const auto& [eta, phi, tot] : Acts::zip(etas, phis, tots)) {
0347
0348
0349
0350
0351 auto activation =
0352 (totalTot != 0.0) ? CLcharge_count[im] * tot / totalTot : 0.0;
0353
0354
0355 ActsFatras::Segmentizer::Bin2D bin;
0356 bin[0] = eta - *minEta;
0357 bin[1] = phi - *minPhi;
0358
0359
0360 cluster.channels.emplace_back(bin, ActsFatras::Segmentizer::Segment2D{},
0361 activation);
0362 }
0363
0364 ACTS_VERBOSE("- shape: " << cluster.channels.size()
0365 << "cells, dimensions: " << cluster.sizeLoc0
0366 << ", " << cluster.sizeLoc1);
0367 }
0368
0369 cluster.globalPosition = {CLx[im], CLy[im], CLz[im]};
0370 cluster.localDirection = {CLloc_direction1[im], CLloc_direction2[im],
0371 CLloc_direction3[im]};
0372 cluster.lengthDirection = {CLJan_loc_direction1[im],
0373 CLJan_loc_direction2[im],
0374 CLJan_loc_direction3[im]};
0375 cluster.localEta = CLloc_eta[im];
0376 cluster.localPhi = CLloc_phi[im];
0377 cluster.globalEta = CLglob_eta[im];
0378 cluster.globalPhi = CLglob_phi[im];
0379 cluster.etaAngle = CLeta_angle[im];
0380 cluster.phiAngle = CLphi_angle[im];
0381
0382
0383 Acts::GeometryIdentifier geoId;
0384 std::vector<double> localParams;
0385 if (m_cfg.geometryIdMap && m_cfg.trackingGeometry) {
0386 const auto& geoIdMap = m_cfg.geometryIdMap->left;
0387 if (geoIdMap.find(CLmoduleID[im]) == geoIdMap.end()) {
0388 ACTS_WARNING("Missing geo id for " << CLmoduleID[im] << ", skip hit");
0389 continue;
0390 }
0391
0392 geoId = m_cfg.geometryIdMap->left.at(CLmoduleID[im]);
0393
0394 auto surface = m_cfg.trackingGeometry->findSurface(geoId);
0395 if (surface == nullptr) {
0396 ACTS_WARNING("Did not find " << geoId
0397 << " in tracking geometry, skip hit");
0398 continue;
0399 }
0400
0401 bool inside =
0402 surface->isOnSurface(gctx, cluster.globalPosition, {},
0403 Acts::BoundaryTolerance::AbsoluteEuclidean(
0404 m_cfg.absBoundaryTolerance),
0405 std::numeric_limits<double>::max());
0406
0407 if (!inside) {
0408 const Acts::Vector3 v =
0409 surface->localToGlobalTransform(gctx).inverse() *
0410 cluster.globalPosition;
0411 ACTS_WARNING("Projected position is not in surface bounds for "
0412 << surface->geometryId() << ", skip hit");
0413 ACTS_WARNING("Position in local coordinates: " << v.transpose());
0414 ACTS_WARNING("Surface details:\n" << surface->toStream(gctx));
0415 continue;
0416 }
0417
0418 auto loc = surface->globalToLocal(gctx, cluster.globalPosition, {},
0419 Acts::s_onSurfaceTolerance);
0420
0421 if (!loc.ok()) {
0422 const Acts::Vector3 v =
0423 surface->localToGlobalTransform(gctx).inverse() *
0424 cluster.globalPosition;
0425 ACTS_WARNING("Global-to-local fit failed on "
0426 << geoId << " (z dist: " << v[2]
0427 << ", projected on surface: " << std::boolalpha << inside
0428 << ") , skip hit");
0429 continue;
0430 }
0431
0432
0433
0434 localParams = std::vector<double>(loc->begin(), loc->end());
0435 } else {
0436 geoId = Acts::GeometryIdentifier(CLmoduleID[im]);
0437 localParams = {CLloc_direction1[im], CLloc_direction2[im]};
0438 }
0439
0440 const auto& locCov = CLlocal_cov->at(im);
0441
0442 DigitizedParameters digiPars;
0443 if (type == ePixel) {
0444 digiPars.indices = {Acts::eBoundLoc0, Acts::eBoundLoc1};
0445 assert(locCov.size() == 4);
0446 digiPars.variances = {locCov[0], locCov[3]};
0447 digiPars.values = localParams;
0448 } else {
0449 assert(!locCov.empty());
0450
0451
0452 const static std::array boundLoc = {Acts::eBoundLoc0, Acts::eBoundLoc1};
0453 auto i = CLbarrel_endcap[im] == 0 ? 0 : 1;
0454 digiPars.variances = {locCov[i]};
0455 digiPars.values = {localParams[i]};
0456 digiPars.indices = {boundLoc[i]};
0457 }
0458
0459 std::size_t measIndex = measurements.size();
0460 ACTS_VERBOSE("Add measurement with index " << measIndex);
0461 imIdxMap.emplace(im, measIndex);
0462 createMeasurement(measurements, geoId, digiPars);
0463 cluster.geometryId = geoId;
0464 clusters.push_back(cluster);
0465
0466 if (!m_cfg.noTruth) {
0467
0468 for (const auto& [subevt, barcode] :
0469 Acts::zip(CLparticleLink_eventIndex->at(im),
0470 CLparticleLink_barcode->at(im))) {
0471 SimBarcode dummyBarcode =
0472 SimBarcode()
0473 .withVertexPrimary(
0474 static_cast<SimBarcode::PrimaryVertexId>(subevt))
0475 .withVertexSecondary(static_cast<SimBarcode::SecondaryVertexId>(
0476 barcode < s_maxBarcodeForPrimary ? 0 : 1))
0477 .withParticle(static_cast<SimBarcode::ParticleId>(barcode));
0478
0479 if (particles.find(dummyBarcode) == particles.end()) {
0480 ACTS_VERBOSE("Particle with subevt "
0481 << subevt << ", barcode " << barcode
0482 << "not found, create dummy one");
0483 particles.emplace(dummyBarcode, Acts::PdgParticle::eInvalid);
0484 }
0485 measPartMap.insert(
0486 std::pair<Index, SimBarcode>{measIndex, dummyBarcode});
0487 }
0488 }
0489 }
0490
0491 if (measurements.size() < static_cast<std::size_t>(nCL)) {
0492 ACTS_WARNING("Could not convert " << nCL - measurements.size() << " / "
0493 << nCL << " measurements");
0494 }
0495
0496 if (particles.size() - prevParticlesSize > 0) {
0497 ACTS_DEBUG("Created " << particles.size() - prevParticlesSize
0498 << " dummy particles");
0499 }
0500
0501 if (nTotalTotZero > 0) {
0502 ACTS_DEBUG(nTotalTotZero << " / " << nCL
0503 << " clusters have zero time-over-threshold");
0504 }
0505
0506 return {std::move(clusters), std::move(measurements), std::move(measPartMap),
0507 std::move(imIdxMap)};
0508 }
0509
0510 std::tuple<SpacePointContainer, SpacePointContainer, SpacePointContainer>
0511 RootAthenaDumpReader::readSpacePoints(
0512 const std::optional<std::unordered_map<int, std::size_t>>& imIdxMap) const {
0513 SpacePointContainer pixelSpacePoints(
0514 SpacePointColumns::SourceLinks | SpacePointColumns::X |
0515 SpacePointColumns::Y | SpacePointColumns::Z |
0516 SpacePointColumns::VarianceZ | SpacePointColumns::VarianceR);
0517 pixelSpacePoints.reserve(nSP);
0518
0519 SpacePointContainer stripSpacePoints(
0520 SpacePointColumns::SourceLinks | SpacePointColumns::X |
0521 SpacePointColumns::Y | SpacePointColumns::Z |
0522 SpacePointColumns::VarianceZ | SpacePointColumns::VarianceR |
0523 SpacePointColumns::StripCalibrationDetails);
0524 stripSpacePoints.reserve(nSP);
0525
0526 SpacePointContainer spacePoints(
0527 SpacePointColumns::SourceLinks | SpacePointColumns::X |
0528 SpacePointColumns::Y | SpacePointColumns::Z |
0529 SpacePointColumns::VarianceZ | SpacePointColumns::VarianceR |
0530 SpacePointColumns::StripCalibrationDetails);
0531 spacePoints.reserve(nSP);
0532
0533
0534 std::size_t skippedSpacePoints = 0;
0535 for (int isp = 0; isp < nSP; isp++) {
0536 auto isPhiOverlap = (SPisOverlap[isp] == 2) || (SPisOverlap[isp] == 3);
0537 auto isEtaOverlap = (SPisOverlap[isp] == 1) || (SPisOverlap[isp] == 3);
0538 if (m_cfg.skipOverlapSPsPhi && isPhiOverlap) {
0539 ++skippedSpacePoints;
0540 continue;
0541 }
0542 if (m_cfg.skipOverlapSPsEta && isEtaOverlap) {
0543 ++skippedSpacePoints;
0544 continue;
0545 }
0546
0547 const Acts::Vector3 globalPos{SPx[isp], SPy[isp], SPz[isp]};
0548 const double spCovr = SPcovr[isp];
0549 const double spCovz = SPcovz[isp];
0550
0551
0552 auto type = SPCL2_index[isp] == -1 ? ePixel : eStrip;
0553
0554 ACTS_VERBOSE("SP:: " << type << " [" << globalPos.transpose() << "] "
0555 << spCovr << " " << spCovz);
0556
0557 boost::container::static_vector<Acts::SourceLink, 2> sLinks;
0558
0559 const auto cl1Index = SPCL1_index[isp];
0560 assert(cl1Index >= 0 && cl1Index < nCL);
0561
0562 auto getGeoId =
0563 [&](auto athenaId) -> std::optional<Acts::GeometryIdentifier> {
0564 if (m_cfg.geometryIdMap == nullptr) {
0565 return Acts::GeometryIdentifier{athenaId};
0566 }
0567 if (m_cfg.geometryIdMap->left.find(athenaId) ==
0568 m_cfg.geometryIdMap->left.end()) {
0569 return std::nullopt;
0570 }
0571 return m_cfg.geometryIdMap->left.at(athenaId);
0572 };
0573
0574 auto cl1GeoId = getGeoId(CLmoduleID[cl1Index]);
0575 if (!cl1GeoId) {
0576 ACTS_WARNING("Could not find geoId for space point cluster 1");
0577 continue;
0578 }
0579
0580 if (imIdxMap && !imIdxMap->contains(cl1Index)) {
0581 ACTS_WARNING("Measurement 1 for space point " << isp << " not created");
0582 continue;
0583 }
0584
0585 IndexSourceLink first(*cl1GeoId,
0586 imIdxMap ? imIdxMap->at(cl1Index) : cl1Index);
0587 sLinks.emplace_back(first);
0588
0589
0590
0591 auto sp = spacePoints.createSpacePoint();
0592 sp.x() = globalPos.x();
0593 sp.y() = globalPos.y();
0594 sp.z() = globalPos.z();
0595 sp.varianceR() = spCovr;
0596 sp.varianceZ() = spCovz;
0597
0598 if (type == ePixel) {
0599 auto pixelSp = pixelSpacePoints.createSpacePoint();
0600 pixelSp.assignSourceLinks(sLinks);
0601 pixelSp.x() = globalPos.x();
0602 pixelSp.y() = globalPos.y();
0603 pixelSp.z() = globalPos.z();
0604 pixelSp.varianceR() = spCovr;
0605 pixelSp.varianceZ() = spCovz;
0606 } else {
0607 const auto cl2Index = SPCL2_index[isp];
0608 assert(cl2Index >= 0 && cl2Index < nCL);
0609
0610 auto cl2GeoId = getGeoId(CLmoduleID[cl2Index]);
0611 if (!cl2GeoId) {
0612 ACTS_WARNING("Could not find geoId for space point cluster 2");
0613 continue;
0614 }
0615
0616 if (imIdxMap && !imIdxMap->contains(cl2Index)) {
0617 ACTS_WARNING("Measurement 2 for space point " << isp << " not created");
0618 continue;
0619 }
0620
0621 IndexSourceLink second(*cl2GeoId,
0622 imIdxMap ? imIdxMap->at(cl2Index) : cl2Index);
0623 sLinks.emplace_back(second);
0624
0625 Acts::Vector3 outerStripCenter = Acts::Vector3::Zero();
0626 Acts::Vector3 stripSeparation = Acts::Vector3::Zero();
0627 Acts::Vector3 outerStripHalfVector = Acts::Vector3::Zero();
0628 Acts::Vector3 innerStripHalfVector = Acts::Vector3::Zero();
0629
0630 if (m_haveStripFeatures) {
0631 outerStripCenter = {SPtopStripCenterPosition->at(isp).at(0),
0632 SPtopStripCenterPosition->at(isp).at(1),
0633 SPtopStripCenterPosition->at(isp).at(2)};
0634 stripSeparation = {SPstripCenterDistance->at(isp).at(0),
0635 SPstripCenterDistance->at(isp).at(1),
0636 SPstripCenterDistance->at(isp).at(2)};
0637 outerStripHalfVector = {SPtopStripDirection->at(isp).at(0),
0638 SPtopStripDirection->at(isp).at(1),
0639 SPtopStripDirection->at(isp).at(2)};
0640 outerStripHalfVector *= SPhl_topstrip[isp];
0641 innerStripHalfVector = {SPbottomStripDirection->at(isp).at(0),
0642 SPbottomStripDirection->at(isp).at(1),
0643 SPbottomStripDirection->at(isp).at(2)};
0644 innerStripHalfVector *= SPhl_botstrip[isp];
0645 }
0646
0647 auto stripSp = stripSpacePoints.createSpacePoint();
0648 stripSp.assignSourceLinks(sLinks);
0649 stripSp.x() = globalPos.x();
0650 stripSp.y() = globalPos.y();
0651 stripSp.z() = globalPos.z();
0652 stripSp.varianceR() = spCovr;
0653 stripSp.varianceZ() = spCovz;
0654
0655 Eigen::Map<Eigen::Vector3f>(
0656 sp.outerStripCalibrationDetails().outerCenter.data()) =
0657 outerStripCenter.cast<float>();
0658 Eigen::Map<Eigen::Vector3f>(
0659 sp.outerStripCalibrationDetails().innerToOuterSeparation.data()) =
0660 stripSeparation.cast<float>();
0661 Eigen::Map<Eigen::Vector3f>(
0662 sp.outerStripCalibrationDetails().outerHalfVector.data()) =
0663 outerStripHalfVector.cast<float>();
0664 Eigen::Map<Eigen::Vector3f>(
0665 sp.outerStripCalibrationDetails().innerHalfVector.data()) =
0666 innerStripHalfVector.cast<float>();
0667
0668 sp.outerStripCalibrationDetails() =
0669 stripSp.outerStripCalibrationDetails();
0670 }
0671
0672 sp.assignSourceLinks(sLinks);
0673 }
0674
0675 if (m_cfg.skipOverlapSPsEta || m_cfg.skipOverlapSPsPhi) {
0676 ACTS_DEBUG("Skipped " << skippedSpacePoints
0677 << " because of eta/phi overlaps");
0678 }
0679 if (spacePoints.size() <
0680 (static_cast<std::size_t>(nSP) - skippedSpacePoints)) {
0681 ACTS_WARNING("Could not convert " << nSP - spacePoints.size() << " of "
0682 << nSP << " space points");
0683 }
0684
0685 ACTS_DEBUG("Created " << spacePoints.size() << " overall space points");
0686 ACTS_DEBUG("Created " << pixelSpacePoints.size() << " "
0687 << " pixel space points");
0688 ACTS_DEBUG("Created " << stripSpacePoints.size() << " "
0689 << " strip space points");
0690
0691 return {std::move(spacePoints), std::move(pixelSpacePoints),
0692 std::move(stripSpacePoints)};
0693 }
0694
0695 std::pair<SimParticleContainer, MeasurementParticlesMap>
0696 RootAthenaDumpReader::reprocessParticles(
0697 const SimParticleContainer& particles,
0698 const MeasurementParticlesMap& measPartMap) const {
0699 std::vector<SimParticle> newParticles;
0700 newParticles.reserve(particles.size());
0701 MeasurementParticlesMap newMeasPartMap;
0702 newMeasPartMap.reserve(measPartMap.size());
0703
0704 const auto partMeasMap = invertIndexMultimap(measPartMap);
0705
0706 std::uint16_t primaryCount = 0;
0707 std::uint16_t secondaryCount = 0;
0708
0709 for (const auto& particle : particles) {
0710 const auto [begin, end] = partMeasMap.equal_range(particle.particleId());
0711
0712 if (begin == end) {
0713 ACTS_VERBOSE("Particle " << particle.particleId()
0714 << " has no measurements");
0715 continue;
0716 }
0717
0718 auto primary = particle.particleId().vertexSecondary() == 0;
0719
0720
0721 SimBarcode fatrasBarcode = SimBarcode().withVertexPrimary(1);
0722 if (primary) {
0723 fatrasBarcode =
0724 fatrasBarcode.withVertexSecondary(0).withParticle(primaryCount);
0725 assert(primaryCount < std::numeric_limits<std::uint16_t>::max());
0726 primaryCount++;
0727 } else {
0728 fatrasBarcode =
0729 fatrasBarcode.withVertexSecondary(1).withParticle(secondaryCount);
0730 assert(primaryCount < std::numeric_limits<std::uint16_t>::max());
0731 secondaryCount++;
0732 }
0733
0734 auto newParticle = particle.withParticleId(fatrasBarcode);
0735 newParticle.finalState().setNumberOfHits(std::distance(begin, end));
0736 newParticles.push_back(newParticle);
0737
0738 for (auto it = begin; it != end; ++it) {
0739 newMeasPartMap.insert(
0740 std::pair<Index, SimBarcode>{it->second, fatrasBarcode});
0741 }
0742 }
0743
0744 ACTS_DEBUG("After reprocessing particles " << newParticles.size() << " of "
0745 << particles.size() << " remain");
0746 return {particleVectorToSet(newParticles), std::move(newMeasPartMap)};
0747 }
0748
0749 ProcessCode RootAthenaDumpReader::read(const AlgorithmContext& ctx) {
0750 ACTS_DEBUG("Reading event " << ctx.eventNumber);
0751 auto entry = ctx.eventNumber;
0752 if (entry >= m_events) {
0753 ACTS_ERROR("event out of bounds");
0754 return ProcessCode::ABORT;
0755 }
0756
0757 std::lock_guard<std::mutex> lock(m_read_mutex);
0758
0759 m_inputchain->GetEntry(entry);
0760
0761 std::optional<std::unordered_map<int, std::size_t>> optImIdxMap;
0762
0763 if (!m_cfg.onlySpacePoints) {
0764 SimParticleContainer candidateParticles;
0765
0766 if (!m_cfg.noTruth) {
0767 candidateParticles = readParticles();
0768 }
0769
0770 auto [clusters, measurements, candidateMeasPartMap, imIdxMap] =
0771 readMeasurements(candidateParticles, ctx.simGeoContext);
0772 optImIdxMap.emplace(std::move(imIdxMap));
0773
0774 m_outputClusters(ctx, std::move(clusters));
0775 const auto& storedMeasurements =
0776 m_outputMeasurements(ctx, std::move(measurements));
0777 std::vector<MeasurementContainer::Index> allIndices(
0778 storedMeasurements.size());
0779 std::iota(allIndices.begin(), allIndices.end(),
0780 MeasurementContainer::Index{0});
0781 m_outputMeasurementSubset(
0782 ctx, MeasurementSubset(storedMeasurements, std::move(allIndices)));
0783
0784 if (!m_cfg.noTruth) {
0785 auto [particles, measPartMap] =
0786 reprocessParticles(candidateParticles, candidateMeasPartMap);
0787
0788 m_outputParticles(ctx, std::move(particles));
0789 m_outputParticleMeasMap(ctx, invertIndexMultimap(measPartMap));
0790 m_outputMeasParticleMap(ctx, std::move(measPartMap));
0791 }
0792 }
0793
0794 auto [spacePoints, pixelSpacePoints, stripSpacePoints] =
0795 readSpacePoints(optImIdxMap);
0796
0797 m_outputPixelSpacePoints(ctx, std::move(pixelSpacePoints));
0798 m_outputStripSpacePoints(ctx, std::move(stripSpacePoints));
0799 m_outputSpacePoints(ctx, std::move(spacePoints));
0800
0801 return ProcessCode::SUCCESS;
0802 }
0803 }