BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSIntegratorMultipoleThin.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 "BDSIntegratorMultipoleThin.hh"
19#include "BDSMagnetStrength.hh"
20#include "BDSStep.hh"
21#include "BDSUtilities.hh"
22
23#include "G4Mag_EqRhs.hh"
24#include "G4ThreeVector.hh"
25
26#include <cmath>
27#include <list>
28#include <vector>
29#include <include/BDSGlobalConstants.hh>
30
31
33 G4double brhoIn,
34 G4Mag_EqRhs* eqOfMIn):
35 BDSIntegratorMag(eqOfMIn, 6),
36 brho(brhoIn)
37{
38 b0l = (*strength)["field"] * brho;
39 G4double l = (*strength)["length"] / CLHEP::m;
40 // avoid potential div by zero in strength normalisation
41 if (!BDS::IsFinite(l))
42 {l=1*CLHEP::m;}
43 std::vector<G4String> normKeys = strength->NormalComponentKeys();
44 std::vector<G4String> skewKeys = strength->SkewComponentKeys();
45 std::vector<G4String>::iterator nkey = normKeys.begin();
46 std::vector<G4String>::iterator skey = skewKeys.begin();
47 for (G4double i = 0; i < normKeys.size(); i++, ++nkey, ++skey)
48 {
49 bnl.push_back((*strength)[*nkey] / (l*std::pow(CLHEP::m,i+1)));
50 bsl.push_back((*strength)[*skey] / (l*std::pow(CLHEP::m,i+1)));
51 nfact.push_back(Factorial(i));
52 }
53
54 G4bool finiteStrength = false;
55 for (const auto& nl : bnl)
56 {finiteStrength = finiteStrength || BDS::IsFiniteStrength(nl);}
57 for (const auto& sl : bsl)
58 {finiteStrength = finiteStrength || BDS::IsFiniteStrength(sl);}
59 zeroStrength = !finiteStrength;
60}
61
62void BDSIntegratorMultipoleThin::Stepper(const G4double yIn[],
63 const G4double[] /*dydx[]*/,
64 const G4double h,
65 G4double yOut[],
66 G4double yErr[])
67{
68 const G4double fcof = eqOfM->FCof();
69 G4double lengthFraction = h / thinElementLength;
70
71 // only apply the kick if we're taking a step longer than half the length of the item,
72 // in which case, apply the full kick. This appears more robust than scaling the kick
73 // by h / thinElementLength as the precise geometrical length depends on the geometry
74 // ie if there's a beam pipe etc -> more length safetys. The geometry layout should
75 // prevent more than one step begin taken, but occasionally, a very small initial step
76 // can be taken resulting in a double kick.
77 if (zeroStrength || lengthFraction < 0.51 || !BDS::IsFiniteStrength(fcof))
78 {
79 AdvanceDriftMag(yIn, h, yOut, yErr);
80 SetDistChord(0);
81 return;
82 }
83
84 G4ThreeVector pos = G4ThreeVector(yIn[0], yIn[1], yIn[2]);
85 G4ThreeVector mom = G4ThreeVector(yIn[3], yIn[4], yIn[5]);
86 G4double momMag = mom.mag();
87
88 // global to local
89 BDSStep localPosMom = ConvertToLocal(pos, mom, h, false, thinElementLength);
90 G4ThreeVector localPos = localPosMom.PreStepPoint();
91 G4ThreeVector localMom = localPosMom.PostStepPoint();
92 G4ThreeVector localMomUnit = localMom.unit();
93
94 // only proceed with thin multipole step if particle is paraxial
95 // judged by forward momentum > 1-limit and |transverse| < limit (default limit=0.1)
96 if (localMomUnit.z() < (1.0 - backupStepperMomLimit))
97 {
98 AdvanceDriftMag(yIn, h, yOut, yErr);
99 SetDistChord(0);
100 return;
101 }
102
103 G4ThreeVector localPosOut;
104 G4ThreeVector localMomUnitOut;
105
106 OneStep(localPos, localMomUnit, momMag, localPosOut, localMomUnitOut, h);
107
108 // xp1 or yp1 may be > 1, so isnan check also needed for zp1.
109 G4double zp1 = localMomUnitOut.z();
110 if (std::isnan(zp1) || (zp1 < backupStepperMomLimit))
111 {
112 AdvanceDriftMag(yIn, h, yOut, yErr);
113 SetDistChord(0);
114 return;
115 }
116
117
118 ConvertToGlobal(localPosOut, localMomUnitOut, yOut, yErr, momMag);
119}
120
121void BDSIntegratorMultipoleThin::OneStep(const G4ThreeVector& posIn,
122 const G4ThreeVector& momUIn,
123 const G4double momIn,
124 G4ThreeVector& posOut,
125 G4ThreeVector& momOut,
126 G4double h) const
127{
128 G4double x0 = posIn.x();
129 G4double y0 = posIn.y();
130 G4double z0 = posIn.z();
131 G4double xp = momUIn.x();
132 G4double yp = momUIn.y();
133 G4double zp = momUIn.z();
134
135 // initialise output variables with input position as default
136 G4double x1 = x0;
137 G4double y1 = y0;
138 G4double z1 = z0 + h; // new z position will be along z by step length h
139 G4double xp1 = xp;
140 G4double yp1 = yp;
141 G4double zp1 = zp;
142
143 // kicks come from pg 27 of mad-8 physical methods manual
144 G4complex kick(0,0);
145 G4complex position(x0, y0);
146 G4complex result(0,0);
147 // components of complex vector
148 G4double knReal = 0;
149 G4double knImag = 0;
150 G4double momx;
151 G4double momy;
152
153 // normalise to momentum and charge
154 G4double ratio = eqOfM->FCof() * std::abs(brho) / momIn;
155
156 G4int n = 1;
157 std::list<double>::const_iterator kn = bnl.begin();
158
159 // sum higher order components into one kick
160 for (; kn != bnl.end(); n++, ++kn)
161 {
162 momx = 0; //reset to zero
163 momy = 0;
164 knReal = (*kn) * ratio * std::pow(position,n).real() / nfact[n];
165 knImag = (*kn) * ratio * std::pow(position,n).imag() / nfact[n];
166 if (!std::isnan(knReal))
167 {momx = knReal;}
168 if (!std::isnan(knImag))
169 {momy = knImag;}
170 result = {momx,momy};
171 kick += result;
172 }
173
174 // reset n for skewed kicks.
175 n=1;
176 G4double ksReal = 0;
177 G4double ksImag = 0;
178 G4complex skewkick(0,0);
179
180 std::list<double>::const_iterator ks = bsl.begin();
181 for (; ks != bsl.end(); n++, ++ks)
182 {
183 if (BDS::IsFinite(*ks))
184 {
185 //reset to zero
186 momx = 0;
187 momy = 0;
188 ksReal = (*ks) * ratio * std::pow(position, n).real() / nfact[n];
189 ksImag = (*ks) * ratio * std::pow(position, n).imag() / nfact[n];
190 if (!std::isnan(ksReal))
191 {momx = ksReal;}
192 if (!std::isnan(ksImag))
193 {momy = ksImag;}
194 result = {momx,momy};
195 skewkick += result;
196 }
197 }
198
199 // apply normal kick
200 xp1 -= kick.real();
201 yp1 += kick.imag();
202
203 //apply skewed kick
204 xp1 -= skewkick.imag();
205 yp1 += skewkick.real();
206
207 zp1 = std::sqrt(1 - std::pow(xp1,2) - std::pow(yp1,2));
208 if (std::isnan(zp1))
209 {zp1 = zp;}
210
211 posOut = G4ThreeVector(x1, y1, z1);
212 momOut = G4ThreeVector(xp1, yp1, zp1);
213}
214
216{
217 G4int result = 1;
218 for (G4int i = 1; i <= n; i++)
219 {result *= i;}
220 return result;
221}
BDSStep ConvertToLocal(G4Step const *const step, G4bool useCurvilinear=true) const
void AdvanceDriftMag(const G4double yIn[], const G4double h, G4double yOut[], G4double yErr[]) const
Error array [6] all 0.
Common functionality to BDSIM integrators.
G4Mag_EqRhs * eqOfM
void SetDistChord(G4double distChordIn)
Setter for distChord to private member.
static G4double thinElementLength
void ConvertToGlobal(const G4ThreeVector &localPos, const G4ThreeVector &localMom, G4double yOut[], G4double yErr[], const G4double momScaling=1.0)
scaling of momentum in case localMom is a unit vector
std::vector< G4int > nfact
Higher order components.
G4int Factorial(G4int n)
Calculate the factorial of n.
void OneStep(const G4ThreeVector &posIn, const G4ThreeVector &momUIn, const G4double momIn, G4ThreeVector &posOut, G4ThreeVector &momOut, G4double h) const
BDSIntegratorMultipoleThin()=delete
Private default constructor to enforce use of supplied constructor.
std::list< double > bsl
Higher order components.
G4double brho
Magnetic rigidity for momentum scaling.
virtual void Stepper(const G4double yIn[], const G4double dydx[], const G4double h, G4double yOut[], G4double yErr[])
std::list< double > bnl
Higher order components.
Efficient storage of magnet strengths.
static std::vector< G4String > SkewComponentKeys()
Accessor for skew component keys - k1 - k12.
static std::vector< G4String > NormalComponentKeys()
Accessor for normal component keys - k1 - k12.
A simple class to represent the positions of a step.
Definition BDSStep.hh:32
G4ThreeVector PostStepPoint() const
Accessor.
Definition BDSStep.hh:42
G4ThreeVector PreStepPoint() const
Accessor.
Definition BDSStep.hh:41
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())
G4bool IsFiniteStrength(G4double variable)