OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
Multipole.cpp
Go to the documentation of this file.
1//
2// Class Multipole
3// The MULTIPOLE element defines a thick multipole.
4//
5// Copyright (c) 2012-2021, Paul Scherrer Institut, Villigen PSI, Switzerland
6// All rights reserved
7//
8// This file is part of OPAL.
9//
10// OPAL is free software: you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// You should have received a copy of the GNU General Public License
16// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
17//
19
22#include "Fields/Fieldmap.h"
23#include "Physics/Physics.h"
25
26namespace{
27 enum {
28 DIPOLE,
33 };
34}
35
36namespace {
37 unsigned int factorial(unsigned int n) {
38 static int fact[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320,
39 362880, 3628800, 39916800, 479001600};
40 if (n > 12) {
41 throw GeneralClassicException("Multipole::factorial", "Factorial can't be larger than 12");
42 }
43 return fact[n];
44 }
45}
46
48 Multipole("")
49{}
50
51
53 Component(right),
54 NormalComponents(right.NormalComponents),
55 NormalComponentErrors(right.NormalComponentErrors),
56 SkewComponents(right.SkewComponents),
57 SkewComponentErrors(right.SkewComponentErrors),
58 max_SkewComponent_m(right.max_SkewComponent_m),
59 max_NormalComponent_m(right.max_NormalComponent_m),
60 nSlices_m(right.nSlices_m) {
61}
62
63
64Multipole::Multipole(const std::string &name):
66 NormalComponents(1, 0.0),
67 NormalComponentErrors(1, 0.0),
68 SkewComponents(1, 0.0),
69 SkewComponentErrors(1, 0.0),
70 max_SkewComponent_m(1),
71 max_NormalComponent_m(1),
72 nSlices_m(1) {
73}
74
75
77{}
78
79
80void Multipole::accept(BeamlineVisitor &visitor) const {
81 visitor.visitMultipole(*this);
82}
83
84
87 return NormalComponents[n];
88 }
89 return 0.0;
90}
91
92
93double Multipole::getSkewComponent(int n) const {
94 if (n < max_SkewComponent_m) {
95 return SkewComponents[n];
96 }
97 return 0.0;
98}
99
100
101void Multipole::setNormalComponent(int n, double v, double vError) {
102 // getField().setNormalComponent(n, v);
103 PAssert_GE(n, 1);
104
109 }
110 switch(n-1) {
111 case DIPOLE:
112 NormalComponents[n - 1] = (v + vError) / 2;
114 break;
115 default:
116 NormalComponents[n - 1] = (v + vError) / factorial(n-1);
117 NormalComponentErrors[n - 1] = vError / factorial(n-1);
118 }
119}
120
121void Multipole::setSkewComponent(int n, double v, double vError) {
122 // getField().setSkewComponent(n, v);
123 PAssert_GT(n, 1);
124
125 if(n > max_SkewComponent_m) {
129 }
130 switch(n-1) {
131 case DIPOLE:
132 SkewComponents[n - 1] = (v + vError) / 2;
134 break;
135 default:
136 SkewComponents[n - 1] = (v + vError) / factorial(n-1);
137 SkewComponentErrors[n - 1] = vError / factorial(n-1);
138 }
139}
140
141//set the number of slices for map tracking
142void Multipole::setNSlices(const std::size_t& nSlices) {
143 nSlices_m = nSlices;
144}
145
146//get the number of slices for map tracking
147std::size_t Multipole::getNSlices() const {
148 return nSlices_m;
149}
150
152 {
153 std::vector<Vector_t> Rn(max_NormalComponent_m + 1);
154 std::vector<double> fact(max_NormalComponent_m + 1);
155 Rn[0] = Vector_t(1.0);
156 fact[0] = 1;
157 for (int i = 0; i < max_NormalComponent_m; ++ i) {
158 switch(i) {
159 case DIPOLE:
160 B(1) += NormalComponents[i];
161 break;
162
163 case QUADRUPOLE:
164 B(0) += NormalComponents[i] * R(1);
165 B(1) += NormalComponents[i] * R(0);
166 break;
167
168 case SEXTUPOLE:
169 B(0) += 2 * NormalComponents[i] * R(0) * R(1);
170 B(1) += NormalComponents[i] * (Rn[2](0) - Rn[2](1));
171 break;
172
173 case OCTUPOLE:
174 B(0) += NormalComponents[i] * (3 * Rn[2](0) * Rn[1](1) - Rn[3](1));
175 B(1) += NormalComponents[i] * (Rn[3](0) - 3 * Rn[1](0) * Rn[2](1));
176 break;
177
178 case DECAPOLE:
179 B(0) += 4 * NormalComponents[i] * (Rn[3](0) * Rn[1](1) - Rn[1](0) * Rn[3](1));
180 B(1) += NormalComponents[i] * (Rn[4](0) - 6 * Rn[2](0) * Rn[2](1) + Rn[4](1));
181 break;
182
183 default:
184 {
185 double powMinusOne = 1;
186 double Bx = 0.0, By = 0.0;
187 for (int j = 1; j <= (i + 1) / 2; ++ j) {
188 Bx += powMinusOne * NormalComponents[i] * (Rn[i - 2 * j + 1](0) * fact[i - 2 * j + 1] *
189 Rn[2 * j - 1](1) * fact[2 * j - 1]);
190 By += powMinusOne * NormalComponents[i] * (Rn[i - 2 * j + 2](0) * fact[i - 2 * j + 2] *
191 Rn[2 * j - 2](1) * fact[2 * j - 2]);
192 powMinusOne *= -1;
193 }
194
195 if ((i + 1) / 2 == i / 2) {
196 int j = (i + 2) / 2;
197 By += powMinusOne * NormalComponents[i] * (Rn[i - 2 * j + 2](0) * fact[i - 2 * j + 2] *
198 Rn[2 * j - 2](1) * fact[2 * j - 2]);
199 }
200 B(0) += Bx;
201 B(1) += By;
202 }
203 }
204
205 Rn[i + 1](0) = Rn[i](0) * R(0);
206 Rn[i + 1](1) = Rn[i](1) * R(1);
207 fact[i + 1] = fact[i] / (i + 1);
208 }
209 }
210
211 {
212
213 std::vector<Vector_t> Rn(max_SkewComponent_m + 1);
214 std::vector<double> fact(max_SkewComponent_m + 1);
215 Rn[0] = Vector_t(1.0);
216 fact[0] = 1;
217 for (int i = 0; i < max_SkewComponent_m; ++ i) {
218 switch(i) {
219 case DIPOLE:
220 B(0) -= SkewComponents[i];
221 break;
222
223 case QUADRUPOLE:
224 B(0) -= SkewComponents[i] * R(0);
225 B(1) += SkewComponents[i] * R(1);
226 break;
227
228 case SEXTUPOLE:
229 B(0) -= SkewComponents[i] * (Rn[2](0) - Rn[2](1));
230 B(1) += 2 * SkewComponents[i] * R(0) * R(1);
231 break;
232
233 case OCTUPOLE:
234 B(0) -= SkewComponents[i] * (Rn[3](0) - 3 * Rn[1](0) * Rn[2](1));
235 B(1) += SkewComponents[i] * (3 * Rn[2](0) * Rn[1](1) - Rn[3](1));
236 break;
237
238 case DECAPOLE:
239 B(0) -= SkewComponents[i] * (Rn[4](0) - 6 * Rn[2](0) * Rn[2](1) + Rn[4](1));
240 B(1) += 4 * SkewComponents[i] * (Rn[3](0) * Rn[1](1) - Rn[1](0) * Rn[3](1));
241 break;
242
243 default:
244 {
245 double powMinusOne = 1;
246 double Bx = 0, By = 0;
247 for (int j = 1; j <= (i + 1) / 2; ++ j) {
248 Bx -= powMinusOne * SkewComponents[i] * (Rn[i - 2 * j + 2](0) * fact[i - 2 * j + 2] *
249 Rn[2 * j - 2](1) * fact[2 * j - 2]);
250 By += powMinusOne * SkewComponents[i] * (Rn[i - 2 * j + 1](0) * fact[i - 2 * j + 1] *
251 Rn[2 * j - 1](1) * fact[2 * j - 1]);
252 powMinusOne *= -1;
253 }
254
255 if ((i + 1) / 2 == i / 2) {
256 int j = (i + 2) / 2;
257 Bx -= powMinusOne * SkewComponents[i] * (Rn[i - 2 * j + 2](0) * fact[i - 2 * j + 2] *
258 Rn[2 * j - 2](1) * fact[2 * j - 2]);
259 }
260
261 B(0) += Bx;
262 B(1) += By;
263 }
264 }
265
266 Rn[i + 1](0) = Rn[i](0) * R(0);
267 Rn[i + 1](1) = Rn[i](1) * R(1);
268 fact[i + 1] = fact[i] / (i + 1);
269 }
270 }
271}
272
273
274bool Multipole::apply(const size_t &i, const double &, Vector_t &E, Vector_t &B) {
275 const Vector_t &R = RefPartBunch_m->R[i];
276 if(R(2) < 0.0 || R(2) > getElementLength()) return false;
278
279 Vector_t Ef(0.0), Bf(0.0);
280 computeField(R, Ef, Bf);
281
282 for (unsigned int d = 0; d < 3; ++ d) {
283 E[d] += Ef(d);
284 B[d] += Bf(d);
285 }
286
287 return false;
288}
289
290bool Multipole::apply(const Vector_t &R, const Vector_t &, const double &, Vector_t &E, Vector_t &B) {
291 if(R(2) < 0.0 || R(2) > getElementLength()) return false;
293
294 computeField(R, E, B);
295
296 return false;
297}
298
299bool Multipole::applyToReferenceParticle(const Vector_t &R, const Vector_t &, const double &, Vector_t &E, Vector_t &B) {
300 if(R(2) < 0.0 || R(2) > getElementLength()) return false;
301 if (!isInsideTransverse(R)) return true;
302
303 for (int i = 0; i < max_NormalComponent_m; ++ i) {
305 }
306 for (int i = 0; i < max_SkewComponent_m; ++ i) {
308 }
309
310 computeField(R, E, B);
311
312 for (int i = 0; i < max_NormalComponent_m; ++ i) {
314 }
315 for (int i = 0; i < max_SkewComponent_m; ++ i) {
317 }
318
319 return false;
320}
321
322void Multipole::initialise(PartBunchBase<double, 3> *bunch, double &startField, double &endField) {
323 RefPartBunch_m = bunch;
324 endField = startField + getElementLength();
325 online_m = true;
326}
327
328
330 online_m = false;
331}
332
333bool Multipole::bends() const {
334 return false;
335}
336
337
338void Multipole::getDimensions(double &zBegin, double &zEnd) const {
339 zBegin = 0.0;
340 zEnd = getElementLength();
341}
342
343
346}
347
348
349bool Multipole::isInside(const Vector_t &r) const {
350 if (r(2) >= 0.0 && r(2) < getElementLength()) {
351 return isInsideTransverse(r);
352 }
353
354 return false;
355}
356
357bool Multipole::isFocusing(unsigned int component) const {
358 if (component >= NormalComponents.size()) throw GeneralClassicException("Multipole::isFocusing", "component too big");
359
360 return NormalComponents[component] * std::pow(-1, component + 1) * RefPartBunch_m->getChargePerParticle() > 0.0;
361}
ElementType
Definition: ElementBase.h:88
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
@ OCTUPOLE
Definition: IndexMap.cpp:167
@ DIPOLE
Definition: IndexMap.cpp:164
@ DECAPOLE
Definition: IndexMap.cpp:168
@ SEXTUPOLE
Definition: IndexMap.cpp:166
@ QUADRUPOLE
Definition: IndexMap.cpp:165
#define PAssert_GE(a, b)
Definition: PAssert.h:109
#define PAssert_GT(a, b)
Definition: PAssert.h:108
const std::string name
ParticlePos_t & R
double getChargePerParticle() const
get the macro particle charge
virtual void visitMultipole(const Multipole &)=0
Apply the algorithm to a multipole.
Interface for a single beam element.
Definition: Component.h:50
bool online_m
Definition: Component.h:192
PartBunchBase< double, 3 > * RefPartBunch_m
Definition: Component.h:191
bool getFlagDeleteOnTransverseExit() const
Definition: ElementBase.h:613
virtual double getElementLength() const
Get design length.
Definition: ElementBase.h:414
bool isInsideTransverse(const Vector_t &r) const
Interface for general multipole.
Definition: Multipole.h:47
virtual bool apply(const size_t &i, const double &t, Vector_t &E, Vector_t &B) override
Definition: Multipole.cpp:274
std::vector< double > SkewComponents
Definition: Multipole.h:139
virtual void accept(BeamlineVisitor &) const override
Apply visitor to Multipole.
Definition: Multipole.cpp:80
int max_NormalComponent_m
Definition: Multipole.h:142
void computeField(Vector_t R, Vector_t &E, Vector_t &B)
Definition: Multipole.cpp:151
virtual void getDimensions(double &zBegin, double &zEnd) const override
Definition: Multipole.cpp:338
std::vector< double > SkewComponentErrors
Definition: Multipole.h:140
virtual void finalise() override
Definition: Multipole.cpp:329
void setNSlices(const std::size_t &nSlices)
Definition: Multipole.cpp:142
virtual bool bends() const override
Definition: Multipole.cpp:333
bool isFocusing(unsigned int component) const
Definition: Multipole.cpp:357
virtual ElementType getType() const override
Get element type std::string.
Definition: Multipole.cpp:344
std::vector< double > NormalComponents
Definition: Multipole.h:137
void setNormalComponent(int, double)
Set normal component.
Definition: Multipole.h:147
double getSkewComponent(int n) const
Get skew component.
Definition: Multipole.cpp:93
int max_SkewComponent_m
Definition: Multipole.h:141
std::size_t getNSlices() const
Definition: Multipole.cpp:147
virtual bool applyToReferenceParticle(const Vector_t &R, const Vector_t &P, const double &t, Vector_t &E, Vector_t &B) override
Definition: Multipole.cpp:299
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
Definition: Multipole.cpp:322
virtual ~Multipole()
Definition: Multipole.cpp:76
void setSkewComponent(int, double)
Set skew component.
Definition: Multipole.h:152
std::vector< double > NormalComponentErrors
Definition: Multipole.h:138
double getNormalComponent(int n) const
Get normal component.
Definition: Multipole.cpp:85
std::size_t nSlices_m
Definition: Multipole.h:143
virtual bool isInside(const Vector_t &r) const override
Definition: Multipole.cpp:349
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6