BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSBunch.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 "BDSAcceleratorModel.hh"
20#include "BDSBeamline.hh"
21#include "BDSBunch.hh"
22#include "BDSDebug.hh"
23#include "BDSException.hh"
24#include "BDSGlobalConstants.hh"
25#include "BDSIonDefinition.hh"
26#include "BDSParticleCoords.hh"
27#include "BDSParticleCoordsFull.hh"
28#include "BDSParticleCoordsFullGlobal.hh"
29#include "BDSParticleDefinition.hh"
30#include "BDSPhysicsUtilities.hh"
31#include "BDSUtilities.hh"
32
33#include "parser/beam.h"
34
35#include "G4IonTable.hh"
36#include "G4ParticleTable.hh"
37#include "G4ThreeVector.hh"
38#include "G4Transform3D.hh"
39#include "G4TwoVector.hh"
40#include "G4Version.hh"
41
42#include "CLHEP/Geometry/Point3D.h"
43
44#include <cmath>
45#include <limits>
46#include <set>
47#include <string>
48
49
50BDSBunch::BDSBunch():
51 BDSBunch("reference")
52{;}
53
54BDSBunch::BDSBunch(const G4String& nameIn):
55 name(nameIn),
56 X0(0.0), Y0(0.0), Z0(0.0), S0(0.0), T0(0.0),
57 Xp0(0.0), Yp0(0.0), Zp0(0.0), E0(0.0), P0(0.0),
58 tilt(0.0),
59 sigmaT(0.0), sigmaP(0.0), sigmaE(0.0), sigmaEk(0.0),
60 useBunchTiming(false),
61 currentBunchIndex(0),
62 eventsPerBunch(1), // so we don't have 0 division
63 bunchPeriod(0),
64 useCurvilinear(false),
65 particleDefinition(nullptr),
66 particleDefinitionHasBeenUpdated(false),
67 finiteTilt(false),
68 finiteSigmaE(true),
69 finiteSigmaT(true),
70 generatePrimariesOnly(false),
71 beamlineTransform(G4Transform3D()),
72 beamlineS(0),
73 mass2(0.0),
74 beamline(nullptr)
75{;}
76
77BDSBunch::~BDSBunch()
78{
79 delete particleDefinition;
80}
81
83 const GMAD::Beam& beam,
84 const BDSBunchType& /*distrType*/,
85 G4Transform3D beamlineTransformIn,
86 G4double beamlineSIn)
87{
88 particleDefinition = new BDSParticleDefinition(*beamParticle); // copy it so this instance owns it
89
90 // back the starting point up by length safety to avoid starting on a boundary
91 G4ThreeVector unitZBeamline = G4ThreeVector(0,0,-1).transform(beamlineTransformIn.getRotation());
92 G4ThreeVector translation = BDSGlobalConstants::Instance()->LengthSafety() * unitZBeamline;
93 beamlineTransform = G4Transform3D(beamlineTransformIn.getRotation(), beamlineTransformIn.getTranslation()+translation);
94
95 beamlineS = beamlineSIn;
96
97 X0 = beam.X0 * CLHEP::m;
98 Y0 = beam.Y0 * CLHEP::m;
99 Z0 = beam.Z0 * CLHEP::m;
100 S0 = beam.S0 * CLHEP::m;
101 T0 = beam.T0 * CLHEP::s;
102 Xp0 = beam.Xp0 * CLHEP::rad;
103 Yp0 = beam.Yp0 * CLHEP::rad;
104 E0 = particleDefinition->TotalEnergy(); // already calculated and set earlier depending on available parameters
106 tilt = beam.tilt * CLHEP::rad;
107 sigmaT = beam.sigmaT;
108 sigmaP = beam.sigmaP;
109 sigmaE = beam.sigmaE;
110 sigmaEk = beam.sigmaEk;
111
112 // bunch offset timing parameters
113 G4bool bff = BDS::IsFinite(beam.bunchFrequency);
114 G4bool bpf = BDS::IsFinite(beam.bunchPeriod);
115 if (bff && bpf)
116 {throw BDSException(__METHOD_NAME__, "only one of \"bunchFrequency\" and \"bunchPeriod\" can be set");}
117 else if (bff || bpf)
118 {
119 useBunchTiming = true;
121 if (eventsPerBunch <= 0)
122 {throw BDSException(__METHOD_NAME__, "\"eventsPerBunch\" <= 0. Must be > 0");}
123 bunchPeriod = bpf ? beam.bunchPeriod*CLHEP::s : (1.0 / beam.bunchFrequency)*CLHEP::s;
124 }
125 else if (!bff && !bpf && beam.eventsPerBunch > 0) // eventsPerBunch > 0 implies expecting bunches but no frequency or period given
126 {throw BDSException(__METHOD_NAME__, "one of \"bunchFrequency\" or \"bunchPeriod\" must be specified if \"eventsPerBunch\" > 0");}
127
131 G4bool finiteSigmaP = BDS::IsFinite(sigmaP);
132 G4bool finiteSigmaEk = BDS::IsFinite(sigmaEk);
133
134 std::set<std::string> keysDesign = {"sigmaE", "sigmaEk", "sigmaP"};
135 G4int nSetDesign = BDS::NBeamParametersSet(beam, keysDesign);
136 BDS::ConflictingParametersSet(beam, keysDesign, nSetDesign, false, "GeV");// warn only if too many set
137 if (finiteSigmaE)
138 {
139 sigmaP = (1./std::pow(beamParticle->Beta(),2)) * sigmaE; // dE/E = (beta^2) dP/P
140 sigmaEk = (beamParticle->TotalEnergy() / beamParticle->KineticEnergy()) * sigmaE;
141 }
142 else if (finiteSigmaP)
143 {
144 sigmaE = std::pow(beamParticle->Beta(),2) * sigmaP;
145 sigmaEk = (beamParticle->TotalEnergy() / beamParticle->KineticEnergy()) * sigmaE;
146 }
147 else if (finiteSigmaEk)
148 {
149 sigmaE = sigmaEk * (beamParticle->KineticEnergy() / beamParticle->TotalEnergy());
150 sigmaP = (1./std::pow(beamParticle->Beta(),2)) * sigmaE; // dE/E = (beta^2) dP/P
151 }
152 // else they'll all be 0 - no need for a calculation
153
154 finiteSigmaE = finiteSigmaE || finiteSigmaP || finiteSigmaEk; // finiteSigmaE used to know whether any variation in other classes
155 if (finiteSigmaE)
156 {
157 G4cout << "Beam> sigmaP: " << sigmaP << G4endl;
158 G4cout << "Beam> sigmaE: " << sigmaE << G4endl;
159 G4cout << "Beam> sigmaEk: " << sigmaEk << G4endl;
160 }
161
162 Zp0 = CalculateZp(Xp0,Yp0,beam.Zp0);
163
164 if (S0 > beamlineS)
165 {
166#ifdef BDSDEBUG
167 G4cout << __METHOD_NAME__ << "using curvilinear transform" << G4endl;
168#endif
169 if (BDS::IsFinite(Z0))
170 {throw BDSException(__METHOD_NAME__, "both Z0 and S0 are defined - please define only one!");}
171 useCurvilinear = true;
172 }
173}
174
176 const GMAD::Beam& beam,
177 G4double& emittGeometricX,
178 G4double& emittGeometricY,
179 G4double& emittNormalisedX,
180 G4double& emittNormalisedY)
181{
182 std::set<std::string> keysDesignX = {"emitx", "emitnx"};
183 G4int nSetDesignX = BDS::NBeamParametersSet(beam, keysDesignX);
184 BDS::ConflictingParametersSet(beam, keysDesignX, nSetDesignX);
185 if (BDS::IsFinite(beam.emitNX))
186 {
187 emittNormalisedX = G4double(beam.emitNX);
188 emittGeometricX = G4double(beam.emitNX) / beamParticle->Gamma();
189 }
190 else
191 {
192 emittGeometricX = G4double(beam.emitx);
193 emittNormalisedX = G4double(beam.emitx) * beamParticle->Gamma();
194 }
195
196 std::set<std::string> keysDesignY = {"emity", "emitny"};
197 G4int nSetDesignY = BDS::NBeamParametersSet(beam, keysDesignY);
198 BDS::ConflictingParametersSet(beam, keysDesignY, nSetDesignY);
199 if (BDS::IsFinite(beam.emitNY))
200 {
201 emittNormalisedY = G4double(beam.emitNY);
202 emittGeometricY = G4double(beam.emitNY) / beamParticle->Gamma();}
203 else
204 {
205 emittGeometricY = G4double(beam.emity);
206 emittNormalisedY = G4double(beam.emity) * beamParticle->Gamma();
207 }
208
209 G4cout << __METHOD_NAME__ << "Geometric (x): " << emittGeometricX
210 << ", Normalised (x): " << emittNormalisedX << G4endl;
211 G4cout << __METHOD_NAME__ << "Geometric (y): " << emittGeometricY
212 << ", Normalised (y): " << emittNormalisedY << G4endl;
213}
214
215void BDSBunch::CalculateBunchIndex(G4int eventIndex)
216{
217 if (!useBunchTiming)
218 {return;}
219 // calculate this freshly each time so it doesn't rely on incremental event indices
220 currentBunchIndex = (G4int)std::floor((G4double)eventIndex / (G4double)eventsPerBunch);
221}
222
224{
225 if (sigmaE < 0)
226 {throw BDSException(__METHOD_NAME__, "sigmaE " + std::to_string(sigmaE) + " < 0!");}
227 if (sigmaT < 0)
228 {throw BDSException(__METHOD_NAME__, "sigmaT " + std::to_string(sigmaT) + " < 0!");}
229}
230
232{;}
233
235{
236 particleDefinitionHasBeenUpdated = false; // reset flag for this call
237 // use a separate flag to record whether the particle definitions has
238 // been updated as subsequent calls to GetNextParticle may reset it to
239 // false but it was updated in the first call
240 G4bool flag = false;
241
242 // continue generating particles until positive finite kinetic energy.
243 G4int n = 0;
245 while (n < maxTries) // prevent infinite loops
246 {
247 ++n;
248 coords = GetNextParticle();
250
251 // ensure total energy is greater than the rest mass
252 if ((coords.local.totalEnergy - particleDefinition->Mass()) > 0)
253 {break;}
254 }
255 if (n >= maxTries)
256 {throw BDSException(__METHOD_NAME__, "unable to generate coordinates above rest mass after 100 attempts.");}
257
259 return coords;
260}
261
263{
264 particleDefinitionHasBeenUpdated = false; // reset flag
266 if (finiteTilt)
267 {ApplyTilt(local);}
269 return all;
270}
271
273{
275 Xp0, Yp0, Zp0,
276 T0, S0, E0, /*weight=*/1.0);
277 return local;
278}
279
280void BDSBunch::RecreateAdvanceToEvent(G4int eventOffset)
281{
282 CalculateBunchIndex(eventOffset);
283}
284
285void BDSBunch::BeginOfRunAction(G4int /*numberOfEvents*/,
286 G4bool /*batchMode*/)
287{;}
288
289void BDSBunch::SetGeneratePrimariesOnly(G4bool generatePrimariesOnlyIn)
290{generatePrimariesOnly = generatePrimariesOnlyIn;}
291
293{
295 if (useCurvilinear) // i.e. S0 is finite - use beam line
296 {result = ApplyCurvilinearTransform(localIn);}
297 else // just general beam line offset
299 if (useBunchTiming)
300 {ApplyBunchTiming(result);}
301 return result;
302}
303
305{
306 G4TwoVector xy(localIn.x, localIn.y);
307 G4TwoVector xpyp(localIn.xp, localIn.yp);
308 xy.rotate(tilt);
309 xpyp.rotate(tilt);
310 localIn.x = xy.x();
311 localIn.y = xy.y();
312 localIn.xp = xpyp.x();
313 localIn.yp = xpyp.y();
314}
315
317{
318 G4double tOffset = ((G4double)currentBunchIndex) * bunchPeriod;
319 coordsIn.global.T += tOffset;
320}
321
323{
324 if (generatePrimariesOnly) // no beam line built so no possible transform
325 {return BDSParticleCoordsFullGlobal(localIn, (BDSParticleCoords)localIn);}
326
327 if (!beamline)
328 {// initialise cache of beam line pointer
329 beamline = BDSAcceleratorModel::Instance()->BeamlineMain();
330 if (!beamline)
331 {throw BDSException(__METHOD_NAME__, "no beamline constructed!");}
332 }
333
334 // 'c' for curvilinear
335 G4int beamlineIndex = 0;
336 G4double S = S0 + localIn.z;
337 G4double sMin = beamline->GetSMinimum();
338 G4double sMax = beamline->GetSMaximum();
339 if (S < sMin - 1*CLHEP::m)
340 {throw BDSException(__METHOD_NAME__, "S less than minimum S (" + std::to_string(sMin) + ") - 1m for particle.");}
341 if (S > sMax + 1*CLHEP::m)
342 {throw BDSException(__METHOD_NAME__, "S greater than maximum S (" + std::to_string(sMax) + ") + 1m for particle.");}
343
344 G4Transform3D cTrans = beamline->GetGlobalEuclideanTransform(S,
345 localIn.x,
346 localIn.y,
347 &beamlineIndex);
348 // rotate the momentum vector
349 G4ThreeVector cMom = G4ThreeVector(localIn.xp, localIn.yp, localIn.zp).transform(cTrans.getRotation());
350 // translation contains displacement from origin already - including any local offset
351 G4ThreeVector cPos = cTrans.getTranslation();
352
353 G4double tOffset = S / CLHEP::c_light; // we assume the velocity of light for timing
354
355 BDSParticleCoords global = BDSParticleCoords(cPos.x(), cPos.y(), cPos.z(),
356 cMom.x(), cMom.y(), cMom.z(),
357 localIn.T + tOffset);
358
360 result.beamlineIndex = beamlineIndex;
361#ifdef BDSDEBUG
362 G4cout << __METHOD_NAME__ << result << G4endl;
363#endif
364 return result;
365}
366
367G4double BDSBunch::CalculateZp(G4double xp, G4double yp, G4double Zp0In)
368{
369 G4double zp;
370 G4double transMom = std::pow(xp, 2) + std::pow(yp, 2);
371
372 if (transMom > (1 - std::numeric_limits<double>::epsilon()))
373 {throw BDSException(__METHOD_NAME__, "xp, yp too large, xp: " + std::to_string(xp) + " yp: " + std::to_string(yp));}
374 if (Zp0In < 0)
375 {zp = -std::sqrt(1.0 - transMom);}
376 else
377 {zp = std::sqrt(1.0 - transMom);}
378
379 return zp;
380}
381
383{
385 {return;}
386
387 G4IonTable* ionTable = G4ParticleTable::GetParticleTable()->GetIonTable();
389 G4ParticleDefinition* ionParticleDef = ionTable->GetIon(ionDefinition->Z(),
390 ionDefinition->A(),
391 ionDefinition->ExcitationEnergy());
393 // Note we don't need to take care of electrons here. These are automatically
394 // allocated by Geant4 when it converts the primary vertex to a dynamic particle
395 // (in the process of constructing a track from it) (done in G4PrimaryTransformer)
396 // this relies on the charge being set correctly - Geant4 detects this isn't the same
397 // as Z and adds electrons accordingly.
398#if G4VERSION_NUMBER > 1049
399 // in the case of ions the particle definition is only available now
400 // fix the looping thresholds now it's available
402#endif
403}
const BDSBeamline * BeamlineMain() const
Accessor.
G4Transform3D GetGlobalEuclideanTransform(G4double s, G4double x=0, G4double y=0, G4int *indexOfFoundElement=nullptr) const
Definition: BDSBeamline.cc:601
The base class for bunch distribution generators.
Definition: BDSBunch.hh:47
BDSParticleCoordsFullGlobal ApplyCurvilinearTransform(const BDSParticleCoordsFull &localIn) const
Calculate the global coordinates from curvilinear coordinates of a beam line.
Definition: BDSBunch.cc:322
G4double sigmaE
Centre of distributions.
Definition: BDSBunch.hh:184
G4bool finiteTilt
Definition: BDSBunch.hh:205
virtual void BeginOfRunAction(G4int numberOfEvents, G4bool batchMode)
Definition: BDSBunch.cc:285
const BDSBeamline * beamline
A reference to the fully constructed beamline that's lazily instantiated.
Definition: BDSBunch.hh:223
bool useBunchTiming
Bunch offset in time parameters.
Definition: BDSBunch.hh:189
G4double Yp0
Centre of distributions.
Definition: BDSBunch.hh:177
G4double T0
Centre of distributions.
Definition: BDSBunch.hh:175
G4bool finiteSigmaE
Flags to ignore random number generator in case of no finite E or T.
Definition: BDSBunch.hh:207
G4double tilt
Centre of distributions.
Definition: BDSBunch.hh:181
BDSParticleCoordsFullGlobal ApplyTransform(const BDSParticleCoordsFull &localIn) const
Definition: BDSBunch.cc:292
virtual void RecreateAdvanceToEvent(G4int eventOffset)
Definition: BDSBunch.cc:280
void ApplyTilt(BDSParticleCoordsFull &localIn) const
Apply a rotation about unitZ for the local coordinates according to member variable tilt.
Definition: BDSBunch.cc:304
G4double S0
Centre of distributions.
Definition: BDSBunch.hh:174
G4int currentBunchIndex
Bunch offset in time parameters.
Definition: BDSBunch.hh:190
G4double P0
central momentum
Definition: BDSBunch.hh:180
G4bool particleDefinitionHasBeenUpdated
Definition: BDSBunch.hh:203
G4bool generatePrimariesOnly
Definition: BDSBunch.hh:213
virtual void SetGeneratePrimariesOnly(G4bool generatePrimariesOnlyIn)
Definition: BDSBunch.cc:289
G4double sigmaP
Centre of distributions.
Definition: BDSBunch.hh:183
G4bool useCurvilinear
Whether to ignore z and use s and transform for curvilinear coordinates.
Definition: BDSBunch.hh:196
G4Transform3D beamlineTransform
Transform that beam line starts with that will also be applied to coordinates.
Definition: BDSBunch.hh:217
void ApplyBunchTiming(BDSParticleCoordsFullGlobal &localIn) const
Add on the offset in T for the current bunch number (i*bunchPeriod).
Definition: BDSBunch.cc:316
G4double sigmaT
Centre of distributions.
Definition: BDSBunch.hh:182
G4double Z0
Centre of distributions.
Definition: BDSBunch.hh:173
void CalculateBunchIndex(G4int eventIndex)
Calculate which bunch index we should be at given an event index.
Definition: BDSBunch.cc:215
virtual BDSParticleCoordsFull GetNextParticleLocal()
Definition: BDSBunch.cc:272
G4double bunchPeriod
Bunch offset in time parameters.
Definition: BDSBunch.hh:192
G4double X0
Centre of distributions.
Definition: BDSBunch.hh:171
G4double Zp0
Centre of distributions.
Definition: BDSBunch.hh:178
virtual void Initialise()
Any initialisation - to be used after SetOptions, then CheckParameters.
Definition: BDSBunch.cc:231
G4double Xp0
Centre of distributions.
Definition: BDSBunch.hh:176
G4double E0
Centre of distributions.
Definition: BDSBunch.hh:179
G4double sigmaEk
Centre of distributions.
Definition: BDSBunch.hh:185
static void SetEmittances(const BDSParticleDefinition *beamParticle, const GMAD::Beam &beam, G4double &emittGeometricX, G4double &emittGeometricY, G4double &emittNormalisedX, G4double &emittNormalisedY)
Definition: BDSBunch.cc:175
G4double Y0
Centre of distributions.
Definition: BDSBunch.hh:172
virtual void SetOptions(const BDSParticleDefinition *beamParticle, const GMAD::Beam &beam, const BDSBunchType &distrType, G4Transform3D beamlineTransformIn=G4Transform3D::Identity, const G4double beamlineS=0)
Definition: BDSBunch.cc:82
virtual void UpdateIonDefinition()
Definition: BDSBunch.cc:382
G4double beamlineS
Beamline initial S position.
Definition: BDSBunch.hh:219
BDSParticleCoordsFullGlobal GetNextParticle()
Definition: BDSBunch.cc:262
G4bool finiteSigmaT
Flags to ignore random number generator in case of no finite E or T.
Definition: BDSBunch.hh:208
static G4double CalculateZp(G4double xp, G4double yp, G4double Zp0)
Calculate zp safely based on other components.
Definition: BDSBunch.cc:367
BDSParticleDefinition * particleDefinition
Particle definition for bunch - this class owns it.
Definition: BDSBunch.hh:199
virtual BDSParticleCoordsFullGlobal GetNextParticleValid(G4int maxTries=100)
Definition: BDSBunch.cc:234
G4int eventsPerBunch
Bunch offset in time parameters.
Definition: BDSBunch.hh:191
virtual void CheckParameters()
Definition: BDSBunch.cc:223
General exception with possible name of object and message.
Definition: BDSException.hh:35
static BDSGlobalConstants * Instance()
Access method.
Class to parse an ion particle definition.
G4int A() const
Accessor.
G4double ExcitationEnergy() const
Accessor.
G4int Z() const
Accessor.
A set of particle coordinates in both local and global.
G4int beamlineIndex
Optional index for where transform was found.
A set of particle coordinates including energy and weight.
A set of particle coordinates.
BDSParticleCoords ApplyTransform(const G4Transform3D &transform) const
Apply a transform to the coordinates and return a copy of them transformed.
Wrapper for particle definition.
G4double Mass() const
Accessor.
G4double Momentum() const
Accessor.
G4double KineticEnergy() const
Accessor.
G4double Beta() const
Accessor.
G4double Gamma() const
Accessor.
BDSIonDefinition * IonDefinition() const
Accessor.
G4double TotalEnergy() const
Accessor.
G4bool IsAnIon() const
Accessor.
void UpdateG4ParticleDefinition(G4ParticleDefinition *particleIn)
Improve type-safety of native enum data type in C++.
double sigmaE
for the gaussian, elliptic shell, ring distributions
Definition: beamBase.h:85
double emity
initial twiss parameters
Definition: beamBase.h:90
double bunchFrequency
Bunch offsets in time.
Definition: beamBase.h:64
double emitNY
initial twiss parameters
Definition: beamBase.h:91
int eventsPerBunch
Bunch offsets in time.
Definition: beamBase.h:66
double tilt
tilt of beam applied as rotation about unit local z
Definition: beamBase.h:79
double emitNX
initial twiss parameters
Definition: beamBase.h:91
double S0
initial beam centroid
Definition: beamBase.h:70
double bunchPeriod
Bunch offsets in time.
Definition: beamBase.h:65
double emitx
initial twiss parameters
Definition: beamBase.h:90
double sigmaT
bunch length
Definition: beamBase.h:82
double Zp0
initial beam centroid
Definition: beamBase.h:71
double Z0
initial beam centroid
Definition: beamBase.h:70
double X0
initial beam centroid
Definition: beamBase.h:70
double Xp0
initial beam centroid
Definition: beamBase.h:71
double Yp0
initial beam centroid
Definition: beamBase.h:71
double Y0
initial beam centroid
Definition: beamBase.h:70
double T0
initial beam centroid
Definition: beamBase.h:72
Beam class.
Definition: beam.h:44
void ConflictingParametersSet(const GMAD::Beam &beamDefinition, const std::set< std::string > &keys, G4int nSet, G4bool warnZeroParamsSet=true, const G4String &unitString="")
Throw an exception if too few or too many parameters are set for the supplied keys.
void FixGeant105ThreshholdsForParticle(const G4ParticleDefinition *particleDefinition)
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())
G4int NBeamParametersSet(const GMAD::Beam &beamDefinition, const std::set< std::string > &keys)
Count how many out of the set of keys in a beam instance are set.