Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:25

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 "Acts/MagneticField/SolenoidBField.hpp"
0010 
0011 #include "Acts/MagneticField/MagneticFieldError.hpp"
0012 #include "Acts/Utilities/VectorHelpers.hpp"
0013 
0014 #include <cmath>
0015 #include <numbers>
0016 
0017 #define BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
0018 
0019 #include <boost/exception/exception.hpp>
0020 #include <boost/math/special_functions/ellint_1.hpp>
0021 #include <boost/math/special_functions/ellint_2.hpp>
0022 
0023 Acts::SolenoidBField::SolenoidBField(Config config) : m_cfg(config) {
0024   m_dz = m_cfg.length / m_cfg.nCoils;
0025   m_R2 = m_cfg.radius * m_cfg.radius;
0026   // we need to scale so we reproduce the expected B field strength
0027   // at the center of the solenoid
0028   Vector2 field = multiCoilField({0, 0}, 1.);  // scale = 1
0029   m_scale = m_cfg.bMagCenter / field.norm();
0030 }
0031 
0032 Acts::MagneticFieldProvider::Cache Acts::SolenoidBField::makeCache(
0033     const MagneticFieldContext& mctx) const {
0034   return MagneticFieldProvider::Cache(std::in_place_type<Cache>, mctx);
0035 }
0036 
0037 Acts::Vector3 Acts::SolenoidBField::getField(const Vector3& position) const {
0038   using VectorHelpers::perp;
0039   Vector2 rzPos(perp(position), position.z());
0040   Vector2 rzField = multiCoilField(rzPos, m_scale);
0041   Vector3 xyzField(0, 0, rzField[1]);
0042 
0043   if (rzPos[0] != 0.) {
0044     // add xy field component, radially symmetric
0045     Vector3 rDir = Vector3(position.x(), position.y(), 0).normalized();
0046     xyzField += rDir * rzField[0];
0047   }
0048 
0049   return xyzField;
0050 }
0051 
0052 Acts::Result<Acts::Vector3> Acts::SolenoidBField::getField(
0053     const Vector3& position, MagneticFieldProvider::Cache& /*cache*/) const {
0054   return Result<Vector3>::success(getField(position));
0055 }
0056 
0057 Acts::Vector2 Acts::SolenoidBField::getField(const Vector2& position) const {
0058   return multiCoilField(position, m_scale);
0059 }
0060 
0061 Acts::Vector2 Acts::SolenoidBField::multiCoilField(const Vector2& pos,
0062                                                    double scale) const {
0063   // iterate over all coils
0064   Vector2 resultField(0, 0);
0065   for (std::size_t coil = 0; coil < m_cfg.nCoils; coil++) {
0066     Vector2 shiftedPos =
0067         Vector2(pos[0], pos[1] + m_cfg.length * 0.5 - m_dz * (coil + 0.5));
0068     resultField += singleCoilField(shiftedPos, scale);
0069   }
0070 
0071   return resultField;
0072 }
0073 
0074 Acts::Vector2 Acts::SolenoidBField::singleCoilField(const Vector2& pos,
0075                                                     double scale) const {
0076   return {B_r(pos, scale), B_z(pos, scale)};
0077 }
0078 
0079 double Acts::SolenoidBField::B_r(const Vector2& pos, double scale) const {
0080   //              _
0081   //     2       /  pi / 2          2    2          - 1 / 2
0082   // E (k )  =   |         ( 1  -  k  sin {theta} )         dtheta
0083   //  1         _/  0
0084   using boost::math::ellint_1;
0085   //              _          ____________________
0086   //     2       /  pi / 2| /       2    2
0087   // E (k )  =   |        |/ 1  -  k  sin {theta} dtheta
0088   //  2         _/  0
0089   using boost::math::ellint_2;
0090 
0091   double r = std::abs(pos[0]);
0092   double z = pos[1];
0093 
0094   if (r == 0) {
0095     return 0.;
0096   }
0097 
0098   //                            _                             _
0099   //              mu  I        |  /     2 \                    |
0100   //                0     kz   |  |2 - k  |    2          2    |
0101   // B (r, z)  =  ----- ------ |  |-------|E (k )  -  E (k )   |
0102   //  r            4pi     ___ |  |      2| 2          1       |
0103   //                    | /  3 |_ \2 - 2k /                   _|
0104   //                    |/ Rr
0105   double k_2 = k2(r, z);
0106   double k = std::sqrt(k_2);
0107   double constant =
0108       scale * k * z /
0109       (4 * std::numbers::pi * std::sqrt(m_cfg.radius * r * r * r));
0110 
0111   double B = (2. - k_2) / (2. - 2. * k_2) * ellint_2(k_2) - ellint_1(k_2);
0112 
0113   // pos[0] is still signed!
0114   return r / pos[0] * constant * B;
0115 }
0116 
0117 double Acts::SolenoidBField::B_z(const Vector2& pos, double scale) const {
0118   //              _
0119   //     2       /  pi / 2          2    2          - 1 / 2
0120   // E (k )  =   |         ( 1  -  k  sin {theta} )         dtheta
0121   //  1         _/  0
0122   using boost::math::ellint_1;
0123   //              _          ____________________
0124   //     2       /  pi / 2| /       2    2
0125   // E (k )  =   |        |/ 1  -  k  sin {theta} dtheta
0126   //  2         _/  0
0127   using boost::math::ellint_2;
0128 
0129   double r = std::abs(pos[0]);
0130   double z = pos[1];
0131 
0132   //                         _                                       _
0133   //             mu  I      |  /         2      \                     |
0134   //               0     k  |  | (R + r)k  - 2r |     2          2    |
0135   // B (r,z)  =  ----- ---- |  | -------------- | E (k )  +  E (k )   |
0136   //  z           4pi    __ |  |           2    |  2          1       |
0137   //                   |/Rr |_ \   2r(1 - k )   /                    _|
0138 
0139   if (r == 0) {
0140     double res = scale / 2. * m_R2 / (std::sqrt(m_R2 + z * z) * (m_R2 + z * z));
0141     return res;
0142   }
0143 
0144   double k_2 = k2(r, z);
0145   double k = std::sqrt(k_2);
0146   double constant =
0147       scale * k / (4 * std::numbers::pi * std::sqrt(m_cfg.radius * r));
0148   double B = ((m_cfg.radius + r) * k_2 - 2. * r) / (2. * r * (1. - k_2)) *
0149                  ellint_2(k_2) +
0150              ellint_1(k_2);
0151 
0152   return constant * B;
0153 }
0154 
0155 double Acts::SolenoidBField::k2(double r, double z) const {
0156   //  2           4Rr
0157   // k   =  ---------------
0158   //               2      2
0159   //        (R + r)   +  z
0160   return 4 * m_cfg.radius * r /
0161          ((m_cfg.radius + r) * (m_cfg.radius + r) + z * z);
0162 }