OPAL (Object Oriented Parallel Accelerator Library)  2024.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 //
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;
113  NormalComponentErrors[n - 1] = NormalComponents[n - 1];
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;
133  SkewComponentErrors[n - 1] = SkewComponents[n - 1];
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;
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;
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 ElementType::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 }
std::vector< double > NormalComponentErrors
Definition: Multipole.h:138
#define PAssert_GE(a, b)
Definition: PAssert.h:109
virtual bool isInside(const Vector_t &r) const override
Definition: Multipole.cpp:349
virtual void accept(BeamlineVisitor &) const override
Apply visitor to Multipole.
Definition: Multipole.cpp:80
void setNormalComponent(int, double)
Set normal component.
Definition: Multipole.h:147
item[EANGLE] Entrance edge counterclockwise This enables to obtain skew at each point along the its radius is computed such that the reference trajectory always remains in the centre of the magnet In the body of the magnet the radius is set from the LENGTH and ANGLE attributes It is then continuously changed to be proportional to the dipole field on the reference trajectory while entering the end fields This attribute is only to be set TRUE for a non zero dipole component(Default:FALSE)\item[VARSTEP] The step size(meters) used in calculating the reference trajectory for VARRARDIUS
bool isFocusing(unsigned int component) const
Definition: Multipole.cpp:357
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6
virtual void finalise() override
Definition: Multipole.cpp:329
virtual bool apply(const size_t &i, const double &t, Vector_t &E, Vector_t &B) override
Definition: Multipole.cpp:274
virtual bool bends() const override
Definition: Multipole.cpp:333
int max_NormalComponent_m
Definition: Multipole.h:142
PartBunchBase< double, 3 > * RefPartBunch_m
Definition: Component.h:191
Interface for general multipole.
Definition: Multipole.h:47
void setNSlices(const std::size_t &nSlices)
Definition: Multipole.cpp:142
virtual ~Multipole()
Definition: Multipole.cpp:76
std::vector< double > NormalComponents
Definition: Multipole.h:137
virtual void visitMultipole(const Multipole &)=0
Apply the algorithm to a multipole.
bool getFlagDeleteOnTransverseExit() const
Definition: ElementBase.h:614
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
std::vector< double > SkewComponents
Definition: Multipole.h:139
bool online_m
Definition: Component.h:192
std::size_t getNSlices() const
Definition: Multipole.cpp:147
virtual void getDimensions(double &zBegin, double &zEnd) const override
Definition: Multipole.cpp:338
ElementType
Definition: ElementBase.h:88
void computeField(Vector_t R, Vector_t &E, Vector_t &B)
Definition: Multipole.cpp:151
virtual double getElementLength() const
Get design length.
Definition: ElementBase.h:415
double getNormalComponent(int n) const
Get normal component.
Definition: Multipole.cpp:85
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
Definition: Multipole.cpp:322
double getChargePerParticle() const
get the macro particle charge
bool isInsideTransverse(const Vector_t &r) const
const std::string name
ParticlePos_t & R
int max_SkewComponent_m
Definition: Multipole.h:141
double getSkewComponent(int n) const
Get skew component.
Definition: Multipole.cpp:93
std::vector< double > SkewComponentErrors
Definition: Multipole.h:140
Interface for a single beam element.
Definition: Component.h:50
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
void setSkewComponent(int, double)
Set skew component.
Definition: Multipole.h:152
#define PAssert_GT(a, b)
Definition: PAssert.h:108
std::size_t nSlices_m
Definition: Multipole.h:143
virtual ElementType getType() const override
Get element type std::string.
Definition: Multipole.cpp:344