50#include <boost/numeric/odeint/stepper/runge_kutta4.hpp>
63 unsigned int Nsectors,
71 ,
nh_m(cycl->getCyclHarm())
77 ,
Emin_m(cycl->getFMLowE())
78 ,
Emax_m(cycl->getFMHighE())
111 H_m = [&](
double h,
double kx,
double ky) {
117 Hsc_m = [&](
double sigx,
double sigy,
double sigz) {
123 double K3 = 3.0 * std::abs(
q_m) *
I_m * lam
134 double sx = std::sqrt(std::abs(sigx));
135 double sy = std::sqrt(std::abs(sigy));
136 double sz = std::sqrt(std::abs(sigz));
138 double tmp = sx * sy;
140 double f = std::sqrt(tmp) / (3.0 *
gamma_m * sz);
141 double kxy = K3 * std::abs(1.0 - f) / ((sx + sy) * sz);
143 double Kx = kxy / sx;
144 double Ky = kxy / sy;
145 double Kz = K3 * f / (tmp * sz);
147 return -0.5 * Kx *
x_m *
x_m
156 unsigned int maxitOrbit,
187 if ( !cof.findOrbit(accuracy, maxitOrbit,
E_m, denergy, rguess) ) {
189 "Closed orbit finder didn't converge.");
192 cof.computeOrbitProperties(
E_m);
195 container_t h = cof.getInverseBendingRadius(angle);
211 if (!std::filesystem::exists(fpath)) {
212 std::filesystem::create_directory(fpath);
215 std::pair<double,double> tunes = cof.getTunes();
216 double ravg = cof.getAverageRadius();
219 *
gmsg <<
"* ----------------------------" <<
endl
220 <<
"* Closed orbit info:" <<
endl
222 <<
"* average radius: " << ravg <<
" [m]" <<
endl
223 <<
"* initial radius: " << r[0] <<
" [m]" <<
endl
224 <<
"* initial momentum: " << peo[0] <<
" [Beta Gamma]" <<
endl
225 <<
"* frequency error: " << cof.getFrequencyError()*100 <<
" [ % ] "<<
endl
226 <<
"* horizontal tune: " << tunes.first <<
endl
227 <<
"* vertical tune: " << tunes.second <<
endl
228 <<
"* ----------------------------" <<
endl <<
endl;
234 std::ofstream writeMturn, writeMcyc, writeMsc;
243 "OneTurnMapsForEnergy" + energy +
"MeV.dat"
246 writeMturn.open(fname, std::ios::out);
251 "SpaceChargeMapPerAngleForEnergy" + energy +
"MeV_iteration_0.dat"
254 writeMsc.open(fname, std::ios::out);
259 "CyclotronMapPerAngleForEnergy" + energy +
"MeV.dat"
262 writeMcyc.open(fname, std::ios::out);
266 for (
unsigned int i = 0; i <
nSteps_m; ++i) {
267 Mcycs[i] = mapgen.generateMap(
H_m(h[i],
286 mapgen.combine(Mscs,Mcycs);
302 while (
error_m > accuracy && !stop) {
325 "SpaceChargeMapPerAngleForEnergy" + energy +
"MeV_iteration_"
330 writeMsc.open(fname, std::ios::out);
334 for (
unsigned int i = 0; i <
nSteps_m; ++i) {
348 mapgen.combine(Mscs,Mcycs);
349 Mturn = mapgen.getMap();
370 }
catch(
const std::exception& e) {
378 "MatchedDistributions.dat"
381 std::ofstream writeSigmaMatched(fname, std::ios::out);
385 writeSigmaMatched <<
"* Converged (Ex, Ey, Ez) = (" << emit[0]
386 <<
", " << emit[1] <<
", " << emit[2]
387 <<
") pi mm mrad for E= " <<
E_m <<
" (MeV)"
388 << std::endl <<
"* Sigma-Matrix " << std::endl;
390 for(
unsigned int i = 0; i <
sigma_m.size1(); ++ i) {
391 writeSigmaMatched << std::setprecision(4) << std::setw(11)
393 for(
unsigned int j = 1; j <
sigma_m.size2(); ++ j) {
394 writeSigmaMatched <<
" & " << std::setprecision(4)
395 << std::setw(11) <<
sigma_m(i,j);
397 writeSigmaMatched <<
" \\\\" << std::endl;
400 writeSigmaMatched << std::endl;
401 writeSigmaMatched.close();
423 rdm_m.diagonalize(Ms,R,invR);
438 eigen(1) = - Ms(1,0);
440 eigen(3) = - Ms(3,2);
451 boost::numeric::ublas::trans(Mturn));
498 double guessedEmittance = std::cbrt(ex * ey * ez);
501 double rcyc = ravg /
beta_m;
504 double avgInverseBendingRadius = 1.0 / ravg;
510 double K3 = 3.0 * std::abs(
q_m) *
I_m * lam
518 * std::sqrt(rcyc * rcyc * rcyc / (std::pow(guessedEmittance, 3))));
520 double sig0 = std::sqrt(2.0 * rcyc * guessedEmittance) /
gamma_m;
525 sig = sig0 * std::cbrt(1.0 + alpha);
526 }
else if (alpha >= 0) {
527 sig = sig0 * (1 + alpha * (0.25 - 0.03125 * alpha));
530 "Negative alpha value: " + std::to_string(alpha) +
" < 0");
534 double K = K3 *
gamma_m / (3.0 * sig * sig * sig);
535 double kx = std::pow(avgInverseBendingRadius, 2) *
gamma2_m;
537 double a = 0.5 * kx - K;
544 "Negative value --> No real-valued frequency.");
546 double tmp =
a *
a - b;
549 "Square root of negative number.");
551 tmp = std::sqrt(tmp);
555 "Square root of negative number.");
557 if (std::pow(avgInverseBendingRadius, 2) * nuz * nuz <= K)
559 "h^{2} * nu_{z}^{2} <= K (i.e. square root of negative number)");
561 double Omega = std::sqrt(
a + tmp);
562 double omega = std::sqrt(
a - tmp);
564 double A = avgInverseBendingRadius / (Omega * Omega + K);
565 double B = avgInverseBendingRadius / (omega * omega + K);
566 double invAB = 1.0 / (B - A);
569 matrix_t sigma = boost::numeric::ublas::zero_matrix<double>(6);
572 sigma(0,0) = invAB * (B * ex / Omega + A * ez / omega);
575 sigma(0,5) = sigma(5,0) = invAB * (ex / Omega + ez / omega);
578 sigma(1,1) = invAB * (B * ex * Omega + A * ez * omega);
581 sigma(1,4) = sigma(4,1) = invAB * (ex * Omega+ez * omega) / (K *
gamma2_m);
584 sigma(2,2) = ey / (std::sqrt(std::pow(avgInverseBendingRadius,2) * nuz * nuz - K));
586 sigma(3,3) = (ey * ey) / sigma(2,2);
589 sigma(4,4) = invAB * (A * ex * Omega + B * ez * omega) / (K *
gamma2_m);
592 sigma(5,5) = invAB * (ex / (B * Omega) + ez / (A * omega));
596 for (
typename std::vector<matrix_t>::iterator it =
sigmas_m.begin(); it !=
sigmas_m.end(); ++it) {
606 "InitialSigmaPerAngleForEnergy" + energy +
"MeV.dat"
609 std::ofstream writeInit(fname, std::ios::out);
675 double betax = std::sqrt(std::fabs(eigen(0) / eigen(1)));
676 double gammax = 1.0 / betax;
680 double betal = std::sqrt(std::fabs(eigen(2) / eigen(3)));
681 double gammal = 1.0 / betal;
703 double cosz = 0.5 * (M(2,2) + M(3,3));
705 double sign = (std::signbit(M(2,3))) ?
double(-1) : double(1);
707 double invsinz =
sign / std::sqrt(std::fabs( 1.0 - cosz * cosz));
709 double alphaz = 0.5 * (M(2,2) - M(3,3)) * invsinz;
710 double betaz = M(2,3) * invsinz;
711 double gammaz = - M(3,2) * invsinz;
714 if (std::signbit(betaz))
718 matrix_t D = boost::numeric::ublas::zero_matrix<double>(6,6);
721 D(1,0) = - gammax * ex;
723 D(2,2) = alphaz * ey;
724 D(3,3) = - alphaz * ey;
726 D(3,2) = - gammaz * ey;
729 D(5,4) = - gammal * ez;
737 S(0,1) = S(2,3) = S(4,5) = 1;
738 S(1,0) = S(3,2) = S(5,4) = -1;
741 sigma = boost::numeric::ublas::prod(sigma,S);
749 "InitialSigmaPerAngleForEnergy" + energy +
"MeV.dat"
752 std::ofstream writeInit(fname, std::ios::app);
762 const std::vector<matrix_t>& Mcycs)
764 std::ofstream writeSigma;
772 "SigmaPerAngleForEnergy" + energy +
"MeV_iteration_"
777 writeSigma.open(fname,std::ios::out);
783 for (
unsigned int i = 1; i <
nSteps_m; ++i) {
785 matrix_t M = boost::numeric::ublas::prod(Mscs[i - 1],Mcycs[i - 1]);
788 boost::numeric::ublas::trans(M));
806 return std::sqrt(std::inner_product(diff.data().begin(),
814 std::ostringstream out;
815 out << std::setprecision(6) << val;
833 "PropertiesForEnergy" + energy +
"MeV.dat"
836 std::ofstream writeProperties(fname, std::ios::out);
838 writeProperties << std::left
839 << std::setw(25) <<
"orbit radius"
840 << std::setw(25) <<
"orbit momentum"
841 << std::setw(25) <<
"inverse bending radius"
842 << std::setw(25) <<
"field index"
843 << std::setw(25) <<
"path length" << std::endl;
845 for (
unsigned int i = 0; i < r.size(); ++i) {
846 writeProperties << std::setprecision(10) << std::left
847 << std::setw(25) << r[i]
848 << std::setw(25) << peo[i]
849 << std::setw(25) << h[i]
850 << std::setw(25) << fidx[i]
851 << std::setw(25) << ds[i] << std::endl;
853 writeProperties.close();
861 for (
unsigned int i = 0; i < 6; ++i) {
862 for (
unsigned int j = 0; j < 6; ++j)
863 os << m(i, j) <<
" ";
Tps< T > sqrt(const Tps< T > &x)
Square root.
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Inform & endl(Inform &inf)
constexpr double two_pi
The value of.
constexpr double epsilon_0
The permittivity of vacuum in As/Vm.
constexpr double mu_0
The permeability of vacuum in Vs/Am.
constexpr double c
The velocity of light in m/s.
constexpr double pi
The value of.
constexpr double mrad2rad
std::string combineFilePath(std::initializer_list< std::string > ilist)
double getBetaGamma(double Ekin, double mass)
BOOST_UBLAS_INLINE M gemmm(const ublas::matrix_expression< E1 > &e1, const ublas::matrix_expression< E2 > &e2, const ublas::matrix_expression< E3 > &e3)
Generalized matrix-matrix-matrix multiplication .
static OpalData * getInstance()
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
virtual double getPHIinit() const
static FTps makeVariable(int var)
static void setGlobalTruncOrder(int order)
This class generates the matrices for the one turn matrix of a cyclotron.
unsigned int niterations_m
Is the number of iterations needed for convergence.
double E_m
Stores the user-define energy, .
bool write_m
Decides for writing output (default: true).
void writeMatrix(std::ofstream &, const matrix_t &)
double isEigenEllipse(const matrix_t &Mturn, const matrix_t &sigma)
Checks if the sigma-matrix is an eigenellipse and returns the L2 error.
std::vector< double > container_t
Container for storing the properties for each angle.
std::array< double, 3 > getEmittances() const
double gamma2_m
Relativistic factor squared.
FTps< double, 2 *3 > Series
Type of the truncated power series.
Hamiltonian H_m
Stores the Hamiltonian of the cyclotron.
double error_m
Error of computation.
matrix_t updateInitialSigma(const matrix_t &, const vector_t &, sparse_matrix_t &, sparse_matrix_t &)
Computes the new initial sigma matrix.
unsigned int nSteps_m
Number of integration steps in total.
RealDiracMatrix::sparse_matrix_t sparse_matrix_t
Type for storing the sparse maps.
unsigned int nSectors_m
Number of (symmetric) sectors the field is averaged over.
unsigned int nStepsPerSector_m
Number of integration steps per sector (--> also: number of maps per sector).
double I_m
Stores the value of the current, .
std::function< Series(double, double, double)> SpaceCharge
Type of the Hamiltonian for the space charge.
double Emin_m
Minimum energy needed in cyclotron, .
unsigned int truncOrder_m
Truncation order of the power series for the Hamiltonian (cyclotron and space charge).
SigmaGenerator(double I, double ex, double ey, double ez, double E, double m, double q, const Cyclotron *cycl, unsigned int N, unsigned int Nsectors, unsigned int truncOrder, bool write=true)
Constructs an object of type SigmaGenerator.
double L2ErrorNorm(const matrix_t &, const matrix_t &)
Returns the L2-error norm between the old and new sigma-matrix.
RealDiracMatrix rdm_m
RealDiracMatrix-class member used for decoupling
FVps< double, 2 *3 > Map
Type of a map.
double mass_m
Is the mass of the particles, .
Series x_m
All variables x, px, z, pz, l, delta.
SpaceCharge Hsc_m
Stores the Hamiltonian for the space charge.
double q_m
Is the particle charge [e].
RealDiracMatrix::matrix_t matrix_t
Type for storing maps.
std::vector< matrix_t > sigmas_m
Vector storing the second moment matrix for each angle.
double Emax_m
Maximum energy reached in cyclotron, .
matrix_t sigma_m
Stores the stationary distribution (sigma matrix).
double nh_m
Harmonic number, .
vector_t decouple(const matrix_t &Mturn, sparse_matrix_t &R, sparse_matrix_t &invR)
Block diagonalizes the symplex part of the one turn transfer matrix.
double wo_m
Is the orbital frequency, .
std::function< Series(double, double, double)> Hamiltonian
Type of the Hamiltonian for the cyclotron.
unsigned int N_m
Number of integration steps for closed orbit computation.
void initialize(double, double)
bool converged_m
Is true if converged, false otherwise.
void writeOrbitOutput_m(const container_t &r_turn, const container_t &peo, const container_t &h_turn, const container_t &fidx_turn, const container_t &ds_turn)
Called within SigmaGenerator::match().
void updateSigma(const std::vector< matrix_t > &, const std::vector< matrix_t > &)
Computes new sigma matrices (one for each angle).
std::string float2string(double val)
Transforms a floating point value to a string.
RealDiracMatrix::vector_t vector_t
Type for storing vectors.
double beta_m
Velocity (c/v), .
std::array< double, 3 > emittance_m
bool match(double accuracy, unsigned int maxit, unsigned int maxitOrbit, Cyclotron *cycl, double denergy, double rguess, bool full)
Searches for a matched distribution.
The base class for all OPAL exceptions.