-
Notifications
You must be signed in to change notification settings - Fork 157
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
1 changed file
with
111 additions
and
112 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,127 +1,126 @@ | ||
# Propagation and extrapolation | ||
|
||
:::{attention} | ||
This section is largely **outdated** and will be replaced in the future. | ||
The track propagation is an essential part of track reconstruction. This section describes the high-level classes and concepts used for this task in Acts. | ||
|
||
## Overview: Steppers, Navigators and Actors | ||
|
||
The propagation through a geometry is based on the interaction of two different components: | ||
|
||
* The **Stepper** provides the implementation of the the solution of the equation of motion (either by analytical means or through numerical integration). | ||
* The **Navigator** keeps track of the current position in the geometry and adjusts the step size so that the stepper does not step through a surface. | ||
|
||
Following the general Acts design, these clases do not manage their internal state via member variables, but provide a internal `State` struct which contains all relevant data and is managed by the propagator. | ||
|
||
The interaction of these two components is handled by the {class}`Acts::Propagator` class template that takes the stepper and the navigator as template parameters: | ||
|
||
```c++ | ||
Propagator<Navigator, Stepper> | ||
``` | ||
|
||
Additional to these mandatory components the Propagator can be equipped with **Actors** and **Aborters** to allow for custom behaviour. These are function objects that are hooked in the propagation loop. Actors just perform some action on the propagator state (e.g. the {class}`Acts::KalmanFitter` is an actor), aborts can abort propagation (e.g., the {class}`Acts::PathLimitReached`). | ||
|
||
The propagator exposes its state to the Actors and Aborters as arguments to `operator()`. Actors must define a default-constructable `result_type`, which can be modified in each call: | ||
|
||
```c++ | ||
|
||
template<typename propagator_state_t, typename stepper_t> | ||
auto operator(propagator_state_t &state, const stepper_t &stepper, result_type &result) const { | ||
|
||
const auto &navigatorState = state.navigation; | ||
const auto &stepperState = state.stepping; | ||
const auto &options = state.options; | ||
} | ||
``` | ||
The result of a propagation consists of the track parameters at the endpoint of the propagation as well as the results of all actors. | ||
## Initialization and running | ||
The {class}`Acts::Propagator` is initialized with the helper class {class}`Acts::PropagatorOptions`, which is templated on the list of actors and aborters. This is done with the classes {class}`Acts::ActionList` and {class}`Acts::AbortList` (which are in fact small wrappers around `std::tuple`): | ||
```c++ | ||
using MyOptions = Acts::PropagatorOptions< | ||
Acts::ActionList<MyActor1, MyActor2>, | ||
Acts::AbortList<MyAborter1, MyAborter2> | ||
>; | ||
``` | ||
|
||
The actors and aborters are instantiated with the options and can be accessed with the `get`-method that expects the corresponding actor type as template parameter. Besides this, the {class}`Acts::PropagatorOptions` also contain a lot general options like the `maxStepSize`: | ||
|
||
```c++ | ||
auto options = MyOptions(); | ||
options.actionList.get<MyActor1>().foo = bar; | ||
options.maxStepSize = 100; | ||
``` | ||
|
||
All available options can be found in the {struct}`Acts::PropagatorPlainOptions`, from which {class}`Acts::PropagatorOptions` inherits. | ||
|
||
:::{tip} | ||
The propagator also contains a loop-protection mechanism. It estimates a circle perimeter from the momentum and the magnetic field, and aborts the propagation when a certain fraction (default: 0.5) of the circle has been propagated. This behaviour can be changed in the {class}`Acts::PropagatorOptions` via the boolean `loopProtection` and the float `loopFraction`. | ||
::: | ||
|
||
The track propagation is an essential part of track reconstruction. The Acts | ||
propagation code is based on the ATLAS `RungeKuttaPropagator`, against which | ||
newer developments where validated. It has since been removed from the | ||
code base. | ||
To run the propagation, we must call the member function `propagate(...)` with the initial track parameters and the propagator options. There are several overloads to the `propagate(...)` function, which allow further customization: | ||
* With target surface or without: The overload with a target surface automatically adds an aborter for the passed `Surface` to the `AbortList`. | ||
* With a prepared result object or without. Without a result object, a suitable result object is default-constructed internally. | ||
|
||
## Steppers and Propagator | ||
The result is a instance of {class}`Acts::Result`, so it can contain an error code if something went wrong, or the actual result. In the actual result, the results of the different actors can again accessed a `get` method: | ||
|
||
The Acts propagator allows for different `Stepper` implementations provided as a | ||
class template. Following the general Acts design, each stepper has a nested | ||
cache `struct`, which is used for caching the field cell and the update the | ||
jacobian for covariance propagation. | ||
```c++ | ||
auto res = propagator.propagate(myParams, options); | ||
|
||
### AtlasStepper | ||
if( res.ok() ) { | ||
res.value().get<MyActor1::result_type>(); | ||
} | ||
``` | ||
|
||
|
||
## Navigators | ||
|
||
Acts comes with two navigators: The standard navigator {class}`Acts::Navigator` that performs the full navigation in the volume/layer/surface hierarchy, and the {class}`Acts::DirectNavigator` that takes a sequence of surfaces and just navigates along this. This sequence must be initialized with a special actor, the {class}`Acts::DirectNavigator::Initializer`. | ||
|
||
The navigators provide information about the current position in the geometry in their state ({struct}`Acts::Navigator::State` and {struct}`Acts::DirectNavigator::State`), e.g. pointers to the `currentSurface` and the `currentVolume`. | ||
|
||
## Steppers | ||
|
||
The `AtlasStepper` is a pure transcript from the ATLAS `RungeKuttaPropagator` | ||
and `RungeKuttaUtils`, and operators with an internal structure of `double[]`. | ||
This example shows a code snippet from the numerical integration. | ||
|
||
```cpp | ||
while (h != 0.) { | ||
double S3 = (1. / 3.) * h, S4 = .25 * h, PS2 = Pi * h; | ||
|
||
// First point | ||
// | ||
double H0[3] = {f0[0] * PS2, f0[1] * PS2, f0[2] * PS2}; | ||
double A0 = A[1] * H0[2] - A[2] * H0[1]; | ||
double B0 = A[2] * H0[0] - A[0] * H0[2]; | ||
double C0 = A[0] * H0[1] - A[1] * H0[0]; | ||
double A2 = A0 + A[0]; | ||
double B2 = B0 + A[1]; | ||
double C2 = C0 + A[2]; | ||
double A1 = A2 + A[0]; | ||
double B1 = B2 + A[1]; | ||
double C1 = C2 + A[2]; | ||
|
||
// Second point | ||
// | ||
if (!Helix) { | ||
const Vector3 pos(R[0] + A1 * S4, R[1] + B1 * S4, R[2] + C1 * S4); | ||
f = getField(cache, pos); | ||
} else { | ||
f = f0; | ||
} | ||
|
||
double H1[3] = {f[0] * PS2, f[1] * PS2, f[2] * PS2}; | ||
double A3 = (A[0] + B2 * H1[2]) - C2 * H1[1]; | ||
double B3 = (A[1] + C2 * H1[0]) - A2 * H1[2]; | ||
double C3 = (A[2] + A2 * H1[1]) - B2 * H1[0]; | ||
double A4 = (A[0] + B3 * H1[2]) - C3 * H1[1]; | ||
double B4 = (A[1] + C3 * H1[0]) - A3 * H1[2]; | ||
double C4 = (A[2] + A3 * H1[1]) - B3 * H1[0]; | ||
double A5 = 2. * A4 - A[0]; | ||
double B5 = 2. * B4 - A[1]; | ||
double C5 = 2. * C4 - A[2]; | ||
|
||
// Last point | ||
// | ||
if (!Helix) { | ||
const Vector3 pos(R[0] + h * A4, R[1] + h * B4, R[2] + h * C4); | ||
f = getField(cache, pos); | ||
} else { | ||
f = f0; | ||
} | ||
|
||
double H2[3] = {f[0] * PS2, f[1] * PS2, f[2] * PS2}; | ||
double A6 = B5 * H2[2] - C5 * H2[1]; | ||
double B6 = C5 * H2[0] - A5 * H2[2]; | ||
double C6 = A5 * H2[1] - B5 * H2[0]; | ||
Acts also provides a variety of stepper implementations. Since these in general can work very differently internally, the state itself is not the main interface to the steppers. Instead all steppers provide a common API, to that we can pass instances of the stepper state. This allows a generic and template-based design even for very different steppers: | ||
|
||
```c++ | ||
template<typename propagator_state_t, typename stepper_t> | ||
auto operator(propagator_state_t &state, const stepper_t &stepper) const { | ||
stepper.foo(state.stepping); | ||
} | ||
``` | ||
### AtlasStepper | ||
The {class}`Acts::AtlasStepper` is a pure transcript from the ATLAS `RungeKuttaPropagator` | ||
and `RungeKuttaUtils`. | ||
### StraightLineStepper | ||
The {class}`Acts::StraightLineStepper` is a very stripped down stepper that just performs a linear propagation without magnetic field. It can be used for debugging, validation or other simple tasks. | ||
### EigenStepper | ||
The `EigenStepper` implements the same functionality as the ATLAS stepper, | ||
however, the stepping code is rewritten with using `Eigen` primitives. The | ||
following code snippet shows the Runge-Kutta stepping code. | ||
|
||
```cpp | ||
// The following functor starts to perform a Runge-Kutta step of a certain | ||
// size, going up to the point where it can return an estimate of the local | ||
// integration error. The results are stated in the local variables above, | ||
// allowing integration to continue once the error is deemed satisfactory | ||
const auto tryRungeKuttaStep = [&](const double h) -> bool { | ||
|
||
// State the square and half of the step size | ||
h2 = h * h; | ||
half_h = h * 0.5; | ||
|
||
// Second Runge-Kutta point | ||
const Vector3 pos1 = state.stepping.pos + half_h * state.stepping.dir | ||
+ h2 * 0.125 * sd.k1; | ||
sd.B_middle = getField(state.stepping, pos1); | ||
if (!state.stepping.extension.k2( | ||
state, sd.k2, sd.B_middle, half_h, sd.k1)) { | ||
return false; | ||
} | ||
|
||
// Third Runge-Kutta point | ||
if (!state.stepping.extension.k3( | ||
state, sd.k3, sd.B_middle, half_h, sd.k2)) { | ||
return false; | ||
} | ||
|
||
// Last Runge-Kutta point | ||
const Vector3 pos2 | ||
= state.stepping.pos + h * state.stepping.dir + h2 * 0.5 * sd.k3; | ||
sd.B_last = getField(state.stepping, pos2); | ||
if (!state.stepping.extension.k4(state, sd.k4, sd.B_last, h, sd.k3)) { | ||
return false; | ||
} | ||
|
||
// Return an estimate of the local integration error | ||
error_estimate = std::max( | ||
h2 * (sd.k1 - sd.k2 - sd.k3 + sd.k4).template lpNorm<1>(), 1e-20); | ||
return true; | ||
}; | ||
The {class}`Acts::EigenStepper` implements the same functionality as the ATLAS stepper, | ||
however, the stepping code is rewritten with using `Eigen` primitives. Thus, it also uses a 4th-order Runge-Kutta algorithm for the integration of the EOM. Additionally, the {class}`Acts::EigenStepper` allows to customize the concrete integration step via **extensions**. | ||
The extensions encapsulate the relevant equations for different environments. There exists a {class}`Acts::DefaultExtension` that is suited for propagation in a vacuum, and the {class}`Acts::DenseEnvironmentExtension`, that contains additional code to handle the propagation inside materials. Which extension is used is selected by a bidding-system. | ||
The extension can be configured via the {class}`Acts::StepperExtensionList`: | ||
```c++ | ||
using Stepper = Acts::EigenStepper< | ||
Acts::StepperExtensionList< | ||
Acts::DefaultExtension, | ||
Acts::DenseEnvironmentExtension | ||
> | ||
>; | ||
``` | ||
|
||
The code includes the extension mechanism, which allows extending the numerical | ||
integration. This is implemented for the custom logic required to integrate | ||
through a volume with dense material. | ||
By default, the {class}`Acts::EigenStepper` only uses the {class}`Acts::DefaultExtension`. | ||
|
||
### MultiEigenStepperLoop | ||
|
||
The {class}`Acts::MultiEigenStepper` is a extension of the {class}`Acts::EigenStepper` and designed to internally handle a multi-component state, while interfacing as a single component to the navigator. It is mainly used for the {class}`Acts::GaussianSumFitter`. |