Extension: Geometries
#include "dg/geometries/geometries.h"
fieldaligned_coarse.h
Go to the documentation of this file.
1#pragma once
2#include <cmath>
3#include <array>
4#include <cusp/csr_matrix.h>
5
6#include "dg/algorithm.h"
7#include "magnetic_field.h"
8#include "fluxfunctions.h"
9#include "curvilinear.h"
10
11namespace dg{
12namespace geo{
13
17{
18 einsPlus = 0,
19 einsPlusT,
20 einsMinus,
22 zeroPlus,
23 zeroMinus,
24 zeroPlusT,
26<<<<<<< Updated upstream
29=======
30 zeroZero
31>>>>>>> Stashed changes
32};
33
36typedef ONE FullLimiter;
37
40typedef ZERO NoLimiter;
42namespace detail{
43
44
45struct DSFieldCylindrical3
46{
47 DSFieldCylindrical3( const dg::geo::CylindricalVectorLvl0& v): m_v(v){}
48 void operator()( double t, const std::array<double,3>& y,
49 std::array<double,3>& yp) const {
50 double R = y[0], Z = y[1];
51 double vz = m_v.z()(R, Z);
52 yp[0] = m_v.x()(R, Z)/vz;
53 yp[1] = m_v.y()(R, Z)/vz;
54 yp[2] = 1./vz;
55 }
56 private:
58};
59
60struct DSFieldCylindrical4
61{
62 DSFieldCylindrical4( const dg::geo::CylindricalVectorLvl1& v): m_v(v){}
63 void operator()( double t, const std::array<double,3>& y,
64 std::array<double,3>& yp) const {
65 double R = y[0], Z = y[1];
66 double vx = m_v.x()(R,Z);
67 double vy = m_v.y()(R,Z);
68 double vz = m_v.z()(R,Z);
69 double divvvz = m_v.divvvz()(R,Z);
70 yp[0] = vx/vz;
71 yp[1] = vy/vz;
72 yp[2] = divvvz*y[2];
73 }
74
75 private:
77};
78
79struct DSField
80{
81 DSField() = default;
82 //z component of v may not vanish
83 DSField( const dg::geo::CylindricalVectorLvl1& v,
84 const dg::aGeometry2d& g ):
85 m_g(g)
86 {
87 dg::HVec v_zeta, v_eta;
88 dg::pushForwardPerp( v.x(), v.y(), v_zeta, v_eta, g);
89 dg::HVec vx = dg::pullback( v.x(), g);
90 dg::HVec vy = dg::pullback( v.y(), g);
91 dg::HVec vz = dg::pullback( v.z(), g);
92 dg::HVec divvvz = dg::pullback( v.divvvz(), g);
93 dg::blas1::pointwiseDivide(v_zeta, vz, v_zeta);
94 dg::blas1::pointwiseDivide(v_eta, vz, v_eta);
95 dzetadphi_ = dg::forward_transform( v_zeta, g );
96 detadphi_ = dg::forward_transform( v_eta, g );
97 dvdphi_ = dg::forward_transform( divvvz, g );
98 }
99 //interpolate the vectors given in the constructor on the given point
100 void operator()(double t, const std::array<double,3>& y, std::array<double,3>& yp) const
101 {
102 // shift point into domain
103 yp[0] = interpolate(dg::lspace, dzetadphi_, y[0], y[1], *m_g);
104 yp[1] = interpolate(dg::lspace, detadphi_, y[0], y[1], *m_g);
105 yp[2] = interpolate(dg::lspace, dvdphi_, y[0], y[1], *m_g)*y[2];
106 }
107 private:
108 thrust::host_vector<double> dzetadphi_, detadphi_, dvdphi_;
110};
111
112//used in constructor of Fieldaligned
113template<class real_type>
114void integrate_all_fieldlines2d( const dg::geo::CylindricalVectorLvl1& vec,
115 const dg::aRealGeometry2d<real_type>& grid_field,
116 const dg::aRealTopology2d<real_type>& grid_evaluate,
117 std::array<thrust::host_vector<real_type>,3>& yp,
118 const thrust::host_vector<double>& vol0,
119 thrust::host_vector<real_type>& yp2b,
120 thrust::host_vector<bool>& in_boxp,
121 real_type deltaPhi, real_type eps)
122{
123 //grid_field contains the global geometry for the field and the boundaries
124 //grid_evaluate contains the points to actually integrate
125 std::array<thrust::host_vector<real_type>,3> y{
126 dg::evaluate( dg::cooX2d, grid_evaluate),
127 dg::evaluate( dg::cooY2d, grid_evaluate),
128 vol0
129 };
130 yp.fill(dg::evaluate( dg::zero, grid_evaluate));
131 //construct field on high polynomial grid, then integrate it
132 dg::geo::detail::DSField field;
133 if( !dynamic_cast<const dg::CartesianGrid2d*>( &grid_field))
134 field = dg::geo::detail::DSField( vec, grid_field);
135
136 //field in case of cartesian grid
137 dg::geo::detail::DSFieldCylindrical4 cyl_field(vec);
138 const unsigned size = grid_evaluate.size();
140 "Dormand-Prince-7-4-5", std::array<real_type,3>{0,0,0});
142 if( dynamic_cast<const dg::CartesianGrid2d*>( &grid_field))
144 cyl_field, dg::pid_control, dg::fast_l2norm, eps, 1e-10);
145 else
147 field, dg::pid_control, dg::fast_l2norm, eps, 1e-10);
148
149 for( unsigned i=0; i<size; i++)
150 {
151 std::array<real_type,3> coords{y[0][i],y[1][i],y[2][i]}, coordsP;
152 //x,y,s
153 real_type phi1 = deltaPhi;
154 odeint.set_dt( deltaPhi/2.);
155 odeint.integrate( 0, coords, phi1, coordsP);
156 yp[0][i] = coordsP[0], yp[1][i] = coordsP[1], yp[2][i] = coordsP[2];
157 }
158 yp2b.assign( grid_evaluate.size(), deltaPhi); //allocate memory for output
159 in_boxp.resize( yp2b.size());
160 //Now integrate again but this time find the boundary distance
161 for( unsigned i=0; i<size; i++)
162 {
163 std::array<real_type,3> coords{y[0][i],y[1][i],y[2][i]}, coordsP;
164 in_boxp[i] = grid_field.contains( yp[0][i], yp[1][i]) ? true : false;
165 if( false == in_boxp[i])
166 {
167 //x,y,s
168 real_type phi1 = deltaPhi;
169 odeint.integrate_in_domain( 0., coords, phi1, coordsP, 0., (const
170 dg::aRealTopology2d<real_type>&)grid_field, eps);
171 yp2b[i] = phi1;
172 }
173 }
174}
175
176
177}//namespace detail
179
186struct WallFieldlineDistance : public aCylindricalFunctor<WallFieldlineDistance>
187{
204 const dg::aRealTopology2d<double>& domain,
205 double maxPhi, double eps, std::string type) :
206 m_domain( domain), m_cyl_field(vec),
207 m_deltaPhi( maxPhi), m_eps( eps), m_type(type)
208 {
209 if( m_type != "phi" && m_type != "s")
210 throw std::runtime_error( "Distance type "+m_type+" not recognized!\n");
211 }
222 double do_compute( double R, double Z) const
223 {
224 std::array<double,3> coords{ R, Z, 0}, coordsP(coords);
225 // determine sign
226 m_cyl_field( 0., coords, coordsP);
227 double sign = coordsP[2] > 0 ? +1. : -1.;
228 double phi1 = sign*m_deltaPhi; // we integrate negative ...
229 try{
231 "Dormand-Prince-7-4-5", coords);
233 m_cyl_field, dg::pid_control, dg::fast_l2norm, m_eps,
234 1e-10);
235 odeint.integrate_in_domain( 0., coords, phi1, coordsP, 0.,
236 m_domain, m_eps);
237 //integration
238 }catch (std::exception& e)
239 {
240 // if not possible the distance is large
241 //std::cerr << e.what();
242 phi1 = sign*m_deltaPhi;
243 coordsP[2] = 1e6*phi1;
244 }
245 if( m_type == "phi")
246 return sign*phi1;
247 return coordsP[2];
248 }
249
250 private:
251 const dg::Grid2d m_domain;
252 dg::geo::detail::DSFieldCylindrical3 m_cyl_field;
253 double m_deltaPhi, m_eps;
254 std::string m_type;
255};
256
269struct WallFieldlineCoordinate : public aCylindricalFunctor<WallFieldlineCoordinate>
270{
274 const dg::aRealTopology2d<double>& domain,
275 double maxPhi, double eps, std::string type) :
276 m_domain( domain), m_cyl_field(vec),
277 m_deltaPhi( maxPhi), m_eps( eps), m_type(type)
278 {
279 if( m_type != "phi" && m_type != "s")
280 throw std::runtime_error( "Distance type "+m_type+" not recognized!\n");
281 }
282 double do_compute( double R, double Z) const
283 {
284 double phiP = m_deltaPhi, phiM = -m_deltaPhi;
285 std::array<double,3> coords{ R, Z, 0}, coordsP(coords), coordsM(coords);
286 // determine sign
287 m_cyl_field( 0., coords, coordsP);
288 double sign = coordsP[2] > 0 ? +1. : -1.;
289 try{
291 dg::Adaptive<dg::ERKStep<std::array<double,3>>>(
292 "Dormand-Prince-7-4-5", coords), m_cyl_field,
293 dg::pid_control, dg::fast_l2norm, m_eps, 1e-10);
294 odeint.integrate_in_domain( 0., coords, phiP, coordsP, 0.,
295 m_domain, m_eps);
296 odeint.integrate_in_domain( 0., coords, phiM, coordsM, 0.,
297 m_domain, m_eps);
298 }catch (std::exception& e)
299 {
300 // if not possible the distance is large
301 phiP = m_deltaPhi;
302 coordsP[2] = 1e6*phiP;
303 phiM = -m_deltaPhi;
304 coordsM[2] = 1e6*phiM;
305 }
306 if( m_type == "phi")
307 return sign*(-phiP-phiM)/(phiP-phiM);
308 double sP = coordsP[2], sM = coordsM[2];
309 double value = sign*(-sP-sM)/(sP-sM);
310 if( (phiM <= -m_deltaPhi) && (phiP >= m_deltaPhi))
311 return 0.; //return exactly zero if sheath not reached
312 if( (phiM <= -m_deltaPhi))
313 return value*sign > 0 ? value : 0.; // avoid false negatives
314 if( (phiP >= m_deltaPhi))
315 return value*sign < 0 ? value : 0.; // avoid false positives
316 return value;
317 }
318
319 private:
320 const dg::Grid2d m_domain;
321 dg::geo::detail::DSFieldCylindrical3 m_cyl_field;
322 double m_deltaPhi, m_eps;
323 std::string m_type;
324};
325
326
365
377template<class ProductGeometry, class IMatrix, class container >
378struct Fieldaligned
379{
380
386 template <class Limiter>
388 const ProductGeometry& grid,
391 Limiter limit = FullLimiter(),
392 double eps = 1e-5,
393 unsigned mx=10, unsigned my=10,
394 double deltaPhi = -1,
395 std::string interpolation_method = "dg",
396 bool benchmark=true
397 ):
398 Fieldaligned( dg::geo::createBHat(vec),
399 grid, bcx, bcy, limit, eps, mx, my, deltaPhi, interpolation_method)
400 {
401 }
402
406 template <class Limiter>
408 const ProductGeometry& grid,
411 Limiter limit = FullLimiter(),
412 double eps = 1e-5,
413 unsigned mx=10, unsigned my=10,
414 double deltaPhi = -1,
415 std::string interpolation_method = "dg",
416 bool benchmark=true
417 );
423 template<class ...Params>
424 void construct( Params&& ...ps)
425 {
426 //construct and swap
427 *this = Fieldaligned( std::forward<Params>( ps)...);
428 }
429
430 dg::bc bcx()const{
431 return m_bcx;
432 }
433 dg::bc bcy()const{
434 return m_bcy;
435 }
436
437
447 void set_boundaries( dg::bc bcz, double left, double right)
448 {
449 m_bcz = bcz;
450 const dg::Grid1d g2d( 0, 1, 1, m_perp_size);
451 m_left = dg::evaluate( dg::CONSTANT(left), g2d);
452 m_right = dg::evaluate( dg::CONSTANT(right),g2d);
453 }
454
464 void set_boundaries( dg::bc bcz, const container& left, const container& right)
465 {
466 m_bcz = bcz;
467 m_left = left;
468 m_right = right;
469 }
470
481 void set_boundaries( dg::bc bcz, const container& global, double scal_left, double scal_right)
482 {
483 dg::split( global, m_f, *m_g);
484 dg::blas1::axpby( scal_left, m_f[0], 0, m_left);
485 dg::blas1::axpby( scal_right, m_f[m_Nz-1], 0, m_right);
486 m_bcz = bcz;
487 }
488
497 void operator()(enum whichMatrix which, const container& in, container& out);
498
499 double deltaPhi() const{return m_deltaPhi;}
502 const container& hbm()const {
503 return m_hbm;
504 }
507 const container& hbp()const {
508 return m_hbp;
509 }
512 const container& sqrtG()const {
513 return m_G;
514 }
517 const container& sqrtGm()const {
518 return m_Gm;
519 }
522 const container& sqrtGp()const {
523 return m_Gp;
524 }
527 const container& bphi()const {
528 return m_bphi;
529 }
532 const container& bphiM()const {
533 return m_bphiM;
534 }
537 const container& bphiP()const {
538 return m_bphiP;
539 }
542 const container& bbm()const {
543 return m_bbm;
544 }
547 const container& bbo()const {
548 return m_bbo;
549 }
552 const container& bbp()const {
553 return m_bbp;
554 }
556 const ProductGeometry& grid()const{return *m_g;}
557
571 container interpolate_from_coarse_grid( const ProductGeometry& grid_coarse, const container& coarse);
581 void integrate_between_coarse_grid( const ProductGeometry& grid_coarse, const container& coarse, container& out );
582
583
612 template< class BinaryOp, class UnaryOp>
613 container evaluate( BinaryOp binary, UnaryOp unary,
614 unsigned p0, unsigned rounds) const;
615
616 std::string method() const{return m_interpolation_method;}
617
618 private:
619 void ePlus( enum whichMatrix which, const container& in, container& out);
620 void eMinus(enum whichMatrix which, const container& in, container& out);
621 void zero( enum whichMatrix which, const container& in, container& out);
622 IMatrix m_plus, m_minus, m_plusT, m_minusT; //2d interpolation matrices
623<<<<<<< Updated upstream
624 container m_tmp; // 3d size
625 IMatrix m_back, m_forw;
626=======
627 IMatrix m_stencil, m_back, m_forw;
628>>>>>>> Stashed changes
629 container m_hbm, m_hbp; //3d size
630 container m_G, m_Gm, m_Gp; // 3d size
631 container m_bphi, m_bphiM, m_bphiP; // 3d size
632 container m_bbm, m_bbp, m_bbo; //3d size masks
633
634 container m_left, m_right, m_temp2d; //perp_size
635 container m_limiter; //perp_size
636 container m_ghostM, m_ghostP; //perp_size
637 unsigned m_Nz, m_perp_size;
638 dg::bc m_bcx, m_bcy, m_bcz;
639 std::vector<dg::View<const container>> m_f;
640 std::vector<dg::View< container>> m_temp;
643 double m_deltaPhi;
644 std::string m_interpolation_method;
645
646 bool m_have_adjoint = false;
647 void updateAdjoint( )
648 {
649 m_plusT = dg::transpose( m_plus);
650 m_minusT = dg::transpose( m_minus);
651 m_have_adjoint = true;
652 }
653};
654
656
658template<class Geometry, class IMatrix, class container>
659template <class Limiter>
662 const Geometry& grid,
663 dg::bc bcx, dg::bc bcy, Limiter limit, double eps,
664 unsigned mx, unsigned my, double deltaPhi, std::string interpolation_method, bool benchmark)
665{
667 if( (grid.bcx() == PER && bcx != PER) || (grid.bcx() != PER && bcx == PER) )
668 throw( dg::Error(dg::Message(_ping_)<<"Fieldaligned: Got conflicting periodicity in x. The grid says "<<bc2str(grid.bcx())<<" while the parameter says "<<bc2str(bcx)));
669 if( (grid.bcy() == PER && bcy != PER) || (grid.bcy() != PER && bcy == PER) )
670 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)));
671 m_Nz=grid.Nz(), m_bcx = bcx, m_bcy = bcy, m_bcz=grid.bcz();
672 m_g.reset(grid);
673 if( deltaPhi <=0) deltaPhi = grid.hz();
674<<<<<<< Updated upstream
675 if( interpolation_method == "dg-const")
676 {
677 m_back = dg::create::inv_backproject( grid); //from equidist to dg
678 m_forw = dg::create::backproject( grid); // from dg to equidist
679 }
681 dg::Timer t;
682 if( benchmark) t.tic();
683 dg::ClonePtr<dg::aGeometry2d> grid_original( grid.perp_grid()) ;
684 dg::ClonePtr<dg::aGeometry2d> grid_transform( grid_original) ;
685 dg::ClonePtr<dg::aGeometry3d> grid_transform3d( grid) ;
686 if( interpolation_method == "dg-const")
687 {
688 grid_transform->set( 1, grid.gx().size(), grid.gy().size());
689 grid_transform3d->set( 1, grid.gx().size(), grid.gy().size(), grid.gz().size());
690 }
691 dg::ClonePtr<dg::aGeometry2d> grid_magnetic = grid_original;//INTEGRATE HIGH ORDER GRID
692 grid_magnetic->set( grid_original->n() < 3 ? 4 : 7, grid_magnetic->Nx(), grid_magnetic->Ny());
694 if( interpolation_method == "dg-const" || interpolation_method == "dg")
695 {
696 grid_fine = grid_original;
697 if( interpolation_method == "dg-const")
698 mx *= grid.n(), my *= grid.n();
699 grid_fine->multiplyCellNumbers((double)mx, (double)my);
700 }
701 else
702 {
703 dg::FemRefinement fem_refX( mx), fem_refY(my);
704 dg::Grid2d tmp( *grid_transform);
705 dg::CartesianRefinedGrid2d ref( fem_refX, fem_refY, tmp.x0(), tmp.x1(),
706 tmp.y0(), tmp.y1(), tmp.n(), tmp.Nx(), tmp.Ny(),
707 tmp.bcx(), tmp.bcy());
708 grid_fine = ref;
709 //grid_fine = grid_transform;
710 if( interpolation_method == "linear")
711 m_inv_linear = dg::create::inv_fem_mass2d( grid);
712 if ( interpolation_method == "linear-const")
713 m_inv_linear = dg::create::inv_fem_linear2const2d( grid);
714 }
715=======
717 dg::ClonePtr<dg::aGeometry2d> grid_coarse( grid.perp_grid()) ;
719 m_stencil = dg::create::window_stencil( {3,3}, *grid_coarse, dg::NEU, dg::NEU);
720 m_back = dg::create::backscatter( *grid_coarse);
721 m_forw = dg::create::inv_backscatter( *grid_coarse);
722
723 m_perp_size = grid_coarse->size();
724 dg::assign( dg::pullback(limit, *grid_coarse), m_limiter);
725 dg::assign( dg::evaluate(dg::zero, *grid_coarse), m_left);
726 m_temp2d = m_ghostM = m_ghostP = m_right = m_left;
728 dg::Timer t;
729 if( benchmark) t.tic();
730 std::array<thrust::host_vector<double>,3> yp_coarse, ym_coarse, yp, ym;
731 dg::ClonePtr<dg::aGeometry2d> grid_magnetic = grid_coarse;//INTEGRATE HIGH ORDER GRID
732 grid_magnetic->set( 7, grid_magnetic->Nx(), grid_magnetic->Ny());
733 dg::Grid2d grid_fine( *grid_coarse );//FINE GRID
734 grid_fine.set( 1, grid_fine.gx().size(), grid_fine.gy().size());
735 grid_fine.multiplyCellNumbers((double)mx, (double)my);
736>>>>>>> Stashed changes
737 if( benchmark)
738 {
739 t.toc();
740 std::cout << "# DS: High order grid gen took: "<<t.diff()<<"\n";
741 t.tic();
742 }
744 std::array<thrust::host_vector<double>,3> yp_trafo, ym_trafo, yp, ym;
745 thrust::host_vector<bool> in_boxp, in_boxm;
746 thrust::host_vector<double> hbp, hbm;
747 thrust::host_vector<double> vol = dg::tensor::volume(grid_transform3d->metric()), vol2d0;
748 auto vol2d = dg::split( vol, grid);
749 dg::assign( vol2d[0], vol2d0);
750<<<<<<< Updated upstream
751 detail::integrate_all_fieldlines2d( vec, *grid_magnetic, *grid_transform,
752 yp_trafo, vol2d0, hbp, in_boxp, deltaPhi, eps);
753 detail::integrate_all_fieldlines2d( vec, *grid_magnetic, *grid_transform,
754 ym_trafo, vol2d0, hbm, in_boxm, -deltaPhi, eps);
755 dg::HVec Xf = dg::pullback( dg::cooX2d, *grid_fine);
756 dg::HVec Yf = dg::pullback( dg::cooY2d, *grid_fine);
757 {
759 *grid_original, dg::NEU, dg::NEU, grid_original->n() < 3 ? "cubic" : "dg"); //INTERPOLATE TO FINE GRID
760 yp.fill(dg::evaluate( dg::zero, *grid_fine));
761=======
762 detail::integrate_all_fieldlines2d( vec, *grid_magnetic, *grid_coarse,
763 yp_coarse, vol2d0, hbp, in_boxp, deltaPhi, eps);
764 detail::integrate_all_fieldlines2d( vec, *grid_magnetic, *grid_coarse,
765 ym_coarse, vol2d0, hbm, in_boxm, -deltaPhi, eps);
766 // maybe "cubic" only for n=1?
768 *grid_coarse, "cubic"); //INTERPOLATE TO FINE GRID
769
770 yp.fill(dg::evaluate( dg::zero, grid_fine));
771>>>>>>> Stashed changes
772 ym = yp;
773 for( int i=0; i<2; i++) //only R and Z get interpolated
774 {
775 dg::blas2::symv( interpolate, yp_trafo[i], yp[i]);
776 dg::blas2::symv( interpolate, ym_trafo[i], ym[i]);
777 }
778 } // release memory for interpolate matrix
779 if( benchmark)
780 {
781 t.toc();
782 std::cout << "# DS: Computing all points took: "<<t.diff()<<"\n";
783 t.tic();
784 }
786 dg::IHMatrix plusFine, minusFine, plus, minus;
787 if( interpolation_method == "dg-const" || interpolation_method == "dg")
788 {
789 plusFine = dg::create::interpolation( yp[0], yp[1],
790 *grid_original, bcx, bcy, "dg");
791 minusFine = dg::create::interpolation( ym[0], ym[1],
792 *grid_original, bcx, bcy, "dg");
793 }
794 else
795 {
796 plusFine = dg::create::interpolation( yp[0], yp[1],
797 *grid_transform, bcx, bcy, "linear");
798 minusFine = dg::create::interpolation( ym[0], ym[1],
799 *grid_transform, bcx, bcy, "linear");
800 //dg::IHMatrix forw = dg::create::backproject( *grid_original); // from dg to equidist
801 //cusp::multiply( plusFineTmp, forw, plusFine);
802 //cusp::multiply( minusFineTmp, forw, minusFine);
803 }
804 if( mx == 1 && my == 1)
805 {
806 plus = plusFine;
807 minus = minusFine;
808 }
809 else
810 {
811<<<<<<< Updated upstream
813 if( interpolation_method == "dg-const" || interpolation_method == "dg")
814 {
815 projection = dg::create::transformation( *grid_transform, *grid_fine);
816 }
817 else
818 {
819 std::string method = "linear";
820 if( interpolation_method == "linear-const")
821 method = "nearest";
823 Yf, *grid_transform, dg::NEU, dg::NEU, method));
826 dg::IHMatrix tmp;
827 cusp::multiply( projection, Wf, tmp);
828 cusp::multiply( Vf, tmp, projection);
829 }
830=======
831 dg::Grid2d grid_project( *grid_coarse );//FINE GRID
832 grid_project.set( 1, grid_project.gx().size(), grid_project.gy().size());
833 dg::IHMatrix proj = dg::create::projection( grid_project, grid_fine), projection;
834 auto forward = dg::create::inv_backscatter( *grid_coarse);
835 cusp::multiply( forward, proj, projection);
836>>>>>>> Stashed changes
837 cusp::multiply( projection, plusFine, plus);
838 cusp::multiply( projection, minusFine, minus);
839 }
840 if( benchmark)
841 {
842 t.toc();
843 std::cout << "# DS: Multiplication PI took: "<<t.diff()<<"\n";
844 }
845 dg::blas2::transfer( plus, m_plus);
846 dg::blas2::transfer( minus, m_minus);
848 dg::HVec hbphi( yp_trafo[2]), hbphiP(hbphi), hbphiM(hbphi);
849 hbphi = dg::pullback( vec.z(), *grid_transform);
850 //this is a pullback bphi( R(zeta, eta), Z(zeta, eta)):
851 if( dynamic_cast<const dg::CartesianGrid2d*>( grid_transform.get()))
852 {
853 for( unsigned i=0; i<hbphiP.size(); i++)
854 {
855 hbphiP[i] = vec.z()(yp_trafo[0][i], yp_trafo[1][i]);
856 hbphiM[i] = vec.z()(ym_trafo[0][i], ym_trafo[1][i]);
857 }
858 }
859 else
860 {
861 dg::HVec Ihbphi = dg::pullback( vec.z(), *grid_magnetic);
862 dg::HVec Lhbphi = dg::forward_transform( Ihbphi, *grid_magnetic);
863 for( unsigned i=0; i<yp_trafo[0].size(); i++)
864 {
865 hbphiP[i] = dg::interpolate( dg::lspace, Lhbphi, yp_trafo[0][i],
866 yp_trafo[1][i], *grid_magnetic);
867 hbphiM[i] = dg::interpolate( dg::lspace, Lhbphi, ym_trafo[0][i],
868 ym_trafo[1][i], *grid_magnetic);
869 }
870 }
871 dg::assign3dfrom2d( hbphi, m_bphi, grid);
872 dg::assign3dfrom2d( hbphiM, m_bphiM, grid);
873 dg::assign3dfrom2d( hbphiP, m_bphiP, grid);
874
875 dg::assign3dfrom2d( yp_trafo[2], m_Gp, grid);
876 dg::assign3dfrom2d( ym_trafo[2], m_Gm, grid);
877 m_G = dg::create::volume(*grid_transform3d);
878 container weights = dg::create::weights( *grid_transform3d);
879 dg::blas1::pointwiseDot( m_Gp, weights, m_Gp);
880 dg::blas1::pointwiseDot( m_Gm, weights, m_Gm);
881
882 dg::assign( dg::evaluate( dg::zero, grid), m_hbm);
883 m_f = dg::split( (const container&)m_hbm, grid);
884 m_temp = dg::split( m_hbm, grid);
885 dg::assign3dfrom2d( hbp, m_hbp, grid);
886 dg::assign3dfrom2d( hbm, m_hbm, grid);
887 dg::blas1::scal( m_hbm, -1.);
888
890 thrust::host_vector<double> bbm( in_boxp.size(),0.), bbo(bbm), bbp(bbm);
891 for( unsigned i=0; i<in_boxp.size(); i++)
892 {
893 if( !in_boxp[i] && !in_boxm[i])
894 bbo[i] = 1.;
895 else if( !in_boxp[i] && in_boxm[i])
896 bbp[i] = 1.;
897 else if( in_boxp[i] && !in_boxm[i])
898 bbm[i] = 1.;
899 // else all are 0
900 }
901 dg::assign3dfrom2d( bbm, m_bbm, grid);
902 dg::assign3dfrom2d( bbo, m_bbo, grid);
903 dg::assign3dfrom2d( bbp, m_bbp, grid);
904
905 m_deltaPhi = deltaPhi; // store for evaluate
906 m_tmp = m_bbm;
907 m_interpolation_method = interpolation_method;
909
910 m_perp_size = grid_transform->size();
911 dg::assign( dg::pullback(limit, *grid_transform), m_limiter);
912 dg::assign( dg::evaluate(dg::zero, *grid_transform), m_left);
913 m_temp2d = m_ghostM = m_ghostP = m_right = m_left;
914}
915
916
917template<class G, class I, class container>
919 const G& grid, const container& in)
920{
921 //I think we need grid as input to split input vector and we need to interpret
922 //the grid nodes as node centered not cell-centered!
923 //idea: apply I+/I- cphi - 1 times in each direction and then apply interpolation formula
924 assert( m_g->Nz() % grid.Nz() == 0);
925 unsigned Nz_coarse = grid.Nz(), Nz = m_g->Nz();
926 unsigned cphi = Nz / Nz_coarse;
927
928 container out = dg::evaluate( dg::zero, *m_g);
929 container helper = dg::evaluate( dg::zero, *m_g);
930 dg::split( helper, m_temp, *m_g);
931 std::vector<dg::View< container>> out_split = dg::split( out, *m_g);
932 std::vector<dg::View< const container>> in_split = dg::split( in, grid);
933 for ( int i=0; i<(int)Nz_coarse; i++)
934 {
935 //1. copy input vector to appropriate place in output
936 dg::blas1::copy( in_split[i], out_split[i*cphi]);
937 dg::blas1::copy( in_split[i], m_temp[i*cphi]);
938 }
939 //Step 1 needs to finish so that m_temp contains values everywhere
940 //2. Now apply plus and minus T to fill in the rest
941 for ( int i=0; i<(int)Nz_coarse; i++)
942 {
943 for( int j=1; j<(int)cphi; j++)
944 {
946 dg::blas2::symv( m_minus, out_split[i*cphi+j-1], out_split[i*cphi+j]);
948 dg::blas2::symv( m_plus, m_temp[(i*cphi+cphi+1-j)%Nz], m_temp[i*cphi+cphi-j]);
949 }
950 }
951 //3. Now add up with appropriate weights
952 for( int i=0; i<(int)Nz_coarse; i++)
953 for( int j=1; j<(int)cphi; j++)
954 {
955 double alpha = (double)(cphi-j)/(double)cphi;
956 double beta = (double)j/(double)cphi;
957 dg::blas1::axpby( alpha, out_split[i*cphi+j], beta, m_temp[i*cphi+j], out_split[i*cphi+j]);
958 }
959 return out;
960}
961template<class G, class I, class container>
962void Fieldaligned<G, I,container>::integrate_between_coarse_grid( const G& grid, const container& in, container& out)
963{
964 assert( m_g->Nz() % grid.Nz() == 0);
965 unsigned Nz_coarse = grid.Nz(), Nz = m_g->Nz();
966 unsigned cphi = Nz / Nz_coarse;
967
968 out = in;
969 container helperP( in), helperM(in), tempP(in), tempM(in);
970
971 //1. Apply plus and minus T and sum up
972 for( int j=1; j<(int)cphi; j++)
973 {
975 dg::blas2::symv( m_minus, helperP, tempP);
976 dg::blas1::axpby( (double)(cphi-j)/(double)cphi, tempP, 1., out );
977 helperP.swap(tempP);
979 dg::blas2::symv( m_plus, helperM, tempM);
980 dg::blas1::axpby( (double)(cphi-j)/(double)cphi, tempM, 1., out );
981 helperM.swap(tempM);
982 }
983 dg::blas1::scal( out, 1./(double)cphi);
984}
985
986template<class G, class I, class container>
987void Fieldaligned<G, I, container >::operator()(enum whichMatrix which, const container& f, container& fe)
988{
989 if( which == einsPlus || which == einsMinusT ) ePlus( which, f, fe);
990 else if(which == einsMinus || which == einsPlusT ) eMinus( which, f, fe);
991 else if(which == zeroMinus || which == zeroPlus ||
992<<<<<<< Updated upstream
993 which == zeroMinusT|| which == zeroPlusT ||
994 which == zeroForw || which == zeroBack ) zero( which, f, fe);
995 if( (m_interpolation_method == "linear" || m_interpolation_method == "linear-const") && which != zeroForw && which != zeroBack)
996 {
997 dg::blas2::symv( m_inv_linear, fe, m_tmp);
998 m_tmp.swap( fe);
999 }
1000=======
1001 which == zeroMinusT|| which == zeroPlusT || which == zeroZero ) zero( which, f, fe);
1002>>>>>>> Stashed changes
1003}
1004
1005template< class G, class I, class container>
1006void Fieldaligned<G, I, container>::zero( enum whichMatrix which,
1007 const container& f, container& f0)
1008{
1009 dg::split( f, m_f, *m_g);
1010 dg::split( f0, m_temp, *m_g);
1011 //1. compute 2d interpolation in every plane and store in m_temp
1012 for( unsigned i0=0; i0<m_Nz; i0++)
1013 {
1014 if(which == zeroPlus)
1015 dg::blas2::symv( m_plus, m_f[i0], m_temp[i0]);
1016 else if(which == zeroMinus)
1017 dg::blas2::symv( m_minus, m_f[i0], m_temp[i0]);
1018 else if(which == zeroPlusT)
1019 {
1020 if( ! m_have_adjoint) updateAdjoint( );
1021 dg::blas2::symv( m_plusT, m_f[i0], m_temp[i0]);
1022 }
1023 else if(which == zeroMinusT)
1024 {
1025 if( ! m_have_adjoint) updateAdjoint( );
1026 dg::blas2::symv( m_minusT, m_f[i0], m_temp[i0]);
1027 }
1028 else if( which == zeroZero)
1029 {
1030 dg::blas2::symv( m_back, m_f[i0], m_temp[i0]);
1031 dg::blas2::stencil( dg::CSRAverageFilter(), m_stencil, m_temp[i0], m_temp2d);
1032 dg::blas2::symv( m_forw, m_temp2d, m_temp[i0]);
1033 }
1034 }
1035 if( which == zeroForw)
1036 {
1037 if( m_interpolation_method == "dg-const")
1038 {
1039 dg::blas2::symv( m_forw, f, f0);
1040 }
1041 //else if ( m_interpolation_method == "linear-const" )
1042 //{
1043 // dg::blas2::symv( m_inv_linear.tri(), f, f0);
1044 //}
1045 else
1046 dg::blas1::copy( f, f0);
1047 }
1048 if( which == zeroBack)
1049 {
1050 if( m_interpolation_method == "dg-const")
1051 {
1052 dg::blas2::symv( m_back, f, f0);
1053 }
1054 //else if ( m_interpolation_method == "linear-const")
1055 //{
1056 // dg::blas2::symv( m_inv_linear, f, f0);
1057 //}
1058 else
1059 dg::blas1::copy( f, f0);
1060 }
1061}
1062template< class G, class I, class container>
1063void Fieldaligned<G, I, container>::ePlus( enum whichMatrix which,
1064 const container& f, container& fpe)
1065{
1066 dg::split( f, m_f, *m_g);
1067 dg::split( fpe, m_temp, *m_g);
1068 //1. compute 2d interpolation in every plane and store in m_temp
1069 for( unsigned i0=0; i0<m_Nz; i0++)
1070 {
1071 unsigned ip = (i0==m_Nz-1) ? 0:i0+1;
1072 if(which == einsPlus)
1073 dg::blas2::symv( m_plus, m_f[ip], m_temp[i0]);
1074 else if(which == einsMinusT)
1075 {
1076 if( ! m_have_adjoint) updateAdjoint( );
1077 dg::blas2::symv( m_minusT, m_f[ip], m_temp[i0]);
1078 }
1079 }
1080 //2. apply right boundary conditions in last plane
1081 unsigned i0=m_Nz-1;
1082 if( m_bcz != dg::PER)
1083 {
1084 if( m_bcz == dg::DIR || m_bcz == dg::NEU_DIR)
1085 dg::blas1::axpby( 2, m_right, -1., m_f[i0], m_ghostP);
1086 if( m_bcz == dg::NEU || m_bcz == dg::DIR_NEU)
1087 dg::blas1::axpby( m_deltaPhi, m_right, 1., m_f[i0], m_ghostP);
1088 //interlay ghostcells with periodic cells: L*g + (1-L)*fpe
1089 dg::blas1::axpby( 1., m_ghostP, -1., m_temp[i0], m_ghostP);
1090 dg::blas1::pointwiseDot( 1., m_limiter, m_ghostP, 1., m_temp[i0]);
1091 }
1092}
1093
1094template< class G, class I, class container>
1095void Fieldaligned<G, I, container>::eMinus( enum whichMatrix which,
1096 const container& f, container& fme)
1097{
1098 dg::split( f, m_f, *m_g);
1099 dg::split( fme, m_temp, *m_g);
1100 //1. compute 2d interpolation in every plane and store in m_temp
1101 for( unsigned i0=0; i0<m_Nz; i0++)
1102 {
1103 unsigned im = (i0==0) ? m_Nz-1:i0-1;
1104 if(which == einsPlusT)
1105 {
1106 if( ! m_have_adjoint) updateAdjoint( );
1107 dg::blas2::symv( m_plusT, m_f[im], m_temp[i0]);
1108 }
1109 else if (which == einsMinus)
1110 dg::blas2::symv( m_minus, m_f[im], m_temp[i0]);
1111 }
1112 //2. apply left boundary conditions in first plane
1113 unsigned i0=0;
1114 if( m_bcz != dg::PER)
1115 {
1116 if( m_bcz == dg::DIR || m_bcz == dg::DIR_NEU)
1117 dg::blas1::axpby( 2., m_left, -1., m_f[i0], m_ghostM);
1118 if( m_bcz == dg::NEU || m_bcz == dg::NEU_DIR)
1119 dg::blas1::axpby( -m_deltaPhi, m_left, 1., m_f[i0], m_ghostM);
1120 //interlay ghostcells with periodic cells: L*g + (1-L)*fme
1121 dg::blas1::axpby( 1., m_ghostM, -1., m_temp[i0], m_ghostM);
1122 dg::blas1::pointwiseDot( 1., m_limiter, m_ghostM, 1., m_temp[i0]);
1123 }
1124}
1125
1126template<class G, class I, class container>
1127template< class BinaryOp, class UnaryOp>
1128container Fieldaligned<G, I,container>::evaluate( BinaryOp binary,
1129 UnaryOp unary, unsigned p0, unsigned rounds) const
1130{
1131 //idea: simply apply I+/I- enough times on the init2d vector to get the result in each plane
1132 //unary function is always such that the p0 plane is at x=0
1133 assert( p0 < m_g->Nz());
1134 const dg::ClonePtr<aGeometry2d> g2d = m_g->perp_grid();
1135 container init2d = dg::pullback( binary, *g2d);
1136 container zero2d = dg::evaluate( dg::zero, *g2d);
1137
1138 container temp(init2d), tempP(init2d), tempM(init2d);
1139 container vec3d = dg::evaluate( dg::zero, *m_g);
1140 std::vector<container> plus2d(m_Nz, zero2d), minus2d(plus2d), result(plus2d);
1141 unsigned turns = rounds;
1142 if( turns ==0) turns++;
1143 //first apply Interpolation many times, scale and store results
1144 for( unsigned r=0; r<turns; r++)
1145 for( unsigned i0=0; i0<m_Nz; i0++)
1146 {
1147 dg::blas1::copy( init2d, tempP);
1148 dg::blas1::copy( init2d, tempM);
1149 unsigned rep = r*m_Nz + i0;
1150 for(unsigned k=0; k<rep; k++)
1151 {
1153 dg::blas2::symv( m_minus, tempP, temp);
1154 temp.swap( tempP);
1156 dg::blas2::symv( m_plus, tempM, temp);
1157 temp.swap( tempM);
1158 }
1159 dg::blas1::scal( tempP, unary( (double)rep*m_deltaPhi ) );
1160 dg::blas1::scal( tempM, unary( -(double)rep*m_deltaPhi ) );
1161 dg::blas1::axpby( 1., tempP, 1., plus2d[i0]);
1162 dg::blas1::axpby( 1., tempM, 1., minus2d[i0]);
1163 }
1164 //now we have the plus and the minus filaments
1165 if( rounds == 0) //there is a limiter
1166 {
1167 for( unsigned i0=0; i0<m_Nz; i0++)
1168 {
1169 int idx = (int)i0 - (int)p0;
1170 if(idx>=0)
1171 result[i0] = plus2d[idx];
1172 else
1173 result[i0] = minus2d[abs(idx)];
1174 thrust::copy( result[i0].begin(), result[i0].end(), vec3d.begin() + i0*m_perp_size);
1175 }
1176 }
1177 else //sum up plus2d and minus2d
1178 {
1179 for( unsigned i0=0; i0<m_Nz; i0++)
1180 {
1181 unsigned revi0 = (m_Nz - i0)%m_Nz; //reverted index
1182 dg::blas1::axpby( 1., plus2d[i0], 0., result[i0]);
1183 dg::blas1::axpby( 1., minus2d[revi0], 1., result[i0]);
1184 }
1185 dg::blas1::axpby( -1., init2d, 1., result[0]);
1186 for(unsigned i0=0; i0<m_Nz; i0++)
1187 {
1188 int idx = ((int)i0 -(int)p0 + m_Nz)%m_Nz; //shift index
1189 thrust::copy( result[idx].begin(), result[idx].end(), vec3d.begin() + i0*m_perp_size);
1190 }
1191 }
1192 return vec3d;
1193}
1194
1195
1197
1229template<class BinaryOp, class UnaryOp>
1230thrust::host_vector<double> fieldaligned_evaluate(
1231 const aProductGeometry3d& grid,
1232 const CylindricalVectorLvl0& vec,
1233 const BinaryOp& binary,
1234 const UnaryOp& unary,
1235 unsigned p0,
1236 unsigned rounds,
1237 double eps = 1e-5)
1238{
1239 unsigned Nz = grid.Nz();
1240 const dg::ClonePtr<aGeometry2d> g2d = grid.perp_grid();
1241 // Construct for field-aligned output
1242 dg::HVec tempP = dg::evaluate( dg::zero, *g2d), tempM( tempP);
1243 std::vector<dg::HVec> plus2d(Nz, tempP), minus2d(plus2d), result(plus2d);
1244 dg::HVec vec3d = dg::evaluate( dg::zero, grid);
1245 dg::HVec init2d = dg::pullback( binary, *g2d);
1246 std::array<dg::HVec,3> yy0{
1247 dg::pullback( dg::cooX2d, *g2d),
1248 dg::pullback( dg::cooY2d, *g2d),
1249 dg::evaluate( dg::zero, *g2d)}, yy1(yy0), xx0( yy0), xx1(yy0); //s
1250 dg::geo::detail::DSFieldCylindrical3 cyl_field(vec);
1251 double deltaPhi = grid.hz();
1252 double phiM0 = 0., phiP0 = 0.;
1253 unsigned turns = rounds;
1254 if( turns == 0) turns++;
1255 for( unsigned r=0; r<turns; r++)
1256 for( unsigned i0=0; i0<Nz; i0++)
1257 {
1258 unsigned rep = r*Nz + i0;
1259 if( rep == 0)
1260 tempM = tempP = init2d;
1261 else
1262 {
1264 "Dormand-Prince-7-4-5", std::array<double,3>{0,0,0});
1266 cyl_field, dg::pid_control, dg::fast_l2norm, eps,
1267 1e-10);
1268 for( unsigned i=0; i<g2d->size(); i++)
1269 {
1270 // minus direction needs positive integration!
1271 double phiM1 = phiM0 + deltaPhi;
1272 std::array<double,3>
1273 coords0{yy0[0][i],yy0[1][i],yy0[2][i]}, coords1;
1274 odeint.integrate_in_domain( phiM0, coords0, phiM1, coords1,
1275 deltaPhi, *g2d, eps);
1276 yy1[0][i] = coords1[0], yy1[1][i] = coords1[1], yy1[2][i] =
1277 coords1[2];
1278 tempM[i] = binary( yy1[0][i], yy1[1][i]);
1279
1280 // plus direction needs negative integration!
1281 double phiP1 = phiP0 - deltaPhi;
1282 coords0 = std::array<double,3>{xx0[0][i],xx0[1][i],xx0[2][i]};
1283 odeint.integrate_in_domain( phiP0, coords0, phiP1, coords1,
1284 -deltaPhi, *g2d, eps);
1285 xx1[0][i] = coords1[0], xx1[1][i] = coords1[1], xx1[2][i] =
1286 coords1[2];
1287 tempP[i] = binary( xx1[0][i], xx1[1][i]);
1288 }
1289 std::swap( yy0, yy1);
1290 std::swap( xx0, xx1);
1291 phiM0 += deltaPhi;
1292 phiP0 -= deltaPhi;
1293 }
1294 dg::blas1::scal( tempM, unary( -(double)rep*deltaPhi ) );
1295 dg::blas1::scal( tempP, unary( (double)rep*deltaPhi ) );
1296 dg::blas1::axpby( 1., tempM, 1., minus2d[i0]);
1297 dg::blas1::axpby( 1., tempP, 1., plus2d[i0]);
1298 }
1299 //now we have the plus and the minus filaments
1300 if( rounds == 0) //there is a limiter
1301 {
1302 for( unsigned i0=0; i0<Nz; i0++)
1303 {
1304 int idx = (int)i0 - (int)p0;
1305 if(idx>=0)
1306 result[i0] = plus2d[idx];
1307 else
1308 result[i0] = minus2d[abs(idx)];
1309 thrust::copy( result[i0].begin(), result[i0].end(), vec3d.begin() +
1310 i0*g2d->size());
1311 }
1312 }
1313 else //sum up plus2d and minus2d
1314 {
1315 for( unsigned i0=0; i0<Nz; i0++)
1316 {
1317 unsigned revi0 = (Nz - i0)%Nz; //reverted index
1318 dg::blas1::axpby( 1., plus2d[i0], 0., result[i0]);
1319 dg::blas1::axpby( 1., minus2d[revi0], 1., result[i0]);
1320 }
1321 dg::blas1::axpby( -1., init2d, 1., result[0]);
1322 for(unsigned i0=0; i0<Nz; i0++)
1323 {
1324 int idx = ((int)i0 -(int)p0 + Nz)%Nz; //shift index
1325 thrust::copy( result[idx].begin(), result[idx].end(), vec3d.begin()
1326 + i0*g2d->size());
1327 }
1328 }
1329 return vec3d;
1330}
1331
1332}//namespace geo
1333}//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 plus(ContainerType &x, get_value_type< ContainerType > alpha)
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 pointwiseDivide(get_value_type< ContainerType > alpha, const ContainerType1 &x1, const ContainerType2 &x2, get_value_type< ContainerType > beta, ContainerType &y)
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)
void stencil(FunctorType f, MatrixType &&M, const ContainerType1 &x, ContainerType2 &y)
static std::string bc2str(bc bcx)
thrust::host_vector< real_type > evaluate(UnaryOp f, const RealGrid1d< real_type > &g)
thrust::host_vector< real_type > fem_inv_weights(const RealGrid1d< real_type > &g)
dg::InverseKroneckerTriDiagonal2d< dg::HVec_t< real_type > > inv_fem_mass2d(const aRealTopology3d< real_type > &g)
dg::InverseKroneckerTriDiagonal2d< dg::HVec_t< real_type > > inv_fem_linear2const2d(const aRealTopology3d< real_type > &g)
whichMatrix
Enum for the use in Fieldaligned.
Definition: fieldaligned.h:17
ZERO NoLimiter
No Limiter.
Definition: fieldaligned.h:35
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:1204
ONE FullLimiter
Full Limiter means there is a limiter everywhere.
Definition: fieldaligned.h:31
@ zeroBack
from transfomred back to dg coordinates
Definition: fieldaligned_coarse.h:27
@ 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 > diagonal(const thrust::host_vector< real_type > &diagonal)
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")
cusp::coo_matrix< int, real_type, cusp::host_memory > transformation(const aRealTopology3d< real_type > &g_new, const aRealTopology3d< real_type > &g_old)
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
get_host_vector< Geometry > volume(const Geometry &g)
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)
thrust::host_vector< real_type > pullback(const Functor &f, const aRealGeometryX2d< real_type > &g)
void pushForwardPerp(const Functor1 &vR, const Functor2 &vZ, container &vx, container &vy, const Geometry &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)
dg::IHMatrix_t< real_type > backscatter(const RealGrid1d< real_type > &g)
dg::IHMatrix_t< real_type > inv_backscatter(const RealGrid1d< real_type > &g)
dg::IHMatrix_t< real_type > window_stencil(unsigned window_size, const RealGrid1d< real_type > &g, dg::bc bcx)
ContainerType volume(const SparseTensor< ContainerType > &t)
static auto pid_control
static auto fast_l2norm
IHMatrix_t< double > IHMatrix
thrust::host_vector< double > HVec
void set_dt(value_type dt)
void integrate_in_domain(value_type t0, const ContainerType &u0, value_type &t1, ContainerType &u1, value_type dt, Domain &&domain, value_type eps_root)
double diff() const
void toc()
void tic()
aRealGeometry2d< real_type > * perp_grid() const
bool contains(real_type x, real_type y) const
unsigned size() const
real_type hz() const
unsigned Nz() const
void integrate(value_type t0, const ContainerType &u0, value_type t1, ContainerType &u1)
Definition: fluxfunctions.h:412
This struct bundles a vector field and its divergence.
Definition: fluxfunctions.h:440
const CylindricalFunctor & y() const
y-component of the vector
Definition: fluxfunctions.h:468
const CylindricalFunctor & x() const
x-component of the vector
Definition: fluxfunctions.h:466
const CylindricalFunctor & divvvz() const
Definition: fluxfunctions.h:474
const CylindricalFunctor & z() const
z-component of the vector
Definition: fluxfunctions.h:470
Create and manage interpolation matrices from fieldline integration.
Definition: fieldaligned.h:433
dg::bc bcx() const
Definition: fieldaligned.h:484
const container & hbp() const
Distance between the planes .
Definition: fieldaligned_coarse.h:507
const container & bphi() const
bphi
Definition: fieldaligned_coarse.h:527
container interpolate_from_coarse_grid(const ProductGeometry &grid_coarse, const container &coarse)
Interpolate along fieldlines from a coarse to a fine grid in phi.
void integrate_between_coarse_grid(const ProductGeometry &grid_coarse, const container &coarse, container &out)
Integrate a 2d function on the fine grid.
const container & bbp() const
Mask plus, 1 if fieldline intersects wall in plus direction but not in minus direction,...
Definition: fieldaligned_coarse.h:552
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_coarse.h:512
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_coarse.h:517
void set_boundaries(dg::bc bcz, double left, double right)
Set boundary conditions in the limiter region.
Definition: fieldaligned_coarse.h:447
std::string method() const
Definition: fieldaligned_coarse.h:616
const container & hbm() const
Distance between the planes and the boundary .
Definition: fieldaligned_coarse.h:502
void set_boundaries(dg::bc bcz, const container &global, double scal_left, double scal_right)
Set boundary conditions in the limiter region.
Definition: fieldaligned_coarse.h:481
const container & bphiM() const
bphi on minus plane
Definition: fieldaligned_coarse.h:532
dg::bc bcy() const
Definition: fieldaligned.h:487
double deltaPhi() const
Definition: fieldaligned.h:553
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=10, unsigned my=10, double deltaPhi=-1, std::string interpolation_method="dg", bool benchmark=true)
Construct from a magnetic field and a grid.
Definition: fieldaligned_coarse.h:387
Fieldaligned()
do not allocate memory; no member call except construct is valid
Definition: fieldaligned_coarse.h:382
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: fieldaligned_coarse.h:424
const container & bbo() const
Mask both, 1 if fieldline intersects wall in plus direction and in minus direction,...
Definition: fieldaligned_coarse.h:547
const container & bbm() const
Mask minus, 1 if fieldline intersects wall in minus direction but not in plus direction,...
Definition: fieldaligned_coarse.h:542
const container & sqrtGp() const
Volume form on plus plane (including weights) .
Definition: fieldaligned_coarse.h:522
const container & bphiP() const
bphi on plus plane
Definition: fieldaligned_coarse.h:537
const ProductGeometry & grid() const
Grid used for construction.
Definition: fieldaligned.h:610
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=10, unsigned my=10, double deltaPhi=-1, std::string interpolation_method="dg", bool benchmark=true)
Construct from a vector field and a grid.
void set_boundaries(dg::bc bcz, const container &left, const container &right)
Set boundary conditions in the limiter region.
Definition: fieldaligned_coarse.h:464
A tokamak field as given by R0, Psi and Ipol plus Meta-data like shape and equilibrium.
Definition: magnetic_field.h:162
WallFieldlineCoordinate(const dg::geo::CylindricalVectorLvl0 &vec, const dg::aRealTopology2d< double > &domain, double maxPhi, double eps, std::string type)
Construct with vector field, domain.
Definition: fieldaligned_coarse.h:272
double do_compute(double R, double Z) const
Definition: fieldaligned_coarse.h:282
WallFieldlineDistance(const dg::geo::CylindricalVectorLvl0 &vec, const dg::aRealTopology2d< double > &domain, double maxPhi, double eps, std::string type)
Construct with vector field, domain.
Definition: fieldaligned_coarse.h:202
double do_compute(double R, double Z) const
Integrate fieldline until wall is reached.
Definition: fieldaligned_coarse.h:222