File indexing completed on 2026-07-16 08:08:08
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/MagneticField/ToroidalFieldMap.hpp"
0010
0011 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0012 #include "ActsExamples/MagneticField/ToroidalField.hpp"
0013
0014 #include <cmath>
0015 #include <limits>
0016
0017 namespace Acts {
0018
0019
0020
0021
0022 InterpolatedBFieldMap<
0023 Grid<Vector3, Axis<AxisType::Equidistant>, Axis<AxisType::Equidistant>,
0024 Axis<AxisType::Equidistant>>>
0025 toroidalFieldMapCyl(
0026 const std::pair<double, double>& rLim,
0027 const std::pair<double, double>& phiLim,
0028 const std::pair<double, double>& zLim,
0029 const std::tuple<std::size_t, std::size_t, std::size_t>& nBins,
0030 const ToroidalField& field) {
0031
0032 MagneticFieldContext ctx;
0033 auto cache = field.makeCache(ctx);
0034
0035 auto [rMin, rMax] = rLim;
0036 auto [pMin, pMax] = phiLim;
0037 auto [zMin, zMax] = zLim;
0038 const auto [nBinsR, nBinsP, nBinsZ] = nBins;
0039
0040
0041 if (nBinsR < 2 || nBinsP < 2 || nBinsZ < 2) {
0042 throw std::invalid_argument(
0043 "toroidalFieldMapCyl: each dimension needs at least 2 bins");
0044 }
0045
0046
0047
0048 double stepR = std::abs(rMax - rMin) / static_cast<double>(nBinsR - 1);
0049 double stepP = std::abs(pMax - pMin) / static_cast<double>(nBinsP - 1);
0050 double stepZ = std::abs(zMax - zMin) / static_cast<double>(nBinsZ - 1);
0051 rMax += stepR;
0052 pMax += stepP;
0053 zMax += stepZ;
0054
0055
0056 Axis rAxis(rMin, rMax, nBinsR);
0057 Axis pAxis(pMin, pMax, nBinsP);
0058 Axis zAxis(zMin, zMax, nBinsZ);
0059
0060
0061 Grid grid(Type<Vector3>, std::move(rAxis), std::move(pAxis),
0062 std::move(zAxis));
0063 using Grid_t = decltype(grid);
0064
0065
0066 auto transformPos = [](const Vector3& pos) {
0067 const double r2 = pos.x() * pos.x() + pos.y() * pos.y();
0068 const double r = std::sqrt(r2);
0069 double phi = 0.0;
0070 if (r2 > std::numeric_limits<double>::min()) {
0071 phi = std::atan2(pos.y(), pos.x());
0072 }
0073 return Vector3(r, phi,
0074 pos.z());
0075 };
0076
0077
0078 auto transformBField = [](const Vector3& bCyl, const Vector3& pos) {
0079 const double r2 = pos.x() * pos.x() + pos.y() * pos.y();
0080 double cosPhi = 1.0, sinPhi = 0.0;
0081 if (r2 > std::numeric_limits<double>::min()) {
0082 const double invR = 1.0 / std::sqrt(r2);
0083 cosPhi = pos.x() * invR;
0084 sinPhi = pos.y() * invR;
0085 }
0086 const double Br = bCyl.x();
0087 const double Bphi = bCyl.y();
0088 const double Bz = bCyl.z();
0089
0090 const double Bx = Br * cosPhi - Bphi * sinPhi;
0091 const double By = Br * sinPhi + Bphi * cosPhi;
0092 return Vector3(Bx, By, Bz);
0093 };
0094
0095
0096 for (std::size_t ir = 0; ir <= nBinsR + 1; ++ir) {
0097 for (std::size_t ip = 0; ip <= nBinsP + 1; ++ip) {
0098 for (std::size_t iz = 0; iz <= nBinsZ + 1; ++iz) {
0099 Grid_t::index_t index({ir, ip, iz});
0100 if (ir == 0 || ip == 0 || iz == 0 || ir == nBinsR + 1 ||
0101 ip == nBinsP + 1 || iz == nBinsZ + 1) {
0102 grid.atLocalBins(index) = Grid_t::value_type(0.0, 0.0, 0.0);
0103 } else {
0104 const Grid_t::point_t ll = grid.lowerLeftBinEdge(index);
0105 const double r = ll[0];
0106 const double phi = ll[1];
0107 const double z = ll[2];
0108
0109 const double x = r * std::cos(phi);
0110 const double y = r * std::sin(phi);
0111
0112
0113 auto res = field.getField(Vector3(x, y, z), cache);
0114
0115 Vector3 Bxyz(0.0, 0.0, 0.0);
0116 if (res.ok()) {
0117 Bxyz = *res;
0118 }
0119
0120
0121 double cosPhi =
0122 (r > std::numeric_limits<double>::min()) ? std::cos(phi) : 1.0;
0123 double sinPhi =
0124 (r > std::numeric_limits<double>::min()) ? std::sin(phi) : 0.0;
0125
0126 const double Br = Bxyz.x() * cosPhi + Bxyz.y() * sinPhi;
0127 const double Bphi = -Bxyz.x() * sinPhi + Bxyz.y() * cosPhi;
0128 const double Bz = Bxyz.z();
0129
0130 grid.atLocalBins(index) = Grid_t::value_type(Br, Bphi, Bz);
0131 }
0132 }
0133 }
0134 }
0135
0136
0137 InterpolatedBFieldMap<Grid_t> map(
0138 {transformPos, transformBField, std::move(grid)});
0139 return map;
0140 }
0141
0142
0143
0144
0145 InterpolatedBFieldMap<
0146 Grid<Vector3, Axis<AxisType::Equidistant>, Axis<AxisType::Equidistant>,
0147 Axis<AxisType::Equidistant>>>
0148 toroidalFieldMapXYZ(
0149 const std::pair<double, double>& xLim,
0150 const std::pair<double, double>& yLim,
0151 const std::pair<double, double>& zLim,
0152 const std::tuple<std::size_t, std::size_t, std::size_t>& nBins,
0153 const ToroidalField& field) {
0154
0155 MagneticFieldContext ctx;
0156 auto cache = field.makeCache(ctx);
0157
0158 auto [xMin, xMax] = xLim;
0159 auto [yMin, yMax] = yLim;
0160 auto [zMin, zMax] = zLim;
0161 const auto [nBinsX, nBinsY, nBinsZ] = nBins;
0162
0163 if (nBinsX < 2 || nBinsY < 2 || nBinsZ < 2) {
0164 throw std::invalid_argument(
0165 "toroidalFieldMapXYZ: each dimension needs at least 2 bins");
0166 }
0167
0168 double stepX = std::abs(xMax - xMin) / static_cast<double>(nBinsX - 1);
0169 double stepY = std::abs(yMax - yMin) / static_cast<double>(nBinsY - 1);
0170 double stepZ = std::abs(zMax - zMin) / static_cast<double>(nBinsZ - 1);
0171 xMax += stepX;
0172 yMax += stepY;
0173 zMax += stepZ;
0174
0175 Axis xAxis(xMin, xMax, nBinsX);
0176 Axis yAxis(yMin, yMax, nBinsY);
0177 Axis zAxis(zMin, zMax, nBinsZ);
0178
0179 Grid grid(Type<Vector3>, std::move(xAxis), std::move(yAxis),
0180 std::move(zAxis));
0181 using Grid_t = decltype(grid);
0182
0183
0184 auto transformPos = [](const Vector3& pos) { return pos; };
0185
0186
0187 auto transformBField = [](const Vector3& bField, const Vector3& ) {
0188 return bField;
0189 };
0190
0191 for (std::size_t ix = 0; ix <= nBinsX + 1; ++ix) {
0192 for (std::size_t iy = 0; iy <= nBinsY + 1; ++iy) {
0193 for (std::size_t iz = 0; iz <= nBinsZ + 1; ++iz) {
0194 Grid_t::index_t index({ix, iy, iz});
0195 if (ix == 0 || iy == 0 || iz == 0 || ix == nBinsX + 1 ||
0196 iy == nBinsY + 1 || iz == nBinsZ + 1) {
0197 grid.atLocalBins(index) = Grid_t::value_type(0.0, 0.0, 0.0);
0198 } else {
0199 const Grid_t::point_t ll = grid.lowerLeftBinEdge(index);
0200 const double x = ll[0];
0201 const double y = ll[1];
0202 const double z = ll[2];
0203
0204 auto res = field.getField(Vector3(x, y, z), cache);
0205 Vector3 B(0.0, 0.0, 0.0);
0206 if (res.ok()) {
0207 B = *res;
0208 }
0209 grid.atLocalBins(index) = Grid_t::value_type(B[0], B[1], B[2]);
0210 }
0211 }
0212 }
0213 }
0214
0215 InterpolatedBFieldMap<Grid_t> map(
0216 {transformPos, transformBField, std::move(grid)});
0217 return map;
0218 }
0219
0220 }