OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
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
20#include "AbsBeamline/Bend2D.h"
25#include "Parser/Statement.h"
26#include "Physics/Physics.h"
28#include "Utilities/Options.h"
30#include "Utilities/Util.h"
31
32#include <boost/regex.hpp>
33
34#include <cmath>
35#include <cctype>
36#include <sstream>
37#include <vector>
38
39
40OpalElement::OpalElement(int size, const char* name, const char* help):
41 Element(size, name, help), itsSize(size) {
43 ("TYPE", "The element design type.",
44 {"RING",
45 "CARBONCYCL",
46 "CYCIAE",
47 "AVFEQ",
48 "FFA",
49 "BANDRF",
50 "SYNCHROCYCLOTRON",
51 "SINGLEGAP",
52 "STANDING",
53 "TEMPORAL",
54 "SPATIAL"});
55
57 ("L", "The element length in m");
58
60 ("ELEMEDGE", "The position of the element in path length (in m)");
61
63 ("APERTURE", "The element aperture");
64
66 ("WAKEF", "Defines the wake function");
67
69 ("PARTICLEMATTERINTERACTION", "Defines the particle mater interaction handler");
70
72 ("ORIGIN", "The location of the element");
73
75 ("ORIENTATION", "The Tait-Bryan angles for the orientation of the element");
76
78 ("X", "The x-coordinate of the location of the element", 0);
79
81 ("Y", "The y-coordinate of the location of the element", 0);
82
84 ("Z", "The z-coordinate of the location of the element", 0);
85
87 ("THETA", "The rotation about the y-axis of the element", 0);
88
90 ("PHI", "The rotation about the x-axis of the element", 0);
91
93 ("PSI", "The rotation about the z-axis of the element", 0);
94
96 ("DX", "Misalignment in x direction",0.0);
97
99 ("DY", "Misalignment in y direction",0.0);
100
102 ("DZ", "Misalignment in z direction",0.0);
103
105 ("DTHETA", "Misalignment in theta (Tait-Bryan angles)",0.0);
106
108 ("DPHI", "Misalignment in theta (Tait-Bryan angles)",0.0);
109
111 ("DPSI", "Misalignment in theta (Tait-Bryan angles)",0.0);
112
114 ("OUTFN", "Output filename");
115
117 ("DELETEONTRANSVERSEEXIT", "Flag controlling if particles should be deleted if they exit "
118 "the element transversally", true);
119
120 const unsigned int end = COMMON;
121 for (unsigned int i = 0; i < end; ++ i) {
123 }
124}
125
126
127OpalElement::OpalElement(const std::string& name, OpalElement* parent):
128 Element(name, parent), itsSize(parent->itsSize)
129{}
130
131
133{}
134
135
136std::pair<ApertureType, std::vector<double> > OpalElement::getApert() const {
137
138 std::pair<ApertureType, std::vector<double> > retvalue(ApertureType::ELLIPTICAL,
139 std::vector<double>({0.5, 0.5, 1.0}));
140 if (!itsAttr[APERT]) return retvalue;
141
142 std::string aperture = Attributes::getString(itsAttr[APERT]);
143
144 boost::regex square("square *\\((.*)\\)", boost::regex::icase);
145 boost::regex rectangle("rectangle *\\((.*)\\)", boost::regex::icase);
146 boost::regex circle("circle *\\((.*)\\)", boost::regex::icase);
147 boost::regex ellipse("ellipse *\\((.*)\\)", boost::regex::icase);
148
149 boost::regex twoArguments("([^,]*),([^,]*)");
150 boost::regex threeArguments("([^,]*),([^,]*),([^,]*)");
151
152 boost::smatch match;
153
154 const double width2HalfWidth = 0.5;
155
156 if (boost::regex_search(aperture, match, square)) {
157 std::string arguments = match[1];
158 if (!boost::regex_search(arguments, match, twoArguments)) {
159 retvalue.first = ApertureType::RECTANGULAR;
160
161 try {
162 retvalue.second[0] = width2HalfWidth * std::stod(arguments);
163 retvalue.second[1] = retvalue.second[0];
164 } catch (const std::exception &ex) {
165 throw OpalException("OpalElement::getApert()",
166 "could not convert '" + arguments + "' to double");
167 }
168
169 } else {
170 retvalue.first = ApertureType::CONIC_RECTANGULAR;
171
172 try {
173 retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
174 retvalue.second[1] = retvalue.second[0];
175 retvalue.second[2] = std::stod(match[2]);
176 } catch (const std::exception &ex) {
177 throw OpalException("OpalElement::getApert()",
178 "could not convert '" + arguments + "' to doubles");
179 }
180 }
181
182 return retvalue;
183 }
184
185 if (boost::regex_search(aperture, match, rectangle)) {
186 std::string arguments = match[1];
187
188 if (!boost::regex_search(arguments, match, threeArguments)) {
189 retvalue.first = ApertureType::RECTANGULAR;
190
191 try {
192 size_t sz = 0;
193
194 retvalue.second[0] = width2HalfWidth * std::stod(arguments, &sz);
195 sz = arguments.find_first_of(",", sz) + 1;
196 retvalue.second[1] = width2HalfWidth * std::stod(arguments.substr(sz));
197
198 } catch (const std::exception &ex) {
199 throw OpalException("OpalElement::getApert()",
200 "could not convert '" + arguments + "' to doubles");
201 }
202
203 } else {
204 retvalue.first = ApertureType::CONIC_RECTANGULAR;
205
206 try {
207 retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
208 retvalue.second[1] = width2HalfWidth * std::stod(match[2]);
209 retvalue.second[2] = std::stod(match[3]);
210 } catch (const std::exception &ex) {
211 throw OpalException("OpalElement::getApert()",
212 "could not convert '" + arguments + "' to doubles");
213 }
214 }
215
216 return retvalue;
217 }
218
219 if (boost::regex_search(aperture, match, circle)) {
220 std::string arguments = match[1];
221 if (!boost::regex_search(arguments, match, twoArguments)) {
222 retvalue.first = ApertureType::ELLIPTICAL;
223
224 try {
225 retvalue.second[0] = width2HalfWidth * std::stod(arguments);
226 retvalue.second[1] = retvalue.second[0];
227 } catch (const std::exception &ex) {
228 throw OpalException("OpalElement::getApert()",
229 "could not convert '" + arguments + "' to double");
230 }
231
232 } else {
233 retvalue.first = ApertureType::CONIC_ELLIPTICAL;
234
235 try {
236 retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
237 retvalue.second[1] = retvalue.second[0];
238 retvalue.second[2] = std::stod(match[2]);
239 } catch (const std::exception &ex) {
240 throw OpalException("OpalElement::getApert()",
241 "could not convert '" + arguments + "' to doubles");
242 }
243 }
244
245 return retvalue;
246 }
247
248 if (boost::regex_search(aperture, match, ellipse)) {
249 std::string arguments = match[1];
250
251 if (!boost::regex_search(arguments, match, threeArguments)) {
252 retvalue.first = ApertureType::ELLIPTICAL;
253
254 try {
255 size_t sz = 0;
256
257 retvalue.second[0] = width2HalfWidth * std::stod(arguments, &sz);
258 sz = arguments.find_first_of(",", sz) + 1;
259 retvalue.second[1] = width2HalfWidth * std::stod(arguments.substr(sz));
260
261 } catch (const std::exception &ex) {
262 throw OpalException("OpalElement::getApert()",
263 "could not convert '" + arguments + "' to doubles");
264 }
265
266 } else {
267 retvalue.first = ApertureType::CONIC_ELLIPTICAL;
268
269 try {
270 retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
271 retvalue.second[1] = width2HalfWidth * std::stod(match[2]);
272 retvalue.second[2] = std::stod(match[3]);
273 } catch (const std::exception &ex) {
274 throw OpalException("OpalElement::getApert()",
275 "could not convert '" + arguments + "' to doubles");
276 }
277 }
278
279 return retvalue;
280 }
281
282 if (!aperture.empty()) {
283 throw OpalException("OpalElement::getApert()",
284 "Unknown aperture type '" + aperture + "'.");
285 }
286
287 return retvalue;
288}
289
292}
293
294
295const std::string OpalElement::getTypeName() const {
296 const Attribute* attr = findAttribute("TYPE");
297 return attr ? Attributes::getString(*attr) : std::string();
298}
299
303const std::string OpalElement::getWakeF() const {
304 const Attribute* attr = findAttribute("WAKEF");
305 return attr ? Attributes::getString(*attr) : std::string();
306}
307
309 const Attribute* attr = findAttribute("PARTICLEMATTERINTERACTION");
310 return attr ? Attributes::getString(*attr) : std::string();
311}
312
314 while (stat.delimiter(',')) {
315 std::string name = Expressions::parseString(stat, "Attribute name expected.");
317
318 if (attr == 0) {
319 throw OpalException("OpalElement::parse",
320 "unknown attribute \"" + name + "\"");
321 }
322
323 if (stat.delimiter('[')) {
324 int index = int(std::round(Expressions::parseRealConst(stat)));
326
327 if (stat.delimiter('=')) {
328 attr->parseComponent(stat, true, index);
329 } else if (stat.delimiter(":=")) {
330 attr->parseComponent(stat, false, index);
331 } else {
332 throw ParseError("OpalElement::parse()",
333 "Delimiter \"=\" or \":=\" expected.");
334 }
335 } else {
336 if (stat.delimiter('=')) {
337 attr->parse(stat, true);
338 } else if (stat.delimiter(":=")) {
339 attr->parse(stat, false);
340 } else {
341 attr->setDefault();
342 }
343 }
344 }
345}
346
347
348void OpalElement::print(std::ostream& os) const {
349 std::string head = getOpalName();
350
351 Object* parent = getParent();
352 if (parent != 0 && ! parent->getOpalName().empty()) {
353 if (! getOpalName().empty()) head += ':';
354 head += parent->getOpalName();
355 }
356
357 os << head;
358 os << ';'; // << "JMJdebug OPALElement.cc" ;
359 os << std::endl;
360}
361
362
364 int order, int& len,
365 const std::string& sName,
366 const std::string& tName,
367 const Attribute& length,
368 const Attribute& sNorm,
369 const Attribute& sSkew) {
370 // Find out which type of output is required.
371 int flag = 0;
372 if (sNorm) {
373 if (sNorm.getBase().isExpression()) {
374 flag += 2;
375 } else if (Attributes::getReal(sNorm) != 0.0) {
376 flag += 1;
377 }
378 }
379
380 if (sSkew) {
381 if (sSkew.getBase().isExpression()) {
382 flag += 6;
383 } else if (Attributes::getReal(sSkew) != 0.0) {
384 flag += 3;
385 }
386 }
387 // cout << "JMJdebug, OpalElement.cc: flag=" << flag << endl ;
388 // Now do the output.
389 int div = 2 * (order + 1);
390
391 switch (flag) {
392
393 case 0:
394 // No component at all.
395 break;
396
397 case 1:
398 case 2:
399 // Pure normal component.
400 {
401 std::string normImage = sNorm.getImage();
402 if (length) {
403 normImage = "(" + normImage + ")*(" + length.getImage() + ")";
404 }
405 printAttribute(os, sName, normImage, len);
406 }
407 break;
408
409 case 3:
410 case 6:
411 // Pure skew component.
412 {
413 std::string skewImage = sSkew.getImage();
414 if (length) {
415 skewImage = "(" + skewImage + ")*(" + length.getImage() + ")";
416 }
417 printAttribute(os, sName, skewImage, len);
418 double tilt = Physics::pi / double(div);
419 printAttribute(os, tName, tilt, len);
420 }
421 break;
422
423 case 4:
424 // Both components are non-zero constants.
425 {
426 double sn = Attributes::getReal(sNorm);
427 double ss = Attributes::getReal(sSkew);
428 double strength = std::sqrt(sn * sn + ss * ss);
429 if (strength) {
430 std::ostringstream ts;
431 ts << strength;
432 std::string image = ts.str();
433 if (length) {
434 image = "(" + image + ")*(" + length.getImage() + ")";
435 }
436 printAttribute(os, sName, image, len);
437 double tilt = - std::atan2(ss, sn) / double(div);
438 if (tilt) printAttribute(os, tName, tilt, len);
439 }
440 }
441 break;
442
443 case 5:
444 case 7:
445 case 8:
446 // One or both components is/are expressions.
447 {
448 std::string normImage = sNorm.getImage();
449 std::string skewImage = sSkew.getImage();
450 std::string image =
451 "SQRT((" + normImage + ")^2+(" + skewImage + ")^2)";
452 printAttribute(os, sName, image, len);
453 if (length) {
454 image = "(" + image + ")*(" + length.getImage() + ")";
455 }
456 std::string divisor;
457 if (div < 9) {
458 divisor = "0";
459 divisor[0] += div;
460 } else {
461 divisor = "00";
462 divisor[0] += div / 10;
463 divisor[1] += div % 10;
464 }
465 image = "-ATAN2(" + skewImage + ',' + normImage + ")/" + divisor;
466 printAttribute(os, tName, image, len);
467 break;
468 }
469 }
470}
471
473 ElementBase* base = getElement();
474
475 auto apert = getApert();
476 base->setAperture(apert.first, apert.second);
477
479 std::vector<double> ori = Attributes::getRealArray(itsAttr[ORIGIN]);
480 std::vector<double> dir = Attributes::getRealArray(itsAttr[ORIENTATION]);
481 Vector_t origin(0.0);
482 Quaternion rotation;
483
484 if (dir.size() == 3) {
485 Quaternion rotTheta(std::cos(0.5 * dir[0]), 0, std::sin(0.5 * dir[0]), 0);
486 Quaternion rotPhi(std::cos(0.5 * dir[1]), std::sin(0.5 * dir[1]), 0, 0);
487 Quaternion rotPsi(std::cos(0.5 * dir[2]), 0, 0, std::sin(0.5 * dir[2]));
488 rotation = rotTheta * (rotPhi * rotPsi);
489 } else {
490 if (itsAttr[ORIENTATION]) {
491 throw OpalException("OpalElement::update",
492 "Parameter orientation is array of 3 values (theta, phi, psi);\n" +
493 std::to_string(dir.size()) + " values provided");
494 }
495 }
496
497 if (ori.size() == 3) {
498 origin = Vector_t(ori[0], ori[1], ori[2]);
499 } else {
500 if (itsAttr[ORIGIN]) {
501 throw OpalException("OpalElement::update",
502 "Parameter origin is array of 3 values (x, y, z);\n" +
503 std::to_string(ori.size()) + " values provided");
504 }
505 }
506
507 CoordinateSystemTrafo global2local(origin,
508 rotation.conjugate());
509 base->setCSTrafoGlobal2Local(global2local);
510 base->fixPosition();
511
512 } else if (!itsAttr[PSI].defaultUsed() &&
513 itsAttr[X].defaultUsed() &&
514 itsAttr[Y].defaultUsed() &&
515 itsAttr[Z].defaultUsed() &&
516 itsAttr[THETA].defaultUsed() &&
517 itsAttr[PHI].defaultUsed()) {
519 } else if (!itsAttr[X].defaultUsed() ||
520 !itsAttr[Y].defaultUsed() ||
521 !itsAttr[Z].defaultUsed() ||
522 !itsAttr[THETA].defaultUsed() ||
523 !itsAttr[PHI].defaultUsed() ||
524 !itsAttr[PSI].defaultUsed()) {
525 const Vector_t origin(Attributes::getReal(itsAttr[X]),
528
529 const double theta = Attributes::getReal(itsAttr[THETA]);
530 const double phi = Attributes::getReal(itsAttr[PHI]);
531 const double psi = Attributes::getReal(itsAttr[PSI]);
532
533 Quaternion rotTheta(std::cos(0.5 * theta), 0, std::sin(0.5 * theta), 0);
534 Quaternion rotPhi(std::cos(0.5 * phi), std::sin(0.5 * phi), 0, 0);
535 Quaternion rotPsi(std::cos(0.5 * psi), 0, 0, std::sin(0.5 * psi));
536 Quaternion rotation = rotTheta * (rotPhi * rotPsi);
537
538 CoordinateSystemTrafo global2local(origin,
539 rotation.conjugate());
540 base->setCSTrafoGlobal2Local(global2local);
541 base->fixPosition();
543 }
544
545 Vector_t misalignmentShift(Attributes::getReal(itsAttr[DX]),
548 double dtheta = Attributes::getReal(itsAttr[DTHETA]);
549 double dphi = Attributes::getReal(itsAttr[DPHI]);
550 double dpsi = Attributes::getReal(itsAttr[DPSI]);
551 Quaternion rotationY(std::cos(0.5 * dtheta), 0, std::sin(0.5 * dtheta), 0);
552 Quaternion rotationX(std::cos(0.5 * dphi), std::sin(0.5 * dphi), 0, 0);
553 Quaternion rotationZ(std::cos(0.5 * dpsi), 0, 0, std::sin(0.5 * dpsi));
554 Quaternion misalignmentRotation = rotationY * rotationX * rotationZ;
555 CoordinateSystemTrafo misalignment(misalignmentShift,
556 misalignmentRotation.conjugate());
557
558 base->setMisalignment(misalignment);
559
560 if (itsAttr[ELEMEDGE])
562
564}
565
567 for (std::vector<Attribute>::size_type i = itsSize;
568 i < itsAttr.size(); ++i) {
569 Attribute &attr = itsAttr[i];
570 base->setAttribute(attr.getName(), Attributes::getReal(attr));
571
572 }
573}
574
575void OpalElement::printAttribute(std::ostream& os, const std::string& name,
576 const std::string& image, int& len) {
577 len += name.length() + image.length() + 2;
578 if (len > 74) {
579 os << ",&\n ";
580 len = name.length() + image.length() + 3;
581 } else {
582 os << ',';
583 }
584 os << name << '=' << image;
585}
586
588(std::ostream &os, const std::string &name, double value, int &len) {
589 std::ostringstream ss;
590 ss << value << std::ends;
591 printAttribute(os, name, ss.str(), len);
592}
593
594
596 if (getParent() != 0) return;
597
598 const unsigned int end = itsSize;
599 const std::string name = getOpalName();
600 for (unsigned int i = COMMON; i < end; ++ i) {
602 }
603}
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
Tps< T > sin(const Tps< T > &x)
Sine.
Definition: TpsMath.h:111
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
PETE_TBTree< FnArcTan2, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > atan2(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
const std::string name
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.
Definition: Attributes.cpp:90
double getReal(const Attribute &attr)
Return real value.
Definition: Attributes.cpp:252
Attribute makePredefinedString(const std::string &name, const std::string &help, const std::initializer_list< std::string > &predefinedStrings)
Make predefined string attribute.
Definition: Attributes.cpp:409
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
Definition: Attributes.cpp:240
bool getBool(const Attribute &attr)
Return logical value.
Definition: Attributes.cpp:100
Attribute makeRealArray(const std::string &name, const std::string &help)
Create real array attribute.
Definition: Attributes.cpp:289
std::vector< double > getRealArray(const Attribute &attr)
Get array value.
Definition: Attributes.cpp:294
std::string getString(const Attribute &attr)
Get string value.
Definition: Attributes.cpp:343
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.
Definition: Attributes.cpp:332
constexpr double pi
The value of.
Definition: Physics.h:30
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.
Definition: Attribute.cpp:145
void parse(Statement &stat, bool eval)
Parse attribute.
Definition: Attribute.cpp:127
void parseComponent(Statement &stat, bool eval, int index)
Parse array component.
Definition: Attribute.cpp:133
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:120
The base class for all OPAL objects.
Definition: Object.h:48
Object * getParent() const
Return parent pointer.
Definition: Object.cpp:315
const std::string & getOpalName() const
Return object name.
Definition: Object.cpp:310
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
void setElementPosition(double elemedge)
Access to ELEMEDGE attribute.
Definition: ElementBase.h:582
void fixPosition()
Definition: ElementBase.h:550
void setAperture(const ApertureType &type, const std::vector< double > &args)
Definition: ElementBase.h:518
void setMisalignment(const CoordinateSystemTrafo &cst)
Definition: ElementBase.h:535
virtual void setAttribute(const std::string &aKey, double val)
Set value of an attribute.
void setFlagDeleteOnTransverseExit(bool=true)
Definition: ElementBase.h:607
void setRotationAboutZ(double rotation)
Set rotation about z axis in bend frame.
Definition: ElementBase.h:568
void setCSTrafoGlobal2Local(const CoordinateSystemTrafo &ori)
Definition: ElementBase.h:490
Quaternion conjugate() const
Definition: Quaternion.h:105
Interface for statements.
Definition: Statement.h:38
bool delimiter(char c)
Test for delimiter.
Definition: Statement.cpp:101
Parse exception.
Definition: ParseError.h:32
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).
@ DELETEONTRANSVERSEEXIT
Definition: OpalElement.h:55
@ PARTICLEMATTERINTERACTION
Definition: OpalElement.h:39
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 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.
void registerOwnership() const
The base class for all OPAL exceptions.
Definition: OpalException.h:28
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6