13struct Monitor :
public aCylindricalFunctor<Monitor>
16 Monitor(
double value,
double eps_value,
double R_X,
double Z_X,
double sigmaR,
double sigmaZ):
17 m_value(value), m_eps_value(eps_value),
18 m_cauchy(R_X, Z_X, sigmaR, sigmaZ, 1){}
19 double do_compute(
double x,
double y)
const
21 return m_value+m_cauchy(x,y)*m_eps_value;
24 double m_value, m_eps_value;
28struct DivMonitor :
public aCylindricalFunctor<DivMonitor>
31 DivMonitor(
double valueX,
double valueY,
double R_X,
double Z_X,
double sigmaR,
double sigmaZ):
32 m_valueX(valueX), m_valueY(valueY),
33 m_cauchy(R_X, Z_X, sigmaR, sigmaZ, 1){}
34 double do_compute(
double x,
double y)
const
36 return m_valueX*m_cauchy.dx(x,y)+m_valueY*m_cauchy.dy(x,y);
39 double m_valueX, m_valueY;
61 double x = R_X,
y = Z_X;
63 double sumpsi = psixx + psiyy;
64 double diffpsi = psixx - psiyy;
65 double alpha = (psixy*psixy - psixx*psiyy)*(diffpsi*diffpsi + 4.*psixy*psixy);
67 double gxx = (-psiyy*diffpsi + 2.*psixy*psixy)/sqrt(alpha);
68 double gyy = ( psixx*diffpsi + 2.*psixy*psixy)/sqrt(alpha);
69 double gxy = ( - sumpsi*psixy)/sqrt(alpha);
70 detail::Monitor xx(1, gxx-1,
x,
y, radiusX, radiusY);
71 detail::Monitor
xy(0, gxy-0,
x,
y, radiusX, radiusY);
72 detail::Monitor yy(1, gyy-1,
x,
y, radiusX, radiusY);
73 detail::DivMonitor divX(gxx-1, gxy,
x,
y, radiusX, radiusY);
74 detail::DivMonitor divY(gxy, gyy-1,
x,
y, radiusX, radiusY);
95 double x = R_X,
y = Z_X;
97 double sumpsi = psixx + psiyy;
98 double diffpsi = psixx - psiyy;
99 double alpha = (psixy*psixy - psixx*psiyy)*(diffpsi*diffpsi + 4.*psixy*psixy);
101 double gxx = (-psiyy*diffpsi + 2.*psixy*psixy)/sqrt(alpha);
102 double gyy = ( psixx*diffpsi + 2.*psixy*psixy)/sqrt(alpha);
103 double gxy = ( - sumpsi*psixy)/sqrt(alpha);
130 XCross(
const CylindricalFunctorsLvl1& psi,
double R_X,
double Z_X,
double distance=1): fieldRZtau_(psi), psip_(psi), dist_(distance)
132 R_X_ = R_X, Z_X_ = Z_X;
134 R_i[0] = R_X_ + dist_, Z_i[0] = Z_X_;
135 R_i[1] = R_X_ , Z_i[1] = Z_X_ + dist_;
136 R_i[2] = R_X_ - dist_, Z_i[2] = Z_X_;
137 R_i[3] = R_X_ , Z_i[3] = Z_X_ - dist_;
144 void set_quadrant(
int quad){quad_ = quad;}
145 double operator()(
double x)
const
147 std::array<double,2> begin, end, end_old;
148 begin[0] = R_i[quad_], begin[1] = Z_i[quad_];
149 double eps = 1e10, eps_old = 2e10;
151 if( quad_ == 0 || quad_ == 2) { begin[1] +=
x;}
152 else if( quad_ == 1 || quad_ == 3) { begin[0] +=
x;}
154 double psi0 = psip_.f()(begin[0], begin[1]);
155 while( (eps < eps_old || eps > 1e-4 ) && eps > 1e-10)
157 eps_old = eps; end_old = end;
159 using Vec = std::array<double,2>;
163 eps = sqrt( (end[0]-end_old[0])*(end[0]-end_old[0]) +
164 (end[1]-end_old[1])*(end[1]-end_old[1]));
165 if( std::isnan(eps)) { eps = eps_old/2.; end = end_old; }
167 if( quad_ == 0 || quad_ == 2){
return end_old[1] - Z_X_;}
168 return end_old[0] - R_X_;
177 void point(
double& R,
double& Z,
double x)
179 if( quad_ == 0 || quad_ == 2){ R = R_i[quad_], Z= Z_i[quad_] +
x;}
180 else if (quad_ == 1 || quad_ == 3) { R = R_i[quad_] +
x, Z = Z_i[quad_];}
185 dg::geo::FieldRZtau fieldRZtau_;
186 CylindricalFunctorsLvl1 psip_;
188 double R_i[4], Z_i[4];
194template <
class FpsiX,
class FieldRZYRYZY>
195void computeX_rzy(FpsiX fpsi, FieldRZYRYZY fieldRZYRYZY,
196 double psi,
const thrust::host_vector<double>& y_vec,
197 const unsigned nodeX0,
const unsigned nodeX1,
198 thrust::host_vector<double>& r,
199 thrust::host_vector<double>& z,
200 thrust::host_vector<double>& yr,
201 thrust::host_vector<double>& yz,
202 thrust::host_vector<double>& xr,
203 thrust::host_vector<double>& xz,
204 double* R_0,
double* Z_0,
209 thrust::host_vector<double> r_old(y_vec.size(), 0), r_diff( r_old), yr_old(r_old), xr_old(r_old);
210 thrust::host_vector<double> z_old(y_vec.size(), 0), z_diff( z_old), yz_old(r_old), xz_old(z_old);
211 r.resize( y_vec.size()),
z.resize(y_vec.size()), yr.resize(y_vec.size()),
yz.resize(y_vec.size()), xr.resize(y_vec.size()),
xz.resize(y_vec.size());
213 std::array<double, 4> begin{ {0,0,0,0} }, end(begin), temp(begin);
214 const double fprime = fpsi.f_prime( psi);
215 f_psi = fpsi.construct_f(psi, R_0, Z_0);
216 fieldRZYRYZY.set_f(f_psi);
217 fieldRZYRYZY.set_fp(fprime);
218 using Vec = std::array<double,4>;
220 begin), fieldRZYRYZY);
221 unsigned steps = 1;
double eps = 1e10, eps_old=2e10;
222 while( (eps < eps_old||eps > 1e-7) && eps > 1e-11)
224 eps_old = eps, r_old = r, z_old =
z, yr_old = yr, yz_old =
yz, xr_old = xr, xz_old =
xz;
228 if(psi<0)begin[0] = R_0[1], begin[1] = Z_0[1];
229 else begin[0] = R_0[0], begin[1] = Z_0[0];
230 fieldRZYRYZY.initialize( begin[0], begin[1], begin[2], begin[3]);
232 odeint.integrate_steps( 0, begin, y_vec[i], end, steps);
233 r[i] = end[0],
z[i] = end[1], yr[i] = end[2],
yz[i] = end[3];
234 fieldRZYRYZY.derive(r[i], z[i], xr[i], xz[i]);
236 for(
int i=nodeX0-2; i>=0; i--)
239 odeint.integrate_steps( y_vec[i+1],temp, y_vec[i], end, steps);
240 r[i] = end[0],
z[i] = end[1], yr[i] = end[2],
yz[i] = end[3];
241 fieldRZYRYZY.derive(r[i], z[i], xr[i], xz[i]);
244 begin[0] = R_0[0], begin[1] = Z_0[0];
245 fieldRZYRYZY.initialize( begin[0], begin[1], begin[2], begin[3]);
247 odeint.integrate_steps( 0, begin, y_vec[i], end, steps);
248 r[i] = end[0],
z[i] = end[1], yr[i] = end[2],
yz[i] = end[3];
249 fieldRZYRYZY.derive(r[i], z[i], xr[i], xz[i]);
250 for(
unsigned i=nodeX0+1; i<nodeX1; i++)
253 odeint.integrate_steps( y_vec[i-1], temp, y_vec[i], end, steps);
254 r[i] = end[0],
z[i] = end[1], yr[i] = end[2],
yz[i] = end[3];
255 fieldRZYRYZY.derive(r[i], z[i], xr[i], xz[i]);
258 odeint.integrate_steps( y_vec[nodeX1-1], temp, 2.*M_PI, end, steps);
260 eps = sqrt( (end[0]-R_0[0])*(end[0]-R_0[0]) + (end[1]-Z_0[0])*(end[1]-Z_0[0]));
262 eps = sqrt( (end[0]-R_0[1])*(end[0]-R_0[1]) + (end[1]-Z_0[1])*(end[1]-Z_0[1]));
263 if(verbose)std::cout <<
"abs. error is "<<eps<<
" with "<<steps<<
" steps\n";
267 begin[0] = R_0[1], begin[1] = Z_0[1];
268 fieldRZYRYZY.initialize( begin[0], begin[1], begin[2], begin[3]);
270 odeint.integrate_steps( 2.*M_PI, begin, y_vec[i], end, steps);
271 r[i] = end[0],
z[i] = end[1], yr[i] = end[2],
yz[i] = end[3];
272 fieldRZYRYZY.derive(r[i], z[i], xr[i], xz[i]);
274 for(
unsigned i=nodeX1+1; i<y_vec.size(); i++)
277 odeint.integrate_steps( y_vec[i-1], temp, y_vec[i] ,end, steps);
278 r[i] = end[0],
z[i] = end[1], yr[i] = end[2],
yz[i] = end[3];
279 fieldRZYRYZY.derive(r[i], z[i], xr[i], xz[i]);
288 eps = sqrt( er + ez)/sqrt(ar+az);
289 if(verbose)std::cout <<
"rel. error is "<<eps<<
" with "<<steps<<
" steps\n";
290 if( std::isnan(eps)) { eps = eps_old/2.; }
293 r = r_old,
z = z_old, yr = yr_old,
yz = yz_old, xr = xr_old,
xz = xz_old;
300template <
class XFieldFinv>
301double construct_psi_values( XFieldFinv fpsiMinv,
302 const double psi_0,
const double x_0,
const thrust::host_vector<double>& x_vec,
const double x_1,
unsigned idxX,
303 thrust::host_vector<double>& psi_x,
bool verbose =
false )
305 psi_x.resize( x_vec.size());
306 thrust::host_vector<double> psi_old(psi_x), psi_diff( psi_old);
310 const double psi_const = fpsiMinv.find_psi( x_vec[idxX]);
311 double psi_1_numerical=0;
312 double eps = 1e10, eps_old=2e10;
315 while( (eps < eps_old || eps > 1e-8) && eps > 1e-11)
319 x0 = x_0, x1 = x_vec[0];
321 double begin(psi_0), end(begin), temp(begin);
322 odeint.integrate_steps( x0, begin, x1, end, N);
323 psi_x[0] = end; fpsiMinv(0.,end,temp);
324 for(
unsigned i=1; i<idxX; i++)
327 x0 = x_vec[i-1], x1 = x_vec[i];
328 odeint.integrate_steps( x0, temp, x1, end, N);
329 psi_x[i] = end; fpsiMinv(0.,end,temp);
334 psi_x[idxX] = end; fpsiMinv(0.,end,temp);
335 for(
unsigned i=idxX+1; i<x_vec.size(); i++)
338 x0 = x_vec[i-1], x1 = x_vec[i];
339 odeint.integrate_steps( x0, temp, x1, end, N);
340 psi_x[i] = end; fpsiMinv(0.,end,temp);
344 odeint.integrate_steps(x1, temp, x_1, end,N);
345 psi_1_numerical = end;
350 if(verbose)std::cout <<
"Effective Psi error is "<<eps<<
" with "<<N<<
" steps\n";
354 return psi_1_numerical;
363 void set_Z(
double z){ Z_=
z;}
364 double operator()(
double R) {
return psip_(R, Z_);}
375 SeparatriX(
const CylindricalFunctorsLvl1& psi,
const CylindricalSymmTensorLvl1& chi,
double xX,
double yX,
double x0,
double y0,
int firstline,
bool verbose=
false):
377 fieldRZYequi_(psi, chi), fieldRZYTequi_(psi, x0, y0, chi), fieldRZYZequi_(psi, chi),
378 fieldRZYconf_(psi, chi), fieldRZYTconf_(psi, x0, y0, chi), fieldRZYZconf_(psi, chi), m_verbose( verbose)
382 double R_X = xX;
double Z_X = yX;
383 double boxR = 0.05, boxZ = 0.01;
384 std::array<double,4> R_min={R_X, R_X*(1.0-boxR), R_X*(1.0-boxR), R_X};
385 std::array<double,4> R_max={R_X*(1.0+boxR), R_X, R_X, R_X*(1.0+boxR)};
386 std::array<double,4> Z_0={Z_X+boxZ*R_X, Z_X+boxZ*R_X, Z_X-boxZ*R_X, Z_X-boxZ*R_X};
387 PsipSep psip_sep( psi.f());
388 for(
unsigned i=0; i<4; i++)
390 psip_sep.set_Z( Z_0[i]);
392 R_i[i] = (R_min[i]+R_max[i])/2., Z_i[i] = Z_0[i];
393 if(m_verbose)std::cout <<
"Found "<<i+1<<
"st point "<<R_i[i]
397 std::array<double, 3> begin2d{ {0,0,0} }, end2d(begin2d);
398 for(
int i=0; i<4; i++)
401 begin2d[0] = end2d[0] = R_i[i];
402 begin2d[1] = end2d[1] = Z_i[i];
403 begin2d[2] = end2d[2] = 0.;
404 double eps = 1e10, eps_old = 2e10;
407 while( (eps < eps_old || eps > 5e-5))
410 using Vec = std::array<double,3>;
414 begin2d), fieldRZYZconf_);
417 begin2d), fieldRZYZequi_);
422 eps = sqrt( (end2d[0]-R_X)*(end2d[0]-R_X))/R_X;
423 if( std::isnan(eps)) { eps = eps_old/2.; }
430 if(m_verbose)std::cout <<
"Found |y_i["<<i<<
"]|: "<<y_i[i]<<
" with eps = "<<eps<<
" and "<<N<<
" steps and diff "<<fabs(end2d[0]-R_X)/R_X<<
"\n";
433 f_psi_ = construct_f( );
434 y_i[0]*=f_psi_, y_i[1]*=f_psi_, y_i[2]*=f_psi_, y_i[3]*=f_psi_;
435 fieldRZYequi_.set_f(f_psi_);
436 fieldRZYconf_.set_f(f_psi_);
439 double get_f( )
const{
return f_psi_;}
442 void compute_rzy(
const thrust::host_vector<double>& y_vec,
443 const unsigned nodeX0,
const unsigned nodeX1,
444 thrust::host_vector<double>& r,
445 thrust::host_vector<double>& z )
const
448 std::array<double, 2> begin{ {0,0} }, end(begin), temp(begin);
449 thrust::host_vector<double> r_old(y_vec.size(), 0), r_diff( r_old);
450 thrust::host_vector<double> z_old(y_vec.size(), 0), z_diff( z_old);
451 r.resize( y_vec.size()),
z.resize(y_vec.size());
452 unsigned steps = 1;
double eps = 1e10, eps_old=2e10;
453 using Vec = std::array<double,2>;
461 while( (eps < eps_old||eps > 1e-7) && eps > 1e-11)
463 eps_old = eps, r_old = r, z_old =
z;
467 begin[0] = R_i[3], begin[1] = Z_i[3];
470 r[nodeX0-1] = end[0],
z[nodeX0-1] = end[1];
472 for(
int i=nodeX0-2; i>=0; i--)
476 r[i] = end[0],
z[i] = end[1];
479 begin[0] = R_i[0], begin[1] = Z_i[0];
481 r[nodeX0] = end[0],
z[nodeX0] = end[1];
482 for(
unsigned i=nodeX0+1; i<nodeX1; i++)
486 r[i] = end[0],
z[i] = end[1];
491 eps = sqrt( (end[0]-R_i[1])*(end[0]-R_i[1]) +
492 (end[1]-Z_i[1])*(end[1]-Z_i[1]));
498 begin[0] = R_i[2], begin[1] = Z_i[2];
501 r[nodeX1] = end[0],
z[nodeX1] = end[1];
503 for(
unsigned i=nodeX1+1; i<y_vec.size(); i++)
507 r[i] = end[0],
z[i] = end[1];
516 eps = sqrt( er + ez)/sqrt(ar+az);
517 if(m_verbose)std::cout <<
"rel. Separatrix error is "<<eps<<
" with "<<steps<<
" steps\n";
520 r = r_old,
z = z_old;
524 double construct_f( )
526 if(m_verbose)std::cout <<
"In construct f function!\n";
528 std::array<double, 3> begin{ {0,0,0} }, end(begin), end_old(begin);
529 begin[0] = R_i[0], begin[1] = Z_i[0];
530 double eps = 1e10, eps_old = 2e10;
532 using Vec = std::array<double,3>;
537 "Feagin-17-8-10", begin), fieldRZYTconf_);
539 "Feagin-17-8-10", begin), fieldRZYZconf_);
544 "Feagin-17-8-10", begin), fieldRZYTequi_);
546 "Feagin-17-8-10", begin), fieldRZYZequi_);
548 while( (eps < eps_old || eps > 1e-7) && N < 1e6)
550 eps_old = eps, end_old = end;
553 std::array<double,3> temp(end);
557 eps = sqrt( (end[0]-R_i[1])*(end[0]-R_i[1]) + (end[1]-Z_i[1])*(end[1]-Z_i[1]));
559 if( std::isnan(eps)) { eps = eps_old/2.; end = end_old; }
562 if(m_verbose)std::cout <<
"Found end[2] = "<< end_old[2]<<
" with eps = "<<eps<<
"\n";
563 if(m_verbose)std::cout <<
"Found f = "<< 2.*
M_PI/(y_i[0]+end_old[2]+y_i[1])<<
" with eps = "<<eps<<
"\n";
564 f_psi_ = 2.*
M_PI/(y_i[0]+end_old[2]+y_i[1]);
568 dg::geo::equalarc::FieldRZY fieldRZYequi_;
569 dg::geo::equalarc::FieldRZYT fieldRZYTequi_;
570 dg::geo::equalarc::FieldRZYZ fieldRZYZequi_;
571 dg::geo::ribeiro::FieldRZY fieldRZYconf_;
572 dg::geo::ribeiro::FieldRZYT fieldRZYTconf_;
573 dg::geo::ribeiro::FieldRZYZ fieldRZYZconf_;
575 double R_i[4], Z_i[4], y_i[4];
589 InitialX(
const CylindricalFunctorsLvl1& psi,
double xX,
double yX,
bool verbose =
false):
590 psip_(psi), fieldRZtau_(psi),
591 xpointer_(psi, xX, yX, 1e-4), m_verbose( verbose)
594 dg::geo::FieldRZtau fieldRZtau_(psi);
595 using Vec = std::array<double,2>;
597 "Fehlberg-6-4-5", Vec{0.,0.}), fieldRZtau_);
598 double eps[] = {1e-11, 1e-12, 1e-11, 1e-12};
599 for(
unsigned i=0; i<4; i++)
601 xpointer_.set_quadrant( i);
602 double x_min = -1e-4, x_max = 1e-4;
604 xpointer_.point( R_i_[i], Z_i_[i], (x_min+x_max)/2.);
606 std::array<double,2> begin, end, end_old;
607 begin[0] = R_i_[i], begin[1] = Z_i_[i];
608 double eps = 1e10, eps_old = 2e10;
610 double psi0 = psip_.f()(begin[0], begin[1]), psi1 = 1e3*psi0;
611 while( (eps < eps_old || eps > 1e-5 ) && eps > 1e-9)
613 eps_old = eps; end_old = end;
617 eps = sqrt( (end[0]-end_old[0])*(end[0]-end_old[0]) + (end[1]-end_old[1])*(end[1]-end_old[1]));
618 if( std::isnan(eps)) { eps = eps_old/2.; end = end_old; }
621 R_i_[i] = end_old[0], Z_i_[i] = end_old[1];
622 begin[0] = R_i_[i], begin[1] = Z_i_[i];
623 eps = 1e10, eps_old = 2e10; N=10;
624 psi0 = psip_.f()(begin[0], begin[1]), psi1 = -0.01;
625 if( i==0||i==2)psi1*=-1.;
626 while( (eps < eps_old || eps > 1e-5 ) && eps > 1e-9)
628 eps_old = eps; end_old = end;
632 eps = sqrt( (end[0]-end_old[0])*(end[0]-end_old[0]) + (end[1]-end_old[1])*(end[1]-end_old[1]));
633 if( std::isnan(eps)) { eps = eps_old/2.; end = end_old; }
636 R_i_[i] = end_old[0], Z_i_[i] = end_old[1];
637 if(m_verbose)std::cout <<
"Quadrant "<<i<<
" Found initial point: "<<R_i_[i]<<
" "<<Z_i_[i]<<
" "<<psip_.f()(R_i_[i], Z_i_[i])<<
"\n";
648 void find_initial(
double psi,
double* R_0,
double* Z_0)
650 std::array<double, 2> begin{ {0,0} }, end(begin), end_old(begin);
651 for(
unsigned i=0; i<2; i++)
655 begin[0] = R_i_[2*i+1], begin[1] = Z_i_[2*i+1]; end = begin;
659 begin[0] = R_i_[2*i], begin[1] = Z_i_[2*i]; end = begin;
662 double eps = 1e10, eps_old=2e10;
663 using Vec = std::array<double,2>;
665 "Fehlberg-6-4-5", Vec{0.,0.}), fieldRZtau_);
666 while( (eps < eps_old||eps > 1e-7) && eps > 1e-11)
668 eps_old = eps; end_old = end;
671 eps = sqrt( (end[0]-end_old[0])*(end[0]- end_old[0]) +
672 (end[1]-end_old[1])*(end[1]-end_old[1]));
674 if( std::isnan(eps)) { eps = eps_old/2.; end = end_old; }
680 R_0[i] = R_i_[2*i+1] = begin[0] = end_old[0], Z_i_[2*i+1] =
681 Z_0[i] = begin[1] = end_old[1];
685 R_0[i] = R_i_[2*i] = begin[0] = end_old[0], Z_i_[2*i] = Z_0[i]
686 = begin[1] = end_old[1];
694 CylindricalFunctorsLvl1 psip_;
695 const dg::geo::FieldRZtau fieldRZtau_;
696 dg::geo::detail::XCross xpointer_;
697 double R_i_[4], Z_i_[4];
void axpby(get_value_type< ContainerType > alpha, const ContainerType1 &x, get_value_type< ContainerType > beta, ContainerType &y)
get_value_type< ContainerType1 > dot(const ContainerType1 &x, const ContainerType2 &y)
RealCylindricalFunctor< double > CylindricalFunctor
Most of the times we use double.
Definition: fluxfunctions.h:50
int bisection1d(UnaryOp &op, double &x_min, double &x_max, const double eps)
static void findXpoint(const CylindricalFunctorsLvl2 &psi, double &RC, double &ZC)
This function finds X-points of psi.
Definition: fluxfunctions.h:350
static CylindricalSymmTensorLvl1 make_Xconst_monitor(const CylindricalFunctorsLvl2 &psi, double &R_X, double &Z_X)
construct a monitor metric in which the Laplacian vanishes at the X-point
Definition: utilitiesX.h:92
static CylindricalSymmTensorLvl1 make_Xbump_monitor(const CylindricalFunctorsLvl2 &psi, double &R_X, double &Z_X, double radiusX, double radiusY)
construct a monitor metric in which the Laplacian vanishes at the X-point
Definition: utilitiesX.h:58
void construct(Params &&...ps)
void integrate_steps(value_type t0, const container_type &u0, value_type t1, container_type &u1, unsigned steps)
Definition: fluxfunctions.h:114
This struct bundles a function and its first and second derivatives.
Definition: fluxfunctions.h:219
const CylindricalFunctor & dfxy() const
Definition: fluxfunctions.h:251
const CylindricalFunctor & dfxx() const
Definition: fluxfunctions.h:249
const CylindricalFunctor & dfyy() const
Definition: fluxfunctions.h:253
Definition: fluxfunctions.h:361