OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
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
29#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
37 : Component(right),
38 planarArcGeometry_m(right.planarArcGeometry_m),
39 dummy(),
40 maxOrder_m(right.maxOrder_m),
41 tanDelta_m(right.tanDelta_m),
42 k_m(right.k_m),
43 Bz_m(right.Bz_m),
44 r0_m(right.r0_m),
45 rMin_m(right.rMin_m),
46 rMax_m(right.rMax_m),
47 phiStart_m(right.phiStart_m),
48 phiEnd_m(right.phiEnd_m),
49 azimuthalExtent_m(right.azimuthalExtent_m),
50 verticalExtent_m(right.verticalExtent_m),
51 centre_m(right.centre_m),
52 endField_m(nullptr),
53 endFieldName_m(right.endFieldName_m),
54 dfCoefficients_m(right.dfCoefficients_m) {
55 endField_m = right.endField_m->clone();
57 Bz_m = right.Bz_m;
58 r0_m = right.r0_m;
59}
60
62
64 ScalingFFAMagnet* magnet = new ScalingFFAMagnet(*this);
65 magnet->initialise();
66 return magnet;
67}
68
70
71const EMField& ScalingFFAMagnet::getField() const { return dummy; }
72
73bool ScalingFFAMagnet::apply(const std::shared_ptr<ParticleContainer_t>& /*pc*/) { return false; }
74
76 const size_t& i, const double& t, Vector_t<double, 3>& E, Vector_t<double, 3>& B) {
77 std::shared_ptr<ParticleContainer_t> pc = RefPartBunch_m->getParticleContainer();
78 auto Rview = pc->R.getView();
79 auto Pview = pc->P.getView();
80
81 const Vector_t<double, 3> R = Rview(i);
82 const Vector_t<double, 3> P = Pview(i);
83 return apply(R, P, t, E, B);
84}
85
87
89 PartBunch_t* bunch, double& /*startField*/, double& /*endField*/) {
90 RefPartBunch_m = bunch;
91 initialise();
92}
93
95
96bool ScalingFFAMagnet::bends() const { return true; }
97
99
101
103 visitor.visitScalingFFAMagnet(*this);
104}
105
108 double r = std::sqrt(pos[0] * pos[0] + pos[2] * pos[2]);
109 double phi = std::atan2(
110 pos[2], pos[0]); // angle between y-axis and position vector in anticlockwise direction
111 Vector_t<double, 3> posCyl({r, pos[1], phi});
112 Vector_t<double, 3> bCyl({0., 0., 0.}); // br bz bphi
113 bool outOfBounds = getFieldValueCylindrical(posCyl, bCyl);
114 // this is cartesian coordinates
115 B[1] += bCyl[1];
116 B[0] += bCyl[0] * std::cos(phi) - bCyl[2] * std::sin(phi);
117 B[2] += bCyl[0] * std::sin(phi) + bCyl[2] * std::cos(phi);
118 return outOfBounds;
119}
120
122 const Vector_t<double, 3>& pos, Vector_t<double, 3>& B) const {
123 double r = pos[0];
124 double z = pos[1];
125 double phi = pos[2];
126 if (r < rMin_m || r > rMax_m) {
127 return true;
128 }
129
130 double normRadius = r / r0_m;
131 double g = tanDelta_m * std::log(normRadius);
132 double phiSpiral = phi - g - phiStart_m;
133 double h = std::pow(normRadius, k_m) * Bz_m;
134 if (phiSpiral < -azimuthalExtent_m || phiSpiral > azimuthalExtent_m) {
135 return true;
136 }
137 if (z < -verticalExtent_m || z > verticalExtent_m) {
138 return true;
139 }
140 // std::cerr << "ScalingFFAMagnet::getFieldValueCylindrical " << phiSpiral << " "
141 // << endField_m->function(phiSpiral, 0) << " " << endField_m->getEndLength()
142 // << " " << endField_m->getCentreLength() << std::endl;
143 std::vector<double> fringeDerivatives(maxOrder_m + 1, 0.);
144 for (size_t i = 0; i < fringeDerivatives.size(); ++i) {
145 fringeDerivatives[i] = endField_m->function(phiSpiral, i); // d^i_phi f
146 }
147 for (size_t n = 0; n < dfCoefficients_m.size(); n += 2) {
148 double f2n = 0;
149 Vector_t<double, 3> deltaB;
150 for (size_t i = 0; i < dfCoefficients_m[n].size(); ++i) {
151 f2n += dfCoefficients_m[n][i] * fringeDerivatives[i];
152 }
153 deltaB[1] = f2n * h * std::pow(z / r, n); // Bz = sum(f_2n * h * (z/r)^2n
154 if (maxOrder_m >= n + 1) {
155 double f2nplus1 = 0;
156 for (size_t i = 0;
157 i < dfCoefficients_m[n + 1].size() && n + 1 < dfCoefficients_m.size(); ++i) {
158 f2nplus1 += dfCoefficients_m[n + 1][i] * fringeDerivatives[i];
159 }
160 deltaB[0] = (f2n * (k_m - n) / (n + 1) - tanDelta_m * f2nplus1) * h
161 * std::pow(z / r, n + 1); // Br
162 deltaB[2] =
163 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
171 const Vector_t<double, 3>& R, const Vector_t<double, 3>& /*P*/, const double& /*t*/,
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] =
190 -(k_m - n) * (k_m - n) / (n + 1) * dfCoefficients_m[n][i] / (n + 2);
191 }
192 for (size_t i = 0; i < dfCoefficients_m[n + 1].size(); ++i) { // i indexes the derivative
193 dfCoefficients_m[n + 2][i] +=
194 2 * (k_m - n) * tanDelta_m * dfCoefficients_m[n + 1][i] / (n + 2);
195 dfCoefficients_m[n + 2][i + 1] -=
196 (1 + tanDelta_m * tanDelta_m) * dfCoefficients_m[n + 1][i] / (n + 2);
197 }
198 }
199}
200
202 if (endField_m != nullptr) {
203 delete endField_m;
204 }
205 endField_m = endField;
206}
207
208extern Inform* gmsg;
209
210// Note this is tested in OpalScalingFFAMagnetTest.*
212 if (endFieldName_m == "") { // no end field is defined
213 return;
214 }
215 std::shared_ptr<endfieldmodel::EndFieldModel> efm =
217 endfieldmodel::EndFieldModel* newEFM = efm->clone();
218 newEFM->rescale(Units::m2mm * 1.0 / getR0());
219 setEndField(newEFM);
220
221 double defaultExtent = (newEFM->getEndLength() * 4. + newEFM->getCentreLength());
222 if (phiStart_m < 0.0) {
223 setPhiStart(defaultExtent / 2.0);
224 } else {
225 setPhiStart(getPhiStart() + newEFM->getCentreLength() * 0.5);
226 }
227 if (phiEnd_m < 0.0) {
228 setPhiEnd(defaultExtent);
229 }
230 if (azimuthalExtent_m < 0.0) {
231 setAzimuthalExtent(newEFM->getEndLength() * 5. + newEFM->getCentreLength() / 2.0);
232 }
235}
ippl::Vector< T, Dim > Vector_t
Template PIC bunch: IPPL PicManager, shared field mesh/solver, and multiple particle containers.
Inform * gmsg
Definition changes.cpp:7
Abstract base class for accelerator geometry classes.
Definition Geometry.h:42
virtual void visitScalingFFAMagnet(const ScalingFFAMagnet &)=0
PartBunch_t * RefPartBunch_m
Definition Component.h:225
Abstract base class for electromagnetic fields.
Definition EMField.h:171
Vector_t< double, Dim > R(size_t)
Do not use; throws (access positions via ParticleContainer::R).
Definition PartBunch.h:611
void setCurvature(double)
Set curvature.
virtual void setElementLength(double)
Set length.
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)
bool apply(const std::shared_ptr< ParticleContainer_t > &pc) override
EMField & getField() override
void setEndField(endfieldmodel::EndFieldModel *endField)
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
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
constexpr double m2mm
Definition Units.h:26