BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
BDSFieldMagMultipole.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 "BDSDebug.hh"
20#include "BDSFieldMagMultipole.hh"
21#include "BDSMagnetStrength.hh"
22#include "BDSUtilities.hh"
23
24#include "globals.hh"
25#include "G4ThreeVector.hh"
26
27#include <cmath>
28#include <vector>
29
31 G4double const brho,
32 G4int const orderIn):
33 order(orderIn),
34 maximumNonZeroOrder(0),
35 normalComponents(strength->NormalComponents()),
36 skewComponents(strength->SkewComponents())
37{
38 // multiple by brho to get field coefficients and work out maximum finite
39 // order to loop up to
40 // power is i+2 as 0th element is quadrupole coefficient which has 1/m^2
41 for (G4int i = 0; i < (G4int)normalComponents.size(); i++)
42 {
43 normalComponents[i] *= (brho / std::pow(CLHEP::m, i+2));
44 G4double kn = normalComponents[i];
45 G4bool nonZeroKN = BDS::IsFiniteStrength(kn);
46 finiteStrength = nonZeroKN || finiteStrength;
47 if (nonZeroKN)
48 {maximumNonZeroOrder = std::max(maximumNonZeroOrder, i);}
49 }
50 for (G4int i = 0; i < (G4int)skewComponents.size(); i++)
51 {
52 skewComponents[i] *= (brho / std::pow(CLHEP::m, i+2));
53 G4double ks = skewComponents[i];
54 G4bool nonZeroKS = BDS::IsFiniteStrength(ks);
55 finiteStrength = nonZeroKS || finiteStrength;
56 if (nonZeroKS)
57 {maximumNonZeroOrder = std::max(maximumNonZeroOrder, i);}
58 }
59 maximumNonZeroOrder += 1; // 0 to 1 counting
60
61 // safety check - ensure we're not going to a higher order than the strength
62 // class supports.
63 if (std::abs(order) > (G4int)normalComponents.size())
64 {order = (G4int)normalComponents.size();}
65}
66
67G4ThreeVector BDSFieldMagMultipole::GetField(const G4ThreeVector &position,
68 const G4double /*t*/) const
69{
70 // Translate cartesian to polar coordinates
71 G4double r = std::hypot(position.x(),position.y());
72 G4double phi = 0;
73 if (BDS::IsFiniteStrength(std::abs(r)))
74 {phi = atan2(position.y(),position.x());}
75
76 // compute B field in cylindrical coordinates first then convert to cartesian
77 // Bx = Br * cos(phi) - Bphi * sin(phi)
78 // By = Br * sin(phi) + Bphi * cos(phi)
79 // where, if n=1 is for dipole:
80 // Br (n) (normal) = +Bn/(n-1)! * r^(n-1) * sin(n*phi)
81 // Bphi(n) (normal) = +Bn/(n-1)! * r^(n-1) * cos(n*phi)
82 // Br (n) (skewed) = +Bn/(n-1)! * r^(n-1) * cos(n*phi)
83 // Bphi(n) (skewed) = -Bn/(n-1)! * r^(n-1) * sin(n*phi)
84 // cumulative variables for calculating the field
85
86 G4double br = 0;
87 G4double bphi = 0;
88 // I want to use the strange convention of dipole coeff. with opposite sign -
89 // then it is the same sign as angle.
90 G4double ffact = -1;
91 for (G4int i = 0; i < maximumNonZeroOrder; i++)
92 {
93 // Here we add to so order represents kn properly
94 G4double o = (G4double)i+2; // the current order
95 br += normalComponents[i] * std::pow(r, o - 1) * std::sin(o * phi) / ffact; //normal
96 br -= skewComponents[i] * std::pow(r, o - 1) * std::cos(o * phi) / ffact; //skewed
97
98 bphi += normalComponents[i] * std::pow(r, o - 1) * std::cos(o * phi) / ffact; //normal
99 bphi += skewComponents[i] * std::pow(r, o - 1) * std::sin(o * phi) / ffact; //skewed
100
101 // Ignore dipole component for now!
102 //if(o==1) // for the angle convention
103 //{br *= -1; bphi *=-1; }
104
105 ffact *= o;
106 }
107
108 G4ThreeVector cartesianField;
109 cartesianField[0] = (br * std::cos(phi) - bphi * std::sin(phi)); // B_x
110 cartesianField[1] = (br * std::sin(phi) + bphi * std::cos(phi)); // B_y
111 cartesianField[2] = 0; // B_z
112
113 return cartesianField;
114}
115
116
117
std::vector< G4double > normalComponents
Normal field components (normal - ie not skew) = kn * brho.
BDSFieldMagMultipole()
Private default constructor to force use of supplied constructor.
std::vector< G4double > skewComponents
Skew field components = kns * brho.
virtual G4ThreeVector GetField(const G4ThreeVector &position, const G4double t=0) const
Access the field value.
Efficient storage of magnet strengths.
G4bool IsFiniteStrength(G4double variable)