1 /* ***************************************************************** 2 MESQUITE -- The Mesh Quality Improvement Toolkit 3 4 Copyright 2006 Sandia National Laboratories. Developed at the 5 University of Wisconsin--Madison under SNL contract number 6 624796. The U.S. Government and the University of Wisconsin 7 retain certain rights to this software. 8 9 This library is free software; you can redistribute it and/or 10 modify it under the terms of the GNU Lesser General Public 11 License as published by the Free Software Foundation; either 12 version 2.1 of the License, or (at your option) any later version. 13 14 This library is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 Lesser General Public License for more details. 18 19 You should have received a copy of the GNU Lesser General Public License 20 (lgpl.txt) along with this library; if not, write to the Free Software 21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 23 (2006) kraftche@cae.wisc.edu 24 25 ***************************************************************** */ 26 27 #ifndef QUALITY_METRIC_TESTER_HPP 28 #define QUALITY_METRIC_TESTER_HPP 29 30 #include "Mesquite.hpp" 31 #include "PlanarDomain.hpp" 32 #include "Settings.hpp" 33 #include <algorithm> 34 35 using namespace MBMesquite; 36 37 namespace MBMesquite { 38 class PatchData; 39 class QualityMetric; 40 class ElemSampleQM; 41 class EdgeQM; 42 } 43 44 class QualityMetricTester 45 { 46 public: 47 void get_ideal_tris ( PatchData& pd, bool unit_area ); 48 void get_ideal_quads( PatchData& pd ); 49 void get_ideal_hexes( PatchData& pd ); 50 void get_ideal_element( EntityTopology type, 51 bool unit_area, 52 PatchData& pd, 53 bool first_vertex_fixed = false ); 54 void get_ideal_element( EntityTopology type, 55 bool unit_area, 56 PatchData& pd, 57 int free_vertex_index ); 58 void get_nonideal_element ( EntityTopology type, PatchData& pd, bool first_vertex_fixed = false ); 59 void get_nonideal_element ( EntityTopology type, PatchData& pd, int free_vertex_index ); 60 void get_degenerate_element( EntityTopology type, PatchData& pd ); 61 void get_zero_element ( EntityTopology type, PatchData& pd ); 62 void get_inverted_element ( EntityTopology type, PatchData& pd ); 63 64 enum ElemTypeGroup { SIMPLICIES, // triangle and tetrahedron 65 NON_MIXED_FE, // tri, quad, tet, hex 66 TWO_D, // tri, quad, polygon 67 TWO_D_FE, // tri, quad 68 THREE_D, // tet, hex, pyr, wedge, septahedron, polyhedron 69 THREE_D_FE, // tet, hex, pyr, wedge, septahedron 70 THREE_D_NON_MIXED_FE, // tet, hex, 71 THREE_D_FE_EXCEPT_SEPTAHEDRON, // tet, hex, pyr, wedge 72 ALL_FE_EXCEPT_SEPTAHEDRON, // tri, quad, tet, hex, pyr, wedge 73 ALL_FE, // everything except polygon and polyhedron 74 ALL }; // everything (including polyhedron) 75 76 QualityMetricTester( ElemTypeGroup group, 77 const Settings* set = 0 ); 78 79 QualityMetricTester( const EntityTopology* supported_elem_types, 80 size_t supported_elem_types_len, 81 const Settings* set = 0 ); 82 83 /** Ideal pyramids should be considerd to have a heigth 84 * equal to the length of a side, rather than the default which 85 * is equilateral triangle faces. 86 */ ideal_pyramid_base_equals_height(bool flag)87 inline void ideal_pyramid_base_equals_height( bool flag ) 88 { degenHexPyramid = flag; } 89 90 /** Test that metric evaluation succeeds for all supported element 91 * types and fails for all unsupported types */ 92 void test_supported_element_types( QualityMetric* qm ); 93 94 /** Test that metric value increases (or decreases if negate_flag is -1) 95 * as the quality of an element worsens. Compares metric values for 96 * ideal element with unit edge length to the value for the same 97 * element with one corner vertex moved 1/2 of the distance towards 98 * the element centroid. This test is applicable only for element-based 99 * metrics. 100 */ 101 void test_measures_quality( QualityMetric* qm ); 102 103 /** Test that metric value increases (or decreases if negate_flag is -1) 104 * as the quality of the element worsen. Compares metric values for 105 * ideal elements with unit edge length to the value for the same 106 * elements with the shared vertex moved 1/2 of the length of one of the 107 * adjacent edges. This test is done only for TRIANGLE, QUADRILATERAL, 108 * and HEXAHEDRAL element types. 109 */ 110 void test_measures_vertex_quality( QualityMetric* qm ); 111 112 /** Test measures deviation from domain */ 113 void test_domain_deviation_quality( QualityMetric* qm ); 114 115 /** Test that metric value increases (or decreases if negate_flag is -1) 116 * as the quality of an element worsens. Compares gradient values for 117 * ideal element with unit edge length to the value for the same 118 * element with one corner vertex moved 1/2 of the distance towards 119 * the element centroid. This test is applicable only for element-based 120 * metrics. 121 */ 122 void test_gradient_reflects_quality( QualityMetric* qm ); 123 124 /** Test that metric value increases (or decreases if negate_flag is -1) 125 * as the quality of the element worsen. Compares gradient values for 126 * ideal elements with unit edge length to the value for the same 127 * elements with the shared vertex moved 1/2 of the length of one of the 128 * adjacent edges. This test is done only for TRIANGLE, QUADRILATERAL, 129 * and HEXAHEDRAL element types. 130 */ 131 void test_vertex_gradient_reflects_quality( QualityMetric* qm ); 132 133 /** Test gradient reflects deviation from domain */ 134 void test_domain_deviation_gradient( QualityMetric* qm ); 135 136 /** Test evaluation of a single ideal element with unit area/volume */ 137 void test_evaluate_unit_element( QualityMetric* qm, EntityTopology type, double value ); 138 /** Test evaluation of a single ideal element with unit edge length */ 139 void test_evaluate_unit_edge_element( QualityMetric* qm, EntityTopology type, double value ); 140 /** Test evaluation of metric over patch with one free vertex surrounded 141 * by 6 ideal unit-area tris */ 142 void test_evaluate_unit_tris_about_vertex( QualityMetric* qm, double expected_val ); 143 /** Test evaluation of metric over patch with one free vertex surrounded 144 * by 4 unit-area quads */ 145 void test_evaluate_unit_quads_about_vertex( QualityMetric* qm, double expected_val ); 146 /** Test evaluation of metric over patch with one free vertex surrounded 147 * by 8 unit-volume hexes */ 148 void test_evaluate_unit_hexes_about_vertex( QualityMetric* qm, double expected_val ); 149 /** Test evaluation of metric over patch with one free vertex surrounded 150 * by 6 ideal unit-edge-length tris */ 151 void test_evaluate_unit_edge_tris_about_vertex( QualityMetric* qm, double expected_val ); 152 153 /** Test that evaluation of the metric for an inverted element does 154 * not pass back an error condition, and that the returned boolean 155 * feasible value is the specified value */ 156 void test_evaluate_inverted_element( QualityMetric* qm, bool should_succeed ); 157 158 /** Test that evaluation of the metric for degenerate element does 159 * not pass back an error condition, and that the returned boolean 160 * feasible value is the specified value */ 161 void test_evaluate_degenerate_element( QualityMetric* qm, bool should_succeed ); 162 163 /** Test that evaluation of the metric for zero area/volume element does 164 * not pass back an error condition, and that the returned boolean 165 * feasible value is the specified value */ 166 void test_evaluate_zero_element( QualityMetric* qm, bool should_succeed ); 167 168 /** Test get_evaluatinos() method for element-based metric */ 169 void test_get_element_evaluations(QualityMetric* qm ); 170 /** Test get_evaluatinos() method for vertex-based metric */ 171 void test_get_vertex_evaluations( QualityMetric* qm ); 172 /** Test get_evaluatinos() method for sample-based metric */ 173 void test_get_sample_evaluations( QualityMetric* qm ); 174 /** Test method to get samples in an element in the EdgeQM base class */ 175 void test_get_edge_evaluations( EdgeQM* qm ); 176 /** Test method to get samples in an element in the ElemSampleQM base class */ 177 void test_get_in_element_evaluations( ElemSampleQM* qm ); 178 179 /** Test that evaluate_with_indices returns indices only for free vertices */ 180 void test_get_indices_fixed( QualityMetric* qm ); 181 182 /** Test indices from evaluate_with_indices() method */ 183 void test_get_element_indices( QualityMetric* qm ); 184 /** Test indices from evaluate_with_indices() method, assuming 185 * quality at a vertex depends only on edge-connected vertices. 186 */ 187 void test_get_vertex_indices( QualityMetric* qm ); 188 void test_get_edge_indices( EdgeQM* qm ); 189 /** Test indices from evaluate_with_indices() method */ 190 void test_get_sample_indices( QualityMetric* qm ); 191 192 /** compare results of evaluate() and evaluate_with_indices() methods */ 193 void compare_eval_and_eval_with_indices( QualityMetric* qm ); 194 void compare_eval_and_eval_with_indices( QualityMetric* qm, PatchData& pd ); 195 /** compare results of evaluate_with_indices() and evaluate_with_gradient() methods */ 196 void compare_eval_with_indices_and_eval_with_gradient( QualityMetric* qm ); 197 void compare_eval_with_indices_and_eval_with_gradient( QualityMetric* qm, PatchData& pd ); 198 /** compare results of evaluate_with_indices() and evaluate_with_Hessian() methods */ 199 void compare_eval_with_indices_and_eval_with_hessian( QualityMetric* qm ); 200 void compare_eval_with_indices_and_eval_with_hessian( QualityMetric* qm, PatchData& pd ); 201 /** compare results of evaluate_with_indices() and evaluate_with_Hessian_diagonal() methods */ 202 void compare_eval_with_indices_and_eval_with_diagonal( QualityMetric* qm ); 203 void compare_eval_with_indices_and_eval_with_diagonal( QualityMetric* qm, PatchData& pd ); 204 /** compare results of evaluate_with_gradient() and evaluate_with_Hessian() methods */ 205 void compare_eval_with_grad_and_eval_with_hessian( QualityMetric* qm ); 206 void compare_eval_with_grad_and_eval_with_hessian( QualityMetric* qm, PatchData& pd ); 207 /** compare results of evaluate_with_gradient() and evaluate_with_Hessian_diagonal() methods */ 208 void compare_eval_with_grad_and_eval_with_diagonal( QualityMetric* qm ); 209 void compare_eval_with_grad_and_eval_with_diagonal( QualityMetric* qm, PatchData& pd ); 210 /** compare results of evaluate_with_Hessian_diagonal() and evaluate_with_Hessian() methods */ 211 void compare_eval_with_diag_and_eval_with_hessian( QualityMetric* qm ); 212 void compare_eval_with_diag_and_eval_with_hessian( QualityMetric* qm, PatchData& pd ); 213 /** compare analytical and numerical gradient results */ 214 void compare_analytical_and_numerical_gradients( QualityMetric* qm ); 215 void compare_analytical_and_numerical_gradients( QualityMetric* qm, PatchData& pd ); 216 /** compare analytical and numerical Hessian results */ 217 void compare_analytical_and_numerical_hessians( QualityMetric* qm ); 218 void compare_analytical_and_numerical_hessians( QualityMetric* qm, PatchData& pd ); 219 /** compare analytical and numerical Hessian diagonal results */ 220 void compare_analytical_and_numerical_diagonals( QualityMetric* qm ); 221 void compare_analytical_and_numerical_diagonals( QualityMetric* qm, PatchData& pd ); 222 223 /** compare gradient w/ no fixed vertices to gradient 224 * for element with all but one vertex fixed. 225 */ 226 void test_gradient_with_fixed_vertex( QualityMetric* qm, const Settings* settings = 0 ); 227 void test_gradient_with_fixed_vertex( EntityTopology type, QualityMetric* qm, 228 const Settings* settings = 0 ); 229 /** compare Hessian w/ no fixed vertices to Hessian 230 * for element with all but one vertex fixed. 231 */ 232 void test_hessian_with_fixed_vertex( QualityMetric* qm, const Settings* settings = 0 ); 233 void test_hessian_with_fixed_vertex( EntityTopology type, QualityMetric* qm, 234 const Settings* settings = 0 ); 235 /** compare Hessian diagonal w/ no fixed vertices to Hessian 236 * for element with all but one vertex fixed. 237 */ 238 void test_diagonal_with_fixed_vertex( QualityMetric* qm, const Settings* settings = 0 ); 239 void test_diagonal_with_fixed_vertex( EntityTopology type, QualityMetric* qm, 240 const Settings* settings = 0 ); 241 242 /** Test that gradient values are zero for an ideal element. 243 * If 'unit_area' is true, then ideal elements have unit measure, 244 * otherwise they have unit edge lengths. This test is applicable 245 * only to element-based metrics. 246 */ 247 void test_ideal_element_zero_gradient( QualityMetric* qm, bool unit_area ); 248 /** Test that gradient values are zero at the shared vertex in a 249 * patch of containing ideal elements. 250 * If 'unit_area' is true, then ideal elements have unit measure, 251 * otherwise they have unit edge lengths. Test is done only for 252 * TRIANGLE, QUADRILATERAL, and HEXAHEDRON element types. 253 */ 254 void test_ideal_element_zero_vertex_gradient( QualityMetric* qm, bool unit_area ); 255 256 /** Test that Hessian is positive-definite for ideal elements */ 257 void test_ideal_element_positive_definite_Hessian( QualityMetric* qm, bool unit_area ); 258 259 /** Test that diagonal bocks of Hessian are symetrical */ 260 void test_symmetric_Hessian_diagonal_blocks( QualityMetric* qm ); 261 262 /** test that metric value is consistent for element translation */ 263 void test_location_invariant( QualityMetric* qm, bool untangler = false ); 264 /** test that metric value is consistent for element scalaing */ 265 void test_scale_invariant( QualityMetric* qm, bool untangler = false ); 266 /** test that metric value is consistent for element rotation */ 267 void test_orient_invariant( QualityMetric* qm, bool untangler = false ); 268 269 /** test that gradient values don't change with element translation */ 270 void test_grad_location_invariant( QualityMetric* qm, bool untangler = false ); 271 /** test that gradient values rotate with element rotation */ 272 void test_grad_orient_invariant( QualityMetric* qm, bool untangler = false ); 273 /** test that Hessian values don't change with element translation */ 274 void test_hessian_location_invariant( QualityMetric* qm, bool untangler = false ); 275 276 /** test that metric inceases (decreases) as size deviates from ideal */ 277 void test_measures_size( QualityMetric* qm, bool unit_area ); 278 /** test that metric value increases as element orientation changes from ideal */ 279 void test_measures_in_plane_orientation( QualityMetric* qm ); 280 /** test that metric value increases as element orientation changes from ideal */ 281 void test_measures_out_of_plane_orientation( QualityMetric* qm ); 282 283 class PatchXform { 284 public: ~PatchXform()285 virtual ~PatchXform() {} 286 virtual void xform(PatchData& pd, PlanarDomain* dom ) = 0; 287 virtual void xform_grad(std::vector<Vector3D>& grads) = 0; 288 }; 289 290 void test_transform_invariant( QualityMetric* qm, 291 PatchXform& transform, 292 bool untangler ); 293 294 void test_grad_transform_invariant( QualityMetric* qm, 295 PatchXform& transform, 296 bool untangler ); 297 298 void test_hessian_transform_invariant( QualityMetric* qm, 299 PatchXform& transform, 300 bool untangler ); 301 302 void test_measures_transform( QualityMetric* qm, 303 PatchXform& transform, 304 bool unit_area ); 305 private: type_is_supported(EntityTopology type)306 inline bool type_is_supported( EntityTopology type ) 307 { return std::find( types.begin(), types.end(), type ) != types.end(); } 308 309 void test_type_is_supported( EntityTopology type, QualityMetric* qm ); 310 void test_type_is_not_supported( EntityTopology type, QualityMetric* qm ); 311 312 bool degenHexPyramid; //!< See: ideal_pyramid_base_equals_height() 313 std::vector<EntityTopology> types; 314 const Settings* mSettings; 315 PlanarDomain geomPlane; 316 }; 317 318 #endif 319 320