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