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

Generated by: LCOV version 1.14