27 #ifndef CLOSEDORBITFINDER_H
28 #define CLOSEDORBITFINDER_H
49 #include <boost/numeric/odeint/integrate/integrate_n_steps.hpp>
53 template<
typename Value_type,
typename Size_type,
class Stepper>
66 typedef std::function<void(const state_type&, state_type&, const double)>
function_t;
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) {
259 template<
typename Value_type,
typename Size_type,
class Stepper>
265 bool domain,
int nSectors)
270 , wo_m(cycl->getRfFrequ()[0]*Units::
MHz2Hz/cycl->getCyclHarm()*2.0*Physics::
pi)
278 , nSectors_m(nSectors)
284 throw OpalException(
"ClosedOrbitFinder::ClosedOrbitFinder()",
285 "Incorrect cyclotron energy (MeV) bounds: Maximum cyclotron energy smaller than minimum cyclotron energy.");
310 template<
typename Value_type,
typename Size_type,
class Stepper>
315 return rotate(angle, h_m);
321 template<
typename Value_type,
typename Size_type,
class Stepper>
326 return rotate(angle, ds_m);
332 template<
typename Value_type,
typename Size_type,
class Stepper>
337 return rotate(angle, fidx_m);
342 template<
typename Value_type,
typename Size_type,
class Stepper>
345 value_type nur = computeTune(x_m,px_m[1],nxcross_m);
348 value_type nuz = computeTune(z_m,pz_m[1],nzcross_m);
350 return std::make_pair(nur,nuz);
353 template<
typename Value_type,
typename Size_type,
class Stepper>
358 return rotate(angle, r_m);
364 template<
typename Value_type,
typename Size_type,
class Stepper>
371 pr = rotate(angle, pr);
396 template<
typename Value_type,
typename Size_type,
class Stepper>
403 template<
typename Value_type,
typename Size_type,
class Stepper>
414 template<
typename Value_type,
typename Size_type,
class Stepper>
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) {
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);
523 std::fill(vpz_m.begin(), vpz_m.end(), 0);
531 *gmsg <<
level3 <<
" Try to find orbit for " << E <<
" MeV ... ";
533 if ( !this->findOrbitOfEnergy_m(E, init, error, accuracy, maxit) ) {
534 *gmsg << endl <<
"ClosedOrbitFinder didn't converge for energy " + std::to_string(E) +
" MeV." <<
endl;
539 *gmsg <<
level3 <<
"Successfully found." <<
endl;
544 rn1 = r_m[0] / (acon * beta);
548 this->computeOrbitProperties(E);
549 value_type reo = this->getOrbit( cycl_m->getPHIinit())[0];
550 value_type peo = this->getMomentum(cycl_m->getPHIinit())[0];
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
561 <<
"* frequency error: " << phase_m << 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 *gmsg <<
level3 <<
"Finished closed orbit finder successfully." <<
endl;
594 phase_m *= cycl_m->getSymmetry();
598 return error < accuracy;
601 template<
typename Value_type,
typename Size_type,
class Stepper>
613 value_type invbcon = 1.0 / bcon_m(E0_m, wo_m);
628 nxcross_m += (idx > 0) * (y[4] * xold < 0);
632 nzcross_m += (idx > 0) * (y[10] * zold < 0);
655 value_type invgamma4 = 1.0 / (gamma2 * gamma2);
670 throw OpalException(
"ClosedOrbitFinder::findOrbitOfEnergy_m()",
671 "p_{r}^2 > p^{2} (defined in Gordon paper) --> Square root of negative number.");
675 invptheta = 1.0 / ptheta;
677 brint=0.0, btint=0.0, bint=0.0;
678 for (
int i = 0; i<nSectors_m; i++) {
680 double tmpbr, tmpbt, tmpb;
682 cycl_m->apply(y[0], y[6], angle, tmpbr, tmpbt, tmpb);
696 dydt[0] = y[0] * y[1] * invptheta;
698 dydt[1] = ptheta - y[0] * bint;
701 dydt[i] = (y[1] * y[i] + y[0] * p2 * y[i+1] * invptheta * invptheta) * invptheta;
702 dydt[i+1] = - y[1] * y[i+1] * invptheta - (bint + y[0] * brint) * y[i];
707 dydt[i] = y[0] * y[i+1] * invptheta;
708 dydt[i+1] = (y[0] * brint - y[1] * invptheta * btint) * y[i];
712 dydt[12] = y[0] * invptheta * gamma - 1;
733 y = {init[0],init[1],
734 x_m[0], px_m[0], x_m[1], px_m[1],
736 z_m[0], pz_m[0], z_m[1], pz_m[1],
742 boost::numeric::odeint::integrate_n_steps(stepper_m, orbit_integration,y,0.0,dtheta_m,N_m,store);
762 err[0] = r_m[N_m] - r_m[0];
763 err[1] = pr_m[N_m] - pr_m[0];
766 value_type invdenom = 1.0 / (x_m[0] + px_m[1] - 2.0);
767 delta[0] = ((px_m[1] - 1.0) * err[0] - x_m[1] * err[1]) * invdenom;
768 delta[1] = (( x_m[0] - 1.0) * err[1] - px_m[0] * err[0]) * invdenom;
775 error =
std::sqrt(delta[0] * delta[0] + delta[1] * delta[1] * invgamma4) / r_m[0];
779 }
while ((error > accuracy) && (niterations++ < maxit));
781 if (error > accuracy) {
782 *gmsg <<
"findOrbit not converged after " << niterations
783 <<
" iterations with error: " << error
784 <<
". Needed accuracy " << accuracy <<
endl;
786 return (error < accuracy);
789 template<
typename Value_type,
typename Size_type,
class Stepper>
801 bool negative = std::signbit(y[1]);
803 bool uneven = (ncross % 2);
813 muPrime = -std::acosh(abscos);
829 if (!negative && std::signbit(
std::sin(mu))) {
831 }
else if (negative && !std::signbit(
std::sin(mu))) {
842 mu *= cycl_m->getSymmetry();
847 template<
typename Value_type,
typename Size_type,
class Stepper>
859 value_type invbcon = 1.0 / bcon_m(E0_m, wo_m);
873 cycl_m->apply(r_m[i], vz_m[i], theta, brint, btint, bint);
883 throw OpalException(
"ClosedOrbitFinder::computeOrbitProperties()",
884 "p_{r}^2 > p^{2} " + std::to_string(p) +
" " + std::to_string(pr_m[i]) +
" (defined in Gordon paper) --> Square root of negative number.");
886 ptheta =
std::sqrt(p2 - pr_m[i] * pr_m[i]);
888 fidx_m[i] = (brint * ptheta - btint * pr_m[i] / r_m[i]) / p2;
891 ds_m[i] = std::hypot(r_m[i] * pr_m[i] / ptheta,r_m[i]) * dtheta_m;
898 ravg_m = std::accumulate(r_m.begin(),r_m.end(),0.0) /
value_type(r_m.size());
901 template<
typename Value_type,
typename Size_type,
class Stepper>
912 unsigned int start = angle / dtheta_m;
914 start %= orbitProperty.size();
917 std::copy(orbitProperty.begin() + start, orbitProperty.end(), orbitPropertyCopy.begin());
920 std::copy_n(orbitProperty.begin(), start, orbitPropertyCopy.end() - start);
922 return orbitPropertyCopy;
value_type wo_m
Is the nominal orbital frequency.
static OpalData * getInstance()
value_type computeTune(const std::array< value_type, 2 > &, value_type, size_type)
This function is called by the function getTunes().
Tps< T > sqrt(const Tps< T > &x)
Square root.
constexpr double c
The velocity of light in m/s.
virtual double getFMHighE() const
std::pair< value_type, value_type > getTunes()
Returns the radial and vertical tunes (in that order)
and give any other recipients of the Program a copy of this License along with the Program You may charge a fee for the physical act of transferring a copy
std::function< double(double)> acon_m
void computeOrbitProperties(const value_type &E)
Fills in the values of h_m, ds_m, fidx_m.
item[EANGLE] Entrance edge angle(radians).\item[ROTATION] Rotation of the magnet about its central axis(radians
constexpr double two_pi
The value of .
void read(const double &scaleFactor)
size_type N_m
Number of integration steps.
virtual const std::string & what() const
Return the message string for the exception.
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().
bool isConverged()
Returns true if a closed orbit could be found.
container_type getOrbit(value_type angle=0)
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
container_type getFieldIndex(const value_type &angle=0)
Returns the field index (size of container N+1)
size_type nzcross_m
Counts the number of zero-line crossings in vertical direction (used for computing vertical tune) ...
value_type getFrequencyError()
Returns the frequency error.
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 value_type
Type of variables.
std::array< value_type, 2 > z_m
Stores current position in vertical direction for the solutions of the ODE with different initial val...
value_type ravg_m
Is the average radius.
container_type getMomentum(value_type angle=0)
std::array< value_type, 2 > px_m
Stores current momenta in horizontal direction for the solutions of the ODE with different initial va...
container_type pr_m
Stores the radial momentum.
value_type E0_m
Is the rest mass [MeV / c**2].
constexpr double pi
The value of .
Inform & endl(Inform &inf)
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
container_type getInverseBendingRadius(const value_type &angle=0)
Returns the inverse bending radius (size of container N+1)
virtual const std::string & where() const
Return the name of the method or function which detected the exception.
std::function< double(double, double)> bcon_m
Cyclotron unit (Tesla)
The base class for all OPAL exceptions.
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
value_type dtheta_m
Is the angle step size.
Stepper stepper_m
Defines the stepper for integration of the ODE's.
container_type vz_m
Stores the vertical oribt (size: N_m+1)
Size_type size_type
Type for specifying sizes.
virtual double getSymmetry() const
value_type phase_m
Is the phase.
constexpr double u_two_pi
The value of .
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.
Tps< T > cos(const Tps< T > &x)
Cosine.
PETE_TUTree< FnArcCos, typename T::PETE_Expr_t > acos(const PETE_Expr< T > &l)
container_type r_m
Stores the radial orbit (size: N_m+1)
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 findOrbitOfEnergy_m(const value_type &, container_type &, value_type &, const value_type &, size_type)
std::array< value_type, 2 > pz_m
Stores current momenta in vertical direction for the solutions of the ODE with different initial valu...
T * value_type(const SliceIterator< T > &)
std::string getInputBasename()
get input file name without extension
Inform & level3(Inform &inf)
virtual double getBScale() const
container_type vpz_m
Stores the vertical momentum.
bool for_each(const BareFieldIterator< T, D > &p, SameFieldID s, C)
std::vector< value_type > container_type
Type of container for storing quantities (path length, orbit, etc.)
container_type getPathLength(const value_type &angle=0)
Returns the step lengths of the path (size of container N+1)
Tps< T > sin(const Tps< T > &x)
Sine.
container_type ds_m
Stores the step length.
container_type h_m
Stores the inverse bending radius.
std::vector< value_type > state_type
Type for holding state of ODE values.
container_type fidx_m
Stores the field index.
size_type nxcross_m
Counts the number of zero-line crossings in horizontal direction (used for computing horizontal tune)...
virtual double getFMLowE() const
std::function< void(const state_type &, state_type &, const double)> function_t
value_type getAverageRadius()
Returns the average orbit radius.