Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:11:44

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2023 CERN for the benefit of the Acts project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/data/test_case.hpp>
0010 #include <boost/test/tools/old/interface.hpp>
0011 #include <boost/test/unit_test.hpp>
0012 #include <boost/test/unit_test_suite.hpp>
0013 
0014 #include "Acts/Definitions/Algebra.hpp"
0015 #include "Acts/Definitions/TrackParametrization.hpp"
0016 #include "Acts/Definitions/Units.hpp"
0017 #include "Acts/EventData/MultiTrajectory.hpp"
0018 #include "Acts/EventData/ParticleHypothesis.hpp"
0019 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0020 #include "Acts/EventData/VectorTrackContainer.hpp"
0021 #include "Acts/Geometry/GeometryContext.hpp"
0022 #include "Acts/Plugins/Podio/PodioTrackContainer.hpp"
0023 #include "Acts/Plugins/Podio/PodioTrackStateContainer.hpp"
0024 #include "Acts/Plugins/Podio/PodioUtil.hpp"
0025 #include "Acts/Surfaces/AnnulusBounds.hpp"
0026 #include "Acts/Surfaces/ConeSurface.hpp"
0027 #include "Acts/Surfaces/ConvexPolygonBounds.hpp"
0028 #include "Acts/Surfaces/CylinderBounds.hpp"
0029 #include "Acts/Surfaces/CylinderSurface.hpp"
0030 #include "Acts/Surfaces/DiamondBounds.hpp"
0031 #include "Acts/Surfaces/DiscBounds.hpp"
0032 #include "Acts/Surfaces/DiscSurface.hpp"
0033 #include "Acts/Surfaces/DiscTrapezoidBounds.hpp"
0034 #include "Acts/Surfaces/EllipseBounds.hpp"
0035 #include "Acts/Surfaces/PerigeeSurface.hpp"
0036 #include "Acts/Surfaces/PlanarBounds.hpp"
0037 #include "Acts/Surfaces/PlaneSurface.hpp"
0038 #include "Acts/Surfaces/RadialBounds.hpp"
0039 #include "Acts/Surfaces/RectangleBounds.hpp"
0040 #include "Acts/Surfaces/StrawSurface.hpp"
0041 #include "Acts/Surfaces/SurfaceBounds.hpp"
0042 #include "Acts/Utilities/Helpers.hpp"
0043 #include "Acts/Utilities/Zip.hpp"
0044 #include "ActsPodioEdm/Surface.h"
0045 #include <ActsPodioEdm/TrackCollection.h>
0046 
0047 #include <algorithm>
0048 #include <iterator>
0049 #include <memory>
0050 #include <random>
0051 #include <stdexcept>
0052 
0053 using namespace Acts;
0054 using namespace Acts::UnitLiterals;
0055 using namespace Acts::HashedStringLiteral;
0056 BOOST_AUTO_TEST_SUITE(PodioTrackContainerTest)
0057 
0058 class NullHelper : public PodioUtil::ConversionHelper {
0059  public:
0060   std::optional<PodioUtil::Identifier> surfaceToIdentifier(
0061       const Surface& /*surface*/) const override {
0062     return {};
0063   }
0064   const Surface* identifierToSurface(
0065       PodioUtil::Identifier /*identifier*/) const override {
0066     return nullptr;
0067   }
0068 
0069   SourceLink identifierToSourceLink(
0070       PodioUtil::Identifier /*identifier*/) const override {
0071     return SourceLink{0};
0072   }
0073 
0074   PodioUtil::Identifier sourceLinkToIdentifier(
0075       const SourceLink& /*sourceLink*/) override {
0076     return 0;
0077   }
0078 };
0079 
0080 struct MapHelper : public NullHelper {
0081   std::optional<PodioUtil::Identifier> surfaceToIdentifier(
0082       const Surface& surface) const override {
0083     for (auto&& [id, srf] : surfaces) {
0084       if (srf == &surface) {
0085         return id;
0086       }
0087     }
0088     return {};
0089   }
0090   const Surface* identifierToSurface(PodioUtil::Identifier id) const override {
0091     auto it = surfaces.find(id);
0092     if (it == surfaces.end()) {
0093       return nullptr;
0094     }
0095 
0096     return it->second;
0097   }
0098 
0099   std::unordered_map<PodioUtil::Identifier, const Surface*> surfaces;
0100 };
0101 
0102 BOOST_AUTO_TEST_CASE(ConvertSurface) {
0103   auto rBounds = std::make_shared<RectangleBounds>(15, 20);
0104 
0105   auto trf = Transform3::Identity();
0106   trf.translation().setRandom();
0107 
0108   auto free = Acts::Surface::makeShared<PlaneSurface>(trf, rBounds);
0109 
0110   NullHelper helper;
0111   auto surface = PodioUtil::convertSurfaceToPodio(helper, *free);
0112 
0113   auto free2 = PodioUtil::convertSurfaceFromPodio(helper, surface);
0114 
0115   Acts::GeometryContext gctx;
0116 
0117   BOOST_REQUIRE(free2);
0118   BOOST_CHECK_EQUAL(free->type(), free2->type());
0119   BOOST_CHECK_EQUAL(free->bounds().type(), free2->bounds().type());
0120   BOOST_CHECK_EQUAL(free->center(gctx), free2->center(gctx));
0121 
0122   const auto* rBounds2 = dynamic_cast<const RectangleBounds*>(&free2->bounds());
0123   BOOST_REQUIRE_NE(rBounds2, nullptr);
0124 
0125   BOOST_CHECK_EQUAL(rBounds2->halfLengthX(), rBounds->halfLengthX());
0126   BOOST_CHECK_EQUAL(rBounds2->halfLengthY(), rBounds->halfLengthY());
0127 
0128   // this could probably use some more complete checks
0129 }
0130 
0131 BOOST_AUTO_TEST_CASE(ConvertTrack) {
0132   auto rBounds = std::make_shared<RectangleBounds>(15, 20);
0133   auto trf = Transform3::Identity();
0134   trf.translation().setRandom();
0135   auto free = Acts::Surface::makeShared<PlaneSurface>(trf, rBounds);
0136 
0137   MapHelper helper;
0138 
0139   auto refCov = BoundMatrix::Random().eval();
0140 
0141   podio::Frame frame;
0142 
0143   ParticleHypothesis pHypo = ParticleHypothesis::pion();
0144 
0145   {
0146     Acts::MutablePodioTrackStateContainer tsc{helper};
0147     Acts::MutablePodioTrackContainer ptc{helper};
0148     ActsPodioEdm::TrackCollection& tracks = ptc.trackCollection();
0149 
0150     Acts::TrackContainer tc{ptc, tsc};
0151 
0152     BOOST_CHECK(!tc.hasColumn("int_column"_hash));
0153     BOOST_CHECK(!tc.hasColumn("float_column"_hash));
0154     tc.addColumn<int32_t>("int_column");
0155     tc.addColumn<float>("float_column");
0156     BOOST_CHECK(tc.hasColumn("int_column"_hash));
0157     BOOST_CHECK(tc.hasColumn("float_column"_hash));
0158 
0159     BOOST_CHECK_EQUAL(tc.size(), 0);
0160 
0161     auto t = tc.makeTrack();
0162     BOOST_CHECK_EQUAL(t.tipIndex(), MultiTrajectoryTraits::kInvalid);
0163 
0164     t.setParticleHypothesis(pHypo);
0165     BOOST_CHECK_EQUAL(t.particleHypothesis(), pHypo);
0166 
0167     BOOST_CHECK_EQUAL(tsc.size(), 0);
0168     auto ts1 = t.appendTrackState();
0169     auto ts2 = t.appendTrackState();
0170     auto ts3 = t.appendTrackState();
0171     BOOST_CHECK_EQUAL(tsc.size(), 3);
0172     BOOST_CHECK_EQUAL(ts1.index(), 0);
0173     BOOST_CHECK_EQUAL(ts2.index(), 1);
0174     BOOST_CHECK_EQUAL(ts3.index(), 2);
0175 
0176     BOOST_CHECK_EQUAL(t.nTrackStates(), 3);
0177     BOOST_CHECK_EQUAL(t.tipIndex(), 2);
0178 
0179     BOOST_CHECK_EQUAL(tc.size(), 1);
0180 
0181     auto pTrack = tracks.at(0);
0182     BOOST_CHECK_EQUAL(pTrack.data().tipIndex, 2);
0183 
0184     t.parameters() << 1, 2, 3, 4, 5, 6;
0185     Eigen::Map<BoundVector> pars{pTrack.data().parameters.data()};
0186     BoundVector bv;
0187     bv << 1, 2, 3, 4, 5, 6;
0188     BOOST_CHECK_EQUAL(pars, bv);
0189 
0190     t.covariance() = refCov;
0191 
0192     Eigen::Map<const BoundMatrix> cov{pTrack.data().covariance.data()};
0193     BOOST_CHECK_EQUAL(refCov, cov);
0194 
0195     t.nMeasurements() = 17;
0196     BOOST_CHECK_EQUAL(pTrack.data().nMeasurements, 17);
0197 
0198     t.nHoles() = 34;
0199     BOOST_CHECK_EQUAL(pTrack.data().nHoles, 34);
0200 
0201     t.chi2() = 882.3f;
0202     BOOST_CHECK_EQUAL(pTrack.data().chi2, 882.3f);
0203 
0204     t.nDoF() = 9;
0205     BOOST_CHECK_EQUAL(pTrack.data().ndf, 9);
0206 
0207     t.nOutliers() = 77;
0208     BOOST_CHECK_EQUAL(pTrack.data().nOutliers, 77);
0209 
0210     t.nSharedHits() = 99;
0211     BOOST_CHECK_EQUAL(pTrack.data().nSharedHits, 99);
0212 
0213     Acts::GeometryContext gctx;
0214     t.setReferenceSurface(free);
0215     const auto& free2 = t.referenceSurface();
0216     BOOST_CHECK_EQUAL(free->center(gctx), free2.center(gctx));
0217 
0218     const auto* rBounds2 =
0219         dynamic_cast<const RectangleBounds*>(&free2.bounds());
0220     BOOST_REQUIRE_NE(rBounds2, nullptr);
0221 
0222     BOOST_CHECK_EQUAL(rBounds2->halfLengthX(), rBounds->halfLengthX());
0223     BOOST_CHECK_EQUAL(rBounds2->halfLengthY(), rBounds->halfLengthY());
0224 
0225     BOOST_CHECK_EQUAL(pTrack.getReferenceSurface().identifier,
0226                       PodioUtil::kNoIdentifier);
0227 
0228     auto t2 = tc.makeTrack();
0229     auto t3 = tc.makeTrack();
0230     BOOST_CHECK_EQUAL(tc.size(), 3);
0231 
0232     // Register surface "with the detector"
0233     helper.surfaces[666] = free.get();
0234     t2.setReferenceSurface(free);
0235     auto pTrack2 = tracks.at(1);
0236     BOOST_CHECK_EQUAL(pTrack2.getReferenceSurface().identifier, 666);
0237 
0238     t.component<int32_t, "int_column"_hash>() = -11;
0239     t2.component<int32_t, "int_column"_hash>() = 42;
0240     t3.component<int32_t, "int_column"_hash>() = -98;
0241 
0242     t.component<float, "float_column"_hash>() = -11.2f;
0243     t2.component<float, "float_column"_hash>() = 42.4f;
0244     t3.component<float, "float_column"_hash>() = -98.9f;
0245 
0246     ptc.releaseInto(frame);
0247     tsc.releaseInto(frame);
0248 
0249     BOOST_REQUIRE_NE(frame.get("tracks"), nullptr);
0250     BOOST_CHECK_EQUAL(frame.get("tracks")->size(), 3);
0251     BOOST_REQUIRE_NE(frame.get("tracks_extra__int_column"), nullptr);
0252     BOOST_REQUIRE_NE(frame.get("tracks_extra__float_column"), nullptr);
0253 
0254     BOOST_REQUIRE_NE(frame.get("trackStates"), nullptr);
0255     BOOST_CHECK_EQUAL(frame.get("trackStates")->size(), 3);
0256   }
0257 
0258   {
0259     Acts::ConstPodioTrackStateContainer tsc{helper, frame};
0260     Acts::ConstPodioTrackContainer ptc{helper, frame};
0261     // const ActsPodioEdm::TrackCollection& tracks = ptc.trackCollection();
0262 
0263     Acts::TrackContainer tc{ptc, tsc};
0264 
0265     BOOST_CHECK(tc.hasColumn("int_column"_hash));
0266     BOOST_CHECK(tc.hasColumn("float_column"_hash));
0267 
0268     BOOST_CHECK_EQUAL(tc.size(), 3);
0269 
0270     auto t = tc.getTrack(0);
0271     const auto& freeRecreated = t.referenceSurface();
0272     // Not the exact same surface, it's recreated from values
0273     BOOST_CHECK_NE(free.get(), &freeRecreated);
0274 
0275     BOOST_CHECK_EQUAL(t.particleHypothesis(), pHypo);
0276 
0277     BOOST_CHECK_EQUAL(t.nMeasurements(), 17);
0278 
0279     BOOST_CHECK_EQUAL(t.nHoles(), 34);
0280 
0281     BOOST_CHECK_EQUAL(t.chi2(), 882.3f);
0282 
0283     BOOST_CHECK_EQUAL(t.nDoF(), 9);
0284 
0285     BOOST_CHECK_EQUAL(t.nOutliers(), 77);
0286 
0287     BOOST_CHECK_EQUAL(t.nSharedHits(), 99);
0288 
0289     BOOST_CHECK_EQUAL(t.tipIndex(), 2);
0290     BOOST_CHECK_EQUAL(t.nTrackStates(), 3);
0291 
0292     auto t2 = tc.getTrack(1);
0293     // Is the exact same surface, because it's looked up in the "detector"
0294     BOOST_CHECK_EQUAL(free.get(), &t2.referenceSurface());
0295     BoundVector bv;
0296     bv << 1, 2, 3, 4, 5, 6;
0297     BOOST_CHECK_EQUAL(t.parameters(), bv);
0298 
0299     BOOST_CHECK_EQUAL(t.covariance(), refCov);
0300 
0301     auto t3 = tc.getTrack(2);
0302     BOOST_CHECK(!t3.hasReferenceSurface());
0303 
0304     BOOST_CHECK_EQUAL((t.component<int32_t, "int_column"_hash>()), -11);
0305     BOOST_CHECK_EQUAL((t2.component<int32_t, "int_column"_hash>()), 42);
0306     BOOST_CHECK_EQUAL((t3.component<int32_t, "int_column"_hash>()), -98);
0307 
0308     BOOST_CHECK_EQUAL((t.component<float, "float_column"_hash>()), -11.2f);
0309     BOOST_CHECK_EQUAL((t2.component<float, "float_column"_hash>()), 42.4f);
0310     BOOST_CHECK_EQUAL((t3.component<float, "float_column"_hash>()), -98.9f);
0311   }
0312 }
0313 
0314 BOOST_AUTO_TEST_CASE(CopyTracksIncludingDynamicColumnsDifferentBackends) {
0315   MapHelper helper;
0316 
0317   podio::Frame frame;
0318 
0319   // mutable source
0320   VectorTrackContainer vtc{};
0321   VectorMultiTrajectory mtj{};
0322   TrackContainer tc{vtc, mtj};
0323   tc.addColumn<uint64_t>("counter");
0324   tc.addColumn<uint8_t>("odd");
0325   mtj.addColumn<uint64_t>("ts_counter");
0326   mtj.addColumn<uint8_t>("ts_odd");
0327 
0328   Acts::MutablePodioTrackStateContainer tsc2{helper};
0329   Acts::MutablePodioTrackContainer ptc2{helper};
0330   Acts::TrackContainer tc2{ptc2, tsc2};
0331   // doesn't have the dynamic column
0332 
0333   Acts::MutablePodioTrackStateContainer tsc3{helper};
0334   Acts::MutablePodioTrackContainer ptc3{helper};
0335   Acts::TrackContainer tc3{ptc3, tsc3};
0336 
0337   tc3.addColumn<uint64_t>("counter");
0338   tc3.addColumn<uint8_t>("odd");
0339   tsc3.addColumn<uint64_t>("ts_counter");
0340   tsc3.addColumn<uint8_t>("ts_odd");
0341 
0342   for (std::size_t i = 0; i < 10; i++) {
0343     auto t = tc.makeTrack();
0344     auto ts = t.appendTrackState();
0345     ts.predicted() = BoundVector::Ones();
0346     ts.component<uint64_t, "ts_counter"_hash>() = i;
0347 
0348     ts = t.appendTrackState();
0349     ts.predicted().setOnes();
0350     ts.predicted() *= 2;
0351     ts.component<uint64_t, "ts_counter"_hash>() = i + 1;
0352 
0353     ts = t.appendTrackState();
0354     ts.predicted().setOnes();
0355     ts.predicted() *= 3;
0356     ts.component<uint64_t, "ts_counter"_hash>() = i + 2;
0357 
0358     t.template component<uint64_t>("counter") = i;
0359     t.template component<uint8_t>("odd") = static_cast<uint8_t>(i % 2 == 0);
0360 
0361     auto t2 = tc2.makeTrack();
0362     BOOST_CHECK_THROW(t2.copyFrom(t),
0363                       std::invalid_argument);  // this should fail
0364 
0365     auto t3 = tc3.makeTrack();
0366     t3.copyFrom(t);  // this should work
0367 
0368     BOOST_CHECK_NE(t3.tipIndex(), MultiTrajectoryTraits::kInvalid);
0369     BOOST_CHECK_GT(t3.nTrackStates(), 0);
0370     BOOST_REQUIRE_EQUAL(t.nTrackStates(), t3.nTrackStates());
0371 
0372     for (auto [tsa, tsb] :
0373          zip(t.trackStatesReversed(), t3.trackStatesReversed())) {
0374       BOOST_CHECK_EQUAL(tsa.predicted(), tsb.predicted());
0375 
0376       BOOST_CHECK_EQUAL(
0377           (tsa.template component<uint64_t, "ts_counter"_hash>()),
0378           (tsb.template component<uint64_t, "ts_counter"_hash>()));
0379 
0380       BOOST_CHECK_EQUAL((tsa.template component<uint8_t, "ts_odd"_hash>()),
0381                         (tsb.template component<uint8_t, "ts_odd"_hash>()));
0382     }
0383 
0384     BOOST_CHECK_EQUAL(t.template component<uint64_t>("counter"),
0385                       t3.template component<uint64_t>("counter"));
0386     BOOST_CHECK_EQUAL(t.template component<uint8_t>("odd"),
0387                       t3.template component<uint8_t>("odd"));
0388   }
0389 }
0390 
0391 BOOST_AUTO_TEST_SUITE_END()