Extension: Geometries
#include "dg/geometries/geometries.h"
Loading...
Searching...
No Matches
fieldaligned.h
Go to the documentation of this file.
1#pragma once
2#include <cmath>
3#include <array>
4
5#include "dg/algorithm.h"
6#include "magnetic_field.h"
7#include "fluxfunctions.h"
8#include "curvilinear.h"
9
10namespace dg{
11namespace geo{
12
27
31
36namespace detail{
37
38template<class Container>
39struct Container2EllSparseBlockMat;
40
41// https://stackoverflow.com/questions/5052211/changing-value-type-of-a-given-stl-container
42template<class real_type, class ... Args, template <class...> class Vector>
43struct Container2EllSparseBlockMat<Vector<real_type, Args...>>
44{
46};
47
48static inline void parse_method( std::string method, std::string& i, std::string& p, std::string& f)
49{
50 f = "dg";
51 if( method == "dg") i = "dg", p = "dg";
52 else if( method == "linear") i = "linear", p = "dg";
53 else if( method == "cubic") i = "cubic", p = "dg";
54 else if( method == "nearest") i = "nearest", p = "dg";
55 else if( method == "dg-nearest") i = "dg", p = "nearest";
56 else if( method == "linear-nearest") i = "linear", p = "nearest";
57 else if( method == "cubic-nearest") i = "cubic", p = "nearest";
58 else if( method == "nearest-nearest") i = "nearest", p = "nearest";
59 else if( method == "dg-linear") i = "dg", p = "linear";
60 else if( method == "linear-linear") i = "linear", p = "linear";
61 else if( method == "cubic-linear") i = "cubic", p = "linear";
62 else if( method == "nearest-linear") i = "nearest", p = "linear";
63 else if( method == "dg-equi") i = "dg", p = "dg", f = "equi";
64 else if( method == "linear-equi") i = "linear", p = "dg", f = "equi";
65 else if( method == "cubic-equi") i = "cubic", p = "dg", f = "equi";
66 else if( method == "nearest-equi") i = "nearest", p = "dg", f = "equi";
67 else if( method == "dg-equi-nearest") i = "dg", p = "nearest", f = "equi";
68 else if( method == "linear-equi-nearest") i = "linear", p = "nearest", f = "equi";
69 else if( method == "cubic-equi-nearest") i = "cubic", p = "nearest", f = "equi";
70 else if( method == "nearest-equi-nearest") i = "nearest", p = "nearest", f = "equi";
71 else if( method == "dg-equi-linear") i = "dg", p = "linear", f = "equi";
72 else if( method == "linear-equi-linear") i = "linear", p = "linear", f = "equi";
73 else if( method == "cubic-equi-linear") i = "cubic", p = "linear", f = "equi";
74 else if( method == "nearest-equi-linear") i = "nearest", p = "linear", f = "equi";
75 else
76 throw Error( Message(_ping_) << "The method "<< method << " is not recognized\n");
77}
78
79struct DSFieldCylindrical3
80{
81 DSFieldCylindrical3( const dg::geo::CylindricalVectorLvl0& v): m_v(v){}
82 void operator()( double, const std::array<double,3>& y,
83 std::array<double,3>& yp) const {
84 double R = y[0], Z = y[1];
85 double vz = m_v.z()(R, Z);
86 yp[0] = m_v.x()(R, Z)/vz;
87 yp[1] = m_v.y()(R, Z)/vz;
88 yp[2] = 1./vz;
89 }
90 private:
92};
93
94struct DSFieldCylindrical4
95{
96 DSFieldCylindrical4( const dg::geo::CylindricalVectorLvl1& v): m_v(v){}
97 void operator()( double, const std::array<double,3>& y,
98 std::array<double,3>& yp) const {
99 double R = y[0], Z = y[1];
100 double vx = m_v.x()(R,Z);
101 double vy = m_v.y()(R,Z);
102 double vz = m_v.z()(R,Z);
103 double divvvz = m_v.divvvz()(R,Z);
104 yp[0] = vx/vz;
105 yp[1] = vy/vz;
106 yp[2] = divvvz*y[2];
107 }
108
109 private:
111};
112
113struct DSField
114{
115 DSField() = default;
116 //z component of v may not vanish
117 DSField( const dg::geo::CylindricalVectorLvl1& v,
118 const dg::aGeometry2d& g ):
119 m_g(g)
120 {
121 dg::HVec v_zeta, v_eta;
122 dg::pushForwardPerp( v.x(), v.y(), v_zeta, v_eta, g);
123 dg::HVec vx = dg::pullback( v.x(), g);
124 dg::HVec vy = dg::pullback( v.y(), g);
125 dg::HVec vz = dg::pullback( v.z(), g);
126 dg::HVec divvvz = dg::pullback( v.divvvz(), g);
127 dg::blas1::pointwiseDivide(v_zeta, vz, v_zeta);
128 dg::blas1::pointwiseDivide(v_eta, vz, v_eta);
129 dzetadphi_ = dg::forward_transform( v_zeta, g );
130 detadphi_ = dg::forward_transform( v_eta, g );
131 dvdphi_ = dg::forward_transform( divvvz, g );
132 }
133 //interpolate the vectors given in the constructor on the given point
134 void operator()(double, const std::array<double,3>& y, std::array<double,3>& yp) const
135 {
136 // shift point into domain
137 yp[0] = interpolate(dg::lspace, dzetadphi_, y[0], y[1], *m_g);
138 yp[1] = interpolate(dg::lspace, detadphi_, y[0], y[1], *m_g);
139 yp[2] = interpolate(dg::lspace, dvdphi_, y[0], y[1], *m_g)*y[2];
140 }
141 private:
142 thrust::host_vector<double> dzetadphi_, detadphi_, dvdphi_;
144};
145
146//used in constructor of Fieldaligned
147template<class real_type>
148void integrate_all_fieldlines2d( const dg::geo::CylindricalVectorLvl1& vec,
149 const dg::aRealGeometry2d<real_type>& grid_field,
150 const dg::aRealTopology2d<real_type>& grid_evaluate,
151 std::array<thrust::host_vector<real_type>,3>& yp,
152 const thrust::host_vector<double>& vol0,
153 thrust::host_vector<real_type>& yp2b,
154 thrust::host_vector<bool>& in_boxp,
155 real_type deltaPhi, real_type eps)
156{
157 //grid_field contains the global geometry for the field and the boundaries
158 //grid_evaluate contains the points to actually integrate
159 std::array<thrust::host_vector<real_type>,3> y{
160 dg::evaluate( dg::cooX2d, grid_evaluate),
161 dg::evaluate( dg::cooY2d, grid_evaluate),
162 vol0
163 };
164 yp.fill(dg::evaluate( dg::zero, grid_evaluate));
165 //construct field on high polynomial grid, then integrate it
166 dg::geo::detail::DSField field;
167 if( !dynamic_cast<const dg::CartesianGrid2d*>( &grid_field))
168 field = dg::geo::detail::DSField( vec, grid_field);
169
170 //field in case of cartesian grid
171 dg::geo::detail::DSFieldCylindrical4 cyl_field(vec);
172 const unsigned size = grid_evaluate.size();
174 "Dormand-Prince-7-4-5", std::array<real_type,3>{0,0,0});
176 if( dynamic_cast<const dg::CartesianGrid2d*>( &grid_field))
178 cyl_field, dg::pid_control, dg::fast_l2norm, eps, 1e-10);
179 else
181 field, dg::pid_control, dg::fast_l2norm, eps, 1e-10);
182
183 for( unsigned i=0; i<size; i++)
184 {
185 std::array<real_type,3> coords{y[0][i],y[1][i],y[2][i]}, coordsP;
186 //x,y,s
187 real_type phi1 = deltaPhi;
188 odeint.set_dt( deltaPhi/2.);
189 odeint.integrate( 0, coords, phi1, coordsP);
190 yp[0][i] = coordsP[0], yp[1][i] = coordsP[1], yp[2][i] = coordsP[2];
191 }
192 yp2b.assign( grid_evaluate.size(), deltaPhi); //allocate memory for output
193 in_boxp.resize( yp2b.size());
194 //Now integrate again but this time find the boundary distance
195 for( unsigned i=0; i<size; i++)
196 {
197 std::array<real_type,3> coords{y[0][i],y[1][i],y[2][i]}, coordsP;
198 in_boxp[i] = grid_field.contains( std::array{yp[0][i], yp[1][i]}) ? true : false;
199 if( false == in_boxp[i])
200 {
201 //x,y,s
202 real_type phi1 = deltaPhi;
203 odeint.integrate_in_domain( 0., coords, phi1, coordsP, 0., (const
204 dg::aRealTopology2d<real_type>&)grid_field, eps);
205 yp2b[i] = phi1;
206 }
207 }
208}
209
210// Add non-overlapping matrices from row blocks
211template<class real_type>
212void add_rowwise_from_sub( dg::IHMatrix_t<real_type>& mat, const dg::IHMatrix_t<real_type>& sub)
213{
214 // all matrices need same number of cols
215 if( sub.num_rows() != mat.num_rows())
216 throw dg::Error(dg::Message(_ping_)<<" Submatrix has "<<sub.num_rows()<<" but should have "<<mat.num_rows()<<" columns!");
217 if( sub.num_cols() != mat.num_cols())
218 throw dg::Error(dg::Message(_ping_)<<" Submatrix has "<<sub.num_cols()<<" but should have "<<mat.num_cols()<<" columns!");
219 dg::blas1::axpby( 1, sub.row_offsets(), 1, mat.row_offsets());
220 mat.column_indices().insert( mat.column_indices().end(),
221 sub.column_indices().begin(), sub.column_indices().end());
222 mat.values().insert( mat.values().end(),
223 sub.values().begin(), sub.values().end());
224}
225// Concatenate matrices from row blocks
226template<class real_type>
227void add_from_sub( dg::IHMatrix_t<real_type>& mat, const dg::IHMatrix_t<real_type>& sub, std::string method)
228{
229 if( mat.values().empty())
230 mat = sub;
231 else if( method != "linear")
232 add_rowwise_from_sub( mat, sub);
233 else
234 mat += sub;
235 return;
236}
237
238}//namespace detail
240
298
310template<class ProductGeometry, class IMatrix, class container >
312{
313
319 template <class Limiter>
321 const ProductGeometry& grid,
324 Limiter limit = FullLimiter(),
325 double eps = 1e-5,
326 unsigned mx=12, unsigned my=12,
327 double deltaPhi = -1,
328 std::string interpolation_method = "linear-nearest",
329 bool benchmark=true
330 ):
331 Fieldaligned( dg::geo::createBHat(vec),
332 grid, bcx, bcy, limit, eps, mx, my, deltaPhi, interpolation_method, benchmark)
333 {
334 }
335
339 template <class Limiter>
341 const ProductGeometry& grid,
344 Limiter limit = FullLimiter(),
345 double eps = 1e-5,
346 unsigned mx=12, unsigned my=12,
347 double deltaPhi = -1,
348 std::string interpolation_method = "linear-nearest",
349 bool benchmark=true
350 );
356 template<class ...Params>
357 void construct( Params&& ...ps)
358 {
359 //construct and swap
360 *this = Fieldaligned( std::forward<Params>( ps)...);
361 }
362
363 dg::bc bcx()const{
364 return m_bcx;
365 }
366 dg::bc bcy()const{
367 return m_bcy;
368 }
369
370
380 void set_boundaries( dg::bc bcz, double left, double right)
381 {
382 m_bcz = bcz;
383 const dg::Grid1d g2d( 0, 1, 1, m_perp_size);
384 m_left = dg::evaluate( dg::CONSTANT(left), g2d);
385 m_right = dg::evaluate( dg::CONSTANT(right),g2d);
386 }
387
397 void set_boundaries( dg::bc bcz, const container& left, const container& right)
398 {
399 m_bcz = bcz;
400 m_left = left;
401 m_right = right;
402 }
403
414 void set_boundaries( dg::bc bcz, const container& global, double scal_left, double scal_right)
415 {
416 dg::split( global, m_split_in, *m_g);
417 dg::blas1::axpby( scal_left, m_split_in[0], 0, m_left);
418 dg::blas1::axpby( scal_right, m_split_in[m_Nz-1], 0, m_right);
419 m_bcz = bcz;
420 }
421
430 void operator()(enum whichMatrix which, const container& in, container& out) const;
431
432 double deltaPhi() const{return m_deltaPhi;}
435 const container& hbm()const {
436 return m_hbm;
437 }
440 const container& hbp()const {
441 return m_hbp;
442 }
445 const container& sqrtG()const {
446 return m_G;
447 }
450 const container& sqrtGm()const {
451 return m_Gm;
452 }
455 const container& sqrtGp()const {
456 return m_Gp;
457 }
460 const container& bphi()const {
461 return m_bphi;
462 }
465 const container& bphiM()const {
466 return m_bphiM;
467 }
470 const container& bphiP()const {
471 return m_bphiP;
472 }
475 const container& bbm()const {
476 return m_bbm;
477 }
480 const container& bbo()const {
481 return m_bbo;
482 }
485 const container& bbp()const {
486 return m_bbp;
487 }
489 const ProductGeometry& grid()const{return *m_g;}
490
504 container interpolate_from_coarse_grid( const ProductGeometry& grid_coarse, const container& coarse) const;
514 void integrate_between_coarse_grid( const ProductGeometry& grid_coarse, const container& coarse, container& out ) const;
515
516
545 template< class BinaryOp, class UnaryOp>
546 container evaluate( BinaryOp binary, UnaryOp unary,
547 unsigned p0, unsigned rounds) const;
548
550 std::string method() const{return m_interpolation_method;}
551
552 private:
553 void ePlus( enum whichMatrix which, const container& in, container& out) const;
554 void eMinus(enum whichMatrix which, const container& in, container& out) const;
555 void zero( enum whichMatrix which, const container& in, container& out) const;
556 IMatrix m_plus, m_zero, m_minus; //2d interpolation matrices
557 mutable IMatrix m_plusT, m_minusT; // only allocated if necessary
558 // backproject
559 typename detail::Container2EllSparseBlockMat<container>::type m_bx, m_by, m_inv_bx, m_inv_by;
560 bool apply_backproject = false, apply_inv_backproject = false;
561 mutable container m_temp0, m_temp1; // 3d size
562 //
563 container m_hbm, m_hbp; //3d size
564 container m_G, m_Gm, m_Gp; // 3d size
565 container m_bphi, m_bphiM, m_bphiP; // 3d size
566 container m_bbm, m_bbp, m_bbo; //3d size masks
567
568 container m_left, m_right; //perp_size
569 container m_limiter; //perp_size
570 mutable container m_ghostM, m_ghostP; //perp_size
571 unsigned m_Nz, m_perp_size;
572 dg::bc m_bcx, m_bcy, m_bcz;
573 mutable std::vector<dg::View<const container>> m_split_in;
574 mutable std::vector<dg::View< container>> m_split_out;
577 double m_deltaPhi;
578 std::string m_interpolation_method;
579
580 mutable bool m_have_adjoint = false;
581 void updateAdjoint( ) const // only changes mutable m_plusT, m_minusT, m_have_adjoint
582 {
583 m_plusT = m_plus.transpose();
584 m_minusT = m_minus.transpose();
585 m_have_adjoint = true;
586 }
587};
588
590
592template<class Geometry, class IMatrix, class container>
593template <class Limiter>
596 const Geometry& grid,
597 dg::bc bcx, dg::bc bcy, Limiter limit, double eps,
598 unsigned mx, unsigned my, double deltaPhi, std::string interpolation_method, bool benchmark) :
599 m_g(grid),
600 m_interpolation_method(interpolation_method)
601{
602
603 std::string inter_m, project_m, fine_m;
604 detail::parse_method( interpolation_method, inter_m, project_m, fine_m);
605 // For project method "const" we round up to the nearest multiple of n
606 if( project_m != "dg" && fine_m == "dg")
607 {
608 unsigned rx = mx % grid.nx(), ry = my % grid.ny();
609 if( 0 != rx || 0 != ry)
610 {
611 std::cerr << "#Warning: for projection method \"const\" mx and my "
612 <<mx<<" "<<my<<" must be multiples of nx and ny "
613 <<grid.nx()<<" "<<grid.ny()<<" ! Rounding up for you ...\n";
614 mx = mx + grid.nx() - rx;
615 my = my + grid.ny() - ry;
616 }
617 }
618 if( benchmark)
619 std::cout << "# Interpolation method: \""<<inter_m
620 << "\" projection method: \""<<project_m
621 <<"\" fine grid \""<<fine_m<<"\"\n";
623 if( (grid.bcx() == PER && bcx != PER) || (grid.bcx() != PER && bcx == PER) )
624 throw( dg::Error(dg::Message(_ping_)<<"Fieldaligned: Got conflicting periodicity in x. The grid says "<<bc2str(grid.bcx())<<" while the parameter says "<<bc2str(bcx)));
625 if( (grid.bcy() == PER && bcy != PER) || (grid.bcy() != PER && bcy == PER) )
626 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)));
627 m_Nz=grid.Nz(), m_bcx = bcx, m_bcy = bcy, m_bcz=grid.bcz();
628 if( deltaPhi <=0) deltaPhi = grid.hz();
630 // grid_trafo -> grid_equi -> grid_fine -> grid_equi -> grid_trafo
631 dg::Timer t;
632 if( benchmark) t.tic();
633 dg::ClonePtr<dg::aGeometry2d> grid_transform( grid.perp_grid()) ;
635 std::array<thrust::host_vector<double>,3> yp_trafo, ym_trafo;
636 thrust::host_vector<bool> in_boxp, in_boxm;
637 thrust::host_vector<double> hbp, hbm;
638 thrust::host_vector<double> vol = dg::tensor::volume(grid.metric()), vol2d0;
639 auto vol2d = dg::split( vol, grid);
640 dg::assign( vol2d[0], vol2d0);
641 dg::ClonePtr<dg::aGeometry2d> grid_magnetic = grid_transform;//INTEGRATE HIGH ORDER GRID
642 // grid_magnetic is only used for integrating in curvilinear coords
643 grid_magnetic->set( grid_transform->n() < 3 ? 4 : 7, grid_magnetic->Nx(), grid_magnetic->Ny());
644 detail::integrate_all_fieldlines2d( vec, *grid_magnetic, *grid_transform,
645 yp_trafo, vol2d0, hbp, in_boxp, deltaPhi, eps);
646 detail::integrate_all_fieldlines2d( vec, *grid_magnetic, *grid_transform,
647 ym_trafo, vol2d0, hbm, in_boxm, -deltaPhi, eps);
648 if( benchmark)
649 {
650 t.toc();
651 std::cout << "# DS: Fieldline integration took: "<<t.diff()<<"\n";
652 t.tic();
653 }
654 // Assemble minus, zero and plus through sub-grids
655 // The idea for the sub-grids is that the fine interpolation matrix takes
656 // up a large chunk of memory which can be avoided by sub-dividing the
657 // fine grid along its rows
658 dg::IHMatrix plus, zero, minus;
659 dg::IHMatrix interpolate, zero_interpolate, projection;
660 for( unsigned sub = 0; sub < grid_transform->Ny(); sub++)
661 {
662 dg::RealGrid2d<double> grid_fine_sub(
663 grid_transform->x0(),
664 grid_transform->x1(),
665 grid_transform->y0() + sub*grid_transform->hy(),
666 // Fix: construction bug The local right boundary should be the same as the global right boundary
667 sub == grid_transform->Ny()-1 ? grid_transform->y1() :
668 grid_transform->y0() + (sub+1)*grid_transform->hy(),
669 grid_transform->n(), grid_transform->Nx(), 1,
670 grid_transform->bcx(), grid_transform->bcy());
671 // We do not need metric of grid_equidist or of grid_fine
672 dg::RealGrid2d<double> grid_equidist( *grid_transform) ;
673 grid_equidist.set( 1, grid_transform->shape(0), grid_transform->shape(1));
674 if( fine_m == "equi")
675 grid_fine_sub.set( 1, grid_fine_sub.shape(0), grid_fine_sub.shape(1));
676 grid_fine_sub.multiplyCellNumbers((double)mx, (double)my);
677 std::array<thrust::host_vector<double>,3> yp, ym;
678 dg::HVec Xf = dg::evaluate( dg::cooX2d, grid_fine_sub);
679 dg::HVec Yf = dg::evaluate( dg::cooY2d, grid_fine_sub);
680 // interpolate matrix is same in all sub the rows just shift ...
681 unsigned shift = grid_transform->shape(0) * grid_transform->n();
682 if( sub <= 1 || sub >= grid_transform->Ny() - 2 || grid_transform->n() < 3) // in latter case boundary conditions could destroy invariance
683 {
685 *grid_transform, dg::NEU, dg::NEU, grid_transform->n() < 3 ? "cubic" : "dg");
686 zero_interpolate = dg::create::interpolation( Xf, Yf,
687 inter_m == "dg" ? dg::RealGrid2d<double>(*grid_transform) :
688 grid_equidist, bcx, bcy, inter_m);
689 }
690 else
691 {
692 dg::blas1::plus( interpolate.column_indices(), shift);
693 dg::blas1::plus( zero_interpolate.column_indices(), shift);
694 }
695 yp.fill(dg::evaluate( dg::zero, grid_fine_sub));
696 ym = yp;
697 for( int i=0; i<2; i++) //only R and Z get interpolated
698 {
699 dg::blas2::symv( interpolate, yp_trafo[i], yp[i]);
700 dg::blas2::symv( interpolate, ym_trafo[i], ym[i]);
701 }
703 if( sub <= 1 || sub >= grid_transform->Ny() -2 )
704 {
705 if( project_m == "dg")
706 {
707 // Note that it is possible to project onto a bigger grid, the corresponding rows are just empty
708 projection = dg::create::projection( *grid_transform, grid_fine_sub);
709 }
710 else
711 {
712 projection = dg::create::projection( grid_equidist,
713 grid_fine_sub, project_m);
714 }
715 }
716 else
717 {
718 // how to add to rows in csr formatted matrix:
719 projection.row_offsets().insert( projection.row_offsets().begin(),
720 shift, 0);
721 projection.row_offsets().erase( projection.row_offsets().end() -
722 shift, projection.row_offsets().end());
723 }
724 std::array<dg::HVec*,3> xcomp{ &yp[0], &Xf, &ym[0]};
725 std::array<dg::HVec*,3> ycomp{ &yp[1], &Yf, &ym[1]};
726 std::array<dg::IHMatrix*,3> result{ &plus, &zero, &minus};
727 dg::IHMatrix subresult;
728
729 for( unsigned u=0; u<3; u++)
730 {
731 if( u == 1)
732 subresult = projection*zero_interpolate;
733 else
734 subresult = projection*dg::create::interpolation( *xcomp[u], *ycomp[u],
735 inter_m == "dg" ? dg::RealGrid2d<double>(*grid_transform) :
736 grid_equidist, bcx, bcy, inter_m);
737 detail::add_from_sub( *result[u], subresult, project_m);
738 }
739 }
740 // 26.9.25: It turns out that directly sandwiching the interpolation
741 // matrices minus,zero,plus with B^{-1} I B makes the average number of
742 // non-zeros per row explode (for n=3 from 9 to up to 50 - 75!). Therefore
743 // it is faster to separately store B^{-1} and B and apply them before and
744 // after I. Separate benchmarks of B = Bx x By reveals that 2 of our
745 // sparseblockmat symv implementation (Bx and By separately) is faster than
746 // any attempt at merging the two kernels into one and certainly faster
747 // than the corresponding dg::IDMatrix symv kernel. In fact, the 2 symv
748 // kernels are almost as fast as just one axpby. So, here we go:
749 if( project_m != "dg")
750 {
751 apply_inv_backproject = true; // from equidist to dg
752 m_inv_bx = dg::create::fast_transform( 0,
753 dg::invert(dg::create::detail::square_backproject( grid.grid(0))),
754 grid);
755 m_inv_by = dg::create::fast_transform( 1,
756 dg::invert(dg::create::detail::square_backproject( grid.grid(1))),
757 grid);
758 }
759 if( inter_m != "dg")
760 {
761 apply_backproject = true; // from dg to equidist
763 dg::create::detail::square_backproject( grid.grid(0)),
764 grid);
766 dg::create::detail::square_backproject( grid.grid(1)),
767 grid);
768 }
769 dg::blas2::transfer( minus, m_minus);
770 dg::blas2::transfer( zero, m_zero);
771 dg::blas2::transfer( plus, m_plus);
772 m_have_adjoint = false;
773
774 if( benchmark)
775 {
776 t.toc();
777 std::cout << "# DS: Assembly of matrices took: "<<t.diff()<<"\n";
778 std::streamsize ss = std::cout.precision();
779 std::cout << std::setprecision(1) << std::fixed;
780 std::cout << "# DS: Average nnz per row (plus | zero | minus): "
781 //<<(double)backproject.num_nnz()/(double)backproject.num_rows()<<" | "
782 <<(double)plus.num_nnz()/(double)plus.num_rows()<<" | "
783 <<(double)zero.num_nnz()/(double)zero.num_rows()<<" | "
784 <<(double)minus.num_nnz()/(double)minus.num_rows()<<"\n";
785 std::cout << std::defaultfloat << std::setprecision(ss);
786 }
788 dg::HVec hbphi( yp_trafo[2]), hbphiP(hbphi), hbphiM(hbphi);
789 hbphi = dg::pullback( vec.z(), *grid_transform);
790 //this is a pullback bphi( R(zeta, eta), Z(zeta, eta)):
791 if( dynamic_cast<const dg::CartesianGrid2d*>( grid_transform.get()))
792 {
793 for( unsigned i=0; i<hbphiP.size(); i++)
794 {
795 hbphiP[i] = vec.z()(yp_trafo[0][i], yp_trafo[1][i]);
796 hbphiM[i] = vec.z()(ym_trafo[0][i], ym_trafo[1][i]);
797 }
798 }
799 else
800 {
801 dg::HVec Ihbphi = dg::pullback( vec.z(), *grid_magnetic);
802 dg::HVec Lhbphi = dg::forward_transform( Ihbphi, *grid_magnetic);
803 for( unsigned i=0; i<yp_trafo[0].size(); i++)
804 {
805 hbphiP[i] = dg::interpolate( dg::lspace, Lhbphi, yp_trafo[0][i],
806 yp_trafo[1][i], *grid_magnetic);
807 hbphiM[i] = dg::interpolate( dg::lspace, Lhbphi, ym_trafo[0][i],
808 ym_trafo[1][i], *grid_magnetic);
809 }
810 }
811 dg::assign3dfrom2d( hbphi, m_bphi, grid);
812 dg::assign3dfrom2d( hbphiM, m_bphiM, grid);
813 dg::assign3dfrom2d( hbphiP, m_bphiP, grid);
814
815 dg::assign3dfrom2d( yp_trafo[2], m_Gp, grid);
816 dg::assign3dfrom2d( ym_trafo[2], m_Gm, grid);
817 // The weights don't matter since they fall out in Div and Lap anyway
818 // But they are good for testing
819 m_G = vol;
820 container weights = dg::create::weights( grid);
821 dg::blas1::pointwiseDot( m_G, weights, m_G);
822 dg::blas1::pointwiseDot( m_Gp, weights, m_Gp);
823 dg::blas1::pointwiseDot( m_Gm, weights, m_Gm);
824
826 m_split_in = dg::split( (const container&)m_hbm, grid);
827 m_split_out = dg::split( m_hbm, grid);
828 dg::assign3dfrom2d( hbp, m_hbp, grid);
829 dg::assign3dfrom2d( hbm, m_hbm, grid);
830 dg::blas1::scal( m_hbm, -1.);
831
832 m_temp0 = m_temp1 = m_hbm; // 3d size
833
835 thrust::host_vector<double> bbm( in_boxp.size(),0.), bbo(bbm), bbp(bbm);
836 for( unsigned i=0; i<in_boxp.size(); i++)
837 {
838 if( !in_boxp[i] && !in_boxm[i])
839 bbo[i] = 1.;
840 else if( !in_boxp[i] && in_boxm[i])
841 bbp[i] = 1.;
842 else if( in_boxp[i] && !in_boxm[i])
843 bbm[i] = 1.;
844 // else all are 0
845 }
846 dg::assign3dfrom2d( bbm, m_bbm, grid);
847 dg::assign3dfrom2d( bbo, m_bbo, grid);
848 dg::assign3dfrom2d( bbp, m_bbp, grid);
849
850 m_deltaPhi = deltaPhi; // store for evaluate
851
853 m_perp_size = grid_transform->size();
854 dg::assign( dg::pullback(limit, *grid_transform), m_limiter);
855 dg::assign( dg::evaluate(dg::zero, *grid_transform), m_left);
856 m_ghostM = m_ghostP = m_right = m_left;
857}
858
859
860template<class G, class I, class container>
862 const G& grid, const container& in) const
863{
864 //I think we need grid as input to split input vector and we need to interpret
865 //the grid nodes as node centered not cell-centered!
866 //idea: apply I+/I- cphi - 1 times in each direction and then apply interpolation formula
867 assert( m_g->Nz() % grid.Nz() == 0);
868 unsigned Nz_coarse = grid.Nz(), Nz = m_g->Nz();
869 unsigned cphi = Nz / Nz_coarse;
870
871 container out = dg::evaluate( dg::zero, *m_g);
872 container helper = dg::evaluate( dg::zero, *m_g);
873 dg::split( helper, m_split_out, *m_g);
874 std::vector<dg::View< container>> out_split = dg::split( out, *m_g);
875 std::vector<dg::View< const container>> in_split = dg::split( in, grid);
876 if( apply_backproject)
877 {
878 dg::blas2::symv( m_bx, in, m_temp0);
879 dg::blas2::symv( m_by, m_temp0, m_temp1);
880 in_split = dg::split( m_temp1, grid);
881 }
882 for ( int i=0; i<(int)Nz_coarse; i++)
883 {
884 //1. copy input vector to appropriate place in output
885 dg::blas1::copy( in_split[i], out_split[i*cphi]);
886 dg::blas1::copy( in_split[i], m_split_out[i*cphi]);
887 }
888 //Step 1 needs to finish so that m_split_out contains values everywhere
889 //2. Now apply plus and minus T to fill in the rest
890 for ( int i=0; i<(int)Nz_coarse; i++)
891 {
892 for( int j=1; j<(int)cphi; j++)
893 {
895 dg::blas2::symv( m_minus, out_split[i*cphi+j-1], out_split[i*cphi+j]);
897 dg::blas2::symv( m_plus, m_split_out[(i*cphi+cphi+1-j)%Nz], m_split_out[i*cphi+cphi-j]);
898 }
899 }
900 //3. Now add up with appropriate weights
901 for( int i=0; i<(int)Nz_coarse; i++)
902 for( int j=1; j<(int)cphi; j++)
903 {
904 double alpha = (double)(cphi-j)/(double)cphi;
905 double beta = (double)j/(double)cphi;
906 dg::blas1::axpby( alpha, out_split[i*cphi+j], beta, m_split_out[i*cphi+j], out_split[i*cphi+j]);
907 }
908 if( apply_inv_backproject)
909 {
910 dg::blas2::symv( m_inv_bx, out, m_temp0);
911 dg::blas2::symv( m_inv_by, m_temp0, out);
912 }
913 return out;
914}
915template<class G, class I, class container>
916void Fieldaligned<G, I,container>::integrate_between_coarse_grid( const G& grid, const container& in, container& out) const
917{
918 // TODO: This function is missing a test
919 assert( m_g->Nz() % grid.Nz() == 0);
920 unsigned Nz_coarse = grid.Nz(), Nz = m_g->Nz();
921 unsigned cphi = Nz / Nz_coarse;
922
923 out = in;
924 container helperP( in), helperM(in), tempP(in), tempM(in);
925 typename detail::Container2EllSparseBlockMat<container>::type bx, by, inv_bx, inv_by;
926 if( apply_backproject)
927 {
929 dg::create::detail::square_backproject( grid.grid(0)),
930 grid);
932 dg::create::detail::square_backproject( grid.grid(1)),
933 grid);
934 }
935 if( apply_inv_backproject)
936 {
937 inv_bx = dg::create::fast_transform( 0,
938 dg::invert(dg::create::detail::square_backproject( grid.grid(0))),
939 grid);
940 inv_by = dg::create::fast_transform( 1,
941 dg::invert(dg::create::detail::square_backproject( grid.grid(1))),
942 grid);
943 }
944
945 //1. Apply plus and minus T and sum up
946 for( int j=1; j<(int)cphi; j++)
947 {
948 if( apply_backproject)
949 {
950 dg::blas2::symv( bx, helperP, tempP);
951 dg::blas2::symv( by, tempP, helperP);
952 dg::blas2::symv( bx, helperM, tempM);
953 dg::blas2::symv( by, tempM, helperM);
954 }
956 dg::blas2::symv( m_minus, helperP, tempP);
957 if( apply_inv_backproject)
958 {
959 dg::blas2::symv( inv_bx, tempP, helperP);
960 dg::blas2::symv( inv_by, helperP, tempP);
961 }
962 dg::blas1::axpby( (double)(cphi-j)/(double)cphi, tempP, 1., out );
963 helperP.swap(tempP);
965 dg::blas2::symv( m_plus, helperM, tempM);
966 if( apply_inv_backproject)
967 {
968 dg::blas2::symv( inv_bx, tempM, helperM);
969 dg::blas2::symv( inv_by, helperM, tempM);
970 }
971 dg::blas1::axpby( (double)(cphi-j)/(double)cphi, tempM, 1., out );
972 helperM.swap(tempM);
973 }
974 dg::blas1::scal( out, 1./(double)cphi);
975}
976
977template<class G, class I, class container>
978void Fieldaligned<G, I, container >::operator()(enum whichMatrix which, const container& f, container& fe) const
979{
980 if( which == einsPlus || which == einsMinusT ) ePlus( which, f, fe);
981 else if(which == einsMinus || which == einsPlusT ) eMinus( which, f, fe);
982 else if(which == zeroMinus || which == zeroPlus ||
983 which == zeroMinusT|| which == zeroPlusT ||
984 which == zeroForw ) zero( which, f, fe);
985}
986
987template< class G, class I, class container>
988void Fieldaligned<G, I, container>::zero( enum whichMatrix which,
989 const container& f, container& f0) const
990{
991 dg::split( f, m_split_in, *m_g);
992 dg::split( f0, m_split_out, *m_g);
993 if( apply_backproject)
994 {
995 dg::blas2::symv( m_bx, f, m_temp0);
996 dg::blas2::symv( m_by, m_temp0, m_temp1);
997 dg::split( (const container&)m_temp1, m_split_in, *m_g);
998 }
999 //1. compute 2d interpolation in every plane and store in m_split_out
1000 for( unsigned i0=0; i0<m_Nz; i0++)
1001 {
1002 if(which == zeroPlus)
1003 dg::blas2::symv( m_plus, m_split_in[i0], m_split_out[i0]);
1004 else if(which == zeroMinus)
1005 dg::blas2::symv( m_minus, m_split_in[i0], m_split_out[i0]);
1006 else if(which == zeroPlusT)
1007 {
1008 if( ! m_have_adjoint) updateAdjoint( );
1009 dg::blas2::symv( m_plusT, m_split_in[i0], m_split_out[i0]);
1010 }
1011 else if(which == zeroMinusT)
1012 {
1013 if( ! m_have_adjoint) updateAdjoint( );
1014 dg::blas2::symv( m_minusT, m_split_in[i0], m_split_out[i0]);
1015 }
1016 else if( which == zeroForw)
1017 {
1018 if ( m_interpolation_method != "dg" )
1019 {
1020 dg::blas2::symv( m_zero, m_split_in[i0], m_split_out[i0]);
1021 }
1022 else
1023 dg::blas1::copy( m_split_in[i0], m_split_out[i0]);
1024 }
1025 }
1026 if( apply_inv_backproject)
1027 {
1028 dg::blas2::symv( m_inv_bx, f0, m_temp0);
1029 dg::blas2::symv( m_inv_by, m_temp0, f0);
1030 }
1031}
1032template< class G, class I, class container>
1033void Fieldaligned<G, I, container>::ePlus( enum whichMatrix which,
1034 const container& f, container& fpe) const
1035{
1036 dg::split( f, m_split_in, *m_g);
1037 dg::split( fpe, m_split_out, *m_g);
1038 if( apply_backproject)
1039 {
1040 dg::blas2::symv( m_bx, f, m_temp0);
1041 dg::blas2::symv( m_by, m_temp0, m_temp1);
1042 dg::split( (const container&)m_temp1, m_split_in, *m_g);
1043 }
1044 //1. compute 2d interpolation in every plane and store in m_split_out
1045 for( unsigned i0=0; i0<m_Nz; i0++)
1046 {
1047 unsigned ip = (i0==m_Nz-1) ? 0:i0+1;
1048 if(which == einsPlus)
1049 dg::blas2::symv( m_plus, m_split_in[ip], m_split_out[i0]);
1050 else if(which == einsMinusT)
1051 {
1052 if( ! m_have_adjoint) updateAdjoint( );
1053 dg::blas2::symv( m_minusT, m_split_in[ip], m_split_out[i0]);
1054 }
1055 }
1056 if( apply_inv_backproject)
1057 {
1058 dg::blas2::symv( m_inv_bx, fpe, m_temp0);
1059 dg::blas2::symv( m_inv_by, m_temp0, fpe);
1060 }
1061 //2. apply right boundary conditions in last plane
1062 unsigned i0=m_Nz-1;
1063 if( m_bcz != dg::PER)
1064 {
1065 dg::split( f, m_split_in, *m_g);
1066 if( m_bcz == dg::DIR || m_bcz == dg::NEU_DIR)
1067 dg::blas1::axpby( 2, m_right, -1., m_split_in[i0], m_ghostP);
1068 if( m_bcz == dg::NEU || m_bcz == dg::DIR_NEU)
1069 dg::blas1::axpby( m_deltaPhi, m_right, 1., m_split_in[i0], m_ghostP);
1070 //interlay ghostcells with periodic cells: L*g + (1-L)*fpe
1071 dg::blas1::axpby( 1., m_ghostP, -1., m_split_out[i0], m_ghostP);
1072 dg::blas1::pointwiseDot( 1., m_limiter, m_ghostP, 1., m_split_out[i0]);
1073 }
1074}
1075
1076template< class G, class I, class container>
1077void Fieldaligned<G, I, container>::eMinus( enum whichMatrix which,
1078 const container& f, container& fme) const
1079{
1080 dg::split( f, m_split_in, *m_g);
1081 dg::split( fme, m_split_out, *m_g);
1082 if( apply_backproject)
1083 {
1084 dg::blas2::symv( m_bx, f, m_temp0);
1085 dg::blas2::symv( m_by, m_temp0, m_temp1);
1086 dg::split( (const container&)m_temp1, m_split_in, *m_g);
1087 }
1088 //1. compute 2d interpolation in every plane and store in m_split_out
1089 for( unsigned i0=0; i0<m_Nz; i0++)
1090 {
1091 unsigned im = (i0==0) ? m_Nz-1:i0-1;
1092 if(which == einsPlusT)
1093 {
1094 if( ! m_have_adjoint) updateAdjoint( );
1095 dg::blas2::symv( m_plusT, m_split_in[im], m_split_out[i0]);
1096 }
1097 else if (which == einsMinus)
1098 dg::blas2::symv( m_minus, m_split_in[im], m_split_out[i0]);
1099 }
1100 if( apply_inv_backproject)
1101 {
1102 dg::blas2::symv( m_inv_bx, fme, m_temp0);
1103 dg::blas2::symv( m_inv_by, m_temp0, fme);
1104 }
1105 //2. apply left boundary conditions in first plane
1106 unsigned i0=0;
1107 if( m_bcz != dg::PER)
1108 {
1109 if( m_bcz == dg::DIR || m_bcz == dg::DIR_NEU)
1110 dg::blas1::axpby( 2., m_left, -1., m_split_in[i0], m_ghostM);
1111 if( m_bcz == dg::NEU || m_bcz == dg::NEU_DIR)
1112 dg::blas1::axpby( -m_deltaPhi, m_left, 1., m_split_in[i0], m_ghostM);
1113 //interlay ghostcells with periodic cells: L*g + (1-L)*fme
1114 dg::blas1::axpby( 1., m_ghostM, -1., m_split_out[i0], m_ghostM);
1115 dg::blas1::pointwiseDot( 1., m_limiter, m_ghostM, 1., m_split_out[i0]);
1116 }
1117}
1118
1119template<class G, class I, class container>
1120template< class BinaryOp, class UnaryOp>
1121container Fieldaligned<G, I,container>::evaluate( BinaryOp binary,
1122 UnaryOp unary, unsigned p0, unsigned rounds) const
1123{
1124 //idea: simply apply I+/I- enough times on the init2d vector to get the result in each plane
1125 //unary function is always such that the p0 plane is at x=0
1126 assert( p0 < m_g->Nz());
1127 const dg::ClonePtr<aGeometry2d> g2d = m_g->perp_grid();
1128 container init2d = dg::pullback( binary, *g2d);
1129 container zero2d = dg::evaluate( dg::zero, *g2d);
1130 typename detail::Container2EllSparseBlockMat<container>::type bx, by, inv_bx, inv_by;
1131 if( apply_backproject)
1132 {
1134 dg::create::detail::square_backproject( g2d->grid(0)),
1135 *g2d);
1137 dg::create::detail::square_backproject( g2d->grid(1)),
1138 *g2d);
1139 }
1140 if( apply_inv_backproject)
1141 {
1142 inv_bx = dg::create::fast_transform( 0,
1143 dg::invert(dg::create::detail::square_backproject( g2d->grid(0))),
1144 *g2d);
1145 inv_by = dg::create::fast_transform( 1,
1146 dg::invert(dg::create::detail::square_backproject( g2d->grid(1))),
1147 *g2d);
1148 }
1149
1150 container temp(init2d), tempP(init2d), tempM(init2d);
1151 container vec3d = dg::evaluate( dg::zero, *m_g);
1152 std::vector<container> plus2d(m_Nz, zero2d), minus2d(plus2d), result(plus2d);
1153 unsigned turns = rounds;
1154 if( turns ==0) turns++;
1155 //first apply Interpolation many times, scale and store results
1156 for( unsigned r=0; r<turns; r++)
1157 for( unsigned i0=0; i0<m_Nz; i0++)
1158 {
1159 dg::blas1::copy( init2d, tempP);
1160 dg::blas1::copy( init2d, tempM);
1161 unsigned rep = r*m_Nz + i0;
1162 for(unsigned k=0; k<rep; k++)
1163 {
1164 if( apply_backproject)
1165 {
1166 dg::blas2::symv( bx, tempP, temp);
1167 dg::blas2::symv( by, temp, tempP);
1168 dg::blas2::symv( bx, tempM, temp);
1169 dg::blas2::symv( by, temp, tempM);
1170 }
1172 dg::blas2::symv( m_minus, tempP, temp);
1173 if( apply_inv_backproject)
1174 {
1175 dg::blas2::symv( inv_bx, temp, tempP);
1176 dg::blas2::symv( inv_by, tempP, temp);
1177 }
1178 temp.swap( tempP);
1180 dg::blas2::symv( m_plus, tempM, temp);
1181 if( apply_inv_backproject)
1182 {
1183 dg::blas2::symv( inv_bx, temp, tempM);
1184 dg::blas2::symv( inv_by, tempM, temp);
1185 }
1186 temp.swap( tempM);
1187 }
1188 dg::blas1::scal( tempP, unary( (double)rep*m_deltaPhi ) );
1189 dg::blas1::scal( tempM, unary( -(double)rep*m_deltaPhi ) );
1190 dg::blas1::axpby( 1., tempP, 1., plus2d[i0]);
1191 dg::blas1::axpby( 1., tempM, 1., minus2d[i0]);
1192 }
1193 //now we have the plus and the minus filaments
1194 if( rounds == 0) //there is a limiter
1195 {
1196 for( unsigned i0=0; i0<m_Nz; i0++)
1197 {
1198 int idx = (int)i0 - (int)p0;
1199 if(idx>=0)
1200 result[i0] = plus2d[idx];
1201 else
1202 result[i0] = minus2d[abs(idx)];
1203 thrust::copy( result[i0].begin(), result[i0].end(), vec3d.begin() + i0*m_perp_size);
1204 }
1205 }
1206 else //sum up plus2d and minus2d
1207 {
1208 for( unsigned i0=0; i0<m_Nz; i0++)
1209 {
1210 unsigned revi0 = (m_Nz - i0)%m_Nz; //reverted index
1211 dg::blas1::axpby( 1., plus2d[i0], 0., result[i0]);
1212 dg::blas1::axpby( 1., minus2d[revi0], 1., result[i0]);
1213 }
1214 dg::blas1::axpby( -1., init2d, 1., result[0]);
1215 for(unsigned i0=0; i0<m_Nz; i0++)
1216 {
1217 int idx = ((int)i0 -(int)p0 + m_Nz)%m_Nz; //shift index
1218 thrust::copy( result[idx].begin(), result[idx].end(), vec3d.begin() + i0*m_perp_size);
1219 }
1220 }
1221 return vec3d;
1222}
1223
1224
1226
1258template<class BinaryOp, class UnaryOp>
1259thrust::host_vector<double> fieldaligned_evaluate(
1260 const aProductGeometry3d& grid,
1261 const CylindricalVectorLvl0& vec,
1262 const BinaryOp& binary,
1263 const UnaryOp& unary,
1264 unsigned p0,
1265 unsigned rounds,
1266 double eps = 1e-5)
1267{
1268 unsigned Nz = grid.Nz();
1269 const dg::ClonePtr<aGeometry2d> g2d = grid.perp_grid();
1270 // Construct for field-aligned output
1271 dg::HVec tempP = dg::evaluate( dg::zero, *g2d), tempM( tempP);
1272 std::vector<dg::HVec> plus2d(Nz, tempP), minus2d(plus2d), result(plus2d);
1273 dg::HVec vec3d = dg::evaluate( dg::zero, grid);
1274 dg::HVec init2d = dg::pullback( binary, *g2d);
1275 std::array<dg::HVec,3> yy0{
1276 dg::pullback( dg::cooX2d, *g2d),
1277 dg::pullback( dg::cooY2d, *g2d),
1278 dg::evaluate( dg::zero, *g2d)}, yy1(yy0), xx0( yy0), xx1(yy0); //s
1279 dg::geo::detail::DSFieldCylindrical3 cyl_field(vec);
1280 double deltaPhi = grid.hz();
1281 double phiM0 = 0., phiP0 = 0.;
1282 unsigned turns = rounds;
1283 if( turns == 0) turns++;
1284 for( unsigned r=0; r<turns; r++)
1285 for( unsigned i0=0; i0<Nz; i0++)
1286 {
1287 unsigned rep = r*Nz + i0;
1288 if( rep == 0)
1289 tempM = tempP = init2d;
1290 else
1291 {
1293 "Dormand-Prince-7-4-5", std::array<double,3>{0,0,0});
1295 cyl_field, dg::pid_control, dg::fast_l2norm, eps,
1296 1e-10);
1297 for( unsigned i=0; i<g2d->size(); i++)
1298 {
1299 // minus direction needs positive integration!
1300 double phiM1 = phiM0 + deltaPhi;
1301 std::array<double,3>
1302 coords0{yy0[0][i],yy0[1][i],yy0[2][i]}, coords1;
1303 odeint.integrate_in_domain( phiM0, coords0, phiM1, coords1,
1304 deltaPhi, *g2d, eps);
1305 yy1[0][i] = coords1[0], yy1[1][i] = coords1[1], yy1[2][i] =
1306 coords1[2];
1307 tempM[i] = binary( yy1[0][i], yy1[1][i]);
1308
1309 // plus direction needs negative integration!
1310 double phiP1 = phiP0 - deltaPhi;
1311 coords0 = std::array<double,3>{xx0[0][i],xx0[1][i],xx0[2][i]};
1312 odeint.integrate_in_domain( phiP0, coords0, phiP1, coords1,
1313 -deltaPhi, *g2d, eps);
1314 xx1[0][i] = coords1[0], xx1[1][i] = coords1[1], xx1[2][i] =
1315 coords1[2];
1316 tempP[i] = binary( xx1[0][i], xx1[1][i]);
1317 }
1318 std::swap( yy0, yy1);
1319 std::swap( xx0, xx1);
1320 phiM0 += deltaPhi;
1321 phiP0 -= deltaPhi;
1322 }
1323 dg::blas1::scal( tempM, unary( -(double)rep*deltaPhi ) );
1324 dg::blas1::scal( tempP, unary( (double)rep*deltaPhi ) );
1325 dg::blas1::axpby( 1., tempM, 1., minus2d[i0]);
1326 dg::blas1::axpby( 1., tempP, 1., plus2d[i0]);
1327 }
1328 //now we have the plus and the minus filaments
1329 if( rounds == 0) //there is a limiter
1330 {
1331 for( unsigned i0=0; i0<Nz; i0++)
1332 {
1333 int idx = (int)i0 - (int)p0;
1334 if(idx>=0)
1335 result[i0] = plus2d[idx];
1336 else
1337 result[i0] = minus2d[abs(idx)];
1338 thrust::copy( result[i0].begin(), result[i0].end(), vec3d.begin() +
1339 i0*g2d->size());
1340 }
1341 }
1342 else //sum up plus2d and minus2d
1343 {
1344 for( unsigned i0=0; i0<Nz; i0++)
1345 {
1346 unsigned revi0 = (Nz - i0)%Nz; //reverted index
1347 dg::blas1::axpby( 1., plus2d[i0], 0., result[i0]);
1348 dg::blas1::axpby( 1., minus2d[revi0], 1., result[i0]);
1349 }
1350 dg::blas1::axpby( -1., init2d, 1., result[0]);
1351 for(unsigned i0=0; i0<Nz; i0++)
1352 {
1353 int idx = ((int)i0 -(int)p0 + Nz)%Nz; //shift index
1354 thrust::copy( result[idx].begin(), result[idx].end(), vec3d.begin()
1355 + i0*g2d->size());
1356 }
1357 }
1358 return vec3d;
1359}
1360
1361}//namespace geo
1362}//namespace dg
#define _ping_
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 pointwiseDivide(value_type alpha, const ContainerType1 &x1, const ContainerType2 &x2, value_type1 beta, ContainerType &y)
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
ZERO NoLimiter
No Limiter.
Definition fieldaligned.h:34
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
@ einsPlusT
transposed plus interpolation in previous plane
Definition fieldaligned.h:18
@ zeroPlus
plus interpolation in the current plane
Definition fieldaligned.h:21
@ einsPlus
plus interpolation in next plane
Definition fieldaligned.h:17
@ zeroForw
from dg to transformed coordinates
Definition fieldaligned.h:25
@ zeroMinusT
transposed minus interpolation in the current plane
Definition fieldaligned.h:24
@ einsMinus
minus interpolation in previous plane
Definition fieldaligned.h:19
@ zeroPlusT
transposed plus interpolation in the current plane
Definition fieldaligned.h:23
@ einsMinusT
transposed minus interpolation in next plane
Definition fieldaligned.h:20
@ zeroMinus
minus interpolation in the current plane
Definition fieldaligned.h:22
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
Geometry::host_vector pullback(const Functor &f, const Geometry &g)
void pushForwardPerp(const Functor1 &vR, const Functor2 &vZ, container &vx, container &vy, 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
size_t & num_cols()
const Vector< Index > & row_offsets() const
size_t & num_rows()
size_t num_nnz() const
const Vector< Index > & column_indices() const
const Vector< Value > & values() const
double diff() const
void toc()
void tic()
aRealGeometry2d< real_type > * perp_grid() const
real_type hz() const
unsigned size() const
unsigned Nz() const
std::enable_if_t<(Md==1), bool > contains(real_type x) const
Definition fluxfunctions.h:415
This struct bundles a vector field and its divergence.
Definition fluxfunctions.h:443
const CylindricalFunctor & y() const
y-component of the vector
Definition fluxfunctions.h:471
const CylindricalFunctor & x() const
x-component of the vector
Definition fluxfunctions.h:469
const CylindricalFunctor & divvvz() const
Definition fluxfunctions.h:477
const CylindricalFunctor & z() const
z-component of the vector
Definition fluxfunctions.h:473
Create and manage interpolation matrices from fieldline integration.
Definition fieldaligned.h:312
dg::bc bcx() const
Definition fieldaligned.h:363
void integrate_between_coarse_grid(const ProductGeometry &grid_coarse, const container &coarse, container &out) const
Integrate a 2d function on the fine grid.
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
Fieldaligned(const dg::geo::TokamakMagneticField &vec, const ProductGeometry &grid, dg::bc bcx=dg::NEU, dg::bc bcy=dg::NEU, Limiter limit=FullLimiter(), double eps=1e-5, unsigned mx=12, unsigned my=12, double deltaPhi=-1, std::string interpolation_method="linear-nearest", bool benchmark=true)
Construct from a magnetic field and a grid.
Definition fieldaligned.h:320
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
container interpolate_from_coarse_grid(const ProductGeometry &grid_coarse, const container &coarse) const
Interpolate along fieldlines from a coarse to a fine grid in phi.
void set_boundaries(dg::bc bcz, const container &global, double scal_left, double scal_right)
Set boundary conditions in the limiter region.
Definition fieldaligned.h:414
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
Fieldaligned(const dg::geo::CylindricalVectorLvl1 &vec, const ProductGeometry &grid, dg::bc bcx=dg::NEU, dg::bc bcy=dg::NEU, Limiter limit=FullLimiter(), double eps=1e-5, unsigned mx=12, unsigned my=12, double deltaPhi=-1, std::string interpolation_method="linear-nearest", bool benchmark=true)
Construct from a vector field and a grid.
const container & bphiP() const
bphi on plus plane
Definition fieldaligned.h:470
const ProductGeometry & grid() const
Grid used for construction.
Definition fieldaligned.h:489
void set_boundaries(dg::bc bcz, const container &left, const container &right)
Set boundary conditions in the limiter region.
Definition fieldaligned.h:397
A tokamak field as given by R0, Psi and Ipol plus Meta-data like shape and equilibrium.
Definition magnetic_field.h:172