LCOV - code coverage report
Current view: top level - src/userobjects - ElementQualityChecker.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 99 116 85.3 %
Date: 2025-08-08 20:01:16 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       28658 : ElementQualityChecker::QualityMetricType()
      20             : {
      21             :   return MooseEnum("ASPECT_RATIO SKEW SHEAR SHAPE MAX_ANGLE MIN_ANGLE CONDITION DISTORTION TAPER "
      22       28658 :                    "WARP STRETCH DIAGONAL ASPECT_RATIO_BETA ASPECT_RATIO_GAMMA SIZE JACOBIAN");
      23             : }
      24             : 
      25             : MooseEnum
      26       14343 : ElementQualityChecker::FailureMessageType()
      27             : {
      28       14343 :   return MooseEnum("WARNING ERROR", "WARNING");
      29             : }
      30             : 
      31             : registerMooseObject("MooseApp", ElementQualityChecker);
      32             : 
      33             : InputParameters
      34       14343 : ElementQualityChecker::validParams()
      35             : {
      36       14343 :   InputParameters params = ElementUserObject::validParams();
      37       14343 :   params.addClassDescription("Class to check the quality of each element using different metrics "
      38             :                              "from libmesh.");
      39             : 
      40       43029 :   params.addRequiredParam<MooseEnum>("metric_type",
      41       28686 :                                      ElementQualityChecker::QualityMetricType(),
      42             :                                      "Type of quality metric to be checked");
      43       14343 :   params.addParam<Real>("upper_bound", "The upper bound for provided metric type");
      44       14343 :   params.addParam<Real>("lower_bound", "The lower bound for provided metric type");
      45       43029 :   params.addParam<bool>("suppress_invalid_metric_warning",
      46       28686 :                         false,
      47             :                         "Whether to print the warning related to the quality metric type not being "
      48             :                         "applicable to a given element type.");
      49       43029 :   params.addParam<MooseEnum>("failure_type",
      50       28686 :                              ElementQualityChecker::FailureMessageType(),
      51             :                              "The way how the failure of quality metric check should respond");
      52       14343 :   params.set<ExecFlagEnum>("execute_on") = EXEC_INITIAL;
      53             : 
      54       14343 :   return params;
      55           0 : }
      56             : 
      57          41 : ElementQualityChecker::ElementQualityChecker(const InputParameters & parameters)
      58             :   : ElementUserObject(parameters),
      59          41 :     _m_type(getParam<MooseEnum>("metric_type").getEnum<libMesh::ElemQuality>()),
      60          41 :     _has_upper_bound(isParamValid("upper_bound")),
      61          41 :     _has_lower_bound(isParamValid("lower_bound")),
      62          41 :     _upper_bound(_has_upper_bound ? getParam<Real>("upper_bound") : 0.0),
      63          41 :     _lower_bound(_has_lower_bound ? getParam<Real>("lower_bound") : 0.0),
      64          41 :     _m_min(0),
      65          41 :     _m_max(0),
      66          41 :     _m_sum(0),
      67          41 :     _suppress_invalid_metric_warning(getParam<bool>("suppress_invalid_metric_warning")),
      68         123 :     _failure_type(getParam<MooseEnum>("failure_type").getEnum<FailureType>())
      69             : {
      70          41 : }
      71             : 
      72             : void
      73          40 : ElementQualityChecker::initialize()
      74             : {
      75          40 :   _m_min = 0;
      76          40 :   _m_max = 0;
      77          40 :   _m_sum = 0;
      78          40 :   _checked_elem_num = 0;
      79          40 :   _elem_ids.clear();
      80          40 :   _bypassed = false;
      81          40 :   _bypassed_elem_type.clear();
      82          40 : }
      83             : 
      84             : void
      85          27 : ElementQualityChecker::execute()
      86             : {
      87             :   // obtain the available quality metric for current ElemType
      88          27 :   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          27 :   if (!checkMetricApplicability(_m_type, metrics_avail))
      92             :   {
      93          16 :     _bypassed = true;
      94          16 :     _bypassed_elem_type.insert(Utility::enum_to_string(_current_elem->type()));
      95             : 
      96          16 :     return;
      97             :   }
      98             : 
      99          11 :   std::pair<Real, Real> default_bounds = _current_elem->qual_bounds(_m_type);
     100          11 :   std::pair<Real, Real> actual_bounds;
     101          11 :   if (_has_lower_bound && _has_upper_bound)
     102             :   {
     103          11 :     if (_lower_bound >= _upper_bound)
     104           0 :       mooseError("Provided lower bound should be less than provided upper bound!");
     105             : 
     106          11 :     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          11 :   Real mv = _current_elem->quality(_m_type);
     129             : 
     130          11 :   _checked_elem_num += 1;
     131          11 :   _m_sum += mv;
     132          11 :   if (mv > _m_max)
     133          11 :     _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          11 :   if (mv < actual_bounds.first || mv > actual_bounds.second)
     140          11 :     _elem_ids.insert(_current_elem->id());
     141          27 : }
     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          36 : ElementQualityChecker::finalize()
     161             : {
     162          36 :   _communicator.min(_m_min);
     163          36 :   _communicator.max(_m_max);
     164          36 :   _communicator.sum(_m_sum);
     165          36 :   _communicator.sum(_checked_elem_num);
     166          36 :   _communicator.set_union(_elem_ids);
     167          36 :   _communicator.max(_bypassed);
     168          36 :   _communicator.set_union(_bypassed_elem_type);
     169             : 
     170          36 :   if (_bypassed)
     171          22 :     if (!_suppress_invalid_metric_warning)
     172          10 :       mooseWarning("Provided quality metric doesn't apply to following element type: " +
     173          20 :                    Moose::stringify(_bypassed_elem_type));
     174             : 
     175          72 :   _console << libMesh::Quality::name(_m_type) << " Metric values:"
     176          36 :            << "\n";
     177          36 :   _console << "              Minimum: " << _m_min << "\n";
     178          36 :   _console << "              Maximum: " << _m_max << "\n";
     179          36 :   _console << "              Average: " << _m_sum / _checked_elem_num << "\n";
     180             : 
     181          36 :   if (!_elem_ids.empty())
     182             :   {
     183          14 :     switch (_failure_type)
     184             :     {
     185          10 :       case FailureType::WARNING:
     186             :       {
     187          10 :         mooseWarning("List of failed element IDs: ", Moose::stringify(_elem_ids));
     188          10 :         break;
     189             :       }
     190             : 
     191           4 :       case FailureType::ERROR:
     192             :       {
     193           4 :         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          32 :   _console << std::flush;
     203          32 : }
     204             : 
     205             : bool
     206          27 : ElementQualityChecker::checkMetricApplicability(
     207             :     const libMesh::ElemQuality & elem_metric,
     208             :     const std::vector<libMesh::ElemQuality> & elem_metrics)
     209             : {
     210          27 :   bool has_metric = false;
     211             : 
     212         486 :   for (unsigned int i = 0; i < elem_metrics.size(); ++i)
     213         459 :     if (elem_metric == elem_metrics[i])
     214          11 :       has_metric = true;
     215             : 
     216          27 :   return has_metric;
     217             : }

Generated by: LCOV version 1.14