This module collects information about classes and typedefs useful for
describing different magnetic field configurations. Acts is independent of the
magnetic field implementation used. Algorithms which need magnetic field
information (e.g. :class:`Acts::AtlasStepper`,
:class:`Acts::EigenStepper`) are templated on the magnetic field. The
requirements for the magnetic field implementation are shown in the example FieldProvider
given below:
struct FieldProvider {
struct Cache {
// implementation specific
};
// get field for a given position, no cache
Vector3D getField(const Vector3D& pos) const;
// get field and the gradient, no cache
Vector3D getFieldGradient(const Vector3D& pos, ActsMatrixD<3, 3>& deriv) const;
// get the field for a given position, and provide the cache object
Vector3D getField(const Vector3D& position, Cache& cache) const;
// get the field and gradient for a given position, provide cache
Vector3D getFieldGradient(const Vector3D& pos,
ActsMatrixD<3, 3>& deriv, // mutable reference
Cache& cache) const;
};
// client code
FieldProvider p;
FieldProvider::Cache cache;
auto field = p.getField({1, 2, 3}, cache); // retrieve field
Each magnetic field implementation expects to be passed a reference to an
implementation specific cache object. The cache type is provided as a nested
struct of the field provider. It can usually be extracted using typename BField::Cache cache
, where BField
is a template parameter. Acts comes
with the following implementations of this (implicit) interface:
The simplest implementation is the a constant field, which returns the same field values at every queried location. It is implemented in the :class:`Acts::ConstantBField` class.
.. doxygenclass:: Acts::ConstantBField :members: ConstantBField
As seen above, the class is constructed from a three-dimensional field vector, which is returned unmodified to every call to :func:`Acts::ConstantBField::getField`.
For more complex magnetic field implementations the :class:`Acts::InterpolatedBFieldMap` can be used. The idea here is to calculate an interpolated value of the magnetic field from a grid of known field values. In 3D, this means the interpolation is done from the 8 cornerpoints of a field cell. The field cell can be retrieved for any given position. Since during typical access patterns, e.g. the propagation, subsequent steps are relatively likely to not cross the field cell boundary, the field cell can be cached.
Illustration of the field cell concept. Subsequent steps are clustered in the same field cell. The field cell only need to be refetched when the propagation crosses into the next grid region.
The class constructor
.. doxygenfunction:: Acts::InterpolatedBFieldMap::InterpolatedBFieldMap :outline:
accepts a single object of type :struct:`Acts::InterpolatedBFieldMap::Config`:
.. doxygenstruct:: Acts::InterpolatedBFieldMap::Config :members: mapper, scale :outline:
The config object contains an instance of a mapper type, as well as a global scale to be applied to any field values.
One implementation :struct:`Acts::InterpolatedBFieldMapper` is provided, but since the mapper type is a template parameter, this implementation can also be switched out. The default implementation uses :class:`Acts::detail::Grid` as the underlying data storage. It is generic over the number of dimensions.
Most notably it exposes a type :struct:`Acts::InterpolatedBFieldMapper::FieldCell` that corresponds to the concept of a field cell discussed above. It also exposes a function
.. doxygenfunction:: Acts::InterpolatedBFieldMapper::getFieldCell :outline:
that allows retrieval of such a field cell at a given position. This function
is used by :class:`Acts::InterpolatedBFieldMap` to lookup and use field cells.
:class:`Acts::InterpolatedBFieldMap` will store the most recent field cell in
the Cache
object provided by the client, and only talk to
:struct:`Acts::InterpolatedBFieldMapper` when the position leaves the current
field cell. Access to the magnetic field is done using the common interface methods
.. doxygenclass:: Acts::InterpolatedBFieldMap :members: getField :outline:
where the Cache
type hides the concrete mapper used.
Helpers to construct mappers from text and root file inputs are provided:
Acts also provides a field provider that calculates the field vectors analytically for a solenoid field.
The implementation can has configurable solenoid parameters:
.. doxygenstruct:: Acts::SolenoidBField::Config
Note
A configuration of
SolenoidBField::Config cfg;
cfg.length = 5.8_m;
cfg.radius = (2.56 + 2.46) * 0.5 * 0.5_m;
cfg.nCoils = 1154;
cfg.bMagCenter = 2_T;
SolenoidBField bField(cfg);
roughly corresponds to the solenoid wrapping the Inner Detector in ATLAS.
The calculation uses two special functions:
- E_1(k^2) is the complete elliptic integral of the 1st kind
- E_2(k^2) is the complete elliptic integral of the 2nd kind
E_1(k^2) and E_2(k^2) are usually indicated as K(k^2) and E(k^2) in literature, respectively:
E_1(k^2) = \int_0^{\pi/2} \left( 1 - k^2 \sin^2{\theta} \right )^{-1/2} \mathop{}\!\mathrm{d}\theta
E_2(k^2) = \int_0^{\pi/2}\sqrt{1 - k^2 \sin^2{\theta}} \mathop{}\!\mathrm{d}\theta
k^2 is a function of the point (r, z) and of the radius of the coil R
k^2 = \frac{4Rr}{(R+r)^2 + z^2}
Using these, you can evaluate the two components B_r and B_z of the magnetic field:
B_r(r, z) = \frac{\mu_0 I}{4\pi} \frac{kz}{\sqrt{Rr^3}} \left[ \left(\frac{2-k^2}{2-2k^2}\right)E_2(k^2) - E_1(k^2) \right ]
B_z(r,z) = \frac{\mu_0 I}{4\pi} \frac{k}{\sqrt{Rr}} \left[ \left( \frac{(R+r)k^2-2r}{2r(1-k^2)} \right ) E_2(k^2) + E_1(k^2) \right ]
In the implementation the factor of (\mu_0\cdot I) is defined to be a scaling factor. It is evaluated and defined the magnetic field in the center of the coil, i.e. the scale set in :any:`Acts::SolenoidBField::Config::bMagCenter`.
Warning
Evaluation of E_1(k^2) and E_2(k^2) is slow. The :class:`Acts::InterpolatedBFieldMap` easily outperforms :class:`Acts::SolenoidBField`. A helper :func:`Acts::solenoidFieldMapper` is provided that builds a map from the analytical implementation and is much faster to lookup.
:class:`Acts::SharedBField` wraps another one of the magnetic field types from above.
Internally, it holds a std::shared_ptr<...>
, so the same field provider can be reused. This is useful in case of a larger map, for example.
.. doxygenfunction:: Acts::SharedBField::SharedBField