Extension: Geometries
#include "dg/geometries/geometries.h"
ribeiroX.h
Go to the documentation of this file.
1#pragma once
2
3#include "dg/algorithm.h"
4#include "generatorX.h"
5#include "utilitiesX.h"
6#include "ribeiro.h"
7
8
9namespace dg
10{
11namespace geo
12{
14namespace ribeiro
15{
16namespace detail
17{
18//This leightweights struct and its methods finds the initial R and Z values and the coresponding f(\psi) as
19//good as it can, i.e. until machine precision is reached
20struct FpsiX
21{
22 FpsiX( const CylindricalFunctorsLvl1& psi, double xX, double yX, double x0, double y0):
23 initX_(psi, xX, yX), fieldRZYT_(psi, x0, y0), fieldRZYZ_(psi)
24 { }
25 //for a given psi finds the four starting points for the integration in y direction on the perpendicular lines through the X-point
26 void find_initial( double psi, double* R_0, double* Z_0)
27 {
28 initX_.find_initial(psi, R_0, Z_0);
29 }
30
31 //compute f for a given psi between psi0 and psi1
32 double construct_f( double psi, double* R_i, double* Z_i)
33 {
34 find_initial( psi, R_i, Z_i);
35 //std::cout << "Begin error "<<eps_old<<" with "<<N<<" steps\n";
36 //std::cout << "In Stepper function:\n";
37 //double y_old=0;
38 std::array<double, 3> begin{ {0,0,0} }, end(begin), end_old(begin);
39 begin[0] = R_i[0], begin[1] = Z_i[0];
40 //std::cout << begin[0]<<" "<<begin[1]<<" "<<begin[2]<<"\n";
41 double eps = 1e10, eps_old = 2e10;
42 unsigned N = 32;
43 //double y_eps;
44 using Vec = std::array<double,3>;
46 "Feagin-17-8-10", begin), fieldRZYT_);;
47 while( (eps < eps_old || eps > 1e-7) && N < 1e6)
48 {
49 //remember old values
50 eps_old = eps, end_old = end; //y_old = end[2];
51 //compute new values
52 N*=2;
53
54 if( psi < 0)
55 {
56 odeintT.integrate_steps( 0., begin, 2.*M_PI, end, N);
57 //std::cout << "result is "<<end[0]<<" "<<end[1]<<" "<<end[2]<<"\n";
58 eps = sqrt( (end[0]-begin[0])*(end[0]-begin[0]) + (end[1]-begin[1])*(end[1]-begin[1]));
59 }
60 else
61 {
63 "Feagin-17-8-10", begin), fieldRZYZ_);;
64 odeintZ.integrate_steps( begin[1], begin, 0., end, N);
65 std::array<double,3> temp(end);
66 odeintT.integrate_steps( 0., begin, M_PI, end, N);
67 temp = end; //temp[1] should be 0 now
68 odeintZ.integrate_steps( temp[1], temp, Z_i[1], end, N);
69 eps = sqrt( (end[0]-R_i[1])*(end[0]-R_i[1]) + (end[1]-Z_i[1])*(end[1]-Z_i[1]));
70 }
71 if( std::isnan(eps)) { eps = eps_old/2.; end = end_old;
72 //std::cerr << "\t nan! error "<<eps<<"\n";
73 } //near X-point integration can go wrong
74 //y_eps = sqrt( (y_old - end[2])*(y_old-end[2]));
75 //std::cout << "error "<<eps<<" with "<<N<<" steps| psip "<<psi_(end[0], end[1])<<"\n";
76 //std::cout <<"error in y is "<<y_eps<<"\n";
77 }
78 double f_psi = 2.*M_PI/end_old[2];
79 //std::cout << "f_psi "<<f_psi<<"\n";
80 return f_psi;
81 //return 1./f_psi;
82 }
83 double operator()( double psi)
84 {
85 double R_0[2], Z_0[2];
86 return construct_f( psi, R_0, Z_0);
87 }
88
94 double find_x( double psi )
95 {
96 unsigned P=6;
97 double x0 = 0, x0_old = 0;
98 double eps=1e10, eps_old=2e10;
99 //std::cout << "In x1 function\n";
100 while( (eps < eps_old||eps>1e-7) && P < 20 )
101 {
102 eps_old = eps; x0_old = x0;
103 P+=2;
104 dg::Grid1d grid( 0, 1, P, 1);
105 if( psi>0)
106 {
107 dg::Grid1d grid1( 0, psi, P, 1);
108 grid = grid1;
109 }
110 else
111 {
112 dg::Grid1d grid2( psi, 0, P, 1);
113 grid = grid2;
114 }
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 //std::cout << " "<<f_vec[i]<<"\n";
122 }
123 if( psi < 0)
124 x0 = dg::blas1::dot( f_vec, w1d);
125 else
126 x0 = -dg::blas1::dot( f_vec, w1d);
127
128 eps = fabs((x0 - x0_old)/x0);
129 if( std::isnan(eps)) { std::cerr << "Attention!!\n"; eps = eps_old -1e-15; x0 = x0_old;} //near X-point integration can go wrong
130 std::cout << "X = "<<-x0<<" rel. error "<<eps<<" with "<<P<<" polynomials\n";
131 }
132 return -x0_old;
133
134 }
135
136 double f_prime( double psi)
137 {
138 //compute fprime
139 double deltaPsi = fabs(psi)/100.;
140 double fofpsi[4];
141 fofpsi[1] = operator()(psi-deltaPsi);
142 fofpsi[2] = operator()(psi+deltaPsi);
143 double fprime = (-0.5*fofpsi[1]+0.5*fofpsi[2])/deltaPsi, fprime_old;
144 double eps = 1e10, eps_old=2e10;
145 while( eps < eps_old || eps > 1e-7)
146 {
147 deltaPsi /=2.;
148 fprime_old = fprime;
149 eps_old = eps;
150 fofpsi[0] = fofpsi[1], fofpsi[3] = fofpsi[2];
151 fofpsi[1] = operator()(psi-deltaPsi);
152 fofpsi[2] = operator()(psi+deltaPsi);
153 //reuse previously computed fpsi for current fprime
154 fprime = (+ 1./12.*fofpsi[0]
155 - 2./3. *fofpsi[1]
156 + 2./3. *fofpsi[2]
157 - 1./12.*fofpsi[3]
158 )/deltaPsi;
159 eps = fabs((fprime - fprime_old)/fprime);
160 }
161 //std::cout << "\t fprime "<<fprime<<" rel error fprime is "<<eps<<" delta psi "<<deltaPsi<<"\n";
162 return fprime_old;
163 }
164 private:
165 dg::geo::orthogonal::detail::InitialX initX_;
166 const dg::geo::ribeiro::FieldRZYT fieldRZYT_;
167 const dg::geo::ribeiro::FieldRZYZ fieldRZYZ_;
168
169};
170
171//This struct computes -2pi/f with a fixed number of steps for all psi
172struct XFieldFinv
173{
174 XFieldFinv( const CylindricalFunctorsLvl1& psi, double xX, double yX, double x0, double y0, unsigned N_steps = 500):
175 fpsi_(psi, xX, yX, x0, y0), fieldRZYT_(psi, x0, y0), fieldRZYZ_(psi) , N_steps(N_steps)
176 { xAtOne_ = fpsi_.find_x(0.1); }
177 void operator()(double ttt, double psi, double& fpsiM)
178 {
179 std::array<double, 3> begin{ {0,0,0} }, end(begin);
180 double R_i[2], Z_i[2];
181 dg::Timer t;
182 t.tic();
183 fpsi_.find_initial( psi, R_i, Z_i);
184 t.toc();
185 //std::cout << "find_initial took "<<t.diff()<< "s\n";
186 t.tic();
187 begin[0] = R_i[0], begin[1] = Z_i[0];
188 unsigned N = N_steps;
189 using Vec = std::array<double,3>;
191 "Feagin-17-8-10", begin), fieldRZYT_);;
192 if( psi < -1. && psi > -2.) N*=2;
193 if( psi < 0 && psi > -1.) N*=10;
194 if( psi <0 )
195 odeintT.integrate_steps( 0., begin, 2.*M_PI, end, N);
196 else
197 {
199 "Feagin-17-8-10", begin), fieldRZYZ_);;
200 odeintZ.integrate_steps( begin[1], begin, 0., end, N);
201 std::array<double,3> temp(end);
202 odeintT.integrate_steps( 0., temp, M_PI, end, N/2);
203 temp = end; //temp[1] should be 0 now
204 odeintZ.integrate_steps( temp[1], temp, Z_i[1], end, N);
205 }
206 //eps = sqrt( (end[0]-begin[0])*(end[0]-begin[0]) + (end[1]-begin[1])*(end[1]-begin[1]));
207 fpsiM = end[2]/2./M_PI;
208 //fpsiM = - 2.*M_PI/end[2];
209 t.toc();
210 //std::cout << "Finding f took "<<t.diff()<<"s\n";
211 //std::cout <<"fpsiMinverse is "<<fpsiM<<" "<<-1./fpsi_(psi)<<" "<<eps<<"\n";
212 }
213 double find_psi( double x)
214 {
215 assert( x > 0);
216 //integrate from x0 to x, with psi(x0) = 0.1;
217 double x0 = xAtOne_;
218 double begin( 0.1), end(begin), end_old(begin);
219 double eps = 1e10, eps_old = 2e10;
220 unsigned N = 1;
221 while( eps < eps_old && N < 1e6 && eps > 1e-9)
222 {
223 eps_old = eps, end_old = end;
225 "Feagin-17-8-10", begin), *this);
226 N*=2; odeint.integrate_steps( x0, begin, x, end, N);
227 eps = fabs( end- end_old);
228 //std::cout << "\t error "<<eps<<" with "<<N<<" steps\n";
229 }
230 return end_old;
231 }
232
233 private:
234 FpsiX fpsi_;
235 dg::geo::ribeiro::FieldRZYT fieldRZYT_;
236 dg::geo::ribeiro::FieldRZYZ fieldRZYZ_;
237 thrust::host_vector<double> fpsi_neg_inv;
238 unsigned N_steps;
239 double xAtOne_;
240};
241} //namespace detail
242}//namespace ribeiro
244
252struct RibeiroX : public aGeneratorX2d
253{
254 RibeiroX( const CylindricalFunctorsLvl2& psi, double psi_0, double fx,
255 double xX, double yX, double x0, double y0):
256 psi_(psi), fpsi_(psi, xX, yX, x0,y0), fpsiMinv_(psi, xX, yX, x0,y0, 500)
257 {
258 assert( psi_0 < 0 );
259 zeta0_ = fpsi_.find_x( psi_0);
260 zeta1_= -fx/(1.-fx)*zeta0_;
261 psi0_=psi_0;
262 }
263
264 virtual RibeiroX* clone() const override final{return new RibeiroX(*this);}
265 private:
266 bool isConformal()const{return false;}
267 virtual bool do_isOrthogonal()const override final{return false;}
268 virtual void do_generate(
269 const thrust::host_vector<double>& zeta1d,
270 const thrust::host_vector<double>& eta1d,
271 unsigned nodeX0, unsigned nodeX1,
272 thrust::host_vector<double>& x,
273 thrust::host_vector<double>& y,
274 thrust::host_vector<double>& zetaX,
275 thrust::host_vector<double>& zetaY,
276 thrust::host_vector<double>& etaX,
277 thrust::host_vector<double>& etaY) const override final
278 {
279 //compute psi(x) for a grid on x and call construct_rzy for all psi
280 unsigned inside=0;
281 for(unsigned i=0; i<zeta1d.size(); i++)
282 if( zeta1d[i]< 0) inside++;//how many points are inside
283 thrust::host_vector<double> psi_x, fx_;
284 dg::geo::detail::construct_psi_values( fpsiMinv_, psi0_, zeta0_, zeta1d, zeta1_, inside, psi_x);
285
286 //std::cout << "In grid function:\n";
287 dg::geo::ribeiro::FieldRZYRYZY fieldRZYRYZYribeiro(psi_);
288 unsigned size = zeta1d.size()*eta1d.size();
289 x.resize(size), y.resize(size);
290 zetaX = zetaY = etaX = etaY =x ;
291 unsigned Nx = zeta1d.size(), Ny = eta1d.size();
292 fx_.resize(Nx);
293 for( unsigned i=0; i<zeta1d.size(); i++)
294 {
295 thrust::host_vector<double> ry, zy;
296 thrust::host_vector<double> yr, yz, xr, xz;
297 double R0[2], Z0[2];
298 dg::geo::detail::computeX_rzy( fpsi_, fieldRZYRYZYribeiro, psi_x[i], eta1d, nodeX0, nodeX1, ry, zy, yr, yz, xr, xz, R0, Z0, fx_[i]);
299 for( unsigned j=0; j<Ny; j++)
300 {
301 x[j*Nx+i] = ry[j], y[j*Nx+i] = zy[j];
302 etaX[j*Nx+i] = yr[j], etaY[j*Nx+i] = yz[j];
303 zetaX[j*Nx+i] = xr[j], zetaY[j*Nx+i] = xz[j];
304 }
305 }
306 }
307
308 virtual double do_zeta0(double fx) const override final { return zeta0_; }
309 virtual double do_zeta1(double fx) const override final { return zeta1_;}
310 virtual double do_eta0(double fy) const override final { return -2.*M_PI*fy/(1.-2.*fy); }
311 virtual double do_eta1(double fy) const override final { return 2.*M_PI*(1.+fy/(1.-2.*fy));}
312 private:
313 CylindricalFunctorsLvl2 psi_;
314 dg::geo::ribeiro::detail::FpsiX fpsi_;
315 dg::geo::ribeiro::detail::XFieldFinv fpsiMinv_;
316 double zeta0_, zeta1_;
317 double psi0_;
318};
319
320
321}//namespace geo
322}//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 toc()
void tic()
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: ribeiroX.h:253
virtual RibeiroX * clone() const override final
Abstract clone method that returns a copy on the heap.
Definition: ribeiroX.h:264
RibeiroX(const CylindricalFunctorsLvl2 &psi, double psi_0, double fx, double xX, double yX, double x0, double y0)
Definition: ribeiroX.h:254
The abstract generator base class.
Definition: generatorX.h:19