OPALX (Object Oriented Parallel Accelerator Library for Exascal) MINIorX
OPALX
TravelingWave.cpp
Go to the documentation of this file.
1//
2// Class TravelingWave
3// Defines the abstract interface for Traveling Wave.
4//
5// Copyright (c) 200x - 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 "PartBunch/PartBunch.h"
22#include "Fields/Fieldmap.h"
23#include "Physics/Units.h"
24
25#include "gsl/gsl_interp.h"
26#include "gsl/gsl_spline.h"
27
28#include <fstream>
29#include <iostream>
30
31extern Inform* gmsg;
32
35
51
52TravelingWave::TravelingWave(const std::string& name)
53 : RFCavity(name),
54 scaleCore_m(1.0),
56 phaseCore1_m(0.0),
57 phaseCore2_m(0.0),
58 phaseExit_m(0.0),
62 periodLength_m(0.0),
63 numCells_m(1),
64 cellLength_m(0.0),
65 mode_m(1) {
66}
67
70
72 visitor.visitTravelingWave(*this);
73}
74
76 const size_t& i, const double& t, Vector_t<double, 3>& E, Vector_t<double, 3>& B) {
77 return apply(RefPartBunch_m->R(i), RefPartBunch_m->P(i), t, E, B);
78}
79
81 const Vector_t<double, 3>& R, const Vector_t<double, 3>& /*P*/, const double& t,
83 if (R(2) < -0.5 * periodLength_m || R(2) + 0.5 * periodLength_m >= getElementLength())
84 return false;
85
86 Vector_t<double, 3> tmpR = Vector_t<double, 3>({R(0), R(1), R(2) + 0.5 * periodLength_m});
87 double tmpcos, tmpsin;
88 Vector_t<double, 3> tmpE({0.0, 0.0, 0.0}), tmpB({0.0, 0.0, 0.0});
89
90 if (tmpR(2) < startCoreField_m) {
91 if (!fieldmap_m->isInside(tmpR))
93
94 tmpcos = (scale_m + scaleError_m) * std::cos(frequency_m * t + phase_m + phaseError_m);
95 tmpsin = -(scale_m + scaleError_m) * std::sin(frequency_m * t + phase_m + phaseError_m);
96
97 } else if (tmpR(2) < startExitField_m) {
98 Vector_t<double, 3> tmpE2({0.0, 0.0, 0.0}), tmpB2({0.0, 0.0, 0.0});
99 tmpR(2) -= startCoreField_m;
100 const double z = tmpR(2);
101 tmpR(2) = tmpR(2) - periodLength_m * std::floor(tmpR(2) / periodLength_m);
102 tmpR(2) += startCoreField_m;
103 if (!fieldmap_m->isInside(tmpR))
105
106 tmpcos = (scaleCore_m + scaleCoreError_m)
107 * std::cos(frequency_m * t + phaseCore1_m + phaseError_m);
108 tmpsin = -(scaleCore_m + scaleCoreError_m)
109 * std::sin(frequency_m * t + phaseCore1_m + phaseError_m);
110 fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
111 E += tmpcos * tmpE;
112 B += tmpsin * tmpB;
113
114 tmpE = 0.0;
115 tmpB = 0.0;
116
117 tmpR(2) = z + cellLength_m;
118 tmpR(2) = tmpR(2) - periodLength_m * std::floor(tmpR(2) / periodLength_m);
119 tmpR(2) += startCoreField_m;
120
121 tmpcos = (scaleCore_m + scaleCoreError_m)
122 * std::cos(frequency_m * t + phaseCore2_m + phaseError_m);
123 tmpsin = -(scaleCore_m + scaleCoreError_m)
124 * std::sin(frequency_m * t + phaseCore2_m + phaseError_m);
125
126 } else {
127 tmpR(2) -= mappedStartExitField_m;
128 if (!fieldmap_m->isInside(tmpR))
130 tmpcos = (scale_m + scaleError_m) * std::cos(frequency_m * t + phaseExit_m + phaseError_m);
131 tmpsin = -(scale_m + scaleError_m) * std::sin(frequency_m * t + phaseExit_m + phaseError_m);
132 }
133
134 fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
135
136 E += tmpcos * tmpE;
137 B += tmpsin * tmpB;
138
139 return false;
140}
141
143 const Vector_t<double, 3>& R, const Vector_t<double, 3>& /*P*/, const double& t,
145 if (R(2) < -0.5 * periodLength_m || R(2) + 0.5 * periodLength_m >= getElementLength())
146 return false;
147
148 Vector_t<double, 3> tmpR = Vector_t<double, 3>({R(0), R(1), R(2) + 0.5 * periodLength_m});
149 double tmpcos, tmpsin;
150 Vector_t<double, 3> tmpE({0.0, 0.0, 0.0}), tmpB({0.0, 0.0, 0.0});
151
152 if (tmpR(2) < startCoreField_m) {
153 if (!fieldmap_m->isInside(tmpR))
154 return true;
155 tmpcos = scale_m * std::cos(frequency_m * t + phase_m);
156 tmpsin = -scale_m * std::sin(frequency_m * t + phase_m);
157
158 } else if (tmpR(2) < startExitField_m) {
159 Vector_t<double, 3> tmpE2({0.0, 0.0, 0.0}), tmpB2({0.0, 0.0, 0.0});
160 tmpR(2) -= startCoreField_m;
161 const double z = tmpR(2);
162 tmpR(2) = tmpR(2) - periodLength_m * std::floor(tmpR(2) / periodLength_m);
163 tmpR(2) += startCoreField_m;
164 if (!fieldmap_m->isInside(tmpR))
165 return true;
166
167 tmpcos = scaleCore_m * std::cos(frequency_m * t + phaseCore1_m);
168 tmpsin = -scaleCore_m * std::sin(frequency_m * t + phaseCore1_m);
169 fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
170 E += tmpcos * tmpE;
171 B += tmpsin * tmpB;
172
173 tmpE = 0.0;
174 tmpB = 0.0;
175
176 tmpR(2) = z + cellLength_m;
177 tmpR(2) = tmpR(2) - periodLength_m * std::floor(tmpR(2) / periodLength_m);
178 tmpR(2) += startCoreField_m;
179
180 tmpcos = scaleCore_m * std::cos(frequency_m * t + phaseCore2_m);
181 tmpsin = -scaleCore_m * std::sin(frequency_m * t + phaseCore2_m);
182
183 } else {
184 tmpR(2) -= mappedStartExitField_m;
185 if (!fieldmap_m->isInside(tmpR))
186 return true;
187
188 tmpcos = scale_m * std::cos(frequency_m * t + phaseExit_m);
189 tmpsin = -scale_m * std::sin(frequency_m * t + phaseExit_m);
190 }
191
192 fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
193 E += tmpcos * tmpE;
194 B += tmpsin * tmpB;
195
196 return false;
197}
198
199void TravelingWave::initialise(PartBunch_t* bunch, double& startField, double& endField) {
200 if (bunch == nullptr) {
201 startField = -0.5 * periodLength_m;
202 endField = startExitField_m;
203 return;
204 }
205
206 Inform msg("TravelingWave ", *gmsg);
207
208 RefPartBunch_m = bunch;
209 double zBegin = 0.0, zEnd = 0.0;
210 RFCavity::initialise(bunch, zBegin, zEnd);
211 if (std::abs(startField_m) > 0.0) {
213 "TravelingWave::initialise",
214 "The field map of a traveling wave structure has to begin at 0.0");
215 }
216
217 periodLength_m = (zEnd - zBegin) / 2.0;
220
224
225 startField = -periodLength_m / 2.0;
226 endField = startField + startExitField_m + periodLength_m / 2.0;
227 setElementLength(endField - startField);
228
234 phase_m
235 - Physics::two_pi * ((numCells_m - 1) * mode_m - std::floor((numCells_m - 1) * mode_m));
236}
237
238void TravelingWave::initialise(PartBunch_t* bunch, std::shared_ptr<AbstractTimeDependence> freq_atd,
239 std::shared_ptr<AbstractTimeDependence> ampl_atd,
240 std::shared_ptr<AbstractTimeDependence> phase_atd) {
241
242}
243
244
247
249 return false;
250}
251
252void TravelingWave::goOnline(const double&) {
253 Fieldmap::readMap(filename_m);
254 online_m = true;
255}
256
258 Fieldmap::freeMap(filename_m);
259}
260
261void TravelingWave::getDimensions(double& zBegin, double& zEnd) const {
262 zBegin = -0.5 * periodLength_m;
263 zEnd = zBegin + getElementLength();
264}
265
266void TravelingWave::getElementDimensions(double& begin, double& end) const {
267 begin = -0.5 * periodLength_m;
269}
270
274
276 const double& E0, const double& t0, const double& q, const double& mass) {
277 std::vector<double> t, E, t2, E2;
278 std::vector<std::pair<double, double> > F;
279 double phi = 0.0, tmp_phi, dphi = 0.5 * Units::deg2rad;
280 double phaseC1 = phaseCore1_m - phase_m;
281 double phaseC2 = phaseCore2_m - phase_m;
282 double phaseE = phaseExit_m - phase_m;
283
284 fieldmap_m->getOnaxisEz(F);
285 if (F.size() == 0)
286 return 0.0;
287
288 int N1 = static_cast<int>(std::floor(F.size() / 4.)) + 1;
289 int N2 = F.size() - 2 * N1 + 1;
290 int N3 = 2 * N1 + static_cast<int>(std::floor((numCells_m - 1) * N2 * mode_m)) - 1;
291 int N4 = static_cast<int>(std::round(N2 * mode_m));
292 double Dz = F[N1 + N2].first - F[N1].first;
293
294 t.resize(N3, t0);
295 t2.resize(N3, t0);
296 E.resize(N3, E0);
297 E2.resize(N3, E0);
298 for (int i = 1; i < N1; ++i) {
299 E[i] = E0 + (F[i].first + F[i - 1].first) / 2. * scale_m / mass;
300 E2[i] = E[i];
301 }
302 for (int i = N1; i < N3 - N1 + 1; ++i) {
303 int I = (i - N1) % N2 + N1;
304 double Z = (F[I].first + F[I - 1].first) / 2. + std::floor((i - N1) / N2) * Dz;
305 E[i] = E0 + Z * scaleCore_m / mass;
306 E2[i] = E[i];
307 }
308 for (int i = N3 - N1 + 1; i < N3; ++i) {
309 int I = i - N3 - 1 + 2 * N1 + N2;
310 double Z = (F[I].first + F[I - 1].first) / 2. + ((numCells_m - 1) * mode_m - 1) * Dz;
311 E[i] = E0 + Z * scale_m / mass;
312 E2[i] = E[i];
313 }
314
315 for (int iter = 0; iter < 10; ++iter) {
316 double A = 0.0;
317 double B = 0.0;
318 for (int i = 1; i < N1; ++i) {
319 t[i] = t[i - 1] + getdT(i, i, E, F, mass);
320 t2[i] = t2[i - 1] + getdT(i, i, E2, F, mass);
321 A += scale_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * getdA(i, i, t, 0.0, F);
322 B += scale_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * getdB(i, i, t, 0.0, F);
323 }
324 for (int i = N1; i < N3 - N1 + 1; ++i) {
325 int I = (i - N1) % N2 + N1;
326 int J = (i - N1 + N4) % N2 + N1;
327 t[i] = t[i - 1] + getdT(i, I, E, F, mass);
328 t2[i] = t2[i - 1] + getdT(i, I, E2, F, mass);
329 A += scaleCore_m * (1. + frequency_m * (t2[i] - t[i]) / dphi)
330 * (getdA(i, I, t, phaseC1, F) + getdA(i, J, t, phaseC2, F));
331 B += scaleCore_m * (1. + frequency_m * (t2[i] - t[i]) / dphi)
332 * (getdB(i, I, t, phaseC1, F) + getdB(i, J, t, phaseC2, F));
333 }
334 for (int i = N3 - N1 + 1; i < N3; ++i) {
335 int I = i - N3 - 1 + 2 * N1 + N2;
336 t[i] = t[i - 1] + getdT(i, I, E, F, mass);
337 t2[i] = t2[i - 1] + getdT(i, I, E2, F, mass);
338 A += scale_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * getdA(i, I, t, phaseE, F);
339 B += scale_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * getdB(i, I, t, phaseE, F);
340 }
341
342 if (std::abs(B) > 0.0000001) {
343 tmp_phi = std::atan(A / B);
344 } else {
345 tmp_phi = Physics::pi / 2;
346 }
347 if (q * (A * std::sin(tmp_phi) + B * std::cos(tmp_phi)) < 0) {
348 tmp_phi += Physics::pi;
349 }
350
351 if (std::abs(phi - tmp_phi) < frequency_m * (t[N3 - 1] - t[0]) / N3) {
352 for (int i = 1; i < N1; ++i) {
353 E[i] = E[i - 1] + q * scale_m * getdE(i, i, t, phi, F);
354 }
355 for (int i = N1; i < N3 - N1 + 1; ++i) {
356 int I = (i - N1) % N2 + N1;
357 int J = (i - N1 + N4) % N2 + N1;
358 E[i] =
359 E[i - 1]
360 + q * scaleCore_m
361 * (getdE(i, I, t, phi + phaseC1, F) + getdE(i, J, t, phi + phaseC2, F));
362 }
363 for (int i = N3 - N1 + 1; i < N3; ++i) {
364 int I = i - N3 - 1 + 2 * N1 + N2;
365 E[i] = E[i - 1] + q * scale_m * getdE(i, I, t, phi + phaseE, F);
366 }
367
368 const int prevPrecision = ippl::Info->precision(8);
369 *ippl::Info << level2 << "estimated phase= " << tmp_phi
370 << " rad = " << tmp_phi * Units::rad2deg << " deg,\n"
371 << "Ekin= " << E[N3 - 1] << " MeV" << std::setprecision(prevPrecision)
372 << "\n"
373 << endl;
374 return tmp_phi;
375 }
376 phi = tmp_phi - std::round(tmp_phi / Physics::two_pi) * Physics::two_pi;
377
378 for (int i = 1; i < N1; ++i) {
379 E[i] = E[i - 1] + q * scale_m * getdE(i, i, t, phi, F);
380 E2[i] = E2[i - 1]
381 + q * scale_m * getdE(i, i, t, phi + dphi, F); // should I use here t or t2?
382 t[i] = t[i - 1] + getdT(i, i, E, F, mass);
383 t2[i] = t2[i - 1] + getdT(i, i, E2, F, mass);
384 E[i] = E[i - 1] + q * scale_m * getdE(i, i, t, phi, F);
385 E2[i] = E2[i - 1] + q * scale_m * getdE(i, i, t2, phi + dphi, F);
386 }
387 for (int i = N1; i < N3 - N1 + 1; ++i) {
388 int I = (i - N1) % N2 + N1;
389 int J = (i - N1 + N4) % N2 + N1;
390 E[i] = E[i - 1]
391 + q * scaleCore_m
392 * (getdE(i, I, t, phi + phaseC1, F) + getdE(i, J, t, phi + phaseC2, F));
393 E2[i] = E2[i - 1]
394 + q * scaleCore_m
395 * (getdE(i, I, t, phi + phaseC1 + dphi, F)
396 + getdE(i, J, t, phi + phaseC2 + dphi, F)); // concerning t: see above
397 t[i] = t[i - 1] + getdT(i, I, E, F, mass);
398 t2[i] = t2[i - 1] + getdT(i, I, E2, F, mass);
399 E[i] = E[i - 1]
400 + q * scaleCore_m
401 * (getdE(i, I, t, phi + phaseC1, F) + getdE(i, J, t, phi + phaseC2, F));
402 E2[i] = E2[i - 1]
403 + q * scaleCore_m
404 * (getdE(i, I, t2, phi + phaseC1 + dphi, F)
405 + getdE(i, J, t2, phi + phaseC2 + dphi, F));
406 }
407 for (int i = N3 - N1 + 1; i < N3; ++i) {
408 int I = i - N3 - 1 + 2 * N1 + N2;
409 E[i] = E[i - 1] + q * scale_m * getdE(i, I, t, phi + phaseE, F);
410 E2[i] =
411 E2[i - 1]
412 + q * scale_m * getdE(i, I, t, phi + phaseE + dphi, F); // concerning t: see above
413 t[i] = t[i - 1] + getdT(i, I, E, F, mass);
414 t2[i] = t2[i - 1] + getdT(i, I, E2, F, mass);
415 E[i] = E[i - 1] + q * scale_m * getdE(i, I, t, phi + phaseE, F);
416 E2[i] = E2[i - 1] + q * scale_m * getdE(i, I, t2, phi + phaseE + dphi, F);
417 }
418 // msg << ", Ekin= " << E[N3-1] << " MeV" << endl;
419 }
420
421 const int prevPrecision = ippl::Info->precision(8);
422 *ippl::Info << level2 << "estimated phase= " << tmp_phi << " rad = " << tmp_phi * Units::rad2deg
423 << " deg,\n"
424 << "Ekin= " << E[N3 - 1] << " MeV" << std::setprecision(prevPrecision) << "\n"
425 << endl;
426
427 return phi;
428}
429
431 return (isInsideTransverse(r) && r(2) >= -0.5 * periodLength_m && r(2) < startExitField_m);
432}
Inform * gmsg
Definition changes.cpp:7
ElementType
Definition ElementBase.h:88
PartBunch< PLayout_t< double, 3 >, double, 3 > PartBunch_t
ippl::Vector< T, Dim > Vector_t
PartBunch< T, Dim >::ConstIterator end(PartBunch< T, Dim > const &bunch)
PartBunch< T, Dim >::ConstIterator begin(PartBunch< T, Dim > const &bunch)
constexpr double two_pi
The value of.
Definition Physics.h:33
constexpr double pi
The value of.
Definition Physics.h:30
constexpr double rad2deg
Definition Units.h:146
constexpr double deg2rad
Definition Units.h:143
virtual void visitTravelingWave(const TravelingWave &)=0
Apply the algorithm to a traveling wave.
bool online_m
Definition Component.h:186
PartBunch_t * RefPartBunch_m
Definition Component.h:185
bool getFlagDeleteOnTransverseExit() const
virtual void setElementLength(double length)
Set design length.
bool isInsideTransverse(const Vector_t< double, 3 > &r) const
Fieldmap * fieldmap_m
Definition RFCavity.h:200
virtual void initialise(PartBunch_t *bunch, double &startField, double &endField) override
Definition RFCavity.cpp:164
std::string filename_m
Definition RFCavity.h:187
double scale_m
Definition RFCavity.h:189
double phaseError_m
Definition RFCavity.h:192
RFCavity(const std::string &name)
Constructor with given name.
Definition RFCavity.cpp:81
double frequency_m
Definition RFCavity.h:193
double startField_m
Definition RFCavity.h:201
double scaleError_m
Definition RFCavity.h:190
virtual double getElementLength() const override
Get design length.
Definition RFCavity.cpp:721
double phase_m
Definition RFCavity.h:191
double periodLength_m
double mappedStartExitField_m
double getdA(const int &i, const int &I, const std::vector< double > &t, const double &phi, const std::vector< std::pair< double, double > > &F) const
virtual ElementType getType() const override
Get element type std::string.
double phaseCore2_m
virtual bool bends() const override
virtual void accept(BeamlineVisitor &) const override
Apply visitor to TravelingWave.
virtual void getDimensions(double &zBegin, double &zEnd) const override
double getdB(const int &i, const int &I, const std::vector< double > &t, const double &phi, const std::vector< std::pair< double, double > > &F) const
virtual double getAutoPhaseEstimate(const double &E0, const double &t0, const double &q, const double &m) override
double startExitField_m
virtual void goOffline() override
double getdE(const int &i, const int &I, const std::vector< double > &t, const double &phi, const std::vector< std::pair< double, double > > &F) const
virtual void initialise(PartBunch_t *bunch, double &startField, double &endField) override
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 bool apply(const size_t &i, const double &t, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B) override
virtual void finalise() override
virtual bool isInside(const Vector_t< double, 3 > &r) const override
double scaleCoreError_m
virtual ~TravelingWave()
virtual void getElementDimensions(double &begin, double &end) const override
TravelingWave(const std::string &name)
Constructor with given name.
double getdT(const int &i, const int &I, const std::vector< double > &E, const std::vector< std::pair< double, double > > &F, const double mass) const
double phaseCore1_m
double startCoreField_m
virtual void goOnline(const double &kineticEnergy) override