openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
SF_fem_utils.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: Apache-2.0
3 
17 #ifndef _SF_FEM_H
18 #define _SF_FEM_H
19 
20 #include <cassert>
21 #include <cmath>
22 #include <cstring>
23 #include <mpi.h>
24 
25 #define SF_MAX_ELEM_NODES 10
26 
27 #include "SF_container.h"
28 
29 #include "SF_abstract_vector.h"
30 #include "SF_abstract_matrix.h"
31 #include "SF_abstract_lin_solver.h"
32 
33 namespace SF {
34 
43 inline short num_dof(elem_t type, short order)
44 {
45  short ndof = -1;
46  switch(type) {
47  case Line:
48  if (order == 1) ndof = 2;
49  else if (order == 2) ndof = 3;
50  else {
51  fprintf(stderr, "Line element order %d not implemented yet.\n", order);
52  exit(1);
53  }
54  break;
55  case Tri:
56  if (order == 1) ndof = 3;
57  else if (order == 2) ndof = 6;
58  else {
59  fprintf(stderr, "Tri element order %d not implemented yet.\n", order);
60  exit(1);
61  }
62  break;
63  case Quad:
64  if (order == 1) ndof = 4;
65  else if (order == 2) ndof = 8;
66  else {
67  fprintf(stderr, "Quad element order %d not implemented yet.\n", order);
68  exit(1);
69  }
70  break;
71  case Tetra:
72  if (order == 1) ndof = 4;
73  else if (order == 2) ndof = 10;
74  else {
75  fprintf(stderr, "Tetra element order %d not implemented yet.\n", order);
76  exit(1);
77  }
78  break;
79  case Hexa:
80  if (order == 1) ndof = 8;
81  else if (order == 2) ndof = 20; // serendipity element
82  else {
83  fprintf(stderr, "Hexa element order %d not implemented yet.\n", order);
84  exit(1);
85  }
86  break;
87 
88  default:
89  fprintf(stderr, "%s error: Unsupported element type.\n", __func__);
90  exit(1);
91  }
92 
93  return ndof;
94 }
95 
96 
106 inline void general_integration_points(const elem_t type,
107  const short order,
108  Point* ip,
109  double* w,
110  int & nint)
111 {
112  switch (type) {
113  case Line:
114  if (order == 1) {
115  ip[0].x = 0.; ip[0].y = 0.; ip[0].z = 0.;
116  w[0] = 2.; nint = 1;
117  } else if (order == 2) {
118  const double sqrt3 = 0.577350269189626; //=sqrt(1./3.)
119  ip[0].x = -sqrt3; ip[0].y = 0.; ip[0].z = 0.;
120  ip[1].x = +sqrt3; ip[1].y = 0.; ip[1].z = 0.;
121  w[0] = 1.; w[1] = 1.; nint = 2;
122  }
123  break;
124 
125  case Tri:
126  if (order == 1) {
127  ip[0].x = 1. / 3.; ip[0].y = 1. / 3.; ip[0].z = 0.;
128  w[0] = 1. / 2.;
129  nint = 1;
130  } else if (order == 2) {
131  ip[0].x = 1. / 6.; ip[0].y = 1. / 6.; ip[0].z = 0.;
132  ip[1].x = 4. / 6.; ip[1].y = 1. / 6.; ip[1].z = 0.;
133  ip[2].x = 1. / 6.; ip[2].y = 4. / 6.; ip[2].z = 0.;
134  w[0] = 1. / 6.; w[1] = 1. / 6.; w[2] = 1. / 6.;
135  nint = 3;
136  } else if (order == 3 || order == 4) {
137  // Gauss computed
138  ip[0].x = 0.188409405952072339650, ip[0].y = 0.787659461760847001700, ip[0].z = 0;
139  ip[1].x = 0.523979067720100721850, ip[1].y = 0.409466864440734712450, ip[1].z = 0;
140  ip[2].x = 0.808694385677669824730, ip[2].y = 0.088587959512703928766, ip[2].z = 0;
141  ip[3].x = 0.106170269119576471390, ip[3].y = 0.787659461760847001700, ip[3].z = 0;
142  ip[4].x = 0.295266567779632616020, ip[4].y = 0.409466864440734712450, ip[4].z = 0;
143  ip[5].x = 0.455706020243648035620, ip[5].y = 0.088587959512703928766, ip[5].z = 0;
144  ip[6].x = 0.023931132287080617016, ip[6].y = 0.787659461760847001700, ip[6].z = 0;
145  ip[7].x = 0.066554067839164496312, ip[7].y = 0.409466864440734712450, ip[7].z = 0;
146  ip[8].x = 0.102717654809626260380, ip[8].y = 0.088587959512703928766, ip[8].z = 0;
147 
148  w[0] = 0.019396383305959434551;
149  w[1] = 0.063678085099884929043;
150  w[2] = 0.055814420483044288601;
151  w[3] = 0.03103421328953510222;
152  w[4] = 0.1018849361598159059;
153  w[5] = 0.089303072772870889517;
154  w[6] = 0.019396383305959434551;
155  w[7] = 0.063678085099884929043;
156  w[8] = 0.055814420483044288601;
157  nint = 9;
158  }
159  break;
160 
161  case Quad:
162  if (order == 1) {
163  ip[0].x = 0.; ip[0].y = 0.; ip[0].z = 0.;
164  w[0] = 4.;
165  nint = 1;
166  } else if (order == 2 || order == 3) {
167  const double sqrt3 = 0.577350269189626; //=sqrt(1./3.)
168  ip[0].x = -sqrt3; ip[0].y = -sqrt3; ip[0].z = 0.;
169  ip[1].x = +sqrt3; ip[1].y = -sqrt3; ip[1].z = 0.;
170  ip[2].x = +sqrt3; ip[2].y = +sqrt3; ip[2].z = 0.;
171  ip[3].x = -sqrt3; ip[3].y = +sqrt3; ip[3].z = 0.;
172  w[0] = 1.; w[1] = 1.; w[2] = 1.; w[3] = 1.;
173  nint = 4;
174  } else if (order == 4) {
175  // Gauss computed
176  ip[0].x = 0.88729833462074170214, ip[0].y = 0.88729833462074170214, ip[0].z = 0;
177  ip[1].x = 0.88729833462074170214, ip[1].y = 0.5, ip[1].z = 0;
178  ip[2].x = 0.88729833462074170214, ip[2].y = 0.11270166537925829786, ip[2].z = 0;
179  ip[3].x = 0.5, ip[3].y = 0.88729833462074170214, ip[3].z = 0;
180  ip[4].x = 0.5, ip[4].y = 0.5, ip[4].z = 0;
181  ip[5].x = 0.5, ip[5].y = 0.11270166537925829786, ip[5].z = 0;
182  ip[6].x = 0.11270166537925829786, ip[6].y = 0.88729833462074170214, ip[6].z = 0;
183  ip[7].x = 0.11270166537925829786, ip[7].y = 0.5, ip[7].z = 0;
184  ip[8].x = 0.11270166537925829786, ip[8].y = 0.11270166537925829786, ip[8].z = 0;
185 
186  w[0] = 0.077160493827160225866;
187  w[1] = 0.12345679012345638081;
188  w[2] = 0.077160493827160225866;
189  w[3] = 0.12345679012345638081;
190  w[4] = 0.19753086419753024261;
191  w[5] = 0.12345679012345638081;
192  w[6] = 0.077160493827160225866;
193  w[7] = 0.12345679012345638081;
194  w[8] = 0.077160493827160225866;
195 
196  nint = 9;
197  }
198  break;
199 
200  case Tetra:
201  if (order == 0 || order == 1) {
202  // exact for linears
203  ip[0].x = 0.25; ip[0].y = 0.25; ip[0].z = 0.25;
204  w[0] = .16666666666666666666;
205  nint = 1;
206  } else if (order == 2) {
207  // exact for quadratics
208  double gauss1 = 0.13819660112501051518; // (5-sqrt(5))/20
209  double gauss2 = 0.58541019662496845446; // (5+3sqrt(5))/20
210  double weight = 0.0416666666666666666666666666666666; // 1/24
211  ip[0].x = gauss1; ip[0].y = gauss1; ip[0].z = gauss1;
212  ip[1].x = gauss2; ip[1].y = gauss1; ip[1].z = gauss1;
213  ip[2].x = gauss1; ip[2].y = gauss2; ip[2].z = gauss1;
214  ip[3].x = gauss1; ip[3].y = gauss1; ip[3].z = gauss2;
215  w[0] = weight; w[1] = weight; w[2] = weight; w[3] = weight;
216  nint = 4;
217  } else if (order == 3 || order == 4) {
218  // Gauss computed
219  ip[0].x = 0.12764656212038541505, ip[0].y = 0.29399880063162286969, ip[0].z = 0.54415184401122529412;
220  ip[1].x = 0.2457133252117133515, ip[1].y = 0.56593316507280100325, ip[1].z = 0.12251482265544139105;
221  ip[2].x = 0.30377276481470755209, ip[2].y = 0.070679724159396897787, ip[2].z = 0.54415184401122529412;
222  ip[3].x = 0.58474756320489440498, ip[3].y = 0.13605497680284600603, ip[3].z = 0.12251482265544139105;
223  ip[4].x = 0.034202793236766414198, ip[4].y = 0.29399880063162286969, ip[4].z = 0.54415184401122529412;
224  ip[5].x = 0.065838687060044420729, ip[5].y = 0.56593316507280100325, ip[5].z = 0.12251482265544139105;
225  ip[6].x = 0.081395667014670256001, ip[6].y = 0.070679724159396897787, ip[6].z = 0.54415184401122529412;
226  ip[7].x = 0.15668263733681833672, ip[7].y = 0.13605497680284600603, ip[7].z = 0.12251482265544139105;
227 
228  w[0] = 0.0091694299214797256314;
229  w[1] = 0.0211570064545240181520;
230  w[2] = 0.0160270405984766287080;
231  w[3] = 0.0369798563588529458080;
232  w[4] = 0.0091694299214797291009;
233  w[5] = 0.0211570064545240285600;
234  w[6] = 0.0160270405984766356470;
235  w[7] = 0.0369798563588529666250;
236 
237  nint = 8;
238  }
239  break;
240 
241  case Hexa:
242  if (order == 0) {
243  ip[0].x = 0.; ip[0].y = 0.; ip[0].z = 0.;
244  w[0] = 8.;
245  nint = 1;
246  } else if (order == 1 || order == 2) {
247  const double sqrt3 = 0.577350269189626; //=sqrt(1./3.)
248  ip[0].x = -sqrt3; ip[0].y = -sqrt3; ip[0].z = -sqrt3;
249  ip[1].x = +sqrt3; ip[1].y = -sqrt3; ip[1].z = -sqrt3;
250  ip[2].x = +sqrt3; ip[2].y = +sqrt3; ip[2].z = -sqrt3;
251  ip[3].x = -sqrt3; ip[3].y = +sqrt3; ip[3].z = -sqrt3;
252  ip[4].x = -sqrt3; ip[4].y = -sqrt3; ip[4].z = +sqrt3;
253  ip[5].x = +sqrt3; ip[5].y = -sqrt3; ip[5].z = +sqrt3;
254  ip[6].x = +sqrt3; ip[6].y = +sqrt3; ip[6].z = +sqrt3;
255  ip[7].x = -sqrt3; ip[7].y = +sqrt3; ip[7].z = +sqrt3;
256  w[0] = 1.; w[1] = 1.; w[2] = 1.; w[3] = 1.;
257  w[4] = 1.; w[5] = 1.; w[6] = 1.; w[7] = 1.;
258  nint = 8;
259  }
260  break;
261 
262  case Prism:
263  if (order == 0) {
264  ip[0].x = 0.33333333333333331, ip[0].y = 0.33333333333333337, ip[0].z = 0.5;
265  w[0] = 0.5;
266  nint = 1;
267  } else if(order == 1 || order == 2) {
268 #if 1
269  ip[0].x = 0.8168475628; ip[0].y = 0.0915762112; ip[0].z = 0.2113248706;
270  ip[1].x = 0.8168475628; ip[1].y = 0.0915762112; ip[1].z = 0.7886751294;
271  ip[2].x = 0.0915762112; ip[2].y = 0.8168475628; ip[2].z = 0.2113248706;
272  ip[3].x = 0.0915762112; ip[3].y = 0.8168475628; ip[3].z = 0.7886751294;
273  ip[4].x = 0.0915762112; ip[4].y = 0.0915762112; ip[4].z = 0.2113248706;
274  ip[5].x = 0.0915762112; ip[5].y = 0.0915762112; ip[5].z = 0.7886751294;
275  w[0] = 0.0833333358;
276  w[1] = 0.0833333358;
277  w[2] = 0.0833333358;
278  w[3] = 0.0833333358;
279  w[4] = 0.0833333358;
280  w[5] = 0.0833333358;
281  nint = 6;
282 #else
283  ip[0].x = 0.28001991549907407, ip[0].y = 0.64494897427831788, ip[0].z = 0.78867513459481287;
284  ip[1].x = 0.28001991549907407, ip[1].y = 0.64494897427831788, ip[1].z = 0.21132486540518713;
285  ip[2].x = 0.66639024601470143, ip[2].y = 0.15505102572168217, ip[2].z = 0.78867513459481287;
286  ip[3].x = 0.66639024601470143, ip[3].y = 0.15505102572168217, ip[3].z = 0.21132486540518713;
287  ip[4].x = 0.075031110222608124, ip[4].y = 0.64494897427831788, ip[4].z = 0.78867513459481287;
288  ip[5].x = 0.075031110222608124, ip[5].y = 0.64494897427831788, ip[5].z = 0.21132486540518713;
289  ip[6].x = 0.17855872826361643, ip[6].y = 0.15505102572168217, ip[6].z = 0.78867513459481287;
290  ip[7].x = 0.17855872826361643, ip[7].y = 0.15505102572168217, ip[7].z = 0.21132486540518713;
291  w[0] = 0.045489654564005534;
292  w[1] = 0.045489654564005548;
293  w[2] = 0.079510345435994237;
294  w[3] = 0.079510345435994265;
295  w[4] = 0.045489654564005548;
296  w[5] = 0.045489654564005562;
297  w[6] = 0.079510345435994265;
298  w[7] = 0.079510345435994292;
299  nint = 8;
300 #endif
301  }
302  break;
303 
304  case Pyramid:
305  if (order == 1) {
306  ip[0].x = -0.433013; ip[0].y = -0.433013; ip[0].z = 0.25;
307  ip[1].x = 0.433013; ip[1].y = -0.433013; ip[1].z = 0.25;
308  ip[2].x = 0.433013; ip[2].y = 0.433013; ip[2].z = 0.25;
309  ip[3].x = -0.433013; ip[3].y = 0.433013; ip[3].z = 0.25;
310  w[0] = 1. / 3;
311  w[1] = 1. / 3;
312  w[2] = 1. / 3;
313  w[3] = 1. / 3;
314  nint = 4;
315  } else if (order == 2) {
316  ip[0 ].x = 0.040086493940919059, ip[0 ].y = 0.040086493940919059, ip[0 ].z = 0.93056815579702623;
317  ip[1 ].x = 0.19053106107826956, ip[1 ].y = 0.19053106107826956, ip[1 ].z = 0.66999052179242813;
318  ip[2 ].x = 0.38681920811135617, ip[2 ].y = 0.38681920811135617, ip[2 ].z = 0.33000947820757187;
319  ip[3 ].x = 0.53726377524870672, ip[3 ].y = 0.53726377524870672, ip[3 ].z = 0.069431844202973714;
320  ip[4 ].x = 0.040086493940919059, ip[4 ].y = -0.040086493940919059, ip[4 ].z = 0.93056815579702623;
321  ip[5 ].x = 0.19053106107826956, ip[5 ].y = -0.19053106107826956, ip[5 ].z = 0.66999052179242813;
322  ip[6 ].x = 0.38681920811135617, ip[6 ].y = -0.38681920811135617, ip[6 ].z = 0.33000947820757187;
323  ip[7 ].x = 0.53726377524870672, ip[7 ].y = -0.53726377524870672, ip[7 ].z = 0.069431844202973714;
324  ip[8 ].x = -0.040086493940919059, ip[8 ].y = 0.040086493940919059, ip[8 ].z = 0.93056815579702623;
325  ip[9 ].x = -0.19053106107826956, ip[9 ].y = 0.19053106107826956, ip[9 ].z = 0.66999052179242813;
326  ip[10].x = -0.38681920811135617, ip[10].y = 0.38681920811135617, ip[10].z = 0.33000947820757187;
327  ip[11].x = -0.53726377524870672, ip[11].y = 0.53726377524870672, ip[11].z = 0.069431844202973714;
328  ip[12].x = -0.040086493940919059, ip[12].y = -0.040086493940919059, ip[12].z = 0.93056815579702623;
329  ip[13].x = -0.19053106107826956, ip[13].y = -0.19053106107826956, ip[13].z = 0.66999052179242813;
330  ip[14].x = -0.38681920811135617, ip[14].y = -0.38681920811135617, ip[14].z = 0.33000947820757187;
331  ip[15].x = -0.53726377524870672, ip[15].y = -0.53726377524870672, ip[15].z = 0.069431844202973714;
332 
333  w[0 ] = 0.000838466012258970;
334  w[1 ] = 0.035511343496716564;
335  w[2 ] = 0.14636983865620462;
336  w[3 ] = 0.15061368516815288;
337  w[4 ] = 0.000838466012258971;
338  w[5 ] = 0.035511343496716585;
339  w[6 ] = 0.1463698386562047;
340  w[7 ] = 0.15061368516815296;
341  w[8 ] = 0.000838466012258971;
342  w[9 ] = 0.035511343496716585;
343  w[10] = 0.1463698386562047;
344  w[11] = 0.15061368516815296;
345  w[12] = 0.000838466012258971;
346  w[13] = 0.035511343496716599;
347  w[14] = 0.14636983865620476;
348  w[15] = 0.15061368516815302;
349  nint = 16;
350  }
351  break;
352 
353  default:
354  fprintf(stderr, "%s error: Unsupported element type.\n", __func__);
355  exit(1);
356  }
357 }
358 
359 
368 inline void reference_shape(const elem_t type,
369  const Point ip,
370  dmat<double> & rshape)
371 {
372  switch (type) {
373  case Line:
374  {
375  rshape[0][0] = 0.5 * (1.0 - ip.x);
376  rshape[0][1] = 0.5 * (1.0 + ip.x);
377 
378  rshape[1][0] = -0.5;
379  rshape[1][1] = 0.5;
380 
381  rshape[2][0] = 0.;
382  rshape[2][1] = 0.;
383 
384  rshape[3][0] = 0.;
385  rshape[3][1] = 0.;
386  break;
387  }
388 
389  case Tri:
390  {
391  double lam0 = (1.0 - ip.x - ip.y);
392  double lam1 = ip.x;
393  double lam2 = ip.y;
394 
395  rshape[0][0] = lam0;
396  rshape[0][1] = lam1;
397  rshape[0][2] = lam2;
398 
399  // derivative w.r.t. xi
400  rshape[1][0] = -1.0;
401  rshape[1][1] = 1.0;
402  rshape[1][2] = 0.0;
403 
404  // derivative w.r.t. eta
405  rshape[2][0] = -1.0;
406  rshape[2][1] = 0.0;
407  rshape[2][2] = 1.0;
408 
409  // derivative w.r.t. zeta (is zero)
410  rshape[3][0] = 0.;
411  rshape[3][1] = 0.;
412  rshape[3][2] = 0.;
413  break;
414  }
415 
416  case Quad: {
417  double qrtr = 0.25;
418  const double node[4][2] =
419  {
420  { -1.0, -1.0},
421  { 1.0, -1.0},
422  { 1.0, 1.0},
423  { -1.0, 1.0}
424  };
425 
426  // adjust to ordering given in carp manual
427  int v[4] = {0, 1, 2, 3};
428 
429  for (int i = 0; i < 4; i++) {
430  // shape function
431  rshape[0][i] = qrtr * (1. + ip.x * node[v[i]][0]) * (1. + ip.y * node[v[i]][1]);
432  // derivative w.r.t. xi
433  rshape[1][i] = node[v[i]][0] * qrtr * (1. + ip.y * node[v[i]][1]);
434  // derivative w.r.t. eta
435  rshape[2][i] = node[v[i]][1] * qrtr * (1. + ip.x * node[v[i]][0]);
436  // derivative w.r.t. zeta (is zero)
437  rshape[3][i] = 0.;
438  }
439  break;
440  }
441 
442  case Tetra:
443  {
444  double lam0 = 1.0 - ip.x - ip.y - ip.z;
445  double lam1 = ip.x;
446  double lam2 = ip.y;
447  double lam3 = ip.z;
448  //static int v[10] = {0,3,1,2,7,8,4,6,9,5};
449 
450  // shape function
451  rshape[0][0] = lam0;
452  rshape[0][1] = lam1;
453  rshape[0][2] = lam2;
454  rshape[0][3] = lam3;
455 
456  // derivative w.r.t. xi
457  rshape[1][0] = -1.0;
458  rshape[1][1] = 1.0;
459  rshape[1][2] = 0.0;
460  rshape[1][3] = 0.0;
461 
462  // derivative w.r.t. eta
463  rshape[2][0] = -1.0;
464  rshape[2][1] = 0.0;
465  rshape[2][2] = 1.0;
466  rshape[2][3] = 0.0;
467 
468  // derivative w.r.t. zeta
469  rshape[3][0] = -1.0;
470  rshape[3][1] = 0.0;
471  rshape[3][2] = 0.0;
472  rshape[3][3] = 1.0;
473  break;
474  }
475 
476  case Hexa:
477  {
478  const double oito = 1.0 / 8.0;
479  static const double node[8][3] =
480  {
481  { -1.0, -1.0, -1.0},
482  { 1.0, -1.0, -1.0},
483  { 1.0, 1.0, -1.0},
484  { -1.0, 1.0, -1.0},
485 
486  { -1.0, -1.0, 1.0},
487  { 1.0, -1.0, 1.0},
488  { 1.0, 1.0, 1.0},
489  { -1.0, 1.0, 1.0}
490  };
491 
492  // adjust to ordering given in carp manual
493  static int v[8] = {4, 7, 6, 5, 0, 1, 2, 3};
494 
495  for (int i = 0; i < 8; i++) {
496  // shape function
497  rshape[0][i] = oito * (1. + ip.x * node[v[i]][0]) * (1. + ip.y * node[v[i]][1]) * (1. + ip.z * node[v[i]][2]);
498  // derivative w.r.t. xi
499  rshape[1][i] = node[v[i]][0] * oito * (1. + ip.y * node[v[i]][1]) * (1. + ip.z * node[v[i]][2]);
500  // derivative w.r.t. eta
501  rshape[2][i] = node[v[i]][1] * oito * (1. + ip.x * node[v[i]][0]) * (1. + ip.z * node[v[i]][2]);
502  // derivative w.r.t zeta
503  rshape[3][i] = node[v[i]][2] * oito * (1. + ip.x * node[v[i]][0]) * (1. + ip.y * node[v[i]][1]);
504  }
505 
506  break;
507  }
508 
509  case Prism:
510  {
511  rshape[0][0] = (1.0 - ip.x - ip.y) * ip.z;
512  rshape[0][1] = ip.y * ip.z;
513  rshape[0][2] = ip.x * ip.z;
514  rshape[0][3] = (1.0 - ip.x - ip.y) * (1. - ip.z);
515  rshape[0][4] = ip.x * (1. - ip.z);
516  rshape[0][5] = ip.y * (1. - ip.z);
517 
518  // derivative w.r.t. x
519  rshape[1][0] = -ip.z;
520  rshape[1][1] = 0.0;
521  rshape[1][2] = ip.z;
522  rshape[1][3] = ip.z - 1.0;
523  rshape[1][4] = 1. - ip.z;
524  rshape[1][5] = 0.0;
525 
526  // derivative w.r.t. y
527  rshape[2][0] = -ip.z;
528  rshape[2][1] = ip.z;
529  rshape[2][2] = 0.0;
530  rshape[2][3] = ip.z - 1.0;
531  rshape[2][4] = 0.0;
532  rshape[2][5] = 1. - ip.z;
533 
534  // derivative w.r.t. z
535  rshape[3][0] = 1.0 - ip.x - ip.y;
536  rshape[3][1] = ip.y;
537  rshape[3][2] = ip.x;
538  rshape[3][3] = ip.x + ip.y - 1.0;
539  rshape[3][4] = -ip.x;
540  rshape[3][5] = -ip.y;
541  break;
542  }
543 
544  case Pyramid:
545  {
546  const double qrtr = 0.25;
547  // shape function
548  const double lterm0 = ip.x * ip.y * ip.z / (1.0 - ip.z);
549  rshape[0][0] = qrtr * ( (1.0 + ip.x) * (1.0 + ip.y) - ip.z + lterm0 );
550  rshape[0][1] = qrtr * ( (1.0 - ip.x) * (1.0 + ip.y) - ip.z - lterm0 );
551  rshape[0][2] = qrtr * ( (1.0 - ip.x) * (1.0 - ip.y) - ip.z + lterm0 );
552  rshape[0][3] = qrtr * ( (1.0 + ip.x) * (1.0 - ip.y) - ip.z - lterm0 );
553  rshape[0][4] = ip.z;
554 
555  // derivative w.r.t. xi
556  const double lterm1 = (ip.y * ip.z) / (1.0 - ip.z);
557  rshape[1][0] = qrtr * ( (1.0 + ip.y) + lterm1 );
558  rshape[1][1] = qrtr * ( -(1.0 + ip.y) - lterm1 );
559  rshape[1][2] = qrtr * ( -(1.0 - ip.y) + lterm1 );
560  rshape[1][3] = qrtr * ( (1.0 - ip.y) - lterm1 );
561  rshape[1][4] = 0.0;
562 
563  // derivative w.r.t. eta
564  const double lterm2 = (ip.x * ip.z) / (1.0 - ip.z);
565  rshape[2][0] = qrtr * ( (1.0 + ip.x) + lterm2 );
566  rshape[2][1] = qrtr * ( (1.0 - ip.x) - lterm2 );
567  rshape[2][2] = qrtr * ( -(1.0 - ip.x) + lterm2 );
568  rshape[2][3] = qrtr * ( -(1.0 + ip.x) - lterm2 );
569  rshape[2][4] = 0.0;
570 
571  // derivative w.r.t zeta
572  const double lterm3 = ((ip.x * ip.y * ip.z) / (1.0 - ip.z) * (1.0 - ip.z)) + (ip.x * ip.y / (1.0 - ip.z));
573  rshape[3][0] = qrtr * ( -1.0 + lterm3 );
574  rshape[3][1] = qrtr * ( -1.0 - lterm3 );
575  rshape[3][2] = qrtr * ( -1.0 + lterm3 );
576  rshape[3][3] = qrtr * ( -1.0 - lterm3 );
577  rshape[3][4] = 1.0;
578  break;
579  }
580 
581  default:
582  fprintf(stderr, "%s: Unimplemented element type! Aborting!\n", __func__);
583  exit(1);
584  }
585 }
586 
595 inline void jacobian_matrix(const dmat<double> & rshape,
596  const int npts,
597  const Point* pts,
598  double *J)
599 {
600  // zero the 3x3 jacobian matrix
601  memset (J, 0, 9 * sizeof(double) );
602  // note that ref_shape hold shape functions in [0][i] and derivatives in [k][i]
603  // if element is 2 dimensional then [3][i] is set to 0!
604  for (int i = 0; i < npts; i++)
605  {
606  J[0] += rshape[1][i] * pts[i].x;
607  J[1] += rshape[1][i] * pts[i].y;
608  J[2] += rshape[1][i] * pts[i].z;
609  J[3] += rshape[2][i] * pts[i].x;
610  J[4] += rshape[2][i] * pts[i].y;
611  J[5] += rshape[2][i] * pts[i].z;
612  J[6] += rshape[3][i] * pts[i].x;
613  J[7] += rshape[3][i] * pts[i].y;
614  J[8] += rshape[3][i] * pts[i].z;
615  }
616 }
617 
618 inline void invert_jacobian_matrix(const elem_t type, double* J, double & detJ)
619 {
620  switch(type)
621  {
622  // all 3D elems
623  default:
624  case Tetra:
625  invert_3x3(J, detJ);
626  break;
627 
628  // 2D elems
629  case Quad:
630  case Tri: {
631  double J2[4] = {J[0], J[1], J[3], J[4]};
632 
633  invert_2x2(J2, detJ);
634  detJ = fabs(detJ);
635 
636  J[0] = J2[0]; J[1] = J2[1]; J[2] = 0.0;
637  J[3] = J2[2]; J[4] = J2[3]; J[5] = 0.0;
638  J[6] = 0.0; J[7] = 0.0; J[8] = 0.0;
639  break;
640  }
641 
642  // 1D elem
643  case Line:
644  detJ = J[0];
645  J[0] = 1.0 / detJ;
646  break;
647  }
648 }
649 
659 inline void shape_deriv(const double *iJ,
660  const dmat<double> & rshape,
661  const int ndof,
662  dmat<double> & shape)
663 {
664  for (int in = 0; in < ndof; in++)
665  {
666  shape[1][in] = iJ[0] * rshape[1][in] +
667  iJ[1] * rshape[2][in] +
668  iJ[2] * rshape[3][in];
669 
670  shape[2][in] = iJ[3] * rshape[1][in] +
671  iJ[4] * rshape[2][in] +
672  iJ[5] * rshape[3][in];
673 
674  shape[3][in] = iJ[6] * rshape[1][in] +
675  iJ[7] * rshape[2][in] +
676  iJ[8] * rshape[3][in];
677  }
678 }
679 
687 template<class T, class S>
689 {
690  private:
691  const meshdata<T, S> & _mesh;
692  const vector<T> & _glob_numbr;
693  T _esize;
694  const T* _offset_con;
695  size_t _eidx;
696  int _rank;
697 
698  public:
704  element_view(const meshdata<T, S> & mesh, const SF_nbr nbr) :
705  _mesh(mesh), _glob_numbr(_mesh.get_numbering(nbr))
706  {
707  if(mesh.l_numelem) this->set_elem(0);
708  MPI_Comm_rank(_mesh.comm, &_rank);
709  }
710 
716  inline void set_elem(size_t eidx)
717  {
718  _eidx = eidx;
719 
720  T offset = _mesh.dsp[_eidx];
721  _esize = _mesh.dsp[_eidx+1] - offset;
722  _offset_con = _mesh.con.data() + offset;
723  }
724 
730  inline bool next()
731  {
732  if(_eidx < (_mesh.l_numelem - 1) )
733  {
734  this->set_elem(_eidx + 1);
735  return true;
736  }
737  else
738  return false;
739  }
740 
746  inline T num_nodes() const
747  {
748  return _esize;
749  }
750 
756  inline elem_t type() const
757  {
758  return _mesh.type[_eidx];
759  }
760 
766  inline T tag() const
767  {
768  return _mesh.tag[_eidx];
769  }
770 
778  inline const T & node(short nidx) const
779  {
780  return _offset_con[nidx];
781  }
782 
790  inline const T & global_node(short nidx) const
791  {
792  return _glob_numbr[_offset_con[nidx]];
793  }
802  inline const T & global_node(short nidx, SF_nbr nbr) const
803  {
804  const vector<T> & n = _mesh.get_numbering(nbr);
805  return n[_offset_con[nidx]];
806  }
807 
813  inline const T* nodes() const
814  {
815  return _offset_con;
816  }
824  inline Point coord(short nidx) const
825  {
826  T idx = _offset_con[nidx];
827  return {_mesh.xyz[idx*3+0], _mesh.xyz[idx*3+1], _mesh.xyz[idx*3+2]};
828  }
829 
835  inline Point fiber() const
836  {
837  if(_mesh.fib.size())
838  return {_mesh.fib[_eidx*3+0], _mesh.fib[_eidx*3+1], _mesh.fib[_eidx*3+2]};
839  else
840  return {0,0,0};
841  }
847  inline Point sheet() const
848  {
849  if(_mesh.she.size())
850  return {_mesh.she[_eidx*3+0], _mesh.she[_eidx*3+1], _mesh.she[_eidx*3+2]};
851  else
852  return {0,0,0};
853  }
854 
860  bool has_sheet() const
861  {
862  return _mesh.she.size() > 0;
863  }
864 
870  inline size_t element_index() const
871  {
872  return _eidx;
873  }
874 
880  inline size_t global_element_index() const
881  {
882  return _mesh.epl.algebraic_layout()[_rank] + _eidx;
883  }
890  inline size_t global_element_index(SF_nbr nbr) const
891  {
892  const vector<T> & en = _mesh.get_numbering(nbr);
893  return en[_eidx];
894  }
895 
896 
897  inline short num_dof(short order) const
898  {
899  return SF::num_dof(_mesh.type[_eidx], order);
900  }
901 
902  inline void integration_points(const short order, Point* ip, double* w, int & nint) const
903  {
904  general_integration_points(_mesh.type[_eidx], order, ip, w, nint);
905  }
906 
907  inline short dimension() const
908  {
909  switch(_mesh.type[_eidx])
910  {
911  default:
912  case Tetra:
913  return 3;
914 
915  case Tri:
916  case Quad:
917  return 2;
918 
919  case Line:
920  return 1;
921  }
922  }
923 };
924 
931 template<class T, class S>
933 {
934  public:
936  virtual void operator() (const element_view<T,S> & elem, dmat<double> & buff) = 0;
938  virtual void dpn(T & row_dpn, T & col_dpn) = 0;
939 };
946 template<class T, class S>
948 {
949  protected:
950  void zero_buff(double* buff, T nrows)
951  {
952  for(T i=0; i<nrows; i++) buff[i] = 0.0;
953  }
954 
955  public:
957  virtual void operator() (const element_view<T,S> & elem, double* buff) = 0;
959  virtual void dpn(T & dpn) = 0;
960 };
961 
962 
972 template<typename T, typename V> inline
973 void canonic_indices(const T* nidx,
974  const T* nbr,
975  const T esize,
976  const short dpn,
977  V* cidx)
978 {
979  for(T i=0; i<esize; i++)
980  for(short j=0; j<dpn; j++)
981  cidx[i*dpn + j] = nbr[nidx[i]]*dpn + j;
982 }
983 
994 template<class T, class S>
998 {
999  int rank;
1000  MPI_Comm_rank(domain.comm, &rank);
1001 
1002  // we want to make sure that the element integrator fits the matrix
1003  mesh_int_t row_dpn, col_dpn;
1004  integrator.dpn(row_dpn, col_dpn);
1005  assert(mat.dpn_row() == row_dpn && mat.dpn_col() == col_dpn);
1006 
1007  // allocate row / col index buffers
1008  vector<T> row_idx(SF_MAX_ELEM_NODES * row_dpn), col_idx(SF_MAX_ELEM_NODES * col_dpn);
1009 
1010  // allocate elem index buffer
1011  dmat<S> ebuff(SF_MAX_ELEM_NODES * row_dpn, SF_MAX_ELEM_NODES * col_dpn);
1012 
1013  const vector<mesh_int_t> & petsc_nbr = domain.get_numbering(NBR_PETSC);
1014 
1015  // start with assembly
1017  for(size_t eidx=0; eidx < domain.l_numelem; eidx++)
1018  {
1019  // set element view to current element
1020  view.set_elem(eidx);
1021 
1022  // calculate row/col indices of entries
1023  mesh_int_t nnodes = view.num_nodes();
1024 
1025  row_idx.resize(nnodes*row_dpn);
1026  col_idx.resize(nnodes*col_dpn);
1027  canonic_indices<mesh_int_t,SF_int>(view.nodes(), petsc_nbr.data(), nnodes, row_dpn, row_idx.data());
1028  canonic_indices<mesh_int_t,SF_int>(view.nodes(), petsc_nbr.data(), nnodes, col_dpn, col_idx.data());
1029 
1030  // call integrator
1031  integrator(view, ebuff);
1032 
1033  // add values into system matrix
1034  const bool add = true;
1035  mat.set_values(row_idx, col_idx, ebuff.data(), add);
1036  }
1037  // finish assembly and progress output
1038  mat.finish_assembly();
1039 }
1040 
1041 template<class T, class S>
1045 {
1046  int rank;
1047  MPI_Comm_rank(domain.comm, &rank);
1048 
1049  // we want to make sure that the element integrator fits the matrix
1050  mesh_int_t row_dpn, col_dpn;
1051  integrator.dpn(row_dpn, col_dpn);
1052 
1053  assert(row_dpn == 1 && row_dpn == mat.dpn_row());
1054 
1055  // allocate row / col index buffers
1056  vector<T> row_idx(SF_MAX_ELEM_NODES * row_dpn);
1057 
1058  // allocate elem index buffer
1059  dmat<S> ebuff(SF_MAX_ELEM_NODES * row_dpn, SF_MAX_ELEM_NODES * col_dpn);
1060  const vector<mesh_int_t> & petsc_nbr = domain.get_numbering(NBR_PETSC);
1061 
1062  // start with assembly
1064  for(size_t eidx=0; eidx < domain.l_numelem; eidx++)
1065  {
1066  // set element view to current element
1067  view.set_elem(eidx);
1068 
1069  // calculate row/col indices of entries
1070  SF_int nnodes = view.num_nodes();
1071  row_idx.resize(nnodes*row_dpn);
1072  canonic_indices<mesh_int_t,T>(view.nodes(), petsc_nbr.data(), nnodes, row_dpn, row_idx.data());
1073 
1074  // call integrator
1075  integrator(view, ebuff);
1076 
1077  // do lumping
1078  for(int i=0; i<nnodes; i++) {
1079  S rowsum = 0.0;
1080 
1081  for(int j=0; j<nnodes; j++)
1082  rowsum += ebuff[i][j];
1083 
1084  // add values into system matrix
1085  mat.set_value(row_idx[i], row_idx[i], rowsum, true);
1086  }
1087  }
1088  // finish assembly and progress output
1089  mat.finish_assembly();
1090 }
1091 
1103 template<class T, class S>
1107 {
1108  int rank;
1109  MPI_Comm_rank(vec.mesh->comm, &rank);
1110 
1111  // we want to make sure that the element integrator fits the matrix
1112  T dpn;
1113  integrator.dpn(dpn);
1114  assert(vec.dpn == dpn);
1115 
1116  // allocate row / col index buffers
1117  vector<T> idx(SF_MAX_ELEM_NODES * dpn);
1118 
1119  // allocate elem index buffer
1120  vector<S> ebuff(SF_MAX_ELEM_NODES * dpn);
1121  const vector<mesh_int_t> & petsc_nbr = domain.get_numbering(NBR_PETSC);
1122 
1123  // start with assembly
1125  for(size_t eidx=0; eidx < domain.l_numelem; eidx++)
1126  {
1127  // set element view to current element
1128  view.set_elem(eidx);
1129 
1130  // calculate row/col indices of entries
1131  SF_int nnodes = view.num_nodes();
1132  canonic_indices<mesh_int_t,T>(view.nodes(), petsc_nbr.data(), nnodes, dpn, idx.data());
1133 
1134  // call integrator
1135  integrator(view, ebuff.data());
1136 
1137  // add values into system matrix
1138  vec.set(idx, ebuff, ADD_VALUES);
1139  }
1140  // finish assembly and progress output
1141  vec.finish_assembly();
1142 }
1143 
1144 template<class T, class S> inline
1146 {
1147  // the dpn has to be set for this to work
1148  int dpn = vec.dpn;
1150  assert(dpn > 0);
1151  assert(vec.layout == nodaltype);
1152 
1153  for(int i=0; i<view.num_nodes(); i++)
1154  for(int j=0; j<dpn; j++) {
1155  int idx = view.node(i)*dpn+j;
1156  buffer[i*dpn+j] = vec.get(idx);
1157  }
1158 }
1159 
1160 template<class T, class S> inline
1162 {
1163  // the dpn has to be set for this to work
1164  int dpn = vec.dpn;
1166  assert(dpn > 0);
1167  assert(vec.layout == nodaltype);
1168 
1169  SF_real* pvec = vec.ptr();
1170 
1171  for(int i=0; i<view.num_nodes(); i++)
1172  for(int j=0; j<dpn; j++) {
1173  int idx = view.node(i)*dpn+j;
1174  pvec[idx] = buffer[i*dpn+j];
1175  }
1176 
1177  vec.release_ptr(pvec);
1178 }
1179 
1180 template<class T, class S> inline
1181 void get_transformed_pts(const element_view<T,S> & view, Point* loc_pts, Point & trsf_fibre, bool orthogonal=true)
1182 {
1183  const elem_t type = view.type();
1184 
1185  switch(type) {
1186  case Line: {
1187  Point p0 = view.coord(0), p1 = view.coord(1);
1188 
1189  loc_pts[0] = {0, 0, 0};
1190  loc_pts[1] = {mag(p1 - p0), 0, 0};
1191  trsf_fibre = {1, 0, 0};
1192  break;
1193  }
1194 
1195  case Tri: {
1196  Point p0 = view.coord(0), p1 = view.coord(1), p2 = view.coord(2);
1197  Point f = trsf_fibre;
1198 
1199  Point p01 = p1 - p0, p02 = p2 - p0;
1200 
1201  Point x = normalize(p01);
1202  Point z = normalize(cross(p01,p02));
1203  Point y = cross(z, x);
1204 
1205  loc_pts[0] = {0, 0, 0};
1206  loc_pts[1] = {mag(p01), 0, 0};
1207  loc_pts[2] = {inner_prod(p02, x), inner_prod(p02, y), 0};
1208  trsf_fibre = {inner_prod(f, x), inner_prod(f, y), 0};
1209 
1210  if((fabs(trsf_fibre.x) + fabs(trsf_fibre.y)) < 1e-8 and orthogonal) {
1211  fprintf(stderr, "Fibre direction is orthogonal to triangle. Assigning (1,0,0) fiber direction.\n");
1212  trsf_fibre = {1, 0, 0};
1213  }
1214  else trsf_fibre = normalize(trsf_fibre);
1215  break;
1216  }
1217 
1218  case Quad: {
1219  Point p0 = view.coord(0), p1 = view.coord(1), p2 = view.coord(2), p3 = view.coord(3);
1220  Point f = trsf_fibre;
1221 
1222  Point p01 = p1 - p0, p02 = p2 - p0, p03 = p3 - p0;
1223 
1224  Point x = normalize(p01);
1225  Point z = normalize(cross(p01, p02));
1226  Point y = cross(z, x);
1227 
1228  loc_pts[0] = {0, 0, 0};
1229  loc_pts[1] = {mag(p01), 0, 0};
1230  loc_pts[2] = {inner_prod(p02, x), inner_prod(p02, y), 0};
1231  loc_pts[3] = {inner_prod(p03, x), inner_prod(p03, y), 0};
1232 
1233  trsf_fibre = {inner_prod(f, x), inner_prod(f, y), 0};
1234 
1235  if((fabs(trsf_fibre.x) + fabs(trsf_fibre.y)) < 1e-8 and orthogonal) {
1236  fprintf(stderr, "Fibre direction is orthogonal to quad. Assigning (1,0,0) fiber direction.\n");
1237  trsf_fibre = {1, 0, 0};
1238  }
1239  else trsf_fibre = normalize(trsf_fibre);
1240  break;
1241  }
1242 
1243  // for 3D elements we just copy over the coords
1244  default:
1245  for(int i=0; i<view.num_nodes(); i++)
1246  loc_pts[i] = view.coord(i);
1247 
1248  break;
1249  }
1250 }
1251 }
1252 
1253 #endif
Basic containers.
opencarp::local_index_t mesh_int_t
Definition: SF_container.h:31
#define SF_MAX_ELEM_NODES
max #nodes defining an element
Definition: SF_fem_utils.h:25
opencarp::real_t SF_real
Global scalar type.
Definition: SF_globals.h:18
opencarp::global_index_t SF_int
Global algebraic index type.
Definition: SF_globals.h:17
virtual void finish_assembly()=0
virtual void set_values(const vector< T > &row_idx, const vector< T > &col_idx, const vector< S > &vals, bool add)=0
virtual void set_value(T row_idx, T col_idx, S val, bool add)=0
virtual void get(const vector< T > &idx, S *out)=0
virtual S * ptr()=0
virtual void release_ptr(S *&p)=0
ltype layout
used vector layout (nodal, algebraic, unset)
int dpn
d.o.f. per mesh vertex; data is stored node-major (index = node*dpn + component).
virtual void set(const vector< T > &idx, const vector< S > &vals, const bool additive=false, const bool local=false)=0
virtual void finish_assembly()=0
const meshdata< mesh_int_t, mesh_real_t > * mesh
the connected mesh
S * data()
Definition: dense_mat.hpp:249
Comfort class. Provides getter functions to access the mesh member variables more comfortably.
Definition: SF_fem_utils.h:689
const T & node(short nidx) const
Access the connectivity information.
Definition: SF_fem_utils.h:778
Point fiber() const
Get element fiber direction.
Definition: SF_fem_utils.h:835
void integration_points(const short order, Point *ip, double *w, int &nint) const
Definition: SF_fem_utils.h:902
short num_dof(short order) const
Definition: SF_fem_utils.h:897
const T * nodes() const
Access the connectivity information.
Definition: SF_fem_utils.h:813
bool next()
Select next element if possible.
Definition: SF_fem_utils.h:730
void set_elem(size_t eidx)
Set the view to a new element.
Definition: SF_fem_utils.h:716
element_view(const meshdata< T, S > &mesh, const SF_nbr nbr)
Constructor. Initializes to element index 0.
Definition: SF_fem_utils.h:704
elem_t type() const
Getter function for the element type.
Definition: SF_fem_utils.h:756
const T & global_node(short nidx) const
Access the connectivity information.
Definition: SF_fem_utils.h:790
const T & global_node(short nidx, SF_nbr nbr) const
Access the connectivity information.
Definition: SF_fem_utils.h:802
T tag() const
Getter function for the element tag.
Definition: SF_fem_utils.h:766
size_t global_element_index(SF_nbr nbr) const
Get currently selected element index.
Definition: SF_fem_utils.h:890
Point coord(short nidx) const
Access vertex coordinates.
Definition: SF_fem_utils.h:824
size_t global_element_index() const
Get currently selected element index.
Definition: SF_fem_utils.h:880
size_t element_index() const
Get currently selected element index.
Definition: SF_fem_utils.h:870
short dimension() const
Definition: SF_fem_utils.h:907
bool has_sheet() const
Check if a sheet direction is present.
Definition: SF_fem_utils.h:860
T num_nodes() const
Getter function for the number of nodes.
Definition: SF_fem_utils.h:746
Point sheet() const
Get element sheet direction.
Definition: SF_fem_utils.h:847
Abstract matrix integration base class.
Definition: SF_fem_utils.h:933
virtual void operator()(const element_view< T, S > &elem, dmat< double > &buff)=0
compute the element matrix for a given element.
virtual void dpn(T &row_dpn, T &col_dpn)=0
return (by reference) the row and column dimensions
The mesh storage class. It contains both element and vertex data.
Definition: SF_container.h:381
vector< T > dsp
connectivity starting index of each element
Definition: SF_container.h:401
vector< S > she
sheet direction
Definition: SF_container.h:406
vector< S > fib
fiber direction
Definition: SF_container.h:405
size_t l_numelem
local number of elements
Definition: SF_container.h:384
vector< elem_t > type
element type
Definition: SF_container.h:403
vector< T > con
Definition: SF_container.h:397
vector< S > xyz
node cooridnates
Definition: SF_container.h:412
MPI_Comm comm
the parallel mesh is defined on a MPI world
Definition: SF_container.h:389
vector< T > & get_numbering(SF_nbr nbr_type)
Get the vector defining a certain numbering.
Definition: SF_container.h:449
vector< T > tag
element tag
Definition: SF_container.h:402
non_overlapping_layout< T > epl
element parallel layout
Definition: SF_container.h:415
Abstract vector integration base class.
Definition: SF_fem_utils.h:948
void zero_buff(double *buff, T nrows)
Definition: SF_fem_utils.h:950
virtual void operator()(const element_view< T, S > &elem, double *buff)=0
compute the element matrix for a given element.
virtual void dpn(T &dpn)=0
return (by reference) the row and column dimensions
A vector storing arbitrary data.
Definition: SF_vector.h:28
size_t size() const
The current size of the vector.
Definition: SF_vector.h:89
void resize(size_t n)
Resize a vector.
Definition: SF_vector.h:194
T * data()
Pointer to the vector's start.
Definition: SF_vector.h:76
Definition: dense_mat.hpp:19
double mag(const Point &vect)
vector magnitude
Definition: SF_container.h:96
void invert_3x3(S *ele, S &det)
Definition: dense_mat.hpp:437
void shape_deriv(const double *iJ, const dmat< double > &rshape, const int ndof, dmat< double > &shape)
Compute shape derivatives for an element, based on the shape derivatives of the associated reference ...
Definition: SF_fem_utils.h:659
double inner_prod(const Point &a, const Point &b)
Definition: SF_container.h:75
void assemble_vector(abstract_vector< T, S > &vec, meshdata< mesh_int_t, mesh_real_t > &domain, vector_integrator< mesh_int_t, mesh_real_t > &integrator)
Generalized vector assembly.
void extract_element_data(const element_view< mesh_int_t, mesh_real_t > &view, abstract_vector< T, S > &vec, SF_real *buffer)
void canonic_indices(const T *nidx, const T *nbr, const T esize, const short dpn, V *cidx)
Compute canonical indices from nodal indices and dpn.
Definition: SF_fem_utils.h:973
dmat< S > invert_2x2(const dmat< S > &m)
Definition: dense_mat.hpp:493
void assemble_matrix(abstract_matrix< T, S > &mat, meshdata< mesh_int_t, mesh_real_t > &domain, matrix_integrator< mesh_int_t, mesh_real_t > &integrator)
Generalized matrix assembly.
Definition: SF_fem_utils.h:995
void jacobian_matrix(const dmat< double > &rshape, const int npts, const Point *pts, double *J)
Compute Jacobian matrix from the real element to the reference element.
Definition: SF_fem_utils.h:595
short num_dof(elem_t type, short order)
Get number of d.o.f. for an element type and an Ansatz function order.
Definition: SF_fem_utils.h:43
Point normalize(const Point &vect)
Definition: SF_container.h:101
void assemble_lumped_matrix(abstract_matrix< T, S > &mat, meshdata< mesh_int_t, mesh_real_t > &domain, matrix_integrator< mesh_int_t, mesh_real_t > &integrator)
void set_element_data(const element_view< mesh_int_t, mesh_real_t > &view, SF_real *buffer, abstract_vector< T, S > &vec)
Point cross(const Point &a, const Point &b)
cross product
Definition: SF_container.h:69
elem_t
element type enum
Definition: SF_container.h:38
@ Line
Definition: SF_container.h:46
@ Tri
Definition: SF_container.h:45
@ Prism
Definition: SF_container.h:43
@ Pyramid
Definition: SF_container.h:42
@ Tetra
Definition: SF_container.h:39
@ Quad
Definition: SF_container.h:44
@ Hexa
Definition: SF_container.h:40
void general_integration_points(const elem_t type, const short order, Point *ip, double *w, int &nint)
Compute the integration point locations and weights.
Definition: SF_fem_utils.h:106
void get_transformed_pts(const element_view< T, S > &view, Point *loc_pts, Point &trsf_fibre, bool orthogonal=true)
void reference_shape(const elem_t type, const Point ip, dmat< double > &rshape)
Compute shape function and its derivatives on a reference element.
Definition: SF_fem_utils.h:368
SF_nbr
Enumeration encoding the different supported numberings.
Definition: SF_container.h:185
@ NBR_PETSC
PETSc numbering of nodes.
Definition: SF_container.h:188
void invert_jacobian_matrix(const elem_t type, double *J, double &detJ)
Definition: SF_fem_utils.h:618
Point and vector struct.
Definition: SF_container.h:50
double y
Definition: SF_container.h:52
double z
Definition: SF_container.h:53
double x
Definition: SF_container.h:51