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