OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
TravelingWave.cpp
Go to the documentation of this file.
1
9
12#include "Fields/Fieldmap.h"
13#include "PartBunch/PartBunch.h"
14#include "Physics/Units.h"
16
17extern Inform* gmsg;
18
20
22 : RFCavity(right),
23 scaleCore_m(right.scaleCore_m),
24 scaleCoreError_m(right.scaleCoreError_m),
25 phaseCore1_m(right.phaseCore1_m),
26 phaseCore2_m(right.phaseCore2_m),
27 phaseExit_m(right.phaseExit_m),
28 startCoreField_m(right.startCoreField_m),
29 startExitField_m(right.startExitField_m),
30 mappedStartExitField_m(right.mappedStartExitField_m),
31 periodLength_m(right.periodLength_m),
32 numCells_m(right.numCells_m),
33 cellLength_m(right.cellLength_m),
34 mode_m(right.mode_m) {}
35
36TravelingWave::TravelingWave(const std::string& name)
37 : RFCavity(name),
38 scaleCore_m(1.0),
39 scaleCoreError_m(0.0),
40 phaseCore1_m(0.0),
41 phaseCore2_m(0.0),
42 phaseExit_m(0.0),
43 startCoreField_m(0.0),
44 startExitField_m(0.0),
45 mappedStartExitField_m(0.0),
46 periodLength_m(0.0),
47 numCells_m(1),
48 cellLength_m(0.0),
49 mode_m(1) {}
50
52
53void TravelingWave::accept(BeamlineVisitor& visitor) const { visitor.visitTravelingWave(*this); }
54
55/* ========================================================================== */
56/* ============================== Apply Functions =========================== */
66bool TravelingWave::apply(const std::shared_ptr<ParticleContainer_t>& pc) {
67 // RF parameters (copied to device)
68 const double freq = frequency_m;
69 const double scaleEntry = scale_m + scaleError_m;
70 const double scaleCore = scaleCore_m + scaleCoreError_m;
71 const double phaseError = phaseError_m;
72
73 const double startField = startField_m;
74 const double startCoreField = startCoreField_m;
75 const double startExitField = startExitField_m;
76 const double mappedStartExit = mappedStartExitField_m;
77 const double periodLength = periodLength_m;
78 const double cellLength = cellLength_m;
79 const double fieldLength = endField_m - startField_m;
80
81 // Reference particle time -> to be consistent with OPAL
82 const double t = RefPartBunch_m->getT() + 0.5 * RefPartBunch_m->getdT();
83 const double omega_t = freq * t;
84
85 const double cosEntry = std::cos(omega_t + phase_m + phaseError);
86 const double sinEntry = std::sin(omega_t + phase_m + phaseError);
87
88 const double cosCore1 = std::cos(omega_t + phaseCore1_m + phaseError);
89 const double sinCore1 = std::sin(omega_t + phaseCore1_m + phaseError);
90
91 const double cosCore2 = std::cos(omega_t + phaseCore2_m + phaseError);
92 const double sinCore2 = std::sin(omega_t + phaseCore2_m + phaseError);
93
94 const double cosExit = std::cos(omega_t + phaseExit_m + phaseError);
95 const double sinExit = std::sin(omega_t + phaseExit_m + phaseError);
96
97 auto* dynamicFieldmap = dynamic_cast<Astra1DDynamic*>(fieldmap_m);
98 if (dynamicFieldmap == nullptr) {
100 "TravelingWave::apply",
101 "TravelingWave particle application currently requires an Astra1DDynamic field "
102 "map.");
103 }
104
105 dynamicFieldmap->applyTravelingWave(
106 pc, scaleEntry * cosEntry, -scaleEntry * sinEntry, scaleCore * cosCore1,
107 -scaleCore * sinCore1, scaleCore * cosCore2, -scaleCore * sinCore2,
108 scaleEntry * cosExit, -scaleEntry * sinExit, startField, startCoreField, startExitField,
109 mappedStartExit, periodLength, cellLength, fieldLength);
110
111 return false;
112}
113
115 const size_t& i, const double& t, Vector_t<double, 3>& E, Vector_t<double, 3>& B) {
116 std::shared_ptr<ParticleContainer_t> pc = RefPartBunch_m->getParticleContainer();
117 auto Rview = pc->R.getView();
118 auto Pview = pc->P.getView();
119 const Vector_t<double, 3> R = Rview(i);
120 const Vector_t<double, 3> P = Pview(i);
121
122 return apply(R, P, t, E, B);
123}
124
126 const Vector_t<double, 3>& R, const Vector_t<double, 3>& /*P*/, const double& t,
128 const double omega_t = frequency_m * t;
129 if (R(2) < startField_m || R(2) >= endField_m) return false;
130
131 Vector_t<double, 3> tmpR({R(0), R(1), R(2) - startField_m});
132 Vector_t<double, 3> tmpE({0.0, 0.0, 0.0}), tmpB({0.0, 0.0, 0.0});
133 double tmpcos = 0.0, tmpsin = 0.0;
134
135 if (tmpR(2) < startCoreField_m) {
137
138 tmpcos = (scale_m + scaleError_m) * std::cos(omega_t + phase_m + phaseError_m);
139 tmpsin = -(scale_m + scaleError_m) * std::sin(omega_t + phase_m + phaseError_m);
140
141 } else if (tmpR(2) < startExitField_m) {
142 tmpR(2) -= startCoreField_m;
143 const double z = tmpR(2);
144 tmpR(2) = tmpR(2) - periodLength_m * std::floor(tmpR(2) / periodLength_m);
145 tmpR(2) += startCoreField_m;
146
148
149 tmpcos = (scaleCore_m + scaleCoreError_m) * std::cos(omega_t + phaseCore1_m + phaseError_m);
150 tmpsin =
151 -(scaleCore_m + scaleCoreError_m) * std::sin(omega_t + phaseCore1_m + phaseError_m);
152
153 fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
154 E += tmpcos * tmpE;
155 B += tmpsin * tmpB;
156
157 tmpE = 0.0;
158 tmpB = 0.0;
159
160 tmpR(2) = z + cellLength_m;
161 tmpR(2) = tmpR(2) - periodLength_m * std::floor(tmpR(2) / periodLength_m);
162 tmpR(2) += startCoreField_m;
163
164 tmpcos = (scaleCore_m + scaleCoreError_m) * std::cos(omega_t + phaseCore2_m + phaseError_m);
165 tmpsin =
166 -(scaleCore_m + scaleCoreError_m) * std::sin(omega_t + phaseCore2_m + phaseError_m);
167
168 } else {
169 tmpR(2) -= mappedStartExitField_m;
171
172 tmpcos = (scale_m + scaleError_m) * std::cos(omega_t + phaseExit_m + phaseError_m);
173 tmpsin = -(scale_m + scaleError_m) * std::sin(omega_t + phaseExit_m + phaseError_m);
174 }
175
176 fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
177 E += tmpcos * tmpE;
178 B += tmpsin * tmpB;
179
180 return false;
181}
182
184 const Vector_t<double, 3>& R, const Vector_t<double, 3>& /*P*/, const double& t,
186 const double omega_t = frequency_m * t;
187
188 if (R(2) < startField_m || R(2) >= endField_m) return false;
189
190 Vector_t<double, 3> tmpR({R(0), R(1), R(2) - startField_m});
191 Vector_t<double, 3> tmpE({0.0, 0.0, 0.0}), tmpB({0.0, 0.0, 0.0});
192 double tmpcos = 0.0, tmpsin = 0.0;
193
194 if (tmpR(2) < startCoreField_m) {
195 if (!fieldmap_m->isInside(tmpR)) return true;
196
197 tmpcos = scale_m * std::cos(omega_t + phase_m);
198 tmpsin = -scale_m * std::sin(omega_t + phase_m);
199
200 } else if (tmpR(2) < startExitField_m) {
201 tmpR(2) -= startCoreField_m;
202 const double z = tmpR(2);
203 tmpR(2) = tmpR(2) - periodLength_m * std::floor(tmpR(2) / periodLength_m);
204 tmpR(2) += startCoreField_m;
205
206 if (!fieldmap_m->isInside(tmpR)) return true;
207
208 tmpcos = scaleCore_m * std::cos(omega_t + phaseCore1_m);
209 tmpsin = -scaleCore_m * std::sin(omega_t + phaseCore1_m);
210
211 fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
212 E += tmpcos * tmpE;
213 B += tmpsin * tmpB;
214
215 tmpE = 0.0;
216 tmpB = 0.0;
217
218 tmpR(2) = z + cellLength_m;
219 tmpR(2) = tmpR(2) - periodLength_m * std::floor(tmpR(2) / periodLength_m);
220 tmpR(2) += startCoreField_m;
221
222 tmpcos = scaleCore_m * std::cos(omega_t + phaseCore2_m);
223 tmpsin = -scaleCore_m * std::sin(omega_t + phaseCore2_m);
224
225 } else {
226 tmpR(2) -= mappedStartExitField_m;
227 if (!fieldmap_m->isInside(tmpR)) return true;
228
229 tmpcos = scale_m * std::cos(omega_t + phaseExit_m);
230 tmpsin = -scale_m * std::sin(omega_t + phaseExit_m);
231 }
232
233 fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
234 E += tmpcos * tmpE;
235 B += tmpsin * tmpB;
236
237 return false;
238}
239
240void TravelingWave::initialise(PartBunch_t* bunch, double& startField, double& endField) {
241 if (bunch == nullptr) {
242 return;
243 }
244
245 Inform msg("TravelingWave ", *gmsg);
246
247 RefPartBunch_m = bunch;
248 double bodyBegin = startField;
249 double dummyStart = 0.0;
250 double dummyEnd = 0.0;
251 RFCavity::initialise(bunch, dummyStart, dummyEnd);
252 if (std::abs(startField_m) > 0.0) {
254 "TravelingWave::initialise",
255 "The field map of a traveling wave structure has to begin at 0.0");
256 }
257
261
265
267
268 startField = bodyBegin + startField_m;
269 endField = bodyBegin + endField_m;
270
276 phase_m
277 - Physics::two_pi * ((numCells_m - 1) * mode_m - std::floor((numCells_m - 1) * mode_m));
278}
279
281 PartBunch_t* /*bunch*/, std::shared_ptr<AbstractTimeDependence> /*freq_atd*/,
282 std::shared_ptr<AbstractTimeDependence> /*ampl_atd*/,
283 std::shared_ptr<AbstractTimeDependence> /*phase_atd*/) {
284 *gmsg << "not implemented:: file: " << __FILE__ << " line: " << __LINE__
285 << " function: " << __func__ << endl;
286}
287
289
290bool TravelingWave::bends() const { return false; }
291
292void TravelingWave::goOnline(const double&) {
293 Fieldmap::readMap(filename_m);
294 online_m = true;
295}
296
297void TravelingWave::goOffline() { Fieldmap::freeMap(filename_m); }
298
299void TravelingWave::getFieldExtend(double& zBegin, double& zEnd) const {
300 zBegin = startField_m;
301 zEnd = endField_m;
302}
303
304void TravelingWave::getElementDimensions(double& begin, double& end) const {
305 begin = 0.0;
306 end = getElementLength();
307}
308
310
312 const double& E0, const double& t0, const double& q, const double& mass) {
313 std::vector<double> t, E, t2, E2;
314 std::vector<std::pair<double, double> > F;
315 double phi = 0.0, tmp_phi, dphi = 0.5 * Units::deg2rad;
316 double phaseC1 = phaseCore1_m - phase_m;
317 double phaseC2 = phaseCore2_m - phase_m;
318 double phaseE = phaseExit_m - phase_m;
319
321 if (F.size() == 0) return 0.0;
322
323 int N1 = static_cast<int>(std::floor(F.size() / 4.)) + 1;
324 int N2 = F.size() - 2 * N1 + 1;
325 int N3 = 2 * N1 + static_cast<int>(std::floor((numCells_m - 1) * N2 * mode_m)) - 1;
326 int N4 = static_cast<int>(std::round(N2 * mode_m));
327 double Dz = F[N1 + N2].first - F[N1].first;
328
329 t.resize(N3, t0);
330 t2.resize(N3, t0);
331 E.resize(N3, E0);
332 E2.resize(N3, E0);
333 for (int i = 1; i < N1; ++i) {
334 E[i] = E0 + (F[i].first + F[i - 1].first) / 2. * scale_m / mass;
335 E2[i] = E[i];
336 }
337 for (int i = N1; i < N3 - N1 + 1; ++i) {
338 int I = (i - N1) % N2 + N1;
339 double Z = (F[I].first + F[I - 1].first) / 2. + std::floor((i - N1) / N2) * Dz;
340 E[i] = E0 + Z * scaleCore_m / mass;
341 E2[i] = E[i];
342 }
343 for (int i = N3 - N1 + 1; i < N3; ++i) {
344 int I = i - N3 - 1 + 2 * N1 + N2;
345 double Z = (F[I].first + F[I - 1].first) / 2. + ((numCells_m - 1) * mode_m - 1) * Dz;
346 E[i] = E0 + Z * scale_m / mass;
347 E2[i] = E[i];
348 }
349
350 for (int iter = 0; iter < 10; ++iter) {
351 double A = 0.0;
352 double B = 0.0;
353 for (int i = 1; i < N1; ++i) {
354 t[i] = t[i - 1] + getdT(i, i, E, F, mass);
355 t2[i] = t2[i - 1] + getdT(i, i, E2, F, mass);
356 A += scale_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * getdA(i, i, t, 0.0, F);
357 B += scale_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * getdB(i, i, t, 0.0, F);
358 }
359 for (int i = N1; i < N3 - N1 + 1; ++i) {
360 int I = (i - N1) % N2 + N1;
361 int J = (i - N1 + N4) % N2 + N1;
362 t[i] = t[i - 1] + getdT(i, I, E, F, mass);
363 t2[i] = t2[i - 1] + getdT(i, I, E2, F, mass);
364 A += scaleCore_m * (1. + frequency_m * (t2[i] - t[i]) / dphi)
365 * (getdA(i, I, t, phaseC1, F) + getdA(i, J, t, phaseC2, F));
366 B += scaleCore_m * (1. + frequency_m * (t2[i] - t[i]) / dphi)
367 * (getdB(i, I, t, phaseC1, F) + getdB(i, J, t, phaseC2, F));
368 }
369 for (int i = N3 - N1 + 1; i < N3; ++i) {
370 int I = i - N3 - 1 + 2 * N1 + N2;
371 t[i] = t[i - 1] + getdT(i, I, E, F, mass);
372 t2[i] = t2[i - 1] + getdT(i, I, E2, F, mass);
373 A += scale_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * getdA(i, I, t, phaseE, F);
374 B += scale_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * getdB(i, I, t, phaseE, F);
375 }
376
377 if (std::abs(B) > 0.0000001) {
378 tmp_phi = std::atan(A / B);
379 } else {
380 tmp_phi = Physics::pi / 2;
381 }
382 if (q * (A * std::sin(tmp_phi) + B * std::cos(tmp_phi)) < 0) {
383 tmp_phi += Physics::pi;
384 }
385
386 if (std::abs(phi - tmp_phi) < frequency_m * (t[N3 - 1] - t[0]) / N3) {
387 for (int i = 1; i < N1; ++i) {
388 E[i] = E[i - 1] + q * scale_m * getdE(i, i, t, phi, F);
389 }
390 for (int i = N1; i < N3 - N1 + 1; ++i) {
391 int I = (i - N1) % N2 + N1;
392 int J = (i - N1 + N4) % N2 + N1;
393 E[i] = E[i - 1]
394 + q * scaleCore_m
395 * (getdE(i, I, t, phi + phaseC1, F)
396 + getdE(i, J, t, phi + phaseC2, F));
397 }
398 for (int i = N3 - N1 + 1; i < N3; ++i) {
399 int I = i - N3 - 1 + 2 * N1 + N2;
400 E[i] = E[i - 1] + q * scale_m * getdE(i, I, t, phi + phaseE, F);
401 }
402
403 const int prevPrecision = ippl::Info->precision(8);
404 Inform m("TravelingWave::getAutoPhaseEstimate");
405 m << level2 << "estimated phase= " << tmp_phi << " rad = " << tmp_phi * Units::rad2deg
406 << " deg,\n"
407 << "Ekin= " << E[N3 - 1] << " MeV" << std::setprecision(prevPrecision) << "\n"
408 << endl;
409 return tmp_phi;
410 }
411 phi = tmp_phi - std::round(tmp_phi / Physics::two_pi) * Physics::two_pi;
412
413 for (int i = 1; i < N1; ++i) {
414 E[i] = E[i - 1] + q * scale_m * getdE(i, i, t, phi, F);
415 E2[i] = E2[i - 1]
416 + q * scale_m * getdE(i, i, t, phi + dphi, F); // should I use here t or t2?
417 t[i] = t[i - 1] + getdT(i, i, E, F, mass);
418 t2[i] = t2[i - 1] + getdT(i, i, E2, F, mass);
419 E[i] = E[i - 1] + q * scale_m * getdE(i, i, t, phi, F);
420 E2[i] = E2[i - 1] + q * scale_m * getdE(i, i, t2, phi + dphi, F);
421 }
422 for (int i = N1; i < N3 - N1 + 1; ++i) {
423 int I = (i - N1) % N2 + N1;
424 int J = (i - N1 + N4) % N2 + N1;
425 E[i] = E[i - 1]
426 + q * scaleCore_m
427 * (getdE(i, I, t, phi + phaseC1, F)
428 + getdE(i, J, t, phi + phaseC2, F));
429 E2[i] = E2[i - 1]
430 + q * scaleCore_m
431 * (getdE(i, I, t, phi + phaseC1 + dphi, F)
432 + getdE(i, J, t, phi + phaseC2 + dphi,
433 F)); // concerning t: see above
434 t[i] = t[i - 1] + getdT(i, I, E, F, mass);
435 t2[i] = t2[i - 1] + getdT(i, I, E2, F, mass);
436 E[i] = E[i - 1]
437 + q * scaleCore_m
438 * (getdE(i, I, t, phi + phaseC1, F)
439 + getdE(i, J, t, phi + phaseC2, F));
440 E2[i] = E2[i - 1]
441 + q * scaleCore_m
442 * (getdE(i, I, t2, phi + phaseC1 + dphi, F)
443 + getdE(i, J, t2, phi + phaseC2 + dphi, F));
444 }
445 for (int i = N3 - N1 + 1; i < N3; ++i) {
446 int I = i - N3 - 1 + 2 * N1 + N2;
447 E[i] = E[i - 1] + q * scale_m * getdE(i, I, t, phi + phaseE, F);
448 E2[i] = E2[i - 1]
449 + q * scale_m
450 * getdE(i, I, t, phi + phaseE + dphi, F); // concerning t: see above
451 t[i] = t[i - 1] + getdT(i, I, E, F, mass);
452 t2[i] = t2[i - 1] + getdT(i, I, E2, F, mass);
453 E[i] = E[i - 1] + q * scale_m * getdE(i, I, t, phi + phaseE, F);
454 E2[i] = E2[i - 1] + q * scale_m * getdE(i, I, t2, phi + phaseE + dphi, F);
455 }
456 // msg << ", Ekin= " << E[N3-1] << " MeV" << endl;
457 }
458
459 const int prevPrecision = ippl::Info->precision(8);
460 Inform m("TravelingWave::getAutoPhaseEstimate");
461 m << level2 << "estimated phase= " << tmp_phi << " rad = " << tmp_phi * Units::rad2deg
462 << " deg,\n"
463 << "Ekin= " << E[N3 - 1] << " MeV" << std::setprecision(prevPrecision) << "\n"
464 << endl;
465
466 return phi;
467}
468
470 return (isInsideTransverse(r) && r(2) >= -0.5 * periodLength_m && r(2) < startExitField_m);
471}
Inform * gmsg
Definition changes.cpp:7
ippl::Vector< T, Dim > Vector_t
ElementType
Definition ElementBase.h:94
Template PIC bunch: IPPL PicManager, shared field mesh/solver, and multiple particle containers.
Inform * gmsg
Definition changes.cpp:7
virtual void visitTravelingWave(const TravelingWave &)=0
Apply the algorithm to a traveling wave.
bool online_m
Definition Component.h:226
PartBunch_t * RefPartBunch_m
Definition Component.h:225
bool getFlagDeleteOnTransverseExit() const
bool isInsideTransverse(const Vector_t< double, 3 > &r) const
virtual bool getFieldstrength(const Vector_t< double, 3 > &R, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B) const =0
Get the field strength at a given point.
virtual void getOnaxisEz(std::vector< std::pair< double, double > > &onaxis)
Definition Fieldmap.cpp:588
virtual bool isInside(const Vector_t< double, 3 > &) const =0
Check if a point is inside the field map.
Vector_t< double, Dim > R(size_t)
Do not use; throws (access positions via ParticleContainer::R).
Definition PartBunch.h:611
double getdT() const
Get the global time step.
Definition PartBunch.h:642
double getT() const
Get the current simulation time.
Definition PartBunch.h:651
Interface for standing wave cavities.
Definition RFCavity.h:34
Fieldmap * fieldmap_m
Definition RFCavity.h:219
virtual void initialise(PartBunch_t *bunch, double &startField, double &endField) override
Definition RFCavity.cpp:195
double endField_m
Definition RFCavity.h:221
std::string filename_m
Definition RFCavity.h:206
double scale_m
Definition RFCavity.h:208
double phaseError_m
Definition RFCavity.h:211
double frequency_m
Definition RFCavity.h:212
double startField_m
Definition RFCavity.h:220
double scaleError_m
Definition RFCavity.h:209
virtual double getElementLength() const override
Return the nominal body length of the cavity.
Definition RFCavity.cpp:716
double phase_m
Definition RFCavity.h:210
Interface for traveling wave cavities.
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.
virtual bool bends() const override
virtual void accept(BeamlineVisitor &) const override
Apply visitor to TravelingWave.
virtual void getFieldExtend(double &zBegin, double &zEnd) const override
Return the field-support interval of the traveling-wave structure.
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
Apply to reference particle with position R and momemtum P.
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
Return the nominal body extent of the element.
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 startCoreField_m
virtual void goOnline(const double &kineticEnergy) override
virtual bool apply(const std::shared_ptr< ParticleContainer_t > &pc) override
Applies the Traveling Wave RF Cavity field to all particles inside the RF cavity Note: The field is a...
constexpr double two_pi
The value of.
Definition Physics.h:40
constexpr double pi
The value of.
Definition Physics.h:36
constexpr double rad2deg
Definition Units.h:146
constexpr double deg2rad
Definition Units.h:143