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