BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSIntegratorKickerThin.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 "BDSDebug.hh"
20#include "BDSIntegratorKickerThin.hh"
21#include "BDSMagnetStrength.hh"
22#include "BDSStep.hh"
23#include "BDSUtilities.hh"
24
25#include "G4Mag_EqRhs.hh"
26#include "G4ThreeVector.hh"
27
28#include <cmath>
29
31 G4double brhoIn,
32 G4Mag_EqRhs* eqOfMIn,
33 G4double minimumRadiusOfCurvatureIn):
34 BDSIntegratorMag(eqOfMIn, 6),
35 hkick((*strength)["hkick"]),
36 vkick((*strength)["vkick"]),
37 brho(brhoIn)
38{
39 // set base class member
40 zeroStrength = (!BDS::IsFiniteStrength(hkick) && !BDS::IsFiniteStrength(vkick));
41
42 // duplicate magnetstrength for fringe field integrators as all its physical parameters are set for the magnet
43 // as a whole, including fringes. Only isentrance bool determines if the object is for an entrance or exit
44 // fringe, therefore set as appropriate (required as BDSIntegratorDipoleFringe members are set upon
45 // instantiation according to isentrance).
46 BDSMagnetStrength* fringeStEntr = new BDSMagnetStrength(*strength);
47 BDSMagnetStrength* fringeStExit = new BDSMagnetStrength(*strength);
48 (*fringeStEntr)["isentrance"] = true;
49 (*fringeStExit)["isentrance"] = false;
50 // tilt is zero as only onestep function in local coords will be called in this integrator
51 fringeIntEntr = new BDSIntegratorDipoleFringe(fringeStEntr, brhoIn, eqOfMIn, minimumRadiusOfCurvatureIn, 0);
52 fringeIntExit = new BDSIntegratorDipoleFringe(fringeStExit, brhoIn, eqOfMIn, minimumRadiusOfCurvatureIn, 0);
53
54 // check if the fringe effect is finite
55 G4bool finiteEntrFringe = false;
56 G4bool finiteExitFringe = false;
57 if (BDS::IsFiniteStrength(fringeIntEntr->GetFringeCorr()) || BDS::IsFiniteStrength(fringeIntEntr->GetSecondFringeCorr()))
58 {finiteEntrFringe = true;}
59 if (BDS::IsFiniteStrength(fringeIntExit->GetFringeCorr()) || BDS::IsFiniteStrength(fringeIntExit->GetSecondFringeCorr()))
60 {finiteExitFringe = true;}
61
62 // only call fringe tracking if the poleface rotation or fringe field correction terms are finite
63 hasEntranceFringe = false;
64 hasExitFringe = false;
65 if (BDS::IsFinite(fringeIntEntr->GetPolefaceAngle()) || finiteEntrFringe)
66 {hasEntranceFringe = true;}
67 if (BDS::IsFinite(fringeIntExit->GetPolefaceAngle()) || finiteExitFringe)
68 {hasExitFringe = true;}
69
70 // effective bending radius needed for fringe field calculations
71 if (BDS::IsFinite((*strength)["field"]))
72 {rho = brhoIn/(*strength)["field"];}
73 else
74 {
75 // zero field means rho cannot be calculated, therefore do not allow fringe kicks.
76 rho = 1; // for safety
77 hasEntranceFringe = false;
78 hasExitFringe = false;
79 }
80
81 // tilt for vertical kickers. Poleface rotations are assumed to be about the vertical axis,
82 // so effect should be applied to rotated axes.
83 tiltAngle = 0;
84 if (!BDS::IsFinite((*strength)["by"]) && ((*strength)["bx"] == 1.0))
85 {tiltAngle = -CLHEP::pi/2.0;}
86
87 delete fringeStEntr;
88 delete fringeStExit;
89}
90
91void BDSIntegratorKickerThin::Stepper(const G4double yIn[],
92 const G4double[] /*dydx[]*/,
93 const G4double h,
94 G4double yOut[],
95 G4double yErr[])
96{
97 const G4double fcof = eqOfM->FCof();
98
99 // only apply the kick if we're taking a step longer than half the length of the item,
100 // in which case, apply the full kick. This appears more robust than scaling the kick
101 // by h / thinElementLength as the precise geometrical length depends on the geometry
102 // ie if there's a beam pipe etc -> more length safetys. The geometry layout should
103 // prevent more than one step begin taken, but occasionally, a very small initial step
104 // can be taken resulting in a double kick.
105 G4double lengthFraction = h / thinElementLength;
106
107 if (!BDS::IsFiniteStrength(fcof) || zeroStrength || lengthFraction < 0.51)
108 {// neutral particle or zero strength - drift through
109 AdvanceDriftMag(yIn, h, yOut, yErr);
110 SetDistChord(0);
111 return;
112 }
113
114 G4ThreeVector pos = G4ThreeVector(yIn[0], yIn[1], yIn[2]);
115 G4ThreeVector mom = G4ThreeVector(yIn[3], yIn[4], yIn[5]);
116
117 // global to local (thinElementLength is static base class member)
118 // purposively control step length as we're dealing with a very short element
119 BDSStep localPosMom = ConvertToLocal(pos, mom, h, false, thinElementLength);
120 G4ThreeVector localPos = localPosMom.PreStepPoint();
121 G4ThreeVector localMom = localPosMom.PostStepPoint();
122 G4ThreeVector localMomUnit = localMom.unit();
123 G4double localMomMag = localMom.mag();
124
125 // only proceed with thin kick if particle is paraxial
126 // judged by forward momentum > 1-limit and |transverse| < limit (default limit=0.1)
127 if (std::abs(localMomUnit.z()) < (1.0 - backupStepperMomLimit))
128 {
129 AdvanceDriftMag(yIn, h, yOut, yErr);
130 SetDistChord(0);
131 return;
132 }
133
134 // normalise to particle charge for fringe/poleface effects
135 G4double charge = fcof / std::abs(fcof);
136 G4double bendingRad = rho * charge;
137
138 // set as local coords in case no entrance fringe effect
139 G4ThreeVector fringeEntrPosOut = localPos;
140 G4ThreeVector fringeEntrMomOut = localMomUnit;
141
143 {
145 {
146 localPos.rotateZ(tiltAngle);
147 localMomUnit.rotateZ(tiltAngle);
148 fringeIntEntr->OneStep(localPos, localMomUnit, fringeEntrPosOut, fringeEntrMomOut, bendingRad);
149 fringeEntrPosOut.rotateZ(-tiltAngle);
150 fringeEntrMomOut.rotateZ(-tiltAngle);
151 }
152 else
153 {fringeIntEntr->OneStep(localPos, localMomUnit, fringeEntrPosOut, fringeEntrMomOut, bendingRad);}
154 }
155 fringeEntrMomOut *= localMomMag; // fringe returns unit momentum m
156
157 G4ThreeVector localPosOut;
158 G4ThreeVector localMomOut;
159
160 // do thin kicker step
161 OneStep(fringeEntrPosOut, fringeEntrMomOut, localMom, h, fcof, localPosOut, localMomOut);
162
163 // set as coords after kick in case no exit fringe effect
164 G4ThreeVector fringeExitPosOut = localPosOut;
165 G4ThreeVector fringeExitMomOut = localMomOut;
166
167 if (hasExitFringe)
168 {
170 {
171 localPosOut.rotateZ(tiltAngle);
172 localMomOut.rotateZ(tiltAngle);
173 fringeIntExit->OneStep(localPosOut, localMomOut.unit(), fringeExitPosOut, fringeExitMomOut, bendingRad);
174 fringeExitPosOut.rotateZ(-tiltAngle);
175 fringeExitMomOut.rotateZ(-tiltAngle);
176 }
177 else
178 {fringeIntExit->OneStep(localPosOut, localMomOut, fringeExitPosOut, fringeExitMomOut, bendingRad);}
179 }
180 fringeExitMomOut *= localMomMag; // fringe returns unit momentum
181
182 // convert back to global
183 ConvertToGlobal(fringeExitPosOut, fringeExitMomOut, yOut, yErr);
184}
185
186void BDSIntegratorKickerThin::OneStep(const G4ThreeVector& localPos,
187 const G4ThreeVector& localMomUnit,
188 const G4ThreeVector& localMom,
189 const G4double& h,
190 const G4double& fcof,
191 G4ThreeVector& localPosOut,
192 G4ThreeVector& localMomOut) const
193{
194 // Transverse position stays the same and the particle is advanced by h along local z.
195 G4double x1 = localPos.x();
196 G4double y1 = localPos.y();
197 G4double z1 = localPos.z();
198
199 G4double factor = 1; // for forwards / backwards action
200 if (localMomUnit.z() < 0)
201 {// backwards travelling
202 z1 -= h;
203 factor = -1;
204 }
205 else
206 {z1 += h;} // forwards travelling
207
208 G4double px = localMom.x();
209 G4double py = localMom.y();
210 G4double pz = localMom.z();
211
212 // Scale the action for the current particle momentum w.r.t.
213 // the design momentum. Even though a thin kicker, it represents
214 // a thin dipole, which would affect different particles differently.
215 G4double localMomMag = localMom.mag();
216 G4double ratio = (fcof * brho ) / localMomMag;
217
218 G4double dpx = ratio * hkick * localMomMag * factor;
219 G4double dpy = ratio * vkick * localMomMag * factor;
220
221 px += dpx;
222 py += dpy;
223 pz -= std::abs(dpx) + std::abs(dpy); // conservation of momentum
224
225 localPosOut = G4ThreeVector(x1, y1, z1);
226 localMomOut = G4ThreeVector(px, py, pz);
227}
BDSStep ConvertToLocal(G4Step const *const step, G4bool useCurvilinear=true) const
Integrator that ignores the field and uses the analytical solution for a dipole kick.
void OneStep(const G4ThreeVector &posIn, const G4ThreeVector &momUIn, G4ThreeVector &posOut, G4ThreeVector &momOut, const G4double &bendingRadius) const
void AdvanceDriftMag(const G4double yIn[], const G4double h, G4double yOut[], G4double yErr[]) const
Error array [6] all 0.
G4bool hasEntranceFringe
Cache if the fringe or pole face effects are to be applied.
G4double rho
Cache of variable.
const G4double hkick
Cache of variable.
BDSIntegratorDipoleFringe * fringeIntEntr
Separate fringe field integrators for entrance and exit fringes.
virtual void Stepper(const G4double yIn[], const G4double dydx[], const G4double h, G4double yOut[], G4double yErr[])
The stepper for integration.
const G4double vkick
Cache of variable.
G4double tiltAngle
Cache of variable.
const G4double brho
Cache of variable.
BDSIntegratorKickerThin()=delete
Private default constructor to enforce use of supplied constructor.
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
Efficient storage of magnet strengths.
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)