LCOV - code coverage report
Current view: top level - src/userobjects - ElementQualityChecker.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #33390 (250e9c) with base 846a5c Lines: 105 117 89.7 %
Date: 2026-07-31 18:15:22 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "ElementQualityChecker.h"
      11             : #include "MooseError.h"
      12             : #include "Conversion.h"
      13             : 
      14             : #include "libmesh/elem_quality.h"
      15             : #include "libmesh/enum_elem_quality.h"
      16             : #include "libmesh/string_to_enum.h"
      17             : 
      18             : #include <limits>
      19             : 
      20             : MooseEnum
      21        6313 : ElementQualityChecker::QualityMetricType()
      22             : {
      23             :   return MooseEnum("ASPECT_RATIO SKEW SHEAR SHAPE MAX_ANGLE MIN_ANGLE CONDITION DISTORTION TAPER "
      24       25252 :                    "WARP STRETCH DIAGONAL ASPECT_RATIO_BETA ASPECT_RATIO_GAMMA SIZE JACOBIAN");
      25             : }
      26             : 
      27             : MooseEnum
      28        3178 : ElementQualityChecker::FailureMessageType()
      29             : {
      30       12712 :   return MooseEnum("WARNING ERROR", "WARNING");
      31             : }
      32             : 
      33             : registerMooseObject("MooseApp", ElementQualityChecker);
      34             : 
      35             : InputParameters
      36        3178 : ElementQualityChecker::validParams()
      37             : {
      38        3178 :   InputParameters params = ElementUserObject::validParams();
      39        6356 :   params.addClassDescription("Class to check the quality of each element using different metrics "
      40             :                              "from libmesh.");
      41             : 
      42        9534 :   params.addRequiredParam<MooseEnum>("metric_type",
      43        6356 :                                      ElementQualityChecker::QualityMetricType(),
      44             :                                      "Type of quality metric to be checked");
      45       12712 :   params.addParam<Real>("upper_bound", "The upper bound for provided metric type");
      46       12712 :   params.addParam<Real>("lower_bound", "The lower bound for provided metric type");
      47        9534 :   params.addParam<bool>("suppress_invalid_metric_warning",
      48        6356 :                         false,
      49             :                         "Whether to print the warning related to the quality metric type not being "
      50             :                         "applicable to a given element type.");
      51        9534 :   params.addParam<MooseEnum>("failure_type",
      52        6356 :                              ElementQualityChecker::FailureMessageType(),
      53             :                              "The way how the failure of quality metric check should respond");
      54        3178 :   params.set<ExecFlagEnum>("execute_on") = EXEC_INITIAL;
      55             : 
      56        3178 :   return params;
      57           0 : }
      58             : 
      59          47 : ElementQualityChecker::ElementQualityChecker(const InputParameters & parameters)
      60             :   : ElementUserObject(parameters),
      61          47 :     _m_type(getParam<MooseEnum>("metric_type").getEnum<libMesh::ElemQuality>()),
      62          94 :     _has_upper_bound(isParamValid("upper_bound")),
      63          94 :     _has_lower_bound(isParamValid("lower_bound")),
      64          61 :     _upper_bound(_has_upper_bound ? getParam<Real>("upper_bound") : 0.0),
      65          61 :     _lower_bound(_has_lower_bound ? getParam<Real>("lower_bound") : 0.0),
      66          47 :     _m_min(std::numeric_limits<Real>::max()),
      67          47 :     _m_max(std::numeric_limits<Real>::lowest()),
      68          47 :     _m_sum(0),
      69          94 :     _suppress_invalid_metric_warning(getParam<bool>("suppress_invalid_metric_warning")),
      70         188 :     _failure_type(getParam<MooseEnum>("failure_type").getEnum<FailureType>())
      71             : {
      72          47 : }
      73             : 
      74             : void
      75          46 : ElementQualityChecker::initialize()
      76             : {
      77          46 :   _m_min = std::numeric_limits<Real>::max();
      78          46 :   _m_max = std::numeric_limits<Real>::lowest();
      79          46 :   _m_sum = 0;
      80          46 :   _checked_elem_num = 0;
      81          46 :   _elem_ids.clear();
      82          46 :   _bypassed = false;
      83          46 :   _bypassed_elem_type.clear();
      84          46 : }
      85             : 
      86             : void
      87          35 : ElementQualityChecker::execute()
      88             : {
      89             :   // obtain the available quality metric for current ElemType
      90          35 :   std::vector<libMesh::ElemQuality> metrics_avail = libMesh::Quality::valid(_current_elem->type());
      91             : 
      92             :   // check whether the provided quality metric is applicable to current ElemType
      93          35 :   if (!checkMetricApplicability(_m_type, metrics_avail))
      94             :   {
      95          14 :     _bypassed = true;
      96          14 :     _bypassed_elem_type.insert(Utility::enum_to_string(_current_elem->type()));
      97             : 
      98          14 :     return;
      99             :   }
     100             : 
     101          21 :   std::pair<Real, Real> default_bounds = _current_elem->qual_bounds(_m_type);
     102          21 :   std::pair<Real, Real> actual_bounds;
     103          21 :   if (_has_lower_bound && _has_upper_bound)
     104             :   {
     105           9 :     if (_lower_bound >= _upper_bound)
     106           0 :       mooseError("Provided lower bound should be less than provided upper bound!");
     107             : 
     108           9 :     actual_bounds = std::make_pair(_lower_bound, _upper_bound);
     109             :   }
     110          12 :   else if (_has_lower_bound)
     111             :   {
     112           0 :     if (_lower_bound >= default_bounds.second)
     113           0 :       mooseError("Provided lower bound should less than the default upper bound: ",
     114             :                  default_bounds.second);
     115             : 
     116           0 :     actual_bounds = std::make_pair(_lower_bound, default_bounds.second);
     117             :   }
     118          12 :   else if (_has_upper_bound)
     119             :   {
     120           0 :     if (_upper_bound <= default_bounds.first)
     121           0 :       mooseError("Provided upper bound should larger than the default lower bound: ",
     122             :                  default_bounds.first);
     123             : 
     124           0 :     actual_bounds = std::make_pair(default_bounds.first, _upper_bound);
     125             :   }
     126             :   else
     127          12 :     actual_bounds = default_bounds;
     128             : 
     129             :   // calculate and save quality metric value for current element
     130          21 :   Real mv = _current_elem->quality(_m_type);
     131             : 
     132          21 :   _checked_elem_num += 1;
     133          21 :   _m_sum += mv;
     134          21 :   if (mv < _m_min)
     135          18 :     _m_min = mv;
     136          21 :   if (mv > _m_max)
     137          18 :     _m_max = mv;
     138             : 
     139             :   // check element quality metric, save ids of elements whose quality metrics exceeds the preset
     140             :   // bounds
     141          21 :   if (mv < actual_bounds.first || mv > actual_bounds.second)
     142           9 :     _elem_ids.insert(_current_elem->id());
     143          35 : }
     144             : 
     145             : void
     146           5 : ElementQualityChecker::threadJoin(const UserObject & uo)
     147             : {
     148           5 :   const auto & eqc = static_cast<const ElementQualityChecker &>(uo);
     149           5 :   _elem_ids.insert(eqc._elem_ids.begin(), eqc._elem_ids.end());
     150           5 :   _bypassed_elem_type.insert(eqc._bypassed_elem_type.begin(), eqc._bypassed_elem_type.end());
     151           5 :   _bypassed |= eqc._bypassed;
     152           5 :   _m_sum += eqc._m_sum;
     153           5 :   _checked_elem_num += eqc._checked_elem_num;
     154             : 
     155           5 :   if (_m_min > eqc._m_min)
     156           0 :     _m_min = eqc._m_min;
     157           5 :   if (_m_max < eqc._m_max)
     158           0 :     _m_max = eqc._m_max;
     159           5 : }
     160             : 
     161             : void
     162          41 : ElementQualityChecker::finalize()
     163             : {
     164          41 :   _communicator.min(_m_min);
     165          41 :   _communicator.max(_m_max);
     166          41 :   _communicator.sum(_m_sum);
     167          41 :   _communicator.sum(_checked_elem_num);
     168          41 :   _communicator.set_union(_elem_ids);
     169          41 :   _communicator.max(_bypassed);
     170          41 :   _communicator.set_union(_bypassed_elem_type);
     171             : 
     172          41 :   if (_bypassed)
     173          20 :     if (!_suppress_invalid_metric_warning)
     174          18 :       mooseWarning("Provided quality metric doesn't apply to following element type: " +
     175          45 :                    Moose::stringify(_bypassed_elem_type));
     176             : 
     177          41 :   _console << libMesh::Quality::name(_m_type) << " Metric values:\n";
     178          41 :   if (_checked_elem_num)
     179             :   {
     180          21 :     _console << "              Minimum: " << _m_min << "\n";
     181          21 :     _console << "              Maximum: " << _m_max << "\n";
     182          21 :     _console << "              Average: " << _m_sum / _checked_elem_num << "\n";
     183             :   }
     184             :   else
     185          20 :     _console << "              No elements were checked.\n";
     186             : 
     187          41 :   if (!_elem_ids.empty())
     188             :   {
     189          12 :     switch (_failure_type)
     190             :     {
     191           9 :       case FailureType::WARNING:
     192             :       {
     193          36 :         mooseWarning("List of failed element IDs: ", Moose::stringify(_elem_ids));
     194           9 :         break;
     195             :       }
     196             : 
     197           3 :       case FailureType::ERROR:
     198             :       {
     199           9 :         mooseError("List of failed element IDs: ", Moose::stringify(_elem_ids));
     200             :         break;
     201             :       }
     202             : 
     203           0 :       default:
     204           0 :         mooseError("Unknown failure type!");
     205             :     }
     206             :   }
     207             : 
     208          38 :   _console << std::flush;
     209          38 : }
     210             : 
     211             : bool
     212          35 : ElementQualityChecker::checkMetricApplicability(
     213             :     const libMesh::ElemQuality & elem_metric,
     214             :     const std::vector<libMesh::ElemQuality> & elem_metrics)
     215             : {
     216          35 :   bool has_metric = false;
     217             : 
     218         630 :   for (unsigned int i = 0; i < elem_metrics.size(); ++i)
     219         595 :     if (elem_metric == elem_metrics[i])
     220          21 :       has_metric = true;
     221             : 
     222          35 :   return has_metric;
     223             : }

Generated by: LCOV version 1.14