OPAL (Object Oriented Parallel Accelerator Library)  2024.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 //
23 #include "AbsBeamline/Undulator.h"
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 
40 extern 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 
60 Undulator::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 
78 void 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 
257  setHasBeenSimulated(true);
258 }
259 
261 }
262 
263 bool Undulator::bends() const {
264  return false;
265 }
266 
267 void Undulator::getDimensions(double& /*zBegin*/, double& /*zEnd*/) const {
268 }
269 
271  return ElementType::UNDULATOR;
272 }
273 
274 void Undulator::setK(double k) {
275  k_m = k;
276 }
277 double Undulator::getK() const {
278  return k_m;
279 }
280 
281 void Undulator::setLambda(double lambda) {
282  lambda_m = lambda;
283 }
284 double Undulator::getLambda() const {
285  return lambda_m;
286 }
287 
288 void Undulator::setNumPeriods(unsigned int np) {
289  numPeriods_m = np;
290 }
291 unsigned int Undulator::getNumPeriods() const {
292  return numPeriods_m;
293 }
294 
295 void Undulator::setAngle(double theta) {
296  angle_m = theta;
297 }
298 double Undulator::getAngle() const {
299  return angle_m;
300 }
301 
302 void Undulator::setFilename(const std::string& fname) {
303  fname_m = fname;
304 }
305 const std::string& Undulator::getFilename() const {
306  return fname_m;
307 }
308 
309 void Undulator::setMeshLength(const std::vector<double>& ml) {
310  meshLength_m = ml;
311 }
312 std::vector<double> Undulator::getMeshLength() const {
313  return meshLength_m;
314 }
315 
316 void Undulator::setMeshResolution(const std::vector<double>& mr) {
317  meshResolution_m = mr;
318 }
319 std::vector<double> Undulator::getMeshResolution() const {
320  return meshResolution_m;
321 }
322 
323 void Undulator::setTruncationOrder(unsigned int trunOrder) {
324  truncationOrder_m = trunOrder;
325 }
326 unsigned int Undulator::getTruncationOrder() const {
327  return truncationOrder_m;
328 }
329 
330 void Undulator::setTotalTime(double tt) {
331  totalTime_m = tt;
332 }
333 double Undulator::getTotalTime() const {
334  return totalTime_m;
335 }
336 
337 void Undulator::setDtBunch(double dtb) {
338  dtBunch_m = dtb;
339 }
340 double Undulator::getDtBunch() const {
341  return dtBunch_m;
342 }
343 
345  hasBeenSimulated_m = hbs;
346 }
348  return hasBeenSimulated_m;
349 }
double getTotalTime() const
Definition: Undulator.cpp:333
unsigned int numPeriods_m
Number of periods.
Definition: Undulator.h:87
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
virtual bool bends() const
Definition: Undulator.cpp:263
int seed
The current random seed.
Definition: Options.cpp:37
std::vector< double > meshLength_m
Size of computational domain.
Definition: Undulator.h:96
void setAngle(double theta)
Definition: Undulator.cpp:295
bool getHasBeenSimulated() const
Definition: Undulator.cpp:347
void setFilename(const std::string &fname)
Definition: Undulator.cpp:302
double dtBunch_m
Time step for the bunch position update.
Definition: Undulator.h:108
const std::string & getFilename() const
Definition: Undulator.cpp:305
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField)
Definition: Undulator.cpp:82
void setDtBunch(double dtb)
Definition: Undulator.cpp:337
CoordinateSystemTrafo inverted() const
ParticleAttrib< Vector_t > P
void setTruncationOrder(unsigned int trunOrder)
Definition: Undulator.cpp:323
void setT(double t)
bool hasBeenSimulated_m
Boolean to indicate whether this undulator has already been simulated.
Definition: Undulator.h:111
void destroy(size_t M, size_t I, bool doNow=false)
Inform & print(Inform &os)
Vector_t get_centroid() const
virtual void finalise()
Definition: Undulator.cpp:260
Vector_t get_pmean() const
double getAngle() const
Definition: Undulator.cpp:298
void calcBeamParameters()
void setMeshResolution(const std::vector< double > &mr)
Definition: Undulator.cpp:316
PartBunchBase< double, 3 > * RefPartBunch_m
Definition: Component.h:191
std::vector< double > getMeshLength() const
Definition: Undulator.cpp:312
void setNumPeriods(unsigned int np)
Definition: Undulator.cpp:288
double totalTime_m
Total time to run undulator.
Definition: Undulator.h:105
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
virtual void accept(BeamlineVisitor &) const
Apply visitor to Undulator.
Definition: Undulator.cpp:78
double getdT() const
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:76
std::string fname_m
Mithra file with output information.
Definition: Undulator.h:93
void setLambda(double lambda)
Definition: Undulator.cpp:281
CoordinateSystemTrafo toLabTrafo_m
virtual ElementType getType() const
Get element type std::string.
Definition: Undulator.cpp:270
unsigned int getTruncationOrder() const
Definition: Undulator.cpp:326
virtual void getDimensions(double &zBegin, double &zEnd) const
Definition: Undulator.cpp:267
double get_gamma() const
std::string::iterator iterator
Definition: MSLang.h:15
std::vector< double > meshResolution_m
Mesh dx, dy, dz.
Definition: Undulator.h:99
T euclidean_norm(const Vector< T > &)
Euclidean norm.
Definition: Vector.h:243
void apply(PartBunchBase< double, 3 > *itsBunch, CoordinateSystemTrafo const &refToLocalCSTrafo)
Definition: Undulator.cpp:87
double getT() const
virtual ~Undulator()
Definition: Undulator.cpp:75
size_t getTotalNum() const
Vector_t rotateTo(const Vector_t &r) const
size_t getLocalNum() const
Definition: Inform.h:42
ElementType
Definition: ElementBase.h:88
void allreduce(const T *input, T *output, int count, Op op)
Definition: GlobalComm.hpp:510
double lambda_m
Undulator period.
Definition: Undulator.h:84
double getDtBunch() const
Definition: Undulator.cpp:340
ParticleAttrib< double > Q
void setTotalTime(double tt)
Definition: Undulator.cpp:330
constexpr double q_e
The elementary charge in As.
Definition: Physics.h:69
Vector_t transformTo(const Vector_t &r) const
std::vector< double > getMeshResolution() const
Definition: Undulator.cpp:319
ParticleAttrib< double > dt
double getLambda() const
Definition: Undulator.cpp:284
double getChargePerParticle() const
get the macro particle charge
void setK(double k)
Definition: Undulator.cpp:274
unsigned int getNumPeriods() const
Definition: Undulator.cpp:291
void setMeshLength(const std::vector< double > &ml)
Definition: Undulator.cpp:309
const std::string name
ParticlePos_t & R
double angle_m
Polarisation angle of the undulator field.
Definition: Undulator.h:90
double k_m
The undulator parameter.
Definition: Undulator.h:81
Vector_t RefPartR_m
void create(size_t M)
constexpr double us2s
Definition: Units.h:41
Interface for a single beam element.
Definition: Component.h:50
Vector_t get_maxExtent() const
unsigned int truncationOrder_m
First or second order absorbing boundary conditions.
Definition: Undulator.h:102
Vector_t RefPartP_m
double getK() const
Definition: Undulator.cpp:277
void setHasBeenSimulated(bool hbs)
Definition: Undulator.cpp:344
Inform * gmsg
Definition: Main.cpp:70