File indexing completed on 2025-12-16 09:25:04
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Seeding/CombinatorialSeedSolver.hpp"
0012 #include "Acts/Surfaces/detail/LineHelper.hpp"
0013 #include "Acts/Surfaces/detail/PlanarHelper.hpp"
0014 #include "Acts/Utilities/detail/Polynomials.hpp"
0015
0016 #include <random>
0017
0018 #include "StrawHitGeneratorHelper.hpp"
0019
0020 using namespace Acts;
0021 using namespace Acts::detail;
0022 using namespace Acts::Experimental;
0023 using namespace Acts::Experimental::detail;
0024 using namespace Acts::UnitLiterals;
0025 using namespace Acts::PlanarHelper;
0026 using namespace Acts::detail::LineHelper;
0027 using namespace Acts::VectorHelpers;
0028
0029 using Line_t = CompSpacePointAuxiliaries::Line_t;
0030 using Config_t = CompSpacePointAuxiliaries::Config;
0031 using ParIdx = CompSpacePointAuxiliaries::FitParIndex;
0032 using ResidualIdx = CompSpacePointAuxiliaries::ResidualIdx;
0033
0034 using Vector = Line_t::Vector;
0035 using Pars_t = Line_t::ParamVector;
0036
0037 constexpr auto logLvl = Logging::Level::INFO;
0038 constexpr std::size_t nEvents = 100;
0039 constexpr double tolerance = 1.e-3;
0040
0041 ACTS_LOCAL_LOGGER(getDefaultLogger("StrawLineResidualTest", logLvl));
0042
0043 namespace ActsTests {
0044
0045 template <typename T>
0046 constexpr T absMax(const T& a, const T& b) {
0047 return std::max(Acts::abs(a), Acts::abs(b));
0048 }
0049 template <typename T, typename... argsT>
0050 constexpr T absMax(const T& a, const argsT... args) {
0051 return std::max(Acts::abs(a), absMax(args...));
0052 }
0053 double angle(const Vector& v1, const Vector& v2) {
0054 const double dots = Acts::abs(v1.dot(v2));
0055 return std::acos(std::clamp(dots, 0., 1.));
0056 }
0057
0058 #define CHECK_CLOSE(a, b, tol) \
0059 BOOST_CHECK_LE(std::abs(a - b) / absMax(a, b, 1.), tol);
0060
0061 #define COMPARE_VECTORS(v1, v2, tol) \
0062 { \
0063 CHECK_CLOSE(v1[toUnderlying(ResidualIdx::bending)], \
0064 v2[toUnderlying(ResidualIdx::bending)], tol); \
0065 CHECK_CLOSE(v1[toUnderlying(ResidualIdx::nonBending)], \
0066 v2[toUnderlying(ResidualIdx::nonBending)], tol); \
0067 CHECK_CLOSE(v1[toUnderlying(ResidualIdx::time)], \
0068 v2[toUnderlying(ResidualIdx::time)], tol); \
0069 }
0070
0071 BOOST_AUTO_TEST_SUITE(SeedingSuite)
0072
0073 void testResidual(const Pars_t& linePars, const FitTestSpacePoint& testPoint) {
0074 Config_t resCfg{};
0075 resCfg.useHessian = true;
0076 resCfg.calcAlongStrip = false;
0077 resCfg.parsToUse = {ParIdx::x0, ParIdx::y0, ParIdx::phi, ParIdx::theta};
0078 Line_t line{linePars};
0079
0080 ACTS_INFO(__func__ << "() - " << __LINE__
0081 << ":\n##############################################\n###"
0082 "###########################################\n"
0083 << "Residual test w.r.t. test line: "
0084 << toString(line.position()) << ", "
0085 << toString(line.direction())
0086 << ", theta: " << (theta(line.direction()) / 1._degree)
0087 << ", phi: " << (phi(line.direction())) / 1._degree);
0088
0089 CompSpacePointAuxiliaries resCalc{resCfg,
0090 Acts::getDefaultLogger("testRes", logLvl)};
0091 resCalc.updateSpatialResidual(line, testPoint);
0092 ACTS_INFO(__func__ << "() - " << __LINE__ << ": Test residual w.r.t. "
0093 << toString(testPoint));
0094 if (testPoint.isStraw()) {
0095 const double lineDist =
0096 signedDistance(testPoint.localPosition(), testPoint.sensorDirection(),
0097 line.position(), line.direction());
0098
0099 ACTS_INFO(__func__ << "() - " << __LINE__
0100 << ": Residual: " << toString(resCalc.residual())
0101 << ", line distance: " << lineDist
0102 << ", analog residual: "
0103 << (lineDist - testPoint.driftRadius()));
0104
0105 CHECK_CLOSE(resCalc.residual()[toUnderlying(ResidualIdx::bending)],
0106 (lineDist - testPoint.driftRadius()), 1.e-8);
0107 if (testPoint.measuresLoc0()) {
0108 auto closePoint =
0109 lineIntersect(line.position(), line.direction(),
0110 testPoint.localPosition(), testPoint.sensorDirection());
0111
0112 ACTS_INFO(__func__
0113 << "() - " << __LINE__ << ": Distance along wire "
0114 << closePoint.pathLength() << ", residual: "
0115 << resCalc.residual()[toUnderlying(ResidualIdx::nonBending)]);
0116
0117 CHECK_CLOSE(resCalc.residual()[toUnderlying(ResidualIdx::nonBending)],
0118 closePoint.pathLength(), 1.e-9);
0119 }
0120 } else {
0121 const Vector3& n{testPoint.planeNormal()};
0122 const Vector3 planeIsect = intersectPlane(line.position(), line.direction(),
0123 n, testPoint.localPosition())
0124 .position();
0125 const Vector3 delta = (planeIsect - testPoint.localPosition());
0126
0127 ACTS_DEBUG(__func__ << "() - " << __LINE__
0128 << ": Residual: " << toString(resCalc.residual())
0129 << ", delta: " << toString(delta)
0130 << ", <delta, n> =" << delta.dot(n));
0131
0132 Acts::ActsSquareMatrix<3> coordTrf{Acts::ActsSquareMatrix<3>::Zero()};
0133 coordTrf.col(toUnderlying(ResidualIdx::bending)) =
0134 testPoint.measuresLoc1() ? testPoint.toNextSensor()
0135 : testPoint.sensorDirection();
0136 coordTrf.col(toUnderlying(ResidualIdx::nonBending)) =
0137 testPoint.measuresLoc1() ? testPoint.sensorDirection()
0138 : testPoint.toNextSensor();
0139 coordTrf.col(2) = n;
0140 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Coordinate trf: \n"
0141 << toString(coordTrf));
0142
0143 const Vector3 trfDelta = coordTrf.inverse() * delta;
0144 ACTS_DEBUG(__func__ << "() - " << __LINE__
0145 << ": Transformed delta: " << toString(trfDelta));
0146
0147 if (testPoint.measuresLoc1()) {
0148 CHECK_CLOSE(trfDelta[toUnderlying(ResidualIdx::bending)],
0149 resCalc.residual()[toUnderlying(ResidualIdx::bending)],
0150 1.e-10);
0151 } else {
0152 CHECK_CLOSE(trfDelta[toUnderlying(ResidualIdx::bending)] *
0153 static_cast<double>(resCfg.calcAlongStrip),
0154 resCalc.residual()[toUnderlying(ResidualIdx::bending)],
0155 1.e-10);
0156 }
0157 if (testPoint.measuresLoc0()) {
0158 CHECK_CLOSE(trfDelta[toUnderlying(ResidualIdx::nonBending)],
0159 resCalc.residual()[toUnderlying(ResidualIdx::nonBending)],
0160 1.e-10);
0161 } else {
0162 CHECK_CLOSE(trfDelta[toUnderlying(ResidualIdx::nonBending)] *
0163 static_cast<double>(resCfg.calcAlongStrip),
0164 resCalc.residual()[toUnderlying(ResidualIdx::nonBending)],
0165 1.e-10);
0166 }
0167 }
0168
0169 constexpr double h = 2.e-7;
0170 for (auto par : resCfg.parsToUse) {
0171 Pars_t lineParsUp{linePars};
0172 Pars_t lineParsDn{linePars};
0173 lineParsUp[toUnderlying(par)] += h;
0174 lineParsDn[toUnderlying(par)] -= h;
0175 const Line_t lineUp{lineParsUp};
0176 const Line_t lineDn{lineParsDn};
0177
0178 CompSpacePointAuxiliaries resCalcUp{
0179 resCfg, Acts::getDefaultLogger("testResUp", logLvl)};
0180 CompSpacePointAuxiliaries resCalcDn{
0181 resCfg, Acts::getDefaultLogger("testResDn", logLvl)};
0182
0183 resCalcUp.updateSpatialResidual(lineUp, testPoint);
0184 resCalcDn.updateSpatialResidual(lineDn, testPoint);
0185
0186 const Vector numDeriv =
0187 (resCalcUp.residual() - resCalcDn.residual()) / (2. * h);
0188
0189 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Derivative test: "
0190 << CompSpacePointAuxiliaries::parName(par)
0191 << ", derivative: " << toString(resCalc.gradient(par))
0192 << ", numerical: " << toString(numDeriv));
0193
0194 COMPARE_VECTORS(numDeriv, resCalc.gradient(par), tolerance);
0195
0196 for (auto par1 : resCfg.parsToUse) {
0197 if (par1 > par) {
0198 break;
0199 }
0200 const Vector numDeriv1{
0201 (resCalcUp.gradient(par1) - resCalcDn.gradient(par1)) / (2. * h)};
0202 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Second deriv ("
0203 << CompSpacePointAuxiliaries::parName(par) << ", "
0204 << CompSpacePointAuxiliaries::parName(par1)
0205 << ") -- numerical: " << toString(numDeriv1)
0206 << ", analytic: "
0207 << toString(resCalc.hessian(par, par1)));
0208 COMPARE_VECTORS(numDeriv1, resCalc.hessian(par, par1), tolerance);
0209 }
0210 }
0211 }
0212
0213 void testSeed(
0214 const std::array<std::shared_ptr<FitTestSpacePoint>, 4>& spacePoints,
0215 const std::array<double, 4>& truthDistances, const Vector3& truthPosZ0,
0216 const Vector3& truthDir) {
0217 const SquareMatrix2 bMatrix =
0218 CombinatorialSeedSolver::betaMatrix(spacePoints);
0219 if (std::abs(bMatrix.determinant()) < std::numeric_limits<float>::epsilon()) {
0220 ACTS_VERBOSE(__func__ << "() " << __LINE__ << ": Beta Matrix \n"
0221 << toString(bMatrix)
0222 << "\nhas zero determinant - skip the combination");
0223 return;
0224 }
0225 const std::array<double, 4> distsAlongStrip =
0226 CombinatorialSeedSolver::defineParameters(bMatrix, spacePoints);
0227 const auto [seedPos, seedDir] =
0228 CombinatorialSeedSolver::seedSolution(spacePoints, distsAlongStrip);
0229
0230 ACTS_DEBUG(__func__ << "() " << __LINE__ << ": Reconstructed position "
0231 << toString(seedPos) << " and direction "
0232 << toString(seedDir));
0233 ACTS_DEBUG(__func__ << "() " << __LINE__ << ": Truth position "
0234 << toString(truthPosZ0) << " and truth direction "
0235 << toString(truthDir));
0236
0237
0238 for (std::size_t i = 0; i < truthDistances.size(); ++i) {
0239 CHECK_CLOSE(Acts::abs(distsAlongStrip[i] + truthDistances[i]), 0.,
0240 tolerance);
0241 }
0242
0243 COMPARE_VECTORS(seedPos, truthPosZ0, tolerance);
0244
0245 CHECK_CLOSE(std::abs(seedDir.dot(truthDir)), 1.,
0246 std::numeric_limits<float>::epsilon());
0247 }
0248
0249 void timeStripResidualTest(const Pars_t& linePars, const double timeT0,
0250 const FitTestSpacePoint& sp,
0251 const Acts::Transform3& locToGlob) {
0252 using ResidualIdx = CompSpacePointAuxiliaries::ResidualIdx;
0253 Config_t resCfg{};
0254 resCfg.localToGlobal = locToGlob;
0255 resCfg.useHessian = true;
0256 resCfg.calcAlongStrip = true;
0257 resCfg.parsToUse = {ParIdx::x0, ParIdx::y0, ParIdx::phi, ParIdx::theta,
0258 ParIdx::t0};
0259 Line_t line{linePars};
0260
0261 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Residual test for line: "
0262 << toString(line.position()) << ", "
0263 << toString(line.direction()) << " with t0: " << timeT0
0264 << ".");
0265
0266 CompSpacePointAuxiliaries resCalc{resCfg,
0267 Acts::getDefaultLogger("timeRes", logLvl)};
0268 resCalc.updateFullResidual(line, timeT0, sp);
0269
0270 const Vector3 planeIsect =
0271 intersectPlane(line.position(), line.direction(), sp.planeNormal(),
0272 sp.localPosition())
0273 .position();
0274 const double ToF =
0275 (locToGlob * planeIsect).norm() / Acts::PhysicalConstants::c + timeT0;
0276
0277 CHECK_CLOSE(resCalc.residual()[toUnderlying(ResidualIdx::time)],
0278 (sp.time() - ToF), 1.e-10);
0279 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Time of flight: " << ToF
0280 << ", measured time : " << sp.time() << " --> residual: "
0281 << (sp.time() - ToF) << " vs. from calculator: "
0282 << resCalc.residual()[toUnderlying(ResidualIdx::time)]
0283 << ".");
0284 constexpr double h = 5.e-9;
0285
0286 Line_t lineUp{}, lineDn{};
0287 for (const auto partial : resCfg.parsToUse) {
0288 CompSpacePointAuxiliaries resCalcUp{
0289 resCfg, Acts::getDefaultLogger("timeResUp", logLvl)};
0290 CompSpacePointAuxiliaries resCalcDn{
0291 resCfg, Acts::getDefaultLogger("timeResDn", logLvl)};
0292
0293 Pars_t lineParsUp{linePars}, lineParsDn{linePars};
0294
0295 if (partial != ParIdx::t0) {
0296 lineParsUp[toUnderlying(partial)] += h;
0297 lineParsDn[toUnderlying(partial)] -= h;
0298 lineUp.updateParameters(lineParsUp);
0299 lineDn.updateParameters(lineParsDn);
0300 resCalcUp.updateFullResidual(lineUp, timeT0, sp);
0301 resCalcDn.updateFullResidual(lineDn, timeT0, sp);
0302 } else {
0303 lineUp.updateParameters(lineParsUp);
0304 lineDn.updateParameters(lineParsDn);
0305 resCalcUp.updateFullResidual(line, timeT0 + h, sp);
0306 resCalcDn.updateFullResidual(line, timeT0 - h, sp);
0307 }
0308
0309 const Vector numDeriv =
0310 (resCalcUp.residual() - resCalcDn.residual()) / (2. * h);
0311
0312 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Derivative test: "
0313 << CompSpacePointAuxiliaries::parName(partial)
0314 << ", derivative: "
0315 << toString(resCalc.gradient(partial))
0316 << ", numerical: " << toString(numDeriv));
0317 COMPARE_VECTORS(numDeriv, resCalc.gradient(partial), tolerance);
0318 for (const auto partial2 : resCfg.parsToUse) {
0319 const Vector numDeriv1{
0320 (resCalcUp.gradient(partial2) - resCalcDn.gradient(partial2)) /
0321 (2. * h)};
0322 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Second deriv ("
0323 << CompSpacePointAuxiliaries::parName(partial) << ", "
0324 << CompSpacePointAuxiliaries::parName(partial2)
0325 << ") -- numerical: " << toString(numDeriv1)
0326 << ", analytic: "
0327 << toString(resCalc.hessian(partial, partial2)));
0328 COMPARE_VECTORS(numDeriv1, resCalc.hessian(partial, partial2), tolerance);
0329 }
0330 }
0331 }
0332 BOOST_AUTO_TEST_CASE(StrawDriftTimeCase) {
0333 ACTS_INFO("Calibration straw point test ");
0334
0335 constexpr double recordedT = 15._ns;
0336 constexpr std::array<double, 3> rtCoeffs{0., 75. / 1_ns,
0337 5000. / Acts::pow(1_ns, 2)};
0338
0339 Config_t resCfg{};
0340 resCfg.useHessian = true;
0341 resCfg.calcAlongStrip = true;
0342 resCfg.parsToUse = {ParIdx::x0, ParIdx::phi, ParIdx::y0, ParIdx::theta,
0343 ParIdx::t0};
0344
0345 auto makeCalculator = [&rtCoeffs, &resCfg](
0346 const std::string& calcName, const Pars_t& linePars,
0347 const Vector& pos, const Vector& dir,
0348 const double t0) {
0349 Line_t line{linePars};
0350 ACTS_DEBUG(__func__ << "() " << __LINE__ << ": Calculate residual w.r.t. "
0351 << toString(line.position()) << ", "
0352 << toString(line.direction()));
0353 auto isectP = lineIntersect(pos, dir, line.position(), line.direction());
0354
0355 const double driftT = recordedT -
0356 (resCfg.localToGlobal * isectP.position()).norm() /
0357 PhysicalConstants::c -
0358 t0;
0359
0360 const double driftR = polynomialSum(driftT, rtCoeffs);
0361 const double driftV = derivativeSum<1>(driftT, rtCoeffs);
0362 const double driftA = derivativeSum<2>(driftT, rtCoeffs);
0363 ACTS_DEBUG(__func__ << "() " << __LINE__ << ": Create new space point @ "
0364 << toString(pos) << ", " << toString(dir)
0365 << ", using t0: " << t0 / 1._ns << " --> drfitT: "
0366 << driftT / 1._ns << " --> driftR: " << driftR
0367 << ", driftV: " << driftV << ", "
0368 << "driftA: " << driftA);
0369
0370 CompSpacePointAuxiliaries resCalc{resCfg,
0371 Acts::getDefaultLogger(calcName, logLvl)};
0372
0373 resCalc.updateFullResidual(
0374 line, t0,
0375 FitTestSpacePoint{pos, dir, driftR, SpCalibrator::driftUncert(driftR)},
0376 driftV, driftA);
0377 return resCalc;
0378 };
0379
0380 auto testTimingResidual = [&makeCalculator, &resCfg](
0381 const Pars_t& linePars, const Vector& wPos,
0382 const Vector& wDir, const double t0) {
0383 auto resCalc = makeCalculator("strawT0Res", linePars, wPos, wDir, t0);
0384 ACTS_DEBUG(__func__ << "() - " << __LINE__
0385 << ": Residual: " << toString(resCalc.residual()));
0386 for (const auto partial : resCfg.parsToUse) {
0387 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": *** partial: "
0388 << CompSpacePointAuxiliaries::parName(partial) << " "
0389 << toString(resCalc.gradient(partial)));
0390 }
0391 constexpr double h = 1.e-7;
0392 for (const auto partial : resCfg.parsToUse) {
0393 Pars_t lineParsUp{linePars}, lineParsDn{linePars};
0394 double t0Up{t0}, t0Dn{t0};
0395 if (partial != ParIdx::t0) {
0396 lineParsUp[toUnderlying(partial)] += h;
0397 lineParsDn[toUnderlying(partial)] -= h;
0398 } else {
0399 t0Up += h;
0400 t0Dn -= h;
0401 }
0402 auto resCalcUp =
0403 makeCalculator("strawT0ResUp", lineParsUp, wPos, wDir, t0Up);
0404 auto resCalcDn =
0405 makeCalculator("strawT0ResDn", lineParsDn, wPos, wDir, t0Dn);
0406
0407 const Vector numDeriv =
0408 (resCalcUp.residual() - resCalcDn.residual()) / (2. * h);
0409 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Partial "
0410 << CompSpacePointAuxiliaries::parName(partial)
0411 << " -- numerical: " << toString(numDeriv)
0412 << ", analytical: "
0413 << toString(resCalc.gradient(partial)));
0414
0415 COMPARE_VECTORS(numDeriv, resCalc.gradient(partial), tolerance);
0416 for (const auto partial2 : resCfg.parsToUse) {
0417 const Vector numDeriv1{
0418 (resCalcUp.gradient(partial2) - resCalcDn.gradient(partial2)) /
0419 (2. * h)};
0420 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Second deriv ("
0421 << CompSpacePointAuxiliaries::parName(partial)
0422 << ", "
0423 << CompSpacePointAuxiliaries::parName(partial2)
0424 << ") -- numerical: " << toString(numDeriv1)
0425 << ", analytic: "
0426 << toString(resCalc.hessian(partial, partial2)));
0427 COMPARE_VECTORS(numDeriv1, resCalc.hessian(partial, partial2),
0428 tolerance);
0429 }
0430 }
0431 };
0432
0433 RandomEngine rndEngine{4711};
0434
0435 const Vector wirePos{100._cm, 50._cm, 30._cm};
0436 for (std::size_t e = 0; e < nEvents; ++e) {
0437 break;
0438 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Run test event: " << e);
0439 resCfg.localToGlobal = Acts::Transform3::Identity();
0440 Line_t line{generateLine(rndEngine, logger())};
0441 const double t0 = uniform{0_ns, 50._ns}(rndEngine);
0442
0443 testTimingResidual(line.parameters(), wirePos, Vector::UnitX(), t0);
0444 testTimingResidual(line.parameters(), wirePos,
0445 Vector{1., 1., 0.}.normalized(), t0);
0446 resCfg.localToGlobal.translation() =
0447 Vector{uniform{-10._cm, 10._cm}(rndEngine),
0448 uniform{-20._cm, 20._cm}(rndEngine),
0449 uniform{-30._cm, 30._cm}(rndEngine)};
0450 testTimingResidual(line.parameters(), wirePos, Vector::UnitX(), t0);
0451 testTimingResidual(line.parameters(), wirePos,
0452 Vector{1., 1., 0.}.normalized(), t0);
0453
0454
0455 resCfg.localToGlobal *=
0456 Acts::AngleAxis3{uniform{-30._degree, 30._degree}(rndEngine),
0457 makeDirectionFromPhiTheta(
0458 uniform{-30._degree, 30._degree}(rndEngine),
0459 uniform{-45._degree, -35._degree}(rndEngine))};
0460 testTimingResidual(line.parameters(), wirePos, Vector::UnitX(), t0);
0461 testTimingResidual(line.parameters(), wirePos,
0462 Vector{1., 1., 0.}.normalized(), t0);
0463 }
0464 }
0465 BOOST_AUTO_TEST_CASE(WireResidualTest) {
0466 RandomEngine rndEngine{2525};
0467 ACTS_INFO("Run WireResidualTest");
0468 const Vector wirePos{100._cm, 50._cm, 30._cm};
0469 const Vector wireDir1{Vector::UnitX()};
0470 const Vector wireDir2{makeDirectionFromPhiTheta(10._degree, 30._degree)};
0471
0472 for (std::size_t e = 0; e < nEvents; ++e) {
0473 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Run test event: " << e);
0474 const Line_t line{generateLine(rndEngine, logger())};
0475
0476 constexpr double R = 10._cm;
0477 const double dR = SpCalibrator::driftUncert(R);
0478 constexpr double uncertWire = 1._cm;
0479 testResidual(line.parameters(),
0480 FitTestSpacePoint{wirePos, wireDir1, R, dR});
0481
0482 testResidual(line.parameters(),
0483 FitTestSpacePoint{wirePos, wireDir2, R, dR});
0484
0485 auto isect =
0486 lineIntersect(line.position(), line.direction(), wirePos, wireDir1);
0487
0488 testResidual(line.parameters(),
0489 FitTestSpacePoint{isect.position() + uniform{-50._cm, 50._cm}(
0490 rndEngine)*wireDir1,
0491 wireDir1, R, dR, uncertWire});
0492
0493 isect = lineIntersect(line.position(), line.direction(), wirePos, wireDir2);
0494 testResidual(line.parameters(),
0495 FitTestSpacePoint{isect.position() + uniform{-50._cm, 50._cm}(
0496 rndEngine)*wireDir2,
0497 wireDir2, R, dR, uncertWire});
0498 }
0499 }
0500 BOOST_AUTO_TEST_CASE(StripResidual) {
0501 ACTS_INFO("Run StripResidualTest");
0502 RandomEngine rndEngine{2505};
0503 const Vector stripPos{75._cm, -75._cm, 100._cm};
0504 const Vector b1{makeDirectionFromPhiTheta(90._degree, 90._degree)};
0505 const Vector b2{makeDirectionFromPhiTheta(0._degree, 90_degree)};
0506 for (std::size_t e = 0; e < nEvents; ++e) {
0507 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Run test event: " << e);
0508 Pars_t linePars{generateLine(rndEngine, logger()).parameters()};
0509
0510
0511 testResidual(linePars, FitTestSpacePoint{stripPos, b1, b2, 0._cm, 1._cm});
0512
0513 testResidual(linePars, FitTestSpacePoint{stripPos, b2, b1, 1._cm, 0._cm});
0514
0515 testResidual(linePars, FitTestSpacePoint{stripPos, b1, b2, 1._cm, 1._cm});
0516 const Vector b3 = makeDirectionFromPhiTheta(30._degree, 90._degree);
0517 const Vector b4 = makeDirectionFromPhiTheta(60._degree, 90._degree);
0518
0519 testResidual(linePars, FitTestSpacePoint{stripPos, b3, b4, 1._cm, 1._cm});
0520 }
0521 }
0522
0523 BOOST_AUTO_TEST_CASE(TimeStripResidual) {
0524 Pars_t linePars{};
0525 linePars[toUnderlying(ParIdx::phi)] = 60._degree;
0526 linePars[toUnderlying(ParIdx::theta)] = 45_degree;
0527
0528 Acts::Transform3 locToGlob{Acts::Transform3::Identity()};
0529
0530 const Vector pos{75._cm, -75._cm, 100._cm};
0531 const Vector pos1{75._cm, -75._cm, 200._cm};
0532
0533 const Vector b1{makeDirectionFromPhiTheta(30._degree, 90._degree)};
0534 const Vector b2{makeDirectionFromPhiTheta(60._degree, 90._degree)};
0535 const Vector b3{makeDirectionFromPhiTheta(00._degree, 90._degree)};
0536 const Vector b4{makeDirectionFromPhiTheta(60._degree, 75._degree)};
0537 const std::array cov{Acts::square(10._cm), Acts::square(10._cm),
0538 Acts::square(1._ns)};
0539 FitTestSpacePoint p1{pos, b1, b2, 15._ns, cov};
0540
0541 FitTestSpacePoint p2{pos1, b3, b4, 15._ns, cov};
0542
0543 timeStripResidualTest(linePars, 10., p1, locToGlob);
0544
0545 timeStripResidualTest(linePars, 10., p2, locToGlob);
0546
0547 locToGlob.translation() = Vector{75._cm, -75._cm, -35._cm};
0548 timeStripResidualTest(linePars, 10., p1, locToGlob);
0549
0550 timeStripResidualTest(linePars, 10., p2, locToGlob);
0551 locToGlob *= Acts::AngleAxis3{
0552 30_degree, makeDirectionFromPhiTheta(30_degree, -45_degree)};
0553 timeStripResidualTest(linePars, 10., p1, locToGlob);
0554
0555 timeStripResidualTest(linePars, 10., p2, locToGlob);
0556 }
0557
0558 BOOST_AUTO_TEST_CASE(ChiSqEvaluation) {
0559 Pars_t linePars{};
0560 linePars[toUnderlying(ParIdx::phi)] = 30._degree;
0561 linePars[toUnderlying(ParIdx::theta)] = 75_degree;
0562 linePars[toUnderlying(ParIdx::x0)] = 10._cm;
0563 linePars[toUnderlying(ParIdx::y0)] = -10_cm;
0564
0565 Config_t resCfg{};
0566 resCfg.useHessian = true;
0567 resCfg.calcAlongStrip = true;
0568 resCfg.parsToUse = {ParIdx::x0, ParIdx::phi, ParIdx::y0, ParIdx::theta,
0569 ParIdx::t0};
0570
0571 Line_t line{linePars};
0572
0573 CompSpacePointAuxiliaries resCalc{resCfg,
0574 Acts::getDefaultLogger("testRes", logLvl)};
0575
0576 const double t0{1._ns};
0577
0578 auto testChi2 = [&line, &t0, &resCalc,
0579 &resCfg](const FitTestSpacePoint& testMe) {
0580 using ChiSq_t = CompSpacePointAuxiliaries::ChiSqWithDerivatives;
0581 ChiSq_t chi2{};
0582 ACTS_DEBUG(__func__ << "() " << __LINE__ << ": Test space point "
0583 << toString(testMe));
0584
0585 resCalc.updateFullResidual(line, t0, testMe);
0586
0587 resCalc.updateChiSq(chi2, testMe.covariance());
0588 resCalc.symmetrizeHessian(chi2);
0589 constexpr auto N = 5u;
0590 for (std::size_t i = 1; i < N; ++i) {
0591 for (std::size_t j = 0; j <= i; ++j) {
0592 BOOST_CHECK_EQUAL(chi2.hessian(i, j), chi2.hessian(j, i));
0593 }
0594 }
0595
0596 ACTS_DEBUG(__func__ << "() - " << __LINE__
0597 << ": Calculated chi2: " << chi2.chi2 << ", Gradient: "
0598 << toString(chi2.gradient) << ", Hessian: \n"
0599 << toString(chi2.hessian)
0600 << "\ndeterminant: " << chi2.hessian.determinant());
0601 CHECK_CLOSE(CompSpacePointAuxiliaries::chi2Term(line, resCfg.localToGlobal,
0602 t0, testMe),
0603 chi2.chi2, 1.e-10);
0604
0605 constexpr double h = 1.e-7;
0606 for (const auto par : resCfg.parsToUse) {
0607 Pars_t lineParsUp{line.parameters()};
0608 Pars_t lineParsDn{line.parameters()};
0609
0610 const auto dIdx = toUnderlying(par);
0611 double t0Up{t0}, t0Dn{t0};
0612 if (par != ParIdx::t0) {
0613 lineParsUp[dIdx] += h;
0614 lineParsDn[dIdx] -= h;
0615 } else {
0616 t0Up += h;
0617 t0Dn -= h;
0618 }
0619 ChiSq_t chi2Up{}, chi2Dn{};
0620
0621 line.updateParameters(lineParsUp);
0622 resCalc.updateFullResidual(line, t0Up, testMe);
0623 resCalc.updateChiSq(chi2Up, testMe.covariance());
0624
0625 line.updateParameters(lineParsDn);
0626 resCalc.updateFullResidual(line, t0Dn, testMe);
0627 resCalc.updateChiSq(chi2Dn, testMe.covariance());
0628
0629 const double anaDeriv = chi2.gradient[dIdx];
0630 const double numDeriv = (chi2Up.chi2 - chi2Dn.chi2) / (2. * h);
0631
0632 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Partial "
0633 << CompSpacePointAuxiliaries::parName(par)
0634 << " -- numerical: " << numDeriv
0635 << ", analytical: " << anaDeriv);
0636 CHECK_CLOSE(numDeriv, anaDeriv, tolerance);
0637 for (const auto par2 : resCfg.parsToUse) {
0638 if (par2 > par) {
0639 break;
0640 }
0641 const auto dIdx2 = toUnderlying(par2);
0642 const double anaHess = chi2.hessian(dIdx, dIdx2);
0643 const double numHess =
0644 (chi2Up.gradient[dIdx2] - chi2Dn.gradient[dIdx2]) / (2. * h);
0645
0646 ACTS_DEBUG(__func__ << "() - " << __LINE__ << ": Second deriv ("
0647 << CompSpacePointAuxiliaries::parName(par) << ", "
0648 << CompSpacePointAuxiliaries::parName(par2)
0649 << ") -- numerical: " << numHess
0650 << ", analytic: " << anaHess);
0651 CHECK_CLOSE(anaHess, numHess, tolerance);
0652 }
0653 }
0654 };
0655
0656
0657 testChi2(FitTestSpacePoint{
0658 line.point(20._cm) + 5._cm * line.direction().cross(Vector::UnitX()),
0659 makeDirectionFromPhiTheta(0_degree, 90._degree),
0660 makeDirectionFromPhiTheta(90._degree, 0._degree),
0661 15._ns,
0662 {Acts::pow(5._cm, 2), Acts::pow(10._cm, 2), Acts::pow(1._ns, 2)}});
0663
0664
0665 testChi2(FitTestSpacePoint{
0666 line.point(20._cm) + 5._cm * line.direction().cross(Vector::UnitX()),
0667 makeDirectionFromPhiTheta(0_degree, 45._degree),
0668 makeDirectionFromPhiTheta(60._degree, 0._degree),
0669 15._ns,
0670 {Acts::pow(5._cm, 2), Acts::pow(10._cm, 2), Acts::pow(1._ns, 2)}});
0671
0672 testChi2(FitTestSpacePoint{
0673 line.point(20._cm) + 5._cm * line.direction().cross(Vector::UnitX()),
0674 Vector3::UnitX(), 5._cm, 10._mm});
0675
0676
0677
0678 testChi2(FitTestSpacePoint{
0679 line.point(20._cm) + 5._cm * line.direction().cross(Vector::UnitX()) +
0680 4._cm * Vector::UnitX(),
0681 Vector3::UnitX(), 5._cm, 0.5_cm});
0682 }
0683
0684 BOOST_AUTO_TEST_CASE(CombinatorialSeedSolverStripsTest) {
0685 ACTS_INFO("Run Combinatorial seed test");
0686 RandomEngine rndEngine{23568};
0687 constexpr std::size_t nStrips = 8;
0688
0689 const std::array<Vector3, nStrips> stripDirections{
0690 Vector3::UnitX(),
0691 Vector3::UnitX(),
0692 makeDirectionFromPhiTheta(1.5_degree, 90_degree),
0693 makeDirectionFromPhiTheta(-1.5_degree, 90_degree),
0694 makeDirectionFromPhiTheta(1.5_degree, 90_degree),
0695 makeDirectionFromPhiTheta(-1.5_degree, 90_degree),
0696 Vector3::UnitX(),
0697 Vector3::UnitX()};
0698
0699 constexpr std::array<double, nStrips> distancesZ{-20., -264., 0., 300.,
0700 350, 370., 400, 450.};
0701
0702 std::array<double, nStrips> parameters{};
0703 std::array<Vector3, nStrips> intersections{};
0704
0705
0706
0707 for (std::size_t i = 0; i < nEvents; ++i) {
0708 ACTS_DEBUG(__func__ << "() " << __LINE__ << " - Combinatorial Seed test - "
0709 << "Processing Event: " << i);
0710
0711 Line_t line{generateLine(rndEngine, logger())};
0712
0713 const Vector3& muonPos = line.position();
0714 const Vector3& muonDir = line.direction();
0715
0716 std::array<std::shared_ptr<FitTestSpacePoint>, nStrips> spacePoints{};
0717 for (std::size_t layer = 0; layer < nStrips; ++layer) {
0718 auto intersection = PlanarHelper::intersectPlane(
0719 muonPos, muonDir, Vector3::UnitZ(), distancesZ[layer]);
0720 intersections[layer] = intersection.position();
0721
0722 auto alongStrip = PlanarHelper::intersectPlane(
0723 intersections[layer], stripDirections[layer], Vector3::UnitX(), 0.);
0724
0725 parameters[layer] = alongStrip.pathLength();
0726
0727 Vector3 stripPos =
0728 intersections[layer] + parameters[layer] * stripDirections[layer];
0729
0730 spacePoints[layer] = std::make_shared<FitTestSpacePoint>(
0731 stripPos, stripDirections[layer], Vector3::UnitZ(), 1._cm, 0._cm);
0732 }
0733
0734
0735
0736 std::array<std::shared_ptr<FitTestSpacePoint>, 4> seedSpacePoints{};
0737 for (unsigned int l = 0; l < distancesZ.size() - 3; ++l) {
0738 seedSpacePoints[0] = spacePoints[l];
0739 for (unsigned int k = l + 1; k < distancesZ.size() - 2; ++k) {
0740 seedSpacePoints[1] = spacePoints[k];
0741 for (unsigned int m = k + 1; m < distancesZ.size() - 1; ++m) {
0742 seedSpacePoints[2] = spacePoints[m];
0743 for (unsigned int n = m + 1; n < distancesZ.size(); ++n) {
0744 seedSpacePoints[3] = spacePoints[n];
0745
0746 const std::array<double, 4> truthDistances = {
0747 parameters[l], parameters[k], parameters[m], parameters[n]};
0748
0749 testSeed(seedSpacePoints, truthDistances, muonPos, muonDir);
0750 }
0751 }
0752 }
0753 }
0754 }
0755 }
0756
0757 }
0758 BOOST_AUTO_TEST_SUITE_END()