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