File indexing completed on 2025-12-16 09:23:58
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->transform(gctx).inverse() * cluster.globalPosition;
0401 ACTS_WARNING("Projected position is not in surface bounds for "
0402 << surface->geometryId() << ", skip hit");
0403 ACTS_WARNING("Position in local coordinates: " << v.transpose());
0404 ACTS_WARNING("Surface details:\n" << surface->toStream(gctx));
0405 continue;
0406 }
0407
0408 auto loc = surface->globalToLocal(gctx, cluster.globalPosition, {},
0409 Acts::s_onSurfaceTolerance);
0410
0411 if (!loc.ok()) {
0412 const Acts::Vector3 v =
0413 surface->transform(gctx).inverse() * cluster.globalPosition;
0414 ACTS_WARNING("Global-to-local fit failed on "
0415 << geoId << " (z dist: " << v[2]
0416 << ", projected on surface: " << std::boolalpha << inside
0417 << ") , skip hit");
0418 continue;
0419 }
0420
0421
0422
0423 localParams = std::vector<double>(loc->begin(), loc->end());
0424 } else {
0425 geoId = Acts::GeometryIdentifier(CLmoduleID[im]);
0426 localParams = {CLloc_direction1[im], CLloc_direction2[im]};
0427 }
0428
0429 DigitizedParameters digiPars;
0430 if (type == ePixel) {
0431 digiPars.indices = {Acts::eBoundLoc0, Acts::eBoundLoc1};
0432 assert(locCov.size() == 4);
0433 digiPars.variances = {locCov[0], locCov[3]};
0434 digiPars.values = localParams;
0435 } else {
0436 assert(!locCov.empty());
0437
0438
0439 const static std::array boundLoc = {Acts::eBoundLoc0, Acts::eBoundLoc1};
0440 auto i = CLbarrel_endcap[im] == 0 ? 0 : 1;
0441 digiPars.variances = {locCov[i]};
0442 digiPars.values = {localParams[i]};
0443 digiPars.indices = {boundLoc[i]};
0444 }
0445
0446 std::size_t measIndex = measurements.size();
0447 ACTS_VERBOSE("Add measurement with index " << measIndex);
0448 imIdxMap.emplace(im, measIndex);
0449 createMeasurement(measurements, geoId, digiPars);
0450 clusters.push_back(cluster);
0451
0452 if (!m_cfg.noTruth) {
0453
0454 for (const auto& [subevt, barcode] :
0455 Acts::zip(CLparticleLink_eventIndex->at(im),
0456 CLparticleLink_barcode->at(im))) {
0457 SimBarcode dummyBarcode =
0458 SimBarcode()
0459 .withVertexPrimary(
0460 static_cast<SimBarcode::PrimaryVertexId>(subevt))
0461 .withVertexSecondary(static_cast<SimBarcode::SecondaryVertexId>(
0462 barcode < s_maxBarcodeForPrimary ? 0 : 1))
0463 .withParticle(static_cast<SimBarcode::ParticleId>(barcode));
0464
0465 if (particles.find(dummyBarcode) == particles.end()) {
0466 ACTS_VERBOSE("Particle with subevt "
0467 << subevt << ", barcode " << barcode
0468 << "not found, create dummy one");
0469 particles.emplace(dummyBarcode, Acts::PdgParticle::eInvalid);
0470 }
0471 measPartMap.insert(
0472 std::pair<Index, ActsFatras::Barcode>{measIndex, dummyBarcode});
0473 }
0474 }
0475 }
0476
0477 if (measurements.size() < static_cast<std::size_t>(nCL)) {
0478 ACTS_WARNING("Could not convert " << nCL - measurements.size() << " / "
0479 << nCL << " measurements");
0480 }
0481
0482 if (particles.size() - prevParticlesSize > 0) {
0483 ACTS_DEBUG("Created " << particles.size() - prevParticlesSize
0484 << " dummy particles");
0485 }
0486
0487 if (nTotalTotZero > 0) {
0488 ACTS_DEBUG(nTotalTotZero << " / " << nCL
0489 << " clusters have zero time-over-threshold");
0490 }
0491
0492 return {std::move(clusters), std::move(measurements), std::move(measPartMap),
0493 std::move(imIdxMap)};
0494 }
0495
0496 std::tuple<SimSpacePointContainer, SimSpacePointContainer,
0497 SimSpacePointContainer>
0498 RootAthenaDumpReader::readSpacepoints(
0499 const std::optional<std::unordered_map<int, std::size_t>>& imIdxMap) const {
0500 SimSpacePointContainer pixelSpacePoints;
0501 pixelSpacePoints.reserve(nSP);
0502
0503 SimSpacePointContainer stripSpacePoints;
0504 stripSpacePoints.reserve(nSP);
0505
0506 SimSpacePointContainer spacePoints;
0507 spacePoints.reserve(nSP);
0508
0509
0510 std::size_t skippedSpacePoints = 0;
0511 for (int isp = 0; isp < nSP; isp++) {
0512 auto isPhiOverlap = (SPisOverlap[isp] == 2) || (SPisOverlap[isp] == 3);
0513 auto isEtaOverlap = (SPisOverlap[isp] == 1) || (SPisOverlap[isp] == 3);
0514 if (m_cfg.skipOverlapSPsPhi && isPhiOverlap) {
0515 ++skippedSpacePoints;
0516 continue;
0517 }
0518 if (m_cfg.skipOverlapSPsEta && isEtaOverlap) {
0519 ++skippedSpacePoints;
0520 continue;
0521 }
0522
0523 const Acts::Vector3 globalPos{SPx[isp], SPy[isp], SPz[isp]};
0524 const double spCovr = SPcovr[isp];
0525 const double spCovz = SPcovz[isp];
0526
0527
0528 auto type = SPCL2_index[isp] == -1 ? ePixel : eStrip;
0529
0530 ACTS_VERBOSE("SP:: " << type << " [" << globalPos.transpose() << "] "
0531 << spCovr << " " << spCovz);
0532
0533 boost::container::static_vector<Acts::SourceLink, 2> sLinks;
0534
0535 const auto cl1Index = SPCL1_index[isp];
0536 assert(cl1Index >= 0 && cl1Index < nCL);
0537
0538 auto getGeoId =
0539 [&](auto athenaId) -> std::optional<Acts::GeometryIdentifier> {
0540 if (m_cfg.geometryIdMap == nullptr) {
0541 return Acts::GeometryIdentifier{athenaId};
0542 }
0543 if (m_cfg.geometryIdMap->left.find(athenaId) ==
0544 m_cfg.geometryIdMap->left.end()) {
0545 return std::nullopt;
0546 }
0547 return m_cfg.geometryIdMap->left.at(athenaId);
0548 };
0549
0550 auto cl1GeoId = getGeoId(CLmoduleID[cl1Index]);
0551 if (!cl1GeoId) {
0552 ACTS_WARNING("Could not find geoId for spacepoint cluster 1");
0553 continue;
0554 }
0555
0556 if (imIdxMap && !imIdxMap->contains(cl1Index)) {
0557 ACTS_WARNING("Measurement 1 for spacepoint " << isp << " not created");
0558 continue;
0559 }
0560
0561 IndexSourceLink first(*cl1GeoId,
0562 imIdxMap ? imIdxMap->at(cl1Index) : cl1Index);
0563 sLinks.emplace_back(first);
0564
0565
0566
0567 SimSpacePoint sp(globalPos, std::nullopt, spCovr, spCovz, std::nullopt,
0568 sLinks);
0569
0570 if (type == ePixel) {
0571 pixelSpacePoints.push_back(sp);
0572 } else {
0573 const auto cl2Index = SPCL2_index[isp];
0574 assert(cl2Index >= 0 && cl2Index < nCL);
0575
0576 auto cl2GeoId = getGeoId(CLmoduleID[cl1Index]);
0577 if (!cl2GeoId) {
0578 ACTS_WARNING("Could not find geoId for spacepoint cluster 2");
0579 continue;
0580 }
0581
0582 if (imIdxMap && !imIdxMap->contains(cl2Index)) {
0583 ACTS_WARNING("Measurement 2 for spacepoint " << isp << " not created");
0584 continue;
0585 }
0586
0587 IndexSourceLink second(*cl2GeoId,
0588 imIdxMap ? imIdxMap->at(cl2Index) : cl2Index);
0589 sLinks.emplace_back(second);
0590
0591 using Vector3f = Eigen::Matrix<float, 3, 1>;
0592 Vector3f topStripDirection = Vector3f::Zero();
0593 Vector3f bottomStripDirection = Vector3f::Zero();
0594 Vector3f stripCenterDistance = Vector3f::Zero();
0595 Vector3f topStripCenterPosition = Vector3f::Zero();
0596
0597 if (m_haveStripFeatures) {
0598 topStripDirection = {SPtopStripDirection->at(isp).at(0),
0599 SPtopStripDirection->at(isp).at(1),
0600 SPtopStripDirection->at(isp).at(2)};
0601 bottomStripDirection = {SPbottomStripDirection->at(isp).at(0),
0602 SPbottomStripDirection->at(isp).at(1),
0603 SPbottomStripDirection->at(isp).at(2)};
0604 stripCenterDistance = {SPstripCenterDistance->at(isp).at(0),
0605 SPstripCenterDistance->at(isp).at(1),
0606 SPstripCenterDistance->at(isp).at(2)};
0607 topStripCenterPosition = {SPtopStripCenterPosition->at(isp).at(0),
0608 SPtopStripCenterPosition->at(isp).at(1),
0609 SPtopStripCenterPosition->at(isp).at(2)};
0610 }
0611 sp = SimSpacePoint(globalPos, std::nullopt, spCovr, spCovz, std::nullopt,
0612 sLinks, SPhl_topstrip[isp], SPhl_botstrip[isp],
0613 topStripDirection.cast<double>(),
0614 bottomStripDirection.cast<double>(),
0615 stripCenterDistance.cast<double>(),
0616 topStripCenterPosition.cast<double>());
0617
0618 stripSpacePoints.push_back(sp);
0619 }
0620
0621 spacePoints.push_back(sp);
0622 }
0623
0624 if (m_cfg.skipOverlapSPsEta || m_cfg.skipOverlapSPsPhi) {
0625 ACTS_DEBUG("Skipped " << skippedSpacePoints
0626 << " because of eta/phi overlaps");
0627 }
0628 if (spacePoints.size() <
0629 (static_cast<std::size_t>(nSP) - skippedSpacePoints)) {
0630 ACTS_WARNING("Could not convert " << nSP - spacePoints.size() << " of "
0631 << nSP << " spacepoints");
0632 }
0633
0634 ACTS_DEBUG("Created " << spacePoints.size() << " overall space points");
0635 ACTS_DEBUG("Created " << pixelSpacePoints.size() << " "
0636 << " pixel space points");
0637 ACTS_DEBUG("Created " << stripSpacePoints.size() << " "
0638 << " strip space points");
0639
0640 return {std::move(spacePoints), std::move(pixelSpacePoints),
0641 std::move(stripSpacePoints)};
0642 }
0643
0644 std::pair<SimParticleContainer, IndexMultimap<ActsFatras::Barcode>>
0645 RootAthenaDumpReader::reprocessParticles(
0646 const SimParticleContainer& particles,
0647 const IndexMultimap<ActsFatras::Barcode>& measPartMap) const {
0648 std::vector<ActsExamples::SimParticle> newParticles;
0649 newParticles.reserve(particles.size());
0650 IndexMultimap<ActsFatras::Barcode> newMeasPartMap;
0651 newMeasPartMap.reserve(measPartMap.size());
0652
0653 const auto partMeasMap = invertIndexMultimap(measPartMap);
0654
0655 std::uint16_t primaryCount = 0;
0656 std::uint16_t secondaryCount = 0;
0657
0658 for (const auto& particle : particles) {
0659 const auto [begin, end] = partMeasMap.equal_range(particle.particleId());
0660
0661 if (begin == end) {
0662 ACTS_VERBOSE("Particle " << particle.particleId()
0663 << " has no measurements");
0664 continue;
0665 }
0666
0667 auto primary = particle.particleId().vertexSecondary() == 0;
0668
0669
0670 ActsFatras::Barcode fatrasBarcode =
0671 ActsFatras::Barcode().withVertexPrimary(1);
0672 if (primary) {
0673 fatrasBarcode =
0674 fatrasBarcode.withVertexSecondary(0).withParticle(primaryCount);
0675 assert(primaryCount < std::numeric_limits<std::uint16_t>::max());
0676 primaryCount++;
0677 } else {
0678 fatrasBarcode =
0679 fatrasBarcode.withVertexSecondary(1).withParticle(secondaryCount);
0680 assert(primaryCount < std::numeric_limits<std::uint16_t>::max());
0681 secondaryCount++;
0682 }
0683
0684 auto newParticle = particle.withParticleId(fatrasBarcode);
0685 newParticle.finalState().setNumberOfHits(std::distance(begin, end));
0686 newParticles.push_back(newParticle);
0687
0688 for (auto it = begin; it != end; ++it) {
0689 newMeasPartMap.insert(
0690 std::pair<Index, ActsFatras::Barcode>{it->second, fatrasBarcode});
0691 }
0692 }
0693
0694 ACTS_DEBUG("After reprocessing particles " << newParticles.size() << " of "
0695 << particles.size() << " remain");
0696 return {particleVectorToSet(newParticles), std::move(newMeasPartMap)};
0697 }
0698
0699 ProcessCode RootAthenaDumpReader::read(const AlgorithmContext& ctx) {
0700 ACTS_DEBUG("Reading event " << ctx.eventNumber);
0701 auto entry = ctx.eventNumber;
0702 if (entry >= m_events) {
0703 ACTS_ERROR("event out of bounds");
0704 return ProcessCode::ABORT;
0705 }
0706
0707 std::lock_guard<std::mutex> lock(m_read_mutex);
0708
0709 m_inputchain->GetEntry(entry);
0710
0711 std::optional<std::unordered_map<int, std::size_t>> optImIdxMap;
0712
0713 if (!m_cfg.onlySpacepoints) {
0714 SimParticleContainer candidateParticles;
0715
0716 if (!m_cfg.noTruth) {
0717 candidateParticles = readParticles();
0718 }
0719
0720 auto [clusters, measurements, candidateMeasPartMap, imIdxMap] =
0721 readMeasurements(candidateParticles, ctx.geoContext);
0722 optImIdxMap.emplace(std::move(imIdxMap));
0723
0724 m_outputClusters(ctx, std::move(clusters));
0725 m_outputMeasurements(ctx, std::move(measurements));
0726
0727 if (!m_cfg.noTruth) {
0728 auto [particles, measPartMap] =
0729 reprocessParticles(candidateParticles, candidateMeasPartMap);
0730
0731 m_outputParticles(ctx, std::move(particles));
0732 m_outputParticleMeasMap(ctx, invertIndexMultimap(measPartMap));
0733 m_outputMeasParticleMap(ctx, std::move(measPartMap));
0734 }
0735 }
0736
0737 auto [spacePoints, pixelSpacePoints, stripSpacePoints] =
0738 readSpacepoints(optImIdxMap);
0739
0740 m_outputPixelSpacePoints(ctx, std::move(pixelSpacePoints));
0741 m_outputStripSpacePoints(ctx, std::move(stripSpacePoints));
0742 m_outputSpacePoints(ctx, std::move(spacePoints));
0743
0744 return ProcessCode::SUCCESS;
0745 }
0746 }