22#include "Utility/IpplInfo.h"
43 phaseTD_m(right.phaseTD_m),
44 phaseName_m(right.phaseName_m),
45 amplitudeTD_m(right.amplitudeTD_m),
46 amplitudeName_m(right.amplitudeName_m),
47 frequencyTD_m(right.frequencyTD_m),
48 frequencyName_m(right.frequencyName_m),
49 filename_m(right.filename_m),
50 scale_m(right.scale_m),
51 scaleError_m(right.scaleError_m),
52 phase_m(right.phase_m),
53 phaseError_m(right.phaseError_m),
54 frequency_m(right.frequency_m),
56 autophaseVeto_m(right.autophaseVeto_m),
57 designEnergy_m(right.designEnergy_m),
58 fieldmap_m(right.fieldmap_m),
59 startField_m(right.startField_m),
60 endField_m(right.endField_m),
64 angle_m(right.angle_m),
65 sinAngle_m(right.sinAngle_m),
66 cosAngle_m(right.cosAngle_m),
68 gapwidth_m(right.gapwidth_m),
73 num_points_m(right.num_points_m) {}
78 amplitudeTD_m(nullptr),
79 frequencyTD_m(nullptr),
87 autophaseVeto_m(false),
132 const double phi = freq * t + phase;
133 const double cosphi = Kokkos::cos(phi);
134 const double sinphi = Kokkos::sin(phi);
136 const double electricScale = scale * cosphi;
137 const double magneticScale = -scale * sinphi;
140 dynamicFieldmap->applyRFField(pc, electricScale, magneticScale, startField, endField);
142 astraFieldmap->applyRFField(pc, electricScale, magneticScale, startField, endField);
146 "RFCavity particle application currently requires an FM2DDynamic or Astra1DDynamic "
155 std::shared_ptr<ParticleContainer_t> pc =
RefPartBunch_m->getParticleContainer();
156 auto Rview = pc->
R.getView();
157 auto Pview = pc->P.getView();
162 return apply(R, P, t, E, B);
187 if (outOfBounds)
return true;
197 if (bunch ==
nullptr) {
201 Inform msg(
"RFCavity ", *
gmsg);
202 std::stringstream errormsg;
209 "RFCavity::initialise",
210 "The length of the field map '" +
filename_m +
"' is zero or negative");
213 msg << level2 <<
getName() <<
" using file ";
216 errormsg <<
"FREQUENCY IN INPUT FILE DIFFERENT THAN IN FIELD MAP '" <<
filename_m <<
"';\n"
219 <<
" MHz; TAKE ON THE LATTER";
220 std::string errormsg_str = Fieldmap::typeset_msg(errormsg.str(),
"warning\n");
221 *ippl::Error << errormsg_str << endl;
222 if (ippl::Comm->rank() == 0) {
223 std::ofstream omsg(
"errormsg.txt", std::ios_base::app);
224 omsg << errormsg_str << std::endl;
229 const double bodyBegin = startField;
236 PartBunch_t* bunch, std::shared_ptr<AbstractTimeDependence> freq_atd,
237 std::shared_ptr<AbstractTimeDependence> ampl_atd,
238 std::shared_ptr<AbstractTimeDependence> phase_atd) {
256 "RFCavity::initialise",
257 "Not enough data in file '" +
filename_m +
"', please check the data format");
263 DvDr_m[i] *= pc->getTotalCharge();
272 *
gmsg <<
"* Cavity voltage data read successfully!" << endl;
333 "RFCavity::getFieldMapFN",
334 "The attribute \"FMAPFN\" isn't set "
335 "for the \"RFCAVITY\" element!");
336 }
else if (std::filesystem::exists(
filename_m)) {
340 "RFCavity::getFieldMapFN",
341 "Failed to open file '" +
filename_m +
"', please check if it exists");
358 const double normalRadius,
double momentum[],
const double t,
const double dtCorrt,
359 const int PID,
const double restMass,
const int chargenumber) {
363 momentum[0] * momentum[0] + momentum[1] * momentum[1] + momentum[2] * momentum[2];
364 double betgam = std::sqrt(momentum2);
366 double gamma = std::sqrt(1.0 + momentum2);
367 double beta = betgam / gamma;
371 double Ufactor = 1.0;
377 Ufactor = std::sin(transit_factor) / transit_factor;
383 double dgam = Voltage * std::cos(nphase) / (restMass);
386 if (tempdegree > 270.0) tempdegree -= 360.0;
390 double newmomentum2 = std::pow(gamma, 2) - 1.0;
393 double ptheta = std::sqrt(newmomentum2 - std::pow(pr, 2));
399 / (betgam * restMass /
Physics::c / chargenumber);
402 momentum[0] = std::cos(rotate) * px + std::sin(rotate) * py;
403 momentum[1] = -std::sin(rotate) * px + std::cos(rotate) * py;
406 Inform m(
"OPAL", *
gmsg, ippl::Comm->rank());
408 m <<
"* Cavity " <<
getName() <<
" Phase= " << tempdegree
409 <<
" [deg] transit time factor= " << Ufactor
412 <<
" [MeV] Time dep freq = " <<
frequencyTD_m->getValue(t) << endl;
434 while ((ih - il) > 1) {
435 int i = (int)((il + ih) / 2.0);
458 double u = (z - x1) / dx;
461 double dy2 = -2.0 * dy;
462 double ya2 = y2a + 2.0 * y1a;
463 double dy3 = 3.0 * dy;
464 double ya3 = y2a + y1a;
465 double yb2 = dy2 + dx * ya3;
466 double yb4 = dy3 - dx * ya2;
467 splint = y1 + u * dx * y1a + u2 * yb4 + u3 * yb2;
468 *za = y1a + 2.0 * u / dx * yb4 + 3.0 * u2 / dx * yb2;
484 const double dt = 1e-13;
496 for (
unsigned int j = 0; j < 2; ++j) {
497 for (
unsigned int i = 0; i < 36; ++i, phi += dphi) {
514 const int prevPrecision = ippl::Info->precision(8);
515 Inform m(
"RFCavity::getAutoPhaseEstimateFallback");
516 m << level2 <<
"estimated phase= " << phimax <<
" rad = " << phimax *
Units::rad2deg <<
" deg\n"
517 <<
"Ekin= " << Emax <<
" MeV" << std::setprecision(prevPrecision) <<
"\n"
525 const double& E0,
const double& t0,
const double& q,
const double& mass) {
526 std::vector<double> t, E, t2, E2;
527 std::vector<double> F;
528 std::vector<std::pair<double, double> > G;
533 double dz = 1.0, length = 0.0;
535 if (G.size() == 0)
return 0.0;
536 double begin = (G.front()).first;
537 double end = (G.back()).first;
538 std::unique_ptr<double[]> zvals(
new double[G.size()]);
539 std::unique_ptr<double[]> onAxisField(
new double[G.size()]);
541 for (
size_t j = 0; j < G.size(); ++j) {
542 zvals[j] = G[j].first;
543 onAxisField[j] = G[j].second;
547 gsl_spline_init(onAxisInterpolants, zvals.get(), onAxisField.get(), G.size());
549 length = end - begin;
550 dz = length / G.size();
554 unsigned int N = (int)std::floor(length / dz + 1);
559 for (
size_t j = 0; j < N; ++j, z += dz) {
571 for (
unsigned int i = 1; i < N; ++i, z += dz) {
572 E[i] = E[i - 1] + dz *
scale_m / mass;
576 for (
int iter = 0; iter < 10; ++iter) {
579 for (
unsigned int i = 1; i < N; ++i) {
580 t[i] = t[i - 1] +
getdT(i, E, dz, mass);
581 t2[i] = t2[i - 1] +
getdT(i, E2, dz, mass);
588 if (std::abs(B) > 0.0000001) {
589 tmp_phi = std::atan(A / B);
593 if (q * (A * std::sin(tmp_phi) + B * std::cos(tmp_phi)) < 0) {
597 if (std::abs(phi - tmp_phi) <
frequency_m * (t[N - 1] - t[0]) / (10 * N)) {
598 for (
unsigned int i = 1; i < N; ++i) {
602 const int prevPrecision = ippl::Info->precision(8);
603 Inform m(
"RFCavity::getAutoPhaseEstimate");
604 m << level2 <<
"estimated phase= " << tmp_phi <<
" rad = " << tmp_phi *
Units::rad2deg
606 <<
"Ekin= " << E[N - 1] <<
" MeV" << std::setprecision(prevPrecision) <<
"\n"
613 for (
unsigned int i = 1; i < N; ++i) {
618 double a = E[i], b = E2[i];
619 if (std::isnan(a) || std::isnan(b)) {
622 t[i] = t[i - 1] +
getdT(i, E, dz, mass);
623 t2[i] = t2[i - 1] +
getdT(i, E2, dz, mass);
631 double cosine_part = 0.0, sine_part = 0.0;
636 double totalEz0 = std::cos(phi) * cosine_part - std::sin(phi) * sine_part;
638 if (p0 + q * totalEz0 * (t[1] - t[0]) *
Physics::c / mass < 0) {
640 tmp_phi = std::atan(cosine_part / sine_part);
649 const int prevPrecision = ippl::Info->precision(8);
650 Inform m(
"RFCavity::getAutoPhaseEstimate");
651 m << level2 <<
"estimated phase= " << tmp_phi <<
" rad = " << tmp_phi *
Units::rad2deg
653 <<
"Ekin= " << E[N - 1] <<
" MeV" << std::setprecision(prevPrecision) <<
"\n"
660 const double& p0,
const double& t0,
const double& dt,
const double& ,
661 const double& mass, std::ofstream* out) {
678 while (z(2) + dz < zend && z(2) + dz > zbegin) {
680 integrator.
push(z, p, dt);
685 if (z(2) >= zbegin && z(2) <= zend) {
689 integrator.
kick(z, p, Ef, Bf, dt, ref.
getM(), ref.
getQ());
691 dz = 0.5 * p(2) / std::sqrt(1.0 +
dot(p, p)) * cdt;
694 integrator.
push(z, p, dt);
703 const double beta = std::sqrt(1. - 1 / (
dot(p, p) + 1.));
704 const double tErr = (z(2) - zend) / (
Physics::c * beta);
705 return std::pair<double, double>(p(2), t - tErr);
Defines the abstract interface for a single beamline component in the accelerator model.
ippl::Vector< T, Dim > Vector_t
constexpr int gsl_interp_cspline
double gsl_spline_eval(const gsl_spline *spline, const double x, gsl_interp_accel *accel)
Evaluate a spline at x using an accelerator.
gsl_interp_accel * gsl_interp_accel_alloc()
Allocate an interpolation accelerator.
void gsl_spline_init(gsl_spline *spline, const double *x, const double *y, const size_t n)
Initialize a spline with tabulated data.
void gsl_spline_free(const gsl_spline *spline)
Free a spline instance.
void gsl_interp_accel_free(const gsl_interp_accel *accel)
Free an accelerator instance.
gsl_spline * gsl_spline_alloc(const int type, size_t)
Allocate a spline instance (size ignored).
Template PIC bunch: IPPL PicManager, shared field mesh/solver, and multiple particle containers.
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Accelerator caching last interval indices.
Base class for the linear and cubic interpolation spline classes.
virtual void visitRFCavity(const RFCavity &)=0
Apply the algorithm to a RF cavity.
Simple bidirectional map with lookup in both directions.
void insert(const Left &left, const Right &right)
Insert or overwrite a left/right association.
right_view right
Right view accessor.
left_view left
Left view accessor.
KOKKOS_INLINE_FUNCTION void kick(const Vector_t< double, 3 > &R, Vector_t< double, 3 > &P, const Vector_t< double, 3 > &Ef, const Vector_t< double, 3 > &Bf, const double &dt, const double &mass, const double &charge) const
KOKKOS_INLINE_FUNCTION void push(Vector_t< double, 3 > &R, const Vector_t< double, 3 > &P, const double &dt) const
PartBunch_t * RefPartBunch_m
virtual const std::string & getName() const
Get element name.
bool getFlagDeleteOnTransverseExit() const
virtual double getElementLength() const
Get design length.
bool isInsideTransverse(const Vector_t< double, 3 > &r) const
virtual bool getFieldstrength(const Vector_t< double, 3 > &R, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B) const =0
Get the field strength at a given point.
virtual void getInfo(Inform *msg)=0
Print info about the field map.
virtual void getFieldDimensions(double &zBegin, double &zEnd) const =0
Get the longitudinal dimensions of the field.
virtual void getOnaxisEz(std::vector< std::pair< double, double > > &onaxis)
virtual double getFrequency() const =0
Get the frequency.
virtual bool isInside(const Vector_t< double, 3 > &) const =0
Check if a point is inside the field map.
Vector_t< double, Dim > R(size_t)
Do not use; throws (access positions via ParticleContainer::R).
double getdT() const
Get the global time step.
double getTotalCharge() const
Get the total charge across all particle containers.
double getT() const
Get the current simulation time.
const PartData * getReference() const
KOKKOS_INLINE_FUNCTION double getM() const
The constant mass per particle.
KOKKOS_INLINE_FUNCTION double getQ() const
The constant charge per particle.
Interface for standing wave cavities.
void setFrequencyModel(std::shared_ptr< AbstractTimeDependence > time_dep)
virtual double getPhasem() const
virtual bool bends() const override
virtual double getRmax() const
void setPerpenDistance(double pdis)
void getMomentaKick(const double normalRadius, double momentum[], const double t, const double dtCorrt, const int PID, const double restMass, const int chargenumber)
used in OPAL-cycl
virtual double getAzimuth() const
virtual void initialise(PartBunch_t *bunch, double &startField, double &endField) override
virtual ElementType getType() const override
Get element type std::string.
double getdE(const int &i, const std::vector< double > &t, const double &dz, const double &phi, const double &frequency, const std::vector< double > &F) const
virtual void accept(BeamlineVisitor &) const override
Apply visitor to RFCavity.
double getdB(const int &i, const std::vector< double > &t, const double &dz, const double &frequency, const std::vector< double > &F) const
std::unique_ptr< double[]> DvDr_m
virtual void finalise() override
void setRmin(double rmin)
virtual bool apply(const std::shared_ptr< ParticleContainer_t > &pc) override
Applies the Standing Wave RF Cavity field to all particles inside the RF cavity.
void setPhaseModel(std::shared_ptr< AbstractTimeDependence > time_dep)
virtual void getElementDimensions(double &begin, double &end) const override
Return the nominal body extent of the element.
virtual double getCosAzimuth() const
std::string frequencyName_m
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)
std::unique_ptr< double[]> RNormal_m
virtual void getFieldExtend(double &zBegin, double &zEnd) const override
Return the field-support interval of the cavity.
virtual void setPhasem(double phase)
virtual double getSinAzimuth() const
void setPhi0(double phi0)
double spline(double z, double *za)
std::shared_ptr< AbstractTimeDependence > frequencyTD_m
virtual std::string getFieldMapFN() const
void setAzimuth(double angle)
std::unique_ptr< double[]> VrNormal_m
virtual void goOnline(const double &kineticEnergy) override
void setCavityType(const std::string &type)
virtual bool isInside(const Vector_t< double, 3 > &r) const override
virtual double getCycFrequency() const
double getdA(const int &i, const std::vector< double > &t, const double &dz, const double &frequency, const std::vector< double > &F) const
virtual double getGapWidth() const
virtual double getAutoPhaseEstimate(const double &E0, const double &t0, const double &q, const double &m)
static const BiMap< CavityType, std::string > bmCavityTypeString_s
virtual double getPerpenDistance() const
void setGapWidth(double gapwidth)
virtual double getElementLength() const override
Return the nominal body length of the cavity.
virtual bool applyToReferenceParticle(const Vector_t< double, 3 > &R, const Vector_t< double, 3 > &P, const double &t, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B) override
Apply to reference particle with position R and momemtum P.
virtual void goOffline() override
virtual double getPhi0() const
virtual double getAutoPhaseEstimateFallback(double E0, double t0, double q, double m)
std::string getCavityTypeString() const
void setRmax(double rmax)
void setAmplitudeModel(std::shared_ptr< AbstractTimeDependence > time_dep)
virtual double getRmin() const
double getdT(const int &i, const std::vector< double > &E, const double &dz, const double mass) const
constexpr double two_pi
The value of.
constexpr double c
The velocity of light in m/s.
constexpr double pi
The value of.
constexpr double MVpm2Vpm
double getBetaGamma(double Ekin, double mass)
double getGamma(ippl::Vector< double, 3 > p)
double getKineticEnergy(ippl::Vector< double, 3 > p, double mass)