NUMCXX  0.13.20181108
Numerical library for small projects and teaching purposes
fem2d.cxx
Go to the documentation of this file.
1 #include <numcxx/numcxx.hxx>
2 #include <numcxx/simplegrid.hxx>
3 #include <numcxx/fem2d.hxx>
4 #include <cmath>
5 #include <cassert>
6 #include <iostream>
7 
8 namespace fem2d
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::DArray2 & SLocal,
38  double & vol)
39  {
40 
41  int i0=cells(icell,0);
42  int i1=cells(icell,1);
43  int i2=cells(icell,2);
44 
45  // Fill matrix V
46  double V00= points(i1,0)- points(i0,0);
47  double V01= points(i2,0)- points(i0,0);
48 
49  double V10= points(i1,1)- points(i0,1);
50  double V11= points(i2,1)- points(i0,1);
51 
52  // Compute determinant
53  double det=V00*V11 - V01*V10;
54  double fac = 0.5/det;
55 
56  // Compute entries of local stiffness matrix
57  SLocal(0,0)= fac * ( ( V10-V11 )*( V10-V11 )+( V01-V00 )*( V01-V00 ) );
58  SLocal(0,1)= fac * ( ( V10-V11 )* V11 - ( V01-V00 )*V01 );
59  SLocal(0,2)= fac * ( -( V10-V11 )* V10 + ( V01-V00 )*V00 );
60 
61  SLocal(1,1)= fac * ( V11*V11 + V01*V01 );
62  SLocal(1,2)= fac * ( -V11*V10 - V01*V00 );
63 
64  SLocal(2,2)= fac * ( V10*V10+ V00*V00 );
65 
66  SLocal(1,0)=SLocal(0,1);
67  SLocal(2,0)=SLocal(0,2);
68  SLocal(2,1)=SLocal(1,2);
69 
70  vol=0.5*det;
71  }
72 
73 
75  const numcxx::SimpleGrid &grid,
76  const numcxx::DArray1& bcfac,
77  const numcxx::DArray1& bcval,
78  const numcxx::DArray1& source,
79  const numcxx::DArray1& kappa,
80  numcxx::DSparseMatrix &SGlobal,
81  numcxx::DArray1 &Rhs)
82  {
83 
84  auto ndim=grid.spacedim(); // space dimension
85  assert(ndim==2);
86  auto points=grid.get_points(); // Array of global nodes
87  auto cells=grid.get_cells(); // Local-global dof map
88 
89  int npoints=grid.npoints();
90  int ncells=grid.ncells();
91  double vol=0.0;
92 
93  // Local stiffness matrix,
94  numcxx::DArray2 SLocal{{0,0,0},{0,0,0},{0,0,0}};
95  numcxx::DArray2 MLocal0{{2,1,1},{1,2,1},{1,1,2}};
96  MLocal0*=1.0/12.0;
97  Rhs=0.0;
98  SGlobal(0,0)=0;
99  SGlobal.clear();
100  double third=1.0/3.0;
101 
102 
103  // Loop over all elements (cells) of the triangulation
104  for (int icell=0; icell<ncells; icell++)
105  {
106  compute_local_stiffness_matrix(icell, points,cells, SLocal, vol);
107 
108  // Assemble into global stiffness matrix
109  double klocal=(kappa(cells(icell,0))+kappa(cells(icell,1))+kappa(cells(icell,2)))/3.0;
110 
111  for (int i=0;i<=ndim;i++)
112  for (int j=0;j<=ndim;j++)
113  {
114  Rhs(cells(icell,i))+=vol*MLocal0(i,j)*source(cells(icell,j));
115  SGlobal(cells(icell,i),cells(icell,j))+=klocal*SLocal(i,j);
116  }
117  }
118 
119 
120  // Assemble boundary conditions (Dirichlet penalty method)
121  int nbfaces=grid.nbfaces();
122  auto bfaces=grid.get_bfaces();
123  auto bfaceregions=grid.get_bfaceregions();
124 
125  for (int ibface=0; ibface<nbfaces; ibface++)
126  {
127  // Obtain number of boundary condition
128  int ireg=bfaceregions(ibface);
129  int i0=bfaces(ibface,0);
130  int i1=bfaces(ibface,1);
131 
132  // Check if it is "Dirichlet"
133  if (bcfac(ireg)>=Dirichlet)
134  {
135  // Assemble penalty values
136  SGlobal(i0,i0)+=bcfac(ireg);
137  Rhs(i0)+=bcfac(ireg)*bcval(ireg);
138 
139  SGlobal(i1,i1)+=bcfac(ireg);
140  Rhs(i1)+=bcfac(ireg)*bcval(ireg);
141 
142  }
143  else if (bcfac(ireg)>0.0)
144  {
145 
146  double dx= points(bfaces(ibface,1),0)-points(bfaces(ibface,0),0);
147  double dy= points(bfaces(ibface,1),1)-points(bfaces(ibface,0),1);
148  double h=sqrt(dx*dx+dy*dy);
149 
150  SGlobal(i0,i0)+=h*bcfac(ireg)/3.0;
151  SGlobal(i0,i1)+=h*bcfac(ireg)/6.0;
152 
153  SGlobal(i1,i0)+=h*bcfac(ireg)/6.0;
154  SGlobal(i1,i1)+=h*bcfac(ireg)/3.0;
155 
156  Rhs(i0)+=0.5*h*bcval(ireg);
157  Rhs(i1)+=0.5*h*bcval(ireg);
158  }
159  }
160  SGlobal.flush();
161  }
162 
163 
164 
166  const numcxx::SimpleGrid &grid,
167  const numcxx::DArray1& bcfac,
168  const numcxx::DArray1& bcval,
169  const numcxx::DArray1& source,
170  const numcxx::DArray1& kappa,
171  double tau, // time step size
172  double theta, // method parameter
173  bool lump, // mass lumping
174  numcxx::DArray1 &OldSol,
175  numcxx::DSparseMatrix &SGlobal,
176  numcxx::DArray1 &Rhs)
177  {
178 
179  auto ndim=grid.spacedim();
180  auto points=grid.get_points(); // Array of global nodes
181  auto cells=grid.get_cells(); // Local-global dof map
182  int npoints=grid.npoints();
183  int ncells=grid.ncells();
184  double tauinv=1.0/tau;
185 
186  // Local stiffness matrix
187  numcxx::DArray2 SLocal{{0,0,0},{0,0,0},{0,0,0}};
188  numcxx::DArray2 MFull{{2,1,1},{1,2,1},{1,1,2}}; // from Stroud quadrature...
189  numcxx::DArray2 MLumped{{4,0,0},{0,4,0},{0,0,4}}; // mass lumping
190  numcxx::DArray2 MLocal(3,3);
191 
192  if (lump)
193  MLocal=MLumped/12.0;
194  else
195  MLocal=MFull/12.0;
196 
197  // Loop over all elements (cells) of the triangulation
198  Rhs=0.0;
199  SGlobal(0,0)=0;
200  SGlobal.clear();
201  double vol;
202  for (int icell=0; icell<ncells; icell++)
203  {
204  compute_local_stiffness_matrix(icell, points,cells, SLocal, vol);
205  double klocal=(kappa(cells(icell,0))+kappa(cells(icell,1))+kappa(cells(icell,2)))/3.0;
206 
207  // Quadrature for heat transfer coefficient
208  double KLocal=(kappa(cells(icell,0))+kappa(cells(icell,1))+kappa(cells(icell,2)))/3.0;
209 
210 
211  int i;
212  for (int i=0;i<=ndim;i++)
213  for (int j=0;j<=ndim;j++)
214  {
215  SGlobal(cells(icell,i),cells(icell,j))+=theta*KLocal*SLocal(i,j)+ tauinv*vol*MLocal(i,j);
216 
217  Rhs(cells(icell,i))+=((theta-1)*KLocal*SLocal(i,j)+tauinv*vol*MLocal(i,j))*
218  OldSol(cells(icell,j))+vol*MLocal(i,j)*source(cells(icell,j));
219  }
220  }
221 
222  // Assemble boundary conditions (Dirichlet penalty method)
223  int nbfaces=grid.nbfaces();
224  auto bfaces=grid.get_bfaces();
225  auto bfaceregions=grid.get_bfaceregions();
226 
227  for (int ibface=0; ibface<nbfaces; ibface++)
228  {
229  // Obtain number of boundary condition
230  int ireg=bfaceregions(ibface);
231  int i0=bfaces(ibface,0);
232  int i1=bfaces(ibface,1);
233 
234  // Check if it is "Dirichlet"
235  if (bcfac(ireg)>=Dirichlet)
236  {
237  // Assemble penalty values
238  SGlobal(i0,i0)+=bcfac(ireg);
239  Rhs(i0)+=bcfac(ireg)*bcval(ireg);
240 
241  SGlobal(i1,i1)+=bcfac(ireg);
242  Rhs(i1)+=bcfac(ireg)*bcval(ireg);
243  }
244  else if (bcfac(ireg)>0.0)
245  {
246 
247  double dx= points(bfaces(ibface,1),0)-points(bfaces(ibface,0),0);
248  double dy= points(bfaces(ibface,1),1)-points(bfaces(ibface,0),1);
249  double h=sqrt(dx*dx+dy*dy);
250  // first oder quadrature, needs to be replaced by second order
251  int i0=bfaces(ibface,0);
252  int i1=bfaces(ibface,1);
253 
254  SGlobal(i0,i0)+=theta*h*bcfac(ireg)/3.0;
255  SGlobal(i0,i1)+=theta*h*bcfac(ireg)/6.0;
256 
257  SGlobal(i1,i0)+=theta*h*bcfac(ireg)/6.0;
258  SGlobal(i1,i1)+=theta*h*bcfac(ireg)/3.0;
259 
260  Rhs(i0)+=OldSol(i0)*(1.0-theta)*h*bcfac(ireg)/3.0;
261  Rhs(i0)+=OldSol(i1)*(1.0-theta)*h*bcfac(ireg)/6.0;
262  Rhs(i1)+=OldSol(i0)*(1.0-theta)*h*bcfac(ireg)/6.0;
263  Rhs(i1)+=OldSol(i1)*(1.0-theta)*h*bcfac(ireg)/3.0;
264 
265  Rhs(i0)+=0.5*h*bcval(ireg);
266  Rhs(i0)+=0.5*h*bcval(ireg);
267  }
268  }
269  SGlobal.flush();
270  }
271 
272 
273 
274 
275  double l2norm(const numcxx::SimpleGrid &grid,
276  const numcxx::DArray1 &u)
277 
278  {
279  auto ndim=grid.spacedim();
280  auto points=grid.get_points(); // Array of global nodes
281  auto cells=grid.get_cells(); // Local-global dof map
282  int npoints=grid.npoints();
283  int ncells=grid.ncells();
284 
285  // Local mass matrix
286  numcxx::DArray2 MLocal{{2,1,1},{1,2,1},{1,1,2}}; // from Stroud quadrature...
287  MLocal*=1.0/12.0;
288 
289  double norm=0.0;
290  for (int icell=0; icell<ncells; icell++)
291  {
292  double vol;
293  compute_cell_volume(icell,points,cells,vol);
294 
295  for (int i=0;i<=ndim;i++)
296  for (int j=0;j<=ndim;j++)
297  norm+=u(cells(icell,i))*u(cells(icell,j))*vol*MLocal(i,j);
298  }
299  return sqrt(norm);
300  }
301 
302  double h1norm(const numcxx::SimpleGrid &grid,
303  const numcxx::DArray1 &u)
304  {
305  auto ndim=grid.spacedim();
306  auto points=grid.get_points(); // Array of global nodes
307  auto cells=grid.get_cells(); // Local-global dof map
308  int npoints=grid.npoints();
309  int ncells=grid.ncells();
310 
311 
312  numcxx::DArray2 SLocal(ndim+1,ndim+1);
313 
314  double norm=0.0;
315  for (int icell=0; icell<ncells; icell++)
316  {
317  double vol;
318  compute_local_stiffness_matrix(icell, points,cells, SLocal, vol);
319  for (int i=0;i<=ndim;i++)
320  for (int j=0;j<=ndim;j++)
321  norm+=u(cells(icell,i))*u(cells(icell,j))*SLocal(i,j);
322  }
323  return sqrt(norm);
324  }
325 
326 
327 
329 
330 
331 
332 
333 
334 
335 
336 }
const int ncells() const
Return number of cells.
Definition: simplegrid.hxx:63
Sparse matrix class using CRS storage scheme.
const int nbfaces() const
Return number of boundary faces.
Definition: simplegrid.hxx:69
void compute_local_stiffness_matrix(const int icell, const numcxx::DArray2 &points, const numcxx::IArray2 &cells, numcxx::DArray2 &SLocal, double &vol)
Definition: fem2d.cxx:33
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 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
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: fem2d.cxx:74
Main header of the library.
const TArray1< int > & get_bfaceregions() const
Get array of boundary markers.
Definition: simplegrid.hxx:54
double h1norm(const numcxx::SimpleGrid &grid, const numcxx::DArray1 &u)
Definition: fem2d.cxx:302
const double Dirichlet
BC value marking Dirichlet boundary condition.
Definition: fem2d.hxx:11
void assemble_transient_heat_problem(const numcxx::SimpleGrid &grid, const numcxx::DArray1 &bcfac, const numcxx::DArray1 &bcval, const numcxx::DArray1 &source, const numcxx::DArray1 &kappa, double tau, double theta, bool lump, numcxx::DArray1 &OldSol, numcxx::DSparseMatrix &SGlobal, numcxx::DArray1 &Rhs)
Definition: fem2d.cxx:165
Definition: fem2d.hxx:7
One dimensional array class.
Definition: tarray1.hxx:31
Class containing data for simple grid data structure.
Definition: simplegrid.hxx:19
void compute_cell_volume(const int icell, const numcxx::DArray2 &points, const numcxx::IArray2 &cells, double &vol)
Definition: fem2d.cxx:11
Two-dimensional array class.
Definition: tarray2.hxx:31
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 TArray2< int > & get_cells() const
Get array of point indices describing cells.
Definition: simplegrid.hxx:45
double l2norm(const numcxx::SimpleGrid &grid, const numcxx::DArray1 &u)
Definition: fem2d.cxx:275
const int spacedim() const
Return dimension of space.
Definition: simplegrid.hxx:57