OPAL (Object Oriented Parallel Accelerator Library)  2024.1
OPAL
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 
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 <iostream>
29 #include <fstream>
30 
31 extern Inform *gmsg;
32 
34  TravelingWave("")
35 {}
36 
37 
39  RFCavity(right),
40  scaleCore_m(right.scaleCore_m),
41  scaleCoreError_m(right.scaleCoreError_m),
42  phaseCore1_m(right.phaseCore1_m),
43  phaseCore2_m(right.phaseCore2_m),
44  phaseExit_m(right.phaseExit_m),
45  startCoreField_m(right.startCoreField_m),
46  startExitField_m(right.startExitField_m),
47  mappedStartExitField_m(right.mappedStartExitField_m),
48  periodLength_m(right.periodLength_m),
49  numCells_m(right.numCells_m),
50  cellLength_m(right.cellLength_m),
51  mode_m(right.mode_m)
52 {}
53 
54 
55 TravelingWave::TravelingWave(const std::string& name):
56  RFCavity(name),
57  scaleCore_m(1.0),
58  scaleCoreError_m(0.0),
59  phaseCore1_m(0.0),
60  phaseCore2_m(0.0),
61  phaseExit_m(0.0),
62  startCoreField_m(0.0),
63  startExitField_m(0.0),
64  mappedStartExitField_m(0.0),
65  periodLength_m(0.0),
66  numCells_m(1),
67  cellLength_m(0.0),
68  mode_m(1)
69 {}
70 
71 
73 }
74 
75 
76 void TravelingWave::accept(BeamlineVisitor& visitor) const {
77  visitor.visitTravelingWave(*this);
78 }
79 
80 bool TravelingWave::apply(const size_t& i, const double& t, Vector_t& E, Vector_t& B) {
81  return apply(RefPartBunch_m->R[i], RefPartBunch_m->P[i], t, E, B);
82 }
83 
85  const Vector_t& /*P*/,
86  const double& t,
87  Vector_t& E, Vector_t& B) {
88 
89  if (R(2) < -0.5 * periodLength_m || R(2) + 0.5 * periodLength_m >= getElementLength()) return false;
90 
91  Vector_t tmpR = Vector_t(R(0), R(1), R(2) + 0.5 * periodLength_m);
92  double tmpcos, tmpsin;
93  Vector_t tmpE(0.0, 0.0, 0.0), tmpB(0.0, 0.0, 0.0);
94 
95  if (tmpR(2) < startCoreField_m) {
96  if (!fieldmap_m->isInside(tmpR)) return getFlagDeleteOnTransverseExit();
97 
100 
101  } else if (tmpR(2) < startExitField_m) {
102  Vector_t tmpE2(0.0, 0.0, 0.0), tmpB2(0.0, 0.0, 0.0);
103  tmpR(2) -= startCoreField_m;
104  const double z = tmpR(2);
105  tmpR(2) = tmpR(2) - periodLength_m * std::floor(tmpR(2) / periodLength_m);
106  tmpR(2) += startCoreField_m;
107  if (!fieldmap_m->isInside(tmpR)) return getFlagDeleteOnTransverseExit();
108 
111  fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
112  E += tmpcos * tmpE;
113  B += tmpsin * tmpB;
114 
115  tmpE = 0.0;
116  tmpB = 0.0;
117 
118  tmpR(2) = z + cellLength_m;
119  tmpR(2) = tmpR(2) - periodLength_m * std::floor(tmpR(2) / periodLength_m);
120  tmpR(2) += startCoreField_m;
121 
124 
125  } else {
126  tmpR(2) -= mappedStartExitField_m;
127  if (!fieldmap_m->isInside(tmpR)) return getFlagDeleteOnTransverseExit();
130  }
131 
132  fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
133 
134  E += tmpcos * tmpE;
135  B += tmpsin * tmpB;
136 
137  return false;
138 }
139 
141  const Vector_t& /*P*/,
142  const double& t, Vector_t& E,
143  Vector_t& B) {
144 
145  if (R(2) < -0.5 * periodLength_m || R(2) + 0.5 * periodLength_m >= getElementLength()) return false;
146 
147  Vector_t tmpR = Vector_t(R(0), R(1), R(2) + 0.5 * periodLength_m);
148  double tmpcos, tmpsin;
149  Vector_t tmpE(0.0, 0.0, 0.0), tmpB(0.0, 0.0, 0.0);
150 
151  if (tmpR(2) < startCoreField_m) {
152  if (!fieldmap_m->isInside(tmpR)) return true;
153  tmpcos = scale_m * std::cos(frequency_m * t + phase_m);
154  tmpsin = -scale_m * std::sin(frequency_m * t + phase_m);
155 
156  } else if (tmpR(2) < startExitField_m) {
157  Vector_t tmpE2(0.0, 0.0, 0.0), tmpB2(0.0, 0.0, 0.0);
158  tmpR(2) -= startCoreField_m;
159  const double z = tmpR(2);
160  tmpR(2) = tmpR(2) - periodLength_m * std::floor(tmpR(2) / periodLength_m);
161  tmpR(2) += startCoreField_m;
162  if (!fieldmap_m->isInside(tmpR)) return true;
163 
164  tmpcos = scaleCore_m * std::cos(frequency_m * t + phaseCore1_m);
165  tmpsin = -scaleCore_m * std::sin(frequency_m * t + phaseCore1_m);
166  fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
167  E += tmpcos * tmpE;
168  B += tmpsin * tmpB;
169 
170  tmpE = 0.0;
171  tmpB = 0.0;
172 
173  tmpR(2) = z + cellLength_m;
174  tmpR(2) = tmpR(2) - periodLength_m * std::floor(tmpR(2) / periodLength_m);
175  tmpR(2) += startCoreField_m;
176 
177  tmpcos = scaleCore_m * std::cos(frequency_m * t + phaseCore2_m);
178  tmpsin = -scaleCore_m * std::sin(frequency_m * t + phaseCore2_m);
179 
180  } else {
181  tmpR(2) -= mappedStartExitField_m;
182  if (!fieldmap_m->isInside(tmpR)) return true;
183 
184  tmpcos = scale_m * std::cos(frequency_m * t + phaseExit_m);
185  tmpsin = -scale_m * std::sin(frequency_m * t + phaseExit_m);
186  }
187 
188  fieldmap_m->getFieldstrength(tmpR, tmpE, tmpB);
189  E += tmpcos * tmpE;
190  B += tmpsin * tmpB;
191 
192  return false;
193 }
194 
195 void TravelingWave::initialise(PartBunchBase<double, 3>* bunch, double& startField, double& endField) {
196 
197  if (bunch == nullptr) {
198  startField = - 0.5 * periodLength_m;
199  endField = startExitField_m;
200  return;
201  }
202 
203  Inform msg("TravelingWave ", *gmsg);
204 
205  RefPartBunch_m = bunch;
206  double zBegin = 0.0, zEnd = 0.0;
207  RFCavity::initialise(bunch, zBegin, zEnd);
208  if (std::abs(startField_m) > 0.0) {
209  throw GeneralClassicException("TravelingWave::initialise",
210  "The field map of a traveling wave structure has to begin at 0.0");
211  }
212 
213  periodLength_m = (zEnd - zBegin) / 2.0;
215  startField_m = -0.5 * periodLength_m;
216 
220 
221  startField = -periodLength_m / 2.0;
222  endField = startField + startExitField_m + periodLength_m / 2.0;
223  setElementLength(endField - startField);
224 
227  phaseCore1_m = phase_m + Physics::pi * mode_m / 2.0;
228  phaseCore2_m = phase_m + Physics::pi * mode_m * 1.5;
229  phaseExit_m = phase_m - Physics::two_pi * ((numCells_m - 1) * mode_m - std::floor((numCells_m - 1) * mode_m));
230 }
231 
233 {}
234 
235 bool TravelingWave::bends() const {
236  return false;
237 }
238 
239 void TravelingWave::goOnline(const double&) {
241  online_m = true;
242 }
243 
246 }
247 
248 void TravelingWave::getDimensions(double& zBegin, double& zEnd) const {
249  zBegin = -0.5 * periodLength_m;
250  zEnd = zBegin + getElementLength();
251 }
252 
253 
254 void TravelingWave::getElementDimensions(double& begin, double& end) const {
255  begin = -0.5 * periodLength_m;
256  end = begin + getElementLength();
257 }
258 
261 }
262 
263 double TravelingWave::getAutoPhaseEstimate(const double& E0,
264  const double& t0,
265  const double& q,
266  const double& mass) {
267  std::vector<double> t, E, t2, E2;
268  std::vector<std::pair<double, double> > F;
269  double phi = 0.0, tmp_phi, dphi = 0.5 * Units::deg2rad;
270  double phaseC1 = phaseCore1_m - phase_m;
271  double phaseC2 = phaseCore2_m - phase_m;
272  double phaseE = phaseExit_m - phase_m;
273 
274  fieldmap_m->getOnaxisEz(F);
275  if (F.size() == 0) return 0.0;
276 
277  int N1 = static_cast<int>(std::floor(F.size() / 4.)) + 1;
278  int N2 = F.size() - 2 * N1 + 1;
279  int N3 = 2 * N1 + static_cast<int>(std::floor((numCells_m - 1) * N2 * mode_m)) - 1;
280  int N4 = static_cast<int>(std::round(N2 * mode_m));
281  double Dz = F[N1 + N2].first - F[N1].first;
282 
283  t.resize(N3, t0);
284  t2.resize(N3, t0);
285  E.resize(N3, E0);
286  E2.resize(N3, E0);
287  for (int i = 1; i < N1; ++ i) {
288  E[i] = E0 + (F[i].first + F[i - 1].first) / 2. * scale_m / mass;
289  E2[i] = E[i];
290  }
291  for (int i = N1; i < N3 - N1 + 1; ++ i) {
292  int I = (i - N1) % N2 + N1;
293  double Z = (F[I].first + F[I - 1].first) / 2. + std::floor((i - N1) / N2) * Dz;
294  E[i] = E0 + Z * scaleCore_m / mass;
295  E2[i] = E[i];
296  }
297  for (int i = N3 - N1 + 1; i < N3; ++ i) {
298  int I = i - N3 - 1 + 2 * N1 + N2;
299  double Z = (F[I].first + F[I - 1].first) / 2. + ((numCells_m - 1) * mode_m - 1) * Dz;
300  E[i] = E0 + Z * scale_m / mass;
301  E2[i] = E[i];
302  }
303 
304  for (int iter = 0; iter < 10; ++ iter) {
305  double A = 0.0;
306  double B = 0.0;
307  for (int i = 1; i < N1; ++ i) {
308  t[i] = t[i - 1] + getdT(i, i, E, F, mass);
309  t2[i] = t2[i - 1] + getdT(i, i, E2, F, mass);
310  A += scale_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * getdA(i, i, t, 0.0, F);
311  B += scale_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * getdB(i, i, t, 0.0, F);
312  }
313  for (int i = N1; i < N3 - N1 + 1; ++ i) {
314  int I = (i - N1) % N2 + N1;
315  int J = (i - N1 + N4) % N2 + N1;
316  t[i] = t[i - 1] + getdT(i, I, E, F, mass);
317  t2[i] = t2[i - 1] + getdT(i, I, E2, F, mass);
318  A += scaleCore_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * (getdA(i, I, t, phaseC1, F) + getdA(i, J, t, phaseC2, F));
319  B += scaleCore_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * (getdB(i, I, t, phaseC1, F) + getdB(i, J, t, phaseC2, F));
320  }
321  for (int i = N3 - N1 + 1; i < N3; ++ i) {
322  int I = i - N3 - 1 + 2 * N1 + N2;
323  t[i] = t[i - 1] + getdT(i, I, E, F, mass);
324  t2[i] = t2[i - 1] + getdT(i, I, E2, F, mass);
325  A += scale_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * getdA(i, I, t, phaseE, F);
326  B += scale_m * (1. + frequency_m * (t2[i] - t[i]) / dphi) * getdB(i, I, t, phaseE, F);
327  }
328 
329  if (std::abs(B) > 0.0000001) {
330  tmp_phi = std::atan(A / B);
331  } else {
332  tmp_phi = Physics::pi / 2;
333  }
334  if (q * (A * std::sin(tmp_phi) + B * std::cos(tmp_phi)) < 0) {
335  tmp_phi += Physics::pi;
336  }
337 
338  if (std::abs(phi - tmp_phi) < frequency_m * (t[N3 - 1] - t[0]) / N3) {
339  for (int i = 1; i < N1; ++ i) {
340  E[i] = E[i - 1] + q * scale_m * getdE(i, i, t, phi, F);
341  }
342  for (int i = N1; i < N3 - N1 + 1; ++ i) {
343  int I = (i - N1) % N2 + N1;
344  int J = (i - N1 + N4) % N2 + N1;
345  E[i] = E[i - 1] + q * scaleCore_m * (getdE(i, I, t, phi + phaseC1, F) + getdE(i, J, t, phi + phaseC2, F));
346  }
347  for (int i = N3 - N1 + 1; i < N3; ++ i) {
348  int I = i - N3 - 1 + 2 * N1 + N2;
349  E[i] = E[i - 1] + q * scale_m * getdE(i, I, t, phi + phaseE, F);
350  }
351 
352  const int prevPrecision = Ippl::Info->precision(8);
353  INFOMSG(level2 << "estimated phase= " << tmp_phi << " rad = "
354  << tmp_phi * Units::rad2deg << " deg,\n"
355  << "Ekin= " << E[N3 - 1] << " MeV" << std::setprecision(prevPrecision) << "\n" << endl);
356  return tmp_phi;
357  }
358  phi = tmp_phi - std::round(tmp_phi / Physics::two_pi) * Physics::two_pi;
359 
360 
361  for (int i = 1; i < N1; ++ i) {
362  E[i] = E[i - 1] + q * scale_m * getdE(i, i, t, phi, F);
363  E2[i] = E2[i - 1] + q * scale_m * getdE(i, i, t, phi + dphi, F); // should I use here t or t2?
364  t[i] = t[i - 1] + getdT(i, i, E, F, mass);
365  t2[i] = t2[i - 1] + getdT(i, i, E2, F, mass);
366  E[i] = E[i - 1] + q * scale_m * getdE(i, i, t, phi, F);
367  E2[i] = E2[i - 1] + q * scale_m * getdE(i, i, t2, phi + dphi, F);
368  }
369  for (int i = N1; i < N3 - N1 + 1; ++ i) {
370  int I = (i - N1) % N2 + N1;
371  int J = (i - N1 + N4) % N2 + N1;
372  E[i] = E[i - 1] + q * scaleCore_m * (getdE(i, I, t, phi + phaseC1, F) + getdE(i, J, t, phi + phaseC2, F));
373  E2[i] = E2[i - 1] + q * scaleCore_m * (getdE(i, I, t, phi + phaseC1 + dphi, F) + getdE(i, J, t, phi + phaseC2 + dphi, F)); //concerning t: see above
374  t[i] = t[i - 1] + getdT(i, I, E, F, mass);
375  t2[i] = t2[i - 1] + getdT(i, I, E2, F, mass);
376  E[i] = E[i - 1] + q * scaleCore_m * (getdE(i, I, t, phi + phaseC1, F) + getdE(i, J, t, phi + phaseC2, F));
377  E2[i] = E2[i - 1] + q * scaleCore_m * (getdE(i, I, t2, phi + phaseC1 + dphi, F) + getdE(i, J, t2, phi + phaseC2 + dphi, F));
378  }
379  for (int i = N3 - N1 + 1; i < N3; ++ i) {
380  int I = i - N3 - 1 + 2 * N1 + N2;
381  E[i] = E[i - 1] + q * scale_m * getdE(i, I, t, phi + phaseE, F);
382  E2[i] = E2[i - 1] + q * scale_m * getdE(i, I, t, phi + phaseE + dphi, F); //concerning t: see above
383  t[i] = t[i - 1] + getdT(i, I, E, F, mass);
384  t2[i] = t2[i - 1] + getdT(i, I, E2, F, mass);
385  E[i] = E[i - 1] + q * scale_m * getdE(i, I, t, phi + phaseE, F);
386  E2[i] = E2[i - 1] + q * scale_m * getdE(i, I, t2, phi + phaseE + dphi, F);
387  }
388  // msg << ", Ekin= " << E[N3-1] << " MeV" << endl;
389  }
390 
391 
392  const int prevPrecision = Ippl::Info->precision(8);
393  INFOMSG(level2 << "estimated phase= " << tmp_phi << " rad = "
394  << tmp_phi * Units::rad2deg << " deg,\n"
395  << "Ekin= " << E[N3 - 1] << " MeV" << std::setprecision(prevPrecision) << "\n" << endl);
396 
397  return phi;
398 }
399 
400 bool TravelingWave::isInside(const Vector_t& r) const {
401  return (isInsideTransverse(r)
402  && r(2) >= -0.5 * periodLength_m
403  && r(2) < startExitField_m);
404 }
virtual void freeMap()=0
constexpr double two_pi
The value of .
Definition: Physics.h:33
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
double phaseError_m
Definition: RFCavity.h:209
ParticleAttrib< Vector_t > P
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 void goOffline() override
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6
virtual void goOnline(const double &kineticEnergy) override
virtual bool apply(const size_t &i, const double &t, Vector_t &E, Vector_t &B) override
virtual bool bends() const override
virtual ElementType getType() const override
Get element type std::string.
PartBunchBase< double, 3 > * RefPartBunch_m
Definition: Component.h:191
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
virtual void visitTravelingWave(const TravelingWave &)=0
Apply the algorithm to a traveling wave.
int precision() const
Definition: Inform.h:112
clearpage the user may choose between constant or variable radius This model includes fringe fields begin
Definition: multipole_t.tex:6
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
Definition: RFCavity.cpp:167
constexpr double pi
The value of .
Definition: Physics.h:30
double mappedStartExitField_m
Definition: TravelingWave.h:96
#define INFOMSG(msg)
Definition: IpplInfo.h:348
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
virtual double getAutoPhaseEstimate(const double &E0, const double &t0, const double &q, const double &m) override
double phaseCore1_m
Definition: TravelingWave.h:90
PETE_TUTree< FnArcTan, typename T::PETE_Expr_t > atan(const PETE_Expr< T > &l)
Definition: PETE.h:727
double scale_m
Definition: RFCavity.h:206
virtual bool isInside(const Vector_t &r) const override
virtual void getDimensions(double &zBegin, double &zEnd) const override
double startExitField_m
Definition: TravelingWave.h:95
double phaseCore2_m
Definition: TravelingWave.h:91
static Inform * Info
Definition: IpplInfo.h:78
double scaleError_m
Definition: RFCavity.h:207
double cellLength_m
double scaleCore_m
Definition: TravelingWave.h:87
virtual void readMap()=0
bool getFlagDeleteOnTransverseExit() const
Definition: ElementBase.h:614
double phaseExit_m
Definition: TravelingWave.h:92
constexpr double deg2rad
Definition: Units.h:143
bool online_m
Definition: Component.h:192
double phase_m
Definition: RFCavity.h:208
Definition: Inform.h:42
virtual void finalise() override
ElementType
Definition: ElementBase.h:88
double frequency_m
Definition: RFCavity.h:210
double startField_m
Definition: RFCavity.h:218
virtual void accept(BeamlineVisitor &) const override
Apply visitor to TravelingWave.
double startCoreField_m
Definition: TravelingWave.h:94
constexpr double rad2deg
Definition: Units.h:146
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
bool isInsideTransverse(const Vector_t &r) const
const std::string name
Fieldmap fieldmap_m
Definition: RFCavity.h:217
ParticlePos_t & R
virtual double getElementLength() const override
Get design length.
Definition: RFCavity.cpp:732
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
virtual bool applyToReferenceParticle(const Vector_t &R, const Vector_t &P, const double &t, Vector_t &E, Vector_t &B) override
virtual void setElementLength(double length)
Set design length.
Definition: ElementBase.h:419
virtual void getElementDimensions(double &begin, double &end) const override
Inform & level2(Inform &inf)
Definition: Inform.cpp:46
virtual ~TravelingWave()
Tps< T > sin(const Tps< T > &x)
Sine.
Definition: TpsMath.h:111
double periodLength_m
Definition: TravelingWave.h:98
double scaleCoreError_m
Definition: TravelingWave.h:88
PETE_TUTree< FnFloor, typename T::PETE_Expr_t > floor(const PETE_Expr< T > &l)
Definition: PETE.h:733
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
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
Inform * gmsg
Definition: Main.cpp:70
end
Definition: multipole_t.tex:9
std::string filename_m
Definition: RFCavity.h:204