File indexing completed on 2025-08-05 08:09:38
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/MagneticField/BFieldMapUtils.hpp"
0010
0011 #include "Acts/MagneticField/MagneticFieldProvider.hpp"
0012 #include "Acts/MagneticField/SolenoidBField.hpp"
0013 #include "Acts/Utilities/Grid.hpp"
0014 #include "Acts/Utilities/Result.hpp"
0015 #include "Acts/Utilities/VectorHelpers.hpp"
0016 #include "Acts/Utilities/detail/Axis.hpp"
0017 #include "Acts/Utilities/detail/grid_helper.hpp"
0018
0019 #include <algorithm>
0020 #include <cmath>
0021 #include <cstdlib>
0022 #include <initializer_list>
0023 #include <limits>
0024 #include <set>
0025 #include <tuple>
0026
0027 using Acts::VectorHelpers::perp;
0028 using Acts::VectorHelpers::phi;
0029
0030 Acts::InterpolatedBFieldMap<
0031 Acts::Grid<Acts::Vector2, Acts::detail::EquidistantAxis,
0032 Acts::detail::EquidistantAxis>>
0033 Acts::fieldMapRZ(
0034 const std::function<std::size_t(std::array<std::size_t, 2> binsRZ,
0035 std::array<std::size_t, 2> nBinsRZ)>&
0036 localToGlobalBin,
0037 std::vector<double> rPos, std::vector<double> zPos,
0038 std::vector<Acts::Vector2> bField, double lengthUnit, double BFieldUnit,
0039 bool firstQuadrant) {
0040
0041
0042 std::sort(rPos.begin(), rPos.end());
0043 std::sort(zPos.begin(), zPos.end());
0044
0045 rPos.erase(std::unique(rPos.begin(), rPos.end()), rPos.end());
0046 zPos.erase(std::unique(zPos.begin(), zPos.end()), zPos.end());
0047 rPos.shrink_to_fit();
0048 zPos.shrink_to_fit();
0049
0050 std::size_t nBinsR = rPos.size();
0051 std::size_t nBinsZ = zPos.size();
0052
0053
0054
0055 double rMin = rPos[0];
0056 double zMin = zPos[0];
0057 double rMax = rPos[nBinsR - 1];
0058 double zMax = zPos[nBinsZ - 1];
0059
0060
0061 double stepZ = std::fabs(zMax - zMin) / (nBinsZ - 1);
0062 double stepR = std::fabs(rMax - rMin) / (nBinsR - 1);
0063 rMax += stepR;
0064 zMax += stepZ;
0065 if (firstQuadrant) {
0066 zMin = -zPos[nBinsZ - 1];
0067 nBinsZ = static_cast<std::size_t>(2. * nBinsZ - 1);
0068 }
0069
0070
0071 Acts::detail::EquidistantAxis rAxis(rMin * lengthUnit, rMax * lengthUnit,
0072 nBinsR);
0073 Acts::detail::EquidistantAxis zAxis(zMin * lengthUnit, zMax * lengthUnit,
0074 nBinsZ);
0075
0076
0077 using Grid_t = Acts::Grid<Acts::Vector2, Acts::detail::EquidistantAxis,
0078 Acts::detail::EquidistantAxis>;
0079 Grid_t grid(std::make_tuple(std::move(rAxis), std::move(zAxis)));
0080
0081
0082 for (std::size_t i = 1; i <= nBinsR; ++i) {
0083 for (std::size_t j = 1; j <= nBinsZ; ++j) {
0084 std::array<std::size_t, 2> nIndices = {{rPos.size(), zPos.size()}};
0085 Grid_t::index_t indices = {{i, j}};
0086 if (firstQuadrant) {
0087
0088
0089
0090 std::size_t n = std::abs(int(j) - int(zPos.size()));
0091 Grid_t::index_t indicesFirstQuadrant = {{i - 1, n}};
0092
0093 grid.atLocalBins(indices) =
0094 bField.at(localToGlobalBin(indicesFirstQuadrant, nIndices)) *
0095 BFieldUnit;
0096 } else {
0097
0098
0099
0100 grid.atLocalBins(indices) =
0101 bField.at(localToGlobalBin({{i - 1, j - 1}}, nIndices)) *
0102 BFieldUnit;
0103 }
0104 }
0105 }
0106 grid.setExteriorBins(Acts::Vector2::Zero());
0107
0108
0109
0110 auto transformPos = [](const Acts::Vector3& pos) {
0111 return Acts::Vector2(perp(pos), pos.z());
0112 };
0113
0114
0115
0116 auto transformBField = [](const Acts::Vector2& field,
0117 const Acts::Vector3& pos) {
0118 double r_sin_theta_2 = pos.x() * pos.x() + pos.y() * pos.y();
0119 double cos_phi = 0, sin_phi = 0;
0120 if (r_sin_theta_2 > std::numeric_limits<double>::min()) {
0121 double inv_r_sin_theta = 1. / sqrt(r_sin_theta_2);
0122 cos_phi = pos.x() * inv_r_sin_theta;
0123 sin_phi = pos.y() * inv_r_sin_theta;
0124 } else {
0125 cos_phi = 1.;
0126 sin_phi = 0.;
0127 }
0128 return Acts::Vector3(field.x() * cos_phi, field.x() * sin_phi, field.y());
0129 };
0130
0131
0132
0133 return Acts::InterpolatedBFieldMap<Grid_t>(
0134 {transformPos, transformBField, std::move(grid)});
0135 }
0136
0137 Acts::InterpolatedBFieldMap<
0138 Acts::Grid<Acts::Vector3, Acts::detail::EquidistantAxis,
0139 Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis>>
0140 Acts::fieldMapXYZ(
0141 const std::function<std::size_t(std::array<std::size_t, 3> binsXYZ,
0142 std::array<std::size_t, 3> nBinsXYZ)>&
0143 localToGlobalBin,
0144 std::vector<double> xPos, std::vector<double> yPos,
0145 std::vector<double> zPos, std::vector<Acts::Vector3> bField,
0146 double lengthUnit, double BFieldUnit, bool firstOctant) {
0147
0148
0149 std::sort(xPos.begin(), xPos.end());
0150 std::sort(yPos.begin(), yPos.end());
0151 std::sort(zPos.begin(), zPos.end());
0152
0153 xPos.erase(std::unique(xPos.begin(), xPos.end()), xPos.end());
0154 yPos.erase(std::unique(yPos.begin(), yPos.end()), yPos.end());
0155 zPos.erase(std::unique(zPos.begin(), zPos.end()), zPos.end());
0156 xPos.shrink_to_fit();
0157 yPos.shrink_to_fit();
0158 zPos.shrink_to_fit();
0159
0160 std::size_t nBinsX = xPos.size();
0161 std::size_t nBinsY = yPos.size();
0162 std::size_t nBinsZ = zPos.size();
0163
0164
0165
0166
0167 double xMin = xPos[0];
0168 double yMin = yPos[0];
0169 double zMin = zPos[0];
0170
0171 double xMax = xPos[nBinsX - 1];
0172 double yMax = yPos[nBinsY - 1];
0173 double zMax = zPos[nBinsZ - 1];
0174
0175
0176 double stepZ = std::fabs(zMax - zMin) / (nBinsZ - 1);
0177 double stepY = std::fabs(yMax - yMin) / (nBinsY - 1);
0178 double stepX = std::fabs(xMax - xMin) / (nBinsX - 1);
0179 xMax += stepX;
0180 yMax += stepY;
0181 zMax += stepZ;
0182
0183
0184 if (firstOctant) {
0185 xMin = -xPos[nBinsX - 1];
0186 yMin = -yPos[nBinsY - 1];
0187 zMin = -zPos[nBinsZ - 1];
0188 nBinsX = 2 * nBinsX - 1;
0189 nBinsY = 2 * nBinsY - 1;
0190 nBinsZ = 2 * nBinsZ - 1;
0191 }
0192 Acts::detail::EquidistantAxis xAxis(xMin * lengthUnit, xMax * lengthUnit,
0193 nBinsX);
0194 Acts::detail::EquidistantAxis yAxis(yMin * lengthUnit, yMax * lengthUnit,
0195 nBinsY);
0196 Acts::detail::EquidistantAxis zAxis(zMin * lengthUnit, zMax * lengthUnit,
0197 nBinsZ);
0198
0199 using Grid_t =
0200 Acts::Grid<Acts::Vector3, Acts::detail::EquidistantAxis,
0201 Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis>;
0202 Grid_t grid(
0203 std::make_tuple(std::move(xAxis), std::move(yAxis), std::move(zAxis)));
0204
0205
0206 for (std::size_t i = 1; i <= nBinsX; ++i) {
0207 for (std::size_t j = 1; j <= nBinsY; ++j) {
0208 for (std::size_t k = 1; k <= nBinsZ; ++k) {
0209 Grid_t::index_t indices = {{i, j, k}};
0210 std::array<std::size_t, 3> nIndices = {
0211 {xPos.size(), yPos.size(), zPos.size()}};
0212 if (firstOctant) {
0213
0214
0215
0216 std::size_t m = std::abs(int(i) - (int(xPos.size())));
0217 std::size_t n = std::abs(int(j) - (int(yPos.size())));
0218 std::size_t l = std::abs(int(k) - (int(zPos.size())));
0219 Grid_t::index_t indicesFirstOctant = {{m, n, l}};
0220
0221 grid.atLocalBins(indices) =
0222 bField.at(localToGlobalBin(indicesFirstOctant, nIndices)) *
0223 BFieldUnit;
0224
0225 } else {
0226
0227
0228
0229 grid.atLocalBins(indices) =
0230 bField.at(localToGlobalBin({{i - 1, j - 1, k - 1}}, nIndices)) *
0231 BFieldUnit;
0232 }
0233 }
0234 }
0235 }
0236 grid.setExteriorBins(Acts::Vector3::Zero());
0237
0238
0239
0240 auto transformPos = [](const Acts::Vector3& pos) { return pos; };
0241
0242
0243
0244 auto transformBField = [](const Acts::Vector3& field,
0245 const Acts::Vector3& ) { return field; };
0246
0247
0248
0249 return Acts::InterpolatedBFieldMap<Grid_t>(
0250 {transformPos, transformBField, std::move(grid)});
0251 }
0252
0253 Acts::InterpolatedBFieldMap<
0254 Acts::Grid<Acts::Vector2, Acts::detail::EquidistantAxis,
0255 Acts::detail::EquidistantAxis>>
0256 Acts::solenoidFieldMap(std::pair<double, double> rlim,
0257 std::pair<double, double> zlim,
0258 std::pair<std::size_t, std::size_t> nbins,
0259 const SolenoidBField& field) {
0260 double rMin = 0, rMax = 0, zMin = 0, zMax = 0;
0261 std::tie(rMin, rMax) = rlim;
0262 std::tie(zMin, zMax) = zlim;
0263
0264 std::size_t nBinsR = 0, nBinsZ = 0;
0265 std::tie(nBinsR, nBinsZ) = nbins;
0266
0267 double stepZ = std::abs(zMax - zMin) / (nBinsZ - 1);
0268 double stepR = std::abs(rMax - rMin) / (nBinsR - 1);
0269
0270 rMax += stepR;
0271 zMax += stepZ;
0272
0273
0274 Acts::detail::EquidistantAxis rAxis(rMin, rMax, nBinsR);
0275 Acts::detail::EquidistantAxis zAxis(zMin, zMax, nBinsZ);
0276
0277
0278 using Grid_t = Acts::Grid<Acts::Vector2, Acts::detail::EquidistantAxis,
0279 Acts::detail::EquidistantAxis>;
0280 Grid_t grid(std::make_tuple(std::move(rAxis), std::move(zAxis)));
0281
0282
0283
0284 auto transformPos = [](const Acts::Vector3& pos) {
0285 return Acts::Vector2(perp(pos), pos.z());
0286 };
0287
0288
0289
0290 auto transformBField = [](const Acts::Vector2& bfield,
0291 const Acts::Vector3& pos) {
0292 double r_sin_theta_2 = pos.x() * pos.x() + pos.y() * pos.y();
0293 double cos_phi = 0, sin_phi = 0;
0294 if (r_sin_theta_2 > std::numeric_limits<double>::min()) {
0295 double inv_r_sin_theta = 1. / sqrt(r_sin_theta_2);
0296 cos_phi = pos.x() * inv_r_sin_theta;
0297 sin_phi = pos.y() * inv_r_sin_theta;
0298 } else {
0299 cos_phi = 1.;
0300 sin_phi = 0.;
0301 }
0302 return Acts::Vector3(bfield.x() * cos_phi, bfield.x() * sin_phi,
0303 bfield.y());
0304 };
0305
0306
0307
0308 for (std::size_t i = 0; i <= nBinsR + 1; i++) {
0309 for (std::size_t j = 0; j <= nBinsZ + 1; j++) {
0310 Grid_t::index_t index({i, j});
0311 if (i == 0 || j == 0 || i == nBinsR + 1 || j == nBinsZ + 1) {
0312
0313 grid.atLocalBins(index) = Grid_t::value_type(0, 0);
0314 } else {
0315
0316 Grid_t::point_t lowerLeft = grid.lowerLeftBinEdge(index);
0317
0318 Vector2 B = field.getField(Vector2(lowerLeft[0], lowerLeft[1]));
0319 grid.atLocalBins(index) = B;
0320 }
0321 }
0322 }
0323
0324
0325
0326 Acts::InterpolatedBFieldMap<Grid_t> map(
0327 {transformPos, transformBField, std::move(grid)});
0328 return map;
0329 }