OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
Undulator.cpp
Go to the documentation of this file.
1//
2// Class Undulator
3// Defines all the methods used by the Undulator element.
4// The Undulator element uses a full wave solver from the
5// MITHRA library, see <https://github.com/aryafallahi/mithra/>.
6//
7// Copyright (c) 2020, Arnau AlbĂ , Paul Scherrer Institut, Villigen PSI, Switzerland
8// All rights reserved.
9//
10// Implemented as part of the MSc thesis
11// "Start-to-End Modelling of the AWA Micro-Bunched Electron Cooling POP-Experiment"
12//
13// This file is part of OPAL.
14//
15// OPAL is free software: you can redistribute it and/or modify
16// it under the terms of the GNU General Public License as published by
17// the Free Software Foundation, either version 3 of the License, or
18// (at your option) any later version.
19//
20// You should have received a copy of the GNU General Public License
21// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
22//
24
27#include "Physics/Physics.h"
28#include "Physics/Units.h"
29
30#include <sys/time.h>
31#include <cmath>
32#include "mithra/classes.h"
33#include "mithra/database.h"
34#include "mithra/datainput.h"
35#include "mithra/fdtdSC.h"
36#include "mithra/fieldvector.h"
37#include "mithra/readdata.h"
38#include "mithra/stdinclude.h"
39
40extern Inform* gmsg;
41
43}
44
46 : Component(right),
47 k_m(right.k_m),
48 lambda_m(right.lambda_m),
49 numPeriods_m(right.numPeriods_m),
50 angle_m(right.angle_m),
51 fname_m(right.fname_m),
52 meshLength_m(right.meshLength_m),
53 meshResolution_m(right.meshResolution_m),
54 truncationOrder_m(right.truncationOrder_m),
55 totalTime_m(right.totalTime_m),
56 dtBunch_m(right.dtBunch_m),
57 hasBeenSimulated_m(right.hasBeenSimulated_m) {
58}
59
60Undulator::Undulator(const std::string& name)
61 : Component(name),
62 k_m(0.0),
63 lambda_m(0.0),
64 numPeriods_m(0),
65 angle_m(0.0),
66 fname_m(""),
67 meshLength_m(3, 0.0),
68 meshResolution_m(3, 0.0),
69 truncationOrder_m(2),
70 totalTime_m(0.0),
71 dtBunch_m(0.0),
72 hasBeenSimulated_m(false) {
73}
74
76}
77
78void Undulator::accept(BeamlineVisitor& visitor) const {
79 visitor.visitUndulator(*this);
80}
81
83 PartBunchBase<double, 3>* bunch, double& /*startField*/, double& /*endField*/) {
84 RefPartBunch_m = bunch;
85}
86
88 PartBunchBase<double, 3>* itsBunch, CoordinateSystemTrafo const& refToLocalCSTrafo) {
89 Inform msg("MITHRA FW solver ", *gmsg);
90
91 // Get local coordinates w.r.t. undulator.
92 const unsigned int localNum = itsBunch->getLocalNum();
93 for (unsigned int i = 0; i < localNum; ++i) {
94 itsBunch->R[i] = refToLocalCSTrafo.transformTo(itsBunch->R[i]);
95 itsBunch->P[i] = refToLocalCSTrafo.rotateTo(itsBunch->P[i]);
96 }
97
98 itsBunch->calcBeamParameters();
99 msg << "Bunch before undulator in local coordinate system: " << endl;
100 itsBunch->print(msg);
101
102 MITHRA::helloMessage();
103
104 // Prepare parameters for full wave solver.
105 MITHRA::BunchInitialize bunchInit;
106 bunchInit.bunchType_ = "other";
107 bunchInit.numberOfParticles_ = itsBunch->getTotalNum();
108 bunchInit.cloudCharge_ =
109 itsBunch->getTotalNum() * itsBunch->getChargePerParticle() / (-Physics::q_e);
110 bunchInit.initialGamma_ = itsBunch->get_gamma();
111 for (unsigned int d = 0; d < 3; ++d)
112 bunchInit.initialDirection_[d] = itsBunch->get_pmean()[d];
113 bunchInit.initialDirection_ /= euclidean_norm(itsBunch->get_pmean());
114 MITHRA::Bunch bunch;
115 bunch.bunchInit_.push_back(bunchInit);
116 bunch.timeStep_ = getDtBunch();
117 msg << "Bunch parameters have been transferred to the full-wave solver." << endl;
118
119 MITHRA::Undulator undulator;
120 undulator.k_ = getK();
121 undulator.lu_ = getLambda();
122 undulator.length_ = getNumPeriods();
123 undulator.theta_ = getAngle();
124 double lFringe = 2 * undulator.lu_; // Fringe field length is 2*lu.
125 undulator.dist_ = lFringe - itsBunch->get_maxExtent()[2]; // Bunch-head to undulator distance.
126 std::vector<MITHRA::Undulator> undulators;
127 undulators.push_back(undulator);
128 msg << "Undulator parameters have been transferred to the full-wave solver." << endl;
129
130 MITHRA::Mesh mesh;
131 mesh.initialize();
132 mesh.lengthScale_ = 1.0; // OPAL uses metres.
133 mesh.timeScale_ = 1.0; // OPAL uses seconds.
134 mesh.meshCenter_ = MITHRA::FieldVector<double>(0.0);
135 mesh.meshLength_ = getMeshLength();
136 mesh.meshResolution_ = getMeshResolution();
137 mesh.totalTime_ = getTotalTime();
138 // If simulation time is not given, run the full-wave solver until the end of the undulator.
139 if (mesh.totalTime_ == 0)
140 mesh.totalDist_ = lFringe + undulator.lu_ * undulator.length_;
141 mesh.truncationOrder_ = getTruncationOrder();
142 mesh.spaceCharge_ = true;
143 mesh.optimizePosition_ = true;
144 msg << "Mesh parameters have been transferred to the full-wave solver." << endl;
145
146 MITHRA::Seed seed;
147 seed.a0_ = 0.0; // initialise unitialised member (see #658)
148 std::vector<MITHRA::ExtField> externalFields;
149 std::vector<MITHRA::FreeElectronLaser> FELs;
150
151 // Get filename with desired output data.
152 if (!fname_m.empty()) {
153 std::list<std::string> jobFile = MITHRA::read_file(fname_m.c_str());
154 MITHRA::cleanJobFile(jobFile);
155 MITHRA::ParseDarius parser(jobFile, mesh, bunch, seed, undulators, externalFields, FELs);
156 parser.setJobParameters();
157 }
158
159 MITHRA::FdTdSC solver(mesh, bunch, seed, undulators, externalFields, FELs);
160
161 // Transfer particles to full wave solver and destroy them from itsBunch.
162 MITHRA::Charge charge;
163 charge.q = itsBunch->getChargePerParticle() / (-Physics::q_e);
164 for (unsigned int i = 0; i < localNum; ++i) {
165 for (unsigned int d = 0; d < 3; ++d) {
166 charge.rnp[d] = itsBunch->R[i][d];
167 charge.gbnp[d] = itsBunch->P[i][d];
168 }
169 solver.chargeVectorn_.push_back(charge);
170 }
171 itsBunch->destroy(localNum, 0, true);
172 msg << "Particles have been transferred to the full-wave solver." << endl;
173
174 // Print the parameters for the simulation.
175 mesh.show();
176 bunch.show();
177 seed.show();
178 for (unsigned int i = 0; i < undulators.size(); i++) {
179 undulators[i].show();
180 }
181 for (unsigned int i = 0; i < externalFields.size(); i++) {
182 externalFields[i].show();
183 }
184
185 // Run the full-wave solver.
186 timeval simulationStart;
187 gettimeofday(&simulationStart, nullptr);
188 solver.solve();
189
190 // Get total computational time of the full wave simulation.
191 timeval simulationEnd;
192 gettimeofday(&simulationEnd, nullptr);
193 double deltaTime = (simulationEnd.tv_usec - simulationStart.tv_usec) * Units::us2s;
194 deltaTime += (simulationEnd.tv_sec - simulationStart.tv_sec);
195 msg << "::: Total full wave simulation time [seconds] = " << deltaTime << endl;
196
197 // Lorentz Transformation back to undulator local coordinates.
198 // First you need to get the position of the bunch tail.
199 double zMin = 1e100;
200 for (auto iter = solver.chargeVectorn_.begin(); iter != solver.chargeVectorn_.end(); iter++) {
201 zMin = std::min(zMin, iter->rnp[2]);
202 }
203 allreduce(&zMin, 1, std::less<double>());
204
205 const double gammaBeta = solver.gamma_ * solver.beta_;
206 const double factor = gammaBeta * solver.c0_ * (solver.timeBunch_ + solver.dt_) + lFringe;
207 for (auto iter = solver.chargeVectorn_.begin(); iter != solver.chargeVectorn_.end(); iter++) {
208 double dist = zMin - iter->rnp[2];
209 // Lorentz transform.
210 iter->rnp[2] = solver.gamma_ * iter->rnp[2] + factor;
211 iter->gbnp[2] =
212 solver.gamma_ * iter->gbnp[2] + gammaBeta * std::sqrt(1 + iter->gbnp.norm2());
213 // Shift to bring all particles to same time in lab frame.
214 double gammaParticle = std::sqrt(1 + iter->gbnp.norm2());
215 iter->rnp[0] += iter->gbnp[0] / gammaParticle * dist * gammaBeta;
216 iter->rnp[1] += iter->gbnp[1] / gammaParticle * dist * gammaBeta;
217 iter->rnp[2] += iter->gbnp[2] / gammaParticle * dist * gammaBeta;
218 }
219
220 // Get total time elapsed in laboratory frame.
221 mesh.totalTime_ =
222 solver.gamma_ * (solver.time_ + solver.beta_ / solver.c0_ * (zMin - bunch.zu_));
223
224 // Return particles to itsBunch in local coordinates.
225 msg << "Transferring particles back to OPAL bunch." << endl;
226 itsBunch->create(solver.chargeVectorn_.size());
227 const double dt = itsBunch->getdT();
228 const unsigned int newLocalNum = itsBunch->getLocalNum();
229 std::list<MITHRA::Charge>::iterator iter = solver.chargeVectorn_.begin();
230 for (unsigned int i = 0; i < newLocalNum; ++i) {
231 for (unsigned int d = 0; d < 3; ++d) {
232 itsBunch->R[i][d] = iter->rnp[d];
233 itsBunch->P[i][d] = iter->gbnp[d];
234 }
235 itsBunch->Q[i] = iter->q * (-Physics::q_e);
236 itsBunch->dt[i] = dt;
237 iter++;
238 }
239 itsBunch->setT(itsBunch->getT() + mesh.totalTime_);
240
241 // Transform back to reference coordinate system.
242 CoordinateSystemTrafo localToRefCSTrafo = refToLocalCSTrafo.inverted();
243 for (unsigned int i = 0; i < newLocalNum; ++i) {
244 itsBunch->R[i] = localToRefCSTrafo.transformTo(itsBunch->R[i]);
245 itsBunch->P[i] = localToRefCSTrafo.rotateTo(itsBunch->P[i]);
246 }
247 itsBunch->calcBeamParameters();
248
249 // Update reference particle.
250 // The reference particle becomes the bunch-centroid after the undulator.
251 itsBunch->RefPartR_m = itsBunch->toLabTrafo_m.transformTo(itsBunch->get_centroid());
252 itsBunch->RefPartP_m = itsBunch->toLabTrafo_m.rotateTo(itsBunch->get_pmean());
253
254 msg << "Bunch after undulator in reference coordinate system: " << endl;
255 itsBunch->print(msg);
256
258}
259
261}
262
263bool Undulator::bends() const {
264 return false;
265}
266
267void Undulator::getDimensions(double& /*zBegin*/, double& /*zEnd*/) const {
268}
269
272}
273
274void Undulator::setK(double k) {
275 k_m = k;
276}
277double Undulator::getK() const {
278 return k_m;
279}
280
281void Undulator::setLambda(double lambda) {
282 lambda_m = lambda;
283}
284double Undulator::getLambda() const {
285 return lambda_m;
286}
287
288void Undulator::setNumPeriods(unsigned int np) {
289 numPeriods_m = np;
290}
291unsigned int Undulator::getNumPeriods() const {
292 return numPeriods_m;
293}
294
295void Undulator::setAngle(double theta) {
296 angle_m = theta;
297}
298double Undulator::getAngle() const {
299 return angle_m;
300}
301
302void Undulator::setFilename(const std::string& fname) {
303 fname_m = fname;
304}
305const std::string& Undulator::getFilename() const {
306 return fname_m;
307}
308
309void Undulator::setMeshLength(const std::vector<double>& ml) {
310 meshLength_m = ml;
311}
312std::vector<double> Undulator::getMeshLength() const {
313 return meshLength_m;
314}
315
316void Undulator::setMeshResolution(const std::vector<double>& mr) {
317 meshResolution_m = mr;
318}
319std::vector<double> Undulator::getMeshResolution() const {
320 return meshResolution_m;
321}
322
323void Undulator::setTruncationOrder(unsigned int trunOrder) {
324 truncationOrder_m = trunOrder;
325}
326unsigned int Undulator::getTruncationOrder() const {
327 return truncationOrder_m;
328}
329
330void Undulator::setTotalTime(double tt) {
331 totalTime_m = tt;
332}
334 return totalTime_m;
335}
336
337void Undulator::setDtBunch(double dtb) {
338 dtBunch_m = dtb;
339}
340double Undulator::getDtBunch() const {
341 return dtBunch_m;
342}
343
345 hasBeenSimulated_m = hbs;
346}
348 return hasBeenSimulated_m;
349}
Inform * gmsg
Definition: Main.cpp:61
ElementType
Definition: ElementBase.h:88
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
T euclidean_norm(const Vector< T > &)
Euclidean norm.
Definition: Vector.h:243
void allreduce(const T *input, T *output, int count, Op op)
Definition: GlobalComm.hpp:510
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:76
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
const std::string name
constexpr double q_e
The elementary charge in As.
Definition: Physics.h:69
constexpr double us2s
Definition: Units.h:41
std::string::iterator iterator
Definition: MSLang.h:16
int seed
The current random seed.
Definition: Options.cpp:37
ParticlePos_t & R
Vector_t RefPartP_m
double getChargePerParticle() const
get the macro particle charge
size_t getLocalNum() const
size_t getTotalNum() const
double get_gamma() const
ParticleAttrib< Vector_t > P
double getdT() const
Inform & print(Inform &os)
Vector_t RefPartR_m
ParticleAttrib< double > Q
void calcBeamParameters()
CoordinateSystemTrafo toLabTrafo_m
ParticleAttrib< double > dt
Vector_t get_maxExtent() const
Vector_t get_centroid() const
Vector_t get_pmean() const
void destroy(size_t M, size_t I, bool doNow=false)
void create(size_t M)
void setT(double t)
double getT() const
Interface for a single beam element.
Definition: Component.h:50
PartBunchBase< double, 3 > * RefPartBunch_m
Definition: Component.h:191
virtual ElementType getType() const
Get element type std::string.
Definition: Undulator.cpp:270
unsigned int numPeriods_m
Number of periods.
Definition: Undulator.h:87
void setAngle(double theta)
Definition: Undulator.cpp:295
double angle_m
Polarisation angle of the undulator field.
Definition: Undulator.h:90
double getK() const
Definition: Undulator.cpp:277
std::vector< double > getMeshLength() const
Definition: Undulator.cpp:312
double lambda_m
Undulator period.
Definition: Undulator.h:84
std::vector< double > meshResolution_m
Mesh dx, dy, dz.
Definition: Undulator.h:99
std::string fname_m
Mithra file with output information.
Definition: Undulator.h:93
double totalTime_m
Total time to run undulator.
Definition: Undulator.h:105
virtual ~Undulator()
Definition: Undulator.cpp:75
void setMeshLength(const std::vector< double > &ml)
Definition: Undulator.cpp:309
void apply(PartBunchBase< double, 3 > *itsBunch, CoordinateSystemTrafo const &refToLocalCSTrafo)
Definition: Undulator.cpp:87
void setLambda(double lambda)
Definition: Undulator.cpp:281
void setFilename(const std::string &fname)
Definition: Undulator.cpp:302
double getDtBunch() const
Definition: Undulator.cpp:340
void setTotalTime(double tt)
Definition: Undulator.cpp:330
virtual void finalise()
Definition: Undulator.cpp:260
void setTruncationOrder(unsigned int trunOrder)
Definition: Undulator.cpp:323
void setNumPeriods(unsigned int np)
Definition: Undulator.cpp:288
virtual bool bends() const
Definition: Undulator.cpp:263
unsigned int getTruncationOrder() const
Definition: Undulator.cpp:326
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField)
Definition: Undulator.cpp:82
double getTotalTime() const
Definition: Undulator.cpp:333
double dtBunch_m
Time step for the bunch position update.
Definition: Undulator.h:108
const std::string & getFilename() const
Definition: Undulator.cpp:305
bool getHasBeenSimulated() const
Definition: Undulator.cpp:347
unsigned int getNumPeriods() const
Definition: Undulator.cpp:291
void setDtBunch(double dtb)
Definition: Undulator.cpp:337
double getAngle() const
Definition: Undulator.cpp:298
std::vector< double > getMeshResolution() const
Definition: Undulator.cpp:319
std::vector< double > meshLength_m
Size of computational domain.
Definition: Undulator.h:96
void setMeshResolution(const std::vector< double > &mr)
Definition: Undulator.cpp:316
bool hasBeenSimulated_m
Boolean to indicate whether this undulator has already been simulated.
Definition: Undulator.h:111
double getLambda() const
Definition: Undulator.cpp:284
void setK(double k)
Definition: Undulator.cpp:274
virtual void getDimensions(double &zBegin, double &zEnd) const
Definition: Undulator.cpp:267
virtual void accept(BeamlineVisitor &) const
Apply visitor to Undulator.
Definition: Undulator.cpp:78
double k_m
The undulator parameter.
Definition: Undulator.h:81
void setHasBeenSimulated(bool hbs)
Definition: Undulator.cpp:344
unsigned int truncationOrder_m
First or second order absorbing boundary conditions.
Definition: Undulator.h:102
Vector_t transformTo(const Vector_t &r) const
Vector_t rotateTo(const Vector_t &r) const
CoordinateSystemTrafo inverted() const
Definition: Inform.h:42