Warning, /acts/docs/core/magnetic_field.md is written in an unsupported language. File is not indexed.
0001 (magnetic-field-core)=
0002 # Magnetic field
0003
0004 The magnetic field component of ACTS provides functionality to describe
0005 arbitrary magnetic field configurations in an experiment. It is implemented in
0006 a generic way and can be extended to connect to an experiment specific upstream
0007 source of field data.
0008
0009 Algorithms which need magnetic field information (e.g.
0010 {class}`Acts::AtlasStepper`, {class}`Acts::EigenStepper`) accept the magnetic
0011 field as an explicit argument.
0012
0013 ## Provider interface
0014
0015 All magnetic field implementations inherit and implement the interface {class}`Acts::MagneticFieldProvider`:
0016
0017
0018 It provides a generic interface over different implementations. To speed up
0019 magnetic field lookup, each implementation can have a *cache* object. The cache
0020 object can for example be used to store a local interpolation domain, to speed
0021 up nearby field lookups. The client is expected to pass into lookup calls:
0022
0023 :::{doxygentypedef} Acts::MagneticFieldProvider::Cache
0024 :::
0025
0026 The implementation is then free to use and update this cache instance as
0027 needed. Before a client can issue field lookup calls, it needs to obtain an
0028 initialized instance of this cache object. This can be achieved generically for
0029 all implementations by using {func}`Acts::MagneticFieldProvider::makeCache`.
0030 This function accepts an instance of {class}`Acts::MagneticFieldContext`, see
0031 [](#magnetic-field-context) for details.
0032
0033 The main lookup method of {class}`Acts::MagneticFieldProvider` is
0034
0035 :::{doxygenfunction} Acts::MagneticFieldProvider::getField
0036 :outline:
0037 :::
0038
0039 Aside from the lookup position as a global position vector, it accepts an
0040 instance of the opaque cache object mentioned before. The return value is a
0041 {class}`Acts::Result` object. It either contains the field value at the
0042 requested location, or an {enum}`Acts::MagneticFieldError` in case of a lookup
0043 failure, like an out-of-bounds lookup position.
0044
0045 Below is an example of how a client can interact with an instance of
0046 {class}`Acts::MagneticFieldProvider`.
0047
0048 ```cpp
0049 // in event context
0050 auto fieldContext = getExperimentFieldContext();
0051 const Acts::MagneticFieldProvider& fieldProvider = getFieldProvider();
0052 auto cache = fieldProvider.makeCache(fieldContext);
0053
0054 auto lookupResult = fieldProvider.getField(Acts::Vector3{10, 10, 10}, cache);
0055 if(!lookupResult.ok()) {
0056 throw std::runtime_error{"Field lookup failure"};
0057 }
0058
0059 Acts::Vector3 fieldValue = *lookupResult;
0060 ```
0061
0062 ## Magnetic field context
0063
0064 :::{doxygenclass} Acts::MagneticFieldContext
0065 :outline:
0066 :::
0067
0068 The magnetic field context is an opaque type which contains experiment specific
0069 event context information. This can be used to supply event dependent data to
0070 the magnetic field instance, in case it is needed to provide correct field
0071 values. The library itself does not make any assumptions on the content of this
0072 context type (it is implemented using `std::any`), but passes a reference
0073 through the call-chain to the field implementation. An experiment specific
0074 field implementation is then expected to performa cast to the concrete type,
0075 and use the contents.
0076
0077 An example use case of the context could be to look up conditions data /
0078 records for the value of the magnetic field at the time of the event.
0079
0080 ## Field provider implementations in Core
0081
0082 There are a number of field provider implementations found in core which serve different purposes.
0083
0084 ### Constant magnetic field
0085
0086 The simplest implementation is a constant field, which returns the same field
0087 values at every queried location. It is implemented in the
0088 {class}`Acts::ConstantBField` class.
0089
0090 :::{doxygenclass} Acts::ConstantBField
0091 :members: ConstantBField
0092 :::
0093
0094 As seen above, the class is constructed from a three-dimensional field vector,
0095 which is returned unmodified to every call to
0096 {func}`Acts::ConstantBField::getField`.
0097
0098 ### Interpolated magnetic field
0099
0100 For more complex magnetic field implementations
0101 {class}`Acts::InterpolatedMagneticField` can be used. The idea here is to calculate
0102 an interpolated value of the magnetic field from a grid of known field values.
0103 In 3D, this means the interpolation is done from the 8 corner points of a *field
0104 cell*. The field cell can be retrieved for any given position. Since during
0105 typical access patterns, e.g. the propagation, subsequent steps are relatively
0106 likely to not cross the field cell boundary, the field cell can be cached.
0107
0108 :::{figure} figures/bfield/field_cell.svg
0109 :width: 300
0110 :align: center
0111 Illustration of the field cell concept. Subsequent steps are clustered in the
0112 same field cell. The field cell only needs to be refetched when the propagation
0113 crosses into the next grid region.
0114 :::
0115
0116 {class}`Acts::InterpolatedMagneticField` extends the
0117 {class}`Acts::MagneticFieldProvider` interface to add a number of additional
0118 methods:
0119
0120 :::{doxygenclass} Acts::InterpolatedMagneticField
0121 :::
0122
0123 This intermediate interface is again implemented by
0124 {class}`Acts::InterpolatedBFieldMap`, which is a template class that depends on
0125 an instance of {class}`Acts::Grid`. Varying configurations are possible,
0126 like a 2D field map that exploits $rz$ symmetry, or a plain 3D grid.
0127
0128 :::{doxygenclass} Acts::InterpolatedBFieldMap
0129 :members: false
0130 :::
0131
0132
0133 The class constructor accepts a single configuration struct that
0134 contains the grid instance, a scale factor and optional conversion function for
0135 the lookup positions and the returned field values.
0136
0137 :::{doxygenstruct} Acts::InterpolatedBFieldMap::Config
0138 :::
0139
0140 Internally, {class}`Acts::InterpolatedBFieldMap` uses a *field interpolation
0141 cell* to speed up lookups. This cell contains the interpolation points so the
0142 grid does not have to be consulted for each lookup. Explicit methods to create
0143 such a field cell are provided, but field cell creation is automatically
0144 handled by {func}`Acts::InterpolatedBFieldMap::makeCache`, opaque to the
0145 client.
0146
0147 Helpers to construct an interpolated field map from text and ROOT file inputs
0148 are provided:
0149
0150 :::{doxygenfunction} Acts::fieldMapRZ
0151 :::
0152
0153 :::{doxygenfunction} Acts::fieldMapXYZ
0154 :::
0155
0156
0157 ### Analytical solenoid magnetic field
0158
0159 :::{warning}
0160 The analytical solenoid field is **slow**. See {func}`Acts::solenoidFieldMap`
0161 to speed it up.
0162 :::
0163
0164 ACTS also provides a field provider that calculates the field vectors
0165 analytically for a [solenoid](https://en.wikipedia.org/wiki/Solenoid) field.
0166
0167 :::{figure} figures/bfield/quiver.png
0168 :width: 600
0169 :align: center
0170 Picture of a solenoid field in rz, with arrows indicating the direction of the
0171 field, and their size denoting the strength. The field is almost homogeneous in
0172 the center.
0173 :::
0174
0175 The implementation has configurable solenoid parameters:
0176
0177 :::{doxygenstruct} Acts::SolenoidBField::Config
0178 :::
0179
0180 :::{note}
0181 A configuration of
0182 ```cpp
0183 SolenoidBField::Config cfg;
0184 cfg.length = 5.8_m;
0185 cfg.radius = (2.56 + 2.46) * 0.5 * 0.5_m;
0186 cfg.nCoils = 1154;
0187 cfg.bMagCenter = 2_T;
0188 SolenoidBField bField(cfg);
0189 ```
0190 roughly corresponds to the solenoid wrapping the Inner Detector in ATLAS.
0191 :::
0192
0193 #### Implementation
0194
0195 The calculation uses two special functions:
0196
0197 - $E_1(k^2)$ is the complete elliptic integral of the 1st kind
0198 - $E_2(k^2)$ is the complete elliptic integral of the 2nd kind
0199
0200 $E_1(k^2)$ and $E_2(k^2)$ are usually indicated as $K(k^2)$ and $E(k^2)$ in literature, respectively:
0201
0202 $$
0203 E_1(k^2) = \int_0^{\pi/2} \left( 1 - k^2 \sin^2{\theta} \right )^{-1/2} \mathop{}\!\mathrm{d}\theta
0204 $$
0205
0206 $$
0207 E_2(k^2) = \int_0^{\pi/2}\sqrt{1 - k^2 \sin^2{\theta}} \mathop{}\!\mathrm{d}\theta
0208 $$
0209
0210 $k^2$ is a function of the point $(r, z)$ and of the radius of the coil $R$
0211
0212 $$
0213 k^2 = \frac{4Rr}{(R+r)^2 + z^2}
0214 $$
0215
0216 Using these, you can evaluate the two components $B_r$ and $B_z$ of the magnetic field:
0217
0218 $$
0219 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 ]
0220 $$
0221
0222 $$
0223 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 ]
0224 $$
0225
0226 In the implementation the factor of $(\mu_0\cdot I)$ is defined to be a scaling
0227 factor. It is evaluated and defined as the magnetic field in the center of the
0228 coil, i.e. the scale set in {member}`Acts::SolenoidBField::Config::bMagCenter`.
0229
0230 As the evaluation of $E_1(k^2)$ and $E_2(k^2)$ is **slow**. The
0231 {class}`Acts::InterpolatedBFieldMap` easily outperforms
0232 {class}`Acts::SolenoidBField`. A helper is provided that builds a map from the
0233 analytical implementation and is much faster to lookup:
0234
0235 :::{doxygenfunction} Acts::solenoidFieldMap
0236 :::
0237
0238 ### Multi-range constant field
0239
0240 The multi-range constant field allows modelling cases where a magnetic field
0241 can be described as multiple (potentially overlapping) regions, each of which
0242 has its own constant magnetic field. This provides more flexibility than the
0243 {class}`Acts::ConstantBField` while providing higher performance than
0244 {class}`Acts::InterpolatedBFieldMap`.
0245
0246 This magnetic field provider is configured using a list of pairs, where each
0247 pair defines a region in three-dimensional space as well as a field vector.
0248 Magnetic field lookup then proceeds by finding the _last_ region in the
0249 user-provided list that contains the requested coordinate and returning the
0250 corresponding field vector.
0251
0252 The implementation uses a simple caching mechanism to store the last matched
0253 region, providing improved performance for consecutive lookups within the same
0254 region. This is thread-safe when each thread uses its own cache instance. The
0255 field configuration itself is immutable after construction.
0256
0257 :::{doxygenclass} Acts::MultiRangeBField
0258 :::
0259
0260 ## Full provider interface
0261
0262 :::{doxygenclass} Acts::MagneticFieldProvider
0263 :::