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