OPALX (Object Oriented Parallel Accelerator Library for Exascal) MINIorX
OPALX
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>
31#include "PartBunch/PartBunch.h"
32#include "Physics/Units.h"
33ScalingFFAMagnet::ScalingFFAMagnet(const std::string& name)
34 : Component(name), planarArcGeometry_m(1., 1.), dummy(), endField_m(nullptr) {
35}
36
38 : Component(right),
40 dummy(),
43 k_m(right.k_m),
44 Bz_m(right.Bz_m),
45 r0_m(right.r0_m),
46 rMin_m(right.rMin_m),
47 rMax_m(right.rMax_m),
49 phiEnd_m(right.phiEnd_m),
52 centre_m(right.centre_m),
53 endField_m(nullptr),
56 endField_m = right.endField_m->clone();
58 Bz_m = right.Bz_m;
59 r0_m = right.r0_m;
60}
61
65
67 ScalingFFAMagnet* magnet = new ScalingFFAMagnet(*this);
68 magnet->initialise();
69 return magnet;
70}
71
75
77 return dummy;
78}
79
81 const size_t& i, const double& t, Vector_t<double, 3>& E, Vector_t<double, 3>& B) {
82 std::shared_ptr<ParticleContainer_t> pc = RefPartBunch_m->getParticleContainer();
83 auto Rview = pc->R.getView();
84 auto Pview = pc->P.getView();
85
86 const Vector_t<double, 3> R = Rview(i);
87 const Vector_t<double, 3> P = Pview(i);
88 return apply(R, P, t, E, B);
89}
90
94
96 PartBunch_t* bunch, double& /*startField*/, double& /*endField*/) {
97 RefPartBunch_m = bunch;
98 initialise();
99}
100
102 RefPartBunch_m = nullptr;
103}
104
106 return true;
107}
108
112
116
118 visitor.visitScalingFFAMagnet(*this);
119}
120
123 double r = std::sqrt(pos[0] * pos[0] + pos[2] * pos[2]);
124 double phi = std::atan2(
125 pos[2], pos[0]); // angle between y-axis and position vector in anticlockwise direction
126 Vector_t<double, 3> posCyl({r, pos[1], phi});
127 Vector_t<double, 3> bCyl({0., 0., 0.}); // br bz bphi
128 bool outOfBounds = getFieldValueCylindrical(posCyl, bCyl);
129 // this is cartesian coordinates
130 B[1] += bCyl[1];
131 B[0] += bCyl[0] * std::cos(phi) - bCyl[2] * std::sin(phi);
132 B[2] += bCyl[0] * std::sin(phi) + bCyl[2] * std::cos(phi);
133 return outOfBounds;
134}
135
137 const Vector_t<double, 3>& pos, Vector_t<double, 3>& B) const {
138 double r = pos[0];
139 double z = pos[1];
140 double phi = pos[2];
141 if (r < rMin_m || r > rMax_m) {
142 return true;
143 }
144
145 double normRadius = r / r0_m;
146 double g = tanDelta_m * std::log(normRadius);
147 double phiSpiral = phi - g - phiStart_m;
148 double h = std::pow(normRadius, k_m) * Bz_m;
149 if (phiSpiral < -azimuthalExtent_m || phiSpiral > azimuthalExtent_m) {
150 return true;
151 }
152 if (z < -verticalExtent_m || z > verticalExtent_m) {
153 return true;
154 }
155 // std::cerr << "ScalingFFAMagnet::getFieldValueCylindrical " << phiSpiral << " "
156 // << endField_m->function(phiSpiral, 0) << " " << endField_m->getEndLength()
157 // << " " << endField_m->getCentreLength() << std::endl;
158 std::vector<double> fringeDerivatives(maxOrder_m + 1, 0.);
159 for (size_t i = 0; i < fringeDerivatives.size(); ++i) {
160 fringeDerivatives[i] = endField_m->function(phiSpiral, i); // d^i_phi f
161 }
162 for (size_t n = 0; n < dfCoefficients_m.size(); n += 2) {
163 double f2n = 0;
164 Vector_t<double, 3> deltaB;
165 for (size_t i = 0; i < dfCoefficients_m[n].size(); ++i) {
166 f2n += dfCoefficients_m[n][i] * fringeDerivatives[i];
167 }
168 deltaB[1] = f2n * h * std::pow(z / r, n); // Bz = sum(f_2n * h * (z/r)^2n
169 if (maxOrder_m >= n + 1) {
170 double f2nplus1 = 0;
171 for (size_t i = 0;
172 i < dfCoefficients_m[n + 1].size() && n + 1 < dfCoefficients_m.size(); ++i) {
173 f2nplus1 += dfCoefficients_m[n + 1][i] * fringeDerivatives[i];
174 }
175 deltaB[0] = (f2n * (k_m - n) / (n + 1) - tanDelta_m * f2nplus1) * h
176 * std::pow(z / r, n + 1); // Br
177 deltaB[2] =
178 f2nplus1 * h * std::pow(z / r, n + 1); // Bphi = sum(f_2n+1 * h * (z/r)^2n+1
179 }
180 B += deltaB;
181 }
182 return false;
183}
184
186 const Vector_t<double, 3>& R, const Vector_t<double, 3>& /*P*/, const double& /*t*/,
188 return getFieldValue(R, B);
189}
190
192 dfCoefficients_m = std::vector<std::vector<double> >(maxOrder_m + 1);
193 dfCoefficients_m[0] = std::vector<double>(1, 1.); // f_0 = 1.*0th derivative
194 for (size_t n = 0; n < maxOrder_m; n += 2) { // n indexes the power in z
195 dfCoefficients_m[n + 1] = std::vector<double>(dfCoefficients_m[n].size() + 1, 0);
196 for (size_t i = 0; i < dfCoefficients_m[n].size(); ++i) { // i indexes the derivative
197 dfCoefficients_m[n + 1][i + 1] = dfCoefficients_m[n][i] / (n + 1);
198 }
199 if (n + 1 == maxOrder_m) {
200 break;
201 }
202 dfCoefficients_m[n + 2] = std::vector<double>(dfCoefficients_m[n].size() + 2, 0);
203 for (size_t i = 0; i < dfCoefficients_m[n].size(); ++i) { // i indexes the derivative
204 dfCoefficients_m[n + 2][i] =
205 -(k_m - n) * (k_m - n) / (n + 1) * dfCoefficients_m[n][i] / (n + 2);
206 }
207 for (size_t i = 0; i < dfCoefficients_m[n + 1].size(); ++i) { // i indexes the derivative
208 dfCoefficients_m[n + 2][i] +=
209 2 * (k_m - n) * tanDelta_m * dfCoefficients_m[n + 1][i] / (n + 2);
210 dfCoefficients_m[n + 2][i + 1] -=
211 (1 + tanDelta_m * tanDelta_m) * dfCoefficients_m[n + 1][i] / (n + 2);
212 }
213 }
214}
215
217 if (endField_m != nullptr) {
218 delete endField_m;
219 }
220 endField_m = endField;
221}
222
223extern Inform* gmsg;
224
225// Note this is tested in OpalScalingFFAMagnetTest.*
227 if (endFieldName_m == "") { // no end field is defined
228 return;
229 }
230 std::shared_ptr<endfieldmodel::EndFieldModel> efm =
232 endfieldmodel::EndFieldModel* newEFM = efm->clone();
233 newEFM->rescale(Units::m2mm * 1.0 / getR0());
234 setEndField(newEFM);
235
236 double defaultExtent = (newEFM->getEndLength() * 4. + newEFM->getCentreLength());
237 if (phiStart_m < 0.0) {
238 setPhiStart(defaultExtent / 2.0);
239 } else {
240 setPhiStart(getPhiStart() + newEFM->getCentreLength() * 0.5);
241 }
242 if (phiEnd_m < 0.0) {
243 setPhiEnd(defaultExtent);
244 }
245 if (azimuthalExtent_m < 0.0) {
246 setAzimuthalExtent(newEFM->getEndLength() * 5. + newEFM->getCentreLength() / 2.0);
247 }
248 planarArcGeometry_m.setElementLength(r0_m * phiEnd_m); // length = phi r
249 planarArcGeometry_m.setCurvature(1. / r0_m);
250}
Inform * gmsg
Definition changes.cpp:7
PartBunch< PLayout_t< double, 3 >, double, 3 > PartBunch_t
ippl::Vector< T, Dim > Vector_t
constexpr double m2mm
Definition Units.h:26
virtual void visitScalingFFAMagnet(const ScalingFFAMagnet &)=0
Component(const std::string &name)
Constructor with given name.
Definition Component.cpp:44
PartBunch_t * RefPartBunch_m
Definition Component.h:185
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 EndFieldModel * clone() const =0
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)
void setPhiStart(double phiStart)
EMField & getField() override
void setEndField(endfieldmodel::EndFieldModel *endField)
bool apply(const size_t &i, const double &t, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B) override
BMultipoleField dummy
void setPhiEnd(double phiEnd)
bool getFieldValue(const Vector_t< double, 3 > &R, Vector_t< double, 3 > &B) const
Vector_t< double, 3 > centre_m
double getR0() const
std::vector< std::vector< double > > dfCoefficients_m
bool getFieldValueCylindrical(const Vector_t< double, 3 > &R, Vector_t< double, 3 > &B) const
double getPhiStart() const
BGeometryBase & getGeometry() override
bool bends() const override
void initialise(PartBunch_t *bunch, double &startField, double &endField) 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