File indexing completed on 2025-01-18 09:12:30
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Direction.hpp"
0012 #include "Acts/Definitions/Units.hpp"
0013 #include "Acts/EventData/TrackParameters.hpp"
0014 #include "Acts/Geometry/GeometryContext.hpp"
0015 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0016 #include "Acts/Surfaces/CylinderSurface.hpp"
0017 #include "Acts/Surfaces/DiscSurface.hpp"
0018 #include "Acts/Surfaces/PlaneSurface.hpp"
0019 #include "Acts/Surfaces/StrawSurface.hpp"
0020 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0021 #include "Acts/Utilities/UnitVectors.hpp"
0022 #include "Acts/Utilities/detail/periodic.hpp"
0023
0024 #include <numbers>
0025 #include <utility>
0026
0027
0028
0029
0030 inline Acts::CurvilinearTrackParameters makeParametersCurvilinear(
0031 double phi, double theta, double absMom, double charge) {
0032 using namespace Acts;
0033 using namespace Acts::UnitLiterals;
0034
0035
0036
0037 if (!((0 < theta) && (theta < std::numbers::pi))) {
0038 phi = 0;
0039 }
0040
0041 Vector4 pos4 = Vector4::Zero();
0042 auto particleHypothesis = ParticleHypothesis::pionLike(std::abs(charge));
0043 return CurvilinearTrackParameters(pos4, phi, theta,
0044 particleHypothesis.qOverP(absMom, charge),
0045 std::nullopt, particleHypothesis);
0046 }
0047
0048
0049 inline Acts::CurvilinearTrackParameters makeParametersCurvilinearWithCovariance(
0050 double phi, double theta, double absMom, double charge) {
0051 using namespace Acts;
0052 using namespace Acts::UnitLiterals;
0053
0054
0055
0056 if (!((0 < theta) && (theta < std::numbers::pi))) {
0057 phi = 0;
0058 }
0059
0060 BoundVector stddev = BoundVector::Zero();
0061
0062 stddev[eBoundLoc0] = 15_um;
0063 stddev[eBoundLoc1] = 80_um;
0064 stddev[eBoundTime] = 25_ns;
0065 stddev[eBoundPhi] = 1_degree;
0066 stddev[eBoundTheta] = 1.5_degree;
0067 stddev[eBoundQOverP] = 1_e / 10_GeV;
0068 BoundSquareMatrix corr = BoundSquareMatrix::Identity();
0069 corr(eBoundLoc0, eBoundLoc1) = corr(eBoundLoc1, eBoundLoc0) = 0.125;
0070 corr(eBoundLoc0, eBoundPhi) = corr(eBoundPhi, eBoundLoc0) = 0.25;
0071 corr(eBoundLoc1, eBoundTheta) = corr(eBoundTheta, eBoundLoc1) = -0.25;
0072 corr(eBoundTime, eBoundQOverP) = corr(eBoundQOverP, eBoundTime) = 0.125;
0073 corr(eBoundPhi, eBoundTheta) = corr(eBoundTheta, eBoundPhi) = -0.25;
0074 corr(eBoundPhi, eBoundQOverP) = corr(eBoundPhi, eBoundQOverP) = -0.125;
0075 corr(eBoundTheta, eBoundQOverP) = corr(eBoundTheta, eBoundQOverP) = 0.5;
0076 BoundSquareMatrix cov = stddev.asDiagonal() * corr * stddev.asDiagonal();
0077
0078 Vector4 pos4 = Vector4::Zero();
0079 auto particleHypothesis = ParticleHypothesis::pionLike(std::abs(charge));
0080 return CurvilinearTrackParameters(pos4, phi, theta,
0081 particleHypothesis.qOverP(absMom, charge),
0082 cov, particleHypothesis);
0083 }
0084
0085
0086 inline Acts::CurvilinearTrackParameters makeParametersCurvilinearNeutral(
0087 double phi, double theta, double absMom) {
0088 using namespace Acts;
0089 using namespace Acts::UnitLiterals;
0090
0091
0092
0093 if (!((0 < theta) && (theta < std::numbers::pi))) {
0094 phi = 0;
0095 }
0096
0097 Vector4 pos4 = Vector4::Zero();
0098 return CurvilinearTrackParameters(pos4, phi, theta, 1 / absMom, std::nullopt,
0099 ParticleHypothesis::pion0());
0100 }
0101
0102
0103
0104
0105
0106
0107 inline void checkParametersConsistency(const Acts::BoundTrackParameters& cmp,
0108 const Acts::BoundTrackParameters& ref,
0109 const Acts::GeometryContext& geoCtx,
0110 double epsPos, double epsDir,
0111 double epsMom) {
0112 using namespace Acts;
0113
0114
0115 CHECK_CLOSE_ABS(cmp.template get<eBoundLoc0>(),
0116 ref.template get<eBoundLoc0>(), epsPos);
0117 CHECK_CLOSE_ABS(cmp.template get<eBoundLoc1>(),
0118 ref.template get<eBoundLoc1>(), epsPos);
0119 CHECK_CLOSE_ABS(cmp.template get<eBoundTime>(),
0120 ref.template get<eBoundTime>(), epsPos);
0121
0122 CHECK_SMALL(detail::radian_sym(cmp.template get<eBoundPhi>() -
0123 ref.template get<eBoundPhi>()),
0124 epsDir);
0125 CHECK_CLOSE_ABS(cmp.template get<eBoundTheta>(),
0126 ref.template get<eBoundTheta>(), epsDir);
0127 CHECK_CLOSE_ABS(cmp.template get<eBoundQOverP>(),
0128 ref.template get<eBoundQOverP>(), epsMom);
0129
0130 CHECK_CLOSE_ABS(cmp.position(geoCtx), ref.position(geoCtx), epsPos);
0131 CHECK_CLOSE_ABS(cmp.time(), ref.time(), epsPos);
0132 CHECK_CLOSE_ABS(cmp.direction(), ref.direction(), epsDir);
0133 CHECK_CLOSE_ABS(cmp.absoluteMomentum(), ref.absoluteMomentum(), epsMom);
0134
0135 BOOST_CHECK_EQUAL(cmp.charge(), ref.charge());
0136 }
0137
0138
0139
0140
0141 inline void checkCovarianceConsistency(const Acts::BoundTrackParameters& cmp,
0142 const Acts::BoundTrackParameters& ref,
0143 double relativeTolerance) {
0144
0145 if (cmp.covariance().has_value()) {
0146
0147 BOOST_CHECK(ref.covariance().has_value());
0148 }
0149 if (ref.covariance().has_value()) {
0150
0151 BOOST_CHECK(cmp.covariance().has_value());
0152 }
0153 if (cmp.covariance().has_value() && ref.covariance().has_value()) {
0154 CHECK_CLOSE_COVARIANCE(cmp.covariance().value(), ref.covariance().value(),
0155 relativeTolerance);
0156 }
0157 }
0158
0159
0160
0161
0162 inline Acts::Transform3 makeCurvilinearTransform(
0163 const Acts::BoundTrackParameters& params,
0164 const Acts::GeometryContext& geoCtx) {
0165 Acts::Vector3 unitW = params.direction();
0166 auto [unitU, unitV] = Acts::makeCurvilinearUnitVectors(unitW);
0167
0168 Acts::RotationMatrix3 rotation = Acts::RotationMatrix3::Zero();
0169 rotation.col(0) = unitU;
0170 rotation.col(1) = unitV;
0171 rotation.col(2) = unitW;
0172 Acts::Translation3 offset(params.position(geoCtx));
0173 Acts::Transform3 toGlobal = offset * rotation;
0174
0175 return toGlobal;
0176 }
0177
0178
0179 struct ZCylinderSurfaceBuilder {
0180 std::shared_ptr<Acts::CylinderSurface> operator()(
0181 const Acts::BoundTrackParameters& params,
0182 const Acts::GeometryContext& geoCtx) {
0183 auto radius = params.position(geoCtx).template head<2>().norm();
0184 auto halfz = std::numeric_limits<double>::max();
0185 return Acts::Surface::makeShared<Acts::CylinderSurface>(
0186 Acts::Transform3::Identity(), radius, halfz);
0187 }
0188 };
0189
0190
0191 struct DiscSurfaceBuilder {
0192 std::shared_ptr<Acts::DiscSurface> operator()(
0193 const Acts::BoundTrackParameters& params,
0194 const Acts::GeometryContext& geoCtx) {
0195 using namespace Acts;
0196 using namespace Acts::UnitLiterals;
0197
0198 auto cl = makeCurvilinearTransform(params, geoCtx);
0199
0200
0201
0202
0203 Acts::Vector3 localOffset = Acts::Vector3::Zero();
0204 localOffset[Acts::ePos0] = 1_cm;
0205 localOffset[Acts::ePos1] = -1_cm;
0206 Acts::Vector3 globalOriginDelta = cl.linear() * localOffset;
0207 cl.pretranslate(globalOriginDelta);
0208
0209 return Acts::Surface::makeShared<Acts::DiscSurface>(cl);
0210 }
0211 };
0212
0213
0214 struct PlaneSurfaceBuilder {
0215 std::shared_ptr<Acts::PlaneSurface> operator()(
0216 const Acts::BoundTrackParameters& params,
0217 const Acts::GeometryContext& geoCtx) {
0218 return Acts::Surface::makeShared<Acts::PlaneSurface>(
0219 makeCurvilinearTransform(params, geoCtx));
0220 }
0221 };
0222
0223
0224 struct ZStrawSurfaceBuilder {
0225 std::shared_ptr<Acts::StrawSurface> operator()(
0226 const Acts::BoundTrackParameters& params,
0227 const Acts::GeometryContext& geoCtx) {
0228 return Acts::Surface::makeShared<Acts::StrawSurface>(
0229 Acts::Transform3(Acts::Translation3(params.position(geoCtx))));
0230 }
0231 };
0232
0233
0234
0235
0236
0237
0238 template <typename propagator_t,
0239 typename options_t = typename propagator_t::template Options<>>
0240 inline std::pair<Acts::CurvilinearTrackParameters, double> transportFreely(
0241 const propagator_t& propagator, const Acts::GeometryContext& geoCtx,
0242 const Acts::MagneticFieldContext& magCtx,
0243 const Acts::CurvilinearTrackParameters& initialParams, double pathLength) {
0244 using namespace Acts::UnitLiterals;
0245
0246
0247 options_t options(geoCtx, magCtx);
0248 options.direction = Acts::Direction::fromScalar(pathLength);
0249 options.pathLimit = pathLength;
0250 options.surfaceTolerance = 1_nm;
0251 options.stepping.stepTolerance = 1_nm;
0252
0253 auto result = propagator.propagate(initialParams, options);
0254 BOOST_CHECK(result.ok());
0255 BOOST_CHECK(result.value().endParameters);
0256
0257 return {*result.value().endParameters, result.value().pathLength};
0258 }
0259
0260
0261 template <typename propagator_t,
0262 typename options_t = typename propagator_t::template Options<>>
0263 inline std::pair<Acts::BoundTrackParameters, double> transportToSurface(
0264 const propagator_t& propagator, const Acts::GeometryContext& geoCtx,
0265 const Acts::MagneticFieldContext& magCtx,
0266 const Acts::CurvilinearTrackParameters& initialParams,
0267 const Acts::Surface& targetSurface, double pathLimit) {
0268 using namespace Acts::UnitLiterals;
0269
0270
0271 options_t options(geoCtx, magCtx);
0272 options.direction = Acts::Direction::Forward();
0273 options.pathLimit = pathLimit;
0274 options.surfaceTolerance = 1_nm;
0275 options.stepping.stepTolerance = 1_nm;
0276
0277 auto result = propagator.propagate(initialParams, targetSurface, options);
0278 BOOST_CHECK(result.ok());
0279 BOOST_CHECK(result.value().endParameters);
0280
0281 return {*result.value().endParameters, result.value().pathLength};
0282 }
0283
0284
0285
0286
0287
0288
0289 template <typename propagator_t,
0290 typename options_t = typename propagator_t::template Options<>>
0291 inline void runForwardBackwardTest(
0292 const propagator_t& propagator, const Acts::GeometryContext& geoCtx,
0293 const Acts::MagneticFieldContext& magCtx,
0294 const Acts::CurvilinearTrackParameters& initialParams, double pathLength,
0295 double epsPos, double epsDir, double epsMom) {
0296
0297 auto [fwdParams, fwdPathLength] = transportFreely<propagator_t, options_t>(
0298 propagator, geoCtx, magCtx, initialParams, pathLength);
0299 CHECK_CLOSE_ABS(fwdPathLength, pathLength, epsPos);
0300
0301 auto [bwdParams, bwdPathLength] = transportFreely<propagator_t, options_t>(
0302 propagator, geoCtx, magCtx, fwdParams, -pathLength);
0303 CHECK_CLOSE_ABS(bwdPathLength, -pathLength, epsPos);
0304
0305 checkParametersConsistency(initialParams, bwdParams, geoCtx, epsPos, epsDir,
0306 epsMom);
0307 }
0308
0309
0310
0311
0312
0313 template <typename propagator_t, typename surface_builder_t,
0314 typename options_t = typename propagator_t::template Options<>>
0315 inline void runToSurfaceTest(
0316 const propagator_t& propagator, const Acts::GeometryContext& geoCtx,
0317 const Acts::MagneticFieldContext& magCtx,
0318 const Acts::CurvilinearTrackParameters& initialParams, double pathLength,
0319 surface_builder_t&& buildTargetSurface, double epsPos, double epsDir,
0320 double epsMom) {
0321
0322 auto [freeParams, freePathLength] = transportFreely<propagator_t, options_t>(
0323 propagator, geoCtx, magCtx, initialParams, pathLength);
0324 CHECK_CLOSE_ABS(freePathLength, pathLength, epsPos);
0325
0326 auto surface = buildTargetSurface(freeParams, geoCtx);
0327 BOOST_CHECK(surface);
0328
0329
0330
0331 auto [surfParams, surfPathLength] =
0332 transportToSurface<propagator_t, options_t>(propagator, geoCtx, magCtx,
0333 initialParams, *surface,
0334 1.5 * pathLength);
0335 CHECK_CLOSE_ABS(surfPathLength, pathLength, epsPos);
0336
0337
0338 CHECK_CLOSE_ABS(surfParams.position(geoCtx), freeParams.position(geoCtx),
0339 epsPos);
0340 CHECK_CLOSE_ABS(surfParams.time(), freeParams.time(), epsPos);
0341 CHECK_CLOSE_ABS(surfParams.direction(), freeParams.direction(), epsDir);
0342 CHECK_CLOSE_ABS(surfParams.absoluteMomentum(), freeParams.absoluteMomentum(),
0343 epsMom);
0344 CHECK_CLOSE_ABS(surfPathLength, freePathLength, epsPos);
0345 }
0346
0347
0348
0349
0350
0351 template <typename cmp_propagator_t, typename ref_propagator_t>
0352 inline void runForwardComparisonTest(
0353 const cmp_propagator_t& cmpPropagator,
0354 const ref_propagator_t& refPropagator, const Acts::GeometryContext& geoCtx,
0355 const Acts::MagneticFieldContext& magCtx,
0356 const Acts::CurvilinearTrackParameters& initialParams, double pathLength,
0357 double epsPos, double epsDir, double epsMom, double tolCov) {
0358
0359 auto [cmpParams, cmpPath] = transportFreely<cmp_propagator_t>(
0360 cmpPropagator, geoCtx, magCtx, initialParams, pathLength);
0361 auto [refParams, refPath] = transportFreely<ref_propagator_t>(
0362 refPropagator, geoCtx, magCtx, initialParams, pathLength);
0363
0364 checkParametersConsistency(cmpParams, refParams, geoCtx, epsPos, epsDir,
0365 epsMom);
0366 checkCovarianceConsistency(cmpParams, refParams, tolCov);
0367 CHECK_CLOSE_ABS(cmpPath, pathLength, epsPos);
0368 CHECK_CLOSE_ABS(refPath, pathLength, epsPos);
0369 CHECK_CLOSE_ABS(cmpPath, refPath, epsPos);
0370 }
0371
0372
0373
0374
0375
0376 template <typename cmp_propagator_t, typename ref_propagator_t,
0377 typename surface_builder_t>
0378 inline void runToSurfaceComparisonTest(
0379 const cmp_propagator_t& cmpPropagator,
0380 const ref_propagator_t& refPropagator, const Acts::GeometryContext& geoCtx,
0381 const Acts::MagneticFieldContext& magCtx,
0382 const Acts::CurvilinearTrackParameters& initialParams, double pathLength,
0383 surface_builder_t&& buildTargetSurface, double epsPos, double epsDir,
0384 double epsMom, double tolCov) {
0385
0386 auto [freeParams, freePathLength] = transportFreely<ref_propagator_t>(
0387 refPropagator, geoCtx, magCtx, initialParams, pathLength);
0388 CHECK_CLOSE_ABS(freePathLength, pathLength, epsPos);
0389
0390
0391 auto surface = buildTargetSurface(freeParams, geoCtx);
0392 BOOST_CHECK(surface);
0393
0394
0395
0396 auto [cmpParams, cmpPath] = transportToSurface<cmp_propagator_t>(
0397 cmpPropagator, geoCtx, magCtx, initialParams, *surface, 1.5 * pathLength);
0398 auto [refParams, refPath] = transportToSurface<ref_propagator_t>(
0399 refPropagator, geoCtx, magCtx, initialParams, *surface, 1.5 * pathLength);
0400
0401 checkParametersConsistency(cmpParams, refParams, geoCtx, epsPos, epsDir,
0402 epsMom);
0403 checkCovarianceConsistency(cmpParams, refParams, tolCov);
0404 CHECK_CLOSE_ABS(cmpPath, pathLength, epsPos);
0405 CHECK_CLOSE_ABS(refPath, pathLength, epsPos);
0406 CHECK_CLOSE_ABS(cmpPath, refPath, epsPos);
0407 }