OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
RBend3D.cpp
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2// $RCSfile: RBend3D.cpp,v $
3// ------------------------------------------------------------------------
4// $Revision: 1.1.1.1 $
5// ------------------------------------------------------------------------
6// Copyright: see Copyright.readme
7// ------------------------------------------------------------------------
8//
9// Class: RBend3D
10// Defines the abstract interface for a solenoid magnet.
11//
12// ------------------------------------------------------------------------
13// Class category: AbsBeamline
14// ------------------------------------------------------------------------
15
16#include "AbsBeamline/RBend3D.h"
20#include "Fields/Fieldmap.h"
22#include "Utilities/Options.h"
24#include "Physics/Physics.h"
25#include "Utilities/Util.h"
26
27#include <iostream>
28#include <fstream>
29#include <cmath>
30
31extern Inform *gmsg;
32
33// Class RBend3D
34// ------------------------------------------------------------------------
35
37 RBend3D("")
38{}
39
40
42 BendBase(right),
43 fieldAmplitudeError_m(right.fieldAmplitudeError_m),
44 startField_m(right.startField_m),
45 lengthField_m(right.lengthField_m),
46 geometry_m(right.geometry_m),
47 dummyField_m() {
48}
49
50
51RBend3D::RBend3D(const std::string &name):
53 fieldAmplitudeError_m(0.0),
54 startField_m(0.0),
55 lengthField_m(0.0),
56 geometry_m(),
57 dummyField_m() {
58}
59
60
62}
63
64void RBend3D::accept(BeamlineVisitor &visitor) const {
65 visitor.visitRBend3D(*this);
66}
67
68bool RBend3D::apply(const size_t &i, const double &t, Vector_t &E, Vector_t &B) {
69 return apply(RefPartBunch_m->R[i], RefPartBunch_m->P[i], t, E, B);
70}
71
72bool RBend3D::apply(const Vector_t &R, const Vector_t &/*P*/, const double &/*t*/, Vector_t &/*E*/, Vector_t &B) {
73 const Vector_t tmpR(R(0), R(1), R(2) - startField_m);
74 Vector_t tmpE(0.0, 0.0, 0.0), tmpB(0.0, 0.0, 0.0);
75
76 fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
77
79
80 return false;
81}
82
83bool RBend3D::applyToReferenceParticle(const Vector_t &R, const Vector_t &/*P*/, const double &/*t*/, Vector_t &/*E*/, Vector_t &B) {
84 const Vector_t tmpR(R(0), R(1), R(2) - startField_m);
85 Vector_t tmpE(0.0), tmpB(0.0);
86
87 fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
88 B += fieldAmplitude_m * tmpB;
89
90 return false;
91}
92
93void RBend3D::initialise(PartBunchBase<double, 3> *bunch, double &startField, double &endField) {
94 Inform msg("RBend3D ", *gmsg);
95
96 RefPartBunch_m = bunch;
97
99 if(fieldmap_m != nullptr) {
100 msg << level2 << getName() << " using file ";
101 fieldmap_m->getInfo(&msg);
102 goOnline(0.0);
103
104 double zBegin = 0.0, zEnd = 0.0;
105 fieldmap_m->getFieldDimensions(zBegin, zEnd);
106
107 if (getElementLength() == 0.0) {
108 chordLength_m = 0.0;
109 double fieldLength = zEnd - zBegin;
110 double z = 0.0, dz = fieldLength / 1000;
111 Vector_t E(0.0), B(0.0);
112 while (z < fieldLength && B(1) < 0.5) {
113 fieldmap_m->getFieldstrength(Vector_t(0.0, 0.0, z), E, B);
114 z += dz;
115 }
116 double zEntryEdge = z;
117 z = fieldLength;
118 B(1) = 0.0;
119 while (z > 0.0 && B(1) < 0.5) {
120 fieldmap_m->getFieldstrength(Vector_t(0.0, 0.0, z), E, B);
121 z -= dz;
122 }
123 chordLength_m = z - zEntryEdge;
125 } else {
127 }
128
129 startField_m = zBegin;
130 lengthField_m = zEnd - zBegin;
131 endField = startField + lengthField_m;
132
133 if (angle_m != 0.0) {
134 if (angle_m < 0.0) {
135 // Negative angle is a positive bend rotated 180 degrees.
139 }
140
141 Vector_t B(0.0), E(0.0);
142 double z = 0.0, dz = lengthField_m / 999;
143 double integratedBy = 0.0;
144
145 fieldmap_m->getFieldstrength(Vector_t(0.0, 0.0, z), E, B);
146 integratedBy += 0.5 * B(1);
147 z = dz;
148 while (z < lengthField_m) {
149 B = 0.0; E = 0.0;
150 fieldmap_m->getFieldstrength(Vector_t(0.0, 0.0, z), E, B);
151 integratedBy += B(1);
152 z += dz;
153 }
154 integratedBy -= 0.5 * B(1);
155 integratedBy *= lengthField_m / 1000;
156
157 // estimate magnitude of field
159
160 double angle = trackRefParticleThrough(bunch->getdT());
161 double error = (angle_m - angle) / angle_m;
162
163 for (unsigned int i = 0; i < 10; ++ i) {
164 fieldAmplitude_m *= (0.5 * error + 1.0);
165 angle = trackRefParticleThrough(bunch->getdT());
166 error = (angle_m - angle) / angle_m;
167
168 if (std::abs(error) < 0.001) break;
169 }
170
172 trackRefParticleThrough(bunch->getdT(), true);
173 } else {
174 double refCharge = bunch->getQ();
176 if (refCharge < 0.0) {
178 }
179 fieldAmplitude_m = std::copysign(1.0, refCharge) * std::hypot(fieldAmplitudeX_m, fieldAmplitudeY_m);
181 }
182
183 } else {
184 endField = startField;
185 }
186}
187
189{}
190
191void RBend3D::goOnline(const double &) {
193 online_m = true;
194}
195
198 online_m = false;
199}
200
201void RBend3D::getDimensions(double &zBegin, double &zEnd) const {
202 zBegin = startField_m;
204}
205
206
209}
210
211bool RBend3D::isInside(const Vector_t &r) const {
212 Vector_t tmpR(r(0), r(1), r(2) - startField_m);
213 return fieldmap_m->isInside(tmpR);
214}
215
217 return new RBend3D(*this);
218}
219
221 return geometry_m;
222}
223
225 return geometry_m;
226}
227
229 return dummyField_m;
230}
231
233 return dummyField_m;
234}
235
237 Vector_t XIni, XFinal;
238 fieldmap_m->getFieldDimensions(XIni(0), XFinal(0),
239 XIni(1), XFinal(1),
240 XIni(2), XFinal(2));
241
242 MeshData mesh;
243 mesh.vertices_m.push_back(Vector_t(XIni(0), XIni(1), XIni(2)));
244 mesh.vertices_m.push_back(Vector_t(XIni(0), XIni(1), XFinal(2)));
245 mesh.vertices_m.push_back(Vector_t(XIni(0), XFinal(1), XIni(2)));
246 mesh.vertices_m.push_back(Vector_t(XIni(0), XFinal(1), XFinal(2)));
247 mesh.vertices_m.push_back(Vector_t(XFinal(0), XIni(1), XIni(2)));
248 mesh.vertices_m.push_back(Vector_t(XFinal(0), XIni(1), XFinal(2)));
249 mesh.vertices_m.push_back(Vector_t(XFinal(0), XFinal(1), XIni(2)));
250 mesh.vertices_m.push_back(Vector_t(XFinal(0), XFinal(1), XFinal(2)));
251
252 mesh.triangles_m.push_back(Vektor<unsigned int, 3>(0, 1, 2));
253 mesh.triangles_m.push_back(Vektor<unsigned int, 3>(2, 1, 3));
254 mesh.triangles_m.push_back(Vektor<unsigned int, 3>(4, 6, 5));
255 mesh.triangles_m.push_back(Vektor<unsigned int, 3>(5, 6, 7));
256 mesh.triangles_m.push_back(Vektor<unsigned int, 3>(1, 5, 3));
257 mesh.triangles_m.push_back(Vektor<unsigned int, 3>(3, 5, 7));
258 mesh.triangles_m.push_back(Vektor<unsigned int, 3>(4, 2, 6));
259 mesh.triangles_m.push_back(Vektor<unsigned int, 3>(4, 0, 2));
260 mesh.triangles_m.push_back(Vektor<unsigned int, 3>(0, 4, 1));
261 mesh.triangles_m.push_back(Vektor<unsigned int, 3>(1, 4, 5));
262 mesh.triangles_m.push_back(Vektor<unsigned int, 3>(2, 3, 6));
263 mesh.triangles_m.push_back(Vektor<unsigned int, 3>(3, 7, 6));
264
265 return mesh;
266}
267
268double RBend3D::trackRefParticleThrough(double dt, bool print) {
269 const double refGamma = calcGamma();
270 const double refBetaGamma = calcBetaGamma();
271 const double stepSize = refBetaGamma / refGamma * Physics::c * dt;
272 const Vector_t scaleFactor(Physics::c * dt);
273 print = print && (Ippl::myNode() == 0);
274
275 std::ofstream trajectoryOutput;
276 if (print) {
277 std::string fname = Util::combineFilePath({
279 OpalData::getInstance()->getInputBasename() + "_" + getName() + "_traj.dat"
280 });
281 trajectoryOutput.open(fname);
282 trajectoryOutput.precision(12);
283 trajectoryOutput << "# " << std::setw(18) << "s"
284 << std::setw(20) << "x"
285 << std::setw(20) << "z"
286 << std::setw(20) << "By"
287 << std::endl;
288 }
289
290 double deltaS = 0.0;
292
293 Vector_t X(0.0), P(0.0);
295 X(2) = startField_m;
296 P(0) = refBetaGamma * std::sin(entranceAngle_m);
297 P(2) = refBetaGamma * std::cos(entranceAngle_m);
298
299 while ((X(2) - startField_m) < lengthField_m && 0.5 * deltaS < lengthField_m) {
300 Vector_t E(0.0), B(0.0);
301
302 X /= scaleFactor;
303 pusher.push(X, P, dt);
304 X *= scaleFactor;
305
306 applyToReferenceParticle(X, P, 0.0, E, B);
307 if (print) {
308 trajectoryOutput << std::setw(20) << deltaS + 0.5 * stepSize
309 << std::setw(20) << X(0)
310 << std::setw(20) << X(2)
311 << std::setw(20) << B(1)
312 << std::endl;
313 }
314
315 pusher.kick(X, P, E, B, dt);
316
317 X /= scaleFactor;
318 pusher.push(X, P, dt);
319 X *= scaleFactor;
320
321 deltaS += stepSize;
322 }
323
324 return -std::atan2(P(0), P(2)) + entranceAngle_m;
325}
Inform * gmsg
Definition: Main.cpp:61
ElementType
Definition: ElementBase.h:88
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
Tps< T > tan(const Tps< T > &x)
Tangent.
Definition: TpsMath.h:147
Tps< T > sin(const Tps< T > &x)
Sine.
Definition: TpsMath.h:111
#define X(arg)
Definition: fftpack.cpp:112
PETE_TBTree< FnCopysign, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > copysign(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
PETE_TBTree< FnArcTan2, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > atan2(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
Inform & level2(Inform &inf)
Definition: Inform.cpp:46
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
const std::string name
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:45
constexpr double pi
The value of.
Definition: Physics.h:30
bool writeBendTrajectories
Definition: Options.cpp:95
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition: Util.cpp:196
ParticlePos_t & R
const PartData * getReference() const
double getQ() const
Access to reference data.
ParticleAttrib< Vector_t > P
double getdT() const
std::string getInputBasename()
get input file name without extension
Definition: OpalData.cpp:669
static OpalData * getInstance()
Definition: OpalData.cpp:196
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Definition: OpalData.cpp:661
virtual void visitRBend3D(const RBend3D &)
Apply the algorithm to a rectangular bend.
double calcGamma() const
Calculate gamma from design energy.
Definition: BendBase.cpp:89
const bool fast_m
Flag to turn on fast field calculation.
Definition: BendBase.h:57
double fieldAmplitude_m
Field amplitude.
Definition: BendBase.h:71
double calcBetaGamma() const
Calculate beta*gamma from design energy.
Definition: BendBase.cpp:95
double entranceAngle_m
Definition: BendBase.h:54
double fieldAmplitudeY_m
Definition: BendBase.h:68
Fieldmap * fieldmap_m
Magnet field map.
Definition: BendBase.h:56
std::string fileName_m
Definition: BendBase.h:73
double chordLength_m
Definition: BendBase.h:52
double calcFieldAmplitude(double radius) const
Calculate field amplitude from design energy and radius.
Definition: BendBase.cpp:70
double fieldAmplitudeX_m
Definition: BendBase.h:66
double angle_m
Bend angle.
Definition: BendBase.h:53
bool online_m
Definition: Component.h:192
PartBunchBase< double, 3 > * RefPartBunch_m
Definition: Component.h:191
virtual const std::string & getName() const
Get element name.
virtual double getElementLength() const
Get design length.
Definition: ElementBase.h:414
virtual void setElementLength(double length)
Set design length.
Definition: ElementBase.h:418
double rotationZAxis_m
Definition: ElementBase.h:372
Interface for solenoids.
Definition: RBend3D.h:39
ElementBase * clone() const override
Definition: RBend3D.cpp:216
virtual bool applyToReferenceParticle(const Vector_t &R, const Vector_t &P, const double &t, Vector_t &E, Vector_t &B) override
Definition: RBend3D.cpp:83
virtual void goOnline(const double &kineticEnergy) override
Definition: RBend3D.cpp:191
virtual void goOffline() override
Definition: RBend3D.cpp:196
BGeometryBase & getGeometry() override
Definition: RBend3D.cpp:220
virtual bool isInside(const Vector_t &r) const override
Definition: RBend3D.cpp:211
StraightGeometry geometry_m
Definition: RBend3D.h:99
virtual bool apply(const size_t &i, const double &t, Vector_t &E, Vector_t &B) override
Definition: RBend3D.cpp:68
double fieldAmplitudeError_m
Definition: RBend3D.h:94
virtual void finalise() override
Definition: RBend3D.cpp:188
BMultipoleField dummyField_m
Definition: RBend3D.h:101
virtual void getDimensions(double &zBegin, double &zEnd) const override
Definition: RBend3D.cpp:201
RBend3D()
Definition: RBend3D.cpp:36
virtual ~RBend3D()
Definition: RBend3D.cpp:61
double lengthField_m
Definition: RBend3D.h:97
double startField_m
Definition: RBend3D.h:96
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
Definition: RBend3D.cpp:93
virtual ElementType getType() const override
Get element type std::string.
Definition: RBend3D.cpp:207
double trackRefParticleThrough(double dt, bool print=false)
Definition: RBend3D.cpp:268
MeshData getSurfaceMesh() const
Definition: RBend3D.cpp:236
EMField & getField() override
Definition: RBend3D.cpp:228
virtual void accept(BeamlineVisitor &) const override
Apply visitor to RBend3D.
Definition: RBend3D.cpp:64
Abstract base class for accelerator geometry classes.
Definition: Geometry.h:43
Abstract base class for electromagnetic fields.
Definition: EMField.h:188
virtual void getInfo(Inform *msg)=0
virtual void getFieldDimensions(double &zBegin, double &zEnd) const =0
static Fieldmap * getFieldmap(std::string Filename, bool fast=false)
Definition: Fieldmap.cpp:50
virtual bool isInside(const Vector_t &) const
Definition: Fieldmap.h:101
virtual void freeMap()=0
virtual bool getFieldstrength(const Vector_t &R, Vector_t &E, Vector_t &B) const =0
virtual void readMap()=0
std::vector< Vektor< unsigned int, 3 > > triangles_m
Definition: MeshGenerator.h:25
std::vector< Vector_t > vertices_m
Definition: MeshGenerator.h:24
void kick(const Vector_t &R, Vector_t &P, const Vector_t &Ef, const Vector_t &Bf, const double &dt) const
Definition: BorisPusher.h:65
void push(Vector_t &R, const Vector_t &P, const double &dt) const
Definition: BorisPusher.h:131
Definition: Inform.h:42
static int myNode()
Definition: IpplInfo.cpp:691
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6