OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
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 //
18 #include "Elements/OpalElement.h"
19 
20 #include "AbsBeamline/Bend2D.h"
24 #include "Attributes/Attributes.h"
25 #include "Parser/Statement.h"
26 #include "Physics/Physics.h"
28 #include "Utilities/Options.h"
29 #include "Utilities/ParseError.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 
40 OpalElement::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 
116  const unsigned int end = COMMON;
117  for (unsigned int i = 0; i < end; ++ i) {
119  }
120 }
121 
122 
123 OpalElement::OpalElement(const std::string& name, OpalElement* parent):
124  Element(name, parent), itsSize(parent->itsSize)
125 {}
126 
127 
129 {}
130 
131 
132 std::pair<ElementBase::ApertureType, std::vector<double> > OpalElement::getApert() const {
133 
134  std::pair<ElementBase::ApertureType, std::vector<double> > retvalue(ElementBase::ELLIPTICAL,
135  std::vector<double>({0.5, 0.5, 1.0}));
136  if (!itsAttr[APERT]) return retvalue;
137 
138  std::string aperture = Attributes::getString(itsAttr[APERT]);
139 
140  boost::regex square("square *\\((.*)\\)", boost::regex::icase);
141  boost::regex rectangle("rectangle *\\((.*)\\)", boost::regex::icase);
142  boost::regex circle("circle *\\((.*)\\)", boost::regex::icase);
143  boost::regex ellipse("ellipse *\\((.*)\\)", boost::regex::icase);
144 
145  boost::regex twoArguments("([^,]*),([^,]*)");
146  boost::regex threeArguments("([^,]*),([^,]*),([^,]*)");
147 
148  boost::smatch match;
149 
150  const double width2HalfWidth = 0.5;
151 
152  if (boost::regex_search(aperture, match, square)) {
153  std::string arguments = match[1];
154  if (!boost::regex_search(arguments, match, twoArguments)) {
155  retvalue.first = ElementBase::RECTANGULAR;
156 
157  try {
158  retvalue.second[0] = width2HalfWidth * std::stod(arguments);
159  retvalue.second[1] = retvalue.second[0];
160  } catch (const std::exception &ex) {
161  throw OpalException("OpalElement::getApert()",
162  "could not convert '" + arguments + "' to double");
163  }
164 
165  } else {
166  retvalue.first = ElementBase::CONIC_RECTANGULAR;
167 
168  try {
169  retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
170  retvalue.second[1] = retvalue.second[0];
171  retvalue.second[2] = std::stod(match[2]);
172  } catch (const std::exception &ex) {
173  throw OpalException("OpalElement::getApert()",
174  "could not convert '" + arguments + "' to doubles");
175  }
176  }
177 
178  return retvalue;
179  }
180 
181  if (boost::regex_search(aperture, match, rectangle)) {
182  std::string arguments = match[1];
183 
184  if (!boost::regex_search(arguments, match, threeArguments)) {
185  retvalue.first = ElementBase::RECTANGULAR;
186 
187  try {
188  size_t sz = 0;
189 
190  retvalue.second[0] = width2HalfWidth * std::stod(arguments, &sz);
191  sz = arguments.find_first_of(",", sz) + 1;
192  retvalue.second[1] = width2HalfWidth * std::stod(arguments.substr(sz));
193 
194  } catch (const std::exception &ex) {
195  throw OpalException("OpalElement::getApert()",
196  "could not convert '" + arguments + "' to doubles");
197  }
198 
199  } else {
200  retvalue.first = ElementBase::CONIC_RECTANGULAR;
201 
202  try {
203  retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
204  retvalue.second[1] = width2HalfWidth * std::stod(match[2]);
205  retvalue.second[2] = std::stod(match[3]);
206  } catch (const std::exception &ex) {
207  throw OpalException("OpalElement::getApert()",
208  "could not convert '" + arguments + "' to doubles");
209  }
210  }
211 
212  return retvalue;
213  }
214 
215  if (boost::regex_search(aperture, match, circle)) {
216  std::string arguments = match[1];
217  if (!boost::regex_search(arguments, match, twoArguments)) {
218  retvalue.first = ElementBase::ELLIPTICAL;
219 
220  try {
221  retvalue.second[0] = width2HalfWidth * std::stod(arguments);
222  retvalue.second[1] = retvalue.second[0];
223  } catch (const std::exception &ex) {
224  throw OpalException("OpalElement::getApert()",
225  "could not convert '" + arguments + "' to double");
226  }
227 
228  } else {
229  retvalue.first = ElementBase::CONIC_ELLIPTICAL;
230 
231  try {
232  retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
233  retvalue.second[1] = retvalue.second[0];
234  retvalue.second[2] = std::stod(match[2]);
235  } catch (const std::exception &ex) {
236  throw OpalException("OpalElement::getApert()",
237  "could not convert '" + arguments + "' to doubles");
238  }
239  }
240 
241  return retvalue;
242  }
243 
244  if (boost::regex_search(aperture, match, ellipse)) {
245  std::string arguments = match[1];
246 
247  if (!boost::regex_search(arguments, match, threeArguments)) {
248  retvalue.first = ElementBase::ELLIPTICAL;
249 
250  try {
251  size_t sz = 0;
252 
253  retvalue.second[0] = width2HalfWidth * std::stod(arguments, &sz);
254  sz = arguments.find_first_of(",", sz) + 1;
255  retvalue.second[1] = width2HalfWidth * std::stod(arguments.substr(sz));
256 
257  } catch (const std::exception &ex) {
258  throw OpalException("OpalElement::getApert()",
259  "could not convert '" + arguments + "' to doubles");
260  }
261 
262  } else {
263  retvalue.first = ElementBase::CONIC_ELLIPTICAL;
264 
265  try {
266  retvalue.second[0] = width2HalfWidth * std::stod(match[1]);
267  retvalue.second[1] = width2HalfWidth * std::stod(match[2]);
268  retvalue.second[2] = std::stod(match[3]);
269  } catch (const std::exception &ex) {
270  throw OpalException("OpalElement::getApert()",
271  "could not convert '" + arguments + "' to doubles");
272  }
273  }
274 
275  return retvalue;
276  }
277 
278  if (aperture != "")
279  throw OpalException("OpalElement::getApert()",
280  "Unknown aperture type '" + aperture + "'.");
281 
282  return retvalue;
283 }
284 
285 double OpalElement::getLength() const {
287 }
288 
289 
290 const std::string OpalElement::getTypeName() const {
291  const Attribute* attr = findAttribute("TYPE");
292  return attr ? Attributes::getString(*attr) : std::string();
293 }
294 
298 const std::string OpalElement::getWakeF() const {
299  const Attribute* attr = findAttribute("WAKEF");
300  return attr ? Attributes::getString(*attr) : std::string();
301 }
302 
303 const std::string OpalElement::getParticleMatterInteraction() const {
304  const Attribute* attr = findAttribute("PARTICLEMATTERINTERACTION");
305  return attr ? Attributes::getString(*attr) : std::string();
306 }
307 
309  while (stat.delimiter(',')) {
310  std::string name = Expressions::parseString(stat, "Attribute name expected.");
311  Attribute *attr = findAttribute(name);
312 
313  if (attr == 0) {
314  throw OpalException("OpalElement::parse",
315  "unknown attribute \"" + name + "\"");
316  }
317 
318  if (stat.delimiter('[')) {
319  int index = int(std::round(Expressions::parseRealConst(stat)));
320  Expressions::parseDelimiter(stat, ']');
321 
322  if (stat.delimiter('=')) {
323  attr->parseComponent(stat, true, index);
324  } else if (stat.delimiter(":=")) {
325  attr->parseComponent(stat, false, index);
326  } else {
327  throw ParseError("OpalElement::parse()",
328  "Delimiter \"=\" or \":=\" expected.");
329  }
330  } else {
331  if (stat.delimiter('=')) {
332  attr->parse(stat, true);
333  } else if (stat.delimiter(":=")) {
334  attr->parse(stat, false);
335  } else {
336  attr->setDefault();
337  }
338  }
339  }
340 }
341 
342 
343 void OpalElement::print(std::ostream& os) const {
344  std::string head = getOpalName();
345 
346  Object* parent = getParent();
347  if (parent != 0 && ! parent->getOpalName().empty()) {
348  if (! getOpalName().empty()) head += ':';
349  head += parent->getOpalName();
350  }
351 
352  os << head;
353  os << ';'; // << "JMJdebug OPALElement.cc" ;
354  os << std::endl;
355 }
356 
357 
359  int order, int& len,
360  const std::string& sName,
361  const std::string& tName,
362  const Attribute& length,
363  const Attribute& sNorm,
364  const Attribute& sSkew) {
365  // Find out which type of output is required.
366  int flag = 0;
367  if (sNorm) {
368  if (sNorm.getBase().isExpression()) {
369  flag += 2;
370  } else if (Attributes::getReal(sNorm) != 0.0) {
371  flag += 1;
372  }
373  }
374 
375  if (sSkew) {
376  if (sSkew.getBase().isExpression()) {
377  flag += 6;
378  } else if (Attributes::getReal(sSkew) != 0.0) {
379  flag += 3;
380  }
381  }
382  // cout << "JMJdebug, OpalElement.cc: flag=" << flag << endl ;
383  // Now do the output.
384  int div = 2 * (order + 1);
385 
386  switch (flag) {
387 
388  case 0:
389  // No component at all.
390  break;
391 
392  case 1:
393  case 2:
394  // Pure normal component.
395  {
396  std::string normImage = sNorm.getImage();
397  if (length) {
398  normImage = "(" + normImage + ")*(" + length.getImage() + ")";
399  }
400  printAttribute(os, sName, normImage, len);
401  }
402  break;
403 
404  case 3:
405  case 6:
406  // Pure skew component.
407  {
408  std::string skewImage = sSkew.getImage();
409  if (length) {
410  skewImage = "(" + skewImage + ")*(" + length.getImage() + ")";
411  }
412  printAttribute(os, sName, skewImage, len);
413  double tilt = Physics::pi / double(div);
414  printAttribute(os, tName, tilt, len);
415  }
416  break;
417 
418  case 4:
419  // Both components are non-zero constants.
420  {
421  double sn = Attributes::getReal(sNorm);
422  double ss = Attributes::getReal(sSkew);
423  double strength = std::sqrt(sn * sn + ss * ss);
424  if (strength) {
425  std::ostringstream ts;
426  ts << strength;
427  std::string image = ts.str();
428  if (length) {
429  image = "(" + image + ")*(" + length.getImage() + ")";
430  }
431  printAttribute(os, sName, image, len);
432  double tilt = - std::atan2(ss, sn) / double(div);
433  if (tilt) printAttribute(os, tName, tilt, len);
434  }
435  }
436  break;
437 
438  case 5:
439  case 7:
440  case 8:
441  // One or both components is/are expressions.
442  {
443  std::string normImage = sNorm.getImage();
444  std::string skewImage = sSkew.getImage();
445  std::string image =
446  "SQRT((" + normImage + ")^2+(" + skewImage + ")^2)";
447  printAttribute(os, sName, image, len);
448  if (length) {
449  image = "(" + image + ")*(" + length.getImage() + ")";
450  }
451  std::string divisor;
452  if (div < 9) {
453  divisor = "0";
454  divisor[0] += div;
455  } else {
456  divisor = "00";
457  divisor[0] += div / 10;
458  divisor[1] += div % 10;
459  }
460  image = "-ATAN2(" + skewImage + ',' + normImage + ")/" + divisor;
461  printAttribute(os, tName, image, len);
462  break;
463  }
464  }
465 }
466 
468  ElementBase* base = getElement();
469 
470  auto apert = getApert();
471  base->setAperture(apert.first, apert.second);
472 
473  if (itsAttr[ORIGIN] || itsAttr[ORIENTATION]) {
474  std::vector<double> ori = Attributes::getRealArray(itsAttr[ORIGIN]);
475  std::vector<double> dir = Attributes::getRealArray(itsAttr[ORIENTATION]);
476  Vector_t origin(0.0);
477  Quaternion rotation;
478 
479  if (dir.size() == 3) {
480  Quaternion rotTheta(std::cos(0.5 * dir[0]), 0, std::sin(0.5 * dir[0]), 0);
481  Quaternion rotPhi(std::cos(0.5 * dir[1]), std::sin(0.5 * dir[1]), 0, 0);
482  Quaternion rotPsi(std::cos(0.5 * dir[2]), 0, 0, std::sin(0.5 * dir[2]));
483  rotation = rotTheta * (rotPhi * rotPsi);
484  } else {
485  if (itsAttr[ORIENTATION]) {
486  throw OpalException("OpalElement::update",
487  "Parameter orientation is array of 3 values (theta, phi, psi);\n" +
488  std::to_string(dir.size()) + " values provided");
489  }
490  }
491 
492  if (ori.size() == 3) {
493  origin = Vector_t(ori[0], ori[1], ori[2]);
494  } else {
495  if (itsAttr[ORIGIN]) {
496  throw OpalException("OpalElement::update",
497  "Parameter origin is array of 3 values (x, y, z);\n" +
498  std::to_string(ori.size()) + " values provided");
499  }
500  }
501 
502  CoordinateSystemTrafo global2local(origin,
503  rotation.conjugate());
504  base->setCSTrafoGlobal2Local(global2local);
505  base->fixPosition();
506 
507  } else if (!itsAttr[PSI].defaultUsed() &&
508  itsAttr[X].defaultUsed() &&
509  itsAttr[Y].defaultUsed() &&
510  itsAttr[Z].defaultUsed() &&
511  itsAttr[THETA].defaultUsed() &&
512  itsAttr[PHI].defaultUsed()) {
514  } else if (!itsAttr[X].defaultUsed() ||
515  !itsAttr[Y].defaultUsed() ||
516  !itsAttr[Z].defaultUsed() ||
517  !itsAttr[THETA].defaultUsed() ||
518  !itsAttr[PHI].defaultUsed() ||
519  !itsAttr[PSI].defaultUsed()) {
520  const Vector_t origin(Attributes::getReal(itsAttr[X]),
523 
524  const double theta = Attributes::getReal(itsAttr[THETA]);
525  const double phi = Attributes::getReal(itsAttr[PHI]);
526  const double psi = Attributes::getReal(itsAttr[PSI]);
527 
528  Quaternion rotTheta(std::cos(0.5 * theta), 0, std::sin(0.5 * theta), 0);
529  Quaternion rotPhi(std::cos(0.5 * phi), std::sin(0.5 * phi), 0, 0);
530  Quaternion rotPsi(std::cos(0.5 * psi), 0, 0, std::sin(0.5 * psi));
531  Quaternion rotation = rotTheta * (rotPhi * rotPsi);
532 
533  CoordinateSystemTrafo global2local(origin,
534  rotation.conjugate());
535  base->setCSTrafoGlobal2Local(global2local);
536  base->fixPosition();
538  }
539 
540  Vector_t misalignmentShift(Attributes::getReal(itsAttr[DX]),
543  double dtheta = Attributes::getReal(itsAttr[DTHETA]);
544  double dphi = Attributes::getReal(itsAttr[DPHI]);
545  double dpsi = Attributes::getReal(itsAttr[DPSI]);
546  Quaternion rotationY(std::cos(0.5 * dtheta), 0, std::sin(0.5 * dtheta), 0);
547  Quaternion rotationX(std::cos(0.5 * dphi), std::sin(0.5 * dphi), 0, 0);
548  Quaternion rotationZ(std::cos(0.5 * dpsi), 0, 0, std::sin(0.5 * dpsi));
549  Quaternion misalignmentRotation = rotationY * rotationX * rotationZ;
550  CoordinateSystemTrafo misalignment(misalignmentShift,
551  misalignmentRotation.conjugate());
552 
553  base->setMisalignment(misalignment);
554 
555  if (itsAttr[ELEMEDGE])
557 }
558 
560  for (std::vector<Attribute>::size_type i = itsSize;
561  i < itsAttr.size(); ++i) {
562  Attribute &attr = itsAttr[i];
563  base->setAttribute(attr.getName(), Attributes::getReal(attr));
564 
565  }
566 }
567 
568 void OpalElement::printAttribute(std::ostream& os, const std::string& name,
569  const std::string& image, int& len) {
570  len += name.length() + image.length() + 2;
571  if (len > 74) {
572  os << ",&\n ";
573  len = name.length() + image.length() + 3;
574  } else {
575  os << ',';
576  }
577  os << name << '=' << image;
578 }
579 
581 (std::ostream &os, const std::string &name, double value, int &len) {
582  std::ostringstream ss;
583  ss << value << std::ends;
584  printAttribute(os, name, ss.str(), len);
585 }
586 
587 
589  if (getParent() != 0) return;
590 
591  const unsigned int end = itsSize;
592  const std::string name = getOpalName();
593  for (unsigned int i = COMMON; i < end; ++ i) {
595  }
596 }
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
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
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.
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
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:286
const std::string & getOpalName() const
Return object name.
Definition: Object.cpp:281
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:600
void fixPosition()
Definition: ElementBase.h:568
void setAperture(const ApertureType &type, const std::vector< double > &args)
Definition: ElementBase.h:536
void setMisalignment(const CoordinateSystemTrafo &cst)
Definition: ElementBase.h:553
virtual void setAttribute(const std::string &aKey, double val)
Set value of an attribute.
void setRotationAboutZ(double rotation)
Set rotation about z axis in bend frame.
Definition: ElementBase.h:586
void setCSTrafoGlobal2Local(const CoordinateSystemTrafo &ori)
Definition: ElementBase.h:508
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
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).
@ 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.
std::pair< ElementBase::ApertureType, std::vector< double > > getApert() const
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