Extension: Geometries
#include "dg/geometries/geometries.h"
Loading...
Searching...
No Matches
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
11
12template <class ProductMPIGeometry, class MIMatrix, class LocalContainer>
13struct Fieldaligned< ProductMPIGeometry, MIMatrix, MPI_Vector<LocalContainer> >
14{
15 Fieldaligned(){}
16 template <class Limiter>
18 const ProductMPIGeometry& grid,
21 Limiter limit = FullLimiter(),
22 double eps = 1e-5,
23 unsigned mx=12, unsigned my=12,
24 double deltaPhi = -1, std::string interpolation_method = "linear-nearest",
25 bool benchmark = true):
26 Fieldaligned( dg::geo::createBHat(vec), grid, bcx, bcy, limit, eps,
27 mx, my, deltaPhi, interpolation_method, benchmark)
28 {
29 }
30 template <class Limiter>
32 const ProductMPIGeometry& grid,
35 Limiter limit = FullLimiter(),
36 double eps = 1e-5,
37 unsigned mx=12, unsigned my=12,
38 double deltaPhi = -1, std::string interpolation_method = "linear-nearest",
39 bool benchmark = true);
40 template<class ...Params>
41 void construct( Params&& ...ps)
42 {
43 //construct and swap
44 *this = Fieldaligned( std::forward<Params>( ps)...);
45 }
46
47 dg::bc bcx()const{
48 return m_bcx;
49 }
50 dg::bc bcy()const{
51 return m_bcy;
52 }
53
54 void set_boundaries( dg::bc bcz, double left, double right)
55 {
56 m_bcz = bcz;
57 dg::blas1::copy( left, m_left);
58 dg::blas1::copy( right, m_right);
59 }
60
61 void set_boundaries( dg::bc bcz, const MPI_Vector<LocalContainer>& left, const MPI_Vector<LocalContainer>& right)
62 {
63 m_bcz = bcz;
64 m_left = left;
65 m_right = right;
66 }
67
68 void set_boundaries( dg::bc bcz, const MPI_Vector<LocalContainer>& global, double scal_left, double scal_right)
69 {
70 dg::split( global, m_split_in, *m_g);
71 dg::blas1::axpby( scal_left, m_split_in[0], 0., m_left);
72 dg::blas1::axpby( scal_right, m_split_in[m_g->local().Nz()-1], 0., m_right);
73 m_bcz = bcz;
74 }
75
76 void operator()(enum whichMatrix which, const MPI_Vector<LocalContainer>& in, MPI_Vector<LocalContainer>& out) const;
77
78 double deltaPhi() const{return m_deltaPhi;}
79 const MPI_Vector<LocalContainer>& hbm()const {
80 return m_hbm;
81 }
82 const MPI_Vector<LocalContainer>& hbp()const {
83 return m_hbp;
84 }
85 const MPI_Vector<LocalContainer>& sqrtG()const {
86 return m_G;
87 }
88 const MPI_Vector<LocalContainer>& sqrtGm()const {
89 return m_Gm;
90 }
91 const MPI_Vector<LocalContainer>& sqrtGp()const {
92 return m_Gp;
93 }
94 const MPI_Vector<LocalContainer>& bphi()const {
95 return m_bphi;
96 }
97 const MPI_Vector<LocalContainer>& bphiM()const {
98 return m_bphiM;
99 }
100 const MPI_Vector<LocalContainer>& bphiP()const {
101 return m_bphiP;
102 }
103 const MPI_Vector<LocalContainer>& bbm()const {
104 return m_bbm;
105 }
106 const MPI_Vector<LocalContainer>& bbo()const {
107 return m_bbo;
108 }
109 const MPI_Vector<LocalContainer>& bbp()const {
110 return m_bbp;
111 }
112 const ProductMPIGeometry& grid() const{return *m_g;}
113
114 template< class BinaryOp, class UnaryOp>
115 MPI_Vector<LocalContainer> evaluate( BinaryOp f, UnaryOp g, unsigned p0,
116 unsigned rounds) const;
117 std::string method() const{return m_interpolation_method;}
118 private:
119 void ePlus( enum whichMatrix which, const MPI_Vector<LocalContainer>& in, MPI_Vector<LocalContainer>& out) const;
120 void eMinus(enum whichMatrix which, const MPI_Vector<LocalContainer>& in, MPI_Vector<LocalContainer>& out) const;
121 void zero(enum whichMatrix which, const MPI_Vector<LocalContainer>& in, MPI_Vector<LocalContainer>& out) const;
122 MIMatrix m_plus, m_zero, m_minus; //2d interpolation matrices
123 mutable MIMatrix m_plusT, m_minusT; // only allocated if necessary
124 // backproject
125 typename detail::Container2EllSparseBlockMat<LocalContainer>::type m_bx, m_by, m_inv_bx, m_inv_by;
126 bool apply_backproject = false, apply_inv_backproject = false;
127 mutable MPI_Vector<LocalContainer> m_temp0, m_temp1; // local 3d size
128 //
129 MPI_Vector<LocalContainer> m_hbm, m_hbp; //3d size
130 MPI_Vector<LocalContainer> m_G, m_Gm, m_Gp; //3d size
131 MPI_Vector<LocalContainer> m_bphi, m_bphiM, m_bphiP; //3d size
132 MPI_Vector<LocalContainer> m_bbm, m_bbp, m_bbo; //3d size
133
134 MPI_Vector<LocalContainer> m_left, m_right; //2d size
135 MPI_Vector<LocalContainer> m_limiter; //2d size
136 mutable MPI_Vector<LocalContainer> m_ghostM, m_ghostP; //2d size
137 mutable std::vector<MPI_Vector<dg::View<const LocalContainer>> > m_split_in;
138 mutable std::vector<MPI_Vector<dg::View<LocalContainer>> > m_split_out;
140 dg::bc m_bcx, m_bcy, m_bcz;
141 unsigned m_Nz, m_perp_size, m_mx, m_my;
142 double m_deltaPhi, m_eps;
143 std::string m_interpolation_method;
144 dg::geo::CylindricalVectorLvl1 m_vec; // to reconstruct adjoint
145 unsigned m_coords2, m_sizeZ; //number of processes in z
146 //we need to manually send data through the host for cuda-unaware-mpi
147 mutable thrust::host_vector<double> m_buffer; //2d size
148 dg::detail::MPIContiguousGather m_from_minus, m_from_plus;
149 mutable bool m_have_adjoint = false;
150 void updateAdjoint( ) const // only changes mutable m_have_adjoint and m_minusT, m_plusT
151 {
152 auto vol = dg::tensor::volume(m_g->metric()), vol2d0(vol);
153 auto vol2d = dg::split( vol, *m_g);
154 dg::assign( vol2d[0], vol2d0);
155 dg::ClonePtr<dg::aMPIGeometry2d> grid_transform( m_g->perp_grid()) ;
156 dg::ClonePtr<dg::aGeometry2d> global_grid_magnetic;
157 std::array<thrust::host_vector<double>,3> yp_trafo, ym_trafo;
158 thrust::host_vector<double> hbp, hbm;
159 thrust::host_vector<bool> in_boxp, in_boxm;
160
161 dg::MIHMatrix minus, zero, plus, minusT, plusT;
162 make_matrices( m_vec, grid_transform, global_grid_magnetic,
163 m_bcx, m_bcy, m_eps, m_mx, m_my, m_deltaPhi,
164 m_interpolation_method,
165 false, vol2d0, hbp, hbm,
166 in_boxp, in_boxm,
167 yp_trafo, ym_trafo,
168 minus, zero, plus, true, minusT, plusT
169 );
170 dg::blas2::transfer( minusT, m_minusT);
171 dg::blas2::transfer( plusT, m_plusT);
172 m_have_adjoint = true;
173 }
174
175 void make_matrices(
177 const dg::ClonePtr<dg::aMPIGeometry2d>& grid_transform,
178 dg::ClonePtr<dg::aGeometry2d>& global_grid_magnetic,
179 dg::bc bcx, dg::bc bcy, double eps,
180 unsigned mx, unsigned my,
181 double deltaPhi, std::string interpolation_method,
182 bool benchmark,
183 const MPI_Vector<thrust::host_vector<double>>& vol2d0,
184 thrust::host_vector<double>& hbp,
185 thrust::host_vector<double>& hbm,
186 thrust::host_vector<bool>& in_boxp,
187 thrust::host_vector<bool>& in_boxm,
188 std::array<thrust::host_vector<double>,3>& yp_trafo,
189 std::array<thrust::host_vector<double>,3>& ym_trafo,
190 dg::MIHMatrix& minus, dg::MIHMatrix& zero, dg::MIHMatrix& plus,
191 bool make_adjoint,
192 dg::MIHMatrix& minusT, dg::MIHMatrix& plusT
193 ) const
194 {
195 int rank;
196 MPI_Comm_rank( m_g->communicator(), &rank);
198 std::string inter_m, project_m, fine_m;
199 detail::parse_method( interpolation_method, inter_m, project_m, fine_m);
200 // For project method "const" we round up to the nearest multiple of n
201 if( project_m != "dg" && fine_m == "dg")
202 {
203 unsigned rx = mx % grid_transform->nx(), ry = my % grid_transform->ny();
204 if( 0 != rx || 0 != ry)
205 {
206 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";
207 mx = mx + grid_transform->nx() - rx;
208 my = my + grid_transform->ny() - ry;
209 }
210 }
211 if( benchmark && rank==0)
212 std::cout << "# Interpolation method: \""<<inter_m
213 << "\" projection method: \""<<project_m
214 <<"\" fine grid \""<<fine_m<<"\"\n";
216 // grid_trafo -> grid_equi -> grid_fine -> grid_equi -> grid_trafo
217 dg::Timer t;
218 if( benchmark) t.tic();
219 // We do not need metric of grid_equidist or or grid_fine
220 dg::ClonePtr<dg::aMPIGeometry2d> grid_magnetic = grid_transform;//INTEGRATE HIGH ORDER GRID
221 // grid_magnetic is only used for integrating in curvilinear coords
222 grid_magnetic->set( grid_transform->n() < 3 ? 4 : 7, grid_magnetic->Nx(), grid_magnetic->Ny());
223 global_grid_magnetic = grid_magnetic->global_geometry();
225 detail::integrate_all_fieldlines2d( vec, *global_grid_magnetic,
226 grid_transform->local(), yp_trafo, vol2d0.data(), hbp, in_boxp,
227 deltaPhi, eps);
228 detail::integrate_all_fieldlines2d( vec, *global_grid_magnetic,
229 grid_transform->local(), ym_trafo, vol2d0.data(), hbm, in_boxm,
230 -deltaPhi, eps);
231 if( benchmark)
232 {
233 t.toc();
234 if(rank==0) std::cout << "# DS: Fieldline integration took: "<<t.diff()<<"\n";
235 t.tic();
236 }
237 // Assemble minus, zero and plus through sub-grids
238 // The idea for the sub-grids is that the fine interpolation matrix takes
239 // up a large chunk of memory which can be avoided by sub-dividing the
240 // fine grid along its rows
241 dg::IHMatrix local_plus, local_zero, local_minus;
242 dg::IHMatrix interpolate, zero_interpolate, projection;
243 for( unsigned sub = 0; sub < grid_transform->local().Ny(); sub++)
244 {
245 dg::RealGrid2d<double> grid_fine_sub( grid_transform->local());
246 grid_fine_sub = dg::RealGrid2d<double>(
247 grid_fine_sub.x0(),
248 grid_fine_sub.x1(),
249 grid_fine_sub.y0() + sub*grid_fine_sub.hy(),
250 // Fix: construction bug The local right boundary should be the same as the global right boundary
251 sub == grid_transform->local().Ny()-1 ? grid_fine_sub.y1() :
252 grid_fine_sub.y0() + (sub+1)*grid_fine_sub.hy(),
253 grid_fine_sub.n(), grid_fine_sub.Nx(), 1,
254 grid_fine_sub.bcx(), grid_fine_sub.bcy());
255
256 // We only need grid_fine_local and grid_equidist_global:
257 // multiplying cell numbers on an MPI grid would redistribute
258 // points for non-equipartition. So we make them RealGrid
259 dg::RealGrid2d<double> grid_equidist_global( grid_transform->global()) ;
260 grid_equidist_global.set( 1, grid_equidist_global.shape(0), grid_equidist_global.shape(1));
261 if( fine_m == "equi")
262 grid_fine_sub.set( 1, grid_fine_sub.shape(0), grid_fine_sub.shape(1));
263 grid_fine_sub.multiplyCellNumbers((double)mx, (double)my);
264 std::array<thrust::host_vector<double>,3> yp, ym;
265 dg::HVec Xf = dg::evaluate( dg::cooX2d, grid_fine_sub);
266 dg::HVec Yf = dg::evaluate( dg::cooY2d, grid_fine_sub);
267 // interpolate matrix is same in all sub the rows just shift ...
268 unsigned shift = grid_transform->local().shape(0) * grid_transform->n();
269 unsigned global_shift = grid_transform->global().shape(0) * grid_transform->n();
270 if( sub <= 1 || sub >= grid_transform->local().Ny() - 2 || grid_transform->n() < 3) // in latter case boundary conditions could destroy invariance
271 {
273 grid_transform->local(), dg::NEU, dg::NEU, grid_transform->n() < 3 ? "cubic" : "dg");
274 zero_interpolate = dg::create::interpolation( Xf, Yf,
275 inter_m == "dg" ? grid_transform->global() :
276 grid_equidist_global, bcx, bcy, inter_m);
277 }
278 else
279 {
280 dg::blas1::plus( interpolate.column_indices(), shift);
281 dg::blas1::plus( zero_interpolate.column_indices(), global_shift);
282 }
283
284 yp.fill(dg::evaluate( dg::zero, grid_fine_sub));
285 ym = yp;
286 for( int i=0; i<2; i++)
287 {
288 dg::blas2::symv( interpolate, yp_trafo[i], yp[i]);
289 dg::blas2::symv( interpolate, ym_trafo[i], ym[i]);
290 }
292 if( sub <= 1 || sub >= grid_transform->local().Ny() -2 )
293 {
294 if( project_m == "dg")
295 {
296 // Note that it is possible to project onto a bigger grid, the corresponding rows are just empty
297 projection = dg::create::projection( grid_transform->global(), grid_fine_sub);
298 }
299 else
300 {
301 projection =
302 dg::create::projection( grid_equidist_global, grid_fine_sub, project_m);
303 }
304 }
305 else
306 {
307 // how to add to rows in csr formatted matrix:
308 projection.row_offsets().insert( projection.row_offsets().begin(),
309 global_shift, 0);
310 projection.row_offsets().erase( projection.row_offsets().end() -
311 global_shift, projection.row_offsets().end());
312 }
313
314 std::array<dg::HVec*,3> xcomp{ &yp[0], &Xf, &ym[0]};
315 std::array<dg::HVec*,3> ycomp{ &yp[1], &Yf, &ym[1]};
316 std::array<dg::IHMatrix*,3> result{ &local_plus, &local_zero, &local_minus};
317 dg::IHMatrix subresult;
318
319 for( unsigned u=0; u<3; u++)
320 {
321 if( u == 1)
322 subresult = projection*zero_interpolate;
323 else
324 subresult = projection*dg::create::interpolation( *xcomp[u], *ycomp[u],
325 inter_m == "dg" ? grid_transform->global() :
326 grid_equidist_global, bcx, bcy, inter_m);
327 detail::add_from_sub( *result[u], subresult, project_m);
328 }
329 }
330 if( benchmark)
331 {
332 t.toc();
333 if(rank==0) std::cout << "# DS: Assembly of matrices took: "<<t.diff()<<"\n";
334 t.tic();
335 }
336 // Now convert to MPI matrices
337 std::array<dg::IHMatrix*,3> input{ &local_plus, &local_zero, &local_minus};
338 std::array<MIHMatrix*,3> result{ &plus, &zero, &minus};
339 std::array<MIHMatrix*,3> resultT{ &plusT, &zero, &minusT};
340 for( unsigned u=0; u<3; u++)
341 {
342 // important! only convert after addition (else the addition is wrong for linear projection)
343 *input[u] = dg::convertGlobal2LocalRows( *input[u], *grid_transform);
344 *result[u] = dg::make_mpi_matrix( *input[u], *grid_transform);
345 if( make_adjoint and u != 1)
346 {
347 dg::IHMatrix inputT = input[u]->transpose();
348 // inputT is column distributed
349 // inputT has global rows and local column indices
350 dg::convertLocal2GlobalCols( inputT, *grid_transform);
351 // now inputT has global rows and global column indices
352 auto mat = dg::convertGlobal2LocalRows( inputT, *grid_transform);
353 // now mat is row distributed with global column indices
354 *resultT[u] = dg::make_mpi_matrix( mat, *grid_transform);
355 }
356 }
357 if( benchmark)
358 {
359 t.toc();
360 if(rank==0)
361 {
362 std::cout << "# DS: MPI conversion took: "<<t.diff()<<"\n";
363 std::streamsize ss = std::cout.precision();
364 std::cout << std::setprecision(1) << std::fixed;
365 std::cout << "# DS: Average nnz per row inner (plus | zero | minus): "
366 <<(double)plus.inner_matrix().num_nnz()/(double)plus.inner_matrix().num_rows()<<" | "
367 <<(double)zero.inner_matrix().num_nnz()/(double)zero.inner_matrix().num_rows()<<" | "
368 <<(double)minus.inner_matrix().num_nnz()/(double)minus.inner_matrix().num_rows()<<"\n";
369 if( plus.outer_matrix().num_nnz() != 0)
370 std::cout << "# DS: Average nnz per row outer (plus | zero | minus): "
371 <<(double)plus.outer_matrix().num_nnz()/(double)plus.outer_matrix().num_rows()<<" | "
372 <<(double)zero.outer_matrix().num_nnz()/(double)zero.outer_matrix().num_rows()<<" | "
373 <<(double)minus.outer_matrix().num_nnz()/(double)minus.outer_matrix().num_rows()<<"\n";
374 std::cout << std::defaultfloat << std::setprecision(ss);
375 }
376 }
377 } // make_matrices
378};
380template<class MPIGeometry, class MIMatrix, class LocalContainer>
381template <class Limiter>
382Fieldaligned<MPIGeometry, MIMatrix, MPI_Vector<LocalContainer> >::Fieldaligned(
384 const MPIGeometry& grid,
385 dg::bc bcx, dg::bc bcy, Limiter limit, double eps,
386 unsigned mx, unsigned my,
387 double deltaPhi, std::string interpolation_method, bool benchmark
388 ):
389 m_g(grid), m_bcx(bcx), m_bcy(bcy), m_bcz(grid.bcz()),
390 m_Nz( grid.local().Nz()), m_mx(mx), m_my(my), m_eps(eps),
391 m_interpolation_method(interpolation_method),
392 m_vec(vec)
393{
394 int rank;
395 MPI_Comm_rank( grid.communicator(), &rank);
396 int dims[3], periods[3], coords[3];
397 dg::mpi_cart_get( m_g->communicator(), 3, dims, periods, coords);
398 m_coords2 = coords[2], m_sizeZ = dims[2];
399
401 if( (grid.bcx() == PER && bcx != PER) || (grid.bcx() != PER && bcx == PER) )
402 throw( dg::Error(dg::Message(_ping_)<<"Fieldaligned: Got conflicting periodicity in x. The grid says "<<bc2str(grid.bcx())<<" while the parameter says "<<bc2str(bcx)));
403 if( (grid.bcy() == PER && bcy != PER) || (grid.bcy() != PER && bcy == PER) )
404 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)));
405 if( deltaPhi <=0) deltaPhi = grid.hz();
406 m_deltaPhi = deltaPhi; // store for evaluate
407
408 auto vol = dg::tensor::volume(grid.metric()), vol2d0(vol);
409 auto vol2d = dg::split( vol, grid);
410 dg::assign( vol2d[0], vol2d0);
411 dg::ClonePtr<dg::aMPIGeometry2d> grid_transform( grid.perp_grid()) ;
412 dg::ClonePtr<dg::aGeometry2d> global_grid_magnetic;
413 std::array<thrust::host_vector<double>,3> yp_trafo, ym_trafo;
414 thrust::host_vector<double> hbp, hbm;
415 thrust::host_vector<bool> in_boxp, in_boxm;
416
417 dg::MIHMatrix minus, zero, plus, minusT, plusT;
418 make_matrices( vec, grid_transform, global_grid_magnetic,
419 bcx, bcy, eps, mx, my, m_deltaPhi, interpolation_method,
420 benchmark, vol2d0, hbp, hbm,
421 in_boxp, in_boxm,
422 yp_trafo, ym_trafo,
423 minus, zero, plus, false, minusT, plusT
424 );
425 dg::blas2::transfer( minus, m_minus);
426 dg::blas2::transfer( zero, m_zero);
427 dg::blas2::transfer( plus, m_plus);
428 m_have_adjoint = false;
429
430 // 26.9.25: See performance comments on backproject on fieldaligned.h
431 std::string inter_m, project_m, fine_m;
432 detail::parse_method( interpolation_method, inter_m, project_m, fine_m);
433 if( project_m != "dg")
434 {
435 apply_inv_backproject = true; // from equidist to dg
436 m_inv_bx = dg::create::fast_transform( 0,
437 dg::invert(dg::create::detail::square_backproject( grid.local().grid(0))),
438 grid.local());
439 m_inv_by = dg::create::fast_transform( 1,
440 dg::invert(dg::create::detail::square_backproject( grid.local().grid(1))),
441 grid.local());
442 }
443 if( inter_m != "dg")
444 {
445 apply_backproject = true; // from dg to equidist
447 dg::create::detail::square_backproject( grid.local().grid(0)),
448 grid.local());
450 dg::create::detail::square_backproject( grid.local().grid(1)),
451 grid.local());
452 }
454 dg::HVec hbphi( yp_trafo[2]), hbphiP(hbphi), hbphiM(hbphi);
455 auto tmp = dg::pullback( vec.z(), *grid_transform);
456 hbphi = tmp.data();
457 //this is a pullback bphi( R(zeta, eta), Z(zeta, eta)):
458 if( dynamic_cast<const dg::CartesianMPIGrid2d*>( grid_transform.get()))
459 {
460 for( unsigned i=0; i<hbphiP.size(); i++)
461 {
462 hbphiP[i] = vec.z()(yp_trafo[0][i], yp_trafo[1][i]);
463 hbphiM[i] = vec.z()(ym_trafo[0][i], ym_trafo[1][i]);
464 }
465 }
466 else
467 {
468 dg::HVec Ihbphi = dg::pullback( vec.z(), *global_grid_magnetic);
469 dg::HVec Lhbphi = dg::forward_transform( Ihbphi, *global_grid_magnetic);
470 for( unsigned i=0; i<yp_trafo[0].size(); i++)
471 {
472 hbphiP[i] = dg::interpolate( dg::lspace, Lhbphi, yp_trafo[0][i],
473 yp_trafo[1][i], *global_grid_magnetic);
474 hbphiM[i] = dg::interpolate( dg::lspace, Lhbphi, ym_trafo[0][i],
475 ym_trafo[1][i], *global_grid_magnetic);
476 }
477 }
478 dg::assign3dfrom2d( dg::MHVec(hbphi, grid_transform->communicator()), m_bphi, grid);
479 dg::assign3dfrom2d( dg::MHVec(hbphiM, grid_transform->communicator()), m_bphiM, grid);
480 dg::assign3dfrom2d( dg::MHVec(hbphiP, grid_transform->communicator()), m_bphiP, grid);
481
482 dg::assign3dfrom2d( dg::MHVec(yp_trafo[2], grid_transform->communicator()), m_Gp, grid);
483 dg::assign3dfrom2d( dg::MHVec(ym_trafo[2], grid_transform->communicator()), m_Gm, grid);
484 MPI_Vector<LocalContainer> weights = dg::create::weights( grid);
485 m_G = vol;
486 dg::blas1::pointwiseDot( m_G, weights, m_G);
487 dg::blas1::pointwiseDot( m_Gp, weights, m_Gp);
488 dg::blas1::pointwiseDot( m_Gm, weights, m_Gm);
489
490 dg::assign( dg::evaluate( dg::zero, grid), m_hbm);
491 m_split_out = dg::split( m_hbm, grid); //3d vector
492 m_split_in = dg::split( (const MPI_Vector<LocalContainer>&)m_hbm, grid);
493 dg::assign3dfrom2d( dg::MHVec(hbp, grid_transform->communicator()), m_hbp, grid);
494 dg::assign3dfrom2d( dg::MHVec(hbm, grid_transform->communicator()), m_hbm, grid);
495 dg::blas1::scal( m_hbm, -1.);
496
497 m_temp0 = m_temp1 = m_hbm; // 3d size
499 thrust::host_vector<double> bbm( in_boxp.size(),0.), bbo(bbm), bbp(bbm);
500 for( unsigned i=0; i<in_boxp.size(); i++)
501 {
502 if( !in_boxp[i] && !in_boxm[i])
503 bbo[i] = 1.;
504 else if( !in_boxp[i] && in_boxm[i])
505 bbp[i] = 1.;
506 else if( in_boxp[i] && !in_boxm[i])
507 bbm[i] = 1.;
508 // else all are 0
509 }
510 dg::assign3dfrom2d( dg::MHVec(bbm, grid_transform->communicator()), m_bbm, grid);
511 dg::assign3dfrom2d( dg::MHVec(bbo, grid_transform->communicator()), m_bbo, grid);
512 dg::assign3dfrom2d( dg::MHVec(bbp, grid_transform->communicator()), m_bbp, grid);
513
514
516 m_perp_size = grid_transform->local().size();
517 dg::assign( dg::pullback(limit, *grid_transform), m_limiter);
518 dg::assign( dg::evaluate(dg::zero, *grid_transform), m_left);
519 m_ghostM = m_ghostP = m_right = m_left;
521 int source, dest;
522 dg::detail::MsgChunk chunk { 0, (int)m_perp_size};
523
524 dg::mpi_cart_shift( grid.comm(2), 0, +1, &source, &dest);
525 std::map<int, thrust::host_vector<dg::detail::MsgChunk>> recvMsgP =
526 {{ dest, thrust::host_vector<dg::detail::MsgChunk>( 1, chunk)}};
527 m_from_plus = dg::detail::MPIContiguousGather( recvMsgP, grid.comm(2));
528
529 dg::mpi_cart_shift( grid.comm(2), 0, -1, &source, &dest);
530 std::map<int, thrust::host_vector<dg::detail::MsgChunk>> recvMsgM =
531 {{ dest, thrust::host_vector<dg::detail::MsgChunk>( 1, chunk)}};
532 m_from_minus = dg::detail::MPIContiguousGather( recvMsgM, grid.comm(2));
533}
534
535
536template<class G, class M, class container>
537void Fieldaligned<G, M, MPI_Vector<container> >::operator()(enum
538 whichMatrix which, const MPI_Vector<container>& f,
539 MPI_Vector<container>& fe) const
540{
541 if( which == einsPlus || which == einsMinusT ) ePlus( which, f, fe);
542 else if(which == einsMinus || which == einsPlusT ) eMinus( which, f, fe);
543 else if(which == zeroMinus || which == zeroPlus ||
544 which == zeroMinusT|| which == zeroPlusT ||
545 which == zeroForw ) zero( which, f, fe);
546}
547template< class G, class M, class container>
548void Fieldaligned<G, M, MPI_Vector<container> >::zero( enum whichMatrix which, const MPI_Vector<container>& f, MPI_Vector<container>& f0) const
549{
550 dg::split( f, m_split_in, *m_g);
551 dg::split( f0, m_split_out, *m_g);
552 if( apply_backproject)
553 {
554 dg::blas2::symv( m_bx, f.data(), m_temp0.data());
555 dg::blas2::symv( m_by, m_temp0.data(), m_temp1.data());
556 dg::split( (const MPI_Vector<container>&)m_temp1, m_split_in, *m_g);
557 }
558 //1. compute 2d interpolation in every plane and store in m_split_out
559 for( unsigned i0=0; i0<m_Nz; i0++)
560 {
561 if(which == zeroPlus)
562 dg::blas2::symv( m_plus, m_split_in[i0], m_split_out[i0]);
563 else if(which == zeroMinus)
564 dg::blas2::symv( m_minus, m_split_in[i0], m_split_out[i0]);
565 else if(which == zeroPlusT)
566 {
567 if( ! m_have_adjoint) updateAdjoint( );
568 dg::blas2::symv( m_plusT, m_split_in[i0], m_split_out[i0]);
569 }
570 else if(which == zeroMinusT)
571 {
572 if( ! m_have_adjoint) updateAdjoint( );
573 dg::blas2::symv( m_minusT, m_split_in[i0], m_split_out[i0]);
574 }
575 else if( which == zeroForw)
576 {
577 if ( m_interpolation_method != "dg" )
578 {
579 dg::blas2::symv( m_zero, m_split_in[i0], m_split_out[i0]);
580 }
581 else
582 dg::blas1::copy( m_split_in[i0], m_split_out[i0]);
583 }
584 }
585 if( apply_inv_backproject)
586 {
587 dg::blas2::symv( m_inv_bx, f0.data(), m_temp0.data());
588 dg::blas2::symv( m_inv_by, m_temp0.data(), f0.data());
589 }
590}
591
592template<class G, class M, class container>
593void Fieldaligned<G,M, MPI_Vector<container> >::ePlus( enum whichMatrix which, const MPI_Vector<container>& f, MPI_Vector<container>& fpe ) const
594{
595 dg::split( f, m_split_in, *m_g);
596 dg::split( fpe, m_split_out, *m_g);
597 if( apply_backproject)
598 {
599 dg::blas2::symv( m_bx, f.data(), m_temp0.data());
600 dg::blas2::symv( m_by, m_temp0.data(), m_temp1.data());
601 dg::split( (const MPI_Vector<container>&)m_temp1, m_split_in, *m_g);
602 }
603 MPI_Vector<dg::View<container>> send_buf(
604 {m_ghostP.data().data(), m_ghostP.size()}, m_g->get_perp_comm());
605 //1. compute 2d interpolation in every plane and store in m_split_out
606 for( unsigned i0=0; i0<m_Nz; i0++)
607 {
608 // If communication necessary we write the symv result into send buffer
609 bool comm_plane = (m_sizeZ != 1 and i0 == m_Nz -1);
610 unsigned ip = (i0==m_Nz-1) ? 0:i0+1;
611 if(which == einsPlus)
612 dg::blas2::symv( m_plus, m_split_in[ip], comm_plane ? send_buf : m_split_out[i0]);
613 else if(which == einsMinusT)
614 {
615 if( ! m_have_adjoint) updateAdjoint( );
616 dg::blas2::symv( m_minusT, m_split_in[ip], comm_plane ? send_buf : m_split_out[i0]);
617 }
618 }
619
620 //2. communicate halo in z
621 if( m_sizeZ != 1)
622 {
623 unsigned i0 = m_Nz-1;
624 m_from_plus.global_gather_init( send_buf.data(), m_split_out[i0].data());
625 m_from_plus.global_gather_wait( m_split_out[i0].data());
626 }
627 if( apply_inv_backproject)
628 {
629 dg::blas2::symv( m_inv_bx, fpe.data(), m_temp0.data());
630 dg::blas2::symv( m_inv_by, m_temp0.data(), fpe.data());
631 }
632
633 //3. apply right boundary conditions in last plane
634 unsigned i0=m_Nz-1;
635 if( m_bcz != dg::PER && m_g->local().z1() == m_g->global().z1())
636 {
637 if( m_bcz == dg::DIR || m_bcz == dg::NEU_DIR)
638 dg::blas1::axpby( 2, m_right, -1., m_split_in[i0], m_ghostP);
639 if( m_bcz == dg::NEU || m_bcz == dg::DIR_NEU)
640 dg::blas1::axpby( m_deltaPhi, m_right, 1., m_split_in[i0], m_ghostP);
641 //interlay ghostcells with periodic cells: L*g + (1-L)*fpe
642 dg::blas1::axpby( 1., m_ghostP, -1., m_split_out[i0], m_ghostP);
643 dg::blas1::pointwiseDot( 1., m_limiter, m_ghostP, 1., m_split_out[i0]);
644 }
645}
646
647template<class G, class M, class container>
648void Fieldaligned<G, M, MPI_Vector<container> >::eMinus( enum
649 whichMatrix which, const MPI_Vector<container>& f, MPI_Vector<container>& fme ) const
650{
651 int rank;
652 MPI_Comm_rank(m_g->communicator(), &rank);
653 dg::split( f, m_split_in, *m_g);
654 dg::split( fme, m_split_out, *m_g);
655 if( apply_backproject)
656 {
657 dg::blas2::symv( m_bx, f.data(), m_temp0.data());
658 dg::blas2::symv( m_by, m_temp0.data(), m_temp1.data());
659 dg::split( (const MPI_Vector<container>&)m_temp1, m_split_in, *m_g);
660 }
661 MPI_Vector<dg::View<container>> send_buf(
662 {m_ghostM.data().data(), m_ghostM.size()}, m_g->get_perp_comm());
663 //1. compute 2d interpolation in every plane and store in m_split_out
664 for( unsigned i0=0; i0<m_Nz; i0++)
665 {
666 // If communication necessary we write the symv result into send buffer
667 bool comm_plane = (m_sizeZ != 1 and i0 == 0);
668 unsigned im = (i0==0) ? m_Nz-1:i0-1;
669 if(which == einsPlusT)
670 {
671 if( ! m_have_adjoint) updateAdjoint( );
672 dg::blas2::symv( m_plusT, m_split_in[im], comm_plane ? send_buf : m_split_out[i0]);
673 }
674 else if(which == einsMinus)
675 dg::blas2::symv( m_minus, m_split_in[im], comm_plane ? send_buf : m_split_out[i0]);
676 }
677
678 //2. communicate halo in z
679 if( m_sizeZ != 1)
680 {
681 unsigned i0 = 0;
682 m_from_minus.global_gather_init( send_buf.data(), m_split_out[i0].data());
683 m_from_minus.global_gather_wait( m_split_out[i0].data());
684 }
685 if( apply_inv_backproject)
686 {
687 dg::blas2::symv( m_inv_bx, fme.data(), m_temp0.data());
688 dg::blas2::symv( m_inv_by, m_temp0.data(), fme.data());
689 }
690
691 //3. apply left boundary conditions in first plane
692 unsigned i0=0;
693 if( m_bcz != dg::PER && m_g->local().z0() == m_g->global().z0())
694 {
695 if( m_bcz == dg::DIR || m_bcz == dg::DIR_NEU)
696 dg::blas1::axpby( 2., m_left, -1., m_split_in[i0], m_ghostM);
697 if( m_bcz == dg::NEU || m_bcz == dg::NEU_DIR)
698 dg::blas1::axpby( -m_deltaPhi, m_left, 1., m_split_in[i0], m_ghostM);
699 //interlay ghostcells with periodic cells: L*g + (1-L)*fme
700 dg::blas1::axpby( 1., m_ghostM, -1., m_split_out[i0], m_ghostM);
701 dg::blas1::pointwiseDot( 1., m_limiter, m_ghostM, 1., m_split_out[i0]);
702 }
703}
704
705template<class G, class M, class container>
706template< class BinaryOp, class UnaryOp>
707MPI_Vector<container> Fieldaligned<G,M, MPI_Vector<container> >::evaluate( BinaryOp binary, UnaryOp unary, unsigned p0, unsigned rounds) const
708{
709 //idea: simply apply I+/I- enough times on the init2d vector to get the result in each plane
710 //unary function is always such that the p0 plane is at x=0
711 assert( p0 < m_g->global().Nz());
712 const dg::ClonePtr<aMPIGeometry2d> g2d = m_g->perp_grid();
713 MPI_Vector<container> init2d = dg::pullback( binary, *g2d);
714 MPI_Vector<container> zero2d = dg::evaluate( dg::zero, *g2d);
715 unsigned globalNz = m_g->global().Nz();
716 typename detail::Container2EllSparseBlockMat<container>::type bx, by, inv_bx, inv_by;
717 if( apply_backproject)
718 {
720 dg::create::detail::square_backproject( g2d->local().grid(0)),
721 g2d->local());
723 dg::create::detail::square_backproject( g2d->local().grid(1)),
724 g2d->local());
725 }
726 if( apply_inv_backproject)
727 {
728 inv_bx = dg::create::fast_transform( 0,
729 dg::invert(dg::create::detail::square_backproject( g2d->local().grid(0))),
730 g2d->local());
731 inv_by = dg::create::fast_transform( 1,
732 dg::invert(dg::create::detail::square_backproject( g2d->local().grid(1))),
733 g2d->local());
734 }
735
736 MPI_Vector<container> temp(init2d), tempP(init2d), tempM(init2d);
737 MPI_Vector<container> vec3d = dg::evaluate( dg::zero, *m_g);
738 std::vector<MPI_Vector<container> > plus2d(globalNz, zero2d), minus2d(plus2d), result(plus2d);
739 unsigned turns = rounds;
740 if( turns ==0) turns++;
741 //first apply Interpolation many times, scale and store results
742 for( unsigned r=0; r<turns; r++)
743 for( unsigned i0=0; i0<globalNz; i0++)
744 {
745 dg::blas1::copy( init2d, tempP);
746 dg::blas1::copy( init2d, tempM);
747 unsigned rep = r*globalNz + i0;
748 for(unsigned k=0; k<rep; k++)
749 {
750 if( apply_backproject)
751 {
752 dg::blas2::symv( bx, tempP.data(), temp.data());
753 dg::blas2::symv( by, temp.data(), tempP.data());
754 dg::blas2::symv( bx, tempM.data(), temp.data());
755 dg::blas2::symv( by, temp.data(), tempM.data());
756 }
758 dg::blas2::symv( m_minus, tempP, temp);
759 if( apply_inv_backproject)
760 {
761 dg::blas2::symv( inv_bx, temp.data(), tempP.data());
762 dg::blas2::symv( inv_by, tempP.data(), temp.data());
763 }
764 temp.swap( tempP);
766 dg::blas2::symv( m_plus, tempM, temp);
767 if( apply_inv_backproject)
768 {
769 dg::blas2::symv( inv_bx, temp.data(), tempM.data());
770 dg::blas2::symv( inv_by, tempM.data(), temp.data());
771 }
772 temp.swap( tempM);
773 }
774 dg::blas1::scal( tempP, unary( (double)rep*m_deltaPhi ) );
775 dg::blas1::scal( tempM, unary( -(double)rep*m_deltaPhi ) );
776 dg::blas1::axpby( 1., tempP, 1., plus2d[i0]);
777 dg::blas1::axpby( 1., tempM, 1., minus2d[i0]);
778 }
779 //now we have the plus and the minus filaments
780 if( rounds == 0) //there is a limiter
781 {
782 for( unsigned i0=0; i0<m_Nz; i0++)
783 {
784 int idx = (int)(i0+m_coords2*m_Nz) - (int)p0;
785 if(idx>=0)
786 result[i0] = plus2d[idx];
787 else
788 result[i0] = minus2d[abs(idx)];
789 thrust::copy( result[i0].data().begin(), result[i0].data().end(),
790 vec3d.data().begin() + i0*m_perp_size);
791 }
792 }
793 else //sum up plus2d and minus2d
794 {
795 for( unsigned i0=0; i0<globalNz; i0++)
796 {
797 unsigned revi0 = (globalNz - i0)%globalNz; //reverted index
798 dg::blas1::axpby( 1., plus2d[i0], 0., result[i0]);
799 dg::blas1::axpby( 1., minus2d[revi0], 1., result[i0]);
800 }
801 dg::blas1::axpby( -1., init2d, 1., result[0]);
802 for(unsigned i0=0; i0<m_Nz; i0++)
803 {
804 int idx = ((int)i0 + m_coords2*m_Nz -(int)p0 + globalNz)%globalNz; //shift index
805 thrust::copy( result[idx].data().begin(), result[idx].data().end(),
806 vec3d.data().begin() + i0*m_perp_size);
807 }
808 }
809 return vec3d;
810}
811
812
814
815
819template<class BinaryOp, class UnaryOp>
821 const aProductMPIGeometry3d& grid,
822 const CylindricalVectorLvl0& vec,
823 const BinaryOp& binary,
824 const UnaryOp& unary,
825 unsigned p0,
826 unsigned rounds,
827 double eps = 1e-5)
828{
829 unsigned Nz = grid.Nz();
830 const dg::ClonePtr<aMPIGeometry2d> g2d = grid.perp_grid();
831 // Construct for field-aligned output
832 dg::MHVec vec3d = dg::evaluate( dg::zero, grid);
833 dg::MHVec tempP = dg::evaluate( dg::zero, *g2d), tempM( tempP);
834 std::vector<dg::MHVec> plus2d(Nz, tempP), minus2d(plus2d), result(plus2d);
835 dg::MHVec init2d = dg::pullback( binary, *g2d);
836 std::array<dg::HVec,3> yy0{
837 dg::evaluate( dg::cooX2d, g2d->local()),
838 dg::evaluate( dg::cooY2d, g2d->local()),
839 dg::evaluate( dg::zero, g2d->local())}, yy1(yy0), xx0( yy0), xx1(yy0); //s
840 dg::geo::detail::DSFieldCylindrical3 cyl_field(vec);
841 double deltaPhi = grid.hz();
842 double phiM0 = 0., phiP0 = 0.;
843 unsigned turns = rounds;
844 if( turns == 0) turns++;
845 for( unsigned r=0; r<turns; r++)
846 for( unsigned i0=0; i0<Nz; i0++)
847 {
848 unsigned rep = r*Nz + i0;
849 if( rep == 0)
850 tempM = tempP = init2d;
851 else
852 {
854 "Dormand-Prince-7-4-5", std::array<double,3>{0,0,0});
856 cyl_field, dg::pid_control, dg::fast_l2norm, eps, 1e-10);
857 for( unsigned i=0; i<g2d->local().size(); i++)
858 {
859 // minus direction needs positive integration!
860 double phiM1 = phiM0 + deltaPhi;
861 std::array<double,3>
862 coords0{yy0[0][i],yy0[1][i],yy0[2][i]}, coords1;
863 odeint.integrate_in_domain( phiM0, coords0, phiM1,
864 coords1, deltaPhi, g2d->global(), eps);
865 yy1[0][i] = coords1[0], yy1[1][i] = coords1[1], yy1[2][i] =
866 coords1[2];
867 tempM.data()[i] = binary( yy1[0][i], yy1[1][i]);
868
869 // plus direction needs negative integration!
870 double phiP1 = phiP0 - deltaPhi;
871 coords0 = std::array<double,3>{xx0[0][i],xx0[1][i],xx0[2][i]};
872 odeint.integrate_in_domain( phiP0, coords0, phiP1,
873 coords1, -deltaPhi, g2d->global(), eps);
874 xx1[0][i] = coords1[0], xx1[1][i] = coords1[1], xx1[2][i] =
875 coords1[2];
876 tempP.data()[i] = binary( xx1[0][i], xx1[1][i]);
877 }
878 std::swap( yy0, yy1);
879 std::swap( xx0, xx1);
880 phiM0 += deltaPhi;
881 phiP0 -= deltaPhi;
882 }
883 dg::blas1::scal( tempM, unary( -(double)rep*deltaPhi ) );
884 dg::blas1::scal( tempP, unary( (double)rep*deltaPhi ) );
885 dg::blas1::axpby( 1., tempM, 1., minus2d[i0]);
886 dg::blas1::axpby( 1., tempP, 1., plus2d[i0]);
887 }
888 //now we have the plus and the minus filaments
889 int dims[3], periods[3], coords[3];
890 mpi_cart_get( grid.communicator(), 3, dims, periods, coords);
891 unsigned coords2 = coords[2];
892 if( rounds == 0) //there is a limiter
893 {
894 for( unsigned i0=0; i0<grid.local().Nz(); i0++)
895 {
896 int idx = (int)(i0+coords2*grid.local().Nz()) - (int)p0;
897 if(idx>=0)
898 result[i0] = plus2d[idx];
899 else
900 result[i0] = minus2d[abs(idx)];
901 thrust::copy( result[i0].data().begin(), result[i0].data().end(),
902 vec3d.data().begin() + i0*g2d->local().size());
903 }
904 }
905 else //sum up plus2d and minus2d
906 {
907 for( unsigned i0=0; i0<Nz; i0++)
908 {
909 unsigned revi0 = (Nz - i0)%Nz; //reverted index
910 dg::blas1::axpby( 1., plus2d[i0], 0., result[i0]);
911 dg::blas1::axpby( 1., minus2d[revi0], 1., result[i0]);
912 }
913 dg::blas1::axpby( -1., init2d, 1., result[0]);
914 for( unsigned i0=0; i0<grid.local().Nz(); i0++)
915 {
916 int idx = ((int)i0 +coords2*grid.local().Nz()-(int)p0 + Nz)%Nz;
917 //shift index
918 thrust::copy( result[idx].data().begin(), result[idx].data().end(),
919 vec3d.data().begin() + i0*g2d->local().size());
920 }
921 }
922 return vec3d;
923}
924
925}//namespace geo
926}//namespace dg
DG_DEVICE double cooX2d(double x, double)
DG_DEVICE double cooY2d(double, double y)
DG_DEVICE T zero(T, Ts ...)
void copy(const ContainerTypeIn &source, ContainerTypeOut &target)
void axpby(value_type alpha, const ContainerType1 &x, value_type1 beta, ContainerType &y)
void pointwiseDot(value_type alpha, const ContainerType1 &x1, const ContainerType2 &x2, value_type1 beta, ContainerType &y)
void plus(ContainerType &x, value_type alpha)
void assign(const from_ContainerType &from, ContainerType &to, Params &&... ps)
void scal(ContainerType &x, value_type alpha)
void transfer(const MatrixType &x, AnotherMatrixType &y)
void symv(MatrixType &&M, const ContainerType1 &x, ContainerType2 &y)
std::string bc2str(bc bcx)
auto weights(const Topology &g)
auto evaluate(Functor &&f, const Topology &g)
EllSparseBlockMat< real_type, thrust::host_vector > fast_transform(unsigned coord, const dg::SquareMatrix< real_type > &opx, const aRealTopology< real_type, Nd > &t)
whichMatrix
Enum for the use in Fieldaligned.
Definition fieldaligned.h:16
thrust::host_vector< double > fieldaligned_evaluate(const aProductGeometry3d &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
Definition fieldaligned.h:1259
ONE FullLimiter
Full Limiter means there is a limiter everywhere.
Definition fieldaligned.h:30
dg::RealGrid< T, 2 > RealGrid2d
Topology::host_vector forward_transform(const typename Topology::host_vector &in, const Topology &g)
real_type interpolate(dg::space sp, const host_vector &v, real_type x, const RealGrid1d< real_type > &g, dg::bc bcx=dg::NEU)
dg::MIHMatrix_t< typename MPITopology::value_type > projection(const MPITopology &g_new, const MPITopology &g_old, std::string method="dg")
dg::SparseMatrix< int, real_type, thrust::host_vector > interpolation(const RecursiveHostVector &x, const aRealTopology< real_type, Nd > &g, std::array< dg::bc, Nd > bcx, std::string method="dg")
dg::SquareMatrix< T > invert(const dg::SquareMatrix< T > &in)
CylindricalVectorLvl1 createBHat(const TokamakMagneticField &mag)
Contravariant components of the magnetic unit vector field and its Divergence and derivative in cylin...
Definition magnetic_field.h:1154
void convertLocal2GlobalCols(dg::IHMatrix_t< real_type > &local, const ConversionPolicy &policy)
dg::IHMatrix_t< real_type > convertGlobal2LocalRows(const dg::IHMatrix_t< real_type > &global, const ConversionPolicy &row_policy)
dg::MIHMatrix_t< real_type > make_mpi_matrix(const dg::IHMatrix_t< real_type > &global_cols, const ConversionPolicy &col_policy)
Geometry::host_vector pullback(const Functor &f, const Geometry &g)
void assign3dfrom2d(const host_vector &in2d, Container &out, const Topology &grid)
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
thrust::host_vector< double > HVec
Cloneable * get()
const container & data() const
const LocalMatrixInner & inner_matrix() const
const LocalMatrixOuter & outer_matrix() const
SparseMatrix transpose() const
const Vector< Index > & column_indices() const
double diff() const
void toc()
void tic()
real_type hz() const
MPI_Comm communicator() const
unsigned Nz() const
const RealGrid< real_type, Nd > & local() const
aRealMPIGeometry2d< real_type > * perp_grid() const
Definition fluxfunctions.h:415
This struct bundles a vector field and its divergence.
Definition fluxfunctions.h:443
const CylindricalFunctor & z() const
z-component of the vector
Definition fluxfunctions.h:473
dg::bc bcx() const
Definition fieldaligned.h:363
const container & hbp() const
Distance between the planes .
Definition fieldaligned.h:440
const container & bphi() const
The contravariant phi component (3rd component) of the vector field .
Definition fieldaligned.h:460
const container & bbp() const
Mask plus, 1 if fieldline intersects wall in plus direction but not in minus direction,...
Definition fieldaligned.h:485
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:445
const container & sqrtGm() const
Volume form on minus plane (including weights) .
Definition fieldaligned.h:450
void set_boundaries(dg::bc bcz, double left, double right)
Set boundary conditions in the limiter region.
Definition fieldaligned.h:380
std::string method() const
Return the interpolation_method string given in the constructor.
Definition fieldaligned.h:550
const container & hbm() const
Distance between the planes and the boundary .
Definition fieldaligned.h:435
const container & bphiM() const
bphi on minus plane
Definition fieldaligned.h:465
dg::bc bcy() const
Definition fieldaligned.h:366
double deltaPhi() const
Definition fieldaligned.h:432
Fieldaligned()
do not allocate memory; no member call except construct is valid
Definition fieldaligned.h:315
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition fieldaligned.h:357
void operator()(enum whichMatrix which, const container &in, container &out) const
Apply the interpolation to three-dimensional vectors.
const container & bbo() const
Mask both, 1 if fieldline intersects wall in plus direction and in minus direction,...
Definition fieldaligned.h:480
const container & bbm() const
Mask minus, 1 if fieldline intersects wall in minus direction but not in plus direction,...
Definition fieldaligned.h:475
const container & sqrtGp() const
Volume form on plus plane (including weights) .
Definition fieldaligned.h:455
const container & bphiP() const
bphi on plus plane
Definition fieldaligned.h:470
const ProductGeometry & grid() const
Grid used for construction.
Definition fieldaligned.h:489
A tokamak field as given by R0, Psi and Ipol plus Meta-data like shape and equilibrium.
Definition magnetic_field.h:172