File indexing completed on 2025-08-05 08:09:16
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0013 #include "Acts/MagneticField/MagneticFieldError.hpp"
0014 #include "Acts/MagneticField/MagneticFieldProvider.hpp"
0015 #include "Acts/Utilities/Grid.hpp"
0016 #include "Acts/Utilities/Interpolation.hpp"
0017 #include "Acts/Utilities/Result.hpp"
0018
0019 #include <functional>
0020 #include <optional>
0021 #include <vector>
0022
0023 namespace Acts {
0024
0025 class InterpolatedMagneticField : public MagneticFieldProvider {
0026 public:
0027
0028
0029
0030 virtual std::vector<std::size_t> getNBins() const = 0;
0031
0032
0033
0034
0035 virtual std::vector<double> getMin() const = 0;
0036
0037
0038
0039
0040 virtual std::vector<double> getMax() const = 0;
0041
0042
0043
0044
0045
0046
0047 virtual bool isInside(const Vector3& position) const = 0;
0048
0049
0050
0051
0052
0053
0054 virtual Vector3 getFieldUnchecked(const Vector3& position) const = 0;
0055 };
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075 template <typename grid_t>
0076 class InterpolatedBFieldMap : public InterpolatedMagneticField {
0077 public:
0078 using Grid = grid_t;
0079 using FieldType = typename Grid::value_type;
0080 static constexpr std::size_t DIM_POS = Grid::DIM;
0081
0082
0083
0084
0085
0086 struct FieldCell {
0087
0088 static constexpr unsigned int N = 1 << DIM_POS;
0089
0090 public:
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101 FieldCell(std::array<double, DIM_POS> lowerLeft,
0102 std::array<double, DIM_POS> upperRight,
0103 std::array<Vector3, N> fieldValues)
0104 : m_lowerLeft(std::move(lowerLeft)),
0105 m_upperRight(std::move(upperRight)),
0106 m_fieldValues(std::move(fieldValues)) {}
0107
0108
0109
0110
0111
0112
0113
0114 Vector3 getField(const ActsVector<DIM_POS>& position) const {
0115
0116 return interpolate(position, m_lowerLeft, m_upperRight, m_fieldValues);
0117 }
0118
0119
0120
0121
0122
0123
0124 bool isInside(const ActsVector<DIM_POS>& position) const {
0125 for (unsigned int i = 0; i < DIM_POS; ++i) {
0126 if (position[i] < m_lowerLeft[i] || position[i] >= m_upperRight[i]) {
0127 return false;
0128 }
0129 }
0130 return true;
0131 }
0132
0133 private:
0134
0135 std::array<double, DIM_POS> m_lowerLeft;
0136
0137
0138 std::array<double, DIM_POS> m_upperRight;
0139
0140
0141
0142
0143
0144 std::array<Vector3, N> m_fieldValues;
0145 };
0146
0147 struct Cache {
0148
0149 Cache(const MagneticFieldContext& ) {}
0150
0151 std::optional<FieldCell> fieldCell;
0152 bool initialized = false;
0153 };
0154
0155
0156 struct Config {
0157
0158
0159 std::function<ActsVector<DIM_POS>(const Vector3&)> transformPos;
0160
0161
0162
0163
0164 std::function<Vector3(const FieldType&, const Vector3&)> transformBField;
0165
0166
0167 Grid grid;
0168
0169
0170
0171
0172
0173 double scale = 1.;
0174 };
0175
0176
0177
0178 InterpolatedBFieldMap(Config cfg) : m_cfg{std::move(cfg)} {
0179 typename Grid::index_t minBin{};
0180 minBin.fill(1);
0181 m_lowerLeft = m_cfg.grid.lowerLeftBinEdge(minBin);
0182 m_upperRight = m_cfg.grid.lowerLeftBinEdge(m_cfg.grid.numLocalBins());
0183 }
0184
0185
0186
0187
0188
0189
0190
0191
0192 Result<FieldCell> getFieldCell(const Vector3& position) const {
0193 const auto& gridPosition = m_cfg.transformPos(position);
0194 const auto& indices = m_cfg.grid.localBinsFromPosition(gridPosition);
0195 const auto& lowerLeft = m_cfg.grid.lowerLeftBinEdge(indices);
0196 const auto& upperRight = m_cfg.grid.upperRightBinEdge(indices);
0197
0198
0199 constexpr std::size_t nCorners = 1 << DIM_POS;
0200 std::array<Vector3, nCorners> neighbors;
0201 const auto& cornerIndices = m_cfg.grid.closestPointsIndices(gridPosition);
0202
0203 if (!isInsideLocal(gridPosition)) {
0204 return MagneticFieldError::OutOfBounds;
0205 }
0206
0207 std::size_t i = 0;
0208 for (std::size_t index : cornerIndices) {
0209 neighbors.at(i++) = m_cfg.transformBField(m_cfg.grid.at(index), position);
0210 }
0211
0212 assert(i == nCorners);
0213
0214 return FieldCell(lowerLeft, upperRight, std::move(neighbors));
0215 }
0216
0217
0218
0219
0220 std::vector<std::size_t> getNBins() const final {
0221 auto nBinsArray = m_cfg.grid.numLocalBins();
0222 return std::vector<std::size_t>(nBinsArray.begin(), nBinsArray.end());
0223 }
0224
0225
0226
0227
0228 std::vector<double> getMin() const final {
0229 return std::vector<double>(m_lowerLeft.begin(), m_lowerLeft.end());
0230 }
0231
0232
0233
0234
0235 std::vector<double> getMax() const final {
0236 return std::vector<double>(m_upperRight.begin(), m_upperRight.end());
0237 }
0238
0239
0240
0241
0242
0243
0244 bool isInside(const Vector3& position) const final {
0245 return isInsideLocal(m_cfg.transformPos(position));
0246 }
0247
0248
0249
0250
0251
0252
0253 bool isInsideLocal(const ActsVector<DIM_POS>& gridPosition) const {
0254 for (unsigned int i = 0; i < DIM_POS; ++i) {
0255 if (gridPosition[i] < m_lowerLeft[i] ||
0256 gridPosition[i] >= m_upperRight[i]) {
0257 return false;
0258 }
0259 }
0260 return true;
0261 }
0262
0263
0264
0265
0266 const Grid& getGrid() const { return m_cfg.grid; }
0267
0268
0269 MagneticFieldProvider::Cache makeCache(
0270 const MagneticFieldContext& mctx) const final {
0271 return MagneticFieldProvider::Cache{std::in_place_type<Cache>, mctx};
0272 }
0273
0274
0275
0276
0277
0278
0279
0280
0281 Result<Vector3> getField(const Vector3& position) const {
0282 const auto gridPosition = m_cfg.transformPos(position);
0283 if (!isInsideLocal(gridPosition)) {
0284 return Result<Vector3>::failure(MagneticFieldError::OutOfBounds);
0285 }
0286
0287 return Result<Vector3>::success(
0288 m_cfg.transformBField(m_cfg.grid.interpolate(gridPosition), position));
0289 }
0290
0291 Vector3 getFieldUnchecked(const Vector3& position) const final {
0292 const auto gridPosition = m_cfg.transformPos(position);
0293 return m_cfg.transformBField(m_cfg.grid.interpolate(gridPosition),
0294 position);
0295 }
0296
0297
0298 Result<Vector3> getField(const Vector3& position,
0299 MagneticFieldProvider::Cache& cache) const final {
0300 Cache& lcache = cache.as<Cache>();
0301 const auto gridPosition = m_cfg.transformPos(position);
0302 if (!lcache.fieldCell || !(*lcache.fieldCell).isInside(gridPosition)) {
0303 auto res = getFieldCell(position);
0304 if (!res.ok()) {
0305 return Result<Vector3>::failure(res.error());
0306 }
0307 lcache.fieldCell = *res;
0308 }
0309 return Result<Vector3>::success((*lcache.fieldCell).getField(gridPosition));
0310 }
0311
0312
0313
0314
0315
0316
0317 Result<Vector3> getFieldGradient(
0318 const Vector3& position, ActsMatrix<3, 3>& derivative,
0319 MagneticFieldProvider::Cache& cache) const final {
0320 (void)derivative;
0321 return getField(position, cache);
0322 }
0323
0324 private:
0325 Config m_cfg;
0326
0327 typename Grid::point_t m_lowerLeft;
0328 typename Grid::point_t m_upperRight;
0329 };
0330
0331 }