Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2026-07-16 08:08:08

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
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 // Cylindrical (r,phi,z) version
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   // Create magnetic field context and cache
0032   MagneticFieldContext ctx;
0033   auto cache = field.makeCache(ctx);
0034 
0035   auto [rMin, rMax] = rLim;
0036   auto [pMin, pMax] = phiLim;  // radians
0037   auto [zMin, zMax] = zLim;
0038   const auto [nBinsR, nBinsP, nBinsZ] = nBins;
0039 
0040   // Guard against degenerate configs
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   // Follow solenoid style: extend upper edge by one step to accommodate
0047   // overflow bin edges
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   // Axes
0056   Axis rAxis(rMin, rMax, nBinsR);
0057   Axis pAxis(pMin, pMax, nBinsP);
0058   Axis zAxis(zMin, zMax, nBinsZ);
0059 
0060   // Grid stores (Br, Bphi, Bz)
0061   Grid grid(Type<Vector3>, std::move(rAxis), std::move(pAxis),
0062             std::move(zAxis));
0063   using Grid_t = decltype(grid);
0064 
0065   // (x,y,z) -> (r,phi,z)
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());  // in (-pi, pi]
0072     }
0073     return Vector3(r, phi,
0074                    pos.z());  // note: we reuse Vector3 to carry (r,phi,z)
0075   };
0076 
0077   // (Br,Bphi,Bz) + Cartesian pos -> (Bx,By,Bz)
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     // Cyl->Cart
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   // Fill bins (including under/overflow halo as zeros)
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);  // (r,phi,z)
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           // Query original field (Cartesian)
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           // Convert to cylindrical components to store
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   // Mapper
0137   InterpolatedBFieldMap<Grid_t> map(
0138       {transformPos, transformBField, std::move(grid)});
0139   return map;
0140 }
0141 
0142 // ---------------------------------
0143 // Cartesian (x,y,z) convenience map
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   // Create magnetic field context and cache
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   // Identity position transform: (x,y,z) -> (x,y,z)
0184   auto transformPos = [](const Vector3& pos) { return pos; };
0185 
0186   // Identity B-field transform: table already stores (Bx,By,Bz)
0187   auto transformBField = [](const Vector3& bField, const Vector3& /*pos*/) {
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;  // already (Bx,By,Bz)
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 }  // namespace Acts