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