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 : }