File indexing completed on 2025-08-06 08:11:42
0001
0002
0003
0004
0005
0006
0007
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/TrackParametrization.hpp"
0015 #include "Acts/EventData/Charge.hpp"
0016 #include "Acts/EventData/GenericBoundTrackParameters.hpp"
0017 #include "Acts/EventData/MultiTrajectory.hpp"
0018 #include "Acts/EventData/TrackHelpers.hpp"
0019 #include "Acts/EventData/TrackStatePropMask.hpp"
0020 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0021 #include "Acts/EventData/VectorTrackContainer.hpp"
0022 #include "Acts/Geometry/GeometryContext.hpp"
0023 #include "Acts/Plugins/EDM4hep/EDM4hepUtil.hpp"
0024 #include "Acts/Propagator/detail/CovarianceEngine.hpp"
0025 #include "Acts/Propagator/detail/JacobianEngine.hpp"
0026 #include "Acts/Surfaces/PerigeeSurface.hpp"
0027 #include "Acts/Surfaces/PlaneSurface.hpp"
0028 #include "Acts/Surfaces/Surface.hpp"
0029 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0030 #include "Acts/Utilities/Logger.hpp"
0031 #include "Acts/Utilities/Zip.hpp"
0032
0033 #include <algorithm>
0034 #include <iostream>
0035 #include <random>
0036
0037 #include <edm4hep/TrackCollection.h>
0038
0039 using namespace Acts;
0040 using namespace Acts::UnitLiterals;
0041 BOOST_AUTO_TEST_SUITE(EDM4hepParameterConversion)
0042
0043 BOOST_AUTO_TEST_CASE(JacobianRoundtrip) {
0044 BoundVector par;
0045 par << 1_mm, 5_mm, 0.1, M_PI_2 * 0.9, -1 / 1_GeV, 5_ns;
0046
0047 BoundMatrix cov;
0048 cov.setIdentity();
0049
0050 double Bz = 2_T;
0051
0052 double tanLambda = std::tan(M_PI_2 - par[Acts::eBoundTheta]);
0053 double omega =
0054 par[Acts::eBoundQOverP] / std::sin(par[Acts::eBoundTheta]) * Bz;
0055
0056 auto J1 = EDM4hepUtil::detail::jacobianToEdm4hep(par[eBoundTheta],
0057 par[eBoundQOverP], Bz);
0058
0059 BoundMatrix cov2 = J1 * cov * J1.transpose();
0060
0061 auto J2 = EDM4hepUtil::detail::jacobianFromEdm4hep(tanLambda, omega, Bz);
0062
0063 BoundMatrix cov3 = J2 * cov2 * J2.transpose();
0064
0065 CHECK_CLOSE_ABS(cov, cov3, 1e-9);
0066 }
0067
0068 BOOST_AUTO_TEST_CASE(ConvertTrackParametersToEdm4hepWithPerigee) {
0069 auto refSurface = Surface::makeShared<PerigeeSurface>(Vector3{50, 30, 20});
0070
0071 BoundVector par;
0072 par << 1_mm, 5_mm, 0, M_PI_2, -1 / 1_GeV,
0073 5_ns;
0074
0075 BoundMatrix cov;
0076 cov.setIdentity();
0077 cov(5, 5) = 25_ns;
0078
0079 BoundTrackParameters boundPar{refSurface, par, cov,
0080 ParticleHypothesis::pion()};
0081
0082 double Bz = 2_T;
0083
0084 Acts::GeometryContext gctx;
0085
0086 EDM4hepUtil::detail::Parameters converted =
0087 EDM4hepUtil::detail::convertTrackParametersToEdm4hep(gctx, Bz, boundPar);
0088
0089 BOOST_CHECK(converted.covariance.has_value());
0090 BOOST_CHECK(converted.surface);
0091
0092
0093 BOOST_CHECK_EQUAL(par.template head<2>(),
0094 converted.values.template head<2>());
0095 BOOST_CHECK_EQUAL(
0096 (converted.covariance.value().template topLeftCorner<4, 4>()),
0097 ActsSquareMatrix<4>::Identity());
0098 BOOST_CHECK_GT(converted.covariance.value()(4, 4), 0);
0099 BOOST_CHECK_EQUAL(converted.covariance.value()(5, 5), 25_ns);
0100
0101
0102
0103 BoundTrackParameters roundtripPar =
0104 EDM4hepUtil::detail::convertTrackParametersFromEdm4hep(Bz, converted);
0105
0106 BOOST_CHECK(roundtripPar.parameters().isApprox(boundPar.parameters()));
0107 BOOST_CHECK(roundtripPar.covariance().value().isApprox(
0108 boundPar.covariance().value()));
0109 }
0110
0111 BOOST_AUTO_TEST_CASE(ConvertTrackParametersToEdm4hepWithOutPerigee) {
0112 auto planeSurface = Surface::makeShared<PlaneSurface>(
0113 Vector3{50, 30, 20}, Vector3{1, 1, 0.3}.normalized());
0114
0115 BoundVector par;
0116 par << 1_mm, 5_mm, M_PI / 4., M_PI_2 * 0.9, -1 / 1_GeV, 5_ns;
0117
0118 BoundMatrix cov;
0119 cov.setIdentity();
0120 cov(5, 5) = 25_ns;
0121
0122 BoundTrackParameters planePar{planeSurface, par, cov,
0123 ParticleHypothesis::pion()};
0124
0125 double Bz = 2_T;
0126
0127 Acts::GeometryContext gctx;
0128
0129 EDM4hepUtil::detail::Parameters converted =
0130 EDM4hepUtil::detail::convertTrackParametersToEdm4hep(gctx, Bz, planePar);
0131
0132 BOOST_CHECK(converted.covariance.has_value());
0133 BOOST_CHECK(converted.surface);
0134
0135
0136 BOOST_CHECK_EQUAL(converted.values.template head<2>(), (Vector2{0, 0}));
0137 CHECK_CLOSE_ABS(converted.values[2], par[2], 1e-6);
0138
0139 BOOST_CHECK_EQUAL(converted.covariance.value()(0, 0), 1);
0140
0141 BOOST_CHECK_LT(converted.covariance.value()(1, 1), 1.2);
0142 BOOST_CHECK_GT(converted.covariance.value()(1, 1), 1);
0143
0144 CHECK_CLOSE_ABS(converted.covariance.value()(2, 2), 1, 1e-6);
0145
0146 BOOST_CHECK_GT(converted.covariance.value()(3, 3), 1);
0147 BOOST_CHECK_LT(converted.covariance.value()(3, 3), 1.2);
0148
0149 BOOST_CHECK_GT(converted.covariance.value()(4, 4), 0);
0150 BOOST_CHECK_EQUAL(converted.covariance.value()(5, 5), 25_ns);
0151
0152
0153 BoundTrackParameters roundtripPar =
0154 EDM4hepUtil::detail::convertTrackParametersFromEdm4hep(Bz, converted);
0155
0156 BOOST_CHECK_NE(dynamic_cast<const Acts::PerigeeSurface*>(
0157 &roundtripPar.referenceSurface()),
0158 nullptr);
0159
0160 BOOST_CHECK((converted.covariance.value().topLeftCorner<3, 3>().isApprox(
0161 roundtripPar.covariance().value().topLeftCorner<3, 3>())));
0162 CHECK_CLOSE_ABS(roundtripPar.covariance().value()(3, 3), 1, 1e-6);
0163 CHECK_CLOSE_ABS(roundtripPar.covariance().value()(4, 4), 1, 1e-6);
0164 BOOST_CHECK_EQUAL(roundtripPar.covariance().value()(5, 5), 25_ns);
0165
0166 auto roundtripPlaneBoundParams =
0167 Acts::detail::boundToBoundConversion(gctx, roundtripPar, *planeSurface)
0168 .value();
0169
0170 BOOST_CHECK(roundtripPlaneBoundParams.parameters().isApprox(par));
0171
0172 CHECK_CLOSE_COVARIANCE(roundtripPlaneBoundParams.covariance().value(),
0173 planePar.covariance().value(), 1e-3);
0174 }
0175
0176 BOOST_AUTO_TEST_CASE(ConvertTrackParametersToEdm4hepWithPerigeeNoCov) {
0177 auto refSurface = Surface::makeShared<PerigeeSurface>(Vector3{50, 30, 20});
0178
0179 BoundVector par;
0180 par << 1_mm, 5_mm, 0, M_PI_2, -1 / 1_GeV,
0181 5_ns;
0182
0183 BoundTrackParameters boundPar{refSurface, par, std::nullopt,
0184 ParticleHypothesis::pion()};
0185
0186 double Bz = 2_T;
0187
0188 Acts::GeometryContext gctx;
0189
0190 EDM4hepUtil::detail::Parameters converted =
0191 EDM4hepUtil::detail::convertTrackParametersToEdm4hep(gctx, Bz, boundPar);
0192
0193 BOOST_CHECK(!converted.covariance.has_value());
0194 BOOST_CHECK(converted.surface);
0195
0196
0197 BOOST_CHECK_EQUAL(par.template head<2>(),
0198 converted.values.template head<2>());
0199
0200
0201
0202 BoundTrackParameters roundtripPar =
0203 EDM4hepUtil::detail::convertTrackParametersFromEdm4hep(Bz, converted);
0204
0205 BOOST_CHECK(roundtripPar.parameters().isApprox(boundPar.parameters()));
0206 BOOST_CHECK(!roundtripPar.covariance().has_value());
0207 }
0208
0209 BOOST_AUTO_TEST_CASE(ConvertTrackParametersToEdm4hepWithOutPerigeeNoCov) {
0210 auto refSurface = Surface::makeShared<PlaneSurface>(
0211 Vector3{50, 30, 20}, Vector3{1, 1, 0.3}.normalized());
0212
0213 BoundVector par;
0214 par << 1_mm, 5_mm, M_PI / 4., M_PI_2, -1 / 1_GeV, 5_ns;
0215
0216 BoundTrackParameters boundPar{refSurface, par, std::nullopt,
0217 ParticleHypothesis::pion()};
0218
0219 double Bz = 2_T;
0220
0221 Acts::GeometryContext gctx;
0222
0223 EDM4hepUtil::detail::Parameters converted =
0224 EDM4hepUtil::detail::convertTrackParametersToEdm4hep(gctx, Bz, boundPar);
0225
0226 BOOST_CHECK(!converted.covariance.has_value());
0227 BOOST_CHECK(converted.surface);
0228
0229
0230 BOOST_CHECK_EQUAL(converted.values.template head<2>(), (Vector2{0, 0}));
0231 CHECK_CLOSE_ABS(converted.values[2], par[2], 1e-6);
0232
0233
0234 BoundTrackParameters roundtripPar =
0235 EDM4hepUtil::detail::convertTrackParametersFromEdm4hep(Bz, converted);
0236
0237 BOOST_CHECK_EQUAL(roundtripPar.parameters().template head<2>(),
0238 (Vector2{0, 0}));
0239 BOOST_CHECK(roundtripPar.parameters().tail<4>().isApprox(par.tail<4>()));
0240 BOOST_CHECK(!roundtripPar.covariance().has_value());
0241 }
0242
0243 BOOST_AUTO_TEST_CASE(CovariancePacking) {
0244 BoundMatrix m;
0245
0246 m << 1, 2, 3, 4, 5, 6,
0247 2, 2, 3, 4, 5, 6,
0248 3, 3, 3, 4, 5, 6,
0249 4, 4, 4, 4, 5, 6,
0250 5, 5, 5, 5, 5, 6,
0251 6, 6, 6, 6, 6, 6;
0252
0253
0254 std::array<float, 21> values{};
0255 EDM4hepUtil::detail::packCovariance(m, values.data());
0256
0257 BoundMatrix m2;
0258 m2.setZero();
0259 EDM4hepUtil::detail::unpackCovariance(values.data(), m2);
0260
0261 CHECK_CLOSE_ABS(m, m2, 1e-9);
0262 }
0263
0264 BOOST_AUTO_TEST_CASE(RoundTripTests) {
0265 auto trackContainer = std::make_shared<Acts::VectorTrackContainer>();
0266 auto trackStateContainer = std::make_shared<Acts::VectorMultiTrajectory>();
0267 TrackContainer tracks(trackContainer, trackStateContainer);
0268
0269 using mutable_proxy_t = decltype(tracks)::TrackProxy;
0270 using const_proxy_t = decltype(tracks)::ConstTrackProxy;
0271
0272 std::mt19937 rng{42};
0273 std::normal_distribution<double> gauss(0., 1.);
0274 std::uniform_real_distribution<double> f(-1, 1);
0275 std::uniform_real_distribution<double> r(0, 1);
0276 std::uniform_int_distribution<std::uint32_t> nTracks(2, 20);
0277 std::uniform_int_distribution<std::uint32_t> nTs(1, 20);
0278 std::uniform_real_distribution<double> phiDist(-M_PI, M_PI);
0279 std::uniform_real_distribution<double> etaDist(-4, 4);
0280 std::uniform_real_distribution<double> ptDist(1_MeV, 10_GeV);
0281 std::uniform_real_distribution<double> qDist(0., 1.);
0282
0283 auto genParams = [&]() -> std::pair<BoundVector, BoundMatrix> {
0284 double d0 = 20_um * gauss(rng);
0285 double z0 = 20_mm * gauss(rng);
0286 double phi = phiDist(rng);
0287 double eta = etaDist(rng);
0288 double theta = 2 * atan(exp(-eta));
0289 double pt = ptDist(rng);
0290 double p = pt / sin(theta);
0291 double charge = qDist(rng) > 0.5 ? 1. : -1.;
0292 double qop = charge / p;
0293 double t = 5_ns * gauss(rng);
0294
0295 BoundVector par;
0296 par << d0, z0, phi, theta, qop, t;
0297 BoundMatrix cov;
0298 cov = BoundMatrix::Identity();
0299 cov.diagonal() << 20_um * 20_um, 20_mm * 20_mm, 0.1, 0.1, 1_GeV, 25_ns;
0300 return {par, cov};
0301 };
0302
0303 std::uint32_t numT = nTracks(rng);
0304 for (std::uint32_t t = 0; t < numT; t++) {
0305 auto track = tracks.makeTrack();
0306 {
0307 auto [par, cov] = genParams();
0308 track.parameters() = par;
0309 track.covariance() = cov;
0310 }
0311 track.setReferenceSurface(
0312 Acts::Surface::makeShared<PerigeeSurface>(Vector3{0, 0, 0}));
0313
0314 std::uint32_t numTs = nTs(rng);
0315 for (std::uint32_t i = 0; i < numTs; i++) {
0316 auto ts = track.appendTrackState(TrackStatePropMask::Smoothed);
0317 double crit = r(rng);
0318 if (crit < 0.1) {
0319 ts.typeFlags().set(TrackStateFlag::HoleFlag);
0320 continue;
0321 } else if (crit < 0.2) {
0322 ts.typeFlags().set(TrackStateFlag::OutlierFlag);
0323 continue;
0324 } else if (crit < 0.3) {
0325 ts.typeFlags().set(TrackStateFlag::SharedHitFlag);
0326 } else if (crit < 0.4) {
0327 ts.typeFlags().set(TrackStateFlag::MaterialFlag);
0328 continue;
0329 }
0330
0331 ts.typeFlags().set(TrackStateFlag::MeasurementFlag);
0332
0333 auto [par, cov] = genParams();
0334 ts.smoothed() = par;
0335 ts.smoothedCovariance() = cov;
0336 Vector3 pos;
0337 pos << 1000 * f(rng), 1000 * f(rng), 3000 * f(rng);
0338 ts.setReferenceSurface(Acts::Surface::makeShared<PerigeeSurface>(pos));
0339 }
0340
0341 calculateTrackQuantities(track);
0342 }
0343
0344 edm4hep::TrackCollection edm4hepTracks;
0345
0346 Acts::GeometryContext gctx;
0347
0348 double Bz = 3_T;
0349
0350 auto logger = getDefaultLogger("EDM4hep", Logging::INFO);
0351
0352 for (const_proxy_t track : tracks) {
0353 auto to = edm4hepTracks.create();
0354 EDM4hepUtil::writeTrack(gctx, track, to, Bz, *logger);
0355 }
0356
0357 BOOST_CHECK_EQUAL(edm4hepTracks.size(), tracks.size());
0358
0359 auto tIt = tracks.begin();
0360 for (auto edm4hepTrack : edm4hepTracks) {
0361 auto track = *tIt;
0362 BOOST_CHECK_EQUAL(track.nMeasurements(),
0363 edm4hepTrack.trackStates_size() - 1);
0364
0365 ++tIt;
0366 }
0367
0368 const edm4hep::TrackCollection& edm4hepTracksConst = edm4hepTracks;
0369
0370 TrackContainer readTracks(std::make_shared<Acts::VectorTrackContainer>(),
0371 std::make_shared<Acts::VectorMultiTrajectory>());
0372
0373 for (const auto edm4hepTrack : edm4hepTracksConst) {
0374 EDM4hepUtil::readTrack(edm4hepTrack, readTracks.makeTrack(), Bz, *logger);
0375 }
0376
0377 BOOST_CHECK_EQUAL(tracks.size(), readTracks.size());
0378 std::size_t t = 0;
0379
0380 auto origTrackIt = tracks.begin();
0381 auto readTrackIt = readTracks.begin();
0382 while (origTrackIt != tracks.end() && readTrackIt != readTracks.end()) {
0383 BOOST_TEST_INFO_SCOPE("Track #" << t);
0384 auto orig = *origTrackIt;
0385 auto read = *readTrackIt;
0386
0387 CHECK_CLOSE_OR_SMALL(orig.parameters(), read.parameters(), 1e-5, 1e-8);
0388 CHECK_CLOSE_OR_SMALL(orig.covariance(), read.covariance(), 1e-5, 1e-8);
0389 BOOST_CHECK_EQUAL(orig.referenceSurface().center(gctx),
0390 read.referenceSurface().center(gctx));
0391
0392 auto origTsIt = orig.trackStatesReversed().begin();
0393 auto readTsIt = read.trackStatesReversed().begin();
0394
0395 std::size_t tsi = 0;
0396 while (origTsIt != orig.trackStatesReversed().end() &&
0397 readTsIt != read.trackStatesReversed().end()) {
0398 BOOST_TEST_INFO_SCOPE("TS: #" << tsi);
0399 auto nextMeas = std::find_if(
0400 origTsIt, orig.trackStatesReversed().end(), [](const auto& ts) {
0401 return ts.typeFlags().test(TrackStateFlag::MeasurementFlag);
0402 });
0403 BOOST_CHECK(nextMeas != orig.trackStatesReversed().end());
0404 origTsIt = nextMeas;
0405 auto origTs = *origTsIt;
0406 auto readTs = *readTsIt;
0407
0408 BOOST_TEST_INFO_SCOPE(
0409 "orig parameters: " << origTs.parameters().transpose());
0410 BOOST_TEST_INFO_SCOPE(
0411 "read parameters: " << readTs.parameters().transpose());
0412 CHECK_CLOSE_OR_SMALL(origTs.smoothedCovariance(),
0413 readTs.smoothedCovariance(), 1e-5, 1e-6);
0414 Vector3 newCenter = readTs.referenceSurface().center(
0415 gctx);
0416
0417 BOOST_CHECK(origTs.referenceSurface().isOnSurface(gctx, newCenter,
0418 Vector3::Zero()));
0419
0420
0421 Vector3 readGlobal = readTs.referenceSurface().localToGlobal(
0422 gctx, readTs.parameters().template head<2>(), Vector3::Zero());
0423 Vector3 origGlobal = origTs.referenceSurface().localToGlobal(
0424 gctx, origTs.parameters().template head<2>(), Vector3::Zero());
0425 CHECK_CLOSE_ABS(readGlobal, origGlobal, 1e-3);
0426 ++origTsIt;
0427 ++readTsIt;
0428 tsi++;
0429 }
0430 ++origTrackIt;
0431 ++readTrackIt;
0432
0433 t++;
0434 }
0435 }
0436
0437 BOOST_AUTO_TEST_SUITE_END()