BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSIntegratorDipoleRodrigues.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 "BDSIntegratorDipoleRodrigues.hh"
20#include "BDSGlobalConstants.hh"
21#include "BDSMagnetStrength.hh"
22#include "BDSPhysicalConstants.hh"
23#include "BDSStep.hh"
24#include "BDSUtilities.hh"
25
26#include "globals.hh" // geant4 types / globals
27#include "G4AffineTransform.hh"
28#include "G4Mag_EqRhs.hh"
29#include "G4ThreeVector.hh"
30
31#include <cmath>
32#include <utility>
33
34BDSIntegratorDipoleRodrigues::BDSIntegratorDipoleRodrigues(BDSMagnetStrength const* strengthIn,
35 G4double /*brho*/,
36 G4Mag_EqRhs* eqOfMIn):
37 BDSIntegratorMag(eqOfMIn, 6),
38 cOverGeV(BDS::cOverGeV),
39 angle((*strengthIn)["angle"]),
40 length((*strengthIn)["length"]),
41 bField((*strengthIn)["field"]),
42 strength(strengthIn),
43 minimumRadiusOfCurvature(BDSGlobalConstants::Instance()->MinimumRadiusOfCurvature())
44{
45 zeroStrength = !BDS::IsFinite(bField);
46#ifdef BDSDEBUG
47 G4cout << __METHOD_NAME__ << "B Field " << bField << G4endl;
48#endif
49}
50
52 const G4double dydx[],
53 G4double h,
54 G4double yOut[],
55 G4double yErr[])
56{
57 const G4double fcof = eqOfM->FCof();
58
59 // In case of zero field or neutral particles do a linear step:
61 {
62 AdvanceDriftMag(yIn, h, yOut, yErr);
63 SetDistChord(0);
64 return;
65 }
66
67 // Construct variables
68 G4ThreeVector pos = G4ThreeVector(yIn[0], yIn[1], yIn[2]);
69 G4ThreeVector mom = G4ThreeVector(yIn[3], yIn[4], yIn[5]);
70 G4double charge = fcof/CLHEP::c_light;
71 G4double momMag = mom.mag();
72 G4double rho = momMag/CLHEP::GeV/(cOverGeV * bField/CLHEP::tesla * charge) * CLHEP::m;
73
74 if (std::abs(rho) < minimumRadiusOfCurvature)
75 {
76 AdvanceDriftMag(yIn, h, yOut, yErr);
77 SetDistChord(0);
78 return;
79 }
80
81 // global to local
82 // false = use the mass world for the transform
83 BDSStep localPosMom = ConvertToLocal(pos, mom, h, false);
84 G4ThreeVector localMom = localPosMom.PostStepPoint();
85 G4ThreeVector localMomUnit = localMom.unit();
86
87 // only proceed with stepping if particle is paraxial
88 // judged by forward momentum > 1-limit (default limit=0.1)
89 if (localMomUnit.z() < (1.0 - backupStepperMomLimit))
90 {// use a classical Runge Kutta stepper here
91 backupStepper->Stepper(yIn, dydx, h, yOut, yErr);
92 SetDistChord(backupStepper->DistChord());
93 return;
94 }
95
96 G4ThreeVector localPos = localPosMom.PreStepPoint();
97 G4ThreeVector initialLocalPos = localPos;
98 G4ThreeVector intiialLocalMomUnit = localMomUnit;
99
100 // advance the orbit
101 std::pair<G4ThreeVector,G4ThreeVector> RandRp = UpdatePandR(rho,h,localPos,localMomUnit);
102 G4ThreeVector outputLocalPos = RandRp.first;
103 G4ThreeVector outputLocalMomUnit = RandRp.second;
104
105 G4double CosT_ov_2 = std::cos(h/rho/2.0);
106 G4double dc = std::abs(rho)*(1.-CosT_ov_2);
107 if (std::isnan(dc))
108 {SetDistChord(rho);}
109 else
110 {SetDistChord(dc);}
111
112 // This uses the mass world volume for the transform!
113 ConvertToGlobal(outputLocalPos, outputLocalMomUnit, yOut, yErr, momMag);
114
115 //BDSStep localCL = GlobalToCurvilinear(strength, pos, mom, h, false, eqOfM->FCof());
116 //BDSStep globalOut = CurvilinearToGlobal(strength, localCL.PreStepPoint(), localCL.PostStepPoint(), false, eqOfM->FCof());
117
118 // If the radius of curvature is too small, reduce the momentum by 2%. This will
119 // cause artificial spiralling for what must be particles well below the design momenta.
120 // Nominally adding a small z increment along the axis of the helix wasn't reliable,
121 // as there can be inconsistencies in the field vectors resulting in 0 additional offset,
122 // plus Geant4 complained about clearly wrong motion. This way works and produces no
123 // errors. The particle would be lost approximately in the current location anyway.
124 if (std::abs(rho) < minimumRadiusOfCurvature)
125 {
126 G4double momentumReduction = 0.98;
127 yOut[3] *= momentumReduction;
128 yOut[4] *= momentumReduction;
129 yOut[5] *= momentumReduction;
130 }
131 return;
132}
133
135 const G4double dydx[],
136 const G4double h,
137 G4double yOut[],
138 G4double yErr[])
139{
140 G4double err = 1e-10 * h; // very small linear increase with distance
141 for (G4int i = 0; i < nVariables; i++)
142 {yErr[i] = err;}
143
144 AdvanceHelix(yIn, dydx, h, yOut, yErr);
145}
146
147std::pair<G4ThreeVector,G4ThreeVector> BDSIntegratorDipoleRodrigues::UpdatePandR(G4double rho,
148 G4double h,
149 G4ThreeVector localPos,
150 G4ThreeVector localMomUnit)
151{
152 G4ThreeVector yhat(0.,1.,0.);
153 G4ThreeVector vhat = localMomUnit;
154 G4ThreeVector vnorm = vhat.cross(yhat);
155
156 G4double Theta = h/rho;
157
158 G4double CosT_ov_2, SinT_ov_2, CosT, SinT;
159 CosT_ov_2 = std::cos(Theta/2);
160 SinT_ov_2 = std::sin(Theta/2);
161
162 CosT = (CosT_ov_2*CosT_ov_2) - (SinT_ov_2*SinT_ov_2);
163 SinT = 2*CosT_ov_2*SinT_ov_2;
164
165 G4ThreeVector dPos = rho*(SinT*vhat + (1-CosT)*vnorm); // missing component parallel to B
166 G4ThreeVector outputLocalPos = localPos+dPos;
167 G4ThreeVector outputLocalMomUnit = CosT*vhat + SinT*vnorm;
168
169 return std::make_pair(outputLocalPos,outputLocalMomUnit);
170}
BDSStep ConvertToLocal(G4Step const *const step, G4bool useCurvilinear=true) const
A class that holds global options and constants.
void AdvanceHelix(const G4double yIn[], const G4double dydx[], G4double h, G4double yOut[], G4double yErr[])
Calculate the new particle coordinates.
virtual void Stepper(const G4double yIn[], const G4double dydx[], const G4double h, G4double yOut[], G4double yErr[])
const G4double minimumRadiusOfCurvature
Minimum tolerable radius of curvature - used to prevent spiraling particles.
G4double bField
Uniform magnetic field in global Y direction.
G4double cOverGeV
Scaling factor in brho calculation.
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.
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
G4MagIntegratorStepper * backupStepper
const G4int nVariables
Cache of the number of variables.
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
Return either G4Tubs or G4CutTubs depending on flat face.
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())
G4bool IsFiniteStrength(G4double variable)