NUMCXX  0.13.20181108
Numerical library for small projects and teaching purposes
fvm2d.cxx
Go to the documentation of this file.
1 #include <numcxx/numcxx.hxx>
2 #include <numcxx/simplegrid.hxx>
3 #include <numcxx/fvm2d.hxx>
4 #include <cmath>
5 #include <cassert>
6 #include <iostream>
7 
8 namespace fvm2d
9 {
10 
11  inline void compute_cell_volume(
12  const int icell,
13  const numcxx::DArray2 & points,
14  const numcxx::IArray2 & cells,
15  double & vol)
16  {
17  int i0=cells(icell,0);
18  int i1=cells(icell,1);
19  int i2=cells(icell,2);
20 
21  // Fill matrix V
22  double V00= points(i1,0)- points(i0,0);
23  double V01= points(i2,0)- points(i0,0);
24 
25  double V10= points(i1,1)- points(i0,1);
26  double V11= points(i2,1)- points(i0,1);
27 
28  // Compute determinant
29  double det=V00*V11 - V01*V10;
30  vol=0.5*det;
31  }
32 
34  const int icell,
35  const numcxx::DArray2 & points,
36  const numcxx::IArray2 & cells,
37  numcxx::DArray1 & epar,
38  numcxx::DArray1 & npar,
39  double & vol)
40  {
41  int i0=cells(icell,0);
42  int i1=cells(icell,1);
43  int i2=cells(icell,2);
44 
45 
46  // Fill matrix of edge vectors
47  double V00= points(i1,0)- points(i0,0);
48  double V10= points(i1,1)- points(i0,1);
49 
50  double V01= points(i2,0)- points(i0,0);
51  double V11= points(i2,1)- points(i0,1);
52 
53  double V02= points(i2,0)- points(i1,0);
54  double V12= points(i2,1)- points(i1,1);
55 
56 
57 
58  // Compute determinant
59  double det=V00*V11 - V01*V10;
60  vol=0.5*det;
61 
62  double ivol = 1.0/vol;
63 
64  // squares of edge lengths
65  double dd0=V02*V02+V12*V12; // l21
66  double dd1=V01*V01+V11*V11; // l20
67  double dd2=V00*V00+V10*V10; // l10
68 
69 
70  // contributions to \sigma_kl/h_kl
71  epar(0)= (dd1+dd2-dd0)*0.125*ivol;
72  epar(1)= (dd2+dd0-dd1)*0.125*ivol;
73  epar(2)= (dd0+dd1-dd2)*0.125*ivol;
74 
75 
76  // contributions to \omega_k
77  npar(0)= (epar(2)*dd2+epar(1)*dd1)*0.25;
78  npar(1)= (epar(0)*dd0+epar(2)*dd2)*0.25;
79  npar(2)= (epar(1)*dd1+epar(0)*dd0)*0.25;
80  }
81 
82 
83  void assemble_bc(
84  const numcxx::SimpleGrid &grid,
85  const numcxx::DArray1& bcfac,
86  const numcxx::DArray1& bcval,
87  numcxx::DSparseMatrix &SGlobal,
88  numcxx::DArray1 &Rhs)
89  {
90  // Assemble boundary conditions (Dirichlet penalty method)
91  int nbfaces=grid.nbfaces();
92  auto points=grid.get_points(); // Array of global nodes
93  auto bfaces=grid.get_bfaces();
94  auto bfaceregions=grid.get_bfaceregions();
95 
96  for (int ibface=0; ibface<nbfaces; ibface++)
97  {
98  // Obtain number of boundary condition
99  int ireg=bfaceregions(ibface);
100  double dx= points(bfaces(ibface,1),0)-points(bfaces(ibface,0),0);
101  double dy= points(bfaces(ibface,1),1)-points(bfaces(ibface,0),1);
102  double h=sqrt(dx*dx+dy*dy);
103  double factor=0.5*h*bcfac(ireg);
104  if (bcfac(ireg)>=Dirichlet) factor=bcfac(ireg);
105 
106  int i;
107  i=bfaces(ibface,0);
108  SGlobal(i,i)+=factor;
109  Rhs(i)+=factor*bcval(ireg);
110 
111  i=bfaces(ibface,1);
112  SGlobal(i,i)+=factor;
113  Rhs(i)+=factor*bcval(ireg);
114  }
115 
116  }
117 
118 
119 
121  const numcxx::SimpleGrid &grid,
122  const numcxx::DArray1& bcfac,
123  const numcxx::DArray1& bcval,
124  numcxx::DSparseMatrix &SGlobal,
125  numcxx::DArray1 &Sol,
126  numcxx::DArray1 &Rhs)
127  {
128  // Assemble boundary conditions (Dirichlet penalty method)
129  int nbfaces=grid.nbfaces();
130  auto points=grid.get_points(); // Array of global nodes
131  auto bfaces=grid.get_bfaces();
132  auto bfaceregions=grid.get_bfaceregions();
133 
134  for (int ibface=0; ibface<nbfaces; ibface++)
135  {
136  // Obtain number of boundary condition
137  int ireg=bfaceregions(ibface);
138  double dx= points(bfaces(ibface,1),0)-points(bfaces(ibface,0),0);
139  double dy= points(bfaces(ibface,1),1)-points(bfaces(ibface,0),1);
140  double h=sqrt(dx*dx+dy*dy);
141  double factor=0.5*h*bcfac(ireg);
142  if (bcfac(ireg)>=Dirichlet) factor=bcfac(ireg);
143 
144  int i;
145  i=bfaces(ibface,0);
146  SGlobal(i,i)+=factor;
147  Rhs(i)+=factor*(Sol(i)-bcval(ireg));
148 
149 
150  i=bfaces(ibface,1);
151  SGlobal(i,i)+=factor;
152  Rhs(i)+=factor*(Sol(i)-bcval(ireg));
153  }
154 
155  }
156 
157 
159  const numcxx::SimpleGrid &grid,
160  const numcxx::DArray1& bcfac,
161  const numcxx::DArray1& bcval,
162  const numcxx::DArray1& source,
163  const numcxx::DArray1& kappa,
164  numcxx::DSparseMatrix &SGlobal,
165  numcxx::DArray1 &Rhs)
166  {
167 
168  auto ndim=grid.spacedim(); // space dimension
169  assert(ndim==2);
170  auto points=grid.get_points(); // Array of global nodes
171  auto cells=grid.get_cells(); // Local-global dof map
172 
173  int npoints=grid.npoints();
174  int ncells=grid.ncells();
175  double vol=0.0;
176 
177  // this needs to coorespond to the edge indices
178  numcxx::IArray2 edgenodes{{1,2},{0,2},{0,1}};
179 
180  const int nnodes_per_cell=3;
181  const int nedges_per_cell=3;
182  numcxx::DArray1 epar(nnodes_per_cell);
183  numcxx::DArray1 npar(nedges_per_cell);
184  Rhs=0.0;
185  SGlobal(0,0)=0;
186  SGlobal.clear();
187 
188  // Loop over all elements (cells) of the triangulation
189  for (int icell=0; icell<ncells; icell++)
190  {
191 
192  compute_local_formfactors(icell, points,cells,epar,npar, vol);
193  for (int inode=0;inode<nnodes_per_cell;inode++)
194  {
195  int k=cells(icell,inode);
196  Rhs(k)=source(k)*npar(inode);
197  }
198 
199  for (int iedge=0;iedge<nedges_per_cell;iedge++)
200  {
201  int k0=cells(icell,edgenodes(iedge,0));
202  int k1=cells(icell,edgenodes(iedge,1));
203 
204  // Assemble fluxes with edge averaged diffusion
205  // coefficients into global matrix
206  SGlobal(k0,k0)+=epar(iedge)*0.5*(kappa(k0)+kappa(k1));
207  SGlobal(k0,k1)-=epar(iedge)*0.5*(kappa(k0)+kappa(k1));
208  SGlobal(k1,k0)-=epar(iedge)*0.5*(kappa(k0)+kappa(k1));
209  SGlobal(k1,k1)+=epar(iedge)*0.5*(kappa(k0)+kappa(k1));
210  }
211  }
212  assemble_bc(grid, bcfac, bcval, SGlobal, Rhs);
213  SGlobal.flush();
214  }
215 
216 
217 
218 
220  const numcxx::SimpleGrid &grid,
221  const numcxx::DArray1& bcfac,
222  const numcxx::DArray1& bcval,
223  const numcxx::DArray1& source,
224  std::function <void(const double, double&, double&)> fkappa,
225  numcxx::DSparseMatrix &SGlobal,
226  numcxx::DArray1 &Sol,
227  numcxx::DArray1 &Rhs)
228  {
229 
230  auto ndim=grid.spacedim(); // space dimension
231  assert(ndim==2);
232  auto points=grid.get_points(); // Array of global nodes
233  auto cells=grid.get_cells(); // Local-global dof map
234 
235  int npoints=grid.npoints();
236  int ncells=grid.ncells();
237  double vol=0.0;
238 
239  // this needs to coorespond to the edge indices
240  numcxx::IArray2 edgenodes{{1,2},{0,2},{0,1}};
241 
242  const int nnodes_per_cell=3;
243  const int nedges_per_cell=3;
244  numcxx::DArray1 epar(nnodes_per_cell);
245  numcxx::DArray1 npar(nedges_per_cell);
246 
247  numcxx::DArray1 kappa(nnodes_per_cell);
248  numcxx::DArray1 dkappa(nnodes_per_cell);
249 
250 
251  Rhs=0.0;
252  SGlobal(0,0)=0;
253  SGlobal.clear();
254 
255 
256  // Loop over all elements (cells) of the triangulation
257  for (int icell=0; icell<ncells; icell++)
258  {
259 
260  compute_local_formfactors(icell, points,cells,epar,npar, vol);
261  for (int inode=0;inode<nnodes_per_cell;inode++)
262  {
263  int k=cells(icell,inode);
264  Rhs(k)-=source(k)*npar(inode);
265  fkappa(Sol(k),kappa(inode),dkappa(inode));
266  }
267 
268  for (int iedge=0;iedge<nedges_per_cell;iedge++)
269  {
270  int i0=edgenodes(iedge,0);
271  int i1=edgenodes(iedge,1);
272  int k0=cells(icell,i0);
273  int k1=cells(icell,i1);
274 
275 
276  double flux=epar(iedge)*0.5*(kappa(i0)+kappa(i1))*(Sol(k0)-Sol(k1));
277  Rhs(k0)+=flux;
278  Rhs(k1)-=flux;
279 
280  SGlobal(k0,k0)+= epar(iedge)*( 0.5*(kappa(i0)+kappa(i1))+0.5*dkappa(i0)*(Sol(k0)-Sol(k1)));
281  SGlobal(k0,k1)+= epar(iedge)*(-0.5*(kappa(i0)+kappa(i1))+0.5*dkappa(i1)*(Sol(k0)-Sol(k1)));
282  SGlobal(k1,k0)+= epar(iedge)*(-0.5*(kappa(i0)+kappa(i1))-0.5*dkappa(i0)*(Sol(k0)-Sol(k1)));
283  SGlobal(k1,k1)+= epar(iedge)*( 0.5*(kappa(i0)+kappa(i1))-0.5*dkappa(i1)*(Sol(k0)-Sol(k1)));
284  }
285  }
286  assemble_apply_bc(grid, bcfac, bcval, SGlobal, Sol,Rhs);
287  SGlobal.flush();
288  }
289 
290 
292  numcxx::SimpleGrid &grid,// Discretization grid
293  numcxx::DArray1& g,
294  numcxx::DArray1& Sol
295  )
296  {
297 
298  int nbfaces=grid.nbfaces();
299  auto bfaces=grid.get_bfaces();
300  auto bfaceregions=grid.get_bfaceregions();
301 
302  for (int ibface=0; ibface<nbfaces; ibface++)
303  {
304  int i;
305  int ireg=bfaceregions(ibface);
306 
307  i=bfaces(ibface,0);
308  Sol(i)=g(ireg);
309 
310  i=bfaces(ibface,1);
311  Sol(i)=g(ireg);
312  }
313 
314  }
315 
316 
317 
318  double l2norm(const numcxx::SimpleGrid &grid,
319  const numcxx::DArray1 &u)
320  {
321  auto ndim=grid.spacedim();
322  auto points=grid.get_points(); // Array of global nodes
323  auto cells=grid.get_cells(); // Local-global dof map
324  int npoints=grid.npoints();
325  int ncells=grid.ncells();
326 
327  double vol=0.0;
328 
329 
330  numcxx::DArray1 epar(ndim+1);
331  numcxx::DArray1 npar(ndim+1);
332 
333 
334  double norm=0.0;
335  for (int icell=0; icell<ncells; icell++)
336  {
337  double vol;
338  compute_local_formfactors(icell, points,cells,epar,npar, vol);
339 
340  for (int i=0;i<=ndim;i++)
341  norm+=u(cells(icell,i))*u(cells(icell,i))*npar(i);
342  }
343  return sqrt(norm);
344  }
345 
346  double h1norm(const numcxx::SimpleGrid &grid,
347  const numcxx::DArray1 &u)
348  {
349  auto ndim=grid.spacedim();
350  auto points=grid.get_points(); // Array of global nodes
351  auto cells=grid.get_cells(); // Local-global dof map
352  int npoints=grid.npoints();
353  int ncells=grid.ncells();
354 
355  double vol=0.0;
356 
357 
358  numcxx::DArray1 epar(ndim+1);
359  numcxx::DArray1 npar(ndim+1);
360 
361 
362  double norm=0.0;
363  for (int icell=0; icell<ncells; icell++)
364  {
365  double vol;
366  compute_local_formfactors(icell, points,cells,epar,npar, vol);
367 
368  double d01=u(cells(icell,0))-u(cells(icell,1));
369  double d02=u(cells(icell,0))-u(cells(icell,2));
370  double d12=u(cells(icell,1))-u(cells(icell,2));
371 
372 
373  norm+=epar(0)*d12*d12+epar(1)*d02*d02+epar(2)*d01*d01;
374  }
375 
376 
377  return sqrt(norm);
378  }
379 
380 
381 
382 
383 
384 
386 
387 
388 
389 
390 
391 
392 
393 }
double l2norm(const numcxx::SimpleGrid &grid, const numcxx::DArray1 &u)
Definition: fvm2d.cxx:318
const int ncells() const
Return number of cells.
Definition: simplegrid.hxx:63
void initialize_bc(numcxx::SimpleGrid &grid, numcxx::DArray1 &g, numcxx::DArray1 &Sol)
Definition: fvm2d.cxx:291
Sparse matrix class using CRS storage scheme.
const int nbfaces() const
Return number of boundary faces.
Definition: simplegrid.hxx:69
const TArray2< int > & get_bfaces() const
Get array of point indices describing boundary faces.
Definition: simplegrid.hxx:51
Header for simple grid data class.
void compute_local_formfactors(const int icell, const numcxx::DArray2 &points, const numcxx::IArray2 &cells, numcxx::DArray1 &epar, numcxx::DArray1 &npar, double &vol)
Definition: fvm2d.cxx:33
void flush()
Re-create the internal data structure in order to accomodated all newly created elements.
const TArray2< double > & get_points() const
Get array of point coordinates.
Definition: simplegrid.hxx:42
Main header of the library.
const TArray1< int > & get_bfaceregions() const
Get array of boundary markers.
Definition: simplegrid.hxx:54
Definition: fvm2d.hxx:9
void compute_cell_volume(const int icell, const numcxx::DArray2 &points, const numcxx::IArray2 &cells, double &vol)
Definition: fvm2d.cxx:11
void assemble_and_apply_nonlinear_heat(const numcxx::SimpleGrid &grid, const numcxx::DArray1 &bcfac, const numcxx::DArray1 &bcval, const numcxx::DArray1 &source, std::function< void(const double, double &, double &)> fkappa, numcxx::DSparseMatrix &SGlobal, numcxx::DArray1 &Sol, numcxx::DArray1 &Rhs)
Definition: fvm2d.cxx:219
void assemble_heat_problem(const numcxx::SimpleGrid &Grid, const numcxx::DArray1 &BCfac, const numcxx::DArray1 &BCval, const numcxx::DArray1 &Source, const numcxx::DArray1 &Kappa, numcxx::DSparseMatrix &SGlobal, numcxx::DArray1 &Rhs)
Definition: fvm2d.cxx:158
void assemble_apply_bc(const numcxx::SimpleGrid &grid, const numcxx::DArray1 &bcfac, const numcxx::DArray1 &bcval, numcxx::DSparseMatrix &SGlobal, numcxx::DArray1 &Sol, numcxx::DArray1 &Rhs)
Definition: fvm2d.cxx:120
One dimensional array class.
Definition: tarray1.hxx:31
Class containing data for simple grid data structure.
Definition: simplegrid.hxx:19
Two-dimensional array class.
Definition: tarray2.hxx:31
double h1norm(const numcxx::SimpleGrid &grid, const numcxx::DArray1 &u)
Definition: fvm2d.cxx:346
void assemble_bc(const numcxx::SimpleGrid &grid, const numcxx::DArray1 &bcfac, const numcxx::DArray1 &bcval, numcxx::DSparseMatrix &SGlobal, numcxx::DArray1 &Rhs)
Definition: fvm2d.cxx:83
const int npoints() const
Return number of points.
Definition: simplegrid.hxx:66
A::value_type norm(const A &a)
Euklidean norm of array or expression.
Definition: util.hxx:54
const double Dirichlet
BC value marking Dirichlet boundary condition.
Definition: fvm2d.hxx:13
const TArray2< int > & get_cells() const
Get array of point indices describing cells.
Definition: simplegrid.hxx:45
const int spacedim() const
Return dimension of space.
Definition: simplegrid.hxx:57