libMesh
Loading...
Searching...
No Matches
elem_quality.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// C++ includes
19#include <iostream>
20#include <sstream>
21
22// Local includes
23#include "libmesh/libmesh_common.h"
24#include "libmesh/elem_quality.h"
25#include "libmesh/enum_elem_type.h"
26#include "libmesh/enum_elem_quality.h"
27
28
29namespace libMesh
30{
31
32// ------------------------------------------------------------
33// Quality function definitions
34
42std::string Quality::name (const ElemQuality q)
43{
44 std::string its_name;
45
46 switch (q)
47 {
48
50 its_name = "Edge Length Ratio";
51 break;
52
53 case ASPECT_RATIO:
54 its_name = "Aspect Ratio";
55 break;
56
57 case SKEW:
58 its_name = "Skew";
59 break;
60
61 case SHEAR:
62 its_name = "Shear";
63 break;
64
65 case SHAPE:
66 its_name = "Shape";
67 break;
68
69 case MAX_ANGLE:
70 its_name = "Maximum Angle";
71 break;
72
73 case MIN_ANGLE:
74 its_name = "Minimum Angle";
75 break;
76
78 its_name = "Maximum Dihedral Angle";
79 break;
80
82 its_name = "Minimum Dihedral Angle";
83 break;
84
85 case CONDITION:
86 its_name = "Condition Number";
87 break;
88
89 case DISTORTION:
90 its_name = "Distortion";
91 break;
92
93 case TAPER:
94 its_name = "Taper";
95 break;
96
97 case WARP:
98 its_name = "Warp";
99 break;
100
101 case STRETCH:
102 its_name = "Stretch";
103 break;
104
105 case DIAGONAL:
106 its_name = "Diagonal";
107 break;
108
110 its_name = "AR Beta";
111 break;
112
114 its_name = "AR Gamma";
115 break;
116
117 case SIZE:
118 its_name = "Size";
119 break;
120
121 case JACOBIAN:
122 its_name = "Jacobian";
123 break;
124
125 case SCALED_JACOBIAN:
126 its_name = "Scaled Jacobian";
127 break;
128
129 default:
130 its_name = "Unknown";
131 break;
132 }
133
134 return its_name;
135}
136
137
138
139
140
146std::string Quality::describe (const ElemQuality q)
147{
148
149 std::ostringstream desc;
150
151 switch (q)
152 {
153
155 case ASPECT_RATIO:
156 desc << "Max edge length ratio\n"
157 << "at element center.\n"
158 << '\n'
159 << "Suggested ranges:\n"
160 << "Hexes: (1 -> 4)\n"
161 << "Quads: (1 -> 4)";
162 break;
163
164 case SKEW:
165 desc << "Maximum |cos A|, where A\n"
166 << "is the angle between edges\n"
167 << "at element center.\n"
168 << '\n'
169 << "Suggested ranges:\n"
170 << "Hexes: (0 -> 0.5)\n"
171 << "Quads: (0 -> 0.5)";
172 break;
173
174 case SHEAR:
175 desc << "LIBMESH_DIM / K(Js)\n"
176 << '\n'
177 << "LIBMESH_DIM = element dimension.\n"
178 << "K(Js) = Condition number of \n"
179 << " Jacobian skew matrix.\n"
180 << '\n'
181 << "Suggested ranges:\n"
182 << "Hexes(LIBMESH_DIM=3): (0.3 -> 1)\n"
183 << "Quads(LIBMESH_DIM=2): (0.3 -> 1)";
184 break;
185
186 case SHAPE:
187 desc << "LIBMESH_DIM / K(Jw)\n"
188 << '\n'
189 << "LIBMESH_DIM = element dimension.\n"
190 << "K(Jw) = Condition number of \n"
191 << " weighted Jacobian\n"
192 << " matrix.\n"
193 << '\n'
194 << "Suggested ranges:\n"
195 << "Hexes(LIBMESH_DIM=3): (0.3 -> 1)\n"
196 << "Tets(LIBMESH_DIM=3): (0.2 -> 1)\n"
197 << "Quads(LIBMESH_DIM=2): (0.3 -> 1).";
198 break;
199
200 case MAX_ANGLE:
201 desc << "Largest angle between all adjacent pairs of edges (in 2D, sides).\n"
202 << '\n'
203 << "Suggested ranges:\n"
204 << "Quads: (90 -> 135)\n"
205 << "Triangles: (60 -> 90)";
206 break;
207
208 case MIN_ANGLE:
209 desc << "Smallest angle between all adjacent pairs of edges (in 2D, sides).\n"
210 << '\n'
211 << "Suggested ranges:\n"
212 << "Quads: (45 -> 90)\n"
213 << "Triangles: (30 -> 60)";
214 break;
215
217 desc << "Largest angle between all adjacent pairs of sides (in 2D, equivalent to MAX_ANGLE).\n"
218 << "In 3D, this is the largest unoriented angle between adjacent side planes, in the range [0, 90].\n"
219 << '\n'
220 << "Suggested ranges:\n"
221 << "Quads: (90 -> 135)\n"
222 << "Triangles: (60 -> 90)\n"
223 << "C0Polyhedra: (60 -> 90)";
224 break;
225
227 desc << "Smallest angle between all adjacent pairs of sides (in 2D, equivalent to MIN_ANGLE).\n"
228 << "In 3D, this is the smallest unoriented angle between adjacent side planes, in the range [0, 90].\n"
229 << '\n'
230 << "Suggested ranges:\n"
231 << "Quads: (45 -> 90)\n"
232 << "Triangles: (30 -> 60)\n"
233 << "C0Polyhedra: (30 -> 90)";
234 break;
235
236 case CONDITION:
237 desc << "Condition number of the\n"
238 << "Jacobian matrix.\n"
239 << '\n'
240 << "Suggested ranges:\n"
241 << "Quads: (1 -> 4)\n"
242 << "Hexes: (1 -> 8)\n"
243 << "Tris: (1 -> 1.3)\n"
244 << "Tets: (1 -> 3)";
245 break;
246
247 case DISTORTION:
248 desc << "min |J| * A / <A>\n"
249 << '\n'
250 << "|J| = norm of Jacobian matrix\n"
251 << " A = actual area\n"
252 << "<A> = reference area\n"
253 << '\n'
254 << "Suggested ranges:\n"
255 << "Quads: (0.6 -> 1), <A>=4\n"
256 << "Hexes: (0.6 -> 1), <A>=8\n"
257 << "Tris: (0.6 -> 1), <A>=1/2\n"
258 << "Tets: (0.6 -> 1), <A>=1/6";
259 break;
260
261 case TAPER:
262 desc << "Maximum ratio of lengths\n"
263 << "derived from opposite edges.\n"
264 << '\n'
265 << "Suggested ranges:\n"
266 << "Quads: (0.7 -> 1)\n"
267 << "Hexes: (0.4 -> 1)";
268 break;
269
270 case WARP:
271 desc << "cos D\n"
272 << '\n'
273 << "D = minimum dihedral angle\n"
274 << " formed by diagonals.\n"
275 << '\n'
276 << "Suggested ranges:\n"
277 << "Quads: (0.9 -> 1)";
278 break;
279
280 case STRETCH:
281 desc << "Sqrt(3) * L_min / L_max\n"
282 << '\n'
283 << "L_min = minimum edge length.\n"
284 << "L_max = maximum edge length.\n"
285 << '\n'
286 << "Suggested ranges:\n"
287 << "Quads: (0.25 -> 1)\n"
288 << "Hexes: (0.25 -> 1)";
289 break;
290
291 case DIAGONAL:
292 desc << "D_min / D_max\n"
293 << '\n'
294 << "D_min = minimum diagonal.\n"
295 << "D_max = maximum diagonal.\n"
296 << '\n'
297 << "Suggested ranges:\n"
298 << "Hexes: (0.65 -> 1)";
299 break;
300
302 desc << "CR / (3 * IR)\n"
303 << '\n'
304 << "CR = circumsphere radius\n"
305 << "IR = inscribed sphere radius\n"
306 << '\n'
307 << "Suggested ranges:\n"
308 << "Tets: (1 -> 3)";
309 break;
310
312 desc << "S^(3/2) / 8.479670 * V\n"
313 << '\n'
314 << "S = sum(si*si/6)\n"
315 << "si = edge length\n"
316 << "V = volume\n"
317 << '\n'
318 << "Suggested ranges:\n"
319 << "Tets: (1 -> 3)";
320 break;
321
322 case SIZE:
323 desc << "min (|J|, |1/J|)\n"
324 << '\n'
325 << "|J| = norm of Jacobian matrix.\n"
326 << '\n'
327 << "Suggested ranges:\n"
328 << "Quads: (0.3 -> 1)\n"
329 << "Hexes: (0.5 -> 1)\n"
330 << "Tris: (0.25 -> 1)\n"
331 << "Tets: (0.2 -> 1)";
332 break;
333
334 case JACOBIAN:
335 case SCALED_JACOBIAN:
336 desc << "Minimum nodal Jacobian.\n"
337 << "The nodal Jacobians are computed by taking the cross product (2D) or scalar product (3D) of the adjacent edges that meet at that node.\n"
338 << "In the SCALED_JACOBIAN case, we also then divide by the lengths of each of the associated edges.\n"
339 << "For Pyramid elements where four edges meet at the apex node, special handling is required.\n"
340 << '\n'
341 << "Suggested acceptable ranges (from Cubit documentation) for SCALED_JACOBIAN metric:\n"
342 << "Quads/Hexes: (0.5 -> 1)\n"
343 << "Tris/Tets: (0.2 -> 1.0)";
344 break;
345
346 default:
347 desc << "Unknown";
348 break;
349 }
350
351 return desc.str();
352}
353
354
355std::vector<ElemQuality> Quality::valid(const ElemType t)
356{
357 std::vector<ElemQuality> v;
358
359 switch (t)
360 {
361 case EDGE2:
362 case EDGE3:
363 case EDGE4:
364 {
365 // None yet
366 break;
367 }
368
369 case TRI3:
370 case TRISHELL3:
371 case TRI6:
372 case TRI7:
373 {
374 v = {
375 CONDITION,
378 JACOBIAN,
380 MAX_ANGLE,
381 MIN_ANGLE,
384 SHAPE,
385 SIZE
386 };
387
388 break;
389 }
390
391 case QUAD4:
392 case QUADSHELL4:
393 case QUAD8:
394 case QUADSHELL8:
395 case QUAD9:
396 case QUADSHELL9:
397 {
398 v = {
400 CONDITION,
403 JACOBIAN,
405 MAX_ANGLE,
406 MIN_ANGLE,
409 SHAPE,
410 SHEAR,
411 SIZE,
412 SKEW,
413 STRETCH,
414 TAPER,
415 WARP
416 };
417
418 break;
419 }
420
421 case TET4:
422 case TET10:
423 case TET14:
424 {
425 v = {
428 CONDITION,
430 JACOBIAN,
432 MAX_ANGLE,
433 MIN_ANGLE,
436 SHAPE,
437 SIZE
438 };
439
440 break;
441 }
442
443 case HEX8:
444 case HEX20:
445 case HEX27:
446 {
447 v = {
449 CONDITION,
450 DIAGONAL,
452 JACOBIAN,
454 MAX_ANGLE,
455 MIN_ANGLE,
458 SHAPE,
459 SHEAR,
460 SIZE,
461 SKEW,
462 STRETCH,
463 TAPER
464 };
465
466 break;
467 }
468
469 case PRISM6:
470 case PRISM18:
471 case PRISM20:
472 case PRISM21:
473 {
474 v = {
476 MAX_ANGLE,
477 MIN_ANGLE,
480 };
481
482 break;
483 }
484
485 case PYRAMID5:
486 case PYRAMID13:
487 case PYRAMID14:
488 case PYRAMID18:
489 {
490 v = {
492 MAX_ANGLE,
493 MIN_ANGLE,
496 };
497
498 break;
499 }
500
501 case C0POLYGON:
502 {
503 v = {
505 JACOBIAN,
507 MAX_ANGLE,
509 };
510
511 break;
512 }
513
514 case C0POLYHEDRON:
515 {
516 // The generic Jacobian metrics only inspect vertices with
517 // exactly three adjacent edges, but arbitrary polyhedra may
518 // have vertices of higher valence.
519 v = {
521 MAX_ANGLE,
522 MIN_ANGLE,
525 };
526
527 break;
528 }
529
530#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
531
532 case INFEDGE2:
533 {
534 // None yet
535 break;
536 }
537
538 case INFQUAD4:
539 case INFQUAD6:
540 case INFHEX8:
541 case INFHEX16:
542 case INFHEX18:
543 case INFPRISM6:
544 case INFPRISM12:
545 {
546 v = {
547 MAX_ANGLE,
548 MIN_ANGLE,
551 };
552
553 break;
554 }
555
556#endif
557
558
559 default:
560 libmesh_error_msg("Undefined element type!");
561 }
562
563 return v;
564}
565
566} // namespace libMesh
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
std::vector< ElemQuality > valid(const ElemType t)
std::string describe(const ElemQuality q)
This function returns a string containing a short description of q.
The libMesh namespace provides an interface to certain functionality in the library.
ElemType
Defines an enum for geometric element types.
ElemQuality
Defines an enum for element quality metrics.