BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSIntegratorQuadrupole.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) Royal Holloway,
3University of London 2001 - 2024.
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 "BDSIntegratorQuadrupole.hh"
21#include "BDSMagnetStrength.hh"
22#include "BDSStep.hh"
23#include "BDSUtilities.hh"
24
25#include "G4Mag_EqRhs.hh"
26#include "G4MagIntegratorStepper.hh"
27#include "G4ThreeVector.hh"
28
29#include "CLHEP/Units/SystemOfUnits.h"
30
31#include <cmath>
32#include <limits>
33
35 G4double brho,
36 G4Mag_EqRhs* eqOfMIn,
37 G4double minimumRadiusOfCurvatureIn):
38 BDSIntegratorMag(eqOfMIn, 6),
39 minimumRadiusOfCurvature(minimumRadiusOfCurvatureIn)
40{
41 // B' = dBy/dx = Brho * (1/Brho dBy/dx) = Brho * k1
42 // we take |Brho| as it depends on charge and so does the eqOfM->FCof()
43 // so they'd both cancel out.
44 bPrime = std::abs(brho) * (*strength)["k1"] / CLHEP::m2;
45
46 zeroStrength = !BDS::IsFiniteStrength(bPrime);
47}
48
49void BDSIntegratorQuadrupole::Stepper(const G4double yIn[],
50 const G4double dydx[],
51 const G4double h,
52 G4double yOut[],
53 G4double yErr[])
54{
55 // in case of zero field or neutral particles do a linear step
56 const G4double fcof = eqOfM->FCof();
58 {
59 AdvanceDriftMag(yIn,h,yOut,yErr);
60 SetDistChord(0);
61 return;
62 }
63
64 G4ThreeVector mom = G4ThreeVector(yIn[3], yIn[4], yIn[5]);
65 G4double momMag = mom.mag();
66
67 // quad strength k normalised to charge and momentum of this particle
68 // note bPrime was calculated w.r.t. the nominal rigidity.
69 // eqOfM->FCof() gives us conversion to MeV,mm and rigidity in Tm correctly
70 // as well as charge of the given particle
71 G4double kappa = fcof*bPrime/momMag;
72
73 // neutral particle or no strength - advance as a drift.
74 if(std::abs(kappa) < 1e-20)
75 {
76 AdvanceDriftMag(yIn, h, yOut, yErr);
77 SetDistChord(0);
78 return;
79 }
80
81 G4ThreeVector pos = G4ThreeVector(yIn[0], yIn[1], yIn[2]);
82 G4ThreeVector momUnit = mom.unit();
83 BDSStep localPosMom = GlobalToCurvilinear(pos, momUnit, h, true);
84 G4ThreeVector localPos = localPosMom.PreStepPoint();
85 G4ThreeVector localMomUnit = localPosMom.PostStepPoint();
86
87 G4double xp = localMomUnit.x();
88 G4double yp = localMomUnit.y();
89 G4double zp = localMomUnit.z();
90
91 // only proceed with thick matrix if particle is paraxial
92 // judged by forward momentum > 1-limit and |transverse| < limit (default limit=0.1)
93 if (zp < (1.0-backupStepperMomLimit) || std::abs(xp) > backupStepperMomLimit || std::abs(yp) > backupStepperMomLimit)
94 {
95 backupStepper->Stepper(yIn, dydx, h, yOut, yErr);
96 SetDistChord(backupStepper->DistChord());
97 return;
98 }
99
100 G4double x0 = localPos.x();
101 G4double y0 = localPos.y();
102 G4double z0 = localPos.z();
103
104 // local r'' (for curvature)
105 G4ThreeVector localA;
106 localA.setX(-zp*x0); // can this be replaced by a cross product?
107 localA.setY( zp*y0); // G4ThreeVector has a cross method
108 localA.setZ( x0*xp - y0*yp);
109 localA *= kappa;
110 // determine effective curvature
111 G4double localAMag = localA.mag();
112 G4double radiusOfCurvature = std::numeric_limits<double>::max();
113 if (BDS::IsFiniteStrength(localAMag))
114 {radiusOfCurvature = 1./localAMag;} // avoid division by 0
115
116 // if we have a low energy particle that makes it into the paraxial cuts
117 // it could cause problems later in paraxial algorithm so use backup integrator
118 if (std::abs(radiusOfCurvature) < minimumRadiusOfCurvature)
119 {
120 backupStepper->Stepper(yIn, dydx, h, yOut, yErr);
121 SetDistChord(backupStepper->DistChord());
122 return;
123 }
124
125 G4double h2 = h*h;
126 // initialise output variables with input position as default
127 G4double x1 = x0;
128 G4double y1 = y0;
129 // z1 calculated below
130 G4double xp1 = xp;
131 G4double yp1 = yp;
132 G4double zp1 = zp;
133
134 // chord distance (simple quadratic approx)
135 G4double dc = h2/(8*radiusOfCurvature);
136 if (std::isnan(dc))
137 {SetDistChord(0);}
138 else
139 {SetDistChord(dc);}
140
141 G4double rootK = std::sqrt(std::abs(kappa*zp)); // direction independent
142 if (std::isnan(rootK))
143 {rootK = 0;}
144 G4double rootKh = rootK*h*zp;
145 G4double X11=0,X12=0,X21=0,X22=0;
146 G4double Y11=0,Y12=0,Y21=0,Y22=0;
147
148 if (kappa >= 0)
149 {//focussing
150 X11 = std::cos(rootKh);
151 X12 = std::sin(rootKh)/rootK;
152 X21 =-std::abs(kappa)*X12;
153 X22 = X11;
154
155 Y11 = std::cosh(rootKh);
156 Y12 = std::sinh(rootKh)/rootK;
157 Y21 = std::abs(kappa)*Y12;
158 Y22 = Y11;
159 }
160 else
161 {// defocussing
162 X11 = cosh(rootKh);
163 X12 = sinh(rootKh)/rootK;
164 X21 = std::abs(kappa)*X12;
165 X22 = X11;
166
167 Y11 = std::cos(rootKh);
168 Y12 = std::sin(rootKh)/rootK;
169 Y21 = -std::abs(kappa)*Y12;
170 Y22 = Y11;
171 }
172
173 x1 = X11*x0 + X12*xp;
174 xp1 = X21*x0 + X22*xp;
175
176 y1 = Y11*y0 + Y12*yp;
177 yp1 = Y21*y0 + Y22*yp;
178
179 // relies on normalised momenta otherwise this will be nan.
180 zp1 = std::sqrt(1 - xp1*xp1 - yp1*yp1);
181 if (std::isnan(zp1))
182 {zp1 = zp;} // ensure not nan
183
184 // new z position will be projection of h onto the z axis
185 G4double z1 = z0 + std::sqrt(h2 - std::pow(x1-x0,2) - std::pow(y1-y0,2));
186
187 localPos.setX(x1);
188 localPos.setY(y1);
189 localPos.setZ(z1);
190 localMomUnit.setX(xp1);
191 localMomUnit.setY(yp1);
192 localMomUnit.setZ(zp1);
193
194 // normalise from unit momentum to absolute momentum
195 G4ThreeVector localMomOut = localMomUnit * momMag;
196
197 // convert to global coordinates
198 BDSStep globalPosMom = CurvilinearToGlobal(localPos, localMomOut, true);
199 G4ThreeVector globalPosOut = globalPosMom.PreStepPoint();
200 G4ThreeVector globalMomOut = globalPosMom.PostStepPoint();
201
202 // error along direction of travel really
203 G4ThreeVector globalMomOutU = globalMomOut.unit();
204 globalMomOutU *= 1e-8;
205
206 // write out coordinates and errors to arrays
207 for (G4int i = 0; i < 3; i++)
208 {
209 yOut[i] = globalPosOut[i];
210 yOut[i+3] = globalMomOut[i];
211 yErr[i] = globalMomOutU[i]*1e-10; // empirically this has to be very small
212 yErr[i+3] = 1e-40;
213 }
214}
215
216
BDSStep GlobalToCurvilinear(const G4double fieldArcLength, const G4ThreeVector &unitField, const G4double angle, const G4ThreeVector &position, const G4ThreeVector &unitMomentum, const G4double h, const G4bool useCurvilinearWorld, const G4double FCof, const G4double tilt=0)
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.
G4MagIntegratorStepper * backupStepper
virtual void Stepper(const G4double y[], const G4double dydx[], const G4double h, G4double yOut[], G4double yErr[])
BDSIntegratorQuadrupole()
Private default constructor to enforce use of supplied constructor.
G4double bPrime
B Field Gradient.
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 IsFiniteStrength(G4double variable)