OPAL (Object Oriented Parallel Accelerator Library) 2022.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//
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
36extern 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
223std::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
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}
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition: Vector3D.cpp:118
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
Inform * gmsg
Definition: Main.cpp:61
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 & endl(Inform &inf)
Definition: Inform.cpp:42
Inform & level1(Inform &inf)
Definition: Inform.cpp:45
#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: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:196
double getKineticEnergy(Vector_t p, double mass)
Definition: Util.h:55
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 const std::string & getName() const
Get element name.
virtual double getPhasem() const
Definition: RFCavity.h:395
virtual double getAmplitudem() const
Definition: RFCavity.h:360
virtual bool getAutophaseVeto() const
Definition: RFCavity.h:435
virtual void setAmplitudem(double vPeak)
Definition: RFCavity.h:355
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:666
virtual void setPhasem(double phase)
Definition: RFCavity.h:390
virtual double getFrequencym() const
Definition: RFCavity.h:385
virtual void setAutophaseVeto(bool veto=true)
Definition: RFCavity.h:430
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:340
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