Extension: Geometries
#include "dg/geometries/geometries.h"
fieldaligned.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{
27};
28
32
37namespace detail{
38
39static void parse_method( std::string method, std::string& i, std::string& p, std::string& f)
40{
41 f = "dg";
42 if( method == "dg") i = "dg", p = "dg";
43 else if( method == "linear") i = "linear", p = "dg";
44 else if( method == "cubic") i = "cubic", p = "dg";
45 else if( method == "nearest") i = "nearest", p = "dg";
46 else if( method == "dg-nearest") i = "dg", p = "nearest";
47 else if( method == "linear-nearest") i = "linear", p = "nearest";
48 else if( method == "cubic-nearest") i = "cubic", p = "nearest";
49 else if( method == "nearest-nearest") i = "nearest", p = "nearest";
50 else if( method == "dg-linear") i = "dg", p = "linear";
51 else if( method == "linear-linear") i = "linear", p = "linear";
52 else if( method == "cubic-linear") i = "cubic", p = "linear";
53 else if( method == "nearest-linear") i = "nearest", p = "linear";
54 else if( method == "dg-equi") i = "dg", p = "dg", f = "equi";
55 else if( method == "linear-equi") i = "linear", p = "dg", f = "equi";
56 else if( method == "cubic-equi") i = "cubic", p = "dg", f = "equi";
57 else if( method == "nearest-equi") i = "nearest", p = "dg", f = "equi";
58 else if( method == "dg-equi-nearest") i = "dg", p = "nearest", f = "equi";
59 else if( method == "linear-equi-nearest") i = "linear", p = "nearest", f = "equi";
60 else if( method == "cubic-equi-nearest") i = "cubic", p = "nearest", f = "equi";
61 else if( method == "nearest-equi-nearest") i = "nearest", p = "nearest", f = "equi";
62 else if( method == "dg-equi-linear") i = "dg", p = "linear", f = "equi";
63 else if( method == "linear-equi-linear") i = "linear", p = "linear", f = "equi";
64 else if( method == "cubic-equi-linear") i = "cubic", p = "linear", f = "equi";
65 else if( method == "nearest-equi-linear") i = "nearest", p = "linear", f = "equi";
66 else
67 throw Error( Message(_ping_) << "The method "<< method << " is not recognized\n");
68}
69
70struct DSFieldCylindrical3
71{
72 DSFieldCylindrical3( const dg::geo::CylindricalVectorLvl0& v): m_v(v){}
73 void operator()( double t, const std::array<double,3>& y,
74 std::array<double,3>& yp) const {
75 double R = y[0], Z = y[1];
76 double vz = m_v.z()(R, Z);
77 yp[0] = m_v.x()(R, Z)/vz;
78 yp[1] = m_v.y()(R, Z)/vz;
79 yp[2] = 1./vz;
80 }
81 private:
83};
84
85struct DSFieldCylindrical4
86{
87 DSFieldCylindrical4( const dg::geo::CylindricalVectorLvl1& v): m_v(v){}
88 void operator()( double t, const std::array<double,3>& y,
89 std::array<double,3>& yp) const {
90 double R = y[0], Z = y[1];
91 double vx = m_v.x()(R,Z);
92 double vy = m_v.y()(R,Z);
93 double vz = m_v.z()(R,Z);
94 double divvvz = m_v.divvvz()(R,Z);
95 yp[0] = vx/vz;
96 yp[1] = vy/vz;
97 yp[2] = divvvz*y[2];
98 }
99
100 private:
102};
103
104struct DSField
105{
106 DSField() = default;
107 //z component of v may not vanish
108 DSField( const dg::geo::CylindricalVectorLvl1& v,
109 const dg::aGeometry2d& g ):
110 m_g(g)
111 {
112 dg::HVec v_zeta, v_eta;
113 dg::pushForwardPerp( v.x(), v.y(), v_zeta, v_eta, g);
114 dg::HVec vx = dg::pullback( v.x(), g);
115 dg::HVec vy = dg::pullback( v.y(), g);
116 dg::HVec vz = dg::pullback( v.z(), g);
117 dg::HVec divvvz = dg::pullback( v.divvvz(), g);
118 dg::blas1::pointwiseDivide(v_zeta, vz, v_zeta);
119 dg::blas1::pointwiseDivide(v_eta, vz, v_eta);
120 dzetadphi_ = dg::forward_transform( v_zeta, g );
121 detadphi_ = dg::forward_transform( v_eta, g );
122 dvdphi_ = dg::forward_transform( divvvz, g );
123 }
124 //interpolate the vectors given in the constructor on the given point
125 void operator()(double t, const std::array<double,3>& y, std::array<double,3>& yp) const
126 {
127 // shift point into domain
128 yp[0] = interpolate(dg::lspace, dzetadphi_, y[0], y[1], *m_g);
129 yp[1] = interpolate(dg::lspace, detadphi_, y[0], y[1], *m_g);
130 yp[2] = interpolate(dg::lspace, dvdphi_, y[0], y[1], *m_g)*y[2];
131 }
132 private:
133 thrust::host_vector<double> dzetadphi_, detadphi_, dvdphi_;
135};
136
137//used in constructor of Fieldaligned
138template<class real_type>
139void integrate_all_fieldlines2d( const dg::geo::CylindricalVectorLvl1& vec,
140 const dg::aRealGeometry2d<real_type>& grid_field,
141 const dg::aRealTopology2d<real_type>& grid_evaluate,
142 std::array<thrust::host_vector<real_type>,3>& yp,
143 const thrust::host_vector<double>& vol0,
144 thrust::host_vector<real_type>& yp2b,
145 thrust::host_vector<bool>& in_boxp,
146 real_type deltaPhi, real_type eps)
147{
148 //grid_field contains the global geometry for the field and the boundaries
149 //grid_evaluate contains the points to actually integrate
150 std::array<thrust::host_vector<real_type>,3> y{
151 dg::evaluate( dg::cooX2d, grid_evaluate),
152 dg::evaluate( dg::cooY2d, grid_evaluate),
153 vol0
154 };
155 yp.fill(dg::evaluate( dg::zero, grid_evaluate));
156 //construct field on high polynomial grid, then integrate it
157 dg::geo::detail::DSField field;
158 if( !dynamic_cast<const dg::CartesianGrid2d*>( &grid_field))
159 field = dg::geo::detail::DSField( vec, grid_field);
160
161 //field in case of cartesian grid
162 dg::geo::detail::DSFieldCylindrical4 cyl_field(vec);
163 const unsigned size = grid_evaluate.size();
165 "Dormand-Prince-7-4-5", std::array<real_type,3>{0,0,0});
167 if( dynamic_cast<const dg::CartesianGrid2d*>( &grid_field))
169 cyl_field, dg::pid_control, dg::fast_l2norm, eps, 1e-10);
170 else
172 field, dg::pid_control, dg::fast_l2norm, eps, 1e-10);
173
174 for( unsigned i=0; i<size; i++)
175 {
176 std::array<real_type,3> coords{y[0][i],y[1][i],y[2][i]}, coordsP;
177 //x,y,s
178 real_type phi1 = deltaPhi;
179 odeint.set_dt( deltaPhi/2.);
180 odeint.integrate( 0, coords, phi1, coordsP);
181 yp[0][i] = coordsP[0], yp[1][i] = coordsP[1], yp[2][i] = coordsP[2];
182 }
183 yp2b.assign( grid_evaluate.size(), deltaPhi); //allocate memory for output
184 in_boxp.resize( yp2b.size());
185 //Now integrate again but this time find the boundary distance
186 for( unsigned i=0; i<size; i++)
187 {
188 std::array<real_type,3> coords{y[0][i],y[1][i],y[2][i]}, coordsP;
189 in_boxp[i] = grid_field.contains( yp[0][i], yp[1][i]) ? true : false;
190 if( false == in_boxp[i])
191 {
192 //x,y,s
193 real_type phi1 = deltaPhi;
194 odeint.integrate_in_domain( 0., coords, phi1, coordsP, 0., (const
195 dg::aRealTopology2d<real_type>&)grid_field, eps);
196 yp2b[i] = phi1;
197 }
198 }
199}
200
201
202}//namespace detail
204
220struct WallFieldlineDistance : public aCylindricalFunctor<WallFieldlineDistance>
221{
234 const dg::aRealTopology2d<double>& domain,
235 double maxPhi, double eps, std::string type) :
236 m_domain( domain), m_cyl_field(vec),
237 m_deltaPhi( maxPhi), m_eps( eps), m_type(type)
238 {
239 if( m_type != "phi" && m_type != "s")
240 throw std::runtime_error( "Distance type "+m_type+" not recognized!\n");
241 }
252 double do_compute( double R, double Z) const
253 {
254 std::array<double,3> coords{ R, Z, 0}, coordsP(coords);
255 // determine sign
256 m_cyl_field( 0., coords, coordsP);
257 double sign = coordsP[2] > 0 ? +1. : -1.;
258 double phi1 = sign*m_deltaPhi; // we integrate negative ...
259 try{
261 "Dormand-Prince-7-4-5", coords);
263 m_cyl_field, dg::pid_control, dg::fast_l2norm, m_eps,
264 1e-10);
265 odeint.integrate_in_domain( 0., coords, phi1, coordsP, 0.,
266 m_domain, m_eps);
267 //integration
268 }catch (std::exception& e)
269 {
270 // if not possible the distance is large
271 //std::cerr << e.what();
272 phi1 = sign*m_deltaPhi;
273 coordsP[2] = 1e6*phi1;
274 }
275 if( m_type == "phi")
276 return sign*phi1;
277 return coordsP[2];
278 }
279
280 private:
281 const dg::Grid2d m_domain;
282 dg::geo::detail::DSFieldCylindrical3 m_cyl_field;
283 double m_deltaPhi, m_eps;
284 std::string m_type;
285};
286
307struct WallFieldlineCoordinate : public aCylindricalFunctor<WallFieldlineCoordinate>
308{
313 const dg::aRealTopology2d<double>& domain,
314 double maxPhi, double eps, std::string type) :
315 m_domain( domain), m_cyl_field(vec),
316 m_deltaPhi( maxPhi), m_eps( eps), m_type(type)
317 {
318 if( m_type != "phi" && m_type != "s")
319 throw std::runtime_error( "Distance type "+m_type+" not recognized!\n");
320 }
321 double do_compute( double R, double Z) const
322 {
323 double phiP = m_deltaPhi, phiM = -m_deltaPhi;
324 std::array<double,3> coords{ R, Z, 0}, coordsP(coords), coordsM(coords);
325 // determine sign
326 m_cyl_field( 0., coords, coordsP);
327 double sign = coordsP[2] > 0 ? +1. : -1.;
328 try{
330 dg::Adaptive<dg::ERKStep<std::array<double,3>>>(
331 "Dormand-Prince-7-4-5", coords), m_cyl_field,
332 dg::pid_control, dg::fast_l2norm, m_eps, 1e-10);
333 odeint.integrate_in_domain( 0., coords, phiP, coordsP, 0.,
334 m_domain, m_eps);
335 odeint.integrate_in_domain( 0., coords, phiM, coordsM, 0.,
336 m_domain, m_eps);
337 }catch (std::exception& e)
338 {
339 // if not possible the distance is large
340 phiP = m_deltaPhi;
341 coordsP[2] = 1e6*phiP;
342 phiM = -m_deltaPhi;
343 coordsM[2] = 1e6*phiM;
344 }
345 if( m_type == "phi")
346 return sign*(-phiP-phiM)/(phiP-phiM);
347 double sP = coordsP[2], sM = coordsM[2];
348 double value = sign*(-sP-sM)/(sP-sM);
349 if( (phiM <= -m_deltaPhi) && (phiP >= m_deltaPhi))
350 return 0.; //return exactly zero if sheath not reached
351 if( (phiM <= -m_deltaPhi))
352 return value*sign > 0 ? value : 0.; // avoid false negatives
353 if( (phiP >= m_deltaPhi))
354 return value*sign < 0 ? value : 0.; // avoid false positives
355 return value;
356 }
357
358 private:
359 const dg::Grid2d m_domain;
360 dg::geo::detail::DSFieldCylindrical3 m_cyl_field;
361 double m_deltaPhi, m_eps;
362 std::string m_type;
363};
364
365
419
431template<class ProductGeometry, class IMatrix, class container >
433{
434
440 template <class Limiter>
442 const ProductGeometry& grid,
445 Limiter limit = FullLimiter(),
446 double eps = 1e-5,
447 unsigned mx=12, unsigned my=12,
448 double deltaPhi = -1,
449 std::string interpolation_method = "linear-nearest",
450 bool benchmark=true
451 ):
452 Fieldaligned( dg::geo::createBHat(vec),
453 grid, bcx, bcy, limit, eps, mx, my, deltaPhi, interpolation_method)
454 {
455 }
456
460 template <class Limiter>
462 const ProductGeometry& grid,
465 Limiter limit = FullLimiter(),
466 double eps = 1e-5,
467 unsigned mx=12, unsigned my=12,
468 double deltaPhi = -1,
469 std::string interpolation_method = "linear-nearest",
470 bool benchmark=true
471 );
477 template<class ...Params>
478 void construct( Params&& ...ps)
479 {
480 //construct and swap
481 *this = Fieldaligned( std::forward<Params>( ps)...);
482 }
483
484 dg::bc bcx()const{
485 return m_bcx;
486 }
487 dg::bc bcy()const{
488 return m_bcy;
489 }
490
491
501 void set_boundaries( dg::bc bcz, double left, double right)
502 {
503 m_bcz = bcz;
504 const dg::Grid1d g2d( 0, 1, 1, m_perp_size);
505 m_left = dg::evaluate( dg::CONSTANT(left), g2d);
506 m_right = dg::evaluate( dg::CONSTANT(right),g2d);
507 }
508
518 void set_boundaries( dg::bc bcz, const container& left, const container& right)
519 {
520 m_bcz = bcz;
521 m_left = left;
522 m_right = right;
523 }
524
535 void set_boundaries( dg::bc bcz, const container& global, double scal_left, double scal_right)
536 {
537 dg::split( global, m_f, *m_g);
538 dg::blas1::axpby( scal_left, m_f[0], 0, m_left);
539 dg::blas1::axpby( scal_right, m_f[m_Nz-1], 0, m_right);
540 m_bcz = bcz;
541 }
542
551 void operator()(enum whichMatrix which, const container& in, container& out);
552
553 double deltaPhi() const{return m_deltaPhi;}
556 const container& hbm()const {
557 return m_hbm;
558 }
561 const container& hbp()const {
562 return m_hbp;
563 }
566 const container& sqrtG()const {
567 return m_G;
568 }
571 const container& sqrtGm()const {
572 return m_Gm;
573 }
576 const container& sqrtGp()const {
577 return m_Gp;
578 }
581 const container& bphi()const {
582 return m_bphi;
583 }
586 const container& bphiM()const {
587 return m_bphiM;
588 }
591 const container& bphiP()const {
592 return m_bphiP;
593 }
596 const container& bbm()const {
597 return m_bbm;
598 }
601 const container& bbo()const {
602 return m_bbo;
603 }
606 const container& bbp()const {
607 return m_bbp;
608 }
610 const ProductGeometry& grid()const{return *m_g;}
611
625 container interpolate_from_coarse_grid( const ProductGeometry& grid_coarse, const container& coarse);
635 void integrate_between_coarse_grid( const ProductGeometry& grid_coarse, const container& coarse, container& out );
636
637
666 template< class BinaryOp, class UnaryOp>
667 container evaluate( BinaryOp binary, UnaryOp unary,
668 unsigned p0, unsigned rounds) const;
669
671 std::string method() const{return m_interpolation_method;}
672
673 private:
674 void ePlus( enum whichMatrix which, const container& in, container& out);
675 void eMinus(enum whichMatrix which, const container& in, container& out);
676 void zero( enum whichMatrix which, const container& in, container& out);
677 IMatrix m_plus, m_zero, m_minus, m_plusT, m_minusT; //2d interpolation matrices
678 container m_hbm, m_hbp; //3d size
679 container m_G, m_Gm, m_Gp; // 3d size
680 container m_bphi, m_bphiM, m_bphiP; // 3d size
681 container m_bbm, m_bbp, m_bbo; //3d size masks
682
683 container m_left, m_right; //perp_size
684 container m_limiter; //perp_size
685 container m_ghostM, m_ghostP; //perp_size
686 unsigned m_Nz, m_perp_size;
687 dg::bc m_bcx, m_bcy, m_bcz;
688 std::vector<dg::View<const container>> m_f;
689 std::vector<dg::View< container>> m_temp;
692 double m_deltaPhi;
693 std::string m_interpolation_method;
694
695 bool m_have_adjoint = false;
696 void updateAdjoint( )
697 {
698 m_plusT = dg::transpose( m_plus);
699 m_minusT = dg::transpose( m_minus);
700 m_have_adjoint = true;
701 }
702};
703
705
707template<class Geometry, class IMatrix, class container>
708template <class Limiter>
711 const Geometry& grid,
712 dg::bc bcx, dg::bc bcy, Limiter limit, double eps,
713 unsigned mx, unsigned my, double deltaPhi, std::string interpolation_method, bool benchmark) :
714 m_g(grid),
715 m_interpolation_method(interpolation_method)
716{
717
718 std::string inter_m, project_m, fine_m;
719 detail::parse_method( interpolation_method, inter_m, project_m, fine_m);
720 if( benchmark) std::cout << "# Interpolation method: \""<<inter_m << "\" projection method: \""<<project_m<<"\" fine grid \""<<fine_m<<"\"\n";
722 if( (grid.bcx() == PER && bcx != PER) || (grid.bcx() != PER && bcx == PER) )
723 throw( dg::Error(dg::Message(_ping_)<<"Fieldaligned: Got conflicting periodicity in x. The grid says "<<bc2str(grid.bcx())<<" while the parameter says "<<bc2str(bcx)));
724 if( (grid.bcy() == PER && bcy != PER) || (grid.bcy() != PER && bcy == PER) )
725 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)));
726 m_Nz=grid.Nz(), m_bcx = bcx, m_bcy = bcy, m_bcz=grid.bcz();
727 if( deltaPhi <=0) deltaPhi = grid.hz();
729 // grid_trafo -> grid_equi -> grid_fine -> grid_equi -> grid_trafo
730 dg::Timer t;
731 if( benchmark) t.tic();
732 dg::ClonePtr<dg::aGeometry2d> grid_transform( grid.perp_grid()) ;
733 // We do not need metric of grid_equidist or or grid_fine
734 dg::RealGrid2d<double> grid_equidist( *grid_transform) ;
735 dg::RealGrid2d<double> grid_fine( *grid_transform);
736 grid_equidist.set( 1, grid.gx().size(), grid.gy().size());
737 dg::ClonePtr<dg::aGeometry2d> grid_magnetic = grid_transform;//INTEGRATE HIGH ORDER GRID
738 grid_magnetic->set( grid_transform->n() < 3 ? 4 : 7, grid_magnetic->Nx(), grid_magnetic->Ny());
739 // For project method "const" we round up to the nearest multiple of n
740 if( project_m != "dg" && fine_m == "dg")
741 {
742 unsigned rx = mx % grid.nx(), ry = my % grid.ny();
743 if( 0 != rx || 0 != ry)
744 {
745 std::cerr << "#Warning: for projection method \"const\" mx and my must be multiples of nx and ny! Rounding up for you ...\n";
746 mx = mx + grid.nx() - rx;
747 my = my + grid.ny() - ry;
748 }
749 }
750 if( fine_m == "equi")
751 grid_fine = grid_equidist;
752 grid_fine.multiplyCellNumbers((double)mx, (double)my);
753 if( benchmark)
754 {
755 t.toc();
756 std::cout << "# DS: High order grid gen took: "<<t.diff()<<"\n";
757 t.tic();
758 }
760 std::array<thrust::host_vector<double>,3> yp_trafo, ym_trafo, yp, ym;
761 thrust::host_vector<bool> in_boxp, in_boxm;
762 thrust::host_vector<double> hbp, hbm;
763 thrust::host_vector<double> vol = dg::tensor::volume(grid.metric()), vol2d0;
764 auto vol2d = dg::split( vol, grid);
765 dg::assign( vol2d[0], vol2d0);
766 detail::integrate_all_fieldlines2d( vec, *grid_magnetic, *grid_transform,
767 yp_trafo, vol2d0, hbp, in_boxp, deltaPhi, eps);
768 detail::integrate_all_fieldlines2d( vec, *grid_magnetic, *grid_transform,
769 ym_trafo, vol2d0, hbm, in_boxm, -deltaPhi, eps);
770 dg::HVec Xf = dg::evaluate( dg::cooX2d, grid_fine);
771 dg::HVec Yf = dg::evaluate( dg::cooY2d, grid_fine);
772 {
774 *grid_transform, dg::NEU, dg::NEU, grid_transform->n() < 3 ? "cubic" : "dg");
775 yp.fill(dg::evaluate( dg::zero, grid_fine));
776 ym = yp;
777 for( int i=0; i<2; i++) //only R and Z get interpolated
778 {
779 dg::blas2::symv( interpolate, yp_trafo[i], yp[i]);
780 dg::blas2::symv( interpolate, ym_trafo[i], ym[i]);
781 }
782 } // release memory for interpolate matrix
783 if( benchmark)
784 {
785 t.toc();
786 std::cout << "# DS: Computing all points took: "<<t.diff()<<"\n";
787 t.tic();
788 }
790 if( inter_m == "dg")
791 {
792 dg::IHMatrix fine, projection, multi;
793 if( project_m == "dg")
794 projection = dg::create::projection( *grid_transform, grid_fine);
795 else
796 {
797 multi = dg::create::projection( grid_equidist, grid_fine, project_m);
798 fine = dg::create::inv_backproject( *grid_transform);
799 cusp::multiply( fine, multi, projection);
800 }
801 fine = dg::create::interpolation( yp[0], yp[1],
802 *grid_transform, bcx, bcy, "dg");
803 cusp::multiply( projection, fine, multi);
804 dg::blas2::transfer( multi, m_plus);
805 fine = dg::create::interpolation( Xf, Yf,
806 *grid_transform, bcx, bcy, "dg");
807 cusp::multiply( projection, fine, multi);
808 dg::blas2::transfer( multi, m_zero);
809 fine = dg::create::interpolation( ym[0], ym[1],
810 *grid_transform, bcx, bcy, "dg");
811 cusp::multiply( projection, fine, multi);
812 dg::blas2::transfer( multi, m_minus);
813 }
814 else
815 {
816 dg::IHMatrix fine, projection, multi, temp;
817 if( project_m == "dg")
818 projection = dg::create::projection( *grid_transform, grid_fine);
819 else
820 {
821 multi = dg::create::projection( grid_equidist, grid_fine, project_m);
822 fine = dg::create::inv_backproject( *grid_transform);
823 cusp::multiply( fine, multi, projection);
824 }
825
826 fine = dg::create::backproject( *grid_transform); // from dg to equidist
827
828 multi = dg::create::interpolation( yp[0], yp[1],
829 grid_equidist, bcx, bcy, inter_m);
830 cusp::multiply( multi, fine, temp);
831 cusp::multiply( projection, temp, multi);
832 dg::blas2::transfer( multi, m_plus);
833
834 multi = dg::create::interpolation( Xf, Yf,
835 grid_equidist, bcx, bcy, inter_m);
836 cusp::multiply( multi, fine, temp);
837 cusp::multiply( projection, temp, multi);
838 dg::blas2::transfer( multi, m_zero);
839
840 multi = dg::create::interpolation( ym[0], ym[1],
841 grid_equidist, bcx, bcy, inter_m);
842 cusp::multiply( multi, fine, temp);
843 cusp::multiply( projection, temp, multi);
844 dg::blas2::transfer( multi, m_minus);
845 }
846
847 if( benchmark)
848 {
849 t.toc();
850 std::cout << "# DS: Multiplication PI took: "<<t.diff()<<"\n";
851 }
853 dg::HVec hbphi( yp_trafo[2]), hbphiP(hbphi), hbphiM(hbphi);
854 hbphi = dg::pullback( vec.z(), *grid_transform);
855 //this is a pullback bphi( R(zeta, eta), Z(zeta, eta)):
856 if( dynamic_cast<const dg::CartesianGrid2d*>( grid_transform.get()))
857 {
858 for( unsigned i=0; i<hbphiP.size(); i++)
859 {
860 hbphiP[i] = vec.z()(yp_trafo[0][i], yp_trafo[1][i]);
861 hbphiM[i] = vec.z()(ym_trafo[0][i], ym_trafo[1][i]);
862 }
863 }
864 else
865 {
866 dg::HVec Ihbphi = dg::pullback( vec.z(), *grid_magnetic);
867 dg::HVec Lhbphi = dg::forward_transform( Ihbphi, *grid_magnetic);
868 for( unsigned i=0; i<yp_trafo[0].size(); i++)
869 {
870 hbphiP[i] = dg::interpolate( dg::lspace, Lhbphi, yp_trafo[0][i],
871 yp_trafo[1][i], *grid_magnetic);
872 hbphiM[i] = dg::interpolate( dg::lspace, Lhbphi, ym_trafo[0][i],
873 ym_trafo[1][i], *grid_magnetic);
874 }
875 }
876 dg::assign3dfrom2d( hbphi, m_bphi, grid);
877 dg::assign3dfrom2d( hbphiM, m_bphiM, grid);
878 dg::assign3dfrom2d( hbphiP, m_bphiP, grid);
879
880 dg::assign3dfrom2d( yp_trafo[2], m_Gp, grid);
881 dg::assign3dfrom2d( ym_trafo[2], m_Gm, grid);
882 // The weights don't matter since they fall out in Div and Lap anyway
883 // But they are good for testing
884 m_G = vol;
885 container weights = dg::create::weights( grid);
887 dg::blas1::pointwiseDot( m_Gp, weights, m_Gp);
888 dg::blas1::pointwiseDot( m_Gm, weights, m_Gm);
889
891 m_f = dg::split( (const container&)m_hbm, grid);
892 m_temp = dg::split( m_hbm, grid);
893 dg::assign3dfrom2d( hbp, m_hbp, grid);
894 dg::assign3dfrom2d( hbm, m_hbm, grid);
895 dg::blas1::scal( m_hbm, -1.);
896
898 thrust::host_vector<double> bbm( in_boxp.size(),0.), bbo(bbm), bbp(bbm);
899 for( unsigned i=0; i<in_boxp.size(); i++)
900 {
901 if( !in_boxp[i] && !in_boxm[i])
902 bbo[i] = 1.;
903 else if( !in_boxp[i] && in_boxm[i])
904 bbp[i] = 1.;
905 else if( in_boxp[i] && !in_boxm[i])
906 bbm[i] = 1.;
907 // else all are 0
908 }
909 dg::assign3dfrom2d( bbm, m_bbm, grid);
910 dg::assign3dfrom2d( bbo, m_bbo, grid);
911 dg::assign3dfrom2d( bbp, m_bbp, grid);
912
913 m_deltaPhi = deltaPhi; // store for evaluate
914
916 m_perp_size = grid_transform->size();
917 dg::assign( dg::pullback(limit, *grid_transform), m_limiter);
918 dg::assign( dg::evaluate(dg::zero, *grid_transform), m_left);
919 m_ghostM = m_ghostP = m_right = m_left;
920}
921
922
923template<class G, class I, class container>
925 const G& grid, const container& in)
926{
927 //I think we need grid as input to split input vector and we need to interpret
928 //the grid nodes as node centered not cell-centered!
929 //idea: apply I+/I- cphi - 1 times in each direction and then apply interpolation formula
930 assert( m_g->Nz() % grid.Nz() == 0);
931 unsigned Nz_coarse = grid.Nz(), Nz = m_g->Nz();
932 unsigned cphi = Nz / Nz_coarse;
933
934 container out = dg::evaluate( dg::zero, *m_g);
935 container helper = dg::evaluate( dg::zero, *m_g);
936 dg::split( helper, m_temp, *m_g);
937 std::vector<dg::View< container>> out_split = dg::split( out, *m_g);
938 std::vector<dg::View< const container>> in_split = dg::split( in, grid);
939 for ( int i=0; i<(int)Nz_coarse; i++)
940 {
941 //1. copy input vector to appropriate place in output
942 dg::blas1::copy( in_split[i], out_split[i*cphi]);
943 dg::blas1::copy( in_split[i], m_temp[i*cphi]);
944 }
945 //Step 1 needs to finish so that m_temp contains values everywhere
946 //2. Now apply plus and minus T to fill in the rest
947 for ( int i=0; i<(int)Nz_coarse; i++)
948 {
949 for( int j=1; j<(int)cphi; j++)
950 {
952 dg::blas2::symv( m_minus, out_split[i*cphi+j-1], out_split[i*cphi+j]);
954 dg::blas2::symv( m_plus, m_temp[(i*cphi+cphi+1-j)%Nz], m_temp[i*cphi+cphi-j]);
955 }
956 }
957 //3. Now add up with appropriate weights
958 for( int i=0; i<(int)Nz_coarse; i++)
959 for( int j=1; j<(int)cphi; j++)
960 {
961 double alpha = (double)(cphi-j)/(double)cphi;
962 double beta = (double)j/(double)cphi;
963 dg::blas1::axpby( alpha, out_split[i*cphi+j], beta, m_temp[i*cphi+j], out_split[i*cphi+j]);
964 }
965 return out;
966}
967template<class G, class I, class container>
968void Fieldaligned<G, I,container>::integrate_between_coarse_grid( const G& grid, const container& in, container& out)
969{
970 assert( m_g->Nz() % grid.Nz() == 0);
971 unsigned Nz_coarse = grid.Nz(), Nz = m_g->Nz();
972 unsigned cphi = Nz / Nz_coarse;
973
974 out = in;
975 container helperP( in), helperM(in), tempP(in), tempM(in);
976
977 //1. Apply plus and minus T and sum up
978 for( int j=1; j<(int)cphi; j++)
979 {
981 dg::blas2::symv( m_minus, helperP, tempP);
982 dg::blas1::axpby( (double)(cphi-j)/(double)cphi, tempP, 1., out );
983 helperP.swap(tempP);
985 dg::blas2::symv( m_plus, helperM, tempM);
986 dg::blas1::axpby( (double)(cphi-j)/(double)cphi, tempM, 1., out );
987 helperM.swap(tempM);
988 }
989 dg::blas1::scal( out, 1./(double)cphi);
990}
991
992template<class G, class I, class container>
993void Fieldaligned<G, I, container >::operator()(enum whichMatrix which, const container& f, container& fe)
994{
995 if( which == einsPlus || which == einsMinusT ) ePlus( which, f, fe);
996 else if(which == einsMinus || which == einsPlusT ) eMinus( which, f, fe);
997 else if(which == zeroMinus || which == zeroPlus ||
998 which == zeroMinusT|| which == zeroPlusT ||
999 which == zeroForw ) zero( which, f, fe);
1000}
1001
1002template< class G, class I, class container>
1003void Fieldaligned<G, I, container>::zero( enum whichMatrix which,
1004 const container& f, container& f0)
1005{
1006 dg::split( f, m_f, *m_g);
1007 dg::split( f0, m_temp, *m_g);
1008 //1. compute 2d interpolation in every plane and store in m_temp
1009 for( unsigned i0=0; i0<m_Nz; i0++)
1010 {
1011 if(which == zeroPlus)
1012 dg::blas2::symv( m_plus, m_f[i0], m_temp[i0]);
1013 else if(which == zeroMinus)
1014 dg::blas2::symv( m_minus, m_f[i0], m_temp[i0]);
1015 else if(which == zeroPlusT)
1016 {
1017 if( ! m_have_adjoint) updateAdjoint( );
1018 dg::blas2::symv( m_plusT, m_f[i0], m_temp[i0]);
1019 }
1020 else if(which == zeroMinusT)
1021 {
1022 if( ! m_have_adjoint) updateAdjoint( );
1023 dg::blas2::symv( m_minusT, m_f[i0], m_temp[i0]);
1024 }
1025 else if( which == zeroForw)
1026 {
1027 if ( m_interpolation_method != "dg" )
1028 {
1029 dg::blas2::symv( m_zero, m_f[i0], m_temp[i0]);
1030 }
1031 else
1032 dg::blas1::copy( m_f[i0], m_temp[i0]);
1033 }
1034 }
1035}
1036template< class G, class I, class container>
1037void Fieldaligned<G, I, container>::ePlus( enum whichMatrix which,
1038 const container& f, container& fpe)
1039{
1040 dg::split( f, m_f, *m_g);
1041 dg::split( fpe, m_temp, *m_g);
1042 //1. compute 2d interpolation in every plane and store in m_temp
1043 for( unsigned i0=0; i0<m_Nz; i0++)
1044 {
1045 unsigned ip = (i0==m_Nz-1) ? 0:i0+1;
1046 if(which == einsPlus)
1047 dg::blas2::symv( m_plus, m_f[ip], m_temp[i0]);
1048 else if(which == einsMinusT)
1049 {
1050 if( ! m_have_adjoint) updateAdjoint( );
1051 dg::blas2::symv( m_minusT, m_f[ip], m_temp[i0]);
1052 }
1053 }
1054 //2. apply right boundary conditions in last plane
1055 unsigned i0=m_Nz-1;
1056 if( m_bcz != dg::PER)
1057 {
1058 if( m_bcz == dg::DIR || m_bcz == dg::NEU_DIR)
1059 dg::blas1::axpby( 2, m_right, -1., m_f[i0], m_ghostP);
1060 if( m_bcz == dg::NEU || m_bcz == dg::DIR_NEU)
1061 dg::blas1::axpby( m_deltaPhi, m_right, 1., m_f[i0], m_ghostP);
1062 //interlay ghostcells with periodic cells: L*g + (1-L)*fpe
1063 dg::blas1::axpby( 1., m_ghostP, -1., m_temp[i0], m_ghostP);
1064 dg::blas1::pointwiseDot( 1., m_limiter, m_ghostP, 1., m_temp[i0]);
1065 }
1066}
1067
1068template< class G, class I, class container>
1069void Fieldaligned<G, I, container>::eMinus( enum whichMatrix which,
1070 const container& f, container& fme)
1071{
1072 dg::split( f, m_f, *m_g);
1073 dg::split( fme, m_temp, *m_g);
1074 //1. compute 2d interpolation in every plane and store in m_temp
1075 for( unsigned i0=0; i0<m_Nz; i0++)
1076 {
1077 unsigned im = (i0==0) ? m_Nz-1:i0-1;
1078 if(which == einsPlusT)
1079 {
1080 if( ! m_have_adjoint) updateAdjoint( );
1081 dg::blas2::symv( m_plusT, m_f[im], m_temp[i0]);
1082 }
1083 else if (which == einsMinus)
1084 dg::blas2::symv( m_minus, m_f[im], m_temp[i0]);
1085 }
1086 //2. apply left boundary conditions in first plane
1087 unsigned i0=0;
1088 if( m_bcz != dg::PER)
1089 {
1090 if( m_bcz == dg::DIR || m_bcz == dg::DIR_NEU)
1091 dg::blas1::axpby( 2., m_left, -1., m_f[i0], m_ghostM);
1092 if( m_bcz == dg::NEU || m_bcz == dg::NEU_DIR)
1093 dg::blas1::axpby( -m_deltaPhi, m_left, 1., m_f[i0], m_ghostM);
1094 //interlay ghostcells with periodic cells: L*g + (1-L)*fme
1095 dg::blas1::axpby( 1., m_ghostM, -1., m_temp[i0], m_ghostM);
1096 dg::blas1::pointwiseDot( 1., m_limiter, m_ghostM, 1., m_temp[i0]);
1097 }
1098}
1099
1100template<class G, class I, class container>
1101template< class BinaryOp, class UnaryOp>
1102container Fieldaligned<G, I,container>::evaluate( BinaryOp binary,
1103 UnaryOp unary, unsigned p0, unsigned rounds) const
1104{
1105 //idea: simply apply I+/I- enough times on the init2d vector to get the result in each plane
1106 //unary function is always such that the p0 plane is at x=0
1107 assert( p0 < m_g->Nz());
1108 const dg::ClonePtr<aGeometry2d> g2d = m_g->perp_grid();
1109 container init2d = dg::pullback( binary, *g2d);
1110 container zero2d = dg::evaluate( dg::zero, *g2d);
1111
1112 container temp(init2d), tempP(init2d), tempM(init2d);
1113 container vec3d = dg::evaluate( dg::zero, *m_g);
1114 std::vector<container> plus2d(m_Nz, zero2d), minus2d(plus2d), result(plus2d);
1115 unsigned turns = rounds;
1116 if( turns ==0) turns++;
1117 //first apply Interpolation many times, scale and store results
1118 for( unsigned r=0; r<turns; r++)
1119 for( unsigned i0=0; i0<m_Nz; i0++)
1120 {
1121 dg::blas1::copy( init2d, tempP);
1122 dg::blas1::copy( init2d, tempM);
1123 unsigned rep = r*m_Nz + i0;
1124 for(unsigned k=0; k<rep; k++)
1125 {
1127 dg::blas2::symv( m_minus, tempP, temp);
1128 temp.swap( tempP);
1130 dg::blas2::symv( m_plus, tempM, temp);
1131 temp.swap( tempM);
1132 }
1133 dg::blas1::scal( tempP, unary( (double)rep*m_deltaPhi ) );
1134 dg::blas1::scal( tempM, unary( -(double)rep*m_deltaPhi ) );
1135 dg::blas1::axpby( 1., tempP, 1., plus2d[i0]);
1136 dg::blas1::axpby( 1., tempM, 1., minus2d[i0]);
1137 }
1138 //now we have the plus and the minus filaments
1139 if( rounds == 0) //there is a limiter
1140 {
1141 for( unsigned i0=0; i0<m_Nz; i0++)
1142 {
1143 int idx = (int)i0 - (int)p0;
1144 if(idx>=0)
1145 result[i0] = plus2d[idx];
1146 else
1147 result[i0] = minus2d[abs(idx)];
1148 thrust::copy( result[i0].begin(), result[i0].end(), vec3d.begin() + i0*m_perp_size);
1149 }
1150 }
1151 else //sum up plus2d and minus2d
1152 {
1153 for( unsigned i0=0; i0<m_Nz; i0++)
1154 {
1155 unsigned revi0 = (m_Nz - i0)%m_Nz; //reverted index
1156 dg::blas1::axpby( 1., plus2d[i0], 0., result[i0]);
1157 dg::blas1::axpby( 1., minus2d[revi0], 1., result[i0]);
1158 }
1159 dg::blas1::axpby( -1., init2d, 1., result[0]);
1160 for(unsigned i0=0; i0<m_Nz; i0++)
1161 {
1162 int idx = ((int)i0 -(int)p0 + m_Nz)%m_Nz; //shift index
1163 thrust::copy( result[idx].begin(), result[idx].end(), vec3d.begin() + i0*m_perp_size);
1164 }
1165 }
1166 return vec3d;
1167}
1168
1169
1171
1203template<class BinaryOp, class UnaryOp>
1204thrust::host_vector<double> fieldaligned_evaluate(
1205 const aProductGeometry3d& grid,
1206 const CylindricalVectorLvl0& vec,
1207 const BinaryOp& binary,
1208 const UnaryOp& unary,
1209 unsigned p0,
1210 unsigned rounds,
1211 double eps = 1e-5)
1212{
1213 unsigned Nz = grid.Nz();
1214 const dg::ClonePtr<aGeometry2d> g2d = grid.perp_grid();
1215 // Construct for field-aligned output
1216 dg::HVec tempP = dg::evaluate( dg::zero, *g2d), tempM( tempP);
1217 std::vector<dg::HVec> plus2d(Nz, tempP), minus2d(plus2d), result(plus2d);
1218 dg::HVec vec3d = dg::evaluate( dg::zero, grid);
1219 dg::HVec init2d = dg::pullback( binary, *g2d);
1220 std::array<dg::HVec,3> yy0{
1221 dg::pullback( dg::cooX2d, *g2d),
1222 dg::pullback( dg::cooY2d, *g2d),
1223 dg::evaluate( dg::zero, *g2d)}, yy1(yy0), xx0( yy0), xx1(yy0); //s
1224 dg::geo::detail::DSFieldCylindrical3 cyl_field(vec);
1225 double deltaPhi = grid.hz();
1226 double phiM0 = 0., phiP0 = 0.;
1227 unsigned turns = rounds;
1228 if( turns == 0) turns++;
1229 for( unsigned r=0; r<turns; r++)
1230 for( unsigned i0=0; i0<Nz; i0++)
1231 {
1232 unsigned rep = r*Nz + i0;
1233 if( rep == 0)
1234 tempM = tempP = init2d;
1235 else
1236 {
1238 "Dormand-Prince-7-4-5", std::array<double,3>{0,0,0});
1240 cyl_field, dg::pid_control, dg::fast_l2norm, eps,
1241 1e-10);
1242 for( unsigned i=0; i<g2d->size(); i++)
1243 {
1244 // minus direction needs positive integration!
1245 double phiM1 = phiM0 + deltaPhi;
1246 std::array<double,3>
1247 coords0{yy0[0][i],yy0[1][i],yy0[2][i]}, coords1;
1248 odeint.integrate_in_domain( phiM0, coords0, phiM1, coords1,
1249 deltaPhi, *g2d, eps);
1250 yy1[0][i] = coords1[0], yy1[1][i] = coords1[1], yy1[2][i] =
1251 coords1[2];
1252 tempM[i] = binary( yy1[0][i], yy1[1][i]);
1253
1254 // plus direction needs negative integration!
1255 double phiP1 = phiP0 - deltaPhi;
1256 coords0 = std::array<double,3>{xx0[0][i],xx0[1][i],xx0[2][i]};
1257 odeint.integrate_in_domain( phiP0, coords0, phiP1, coords1,
1258 -deltaPhi, *g2d, eps);
1259 xx1[0][i] = coords1[0], xx1[1][i] = coords1[1], xx1[2][i] =
1260 coords1[2];
1261 tempP[i] = binary( xx1[0][i], xx1[1][i]);
1262 }
1263 std::swap( yy0, yy1);
1264 std::swap( xx0, xx1);
1265 phiM0 += deltaPhi;
1266 phiP0 -= deltaPhi;
1267 }
1268 dg::blas1::scal( tempM, unary( -(double)rep*deltaPhi ) );
1269 dg::blas1::scal( tempP, unary( (double)rep*deltaPhi ) );
1270 dg::blas1::axpby( 1., tempM, 1., minus2d[i0]);
1271 dg::blas1::axpby( 1., tempP, 1., plus2d[i0]);
1272 }
1273 //now we have the plus and the minus filaments
1274 if( rounds == 0) //there is a limiter
1275 {
1276 for( unsigned i0=0; i0<Nz; i0++)
1277 {
1278 int idx = (int)i0 - (int)p0;
1279 if(idx>=0)
1280 result[i0] = plus2d[idx];
1281 else
1282 result[i0] = minus2d[abs(idx)];
1283 thrust::copy( result[i0].begin(), result[i0].end(), vec3d.begin() +
1284 i0*g2d->size());
1285 }
1286 }
1287 else //sum up plus2d and minus2d
1288 {
1289 for( unsigned i0=0; i0<Nz; i0++)
1290 {
1291 unsigned revi0 = (Nz - i0)%Nz; //reverted index
1292 dg::blas1::axpby( 1., plus2d[i0], 0., result[i0]);
1293 dg::blas1::axpby( 1., minus2d[revi0], 1., result[i0]);
1294 }
1295 dg::blas1::axpby( -1., init2d, 1., result[0]);
1296 for(unsigned i0=0; i0<Nz; i0++)
1297 {
1298 int idx = ((int)i0 -(int)p0 + Nz)%Nz; //shift index
1299 thrust::copy( result[idx].begin(), result[idx].end(), vec3d.begin()
1300 + i0*g2d->size());
1301 }
1302 }
1303 return vec3d;
1304}
1305
1306}//namespace geo
1307}//namespace dg
#define _ping_
void assign(const from_ContainerType &from, ContainerType &to, Params &&... ps)
static DG_DEVICE double cooY2d(double x, double y)
static DG_DEVICE double zero(double x)
static DG_DEVICE double cooX2d(double x, double y)
void copy(const ContainerTypeIn &source, ContainerTypeOut &target)
void axpby(get_value_type< ContainerType > alpha, const ContainerType1 &x, get_value_type< ContainerType > beta, ContainerType &y)
void scal(ContainerType &x, get_value_type< ContainerType > alpha)
void 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)
static std::string bc2str(bc bcx)
thrust::host_vector< real_type > evaluate(UnaryOp f, const RealGrid1d< 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
@ zeroPlusT
transposed plus interpolation in the current plane
Definition: fieldaligned.h:24
@ einsMinus
minus interpolation in previous plane
Definition: fieldaligned.h:20
@ einsMinusT
transposed minus interpolation in next plane
Definition: fieldaligned.h:21
@ zeroMinusT
transposed minus interpolation in the current plane
Definition: fieldaligned.h:25
@ einsPlusT
transposed plus interpolation in previous plane
Definition: fieldaligned.h:19
@ zeroForw
from dg to transformed coordinates
Definition: fieldaligned.h:26
@ zeroMinus
minus interpolation in the current plane
Definition: fieldaligned.h:23
@ zeroPlus
plus interpolation in the current plane
Definition: fieldaligned.h:22
@ einsPlus
plus interpolation in next plane
Definition: fieldaligned.h:18
MPI_Vector< thrust::host_vector< real_type > > weights(const aRealMPITopology2d< real_type > &g)
cusp::coo_matrix< int, real_type, cusp::host_memory > interpolation(const thrust::host_vector< real_type > &x, const RealGrid1d< real_type > &g, dg::bc bcx=dg::NEU, std::string method="dg")
real_type interpolate(dg::space sp, const thrust::host_vector< real_type > &v, real_type x, const RealGrid1d< real_type > &g, dg::bc bcx=dg::NEU)
dg::MIHMatrix_t< real_type > projection(const aRealMPITopology2d< real_type > &g_new, const aRealMPITopology2d< real_type > &g_old, std::string method="dg")
CylindricalVectorLvl1 createBHat(const TokamakMagneticField &mag)
Contravariant components of the magnetic unit vector field and its Divergence and derivative in cylin...
Definition: magnetic_field.h:931
thrust::host_vector< real_type > forward_transform(const thrust::host_vector< real_type > &in, const aRealTopology2d< real_type > &g)
void transpose(unsigned nx, unsigned ny, const ContainerType &in, ContainerType &out)
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)
ContainerType volume(const SparseTensor< ContainerType > &t)
static auto pid_control
static auto fast_l2norm
IHMatrix_t< double > IHMatrix
thrust::host_vector< double > HVec
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
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.h:561
const container & bphi() const
bphi
Definition: fieldaligned.h:581
container interpolate_from_coarse_grid(const ProductGeometry &grid_coarse, const container &coarse)
Interpolate along fieldlines from a coarse to a fine grid in phi.
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:441
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.h:606
container evaluate(BinaryOp binary, UnaryOp unary, unsigned p0, unsigned rounds) const
Evaluate a 2d functor and transform to all planes along the fieldline
const container & sqrtG() const
Volume form (including weights) .
Definition: fieldaligned.h:566
void operator()(enum whichMatrix which, const container &in, container &out)
Apply the interpolation to three-dimensional vectors.
const container & sqrtGm() const
Volume form on minus plane (including weights) .
Definition: fieldaligned.h:571
void set_boundaries(dg::bc bcz, double left, double right)
Set boundary conditions in the limiter region.
Definition: fieldaligned.h:501
std::string method() const
Return the interpolation_method string given in the constructor.
Definition: fieldaligned.h:671
const container & hbm() const
Distance between the planes and the boundary .
Definition: fieldaligned.h:556
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:535
const container & bphiM() const
bphi on minus plane
Definition: fieldaligned.h:586
dg::bc bcy() const
Definition: fieldaligned.h:487
double deltaPhi() const
Definition: fieldaligned.h:553
Fieldaligned()
do not allocate memory; no member call except construct is valid
Definition: fieldaligned.h:436
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: fieldaligned.h:478
const container & bbo() const
Mask both, 1 if fieldline intersects wall in plus direction and in minus direction,...
Definition: fieldaligned.h:601
const container & bbm() const
Mask minus, 1 if fieldline intersects wall in minus direction but not in plus direction,...
Definition: fieldaligned.h:596
const container & sqrtGp() const
Volume form on plus plane (including weights) .
Definition: fieldaligned.h:576
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:591
const ProductGeometry & grid() const
Grid used for construction.
Definition: fieldaligned.h:610
void set_boundaries(dg::bc bcz, const container &left, const container &right)
Set boundary conditions in the limiter region.
Definition: fieldaligned.h:518
A tokamak field as given by R0, Psi and Ipol plus Meta-data like shape and equilibrium.
Definition: magnetic_field.h:162
Normalized coordinate relative to wall along fieldline in phi or s coordinate.
Definition: fieldaligned.h:308
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.h:311
double do_compute(double R, double Z) const
Definition: fieldaligned.h:321
Distance to wall along fieldline in phi or s coordinate
Definition: fieldaligned.h:221
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.h:232
double do_compute(double R, double Z) const
Integrate fieldline until wall is reached.
Definition: fieldaligned.h:252
Represent functions written in cylindrical coordinates that are independent of the angle phi serving ...
Definition: fluxfunctions.h:66