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