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