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