OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
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
24#include "Physics/Physics.h"
27
28#include <cmath>
29#include <exception>
30#include <regex>
31#include <sstream>
32#include <vector>
33
34OpalElement::OpalElement(int size, const char* name, const char* help)
35 : Element(size, name, help), itsSize(size) {
37 "TYPE", "The element design type.",
38 {"RING", "CARBONCYCL", "CYCIAE", "AVFEQ", "FFA", "BANDRF", "SYNCHROCYCLOTRON",
39 "SINGLEGAP", "STANDING", "TEMPORAL", "SPATIAL"});
40
41 itsAttr[LENGTH] = Attributes::makeReal("L", "The element length in m");
42
44 Attributes::makeReal("ELEMEDGE", "The position of the element in path length (in m)");
45
46 itsAttr[APERT] = Attributes::makeString("APERTURE", "The element aperture");
47
48 itsAttr[WAKEF] = Attributes::makeString("WAKEF", "Defines the wake function");
49
51 "PARTICLEMATTERINTERACTION", "Defines the particle mater interaction handler");
52
53 itsAttr[ORIGIN] = Attributes::makeRealArray("ORIGIN", "The location of the element");
54
56 "ORIENTATION", "The Tait-Bryan angles for the orientation of the element");
57
58 itsAttr[X] = Attributes::makeReal("X", "The x-coordinate of the location of the element", 0);
59
60 itsAttr[Y] = Attributes::makeReal("Y", "The y-coordinate of the location of the element", 0);
61
62 itsAttr[Z] = Attributes::makeReal("Z", "The z-coordinate of the location of the element", 0);
63
64 itsAttr[THETA] =
65 Attributes::makeReal("THETA", "The rotation about the y-axis of the element", 0);
66
67 itsAttr[PHI] = Attributes::makeReal("PHI", "The rotation about the x-axis of the element", 0);
68
69 itsAttr[PSI] = Attributes::makeReal("PSI", "The rotation about the z-axis of the element", 0);
70
71 itsAttr[DX] = Attributes::makeReal("DX", "Misalignment in x direction", 0.0);
72
73 itsAttr[DY] = Attributes::makeReal("DY", "Misalignment in y direction", 0.0);
74
75 itsAttr[DZ] = Attributes::makeReal("DZ", "Misalignment in z direction", 0.0);
76
78 Attributes::makeReal("DTHETA", "Misalignment in theta (Tait-Bryan angles)", 0.0);
79
80 itsAttr[DPHI] = Attributes::makeReal("DPHI", "Misalignment in theta (Tait-Bryan angles)", 0.0);
81
82 itsAttr[DPSI] = Attributes::makeReal("DPSI", "Misalignment in theta (Tait-Bryan angles)", 0.0);
83
84 itsAttr[OUTFN] = Attributes::makeString("OUTFN", "Output filename");
85
87 "DELETEONTRANSVERSEEXIT",
88 "Flag controlling if particles should be deleted if they exit "
89 "the element transversally",
90 true);
91
92 const unsigned int end = COMMON;
93 for (unsigned int i = 0; i < end; ++i) {
95 }
96}
97
98OpalElement::OpalElement(const std::string& name, OpalElement* parent)
99 : Element(name, parent), itsSize(parent->itsSize) {}
100
102
103std::pair<ApertureType, std::vector<double>> OpalElement::getApert() const {
104 std::pair<ApertureType, std::vector<double>> retvalue(
105 ApertureType::ELLIPTICAL, std::vector<double>({0.5, 0.5, 1.0}));
106 if (!itsAttr[APERT]) {
107 return retvalue;
108 }
109
110 std::string aperture = Attributes::getString(itsAttr[APERT]);
111
112 std::regex square("square *\\((.*)\\)", std::regex::icase);
113 std::regex rectangle("rectangle *\\((.*)\\)", std::regex::icase);
114 std::regex circle("circle *\\((.*)\\)", std::regex::icase);
115 std::regex ellipse("ellipse *\\((.*)\\)", std::regex::icase);
116
117 std::regex twoArguments("^\\s*([^,]+)\\s*,\\s*([^,]+)\\s*$");
118 std::regex threeArguments("^\\s*([^,]+)\\s*,\\s*([^,]+)\\s*,\\s*([^,]+)\\s*$");
119
120 std::smatch match;
121
122 const double width2HalfWidth = 0.5;
123
124 auto validateConicScale = [&](double scale, const std::string& arguments) {
125 if (!(scale > 0.0)) {
126 throw OpalException(
127 "OpalElement::getApert()", "invalid conic aperture scale in '" + arguments
128 + "': expected positive real value");
129 }
130 };
131
132 if (std::regex_search(aperture, match, square)) {
133 std::string arguments = match[1];
134 if (!std::regex_search(arguments, match, twoArguments)) {
135 retvalue.first = ApertureType::RECTANGULAR;
136
137 try {
138 retvalue.second[0] = width2HalfWidth * std::stod(arguments);
139 retvalue.second[1] = retvalue.second[0];
140 } catch (const std::exception& ex) {
141 throw OpalException(
142 "OpalElement::getApert()",
143 "could not convert '" + arguments + "' to double");
144 }
145
146 } else {
147 retvalue.first = ApertureType::CONIC_RECTANGULAR;
148
149 try {
150 retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
151 retvalue.second[1] = retvalue.second[0];
152 retvalue.second[2] = std::stod(match[2]);
153 } catch (const std::exception& ex) {
154 throw OpalException(
155 "OpalElement::getApert()",
156 "could not convert '" + arguments + "' to doubles");
157 }
158 validateConicScale(retvalue.second[2], arguments);
159 }
160
161 return retvalue;
162 }
163
164 if (std::regex_search(aperture, match, rectangle)) {
165 std::string arguments = match[1];
166
167 if (!std::regex_search(arguments, match, threeArguments)) {
168 retvalue.first = ApertureType::RECTANGULAR;
169
170 try {
171 size_t sz = 0;
172
173 retvalue.second[0] = width2HalfWidth * std::stod(arguments, &sz);
174 sz = arguments.find_first_of(",", sz) + 1;
175 retvalue.second[1] = width2HalfWidth * std::stod(arguments.substr(sz));
176
177 } catch (const std::exception& ex) {
178 throw OpalException(
179 "OpalElement::getApert()",
180 "could not convert '" + arguments + "' to doubles");
181 }
182
183 } else {
184 retvalue.first = ApertureType::CONIC_RECTANGULAR;
185
186 try {
187 retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
188 retvalue.second[1] = width2HalfWidth * std::stod(match[2]);
189 retvalue.second[2] = std::stod(match[3]);
190 } catch (const std::exception& ex) {
191 throw OpalException(
192 "OpalElement::getApert()",
193 "could not convert '" + arguments + "' to doubles");
194 }
195 validateConicScale(retvalue.second[2], arguments);
196 }
197
198 return retvalue;
199 }
200
201 if (std::regex_search(aperture, match, circle)) {
202 std::string arguments = match[1];
203 if (!std::regex_search(arguments, match, twoArguments)) {
204 retvalue.first = ApertureType::ELLIPTICAL;
205
206 try {
207 retvalue.second[0] = width2HalfWidth * std::stod(arguments);
208 retvalue.second[1] = retvalue.second[0];
209 } catch (const std::exception& ex) {
210 throw OpalException(
211 "OpalElement::getApert()",
212 "could not convert '" + arguments + "' to double");
213 }
214
215 } else {
216 retvalue.first = ApertureType::CONIC_ELLIPTICAL;
217
218 try {
219 retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
220 retvalue.second[1] = retvalue.second[0];
221 retvalue.second[2] = std::stod(match[2]);
222 } catch (const std::exception& ex) {
223 throw OpalException(
224 "OpalElement::getApert()",
225 "could not convert '" + arguments + "' to doubles");
226 }
227 validateConicScale(retvalue.second[2], arguments);
228 }
229
230 return retvalue;
231 }
232
233 if (std::regex_search(aperture, match, ellipse)) {
234 std::string arguments = match[1];
235
236 if (!std::regex_search(arguments, match, threeArguments)) {
237 retvalue.first = ApertureType::ELLIPTICAL;
238
239 try {
240 size_t sz = 0;
241
242 retvalue.second[0] = width2HalfWidth * std::stod(arguments, &sz);
243 sz = arguments.find_first_of(",", sz) + 1;
244 retvalue.second[1] = width2HalfWidth * std::stod(arguments.substr(sz));
245
246 } catch (const std::exception& ex) {
247 throw OpalException(
248 "OpalElement::getApert()",
249 "could not convert '" + arguments + "' to doubles");
250 }
251
252 } else {
253 retvalue.first = ApertureType::CONIC_ELLIPTICAL;
254
255 try {
256 retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
257 retvalue.second[1] = width2HalfWidth * std::stod(match[2]);
258 retvalue.second[2] = std::stod(match[3]);
259 } catch (const std::exception& ex) {
260 throw OpalException(
261 "OpalElement::getApert()",
262 "could not convert '" + arguments + "' to doubles");
263 }
264 validateConicScale(retvalue.second[2], arguments);
265 }
266
267 return retvalue;
268 }
269
270 if (!aperture.empty()) {
271 throw OpalException("OpalElement::getApert()", "Unknown aperture type '" + aperture + "'.");
272 }
273
274 return retvalue;
275}
276
278
279const std::string OpalElement::getTypeName() const {
280 const Attribute* attr = findAttribute("TYPE");
281 return attr ? Attributes::getString(*attr) : std::string();
282}
283
287const std::string OpalElement::getWakeF() const {
288 const Attribute* attr = findAttribute("WAKEF");
289 return attr ? Attributes::getString(*attr) : std::string();
290}
291
293 const Attribute* attr = findAttribute("PARTICLEMATTERINTERACTION");
294 return attr ? Attributes::getString(*attr) : std::string();
295}
296
298 while (stat.delimiter(',')) {
299 std::string name = Expressions::parseString(stat, "Attribute name expected.");
300 Attribute* attr = findAttribute(name);
301
302 if (attr == 0) {
303 throw OpalException("OpalElement::parse", "unknown attribute \"" + name + "\"");
304 }
305
306 if (stat.delimiter('[')) {
307 int index = int(std::round(Expressions::parseRealConst(stat)));
309
310 if (stat.delimiter('=')) {
311 attr->parseComponent(stat, true, index);
312 } else if (stat.delimiter(":=")) {
313 attr->parseComponent(stat, false, index);
314 } else {
315 throw ParseError("OpalElement::parse()", "Delimiter \"=\" or \":=\" expected.");
316 }
317 } else {
318 if (stat.delimiter('=')) {
319 attr->parse(stat, true);
320 } else if (stat.delimiter(":=")) {
321 attr->parse(stat, false);
322 } else {
323 attr->setDefault();
324 }
325 }
326 }
327}
328
329void OpalElement::print(std::ostream& os) const {
330 std::string head = getOpalName();
331
332 Object* parent = getParent();
333 if (parent != 0 && !parent->getOpalName().empty()) {
334 if (!getOpalName().empty()) head += ':';
335 head += parent->getOpalName();
336 }
337
338 os << head;
339 os << ';';
340 os << std::endl;
341}
342
344 std::ostream& os, int order, int& len, const std::string& sName, const std::string& tName,
345 const Attribute& length, const Attribute& sNorm, const Attribute& sSkew) {
346 // Find out which type of output is required.
347 int flag = 0;
348 if (sNorm) {
349 if (sNorm.getBase().isExpression()) {
350 flag += 2;
351 } else if (Attributes::getReal(sNorm) != 0.0) {
352 flag += 1;
353 }
354 }
355
356 if (sSkew) {
357 if (sSkew.getBase().isExpression()) {
358 flag += 6;
359 } else if (Attributes::getReal(sSkew) != 0.0) {
360 flag += 3;
361 }
362 }
363 // Now do the output.
364 int div = 2 * (order + 1);
365
366 switch (flag) {
367 case 0:
368 // No component at all.
369 break;
370
371 case 1:
372 case 2:
373 // Pure normal component.
374 {
375 std::string normImage = sNorm.getImage();
376 if (length) {
377 normImage = "(" + normImage + ")*(" + length.getImage() + ")";
378 }
379 printAttribute(os, sName, normImage, len);
380 }
381 break;
382
383 case 3:
384 case 6:
385 // Pure skew component.
386 {
387 std::string skewImage = sSkew.getImage();
388 if (length) {
389 skewImage = "(" + skewImage + ")*(" + length.getImage() + ")";
390 }
391 printAttribute(os, sName, skewImage, len);
392 double tilt = Physics::pi / double(div);
393 printAttribute(os, tName, tilt, len);
394 }
395 break;
396
397 case 4:
398 // Both components are non-zero constants.
399 {
400 double sn = Attributes::getReal(sNorm);
401 double ss = Attributes::getReal(sSkew);
402 double strength = std::sqrt(sn * sn + ss * ss);
403 if (strength) {
404 std::ostringstream ts;
405 ts << strength;
406 std::string image = ts.str();
407 if (length) {
408 image = "(" + image + ")*(" + length.getImage() + ")";
409 }
410 printAttribute(os, sName, image, len);
411 double tilt = -std::atan2(ss, sn) / double(div);
412 if (tilt) printAttribute(os, tName, tilt, len);
413 }
414 }
415 break;
416
417 case 5:
418 case 7:
419 case 8:
420 // One or both components is/are expressions.
421 {
422 std::string normImage = sNorm.getImage();
423 std::string skewImage = sSkew.getImage();
424 std::string image = "SQRT((" + normImage + ")^2+(" + skewImage + ")^2)";
425 printAttribute(os, sName, image, len);
426 if (length) {
427 image = "(" + image + ")*(" + length.getImage() + ")";
428 }
429 std::string divisor;
430 if (div < 9) {
431 divisor = "0";
432 divisor[0] += div;
433 } else {
434 divisor = "00";
435 divisor[0] += div / 10;
436 divisor[1] += div % 10;
437 }
438 image = "-ATAN2(" + skewImage + ',' + normImage + ")/" + divisor;
439 printAttribute(os, tName, image, len);
440 break;
441 }
442 }
443}
444
446 ElementBase* base = getElement();
447
448 auto apert = getApert();
449 base->setAperture(apert.first, apert.second);
450
452 std::vector<double> ori = Attributes::getRealArray(itsAttr[ORIGIN]);
453 std::vector<double> dir = Attributes::getRealArray(itsAttr[ORIENTATION]);
454 Vector_t<double, 3> origin(0.0);
455 Quaternion rotation;
456
457 if (dir.size() == 3) {
458 Quaternion rotTheta(std::cos(0.5 * dir[0]), 0, std::sin(0.5 * dir[0]), 0);
459 Quaternion rotPhi(std::cos(0.5 * dir[1]), std::sin(0.5 * dir[1]), 0, 0);
460 Quaternion rotPsi(std::cos(0.5 * dir[2]), 0, 0, std::sin(0.5 * dir[2]));
461 rotation = rotTheta * (rotPhi * rotPsi);
462 } else {
463 if (itsAttr[ORIENTATION]) {
464 throw OpalException(
465 "OpalElement::update",
466 "Parameter orientation is array of 3 values (theta, phi, psi);\n"
467 + std::to_string(dir.size()) + " values provided");
468 }
469 }
470
471 if (ori.size() == 3) {
472 origin = Vector_t<double, 3>(ori[0], ori[1], ori[2]);
473 } else {
474 if (itsAttr[ORIGIN]) {
475 throw OpalException(
476 "OpalElement::update", "Parameter origin is array of 3 values (x, y, z);\n"
477 + std::to_string(ori.size())
478 + " values provided");
479 }
480 }
481
482 CoordinateSystemTrafo global2local(origin, rotation.conjugate());
483 base->setCSTrafoGlobal2Local(global2local);
484 base->fixPosition();
485
486 } else if (
487 !itsAttr[PSI].defaultUsed() && itsAttr[X].defaultUsed() && itsAttr[Y].defaultUsed()
488 && itsAttr[Z].defaultUsed() && itsAttr[THETA].defaultUsed()
489 && itsAttr[PHI].defaultUsed()) {
491 } else if (
492 !itsAttr[X].defaultUsed() || !itsAttr[Y].defaultUsed() || !itsAttr[Z].defaultUsed()
493 || !itsAttr[THETA].defaultUsed() || !itsAttr[PHI].defaultUsed()
494 || !itsAttr[PSI].defaultUsed()) {
495 const Vector_t<double, 3> origin(
498
499 const double theta = Attributes::getReal(itsAttr[THETA]);
500 const double phi = Attributes::getReal(itsAttr[PHI]);
501 const double psi = Attributes::getReal(itsAttr[PSI]);
502
503 Quaternion rotTheta(std::cos(0.5 * theta), 0, std::sin(0.5 * theta), 0);
504 Quaternion rotPhi(std::cos(0.5 * phi), std::sin(0.5 * phi), 0, 0);
505 Quaternion rotPsi(std::cos(0.5 * psi), 0, 0, std::sin(0.5 * psi));
506 Quaternion rotation = rotTheta * (rotPhi * rotPsi);
507
508 CoordinateSystemTrafo global2local(origin, rotation.conjugate());
509 base->setCSTrafoGlobal2Local(global2local);
510 base->fixPosition();
512 }
513
514 Vector_t<double, 3> misalignmentShift(
517 double dtheta = Attributes::getReal(itsAttr[DTHETA]);
518 double dphi = Attributes::getReal(itsAttr[DPHI]);
519 double dpsi = Attributes::getReal(itsAttr[DPSI]);
520 Quaternion rotationY(std::cos(0.5 * dtheta), 0, std::sin(0.5 * dtheta), 0);
521 Quaternion rotationX(std::cos(0.5 * dphi), std::sin(0.5 * dphi), 0, 0);
522 Quaternion rotationZ(std::cos(0.5 * dpsi), 0, 0, std::sin(0.5 * dpsi));
523 Quaternion misalignmentRotation = rotationY * rotationX * rotationZ;
524 CoordinateSystemTrafo misalignment(misalignmentShift, misalignmentRotation.conjugate());
525
526 base->setMisalignment(misalignment);
527
529
531}
532
534 for (std::vector<Attribute>::size_type i = itsSize; i < itsAttr.size(); ++i) {
535 Attribute& attr = itsAttr[i];
536 base->setAttribute(attr.getName(), Attributes::getReal(attr));
537 }
538}
539
541 std::ostream& os, const std::string& name, const std::string& image, int& len) {
542 len += name.length() + image.length() + 2;
543 if (len > 74) {
544 os << ",&\n ";
545 len = name.length() + image.length() + 3;
546 } else {
547 os << ',';
548 }
549 os << name << '=' << image;
550}
551
553 std::ostream& os, const std::string& name, double value, int& len) {
554 std::ostringstream ss;
555 ss << value << std::ends;
556 printAttribute(os, name, ss.str(), len);
557}
558
560 if (getParent() != 0) return;
561
562 const unsigned int end = itsSize;
563 const std::string name = getOpalName();
564 for (unsigned int i = COMMON; i < end; ++i) {
566 }
567}
ippl::Vector< T, Dim > Vector_t
virtual bool isExpression() const
Test for expression.
static void addAttributeOwner(const std::string &owner, const OwnerType &type, const std::string &name)
A representation of an Object attribute.
Definition Attribute.h:52
AttributeBase & getBase() const
Return reference to polymorphic value.
Definition Attribute.cpp:52
const std::string & getName() const
Return the attribute name.
Definition Attribute.cpp:62
void setDefault()
Assign default value.
Definition Attribute.cpp:91
void parse(Statement &stat, bool eval)
Parse attribute.
Definition Attribute.cpp:76
void parseComponent(Statement &stat, bool eval, int index)
Parse array component.
Definition Attribute.cpp:81
std::string getImage() const
Return printable representation.
Definition Attribute.cpp:60
Rigid spatial transform between a parent frame and a local frame.
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)
ElementBase * getElement() const
Return the embedded OPALX element.
Definition Element.h:119
The base class for all OPAL objects.
Definition Object.h:45
Object * getParent() const
Return parent pointer.
Definition Object.cpp:269
const std::string & getOpalName() const
Return object name.
Definition Object.cpp:267
virtual Attribute * findAttribute(const std::string &name)
Find an attribute by name.
Definition Object.cpp:56
std::vector< Attribute > itsAttr
The object attributes.
Definition Object.h:210
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
const std::string getWakeF() const
Return the element's type name.
virtual void updateUnknown(ElementBase *)
Transmit the `‘unknown’' (not known to OPALX) attributes to OPALX.
@ DELETEONTRANSVERSEEXIT
Definition OpalElement.h:56
@ PARTICLEMATTERINTERACTION
Definition OpalElement.h:40
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 OPALX element.
void registerOwnership() const
Parse exception.
Definition ParseError.h:31
Quaternion storage and rotation algebra used by OPALX geometry code.
Quaternion conjugate() const
Return the quaternion conjugate .
Interface for statements.
Definition Statement.h:37
bool delimiter(char c)
Test for delimiter.
Definition Statement.cpp:83
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.
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.
constexpr double pi
The value of.
Definition Physics.h:36