File indexing completed on 2025-08-05 08:09:48
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "Acts/Seeding/detail/StrawLineFitAuxiliaries.hpp"
0013 #include "Acts/Surfaces/detail/LineHelper.hpp"
0014 #include "Acts/Surfaces/detail/PlanarHelper.hpp"
0015 #include "Acts/Utilities/StringHelpers.hpp"
0016
0017 using namespace Acts;
0018 using namespace Acts::detail;
0019 using namespace Acts::Experimental::detail;
0020 using namespace Acts::UnitLiterals;
0021 using namespace Acts::PlanarHelper;
0022
0023 using Line_t = StrawLineFitAuxiliaries::Line_t;
0024 using Config_t = StrawLineFitAuxiliaries::Config;
0025 using ParIdx = StrawLineFitAuxiliaries::FitParIndex;
0026
0027 using Vector = Line_t::Vector;
0028 using Pars_t = Line_t::ParamVector;
0029
0030 namespace Acts::Test {
0031 class TestSpacePoint {
0032 public:
0033
0034
0035 enum ProjectorMask : std::size_t {
0036 bendingDir = 1 << 0,
0037 nonBendingDir = 1 << 1,
0038 timeOfArrival = 1 << 2,
0039 bothDirections = bendingDir | nonBendingDir
0040 };
0041
0042 TestSpacePoint(
0043 const Vector3& pos, const Vector3& wireDir, const double radius,
0044 bool measNonPrec = false,
0045 const std::array<double, 3>& cov = Acts::filledArray<double, 3>(0.))
0046 : m_pos{pos},
0047 m_dir{wireDir},
0048 m_radius{radius},
0049 m_dirMask{measNonPrec ? bothDirections : bendingDir},
0050 m_cov{cov} {}
0051
0052 TestSpacePoint(
0053 const Vector3& pos, const Vector3& stripDir, const Vector3& stripNorm,
0054 ProjectorMask mask,
0055 const std::array<double, 3>& cov = Acts::filledArray<double, 3>(0.))
0056 : m_pos{pos},
0057 m_dir{stripDir},
0058 m_toNext{stripNorm},
0059 m_dirMask{mask},
0060 m_cov{cov},
0061 m_isStraw{false} {}
0062
0063 const Vector3& localPosition() const { return m_pos; }
0064 const Vector3& sensorDirection() const { return m_dir; }
0065 const Vector3& toNextSensor() const { return m_toNext; }
0066 const Vector3& planeNormal() const { return m_planeNorm; }
0067
0068 bool isStraw() const { return m_isStraw; }
0069 bool hasTime() const {
0070 return (m_dirMask & (ProjectorMask::timeOfArrival)) != 0u;
0071 }
0072 bool measuresLoc1() const {
0073 return (m_dirMask & (ProjectorMask::bendingDir)) != 0u;
0074 }
0075 bool measuresLoc0() const {
0076 return (m_dirMask & (ProjectorMask::nonBendingDir)) != 0u;
0077 }
0078
0079 double driftRadius() const { return m_radius; }
0080 double time() const { return m_time; }
0081 const std::array<double, 3>& covariance() const { return m_cov; }
0082
0083 private:
0084 Vector3 m_pos{Vector3::Zero()};
0085 Vector3 m_dir{Vector3::Zero()};
0086 Vector3 m_toNext{Vector3::Zero()};
0087 Vector3 m_planeNorm{m_dir.cross(m_toNext).normalized()};
0088 double m_radius{0.};
0089 double m_time{0.};
0090 ProjectorMask m_dirMask{ProjectorMask::bothDirections};
0091 std::array<double, 3> m_cov{Acts::filledArray<double, 3>(0.)};
0092 bool m_isStraw{true};
0093 };
0094
0095 BOOST_AUTO_TEST_SUITE(StrawLineSeederTest)
0096
0097 void testResidual(const Pars_t& linePars, const TestSpacePoint& testPoint) {
0098 constexpr auto logLvl = Logging::Level::INFO;
0099 using namespace Acts::detail::LineHelper;
0100 using ResidualIdx = StrawLineFitAuxiliaries::ResidualIdx;
0101 Config_t resCfg{};
0102 resCfg.useHessian = true;
0103 resCfg.calcAlongStrip = false;
0104 resCfg.parsToUse = {ParIdx::x0, ParIdx::y0, ParIdx::phi, ParIdx::theta};
0105 Line_t line{};
0106 line.updateParameters(linePars);
0107
0108 std::cout << "\n\n\nResidual test - Test line: " << toString(line.position())
0109 << ", " << toString(line.direction()) << std::endl;
0110
0111 StrawLineFitAuxiliaries resCalc{resCfg,
0112 Acts::getDefaultLogger("testRes", logLvl)};
0113 resCalc.updateSpatialResidual(line, testPoint);
0114 if (testPoint.isStraw()) {
0115 const double lineDist =
0116 signedDistance(testPoint.localPosition(), testPoint.sensorDirection(),
0117 line.position(), line.direction());
0118 std::cout << "Test residual w.r.t. sp with position: "
0119 << toString(testPoint.localPosition())
0120 << ", orientation: " << toString(testPoint.sensorDirection())
0121 << ", r: " << testPoint.driftRadius() << std::endl;
0122
0123 std::cout << "Residual: " << toString(resCalc.residual())
0124 << ", line distance: " << lineDist << std::endl;
0125
0126 BOOST_CHECK_CLOSE(resCalc.residual()[ResidualIdx::bending],
0127 lineDist - testPoint.driftRadius(), 1.e-12);
0128 } else {
0129 std::cout << "Test residual w.r.t strip space point -- position: "
0130 << toString(testPoint.localPosition())
0131 << ", normal: " << toString(testPoint.planeNormal())
0132 << ", strip: " << toString(testPoint.sensorDirection())
0133 << ", to-next: " << toString(testPoint.toNextSensor())
0134 << std::endl;
0135 const Vector3& n{testPoint.planeNormal()};
0136 const Vector3 planeIsect = intersectPlane(line.position(), line.direction(),
0137 n, testPoint.localPosition())
0138 .position();
0139 const Vector3 delta = (planeIsect - testPoint.localPosition());
0140
0141 std::cout << "Residual: " << toString(resCalc.residual())
0142 << ", delta: " << toString(delta)
0143 << ", <delta, n> =" << delta.dot(n) << std::endl;
0144
0145 Acts::ActsSquareMatrix<3> coordTrf{Acts::ActsSquareMatrix<3>::Zero()};
0146 coordTrf.col(ResidualIdx::bending) = testPoint.measuresLoc1()
0147 ? testPoint.toNextSensor()
0148 : testPoint.sensorDirection();
0149 coordTrf.col(ResidualIdx::nonBending) = testPoint.measuresLoc1()
0150 ? testPoint.sensorDirection()
0151 : testPoint.toNextSensor();
0152 coordTrf.col(2) = n;
0153 std::cout << "Coordinate trf: \n" << coordTrf << std::endl;
0154
0155 const Vector3 trfDelta = coordTrf.inverse() * delta;
0156 std::cout << "Transformed delta: " << toString(trfDelta) << std::endl;
0157
0158 if (testPoint.measuresLoc1()) {
0159 BOOST_CHECK_CLOSE(trfDelta[ResidualIdx::bending],
0160 resCalc.residual()[ResidualIdx::bending], 1.e-10);
0161 } else {
0162 BOOST_CHECK_CLOSE(trfDelta[ResidualIdx::bending] *
0163 static_cast<double>(resCfg.calcAlongStrip),
0164 resCalc.residual()[ResidualIdx::bending], 1.e-10);
0165 }
0166
0167 if (testPoint.measuresLoc0()) {
0168 BOOST_CHECK_CLOSE(trfDelta[ResidualIdx::nonBending],
0169 resCalc.residual()[ResidualIdx::nonBending], 1.e-10);
0170 } else {
0171 BOOST_CHECK_CLOSE(trfDelta[ResidualIdx::nonBending] *
0172 static_cast<double>(resCfg.calcAlongStrip),
0173 resCalc.residual()[ResidualIdx::nonBending], 1.e-10);
0174 }
0175 }
0176
0177 constexpr double h = 5.e-9;
0178 constexpr double tolerance = 1.e-3;
0179 for (auto par : resCfg.parsToUse) {
0180 Pars_t lineParsUp{linePars}, lineParsDn{linePars};
0181 lineParsUp[static_cast<std::size_t>(par)] += h;
0182 lineParsDn[static_cast<std::size_t>(par)] -= h;
0183 Line_t lineUp{}, lineDn{};
0184 lineUp.updateParameters(lineParsUp);
0185 lineDn.updateParameters(lineParsDn);
0186
0187 StrawLineFitAuxiliaries resCalcUp{
0188 resCfg, Acts::getDefaultLogger("testResUp", logLvl)};
0189 StrawLineFitAuxiliaries resCalcDn{
0190 resCfg, Acts::getDefaultLogger("testResDn", logLvl)};
0191
0192 resCalcUp.updateSpatialResidual(lineUp, testPoint);
0193 resCalcDn.updateSpatialResidual(lineDn, testPoint);
0194
0195 const Vector numDeriv =
0196 (resCalcUp.residual() - resCalcDn.residual()) / (2. * h);
0197
0198 std::cout << "Derivative test: " << StrawLineFitAuxiliaries::parName(par)
0199 << ", derivative: " << toString(resCalc.gradient(par))
0200 << ", numerical: " << toString(numDeriv) << std::endl;
0201 BOOST_CHECK_LE((numDeriv - resCalc.gradient(par)).norm() /
0202 std::max(numDeriv.norm(), 1.),
0203 tolerance);
0204
0205 for (auto par1 : resCfg.parsToUse) {
0206 lineParsUp = linePars;
0207 lineParsDn = linePars;
0208 lineParsUp[static_cast<std::size_t>(par1)] += h;
0209 lineParsDn[static_cast<std::size_t>(par1)] -= h;
0210
0211 lineUp.updateParameters(lineParsUp);
0212 lineDn.updateParameters(lineParsDn);
0213
0214 resCalcUp.updateSpatialResidual(lineUp, testPoint);
0215 resCalcDn.updateSpatialResidual(lineDn, testPoint);
0216
0217 const Vector numDeriv1{
0218 (resCalcUp.gradient(par) - resCalcDn.gradient(par)) / (2. * h)};
0219 const Vector& analyticDeriv = resCalc.hessian(par, par1);
0220 std::cout << "Second deriv (" << StrawLineFitAuxiliaries::parName(par)
0221 << ", " << StrawLineFitAuxiliaries::parName(par1)
0222 << ") -- numerical: " << toString(numDeriv1)
0223 << ", analytic: " << toString(analyticDeriv) << std::endl;
0224 BOOST_CHECK_LE((numDeriv1 - analyticDeriv).norm(), tolerance);
0225 }
0226 }
0227 }
0228
0229 BOOST_AUTO_TEST_CASE(WireResidualTest) {
0230
0231 using Pars_t = Line_t::ParamVector;
0232 using ParIdx = Line_t::ParIndex;
0233 Pars_t linePars{};
0234 linePars[static_cast<std::size_t>(ParIdx::phi)] = 90. * 1_degree;
0235 linePars[static_cast<std::size_t>(ParIdx::theta)] = 45. * 1_degree;
0236
0237 const Vector wireDir = Vector::UnitX();
0238
0239 testResidual(linePars,
0240 TestSpacePoint{Vector{100. * 1_cm, 50. * 1_cm, 30. * 1_cm},
0241 wireDir, 10. * 1_cm});
0242 testResidual(
0243 linePars,
0244 TestSpacePoint{Vector{100. * 1_cm, 50. * 1_cm, 30. * 1_cm},
0245 makeDirectionFromPhiTheta(10. * 1_degree, 30. * 1_degree),
0246 10. * 1_cm});
0247
0248 testResidual(linePars,
0249 TestSpacePoint{Vector{100. * 1_cm, 50. * 1_cm, 30. * 1_cm},
0250 wireDir, 10. * 1_cm, true});
0251
0252 linePars[static_cast<std::size_t>(ParIdx::phi)] = 30. * 1_degree;
0253 linePars[static_cast<std::size_t>(ParIdx::theta)] = 60. * 1_degree;
0254
0255 testResidual(linePars,
0256 TestSpacePoint{Vector{100. * 1_cm, 50. * 1_cm, 30. * 1_cm},
0257 wireDir, 10. * 1_cm});
0258
0259 testResidual(linePars,
0260 TestSpacePoint{Vector{100. * 1_cm, 50. * 1_cm, 30. * 1_cm},
0261 wireDir, 10. * 1_cm, true});
0262
0263 linePars[static_cast<std::size_t>(ParIdx::phi)] = 60. * 1_degree;
0264 linePars[static_cast<std::size_t>(ParIdx::theta)] = 30. * 1_degree;
0265
0266 testResidual(linePars,
0267 TestSpacePoint{Vector{100. * 1_cm, 50. * 1_cm, 30. * 1_cm},
0268 wireDir, 10. * 1_cm});
0269 testResidual(linePars,
0270 TestSpacePoint{Vector{100. * 1_cm, 50. * 1_cm, 30. * 1_cm},
0271 wireDir, 10. * 1_cm, true});
0272
0273 testResidual(
0274 linePars,
0275 TestSpacePoint{Vector{100. * 1_cm, 50. * 1_cm, 30. * 1_cm},
0276 makeDirectionFromPhiTheta(20. * 1_degree, 30 * 1_degree),
0277 10. * 1_cm});
0278 testResidual(
0279 linePars,
0280 TestSpacePoint{Vector{100. * 1_cm, 50. * 1_cm, 30. * 1_cm},
0281 makeDirectionFromPhiTheta(40. * 1_degree, 50 * 1_degree),
0282 10. * 1_cm, true});
0283 }
0284
0285 BOOST_AUTO_TEST_CASE(StripResidual) {
0286 Pars_t linePars{};
0287 linePars[static_cast<std::size_t>(ParIdx::phi)] = 60. * 1_degree;
0288 linePars[static_cast<std::size_t>(ParIdx::theta)] = 45 * 1_degree;
0289
0290 testResidual(
0291 linePars,
0292 TestSpacePoint{Vector{75. * 1_cm, -75. * 1_cm, 100. * 1_cm},
0293 makeDirectionFromPhiTheta(90. * 1_degree, 90. * 1_degree),
0294 makeDirectionFromPhiTheta(0. * 1_degree, 90 * 1_degree),
0295 TestSpacePoint::bendingDir});
0296
0297 testResidual(
0298 linePars,
0299 TestSpacePoint{Vector{75. * 1_cm, -75. * 1_cm, 100. * 1_cm},
0300 makeDirectionFromPhiTheta(0. * 1_degree, 90. * 1_degree),
0301 makeDirectionFromPhiTheta(90. * 1_degree, 90 * 1_degree),
0302 TestSpacePoint::nonBendingDir});
0303
0304 testResidual(
0305 linePars,
0306 TestSpacePoint{Vector{75. * 1_cm, -75. * 1_cm, 100. * 1_cm},
0307 makeDirectionFromPhiTheta(90. * 1_degree, 90. * 1_degree),
0308 makeDirectionFromPhiTheta(0. * 1_degree, 90 * 1_degree),
0309 TestSpacePoint::bothDirections});
0310
0311 testResidual(
0312 linePars,
0313 TestSpacePoint{Vector{75. * 1_cm, -75. * 1_cm, 100. * 1_cm},
0314 makeDirectionFromPhiTheta(30. * 1_degree, 90. * 1_degree),
0315 makeDirectionFromPhiTheta(60. * 1_degree, 90 * 1_degree),
0316 TestSpacePoint::bothDirections});
0317 }
0318
0319 }
0320 BOOST_AUTO_TEST_SUITE_END()