OPALX (Object Oriented Parallel Accelerator Library for Exascal) MINIorX
OPALX
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
21#include "Fields/Fieldmap.h"
22#include "PartBunch/PartBunch.h"
23#include "Physics/Physics.h"
25
26namespace {
28}
29
30namespace {
31 unsigned int factorial(unsigned int n) {
32 static int fact[] = {1, 1, 2, 6, 24, 120, 720,
33 5040, 40320, 362880, 3628800, 39916800, 479001600};
34 if (n > 12) {
36 "Multipole::factorial", "Factorial can't be larger than 12");
37 }
38 return fact[n];
39 }
40} // namespace
41
44
55
56Multipole::Multipole(const std::string& name)
57 : Component(name),
58 NormalComponents(1, 0.0),
60 SkewComponents(1, 0.0),
61 SkewComponentErrors(1, 0.0),
64 nSlices_m(1) {
65}
66
69
70void Multipole::accept(BeamlineVisitor& visitor) const {
71 visitor.visitMultipole(*this);
72}
73
74double Multipole::getNormalComponent(int n) const {
75 if (n < max_NormalComponent_m) {
76 return NormalComponents[n];
77 }
78 return 0.0;
79}
80
81double Multipole::getSkewComponent(int n) const {
82 if (n < max_SkewComponent_m) {
83 return SkewComponents[n];
84 }
85 return 0.0;
86}
87
88void Multipole::setNormalComponent(int n, double v, double vError) {
89 // getField().setNormalComponent(n, v);
90 PAssert_GE(n, 1);
91
92 if (n > max_NormalComponent_m) {
96 }
97 switch (n - 1) {
98 case DIPOLE:
99 NormalComponents[n - 1] = (v + vError) / 2;
101 break;
102 default:
103 NormalComponents[n - 1] = (v + vError) / factorial(n - 1);
104 NormalComponentErrors[n - 1] = vError / factorial(n - 1);
105 }
106}
107
108void Multipole::setSkewComponent(int n, double v, double vError) {
109 // getField().setSkewComponent(n, v);
110 PAssert_GT(n, 1);
111
112 if (n > max_SkewComponent_m) {
116 }
117 switch (n - 1) {
118 case DIPOLE:
119 SkewComponents[n - 1] = (v + vError) / 2;
120 SkewComponentErrors[n - 1] = SkewComponents[n - 1];
121 break;
122 default:
123 SkewComponents[n - 1] = (v + vError) / factorial(n - 1);
124 SkewComponentErrors[n - 1] = vError / factorial(n - 1);
125 }
126}
127
128// set the number of slices for map tracking
129void Multipole::setNSlices(const std::size_t& nSlices) {
130 nSlices_m = nSlices;
131}
132
133// get the number of slices for map tracking
134std::size_t Multipole::getNSlices() const {
135 return nSlices_m;
136}
137
140 {
141 std::vector<Vector_t<double, 3>> Rn(max_NormalComponent_m + 1);
142 std::vector<double> fact(max_NormalComponent_m + 1);
143 Rn[0] = Vector_t<double, 3>(1.0);
144 fact[0] = 1;
145 for (int i = 0; i < max_NormalComponent_m; ++i) {
146 switch (i) {
147 case DIPOLE:
148 B(1) += NormalComponents[i];
149 break;
150
151 case QUADRUPOLE:
152 B(0) += NormalComponents[i] * R(1);
153 B(1) += NormalComponents[i] * R(0);
154 break;
155
156 case SEXTUPOLE:
157 B(0) += 2 * NormalComponents[i] * R(0) * R(1);
158 B(1) += NormalComponents[i] * (Rn[2](0) - Rn[2](1));
159 break;
160
161 case OCTUPOLE:
162 B(0) += NormalComponents[i] * (3 * Rn[2](0) * Rn[1](1) - Rn[3](1));
163 B(1) += NormalComponents[i] * (Rn[3](0) - 3 * Rn[1](0) * Rn[2](1));
164 break;
165
166 case DECAPOLE:
167 B(0) += 4 * NormalComponents[i] * (Rn[3](0) * Rn[1](1) - Rn[1](0) * Rn[3](1));
168 B(1) += NormalComponents[i] * (Rn[4](0) - 6 * Rn[2](0) * Rn[2](1) + Rn[4](1));
169 break;
170
171 default: {
172 double powMinusOne = 1;
173 double Bx = 0.0, By = 0.0;
174 for (int j = 1; j <= (i + 1) / 2; ++j) {
175 Bx += powMinusOne * NormalComponents[i]
176 * (Rn[i - 2 * j + 1](0) * fact[i - 2 * j + 1] * Rn[2 * j - 1](1)
177 * fact[2 * j - 1]);
178 By += powMinusOne * NormalComponents[i]
179 * (Rn[i - 2 * j + 2](0) * fact[i - 2 * j + 2] * Rn[2 * j - 2](1)
180 * fact[2 * j - 2]);
181 powMinusOne *= -1;
182 }
183
184 if ((i + 1) / 2 == i / 2) {
185 int j = (i + 2) / 2;
186 By += powMinusOne * NormalComponents[i]
187 * (Rn[i - 2 * j + 2](0) * fact[i - 2 * j + 2] * Rn[2 * j - 2](1)
188 * fact[2 * j - 2]);
189 }
190 B(0) += Bx;
191 B(1) += By;
192 }
193 }
194
195 Rn[i + 1](0) = Rn[i](0) * R(0);
196 Rn[i + 1](1) = Rn[i](1) * R(1);
197 fact[i + 1] = fact[i] / (i + 1);
198 }
199 }
200
201 {
202 std::vector<Vector_t<double, 3>> Rn(max_SkewComponent_m + 1);
203 std::vector<double> fact(max_SkewComponent_m + 1);
204 Rn[0] = Vector_t<double, 3>(1.0);
205 fact[0] = 1;
206 for (int i = 0; i < max_SkewComponent_m; ++i) {
207 switch (i) {
208 case DIPOLE:
209 B(0) -= SkewComponents[i];
210 break;
211
212 case QUADRUPOLE:
213 B(0) -= SkewComponents[i] * R(0);
214 B(1) += SkewComponents[i] * R(1);
215 break;
216
217 case SEXTUPOLE:
218 B(0) -= SkewComponents[i] * (Rn[2](0) - Rn[2](1));
219 B(1) += 2 * SkewComponents[i] * R(0) * R(1);
220 break;
221
222 case OCTUPOLE:
223 B(0) -= SkewComponents[i] * (Rn[3](0) - 3 * Rn[1](0) * Rn[2](1));
224 B(1) += SkewComponents[i] * (3 * Rn[2](0) * Rn[1](1) - Rn[3](1));
225 break;
226
227 case DECAPOLE:
228 B(0) -= SkewComponents[i] * (Rn[4](0) - 6 * Rn[2](0) * Rn[2](1) + Rn[4](1));
229 B(1) += 4 * SkewComponents[i] * (Rn[3](0) * Rn[1](1) - Rn[1](0) * Rn[3](1));
230 break;
231
232 default: {
233 double powMinusOne = 1;
234 double Bx = 0, By = 0;
235 for (int j = 1; j <= (i + 1) / 2; ++j) {
236 Bx -= powMinusOne * SkewComponents[i]
237 * (Rn[i - 2 * j + 2](0) * fact[i - 2 * j + 2] * Rn[2 * j - 2](1)
238 * fact[2 * j - 2]);
239 By += powMinusOne * SkewComponents[i]
240 * (Rn[i - 2 * j + 1](0) * fact[i - 2 * j + 1] * Rn[2 * j - 1](1)
241 * fact[2 * j - 1]);
242 powMinusOne *= -1;
243 }
244
245 if ((i + 1) / 2 == i / 2) {
246 int j = (i + 2) / 2;
247 Bx -= powMinusOne * SkewComponents[i]
248 * (Rn[i - 2 * j + 2](0) * fact[i - 2 * j + 2] * Rn[2 * j - 2](1)
249 * fact[2 * j - 2]);
250 }
251
252 B(0) += Bx;
253 B(1) += By;
254 }
255 }
256
257 Rn[i + 1](0) = Rn[i](0) * R(0);
258 Rn[i + 1](1) = Rn[i](1) * R(1);
259 fact[i + 1] = fact[i] / (i + 1);
260 }
261 }
262}
263
265 const size_t& i, const double&, Vector_t<double, 3>& E, Vector_t<double, 3>& B) {
266 //
267 // \todo this is most inefficient
268 std::shared_ptr<ParticleContainer_t> pc = RefPartBunch_m->getParticleContainer();
269 auto Rview = pc->R.getView();
270 const Vector_t<double, 3> R = Rview(i);
271
272 if (R(2) < 0.0 || R(2) > getElementLength())
273 return false;
274 if (!isInsideTransverse(R))
276
277 Vector_t<double, 3> Ef(0.0), Bf(0.0);
278 computeField(R, Ef, Bf);
279
280 for (unsigned int d = 0; d < 3; ++d) {
281 E[d] += Ef(d);
282 B[d] += Bf(d);
283 }
284
285 return false;
286}
287
289 const Vector_t<double, 3>& R, const Vector_t<double, 3>&, const double&, Vector_t<double, 3>& E,
291 if (R(2) < 0.0 || R(2) > getElementLength())
292 return false;
293 if (!isInsideTransverse(R))
295
296 computeField(R, E, B);
297
298 return false;
299}
300
302 const Vector_t<double, 3>& R, const Vector_t<double, 3>&, const double&, Vector_t<double, 3>& E,
304 if (R(2) < 0.0 || R(2) > getElementLength())
305 return false;
306 if (!isInsideTransverse(R))
307 return true;
308
309 for (int i = 0; i < max_NormalComponent_m; ++i) {
311 }
312 for (int i = 0; i < max_SkewComponent_m; ++i) {
314 }
315
316 computeField(R, E, B);
317
318 for (int i = 0; i < max_NormalComponent_m; ++i) {
320 }
321 for (int i = 0; i < max_SkewComponent_m; ++i) {
323 }
324
325 return false;
326}
327
328void Multipole::initialise(PartBunch_t* bunch, double& startField, double& endField) {
329 RefPartBunch_m = bunch;
330 endField = startField + getElementLength();
331 online_m = true;
332}
333
335 online_m = false;
336}
337
338bool Multipole::bends() const {
339 return false;
340}
341
342void Multipole::getDimensions(double& zBegin, double& zEnd) const {
343 zBegin = 0.0;
344 zEnd = getElementLength();
345}
346
350
352 if (r(2) >= 0.0 && r(2) < getElementLength()) {
353 return isInsideTransverse(r);
354 }
355
356 return false;
357}
358
359bool Multipole::isFocusing(unsigned int component) const {
360 if (component >= NormalComponents.size())
361 throw GeneralClassicException("Multipole::isFocusing", "component too big");
362
363 return NormalComponents[component] * std::pow(-1, component + 1)
364 * RefPartBunch_m->getChargePerParticle()
365 > 0.0;
366}
ElementType
Definition ElementBase.h:88
PartBunch< PLayout_t< double, 3 >, double, 3 > PartBunch_t
@ OCTUPOLE
Definition IndexMap.cpp:166
@ DIPOLE
Definition IndexMap.cpp:163
@ DECAPOLE
Definition IndexMap.cpp:167
@ SEXTUPOLE
Definition IndexMap.cpp:165
@ QUADRUPOLE
Definition IndexMap.cpp:164
ippl::Vector< T, Dim > Vector_t
virtual void visitMultipole(const Multipole &)=0
Apply the algorithm to a multipole.
bool online_m
Definition Component.h:186
Component(const std::string &name)
Constructor with given name.
Definition Component.cpp:44
PartBunch_t * RefPartBunch_m
Definition Component.h:185
bool getFlagDeleteOnTransverseExit() const
virtual double getElementLength() const
Get design length.
bool isInsideTransverse(const Vector_t< double, 3 > &r) const
std::vector< double > SkewComponents
Definition Multipole.h:140
virtual void accept(BeamlineVisitor &) const override
Apply visitor to Multipole.
Definition Multipole.cpp:70
int max_NormalComponent_m
Definition Multipole.h:143
virtual void getDimensions(double &zBegin, double &zEnd) const override
virtual void initialise(PartBunch_t *bunch, double &startField, double &endField) override
virtual bool apply(const size_t &i, const double &t, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B) override
std::vector< double > SkewComponentErrors
Definition Multipole.h:141
virtual bool applyToReferenceParticle(const Vector_t< double, 3 > &R, const Vector_t< double, 3 > &P, const double &t, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B) override
virtual void finalise() override
void setNSlices(const std::size_t &nSlices)
virtual bool bends() const override
bool isFocusing(unsigned int component) const
virtual ElementType getType() const override
Get element type std::string.
virtual bool isInside(const Vector_t< double, 3 > &r) const override
std::vector< double > NormalComponents
Definition Multipole.h:138
void computeField(Vector_t< double, 3 > R, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B)
void setNormalComponent(int, double)
Set normal component.
Definition Multipole.h:147
Multipole(const std::string &name)
Constructor with given name.
Definition Multipole.cpp:56
double getSkewComponent(int n) const
Get skew component.
Definition Multipole.cpp:81
int max_SkewComponent_m
Definition Multipole.h:142
std::size_t getNSlices() const
virtual ~Multipole()
Definition Multipole.cpp:67
void setSkewComponent(int, double)
Set skew component.
Definition Multipole.h:151
std::vector< double > NormalComponentErrors
Definition Multipole.h:139
double getNormalComponent(int n) const
Get normal component.
Definition Multipole.cpp:74
std::size_t nSlices_m
Definition Multipole.h:144