OPAL (Object Oriented Parallel Accelerator Library)  2024.1
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 "AbsBeamline/RFCavity.h"
26 #include "Algorithms/Vektor.h"
27 #include "Physics/Units.h"
29 #include "Utilities/Options.h"
30 #include "Utilities/Util.h"
31 
32 #include <fstream>
33 #include <iostream>
34 #include <string>
35 
36 extern Inform *gmsg;
37 
39  std::shared_ptr<Component> cavity):
40  itsReference_m(ref),
41  itsCavity_m(cavity)
42 {
43  double zbegin = 0.0, zend = 0.0;
44  cavity->getDimensions(zbegin, zend);
45  initialR_m = Vector_t(0, 0, zbegin);
46 }
47 
49 
50 }
51 
53  const Vector_t &P,
54  double t,
55  double dt) {
56  if(!(itsCavity_m->getType() == ElementType::TRAVELINGWAVE ||
57  itsCavity_m->getType() == ElementType::RFCAVITY)) {
58  throw OpalException("CavityAutophaser::getPhaseAtMaxEnergy()",
59  "given element is not a cavity");
60  }
61 
63 
64  RFCavity *element = static_cast<RFCavity *>(itsCavity_m.get());
65  bool apVeto = element->getAutophaseVeto();
66  bool isDCGun = false;
67  double originalPhase = element->getPhasem();
68  double tErr = (initialR_m(2) - R(2)) * sqrt(dot(P,P) + 1.0) / (P(2) * Physics::c);
69  double optimizedPhase = 0.0;
70  double finalEnergy = 0.0;
71  double newPhase = 0.0;
72  double amplitude = element->getAmplitudem();
73  double basePhase = std::fmod(element->getFrequencym() * (t + tErr), Physics::two_pi);
74  double frequency = element->getFrequencym();
75 
76  if ((!apVeto) && frequency <= (1.0 + 1e-6) * Physics::two_pi) { // DC gun
77  optimizedPhase = (amplitude * itsReference_m.getQ() > 0.0? 0.0: Physics::pi);
78  element->setPhasem(optimizedPhase + originalPhase);
79  element->setAutophaseVeto();
80 
81  originalPhase += optimizedPhase;
82  OpalData::getInstance()->setMaxPhase(itsCavity_m->getName(), originalPhase);
83 
84  apVeto = true;
85  isDCGun = true;
86  }
87 
88  std::stringstream ss;
89  for (char c: itsCavity_m->getName()) {
90  ss << std::setw(2) << std::left << c;
91  }
92  INFOMSG(level1 << "\n* ************* "
93  << std::left << std::setw(68) << std::setfill('*') << ss.str()
94  << std::setfill(' ') << endl);
95  if (!apVeto) {
96  double initialEnergy = Util::getKineticEnergy(P, itsReference_m.getM()) * Units::eV2MeV;
97  double AstraPhase = 0.0;
98  double designEnergy = element->getDesignEnergy();
99 
100  if (amplitude < 0.0) {
101  amplitude = -amplitude;
102  element->setAmplitudem(amplitude);
103  }
104 
105  double initialPhase = guessCavityPhase(t + tErr);
106 
107  if (amplitude == 0.0 && designEnergy <= 0.0) {
108  throw OpalException("CavityAutophaser::getPhaseAtMaxEnergy()",
109  "neither amplitude or design energy given to cavity " + element->getName());
110  }
111 
112  if (designEnergy > 0.0) {
113  const double length = itsCavity_m->getElementLength();
114  if (length <= 0.0) {
115  throw OpalException("CavityAutophaser::getPhaseAtMaxEnergy()",
116  "length of cavity " + element->getName() + " is zero");
117  }
118 
119  amplitude = 2 * (designEnergy - initialEnergy) / (std::abs(itsReference_m.getQ()) * length);
120 
121  element->setAmplitudem(amplitude);
122 
123  int count = 0;
124  while (count < 1000) {
125  initialPhase = guessCavityPhase(t + tErr);
126  auto status = optimizeCavityPhase(initialPhase, t + tErr, dt);
127 
128  optimizedPhase = status.first;
129  finalEnergy = status.second;
130 
131  if (std::abs(designEnergy - finalEnergy) < 1e-7) break;
132 
133  amplitude *= std::abs(designEnergy / finalEnergy);
134  element->setAmplitudem(amplitude);
135  initialPhase = optimizedPhase;
136 
137  ++ count;
138  }
139  }
140  auto status = optimizeCavityPhase(initialPhase, t + tErr, dt);
141 
142  optimizedPhase = status.first;
143  finalEnergy = status.second;
144 
145  AstraPhase = std::fmod(optimizedPhase + Physics::pi / 2 + Physics::two_pi, Physics::two_pi);
146  newPhase = std::fmod(originalPhase + optimizedPhase + Physics::two_pi, Physics::two_pi);
147  element->setPhasem(newPhase);
148  element->setAutophaseVeto();
149 
150  auto opal = OpalData::getInstance();
151 
152  opal->setMaxPhase(itsCavity_m->getName(), newPhase);
153 
154  newPhase = std::fmod(newPhase + basePhase, Physics::two_pi);
155 
156  if (!opal->isOptimizerRun()) {
157  std::string fname = Util::combineFilePath({
158  opal->getAuxiliaryOutputDirectory(),
159  itsCavity_m->getName() + "_AP.dat"
160  });
161  std::ofstream out(fname);
162  track(t + tErr, dt, newPhase, &out);
163  out.close();
164  } else {
165  track(t + tErr, dt, newPhase, nullptr);
166  }
167 
168  INFOMSG(level1 << std::fixed << std::setprecision(4)
169  << itsCavity_m->getName() << "_phi = " << newPhase * Units::rad2deg << " [deg], "
170  << "corresp. in Astra = " << AstraPhase * Units::rad2deg << " [deg],\n"
171  << "E = " << finalEnergy << " [MeV], " << "phi_nom = " << originalPhase * Units::rad2deg << " [deg]\n"
172  << "Ez_0 = " << amplitude << " [MV/m]" << "\n"
173  << "time = " << (t + tErr) * Units::s2ns << " [ns], dt = " << dt * Units::s2ps << " [ps]" << endl);
174 
175  } else {
176  auto status = optimizeCavityPhase(originalPhase, t + tErr, dt);
177 
178  finalEnergy = status.second;
179 
180  originalPhase = std::fmod(originalPhase, Physics::two_pi);
181  double AstraPhase = std::fmod(optimizedPhase + Physics::pi / 2 + Physics::two_pi, Physics::two_pi);
182 
183  if (!isDCGun) {
184  INFOMSG(level1 << ">>>>>> APVETO >>>>>> " << endl);
185  }
186  INFOMSG(level1 << std::fixed << std::setprecision(4)
187  << itsCavity_m->getName() << "_phi = " << originalPhase * Units::rad2deg << " [deg], "
188  << "corresp. in Astra = " << AstraPhase * Units::rad2deg << " [deg],\n"
189  << "E = " << finalEnergy << " [MeV], " << "phi_nom = " << originalPhase * Units::rad2deg << " [deg]\n"
190  << "Ez_0 = " << amplitude << " [MV/m]" << "\n"
191  << "time = " << (t + tErr) * Units::s2ns << " [ns], dt = " << dt * Units::s2ps << " [ps]" << endl);
192  if (!isDCGun) {
193  INFOMSG(level1 << " <<<<<< APVETO <<<<<< " << endl);
194  }
195 
196  optimizedPhase = originalPhase;
197  }
198  INFOMSG(level1 << "* " << std::right << std::setw(83) << std::setfill('*') << "*\n"
199  << std::setfill(' ') << endl);
200 
201  return optimizedPhase;
202 }
203 
205  const Vector_t &refP = initialP_m;
206  double Phimax = 0.0;
207  bool apVeto;
208  RFCavity *element = static_cast<RFCavity *>(itsCavity_m.get());
209  double orig_phi = element->getPhasem();
210  apVeto = element->getAutophaseVeto();
211  if (apVeto) {
212  return orig_phi;
213  }
214 
216  t,
219 
220  return std::fmod(Phimax + Physics::two_pi, Physics::two_pi);
221 }
222 
223 std::pair<double, double> CavityAutophaser::optimizeCavityPhase(double initialPhase,
224  double t,
225  double dt) {
226 
227  RFCavity *element = static_cast<RFCavity *>(itsCavity_m.get());
228  double originalPhase = element->getPhasem();
229 
230  if (element->getAutophaseVeto()) {
231  double basePhase = std::fmod(element->getFrequencym() * t, Physics::two_pi);
232  double phase = std::fmod(originalPhase - basePhase + Physics::two_pi, Physics::two_pi);
233  double E = track(t, dt, phase);
234  std::pair<double, double> status(originalPhase, E);//-basePhase, E);
235  return status;
236  }
237 
238  double Phimax = initialPhase;
239  double phi = initialPhase;
240  double dphi = Physics::pi / 360.0;
241  const int numRefinements = Options::autoPhase;
242 
243  int j = -1;
244  double E = track(t, dt, phi);
245  double Emax = E;
246 
247  do {
248  j ++;
249  Emax = E;
250  initialPhase = phi;
251  phi -= dphi;
252  E = track(t, dt, phi);
253  } while(E > Emax);
254 
255  if(j == 0) {
256  phi = initialPhase;
257  E = Emax;
258  // j = -1;
259  do {
260  // j ++;
261  Emax = E;
262  initialPhase = phi;
263  phi += dphi;
264  E = track(t, dt, phi);
265  } while(E > Emax);
266  }
267 
268  for(int rl = 0; rl < numRefinements; ++ rl) {
269  dphi /= 2.;
270  phi = initialPhase - dphi;
271  E = track(t, dt, phi);
272  if(E > Emax) {
273  initialPhase = phi;
274  Emax = E;
275  } else {
276  phi = initialPhase + dphi;
277  E = track(t, dt, phi);
278  if(E > Emax) {
279  initialPhase = phi;
280  Emax = E;
281  }
282  }
283  }
284  Phimax = std::fmod(initialPhase + Physics::two_pi, Physics::two_pi);
285 
286  E = track(t, dt, Phimax + originalPhase);
287  std::pair<double, double> status(Phimax, E);
288 
289  return status;
290 }
291 
292 double CavityAutophaser::track(double t,
293  const double dt,
294  const double phase,
295  std::ofstream *out) const {
296  const Vector_t &refP = initialP_m;
297 
298  RFCavity *rfc = static_cast<RFCavity *>(itsCavity_m.get());
299  double initialPhase = rfc->getPhasem();
300  rfc->setPhasem(phase);
301 
302  std::pair<double, double> pe = rfc->trackOnAxisParticle(refP(2),
303  t,
304  dt,
307  out);
308  rfc->setPhasem(initialPhase);
309 
310  double finalKineticEnergy = Util::getKineticEnergy(Vector_t(0.0, 0.0, pe.first), itsReference_m.getM() * Units::eV2MeV);
311 
312  return finalKineticEnergy;
313 }
virtual bool getAutophaseVeto() const
Definition: RFCavity.h:434
static OpalData * getInstance()
Definition: OpalData.cpp:196
virtual double getAmplitudem() const
Definition: RFCavity.h:359
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
double track(double t, const double dt, const double phase, std::ofstream *out=nullptr) const
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:45
double getQ() const
The constant charge per particle.
Definition: PartData.h:118
virtual double getAutoPhaseEstimate(const double &E0, const double &t0, const double &q, const double &m)
Definition: RFCavity.cpp:545
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)
void setMaxPhase(std::string elName, double phi)
Definition: OpalData.cpp:394
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6
double getM() const
The constant mass per particle.
Definition: PartData.h:122
virtual const std::string & getName() const
Get element name.
constexpr double pi
The value of .
Definition: Physics.h:30
#define INFOMSG(msg)
Definition: IpplInfo.h:348
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
virtual double getDesignEnergy() const override
Definition: RFCavity.h:339
T euclidean_norm(const Vector< T > &)
Euclidean norm.
Definition: Vector.h:243
constexpr double s2ps
Definition: Units.h:50
virtual double getPhasem() const
Definition: RFCavity.h:394
virtual double getFrequencym() const
Definition: RFCavity.h:384
The base class for all OPAL exceptions.
Definition: OpalException.h:28
int autoPhase
Definition: Options.cpp:69
double guessCavityPhase(double t)
virtual std::pair< double, double > trackOnAxisParticle(const double &p0, const double &t0, const double &dt, const double &q, const double &mass, std::ofstream *out=nullptr)
Definition: RFCavity.cpp:675
Definition: Inform.h:42
virtual void setAmplitudem(double vPeak)
Definition: RFCavity.h:354
double getKineticEnergy(Vector_t p, double mass)
Definition: Util.h:56
constexpr double s2ns
Definition: Units.h:44
virtual void setAutophaseVeto(bool veto=true)
Definition: RFCavity.h:429
constexpr double rad2deg
Definition: Units.h:146
PETE_TBTree< FnFmod, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > fmod(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
CavityAutophaser(const PartData &ref, std::shared_ptr< Component > cavity)
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition: Util.cpp:197
const PartData & itsReference_m
double getPhaseAtMaxEnergy(const Vector_t &R, const Vector_t &P, double t, double dt)
constexpr double e
The value of .
Definition: Physics.h:39
std::shared_ptr< Component > itsCavity_m
std::pair< double, double > optimizeCavityPhase(double initialGuess, double t, double dt)
Inform & level1(Inform &inf)
Definition: Inform.cpp:45
Inform * gmsg
Definition: Main.cpp:70
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition: Vector3D.cpp:118
constexpr double eV2MeV
Definition: Units.h:77
virtual void setPhasem(double phase)
Definition: RFCavity.h:389