Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:09:38

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2017-2018 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 http://mozilla.org/MPL/2.0/.
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   // [1] Create Grid
0041   // sort the values
0042   std::sort(rPos.begin(), rPos.end());
0043   std::sort(zPos.begin(), zPos.end());
0044   // Get unique values
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   // get the number of bins
0050   std::size_t nBinsR = rPos.size();
0051   std::size_t nBinsZ = zPos.size();
0052 
0053   // get the minimum and maximum. We just sorted the vectors, so these are just
0054   // the first and last elements.
0055   double rMin = rPos[0];
0056   double zMin = zPos[0];
0057   double rMax = rPos[nBinsR - 1];
0058   double zMax = zPos[nBinsZ - 1];
0059   // calculate maxima (add one last bin, because bin value always corresponds to
0060   // left boundary)
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   // Create the axis for the grid
0071   Acts::detail::EquidistantAxis rAxis(rMin * lengthUnit, rMax * lengthUnit,
0072                                       nBinsR);
0073   Acts::detail::EquidistantAxis zAxis(zMin * lengthUnit, zMax * lengthUnit,
0074                                       nBinsZ);
0075 
0076   // Create the grid
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   // [2] Set the bField values
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         // std::vectors begin with 0 and we do not want the user needing to
0088         // take underflow or overflow bins in account this is why we need to
0089         // subtract by one
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         // std::vectors begin with 0 and we do not want the user needing to
0098         // take underflow or overflow bins in account this is why we need to
0099         // subtract by one
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   // [3] Create the transformation for the position
0109   // map (x,y,z) -> (r,z)
0110   auto transformPos = [](const Acts::Vector3& pos) {
0111     return Acts::Vector2(perp(pos), pos.z());
0112   };
0113 
0114   // [4] Create the transformation for the bfield
0115   // map (Br,Bz) -> (Bx,By,Bz)
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   // [5] Create the mapper & BField Service
0132   // create field mapping
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   // [1] Create Grid
0148   // Sort the values
0149   std::sort(xPos.begin(), xPos.end());
0150   std::sort(yPos.begin(), yPos.end());
0151   std::sort(zPos.begin(), zPos.end());
0152   // Get unique values
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   // get the number of bins
0160   std::size_t nBinsX = xPos.size();
0161   std::size_t nBinsY = yPos.size();
0162   std::size_t nBinsZ = zPos.size();
0163 
0164   // Create the axis for the grid
0165   // get minima and maximia. We just sorted the vectors, so these are just the
0166   // first and last elements.
0167   double xMin = xPos[0];
0168   double yMin = yPos[0];
0169   double zMin = zPos[0];
0170   // get maxima
0171   double xMax = xPos[nBinsX - 1];
0172   double yMax = yPos[nBinsY - 1];
0173   double zMax = zPos[nBinsZ - 1];
0174   // calculate maxima (add one last bin, because bin value always corresponds to
0175   // left boundary)
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   // If only the first octant is given
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   // Create the grid
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   // [2] Set the bField values
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           // std::vectors begin with 0 and we do not want the user needing to
0214           // take underflow or overflow bins in account this is why we need to
0215           // subtract by one
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           // std::vectors begin with 0 and we do not want the user needing to
0227           // take underflow or overflow bins in account this is why we need to
0228           // subtract by one
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   // [3] Create the transformation for the position
0239   // map (x,y,z) -> (r,z)
0240   auto transformPos = [](const Acts::Vector3& pos) { return pos; };
0241 
0242   // [4] Create the transformation for the bfield
0243   // map (Bx,By,Bz) -> (Bx,By,Bz)
0244   auto transformBField = [](const Acts::Vector3& field,
0245                             const Acts::Vector3& /*pos*/) { return field; };
0246 
0247   // [5] Create the mapper & BField Service
0248   // create field mapping
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   // Create the axis for the grid
0274   Acts::detail::EquidistantAxis rAxis(rMin, rMax, nBinsR);
0275   Acts::detail::EquidistantAxis zAxis(zMin, zMax, nBinsZ);
0276 
0277   // Create the grid
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   // Create the transformation for the position
0283   // map (x,y,z) -> (r,z)
0284   auto transformPos = [](const Acts::Vector3& pos) {
0285     return Acts::Vector2(perp(pos), pos.z());
0286   };
0287 
0288   // Create the transformation for the bfield
0289   // map (Br,Bz) -> (Bx,By,Bz)
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   // iterate over all bins, set their value to the solenoid value
0307   // at their lower left position
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         // under or overflow bin, set zero
0313         grid.atLocalBins(index) = Grid_t::value_type(0, 0);
0314       } else {
0315         // regular bin, get lower left boundary
0316         Grid_t::point_t lowerLeft = grid.lowerLeftBinEdge(index);
0317         // do lookup
0318         Vector2 B = field.getField(Vector2(lowerLeft[0], lowerLeft[1]));
0319         grid.atLocalBins(index) = B;
0320       }
0321     }
0322   }
0323 
0324   // Create the mapper & BField Service
0325   // create field mapping
0326   Acts::InterpolatedBFieldMap<Grid_t> map(
0327       {transformPos, transformBField, std::move(grid)});
0328   return map;
0329 }