BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSFieldMagSolenoidLoop.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) BDSIM Collaboration, 2001 - 2026.
3
4This file is part of BDSIM.
5
6BDSIM is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published
8by the Free Software Foundation version 3 of the License.
9
10BDSIM is distributed in the hope that it will be useful, but
11WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
17*/
18#include "BDSFieldMagSolenoidLoop.hh"
19#include "BDSMagnetStrength.hh"
20#include "BDSSpecialFunctions.hh"
21#include "BDSUtilities.hh"
22
23#include "G4ThreeVector.hh"
24#include "G4Types.hh"
25
26#include "CLHEP/Units/PhysicalConstants.h"
27#include "CLHEP/Units/SystemOfUnits.h"
28
29#include <cmath>
30
31BDSFieldMagSolenoidLoop::BDSFieldMagSolenoidLoop(BDSMagnetStrength const* strength,
32 G4double radiusIn):
33 BDSFieldMagSolenoidLoop((*strength)["field"], false, radiusIn)
34{;}
35
36BDSFieldMagSolenoidLoop::BDSFieldMagSolenoidLoop(G4double strength,
37 G4bool strengthIsCurrent,
38 G4double radiusIn):
39 a(radiusIn),
40 B0(0),
41 I(0),
42 spatialLimit(1e-6*radiusIn),
43 mu0OverPiTimesITimesA(1)
44{
45 // 'strength' can be current or B field
46 finiteStrength = BDS::IsFinite(std::abs(strength));
47
48 // apply relationship B0 = mu_0 I / 2 a for on-axis rho=0,z=0
49 if (strengthIsCurrent)
50 {
51 I = strength;
52 B0 = CLHEP::mu0 * strength / (2*a);
53 }
54 else
55 {// strength is B0 -> calculate current
56 B0 = strength;
57 I = B0 * 2 * a / CLHEP::mu0;
58 }
59
60 mu0OverPiTimesITimesA = CLHEP::mu0 * I * a / CLHEP::pi;
61}
62
63G4ThreeVector BDSFieldMagSolenoidLoop::GetField(const G4ThreeVector& position,
64 const G4double /*t*/) const
65{
66 G4double z = position.z();
67 G4double rho = position.perp();
68 G4double phi = position.phi(); // angle about z axis
69
70 // check if close to current loop - function not well-behaved at exactly
71 // the rho of the current loop
72 if (std::abs(z) < spatialLimit && (std::abs(rho - a) < spatialLimit))
73 {return G4ThreeVector();}
74
75 G4double zSq = z*z;
76
77 G4double aPlusRho = a + rho;
78 G4double aPlusRhoSq = aPlusRho * aPlusRho;
79 G4double aMinusRho = a - rho;
80 G4double aMinusRhoSq = aMinusRho*aMinusRho;
81
82 G4double gamma = aMinusRho / aPlusRho;
83
84 G4double zSqPlusAPlusRhoSq = zSq + aPlusRhoSq;
85 G4double zSqPlusAMinusRhoSq = zSq + aMinusRhoSq;
86
87 G4double k1Sq = zSqPlusAMinusRhoSq / zSqPlusAPlusRhoSq;
88 G4double k1 = std::sqrt(k1Sq);
89
90 G4double zSqPlusAPlusRhoSqFactor3o2 = std::pow(zSqPlusAPlusRhoSq, 1.5);
91
92 G4double commonFactor = mu0OverPiTimesITimesA / zSqPlusAPlusRhoSqFactor3o2;
93
94 G4double Brho = commonFactor * z * BDS::CEL(k1, k1Sq, -1, 1);
95 G4double Bz = commonFactor * aPlusRho * BDS::CEL(k1, k1Sq, 1, gamma);
96
97 // technically possible for integral to return nan, so protect against it and default to B0 along z
98 if (std::isnan(Brho))
99 {Brho = 0;}
100 if (std::isnan(Bz))
101 {Bz = B0;}
102
103 // we have to be consistent with the phi we calculated at the beginning,
104 // so unit rho is in the x direction.
105 G4ThreeVector result = G4ThreeVector(Brho,0,Bz);
106 result = result.rotateZ(phi);
107 return result;
108}
Class that provides the magnetic field due to a cylinder of current.
virtual G4ThreeVector GetField(const G4ThreeVector &position, const G4double t=0) const
Calculate the field value.
G4bool finiteStrength
Flag to cache whether finite nor not.
Efficient storage of magnet strengths.
G4double CEL(G4double kc, G4double p, G4double c, G4double s, G4int nIterationLimit=1000)
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())