Extension: Geometries
#include "dg/geometries/geometries.h"
ribeiro.h
Go to the documentation of this file.
1#pragma once
2
3#include "dg/algorithm.h"
4#include "generator.h"
5#include "utilities.h"
6
7
8
9namespace dg
10{
11namespace geo
12{
14namespace ribeiro
15{
16namespace detail
17{
18
19//This leightweights struct and its methods finds the initial R and Z values and the coresponding f(\psi) as
20//good as it can, i.e. until machine precision is reached
21struct Fpsi
22{
23 Fpsi( const CylindricalFunctorsLvl1& psi, double x0, double y0, int mode, bool verbose = false):
24 psip_(psi), fieldRZYTribeiro_(psi,x0, y0),fieldRZYTequalarc_(psi, x0, y0), fieldRZtau_(psi), mode_(mode), m_verbose(verbose)
25 {
26 R_init = x0; Z_init = y0;
27 while( fabs( psi.dfx()(R_init, Z_init)) <= 1e-10 && fabs( psi.dfy()( R_init, Z_init)) <= 1e-10)
28 {
29 R_init = x0 + 1.;
30 Z_init = y0;
31 }
32 }
33 //finds the starting points for the integration in y direction
34 void find_initial( double psi, double& R_0, double& Z_0)
35 {
36 unsigned N = 50;
37 std::array<double, 2> begin2d{ {0,0} }, end2d(begin2d), end2d_old(begin2d);
38 begin2d[0] = end2d[0] = end2d_old[0] = R_init;
39 begin2d[1] = end2d[1] = end2d_old[1] = Z_init;
40 if(m_verbose)std::cout << "In init function\n";
41 double eps = 1e10, eps_old = 2e10;
42 using Vec = std::array<double,2>;
43 dg::SinglestepTimeloop<Vec> odeint( dg::RungeKutta<Vec>( "Feagin-17-8-10",
44 begin2d), fieldRZtau_);
45 while( (eps < eps_old || eps > 1e-7) && eps > 1e-14)
46 {
47 eps_old = eps; end2d_old = end2d;
48 N*=2; odeint.integrate_steps( psip_.f()(R_init, Z_init), begin2d,
49 psi, end2d, N);
50 eps = sqrt( (end2d[0]-end2d_old[0])*(end2d[0]-end2d_old[0]) +
51 (end2d[1]-end2d_old[1])*(end2d[1]-end2d_old[1]));
52 }
53 R_init = R_0 = end2d_old[0], Z_init = Z_0 = end2d_old[1];
54 if(m_verbose)std::cout << "In init function error: psi(R,Z)-psi0: "<<psip_.f()(R_init, Z_init)-psi<<"\n";
55 }
56
57 //compute f for a given psi between psi0 and psi1
58 double construct_f( double psi, double& R_0, double& Z_0)
59 {
60 find_initial( psi, R_0, Z_0);
61 std::array<double, 3> begin{ {0,0,0} }, end(begin), end_old(begin);
62 begin[0] = R_0, begin[1] = Z_0;
63 if(m_verbose)std::cout << begin[0]<<" "<<begin[1]<<" "<<begin[2]<<"\n";
64 double eps = 1e10, eps_old = 2e10;
65 unsigned N = 50;
66 //double y_eps = 1;
67 using Vec = std::array<double,3>;
69 if( mode_ == 0)
70 odeint.construct( dg::RungeKutta<Vec>( "Feagin-17-8-10",
71 begin), fieldRZYTribeiro_);
72 if( mode_ == 1)
73 odeint.construct( dg::RungeKutta<Vec>( "Feagin-17-8-10",
74 begin), fieldRZYTequalarc_);
75 while( (eps < eps_old || eps > 1e-7)&& N < 1e6)
76 {
77 eps_old = eps, end_old = end; N*=2;
78 odeint.integrate_steps( 0., begin, 2*M_PI, end, N);
79 eps = sqrt( (end[0]-begin[0])*(end[0]-begin[0]) +
80 (end[1]-begin[1])*(end[1]-begin[1]));
81 }
82 if(m_verbose)std::cout << "\t error "<<eps<<" with "<<N<<" steps\t";
83 if(m_verbose)std::cout <<end_old[2] << " "<<end[2] <<"\n";
84 double f_psi = 2.*M_PI/end_old[2];
85 return f_psi;
86 }
87 double operator()( double psi)
88 {
89 double R_0, Z_0;
90 return construct_f( psi, R_0, Z_0);
91 }
92
101 double find_x1( double psi_0, double psi_1 )
102 {
103 unsigned P=8;
104 double x1 = 0, x1_old = 0;
105 double eps=1e10, eps_old=2e10;
106 if(m_verbose)std::cout << "In x1 function\n";
107 while(eps < eps_old && P < 20 && eps > 1e-15)
108 {
109 eps_old = eps;
110 x1_old = x1;
111
112 P+=1;
113 if( psi_1 < psi_0) std::swap(psi_0, psi_1);
114 dg::Grid1d grid( psi_0, psi_1, P, 1);
115 thrust::host_vector<double> psi_vec = dg::evaluate( dg::cooX1d, grid);
116 thrust::host_vector<double> f_vec(grid.size(), 0);
117 thrust::host_vector<double> w1d = dg::create::weights(grid);
118 for( unsigned i=0; i<psi_vec.size(); i++)
119 {
120 f_vec[i] = this->operator()( psi_vec[i]);
121 }
122 x1 = dg::blas1::dot( f_vec, w1d);
123
124 eps = fabs((x1 - x1_old)/x1);
125 //std::cout << "X1 = "<<-x1<<" rel. error "<<eps<<" with "<<P<<" polynomials\n";
126 }
127 return -x1_old;
128 }
129
130 double f_prime( double psi)
131 {
132 //compute fprime
133 double deltaPsi = fabs(psi)/100.;
134 double fofpsi[4];
135 fofpsi[1] = operator()(psi-deltaPsi);
136 fofpsi[2] = operator()(psi+deltaPsi);
137 double fprime = (-0.5*fofpsi[1]+0.5*fofpsi[2])/deltaPsi, fprime_old;
138 double eps = 1e10, eps_old=2e10;
139 while( eps < eps_old)
140 {
141 deltaPsi /=2.;
142 fprime_old = fprime;
143 eps_old = eps;
144 fofpsi[0] = fofpsi[1], fofpsi[3] = fofpsi[2];
145 fofpsi[1] = operator()(psi-deltaPsi);
146 fofpsi[2] = operator()(psi+deltaPsi);
147 //reuse previously computed fpsi for current fprime
148 fprime = (+ 1./12.*fofpsi[0]
149 - 2./3. *fofpsi[1]
150 + 2./3. *fofpsi[2]
151 - 1./12.*fofpsi[3]
152 )/deltaPsi;
153 eps = fabs((fprime - fprime_old)/fprime);
154 //std::cout << "fprime "<<fprime<<" rel error fprime is "<<eps<<" delta psi "<<deltaPsi<<"\n";
155 }
156 return fprime_old;
157 }
158
159 private:
160 double R_init, Z_init;
161 CylindricalFunctorsLvl1 psip_;
162 dg::geo::ribeiro::FieldRZYT fieldRZYTribeiro_;
163 dg::geo::equalarc::FieldRZYT fieldRZYTequalarc_;
164 dg::geo::FieldRZtau fieldRZtau_;
165 int mode_;
166 bool m_verbose;
167};
168
169//This struct computes -2pi/f with a fixed number of steps for all psi
170struct FieldFinv
171{
172 FieldFinv( const CylindricalFunctorsLvl1& psi, double x0, double y0, unsigned N_steps, int mode):
173 fpsi_(psi, x0, y0, mode), fieldRZYTribeiro_(psi, x0, y0), fieldRZYTequalarc_(psi, x0, y0), N_steps(N_steps), mode_(mode) { }
174 void operator()(double t, double psi, double& fpsiM)
175 {
176 std::array<double, 3> begin{ {0,0,0} }, end(begin);
177 fpsi_.find_initial( psi, begin[0], begin[1]);
178 using Vec = std::array<double,3>;
180 if( mode_ == 0)
181 odeint.construct( dg::RungeKutta<Vec>( "Feagin-17-8-10",
182 begin), fieldRZYTribeiro_);
183 if( mode_ == 1)
184 odeint.construct( dg::RungeKutta<Vec>( "Feagin-17-8-10",
185 begin), fieldRZYTequalarc_);
186 odeint.integrate_steps( 0., begin, 2*M_PI, end, N_steps);
187 fpsiM = end[2]/2./M_PI;
188 //std::cout <<"fpsiMinverse is "<<fpsiM[0]<<" "<<-1./fpsi_(psi[0])<<" "<<eps<<"\n";
189 }
190 private:
191 Fpsi fpsi_;
192 dg::geo::ribeiro::FieldRZYT fieldRZYTribeiro_;
193 dg::geo::equalarc::FieldRZYT fieldRZYTequalarc_;
194 unsigned N_steps;
195 int mode_;
196};
197} //namespace detail
198}//namespace ribeiro
200
206struct Ribeiro : public aGenerator2d
207{
219 Ribeiro( const CylindricalFunctorsLvl2& psi, double psi_0, double psi_1, double x0, double y0, int mode = 0, bool verbose = false):
220 psi_(psi), mode_(mode), m_verbose(verbose)
221 {
222 assert( psi_1 != psi_0);
223 ribeiro::detail::Fpsi fpsi(psi, x0, y0, mode);
224 lx_ = fabs(fpsi.find_x1( psi_0, psi_1));
225 x0_=x0, y0_=y0, psi0_=psi_0, psi1_=psi_1;
226 if(m_verbose)std::cout << "lx = "<<lx_<<"\n";
227 }
228 virtual Ribeiro* clone() const override final{return new Ribeiro(*this);}
229
230 private:
238 virtual double do_width() const override final{return lx_;}
245 virtual double do_height() const override final{return 2.*M_PI;}
246 virtual void do_generate(
247 const thrust::host_vector<double>& zeta1d,
248 const thrust::host_vector<double>& eta1d,
249 thrust::host_vector<double>& x,
250 thrust::host_vector<double>& y,
251 thrust::host_vector<double>& zetaX,
252 thrust::host_vector<double>& zetaY,
253 thrust::host_vector<double>& etaX,
254 thrust::host_vector<double>& etaY) const override final
255 {
256 //compute psi(x) for a grid on x and call construct_rzy for all psi
257 ribeiro::detail::FieldFinv fpsiMinv_(psi_, x0_,y0_, 500, mode_);
258 thrust::host_vector<double> psi_x, fx_;
259 dg::geo::detail::construct_psi_values( fpsiMinv_, psi0_, psi1_, 0., zeta1d, lx_, psi_x, fx_);
260
261 if(m_verbose)std::cout << "In grid function:\n";
262 ribeiro::detail::Fpsi fpsi(psi_, x0_, y0_, mode_, m_verbose);
263 dg::geo::ribeiro::FieldRZYRYZY fieldRZYRYZYribeiro(psi_);
264 dg::geo::equalarc::FieldRZYRYZY fieldRZYRYZYequalarc(psi_);
265 thrust::host_vector<double> f_p(fx_);
266 unsigned Nx = zeta1d.size(), Ny = eta1d.size();
267 for( unsigned i=0; i<zeta1d.size(); i++)
268 {
269 thrust::host_vector<double> ry, zy;
270 thrust::host_vector<double> yr, yz, xr, xz;
271 double R0, Z0;
272 if(mode_==0)dg::geo::detail::compute_rzy( fpsi, fieldRZYRYZYribeiro, psi_x[i], eta1d, ry, zy, yr, yz, xr, xz, R0, Z0, fx_[i], f_p[i], m_verbose);
273 if(mode_==1)dg::geo::detail::compute_rzy( fpsi, fieldRZYRYZYequalarc, psi_x[i], eta1d, ry, zy, yr, yz, xr, xz, R0, Z0, fx_[i], f_p[i], m_verbose);
274 for( unsigned j=0; j<Ny; j++)
275 {
276 x[j*Nx+i] = ry[j], y[j*Nx+i] = zy[j];
277 etaX[j*Nx+i] = yr[j], etaY[j*Nx+i] = yz[j];
278 zetaX[j*Nx+i] = xr[j], zetaY[j*Nx+i] = xz[j];
279 }
280 }
281 }
282 CylindricalFunctorsLvl2 psi_;
283 double lx_, x0_, y0_, psi0_, psi1_;
284 int mode_; //0 = ribeiro, 1 = equalarc
285 bool m_verbose;
286};
287
288} //namespace geo
289} //namespace dg
#define M_PI
static DG_DEVICE double cooX1d(double x)
get_value_type< ContainerType1 > dot(const ContainerType1 &x, const ContainerType2 &y)
thrust::host_vector< real_type > evaluate(UnaryOp f, const RealGrid1d< real_type > &g)
MPI_Vector< thrust::host_vector< real_type > > weights(const aRealMPITopology2d< real_type > &g)
void construct(Params &&...ps)
void integrate_steps(value_type t0, const container_type &u0, value_type t1, container_type &u1, unsigned steps)
This struct bundles a function and its first and second derivatives.
Definition: fluxfunctions.h:219
A two-dimensional grid based on "almost-conformal" coordinates by Ribeiro and Scott 2010.
Definition: ribeiro.h:207
virtual Ribeiro * clone() const override final
Abstract clone method that returns a copy on the heap.
Definition: ribeiro.h:228
Ribeiro(const CylindricalFunctorsLvl2 &psi, double psi_0, double psi_1, double x0, double y0, int mode=0, bool verbose=false)
Construct a near-conformal grid generator.
Definition: ribeiro.h:219
The abstract generator base class.
Definition: generator.h:20