Extension: Geometries
#include "dg/geometries/geometries.h"
mpi_fieldaligned.h
Go to the documentation of this file.
1#pragma once
2
3#include "dg/algorithm.h"
4#include "fieldaligned.h"
5#include "dg/backend/timer.h"
6
7namespace dg{
8namespace geo{
9
11namespace detail{
12
14template<class thrust_vector0, class thrust_vector1>
15void sendForward( const thrust_vector0& in, thrust_vector1& out, MPI_Comm comm) //send to next plane
16{
17 int source, dest;
18 MPI_Status status;
19 MPI_Cart_shift( comm, 2, +1, &source, &dest);
20#if THRUST_DEVICE_SYSTEM==THRUST_DEVICE_SYSTEM_CUDA
21 if( std::is_same< get_execution_policy<thrust_vector0>, CudaTag>::value) //could be serial tag
22 {
23 cudaError_t code = cudaGetLastError( );
24 if( code != cudaSuccess)
25 throw dg::Error(dg::Message(_ping_)<<cudaGetErrorString(code));
26 code = cudaDeviceSynchronize(); //wait until device functions are finished before sending data
27 if( code != cudaSuccess)
28 throw dg::Error(dg::Message(_ping_)<<cudaGetErrorString(code));
29 }
30#endif //THRUST_DEVICE_SYSTEM
31 unsigned size = in.size();
32 MPI_Sendrecv( thrust::raw_pointer_cast(in.data()), size, MPI_DOUBLE, //sender
33 dest, 9, //destination
34 thrust::raw_pointer_cast(out.data()), size, MPI_DOUBLE, //receiver
35 source, 9, //source
36 comm, &status);
37}
39template<class thrust_vector0, class thrust_vector1>
40void sendBackward( const thrust_vector0& in, thrust_vector1& out, MPI_Comm comm) //send to next plane
41{
42 int source, dest;
43 MPI_Status status;
44 MPI_Cart_shift( comm, 2, -1, &source, &dest);
45#if THRUST_DEVICE_SYSTEM==THRUST_DEVICE_SYSTEM_CUDA
46 if( std::is_same< get_execution_policy<thrust_vector0>, CudaTag>::value) //could be serial tag
47 {
48 cudaError_t code = cudaGetLastError( );
49 if( code != cudaSuccess)
50 throw dg::Error(dg::Message(_ping_)<<cudaGetErrorString(code));
51 code = cudaDeviceSynchronize(); //wait until device functions are finished before sending data
52 if( code != cudaSuccess)
53 throw dg::Error(dg::Message(_ping_)<<cudaGetErrorString(code));
54 }
55#endif //THRUST_DEVICE_SYSTEM
56 unsigned size = in.size();
57 MPI_Sendrecv( thrust::raw_pointer_cast(in.data()), size, MPI_DOUBLE, //sender
58 dest, 3, //destination
59 thrust::raw_pointer_cast(out.data()), size, MPI_DOUBLE, //receiver
60 source, 3, //source
61 comm, &status);
62}
63}//namespace detail
64
65template <class ProductMPIGeometry, class LocalIMatrix, class CommunicatorXY, class LocalContainer>
66struct Fieldaligned< ProductMPIGeometry, MPIDistMat<LocalIMatrix, CommunicatorXY>, MPI_Vector<LocalContainer> >
67{
68 Fieldaligned(){}
69 template <class Limiter>
71 const ProductMPIGeometry& grid,
74 Limiter limit = FullLimiter(),
75 double eps = 1e-5,
76 unsigned mx=12, unsigned my=12,
77 double deltaPhi = -1, std::string interpolation_method = "linear-nearest",
78 bool benchmark = true):
79 Fieldaligned( dg::geo::createBHat(vec), grid, bcx, bcy, limit, eps,
80 mx, my, deltaPhi, interpolation_method)
81 {
82 }
83 template <class Limiter>
85 const ProductMPIGeometry& grid,
88 Limiter limit = FullLimiter(),
89 double eps = 1e-5,
90 unsigned mx=12, unsigned my=12,
91 double deltaPhi = -1, std::string interpolation_method = "linear-nearest",
92 bool benchmark = true);
93 template<class ...Params>
94 void construct( Params&& ...ps)
95 {
96 //construct and swap
97 *this = Fieldaligned( std::forward<Params>( ps)...);
98 }
99
100 dg::bc bcx()const{
101 return m_bcx;
102 }
103 dg::bc bcy()const{
104 return m_bcy;
105 }
106
107 void set_boundaries( dg::bc bcz, double left, double right)
108 {
109 m_bcz = bcz;
110 dg::blas1::copy( left, m_left);
111 dg::blas1::copy( right, m_right);
112 }
113
114 void set_boundaries( dg::bc bcz, const MPI_Vector<LocalContainer>& left, const MPI_Vector<LocalContainer>& right)
115 {
116 m_bcz = bcz;
117 m_left = left;
118 m_right = right;
119 }
120
121 void set_boundaries( dg::bc bcz, const MPI_Vector<LocalContainer>& global, double scal_left, double scal_right)
122 {
123 dg::split( global, m_f, *m_g);
124 dg::blas1::axpby( scal_left, m_f[0], 0., m_left);
125 dg::blas1::axpby( scal_right, m_f[m_g->local().Nz()-1], 0., m_right);
126 m_bcz = bcz;
127 }
128
129 void operator()(enum whichMatrix which, const MPI_Vector<LocalContainer>& in, MPI_Vector<LocalContainer>& out);
130
131 double deltaPhi() const{return m_deltaPhi;}
132 const MPI_Vector<LocalContainer>& hbm()const {
133 return m_hbm;
134 }
135 const MPI_Vector<LocalContainer>& hbp()const {
136 return m_hbp;
137 }
138 const MPI_Vector<LocalContainer>& sqrtG()const {
139 return m_G;
140 }
141 const MPI_Vector<LocalContainer>& sqrtGm()const {
142 return m_Gm;
143 }
144 const MPI_Vector<LocalContainer>& sqrtGp()const {
145 return m_Gp;
146 }
147 const MPI_Vector<LocalContainer>& bphi()const {
148 return m_bphi;
149 }
150 const MPI_Vector<LocalContainer>& bphiM()const {
151 return m_bphiM;
152 }
153 const MPI_Vector<LocalContainer>& bphiP()const {
154 return m_bphiP;
155 }
156 const MPI_Vector<LocalContainer>& bbm()const {
157 return m_bbm;
158 }
159 const MPI_Vector<LocalContainer>& bbo()const {
160 return m_bbo;
161 }
162 const MPI_Vector<LocalContainer>& bbp()const {
163 return m_bbp;
164 }
165 const ProductMPIGeometry& grid() const{return *m_g;}
166
167 template< class BinaryOp, class UnaryOp>
168 MPI_Vector<LocalContainer> evaluate( BinaryOp f, UnaryOp g, unsigned p0,
169 unsigned rounds) const;
170 std::string method() const{return m_interpolation_method;}
171 private:
172 void ePlus( enum whichMatrix which, const MPI_Vector<LocalContainer>& in, MPI_Vector<LocalContainer>& out);
173 void eMinus(enum whichMatrix which, const MPI_Vector<LocalContainer>& in, MPI_Vector<LocalContainer>& out);
174 void zero(enum whichMatrix which, const MPI_Vector<LocalContainer>& in, MPI_Vector<LocalContainer>& out);
175 MPIDistMat<LocalIMatrix, CommunicatorXY> m_plus, m_zero, m_minus, m_plusT, m_minusT; //2d interpolation matrices
176 MPI_Vector<LocalContainer> m_hbm, m_hbp; //3d size
177 MPI_Vector<LocalContainer> m_G, m_Gm, m_Gp; //3d size
178 MPI_Vector<LocalContainer> m_bphi, m_bphiM, m_bphiP; //3d size
179 MPI_Vector<LocalContainer> m_bbm, m_bbp, m_bbo; //3d size
180
181 MPI_Vector<LocalContainer> m_left, m_right; //2d size
182 MPI_Vector<LocalContainer> m_limiter; //2d size
183 MPI_Vector<LocalContainer> m_ghostM, m_ghostP; //2d size
184 unsigned m_Nz, m_perp_size;
185 dg::bc m_bcx, m_bcy, m_bcz;
186 std::vector<MPI_Vector<dg::View<const LocalContainer>> > m_f;
187 std::vector<MPI_Vector<dg::View<LocalContainer>> > m_temp;
189 double m_deltaPhi;
190 std::string m_interpolation_method;
191 unsigned m_coords2, m_sizeZ; //number of processes in z
192#ifdef _DG_CUDA_UNAWARE_MPI
193 //we need to manually send data through the host
194 thrust::host_vector<double> m_send_buffer, m_recv_buffer; //2d size
195#endif
196 bool m_have_adjoint = false;
197 void updateAdjoint( )
198 {
199 m_plusT = dg::transpose( m_plus);
200 m_minusT = dg::transpose( m_minus);
201 m_have_adjoint = true;
202 }
203};
205template<class MPIGeometry, class LocalIMatrix, class CommunicatorXY, class LocalContainer>
206template <class Limiter>
207Fieldaligned<MPIGeometry, MPIDistMat<LocalIMatrix, CommunicatorXY>, MPI_Vector<LocalContainer> >::Fieldaligned(
209 const MPIGeometry& grid,
210 dg::bc bcx, dg::bc bcy, Limiter limit, double eps,
211 unsigned mx, unsigned my, double deltaPhi, std::string interpolation_method, bool benchmark
212 ):
213 m_g(grid),
214 m_interpolation_method(interpolation_method)
215{
216 int rank;
217 MPI_Comm_rank( grid.communicator(), &rank);
218 int dims[3], periods[3], coords[3];
219 MPI_Cart_get( m_g->communicator(), 3, dims, periods, coords);
220 m_coords2 = coords[2], m_sizeZ = dims[2];
221
222 std::string inter_m, project_m, fine_m;
223 detail::parse_method( interpolation_method, inter_m, project_m, fine_m);
224 if( benchmark && rank==0) std::cout << "# Interpolation method: \""<<inter_m << "\" projection method: \""<<project_m<<"\" fine grid \""<<fine_m<<"\"\n";
226 if( (grid.bcx() == PER && bcx != PER) || (grid.bcx() != PER && bcx == PER) )
227 throw( dg::Error(dg::Message(_ping_)<<"Fieldaligned: Got conflicting periodicity in x. The grid says "<<bc2str(grid.bcx())<<" while the parameter says "<<bc2str(bcx)));
228 if( (grid.bcy() == PER && bcy != PER) || (grid.bcy() != PER && bcy == PER) )
229 throw( dg::Error(dg::Message(_ping_)<<"Fieldaligned: Got conflicting boundary conditions in y. The grid says "<<bc2str(grid.bcy())<<" while the parameter says "<<bc2str(bcy)));
230 m_Nz=grid.local().Nz(), m_bcz=grid.bcz(), m_bcx = bcx, m_bcy = bcy;
231 if( deltaPhi <=0) deltaPhi = grid.hz();
233 // grid_trafo -> grid_equi -> grid_fine -> grid_equi -> grid_trafo
234 dg::Timer t;
235 if( benchmark) t.tic();
236 dg::ClonePtr<dg::aMPIGeometry2d> grid_transform( grid.perp_grid()) ;
237 // We do not need metric of grid_equidist or or grid_fine
238 dg::RealMPIGrid2d<double> grid_equidist( *grid_transform) ;
239 dg::RealMPIGrid2d<double> grid_fine( *grid_transform);
240 grid_equidist.set( 1, grid.global().gx().size(), grid.global().gy().size());
241 dg::ClonePtr<dg::aMPIGeometry2d> grid_magnetic = grid_transform;//INTEGRATE HIGH ORDER GRID
242 grid_magnetic->set( grid_transform->n() < 3 ? 4 : 7, grid_magnetic->Nx(), grid_magnetic->Ny());
243 dg::ClonePtr<dg::aGeometry2d> global_grid_magnetic =
244 grid_magnetic->global_geometry();
245 // For project method "const" we round up to the nearest multiple of n
246 if( project_m != "dg" && fine_m == "dg")
247 {
248 unsigned rx = mx % grid.nx(), ry = my % grid.ny();
249 if( 0 != rx || 0 != ry)
250 {
251 if(rank==0)std::cerr << "#Warning: for projection method \"const\" mx and my must be multiples of nx and ny! Rounding up for you ...\n";
252 mx = mx + grid.nx() - rx;
253 my = my + grid.ny() - ry;
254 }
255 }
256 if( fine_m == "equi")
257 grid_fine = grid_equidist;
258 grid_fine.multiplyCellNumbers((double)mx, (double)my);
259 if( benchmark)
260 {
261 t.toc();
262 if(rank==0) std::cout << "# DS: High order grid gen took: "<<t.diff()<<"\n";
263 t.tic();
264 }
266 std::array<thrust::host_vector<double>,3> yp_trafo, ym_trafo, yp, ym;
267 thrust::host_vector<bool> in_boxp, in_boxm;
268 thrust::host_vector<double> hbp, hbm;
269 auto vol = dg::tensor::volume(grid.metric()), vol2d0(vol);
270 auto vol2d = dg::split( vol, grid);
271 dg::assign( vol2d[0], vol2d0);
272 detail::integrate_all_fieldlines2d( vec, *global_grid_magnetic,
273 grid_transform->local(), yp_trafo, vol2d0.data(), hbp, in_boxp,
274 deltaPhi, eps);
275 detail::integrate_all_fieldlines2d( vec, *global_grid_magnetic,
276 grid_transform->local(), ym_trafo, vol2d0.data(), hbm, in_boxm,
277 -deltaPhi, eps);
278 dg::HVec Xf = dg::evaluate( dg::cooX2d, grid_fine.local());
279 dg::HVec Yf = dg::evaluate( dg::cooY2d, grid_fine.local());
280 {
282 grid_transform->local(), dg::NEU, dg::NEU, grid_transform->n() < 3 ? "cubic" : "dg");
283 yp.fill(dg::evaluate( dg::zero, grid_fine.local()));
284 ym = yp;
285 for( int i=0; i<2; i++)
286 {
287 dg::blas2::symv( interpolate, yp_trafo[i], yp[i]);
288 dg::blas2::symv( interpolate, ym_trafo[i], ym[i]);
289 }
290 } // release memory for interpolate matrix
291 if(benchmark)
292 {
293 t.toc();
294 if(rank==0) std::cout << "# DS: Fieldline integration took: "<<t.diff()<<"\n";
295 t.tic();
296 }
298 if( inter_m == "dg")
299 {
300 dg::IHMatrix fine, projection, multi, temp;
301 if( project_m == "dg")
302 projection = dg::create::projection( grid_transform->global(), grid_fine.local());
303 else
304 projection = dg::create::projection( grid_equidist.global(), grid_fine.local(), project_m);
305
306 fine = dg::create::interpolation( yp[0], yp[1],
307 grid_transform->global(), bcx, bcy, "dg");
308 cusp::multiply( projection, fine, multi);
309 multi = dg::convertGlobal2LocalRows( multi, *grid_transform);
310 if( project_m != "dg")
311 {
312 fine = dg::create::inv_backproject( grid_transform->local());
313 cusp::multiply( fine, multi, temp);
314 temp.swap(multi);
315 }
316 dg::MIHMatrix mpi = dg::convert( multi, *grid_transform); //, tempT;
317 dg::blas2::transfer( mpi, m_plus);
318
319 fine = dg::create::interpolation( Xf, Yf,
320 grid_transform->global(), bcx, bcy, "dg");
321 cusp::multiply( projection, fine, multi);
322 multi = dg::convertGlobal2LocalRows( multi, *grid_transform);
323 if( project_m != "dg")
324 {
325 fine = dg::create::inv_backproject( grid_transform->local());
326 cusp::multiply( fine, multi, temp);
327 temp.swap(multi);
328 }
329 mpi = dg::convert( multi, *grid_transform); //, tempT;
330 dg::blas2::transfer( mpi, m_zero);
331
332 fine = dg::create::interpolation( ym[0], ym[1],
333 grid_transform->global(), bcx, bcy, "dg");
334 cusp::multiply( projection, fine, multi);
335 multi = dg::convertGlobal2LocalRows( multi, *grid_transform);
336 if( project_m != "dg")
337 {
338 fine = dg::create::inv_backproject( grid_transform->local());
339 cusp::multiply( fine, multi, temp);
340 temp.swap(multi);
341 }
342 mpi = dg::convert( multi, *grid_transform); //, tempT;
343 dg::blas2::transfer( mpi, m_minus);
344 }
345 else
346 {
347 dg::IHMatrix fine, projection, multi, temp;
348 if( project_m == "dg")
349 projection = dg::create::projection( grid_transform->global(), grid_fine.local());
350 else
351 projection = dg::create::projection( grid_equidist.global(), grid_fine.local(), project_m);
352
353 fine = dg::create::backproject( grid_transform->global()); // from dg to equidist
354 multi = dg::create::interpolation( yp[0], yp[1],
355 grid_equidist.global(), bcx, bcy, inter_m);
356 cusp::multiply( multi, fine, temp);
357 cusp::multiply( projection, temp, multi);
358 multi = dg::convertGlobal2LocalRows( multi, *grid_transform);
359 if( project_m != "dg")
360 {
361 fine = dg::create::inv_backproject( grid_transform->local());
362 cusp::multiply( fine, multi, temp);
363 temp.swap(multi);
364 }
365 dg::MIHMatrix mpi = dg::convert( multi, *grid_transform);
366 dg::blas2::transfer( mpi, m_plus);
367
368 fine = dg::create::backproject( grid_transform->global()); // from dg to equidist
369 multi = dg::create::interpolation( Xf, Yf,
370 grid_equidist.global(), bcx, bcy, inter_m);
371 cusp::multiply( multi, fine, temp);
372 cusp::multiply( projection, temp, multi);
373 multi = dg::convertGlobal2LocalRows( multi, *grid_transform);
374 if( project_m != "dg")
375 {
376 fine = dg::create::inv_backproject( grid_transform->local());
377 cusp::multiply( fine, multi, temp);
378 temp.swap(multi);
379 }
380 mpi = dg::convert( multi, *grid_transform);
381 dg::blas2::transfer( mpi, m_zero);
382
383 fine = dg::create::backproject( grid_transform->global()); // from dg to equidist
384 multi = dg::create::interpolation( ym[0], ym[1],
385 grid_equidist.global(), bcx, bcy, inter_m);
386 cusp::multiply( multi, fine, temp);
387 cusp::multiply( projection, temp, multi);
388 multi = dg::convertGlobal2LocalRows( multi, *grid_transform);
389 if( project_m != "dg")
390 {
391 fine = dg::create::inv_backproject( grid_transform->local());
392 cusp::multiply( fine, multi, temp);
393 temp.swap(multi);
394 }
395 mpi = dg::convert( multi, *grid_transform);
396 dg::blas2::transfer( mpi, m_minus);
397 }
398 if( benchmark)
399 {
400 t.toc();
401 if(rank==0) std::cout << "# DS: Multiplication PI took: "<<t.diff()<<"\n";
402 }
404 dg::HVec hbphi( yp_trafo[2]), hbphiP(hbphi), hbphiM(hbphi);
405 auto tmp = dg::pullback( vec.z(), *grid_transform);
406 hbphi = tmp.data();
407 //this is a pullback bphi( R(zeta, eta), Z(zeta, eta)):
408 if( dynamic_cast<const dg::CartesianMPIGrid2d*>( grid_transform.get()))
409 {
410 for( unsigned i=0; i<hbphiP.size(); i++)
411 {
412 hbphiP[i] = vec.z()(yp_trafo[0][i], yp_trafo[1][i]);
413 hbphiM[i] = vec.z()(ym_trafo[0][i], ym_trafo[1][i]);
414 }
415 }
416 else
417 {
418 dg::HVec Ihbphi = dg::pullback( vec.z(), *global_grid_magnetic);
419 dg::HVec Lhbphi = dg::forward_transform( Ihbphi, *global_grid_magnetic);
420 for( unsigned i=0; i<yp_trafo[0].size(); i++)
421 {
422 hbphiP[i] = dg::interpolate( dg::lspace, Lhbphi, yp_trafo[0][i],
423 yp_trafo[1][i], *global_grid_magnetic);
424 hbphiM[i] = dg::interpolate( dg::lspace, Lhbphi, ym_trafo[0][i],
425 ym_trafo[1][i], *global_grid_magnetic);
426 }
427 }
428 dg::assign3dfrom2d( dg::MHVec(hbphi, MPI_COMM_WORLD), m_bphi, grid);
429 dg::assign3dfrom2d( dg::MHVec(hbphiM, MPI_COMM_WORLD), m_bphiM, grid);
430 dg::assign3dfrom2d( dg::MHVec(hbphiP, MPI_COMM_WORLD), m_bphiP, grid);
431
432 dg::assign3dfrom2d( dg::MHVec(yp_trafo[2], MPI_COMM_WORLD), m_Gp, grid);
433 dg::assign3dfrom2d( dg::MHVec(ym_trafo[2], MPI_COMM_WORLD), m_Gm, grid);
434 m_G = vol;
435 MPI_Vector<LocalContainer> weights = dg::create::weights( grid);
437 dg::blas1::pointwiseDot( m_Gp, weights, m_Gp);
438 dg::blas1::pointwiseDot( m_Gm, weights, m_Gm);
439
440 dg::assign( dg::evaluate( dg::zero, grid), m_hbm);
441 m_temp = dg::split( m_hbm, grid); //3d vector
442 m_f = dg::split( (const MPI_Vector<LocalContainer>&)m_hbm, grid);
443 dg::assign3dfrom2d( dg::MHVec(hbp, MPI_COMM_WORLD), m_hbp, grid);
444 dg::assign3dfrom2d( dg::MHVec(hbm, MPI_COMM_WORLD), m_hbm, grid);
445 dg::blas1::scal( m_hbm, -1.);
447 thrust::host_vector<double> bbm( in_boxp.size(),0.), bbo(bbm), bbp(bbm);
448 for( unsigned i=0; i<in_boxp.size(); i++)
449 {
450 if( !in_boxp[i] && !in_boxm[i])
451 bbo[i] = 1.;
452 else if( !in_boxp[i] && in_boxm[i])
453 bbp[i] = 1.;
454 else if( in_boxp[i] && !in_boxm[i])
455 bbm[i] = 1.;
456 // else all are 0
457 }
458 dg::assign3dfrom2d( dg::MHVec(bbm, MPI_COMM_WORLD), m_bbm, grid);
459 dg::assign3dfrom2d( dg::MHVec(bbo, MPI_COMM_WORLD), m_bbo, grid);
460 dg::assign3dfrom2d( dg::MHVec(bbp, MPI_COMM_WORLD), m_bbp, grid);
461
462 m_deltaPhi = deltaPhi; // store for evaluate
463
465 m_perp_size = grid_transform->local().size();
466 dg::assign( dg::pullback(limit, *grid_transform), m_limiter);
467 dg::assign( dg::evaluate(dg::zero, *grid_transform), m_left);
468 m_ghostM = m_ghostP = m_right = m_left;
469#ifdef _DG_CUDA_UNAWARE_MPI
470 m_recv_buffer = m_send_buffer = m_ghostP.data();
471#endif
472}
473
474
475template<class G, class M, class C, class container>
476void Fieldaligned<G, MPIDistMat<M,C>, MPI_Vector<container> >::operator()(enum
477 whichMatrix which, const MPI_Vector<container>& f,
478 MPI_Vector<container>& fe)
479{
480 if(which == einsPlus || which == einsMinusT) ePlus( which, f, fe);
481 if(which == einsMinus || which == einsPlusT) eMinus( which, f, fe);
482 if( which == einsPlus || which == einsMinusT ) ePlus( which, f, fe);
483 else if(which == einsMinus || which == einsPlusT ) eMinus( which, f, fe);
484 else if(which == zeroMinus || which == zeroPlus ||
485 which == zeroMinusT|| which == zeroPlusT ||
486 which == zeroForw ) zero( which, f, fe);
487}
488template< class G, class M, class C, class container>
489void Fieldaligned<G, MPIDistMat<M,C>, MPI_Vector<container> >::zero( enum whichMatrix which, const MPI_Vector<container>& f, MPI_Vector<container>& f0)
490{
491 dg::split( f, m_f, *m_g);
492 dg::split( f0, m_temp, *m_g);
493 //1. compute 2d interpolation in every plane and store in m_temp
494 for( unsigned i0=0; i0<m_Nz; i0++)
495 {
496 if(which == zeroPlus)
497 dg::blas2::symv( m_plus, m_f[i0], m_temp[i0]);
498 else if(which == zeroMinus)
499 dg::blas2::symv( m_minus, m_f[i0], m_temp[i0]);
500 else if(which == zeroPlusT)
501 {
502 if( ! m_have_adjoint) updateAdjoint( );
503 dg::blas2::symv( m_plusT, m_f[i0], m_temp[i0]);
504 }
505 else if(which == zeroMinusT)
506 {
507 if( ! m_have_adjoint) updateAdjoint( );
508 dg::blas2::symv( m_minusT, m_f[i0], m_temp[i0]);
509 }
510 else if( which == zeroForw)
511 {
512 if ( m_interpolation_method != "dg" )
513 {
514 dg::blas2::symv( m_zero, m_f[i0], m_temp[i0]);
515 }
516 else
517 dg::blas1::copy( m_f[i0], m_temp[i0]);
518 }
519 }
520}
521
522template<class G, class M, class C, class container>
523void Fieldaligned<G,MPIDistMat<M,C>, MPI_Vector<container> >::ePlus( enum whichMatrix which, const MPI_Vector<container>& f, MPI_Vector<container>& fpe )
524{
525 dg::split( f, m_f, *m_g);
526 dg::split( fpe, m_temp, *m_g);
527 //1. compute 2d interpolation in every plane and store in m_temp
528 for( unsigned i0=0; i0<m_Nz; i0++)
529 {
530 unsigned ip = (i0==m_Nz-1) ? 0:i0+1;
531 if(which == einsPlus)
532 dg::blas2::symv( m_plus, m_f[ip], m_temp[i0]);
533 else if(which == einsMinusT)
534 {
535 if( ! m_have_adjoint) updateAdjoint( );
536 dg::blas2::symv( m_minusT, m_f[ip], m_temp[i0]);
537 }
538 }
539
540 //2. communicate halo in z
541 if( m_sizeZ != 1)
542 {
543 unsigned i0 = m_Nz-1;
544#ifdef _DG_CUDA_UNAWARE_MPI
545 thrust::copy( m_temp[i0].data().cbegin(), m_temp[i0].data().cend(), m_send_buffer.begin());
546 detail::sendBackward( m_send_buffer, m_recv_buffer, m_g->communicator());
547 thrust::copy( m_recv_buffer.cbegin(), m_recv_buffer.cend(), m_temp[i0].data().begin());
548#else
549 detail::sendBackward( m_temp[i0].data(), m_ghostM.data(), m_g->communicator());
550 dg::blas1::copy( m_ghostM, m_temp[i0]);
551#endif //_DG_CUDA_UNAWARE_MPI
552 }
553
554 //3. apply right boundary conditions in last plane
555 unsigned i0=m_Nz-1;
556 if( m_bcz != dg::PER && m_g->local().z1() == m_g->global().z1())
557 {
558 if( m_bcz == dg::DIR || m_bcz == dg::NEU_DIR)
559 dg::blas1::axpby( 2, m_right, -1., m_f[i0], m_ghostP);
560 if( m_bcz == dg::NEU || m_bcz == dg::DIR_NEU)
561 dg::blas1::axpby( m_deltaPhi, m_right, 1., m_f[i0], m_ghostP);
562 //interlay ghostcells with periodic cells: L*g + (1-L)*fpe
563 dg::blas1::axpby( 1., m_ghostP, -1., m_temp[i0], m_ghostP);
564 dg::blas1::pointwiseDot( 1., m_limiter, m_ghostP, 1., m_temp[i0]);
565 }
566}
567
568template<class G, class M, class C, class container>
569void Fieldaligned<G,MPIDistMat<M,C>, MPI_Vector<container> >::eMinus( enum whichMatrix which, const MPI_Vector<container>& f, MPI_Vector<container>& fme )
570{
571 int rank;
572 MPI_Comm_rank(m_g->communicator(), &rank);
573 dg::split( f, m_f, *m_g);
574 dg::split( fme, m_temp, *m_g);
575 //1. compute 2d interpolation in every plane and store in m_temp
576 for( unsigned i0=0; i0<m_Nz; i0++)
577 {
578 unsigned im = (i0==0) ? m_Nz-1:i0-1;
579 if(which == einsPlusT)
580 {
581 if( ! m_have_adjoint) updateAdjoint( );
582 dg::blas2::symv( m_plusT, m_f[im], m_temp[i0]);
583 }
584 else if(which == einsMinus)
585 dg::blas2::symv( m_minus, m_f[im], m_temp[i0]);
586 }
587
588 //2. communicate halo in z
589 if( m_sizeZ != 1)
590 {
591 unsigned i0 = 0;
592#ifdef _DG_CUDA_UNAWARE_MPI
593 thrust::copy( m_temp[i0].data().cbegin(), m_temp[i0].data().cend(), m_send_buffer.begin());
594 detail::sendForward( m_send_buffer, m_recv_buffer, m_g->communicator());
595 thrust::copy( m_recv_buffer.cbegin(), m_recv_buffer.cend(), m_temp[i0].data().begin());
596#else
597 detail::sendForward( m_temp[i0].data(), m_ghostP.data(), m_g->communicator());
598 dg::blas1::copy( m_ghostP, m_temp[i0]);
599#endif //_DG_CUDA_UNAWARE_MPI
600 }
601
602 //3. apply left boundary conditions in first plane
603 unsigned i0=0;
604 if( m_bcz != dg::PER && m_g->local().z0() == m_g->global().z0())
605 {
606 if( m_bcz == dg::DIR || m_bcz == dg::DIR_NEU)
607 dg::blas1::axpby( 2., m_left, -1., m_f[i0], m_ghostM);
608 if( m_bcz == dg::NEU || m_bcz == dg::NEU_DIR)
609 dg::blas1::axpby( -m_deltaPhi, m_left, 1., m_f[i0], m_ghostM);
610 //interlay ghostcells with periodic cells: L*g + (1-L)*fme
611 dg::blas1::axpby( 1., m_ghostM, -1., m_temp[i0], m_ghostM);
612 dg::blas1::pointwiseDot( 1., m_limiter, m_ghostM, 1., m_temp[i0]);
613 }
614}
615
616template<class G, class M, class C, class container>
617template< class BinaryOp, class UnaryOp>
618MPI_Vector<container> Fieldaligned<G,MPIDistMat<M,C>, MPI_Vector<container> >::evaluate( BinaryOp binary, UnaryOp unary, unsigned p0, unsigned rounds) const
619{
620 //idea: simply apply I+/I- enough times on the init2d vector to get the result in each plane
621 //unary function is always such that the p0 plane is at x=0
622 assert( p0 < m_g->global().Nz());
623 const dg::ClonePtr<aMPIGeometry2d> g2d = m_g->perp_grid();
624 MPI_Vector<container> init2d = dg::pullback( binary, *g2d);
625 MPI_Vector<container> zero2d = dg::evaluate( dg::zero, *g2d);
626 unsigned globalNz = m_g->global().Nz();
627
628 MPI_Vector<container> temp(init2d), tempP(init2d), tempM(init2d);
629 MPI_Vector<container> vec3d = dg::evaluate( dg::zero, *m_g);
630 std::vector<MPI_Vector<container> > plus2d(globalNz, zero2d), minus2d(plus2d), result(plus2d);
631 unsigned turns = rounds;
632 if( turns ==0) turns++;
633 //first apply Interpolation many times, scale and store results
634 for( unsigned r=0; r<turns; r++)
635 for( unsigned i0=0; i0<globalNz; i0++)
636 {
637 dg::blas1::copy( init2d, tempP);
638 dg::blas1::copy( init2d, tempM);
639 unsigned rep = r*globalNz + i0;
640 for(unsigned k=0; k<rep; k++)
641 {
643 dg::blas2::symv( m_minus, tempP, temp);
644 temp.swap( tempP);
646 dg::blas2::symv( m_plus, tempM, temp);
647 temp.swap( tempM);
648 }
649 dg::blas1::scal( tempP, unary( (double)rep*m_deltaPhi ) );
650 dg::blas1::scal( tempM, unary( -(double)rep*m_deltaPhi ) );
651 dg::blas1::axpby( 1., tempP, 1., plus2d[i0]);
652 dg::blas1::axpby( 1., tempM, 1., minus2d[i0]);
653 }
654 //now we have the plus and the minus filaments
655 if( rounds == 0) //there is a limiter
656 {
657 for( unsigned i0=0; i0<m_Nz; i0++)
658 {
659 int idx = (int)(i0+m_coords2*m_Nz) - (int)p0;
660 if(idx>=0)
661 result[i0] = plus2d[idx];
662 else
663 result[i0] = minus2d[abs(idx)];
664 thrust::copy( result[i0].data().begin(), result[i0].data().end(),
665 vec3d.data().begin() + i0*m_perp_size);
666 }
667 }
668 else //sum up plus2d and minus2d
669 {
670 for( unsigned i0=0; i0<globalNz; i0++)
671 {
672 unsigned revi0 = (globalNz - i0)%globalNz; //reverted index
673 dg::blas1::axpby( 1., plus2d[i0], 0., result[i0]);
674 dg::blas1::axpby( 1., minus2d[revi0], 1., result[i0]);
675 }
676 dg::blas1::axpby( -1., init2d, 1., result[0]);
677 for(unsigned i0=0; i0<m_Nz; i0++)
678 {
679 int idx = ((int)i0 + m_coords2*m_Nz -(int)p0 + globalNz)%globalNz; //shift index
680 thrust::copy( result[idx].data().begin(), result[idx].data().end(),
681 vec3d.data().begin() + i0*m_perp_size);
682 }
683 }
684 return vec3d;
685}
686
687
689
690
694template<class BinaryOp, class UnaryOp>
696 const aProductMPIGeometry3d& grid,
697 const CylindricalVectorLvl0& vec,
698 const BinaryOp& binary,
699 const UnaryOp& unary,
700 unsigned p0,
701 unsigned rounds,
702 double eps = 1e-5)
703{
704 unsigned Nz = grid.Nz();
705 const dg::ClonePtr<aMPIGeometry2d> g2d = grid.perp_grid();
706 // Construct for field-aligned output
707 dg::MHVec vec3d = dg::evaluate( dg::zero, grid);
708 dg::MHVec tempP = dg::evaluate( dg::zero, *g2d), tempM( tempP);
709 std::vector<dg::MHVec> plus2d(Nz, tempP), minus2d(plus2d), result(plus2d);
710 dg::MHVec init2d = dg::pullback( binary, *g2d);
711 std::array<dg::HVec,3> yy0{
712 dg::evaluate( dg::cooX2d, g2d->local()),
713 dg::evaluate( dg::cooY2d, g2d->local()),
714 dg::evaluate( dg::zero, g2d->local())}, yy1(yy0), xx0( yy0), xx1(yy0); //s
715 dg::geo::detail::DSFieldCylindrical3 cyl_field(vec);
716 double deltaPhi = grid.hz();
717 double phiM0 = 0., phiP0 = 0.;
718 unsigned turns = rounds;
719 if( turns == 0) turns++;
720 for( unsigned r=0; r<turns; r++)
721 for( unsigned i0=0; i0<Nz; i0++)
722 {
723 unsigned rep = r*Nz + i0;
724 if( rep == 0)
725 tempM = tempP = init2d;
726 else
727 {
729 "Dormand-Prince-7-4-5", std::array<double,3>{0,0,0});
731 cyl_field, dg::pid_control, dg::fast_l2norm, eps, 1e-10);
732 for( unsigned i=0; i<g2d->local().size(); i++)
733 {
734 // minus direction needs positive integration!
735 double phiM1 = phiM0 + deltaPhi;
736 std::array<double,3>
737 coords0{yy0[0][i],yy0[1][i],yy0[2][i]}, coords1;
738 odeint.integrate_in_domain( phiM0, coords0, phiM1,
739 coords1, deltaPhi, g2d->global(), eps);
740 yy1[0][i] = coords1[0], yy1[1][i] = coords1[1], yy1[2][i] =
741 coords1[2];
742 tempM.data()[i] = binary( yy1[0][i], yy1[1][i]);
743
744 // plus direction needs negative integration!
745 double phiP1 = phiP0 - deltaPhi;
746 coords0 = std::array<double,3>{xx0[0][i],xx0[1][i],xx0[2][i]};
747 odeint.integrate_in_domain( phiP0, coords0, phiP1,
748 coords1, -deltaPhi, g2d->global(), eps);
749 xx1[0][i] = coords1[0], xx1[1][i] = coords1[1], xx1[2][i] =
750 coords1[2];
751 tempP.data()[i] = binary( xx1[0][i], xx1[1][i]);
752 }
753 std::swap( yy0, yy1);
754 std::swap( xx0, xx1);
755 phiM0 += deltaPhi;
756 phiP0 -= deltaPhi;
757 }
758 dg::blas1::scal( tempM, unary( -(double)rep*deltaPhi ) );
759 dg::blas1::scal( tempP, unary( (double)rep*deltaPhi ) );
760 dg::blas1::axpby( 1., tempM, 1., minus2d[i0]);
761 dg::blas1::axpby( 1., tempP, 1., plus2d[i0]);
762 }
763 //now we have the plus and the minus filaments
764 int dims[3], periods[3], coords[3];
765 MPI_Cart_get( grid.communicator(), 3, dims, periods, coords);
766 unsigned coords2 = coords[2];
767 if( rounds == 0) //there is a limiter
768 {
769 for( unsigned i0=0; i0<grid.local().Nz(); i0++)
770 {
771 int idx = (int)(i0+coords2*grid.local().Nz()) - (int)p0;
772 if(idx>=0)
773 result[i0] = plus2d[idx];
774 else
775 result[i0] = minus2d[abs(idx)];
776 thrust::copy( result[i0].data().begin(), result[i0].data().end(),
777 vec3d.data().begin() + i0*g2d->local().size());
778 }
779 }
780 else //sum up plus2d and minus2d
781 {
782 for( unsigned i0=0; i0<Nz; i0++)
783 {
784 unsigned revi0 = (Nz - i0)%Nz; //reverted index
785 dg::blas1::axpby( 1., plus2d[i0], 0., result[i0]);
786 dg::blas1::axpby( 1., minus2d[revi0], 1., result[i0]);
787 }
788 dg::blas1::axpby( -1., init2d, 1., result[0]);
789 for( unsigned i0=0; i0<grid.local().Nz(); i0++)
790 {
791 int idx = ((int)i0 +coords2*grid.local().Nz()-(int)p0 + Nz)%Nz;
792 //shift index
793 thrust::copy( result[idx].data().begin(), result[idx].data().end(),
794 vec3d.data().begin() + i0*g2d->local().size());
795 }
796 }
797 return vec3d;
798}
799
800}//namespace geo
801}//namespace dg
void assign(const from_ContainerType &from, ContainerType &to, Params &&... ps)
static DG_DEVICE double cooY2d(double x, double y)
static DG_DEVICE double zero(double x)
static DG_DEVICE double cooX2d(double x, double y)
void copy(const ContainerTypeIn &source, ContainerTypeOut &target)
void axpby(get_value_type< ContainerType > alpha, const ContainerType1 &x, get_value_type< ContainerType > beta, ContainerType &y)
void scal(ContainerType &x, get_value_type< ContainerType > alpha)
void evaluate(ContainerType &y, BinarySubroutine f, Functor g, const ContainerType0 &x0, const ContainerTypes &...xs)
void pointwiseDot(get_value_type< ContainerType > alpha, const ContainerType1 &x1, const ContainerType2 &x2, get_value_type< ContainerType > beta, ContainerType &y)
void transfer(const MatrixType &x, AnotherMatrixType &y)
void symv(MatrixType &&M, const ContainerType1 &x, ContainerType2 &y)
static std::string bc2str(bc bcx)
PER
thrust::host_vector< real_type > evaluate(UnaryOp f, const RealGrid1d< real_type > &g)
whichMatrix
Enum for the use in Fieldaligned.
Definition: fieldaligned.h:17
ONE FullLimiter
Full Limiter means there is a limiter everywhere.
Definition: fieldaligned.h:31
MPI_Vector< thrust::host_vector< double > > fieldaligned_evaluate(const aProductMPIGeometry3d &grid, const CylindricalVectorLvl0 &vec, const BinaryOp &binary, const UnaryOp &unary, unsigned p0, unsigned rounds, double eps=1e-5)
Evaluate a 2d functor and transform to all planes along the fieldlines (MPI Version)
Definition: mpi_fieldaligned.h:695
@ zeroPlusT
transposed plus interpolation in the current plane
Definition: fieldaligned.h:24
@ einsMinus
minus interpolation in previous plane
Definition: fieldaligned.h:20
@ einsMinusT
transposed minus interpolation in next plane
Definition: fieldaligned.h:21
@ zeroMinusT
transposed minus interpolation in the current plane
Definition: fieldaligned.h:25
@ einsPlusT
transposed plus interpolation in previous plane
Definition: fieldaligned.h:19
@ zeroForw
from dg to transformed coordinates
Definition: fieldaligned.h:26
@ zeroMinus
minus interpolation in the current plane
Definition: fieldaligned.h:23
@ zeroPlus
plus interpolation in the current plane
Definition: fieldaligned.h:22
@ einsPlus
plus interpolation in next plane
Definition: fieldaligned.h:18
MPI_Vector< thrust::host_vector< real_type > > weights(const aRealMPITopology2d< real_type > &g)
cusp::coo_matrix< int, real_type, cusp::host_memory > interpolation(const thrust::host_vector< real_type > &x, const RealGrid1d< real_type > &g, dg::bc bcx=dg::NEU, std::string method="dg")
real_type interpolate(dg::space sp, const thrust::host_vector< real_type > &v, real_type x, const RealGrid1d< real_type > &g, dg::bc bcx=dg::NEU)
dg::MIHMatrix_t< real_type > projection(const aRealMPITopology2d< real_type > &g_new, const aRealMPITopology2d< real_type > &g_old, std::string method="dg")
CylindricalVectorLvl1 createBHat(const TokamakMagneticField &mag)
Contravariant components of the magnetic unit vector field and its Divergence and derivative in cylin...
Definition: magnetic_field.h:931
thrust::host_vector< real_type > forward_transform(const thrust::host_vector< real_type > &in, const aRealTopology2d< real_type > &g)
void transpose(unsigned nx, unsigned ny, const ContainerType &in, ContainerType &out)
bool is_same(double x, double y, double eps=1e-15)
dg::MIHMatrix_t< real_type > convert(const dg::IHMatrix_t< real_type > &global, const ConversionPolicy &policy)
dg::IHMatrix_t< real_type > convertGlobal2LocalRows(const dg::IHMatrix_t< real_type > &global, const ConversionPolicy &policy)
thrust::host_vector< real_type > pullback(const Functor &f, const aRealGeometryX2d< real_type > &g)
void assign3dfrom2d(const thrust::host_vector< real_type > &in2d, Container &out, const aRealTopology3d< real_type > &grid)
dg::IHMatrix_t< real_type > backproject(const RealGrid1d< real_type > &g)
dg::IHMatrix_t< real_type > inv_backproject(const RealGrid1d< real_type > &g)
void split(SharedContainer &in, std::vector< View< SharedContainer > > &out, const aRealTopology3d< real_type > &grid)
ContainerType volume(const SparseTensor< ContainerType > &t)
static auto pid_control
static auto fast_l2norm
typename TensorTraits< std::decay_t< Vector > >::execution_policy get_execution_policy
IHMatrix_t< double > IHMatrix
thrust::host_vector< double > HVec
const container & data() const
double diff() const
void toc()
void tic()
real_type hz() const
unsigned Nz() const
MPI_Comm communicator() const
const RealGrid3d< real_type > & local() const
aRealMPIGeometry2d< real_type > * perp_grid() const
Definition: fluxfunctions.h:412
This struct bundles a vector field and its divergence.
Definition: fluxfunctions.h:440
const CylindricalFunctor & z() const
z-component of the vector
Definition: fluxfunctions.h:470
dg::bc bcx() const
Definition: fieldaligned.h:484
const container & hbp() const
Distance between the planes .
Definition: fieldaligned.h:561
const container & bphi() const
bphi
Definition: fieldaligned.h:581
const container & bbp() const
Mask plus, 1 if fieldline intersects wall in plus direction but not in minus direction,...
Definition: fieldaligned.h:606
container evaluate(BinaryOp binary, UnaryOp unary, unsigned p0, unsigned rounds) const
Evaluate a 2d functor and transform to all planes along the fieldline
const container & sqrtG() const
Volume form (including weights) .
Definition: fieldaligned.h:566
void operator()(enum whichMatrix which, const container &in, container &out)
Apply the interpolation to three-dimensional vectors.
const container & sqrtGm() const
Volume form on minus plane (including weights) .
Definition: fieldaligned.h:571
void set_boundaries(dg::bc bcz, double left, double right)
Set boundary conditions in the limiter region.
Definition: fieldaligned.h:501
std::string method() const
Return the interpolation_method string given in the constructor.
Definition: fieldaligned.h:671
const container & hbm() const
Distance between the planes and the boundary .
Definition: fieldaligned.h:556
const container & bphiM() const
bphi on minus plane
Definition: fieldaligned.h:586
dg::bc bcy() const
Definition: fieldaligned.h:487
double deltaPhi() const
Definition: fieldaligned.h:553
Fieldaligned()
do not allocate memory; no member call except construct is valid
Definition: fieldaligned.h:436
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: fieldaligned.h:478
const container & bbo() const
Mask both, 1 if fieldline intersects wall in plus direction and in minus direction,...
Definition: fieldaligned.h:601
const container & bbm() const
Mask minus, 1 if fieldline intersects wall in minus direction but not in plus direction,...
Definition: fieldaligned.h:596
const container & sqrtGp() const
Volume form on plus plane (including weights) .
Definition: fieldaligned.h:576
const container & bphiP() const
bphi on plus plane
Definition: fieldaligned.h:591
const ProductGeometry & grid() const
Grid used for construction.
Definition: fieldaligned.h:610
A tokamak field as given by R0, Psi and Ipol plus Meta-data like shape and equilibrium.
Definition: magnetic_field.h:162