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