LCOV - code coverage report
Current view: top level - src/userobjects - ElementQualityChecker.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 99 116 85.3 %
Date: 2026-05-29 20:35:17 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             : MooseEnum
      19        6238 : ElementQualityChecker::QualityMetricType()
      20             : {
      21             :   return MooseEnum("ASPECT_RATIO SKEW SHEAR SHAPE MAX_ANGLE MIN_ANGLE CONDITION DISTORTION TAPER "
      22       24952 :                    "WARP STRETCH DIAGONAL ASPECT_RATIO_BETA ASPECT_RATIO_GAMMA SIZE JACOBIAN");
      23             : }
      24             : 
      25             : MooseEnum
      26        3131 : ElementQualityChecker::FailureMessageType()
      27             : {
      28       12524 :   return MooseEnum("WARNING ERROR", "WARNING");
      29             : }
      30             : 
      31             : registerMooseObject("MooseApp", ElementQualityChecker);
      32             : 
      33             : InputParameters
      34        3131 : ElementQualityChecker::validParams()
      35             : {
      36        3131 :   InputParameters params = ElementUserObject::validParams();
      37        6262 :   params.addClassDescription("Class to check the quality of each element using different metrics "
      38             :                              "from libmesh.");
      39             : 
      40        9393 :   params.addRequiredParam<MooseEnum>("metric_type",
      41        6262 :                                      ElementQualityChecker::QualityMetricType(),
      42             :                                      "Type of quality metric to be checked");
      43       12524 :   params.addParam<Real>("upper_bound", "The upper bound for provided metric type");
      44       12524 :   params.addParam<Real>("lower_bound", "The lower bound for provided metric type");
      45        9393 :   params.addParam<bool>("suppress_invalid_metric_warning",
      46        6262 :                         false,
      47             :                         "Whether to print the warning related to the quality metric type not being "
      48             :                         "applicable to a given element type.");
      49        9393 :   params.addParam<MooseEnum>("failure_type",
      50        6262 :                              ElementQualityChecker::FailureMessageType(),
      51             :                              "The way how the failure of quality metric check should respond");
      52        3131 :   params.set<ExecFlagEnum>("execute_on") = EXEC_INITIAL;
      53             : 
      54        3131 :   return params;
      55           0 : }
      56             : 
      57          37 : ElementQualityChecker::ElementQualityChecker(const InputParameters & parameters)
      58             :   : ElementUserObject(parameters),
      59          37 :     _m_type(getParam<MooseEnum>("metric_type").getEnum<libMesh::ElemQuality>()),
      60          74 :     _has_upper_bound(isParamValid("upper_bound")),
      61          74 :     _has_lower_bound(isParamValid("lower_bound")),
      62          51 :     _upper_bound(_has_upper_bound ? getParam<Real>("upper_bound") : 0.0),
      63          51 :     _lower_bound(_has_lower_bound ? getParam<Real>("lower_bound") : 0.0),
      64          37 :     _m_min(0),
      65          37 :     _m_max(0),
      66          37 :     _m_sum(0),
      67          74 :     _suppress_invalid_metric_warning(getParam<bool>("suppress_invalid_metric_warning")),
      68         148 :     _failure_type(getParam<MooseEnum>("failure_type").getEnum<FailureType>())
      69             : {
      70          37 : }
      71             : 
      72             : void
      73          36 : ElementQualityChecker::initialize()
      74             : {
      75          36 :   _m_min = 0;
      76          36 :   _m_max = 0;
      77          36 :   _m_sum = 0;
      78          36 :   _checked_elem_num = 0;
      79          36 :   _elem_ids.clear();
      80          36 :   _bypassed = false;
      81          36 :   _bypassed_elem_type.clear();
      82          36 : }
      83             : 
      84             : void
      85          23 : ElementQualityChecker::execute()
      86             : {
      87             :   // obtain the available quality metric for current ElemType
      88          23 :   std::vector<libMesh::ElemQuality> metrics_avail = libMesh::Quality::valid(_current_elem->type());
      89             : 
      90             :   // check whether the provided quality metric is applicable to current ElemType
      91          23 :   if (!checkMetricApplicability(_m_type, metrics_avail))
      92             :   {
      93          14 :     _bypassed = true;
      94          14 :     _bypassed_elem_type.insert(Utility::enum_to_string(_current_elem->type()));
      95             : 
      96          14 :     return;
      97             :   }
      98             : 
      99           9 :   std::pair<Real, Real> default_bounds = _current_elem->qual_bounds(_m_type);
     100           9 :   std::pair<Real, Real> actual_bounds;
     101           9 :   if (_has_lower_bound && _has_upper_bound)
     102             :   {
     103           9 :     if (_lower_bound >= _upper_bound)
     104           0 :       mooseError("Provided lower bound should be less than provided upper bound!");
     105             : 
     106           9 :     actual_bounds = std::make_pair(_lower_bound, _upper_bound);
     107             :   }
     108           0 :   else if (_has_lower_bound)
     109             :   {
     110           0 :     if (_lower_bound >= default_bounds.second)
     111           0 :       mooseError("Provided lower bound should less than the default upper bound: ",
     112             :                  default_bounds.second);
     113             : 
     114           0 :     actual_bounds = std::make_pair(_lower_bound, default_bounds.second);
     115             :   }
     116           0 :   else if (_has_upper_bound)
     117             :   {
     118           0 :     if (_upper_bound <= default_bounds.first)
     119           0 :       mooseError("Provided upper bound should larger than the default lower bound: ",
     120             :                  default_bounds.first);
     121             : 
     122           0 :     actual_bounds = std::make_pair(default_bounds.first, _upper_bound);
     123             :   }
     124             :   else
     125           0 :     actual_bounds = default_bounds;
     126             : 
     127             :   // calculate and save quality metric value for current element
     128           9 :   Real mv = _current_elem->quality(_m_type);
     129             : 
     130           9 :   _checked_elem_num += 1;
     131           9 :   _m_sum += mv;
     132           9 :   if (mv > _m_max)
     133           9 :     _m_max = mv;
     134           0 :   else if (mv < _m_min)
     135           0 :     _m_min = mv;
     136             : 
     137             :   // check element quality metric, save ids of elements whose quality metrics exceeds the preset
     138             :   // bounds
     139           9 :   if (mv < actual_bounds.first || mv > actual_bounds.second)
     140           9 :     _elem_ids.insert(_current_elem->id());
     141          23 : }
     142             : 
     143             : void
     144           4 : ElementQualityChecker::threadJoin(const UserObject & uo)
     145             : {
     146           4 :   const auto & eqc = static_cast<const ElementQualityChecker &>(uo);
     147           4 :   _elem_ids.insert(eqc._elem_ids.begin(), eqc._elem_ids.end());
     148           4 :   _bypassed_elem_type.insert(eqc._bypassed_elem_type.begin(), eqc._bypassed_elem_type.end());
     149           4 :   _bypassed |= eqc._bypassed;
     150           4 :   _m_sum += eqc._m_sum;
     151           4 :   _checked_elem_num += eqc._checked_elem_num;
     152             : 
     153           4 :   if (_m_min > eqc._m_min)
     154           0 :     _m_min = eqc._m_min;
     155           4 :   if (_m_max < eqc._m_max)
     156           0 :     _m_max = eqc._m_max;
     157           4 : }
     158             : 
     159             : void
     160          32 : ElementQualityChecker::finalize()
     161             : {
     162          32 :   _communicator.min(_m_min);
     163          32 :   _communicator.max(_m_max);
     164          32 :   _communicator.sum(_m_sum);
     165          32 :   _communicator.sum(_checked_elem_num);
     166          32 :   _communicator.set_union(_elem_ids);
     167          32 :   _communicator.max(_bypassed);
     168          32 :   _communicator.set_union(_bypassed_elem_type);
     169             : 
     170          32 :   if (_bypassed)
     171          20 :     if (!_suppress_invalid_metric_warning)
     172          18 :       mooseWarning("Provided quality metric doesn't apply to following element type: " +
     173          45 :                    Moose::stringify(_bypassed_elem_type));
     174             : 
     175          64 :   _console << libMesh::Quality::name(_m_type) << " Metric values:"
     176          32 :            << "\n";
     177          32 :   _console << "              Minimum: " << _m_min << "\n";
     178          32 :   _console << "              Maximum: " << _m_max << "\n";
     179          32 :   _console << "              Average: " << _m_sum / _checked_elem_num << "\n";
     180             : 
     181          32 :   if (!_elem_ids.empty())
     182             :   {
     183          12 :     switch (_failure_type)
     184             :     {
     185           9 :       case FailureType::WARNING:
     186             :       {
     187          36 :         mooseWarning("List of failed element IDs: ", Moose::stringify(_elem_ids));
     188           9 :         break;
     189             :       }
     190             : 
     191           3 :       case FailureType::ERROR:
     192             :       {
     193           9 :         mooseError("List of failed element IDs: ", Moose::stringify(_elem_ids));
     194             :         break;
     195             :       }
     196             : 
     197           0 :       default:
     198           0 :         mooseError("Unknown failure type!");
     199             :     }
     200             :   }
     201             : 
     202          29 :   _console << std::flush;
     203          29 : }
     204             : 
     205             : bool
     206          23 : ElementQualityChecker::checkMetricApplicability(
     207             :     const libMesh::ElemQuality & elem_metric,
     208             :     const std::vector<libMesh::ElemQuality> & elem_metrics)
     209             : {
     210          23 :   bool has_metric = false;
     211             : 
     212         414 :   for (unsigned int i = 0; i < elem_metrics.size(); ++i)
     213         391 :     if (elem_metric == elem_metrics[i])
     214           9 :       has_metric = true;
     215             : 
     216          23 :   return has_metric;
     217             : }

Generated by: LCOV version 1.14