OPAL (Object Oriented Parallel Accelerator Library) 2024.2
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
25 planarArcGeometry_m(1., 1.),
26 dummy(),
27 endField_m(nullptr) {
28}
29
47
51
53 ScalingFFAMagnet* magnet = new ScalingFFAMagnet(*this);
54 magnet->initialise();
55 return magnet;
56}
57
61
63 return dummy;
64}
65
69
70void 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
86
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);
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 }
218 planarArcGeometry_m.setElementLength(std::abs(r0_m)*phiEnd_m); // length = phi r
219 planarArcGeometry_m.setCurvature(1./r0_m);
220}
const std::string name
virtual void visitScalingFFAMagnet(const ScalingFFAMagnet &)=0
Apply the algorithm to a scaling FFA magnet.
Component(const std::string &name)
Constructor with given name.
Definition Component.cpp:53
PartBunchBase< double, 3 > * RefPartBunch_m
Definition Component.h:191
static std::shared_ptr< EndFieldModel > getEndFieldModel(std::string name)
virtual void rescale(double scaleFactor)=0
virtual double getCentreLength() const =0
virtual double getEndLength() const =0
virtual void setMaximumDerivative(size_t n)=0
virtual EndFieldModel * clone() const =0
bool getFieldValue(const Vector_t &R, Vector_t &B) const
std::string endFieldName_m
void accept(BeamlineVisitor &visitor) const override
void setAzimuthalExtent(double azimuthalExtent)
void finalise() override
endfieldmodel::EndFieldModel * endField_m
ScalingFFAMagnet * clone() const override
ScalingFFAMagnet(const std::string &name)
bool getFieldValueCylindrical(const Vector_t &R, Vector_t &B) const
void setPhiStart(double phiStart)
EMField & getField() override
void setEndField(endfieldmodel::EndFieldModel *endField)
BMultipoleField dummy
void setPhiEnd(double phiEnd)
std::vector< std::vector< double > > dfCoefficients_m
void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
double getPhiStart() const
BGeometryBase & getGeometry() override
bool bends() const override
PlanarArcGeometry planarArcGeometry_m
Abstract base class for accelerator geometry classes.
Definition Geometry.h:43
Abstract base class for electromagnetic fields.
Definition EMField.h:188
Vektor< double, 3 > Vector_t