OPAL (Object Oriented Parallel Accelerator Library) 2022.1
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 - 2022 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
24
30#include "BasicActions/Option.h"
32#include "Physics/Units.h"
34#include "Utilities/Options.h"
35#include "Utilities/Util.h"
36
37#include <boost/filesystem.hpp>
38
39#include <cmath>
40#include <iostream>
41#include <limits>
42
43#define HITMATERIAL 0x80000000
44#define EOL 0x40000000
45#define EVERYTHINGFINE 0x00000000
46extern Inform *gmsg;
47
49 const Vector_t &r,
50 const Vector_t &p,
51 double s,
52 double maxDiffZBunch,
53 double t,
54 double dt,
55 StepSizeConfig stepSizes,
56 OpalBeamline &bl) :
57 r_m(r),
58 p_m(p),
59 pathLength_m(s),
60 time_m(t),
61 dt_m(dt),
62 stepSizes_m(stepSizes),
63 zstop_m(stepSizes.getFinalZStop() + std::copysign(1.0, dt) * 2 * maxDiffZBunch),
64 itsOpalBeamline_m(bl),
65 errorFlag_m(0),
66 integrator_m(ref),
67 reference_m(ref)
68{
69 auto opal = OpalData::getInstance();
70 if (Ippl::myNode() == 0 && !opal->isOptimizerRun()) {
71 std::string fileName = Util::combineFilePath({
72 opal->getAuxiliaryOutputDirectory(),
73 opal->getInputBasename() + "_DesignPath.dat"
74 });
75 if (opal->getOpenMode() == OpalData::OpenMode::WRITE ||
76 !boost::filesystem::exists(fileName)) {
77 logger_m.open(fileName);
78 logger_m << "#"
79 << std::setw(17) << "1 - s"
80 << std::setw(18) << "2 - Rx"
81 << std::setw(18) << "3 - Ry"
82 << std::setw(18) << "4 - Rz"
83 << std::setw(18) << "5 - Px"
84 << std::setw(18) << "6 - Py"
85 << std::setw(18) << "7 - Pz"
86 << std::setw(18) << "8 - Efx"
87 << std::setw(18) << "9 - Efy"
88 << std::setw(18) << "10 - Efz"
89 << std::setw(18) << "11 - Bfx"
90 << std::setw(18) << "12 - Bfy"
91 << std::setw(18) << "13 - Bfz"
92 << std::setw(18) << "14 - Ekin"
93 << std::setw(18) << "15 - t"
94 << std::endl;
95 } else {
96 logger_m.open(fileName, std::ios_base::app);
97 }
98
99 loggingFrequency_m = std::max(1.0, std::round(1e-11 / std::abs(dt_m)));
100 } else {
102 }
108 distTrackBack_m = std::min(pathLength_m, std::max(0.0, maxDiffZBunch));
110}
111
112void OrbitThreader::checkElementLengths(const std::set<std::shared_ptr<Component>>& fields) {
114 ++ stepSizes_m;
115 }
116 if (stepSizes_m.reachedEnd()) {
117 return;
118 }
120 for (const std::shared_ptr<Component>& field : fields) {
121 double length = field->getElementLength();
122 int numSteps = field->getRequiredNumberOfTimeSteps();
123
124 if (length < numSteps * driftLength) {
125 throw OpalException("OrbitThreader::checkElementLengths",
126 "The time step is too long compared to the length of the\n"
127 "element '" + field->getName() + "'\n" +
128 "The length of the element is: " + std::to_string(length) + "\n"
129 "The distance the particles drift in " + std::to_string(numSteps) +
130 " time step(s) is: " + std::to_string(numSteps * driftLength));
131 }
132 }
133}
134
136 double initialPathLength = pathLength_m;
137
139 std::set<std::string> visitedElements;
140
141 trackBack();
144
145 Vector_t nextR = r_m / (Physics::c * dt_m);
146 integrator_m.push(nextR, p_m, dt_m);
147 nextR *= Physics::c * dt_m;
148
149 setDesignEnergy(allElements, visitedElements);
150
151 auto elementSet = itsOpalBeamline_m.getElements(nextR);
152 std::set<std::shared_ptr<Component>> intersection, currentSet;
154 do {
155 checkElementLengths(elementSet);
156 if (containsCavity(elementSet)) {
157 autophaseCavities(elementSet, visitedElements);
158 }
159
160 double initialS = pathLength_m;
161 Vector_t initialR = r_m;
162 Vector_t initialP = p_m;
163 double maxDistance = computeDriftLengthToBoundingBox(elementSet, r_m, p_m);
164 integrate(elementSet, maxDistance);
165
166 registerElement(elementSet, initialS, initialR, initialP);
167
168 if (errorFlag_m == HITMATERIAL) {
169 // Shouldn't be reached because reference particle
170 // isn't stopped by collimators
172 }
173
174 imap_m.add(initialS, pathLength_m, elementSet);
175
176 IndexMap::value_t::const_iterator it = elementSet.begin();
177 const IndexMap::value_t::const_iterator end = elementSet.end();
178 for (; it != end; ++ it) {
179 visitedElements.insert((*it)->getName());
180 }
181
182 setDesignEnergy(allElements, visitedElements);
183
184 currentSet = elementSet;
186 nextR = r_m / (Physics::c * dt_m);
187 integrator_m.push(nextR, p_m, dt_m);
188 nextR *= Physics::c * dt_m;
189
190 elementSet = itsOpalBeamline_m.getElements(nextR);
191 }
192 intersection.clear();
193 std::set_intersection(currentSet.begin(), currentSet.end(),
194 elementSet.begin(), elementSet.end(),
195 std::inserter(intersection, intersection.begin()));
196 } while (errorFlag_m != HITMATERIAL &&
197 errorFlag_m != EOL &&
200 intersection.empty() && !(elementSet.empty() || currentSet.empty())));
201
203 *gmsg << level1 << "\n" << imap_m << endl;
204 imap_m.saveSDDS(initialPathLength);
205
207}
208
209void OrbitThreader::integrate(const IndexMap::value_t &activeSet, double /*maxDrift*/) {
211 Vector_t nextR;
212 do {
214
215 IndexMap::value_t::const_iterator it = activeSet.begin();
216 const IndexMap::value_t::const_iterator end = activeSet.end();
217 Vector_t oldR = r_m;
218
219 r_m /= Physics::c * dt_m;
221 r_m *= Physics::c * dt_m;
222
223 Vector_t Ef(0.0), Bf(0.0);
224 std::string names("\t");
225 for (; it != end; ++ it) {
228 Vector_t localE(0.0), localB(0.0);
229
230 if ((*it)->applyToReferenceParticle(localR, localP, time_m + 0.5 * dt_m, localE, localB)) {
232 return;
233 }
234 names += (*it)->getName() + ", ";
235
236 Ef += itsOpalBeamline_m.rotateFromLocalCS(*it, localE);
237 Bf += itsOpalBeamline_m.rotateFromLocalCS(*it, localB);
238 }
239
240 if (((pathLength_m > 0.0 &&
241 pathLength_m < zstop_m) || dt_m < 0.0) &&
243 !OpalData::getInstance()->isOptimizerRun()) {
244 logger_m << std::setw(18) << std::setprecision(8) << pathLength_m + std::copysign(euclidean_norm(r_m - oldR), dt_m)
245 << std::setw(18) << std::setprecision(8) << r_m(0)
246 << std::setw(18) << std::setprecision(8) << r_m(1)
247 << std::setw(18) << std::setprecision(8) << r_m(2)
248 << std::setw(18) << std::setprecision(8) << p_m(0)
249 << std::setw(18) << std::setprecision(8) << p_m(1)
250 << std::setw(18) << std::setprecision(8) << p_m(2)
251 << std::setw(18) << std::setprecision(8) << Ef(0)
252 << std::setw(18) << std::setprecision(8) << Ef(1)
253 << std::setw(18) << std::setprecision(8) << Ef(2)
254 << std::setw(18) << std::setprecision(8) << Bf(0)
255 << std::setw(18) << std::setprecision(8) << Bf(1)
256 << std::setw(18) << std::setprecision(8) << Bf(2)
257 << std::setw(18) << std::setprecision(8) << reference_m.getM() * (sqrt(dot(p_m, p_m) + 1) - 1) * Units::eV2MeV
258 << std::setw(18) << std::setprecision(8) << (time_m + 0.5 * dt_m) * Units::s2ns
259 << names
260 << std::endl;
261 }
262
263 r_m /= Physics::c * dt_m;
264 integrator_m.kick(r_m, p_m, Ef, Bf, dt_m);
266 r_m *= Physics::c * dt_m;
267
269 ++ currentStep_m;
270 time_m += dt_m;
271
272 nextR = r_m / (Physics::c * dt_m);
273 integrator_m.push(nextR, p_m, dt_m);
274 nextR *= Physics::c * dt_m;
275
276 if (activeSet.empty() &&
281 return;
282 }
283
284 } while (activeSet == itsOpalBeamline_m.getElements(nextR));
285}
286
288 IndexMap::value_t::const_iterator it = activeSet.begin();
289 const IndexMap::value_t::const_iterator end = activeSet.end();
290
291 for (; it != end; ++ it) {
292 if ((*it)->getType() == ElementType::TRAVELINGWAVE ||
293 (*it)->getType() == ElementType::RFCAVITY) {
294 return true;
295 }
296 }
297
298 return false;
299}
300
302 const std::set<std::string> &visitedElements) {
303 if (Options::autoPhase == 0) return;
304
305 IndexMap::value_t::const_iterator it = activeSet.begin();
306 const IndexMap::value_t::const_iterator end = activeSet.end();
307
308 for (; it != end; ++ it) {
309 if (((*it)->getType() == ElementType::TRAVELINGWAVE ||
310 (*it)->getType() == ElementType::RFCAVITY) &&
311 visitedElements.find((*it)->getName()) == visitedElements.end()) {
312
315
317 ap.getPhaseAtMaxEnergy(initialR,
318 initialP,
319 time_m,
320 dt_m);
321 }
322 }
323}
324
325
327{
328 IndexMap::value_t::const_iterator it = elementSet.begin();
329 const IndexMap::value_t::const_iterator end = elementSet.end();
330
331 double designEnergy = 0.0;
332 for (; it != end; ++ it) {
333 if ((*it)->getType() == ElementType::TRAVELINGWAVE ||
334 (*it)->getType() == ElementType::RFCAVITY) {
335 const RFCavity *element = static_cast<const RFCavity *>((*it).get());
336 designEnergy = std::max(designEnergy, element->getDesignEnergy());
337 }
338 }
339
340 return designEnergy;
341}
342
344 dt_m *= -1;
345 ValueRange<double> tmpRange;
346 std::swap(tmpRange, pathLengthRange_m);
347 double initialPathLength = pathLength_m;
348
349 Vector_t nextR = r_m / (Physics::c * dt_m);
350 integrator_m.push(nextR, p_m, dt_m);
351 nextR *= Physics::c * dt_m;
352
353 while (std::abs(initialPathLength - pathLength_m) < distTrackBack_m) {
354 auto elementSet = itsOpalBeamline_m.getElements(nextR);
355
356 double maxDrift = computeDriftLengthToBoundingBox(elementSet, r_m, -p_m);
357 maxDrift = std::min(maxDrift, distTrackBack_m);
358 integrate(elementSet, maxDrift);
359
360 nextR = r_m / (Physics::c * dt_m);
361 integrator_m.push(nextR, p_m, dt_m);
362 nextR *= Physics::c * dt_m;
363 }
364 std::swap(tmpRange, pathLengthRange_m);
365 currentStep_m *= -1;
366 dt_m *= -1;
367
369}
370
372 double start,
373 const Vector_t &R,
374 const Vector_t &P) {
375
376 IndexMap::value_t::const_iterator it = elementSet.begin();
377 const IndexMap::value_t::const_iterator end = elementSet.end();
378
379 for (; it != end; ++ it) {
380 bool found = false;
381 std::string name = (*it)->getName();
382 auto prior = elementRegistry_m.equal_range(name);
383
384 for (auto pit = prior.first; pit != prior.second; ++ pit) {
385 if (std::abs((*pit).second.endField_m - start) < 1e-10) {
386 found = true;
387 (*pit).second.endField_m = pathLength_m;
388 break;
389 }
390 }
391
392 if (found) continue;
393
395 Vector_t initialP = itsOpalBeamline_m.rotateToLocalCS(*it, P);
396 double elementEdge = start - initialR(2) * euclidean_norm(initialP) / initialP(2);
397
398 elementPosition ep = {start, pathLength_m, elementEdge};
399 elementRegistry_m.insert(std::make_pair(name, ep));
400 }
401}
402
404 std::map<std::string, std::set<elementPosition, elementPositionComp> > tmpRegistry;
405
406 for (auto it = elementRegistry_m.begin(); it != elementRegistry_m.end(); ++ it) {
407 const std::string &name = (*it).first;
408 elementPosition &ep = (*it).second;
409
410 auto prior = tmpRegistry.find(name);
411 if (prior == tmpRegistry.end()) {
412 std::set<elementPosition, elementPositionComp> tmpSet;
413 tmpSet.insert(ep);
414 tmpRegistry.insert(std::make_pair(name, tmpSet));
415 continue;
416 }
417
418 std::set<elementPosition, elementPositionComp> &set = (*prior).second;
419 set.insert(ep);
420 }
421
423 FieldList::iterator it = allElements.begin();
424 const FieldList::iterator end = allElements.end();
425 for (; it != end; ++ it) {
426 std::string name = (*it).getElement()->getName();
427 auto trit = tmpRegistry.find(name);
428 if (trit == tmpRegistry.end()) continue;
429
430 std::queue<std::pair<double, double> > range;
431 std::set<elementPosition, elementPositionComp> &set = (*trit).second;
432
433 for (auto sit = set.begin(); sit != set.end(); ++ sit) {
434 range.push(std::make_pair((*sit).elementEdge_m, (*sit).endField_m));
435 }
436 (*it).getElement()->setActionRange(range);
437 }
438}
439
440void OrbitThreader::setDesignEnergy(FieldList &allElements, const std::set<std::string> &visitedElements) {
441 double kineticEnergyeV = reference_m.getM() * (sqrt(dot(p_m, p_m) + 1.0) - 1.0);
442
443 FieldList::iterator it = allElements.begin();
444 const FieldList::iterator end = allElements.end();
445 for (; it != end; ++ it) {
446 std::shared_ptr<Component> element = (*it).getElement();
447 if (visitedElements.find(element->getName()) == visitedElements.end() &&
448 !(element->getType() == ElementType::RFCAVITY ||
449 element->getType() == ElementType::TRAVELINGWAVE)) {
450
451 element->setDesignEnergy(kineticEnergyeV);
452 }
453 }
454}
455
458 FieldList::iterator it = allElements.begin();
459 const FieldList::iterator end = allElements.end();
460
461 for (; it != end; ++ it) {
462 if (it->getElement()->getType() == ElementType::MARKER) {
463 continue;
464 }
465 BoundingBox other = it->getBoundingBoxInLabCoords();
467 }
468
470}
471
472
475 for (const Vector_t& pos : {r_m - 10 * dR, r_m + 10 * dR}) {
477 }
478}
479
480double OrbitThreader::computeDriftLengthToBoundingBox(const std::set<std::shared_ptr<Component>> & elements,
481 const Vector_t & position,
482 const Vector_t & direction) const {
483 if (elements.empty() ||
484 (elements.size() == 1 && (*elements.begin())->getType() == ElementType::DRIFT)) {
485 boost::optional<Vector_t> intersectionPoint = globalBoundingBox_m.getIntersectionPoint(position, direction);
486
487 return intersectionPoint ? euclidean_norm(intersectionPoint.get() - position): 10.0;
488 }
489
491}
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition: Vector3D.cpp:118
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
std::list< ClassicField > FieldList
Definition: ClassicField.h:43
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
elements
Definition: IndexMap.cpp:163
#define EOL
#define HITMATERIAL
#define EVERYTHINGFINE
Inform * gmsg
Definition: Main.cpp:61
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_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)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
Inform & level1(Inform &inf)
Definition: Inform.cpp:45
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:45
constexpr double eV2MeV
Definition: Units.h:77
constexpr double s2ns
Definition: Units.h:44
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:196
double getGamma(Vector_t p)
Definition: Util.h:45
static OpalData * getInstance()
Definition: OpalData.cpp:196
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()
void checkElementLengths(const std::set< std::shared_ptr< Component > > &elements)
double distTrackBack_m
Definition: OrbitThreader.h:70
void setDesignEnergy(FieldList &allElements, const std::set< std::string > &visitedElements)
BorisPusher integrator_m
Definition: OrbitThreader.h:88
ValueRange< double > pathLengthRange_m
Definition: OrbitThreader.h:81
IndexMap imap_m
Definition: OrbitThreader.h:84
ValueRange< long > stepRange_m
Definition: OrbitThreader.h:75
unsigned int errorFlag_m
Definition: OrbitThreader.h:86
double dt_m
the time step
Definition: OrbitThreader.h:74
double time_m
the simulated time
Definition: OrbitThreader.h:72
OpalBeamline & itsOpalBeamline_m
Definition: OrbitThreader.h:83
double computeDriftLengthToBoundingBox(const std::set< std::shared_ptr< Component > > &elements, const Vector_t &position, const Vector_t &direction) const
std::multimap< std::string, elementPosition > elementRegistry_m
Vector_t r_m
position of reference particle in lab coordinates
Definition: OrbitThreader.h:63
const PartData & reference_m
Definition: OrbitThreader.h:89
std::ofstream logger_m
Definition: OrbitThreader.h:91
BoundingBox globalBoundingBox_m
Definition: OrbitThreader.h:94
Vector_t p_m
momentum of reference particle
Definition: OrbitThreader.h:65
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:79
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:67
void autophaseCavities(const IndexMap::value_t &activeSet, const std::set< std::string > &visitedElements)
void computeBoundingBox()
size_t loggingFrequency_m
Definition: OrbitThreader.h:92
const double zstop_m
Definition: OrbitThreader.h:80
double getdT() const
unsigned long long getNumStepsFinestResolution() const
double getZStop() const
bool reachedEnd() const
ValueRange< double > getPathLengthRange() const
virtual double getDesignEnergy() const override
Definition: RFCavity.h:340
Particle reference data.
Definition: PartData.h:35
double getM() const
The constant mass per particle.
Definition: PartData.h:109
boost::optional< Vector_t > getIntersectionPoint(const Vector_t &position, const Vector_t &direction) const
Definition: BoundingBox.cpp:57
void enlargeToContainBoundingBox(const BoundingBox &boundingBox)
Definition: BoundingBox.cpp:49
void enlargeToContainPosition(const Vector_t &position)
Definition: BoundingBox.cpp:41
bool isOutside(T value) const
Definition: ValueRange.h:46
void enlargeIfOutside(T value)
Definition: ValueRange.h:36
bool isInside(T value) const
Definition: ValueRange.h:41
FieldList getElementByType(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