OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
ScalingFFAMagnet.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017, Chris Rogers
3 * All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * 1. Redistributions of source code must retain the above copyright notice,
7 * this list of conditions and the following disclaimer.
8 * 2. Redistributions in binary form must reproduce the above copyright notice,
9 * this list of conditions and the following disclaimer in the documentation
10 * and/or other materials provided with the distribution.
11 * 3. Neither the name of STFC nor the names of its contributors may be used to
12 * endorse or promote products derived from this software without specific
13 * prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <cmath>
29
33
35 : Component(name),
36 planarArcGeometry_m(1., 1.), dummy(), endField_m(nullptr) {
37}
38
40 : Component(right),
41 planarArcGeometry_m(right.planarArcGeometry_m),
42 dummy(), maxOrder_m(right.maxOrder_m), tanDelta_m(right.tanDelta_m),
43 k_m(right.k_m), Bz_m(right.Bz_m), r0_m(right.r0_m),
44 rMin_m(right.rMin_m), rMax_m(right.rMax_m), phiStart_m(right.phiStart_m),
45 phiEnd_m(right.phiEnd_m), azimuthalExtent_m(right.azimuthalExtent_m),
46 verticalExtent_m(right.verticalExtent_m), centre_m(right.centre_m),
47 endField_m(nullptr), endFieldName_m(right.endFieldName_m),
48 dfCoefficients_m(right.dfCoefficients_m) {
49 endField_m = right.endField_m->clone();
51 Bz_m = right.Bz_m;
52 r0_m = right.r0_m;
53}
54
56 delete endField_m;
57}
58
60 ScalingFFAMagnet* magnet = new ScalingFFAMagnet(*this);
61 magnet->initialise();
62 return magnet;
63}
64
66 return dummy;
67}
68
70 return dummy;
71}
72
73bool ScalingFFAMagnet::apply(const size_t &i, const double &t,
74 Vector_t &E, Vector_t &B) {
75 return apply(RefPartBunch_m->R[i], RefPartBunch_m->P[i], t, E, B);
76}
77
80}
81
82void ScalingFFAMagnet::initialise(PartBunchBase<double, 3> *bunch, double &/*startField*/, double &/*endField*/) {
83 RefPartBunch_m = bunch;
84 initialise();
85}
86
88 RefPartBunch_m = nullptr;
89}
90
92 return true;
93}
94
97}
98
100 return planarArcGeometry_m;
101}
102
104 visitor.visitScalingFFAMagnet(*this);
105}
106
107
109 Vector_t pos = R - centre_m;
110 double r = std::sqrt(pos[0]*pos[0]+pos[2]*pos[2]);
111 double phi = std::atan2(pos[2], pos[0]); // angle between y-axis and position vector in anticlockwise direction
112 Vector_t posCyl(r, pos[1], phi);
113 Vector_t bCyl(0., 0., 0.); //br bz bphi
114 bool outOfBounds = getFieldValueCylindrical(posCyl, bCyl);
115 // this is cartesian coordinates
116 B[1] += bCyl[1];
117 B[0] += bCyl[0]*std::cos(phi) -bCyl[2]*std::sin(phi);
118 B[2] += bCyl[0]*std::sin(phi) +bCyl[2]*std::cos(phi);
119 return outOfBounds;
120
121}
122
123
125
126 double r = pos[0];
127 double z = pos[1];
128 double phi = pos[2];
129 if (r < rMin_m || r > rMax_m) {
130 return true;
131 }
132
133 double normRadius = r/r0_m;
134 double g = tanDelta_m*std::log(normRadius);
135 double phiSpiral = phi - g - phiStart_m;
136 double h = std::pow(normRadius, k_m)*Bz_m;
137 if (phiSpiral < -azimuthalExtent_m || phiSpiral > azimuthalExtent_m) {
138 return true;
139 }
140 if (z < -verticalExtent_m || z > verticalExtent_m) {
141 return true;
142 }
143 //std::cerr << "ScalingFFAMagnet::getFieldValueCylindrical " << phiSpiral << " "
144 // << endField_m->function(phiSpiral, 0) << " " << endField_m->getEndLength()
145 // << " " << endField_m->getCentreLength() << std::endl;
146 std::vector<double> fringeDerivatives(maxOrder_m+1, 0.);
147 for (size_t i = 0; i < fringeDerivatives.size(); ++i) {
148 fringeDerivatives[i] = endField_m->function(phiSpiral, i); // d^i_phi f
149 }
150 for (size_t n = 0; n < dfCoefficients_m.size(); n += 2) {
151 double f2n = 0;
152 Vector_t deltaB;
153 for (size_t i = 0; i < dfCoefficients_m[n].size(); ++i) {
154 f2n += dfCoefficients_m[n][i]*fringeDerivatives[i];
155 }
156 deltaB[1] = f2n*h*std::pow(z/r, n); // Bz = sum(f_2n * h * (z/r)^2n
157 if (maxOrder_m >= n+1) {
158 double f2nplus1 = 0;
159 for (size_t i = 0; i < dfCoefficients_m[n+1].size() && n+1 < dfCoefficients_m.size(); ++i) {
160 f2nplus1 += dfCoefficients_m[n+1][i]*fringeDerivatives[i];
161 }
162 deltaB[0] = (f2n*(k_m-n)/(n+1) - tanDelta_m*f2nplus1)*h*std::pow(z/r, n+1); // Br
163 deltaB[2] = f2nplus1*h*std::pow(z/r, n+1); // Bphi = sum(f_2n+1 * h * (z/r)^2n+1
164 }
165 B += deltaB;
166 }
167 return false;
168}
169
170
171bool ScalingFFAMagnet::apply(const Vector_t &R, const Vector_t &/*P*/,
172 const double &/*t*/, Vector_t &/*E*/, Vector_t &B) {
173 return getFieldValue(R, B);
174}
175
177 dfCoefficients_m = std::vector<std::vector<double> >(maxOrder_m+1);
178 dfCoefficients_m[0] = std::vector<double>(1, 1.); // f_0 = 1.*0th derivative
179 for (size_t n = 0; n < maxOrder_m; n += 2) { // n indexes the power in z
180 dfCoefficients_m[n+1] = std::vector<double>(dfCoefficients_m[n].size()+1, 0);
181 for (size_t i = 0; i < dfCoefficients_m[n].size(); ++i) { // i indexes the derivative
182 dfCoefficients_m[n+1][i+1] = dfCoefficients_m[n][i]/(n+1);
183 }
184 if (n+1 == maxOrder_m) {
185 break;
186 }
187 dfCoefficients_m[n+2] = std::vector<double>(dfCoefficients_m[n].size()+2, 0);
188 for(size_t i = 0; i < dfCoefficients_m[n].size(); ++i) { // i indexes the derivative
189 dfCoefficients_m[n+2][i] = -(k_m-n)*(k_m-n)/(n+1)*dfCoefficients_m[n][i]/(n+2);
190 }
191 for(size_t i = 0; i < dfCoefficients_m[n+1].size(); ++i) { // i indexes the derivative
192 dfCoefficients_m[n+2][i] += 2*(k_m-n)*tanDelta_m*dfCoefficients_m[n+1][i]/(n+2);
193 dfCoefficients_m[n+2][i+1] -= (1+tanDelta_m*tanDelta_m)*dfCoefficients_m[n+1][i]/(n+2);
194 }
195 }
196
197}
198
200 if (endField_m != nullptr) {
201 delete endField_m;
202 }
203 endField_m = endField;
204}
205
206extern Inform* gmsg;
207
208// Note this is tested in OpalScalingFFAMagnetTest.*
210 if (endFieldName_m == "") { // no end field is defined
211 return;
212 }
213 std::shared_ptr<endfieldmodel::EndFieldModel> efm
215 endfieldmodel::EndFieldModel* newEFM = efm->clone();
216 newEFM->rescale(Units::m2mm*1.0/getR0());
217 setEndField(newEFM);
218
219 double defaultExtent = (newEFM->getEndLength()*4.+
220 newEFM->getCentreLength());
221 if (phiStart_m < 0.0) {
222 setPhiStart(defaultExtent/2.0);
223 } else {
224 setPhiStart(getPhiStart()+newEFM->getCentreLength()*0.5);
225 }
226 if (phiEnd_m < 0.0) {
227 setPhiEnd(defaultExtent);
228 }
229 if (azimuthalExtent_m < 0.0) {
230 setAzimuthalExtent(newEFM->getEndLength()*5.+
231 newEFM->getCentreLength()/2.0);
232 }
235}
Inform * gmsg
Definition: Main.cpp:61
Tps< T > log(const Tps< T > &x)
Natural logarithm.
Definition: TpsMath.h:182
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
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
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)
const std::string name
constexpr double m2mm
Definition: Units.h:26
ParticlePos_t & R
ParticleAttrib< Vector_t > P
virtual void visitScalingFFAMagnet(const ScalingFFAMagnet &)=0
Apply the algorithm to a scaling FFA magnet.
Interface for a single beam element.
Definition: Component.h:50
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 double function(double x, int n) const =0
virtual EndFieldModel * clone() const =0
bool getFieldValue(const Vector_t &R, Vector_t &B) const
std::string endFieldName_m
bool apply(const size_t &i, const double &t, Vector_t &E, Vector_t &B) override
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)
double getR0() const
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
void setCurvature(double)
Set curvature.
virtual void setElementLength(double)
Set length.
Abstract base class for electromagnetic fields.
Definition: EMField.h:188
Definition: Inform.h:42