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