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