OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
CavityAutophaser.cpp
Go to the documentation of this file.
1 //
2 // Class CavityAutophaser
3 //
4 // This class determines the phase of an RF cavity for which the reference particle
5 // is accelerated to the highest energy.
6 //
7 // Copyright (c) 2016, Christof Metzger-Kraus, Helmholtz-Zentrum Berlin, Germany
8 // 2017 - 2020 Christof Metzger-Kraus
9 //
10 // All rights reserved
11 //
12 // This file is part of OPAL.
13 //
14 // OPAL is free software: you can redistribute it and/or modify
15 // it under the terms of the GNU General Public License as published by
16 // the Free Software Foundation, either version 3 of the License, or
17 // (at your option) any later version.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with OPAL. If not, see <https://www.gnu.org/licenses/>.
21 //
23 #include "Algorithms/Vektor.h"
24 #include "AbsBeamline/RFCavity.h"
26 #include "Utilities/Options.h"
28 #include "Utilities/Util.h"
30 
31 #include <fstream>
32 #include <iostream>
33 #include <string>
34 
35 extern Inform *gmsg;
36 
38  std::shared_ptr<Component> cavity):
39  itsReference_m(ref),
40  itsCavity_m(cavity)
41 {
42  double zbegin = 0.0, zend = 0.0;
43  cavity->getDimensions(zbegin, zend);
44  initialR_m = Vector_t(0, 0, zbegin);
45 }
46 
48 
49 }
50 
52  const Vector_t &P,
53  double t,
54  double dt) {
55  if(!(itsCavity_m->getType() == ElementBase::TRAVELINGWAVE ||
56  itsCavity_m->getType() == ElementBase::RFCAVITY)) {
57  throw OpalException("CavityAutophaser::getPhaseAtMaxEnergy()",
58  "given element is not a cavity");
59  }
60 
62 
63  RFCavity *element = static_cast<RFCavity *>(itsCavity_m.get());
64  bool apVeto = element->getAutophaseVeto();
65  bool isDCGun = false;
66  double originalPhase = element->getPhasem();
67  double tErr = (initialR_m(2) - R(2)) * sqrt(dot(P,P) + 1.0) / (P(2) * Physics::c);
68  double optimizedPhase = 0.0;
69  double finalEnergy = 0.0;
70  double newPhase = 0.0;
71  double amplitude = element->getAmplitudem();
72  double basePhase = std::fmod(element->getFrequencym() * (t + tErr), Physics::two_pi);
73  double frequency = element->getFrequencym();
74 
75  if ((!apVeto) && frequency <= (1.0 + 1e-6) * Physics::two_pi) { // DC gun
76  optimizedPhase = (amplitude * itsReference_m.getQ() > 0.0? 0.0: Physics::pi);
77  element->setPhasem(optimizedPhase + originalPhase);
78  element->setAutophaseVeto();
79 
80  originalPhase += optimizedPhase;
81  OpalData::getInstance()->setMaxPhase(itsCavity_m->getName(), originalPhase);
82 
83  apVeto = true;
84  isDCGun = true;
85  }
86 
87  std::stringstream ss;
88  for (char c: itsCavity_m->getName()) {
89  ss << std::setw(2) << std::left << c;
90  }
91  INFOMSG(level1 << "\n* ************* "
92  << std::left << std::setw(68) << std::setfill('*') << ss.str()
93  << std::setfill(' ') << endl);
94  if (!apVeto) {
95  double initialEnergy = Util::getKineticEnergy(P, itsReference_m.getM()) * 1e-6;
96  double AstraPhase = 0.0;
97  double designEnergy = element->getDesignEnergy();
98 
99  if (amplitude < 0.0) {
100  amplitude = -amplitude;
101  element->setAmplitudem(amplitude);
102  }
103 
104  double initialPhase = guessCavityPhase(t + tErr);
105 
106  if (amplitude == 0.0 && designEnergy <= 0.0) {
107  throw OpalException("CavityAutophaser::getPhaseAtMaxEnergy()",
108  "neither amplitude or design energy given to cavity " + element->getName());
109  }
110 
111  if (designEnergy > 0.0) {
112  const double length = itsCavity_m->getElementLength();
113  if (length <= 0.0) {
114  throw OpalException("CavityAutophaser::getPhaseAtMaxEnergy()",
115  "length of cavity " + element->getName() + " is zero");
116  }
117 
118  amplitude = 2 * (designEnergy - initialEnergy) / (std::abs(itsReference_m.getQ()) * length);
119 
120  element->setAmplitudem(amplitude);
121 
122  int count = 0;
123  while (count < 1000) {
124  initialPhase = guessCavityPhase(t + tErr);
125  auto status = optimizeCavityPhase(initialPhase, t + tErr, dt);
126 
127  optimizedPhase = status.first;
128  finalEnergy = status.second;
129 
130  if (std::abs(designEnergy - finalEnergy) < 1e-7) break;
131 
132  amplitude *= std::abs(designEnergy / finalEnergy);
133  element->setAmplitudem(amplitude);
134  initialPhase = optimizedPhase;
135 
136  ++ count;
137  }
138  }
139  auto status = optimizeCavityPhase(initialPhase, t + tErr, dt);
140 
141  optimizedPhase = status.first;
142  finalEnergy = status.second;
143 
144  AstraPhase = std::fmod(optimizedPhase + Physics::pi / 2 + Physics::two_pi, Physics::two_pi);
145  newPhase = std::fmod(originalPhase + optimizedPhase + Physics::two_pi, Physics::two_pi);
146  element->setPhasem(newPhase);
147  element->setAutophaseVeto();
148 
149  auto opal = OpalData::getInstance();
150 
151  opal->setMaxPhase(itsCavity_m->getName(), newPhase);
152 
153  newPhase = std::fmod(newPhase + basePhase, Physics::two_pi);
154 
155  if (!opal->isOptimizerRun()) {
156  std::string fname = Util::combineFilePath({
157  opal->getAuxiliaryOutputDirectory(),
158  itsCavity_m->getName() + "_AP.dat"
159  });
160  std::ofstream out(fname);
161  track(t + tErr, dt, newPhase, &out);
162  out.close();
163  } else {
164  track(t + tErr, dt, newPhase, NULL);
165  }
166 
167  INFOMSG(level1 << std::fixed << std::setprecision(4)
168  << itsCavity_m->getName() << "_phi = " << newPhase * Physics::rad2deg << " [deg], "
169  << "corresp. in Astra = " << AstraPhase * Physics::rad2deg << " [deg],\n"
170  << "E = " << finalEnergy << " [MeV], " << "phi_nom = " << originalPhase * Physics::rad2deg << " [deg]\n"
171  << "Ez_0 = " << amplitude << " [MV/m]" << "\n"
172  << "time = " << (t + tErr) * 1e9 << " [ns], dt = " << dt * 1e12 << " [ps]" << endl);
173 
174  } else {
175  auto status = optimizeCavityPhase(originalPhase, t + tErr, dt);
176 
177  finalEnergy = status.second;
178 
179  originalPhase = std::fmod(originalPhase, Physics::two_pi);
180  double AstraPhase = std::fmod(optimizedPhase + Physics::pi / 2 + Physics::two_pi, Physics::two_pi);
181 
182  if (!isDCGun) {
183  INFOMSG(level1 << ">>>>>> APVETO >>>>>> " << endl);
184  }
185  INFOMSG(level1 << std::fixed << std::setprecision(4)
186  << itsCavity_m->getName() << "_phi = " << originalPhase * Physics::rad2deg << " [deg], "
187  << "corresp. in Astra = " << AstraPhase * Physics::rad2deg << " [deg],\n"
188  << "E = " << finalEnergy << " [MeV], " << "phi_nom = " << originalPhase * Physics::rad2deg << " [deg]\n"
189  << "Ez_0 = " << amplitude << " [MV/m]" << "\n"
190  << "time = " << (t + tErr) * 1e9 << " [ns], dt = " << dt * 1e12 << " [ps]" << endl);
191  if (!isDCGun) {
192  INFOMSG(level1 << " <<<<<< APVETO <<<<<< " << endl);
193  }
194 
195  optimizedPhase = originalPhase;
196  }
197  INFOMSG(level1 << "* " << std::right << std::setw(83) << std::setfill('*') << "*\n"
198  << std::setfill(' ') << endl);
199 
200  return optimizedPhase;
201 }
202 
204  const Vector_t &refP = initialP_m;
205  double Phimax = 0.0;
206  bool apVeto;
207  RFCavity *element = static_cast<RFCavity *>(itsCavity_m.get());
208  double orig_phi = element->getPhasem();
209  apVeto = element->getAutophaseVeto();
210  if (apVeto) {
211  return orig_phi;
212  }
213 
214  Phimax = element->getAutoPhaseEstimate(Util::getKineticEnergy(refP, itsReference_m.getM()) * 1e-6,
215  t,
217  itsReference_m.getM() * 1e-6);
218 
219  return std::fmod(Phimax + Physics::two_pi, Physics::two_pi);
220 }
221 
222 std::pair<double, double> CavityAutophaser::optimizeCavityPhase(double initialPhase,
223  double t,
224  double dt) {
225 
226  RFCavity *element = static_cast<RFCavity *>(itsCavity_m.get());
227  double originalPhase = element->getPhasem();
228 
229  if (element->getAutophaseVeto()) {
230  double basePhase = std::fmod(element->getFrequencym() * t, Physics::two_pi);
231  double phase = std::fmod(originalPhase - basePhase + Physics::two_pi, Physics::two_pi);
232  double E = track(t, dt, phase);
233  std::pair<double, double> status(originalPhase, E);//-basePhase, E);
234  return status;
235  }
236 
237  double Phimax = initialPhase;
238  double phi = initialPhase;
239  double dphi = Physics::pi / 360.0;
240  const int numRefinements = Options::autoPhase;
241 
242  int j = -1;
243  double E = track(t, dt, phi);
244  double Emax = E;
245 
246  do {
247  j ++;
248  Emax = E;
249  initialPhase = phi;
250  phi -= dphi;
251  E = track(t, dt, phi);
252  } while(E > Emax);
253 
254  if(j == 0) {
255  phi = initialPhase;
256  E = Emax;
257  // j = -1;
258  do {
259  // j ++;
260  Emax = E;
261  initialPhase = phi;
262  phi += dphi;
263  E = track(t, dt, phi);
264  } while(E > Emax);
265  }
266 
267  for(int rl = 0; rl < numRefinements; ++ rl) {
268  dphi /= 2.;
269  phi = initialPhase - dphi;
270  E = track(t, dt, phi);
271  if(E > Emax) {
272  initialPhase = phi;
273  Emax = E;
274  } else {
275  phi = initialPhase + dphi;
276  E = track(t, dt, phi);
277  if(E > Emax) {
278  initialPhase = phi;
279  Emax = E;
280  }
281  }
282  }
283  Phimax = std::fmod(initialPhase + Physics::two_pi, Physics::two_pi);
284 
285  E = track(t, dt, Phimax + originalPhase);
286  std::pair<double, double> status(Phimax, E);
287 
288  return status;
289 }
290 
291 double CavityAutophaser::track(double t,
292  const double dt,
293  const double phase,
294  std::ofstream *out) const {
295  const Vector_t &refP = initialP_m;
296 
297  RFCavity *rfc = static_cast<RFCavity *>(itsCavity_m.get());
298  double initialPhase = rfc->getPhasem();
299  rfc->setPhasem(phase);
300 
301  std::pair<double, double> pe = rfc->trackOnAxisParticle(refP(2),
302  t,
303  dt,
305  itsReference_m.getM() * 1e-6,
306  out);
307  rfc->setPhasem(initialPhase);
308 
309  double finalKineticEnergy = Util::getKineticEnergy(Vector_t(0.0, 0.0, pe.first), itsReference_m.getM() * 1e-6);
310 
311  return finalKineticEnergy;
312 }
Inform * gmsg
Definition: Main.cpp:62
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
T euclidean_norm(const Vector< T > &)
Euclidean norm.
Definition: Vector.h:243
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition: Vector3D.cpp:118
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
PETE_TBTree< FnFmod, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > fmod(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
Inform & level1(Inform &inf)
Definition: Inform.cpp:45
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define INFOMSG(msg)
Definition: IpplInfo.h:348
constexpr double two_pi
The value of.
Definition: Physics.h:33
constexpr double e
The value of.
Definition: Physics.h:39
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:51
constexpr double pi
The value of.
Definition: Physics.h:30
constexpr double rad2deg
The conversion factor from radians to degrees.
Definition: Physics.h:45
int autoPhase
Definition: Options.cpp:69
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition: Util.cpp:139
double getKineticEnergy(Vector_t p, double mass)
Definition: Util.h:37
void setMaxPhase(std::string elName, double phi)
Definition: OpalData.cpp:393
static OpalData * getInstance()
Definition: OpalData.cpp:195
const PartData & itsReference_m
double guessCavityPhase(double t)
std::pair< double, double > optimizeCavityPhase(double initialGuess, double t, double dt)
double getPhaseAtMaxEnergy(const Vector_t &R, const Vector_t &P, double t, double dt)
std::shared_ptr< Component > itsCavity_m
double track(double t, const double dt, const double phase, std::ofstream *out=NULL) const
CavityAutophaser(const PartData &ref, std::shared_ptr< Component > cavity)
virtual const std::string & getName() const
Get element name.
Interface for RF cavity.
Definition: RFCavity.h:37
virtual double getPhasem() const
Definition: RFCavity.h:408
virtual std::pair< double, double > trackOnAxisParticle(const double &p0, const double &t0, const double &dt, const double &q, const double &mass, std::ofstream *out=NULL)
Definition: RFCavity.cpp:665
virtual double getAmplitudem() const
Definition: RFCavity.h:373
virtual bool getAutophaseVeto() const
Definition: RFCavity.h:453
virtual void setAmplitudem(double vPeak)
Definition: RFCavity.h:368
virtual void setPhasem(double phase)
Definition: RFCavity.h:403
virtual double getFrequencym() const
Definition: RFCavity.h:398
virtual void setAutophaseVeto(bool veto=true)
Definition: RFCavity.h:448
virtual double getAutoPhaseEstimate(const double &E0, const double &t0, const double &q, const double &m)
Definition: RFCavity.cpp:536
virtual double getDesignEnergy() const override
Definition: RFCavity.h:348
Particle reference data.
Definition: PartData.h:35
double getQ() const
The constant charge per particle.
Definition: PartData.h:104
double getM() const
The constant mass per particle.
Definition: PartData.h:109
The base class for all OPAL exceptions.
Definition: OpalException.h:28
Definition: Inform.h:42
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6