Discontinuous Galerkin Library
#include "dg/algorithm.h"
fem.h
Go to the documentation of this file.
1#pragma once
2
3#include "../blas.h"
4#include "grid.h"
5#include "xspacelib.h"
6#include "fem_weights.h"
7
8namespace dg{
9
12
19template<class Container>
21{
23 TriDiagonal() = default;
24 TriDiagonal( unsigned size) : M(size), O(size), P(size){}
25 TriDiagonal( Container M, Container O, Container P)
26 : M(M), O(O), P(P){}
27 template<class Container2>
29 dg::assign( other.M, this->M);
30 dg::assign( other.O, this->O);
31 dg::assign( other.P, this->P);
32 }
33 unsigned size()const {return O.size();}
34 void operator()( const Container& x, Container& y) const
35 {
36 unsigned size = M.size();
38 unsigned i,
39 const value_type* M,
40 const value_type* O,
41 const value_type* P,
42 const value_type* x, value_type* y)
43 {
44 if(i==0)
45 y[i] = O[i]*x[i] + P[i]*x[i+1];
46 else if ( i == size -1 )
47 y[i] = M[i]*x[i-1] + O[i] * x[i];
48 else
49 y[i] = M[i]*x[i-1] + O[i] * x[i] + P[i] *x[i+1];
50 }, M.size(), M, O, P, x, y);
51 }
52
55 unsigned size = M.size();
56 cusp::coo_matrix<int,value_type,cusp::host_memory> A( size, size, 3*size-2);
57 A.row_indices[0] = 0;
58 A.column_indices[0] = 0;
59 A.values[0] = O[0];
60
61 A.row_indices[1] = 0;
62 A.column_indices[1] = 1;
63 A.values[1] = P[0];
64
65 for( unsigned i=1;i<size; i++)
66 {
67 A.row_indices[3*i-1+0] = i;
68 A.column_indices[3*i-1+0] = i-1;
69 A.values[3*i-1+0] = M[i];
70
71 A.row_indices[3*i-1+1] = i;
72 A.column_indices[3*i-1+1] = i;
73 A.values[3*i-1+1] = O[i];
74
75 if( i != (size-1))
76 {
77 A.row_indices[3*i-1+2] = i;
78 A.column_indices[3*i-1+2] = i+1;
79 A.values[3*i-1+2] = P[i];
80 }
81 }
83 }
84
85 Container M, O, P;
86};
87
93template<class value_type>
95{
96 InverseTriDiagonal() = default;
97 InverseTriDiagonal( const TriDiagonal<thrust::host_vector<value_type>>& tri)
98 {
99 dg::assign( tri.M, this->M);
100 dg::assign( tri.O, this->O);
101 dg::assign( tri.P, this->P);
102 }
103
104 void operator()( const thrust::host_vector<value_type>& y, thrust::host_vector<value_type>& x) const
105 {
106 unsigned size = M.size();
107 thrust::host_vector<value_type> ci(size), di(size);
108 x.resize(size);
109 ci[0] = P[0]/O[0];
110 di[0] = y[0]/O[0];
111 for( unsigned i=1; i<size; i++)
112 {
113 ci[i] = P[i]/ ( O[i] -M[i]*ci[i-1]);
114 di[i] = (y[i]-M[i]*di[i-1])/(O[i] -M[i]*ci[i-1]);
115 }
116 x[size-1] = di[size-1];
117 for( int i=size-2; i>=0; i--)
118 x[i] = di[i] - ci[i]*x[i+1];
119 }
120 private:
121 thrust::host_vector<value_type> M, O, P;
122};
123
130template<class Container>
132{
136 KroneckerTriDiagonal2d( unsigned nz, TriDiagonal<Container> my, TriDiagonal<Container> mx): m_nz(nz), m_y(my), m_x(mx){}
137
138 unsigned& nz() { return m_nz;}
139 unsigned nz() const { return m_nz;}
140 template<class Container2>
142 m_x = other.x();
143 m_y = other.y();
144 m_nz = other.nz();
145 }
146 const TriDiagonal<Container>& x() const {return m_x;}
147 const TriDiagonal<Container>& y() const {return m_y;}
148 template<class ContainerType0, class ContainerType1>
149 void operator()( const ContainerType0& x, ContainerType1& y) const
150 {
151 unsigned size = m_y.size()*m_x.size()*m_nz;
152 unsigned Nx = m_x.size(), Ny = m_y.size();
154 unsigned i,
155 const value_type* yM,
156 const value_type* yO,
157 const value_type* yP,
158 const value_type* xM,
159 const value_type* xO,
160 const value_type* xP,
161 const value_type* x, value_type* y){
162 unsigned j = (i/Nx)/Ny;
163 unsigned k = (i/Nx)%Ny, l = i%Nx;
164 value_type a, b, c;
165 if(l==0)
166 {
167 if( k==0)
168 {
169 b = xO[l]*x[(j*Ny+k)*Nx+l] + xP[l]*x[(j*Ny+k)*Nx+l+1];
170 c = xO[l]*x[(j*Ny+k+1)*Nx+l] + xP[l]*x[(j*Ny+k+1)*Nx+l+1];
171 y[i] = yO[k]*b + yP[k]*c;
172 }
173 else if( k == Ny-1)
174 {
175 a = xO[l]*x[(j*Ny+k-1)*Nx+l] + xP[l]*x[(j*Ny+k-1)*Nx+l+1];
176 b = xO[l]*x[(j*Ny+k)*Nx+l] + xP[l]*x[(j*Ny+k)*Nx+l+1];
177 y[i] = yM[k]*a + yO[k]*b;
178 }
179 else
180 {
181 a = xO[l]*x[(j*Ny+k-1)*Nx+l] + xP[l]*x[(j*Ny+k-1)*Nx+l+1];
182 b = xO[l]*x[(j*Ny+k)*Nx+l] + xP[l]*x[(j*Ny+k)*Nx+l+1];
183 c = xO[l]*x[(j*Ny+k+1)*Nx+l] + xP[l]*x[(j*Ny+k+1)*Nx+l+1];
184 y[i] = yM[k]*a + yO[k]*b + yP[k]*c;
185 }
186 }
187 else if ( l == Nx -1 )
188 {
189 if( k==0)
190 {
191 b = xM[l]*x[(j*Ny+k)*Nx+l-1] + xO[l]*x[(j*Ny+k)*Nx+l];
192 c = xM[l]*x[(j*Ny+k+1)*Nx+l-1] + xO[l]*x[(j*Ny+k+1)*Nx+l];
193 y[i] = yO[k]*b + yP[k]*c;
194 }
195 else if ( k == Ny -1)
196 {
197 a = xM[l]*x[(j*Ny+k-1)*Nx+l-1] + xO[l]*x[(j*Ny+k-1)*Nx+l];
198 b = xM[l]*x[(j*Ny+k)*Nx+l-1] + xO[l]*x[(j*Ny+k)*Nx+l];
199 y[i] = yM[k]*a + yO[k]*b;
200 }
201 else
202 {
203 a = xM[l]*x[(j*Ny+k-1)*Nx+l-1] + xO[l]*x[(j*Ny+k-1)*Nx+l];
204 b = xM[l]*x[(j*Ny+k)*Nx+l-1] + xO[l]*x[(j*Ny+k)*Nx+l];
205 c = xM[l]*x[(j*Ny+k+1)*Nx+l-1] + xO[l]*x[(j*Ny+k+1)*Nx+l];
206 y[i] = yM[k]*a + yO[k]*b + yP[k]*c;
207 }
208 }
209 else
210 {
211 if( k==0)
212 {
213 b = xM[l]*x[(j*Ny+k)*Nx+l-1] + xO[l]*x[(j*Ny+k)*Nx+l] +
214 xP[l]*x[(j*Ny+k)*Nx+l+1];
215 c = xM[l]*x[(j*Ny+k+1)*Nx+l-1] + xO[l]*x[(j*Ny+k+1)*Nx+l] +
216 xP[l]*x[(j*Ny+k+1)*Nx+l+1];
217 y[i] = yO[k]*b + yP[k]*c;
218 }
219 else if ( k == Ny -1)
220 {
221 a = xM[l]*x[(j*Ny+k-1)*Nx+l-1] + xO[l]*x[(j*Ny+k-1)*Nx+l] +
222 xP[l]*x[(j*Ny+k-1)*Nx+l+1];
223 b = xM[l]*x[(j*Ny+k)*Nx+l-1] + xO[l]*x[(j*Ny+k)*Nx+l] +
224 xP[l]*x[(j*Ny+k)*Nx+l+1];
225 y[i] = yM[k]*a + yO[k]*b;
226 }
227 else
228 {
229 a = xM[l]*x[(j*Ny+k-1)*Nx+l-1] + xO[l]*x[(j*Ny+k-1)*Nx+l] +
230 xP[l]*x[(j*Ny+k-1)*Nx+l+1];
231 b = xM[l]*x[(j*Ny+k)*Nx+l-1] + xO[l]*x[(j*Ny+k)*Nx+l] +
232 xP[l]*x[(j*Ny+k)*Nx+l+1];
233 c = xM[l]*x[(j*Ny+k+1)*Nx+l-1] + xO[l]*x[(j*Ny+k+1)*Nx+l] +
234 xP[l]*x[(j*Ny+k+1)*Nx+l+1];
235 y[i] = yM[k]*a + yO[k]*b + yP[k]*c;
236 }
237 }
238 }, size, m_y.M, m_y.O, m_y.P, m_x.M, m_x.O, m_x.P, x, y);
239 }
240 private:
241 unsigned m_nz;
243};
244
251template<class Container>
253{
257 {
258 m_t = tri;
259 unsigned size = m_t.x().size()*m_t.y().size()*m_t.nz();
260 m_ci.resize( size);
261 m_di.resize( size);
262 m_tmp.resize( size);
263 }
264 template<class Container2>
266 {
267 m_t = inv_tri.tri();
268 unsigned size = m_t.x().size()*m_t.y().size()*m_t.nz();
269 m_ci.resize( size);
270 m_di.resize( size);
271 m_tmp.resize( size);
272 }
273 const KroneckerTriDiagonal2d<Container>& tri() const {return m_t;}
274 template<class ContainerType0, class ContainerType1>
275 void operator()( const ContainerType0& y, ContainerType1& x)
276 {
277 unsigned Nx = m_t.x().size(), Ny = m_t.y().size();
278 // solve in two passes, first x then y
280 unsigned k,
281 const value_type* M,
282 const value_type* O,
283 const value_type* P,
284 value_type* ci,
285 value_type* di,
286 const value_type* y, value_type* x){
287 ci[k*Nx + 0] = P[0]/O[0];
288 di[k*Nx + 0] = y[k*Nx + 0]/O[0];
289 for( unsigned i=1; i<Nx; i++)
290 {
291 ci[k*Nx+i] = P[i]/ ( O[i] -M[i]*ci[k*Nx+i-1]);
292 di[k*Nx+i] = (y[k*Nx+i]-M[i]*di[k*Nx+i-1])/(O[i] -M[i]*ci[k*Nx+i-1]);
293 }
294 x[k*Nx + Nx-1] = di[k*Nx + Nx-1];
295 for( int i=Nx-2; i>=0; i--)
296 x[k*Nx+i] = di[k*Nx+i] - ci[k*Nx+i]*x[k*Nx +i+1];
297
298 }, m_t.y().size()*m_t.nz(), m_t.x().M, m_t.x().O, m_t.x().P, m_ci, m_di, y, m_tmp);
299
300 dg::blas2::parallel_for( [ this, Nx, Ny] DG_DEVICE(
301 unsigned l,
302 const value_type* M,
303 const value_type* O,
304 const value_type* P,
305 value_type* ci,
306 value_type* di,
307 const value_type* y, value_type* x){
308 unsigned i = l%Nx, j = l/Nx;
309 ci[(j*Ny+0)*Nx + i] = P[0]/O[0];
310 di[(j*Ny+0)*Nx + i] = y[(j*Ny+0)*Nx + i]/O[0];
311 for( unsigned k=1; k<Ny; k++)
312 {
313 ci[(j*Ny+k)*Nx+i] = P[k]/ ( O[k] -M[k]*ci[(j*Ny+k-1)*Nx+i]);
314 di[(j*Ny+k)*Nx+i] = (y[(j*Ny+k)*Nx+i]-M[k]*di[(j*Ny+k-1)*Nx+i])/(O[k] -M[k]*ci[(j*Ny+k-1)*Nx+i]);
315 }
316 x[(j*Ny+Ny-1)*Nx + i] = di[(j*Ny+Ny-1)*Nx + i];
317 for( int k=Ny-2; k>=0; k--)
318 x[(j*Ny+k)*Nx+i] = di[(j*Ny+k)*Nx+i] - ci[(j*Ny+k)*Nx+i]*x[(j*Ny+k+1)*Nx +i];
319
320 }, m_t.x().size()*m_t.nz(), m_t.y().M, m_t.y().O, m_t.y().P, m_ci, m_di,m_tmp, x);
321 }
322
323 private:
325 Container m_ci, m_di, m_tmp;
326
327};
329
330namespace create{
331
334
366template<class real_type>
368 const RealGrid1d<real_type>& g)
369{
371 std::vector<real_type> xx = g.dlt().abscissas();
372 std::vector<real_type> xa( g.n()+2);
373 xa[0] = (xx[g.n()-1]-2)*g.h()/2.; // the last one from the previous cell
374 for( unsigned i=0; i<g.n(); i++)
375 xa[i+1]=xx[i]*g.h()/2.;
376 xa[g.n()+1] = (xx[0]+2)*g.h()/2.; // the first one from next cell
377 const real_type* x = &xa[1];
378 real_type xleft = -g.h()/2., xright = g.h()/2.;
379 auto weights = fem_weights(g);
380 for( unsigned i=0; i<g.N(); i++)
381 for( int k=0; k<(int)g.n(); k++)
382 {
383 if( i==0 && k == 0)
384 {
385 A.M[0] = 0.;
386 A.O[0] = (4*x[0]-6*xleft+2*x[1])/6./weights[0];
387 A.P[0] = (x[1]-x[0])/6./weights[0];
388 continue;
389 }
390 int I = (i*g.n()+k);
391 if( (i==g.N()-1) && (k == (int)g.n()-1))
392 {
393 A.M[I] = (x[k]-x[k-1])/6./weights[I];
394 A.O[I] = (-4*x[k]+6*xright-2*x[k-1])/6./weights[I];
395 A.P[I] = 0.;
396 continue;
397 }
398 A.M[I] = (x[k]-x[k-1])/6./weights[I];
399 A.O[I] = 2.*(x[k+1]-x[k-1])/6./weights[I];
400 A.P[I] = (x[k+1]-x[k])/6./weights[I];
401 }
402 return A;
403}
404
406template<class real_type>
408 const RealGrid1d<real_type>& g)
409{
410 //bug! periodic boundary conditions
412 std::vector<real_type> xx = g.dlt().abscissas();
413 std::vector<real_type> xa( g.n()+2);
414 xa[0] = (xx[g.n()-1]-2)*g.h()/2.; // the last one from the previous cell
415 for( unsigned i=0; i<g.n(); i++)
416 xa[i+1]=xx[i]*g.h()/2.;
417 xa[g.n()+1] = (xx[0]+2)*g.h()/2.; // the first one from next cell
418 const real_type* x = &xa[1];
419 real_type xleft = -g.h()/2., xright = g.h()/2.;
420 auto weights = fem_weights(g);
421
422 for( unsigned i=0; i<g.N(); i++)
423 for( int k=0; k<(int)g.n(); k++)
424 {
425 if( i==0 && k == 0)
426 {
427 A.M[0] = 0.;
428 A.O[0] = (5*x[0]-8*xleft+3*x[1])/8./weights[0];
429 A.P[0] = (x[1]-x[0])/8./weights[0];
430 continue;
431 }
432 int I = (i*g.n()+k);
433 if( (i==g.N()-1) && (k == (int)g.n()-1))
434 {
435 A.M[I] = (x[k]-x[k-1])/8./weights[I];
436 A.O[I] = (-5*x[k]+8*xright-3*x[k-1])/8./weights[I];
437 A.P[I] = 0.;
438 continue;
439 }
440 A.M[I] = (x[k]-x[k-1])/8./weights[I];
441 A.O[I] = 3.*(x[k+1]-x[k-1])/8./weights[I];
442 A.P[I] = (x[k+1]-x[k])/8./weights[I];
443 }
444 return A;
445}
446
448template<class real_type>
451{
452 auto mx = fem_mass(g.gx());
453 auto my = fem_mass(g.gy());
454 return {my, mx};
455}
456
458template<class real_type>
461{
462 auto tri = fem_mass( g);
463 return {tri};
464}
465
467template<class real_type>
470{
471 auto mx = fem_linear2const(g.gx());
472 auto my = fem_linear2const(g.gy());
473 return {my, mx};
474}
475
477template<class real_type>
480{
481 auto tri = fem_linear2const( g);
482 return {tri};
483}
484
486template<class real_type>
489{
490 auto mx = fem_mass(g.gx());
491 auto my = fem_mass(g.gy());
492 return {g.gz().size(), my, mx};
493}
494
496template<class real_type>
499{
500 auto tri = fem_mass2d( g);
501 return {tri};
502}
503
505template<class real_type>
508{
509 auto mx = fem_linear2const(g.gx());
510 auto my = fem_linear2const(g.gy());
511 return {g.gz().size(), my, mx};
512}
513
515template<class real_type>
518{
519 auto tri = fem_linear2const2d( g);
520 return {tri};
521}
522
524}//namespace create
525}//namespace dg
Creation functions for finite element utilities.
#define DG_DEVICE
Expands to __host__ __device__ if compiled with nvcc else is empty.
Definition: functions.h:9
base topology classes
void assign(const from_ContainerType &from, ContainerType &to, Params &&... ps)
Generic way to assign the contents of a from_ContainerType object to a ContainerType object optionall...
Definition: blas1.h:665
void parallel_for(Stencil f, unsigned N, ContainerType &&x, ContainerTypes &&... xs)
; Customizable and generic for loop
Definition: blas2.h:378
@ y
y direction
@ x
x direction
dg::InverseKroneckerTriDiagonal2d< dg::HVec_t< real_type > > inv_fem_mass(const aRealTopology2d< real_type > &g)
Inverse finite element mass matrix .
Definition: fem.h:459
dg::InverseKroneckerTriDiagonal2d< dg::HVec_t< real_type > > inv_fem_mass2d(const aRealTopology3d< real_type > &g)
Inverse finite element mass matrix .
Definition: fem.h:497
thrust::host_vector< real_type > fem_weights(const RealGrid1d< real_type > &g)
finite element weight coefficients
Definition: fem_weights.h:53
dg::InverseKroneckerTriDiagonal2d< dg::HVec_t< real_type > > inv_fem_linear2const(const aRealTopology2d< real_type > &g)
Inverse finite element mass matrix .
Definition: fem.h:478
dg::InverseKroneckerTriDiagonal2d< dg::HVec_t< real_type > > inv_fem_linear2const2d(const aRealTopology3d< real_type > &g)
Inverse finite element mass matrix .
Definition: fem.h:516
dg::KroneckerTriDiagonal2d< dg::HVec_t< real_type > > fem_linear2const2d(const aRealTopology3d< real_type > &g)
finite element projection matrix
Definition: fem.h:506
dg::TriDiagonal< dg::HVec_t< real_type > > fem_mass(const RealGrid1d< real_type > &g)
finite element projection matrix
Definition: fem.h:367
dg::KroneckerTriDiagonal2d< dg::HVec_t< real_type > > fem_mass2d(const aRealTopology3d< real_type > &g)
finite element projection matrix
Definition: fem.h:487
dg::TriDiagonal< dg::HVec_t< real_type > > fem_linear2const(const RealGrid1d< real_type > &g)
finite element projection matrix
Definition: fem.h:407
MPI_Vector< thrust::host_vector< real_type > > weights(const aRealMPITopology2d< real_type > &g)
Nodal weight coefficients.
Definition: mpi_weights.h:22
typename TensorTraits< std::decay_t< Vector > >::value_type get_value_type
Definition: tensor_traits.h:38
cusp::csr_matrix< int, real_type, cusp::host_memory > IHMatrix_t
Definition: typedefs.h:37
This is the namespace for all functions and classes defined and used by the discontinuous Galerkin li...
Fast inverse tridiagonal sparse matrix in 2d .
Definition: fem.h:253
InverseKroneckerTriDiagonal2d(const KroneckerTriDiagonal2d< Container > &tri)
Definition: fem.h:256
InverseKroneckerTriDiagonal2d(const InverseKroneckerTriDiagonal2d< Container2 > &inv_tri)
Definition: fem.h:265
dg::get_value_type< Container > value_type
Definition: fem.h:254
void operator()(const ContainerType0 &y, ContainerType1 &x)
Definition: fem.h:275
const KroneckerTriDiagonal2d< Container > & tri() const
Definition: fem.h:273
Fast inverse tridiagonal sparse matrix.
Definition: fem.h:95
InverseTriDiagonal(const TriDiagonal< thrust::host_vector< value_type > > &tri)
Definition: fem.h:97
void operator()(const thrust::host_vector< value_type > &y, thrust::host_vector< value_type > &x) const
Definition: fem.h:104
InverseTriDiagonal()=default
Fast tridiagonal sparse matrix in 2d .
Definition: fem.h:132
KroneckerTriDiagonal2d(unsigned nz, TriDiagonal< Container > my, TriDiagonal< Container > mx)
Definition: fem.h:136
unsigned nz() const
Definition: fem.h:139
dg::get_value_type< Container > value_type
Definition: fem.h:133
unsigned & nz()
Definition: fem.h:138
KroneckerTriDiagonal2d(const KroneckerTriDiagonal2d< Container2 > &other)
Definition: fem.h:141
const TriDiagonal< Container > & x() const
Definition: fem.h:146
const TriDiagonal< Container > & y() const
Definition: fem.h:147
void operator()(const ContainerType0 &x, ContainerType1 &y) const
Definition: fem.h:149
KroneckerTriDiagonal2d(TriDiagonal< Container > my, TriDiagonal< Container > mx)
Definition: fem.h:135
1D grid
Definition: grid.h:80
real_type h() const
cell size
Definition: grid.h:129
unsigned n() const
number of polynomial coefficients
Definition: grid.h:141
const DLT< real_type > & dlt() const
the discrete legendre transformation
Definition: grid.h:197
unsigned size() const
n()*N() (Total number of grid points)
Definition: grid.h:191
unsigned N() const
number of cells
Definition: grid.h:135
Fast (shared memory) tridiagonal sparse matrix.
Definition: fem.h:21
Container P
Definition: fem.h:85
TriDiagonal()=default
TriDiagonal(unsigned size)
Definition: fem.h:24
dg::get_value_type< Container > value_type
Definition: fem.h:22
TriDiagonal(const TriDiagonal< Container2 > &other)
Definition: fem.h:28
dg::IHMatrix_t< value_type > asIMatrix() const
convert to a sparse matrix format
Definition: fem.h:54
TriDiagonal(Container M, Container O, Container P)
Definition: fem.h:25
unsigned size() const
Definition: fem.h:33
Container M
Definition: fem.h:85
void operator()(const Container &x, Container &y) const
Definition: fem.h:34
Container O
Definition: fem.h:85
An abstract base class for two-dimensional grids.
Definition: grid.h:277
const RealGrid1d< real_type > & gy() const
The y-axis grid.
Definition: grid.h:379
const RealGrid1d< real_type > & gx() const
The x-axis grid.
Definition: grid.h:377
An abstract base class for three-dimensional grids.
Definition: grid.h:523
const RealGrid1d< real_type > & gz() const
The z-axis grid.
Definition: grid.h:664
const RealGrid1d< real_type > & gx() const
The x-axis grid.
Definition: grid.h:660
const RealGrid1d< real_type > & gy() const
The y-axis grid.
Definition: grid.h:662
utility functions