OPALX (Object Oriented Parallel Accelerator Library for Exascal) MINIorX
OPALX
OpalElement.cpp
Go to the documentation of this file.
1//
2// Class OpalElement
3// Base class for all beam line elements.
4//
5// Copyright (c) 200x - 2020, Paul Scherrer Institut, Villigen PSI, Switzerland
6// All rights reserved
7//
8// This file is part of OPAL.
9//
10// OPAL is free software: you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// You should have received a copy of the GNU General Public License
16// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
17//
19
25#include "Physics/Physics.h"
27#include "Utilities/Options.h"
29#include "Utilities/Util.h"
30
31#include <boost/regex.hpp>
32
33#include <cmath>
34#include <cctype>
35#include <sstream>
36#include <vector>
37
38
39OpalElement::OpalElement(int size, const char* name, const char* help):
40 Element(size, name, help), itsSize(size) {
42 ("TYPE", "The element design type.",
43 {"RING",
44 "CARBONCYCL",
45 "CYCIAE",
46 "AVFEQ",
47 "FFA",
48 "BANDRF",
49 "SYNCHROCYCLOTRON",
50 "SINGLEGAP",
51 "STANDING",
52 "TEMPORAL",
53 "SPATIAL"});
54
56 ("L", "The element length in m");
57
59 ("ELEMEDGE", "The position of the element in path length (in m)");
60
62 ("APERTURE", "The element aperture");
63
65 ("WAKEF", "Defines the wake function");
66
68 ("PARTICLEMATTERINTERACTION", "Defines the particle mater interaction handler");
69
71 ("ORIGIN", "The location of the element");
72
74 ("ORIENTATION", "The Tait-Bryan angles for the orientation of the element");
75
77 ("X", "The x-coordinate of the location of the element", 0);
78
80 ("Y", "The y-coordinate of the location of the element", 0);
81
83 ("Z", "The z-coordinate of the location of the element", 0);
84
86 ("THETA", "The rotation about the y-axis of the element", 0);
87
89 ("PHI", "The rotation about the x-axis of the element", 0);
90
92 ("PSI", "The rotation about the z-axis of the element", 0);
93
95 ("DX", "Misalignment in x direction",0.0);
96
98 ("DY", "Misalignment in y direction",0.0);
99
101 ("DZ", "Misalignment in z direction",0.0);
102
104 ("DTHETA", "Misalignment in theta (Tait-Bryan angles)",0.0);
105
107 ("DPHI", "Misalignment in theta (Tait-Bryan angles)",0.0);
108
110 ("DPSI", "Misalignment in theta (Tait-Bryan angles)",0.0);
111
113 ("OUTFN", "Output filename");
114
116 ("DELETEONTRANSVERSEEXIT", "Flag controlling if particles should be deleted if they exit "
117 "the element transversally", true);
118
119 const unsigned int end = COMMON;
120 for (unsigned int i = 0; i < end; ++ i) {
122 }
123}
124
125
126OpalElement::OpalElement(const std::string& name, OpalElement* parent):
127 Element(name, parent), itsSize(parent->itsSize)
128{}
129
130
133
134
135std::pair<ApertureType, std::vector<double> > OpalElement::getApert() const {
136
137 std::pair<ApertureType, std::vector<double> > retvalue(ApertureType::ELLIPTICAL,
138 std::vector<double>({0.5, 0.5, 1.0}));
139 if (!itsAttr[APERT]) return retvalue;
140
141 std::string aperture = Attributes::getString(itsAttr[APERT]);
142
143 boost::regex square("square *\\((.*)\\)", boost::regex::icase);
144 boost::regex rectangle("rectangle *\\((.*)\\)", boost::regex::icase);
145 boost::regex circle("circle *\\((.*)\\)", boost::regex::icase);
146 boost::regex ellipse("ellipse *\\((.*)\\)", boost::regex::icase);
147
148 boost::regex twoArguments("([^,]*),([^,]*)");
149 boost::regex threeArguments("([^,]*),([^,]*),([^,]*)");
150
151 boost::smatch match;
152
153 const double width2HalfWidth = 0.5;
154
155 if (boost::regex_search(aperture, match, square)) {
156 std::string arguments = match[1];
157 if (!boost::regex_search(arguments, match, twoArguments)) {
158 retvalue.first = ApertureType::RECTANGULAR;
159
160 try {
161 retvalue.second[0] = width2HalfWidth * std::stod(arguments);
162 retvalue.second[1] = retvalue.second[0];
163 } catch (const std::exception &ex) {
164 throw OpalException("OpalElement::getApert()",
165 "could not convert '" + arguments + "' to double");
166 }
167
168 } else {
169 retvalue.first = ApertureType::CONIC_RECTANGULAR;
170
171 try {
172 retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
173 retvalue.second[1] = retvalue.second[0];
174 retvalue.second[2] = std::stod(match[2]);
175 } catch (const std::exception &ex) {
176 throw OpalException("OpalElement::getApert()",
177 "could not convert '" + arguments + "' to doubles");
178 }
179 }
180
181 return retvalue;
182 }
183
184 if (boost::regex_search(aperture, match, rectangle)) {
185 std::string arguments = match[1];
186
187 if (!boost::regex_search(arguments, match, threeArguments)) {
188 retvalue.first = ApertureType::RECTANGULAR;
189
190 try {
191 size_t sz = 0;
192
193 retvalue.second[0] = width2HalfWidth * std::stod(arguments, &sz);
194 sz = arguments.find_first_of(",", sz) + 1;
195 retvalue.second[1] = width2HalfWidth * std::stod(arguments.substr(sz));
196
197 } catch (const std::exception &ex) {
198 throw OpalException("OpalElement::getApert()",
199 "could not convert '" + arguments + "' to doubles");
200 }
201
202 } else {
203 retvalue.first = ApertureType::CONIC_RECTANGULAR;
204
205 try {
206 retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
207 retvalue.second[1] = width2HalfWidth * std::stod(match[2]);
208 retvalue.second[2] = std::stod(match[3]);
209 } catch (const std::exception &ex) {
210 throw OpalException("OpalElement::getApert()",
211 "could not convert '" + arguments + "' to doubles");
212 }
213 }
214
215 return retvalue;
216 }
217
218 if (boost::regex_search(aperture, match, circle)) {
219 std::string arguments = match[1];
220 if (!boost::regex_search(arguments, match, twoArguments)) {
221 retvalue.first = ApertureType::ELLIPTICAL;
222
223 try {
224 retvalue.second[0] = width2HalfWidth * std::stod(arguments);
225 retvalue.second[1] = retvalue.second[0];
226 } catch (const std::exception &ex) {
227 throw OpalException("OpalElement::getApert()",
228 "could not convert '" + arguments + "' to double");
229 }
230
231 } else {
232 retvalue.first = ApertureType::CONIC_ELLIPTICAL;
233
234 try {
235 retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
236 retvalue.second[1] = retvalue.second[0];
237 retvalue.second[2] = std::stod(match[2]);
238 } catch (const std::exception &ex) {
239 throw OpalException("OpalElement::getApert()",
240 "could not convert '" + arguments + "' to doubles");
241 }
242 }
243
244 return retvalue;
245 }
246
247 if (boost::regex_search(aperture, match, ellipse)) {
248 std::string arguments = match[1];
249
250 if (!boost::regex_search(arguments, match, threeArguments)) {
251 retvalue.first = ApertureType::ELLIPTICAL;
252
253 try {
254 size_t sz = 0;
255
256 retvalue.second[0] = width2HalfWidth * std::stod(arguments, &sz);
257 sz = arguments.find_first_of(",", sz) + 1;
258 retvalue.second[1] = width2HalfWidth * std::stod(arguments.substr(sz));
259
260 } catch (const std::exception &ex) {
261 throw OpalException("OpalElement::getApert()",
262 "could not convert '" + arguments + "' to doubles");
263 }
264
265 } else {
266 retvalue.first = ApertureType::CONIC_ELLIPTICAL;
267
268 try {
269 retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
270 retvalue.second[1] = width2HalfWidth * std::stod(match[2]);
271 retvalue.second[2] = std::stod(match[3]);
272 } catch (const std::exception &ex) {
273 throw OpalException("OpalElement::getApert()",
274 "could not convert '" + arguments + "' to doubles");
275 }
276 }
277
278 return retvalue;
279 }
280
281 if (!aperture.empty()) {
282 throw OpalException("OpalElement::getApert()",
283 "Unknown aperture type '" + aperture + "'.");
284 }
285
286 return retvalue;
287}
288
291}
292
293
294const std::string OpalElement::getTypeName() const {
295 const Attribute* attr = findAttribute("TYPE");
296 return attr ? Attributes::getString(*attr) : std::string();
297}
298
302const std::string OpalElement::getWakeF() const {
303 const Attribute* attr = findAttribute("WAKEF");
304 return attr ? Attributes::getString(*attr) : std::string();
305}
306
308 const Attribute* attr = findAttribute("PARTICLEMATTERINTERACTION");
309 return attr ? Attributes::getString(*attr) : std::string();
310}
311
313 while (stat.delimiter(',')) {
314 std::string name = Expressions::parseString(stat, "Attribute name expected.");
315 Attribute *attr = findAttribute(name);
316
317 if (attr == 0) {
318 throw OpalException("OpalElement::parse",
319 "unknown attribute \"" + name + "\"");
320 }
321
322 if (stat.delimiter('[')) {
323 int index = int(std::round(Expressions::parseRealConst(stat)));
325
326 if (stat.delimiter('=')) {
327 attr->parseComponent(stat, true, index);
328 } else if (stat.delimiter(":=")) {
329 attr->parseComponent(stat, false, index);
330 } else {
331 throw ParseError("OpalElement::parse()",
332 "Delimiter \"=\" or \":=\" expected.");
333 }
334 } else {
335 if (stat.delimiter('=')) {
336 attr->parse(stat, true);
337 } else if (stat.delimiter(":=")) {
338 attr->parse(stat, false);
339 } else {
340 attr->setDefault();
341 }
342 }
343 }
344}
345
346
347void OpalElement::print(std::ostream& os) const {
348 std::string head = getOpalName();
349
350 Object* parent = getParent();
351 if (parent != 0 && ! parent->getOpalName().empty()) {
352 if (! getOpalName().empty()) head += ':';
353 head += parent->getOpalName();
354 }
355
356 os << head;
357 os << ';'; // << "JMJdebug OPALElement.cc" ;
358 os << std::endl;
359}
360
361
363 int order, int& len,
364 const std::string& sName,
365 const std::string& tName,
366 const Attribute& length,
367 const Attribute& sNorm,
368 const Attribute& sSkew) {
369 // Find out which type of output is required.
370 int flag = 0;
371 if (sNorm) {
372 if (sNorm.getBase().isExpression()) {
373 flag += 2;
374 } else if (Attributes::getReal(sNorm) != 0.0) {
375 flag += 1;
376 }
377 }
378
379 if (sSkew) {
380 if (sSkew.getBase().isExpression()) {
381 flag += 6;
382 } else if (Attributes::getReal(sSkew) != 0.0) {
383 flag += 3;
384 }
385 }
386 // cout << "JMJdebug, OpalElement.cc: flag=" << flag << endl ;
387 // Now do the output.
388 int div = 2 * (order + 1);
389
390 switch (flag) {
391
392 case 0:
393 // No component at all.
394 break;
395
396 case 1:
397 case 2:
398 // Pure normal component.
399 {
400 std::string normImage = sNorm.getImage();
401 if (length) {
402 normImage = "(" + normImage + ")*(" + length.getImage() + ")";
403 }
404 printAttribute(os, sName, normImage, len);
405 }
406 break;
407
408 case 3:
409 case 6:
410 // Pure skew component.
411 {
412 std::string skewImage = sSkew.getImage();
413 if (length) {
414 skewImage = "(" + skewImage + ")*(" + length.getImage() + ")";
415 }
416 printAttribute(os, sName, skewImage, len);
417 double tilt = Physics::pi / double(div);
418 printAttribute(os, tName, tilt, len);
419 }
420 break;
421
422 case 4:
423 // Both components are non-zero constants.
424 {
425 double sn = Attributes::getReal(sNorm);
426 double ss = Attributes::getReal(sSkew);
427 double strength = std::sqrt(sn * sn + ss * ss);
428 if (strength) {
429 std::ostringstream ts;
430 ts << strength;
431 std::string image = ts.str();
432 if (length) {
433 image = "(" + image + ")*(" + length.getImage() + ")";
434 }
435 printAttribute(os, sName, image, len);
436 double tilt = - std::atan2(ss, sn) / double(div);
437 if (tilt) printAttribute(os, tName, tilt, len);
438 }
439 }
440 break;
441
442 case 5:
443 case 7:
444 case 8:
445 // One or both components is/are expressions.
446 {
447 std::string normImage = sNorm.getImage();
448 std::string skewImage = sSkew.getImage();
449 std::string image =
450 "SQRT((" + normImage + ")^2+(" + skewImage + ")^2)";
451 printAttribute(os, sName, image, len);
452 if (length) {
453 image = "(" + image + ")*(" + length.getImage() + ")";
454 }
455 std::string divisor;
456 if (div < 9) {
457 divisor = "0";
458 divisor[0] += div;
459 } else {
460 divisor = "00";
461 divisor[0] += div / 10;
462 divisor[1] += div % 10;
463 }
464 image = "-ATAN2(" + skewImage + ',' + normImage + ")/" + divisor;
465 printAttribute(os, tName, image, len);
466 break;
467 }
468 }
469}
470
472 ElementBase* base = getElement();
473
474 auto apert = getApert();
475 base->setAperture(apert.first, apert.second);
476
478 std::vector<double> ori = Attributes::getRealArray(itsAttr[ORIGIN]);
479 std::vector<double> dir = Attributes::getRealArray(itsAttr[ORIENTATION]);
480 Vector_t<double, 3> origin(0.0);
481 Quaternion rotation;
482
483 if (dir.size() == 3) {
484 Quaternion rotTheta(std::cos(0.5 * dir[0]), 0, std::sin(0.5 * dir[0]), 0);
485 Quaternion rotPhi(std::cos(0.5 * dir[1]), std::sin(0.5 * dir[1]), 0, 0);
486 Quaternion rotPsi(std::cos(0.5 * dir[2]), 0, 0, std::sin(0.5 * dir[2]));
487 rotation = rotTheta * (rotPhi * rotPsi);
488 } else {
489 if (itsAttr[ORIENTATION]) {
490 throw OpalException("OpalElement::update",
491 "Parameter orientation is array of 3 values (theta, phi, psi);\n" +
492 std::to_string(dir.size()) + " values provided");
493 }
494 }
495
496 if (ori.size() == 3) {
497 origin = Vector_t<double, 3>(ori[0], ori[1], ori[2]);
498 } else {
499 if (itsAttr[ORIGIN]) {
500 throw OpalException("OpalElement::update",
501 "Parameter origin is array of 3 values (x, y, z);\n" +
502 std::to_string(ori.size()) + " values provided");
503 }
504 }
505
506 CoordinateSystemTrafo global2local(origin,
507 rotation.conjugate());
508 base->setCSTrafoGlobal2Local(global2local);
509 base->fixPosition();
510
511 } else if (!itsAttr[PSI].defaultUsed() &&
512 itsAttr[X].defaultUsed() &&
513 itsAttr[Y].defaultUsed() &&
514 itsAttr[Z].defaultUsed() &&
515 itsAttr[THETA].defaultUsed() &&
516 itsAttr[PHI].defaultUsed()) {
518 } else if (!itsAttr[X].defaultUsed() ||
519 !itsAttr[Y].defaultUsed() ||
520 !itsAttr[Z].defaultUsed() ||
521 !itsAttr[THETA].defaultUsed() ||
522 !itsAttr[PHI].defaultUsed() ||
523 !itsAttr[PSI].defaultUsed()) {
527
528 const double theta = Attributes::getReal(itsAttr[THETA]);
529 const double phi = Attributes::getReal(itsAttr[PHI]);
530 const double psi = Attributes::getReal(itsAttr[PSI]);
531
532 Quaternion rotTheta(std::cos(0.5 * theta), 0, std::sin(0.5 * theta), 0);
533 Quaternion rotPhi(std::cos(0.5 * phi), std::sin(0.5 * phi), 0, 0);
534 Quaternion rotPsi(std::cos(0.5 * psi), 0, 0, std::sin(0.5 * psi));
535 Quaternion rotation = rotTheta * (rotPhi * rotPsi);
536
537 CoordinateSystemTrafo global2local(origin,
538 rotation.conjugate());
539 base->setCSTrafoGlobal2Local(global2local);
540 base->fixPosition();
542 }
543
547 double dtheta = Attributes::getReal(itsAttr[DTHETA]);
548 double dphi = Attributes::getReal(itsAttr[DPHI]);
549 double dpsi = Attributes::getReal(itsAttr[DPSI]);
550 Quaternion rotationY(std::cos(0.5 * dtheta), 0, std::sin(0.5 * dtheta), 0);
551 Quaternion rotationX(std::cos(0.5 * dphi), std::sin(0.5 * dphi), 0, 0);
552 Quaternion rotationZ(std::cos(0.5 * dpsi), 0, 0, std::sin(0.5 * dpsi));
553 Quaternion misalignmentRotation = rotationY * rotationX * rotationZ;
554 CoordinateSystemTrafo misalignment(misalignmentShift,
555 misalignmentRotation.conjugate());
556
557 base->setMisalignment(misalignment);
558
559 if (itsAttr[ELEMEDGE])
561
563}
564
566 for (std::vector<Attribute>::size_type i = itsSize;
567 i < itsAttr.size(); ++i) {
568 Attribute &attr = itsAttr[i];
569 base->setAttribute(attr.getName(), Attributes::getReal(attr));
570
571 }
572}
573
574void OpalElement::printAttribute(std::ostream& os, const std::string& name,
575 const std::string& image, int& len) {
576 len += name.length() + image.length() + 2;
577 if (len > 74) {
578 os << ",&\n ";
579 len = name.length() + image.length() + 3;
580 } else {
581 os << ',';
582 }
583 os << name << '=' << image;
584}
585
587(std::ostream &os, const std::string &name, double value, int &len) {
588 std::ostringstream ss;
589 ss << value << std::ends;
590 printAttribute(os, name, ss.str(), len);
591}
592
593
595 if (getParent() != 0) return;
596
597 const unsigned int end = itsSize;
598 const std::string name = getOpalName();
599 for (unsigned int i = COMMON; i < end; ++ i) {
601 }
602}
ippl::Vector< T, Dim > Vector_t
PartBunch< T, Dim >::ConstIterator end(PartBunch< T, Dim > const &bunch)
std::string parseString(Statement &, const char msg[])
Parse string value.
void parseDelimiter(Statement &stat, char delim)
Test for one-character delimiter.
double parseRealConst(Statement &)
Parse real constant.
Attribute makeBool(const std::string &name, const std::string &help)
Make logical attribute.
double getReal(const Attribute &attr)
Return real value.
Attribute makePredefinedString(const std::string &name, const std::string &help, const std::initializer_list< std::string > &predefinedStrings)
Make predefined string attribute.
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
bool getBool(const Attribute &attr)
Return logical value.
Attribute makeRealArray(const std::string &name, const std::string &help)
Create real array attribute.
std::vector< double > getRealArray(const Attribute &attr)
Get array value.
std::string getString(const Attribute &attr)
Get string value.
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.
constexpr double pi
The value of.
Definition Physics.h:30
void setElementPosition(double elemedge)
Access to ELEMEDGE attribute.
void fixPosition()
void setAperture(const ApertureType &type, const std::vector< double > &args)
void setMisalignment(const CoordinateSystemTrafo &cst)
virtual void setAttribute(const std::string &aKey, double val)
Set value of an attribute.
void setFlagDeleteOnTransverseExit(bool=true)
void setRotationAboutZ(double rotation)
Set rotation about z axis in bend frame.
void setCSTrafoGlobal2Local(const CoordinateSystemTrafo &ori)
A representation of an Object attribute.
Definition Attribute.h:52
AttributeBase & getBase() const
Return reference to polymorphic value.
Definition Attribute.cpp:69
const std::string & getName() const
Return the attribute name.
Definition Attribute.cpp:92
void setDefault()
Assign default value.
void parse(Statement &stat, bool eval)
Parse attribute.
void parseComponent(Statement &stat, bool eval, int index)
Parse array component.
std::string getImage() const
Return printable representation.
Definition Attribute.cpp:87
virtual bool isExpression() const
Test for expression.
static void addAttributeOwner(const std::string &owner, const OwnerType &type, const std::string &name)
ElementBase * getElement() const
Return the embedded CLASSIC element.
Definition Element.h:121
Element(int size, const char *name, const char *help)
Constructor for exemplars.
Definition Element.cpp:107
Object * getParent() const
Return parent pointer.
Definition Object.cpp:313
const std::string & getOpalName() const
Return object name.
Definition Object.cpp:308
Object(int size, const char *name, const char *help)
Constructor for exemplars.
Definition Object.cpp:354
virtual Attribute * findAttribute(const std::string &name)
Find an attribute by name.
Definition Object.cpp:64
std::vector< Attribute > itsAttr
The object attributes.
Definition Object.h:216
Quaternion conjugate() const
std::pair< ApertureType, std::vector< double > > getApert() const
static void printMultipoleStrength(std::ostream &os, int order, int &len, const std::string &sName, const std::string &tName, const Attribute &length, const Attribute &vNorm, const Attribute &vSkew)
Print multipole components in OPAL-8 format.
virtual double getLength() const
Return element length.
static void printAttribute(std::ostream &os, const std::string &name, const std::string &image, int &len)
Print an attribute with a OPAL-8 name (as an expression).
virtual void parse(Statement &)
Parse the element.
const std::string getParticleMatterInteraction() const
@ DELETEONTRANSVERSEEXIT
Definition OpalElement.h:55
@ PARTICLEMATTERINTERACTION
Definition OpalElement.h:39
const std::string getWakeF() const
Return the element's type name.
virtual void updateUnknown(ElementBase *)
Transmit the ``unknown'' (not known to OPAL) attributes to CLASSIC.
const std::string getTypeName() const
Return the element's type name.
virtual void print(std::ostream &) const
Print the object.
virtual ~OpalElement()
virtual void update()
Update the embedded CLASSIC element.
OpalElement(int size, const char *name, const char *help)
Exemplar constructor.
void registerOwnership() const
Interface for statements.
Definition Statement.h:38
bool delimiter(char c)
Test for delimiter.
The base class for all OPAL exceptions.
Parse exception.
Definition ParseError.h:32