OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
Tracker.cpp
Go to the documentation of this file.
1 // ------------------------------------------------------------------------
2 // $RCSfile: Tracker.cpp,v $
3 // ------------------------------------------------------------------------
4 // $Revision: 1.3.2.1 $
5 // ------------------------------------------------------------------------
6 // Copyright: see Copyright.readme
7 // ------------------------------------------------------------------------
8 //
9 // Class: Tracker
10 // The visitor class for tracking a bunch of particles through a beamline
11 // using a thin-lens approximation for all elements.
12 //
13 // ------------------------------------------------------------------------
14 // Class category: Algorithms
15 // ------------------------------------------------------------------------
16 //
17 // $Date: 2004/11/12 18:57:53 $
18 // $Author: adelmann $
19 //
20 // ------------------------------------------------------------------------
21 
22 #include "Algorithms/Tracker.h"
24 #include "AbsBeamline/Patch.h"
26 #include "Fields/BMultipoleField.h"
27 
28 //FIXME Remove headers and dynamic_cast in readOneBunchFromFile
29 #include "Algorithms/PartBunch.h"
30 #ifdef ENABLE_AMR
31  #include "Algorithms/AmrPartBunch.h"
32 #endif
33 
34 #include <cfloat>
35 #include <cmath>
36 #include <limits>
37 
40 
41 // Class Tracker
42 // ------------------------------------------------------------------------
43 
44 
45 Tracker::Tracker(const Beamline &beamline, const PartData &reference,
46  bool backBeam, bool backTrack):
47  AbstractTracker(beamline, reference, backBeam, backTrack),
48  itsBeamline_m(beamline),
49  itsBunch_m(nullptr)
50 {
51 // #ifdef ENABLE_AMR
52 // if ( Options::amr )
53 // itsBunch = new AmrPartBunch(&reference);
54 // else
55 // #endif
56 // itsBunch = new PartBunch(&reference);
57 }
58 
59 
60 Tracker::Tracker(const Beamline &beamline,
62  const PartData &reference,
63  bool backBeam, bool backTrack):
64  AbstractTracker(beamline, reference, backBeam, backTrack),
65  itsBeamline_m(beamline),
66  itsBunch_m(bunch)
67 {}
68 
69 
71 {}
72 
73 
75  return itsBunch_m;
76 }
77 
78 
79 void Tracker::addToBunch(const OpalParticle &part) {
80  itsBunch_m->push_back(part);
81 }
82 
83 
84 //~ void Tracker::setBunch(const PartBunch &bunch) {
85  //~ itsBunch_m = &bunch;
86 //~ }
87 
88 
91 }
92 
93 
94 void Tracker::visitPatch(const Patch &patch) {
95  Euclid3D transform = patch.getPatch();
96  if(back_path) transform = Inverse(transform);
97  applyTransform(transform);
98 }
99 
100 
102  if(wrap.offset().isIdentity()) {
103  wrap.getElement()->accept(*this);
104  } else {
105  Euclid3D e1 = wrap.getEntranceTransform();
106  Euclid3D e2 = wrap.getExitTransform();
107 
108  if(back_path) {
109  // Tracking right to left.
110  applyTransform(Inverse(e2));
111  wrap.getElement()->accept(*this);
112  applyTransform(Inverse(e1));
113  } else {
114  // Tracking left to right.
115  applyTransform(e1);
116  wrap.getElement()->accept(*this);
117  applyTransform(e2);
118  }
119  }
120 }
121 
122 
125 }
126 
127 
130 }
131 
132 
133 void Tracker::applyDrift(double length) {
134  double kin = itsReference.getM() / itsReference.getP();
135  double refTime = length / itsReference.getBeta();
136 
137  for(unsigned int i = 0; i < itsBunch_m->getLocalNum(); i++) {
138  OpalParticle part = itsBunch_m->get_part(i);
139  if(part.x() != std::numeric_limits<double>::max()) {
140  double px = part.px();
141  double py = part.py();
142  double pt = part.pt() + 1.0;
143  double lByPz = length / sqrt(pt * pt - px * px - py * py);
144  part.x() += px * lByPz;
145  part.y() += py * lByPz;
146  part.t() += pt * (refTime / sqrt(pt * pt + kin * kin) - lByPz);
147  }
148  itsBunch_m->set_part(part, i);
149  }
150 }
151 
152 
154 (const BMultipoleField &field, double scale) {
155  int order = field.order();
156 
157  if(order > 0) {
158  for(unsigned int i = 0; i < itsBunch_m->getLocalNum(); i++) {
159  OpalParticle part = itsBunch_m->get_part(i);
160  if(part.x() != std::numeric_limits<double>::max()) {
161  double x = part.x();
162  double y = part.y();
163  double kx = + field.normal(order);
164  double ky = - field.skew(order);
165 
166  int ord = order;
167  while(--ord > 0) {
168  double kxt = x * kx - y * ky;
169  double kyt = x * ky + y * kx;
170  kx = kxt + field.normal(ord);
171  ky = kyt - field.skew(ord);
172  }
173  part.px() -= kx * scale;
174  part.py() += ky * scale;
175  }
176  itsBunch_m->set_part(part, i);
177  }
178  }
179 }
180 
181 
183 (const BMultipoleField &field, double scale, double h) {
184  Series2 As = buildSBendVectorPotential2D(field, h) * scale;
185  Series2 Fx = As.derivative(0);
186  Series2 Fy = As.derivative(1);
187 
188  // These substitutions work because As depends on x and y only,
189  // and not on px or py.
190  for(unsigned int i = 0; i < itsBunch_m->getLocalNum(); i++) {
191  OpalParticle part = itsBunch_m->get_part(i);
193  z[0] = part.x();
194  z[1] = part.y();
195  part.px() -= Fx.evaluate(z);
196  part.py() -= Fy.evaluate(z);
197  itsBunch_m->set_part(part, i);
198  }
199 }
200 
201 
202 void Tracker::applyTransform(const Euclid3D &euclid, double refLength) {
203  if(! euclid.isIdentity()) {
204  double kin = itsReference.getM() / itsReference.getP();
205  double refTime = refLength / itsReference.getBeta();
206 
207  for(unsigned int i = 0; i < itsBunch_m->getLocalNum(); i++) {
208  OpalParticle part = itsBunch_m->get_part(i);
209  double px = part.px();
210  double py = part.py();
211  double pt = part.pt() + 1.0;
212  double pz = sqrt(pt * pt - px * px - py * py);
213 
214  part.px() = euclid.M(0, 0) * px + euclid.M(1, 0) * py + euclid.M(2, 0) * pz;
215  part.py() = euclid.M(0, 1) * px + euclid.M(1, 1) * py + euclid.M(2, 1) * pz;
216  pz = euclid.M(0, 2) * px + euclid.M(1, 2) * py + euclid.M(2, 2) * pz;
217 
218  double x = part.x() - euclid.getX();
219  double y = part.y() - euclid.getY();
220  double x2 =
221  euclid.M(0, 0) * x + euclid.M(1, 0) * y - euclid.M(2, 0) * euclid.getZ();
222  double y2 =
223  euclid.M(0, 1) * x + euclid.M(1, 1) * y - euclid.M(2, 1) * euclid.getZ();
224  double s2 =
225  euclid.M(0, 2) * x + euclid.M(1, 2) * y - euclid.M(2, 2) * euclid.getZ();
226  double sByPz = s2 / pz;
227 
228  double E = sqrt(pt * pt + kin * kin);
229  part.x() = x2 - sByPz * part.px();
230  part.y() = y2 - sByPz * part.py();
231  part.t() += pt * (refTime / E + sByPz);
232  itsBunch_m->set_part(part, i);
233  }
234  }
235 }
236 
237 
240  int order = field.order();
241 
242  if(order > 0) {
243  static const Series2 x = Series2::makeVariable(0);
244  static const Series2 y = Series2::makeVariable(1);
245  Series2 kx = + field.normal(order) / double(order);
246  Series2 ky = - field.skew(order) / double(order);
247 
248  while(order > 1) {
249  Series2 kxt = x * kx - y * ky;
250  Series2 kyt = x * ky + y * kx;
251  order--;
252  kx = kxt + field.normal(order) / double(order);
253  ky = kyt - field.skew(order) / double(order);
254  }
255 
256  Series2 As = x * kx - y * ky;
257  As.setTruncOrder(As.getMaxOrder());
258  return As;
259  } else {
260  return Series2(0.0);
261  }
262 }
263 
264 
267  int order = field.order();
268 
269  if(order > 0) {
270  static const Series x = Series::makeVariable(X);
271  static const Series y = Series::makeVariable(Y);
272  Series kx = + field.normal(order) / double(order);
273  Series ky = - field.skew(order) / double(order);
274 
275  while(order > 1) {
276  Series kxt = x * kx - y * ky;
277  Series kyt = x * ky + y * kx;
278  order--;
279  kx = kxt + field.normal(order) / double(order);
280  ky = kyt - field.skew(order) / double(order);
281  }
282 
283  Series As = x * kx - y * ky;
284  As.setTruncOrder(As.getMaxOrder());
285  return As;
286  } else {
287  return Series(0.0);
288  }
289 }
290 
291 
292 Series2
294  int order = field.order();
295  Series2 As;
296 
297  if(order > 0) {
298  static const Series2 x = Series2::makeVariable(0);
299  static const Series2 y = Series2::makeVariable(1);
300 
301  // Construct terms constant and linear in y.
302  Series2 Ae = + field.normal(order); // Term even in y.
303  Series2 Ao = - field.skew(order); // Term odd in y.
304 
305  for(int i = order; --i >= 1;) {
306  Ae = Ae * x + field.normal(i);
307  Ao = Ao * x - field.skew(i);
308  }
309  Ae.setTruncOrder(Ae.getMaxOrder());
310  Ao.setTruncOrder(Ao.getMaxOrder());
311 
312  Series2 hx1 = 1. + h * x; // normalized radius
313  Ae = + (Ae * hx1).integral(X);
314  Ao = - (Ao * hx1);
315  // Add terms up to maximum order.
316  As = Ae + y * Ao;
317 
318  int k = 2;
319  if(k <= order) {
320  Series2 yp = y * y / 2.0;
321 
322  while(true) {
323  // Terms even in y.
324  Ae = Ae.derivative(0);
325  Ae = h * Ae / hx1 - Ae.derivative(0);
326  As += Ae * yp;
327  if(++k > order) break;
328  yp *= y / double(k);
329 
330  // Terms odd in y.
331  Ao = Ao.derivative(0);
332  Ao = h * Ao / hx1 - Ao.derivative(0);
333  As += Ao * yp;
334  if(++k > order) break;
335  yp *= y / double(k);
336  }
337  }
338  }
339 
340  return As;
341 }
342 
343 
344 Series
346  int order = field.order();
347  Series As;
348 
349  if(order > 0) {
350  static const Series x = Series::makeVariable(X);
351  static const Series y = Series::makeVariable(Y);
352 
353  // Construct terms constant and linear in y.
354  Series Ae = + field.normal(order); // Term even in y.
355  Series Ao = - field.skew(order); // Term odd in y.
356 
357  for(int i = order; --i >= 1;) {
358  Ae = Ae * x + field.normal(i);
359  Ao = Ao * x - field.skew(i);
360  }
361  Ae.setTruncOrder(Ae.getMaxOrder());
362  Ao.setTruncOrder(Ao.getMaxOrder());
363 
364  Series hx1 = 1. + h * x; // normalized radius
365  Ae = + (Ae * hx1).integral(X);
366  Ao = - (Ao * hx1);
367  // Add terms up to maximum order.
368  As = Ae + y * Ao;
369 
370  int k = 2;
371  if(k <= order) {
372  Series yp = y * y / 2.0;
373 
374  while(true) {
375  // Terms even in y.
376  Ae = Ae.derivative(X);
377  Ae = h * Ae / hx1 - Ae.derivative(X);
378  As += Ae * yp;
379  if(++k > order) break;
380  yp *= y / double(k);
381 
382  // Terms odd in y.
383  Ao = Ao.derivative(X);
384  Ao = h * Ao / hx1 - Ao.derivative(X);
385  As += Ao * yp;
386  if(++k > order) break;
387  yp *= y / double(k);
388  }
389  }
390  }
391 
392  return As;
393 }
double & py()
Get reference to vertical momentum (no dimension).
Definition: OpalParticle.h:122
virtual ElementBase * getElement() const
Return the contained element.
Euclid3D & offset() const
Return the offset.
double getX() const
Get displacement.
Definition: Euclid3D.h:216
Track particles or bunches.
int getMaxOrder() const
Get maximum order.
Definition: FTps.h:174
double normal(int) const
Get component.
void addToBunch(const OpalParticle &)
Add particle to bunch.
Definition: Tracker.cpp:79
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:123
double & x()
Get reference to horizontal position in m.
Definition: OpalParticle.h:110
Define the position of a misaligned element.
Definition: AlignWrapper.h:39
double getZ() const
Get displacement.
Definition: Euclid3D.h:224
FTps< double, 2 > buildSBendVectorPotential2D(const BMultipoleField &, double h)
Construct vector potential for a SBend.
Definition: Tracker.cpp:293
virtual Euclid3D getEntranceTransform() const
Get entrance patch.
Particle reference data.
Definition: PartData.h:38
void applyDrift(double length)
Apply a drift length.
Definition: Tracker.cpp:133
void push_back(OpalParticle p)
virtual void visitPatch(const Patch &pat)
Apply the algorithm to a patch.
Definition: Tracker.cpp:94
double getBeta() const
The relativistic beta per particle.
Definition: PartData.h:127
virtual ~Tracker()
Definition: Tracker.cpp:70
double M(int row, int col) const
Get component.
Definition: Euclid3D.h:228
FTps< double, 6 > Series
Definition: LieMapper.cpp:60
Euclid3D Inverse(const Euclid3D &t)
Euclidean inverse.
Definition: Euclid3D.h:204
FTps< double, 6 > buildMultipoleVectorPotential(const BMultipoleField &)
Construct vector potential for a Multipole.
Definition: Tracker.cpp:266
FTps< double, 2 > buildMultipoleVectorPotential2D(const BMultipoleField &)
Construct vector potential for a Multipole.
Definition: Tracker.cpp:239
virtual Euclid3D getExitTransform() const
Get exit patch.
virtual void visitAlignWrapper(const AlignWrapper &)
Apply the algorithm to an align wrapper.
Definition: Tracker.cpp:101
double skew(int) const
Get component.
virtual void accept(BeamlineVisitor &visitor) const =0
Apply visitor.
OpalParticle get_part(int ii)
virtual void trackBunch(PartBunchBase< double, 3 > *bunch, const PartData &, bool revBeam, bool revTrack) const
Track particle bunch.
Definition: Component.cpp:71
Displacement and rotation in space.
Definition: Euclid3D.h:68
virtual void visitMapIntegrator(const MapIntegrator &)
Apply the algorithm to an integrator capable of mapping.
Definition: Tracker.cpp:128
bool isIdentity() const
Test for identity.
Definition: Euclid3D.h:233
virtual void trackBunch(PartBunchBase< double, 3 > *, const PartData &, bool revBeam, bool revTrack) const
Track a particle bunch.
An abstract sequence of beam line components.
Definition: Beamline.h:37
Integrate particle.
const PartData itsReference
The reference information.
size_t getLocalNum() const
void set_part(FVector< double, 6 > z, int ii)
double & pt()
Get reference to relative momentum error (no dimension).
Definition: OpalParticle.h:125
T evaluate(const FVector< T, N > &) const
Evaluate FTps at point.
Definition: FTps.hpp:934
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
FTps derivative(int var) const
Partial derivative.
Definition: FTps.hpp:1396
virtual void visitComponent(const Component &)
Store the bunch.
Definition: Tracker.cpp:89
double getP() const
The constant reference momentum per particle.
Definition: PartData.h:117
virtual void visitTrackIntegrator(const TrackIntegrator &)
Apply the algorithm to an integrator capable of tracking.
Definition: Tracker.cpp:123
The magnetic field of a multipole.
double getM() const
The constant mass per particle.
Definition: PartData.h:112
FTps< double, 2 > Series2
double & y()
Get reference to vertical displacement in m.
Definition: OpalParticle.h:113
const PartBunchBase< double, 3 > * getBunch() const
Return the current bunch.
Definition: Tracker.cpp:74
FTps< double, 6 > buildSBendVectorPotential(const BMultipoleField &, double h)
Construct vector potential for a SBend.
Definition: Tracker.cpp:345
double & t()
Get reference to longitudinal displacement c*t in m.
Definition: OpalParticle.h:116
void setTruncOrder(int order)
Set truncation order.
Definition: FTps.hpp:393
double & px()
Get reference to horizontal momentum (no dimension).
Definition: OpalParticle.h:119
Truncated power series in N variables of type T.
Interface for a geometric patch.
Definition: Patch.h:34
Interface for a single beam element.
Definition: Component.h:51
void applyThinSBend(const BMultipoleField &field, double scale, double h)
Definition: Tracker.cpp:183
virtual const Euclid3D & getPatch() const =0
Get patch transform.
OpalParticle position.
Definition: OpalParticle.h:38
double getY() const
Get displacement.
Definition: Euclid3D.h:220
PartBunchBase< double, 3 > * itsBunch_m
The bunch of particles to be tracked.
Definition: Tracker.h:174
static FTps makeVariable(int var)
Make variable.
Definition: FTps.hpp:481
int order() const
Return order.
void applyThinMultipole(const BMultipoleField &field, double factor)
Definition: Tracker.cpp:154
Integrate a map.
Definition: MapIntegrator.h:41
virtual void trackBunch(PartBunchBase< double, 3 > *, const PartData &, bool revBeam, bool revTrack) const =0
Track a particle bunch.
void applyTransform(const Euclid3D &, double refLength=0.0)
Apply a geometric transformation.
Definition: Tracker.cpp:202