OPAL (Object Oriented Parallel Accelerator Library)  2024.1
OPAL
OpalScalingFFAMagnet.cpp
Go to the documentation of this file.
1 //
2 // Class OpalScalingFFAMagnet
3 // The class provides the user interface for the SCALINGFFAMAGNET object.
4 //
5 // Copyright (c) 2017 - 2023, Chris Rogers, STFC Rutherford Appleton Laboratory, Didcot, UK
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 
22 #include "Attributes/Attributes.h"
23 #include "Physics/Units.h"
25 
27  OpalElement(SIZE, "SCALINGFFAMAGNET",
28  "The \"ScalingFFAMagnet\" element defines a FFA scaling magnet with zero or non-zero spiral angle.") {
29 
31  ("B0", "The nominal dipole field of the magnet [T].");
32 
34  ("R0", "Radial scale [m].");
35 
37  ("FIELD_INDEX", "The scaling magnet field index.");
38 
40  ("TAN_DELTA", "Tangent of the spiral angle; set to 0 to make a radial sector magnet.");
41 
43  ("MAX_Y_POWER", "The maximum power in y that will be considered in the field expansion.");
44 
46  ("END_FIELD_MODEL",
47  "Names the end field model of the ring, giving dipole field along a line of "
48  "constant radius. If blank, uses the default 'END_LENGTH' and 'CENTRE_LENGTH' "
49  "parameters and a tanh model. If 'END_FIELD_MODEL' is not blank, Opal will seek "
50  "an END_FIELD_MODEL corresponding to the name defined in this string.");
51 
53  ("END_LENGTH", "The end length of the spiral FFA [m].");
54 
56  ("HEIGHT",
57  "Full height of the magnet. Particles moving more than height/2. "
58  "off the midplane (either above or below) are out of the aperture [m].");
59 
61  ("CENTRE_LENGTH", "The centre length of the spiral FFA [m].");
62 
64  ("RADIAL_NEG_EXTENT",
65  "Particles are considered outside the tracking region if "
66  "radius is greater than R0-RADIAL_NEG_EXTENT [m].", 1);
67 
69  ("RADIAL_POS_EXTENT",
70  "Particles are considered outside the tracking region if "
71  "radius is greater than R0+RADIAL_POS_EXTENT [m].", 1);
72 
74  ("MAGNET_START",
75  "Determines the position of the central portion of the magnet field "
76  "relative to the element start (default is 2*end_length) [m].");
77 
79  ("MAGNET_END",
80  "Offset to the end of the magnet, i.e. placement of the next element."
81  "Default is centre_length + 4*end_length.");
82 
84  ("AZIMUTHAL_EXTENT",
85  "The field will be assumed zero if particles are more than AZIMUTHAL_EXTENT "
86  "from the magnet centre (psi=0). Default is CENTRE_LENGTH/2.+5.*END_LENGTH [m].");
87 
89 
90  ScalingFFAMagnet* magnet = new ScalingFFAMagnet("ScalingFFAMagnet");
91  magnet->setEndField(new endfieldmodel::Tanh(1., 1., 1));
92  setElement(magnet);
93 }
94 
96  OpalScalingFFAMagnet* parent):
97  OpalElement(name, parent) {
99  magnet->setEndField(new endfieldmodel::Tanh(1., 1., 1));
100  setElement(magnet);
101 }
102 
104 }
105 
107  return new OpalScalingFFAMagnet(name, this);
108 }
109 
111  ScalingFFAMagnet* magnet = dynamic_cast<ScalingFFAMagnet*>(getElement());
112  // get centre length and end length in metres
113  endfieldmodel::Tanh* endField = new endfieldmodel::Tanh();
114  double end_length = Attributes::getReal(itsAttr[END_LENGTH]);
115  double centre_length = Attributes::getReal(itsAttr[CENTRE_LENGTH])/2.;
116  endField->setLambda(end_length);
117  // x0 is the distance between B=0.5*B0 and B=B0 i.e. half the centre length
118  endField->setX0(centre_length);
119  std::shared_ptr<endfieldmodel::EndFieldModel> efm(endField);
120  std::string endName = "__opal_internal__" + getOpalName();
122  magnet->setEndFieldName(endName);
123 }
124 
126  if (!itsAttr[END_FIELD_MODEL]) {
127  return;
128  }
129  std::string name = Attributes::getString(itsAttr[END_FIELD_MODEL]);
130  ScalingFFAMagnet* magnet = dynamic_cast<ScalingFFAMagnet*>(getElement());
131  magnet->setEndFieldName(name);
132 }
133 
135  ScalingFFAMagnet* magnet = dynamic_cast<ScalingFFAMagnet*>(getElement());
136 
137  // use L = r0*theta; we define the magnet into length for UI but into angles
138  // internally; and use m as external default unit
139  double r0Abs = std::abs(Attributes::getReal(itsAttr[R0]));
140  double r0Signed = Attributes::getReal(itsAttr[R0]);
141  magnet->setR0(r0Signed);
143 
144  // dimensionless quantities
148  magnet->setMaxOrder(maxOrder);
149 
150  if (itsAttr[END_FIELD_MODEL]) {
152  } else {
154  }
155  // internally OpalScalingFFAMagnet uses radians, so we scale all lengths to
156  // radians.
157  magnet->getEndField()->rescale(1/r0Abs);
158 
159  // get rmin and rmax bounding box edge
160  if (!itsAttr[RADIAL_NEG_EXTENT]) {
161  throw OpalException("OpalScalingFFAMagnet::update()",
162  "RADIAL_NEG_EXTENT needs to be defined");
163  }
164  double rmin = r0Abs - Attributes::getReal(itsAttr[RADIAL_NEG_EXTENT]);
165 
166  if (!itsAttr[RADIAL_POS_EXTENT]) {
167  throw OpalException("OpalScalingFFAMagnet::update()",
168  "RADIAL_POS_EXTENT needs to be defined");
169  }
170  double rmax = r0Abs + Attributes::getReal(itsAttr[RADIAL_POS_EXTENT]);
171  magnet->setRMin(rmin);
172  magnet->setRMax(rmax);
173 
174  Vector_t centre(r0Signed, 0, 0);
175  magnet->setCentre(centre);
176 
177  // we store maximum vertical displacement (which is half the height)
178  double height = Attributes::getReal(itsAttr[HEIGHT]);
179  magnet->setVerticalExtent(height/2.);
180  // end of the magnet marks the point at which the next element starts
181  if (itsAttr[MAGNET_END]) {
182  if (Attributes::getReal(itsAttr[MAGNET_END]) < 0.0) {
183  throw OpalException("OpalScalingFFAMagnet::update()",
184  "MAGNET_END must be > 0.0");
185  }
186  double phi_end = Attributes::getReal(itsAttr[MAGNET_END]) / r0Abs;
187  magnet->setPhiEnd(phi_end);
188  } else {
189  magnet->setPhiEnd(-1); // flag for setupEndField
190  }
191 
192  // get start of the magnet element in radians
193  // setPhiStart sets the position of the 0 point of the endFieldModel, which
194  // is typically the magnet centre
195  if (itsAttr[MAGNET_START]) {
196  if (Attributes::getReal(itsAttr[MAGNET_START]) < 0.0) {
197  throw OpalException("OpalScalingFFAMagnet::update()",
198  "MAGNET_START must be > 0.0");
199  }
200  double phi_start = Attributes::getReal(itsAttr[MAGNET_START]) / r0Abs;
201  magnet->setPhiStart(phi_start);
202  } else {
203  magnet->setPhiStart(-1); // flag for setupEndField
204  }
205  // get azimuthal extent in radians; this is just the bounding box
206  if (itsAttr[AZIMUTHAL_EXTENT]) {
207  if (Attributes::getReal(itsAttr[AZIMUTHAL_EXTENT]) < 0.0) {
208  throw OpalException("OpalScalingFFAMagnet::update()",
209  "AZIMUTHAL_EXTENT must be > 0.0");
210  }
211  magnet->setAzimuthalExtent(Attributes::getReal(itsAttr[AZIMUTHAL_EXTENT]) / r0Abs);
212  } else {
213  magnet->setAzimuthalExtent(-1); // flag for setupEndField
214  }
215  magnet->initialise();
216  setElement(magnet);
217 }
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
Definition: Attributes.cpp:240
void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
std::string getString(const Attribute &attr)
Get string value.
Definition: Attributes.cpp:343
void setPhiStart(double phiStart)
void setTanDelta(double tanDelta)
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
void setEndFieldName(std::string name)
void setDipoleConstant(double Bz)
virtual OpalScalingFFAMagnet * clone(const std::string &name)
void setR0(double r0)
void setLambda(double lambda)
Definition: Tanh.h:107
constexpr double T2kG
Definition: Units.h:56
void setRMax(double rMax)
void setEndField(endfieldmodel::EndFieldModel *endField)
void setElement(ElementBase *)
Assign new CLASSIC element.
Definition: Element.h:125
The base class for all OPAL exceptions.
Definition: OpalException.h:28
void setX0(double x0)
Definition: Tanh.h:110
void setMaxOrder(size_t maxOrder)
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.
Definition: Attributes.cpp:332
ElementBase * getElement() const
Return the embedded CLASSIC element.
Definition: Element.h:120
virtual void rescale(double scaleFactor)=0
endfieldmodel::EndFieldModel * getEndField() const
const std::string & getOpalName() const
Return object name.
Definition: Object.cpp:310
void setRMin(double rMin)
std::vector< Attribute > itsAttr
The object attributes.
Definition: Object.h:216
void setFieldIndex(double k)
void setCentre(Vector_t centre)
const std::string name
double getReal(const Attribute &attr)
Return real value.
Definition: Attributes.cpp:252
void setVerticalExtent(double verticalExtent)
static void setEndFieldModel(std::string name, std::shared_ptr< EndFieldModel > efm)
PETE_TUTree< FnFloor, typename T::PETE_Expr_t > floor(const PETE_Expr< T > &l)
Definition: PETE.h:733
void setAzimuthalExtent(double azimuthalExtent)
void setPhiEnd(double phiEnd)
void registerOwnership() const
item[EANGLE] Entrance edge counterclockwise This enables to obtain skew at each point along the magnet
Definition: multipole_t.tex:32