OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
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 //
18 #include "AbsBeamline/Multipole.h"
19 
22 #include "Fields/Fieldmap.h"
23 #include "Physics/Physics.h"
25 
26 namespace{
27  enum {
28  DIPOLE,
29  QUADRUPOLE,
30  SEXTUPOLE,
31  OCTUPOLE,
32  DECAPOLE
33  };
34 }
35 
36 namespace {
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 
64 Multipole::Multipole(const std::string &name):
65  Component(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 
80 void Multipole::accept(BeamlineVisitor &visitor) const {
81  visitor.visitMultipole(*this);
82 }
83 
84 
85 double Multipole::getNormalComponent(int n) const {
86  if (n < max_NormalComponent_m) {
87  return NormalComponents[n];
88  }
89  return 0.0;
90 }
91 
92 
93 double Multipole::getSkewComponent(int n) const {
94  if (n < max_SkewComponent_m) {
95  return SkewComponents[n];
96  }
97  return 0.0;
98 }
99 
100 
101 void Multipole::setNormalComponent(int n, double v, double vError) {
102  // getField().setNormalComponent(n, v);
103  PAssert_GE(n, 1);
104 
105  if(n > max_NormalComponent_m) {
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 
121 void 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) {
127  SkewComponents.resize(max_SkewComponent_m, 0.0);
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
142 void Multipole::setNSlices(const std::size_t& nSlices) {
143  nSlices_m = nSlices;
144 }
145 
146 //get the number of slices for map tracking
147 std::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 
274 bool 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;
277  if (!isInsideTransverse(R)) return true;
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 
290 bool 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;
292  if (!isInsideTransverse(R)) return true;
293 
294  computeField(R, E, B);
295 
296  return false;
297 }
298 
299 bool 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 
322 void 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 
333 bool Multipole::bends() const {
334  return false;
335 }
336 
337 
338 void Multipole::getDimensions(double &zBegin, double &zEnd) const {
339  zBegin = 0.0;
340  zEnd = getElementLength();
341 }
342 
343 
345  return MULTIPOLE;
346 }
347 
348 
349 bool 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 
357 bool 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 }
@ 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
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
#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:195
PartBunchBase< double, 3 > * RefPartBunch_m
Definition: Component.h:194
virtual double getElementLength() const
Get design length.
Definition: ElementBase.h:432
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
virtual ElementBase::ElementType getType() const override
Get element type std::string.
Definition: Multipole.cpp:344
bool isFocusing(unsigned int component) const
Definition: Multipole.cpp:357
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