Discontinuous Galerkin Library
#include "dg/algorithm.h"
Loading...
Searching...
No Matches
interpolation.h
Go to the documentation of this file.
1#pragma once
2//#include <iomanip>
3
5#include "dg/backend/view.h"
6#include "grid.h"
7#include "evaluation.h"
8#include "functions.h"
9#include "operator_tensor.h"
10#include "xspacelib.h"
11
17namespace dg{
18
19namespace create{
21namespace detail{
42template<class real_type>
43void shift( bool& negative, real_type & x, dg::bc bc, real_type x0, real_type x1)
44{
45 // This is now a free function because not all Topologies may have it
46 if( bc == dg::PER)
47 {
48 real_type N0 = floor((x-x0)/(x1-x0)); // ... -2[ -1[ 0[ 1[ 2[ ...
49 x = x == x1 ? x0 : x - N0*(x1-x0); //shift
50 }
51 //mirror along boundary as often as necessary
52 while( (x<x0) || (x>x1) )
53 {
54 if( x < x0){
55 x = 2.*x0 - x;
56 //every mirror swaps the sign if Dirichlet
57 if( bc == dg::DIR || bc == dg::DIR_NEU)
58 negative = !negative;//swap sign
59 }
60 if( x >= x1){
61 x = 2.*x1 - x;
62 if( bc == dg::DIR || bc == dg::NEU_DIR) //notice the different boundary NEU_DIR to the above DIR_NEU !
63 negative = !negative; //swap sign
64 }
65 }
66}
67
76template<class real_type>
77std::vector<real_type> legendre( real_type xn, unsigned n)
78{
79 assert( xn <= 1. && xn >= -1.);
80 std::vector<real_type> px(n);
81 if( xn == -1)
82 {
83 for( unsigned u=0; u<n; u++)
84 px[u] = (u%2 == 0) ? +1. : -1.;
85 }
86 else if( xn == 1)
87 {
88 for( unsigned i=0; i<n; i++)
89 px[i] = 1.;
90 }
91 else
92 {
93 px[0] = 1.;
94 if( n > 1)
95 {
96 px[1] = xn;
97 for( unsigned i=1; i<n-1; i++)
98 px[i+1] = ((real_type)(2*i+1)*xn*px[i]-(real_type)i*px[i-1])/(real_type)(i+1);
99 }
100 }
101 return px;
102}
103
104// evaluate n base polynomials for n given abscissas
105template<class real_type>
106std::vector<real_type> lagrange( real_type x, const std::vector<real_type>& xi)
107{
108 unsigned n = xi.size();
109 std::vector<real_type> l( n , 1.);
110 for( unsigned i=0; i<n; i++)
111 for( unsigned k=0; k<n; k++)
112 {
113 if ( k != i)
114 l[i] *= (x-xi[k])/(xi[i]-xi[k]);
115 }
116 return l;
117}
118
119template<class real_type>
120void choose_1d_abscissas( real_type X,
121 unsigned points_per_line, double lx,// const RealGrid1d<real_type>& g,
122 const thrust::host_vector<real_type>& abs, dg::bc bcx,
123 thrust::host_vector<int>& cols,
124 thrust::host_vector<real_type>& px
125 )
126{
127 // Select points for nearest, linear or cubic interpolation
128 // (Optimisation 9.9.25: the fact that abs are equidistant does not gain a speedup)
129 // lx is needed for PER bondary conditions
130 //determine which cell (X) lies in
131 // abs must be sorted for std::lower_bound to work
132 // std::lower_bound finds the first abs that is >= X
133 auto it = std::lower_bound( abs.begin(), abs.end(), X);
134 // Test if point already exists since then no interpolation is needed
135 int idxX = -1;
136 if( fabs( X - *it) < 1e-13)
137 idxX = it - abs.begin();
138 if( it != abs.begin() and fabs( X - *(it-1)) < 1e-13)
139 idxX = (it - abs.begin())-1;
140 if( idxX >= 0)
141 {
142 cols.assign(1, idxX );
143 px.assign( 1, 1.0);
144 return;
145 }
146
147 std::vector<real_type> xs( points_per_line, 0);
148 cols.resize( points_per_line, 0);
149 switch( points_per_line)
150 {
151 case 1: xs[0] = 1.;
152 if( it == abs.begin())
153 cols[0] = 0;
154 else if( it == abs.end())
155 cols[0] = it - abs.begin() - 1;
156 else
157 {
158 if ( fabs(X - *it) < fabs( X - *(it-1)))
159 cols[0] = it - abs.begin();
160 else
161 cols[0] = it - abs.begin() -1;
162 }
163 break;
164 case 2: if( it == abs.begin())
165 {
166 if( bcx == dg::PER)
167 {
168 xs[0] = *it;
169 xs[1] = *(abs.end() -1)-lx;;
170 cols[0] = 0, cols[1] = abs.end()-abs.begin()-1;
171 }
172 else
173 {
174 // Nearest Neigbor: This makes it consistent with fem_t
175 xs.resize(1);
176 cols.resize(1);
177 xs[0] = *it;
178 cols[0] = 0;
179 }
180 }
181 else if( it == abs.end())
182 {
183 if( bcx == dg::PER)
184 {
185 xs[0] = *(abs.begin())+lx;
186 xs[1] = *(it-1);
187 cols[0] = 0, cols[1] = it-abs.begin()-1;
188 }
189 else
190 {
191 // Nearest neighbor: this makes it consistent with fem_t
192 xs.resize(1);
193 cols.resize(1);
194 xs[0] = *(it-1);
195 cols[0] = it-abs.begin()-1;
196 }
197 }
198 else
199 {
200 xs[0] = *(it-1);
201 xs[1] = *it;
202 cols[0] = it - abs.begin() - 1;
203 cols[1] = cols[0]+1;
204 }
205 break;
206 case 4: if( it <= abs.begin() +1)
207 {
208 if( bcx == dg::PER)
209 {
210 xs[0] = *abs.begin(), cols[0] = 0;
211 xs[1] = *(abs.begin()+1), cols[1] = 1;
212 xs[2] = it == abs.begin() ? *(abs.end() -2) -lx: *(abs.begin()+2);
213 cols[2] = it == abs.begin() ? abs.end()-abs.begin() -2 : 2;
214 xs[3] = *(abs.end() -1) -lx;
215 cols[3] = abs.end()-abs.begin() -1;
216 }
217 else
218 { // use boundary polynomial
219 it = abs.begin();
220 xs[0] = *it, xs[1] = *(it+1);
221 xs[2] = *(it+2), xs[3] = *(it+3);
222 cols[0] = 0, cols[1] = 1;
223 cols[2] = 2, cols[3] = 3;
224 }
225 }
226 else if( it >= abs.end() -1)
227 {
228 if( bcx == dg::PER)
229 {
230 xs[0] = *abs.begin()+lx, cols[0] = 0;
231 xs[1] = it == abs.end() ? *(abs.begin()+1) + lx : *(abs.end() -3) ;
232 cols[1] = it == abs.end() ? 1 : abs.end()-abs.begin()-3 ;
233 xs[2] = *(abs.end() - 2), cols[2] = abs.end()-abs.begin()-2;
234 xs[3] = *(abs.end() - 1), cols[3] = abs.end()-abs.begin()-1;
235 }
236 else
237 { // use boundary polynomial
238 it = abs.end();
239 xs[0] = *(it-4), xs[1] = *(it-3);
240 xs[2] = *(it-2), xs[3] = *(it-1);
241 cols[0] = it - abs.begin() - 4;
242 cols[1] = cols[0]+1;
243 cols[2] = cols[1]+1;
244 cols[3] = cols[2]+1;
245 }
246 }
247 else
248 {
249 xs[0] = *(it-2), xs[1] = *(it-1);
250 xs[2] = *(it ), xs[3] = *(it+1);
251 cols[0] = it - abs.begin() - 2;
252 cols[1] = cols[0]+1;
253 cols[2] = cols[1]+1;
254 cols[3] = cols[2]+1;
255 }
256 break;
257 }
258 px = detail::lagrange( X, xs);
259}
260
261template<class real_type>
262void interpolation_row( dg::space sp, real_type X,
263 const RealGrid1d<real_type>& g, dg::bc bcx,
264 thrust::host_vector<int>& cols,
265 thrust::host_vector<real_type>& vals)
266{
267 bool negative = false;
268 detail::shift( negative, X, bcx, g.x0(), g.x1());
269
270 //determine which cell (x) lies in
271 real_type xnn = (X-g.x0())/g.h();
272 unsigned nn = (unsigned)floor(xnn);
273 //determine normalized coordinates
274 real_type xn = 2.*xnn - (real_type)(2*nn+1);
275 //intervall correction
276 if (nn==g.N()) { //only happens fo X == x1
277 nn-=1;
278 xn = 1.;
279 }
280 //Test if the point is a Gauss point since then no interpolation is needed
281 int idxX =-1;
282 std::vector<real_type> gauss_nodesx = dg::DLT<real_type>::abscissas(g.n());
283 for( unsigned k=0; k<g.nx(); k++)
284 {
285 // Due to rounding errors xn will not perfectly be gauss_nodex[k] ( errors ~ 1e-14 possible)
286 // even if x are the abscissas of the grid
287 if( fabs( xn - gauss_nodesx[k]) < 1e-13)
288 idxX = nn*g.nx() + k; //determine which grid column it is
289 }
290 if( idxX < 0 or sp == dg::lspace) //there is no corresponding point
291 {
292 //evaluate 1d Legendre polynomials at (xn, yn)...
293 std::vector<real_type> px = detail::legendre( xn, g.n());
294 //...these are the matrix coefficients with which to multiply
295 if( sp == dg::xspace)
296 {
297 std::vector<real_type> pxF(px.size(), 0);
298 std::vector<real_type> forward =
300 for( unsigned l=0; l<g.n(); l++)
301 for( unsigned k=0; k<g.n(); k++)
302 pxF[l]+= px[k]*forward[k*g.n() + l];
303 px.swap( pxF);
304 }
305 for ( unsigned l=0; l<g.n(); l++)
306 {
307 cols.push_back( nn*g.n() + l);
308 vals.push_back( negative ? -px[l] : px[l]);
309 }
310 }
311 else //the point already exists
312 {
313 cols.push_back( idxX);
314 vals.push_back( negative ? -1. : 1.);
315 }
316}
317
318
319// dG interpolation
320template<class host_vector, class real_type>
322 dg::space sp,
323 const host_vector& x, // can be a view...
324 const RealGrid1d<real_type>& g,
325 dg::bc bcx )
326{
327 thrust::host_vector<real_type> values;
328 thrust::host_vector<int> row_offsets;
329 thrust::host_vector<int> column_indices;
330 auto ptr = x.begin();
331 row_offsets.push_back(0);
332 for( unsigned i=0; i<x.size(); i++)
333 {
334 interpolation_row( sp, *ptr, g, bcx, column_indices, values);
335 row_offsets.push_back( values.size());
336 ptr++;
337 }
338 return {x.size(), g.size(), row_offsets, column_indices, values};
339}
340
341// nearest, linear or cubic interpolation
342template<class host_vector1, class host_vector2 >
343dg::SparseMatrix<int, dg::get_value_type<host_vector2>, thrust::host_vector> interpolation1d(
344 const host_vector1& x,
345 const host_vector2& abs, // must be sorted
347 std::string method )
348{
349 using real_type = dg::get_value_type<host_vector2>;
350 // boundary condidions for dg::Box likely won't work | Box is now removed
351 // from library ...
352 thrust::host_vector<real_type> values;
353 thrust::host_vector<int> row_offsets;
354 thrust::host_vector<int> column_indices;
355 unsigned points_per_line = 1;
356 if( method == "nearest")
357 points_per_line = 1;
358 else if( method == "linear")
359 points_per_line = 2;
360 else if( method == "cubic")
361 points_per_line = 4;
362 else
363 throw std::runtime_error( "Interpolation method "+method+" not recognized!\n");
364 if( abs.size() < points_per_line)
365 throw std::runtime_error( "There must be more points to interpolate\n");
366 auto ptr = x.begin();
367 row_offsets.push_back(0);
368 thrust::host_vector<int> cols;
369 thrust::host_vector<real_type> px;
370 for( unsigned i=0; i<x.size(); i++)
371 {
372 row_offsets.push_back(row_offsets[i]);
373 real_type X = *ptr;
374 ptr++;
375 bool negative = false;
376 detail::shift( negative, X, bcx, x0, x1);
377 // THIS IS A VERY BAD IDEA PERFORMANCE WISE
378 //for( unsigned u=0; u<abs.size(); u++)
379 // if( fabs( X - abs[u]) <1e-13)
380 // idxX = u;
381 detail::choose_1d_abscissas( X,
382 points_per_line, x1-x0, abs, bcx, cols, px);
383
384 // px may have size != points_per_line (at boundary)
385 for ( unsigned l=0; l<px.size(); l++)
386 {
387 row_offsets[i+1]++;
388 column_indices.push_back( cols[l]);
389 values.push_back(negative ? -px[l] : px[l]);
390 }
391 }
392 return {x.size(), abs.size(), row_offsets, column_indices, values};
393}
394
395}//namespace detail
399
444template<class RecursiveHostVector, class real_type, size_t Nd>
446 const RecursiveHostVector& x,
448 std::array<dg::bc, Nd> bcx,
449 std::string method = "dg")
450{
451
452 std::array<dg::SparseMatrix<int,real_type,thrust::host_vector>,Nd> axes;
453 for( unsigned u=0; u<Nd; u++)
454 {
455 if( x[u].size() != x[0].size())
456 throw dg::Error( dg::Message(_ping_)<<"All coordinate lists must have same size "<<x[0].size());
457 if( method == "dg")
458 {
459 axes[u] = detail::interpolation1d( dg::xspace, x[u], g.grid(u), bcx[u]);
460 }
461 else
462 {
463 axes[u] = detail::interpolation1d( x[u], g.abscissas(u), bcx[u], g.p(u), g.q(u), method);
464 }
465 }
466 for( unsigned u=1; u<Nd; u++)
467 {
468 axes[0] = dg::tensorproduct_cols( axes[u], axes[0]);
469 }
470 return axes[0];
471}
472
491template<class host_vector, class real_type, typename = std::enable_if_t<dg::is_vector_v<host_vector>>>
493 const host_vector& x,
494 const RealGrid1d<real_type>& g,
495 dg::bc bcx = dg::NEU,
496 std::string method = "dg")
497{
498 dg::View<const host_vector> vx( x.data(), x.size());
499 return interpolation(
500 std::vector{vx}, g,
501 std::array<dg::bc,1>{bcx}, method);
502}
503
525template<class host_vector, class real_type>
527 const host_vector& x,
528 const host_vector& y,
530 dg::bc bcx = dg::NEU, dg::bc bcy = dg::NEU,
531 std::string method = "dg")
532{
533 dg::View<const host_vector> vx( x.data(), x.size());
534 dg::View<const host_vector> vy( y.data(), y.size());
535 return interpolation( std::vector{vx,vy}, g, {bcx,bcy}, method);
536}
537
538
539
563template<class host_vector, class real_type>
565 const host_vector& x,
566 const host_vector& y,
567 const host_vector& z,
569 dg::bc bcx = dg::NEU, dg::bc bcy = dg::NEU, dg::bc bcz = dg::PER,
570 std::string method = "dg")
571{
572 dg::View<const host_vector> vx( x.data(), x.size());
573 dg::View<const host_vector> vy( y.data(), y.size());
574 dg::View<const host_vector> vz( z.data(), z.size());
575 return interpolation( std::vector{vx,vy,vz}, g, {bcx,bcy,bcz}, method);
576}
597template<class real_type, size_t Nd>
599 const aRealTopology<real_type,Nd>& g_new,
600 const aRealTopology<real_type,Nd>& g_old, std::string method = "dg")
601{
602 //assert both grids are on the same box
603 for( unsigned u=0; u<Nd; u++)
604 {
605 if( g_new.p(u) < g_old.p(u))
606 std::cerr << "ERROR: New grid boundary number "<<u<<" with value p "<<g_new.p(u)<<" lies outside old grid "<<g_old.p(u)<<" "<<g_old.p(u)-g_new.p(u)<<"\n";
607 assert( g_new.p(u) >= g_old.p(u));
608 if( g_new.q(u) > g_old.q(u))
609 std::cerr << "ERROR: New grid boundary number "<<u<<" with value q "<<g_new.q(u)<<" lies outside old grid "<<g_old.q(u)<<" "<<g_old.q(u)-g_new.q(u)<<"\n";
610 assert( g_new.q(u) <= g_old.q(u));
611 }
612 std::array<dg::SparseMatrix<int,real_type,thrust::host_vector>,Nd> axes;
613 for( unsigned u=0; u<Nd; u++)
614 {
615 if( method == "dg")
616 {
617 axes[u] = detail::interpolation1d( dg::xspace, g_new.abscissas(u),
618 g_old.grid(u), g_old.bc(u));
619 }
620 else
621 {
622 axes[u] = detail::interpolation1d( g_new.abscissas(u),
623 g_old.abscissas(u), g_old.bc(u), g_old.p(u), g_old.q(u),
624 method);
625 }
626 }
627 for( unsigned u=1; u<Nd; u++)
628 axes[0] = dg::tensorproduct( axes[u], axes[0]);
629 return axes[0];
630
631}
633
634
635}//namespace create
636
637
655template<class host_vector, class real_type>
656real_type interpolate(
657 dg::space sp,
658 const host_vector& v,
659 real_type x,
660 const RealGrid1d<real_type>& g,
661 dg::bc bcx = dg::NEU)
662{
663 assert( v.size() == g.size());
664 thrust::host_vector<real_type> vals;
665 thrust::host_vector<int> cols;
666 create::detail::interpolation_row( sp, x, g, bcx, cols, vals);
667 //multiply x
668 real_type value = 0;
669 for( unsigned j=0; j<vals.size(); j++)
670 value += v[cols[j]]*vals[j];
671 return value;
672}
673
693template<class host_vector, class real_type>
694real_type interpolate(
695 dg::space sp,
696 const host_vector& v,
697 real_type x, real_type y,
699 dg::bc bcx = dg::NEU, dg::bc bcy = dg::NEU )
700{
701 assert( v.size() == g.size());
702 thrust::host_vector<real_type> valsx;
703 thrust::host_vector<int> colsx;
704 create::detail::interpolation_row( sp, x, g.gx(), bcx, colsx, valsx);
705 thrust::host_vector<real_type> valsy;
706 thrust::host_vector<int> colsy;
707 create::detail::interpolation_row( sp, y, g.gy(), bcy, colsy, valsy);
708 //multiply x
709 real_type value = 0;
710 for( unsigned i=0; i<valsy.size(); i++)
711 for( unsigned j=0; j<valsx.size(); j++)
712 value += v[colsy[i]*g.shape(0) + colsx[j]]*valsx[j]*valsy[i];
713 return value;
714}
715
716
717} //namespace dg
class intended for the use in throw statements
Definition exceptions.h:83
small class holding a stringstream
Definition exceptions.h:29
Function discretization routines.
#define _ping_
Definition exceptions.h:12
Some utility functions for the dg::evaluate routines.
base topology classes
bc
Switch between boundary conditions.
Definition enums.h:15
space
Space of DG coefficients.
Definition enums.h:164
@ z
z direction
@ NEU_DIR
Neumann on left, Dirichlet on right boundary.
Definition enums.h:19
@ PER
periodic boundaries
Definition enums.h:16
@ NEU
Neumann on both boundaries.
Definition enums.h:20
@ DIR
homogeneous dirichlet boundaries
Definition enums.h:17
@ DIR_NEU
Dirichlet on left, Neumann on right boundary.
Definition enums.h:18
@ xspace
Configuration space "nodal values".
Definition enums.h:166
@ lspace
DG Polynomial space "modal values".
Definition enums.h:165
@ forward
forward derivative (cell to the right and current cell)
Definition enums.h:98
@ y
y direction
@ x
x direction
typename TensorTraits< std::decay_t< Vector > >::value_type get_value_type
Definition tensor_traits.h:45
real_type interpolate(dg::space sp, const host_vector &v, real_type x, const RealGrid1d< real_type > &g, dg::bc bcx=dg::NEU)
Interpolate a vector on a single point on a 1d Grid.
Definition interpolation.h:656
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")
Create interpolation matrix of a list of points in given grid.
Definition interpolation.h:445
dg::SparseMatrix< int, T, thrust::host_vector > tensorproduct_cols(const dg::SparseMatrix< int, T, thrust::host_vector > &lhs, const dg::SparseMatrix< int, T, thrust::host_vector > &rhs)
Form the tensor (Kronecker) product between two matrices in the column index
Definition xspacelib.h:89
SquareMatrix< T > tensorproduct(const SquareMatrix< T > &op1, const SquareMatrix< T > &op2)
Form the tensor product between two operators.
Definition operator_tensor.h:25
dg::bc bcy
const double lx
dg::bc bcx
const double n
This is the namespace for all functions and classes defined and used by the discontinuous Galerkin li...
static std::vector< real_type > abscissas(unsigned n)
Return Gauss-Legendre nodes on the interval [-1,1].
Definition dlt.h:27
static std::vector< real_type > forward(unsigned n)
Return forward DLT trafo matrix.
Definition dlt.h:195
The simplest implementation of aRealTopology.
Definition grid.h:710
A CSR formatted sparse matrix.
Definition sparsematrix.h:102
A vector view class, usable in dg functions.
Definition view.h:45
An abstract base class for Nd-dimensional dG grids.
Definition grid.h:95
RealGrid< real_type, 1 > gy() const
Equivalent to grid(1)
Definition grid.h:360
real_type q(unsigned u=0) const
Get right boundary point for axis u.
Definition grid.h:253
RealGrid< real_type, 1 > gx() const
Equivalent to grid(0)
Definition grid.h:354
unsigned size() const
The total number of points.
Definition grid.h:532
host_vector abscissas(unsigned u=0) const
Construct grid abscissas of the u axis.
Definition grid.h:128
RealGrid< real_type, 1 > grid(unsigned u) const
Get axis u as a 1d grid.
Definition grid.h:274
real_type p(unsigned u=0) const
Get left boundary point for axis u.
Definition grid.h:250
dg::bc bc(unsigned u=0) const
Get boundary condition for axis u.
Definition grid.h:268
unsigned shape(unsigned u=0) const
the total number of points of an axis
Definition grid.h:114
Useful typedefs of commonly used types.
utility functions