Skip to content

Commit 458fbd8

Browse files
authored
feat: Demonstrator for MillePede alignment of ACTS Kalman tracks (#5256)
Add a first demonstrator of MillePede alignment, using existing ACTS Kalman tracks.
1 parent 4e373ef commit 458fbd8

33 files changed

Lines changed: 2143 additions & 343 deletions

Alignment/include/ActsAlignment/Kernel/Alignment.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#pragma once
1010

1111
#include "Acts/Definitions/Alignment.hpp"
12+
#include "Acts/EventData/BoundTrackParameters.hpp"
1213
#include "Acts/Geometry/GeometryContext.hpp"
1314
#include "Acts/Surfaces/Surface.hpp"
1415
#include "Acts/Utilities/Logger.hpp"
@@ -189,6 +190,17 @@ struct Alignment {
189190
const fit_options_t& fitOptions, AlignmentResult& alignResult,
190191
const AlignmentMask& alignMask = AlignmentMask::All) const;
191192

193+
/// @brief calculate the alignment parameters delta from a set of
194+
/// TrackAlignmentStates
195+
///
196+
/// @param TrackStateCollection The collection of TrackAlignmentStates
197+
/// as input of fitting
198+
/// @param alignResult [in, out] The aligned result
199+
/// @param alignMask The alignment mask (same for all measurements now)
200+
void calculateAlignmentParameters(
201+
const std::vector<detail::TrackAlignmentState>& trackAlignmentStates,
202+
AlignmentResult& alignResult) const;
203+
192204
/// @brief update the detector element alignment parameters
193205
///
194206
/// @param gctx The geometry context

Alignment/include/ActsAlignment/Kernel/Alignment.ipp

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "Acts/TrackFitting/detail/KalmanGlobalCovariance.hpp"
1616
#include "Acts/Utilities/detail/EigenCompat.hpp"
1717
#include "ActsAlignment/Kernel/AlignmentError.hpp"
18+
#include "ActsAlignment/Kernel/detail/AlignmentEngine.hpp"
1819

1920
#include <queue>
2021

@@ -76,19 +77,14 @@ void ActsAlignment::Alignment<fitter_t>::calculateAlignmentParameters(
7677
// The total alignment degree of freedom
7778
alignResult.alignmentDof =
7879
alignResult.idxedAlignSurfaces.size() * Acts::eAlignmentSize;
79-
// Initialize derivative of chi2 w.r.t. alignment parameters for all tracks
80-
Acts::DynamicVector sumChi2Derivative =
81-
Acts::DynamicVector::Zero(alignResult.alignmentDof);
82-
Acts::DynamicMatrix sumChi2SecondDerivative = Acts::DynamicMatrix::Zero(
83-
alignResult.alignmentDof, alignResult.alignmentDof);
8480
// Copy the fit options
8581
fit_options_t fitOptionsWithRefSurface = fitOptions;
8682
// Calculate contribution to chi2 derivatives from all input trajectories
8783
// @Todo: How to update the source link error iteratively?
8884
alignResult.chi2 = 0;
8985
alignResult.measurementDim = 0;
9086
alignResult.numTracks = trajectoryCollection.size();
91-
double sumChi2ONdf = 0;
87+
std::vector<detail::TrackAlignmentState> alignmentStates;
9288
for (unsigned int iTraj = 0; iTraj < trajectoryCollection.size(); iTraj++) {
9389
const auto& sourceLinks = trajectoryCollection.at(iTraj);
9490
const auto& sParameters = startParametersCollection.at(iTraj);
@@ -104,6 +100,28 @@ void ActsAlignment::Alignment<fitter_t>::calculateAlignmentParameters(
104100
continue;
105101
}
106102
const auto& alignState = evaluateRes.value();
103+
alignmentStates.push_back(alignState);
104+
}
105+
return calculateAlignmentParameters(alignmentStates, alignResult);
106+
}
107+
108+
template <typename fitter_t>
109+
void ActsAlignment::Alignment<fitter_t>::calculateAlignmentParameters(
110+
const std::vector<detail::TrackAlignmentState>& trackAlignmentStates,
111+
AlignmentResult& alignResult) const {
112+
// The total alignment degree of freedom
113+
alignResult.alignmentDof =
114+
alignResult.idxedAlignSurfaces.size() * Acts::eAlignmentSize;
115+
// Initialize derivative of chi2 w.r.t. alignment parameters for all tracks
116+
Acts::DynamicVector sumChi2Derivative =
117+
Acts::DynamicVector::Zero(alignResult.alignmentDof);
118+
Acts::DynamicMatrix sumChi2SecondDerivative = Acts::DynamicMatrix::Zero(
119+
alignResult.alignmentDof, alignResult.alignmentDof);
120+
alignResult.chi2 = 0;
121+
alignResult.measurementDim = 0;
122+
alignResult.numTracks = trackAlignmentStates.size();
123+
double sumChi2ONdf = 0;
124+
for (const auto& alignState : trackAlignmentStates) {
107125
for (const auto& [rowSurface, rows] : alignState.alignedSurfaces) {
108126
const auto& [dstRow, srcRow] = rows;
109127
// Fill the results into full chi2 derivative matrix

Alignment/include/ActsAlignment/Kernel/detail/AlignmentEngine.hpp

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,43 @@ struct TrackAlignmentState {
7474
void resetAlignmentDerivative(Acts::AlignmentToBoundMatrix& alignToBound,
7575
AlignmentMask mask);
7676

77+
/// @brief Helper function to calculate first and second derivative
78+
/// of chi2 w.r.t. alignment parameters for a single track once the
79+
/// relevant information has
80+
/// been retrieved from the respective track.
81+
/// Updates in-place the chi2 and the matrix/vector forming the final
82+
/// equation.
83+
/// @param [in,out] alignState: TrackAlignmentState to modify (in-place).
84+
inline void finaliseTrackAlignState(TrackAlignmentState& alignState) {
85+
// Calculate the chi2 and chi2 derivatives based on the alignment matrixs
86+
alignState.chi2 = alignState.residual.transpose() *
87+
alignState.measurementCovariance.inverse() *
88+
alignState.residual;
89+
alignState.alignmentToChi2Derivative =
90+
Acts::DynamicVector::Zero(alignState.alignmentDof);
91+
alignState.alignmentToChi2SecondDerivative = Acts::DynamicMatrix::Zero(
92+
alignState.alignmentDof, alignState.alignmentDof);
93+
// The covariance of residual
94+
alignState.residualCovariance = Acts::DynamicMatrix::Zero(
95+
alignState.measurementDim, alignState.measurementDim);
96+
alignState.residualCovariance = alignState.measurementCovariance -
97+
alignState.projectionMatrix *
98+
alignState.trackParametersCovariance *
99+
alignState.projectionMatrix.transpose();
100+
101+
alignState.alignmentToChi2Derivative =
102+
2 * alignState.alignmentToResidualDerivative.transpose() *
103+
alignState.measurementCovariance.inverse() *
104+
alignState.residualCovariance *
105+
alignState.measurementCovariance.inverse() * alignState.residual;
106+
alignState.alignmentToChi2SecondDerivative =
107+
2 * alignState.alignmentToResidualDerivative.transpose() *
108+
alignState.measurementCovariance.inverse() *
109+
alignState.residualCovariance *
110+
alignState.measurementCovariance.inverse() *
111+
alignState.alignmentToResidualDerivative;
112+
}
113+
77114
///
78115
/// Calculate the first and second derivative of chi2 w.r.t. alignment
79116
/// parameters for a single track
@@ -266,34 +303,7 @@ TrackAlignmentState trackAlignmentState(
266303
correlation;
267304
}
268305
}
269-
270-
// Calculate the chi2 and chi2 derivatives based on the alignment matrixs
271-
alignState.chi2 = alignState.residual.transpose() *
272-
alignState.measurementCovariance.inverse() *
273-
alignState.residual;
274-
alignState.alignmentToChi2Derivative =
275-
Acts::DynamicVector::Zero(alignState.alignmentDof);
276-
alignState.alignmentToChi2SecondDerivative = Acts::DynamicMatrix::Zero(
277-
alignState.alignmentDof, alignState.alignmentDof);
278-
// The covariance of residual
279-
alignState.residualCovariance = Acts::DynamicMatrix::Zero(
280-
alignState.measurementDim, alignState.measurementDim);
281-
alignState.residualCovariance = alignState.measurementCovariance -
282-
alignState.projectionMatrix *
283-
alignState.trackParametersCovariance *
284-
alignState.projectionMatrix.transpose();
285-
286-
alignState.alignmentToChi2Derivative =
287-
2 * alignState.alignmentToResidualDerivative.transpose() *
288-
alignState.measurementCovariance.inverse() *
289-
alignState.residualCovariance *
290-
alignState.measurementCovariance.inverse() * alignState.residual;
291-
alignState.alignmentToChi2SecondDerivative =
292-
2 * alignState.alignmentToResidualDerivative.transpose() *
293-
alignState.measurementCovariance.inverse() *
294-
alignState.residualCovariance *
295-
alignState.measurementCovariance.inverse() *
296-
alignState.alignmentToResidualDerivative;
306+
finaliseTrackAlignState(alignState);
297307

298308
return alignState;
299309
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
acts_add_library(
2+
ExamplesAlignmentMillePede
3+
src/MillePedeAlignmentSandbox.cpp
4+
src/ActsSolverFromMille.cpp
5+
)
6+
target_include_directories(
7+
ActsExamplesAlignmentMillePede
8+
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
9+
)
10+
target_link_libraries(
11+
ActsExamplesAlignmentMillePede
12+
PUBLIC
13+
Acts::Alignment
14+
Acts::ExamplesFramework
15+
Acts::ExamplesMagneticField
16+
ActsPluginMille
17+
)
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// This file is part of the ACTS project.
2+
//
3+
// Copyright (C) 2016 CERN for the benefit of the ACTS project
4+
//
5+
// This Source Code Form is subject to the terms of the Mozilla Public
6+
// License, v. 2.0. If a copy of the MPL was not distributed with this
7+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
9+
#pragma once
10+
11+
#include "Acts/Geometry/GeometryIdentifier.hpp"
12+
#include "Acts/Propagator/EigenStepper.hpp"
13+
#include "Acts/Propagator/Navigator.hpp"
14+
#include "Acts/Propagator/Propagator.hpp"
15+
#include "Acts/Propagator/detail/SteppingLogger.hpp"
16+
#include "Acts/TrackFitting/KalmanFitter.hpp"
17+
#include "ActsAlignment/Kernel/Alignment.hpp"
18+
#include "ActsExamples/Framework/DataHandle.hpp"
19+
#include "ActsExamples/Framework/IAlgorithm.hpp"
20+
21+
#include <memory>
22+
23+
namespace Acts {
24+
class MagneticFieldProvider;
25+
}
26+
27+
namespace ActsExamples {
28+
29+
/// @brief Algorithm for reading Mille binaries into ACTS
30+
/// and solving using them to run an alignment fit
31+
/// with the built-in solver.
32+
class ActsSolverFromMille final : public IAlgorithm {
33+
public:
34+
using SteppingLogger = Acts::detail::SteppingLogger;
35+
using EndOfWorld = Acts::EndOfWorldReached;
36+
using Stepper = Acts::EigenStepper<>;
37+
using Propagator = Acts::Propagator<Stepper, Acts::Navigator>;
38+
using Fitter = Acts::KalmanFitter<Propagator, Acts::VectorMultiTrajectory>;
39+
using Alignment = ActsAlignment::Alignment<Fitter>;
40+
41+
using AlignmentParameters =
42+
std::unordered_map<Acts::SurfacePlacementBase*, Acts::Transform3>;
43+
44+
/// configuration
45+
struct Config {
46+
/// name of the mille input binary. You can choose
47+
/// between ".root" / ".csv" / ".dat" extensions
48+
/// to get ROOT tree / plain text / classic Millepede
49+
/// binary outputs. All three can be read by the interface.
50+
std::string milleInput;
51+
// the tracking geometry to use
52+
std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry;
53+
// magnetic field
54+
std::shared_ptr<const Acts::MagneticFieldProvider> magneticField;
55+
// modules to fix in the alignment to suppress global movements
56+
std::set<Acts::GeometryIdentifier> fixModules;
57+
};
58+
59+
/// Constructor of the sandbox algorithm
60+
/// @param cfg is the config struct to configure the algorithm
61+
/// @param level is the logging level
62+
explicit ActsSolverFromMille(
63+
Config cfg, std::unique_ptr<const Acts::Logger> logger = nullptr);
64+
65+
/// Framework execute method of the sandbox algorithm
66+
///
67+
/// @param ctx is the algorithm context that holds event-wise information
68+
/// @return a process code to steer the algorithm flow
69+
ProcessCode execute(const AlgorithmContext& ctx) const override;
70+
ProcessCode finalize() override;
71+
72+
/// Get readonly access to the config parameters
73+
const Config& config() const { return m_cfg; }
74+
75+
private:
76+
/// configuration instance
77+
Config m_cfg;
78+
79+
/// alignment module instance - reuse as much as possible
80+
std::shared_ptr<Alignment> m_align;
81+
/// tracking geometry
82+
std::shared_ptr<const Acts::TrackingGeometry> m_trackingGeometry;
83+
};
84+
85+
} // namespace ActsExamples
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// This file is part of the ACTS project.
2+
//
3+
// Copyright (C) 2016 CERN for the benefit of the ACTS project
4+
//
5+
// This Source Code Form is subject to the terms of the Mozilla Public
6+
// License, v. 2.0. If a copy of the MPL was not distributed with this
7+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
9+
#pragma once
10+
11+
#include "Acts/Geometry/GeometryIdentifier.hpp"
12+
#include "Acts/Propagator/EigenStepper.hpp"
13+
#include "Acts/Propagator/Navigator.hpp"
14+
#include "Acts/Propagator/Propagator.hpp"
15+
#include "Acts/Propagator/detail/SteppingLogger.hpp"
16+
#include "Acts/TrackFitting/KalmanFitter.hpp"
17+
#include "ActsAlignment/Kernel/Alignment.hpp"
18+
#include "ActsExamples/EventData/Measurement.hpp"
19+
#include "ActsExamples/EventData/Track.hpp"
20+
#include "ActsExamples/Framework/DataHandle.hpp"
21+
#include "ActsExamples/Framework/IAlgorithm.hpp"
22+
23+
#include <memory>
24+
25+
#include "Mille/MilleFactory.h"
26+
27+
namespace Acts {
28+
class MagneticFieldProvider;
29+
}
30+
31+
namespace ActsExamples {
32+
33+
/// @brief Sandbox algorithm for experimenting with
34+
/// writing ACTS Kalman tracks to Millepede
35+
/// and passing them to the (external)
36+
/// Millepede alignment fit.
37+
/// Will consume an input track collection,
38+
/// pass the tracks through the existing
39+
/// Kalman alignment module and then
40+
/// write this information to a user-configured
41+
/// Mille binary that can be read by the solver.
42+
///
43+
/// You can either pass standard MC tracks and
44+
/// look for a zero-correction, or pass
45+
/// deliberately misaligned tracks and fit back
46+
/// out the injected misalignment. The module
47+
/// will **ignore** any external geometry context,
48+
/// so injected alignment corrections in the upstream
49+
/// job will show up as distortions here.
50+
class MillePedeAlignmentSandbox final : public IAlgorithm {
51+
public:
52+
using SteppingLogger = Acts::detail::SteppingLogger;
53+
using EndOfWorld = Acts::EndOfWorldReached;
54+
using Stepper = Acts::EigenStepper<>;
55+
using Propagator = Acts::Propagator<Stepper, Acts::Navigator>;
56+
using Fitter = Acts::KalmanFitter<Propagator, Acts::VectorMultiTrajectory>;
57+
using Alignment = ActsAlignment::Alignment<Fitter>;
58+
59+
using AlignmentParameters =
60+
std::unordered_map<Acts::SurfacePlacementBase*, Acts::Transform3>;
61+
62+
/// configuration
63+
struct Config {
64+
/// name of the mille output binary. You can choose
65+
/// between ".root" / ".csv" / ".dat" extensions
66+
/// to get ROOT tree / plain text / classic Millepede
67+
/// binary outputs. All three can be read by the solver.
68+
std::string milleOutput;
69+
/// Input measurements collection.
70+
std::string inputMeasurements;
71+
/// Input tracks
72+
std::string inputTracks;
73+
// the tracking geometry to use
74+
std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry;
75+
// magnetic field
76+
std::shared_ptr<const Acts::MagneticFieldProvider> magneticField;
77+
// modules to fix in the alignment to suppress global movements
78+
std::set<Acts::GeometryIdentifier> fixModules;
79+
};
80+
81+
/// Constructor of the sandbox algorithm
82+
/// @param cfg is the config struct to configure the algorithm
83+
/// @param level is the logging level
84+
explicit MillePedeAlignmentSandbox(
85+
Config cfg, std::unique_ptr<const Acts::Logger> logger = nullptr);
86+
87+
/// Framework execute method of the sandbox algorithm
88+
///
89+
/// @param ctx is the algorithm context that holds event-wise information
90+
/// @return a process code to steer the algorithm flow
91+
ProcessCode execute(const AlgorithmContext& ctx) const override;
92+
ProcessCode finalize() override;
93+
94+
/// Get readonly access to the config parameters
95+
const Config& config() const { return m_cfg; }
96+
97+
private:
98+
/// configuration instance
99+
Config m_cfg;
100+
101+
/// measurement container containing the measurements on the input tracks
102+
/// below
103+
ReadDataHandle<MeasurementContainer> m_inputMeasurements{this,
104+
"InputMeasurements"};
105+
/// tracks to use for the alignment
106+
ReadDataHandle<ConstTrackContainer> m_inputTracks{this, "InputTracks"};
107+
108+
/// alignment module instance - reuse as much as possible
109+
std::shared_ptr<Alignment> m_align;
110+
/// tracking geometry
111+
std::shared_ptr<const Acts::TrackingGeometry> m_trackingGeometry;
112+
/// the Mille record instance for writing our alignment info.
113+
std::unique_ptr<Mille::MilleRecord> m_milleOut = nullptr;
114+
};
115+
116+
} // namespace ActsExamples

0 commit comments

Comments
 (0)