BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSIntegratorSolenoid.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 "BDSIntegratorSolenoid.hh"
21#include "BDSMagnetStrength.hh"
22#include "BDSStep.hh"
23#include "BDSUtilities.hh"
24
25#include "globals.hh" // geant4 types / globals.hh
26#include "G4Mag_EqRhs.hh"
27#include "G4ThreeVector.hh"
28
29#include <cmath>
30#include <limits>
31
33 G4double brho,
34 G4Mag_EqRhs* eqOfMIn):
35 BDSIntegratorMag(eqOfMIn, 6)
36{
37 bField = brho * (*strength)["ks"];
38 zeroStrength = !BDS::IsFinite(bField);
39#ifdef BDSDEBUG
40 G4cout << __METHOD_NAME__ << "B (local) = " << bField << G4endl;
41#endif
42}
43
44void BDSIntegratorSolenoid::Stepper(const G4double yIn[],
45 const G4double dydx[],
46 G4double h,
47 G4double yOut[],
48 G4double yErr[])
49{
50 // in case of zero field or neutral particles do a linear step
51 const G4double fcof = eqOfM->FCof();
52 if (zeroStrength || !BDS::IsFiniteStrength(fcof) || h < 1e-9)
53 {
54 AdvanceDriftMag(yIn,h,yOut,yErr);
55 SetDistChord(0);
56 return;
57 }
58
59 G4ThreeVector mom = G4ThreeVector(yIn[3], yIn[4], yIn[5]);
60 G4double momMag = mom.mag();
61
62 // kappa unit is m^-1, so scale to mm.
63 G4double kappa = 0.5*fcof*bField/momMag / CLHEP::m;
64
65 // neutral particle or no strength - advance as a drift.
66 if (std::abs(kappa)<1e-20)
67 {
68 AdvanceDriftMag(yIn, h, yOut, yErr);
69 SetDistChord(0);
70 return;
71 }
72
73 G4ThreeVector pos = G4ThreeVector(yIn[0], yIn[1], yIn[2]);
74 G4ThreeVector momUnit = mom.unit();
75 G4double h2 = h*h;
76 BDSStep localPosMom = GlobalToCurvilinear(pos, momUnit, h, true);
77 G4ThreeVector localPos = localPosMom.PreStepPoint();
78 G4ThreeVector localMom = localPosMom.PostStepPoint();
79 G4ThreeVector localMomUnit = localMom.unit();
80
81 // finite strength - treat as a solenoid
82 G4double x0 = localPos.x();
83 G4double y0 = localPos.y();
84 G4double z0 = localPos.z();
85 G4double xp0 = localMomUnit.x();
86 G4double yp0 = localMomUnit.y();
87 G4double zp0 = localMomUnit.z();
88
89 // only proceed with thick matrix if particle is paraxial
90 // judged by forward momentum > 1-limit and |transverse| < limit (default limit=0.1)
91 if (zp0 < (1.0-backupStepperMomLimit) || std::abs(xp0) > backupStepperMomLimit || std::abs(yp0) > backupStepperMomLimit)
92 {
93 backupStepper->Stepper(yIn, dydx, h, yOut, yErr);
94 SetDistChord(backupStepper->DistChord());
95 return;
96 }
97
98 // local r'' (for curvature)
99 G4ThreeVector localA;
100 localA.setX(-zp0*x0);
101 localA.setY( zp0*y0);
102 localA.setZ( x0*xp0 - y0*yp0);
103 localA *= kappa;
104
105 // determine effective curvature
106 G4double localAMag = localA.mag();
107
108 // low strength - drift
109 if (localAMag < 1e-15)
110 {
111 AdvanceDriftMag(yIn, h, yOut, yErr);
112 SetDistChord(0);
113 return;
114 }
115
116 G4double radiusOfCurvature = std::numeric_limits<double>::max();
117 if (BDS::IsFiniteStrength(localAMag))
118 {radiusOfCurvature = 1./localAMag;} // avoid division by 0
119
120 // chord distance (simple quadratic approx)
121 G4double dc = h2/(8*radiusOfCurvature);
122 if (std::isnan(dc))
123 {SetDistChord(0);}
124 else
125 {SetDistChord(dc);}
126
127 // From USPAS lecture (http://uspas.fnal.gov/materials/13Duke/SCL_Chap3.pdf)
128 // (1 , S / 2K , 0 , (1-C) / 2K ) (x )
129 // (0 , C , 0 , S ) (x')
130 // (0 , -(1-C) / 2K , 1 , S / 2K ) (y )
131 // (0 , -S , 0 , C ) (y')
132 //
133 // K = B_0 / 2*Brho
134 // B_0 is field in solenoid
135 // Brho is momentum of central trajectory
136 // C = cos( 2KL )
137 // S = sin( 2KL )
138
139 G4double C = std::cos(2 * kappa * h);
140 G4double S = std::sin(2 * kappa * h);
141 G4double S2oK = S / kappa;
142 G4double OmC2oK = (1.0 - C) / kappa;
143
144 G4double X11 = 1, X12 = 0.5*S2oK, X13 = 0, X14 = 0.5*OmC2oK;
145 G4double X21 = 0, X22 = C, X23 = 0, X24 = S;
146 G4double X31 = 0, X32 = -0.5*OmC2oK, X33 = 1, X34 = 0.5*S2oK;
147 G4double X41 = 0, X42 = -S, X43 = 0, X44 = C ;
148
149 G4double x1 = x0*X11 + xp0*X12 + y0*X13 + yp0*X14;
150 G4double xp1 = x0*X21 + xp0*X22 + y0*X23 + yp0*X24;
151 G4double y1 = x0*X31 + xp0*X32 + y0*X33 + yp0*X34;
152 G4double yp1 = x0*X41 + xp0*X42 + y0*X43 + yp0*X44;
153
154 G4double z1 = z0 + h;
155 // ensure normalisation for vector
156 G4double zp1 = std::sqrt(1 - xp1*xp1 - yp1*yp1);
157 if (std::isnan(zp1))
158 {zp1 = zp0;}
159
160 localPos.setX(x1);
161 localPos.setY(y1);
162 localPos.setZ(z1);
163 localMomUnit.setX(xp1);
164 localMomUnit.setY(yp1);
165 localMomUnit.setZ(zp1);
166
167 // normalise from unit momentum to absolute momentum
168 G4ThreeVector localMomOut = localMomUnit * momMag;
169
170 // convert to global coordinates
171 BDSStep globalPosMom = CurvilinearToGlobal(localPos, localMomOut, true);
172 G4ThreeVector globalPosOut = globalPosMom.PreStepPoint();
173 G4ThreeVector globalMomOut = globalPosMom.PostStepPoint();
174
175 // error along direction of travel really
176 G4ThreeVector globalMomOutU = globalMomOut.unit();
177 globalMomOutU *= 1e-8;
178
179 // write out coordinates and errors to arrays
180 for (G4int i = 0; i < 3; i++)
181 {
182 yOut[i] = globalPosOut[i];
183 yOut[i+3] = globalMomOut[i];
184 yErr[i] = globalMomOutU[i]*1e-10; // empirically this has to be very small
185 yErr[i+3] = 1e-40;
186 }
187}
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[])
Calculate the particle motion along step length l in the paraxial approximation.
BDSIntegratorSolenoid()
Private default constructor to enforce use of supplied constructor.
G4double bField
The field strength.
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)