27#ifndef CLOSEDORBITFINDER_H
28#define CLOSEDORBITFINDER_H
49#include <boost/numeric/odeint/integrate/integrate_n_steps.hpp>
53template<
typename Value_type,
typename Size_type,
class Stepper>
80 Cyclotron* cycl,
bool domain =
true,
int Nsectors = 1);
92 std::pair<value_type,value_type>
getTunes();
134 bool isTuneMode =
false);
159 std::array<value_type,2>
x_m;
163 std::array<value_type,2>
z_m;
248 std::function<double(
double,
double)>
bcon_m = [
this](
double e0,
double wo) {
259template<
typename Value_type,
typename Size_type,
class Stepper>
265 bool domain,
int nSectors)
284 throw OpalException(
"ClosedOrbitFinder::ClosedOrbitFinder()",
285 "Incorrect cyclotron energy (MeV) bounds: Maximum cyclotron energy smaller than minimum cyclotron energy.");
310template<
typename Value_type,
typename Size_type,
class Stepper>
321template<
typename Value_type,
typename Size_type,
class Stepper>
332template<
typename Value_type,
typename Size_type,
class Stepper>
342template<
typename Value_type,
typename Size_type,
class Stepper>
350 return std::make_pair(nur,nuz);
353template<
typename Value_type,
typename Size_type,
class Stepper>
364template<
typename Value_type,
typename Size_type,
class Stepper>
391 std::for_each(pr.begin(), pr.end(), [factor](
value_type& p) { p *= factor; });
396template<
typename Value_type,
typename Size_type,
class Stepper>
403template<
typename Value_type,
typename Size_type,
class Stepper>
414template<
typename Value_type,
typename Size_type,
class Stepper>
436 value_type error = std::numeric_limits<value_type>::max();
456 E_fin =
cycl_m->getFMHighE();
459 namespace fs = std::filesystem;
462 std::string tunefile = (dir /
"tunes.dat").
string();
465 std::ofstream out(tunefile, std::ios::out);
468 << std::setw(15) <<
"# energy[MeV]"
469 << std::setw(15) <<
"radius_ini[m]"
470 << std::setw(15) <<
"momentum_ini[Beta Gamma]"
471 << std::setw(15) <<
"radius_avg[m]"
472 << std::setw(15) <<
"nu_r"
473 << std::setw(15) <<
"nu_z"
478 enum Guess {
NONE, FIRST, SECOND};
485 *
gmsg <<
level3 <<
"Start iteration to find closed orbit of energy "
486 << E_fin <<
" MeV " <<
"in steps of " << dE <<
" MeV." <<
endl;
488 for (; E <= E_fin + eps; E += dE) {
490 error = std::numeric_limits<value_type>::max();
496 value_type beta = std::sqrt(1.0 - 1.0 / gamma2);
504 init = {beta * acon, 0.0, 0.0, 1.0};
509 }
else if (guess == FIRST) {
511 init[0] = (beta*acon) * rn1;
514 }
else if (guess == SECOND) {
516 init[0] = (beta*acon) * (rn1 + (rn1-rn2));
517 init[1] = p*(pn1 + (pn1-pn2));
520 std::fill(
r_m.begin(),
r_m.end(), 0);
521 std::fill(
pr_m.begin(),
pr_m.end(), 0);
522 std::fill(
vz_m.begin(),
vz_m.end(), 0);
531 *
gmsg <<
level3 <<
" Try to find orbit for " << E <<
" MeV ... ";
534 *
gmsg <<
endl <<
"ClosedOrbitFinder didn't converge for energy " + std::to_string(E) +
" MeV." <<
endl;
544 rn1 =
r_m[0] / (acon * beta);
551 std::pair<value_type, value_type> tunes = this->
getTunes();
554 <<
"* ----------------------------" <<
endl
555 <<
"* Closed orbit info (Gordon units):" <<
endl
557 <<
"* kinetic energy: " << std::setw(12) << E <<
" [MeV]" <<
endl
558 <<
"* average radius: " << std::setw(12) <<
ravg_m <<
" [m]" <<
endl
559 <<
"* initial radius: " << std::setw(12) << reo <<
" [m]" <<
endl
560 <<
"* initial momentum: " << std::setw(12) << peo <<
" [Beta Gamma]" <<
endl
562 <<
"* horizontal tune: " << tunes.first <<
endl
563 <<
"* vertical tune: " << tunes.second <<
endl
564 <<
"* ----------------------------" <<
endl <<
endl;
566 std::ofstream out(tunefile, std::ios::app);
568 << std::setw(15) << E
569 << std::setw(15) << reo
570 << std::setw(15) << peo
571 << std::setw(15) <<
ravg_m
572 << std::setw(15) << tunes.first
573 << std::setw(15) << tunes.second << std::endl;
578 bool isConvergent = error < accuracy;
580 *
gmsg <<
level3 <<
"Finished closed orbit finder successfully." <<
endl;
604template<
typename Value_type,
typename Size_type,
class Stepper>
631 nxcross_m += (idx > 0) * (y[4] * xold < 0);
635 nzcross_m += (idx > 0) * (y[10] * zold < 0);
658 value_type invgamma4 = 1.0 / (gamma2 * gamma2);
673 throw OpalException(
"ClosedOrbitFinder::findOrbitOfEnergy_m()",
674 "p_{r}^2 > p^{2} (defined in Gordon paper) --> Square root of negative number.");
677 ptheta = std::sqrt(p2 - pr2);
678 invptheta = 1.0 / ptheta;
680 brint=0.0, btint=0.0, bint=0.0;
683 double tmpbr, tmpbt, tmpb;
685 cycl_m->apply(y[0], y[6], angle, tmpbr, tmpbt, tmpb);
699 dydt[0] = y[0] * y[1] * invptheta;
701 dydt[1] = ptheta - y[0] * bint;
704 dydt[i] = (y[1] * y[i] + y[0] * p2 * y[i+1] * invptheta * invptheta) * invptheta;
705 dydt[i+1] = - y[1] * y[i+1] * invptheta - (bint + y[0] * brint) * y[i];
710 dydt[i] = y[0] * y[i+1] * invptheta;
711 dydt[i+1] = (y[0] * brint - y[1] * invptheta * btint) * y[i];
715 dydt[12] = y[0] * invptheta * gamma - 1;
736 y = {init[0],init[1],
745 boost::numeric::odeint::integrate_n_steps(
stepper_m, orbit_integration,y,0.0,
dtheta_m,
N_m,store);
770 delta[0] = ((
px_m[1] - 1.0) * err[0] -
x_m[1] * err[1]) * invdenom;
771 delta[1] = ((
x_m[0] - 1.0) * err[1] -
px_m[0] * err[0]) * invdenom;
778 error = std::sqrt(delta[0] * delta[0] + delta[1] * delta[1] * invgamma4) /
r_m[0];
782 }
while ((error > accuracy) && (niterations++ < maxit));
784 if (error > accuracy) {
785 *
gmsg <<
"findOrbit not converged after " << niterations
786 <<
" iterations with error: " << error
787 <<
". Needed accuracy " << accuracy <<
endl;
789 return (error < accuracy);
792template<
typename Value_type,
typename Size_type,
class Stepper>
804 bool negative = std::signbit(y[1]);
806 bool uneven = (ncross % 2);
816 muPrime = -std::acosh(abscos);
819 muPrime = (uneven) ? std::acos(-
cos) : std::acos(
cos);
832 if (!negative && std::signbit(std::sin(mu))) {
834 }
else if (negative && !std::signbit(std::sin(mu))) {
845 mu *=
cycl_m->getSymmetry();
850template<
typename Value_type,
typename Size_type,
class Stepper>
886 throw OpalException(
"ClosedOrbitFinder::computeOrbitProperties()",
887 "p_{r}^2 > p^{2} " + std::to_string(p) +
" " + std::to_string(
pr_m[i]) +
" (defined in Gordon paper) --> Square root of negative number.");
889 ptheta = std::sqrt(p2 -
pr_m[i] *
pr_m[i]);
891 fidx_m[i] = (brint * ptheta - btint *
pr_m[i] /
r_m[i]) / p2;
904template<
typename Value_type,
typename Size_type,
class Stepper>
915 unsigned int start = angle /
dtheta_m;
917 start %= orbitProperty.size();
920 std::copy(orbitProperty.begin() + start, orbitProperty.end(), orbitPropertyCopy.begin());
923 std::copy_n(orbitProperty.begin(), start, orbitPropertyCopy.end() - start);
925 return orbitPropertyCopy;
Tps< T > cos(const Tps< T > &x)
Cosine.
T * value_type(const SliceIterator< T > &)
Inform & endl(Inform &inf)
Inform & level3(Inform &inf)
constexpr double u_two_pi
The value of.
constexpr double two_pi
The value of.
constexpr double c
The velocity of light in m/s.
constexpr double pi
The value of.
std::string getInputBasename()
get input file name without extension
static OpalData * getInstance()
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
std::vector< value_type > container_type
Type of container for storing quantities (path length, orbit, etc.).
std::pair< value_type, value_type > getTunes()
Returns the radial and vertical tunes (in that order).
std::array< value_type, 2 > px_m
Stores current momenta in horizontal direction for the solutions of the ODE with different initial va...
size_type N_m
Number of integration steps.
ClosedOrbitFinder(value_type E0, value_type q, size_type N, Cyclotron *cycl, bool domain=true, int Nsectors=1)
Sets the initial values for the integration and calls findOrbit().
container_type vz_m
Stores the vertical oribt (size: N_m+1).
size_type nzcross_m
Counts the number of zero-line crossings in vertical direction (used for computing vertical tune).
value_type phase_m
Is the phase.
bool findOrbitOfEnergy_m(const value_type &, container_type &, value_type &, const value_type &, size_type)
std::vector< value_type > state_type
Type for holding state of ODE values.
void computeOrbitProperties(const value_type &E)
Fills in the values of h_m, ds_m, fidx_m.
std::array< value_type, 2 > z_m
Stores current position in vertical direction for the solutions of the ODE with different initial val...
container_type fidx_m
Stores the field index.
value_type wo_m
Is the nominal orbital frequency.
container_type ds_m
Stores the step length.
bool findOrbit(value_type accuracy, size_type maxit, value_type ekin, value_type dE=1.0, value_type rguess=-1.0, bool isTuneMode=false)
Computes the closed orbit.
container_type h_m
Stores the inverse bending radius.
std::function< double(double, double)> bcon_m
Cyclotron unit (Tesla).
container_type r_m
Stores the radial orbit (size: N_m+1).
Size_type size_type
Type for specifying sizes.
container_type vpz_m
Stores the vertical momentum.
value_type getAverageRadius()
Returns the average orbit radius.
std::function< double(double)> acon_m
value_type dtheta_m
Is the angle step size.
std::function< void(const state_type &, state_type &, const double)> function_t
container_type getFieldIndex(const value_type &angle=0)
Returns the field index (size of container N+1).
Value_type value_type
Type of variables.
container_type getMomentum(value_type angle=0)
container_type getOrbit(value_type angle=0)
container_type rotate(value_type angle, const container_type &orbitProperty)
This function computes nzcross_ which is used to compute the tune in z-direction and the frequency er...
bool isConverged()
Returns true if a closed orbit could be found.
container_type getPathLength(const value_type &angle=0)
Returns the step lengths of the path (size of container N+1).
std::array< value_type, 2 > pz_m
Stores current momenta in vertical direction for the solutions of the ODE with different initial valu...
std::array< value_type, 2 > x_m
Stores current position in horizontal direction for the solutions of the ODE with different initial v...
value_type ravg_m
Is the average radius.
container_type pr_m
Stores the radial momentum.
container_type getInverseBendingRadius(const value_type &angle=0)
Returns the inverse bending radius (size of container N+1).
value_type getFrequencyError()
Returns the frequency error.
value_type computeTune(const std::array< value_type, 2 > &, value_type, size_type)
This function is called by the function getTunes().
value_type E0_m
Is the rest mass [MeV / c**2].
size_type nxcross_m
Counts the number of zero-line crossings in horizontal direction (used for computing horizontal tune)...
Stepper stepper_m
Defines the stepper for integration of the ODE's.
The base class for all OPAL exceptions.
virtual const std::string & what() const
Return the message string for the exception.
virtual const std::string & where() const
Return the name of the method or function which detected the exception.