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