LCOV - code coverage report
Current view: top level - src/geom - elem_quality.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4506 (f0a4b5) with base 5112d2 Lines: 19 175 10.9 %
Date: 2026-07-29 17:31:56 Functions: 2 3 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
      29             : namespace libMesh
      30             : {
      31             : 
      32             : // ------------------------------------------------------------
      33             : // Quality function definitions
      34             : 
      35             : /**
      36             :  * This function returns a string containing some name
      37             :  * for q.  Useful for asking the enum what its name is.
      38             :  * I added this since you may want a simple way to attach
      39             :  * a name or description to the ElemQuality enums.
      40             :  * It can be removed if it is found to be useless.
      41             :  */
      42          12 : std::string Quality::name (const ElemQuality q)
      43             : {
      44           1 :   std::string its_name;
      45             : 
      46          12 :   switch (q)
      47             :     {
      48             : 
      49           1 :     case EDGE_LENGTH_RATIO:
      50           1 :       its_name = "Edge Length Ratio";
      51           1 :       break;
      52             : 
      53           0 :     case ASPECT_RATIO:
      54           0 :       its_name = "Aspect Ratio";
      55           0 :       break;
      56             : 
      57           0 :     case SKEW:
      58           0 :       its_name = "Skew";
      59           0 :       break;
      60             : 
      61           0 :     case SHEAR:
      62           0 :       its_name = "Shear";
      63           0 :       break;
      64             : 
      65           0 :     case SHAPE:
      66           0 :       its_name = "Shape";
      67           0 :       break;
      68             : 
      69           0 :     case MAX_ANGLE:
      70           0 :       its_name = "Maximum Angle";
      71           0 :       break;
      72             : 
      73           0 :     case MIN_ANGLE:
      74           0 :       its_name = "Minimum Angle";
      75           0 :       break;
      76             : 
      77           0 :     case MAX_DIHEDRAL_ANGLE:
      78           0 :       its_name = "Maximum Dihedral Angle";
      79           0 :       break;
      80             : 
      81           0 :     case MIN_DIHEDRAL_ANGLE:
      82           0 :       its_name = "Minimum Dihedral Angle";
      83           0 :       break;
      84             : 
      85           0 :     case CONDITION:
      86           0 :       its_name = "Condition Number";
      87           0 :       break;
      88             : 
      89           0 :     case DISTORTION:
      90           0 :       its_name = "Distortion";
      91           0 :       break;
      92             : 
      93           0 :     case TAPER:
      94           0 :       its_name = "Taper";
      95           0 :       break;
      96             : 
      97           0 :     case WARP:
      98           0 :       its_name = "Warp";
      99           0 :       break;
     100             : 
     101           0 :     case STRETCH:
     102           0 :       its_name = "Stretch";
     103           0 :       break;
     104             : 
     105           0 :     case DIAGONAL:
     106           0 :       its_name = "Diagonal";
     107           0 :       break;
     108             : 
     109           0 :     case ASPECT_RATIO_BETA:
     110           0 :       its_name = "AR Beta";
     111           0 :       break;
     112             : 
     113           0 :     case ASPECT_RATIO_GAMMA:
     114           0 :       its_name = "AR Gamma";
     115           0 :       break;
     116             : 
     117           0 :     case SIZE:
     118           0 :       its_name = "Size";
     119           0 :       break;
     120             : 
     121           0 :     case JACOBIAN:
     122           0 :       its_name = "Jacobian";
     123           0 :       break;
     124             : 
     125           0 :     case SCALED_JACOBIAN:
     126           0 :       its_name = "Scaled Jacobian";
     127           0 :       break;
     128             : 
     129           0 :     default:
     130           0 :       its_name = "Unknown";
     131           0 :       break;
     132             :     }
     133             : 
     134          12 :   return its_name;
     135             : }
     136             : 
     137             : 
     138             : 
     139             : 
     140             : 
     141             : /**
     142             :  * This function returns a string containing a short
     143             :  * description of q.  Useful for asking the enum what
     144             :  * it computes.
     145             :  */
     146           0 : std::string Quality::describe (const ElemQuality q)
     147             : {
     148             : 
     149           0 :   std::ostringstream desc;
     150             : 
     151           0 :   switch (q)
     152             :     {
     153             : 
     154           0 :     case EDGE_LENGTH_RATIO:
     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           0 :            << "Quads: (1 -> 4)";
     162           0 :       break;
     163             : 
     164           0 :     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           0 :            << "Quads: (0 -> 0.5)";
     172           0 :       break;
     173             : 
     174           0 :     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           0 :            << "Quads(LIBMESH_DIM=2): (0.3 -> 1)";
     184           0 :       break;
     185             : 
     186           0 :     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           0 :            << "Quads(LIBMESH_DIM=2): (0.3 -> 1).";
     198           0 :       break;
     199             : 
     200           0 :     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           0 :            << "Triangles: (60 -> 90)";
     206           0 :       break;
     207             : 
     208           0 :     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           0 :            << "Triangles: (30 -> 60)";
     214           0 :       break;
     215             : 
     216           0 :     case MAX_DIHEDRAL_ANGLE:
     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           0 :            << "C0Polyhedra: (60 -> 90)";
     224           0 :       break;
     225             : 
     226           0 :     case MIN_DIHEDRAL_ANGLE:
     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           0 :            << "C0Polyhedra: (30 -> 90)";
     234           0 :       break;
     235             : 
     236           0 :     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           0 :            << "Tets: (1 -> 3)";
     245           0 :       break;
     246             : 
     247           0 :     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           0 :            << "Tets: (0.6 -> 1), <A>=1/6";
     259           0 :       break;
     260             : 
     261           0 :     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           0 :            << "Hexes: (0.4 -> 1)";
     268           0 :       break;
     269             : 
     270           0 :     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           0 :            << "Quads: (0.9 -> 1)";
     278           0 :       break;
     279             : 
     280           0 :     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           0 :            << "Hexes: (0.25 -> 1)";
     289           0 :       break;
     290             : 
     291           0 :     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           0 :            << "Hexes: (0.65 -> 1)";
     299           0 :       break;
     300             : 
     301           0 :     case ASPECT_RATIO_BETA:
     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           0 :            << "Tets: (1 -> 3)";
     309           0 :       break;
     310             : 
     311           0 :     case ASPECT_RATIO_GAMMA:
     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           0 :            << "Tets: (1 -> 3)";
     320           0 :       break;
     321             : 
     322           0 :     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           0 :            << "Tets: (0.2 -> 1)";
     332           0 :       break;
     333             : 
     334           0 :     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           0 :            << "Tris/Tets: (0.2 -> 1.0)";
     344           0 :       break;
     345             : 
     346           0 :     default:
     347           0 :       desc << "Unknown";
     348           0 :       break;
     349             :     }
     350             : 
     351           0 :   return desc.str();
     352           0 : }
     353             : 
     354             : 
     355          24 : std::vector<ElemQuality> Quality::valid(const ElemType t)
     356             : {
     357           2 :   std::vector<ElemQuality> v;
     358             : 
     359          24 :   switch (t)
     360             :     {
     361           0 :     case EDGE2:
     362             :     case EDGE3:
     363             :     case EDGE4:
     364             :       {
     365             :         // None yet
     366           0 :         break;
     367             :       }
     368             : 
     369           0 :     case TRI3:
     370             :     case TRISHELL3:
     371             :     case TRI6:
     372             :     case TRI7:
     373             :       {
     374           0 :         v = {
     375             :           CONDITION,
     376             :           DISTORTION,
     377             :           EDGE_LENGTH_RATIO,
     378             :           JACOBIAN,
     379             :           SCALED_JACOBIAN,
     380             :           MAX_ANGLE,
     381             :           MIN_ANGLE,
     382             :           MAX_DIHEDRAL_ANGLE,
     383             :           MIN_DIHEDRAL_ANGLE,
     384             :           SHAPE,
     385             :           SIZE
     386           0 :         };
     387             : 
     388           0 :         break;
     389             :       }
     390             : 
     391           0 :     case QUAD4:
     392             :     case QUADSHELL4:
     393             :     case QUAD8:
     394             :     case QUADSHELL8:
     395             :     case QUAD9:
     396             :     case QUADSHELL9:
     397             :       {
     398           0 :         v = {
     399             :           ASPECT_RATIO,
     400             :           CONDITION,
     401             :           DISTORTION,
     402             :           EDGE_LENGTH_RATIO,
     403             :           JACOBIAN,
     404             :           SCALED_JACOBIAN,
     405             :           MAX_ANGLE,
     406             :           MIN_ANGLE,
     407             :           MAX_DIHEDRAL_ANGLE,
     408             :           MIN_DIHEDRAL_ANGLE,
     409             :           SHAPE,
     410             :           SHEAR,
     411             :           SIZE,
     412             :           SKEW,
     413             :           STRETCH,
     414             :           TAPER,
     415             :           WARP
     416           0 :         };
     417             : 
     418           0 :         break;
     419             :       }
     420             : 
     421           0 :     case TET4:
     422             :     case TET10:
     423             :     case TET14:
     424             :       {
     425           0 :         v = {
     426             :           ASPECT_RATIO_BETA,
     427             :           ASPECT_RATIO_GAMMA,
     428             :           CONDITION,
     429             :           DISTORTION,
     430             :           JACOBIAN,
     431             :           SCALED_JACOBIAN,
     432             :           MAX_ANGLE,
     433             :           MIN_ANGLE,
     434             :           MAX_DIHEDRAL_ANGLE,
     435             :           MIN_DIHEDRAL_ANGLE,
     436             :           SHAPE,
     437             :           SIZE
     438           0 :         };
     439             : 
     440           0 :         break;
     441             :       }
     442             : 
     443           0 :     case HEX8:
     444             :     case HEX20:
     445             :     case HEX27:
     446             :       {
     447           0 :         v = {
     448             :           ASPECT_RATIO,
     449             :           CONDITION,
     450             :           DIAGONAL,
     451             :           DISTORTION,
     452             :           JACOBIAN,
     453             :           SCALED_JACOBIAN,
     454             :           MAX_ANGLE,
     455             :           MIN_ANGLE,
     456             :           MAX_DIHEDRAL_ANGLE,
     457             :           MIN_DIHEDRAL_ANGLE,
     458             :           SHAPE,
     459             :           SHEAR,
     460             :           SIZE,
     461             :           SKEW,
     462             :           STRETCH,
     463             :           TAPER
     464           0 :         };
     465             : 
     466           0 :         break;
     467             :       }
     468             : 
     469           0 :     case PRISM6:
     470             :     case PRISM18:
     471             :     case PRISM20:
     472             :     case PRISM21:
     473             :       {
     474           0 :         v = {
     475             :           EDGE_LENGTH_RATIO,
     476             :           MAX_ANGLE,
     477             :           MIN_ANGLE,
     478             :           MAX_DIHEDRAL_ANGLE,
     479             :           MIN_DIHEDRAL_ANGLE,
     480           0 :         };
     481             : 
     482           0 :         break;
     483             :       }
     484             : 
     485           0 :     case PYRAMID5:
     486             :     case PYRAMID13:
     487             :     case PYRAMID14:
     488             :     case PYRAMID18:
     489             :       {
     490           0 :         v = {
     491             :           EDGE_LENGTH_RATIO,
     492             :           MAX_ANGLE,
     493             :           MIN_ANGLE,
     494             :           MAX_DIHEDRAL_ANGLE,
     495             :           MIN_DIHEDRAL_ANGLE,
     496           0 :         };
     497             : 
     498           0 :         break;
     499             :       }
     500             : 
     501          12 :     case C0POLYGON:
     502             :       {
     503          21 :         v = {
     504             :           EDGE_LENGTH_RATIO,
     505             :           JACOBIAN,
     506             :           SCALED_JACOBIAN,
     507             :           MAX_ANGLE,
     508             :           MIN_ANGLE
     509          11 :         };
     510             : 
     511          12 :         break;
     512             :       }
     513             : 
     514          12 :     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           3 :         v = {
     520             :           EDGE_LENGTH_RATIO,
     521             :           MAX_ANGLE,
     522             :           MIN_ANGLE,
     523             :           MAX_DIHEDRAL_ANGLE,
     524             :           MIN_DIHEDRAL_ANGLE
     525          11 :         };
     526             : 
     527          12 :         break;
     528             :       }
     529             : 
     530             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
     531             : 
     532           0 :     case INFEDGE2:
     533             :       {
     534             :         // None yet
     535           0 :         break;
     536             :       }
     537             : 
     538           0 :     case INFQUAD4:
     539             :     case INFQUAD6:
     540             :     case INFHEX8:
     541             :     case INFHEX16:
     542             :     case INFHEX18:
     543             :     case INFPRISM6:
     544             :     case INFPRISM12:
     545             :       {
     546           0 :         v = {
     547             :           MAX_ANGLE,
     548             :           MIN_ANGLE,
     549             :           MAX_DIHEDRAL_ANGLE,
     550             :           MIN_DIHEDRAL_ANGLE,
     551           0 :         };
     552             : 
     553           0 :         break;
     554             :       }
     555             : 
     556             : #endif
     557             : 
     558             : 
     559           0 :     default:
     560           0 :       libmesh_error_msg("Undefined element type!");
     561             :     }
     562             : 
     563          24 :   return v;
     564             : }
     565             : 
     566             : } // namespace libMesh

Generated by: LCOV version 1.14