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 - 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 "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#ifdef BDSDEBUG
48 G4cout << __METHOD_NAME__ << "B' = " << bPrime << G4endl;
49#endif
50}
51
52void BDSIntegratorQuadrupole::Stepper(const G4double yIn[],
53 const G4double dydx[],
54 const G4double h,
55 G4double yOut[],
56 G4double yErr[])
57{
58 // in case of zero field or neutral particles do a linear step
59 const G4double fcof = eqOfM->FCof();
61 {
62 AdvanceDriftMag(yIn,h,yOut,yErr);
63 SetDistChord(0);
64 return;
65 }
66
67 G4ThreeVector mom = G4ThreeVector(yIn[3], yIn[4], yIn[5]);
68 G4double momMag = mom.mag();
69
70 // quad strength k normalised to charge and momentum of this particle
71 // note bPrime was calculated w.r.t. the nominal rigidity.
72 // eqOfM->FCof() gives us conversion to MeV,mm and rigidity in Tm correctly
73 // as well as charge of the given particle
74 G4double kappa = fcof*bPrime/momMag;
75
76 // neutral particle or no strength - advance as a drift.
77 if(std::abs(kappa) < 1e-20)
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 momUnit = mom.unit();
86 BDSStep localPosMom = GlobalToCurvilinear(pos, momUnit, h, true);
87 G4ThreeVector localPos = localPosMom.PreStepPoint();
88 G4ThreeVector localMomUnit = localPosMom.PostStepPoint();
89
90 G4double xp = localMomUnit.x();
91 G4double yp = localMomUnit.y();
92 G4double zp = localMomUnit.z();
93
94 // only proceed with thick matrix if particle is paraxial
95 // judged by forward momentum > 1-limit and |transverse| < limit (default limit=0.1)
96 if (zp < (1.0-backupStepperMomLimit) || std::abs(xp) > backupStepperMomLimit || std::abs(yp) > backupStepperMomLimit)
97 {
98 backupStepper->Stepper(yIn, dydx, h, yOut, yErr);
99 SetDistChord(backupStepper->DistChord());
100 return;
101 }
102
103 G4double x0 = localPos.x();
104 G4double y0 = localPos.y();
105 G4double z0 = localPos.z();
106
107 // local r'' (for curvature)
108 G4ThreeVector localA;
109 localA.setX(-zp*x0); // can this be replaced by a cross product?
110 localA.setY( zp*y0); // G4ThreeVector has a cross method
111 localA.setZ( x0*xp - y0*yp);
112 localA *= kappa;
113 // determine effective curvature
114 G4double localAMag = localA.mag();
115 G4double radiusOfCurvature = std::numeric_limits<double>::max();
116 if (BDS::IsFiniteStrength(localAMag))
117 {radiusOfCurvature = 1./localAMag;} // avoid division by 0
118
119 // if we have a low energy particle that makes it into the paraxial cuts
120 // it could cause problems later in paraxial algorithm so use backup integrator
121 if (std::abs(radiusOfCurvature) < minimumRadiusOfCurvature)
122 {
123 backupStepper->Stepper(yIn, dydx, h, yOut, yErr);
124 SetDistChord(backupStepper->DistChord());
125 return;
126 }
127
128 G4double h2 = h*h;
129 // initialise output variables with input position as default
130 G4double x1 = x0;
131 G4double y1 = y0;
132 // z1 calculated below
133 G4double xp1 = xp;
134 G4double yp1 = yp;
135 G4double zp1 = zp;
136
137 // chord distance (simple quadratic approx)
138 G4double dc = h2/(8*radiusOfCurvature);
139 if (std::isnan(dc))
140 {SetDistChord(0);}
141 else
142 {SetDistChord(dc);}
143
144 G4double rootK = std::sqrt(std::abs(kappa*zp)); // direction independent
145 if (std::isnan(rootK))
146 {rootK = 0;}
147 G4double rootKh = rootK*h*zp;
148 G4double X11=0,X12=0,X21=0,X22=0;
149 G4double Y11=0,Y12=0,Y21=0,Y22=0;
150
151 if (kappa >= 0)
152 {//focussing
153 X11 = std::cos(rootKh);
154 X12 = std::sin(rootKh)/rootK;
155 X21 =-std::abs(kappa)*X12;
156 X22 = X11;
157
158 Y11 = std::cosh(rootKh);
159 Y12 = std::sinh(rootKh)/rootK;
160 Y21 = std::abs(kappa)*Y12;
161 Y22 = Y11;
162 }
163 else
164 {// defocussing
165 X11 = cosh(rootKh);
166 X12 = sinh(rootKh)/rootK;
167 X21 = std::abs(kappa)*X12;
168 X22 = X11;
169
170 Y11 = std::cos(rootKh);
171 Y12 = std::sin(rootKh)/rootK;
172 Y21 = -std::abs(kappa)*Y12;
173 Y22 = Y11;
174 }
175
176 x1 = X11*x0 + X12*xp;
177 xp1 = X21*x0 + X22*xp;
178
179 y1 = Y11*y0 + Y12*yp;
180 yp1 = Y21*y0 + Y22*yp;
181
182 // relies on normalised momenta otherwise this will be nan.
183 zp1 = std::sqrt(1 - xp1*xp1 - yp1*yp1);
184 if (std::isnan(zp1))
185 {zp1 = zp;} // ensure not nan
186
187 // new z position will be projection of h onto the z axis
188 G4double z1 = z0 + std::sqrt(h2 - std::pow(x1-x0,2) - std::pow(y1-y0,2));
189
190 localPos.setX(x1);
191 localPos.setY(y1);
192 localPos.setZ(z1);
193 localMomUnit.setX(xp1);
194 localMomUnit.setY(yp1);
195 localMomUnit.setZ(zp1);
196
197 // normalise from unit momentum to absolute momentum
198 G4ThreeVector localMomOut = localMomUnit * momMag;
199
200 // convert to global coordinates
201 BDSStep globalPosMom = CurvilinearToGlobal(localPos, localMomOut, true);
202 G4ThreeVector globalPosOut = globalPosMom.PreStepPoint();
203 G4ThreeVector globalMomOut = globalPosMom.PostStepPoint();
204
205 // error along direction of travel really
206 G4ThreeVector globalMomOutU = globalMomOut.unit();
207 globalMomOutU *= 1e-8;
208
209 // write out coordinates and errors to arrays
210 for (G4int i = 0; i < 3; i++)
211 {
212 yOut[i] = globalPosOut[i];
213 yOut[i+3] = globalMomOut[i];
214 yErr[i] = globalMomOutU[i]*1e-10; // empirically this has to be very small
215 yErr[i+3] = 1e-40;
216 }
217}
218
219
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.
G4double backupStepperMomLimit
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)