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