OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
OrbitThreader.cpp
Go to the documentation of this file.
1 //
2 // Class OrbitThreader
3 //
4 // This class determines the design path by tracking the reference particle through
5 // the 3D lattice.
6 //
7 // Copyright (c) 2016, Christof Metzger-Kraus, Helmholtz-Zentrum Berlin, Germany
8 // 2017 - 2020 Christof Metzger-Kraus
9 //
10 // All rights reserved
11 //
12 // This file is part of OPAL.
13 //
14 // OPAL is free software: you can redistribute it and/or modify
15 // it under the terms of the GNU General Public License as published by
16 // the Free Software Foundation, either version 3 of the License, or
17 // (at your option) any later version.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with OPAL. If not, see <https://www.gnu.org/licenses/>.
21 //
22 
25 
26 #include "AbsBeamline/RFCavity.h"
27 #include "AbsBeamline/BendBase.h"
29 #include "BeamlineCore/MarkerRep.h"
30 
32 #include "BasicActions/Option.h"
33 #include "Utilities/Options.h"
34 
36 #include "Utilities/Util.h"
37 
38 #include <boost/filesystem.hpp>
39 
40 #include <cmath>
41 #include <iostream>
42 #include <limits>
43 
44 #define HITMATERIAL 0x80000000
45 #define EOL 0x40000000
46 #define EVERYTHINGFINE 0x00000000
47 extern Inform *gmsg;
48 
50  const Vector_t &r,
51  const Vector_t &p,
52  double s,
53  double maxDiffZBunch,
54  double t,
55  double dt,
56  StepSizeConfig stepSizes,
57  OpalBeamline &bl) :
58  r_m(r),
59  p_m(p),
60  pathLength_m(s),
61  time_m(t),
62  dt_m(dt),
63  stepSizes_m(stepSizes),
64  zstop_m(stepSizes.getFinalZStop() + std::copysign(1.0, dt) * 2 * maxDiffZBunch),
65  itsOpalBeamline_m(bl),
66  errorFlag_m(0),
67  integrator_m(ref),
68  reference_m(ref)
69 {
70  auto opal = OpalData::getInstance();
71  if (Ippl::myNode() == 0 && !opal->isOptimizerRun()) {
72  std::string fileName = Util::combineFilePath({
73  opal->getAuxiliaryOutputDirectory(),
74  opal->getInputBasename() + "_DesignPath.dat"
75  });
76  if (opal->getOpenMode() == OpalData::OPENMODE::WRITE ||
77  !boost::filesystem::exists(fileName)) {
78  logger_m.open(fileName);
79  logger_m << "#"
80  << std::setw(17) << "1 - s"
81  << std::setw(18) << "2 - Rx"
82  << std::setw(18) << "3 - Ry"
83  << std::setw(18) << "4 - Rz"
84  << std::setw(18) << "5 - Px"
85  << std::setw(18) << "6 - Py"
86  << std::setw(18) << "7 - Pz"
87  << std::setw(18) << "8 - Efx"
88  << std::setw(18) << "9 - Efy"
89  << std::setw(18) << "10 - Efz"
90  << std::setw(18) << "11 - Bfx"
91  << std::setw(18) << "12 - Bfy"
92  << std::setw(18) << "13 - Bfz"
93  << std::setw(18) << "14 - Ekin"
94  << std::setw(18) << "15 - t"
95  << std::endl;
96  } else {
97  logger_m.open(fileName, std::ios_base::app);
98  }
99 
100  loggingFrequency_m = std::max(1.0, std::round(1e-11 / std::abs(dt_m)));
101  } else {
103  }
104 
105  distTrackBack_m = std::min(pathLength_m, std::max(0.0, maxDiffZBunch));
107 }
108 
109 void OrbitThreader::checkElementLengths(const std::set<std::shared_ptr<Component>>& fields) {
111  ++ stepSizes_m;
112  }
113  if (stepSizes_m.reachedEnd()) {
114  return;
115  }
116  double driftLength = Physics::c * std::abs(stepSizes_m.getdT()) * euclidean_norm(p_m) / Util::getGamma(p_m);
117  for (const std::shared_ptr<Component>& field : fields) {
118  double length = field->getElementLength();
119  int numSteps = field->getRequiredNumberOfTimeSteps();
120 
121  if (length < numSteps * driftLength) {
122  throw OpalException("OrbitThreader::checkElementLengths",
123  "The time step is too long compared to the length of the\n"
124  "element '" + field->getName() + "'\n" +
125  "The length of the element is: " + std::to_string(length) + "\n"
126  "The distance the particles drift in " + std::to_string(numSteps) +
127  " time step(s) is: " + std::to_string(numSteps * driftLength));
128  }
129  }
130 }
131 
133  double initialPathLength = pathLength_m;
134 
136  std::set<std::string> visitedElements;
137 
138  trackBack();
140 
141  Vector_t nextR = r_m / (Physics::c * dt_m);
142  integrator_m.push(nextR, p_m, dt_m);
143  nextR *= Physics::c * dt_m;
144 
145  setDesignEnergy(allElements, visitedElements);
146 
147  auto elementSet = itsOpalBeamline_m.getElements(nextR);
149  do {
150  checkElementLengths(elementSet);
151  if (containsCavity(elementSet)) {
152  autophaseCavities(elementSet, visitedElements);
153  }
154 
155  double initialS = pathLength_m;
156  Vector_t initialR = r_m;
157  Vector_t initialP = p_m;
158  double maxDistance = computeDriftLengthToBoundingBox(elementSet, r_m, p_m);
159  integrate(elementSet, maxDistance);
160 
161  registerElement(elementSet, initialS, initialR, initialP);
162 
163  if (errorFlag_m == HITMATERIAL) {
164  // Shouldn't be reached because reference particle
165  // isn't stopped by collimators
167  }
168 
169  imap_m.add(initialS, pathLength_m, elementSet);
170 
171  IndexMap::value_t::const_iterator it = elementSet.begin();
172  const IndexMap::value_t::const_iterator end = elementSet.end();
173  for (; it != end; ++ it) {
174  visitedElements.insert((*it)->getName());
175  }
176 
177  setDesignEnergy(allElements, visitedElements);
178 
179  if (errorFlag_m == EVERYTHINGFINE) {
180  nextR = r_m / (Physics::c * dt_m);
181  integrator_m.push(nextR, p_m, dt_m);
182  nextR *= Physics::c * dt_m;
183 
184  elementSet = itsOpalBeamline_m.getElements(nextR);
185  }
186  } while (errorFlag_m != HITMATERIAL &&
187  errorFlag_m != EOL);
188 
190  *gmsg << level1 << "\n" << imap_m << endl;
191  imap_m.saveSDDS(initialPathLength);
192 
194 }
195 
196 void OrbitThreader::integrate(const IndexMap::value_t &activeSet, double maxDrift) {
197  static size_t step = 0;
199  const double oldPathLength = pathLength_m;
200  Vector_t nextR;
201  do {
203 
204  IndexMap::value_t::const_iterator it = activeSet.begin();
205  const IndexMap::value_t::const_iterator end = activeSet.end();
206  Vector_t oldR = r_m;
207 
208  r_m /= Physics::c * dt_m;
210  r_m *= Physics::c * dt_m;
211 
212  Vector_t Ef(0.0), Bf(0.0);
213  std::string names("\t");
214  for (; it != end; ++ it) {
217  Vector_t localE(0.0), localB(0.0);
218 
219  if ((*it)->applyToReferenceParticle(localR, localP, time_m + 0.5 * dt_m, localE, localB)) {
221  return;
222  }
223  names += (*it)->getName() + ", ";
224 
225  Ef += itsOpalBeamline_m.rotateFromLocalCS(*it, localE);
226  Bf += itsOpalBeamline_m.rotateFromLocalCS(*it, localB);
227  }
228 
229  if (pathLength_m > 0.0 &&
230  pathLength_m < zstop_m &&
231  step % loggingFrequency_m == 0 && Ippl::myNode() == 0 &&
232  !OpalData::getInstance()->isOptimizerRun()) {
233  logger_m << std::setw(18) << std::setprecision(8) << pathLength_m + std::copysign(euclidean_norm(r_m - oldR), dt_m)
234  << std::setw(18) << std::setprecision(8) << r_m(0)
235  << std::setw(18) << std::setprecision(8) << r_m(1)
236  << std::setw(18) << std::setprecision(8) << r_m(2)
237  << std::setw(18) << std::setprecision(8) << p_m(0)
238  << std::setw(18) << std::setprecision(8) << p_m(1)
239  << std::setw(18) << std::setprecision(8) << p_m(2)
240  << std::setw(18) << std::setprecision(8) << Ef(0)
241  << std::setw(18) << std::setprecision(8) << Ef(1)
242  << std::setw(18) << std::setprecision(8) << Ef(2)
243  << std::setw(18) << std::setprecision(8) << Bf(0)
244  << std::setw(18) << std::setprecision(8) << Bf(1)
245  << std::setw(18) << std::setprecision(8) << Bf(2)
246  << std::setw(18) << std::setprecision(8) << reference_m.getM() * (sqrt(dot(p_m, p_m) + 1) - 1) * 1e-6
247  << std::setw(18) << std::setprecision(8) << (time_m + 0.5 * dt_m) * 1e9
248  << names
249  << std::endl;
250  }
251 
252  r_m /= Physics::c * dt_m;
253  integrator_m.kick(r_m, p_m, Ef, Bf, dt_m);
255  r_m *= Physics::c * dt_m;
256 
258  ++ step;
259  time_m += dt_m;
260 
261  nextR = r_m / (Physics::c * dt_m);
262  integrator_m.push(nextR, p_m, dt_m);
263  nextR *= Physics::c * dt_m;
264 
265  if ((activeSet.size() == 0 && std::abs(pathLength_m - oldPathLength) > maxDrift) ||
266  (activeSet.size() > 0 && dt_m * pathLength_m > dt_m * zstop_m) ||
267  (pathLength_m < 0.0 && dt_m < 0.0)) {
268  errorFlag_m = EOL;
269  return;
270  }
271 
272  } while (activeSet == itsOpalBeamline_m.getElements(nextR));
273 }
274 
276  IndexMap::value_t::const_iterator it = activeSet.begin();
277  const IndexMap::value_t::const_iterator end = activeSet.end();
278 
279  for (; it != end; ++ it) {
280  if ((*it)->getType() == ElementBase::TRAVELINGWAVE ||
281  (*it)->getType() == ElementBase::RFCAVITY) {
282  return true;
283  }
284  }
285 
286  return false;
287 }
288 
290  const std::set<std::string> &visitedElements) {
291  if (Options::autoPhase == 0) return;
292 
293  IndexMap::value_t::const_iterator it = activeSet.begin();
294  const IndexMap::value_t::const_iterator end = activeSet.end();
295 
296  for (; it != end; ++ it) {
297  if (((*it)->getType() == ElementBase::TRAVELINGWAVE ||
298  (*it)->getType() == ElementBase::RFCAVITY) &&
299  visitedElements.find((*it)->getName()) == visitedElements.end()) {
300 
303 
304  CavityAutophaser ap(reference_m, *it);
305  ap.getPhaseAtMaxEnergy(initialR,
306  initialP,
307  time_m,
308  dt_m);
309  }
310  }
311 }
312 
313 
315 {
316  IndexMap::value_t::const_iterator it = elementSet.begin();
317  const IndexMap::value_t::const_iterator end = elementSet.end();
318 
319  double designEnergy = 0.0;
320  for (; it != end; ++ it) {
321  if ((*it)->getType() == ElementBase::TRAVELINGWAVE ||
322  (*it)->getType() == ElementBase::RFCAVITY) {
323  const RFCavity *element = static_cast<const RFCavity *>((*it).get());
324  designEnergy = std::max(designEnergy, element->getDesignEnergy());
325  }
326  }
327 
328  return designEnergy;
329 }
330 
332  dt_m *= -1;
333  double initialPathLength = pathLength_m;
334 
335  Vector_t nextR = r_m / (Physics::c * dt_m);
336  integrator_m.push(nextR, p_m, dt_m);
337  nextR *= Physics::c * dt_m;
338 
339  while (std::abs(initialPathLength - pathLength_m) < distTrackBack_m) {
340  auto elementSet = itsOpalBeamline_m.getElements(nextR);
341 
342  double maxDrift = computeDriftLengthToBoundingBox(elementSet, r_m, -p_m);
343  maxDrift = std::min(maxDrift, distTrackBack_m);
344  integrate(elementSet, maxDrift);
345 
346  nextR = r_m / (Physics::c * dt_m);
347  integrator_m.push(nextR, p_m, dt_m);
348  nextR *= Physics::c * dt_m;
349  }
350 
351  dt_m *= -1;
352 }
353 
355  double start,
356  const Vector_t &R,
357  const Vector_t &P) {
358 
359  IndexMap::value_t::const_iterator it = elementSet.begin();
360  const IndexMap::value_t::const_iterator end = elementSet.end();
361 
362  for (; it != end; ++ it) {
363  bool found = false;
364  std::string name = (*it)->getName();
365  auto prior = elementRegistry_m.equal_range(name);
366 
367  for (auto pit = prior.first; pit != prior.second; ++ pit) {
368  if (std::abs((*pit).second.endField_m - start) < 1e-10) {
369  found = true;
370  (*pit).second.endField_m = pathLength_m;
371  break;
372  }
373  }
374 
375  if (found) continue;
376 
378  Vector_t initialP = itsOpalBeamline_m.rotateToLocalCS(*it, P);
379  double elementEdge = start - initialR(2) * euclidean_norm(initialP) / initialP(2);
380 
381  elementPosition ep = {start, pathLength_m, elementEdge};
382  elementRegistry_m.insert(std::make_pair(name, ep));
383  }
384 }
385 
387  std::map<std::string, std::set<elementPosition, elementPositionComp> > tmpRegistry;
388 
389  for (auto it = elementRegistry_m.begin(); it != elementRegistry_m.end(); ++ it) {
390  const std::string &name = (*it).first;
391  elementPosition &ep = (*it).second;
392 
393  auto prior = tmpRegistry.find(name);
394  if (prior == tmpRegistry.end()) {
395  std::set<elementPosition, elementPositionComp> tmpSet;
396  tmpSet.insert(ep);
397  tmpRegistry.insert(std::make_pair(name, tmpSet));
398  continue;
399  }
400 
401  std::set<elementPosition, elementPositionComp> &set = (*prior).second;
402  set.insert(ep);
403  }
404 
406  FieldList::iterator it = allElements.begin();
407  const FieldList::iterator end = allElements.end();
408  for (; it != end; ++ it) {
409  std::string name = (*it).getElement()->getName();
410  auto trit = tmpRegistry.find(name);
411  if (trit == tmpRegistry.end()) continue;
412 
413  std::queue<std::pair<double, double> > range;
414  std::set<elementPosition, elementPositionComp> &set = (*trit).second;
415 
416  for (auto sit = set.begin(); sit != set.end(); ++ sit) {
417  range.push(std::make_pair((*sit).elementEdge_m, (*sit).endField_m));
418  }
419  (*it).getElement()->setActionRange(range);
420  }
421 }
422 
423 void OrbitThreader::setDesignEnergy(FieldList &allElements, const std::set<std::string> &visitedElements) {
424  double kineticEnergyeV = reference_m.getM() * (sqrt(dot(p_m, p_m) + 1.0) - 1.0);
425 
426  FieldList::iterator it = allElements.begin();
427  const FieldList::iterator end = allElements.end();
428  for (; it != end; ++ it) {
429  std::shared_ptr<Component> element = (*it).getElement();
430  if (visitedElements.find(element->getName()) == visitedElements.end() &&
431  !(element->getType() == ElementBase::RFCAVITY ||
432  element->getType() == ElementBase::TRAVELINGWAVE)) {
433 
434  element->setDesignEnergy(kineticEnergyeV);
435  }
436  }
437 }
438 
441  FieldList::iterator it = allElements.begin();
442  const FieldList::iterator end = allElements.end();
443 
446 
447  for (; it != end; ++ it) {
448  if (it->getElement()->getType() == ElementBase::MARKER) {
449  continue;
450  }
451  ElementBase::BoundingBox other = it->getBoundingBoxInLabCoords();
453  }
454 
456 }
457 
458 
463 }
464 
465 double OrbitThreader::computeDriftLengthToBoundingBox(const std::set<std::shared_ptr<Component>> & elements,
466  const Vector_t & position,
467  const Vector_t & direction) const {
468  if (elements.empty() ||
469  (elements.size() == 1 && (*elements.begin())->getType() == ElementBase::ElementType::DRIFT)) {
470  boost::optional<Vector_t> intersectionPoint = globalBoundingBox_m.getPointOfIntersection(position, direction);
471  return intersectionPoint ? euclidean_norm(intersectionPoint.get() - position): 10.0;
472  }
473 
475 }
elements
Definition: IndexMap.cpp:163
#define EOL
#define HITMATERIAL
#define EVERYTHINGFINE
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
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition: Vector3D.cpp:118
std::list< ClassicField > FieldList
Definition: ClassicField.h:42
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:84
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:76
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
PETE_TBTree< FnCopysign, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > copysign(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
Inform & level1(Inform &inf)
Definition: Inform.cpp:45
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
const std::string name
constexpr double e
The value of.
Definition: Physics.h:39
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:51
std::string::iterator iterator
Definition: MSLang.h:16
int autoPhase
Definition: Options.cpp:69
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition: Util.cpp:139
double getGamma(Vector_t p)
Definition: Util.h:27
static OpalData * getInstance()
Definition: OpalData.cpp:195
double getPhaseAtMaxEnergy(const Vector_t &R, const Vector_t &P, double t, double dt)
void add(key_t::first_type initialStep, key_t::second_type finalStep, const value_t &val)
Definition: IndexMap.cpp:113
void tidyUp(double zstop)
Definition: IndexMap.cpp:148
std::set< std::shared_ptr< Component > > value_t
Definition: IndexMap.h:47
void saveSDDS(double startS) const
Definition: IndexMap.cpp:177
void processElementRegister()
void updateBoundingBoxWithCurrentPosition()
double distTrackBack_m
Definition: OrbitThreader.h:66
void setDesignEnergy(FieldList &allElements, const std::set< std::string > &visitedElements)
BorisPusher integrator_m
Definition: OrbitThreader.h:81
IndexMap imap_m
Definition: OrbitThreader.h:77
unsigned int errorFlag_m
Definition: OrbitThreader.h:79
double dt_m
the time step
Definition: OrbitThreader.h:70
double time_m
the simulated time
Definition: OrbitThreader.h:68
OpalBeamline & itsOpalBeamline_m
Definition: OrbitThreader.h:76
std::multimap< std::string, elementPosition > elementRegistry_m
Vector_t r_m
position of reference particle in lab coordinates
Definition: OrbitThreader.h:59
const PartData & reference_m
Definition: OrbitThreader.h:82
std::ofstream logger_m
Definition: OrbitThreader.h:84
Vector_t p_m
momentum of reference particle
Definition: OrbitThreader.h:61
bool containsCavity(const IndexMap::value_t &activeSet)
void integrate(const IndexMap::value_t &activeSet, double maxDrift=10.0)
OrbitThreader(const PartData &ref, const Vector_t &r, const Vector_t &p, double s, double maxDiffZBunch, double t, double dT, StepSizeConfig stepSizes, OpalBeamline &bl)
StepSizeConfig stepSizes_m
final position in path length
Definition: OrbitThreader.h:73
ElementBase::BoundingBox globalBoundingBox_m
Definition: OrbitThreader.h:87
double computeDriftLengthToBoundingBox(const std::set< std::shared_ptr< Component >> &elements, const Vector_t &position, const Vector_t &direction) const
void checkElementLengths(const std::set< std::shared_ptr< Component >> &elements)
double getMaxDesignEnergy(const IndexMap::value_t &elementSet) const
void registerElement(const IndexMap::value_t &elementSet, double, const Vector_t &r, const Vector_t &p)
double pathLength_m
position of reference particle in path length
Definition: OrbitThreader.h:63
void autophaseCavities(const IndexMap::value_t &activeSet, const std::set< std::string > &visitedElements)
void computeBoundingBox()
size_t loggingFrequency_m
Definition: OrbitThreader.h:85
const double zstop_m
Definition: OrbitThreader.h:74
double getdT() const
double getZStop() const
bool reachedEnd() const
static BoundingBox getBoundingBox(const std::vector< Vector_t > &points)
void getCombinedBoundingBox(const BoundingBox &other)
Definition: ElementBase.h:347
boost::optional< Vector_t > getPointOfIntersection(const Vector_t &position, const Vector_t &direction) const
Interface for RF cavity.
Definition: RFCavity.h:37
virtual double getDesignEnergy() const override
Definition: RFCavity.h:348
Particle reference data.
Definition: PartData.h:35
double getM() const
The constant mass per particle.
Definition: PartData.h:109
FieldList getElementByType(ElementBase::ElementType)
Vector_t rotateToLocalCS(const std::shared_ptr< Component > &comp, const Vector_t &r) const
Definition: OpalBeamline.h:178
Vector_t transformToLocalCS(const std::shared_ptr< Component > &comp, const Vector_t &r) const
Definition: OpalBeamline.h:166
Vector_t rotateFromLocalCS(const std::shared_ptr< Component > &comp, const Vector_t &r) const
Definition: OpalBeamline.h:184
CoordinateSystemTrafo getCSTrafoLab2Local(const std::shared_ptr< Component > &comp) const
Definition: OpalBeamline.h:190
std::set< std::shared_ptr< Component > > getElements(const Vector_t &x)
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
The base class for all OPAL exceptions.
Definition: OpalException.h:28
Definition: Inform.h:42
static int myNode()
Definition: IpplInfo.cpp:691
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6