OPAL (Object Oriented Parallel Accelerator Library)  2024.1
OPAL
ScalingFFAMagnet.cpp
Go to the documentation of this file.
1 //
2 // Class ScalingFFAMagnet
3 // Defines the abstract interface for a sector FFA magnet
4 // with radially scaling fringe fields.
5 //
6 // Copyright (c) 2017 - 2023, Chris Rogers, STFC Rutherford Appleton Laboratory, Didcot, UK
7 // All rights reserved
8 //
9 // This file is part of OPAL.
10 //
11 // OPAL is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with OPAL. If not, see <https://www.gnu.org/licenses/>.
18 //
20 
22 
24  Component(name),
25  planarArcGeometry_m(1., 1.),
26  dummy(),
27  endField_m(nullptr) {
28 }
29 
31  Component(right),
32  planarArcGeometry_m(right.planarArcGeometry_m),
33  dummy(), maxOrder_m(right.maxOrder_m), tanDelta_m(right.tanDelta_m),
34  k_m(right.k_m), Bz_m(right.Bz_m), r0_m(right.r0_m),
35  rMin_m(right.rMin_m), rMax_m(right.rMax_m), phiStart_m(right.phiStart_m),
36  phiEnd_m(right.phiEnd_m), azimuthalExtent_m(right.azimuthalExtent_m),
37  verticalExtent_m(right.verticalExtent_m), centre_m(right.centre_m),
38  endField_m(nullptr), endFieldName_m(right.endFieldName_m),
39  dfCoefficients_m(right.dfCoefficients_m)
40 {
41  endField_m = right.endField_m->clone();
43  Bz_m = right.Bz_m;
44  r0_m = right.r0_m;
45  r0Sign_m = right.r0Sign_m;
46 }
47 
49  delete endField_m;
50 }
51 
54  magnet->initialise();
55  return magnet;
56 }
57 
59  return dummy;
60 }
61 
63  return dummy;
64 }
65 
68 }
69 
70 void ScalingFFAMagnet::initialise(PartBunchBase<double, 3>* bunch, double& /*startField*/, double& /*endField*/) {
71  RefPartBunch_m = bunch;
72  initialise();
73 }
74 
76  RefPartBunch_m = nullptr;
77 }
78 
80  return true;
81 }
82 
84  return planarArcGeometry_m;
85 }
86 
88  return planarArcGeometry_m;
89 }
90 
92  visitor.visitScalingFFAMagnet(*this);
93 }
94 
96  double x = r0Sign_m * (r0_m + R[0]);
97  double r = std::sqrt(x * x + R[2] * R[2]);
98  double phi = std::atan2(R[2], x); // angle between y-axis and position vector in anticlockwise direction
99  Vector_t posCyl(r, R[1], phi);
100  //Vector_t posCyl(r, pos[1], phi);
101  Vector_t bCyl(0., 0., 0.); //br bz bphi
102  bool outOfBounds = getFieldValueCylindrical(posCyl, bCyl);
103 
104  // this is cartesian coordinates
105  B[1] += bCyl[1];
106  B[0] += -r0Sign_m * (-bCyl[0] * std::cos(phi) + bCyl[2] * std::sin(phi));
107  B[2] += bCyl[0] * std::sin(phi) + bCyl[2] * std::cos(phi);
108  return outOfBounds;
109 }
110 
112  double r = pos[0];
113  double z = pos[1];
114  double phi = pos[2];
115  if (r < rMin_m || r > rMax_m) {
116  return true;
117  }
118  if (z < -verticalExtent_m || z > verticalExtent_m) {
119  return true;
120  }
121  double normRadius = r/std::abs(r0_m);
122  double g = tanDelta_m*std::log(normRadius);
123  double phiSpiral = phi - g - phiStart_m;
124  if (phiSpiral < -azimuthalExtent_m || phiSpiral > azimuthalExtent_m) {
125  return true;
126  }
127 
128  double h = std::pow(normRadius, k_m)*Bz_m;
129  std::vector<double> fringeDerivatives(maxOrder_m+1, 0.);
130  for (size_t i = 0; i < fringeDerivatives.size(); ++i) {
131  fringeDerivatives[i] = endField_m->function(phiSpiral, i); // d^i_phi f
132  }
133 
134  double zOverR = r0Sign_m * z/r;
135  std::vector<double> zOverRVec(dfCoefficients_m.size()+1); // zOverR^n
136  zOverRVec[0] = 1.0;
137  for (size_t n = 1; n < zOverRVec.size(); ++n) {
138  zOverRVec[n] = zOverRVec[n-1] * zOverR;
139  }
140  for (size_t n = 0; n < dfCoefficients_m.size(); n += 2) {
141  double f2n = 0;
142  Vector_t deltaB;
143  for (size_t i = 0; i < dfCoefficients_m[n].size(); ++i) {
144  f2n += dfCoefficients_m[n][i]*fringeDerivatives[i];
145  }
146  deltaB[1] = f2n * h * zOverRVec[n]; // Bz = sum(f_2n * h * (z/r)^2n
147  if (maxOrder_m >= n+1) {
148  double f2nplus1 = 0;
149  for (size_t i = 0; i < dfCoefficients_m[n+1].size() && n+1 < dfCoefficients_m.size(); ++i) {
150  f2nplus1 += dfCoefficients_m[n+1][i]*fringeDerivatives[i];
151  }
152  deltaB[0] = r0Sign_m * (f2n * (k_m-n) / (n+1) - tanDelta_m * f2nplus1) * h * zOverRVec[n+1]; // Br
153  deltaB[2] = r0Sign_m * f2nplus1 * h * zOverRVec[n+1]; // Bphi = sum(f_2n+1 * h * (z/r)^2n+1
154  }
155  B += deltaB;
156  }
157  return false;
158 }
159 
161  dfCoefficients_m = std::vector<std::vector<double> >(maxOrder_m+1);
162  dfCoefficients_m[0] = std::vector<double>(1, 1.); // f_0 = 1.*0th derivative
163  for (size_t n = 0; n < maxOrder_m; n += 2) { // n indexes the power in z
164  dfCoefficients_m[n+1] = std::vector<double>(dfCoefficients_m[n].size()+1, 0);
165  for (size_t i = 0; i < dfCoefficients_m[n].size(); ++i) { // i indexes the derivative
166  dfCoefficients_m[n+1][i+1] = dfCoefficients_m[n][i]/(n+1);
167  }
168  if (n+1 == maxOrder_m) {
169  break;
170  }
171  dfCoefficients_m[n+2] = std::vector<double>(dfCoefficients_m[n].size()+2, 0);
172  for (size_t i = 0; i < dfCoefficients_m[n].size(); ++i) { // i indexes the derivative
173  dfCoefficients_m[n+2][i] = -(k_m-n)*(k_m-n)/(n+1)*dfCoefficients_m[n][i]/(n+2);
174  }
175  for (size_t i = 0; i < dfCoefficients_m[n+1].size(); ++i) { // i indexes the derivative
176  dfCoefficients_m[n+2][i] += 2*(k_m-n)*tanDelta_m*dfCoefficients_m[n+1][i]/(n+2);
177  dfCoefficients_m[n+2][i+1] -= (1+tanDelta_m*tanDelta_m)*dfCoefficients_m[n+1][i]/(n+2);
178  }
179  }
180 
181 }
182 
184  if (endField_m != nullptr) {
185  delete endField_m;
186  }
187  endField_m = endField;
188 }
189 
190 // Note this is tested in OpalScalingFFAMagnetTest.*
192  if (endFieldName_m.empty()) { // no end field is defined
193  return;
194  }
195 
196  std::shared_ptr<endfieldmodel::EndFieldModel> efm
198 
199  endfieldmodel::EndFieldModel* newEFM = efm->clone();
200  newEFM->rescale(1.0/std::abs(r0_m));
201  setEndField(newEFM);
202  newEFM->setMaximumDerivative(maxOrder_m+2);
203 
204  double defaultExtent = (newEFM->getEndLength()*4.+
205  newEFM->getCentreLength());
206  if (phiStart_m < 0.0) {
207  setPhiStart(defaultExtent/2.0);
208  } else {
209  setPhiStart(getPhiStart()+newEFM->getCentreLength()*0.5);
210  }
211  if (phiEnd_m < 0.0) {
212  setPhiEnd(defaultExtent);
213  }
214  if (azimuthalExtent_m < 0.0) {
215  setAzimuthalExtent(newEFM->getEndLength()*5.+
216  newEFM->getCentreLength()/2.0);
217  }
220 }
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
virtual void visitScalingFFAMagnet(const ScalingFFAMagnet &)=0
Apply the algorithm to a scaling FFA magnet.
BGeometryBase & getGeometry() override
void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
virtual void setElementLength(double)
Set length.
void setPhiStart(double phiStart)
bool bends() const override
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
Abstract base class for electromagnetic fields.
Definition: EMField.h:188
virtual void setMaximumDerivative(size_t n)=0
BMultipoleField dummy
void finalise() override
virtual double getEndLength() const =0
Abstract base class for accelerator geometry classes.
Definition: Geometry.h:43
PartBunchBase< double, 3 > * RefPartBunch_m
Definition: Component.h:191
std::string endFieldName_m
ScalingFFAMagnet * clone() const override
void setCurvature(double)
Set curvature.
ScalingFFAMagnet(const std::string &name)
EMField & getField() override
void setEndField(endfieldmodel::EndFieldModel *endField)
PETE_TBTree< FnArcTan2, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > atan2(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
PlanarArcGeometry planarArcGeometry_m
bool getFieldValue(const Vector_t &R, Vector_t &B) const
double getPhiStart() const
virtual EndFieldModel * clone() const =0
bool getFieldValueCylindrical(const Vector_t &R, Vector_t &B) const
virtual void rescale(double scaleFactor)=0
virtual double getCentreLength() const =0
void accept(BeamlineVisitor &visitor) const override
virtual double function(double x, int n) const =0
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
Tps< T > log(const Tps< T > &x)
Natural logarithm.
Definition: TpsMath.h:182
const std::string name
std::vector< std::vector< double > > dfCoefficients_m
endfieldmodel::EndFieldModel * endField_m
Interface for a single beam element.
Definition: Component.h:50
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
Tps< T > sin(const Tps< T > &x)
Sine.
Definition: TpsMath.h:111
static std::shared_ptr< EndFieldModel > getEndFieldModel(std::string name)
void setAzimuthalExtent(double azimuthalExtent)
void setPhiEnd(double phiEnd)
item[EANGLE] Entrance edge counterclockwise This enables to obtain skew at each point along the magnet
Definition: multipole_t.tex:32