libMesh
Loading...
Searching...
No Matches
face_quad9.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18// Local includes
19#include "libmesh/edge_edge3.h"
20#include "libmesh/face_quad9.h"
21#include "libmesh/enum_io_package.h"
22#include "libmesh/enum_order.h"
23
24namespace libMesh
25{
26
27
28
29
30// ------------------------------------------------------------
31// Quad9 class static member initializations
32const int Quad9::num_nodes;
33const int Quad9::nodes_per_side;
34
35
36#ifdef LIBMESH_ENABLE_AMR
37
39 {
40 // embedding matrix for child 0
41 {
42 // 0 1 2 3 4 5 6 7 8
43 { 1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000 }, // 0
44 { 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.00000, 0.00000, 0.00000 }, // 1
45 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000 }, // 2
46 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000 }, // 3
47 { 0.375000, -0.125000, 0.00000, 0.00000, 0.750000, 0.00000, 0.00000, 0.00000, 0.00000 }, // 4
48 { 0.00000, 0.00000, 0.00000, 0.00000, 0.375000, 0.00000, -0.125000, 0.00000, 0.750000 }, // 5
49 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.125000, 0.00000, 0.375000, 0.750000 }, // 6
50 { 0.375000, 0.00000, 0.00000, -0.125000, 0.00000, 0.00000, 0.00000, 0.750000, 0.00000 }, // 7
51 { 0.140625, -0.0468750, 0.0156250, -0.0468750, 0.281250, -0.0937500, -0.0937500, 0.281250, 0.562500 } // 8
52 },
53
54 // embedding matrix for child 1
55 {
56 // 0 1 2 3 4 5 6 7 8
57 { 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.00000, 0.00000, 0.00000 }, // 0
58 { 0.00000, 1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000 }, // 1
59 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.00000, 0.00000 }, // 2
60 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000 }, // 3
61 { -0.125000, 0.375000, 0.00000, 0.00000, 0.750000, 0.00000, 0.00000, 0.00000, 0.00000 }, // 4
62 { 0.00000, 0.375000, -0.125000, 0.00000, 0.00000, 0.750000, 0.00000, 0.00000, 0.00000 }, // 5
63 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.375000, 0.00000, -0.125000, 0.750000 }, // 6
64 { 0.00000, 0.00000, 0.00000, 0.00000, 0.375000, 0.00000, -0.125000, 0.00000, 0.750000 }, // 7
65 { -0.0468750, 0.140625, -0.0468750, 0.0156250, 0.281250, 0.281250, -0.0937500, -0.0937500, 0.562500 } // 8
66 },
67
68 // embedding matrix for child 2
69 {
70 // 0 1 2 3 4 5 6 7 8
71 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000 }, // 0
72 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000 }, // 1
73 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.00000 }, // 2
74 { 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000 }, // 3
75 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.125000, 0.00000, 0.375000, 0.750000 }, // 4
76 { 0.00000, 0.00000, 0.00000, 0.00000, -0.125000, 0.00000, 0.375000, 0.00000, 0.750000 }, // 5
77 { 0.00000, 0.00000, -0.125000, 0.375000, 0.00000, 0.00000, 0.750000, 0.00000, 0.00000 }, // 6
78 { -0.125000, 0.00000, 0.00000, 0.375000, 0.00000, 0.00000, 0.00000, 0.750000, 0.00000 }, // 7
79 { -0.0468750, 0.0156250, -0.0468750, 0.140625, -0.0937500, -0.0937500, 0.281250, 0.281250, 0.562500 } // 8
80 },
81
82 // embedding matrix for child 3
83 {
84 // 0 1 2 3 4 5 6 7 8
85 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000 }, // 0
86 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.00000, 0.00000 }, // 1
87 { 0.00000, 0.00000, 1.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000 }, // 2
88 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.00000 }, // 3
89 { 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.375000, 0.00000, -0.125000, 0.750000 }, // 4
90 { 0.00000, -0.125000, 0.375000, 0.00000, 0.00000, 0.750000, 0.00000, 0.00000, 0.00000 }, // 5
91 { 0.00000, 0.00000, 0.375000, -0.125000, 0.00000, 0.00000, 0.750000, 0.00000, 0.00000 }, // 6
92 { 0.00000, 0.00000, 0.00000, 0.00000, -0.125000, 0.00000, 0.375000, 0.00000, 0.750000 }, // 7
93 { 0.0156250, -0.0468750, 0.140625, -0.0468750, -0.0937500, 0.281250, 0.281250, -0.0937500, 0.562500 } // 8
94 }
95 };
96
97#endif
98
99
100
101// ------------------------------------------------------------
102// Quad9 class member functions
103
104bool Quad9::is_vertex(const unsigned int i) const
105{
106 if (i < 4)
107 return true;
108 return false;
109}
110
111bool Quad9::is_edge(const unsigned int i) const
112{
113 if (i < 4)
114 return false;
115 if (i > 7)
116 return false;
117 return true;
118}
119
120bool Quad9::is_face(const unsigned int i) const
121{
122 if (i > 7)
123 return true;
124 return false;
125}
126
127bool Quad9::is_node_on_side(const unsigned int n,
128 const unsigned int s) const
129{
130 libmesh_assert_less (s, n_sides());
131 return std::find(std::begin(side_nodes_map[s]),
132 std::end(side_nodes_map[s]),
133 n) != std::end(side_nodes_map[s]);
134}
135
136std::vector<unsigned>
137Quad9::nodes_on_side(const unsigned int s) const
138{
139 libmesh_assert_less(s, n_sides());
140 return {std::begin(side_nodes_map[s]), std::end(side_nodes_map[s])};
141}
142
143std::vector<unsigned>
144Quad9::nodes_on_edge(const unsigned int e) const
145{
146 return nodes_on_side(e);
147}
148
150{
151 // make sure corners form a parallelogram
152 Point v = this->point(1) - this->point(0);
153 if (!v.relative_fuzzy_equals(this->point(2) - this->point(3), affine_tol))
154 return false;
155 // make sure "horizontal" sides are straight
156 v /= 2;
157 if (!v.relative_fuzzy_equals(this->point(4) - this->point(0), affine_tol) ||
158 !v.relative_fuzzy_equals(this->point(6) - this->point(3), affine_tol))
159 return false;
160 // make sure "vertical" sides are straight
161 // and the center node is centered
162 v = (this->point(3) - this->point(0))/2;
163 if (!v.relative_fuzzy_equals(this->point(7) - this->point(0), affine_tol) ||
164 !v.relative_fuzzy_equals(this->point(5) - this->point(1), affine_tol) ||
165 !v.relative_fuzzy_equals(this->point(8) - this->point(4), affine_tol))
166 return false;
167 return true;
168}
169
170
171
173{
174 return SECOND;
175}
176
177
178
179dof_id_type Quad9::key (const unsigned int s) const
180{
181 libmesh_assert_less (s, this->n_sides());
182
183 switch (s)
184 {
185 case 0:
186
187 return
188 this->compute_key (this->node_id(4));
189
190 case 1:
191
192 return
193 this->compute_key (this->node_id(5));
194
195 case 2:
196
197 return
198 this->compute_key (this->node_id(6));
199
200 case 3:
201
202 return
203 this->compute_key (this->node_id(7));
204
205 default:
206 libmesh_error_msg("Invalid side s = " << s);
207 }
208}
209
210
211
213{
214 return this->compute_key(this->node_id(8));
215}
216
217
218
219unsigned int Quad9::local_side_node(unsigned int side,
220 unsigned int side_node) const
221{
222 libmesh_assert_less (side, this->n_sides());
223 libmesh_assert_less (side_node, Quad9::nodes_per_side);
224
225 return Quad9::side_nodes_map[side][side_node];
226}
227
228
229
230std::unique_ptr<Elem> Quad9::build_side_ptr (const unsigned int i)
231{
232 return this->simple_build_side_ptr<Edge3, Quad9>(i);
233}
234
235
236
237void Quad9::build_side_ptr (std::unique_ptr<Elem> & side,
238 const unsigned int i)
239{
240 this->simple_build_side_ptr<Quad9>(side, i, EDGE3);
241}
242
243
244
245void Quad9::connectivity(const unsigned int sf,
246 const IOPackage iop,
247 std::vector<dof_id_type> & conn) const
248{
249 libmesh_assert_less (sf, this->n_sub_elem());
250 libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);
251
252 conn.resize(4);
253
254 switch (iop)
255 {
256 case TECPLOT:
257 {
258 switch(sf)
259 {
260 case 0:
261 // linear sub-quad 0
262 conn[0] = this->node_id(0)+1;
263 conn[1] = this->node_id(4)+1;
264 conn[2] = this->node_id(8)+1;
265 conn[3] = this->node_id(7)+1;
266 return;
267
268 case 1:
269 // linear sub-quad 1
270 conn[0] = this->node_id(4)+1;
271 conn[1] = this->node_id(1)+1;
272 conn[2] = this->node_id(5)+1;
273 conn[3] = this->node_id(8)+1;
274 return;
275
276 case 2:
277 // linear sub-quad 2
278 conn[0] = this->node_id(7)+1;
279 conn[1] = this->node_id(8)+1;
280 conn[2] = this->node_id(6)+1;
281 conn[3] = this->node_id(3)+1;
282 return;
283
284 case 3:
285 // linear sub-quad 3
286 conn[0] = this->node_id(8)+1;
287 conn[1] = this->node_id(5)+1;
288 conn[2] = this->node_id(2)+1;
289 conn[3] = this->node_id(6)+1;
290 return;
291
292 default:
293 libmesh_error_msg("Invalid sf = " << sf);
294 }
295 }
296
297 case VTK:
298 {
299 conn.resize(Quad9::num_nodes);
300 for (auto i : index_range(conn))
301 conn[i] = this->node_id(i);
302 return;
303 }
304
305 default:
306 libmesh_error_msg("Unsupported IO package " << iop);
307 }
308}
309
310
311
313{
314 // This might have curved edges, or might be a curved surface in
315 // 3-space, in which case the full bounding box can be larger than
316 // the bounding box of just the nodes.
317 //
318 //
319 // FIXME - I haven't yet proven the formula below to be correct for
320 // biquadratics - RHS
321 Point pmin, pmax;
322
323 for (unsigned d=0; d<LIBMESH_DIM; ++d)
324 {
325 const Real center = this->point(8)(d);
326 Real hd = std::abs(center - this->point(0)(d));
327 for (unsigned int p=0; p != 8; ++p)
328 hd = std::max(hd, std::abs(center - this->point(p)(d)));
329
330 pmin(d) = center - hd;
331 pmax(d) = center + hd;
332 }
333
334 return BoundingBox(pmin, pmax);
335}
336
337
338
340{
341 // This specialization is good for Lagrange mappings only
342 if (this->mapping_type() != LAGRANGE_MAP)
343 return this->Elem::volume();
344
345 // Make copies of our points. It makes the subsequent calculations a bit
346 // shorter and avoids dereferencing the same pointer multiple times.
347 Point
348 x0 = point(0), x1 = point(1), x2 = point(2),
349 x3 = point(3), x4 = point(4), x5 = point(5),
350 x6 = point(6), x7 = point(7), x8 = point(8);
351
352 // Construct constant data vectors.
353 // \vec{x}_{\xi} = \vec{a1}*xi*eta^2 + \vec{b1}*eta**2 + \vec{c1}*xi*eta + \vec{d1}*xi + \vec{e1}*eta + \vec{f1}
354 // \vec{x}_{\eta} = \vec{a2}*xi^2*eta + \vec{b2}*xi**2 + \vec{c2}*xi*eta + \vec{d2}*xi + \vec{e2}*eta + \vec{f2}
355 // This is copy-pasted directly from the output of a Python script.
356 Point
357 a1 = x0/2 + x1/2 + x2/2 + x3/2 - x4 - x5 - x6 - x7 + 2*x8,
358 b1 = -x0/4 + x1/4 + x2/4 - x3/4 - x5/2 + x7/2,
359 c1 = -x0/2 - x1/2 + x2/2 + x3/2 + x4 - x6,
360 d1 = x5 + x7 - 2*x8,
361 e1 = x0/4 - x1/4 + x2/4 - x3/4,
362 f1 = x5/2 - x7/2,
363 a2 = a1,
364 b2 = -x0/4 - x1/4 + x2/4 + x3/4 + x4/2 - x6/2,
365 c2 = -x0/2 + x1/2 + x2/2 - x3/2 - x5 + x7,
366 d2 = x0/4 - x1/4 + x2/4 - x3/4,
367 e2 = x4 + x6 - 2*x8,
368 f2 = -x4/2 + x6/2;
369
370 // 3x3 quadrature, exact for bi-quintics
371 const unsigned int N = 3;
372 const Real q[N] = {-std::sqrt(15)/5., 0., std::sqrt(15)/5.};
373 const Real w[N] = {5./9, 8./9, 5./9};
374
375 Real vol=0.;
376 for (unsigned int i=0; i<N; ++i)
377 for (unsigned int j=0; j<N; ++j)
378 vol += w[i] * w[j] *
379 cross_norm(q[i]*q[j]*q[j]*a1 + q[j]*q[j]*b1 + q[j]*q[i]*c1 + q[i]*d1 + q[j]*e1 + f1,
380 q[i]*q[i]*q[j]*a2 + q[i]*q[i]*b2 + q[j]*q[i]*c2 + q[i]*d2 + q[j]*e2 + f2);
381
382 return vol;
383}
384
385
386
387
388unsigned int Quad9::n_second_order_adjacent_vertices (const unsigned int n) const
389{
390 switch (n)
391 {
392 case 4:
393 case 5:
394 case 6:
395 case 7:
396 return 2;
397
398 case 8:
399 return 4;
400
401 default:
402 libmesh_error_msg("Invalid n = " << n);
403 }
404}
405
406
407
408unsigned short int Quad9::second_order_adjacent_vertex (const unsigned int n,
409 const unsigned int v) const
410{
411 libmesh_assert_greater_equal (n, this->n_vertices());
412 libmesh_assert_less (n, this->n_nodes());
413
414 switch (n)
415 {
416 case 8:
417 {
418 libmesh_assert_less (v, 4);
419 return static_cast<unsigned short int>(v);
420 }
421
422 default:
423 {
424 libmesh_assert_less (v, 2);
425 // use the matrix that we inherited from \p Quad
426 return _second_order_adjacent_vertices[n-this->n_vertices()][v];
427 }
428 }
429}
430
431
432
433std::pair<unsigned short int, unsigned short int>
434Quad9::second_order_child_vertex (const unsigned int n) const
435{
436 libmesh_assert_greater_equal (n, this->n_vertices());
437 libmesh_assert_less (n, this->n_nodes());
438 /*
439 * the _second_order_vertex_child_* vectors are
440 * stored in face_quad.C, since they are identical
441 * for Quad8 and Quad9 (for the first 4 higher-order nodes)
442 */
443 return std::pair<unsigned short int, unsigned short int>
446}
447
448
449void Quad9::permute(unsigned int perm_num)
450{
451 libmesh_assert_less (perm_num, 4);
452
453 for (unsigned int i = 0; i != perm_num; ++i)
454 {
455 swap4nodes(0,1,2,3);
456 swap4nodes(4,5,6,7);
457 swap4neighbors(0,1,2,3);
458 }
459}
460
461
462void Quad9::flip(BoundaryInfo * boundary_info)
463{
464 libmesh_assert(boundary_info);
465
466 swap2nodes(0,1);
467 swap2nodes(2,3);
468 swap2nodes(5,7);
469 swap2neighbors(1,3);
470 swap2boundarysides(1,3,boundary_info);
471 swap2boundaryedges(1,3,boundary_info);
472}
473
474
475unsigned int Quad9::center_node_on_side(const unsigned short side) const
476{
477 libmesh_assert_less (side, Quad9::num_sides);
478 return side + 4;
479}
480
481
482ElemType Quad9::side_type (const unsigned int libmesh_dbg_var(s)) const
483{
484 libmesh_assert_less (s, 4);
485 return EDGE3;
486}
487
488
489} // namespace libMesh
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
Defines a Cartesian bounding box by the two corner extremum.
void swap4nodes(unsigned int n1, unsigned int n2, unsigned int n3, unsigned int n4)
Swaps four node_ptrs, "rotating" them.
Definition elem.h:2273
static constexpr Real affine_tol
Default tolerance to use in has_affine_map().
Definition elem.h:2191
const Point & point(const unsigned int i) const
Definition elem.h:2583
void swap2nodes(unsigned int n1, unsigned int n2)
Swaps two node_ptrs.
Definition elem.h:2222
void swap2neighbors(unsigned int n1, unsigned int n2)
Swaps two neighbor_ptrs.
Definition elem.h:2232
void swap2boundarysides(unsigned short s1, unsigned short s2, BoundaryInfo *boundary_info) const
Swaps two sides in boundary_info, if it is non-null.
Definition elem.C:3982
ElemMappingType mapping_type() const
Definition elem.h:3258
static dof_id_type compute_key(dof_id_type n0)
Definition elem.h:3432
virtual Real volume() const
Definition elem.C:3865
void swap2boundaryedges(unsigned short e1, unsigned short e2, BoundaryInfo *boundary_info) const
Swaps two edges in boundary_info, if it is non-null.
Definition elem.C:3998
dof_id_type node_id(const unsigned int i) const
Definition elem.h:2605
void swap4neighbors(unsigned int n1, unsigned int n2, unsigned int n3, unsigned int n4)
Swaps four neighbor_ptrs, "rotating" them.
Definition elem.h:2283
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:41
virtual bool is_vertex(const unsigned int i) const override
Definition face_quad9.C:104
virtual std::vector< unsigned int > nodes_on_side(const unsigned int s) const override
Definition face_quad9.C:137
virtual Real volume() const override
An optimized method for approximating the area of a QUAD9 using quadrature.
Definition face_quad9.C:339
virtual BoundingBox loose_bounding_box() const override
Definition face_quad9.C:312
static const int nodes_per_side
Definition face_quad9.h:200
unsigned int center_node_on_side(const unsigned short side) const override final
Definition face_quad9.C:475
virtual bool is_edge(const unsigned int i) const override
Definition face_quad9.C:111
static const int num_nodes
Geometric constants for Quad9.
Definition face_quad9.h:199
static constexpr const unsigned int(& side_nodes_map)[num_sides][nodes_per_side]
Definition face_quad9.h:209
virtual dof_id_type key() const override
Compute a unique key for this element which is suitable for hashing (not necessarily unique,...
Definition face_quad9.C:212
static const Real _embedding_matrix[num_children][num_nodes][num_nodes]
Matrix that computes new nodal locations/solution values from current nodes/solution.
Definition face_quad9.h:254
virtual unsigned int n_second_order_adjacent_vertices(const unsigned int n) const override
Definition face_quad9.C:388
virtual bool is_face(const unsigned int i) const override
Definition face_quad9.C:120
virtual std::vector< unsigned int > nodes_on_edge(const unsigned int e) const override
Definition face_quad9.C:144
virtual std::pair< unsigned short int, unsigned short int > second_order_child_vertex(const unsigned int n) const override
Definition face_quad9.C:434
virtual unsigned int n_sub_elem() const override
Definition face_quad9.h:83
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const override
Definition face_quad9.C:219
virtual bool has_affine_map() const override
Definition face_quad9.C:149
virtual unsigned int n_nodes() const override
Definition face_quad9.h:78
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i) override
Definition face_quad9.C:230
virtual Order default_order() const override
Definition face_quad9.C:172
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const override
Definition face_quad9.C:127
virtual unsigned short int second_order_adjacent_vertex(const unsigned int n, const unsigned int v) const override
Definition face_quad9.C:408
virtual void permute(unsigned int perm_num) override final
Permutes the element (by swapping node and neighbor pointers) according to the specified index.
Definition face_quad9.C:449
virtual void flip(BoundaryInfo *) override final
Flips the element (by swapping node and neighbor pointers) to have a mapping Jacobian of opposite sig...
Definition face_quad9.C:462
virtual void connectivity(const unsigned int sf, const IOPackage iop, std::vector< dof_id_type > &conn) const override
Definition face_quad9.C:245
ElemType side_type(const unsigned int s) const override final
Definition face_quad9.C:482
virtual unsigned int n_vertices() const override final
Definition face_quad.h:102
static const int num_children
Definition face_quad.h:86
static const int num_sides
Geometric constants for Quad4.
Definition face_quad.h:85
virtual unsigned int n_sides() const override final
Definition face_quad.h:97
static const unsigned short int _second_order_adjacent_vertices[4][2]
Matrix that tells which vertices define the location of mid-side (or second-order) nodes.
Definition face_quad.h:224
static const unsigned short int _second_order_vertex_child_number[9]
Vector that names a child sharing each second order node.
Definition face_quad.h:229
static const unsigned short int _second_order_vertex_child_index[9]
Vector that names the child vertex index for each second order node.
Definition face_quad.h:234
bool relative_fuzzy_equals(const TypeVector< T > &rhs, Real tol=TOLERANCE) const
The libMesh namespace provides an interface to certain functionality in the library.
LIBMESH_DEVICE_INLINE T cross_norm(const TypeVector< T > &b, const TypeVector< T > &c)
Calls cross_norm_sq() and takes the square root of the result.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
IOPackage
libMesh interfaces with several different software packages for the purposes of creating,...
ElemType
Defines an enum for geometric element types.
libmesh_assert(ctx)
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real