OPALX (Object Oriented Parallel Accelerator Library for Exascal) MINIorX
OPALX
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//
22#include "Ippl.h"
23#include "OPALTypes.h"
24
29//
30#include "Physics/Units.h"
32#include "Utilities/Options.h"
33#include "Utilities/Util.h"
34
35#include <fstream>
36#include <iostream>
37#include <string>
38
39extern Inform* gmsg;
40
41CavityAutophaser::CavityAutophaser(const PartData& ref, std::shared_ptr<Component> cavity)
42 : itsReference_m(ref), itsCavity_m(cavity) {
43 double zbegin = 0.0, zend = 0.0;
44 cavity->getDimensions(zbegin, zend);
45 initialR_m = Vector_t<double, 3>(0, 0, zbegin);
46}
47
50
52 const Vector_t<double, 3>& R, const Vector_t<double, 3>& P, double t, double dt) {
53 if (!(itsCavity_m->getType() == ElementType::TRAVELINGWAVE
54 || itsCavity_m->getType() == ElementType::RFCAVITY)) {
55 throw OpalException(
56 "CavityAutophaser::getPhaseAtMaxEnergy()", "given element is not a cavity");
57 }
58
59 initialP_m = P; // \todo need to check ... Vector_t<double, 3>(0, 0, std::sqrt(dot(P, P)));
60
61 RFCavity* element = static_cast<RFCavity*>(itsCavity_m.get());
62 bool apVeto = element->getAutophaseVeto();
63 bool isDCGun = false;
64 double originalPhase = element->getPhasem();
65 double tErr = (initialR_m(2) - R(2)) * std::sqrt(dot(P, P) + 1.0) / (P(2) * Physics::c);
66 double optimizedPhase = 0.0;
67 double finalEnergy = 0.0;
68 double newPhase = 0.0;
69 double amplitude = element->getAmplitudem();
70 double basePhase = std::fmod(element->getFrequencym() * (t + tErr), Physics::two_pi);
71 double frequency = element->getFrequencym();
72
73 if ((!apVeto) && frequency <= (1.0 + 1e-6) * Physics::two_pi) { // DC gun
74 optimizedPhase = (amplitude * itsReference_m.getQ() > 0.0 ? 0.0 : Physics::pi);
75 element->setPhasem(optimizedPhase + originalPhase);
76 element->setAutophaseVeto();
77
78 originalPhase += optimizedPhase;
79 OpalData::getInstance()->setMaxPhase(itsCavity_m->getName(), originalPhase);
80
81 apVeto = true;
82 isDCGun = true;
83 }
84
85 std::stringstream ss;
86 for (char c : itsCavity_m->getName()) {
87 ss << std::setw(2) << std::left << c;
88 }
89 *ippl::Info << level1 << "\n* ************* " << std::left << std::setw(68) << std::setfill('*')
90 << ss.str() << std::setfill(' ') << endl;
91 if (!apVeto) {
92 double initialEnergy = Util::getKineticEnergy(P, itsReference_m.getM()) * Units::eV2MeV;
93 double AstraPhase = 0.0;
94 double designEnergy = element->getDesignEnergy();
95
96 if (amplitude < 0.0) {
97 amplitude = -amplitude;
98 element->setAmplitudem(amplitude);
99 }
100
101 double initialPhase = guessCavityPhase(t + tErr);
102
103 if (amplitude == 0.0 && designEnergy <= 0.0) {
104 throw OpalException(
105 "CavityAutophaser::getPhaseAtMaxEnergy()",
106 "neither amplitude or design energy given to cavity " + element->getName());
107 }
108
109 if (designEnergy > 0.0) {
110 const double length = itsCavity_m->getElementLength();
111 if (length <= 0.0) {
112 throw OpalException(
113 "CavityAutophaser::getPhaseAtMaxEnergy()",
114 "length of cavity " + element->getName() + " is zero");
115 }
116
117 amplitude =
118 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)
131 break;
132
133 amplitude *= std::abs(designEnergy / finalEnergy);
134 element->setAmplitudem(amplitude);
135 initialPhase = optimizedPhase;
136
137 ++count;
138 }
139 }
140
141 auto status = optimizeCavityPhase(initialPhase, t + tErr, dt);
142
143 optimizedPhase = status.first;
144 finalEnergy = status.second;
145
146 AstraPhase = std::fmod(optimizedPhase + Physics::pi / 2 + Physics::two_pi, Physics::two_pi);
147 newPhase = std::fmod(originalPhase + optimizedPhase + Physics::two_pi, Physics::two_pi);
148 element->setPhasem(newPhase);
149 element->setAutophaseVeto();
150
151 auto opal = OpalData::getInstance();
152
153 opal->setMaxPhase(itsCavity_m->getName(), newPhase);
154
155 newPhase = std::fmod(newPhase + basePhase, Physics::two_pi);
156
157 if (!opal->isOptimizerRun()) {
158 std::string fname = Util::combineFilePath(
159 {opal->getAuxiliaryOutputDirectory(), itsCavity_m->getName() + "_AP.dat"});
160 std::ofstream out(fname);
161 track(t + tErr, dt, newPhase, &out);
162 out.close();
163 } else {
164 track(t + tErr, dt, newPhase, nullptr);
165 }
166
167 *ippl::Info << level1 << std::fixed << std::setprecision(4) << itsCavity_m->getName()
168 << "_phi1 = " << newPhase * Units::rad2deg << " [deg], "
169 << "corresp. in Astra = " << AstraPhase * Units::rad2deg << " [deg],\n"
170 << "E = " << finalEnergy << " [MeV], "
171 << "phi_nom = " << originalPhase * Units::rad2deg << " [deg]\n"
172 << "Ez_0 = " << amplitude << " [MV/m]"
173 << "\n"
174 << "time = " << (t + tErr) * Units::s2ns << " [ns], dt = " << dt * Units::s2ps
175 << " [ps]" << endl;
176
177 } else {
178 auto status = optimizeCavityPhase(originalPhase, t + tErr, dt);
179
180 finalEnergy = status.second;
181
182 originalPhase = std::fmod(originalPhase, Physics::two_pi);
183 double AstraPhase =
184 std::fmod(optimizedPhase + Physics::pi / 2 + Physics::two_pi, Physics::two_pi);
185
186 if (!isDCGun) {
187 *ippl::Info << level1 << ">>>>>> APVETO >>>>>> " << endl;
188 }
189 *ippl::Info << level1 << std::fixed << std::setprecision(4) << itsCavity_m->getName()
190 << "_phi2 = " << originalPhase * Units::rad2deg << " [deg], "
191 << "corresp. in Astra = " << AstraPhase * Units::rad2deg << " [deg],\n"
192 << "E = " << finalEnergy << " [MeV], "
193 << "phi_nom = " << originalPhase * Units::rad2deg << " [deg]\n"
194 << "Ez_0 = " << amplitude << " [MV/m]"
195 << "\n"
196 << "time = " << (t + tErr) * Units::s2ns << " [ns], dt = " << dt * Units::s2ps
197 << " [ps]" << endl;
198 if (!isDCGun) {
199 *ippl::Info << level1 << " <<<<<< APVETO <<<<<< " << endl;
200 }
201
202 optimizedPhase = originalPhase;
203 }
204 *ippl::Info << level1 << "* " << std::right << std::setw(83) << std::setfill('*') << "*\n"
205 << std::setfill(' ') << endl;
206
207 return optimizedPhase;
208}
209
211 const Vector_t<double, 3>& refP = initialP_m;
212 double Phimax = 0.0;
213 bool apVeto;
214 RFCavity* element = static_cast<RFCavity*>(itsCavity_m.get());
215 double orig_phi = element->getPhasem();
216 apVeto = element->getAutophaseVeto();
217 if (apVeto) {
218 return orig_phi;
219 }
220
221 Phimax = element->getAutoPhaseEstimate(
224
225 return std::fmod(Phimax + Physics::two_pi, Physics::two_pi);
226}
227
229 double initialPhase, double t, double dt) {
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 int j = -1;
246
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 E = track(t, dt, Phimax + originalPhase);
289 std::pair<double, double> status(Phimax, E);
290
291 return status;
292}
293
295 double t, const double dt, const double phase, std::ofstream* out) const {
296 const Vector_t<double, 3>& 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(
303 refP(2), t, dt, itsReference_m.getQ(), itsReference_m.getM() * Units::eV2MeV, out);
304 rfc->setPhasem(initialPhase);
305
306 double finalKineticEnergy = Util::getKineticEnergy(
307 Vector_t<double, 3>(0.0, 0.0, pe.first), itsReference_m.getM() * Units::eV2MeV);
308 return finalKineticEnergy;
309}
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition Vector3D.cpp:118
Inform * gmsg
Definition changes.cpp:7
ippl::Vector< T, Dim > Vector_t
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:69
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition Util.cpp:197
double getKineticEnergy(ippl::Vector< double, 3 > p, double mass)
Definition Util.h:55
virtual const std::string & getName() const
Get element name.
virtual double getPhasem() const
Definition RFCavity.h:348
virtual double getAmplitudem() const
Definition RFCavity.h:320
virtual bool getAutophaseVeto() const
Definition RFCavity.h:380
virtual void setAmplitudem(double vPeak)
Definition RFCavity.h:316
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:665
virtual void setPhasem(double phase)
Definition RFCavity.h:344
virtual double getFrequencym() const
Definition RFCavity.h:340
virtual void setAutophaseVeto(bool veto=true)
Definition RFCavity.h:376
virtual double getAutoPhaseEstimate(const double &E0, const double &t0, const double &q, const double &m)
Definition RFCavity.cpp:530
virtual double getDesignEnergy() const override
Definition RFCavity.h:304
void setMaxPhase(std::string elName, double phi)
Definition OpalData.cpp:393
static OpalData * getInstance()
Definition OpalData.cpp:195
Vector_t< double, 3 > initialR_m
double getPhaseAtMaxEnergy(const Vector_t< double, 3 > &R, const Vector_t< double, 3 > &P, double t, double dt)
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)
Vector_t< double, 3 > initialP_m
std::shared_ptr< Component > itsCavity_m
CavityAutophaser(const PartData &ref, std::shared_ptr< Component > cavity)
Particle reference data.
Definition PartData.h:37
The base class for all OPAL exceptions.