File indexing completed on 2026-10-20 08:42:21
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Alignment.hpp"
0013 #include "Acts/Definitions/TrackParametrization.hpp"
0014 #include "Acts/Surfaces/PlaneSurface.hpp"
0015 #include "Acts/Surfaces/RectangleBounds.hpp"
0016 #include "Acts/Surfaces/Surface.hpp"
0017 #include "Acts/Utilities/Logger.hpp"
0018 #include "ActsAlignment/Kernel/detail/AlignmentEngine.hpp"
0019 #include "ActsPlugins/Mille/ActsToMille.hpp"
0020
0021 #include <cmath>
0022 #include <memory>
0023 #include <string>
0024 #include <unordered_map>
0025 #include <vector>
0026
0027 #include "Mille/MilleDecoder.h"
0028 #include "Mille/MilleFactory.h"
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 BOOST_AUTO_TEST_SUITE(ActsToMillePseudoResidualsTests)
0039
0040 BOOST_AUTO_TEST_CASE(SmoothedTrackIsLocalFitMinimum) {
0041
0042 constexpr std::size_t nStates = 3;
0043 constexpr std::size_t nPar = nStates * Acts::eBoundSize;
0044 constexpr std::size_t nMeas = 2 * nStates;
0045
0046 constexpr std::size_t iMeasNotAligned = nMeas - 1;
0047
0048 auto surface = Acts::Surface::makeShared<Acts::PlaneSurface>(
0049 Acts::Transform3::Identity(),
0050 std::make_shared<Acts::RectangleBounds>(10., 10.));
0051
0052 ActsAlignment::detail::TrackAlignmentState state;
0053 state.measurementDim = nMeas;
0054 state.trackParametersDim = nPar;
0055 state.alignmentDof = Acts::eAlignmentSize;
0056 state.alignedSurfaces.emplace(surface.get(), std::make_pair(0u, 0u));
0057
0058 state.measurementCovariance =
0059 Acts::DynamicMatrix::Identity(nMeas, nMeas) * 0.05 * 0.05;
0060 state.projectionMatrix = Acts::DynamicMatrix::Zero(nMeas, nPar);
0061 for (std::size_t s = 0; s < nStates; ++s) {
0062 const std::size_t o = s * Acts::eBoundSize;
0063 state.projectionMatrix(2 * s, o + Acts::eBoundLoc0) = 1.;
0064 state.projectionMatrix(2 * s + 1, o + Acts::eBoundLoc1) = 1.;
0065 }
0066
0067
0068
0069
0070 Acts::DynamicMatrix b(nPar, nPar);
0071 for (std::size_t i = 0; i < nPar; ++i) {
0072 for (std::size_t j = 0; j < nPar; ++j) {
0073 b(i, j) = std::sin(1. + i + 2. * j);
0074 }
0075 }
0076 const Acts::DynamicMatrix correlationTerm =
0077 b.transpose() * b + Acts::DynamicMatrix::Identity(nPar, nPar);
0078 const Acts::DynamicMatrix weightMatMeasurements =
0079 state.projectionMatrix.transpose() *
0080 state.measurementCovariance.inverse() * state.projectionMatrix;
0081 state.trackParametersCovariance =
0082 (weightMatMeasurements + correlationTerm).inverse();
0083
0084
0085 state.residual = Acts::DynamicVector::Zero(nMeas);
0086 state.alignmentToResidualDerivative =
0087 Acts::DynamicMatrix::Zero(nMeas, state.alignmentDof);
0088 for (std::size_t i = 0; i < nMeas; ++i) {
0089 state.residual(i) = 0.01 * (i % 2 == 0 ? 1. : -2.) * (i + 1);
0090 if (i == iMeasNotAligned) {
0091 continue;
0092 }
0093 for (std::size_t a = 0; a < Acts::eAlignmentSize; ++a) {
0094 state.alignmentToResidualDerivative(i, a) = 0.1 * (a + 1) + 0.01 * i;
0095 }
0096 }
0097 const Acts::DynamicVector measGradient =
0098 state.projectionMatrix.transpose() *
0099 state.measurementCovariance.inverse() * state.residual;
0100 BOOST_REQUIRE(measGradient.norm() > 1.);
0101
0102 auto logger = Acts::getDefaultLogger("ActsToMillePseudoResiduals",
0103 Acts::Logging::WARNING);
0104
0105 const std::string fname = "ActsToMillePseudoResiduals.dat";
0106 {
0107 std::unique_ptr<Mille::MilleRecord> out = Mille::spawnMilleRecord(fname);
0108 BOOST_REQUIRE(out != nullptr);
0109 ActsPlugins::ActsToMille::dumpToMille(state, *out, false, *logger);
0110 }
0111
0112 auto reader = Mille::spawnMilleReader(fname);
0113 BOOST_REQUIRE(reader != nullptr);
0114 BOOST_REQUIRE(reader->open(fname));
0115 Mille::MilleDecoder decoder;
0116 std::vector<Mille::MilleMeasurement> measurements;
0117 BOOST_REQUIRE(decoder.decode(*reader, measurements) ==
0118 Mille::MilleDecoder::ReadResult::OK);
0119 BOOST_REQUIRE_EQUAL(measurements.size(), nMeas + nPar);
0120
0121
0122
0123
0124
0125 Acts::DynamicVector localGradient = Acts::DynamicVector::Zero(nPar);
0126 std::size_t nPseudoNonZero = 0;
0127 for (const auto& measurement : measurements) {
0128 const double weight =
0129 1. / (measurement.uncertainty * measurement.uncertainty);
0130 for (std::size_t iLoc = 0; iLoc < measurement.localLabels.size(); ++iLoc) {
0131 localGradient(measurement.localLabels[iLoc] - 1) +=
0132 weight * measurement.measurement * measurement.localDerivatives[iLoc];
0133 }
0134 if (measurement.globalLabels.empty() &&
0135 measurement.localLabels.size() > 1 && measurement.measurement != 0) {
0136 ++nPseudoNonZero;
0137 }
0138 }
0139 BOOST_CHECK_EQUAL(nPseudoNonZero, nPar);
0140 BOOST_CHECK_SMALL(localGradient.norm() / measGradient.norm(), 1e-5);
0141
0142
0143
0144 auto reader2 = Mille::spawnMilleReader(fname);
0145 BOOST_REQUIRE(reader2 != nullptr);
0146 BOOST_REQUIRE(reader2->open(fname));
0147 const std::unordered_map<const Acts::Surface*, std::size_t>
0148 idxedAlignSurfaces{{surface.get(), 0}};
0149 ActsAlignment::detail::TrackAlignmentState readState;
0150 BOOST_REQUIRE(ActsPlugins::ActsToMille::unpackMilleRecord(
0151 *reader2, readState, idxedAlignSurfaces, *logger) ==
0152 Mille::MilleDecoder::ReadResult::OK);
0153 BOOST_CHECK_EQUAL(readState.measurementDim, nMeas);
0154 BOOST_CHECK_EQUAL(readState.trackParametersDim, nPar);
0155 BOOST_REQUIRE_EQUAL(readState.residual.size(), nMeas);
0156 for (std::size_t i = 0; i < nMeas; ++i) {
0157 BOOST_CHECK_CLOSE(readState.residual(i), state.residual(i), 1e-4);
0158 }
0159 BOOST_CHECK(readState.projectionMatrix.isApprox(state.projectionMatrix));
0160 }
0161
0162 BOOST_AUTO_TEST_SUITE_END()