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