OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
Tracker.cpp
Go to the documentation of this file.
1//
2// Class Tracker
3// Track particles or bunches.
4// An abstract base class for all visitors capable of tracking particles
5// through a beam element.
6// [P]
7// Phase space coordinates (in this order):
8// [DL]
9// [DT]x:[DD]
10// horizontal displacement (metres).
11// [DT]p_x/p_r:[DD]
12// horizontal canonical momentum (no dimension).
13// [DT]y:[DD]
14// vertical displacement (metres).
15// [DT]p_y/p_r:[DD]
16// vertical canonical momentum (no dimension).
17// [DT]delta_p/p_r:[DD]
18// relative momentum error (no dimension).
19// [DT]v*delta_t:[DD]
20// time difference delta_t w.r.t. the reference frame which moves with
21// uniform velocity
22// [P]
23// v_r = c*beta_r = p_r/m
24// [P]
25// along the design orbit, multiplied by the instantaneous velocity v of
26// the particle (metres).
27// [/DL]
28// Where
29// [DL]
30// [DT]p_r:[DD]
31// is the constant reference momentum defining the reference frame velocity.
32// [DT]m:[DD]
33// is the rest mass of the particles.
34// [/DL]
35// Other units used:
36// [DL]
37// [DT]reference momentum:[DD]
38// electron-volts.
39// [DT]accelerating voltage:[DD]
40// volts.
41// [DT]separator voltage:[DD]
42// volts.
43// [DT]frequencies:[DD]
44// hertz.
45// [DT]phase lags:[DD]
46// multiples of (2*pi).
47// [/DL]
48//
49// Copyright (c) 200x - 2020, Paul Scherrer Institut, Villigen PSI, Switzerland
50// All rights reserved
51//
52// This file is part of OPAL.
53//
54// OPAL is free software: you can redistribute it and/or modify
55// it under the terms of the GNU General Public License as published by
56// the Free Software Foundation, either version 3 of the License, or
57// (at your option) any later version.
58//
59// You should have received a copy of the GNU General Public License
60// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
61//
62#include "Algorithms/Tracker.h"
64
65//FIXME Remove headers and dynamic_cast in readOneBunchFromFile
67#ifdef ENABLE_AMR
69#endif
70
71#include <cfloat>
72#include <cmath>
73#include <limits>
74
77
78// Class Tracker
79// ------------------------------------------------------------------------
80
81
82Tracker::Tracker(const Beamline &beamline, const PartData &reference,
83 bool backBeam, bool backTrack):
84 Tracker(beamline, nullptr, reference, backBeam, backTrack)
85{}
86
87
88Tracker::Tracker(const Beamline &beamline,
90 const PartData &reference,
91 bool backBeam, bool backTrack):
92 AbstractTracker(beamline, reference, backBeam, backTrack),
93 itsBeamline_m(beamline),
94 itsBunch_m(bunch)
95{}
96
97
100
101
103 return itsBunch_m;
104}
105
106
108 itsBunch_m->push_back(part);
109}
110
111
112//~ void Tracker::setBunch(const PartBunch &bunch) {
113 //~ itsBunch_m = &bunch;
114//~ }
115
116
120
121
122void Tracker::applyDrift(double length) {
123 double kin = itsReference.getM() / itsReference.getP();
124 double refTime = length / itsReference.getBeta();
125
126 for(unsigned int i = 0; i < itsBunch_m->getLocalNum(); i++) {
127 OpalParticle part = itsBunch_m->getParticle(i);
128 if(part.getX() != std::numeric_limits<double>::max()) {
129 const Vector_t& P = part.getP();
130 double lByPz = length / std::sqrt(2 * P[2] * P[2] - dot(P, P));
131 part.setX(part.getX() + P[0] * lByPz);
132 part.setY(part.getY() + P[1] * lByPz);
133 part.setZ(part.getZ() + P[2] * (refTime / std::sqrt(P[2] * P[2] + kin * kin) - lByPz));
134 }
135 itsBunch_m->setParticle(part, i);
136 }
137}
138
139
141(const BMultipoleField &field, double scale) {
142 int order = field.order();
143
144 if(order > 0) {
145 for(unsigned int i = 0; i < itsBunch_m->getLocalNum(); i++) {
146 OpalParticle part = itsBunch_m->getParticle(i);
147 if(part.getX() != std::numeric_limits<double>::max()) {
148 double x = part.getX();
149 double y = part.getY();
150 double kx = + field.normal(order);
151 double ky = - field.skew(order);
152
153 int ord = order;
154 while(--ord > 0) {
155 double kxt = x * kx - y * ky;
156 double kyt = x * ky + y * kx;
157 kx = kxt + field.normal(ord);
158 ky = kyt - field.skew(ord);
159 }
160 part.setPx(part.getPx() - kx * scale);
161 part.setPy(part.getPy() + ky * scale);
162 }
163 itsBunch_m->setParticle(part, i);
164 }
165 }
166}
167
168
170(const BMultipoleField &field, double scale, double h) {
171 Series2 As = buildSBendVectorPotential2D(field, h) * scale;
172 Series2 Fx = As.derivative(0);
173 Series2 Fy = As.derivative(1);
174
175 // These substitutions work because As depends on x and y only,
176 // and not on px or py.
177 for(unsigned int i = 0; i < itsBunch_m->getLocalNum(); i++) {
178 OpalParticle part = itsBunch_m->getParticle(i);
180 z[0] = part.getX();
181 z[1] = part.getY();
182 part.setPx(part.getPx() - Fx.evaluate(z));
183 part.setPy(part.getPy() - Fy.evaluate(z));
184 itsBunch_m->setParticle(part, i);
185 }
186}
187
188
189void Tracker::applyTransform(const Euclid3D &euclid, double refLength) {
190 if(! euclid.isIdentity()) {
191 double kin = itsReference.getM() / itsReference.getP();
192 double refTime = refLength / itsReference.getBeta();
193
194 for(unsigned int i = 0; i < itsBunch_m->getLocalNum(); i++) {
195 OpalParticle part = itsBunch_m->getParticle(i);
196 double px = part.getPx();
197 double py = part.getPy();
198 double pt = part.getPz() + 1.0;
199 double pz = std::sqrt(pt * pt - px * px - py * py);
200
201 part.setPx(euclid.M(0, 0) * px + euclid.M(1, 0) * py + euclid.M(2, 0) * pz);
202 part.setPy(euclid.M(0, 1) * px + euclid.M(1, 1) * py + euclid.M(2, 1) * pz);
203 pz = euclid.M(0, 2) * px + euclid.M(1, 2) * py + euclid.M(2, 2) * pz;
204
205 double x = part.getX() - euclid.getX();
206 double y = part.getY() - euclid.getY();
207 double x2 =
208 euclid.M(0, 0) * x + euclid.M(1, 0) * y - euclid.M(2, 0) * euclid.getZ();
209 double y2 =
210 euclid.M(0, 1) * x + euclid.M(1, 1) * y - euclid.M(2, 1) * euclid.getZ();
211 double s2 =
212 euclid.M(0, 2) * x + euclid.M(1, 2) * y - euclid.M(2, 2) * euclid.getZ();
213 double sByPz = s2 / pz;
214
215 double E = std::sqrt(pt * pt + kin * kin);
216 part.setX(x2 - sByPz * part.getPx());
217 part.setY(y2 - sByPz * part.getPy());
218 part.setZ(part.getZ() + pt * (refTime / E + sByPz));
219 itsBunch_m->setParticle(part, i);
220 }
221 }
222}
223
224
227 int order = field.order();
228
229 if(order > 0) {
230 static const Series2 x = Series2::makeVariable(0);
231 static const Series2 y = Series2::makeVariable(1);
232 Series2 kx = + field.normal(order) / double(order);
233 Series2 ky = - field.skew(order) / double(order);
234
235 while(order > 1) {
236 Series2 kxt = x * kx - y * ky;
237 Series2 kyt = x * ky + y * kx;
238 order--;
239 kx = kxt + field.normal(order) / double(order);
240 ky = kyt - field.skew(order) / double(order);
241 }
242
243 Series2 As = x * kx - y * ky;
244 As.setTruncOrder(As.getMaxOrder());
245 return As;
246 } else {
247 return Series2(0.0);
248 }
249}
250
251
254 int order = field.order();
255
256 if(order > 0) {
257 static const Series x = Series::makeVariable(X);
258 static const Series y = Series::makeVariable(Y);
259 Series kx = + field.normal(order) / double(order);
260 Series ky = - field.skew(order) / double(order);
261
262 while(order > 1) {
263 Series kxt = x * kx - y * ky;
264 Series kyt = x * ky + y * kx;
265 order--;
266 kx = kxt + field.normal(order) / double(order);
267 ky = kyt - field.skew(order) / double(order);
268 }
269
270 Series As = x * kx - y * ky;
271 As.setTruncOrder(As.getMaxOrder());
272 return As;
273 } else {
274 return Series(0.0);
275 }
276}
277
278
281 int order = field.order();
282 Series2 As;
283
284 if(order > 0) {
285 static const Series2 x = Series2::makeVariable(0);
286 static const Series2 y = Series2::makeVariable(1);
287
288 // Construct terms constant and linear in y.
289 Series2 Ae = + field.normal(order); // Term even in y.
290 Series2 Ao = - field.skew(order); // Term odd in y.
291
292 for(int i = order; --i >= 1;) {
293 Ae = Ae * x + field.normal(i);
294 Ao = Ao * x - field.skew(i);
295 }
296 Ae.setTruncOrder(Ae.getMaxOrder());
297 Ao.setTruncOrder(Ao.getMaxOrder());
298
299 Series2 hx1 = 1. + h * x; // normalized radius
300 Ae = + (Ae * hx1).integral(X);
301 Ao = - (Ao * hx1);
302 // Add terms up to maximum order.
303 As = Ae + y * Ao;
304
305 int k = 2;
306 if(k <= order) {
307 Series2 yp = y * y / 2.0;
308
309 while(true) {
310 // Terms even in y.
311 Ae = Ae.derivative(0);
312 Ae = h * Ae / hx1 - Ae.derivative(0);
313 As += Ae * yp;
314 if(++k > order) break;
315 yp *= y / double(k);
316
317 // Terms odd in y.
318 Ao = Ao.derivative(0);
319 Ao = h * Ao / hx1 - Ao.derivative(0);
320 As += Ao * yp;
321 if(++k > order) break;
322 yp *= y / double(k);
323 }
324 }
325 }
326
327 return As;
328}
329
330
331Series
333 int order = field.order();
334 Series As;
335
336 if(order > 0) {
337 static const Series x = Series::makeVariable(X);
338 static const Series y = Series::makeVariable(Y);
339
340 // Construct terms constant and linear in y.
341 Series Ae = + field.normal(order); // Term even in y.
342 Series Ao = - field.skew(order); // Term odd in y.
343
344 for(int i = order; --i >= 1;) {
345 Ae = Ae * x + field.normal(i);
346 Ao = Ao * x - field.skew(i);
347 }
348 Ae.setTruncOrder(Ae.getMaxOrder());
349 Ao.setTruncOrder(Ao.getMaxOrder());
350
351 Series hx1 = 1. + h * x; // normalized radius
352 Ae = + (Ae * hx1).integral(X);
353 Ao = - (Ao * hx1);
354 // Add terms up to maximum order.
355 As = Ae + y * Ao;
356
357 int k = 2;
358 if(k <= order) {
359 Series yp = y * y / 2.0;
360
361 while(true) {
362 // Terms even in y.
363 Ae = Ae.derivative(X);
364 Ae = h * Ae / hx1 - Ae.derivative(X);
365 As += Ae * yp;
366 if(++k > order) break;
367 yp *= y / double(k);
368
369 // Terms odd in y.
370 Ao = Ao.derivative(X);
371 Ao = h * Ao / hx1 - Ao.derivative(X);
372 As += Ao * yp;
373 if(++k > order) break;
374 yp *= y / double(k);
375 }
376 }
377 }
378
379 return As;
380}
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition Vector3D.cpp:118
FTps< double, 6 > Series
Definition Tracker.cpp:76
FTps< double, 2 > Series2
Definition Tracker.cpp:75
Interface for a single beam element.
Definition Component.h:50
virtual void trackBunch(PartBunchBase< double, 3 > *bunch, const PartData &, bool revBeam, bool revTrack) const
Track particle bunch.
Definition Component.cpp:71
const PartData itsReference
The reference information.
AbstractTracker(const Beamline &, const PartData &, bool backBeam, bool backTrack)
Constructor.
void setPy(double)
Set the vertical momentum.
double getPy() const
Get vertical momentum (no dimension).
const Vector_t & getP() const
Get momentum.
double getPz() const
Get relative momentum error (no dimension).
void setPx(double)
Set the horizontal momentum.
void setZ(double)
Set longitudinal position in m.
void setY(double)
Set the vertical displacement in m.
double getY() const
Get vertical displacement in m.
double getZ() const
Get longitudinal displacement c*t in m.
double getPx() const
Get horizontal momentum (no dimension).
double getX() const
Get horizontal position in m.
void setX(double)
Set the horizontal position in m.
virtual ~Tracker()
Definition Tracker.cpp:98
void applyThinMultipole(const BMultipoleField &field, double factor)
Definition Tracker.cpp:141
void applyTransform(const Euclid3D &, double refLength=0.0)
Apply a geometric transformation.
Definition Tracker.cpp:189
FTps< double, 2 > buildSBendVectorPotential2D(const BMultipoleField &, double h)
Construct vector potential for a SBend.
Definition Tracker.cpp:280
FTps< double, 6 > buildSBendVectorPotential(const BMultipoleField &, double h)
Construct vector potential for a SBend.
Definition Tracker.cpp:332
void applyThinSBend(const BMultipoleField &field, double scale, double h)
Definition Tracker.cpp:170
FTps< double, 6 > buildMultipoleVectorPotential(const BMultipoleField &)
Construct vector potential for a Multipole.
Definition Tracker.cpp:253
Tracker(const Beamline &, const PartData &, bool backBeam, bool backTrack)
Constructor.
Definition Tracker.cpp:82
const Beamline & itsBeamline_m
Definition Tracker.h:122
virtual void visitComponent(const Component &)
Store the bunch.
Definition Tracker.cpp:117
void addToBunch(const OpalParticle &)
Add particle to bunch.
Definition Tracker.cpp:107
void applyDrift(double length)
Apply a drift length.
Definition Tracker.cpp:122
PartBunchBase< double, 3 > * itsBunch_m
The bunch of particles to be tracked.
Definition Tracker.h:151
const PartBunchBase< double, 3 > * getBunch() const
Return the current bunch.
Definition Tracker.cpp:102
FTps< double, 2 > buildMultipoleVectorPotential2D(const BMultipoleField &)
Construct vector potential for a Multipole.
Definition Tracker.cpp:226
Displacement and rotation in space.
Definition Euclid3D.h:68
double getX() const
Get displacement.
Definition Euclid3D.h:216
double getY() const
Get displacement.
Definition Euclid3D.h:220
double M(int row, int col) const
Get component.
Definition Euclid3D.h:228
bool isIdentity() const
Test for identity.
Definition Euclid3D.h:233
double getZ() const
Get displacement.
Definition Euclid3D.h:224
An abstract sequence of beam line components.
Definition Beamline.h:34
The magnetic field of a multipole.
int order() const
Return order.
double normal(int) const
Get component.
double skew(int) const
Get component.
Truncated power series in N variables of type T.
Definition FTps.h:45
void setTruncOrder(int order)
Set truncation order.
Definition FTps.hpp:393
FTps derivative(int var) const
Partial derivative.
Definition FTps.hpp:1396
static FTps makeVariable(int var)
T evaluate(const FVector< T, N > &) const
Evaluate FTps at point.
Definition FTps.hpp:934
int getMaxOrder() const
Get maximum order.
Definition FTps.h:174
A templated representation for vectors.
Definition FVector.h:38
Vektor< double, 3 > Vector_t