Branch data Line data Source code
1 : : /* *****************************************************************
2 : : MESQUITE -- The Mesh Quality Improvement Toolkit
3 : :
4 : : Copyright 2004 Sandia Corporation and Argonne National
5 : : Laboratory. Under the terms of Contract DE-AC04-94AL85000
6 : : with Sandia Corporation, the U.S. Government retains certain
7 : : rights in 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 : : [email protected], [email protected], [email protected],
24 : : [email protected], [email protected], [email protected]
25 : :
26 : : ***************************************************************** */
27 : : /*!
28 : : \file QualityAssessor.cpp
29 : : \brief Member function of the MBMesquite::QualityAssessor class
30 : :
31 : : \author Thomas Leurent
32 : : \date 2002-05-23
33 : : */
34 : :
35 : : #include "QualityAssessor.hpp"
36 : : #include "QualityMetric.hpp"
37 : : #include "TMPQualityMetric.hpp"
38 : : #include "ElementMaxQM.hpp"
39 : : #include "ElementAvgQM.hpp"
40 : : #include "PatchData.hpp"
41 : : #include "MsqMeshEntity.hpp"
42 : : #include "MsqVertex.hpp"
43 : : #include "MsqDebug.hpp"
44 : : #include "MeshInterface.hpp"
45 : : #include "VertexPatches.hpp"
46 : : #include "ElementPatches.hpp"
47 : : #include "ParallelMeshInterface.hpp"
48 : : #include "ParallelHelperInterface.hpp"
49 : :
50 : : #include <list>
51 : : #include <vector>
52 : : #include <iostream>
53 : : #include <fstream>
54 : : #include <iomanip>
55 : : #include <set>
56 : : #include <math.h>
57 : :
58 : : #ifdef HAVE_SYS_IOCTL_H
59 : : #include <sys/ioctl.h>
60 : : #endif
61 : : #ifdef HAVE_UNISTD_H
62 : : #include <unistd.h>
63 : : #endif
64 : : #ifdef HAVE_TERMIOS_H
65 : : #include <termios.h>
66 : : #endif
67 : :
68 : : namespace MBMesquite
69 : : {
70 : :
71 : 57 : const char* default_name( bool free_only )
72 : : {
73 : : static const char all_name[] = "QualityAssessor";
74 : : static const char free_name[] = "QualityAssessor(free only)";
75 [ + + ]: 57 : return free_only ? free_name : all_name;
76 : : }
77 : :
78 : 37 : QualityAssessor::QualityAssessor( bool p_print_summary, bool free_only, const char* inverted_tag_name,
79 : : std::string p_name )
80 [ + - ]: 37 : : myData( new Data ), qualityAssessorName( p_name ), outputStream( std::cout ), printSummary( p_print_summary ),
81 [ + - ][ + - ]: 74 : skipFixedSamples( free_only )
[ + - ][ + - ]
[ + - ]
82 : : {
83 [ - + ][ # # ]: 37 : if( inverted_tag_name ) tag_inverted_elements( inverted_tag_name );
[ # # ]
84 : :
85 [ + - ][ + - ]: 37 : if( qualityAssessorName.empty() ) qualityAssessorName = default_name( free_only );
[ + - ]
86 : :
87 [ + + ]: 407 : for( int i = POLYGON; i <= MIXED; i++ )
88 : 370 : elementTypeCount[i - POLYGON] = 0;
89 : 37 : }
90 : :
91 : 0 : QualityAssessor::QualityAssessor( std::ostream& stream, bool free_only, const char* inverted_tag_name,
92 : : std::string name )
93 [ # # ]: 0 : : myData( new Data ), qualityAssessorName( name ), outputStream( stream ), printSummary( true ),
94 [ # # ][ # # ]: 0 : skipFixedSamples( free_only )
[ # # ][ # # ]
[ # # ]
95 : : {
96 [ # # ][ # # ]: 0 : if( inverted_tag_name ) tag_inverted_elements( inverted_tag_name );
[ # # ]
97 : :
98 [ # # ][ # # ]: 0 : if( qualityAssessorName.empty() ) qualityAssessorName = default_name( free_only );
[ # # ]
99 : :
100 [ # # ]: 0 : for( int i = POLYGON; i <= MIXED; i++ )
101 : 0 : elementTypeCount[i - POLYGON] = 0;
102 : 0 : }
103 : :
104 : 0 : QualityAssessor::QualityAssessor( std::ostream& output_stream, QualityMetric* metric, int histogram_intervals,
105 : : double power_mean, bool free_only, const char* metric_value_tag_name,
106 : : const char* inverted_tag_name, std::string name )
107 [ # # ]: 0 : : myData( new Data ), qualityAssessorName( name ), outputStream( output_stream ), printSummary( true ),
108 [ # # ][ # # ]: 0 : skipFixedSamples( free_only )
[ # # ][ # # ]
[ # # ]
109 : : {
110 [ # # ][ # # ]: 0 : if( inverted_tag_name ) tag_inverted_elements( inverted_tag_name );
[ # # ]
111 : :
112 [ # # ][ # # ]: 0 : if( qualityAssessorName.empty() ) qualityAssessorName = default_name( free_only );
[ # # ]
113 : :
114 [ # # ]: 0 : set_stopping_assessment( metric, histogram_intervals, power_mean, metric_value_tag_name );
115 : :
116 [ # # ]: 0 : for( int i = POLYGON; i <= MIXED; i++ )
117 : 0 : elementTypeCount[i - POLYGON] = 0;
118 : 0 : }
119 : :
120 : 20 : QualityAssessor::QualityAssessor( QualityMetric* metric, int histogram_intervals, double power_mean, bool free_only,
121 : : const char* metric_value_tag_name, bool p_print_summary,
122 : : const char* inverted_tag_name, std::string name )
123 [ + - ]: 20 : : myData( new Data ), qualityAssessorName( name ), outputStream( std::cout ), printSummary( p_print_summary ),
124 [ + - ][ + - ]: 40 : skipFixedSamples( free_only )
[ + - ][ + - ]
[ + - ]
125 : : {
126 [ - + ][ # # ]: 20 : if( inverted_tag_name ) tag_inverted_elements( inverted_tag_name );
[ # # ]
127 : :
128 [ + - ][ + - ]: 20 : if( qualityAssessorName.empty() ) qualityAssessorName = default_name( free_only );
[ + - ]
129 : :
130 [ + - ]: 20 : set_stopping_assessment( metric, histogram_intervals, power_mean, metric_value_tag_name );
131 : :
132 [ + + ]: 220 : for( int i = POLYGON; i <= MIXED; i++ )
133 : 200 : elementTypeCount[i - POLYGON] = 0;
134 : 20 : }
135 : :
136 : 39 : QualityAssessor::QualityAssessor( const QualityAssessor& copy )
137 : : : myData( copy.myData ), qualityAssessorName( copy.qualityAssessorName ), assessList( copy.assessList ),
138 : : outputStream( copy.outputStream ), printSummary( copy.printSummary ), invertedTagName( copy.invertedTagName ),
139 [ + - ][ + - ]: 39 : fixedTagName( copy.fixedTagName ), skipFixedSamples( copy.skipFixedSamples )
[ + - ][ + - ]
140 : :
141 : : {
142 [ + - ]: 39 : list_type::iterator iter;
143 [ + - ][ + - ]: 40 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + + ]
144 [ + - ]: 1 : ( *iter )->referenceCount++;
145 : 39 : myData->referenceCount++;
146 : :
147 [ + + ]: 429 : for( int i = POLYGON; i <= MIXED; i++ )
148 : 390 : elementTypeCount[i - POLYGON] = copy.elementTypeCount[i - POLYGON];
149 : 39 : }
150 : :
151 : 0 : QualityAssessor& QualityAssessor::operator=( const QualityAssessor& copy )
152 : : {
153 [ # # ]: 0 : list_type::iterator iter;
154 [ # # ][ # # ]: 0 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ # # ]
155 : : {
156 [ # # ]: 0 : Assessor* assessor = *iter;
157 [ # # ][ # # ]: 0 : if( 0 == --assessor->referenceCount ) delete assessor;
158 : : }
159 : :
160 : 0 : myData = copy.myData;
161 [ # # ]: 0 : qualityAssessorName = copy.qualityAssessorName;
162 [ # # ]: 0 : assessList = copy.assessList;
163 : 0 : printSummary = copy.printSummary;
164 [ # # ]: 0 : invertedTagName = copy.invertedTagName;
165 [ # # ]: 0 : fixedTagName = copy.fixedTagName;
166 : 0 : skipFixedSamples = copy.skipFixedSamples;
167 : :
168 [ # # ][ # # ]: 0 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ # # ]
169 [ # # ]: 0 : ( *iter )->referenceCount++;
170 : 0 : myData->referenceCount++;
171 : :
172 [ # # ]: 0 : for( int i = POLYGON; i <= MIXED; i++ )
173 : 0 : elementTypeCount[i - POLYGON] = copy.elementTypeCount[i - POLYGON];
174 : :
175 : 0 : return *this;
176 : : }
177 : :
178 : 223 : QualityAssessor::~QualityAssessor()
179 : : {
180 : 96 : list_type::iterator iter;
181 [ + + ]: 175 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
182 : : {
183 : 79 : Assessor* assessor = *iter;
184 [ + + ][ + - ]: 79 : if( 0 == --assessor->referenceCount ) delete assessor;
185 : : }
186 [ + + ]: 96 : if( 0 == --myData->referenceCount ) delete myData;
187 [ - + ]: 127 : }
188 : :
189 : 178 : double QualityAssessor::Assessor::get_average() const
190 : : {
191 [ + - ]: 178 : return count ? sum / count : 0;
192 : : }
193 : :
194 : 141 : double QualityAssessor::Assessor::get_rms() const
195 : : {
196 [ + - ]: 141 : return count ? sqrt( sqrSum / count ) : 0;
197 : : }
198 : :
199 : 151 : double QualityAssessor::Assessor::get_stddev() const
200 : : {
201 [ + - ]: 151 : double sqr = count ? sqrSum / count - sum * sum / ( (double)count * count ) : 0;
202 [ - + ]: 151 : return sqr < 0 ? 0 : sqrt( sqr );
203 : : }
204 : :
205 : 0 : double QualityAssessor::Assessor::get_power_mean() const
206 : : {
207 [ # # ][ # # ]: 0 : return ( count && pMean ) ? pow( pSum / count, 1 / pMean ) : 0;
208 : : }
209 : :
210 : 16 : bool QualityAssessor::get_inverted_element_count( int& inverted_elems, int& inverted_samples, MsqError& err )
211 : : {
212 [ - + ]: 16 : if( myData->invertedElementCount == -1 )
213 : : {
214 : : MSQ_SETERR( err )
215 [ # # ]: 0 : ( "Number of inverted elements has not yet been calculated.", MsqError::INVALID_STATE );
216 : 0 : return false;
217 : : }
218 : 16 : inverted_elems = myData->invertedElementCount;
219 : 16 : inverted_samples = myData->invertedSampleCount;
220 : 16 : return true;
221 : : }
222 : :
223 : 58 : void QualityAssessor::add_quality_assessment( QualityMetric* metric, int histogram_intervals, double power_mean,
224 : : const char* tag_name, const char* label )
225 : : {
226 [ + - ]: 58 : list_type::iterator i = find_or_add( metric, label );
227 [ + - ]: 58 : ( *i )->pMean = power_mean;
228 [ + + ]: 58 : if( histogram_intervals > 0 )
229 [ + - ][ + - ]: 2 : ( *i )->histogram.resize( histogram_intervals + 2 );
230 : : else
231 [ + - ]: 56 : ( *i )->histogram.clear();
232 [ + - ]: 58 : ( *i )->haveHistRange = false;
233 [ + - ]: 58 : if( !tag_name )
234 [ + - ]: 58 : ( *i )->tagName.clear();
235 : : else
236 [ # # ][ # # ]: 0 : ( *i )->tagName = tag_name;
237 : 58 : }
238 : :
239 : 78 : QualityAssessor::list_type::iterator QualityAssessor::find_or_add( QualityMetric* qm, const char* label )
240 : : {
241 [ + - ]: 78 : list_type::iterator iter;
242 : :
243 : : // If metric is already in list, find it
244 [ + - ][ + - ]: 95 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + + ]
245 [ + - ][ - + ]: 17 : if( ( *iter )->qualMetric == qm ) break;
246 : :
247 : : // If metric not found in list, add it
248 [ + - ][ + - ]: 78 : if( iter == assessList.end() )
249 : : {
250 [ + - ][ + - ]: 78 : Assessor* new_assessor = new Assessor( qm, label );
251 : 78 : new_assessor->referenceCount = 1;
252 [ + - ][ + + ]: 78 : if( qm->get_metric_type() == QualityMetric::VERTEX_BASED )
253 : : {
254 [ + - ]: 8 : assessList.push_back( new_assessor );
255 [ + - ]: 8 : iter = --assessList.end();
256 : : }
257 : : else
258 : : {
259 [ + - ]: 70 : assessList.push_front( new_assessor );
260 : 78 : iter = assessList.begin();
261 : : }
262 : : }
263 : :
264 : 78 : return iter;
265 : : }
266 : :
267 : 141 : QualityAssessor::list_type::iterator QualityAssessor::find_stopping_assessment()
268 : : {
269 [ + - ]: 141 : list_type::iterator iter;
270 [ + - ][ + - ]: 250 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + + ]
271 [ + - ][ + - ]: 144 : if( ( *iter )->stopping_function() ) break;
[ + + ]
272 : 141 : return iter;
273 : : }
274 : :
275 : : /*!Sets which QualityMetric and QAFunction
276 : : combination is used to determine the value return from assess_mesh_quality().
277 : : It first ensures that the inputed QAFunction was not HISTOGRAM. It then
278 : : calls add_quality_assessment with the given QualityMetric and QAFunction,
279 : : to ensure that this combination will be computed. Finally, it sets
280 : : the stoppingMetric pointer and the stoppingFunction data members.
281 : : \param qm Pointer to QualityMetric.
282 : : \param func (QAFUNCTION) Wrapper function for qm (e.g. MINIMUM, MAXIMUM,...).
283 : : */
284 : 20 : void QualityAssessor::set_stopping_assessment( QualityMetric* metric, int histogram_intervals, double power_mean,
285 : : const char* tag_name, const char* label )
286 : : {
287 [ + - ]: 20 : list_type::iterator i = find_stopping_assessment();
288 [ + - ][ - + ]: 20 : if( i != assessList.end() ) ( *i )->set_stopping_function( false );
[ # # ][ # # ]
289 : :
290 [ + - ]: 20 : i = find_or_add( metric, label );
291 [ + - ]: 20 : ( *i )->pMean = power_mean;
292 [ + + ]: 20 : if( histogram_intervals > 0 )
293 [ + - ][ + - ]: 4 : ( *i )->histogram.resize( histogram_intervals + 2 );
294 : : else
295 [ + - ]: 16 : ( *i )->histogram.clear();
296 [ + - ]: 20 : ( *i )->haveHistRange = false;
297 [ + - ]: 20 : if( !tag_name )
298 [ + - ]: 20 : ( *i )->tagName.clear();
299 : : else
300 [ # # ][ # # ]: 0 : ( *i )->tagName = tag_name;
301 [ + - ][ + - ]: 20 : ( *i )->set_stopping_function( true );
302 : 20 : }
303 : :
304 : : /*!
305 : : Checks first to see if the QualityMetric, qm, has been added to this
306 : : QualityAssessor, and if it has not, adds it. It then adds HISTOGRAM as a
307 : : QAFunciton for that metric. It then sets the minimum and maximum values
308 : : for the histogram.
309 : : \param qm Pointer to the QualityMetric to be used in histogram.
310 : : \param min_val (double) Minimum range of histogram.
311 : : \param max_val (double) Maximum range of histogram.
312 : : \param intervals Number of histogram intervals
313 : : */
314 : 0 : void QualityAssessor::add_histogram_assessment( QualityMetric* metric, double min_val, double max_val, int intervals,
315 : : double power_mean, const char* tag_name, const char* label )
316 : : {
317 [ # # ]: 0 : if( intervals < 1 ) intervals = 1;
318 [ # # ]: 0 : list_type::iterator i = find_or_add( metric, label );
319 [ # # ]: 0 : ( *i )->pMean = power_mean;
320 [ # # ]: 0 : ( *i )->histMin = min_val;
321 [ # # ]: 0 : ( *i )->histMax = max_val;
322 [ # # ]: 0 : ( *i )->haveHistRange = min_val < max_val;
323 [ # # ][ # # ]: 0 : ( *i )->histogram.resize( intervals + 2 );
324 [ # # ]: 0 : if( !tag_name )
325 [ # # ]: 0 : ( *i )->tagName.clear();
326 : : else
327 [ # # ][ # # ]: 0 : ( *i )->tagName = tag_name;
328 : 0 : }
329 : :
330 : 0 : TagHandle QualityAssessor::get_tag( Mesh* mesh, std::string name, Mesh::TagType type, unsigned size, MsqError& err )
331 : : {
332 : 0 : TagHandle tag = mesh->tag_get( name, err );
333 [ # # ]: 0 : if( !err )
334 : : {
335 : : Mesh::TagType exist_type;
336 [ # # ]: 0 : std::string junk;
337 : : unsigned exist_size;
338 [ # # ]: 0 : mesh->tag_properties( tag, junk, exist_type, exist_size, err );
339 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
340 [ # # ][ # # ]: 0 : if( type != exist_type || size != exist_size )
341 : : {
342 : : MSQ_SETERR( err )
343 [ # # ][ # # ]: 0 : ( MsqError::TAG_ALREADY_EXISTS, "Tag \"%s\" exists with incorrect type or length.", name.c_str() );
[ # # ]
344 : 0 : }
345 : : }
346 [ # # ]: 0 : else if( err.error_code() == MsqError::TAG_NOT_FOUND )
347 : : {
348 : 0 : err.clear();
349 : 0 : tag = mesh->tag_create( name, type, size, 0, err );
350 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ]
351 : : }
352 : : else
353 : : {
354 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ]
355 : : }
356 : :
357 : 0 : return tag;
358 : : }
359 : :
360 : 121 : void QualityAssessor::initialize_queue( MeshDomainAssoc* mesh_and_domain, const Settings* settings, MsqError& err )
361 : : {
362 [ + - ][ + - ]: 267 : for( list_type::iterator i = assessList.begin(); i != assessList.end(); ++i )
[ + + ]
363 : : {
364 [ + - ][ + - ]: 267 : ( *i )->get_metric()->initialize_queue( mesh_and_domain, settings, err );MSQ_ERRRTN( err );
[ + - ][ + - ]
[ - + ][ # # ]
[ # # ][ - + ]
365 : : }
366 : : }
367 : :
368 : : /*!
369 : : Computes the quality data for a given
370 : : MeshSet, ms. What quality information is calculated, depends
371 : : on what has been requested through the use of the QualityAssessor
372 : : constructor, add_quality_assessment(), and set_stopping_assessment().
373 : : The resulting data is printed in a table unless disable_printing_results()
374 : : has been called. The double returned depends on the QualityMetric
375 : : and QAFunction "return" combination, which can be set using
376 : : set_stopping_assessemnt().
377 : : \param ms (const MeshSet &) MeshSet used for quality assessment.
378 : : */
379 : 121 : double QualityAssessor::loop_over_mesh( MeshDomainAssoc* mesh_and_domain, const Settings* settings, MsqError& err )
380 : : {
381 : 121 : return loop_over_mesh_internal( mesh_and_domain, settings, NULL, err );
382 : : }
383 : :
384 : : /*!
385 : : Computes the quality data for a given
386 : : MeshSet, ms. What quality information is calculated, depends
387 : : on what has been requested through the use of the QualityAssessor
388 : : constructor, add_quality_assessment(), and set_stopping_assessment().
389 : : The resulting data is printed in a table unless disable_printing_results()
390 : : has been called. The double returned depends on the QualityMetric
391 : : and QAFunction "return" combination, which can be set using
392 : : set_stopping_assessemnt().
393 : : \param ms (const MeshSet &) MeshSet used for quality assessment.
394 : : */
395 : 0 : double QualityAssessor::loop_over_mesh( ParallelMesh* mesh, MeshDomain* domain, const Settings* settings,
396 : : MsqError& err )
397 : : {
398 [ # # ][ # # ]: 0 : MeshDomainAssoc mesh_and_domain = MeshDomainAssoc( (Mesh*)mesh, domain, false, true );
399 [ # # ][ # # ]: 0 : return loop_over_mesh_internal( &mesh_and_domain, settings, mesh->get_parallel_helper(), err );
400 : : }
401 : :
402 : 121 : double QualityAssessor::loop_over_mesh_internal( MeshDomainAssoc* mesh_and_domain, const Settings* settings,
403 : : ParallelHelper* helper, MsqError& err )
404 : : {
405 : : // Clear out any previous data
406 [ + - ]: 121 : reset_data();
407 : :
408 : : // Clear culling flag, set hard fixed flag, etc on all vertices
409 [ + - ]: 121 : initialize_vertex_byte( mesh_and_domain, settings, err );
410 [ + - ][ - + ]: 121 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ - + ]
411 : :
412 [ + - ]: 121 : Mesh* mesh = mesh_and_domain->get_mesh();
413 [ + - ]: 121 : MeshDomain* domain = mesh_and_domain->get_domain();
414 : 121 : invalid_values = false;
415 : :
416 [ + - ]: 121 : PatchData patch;
417 [ + - ]: 121 : patch.set_mesh( mesh );
418 [ + - ]: 121 : patch.set_domain( domain );
419 [ + - ][ + - ]: 121 : if( settings ) patch.attach_settings( settings );
420 : :
421 [ + - ]: 242 : ElementPatches elem_patches;
422 [ + - ]: 121 : elem_patches.set_mesh( mesh );
423 [ + - ]: 242 : VertexPatches vert_patches( 1, false );
424 [ + - ]: 121 : vert_patches.set_mesh( mesh );
425 : :
426 [ + - ]: 242 : std::vector< PatchSet::PatchHandle > patches;
427 : 121 : std::vector< PatchSet::PatchHandle >::iterator p;
428 [ + - ]: 242 : std::vector< Mesh::VertexHandle > patch_verts;
429 [ + - ]: 242 : std::vector< Mesh::ElementHandle > patch_elems;
430 [ + - ]: 242 : std::vector< size_t > metric_handles;
431 : :
432 : : // Check if we really need the helper
433 [ - + ][ # # ]: 121 : if( helper && helper->get_nprocs() == 1 ) helper = 0;
[ # # ][ - + ]
434 : :
435 : : // Get any necessary tag handles.
436 : 121 : TagHandle invertedTag = 0;
437 [ + - ][ - + ]: 121 : if( tagging_inverted_elements() )
438 : : {
439 [ # # ][ # # ]: 0 : invertedTag = get_tag( mesh, invertedTagName, Mesh::INT, 1, err );
440 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
441 : : }
442 [ + - ]: 121 : list_type::iterator iter;
443 [ + - ][ + - ]: 267 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + + ]
444 : : {
445 [ + - ][ + - ]: 146 : if( ( *iter )->write_to_tag() )
[ - + ]
446 : : {
447 [ # # ][ # # ]: 0 : ( *iter )->tagHandle = get_tag( mesh, ( *iter )->tagName, Mesh::DOUBLE, 1, err );
[ # # ][ # # ]
448 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
449 : : }
450 : : }
451 : :
452 : 121 : TagHandle fixedTag = 0;
453 [ + - ][ - + ]: 121 : if( tagging_fixed_elements() )
454 : : {
455 [ # # ][ # # ]: 0 : fixedTag = get_tag( mesh, fixedTagName, Mesh::INT, 1, err );
456 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
457 : : }
458 : :
459 : : // Record the type of metric for each assessment so that it can be
460 : : // included in the QualitySummary report.
461 [ + - ][ + - ]: 267 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + + ]
462 : : {
463 [ + - ][ + - ]: 146 : ElementAvgQM* avg_ptr = dynamic_cast< ElementAvgQM* >( ( *iter )->get_metric() );
[ - + ]
464 [ + - ][ + - ]: 146 : ElementMaxQM* max_ptr = dynamic_cast< ElementMaxQM* >( ( *iter )->get_metric() );
[ - + ]
465 [ + - ][ + - ]: 146 : TMPQualityMetric* tq_ptr = dynamic_cast< TMPQualityMetric* >( ( *iter )->get_metric() );
[ - + ]
466 [ - + ]: 146 : if( avg_ptr )
467 [ # # ]: 0 : ( *iter )->assessScheme = ELEMENT_AVG_QM;
468 [ + + ]: 146 : else if( max_ptr )
469 [ + - ]: 3 : ( *iter )->assessScheme = ELEMENT_MAX_QM;
470 [ + + ]: 143 : else if( tq_ptr )
471 [ + - ]: 15 : ( *iter )->assessScheme = TMP_QUALITY_METRIC;
472 : : else
473 [ + - ]: 128 : ( *iter )->assessScheme = QUALITY_METRIC;
474 : : }
475 : :
476 : : // Check for any metrics for which a histogram is to be
477 : : // calculated and for which the user has not specified
478 : : // minimum and maximum values.
479 : : // Element-based metrics are first in list, followed
480 : : // by vertex-based metrics. Find first vertex-based
481 : : // metric also such that element metrics go from
482 : : // assessList.begin() to elem_end and vertex metrics
483 : : // go from elem_end to assessList.end()
484 : 121 : list_type::iterator elem_end = assessList.end();
485 : 121 : bool need_second_pass_for_elements = false;
486 : 121 : bool need_second_pass_for_vertices = false;
487 [ + - ][ + - ]: 253 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + + ]
488 : : {
489 [ + - ][ + - ]: 146 : if( ( *iter )->get_metric()->get_metric_type() == QualityMetric::VERTEX_BASED ) break;
[ + - ][ + + ]
490 : :
491 [ + - ][ + - ]: 132 : if( ( *iter )->have_histogram() && !( *iter )->haveHistRange ) need_second_pass_for_elements = true;
[ + + ][ + - ]
[ + - ][ + + ]
492 : : }
493 : 121 : elem_end = iter;
494 [ + - ][ + - ]: 135 : for( ; iter != assessList.end(); ++iter )
[ + + ]
495 : : {
496 [ + - ][ + - ]: 14 : if( ( *iter )->have_histogram() && !( *iter )->haveHistRange ) need_second_pass_for_vertices = true;
[ - + ][ # # ]
[ # # ][ - + ]
497 : : }
498 : :
499 : : // Do element-based metrics
500 [ + - ]: 121 : elem_patches.get_patch_handles( patches, err );
501 [ + - ][ - + ]: 121 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ - + ]
502 : :
503 : 121 : myData->invertedElementCount = myData->invertedSampleCount = myData->sampleCount = 0;
504 : 121 : myData->elementCount = patches.size();
505 : 121 : myData->freeElementCount = 0;
506 : :
507 : : int inverted, samples;
508 : 121 : bool first_pass = false;
509 [ + + ]: 129 : do
510 : : { // might need to loop twice to calculate histograms
511 : 129 : first_pass = !first_pass;
512 : :
513 : : // until there are no more patches
514 : : // there is another get_next_patch at
515 : : // the end of this loop
516 [ + - ][ + - ]: 260325 : for( p = patches.begin(); p != patches.end(); ++p )
[ + + ]
517 : : {
518 [ + - ][ + - ]: 260196 : elem_patches.get_patch( *p, patch_elems, patch_verts, err );
519 [ + - ][ - + ]: 260196 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ - + ]
520 : :
521 [ - + ]: 260196 : if( helper )
522 : : {
523 [ # # ][ # # ]: 0 : bool ours = helper->is_our_element( patch_elems[0], err );
524 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
525 [ # # ]: 0 : if( !ours )
526 : : {
527 : 0 : --myData->elementCount;
528 : 0 : continue;
529 : : }
530 : : }
531 [ + - ]: 260196 : patch.set_mesh_entities( patch_elems, patch_verts, err );
532 [ + - ][ - + ]: 260196 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ - + ]
533 : :
534 [ + + ]: 260196 : if( first_pass )
535 : : {
536 : : // record element type for use in print_summary
537 [ + - ][ + + ]: 519960 : for( size_t i = 0; i < patch.num_elements(); i++ )
538 : : {
539 [ + - ]: 259980 : const MsqMeshEntity* elem = &patch.element_by_index( i );
540 [ + - ]: 259980 : EntityTopology topo = elem->get_element_type();
541 : 259980 : elementTypeCount[topo - POLYGON]++;
542 : : }
543 : : }
544 : :
545 [ + - ][ + + ]: 260196 : if( 0 == patch.num_free_vertices() )
546 : : {
547 [ + - ][ - + ]: 1606 : if( tagging_fixed_elements() )
548 : : {
549 [ # # ]: 0 : Mesh::ElementHandle h = patch.get_element_handles_array()[0];
550 : 0 : int val = 1;
551 [ # # ]: 0 : mesh->tag_set_element_data( fixedTag, 1, &h, &val, err );
552 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
553 : : }
554 [ + + ]: 1606 : if( skipFixedSamples ) continue;
555 : : }
556 : :
557 : : // first check for inverted elements
558 [ + + ]: 258768 : if( first_pass )
559 : : {
560 : 258552 : ++myData->freeElementCount;
561 : 258552 : inverted = samples = 0;
562 [ + - ][ + - ]: 258552 : patch.element_by_index( 0 ).check_element_orientation( patch, inverted, samples, err );
563 [ + - ][ - + ]: 258552 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ - + ]
564 : 258552 : myData->invertedElementCount += ( inverted != 0 );
565 : 258552 : myData->invertedSampleCount += inverted;
566 : 258552 : myData->sampleCount += samples;
567 : :
568 [ + - ][ - + ]: 258552 : if( tagging_inverted_elements() )
569 : : {
570 [ # # ]: 0 : Mesh::ElementHandle h = patch.get_element_handles_array()[0];
571 : 0 : int val = ( inverted != 0 );
572 [ # # ]: 0 : mesh->tag_set_element_data( invertedTag, 1, &h, &val, err );
573 [ # # ][ # # ]: 258552 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
574 : : }
575 : : }
576 : :
577 : : // now process all element-based metrics
578 [ + - ][ + - ]: 602949 : for( iter = assessList.begin(); iter != elem_end; ++iter )
[ + + ]
579 : : {
580 : : // If first pass, get values for all metrics
581 [ + + ]: 344181 : if( first_pass )
582 : : {
583 : 343957 : double value = 0.0;
584 : 343957 : metric_handles.clear();
585 [ + - ][ + - ]: 343957 : QualityMetric* qm = ( *iter )->get_metric();
586 [ + - ]: 343957 : qm->get_single_pass( patch, metric_handles, skipFixedSamples, err );
587 [ + - ][ - + ]: 343957 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ - + ]
588 [ + - ][ + - ]: 688682 : for( std::vector< size_t >::iterator j = metric_handles.begin(); j != metric_handles.end(); ++j )
[ + + ]
589 : : {
590 [ + - ][ + - ]: 344725 : bool valid = ( *iter )->get_metric()->evaluate( patch, *j, value, err ); // MSQ_ERRZERO(err);
[ + - ][ + - ]
591 [ + - ][ + + ]: 344725 : if( err.error_code() == err.BARRIER_VIOLATED )
592 : : {
593 [ + - ]: 5 : err.clear();
594 : 5 : invalid_values = true;
595 : : }
596 [ + - ][ + - ]: 344725 : ( *iter )->add_value( value );
597 [ + + ][ + - ]: 344725 : if( !valid ) ( *iter )->add_invalid_value();
[ + - ]
598 : : }
599 : : // we don't do tag stuff unless metric is truely element-based
600 : : // (only one value per element)
601 [ + - ][ + - ]: 343957 : if( ( *iter )->write_to_tag() && metric_handles.size() == 1 )
[ - + ][ # # ]
[ - + ]
602 : : {
603 [ # # ]: 0 : Mesh::ElementHandle h = patch.get_element_handles_array()[0];
604 [ # # ][ # # ]: 0 : mesh->tag_set_element_data( ( *iter )->tagHandle, 1, &h, &value, err );
605 [ # # ][ # # ]: 343957 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
606 : : }
607 : : }
608 : : // If second pass, only do metrics for which the
609 : : // histogram hasn't been calculated yet.
610 [ + - ][ + - ]: 224 : else if( ( *iter )->have_histogram() && !( *iter )->haveHistRange )
[ + + ][ + - ]
[ + - ][ + + ]
611 : : {
612 : 216 : metric_handles.clear();
613 [ + - ][ + - ]: 216 : QualityMetric* qm = ( *iter )->get_metric();
614 [ + - ]: 216 : qm->get_evaluations( patch, metric_handles, skipFixedSamples, err );
615 [ + - ][ - + ]: 216 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ - + ]
616 [ + - ][ + - ]: 480 : for( std::vector< size_t >::iterator j = metric_handles.begin(); j != metric_handles.end(); ++j )
[ + + ]
617 : : {
618 : : double value;
619 [ + - ][ + - ]: 264 : ( *iter )->get_metric()->evaluate( patch, *j, value, err );
[ + - ][ + - ]
620 [ + - ][ - + ]: 264 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ - + ]
621 [ + - ][ + - ]: 264 : ( *iter )->add_hist_value( value );
622 : : }
623 : : }
624 : : }
625 : : }
626 [ + - ][ - + ]: 129 : if( MSQ_CHKERR( err ) ) return 0.0;
[ # # ][ # # ]
[ - + ]
627 : :
628 : : // Fix up any histogram ranges which were calculated
629 [ + - ][ + - ]: 270 : for( iter = assessList.begin(); iter != elem_end; ++iter )
[ + + ]
630 [ + - ][ + - ]: 141 : if( ( *iter )->have_histogram() && !( *iter )->haveHistRange )
[ + + ][ + - ]
[ + - ][ + + ]
631 [ + + ]: 17 : if( first_pass )
632 : : {
633 [ - + ]: 9 : if( helper )
634 : : {
635 [ # # ][ # # ]: 0 : helper->communicate_min_max_to_all( &( ( *iter )->minimum ), &( ( *iter )->maximum ), err );
[ # # ]
636 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
637 : : }
638 : :
639 [ + - ][ + - ]: 9 : ( *iter )->calculate_histogram_range();
640 : : // Uncomment the following to have the QA keep the first
641 : : // calculated histogram range for all subsequent iterations.
642 : : // else
643 : : // (*iter)->haveHistRange = true;
644 : : }
645 [ + + ][ + + ]: 121 : } while( first_pass && need_second_pass_for_elements && !invalid_values );
646 : :
647 : : // Do vertex-based metrics
648 [ + - ][ + + ]: 121 : if( assessList.end() != elem_end )
649 : : {
650 [ + - ]: 14 : vert_patches.get_patch_handles( patches, err );
651 [ + - ][ - + ]: 14 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ - + ]
652 : :
653 : 14 : first_pass = false;
654 [ + - ]: 14 : do
655 : : { // might need to loop twice to calculate histograms
656 : 14 : first_pass = !first_pass;
657 : :
658 : : // until there are no more patches
659 : : // there is another get_next_patch at
660 : : // the end of this loop
661 [ + - ][ + - ]: 37710 : for( p = patches.begin(); p != patches.end(); ++p )
[ + + ]
662 : : {
663 [ + - ][ + - ]: 37696 : vert_patches.get_patch( *p, patch_elems, patch_verts, err );
664 [ + - ][ - + ]: 37696 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ - + ]
665 [ + - ]: 37696 : patch.set_mesh_entities( patch_elems, patch_verts, err );
666 [ + - ][ - + ]: 37696 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ - + ]
667 [ + - ][ + - ]: 37696 : if( skipFixedSamples && 0 == patch.num_free_vertices() ) continue;
[ + + ][ + + ]
668 : :
669 [ + - ]: 36632 : Mesh::VertexHandle vert_handle = reinterpret_cast< Mesh::VertexHandle >( *p );
670 : :
671 [ + - ][ + - ]: 73264 : for( iter = elem_end; iter != assessList.end(); ++iter )
[ + + ]
672 : : {
673 : : // If first pass, get values for all metrics
674 [ + - ]: 36632 : if( first_pass )
675 : : {
676 : 36632 : double value = 0.0;
677 : 36632 : metric_handles.clear();
678 [ + - ][ + - ]: 36632 : QualityMetric* qm = ( *iter )->get_metric();
679 [ + - ]: 36632 : qm->get_single_pass( patch, metric_handles, skipFixedSamples, err );
680 [ + - ][ - + ]: 36632 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ - + ]
681 [ + - ][ + - ]: 183106 : for( std::vector< size_t >::iterator j = metric_handles.begin(); j != metric_handles.end();
[ + + ]
682 : : ++j )
683 : : {
684 [ + - ][ + - ]: 146474 : bool valid = ( *iter )->get_metric()->evaluate( patch, *j, value, err );
[ + - ][ + - ]
685 [ + - ][ - + ]: 146474 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ - + ]
686 [ + - ][ + - ]: 146474 : ( *iter )->add_value( value );
687 [ - + ][ # # ]: 146474 : if( !valid ) ( *iter )->add_invalid_value();
[ # # ]
688 : : }
689 : : // we don't do tag stuff unless metric is truely vertex-based
690 : : // (only one value per vertex)
691 [ + - ][ + - ]: 36632 : if( ( *iter )->write_to_tag() && metric_handles.size() == 1 )
[ - + ][ # # ]
[ - + ]
692 : : {
693 [ # # ][ # # ]: 0 : mesh->tag_set_vertex_data( ( *iter )->tagHandle, 1, &vert_handle, &value, err );
694 [ # # ][ # # ]: 36632 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
695 : : }
696 : : }
697 : : // If second pass, only do metrics for which the
698 : : // histogram hasn't been calculated yet.
699 [ # # ][ # # ]: 0 : else if( ( *iter )->have_histogram() && !( *iter )->haveHistRange )
[ # # ][ # # ]
[ # # ][ # # ]
700 : : {
701 : 0 : metric_handles.clear();
702 [ # # ][ # # ]: 0 : QualityMetric* qm = ( *iter )->get_metric();
703 [ # # ]: 0 : qm->get_evaluations( patch, metric_handles, skipFixedSamples, err );
704 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
705 [ # # ][ # # ]: 0 : for( std::vector< size_t >::iterator j = metric_handles.begin(); j != metric_handles.end();
[ # # ]
706 : : ++j )
707 : : {
708 : : double value;
709 [ # # ][ # # ]: 0 : ( *iter )->get_metric()->evaluate( patch, *j, value, err );
[ # # ][ # # ]
710 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
711 [ # # ][ # # ]: 0 : ( *iter )->add_hist_value( value );
712 : : }
713 : : }
714 : : }
715 : : }
716 [ + - ][ - + ]: 14 : if( MSQ_CHKERR( err ) ) return 0.0;
[ # # ][ # # ]
[ - + ]
717 : :
718 : : // Fix up any histogram ranges which were calculated
719 [ + - ][ + - ]: 28 : for( iter = elem_end; iter != assessList.end(); ++iter )
[ + + ]
720 [ + - ][ + - ]: 14 : if( ( *iter )->have_histogram() && !( *iter )->haveHistRange )
[ - + ][ # # ]
[ # # ][ - + ]
721 [ # # ]: 0 : if( first_pass )
722 : : {
723 [ # # ]: 0 : if( helper )
724 : : {
725 [ # # ][ # # ]: 0 : helper->communicate_min_max_to_all( &( ( *iter )->minimum ), &( ( *iter )->maximum ), err );
[ # # ]
726 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
727 : : }
728 [ # # ][ # # ]: 0 : ( *iter )->calculate_histogram_range();
729 : : // Uncomment the following to have the QA keep the first
730 : : // calculated histogram range for all subsequent iterations.
731 : : // else
732 : : // (*iter)->haveHistRange = true;
733 : : }
734 [ - + ][ # # ]: 14 : } while( first_pass && need_second_pass_for_vertices && !invalid_values );
735 : : }
736 : :
737 [ - + ]: 121 : if( helper )
738 : : {
739 [ # # ][ # # ]: 0 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ # # ]
740 : : {
741 : :
742 [ # # ][ # # ]: 0 : helper->communicate_min_max_to_zero( &( ( *iter )->minimum ), &( ( *iter )->maximum ), err );
[ # # ]
743 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
744 : :
745 : : helper->communicate_sums_to_zero( &myData->freeElementCount, &myData->invertedElementCount,
746 : : &myData->elementCount, &myData->invertedSampleCount, &myData->sampleCount,
747 [ # # ][ # # ]: 0 : &( ( *iter )->count ), &( ( *iter )->numInvalid ), &( ( *iter )->sum ),
[ # # ]
748 [ # # ][ # # ]: 0 : &( ( *iter )->sqrSum ), err );
749 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
750 : :
751 [ # # ][ # # ]: 0 : if( ( *iter )->have_power_mean() )
[ # # ]
752 : : {
753 [ # # ][ # # ]: 0 : helper->communicate_power_sum_to_zero( &( ( *iter )->pMean ), err );
754 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
755 : : }
756 : :
757 [ # # ][ # # ]: 0 : if( ( *iter )->have_histogram() )
[ # # ]
758 : : {
759 [ # # ][ # # ]: 0 : helper->communicate_histogram_to_zero( ( *iter )->histogram, err );
760 [ # # ][ # # ]: 0 : MSQ_ERRZERO( err );
[ # # ][ # # ]
[ # # ]
761 : : }
762 : : }
763 : : }
764 : :
765 : : // Print results, if requested
766 [ + + ][ - + ]: 121 : if( printSummary && ( !helper || helper->get_rank() == 0 ) ) print_summary( this->outputStream );
[ # # ][ # # ]
[ + + ][ + - ]
767 : :
768 [ + - ]: 121 : list_type::iterator i = find_stopping_assessment();
769 [ + - ][ + + ]: 242 : return i == assessList.end() ? 0 : ( *i )->stopping_function_value();
[ + - ][ + - ]
770 : : }
771 : :
772 : 3 : bool QualityAssessor::invalid_elements() const
773 : : {
774 : 3 : bool result = false;
775 [ + - ]: 3 : list_type::const_iterator iter;
776 [ + - ][ + - ]: 4 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + + ]
777 [ + - ][ + - ]: 1 : if( ( *iter )->get_invalid_element_count() ) result = true;
[ - + ]
778 : 3 : return result;
779 : : }
780 : :
781 : 121 : void QualityAssessor::reset_data()
782 : : {
783 [ + - ]: 121 : list_type::iterator iter;
784 [ + - ][ + - ]: 267 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + + ]
785 [ + - ][ + - ]: 146 : ( *iter )->reset_data();
786 : 121 : myData->invertedElementCount = -1;
787 : 121 : myData->invertedSampleCount = -1;
788 : :
789 [ + + ]: 1331 : for( int i = POLYGON; i <= MIXED; i++ )
790 : 1210 : elementTypeCount[i - POLYGON] = 0;
791 : 121 : }
792 : :
793 : 1 : void QualityAssessor::scale_histograms( QualityAssessor* optimized )
794 : : {
795 : : // find the histograms to scale
796 [ + - ]: 1 : list_type::iterator iter;
797 [ + - ]: 1 : list_type::iterator initial;
798 [ + - ]: 1 : list_type::iterator optimal;
799 : 1 : bool initial_found = false, optimal_found = false;
800 [ + - ][ + - ]: 2 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + - ]
801 : : {
802 [ + - ][ + + ]: 2 : if( ( *iter )->histogram.size() > 0 )
803 : : {
804 [ + - ]: 1 : if( initial_found == false )
805 : : {
806 : 1 : initial = iter;
807 : 1 : initial_found = true;
808 : 1 : break;
809 : : }
810 : : }
811 : : }
812 [ # # ][ + - ]: 1 : for( iter = optimized->assessList.begin(); iter != optimized->assessList.end(); ++iter )
[ + - ]
813 : : {
814 [ + - ][ + - ]: 1 : if( ( *iter )->histogram.size() > 0 )
815 : : {
816 : 1 : optimal = iter;
817 : 1 : optimal_found = true;
818 : 1 : break;
819 : : }
820 : : }
821 [ + - ][ - + ]: 1 : if( !initial_found || !optimal_found )
822 : : {
823 : : // issue warning: orig histograms not found
824 [ # # ]: 0 : if( !initial_found )
825 [ # # ][ # # ]: 0 : outputStream << "WARNING: 'before' histogram not found" << std::endl;
826 : : else
827 [ # # ][ # # ]: 0 : outputStream << "WARNING: 'after' histogram not found" << std::endl;
828 : 0 : return;
829 : : }
830 : :
831 : : // check number of intervals (bins) for each histogram
832 [ + - ]: 1 : int num_intervals = ( *initial )->histogram.size() - 2;
833 [ + - ][ - + ]: 1 : if( num_intervals != int( ( *optimal )->histogram.size() - 2 ) )
834 : : {
835 : : // issue warning: number of intervals not the same
836 [ # # ][ # # ]: 0 : outputStream << "WARNING: histogram intervals are not the same" << std::endl;
837 : 0 : return;
838 : : }
839 : :
840 : : // calculate new max and min values
841 : : double combined_min, combined_max;
842 [ + - ][ + - ]: 1 : if( ( *initial )->histMin < ( *optimal )->histMin )
[ + - ]
843 [ + - ]: 1 : combined_min = ( *initial )->histMin;
844 : : else
845 [ # # ]: 0 : combined_min = ( *optimal )->histMin;
846 : :
847 [ + - ][ + - ]: 1 : if( ( *initial )->histMax > ( *optimal )->histMax )
[ + - ]
848 [ + - ]: 1 : combined_max = ( *initial )->histMax;
849 : : else
850 [ # # ]: 0 : combined_max = ( *optimal )->histMax;
851 : :
852 : : // put the before quality values into the correct new bins
853 : :
854 : : // First and last values in array are counts of valuesnum_intervals+1
855 : : // outside the user-specified range of the histogram
856 : : // (below and above, respectively.)
857 [ + - ]: 1 : std::vector< int > new_initial_histogram;
858 [ + - ][ + - ]: 1 : new_initial_histogram.resize( ( *initial )->histogram.size(), 0 );
859 [ + - ][ + - ]: 1 : new_initial_histogram[0] = ( *initial )->histogram[0];
[ + - ]
860 [ + - ]: 1 : new_initial_histogram[new_initial_histogram.size() - 1] =
861 [ + - ][ + - ]: 1 : ( *initial )->histogram[( *initial )->histogram.size() - 1];
[ + - ]
862 : :
863 : : // Re-calculate which interval the value is in. Add one
864 : : // because first entry is for values below user-specifed
865 : : // minimum value for histogram.
866 : 1 : double combined_range = combined_max - combined_min;
867 [ + - ]: 1 : double initial_min = ( *initial )->histMin;
868 [ + - ]: 1 : double optimal_min = ( *optimal )->histMin;
869 [ + - ][ + - ]: 1 : double initial_range = ( *initial )->histMax - ( *initial )->histMin;
870 [ + - ][ + - ]: 1 : double optimal_range = ( *optimal )->histMax - ( *optimal )->histMin;
871 : 1 : double combined_step = combined_range / num_intervals;
872 : 1 : double initial_step = initial_range / num_intervals;
873 : 1 : double optimal_step = optimal_range / num_intervals;
874 : : // round steps to 3 significant digits
875 [ + - ][ + - ]: 1 : if( combined_step >= 0.001 ) combined_step = round_to_3_significant_digits( combined_step );
876 [ + - ][ + - ]: 1 : if( initial_step >= 0.001 ) initial_step = round_to_3_significant_digits( initial_step );
877 [ - + ][ # # ]: 1 : if( optimal_step >= 0.001 ) optimal_step = round_to_3_significant_digits( optimal_step );
878 : :
879 : : // populate initial histogram
880 [ + - ]: 1 : if( initial_range == combined_range )
881 : : {
882 : : // just copy histogram
883 [ + - ][ + - ]: 1 : new_initial_histogram = ( *initial )->histogram;
884 : : }
885 : : else
886 : : {
887 [ # # ]: 0 : for( size_t i = 1; i < new_initial_histogram.size() - 1; i++ )
888 : : {
889 : 0 : double combined_bin_value = combined_min + ( combined_step * ( i - 1 ) );
890 [ # # ]: 0 : for( size_t j = 1; j < new_initial_histogram.size() - 1; j++ )
891 : : {
892 : 0 : double initial_bin_value = initial_min + ( initial_step * ( j - 1 ) );
893 [ # # ][ # # ]: 0 : if( initial_bin_value >= combined_bin_value && initial_bin_value < combined_bin_value + combined_step )
894 [ # # ][ # # ]: 0 : { new_initial_histogram[i] += ( *initial )->histogram[j]; }
[ # # ]
895 : : }
896 : : }
897 : : }
898 : :
899 : : // put the optimal quality values into the correct new bins
900 [ + - ]: 2 : std::vector< int > new_optimal_histogram;
901 [ + - ][ + - ]: 1 : new_optimal_histogram.resize( ( *optimal )->histogram.size(), 0 );
902 [ + - ][ + - ]: 1 : new_optimal_histogram[0] = ( *optimal )->histogram[0];
[ + - ]
903 [ + - ]: 1 : new_optimal_histogram[new_optimal_histogram.size() - 1] =
904 [ + - ][ + - ]: 1 : ( *optimal )->histogram[( *optimal )->histogram.size() - 1];
[ + - ]
905 : :
906 : : // populate optimal histogram
907 [ - + ]: 1 : if( optimal_range == combined_range )
908 : : {
909 : : // just copy histogram
910 [ # # ][ # # ]: 0 : new_optimal_histogram = ( *optimal )->histogram;
911 : : }
912 : : else
913 : : {
914 [ + + ]: 11 : for( size_t i = 1; i < new_optimal_histogram.size() - 1; i++ )
915 : : {
916 : 10 : double combined_bin_value = combined_min + ( combined_step * ( i - 1 ) );
917 [ + + ]: 110 : for( size_t j = 1; j < new_optimal_histogram.size() - 1; j++ )
918 : : {
919 : 100 : double optimal_bin_value = optimal_min + ( optimal_step * ( j - 1 ) );
920 [ + + ][ + + ]: 100 : if( optimal_bin_value >= combined_bin_value && optimal_bin_value < combined_bin_value + combined_step )
921 [ + - ][ + - ]: 10 : { new_optimal_histogram[i] += ( *optimal )->histogram[j]; }
[ + - ]
922 : : }
923 : : }
924 : : }
925 : :
926 : : // determine largest number of values in a 'bin' for both histograms
927 : : unsigned i;
928 : 1 : int max_interval_num = 1;
929 [ + + ]: 13 : for( i = 0; i < new_initial_histogram.size(); ++i )
930 : : {
931 [ + - ][ + + ]: 12 : if( new_initial_histogram[i] > max_interval_num ) max_interval_num = new_initial_histogram[i];
[ + - ]
932 : : }
933 [ + + ]: 13 : for( i = 0; i < new_optimal_histogram.size(); ++i )
934 : : {
935 [ + - ][ + + ]: 12 : if( new_optimal_histogram[i] > max_interval_num ) max_interval_num = new_optimal_histogram[i];
[ + - ]
936 : : }
937 : :
938 : : // calculate how many bar graph characters will represent the
939 : : // largest 'bin' value.
940 : : // create the 'before' histogram
941 [ + - ]: 1 : int termwidth = get_terminal_width();
942 : 1 : const char indent[] = " ";
943 : 1 : const char GRAPH_CHAR = '='; // Character used to create bar graphs
944 [ - + ]: 1 : const int TOTAL_WIDTH = termwidth > 30 ? termwidth : 70; // Width of histogram
945 : 1 : int GRAPHW = TOTAL_WIDTH - sizeof( indent );
946 : :
947 [ - + ]: 1 : if( 0 == max_interval_num ) return; // no data
948 : :
949 : : // Calculate width of field containing counts for
950 : : // histogram intervals (log10(max_interval)).
951 : 1 : int num_width = 1;
952 [ + + ]: 3 : for( int temp = max_interval_num; temp > 0; temp /= 10 )
953 : 2 : ++num_width;
954 : 1 : GRAPHW -= num_width;
955 : :
956 : : // Create an array of bar graph characters for use in output
957 [ + - ]: 2 : std::vector< char > graph_chars( GRAPHW + 1, GRAPH_CHAR );
958 : :
959 : : // Check if bar-graph should be linear or log10 plot
960 : : // Do log plot if standard deviation is less that 1.5
961 : : // histogram intervals.
962 : :
963 : 1 : bool log_plot = false;
964 [ + - ][ + - ]: 1 : double stddev = ( *initial )->get_stddev();
965 [ + - ][ - + ]: 1 : if( stddev > 0 && stddev < 2.0 * combined_step )
966 : : {
967 : 0 : int new_interval = (int)( log10( (double)( 1 + max_interval_num ) ) );
968 [ # # ]: 0 : if( new_interval > 0 )
969 : : {
970 : 0 : log_plot = true;
971 : 0 : max_interval_num = new_interval;
972 : : }
973 : : }
974 : : // output the 'before' histogram
975 : :
976 : : // Write title
977 [ + - ][ + - ]: 1 : outputStream << std::endl << "************** Common-scale Histograms **************" << std::endl << std::endl;
[ + - ][ + - ]
978 [ + - ][ + - ]: 1 : outputStream << indent << ( *initial )->get_label() << " histogram (initial mesh):";
[ + - ][ + - ]
[ + - ]
979 [ - + ][ # # ]: 1 : if( log_plot ) outputStream << " (log10 plot)";
980 [ + - ]: 1 : outputStream << std::endl;
981 : :
982 : : // Calculate width of a single quality interval value
983 : 1 : double interval_value = 0.0;
984 : 1 : int max_interval_width = 0;
985 [ + - ][ + - ]: 2 : std::stringstream str_stream;
986 [ + - ]: 2 : std::string interval_string;
987 [ + + ]: 13 : for( i = 0; i < new_initial_histogram.size(); ++i )
988 : : {
989 : 12 : interval_value = combined_min + (i)*combined_step;
990 [ + - ][ + - ]: 12 : if( combined_step >= .001 ) interval_value = round_to_3_significant_digits( interval_value );
991 [ + - ]: 12 : str_stream.clear();
992 [ + - ][ + - ]: 12 : str_stream.str( "" );
993 [ + - ]: 12 : interval_string = "";
994 [ + - ]: 12 : str_stream << interval_value;
995 [ + - ][ + - ]: 12 : interval_string = str_stream.str();
996 [ + + ]: 12 : if( interval_string.length() > (size_t)max_interval_width ) max_interval_width = interval_string.length();
997 : : }
998 : :
999 : : // adjust graph width for actual size of interval values
1000 : 1 : GRAPHW = GRAPHW - ( max_interval_width * 2 ) - 5;
1001 : :
1002 : : // For each interval of histogram
1003 [ + + ]: 13 : for( i = 0; i < new_initial_histogram.size(); ++i )
1004 : : {
1005 : : // First value is the count of the number of values that
1006 : : // were below the minimum value of the histogram.
1007 [ + + ]: 12 : if( 0 == i )
1008 : : {
1009 [ + - ][ + - ]: 1 : if( 0 == new_initial_histogram[i] ) continue;
1010 [ # # ][ # # ]: 0 : outputStream << indent << std::setw( max_interval_width ) << "under min";
[ # # ][ # # ]
1011 : : }
1012 : : // Last value is the count of the number of values that
1013 : : // were above the maximum value of the histogram.
1014 [ + + ]: 11 : else if( i + 1 == new_initial_histogram.size() )
1015 : : {
1016 [ + - ][ + - ]: 1 : if( 0 == new_initial_histogram[i] ) continue;
1017 [ # # ][ # # ]: 0 : outputStream << indent << std::setw( max_interval_width ) << "over max";
[ # # ][ # # ]
1018 : : }
1019 : : // Anything else is a valid interval of the histogram.
1020 : : // Print the range for each interval.
1021 : : else
1022 : : {
1023 : 10 : double start_value = combined_min + ( i - 1 ) * combined_step;
1024 : 10 : double end_value = combined_min + (i)*combined_step;
1025 : :
1026 [ + - ]: 10 : if( combined_step >= 0.001 )
1027 : : {
1028 [ + - ]: 10 : start_value = round_to_3_significant_digits( start_value );
1029 [ + - ]: 10 : end_value = round_to_3_significant_digits( end_value );
1030 : : }
1031 : :
1032 [ + - ][ + - ]: 10 : outputStream << indent << "(" << std::setw( max_interval_width ) << std::right << start_value << "-"
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
1033 [ + - ][ + - ]: 20 : << std::setw( max_interval_width ) << std::left << end_value << ") |";
[ + - ][ + - ]
[ + - ]
1034 : : }
1035 : :
1036 : : // Print bar graph
1037 : :
1038 : : // First calculate the number of characters to output
1039 : : int num_graph;
1040 [ - + ]: 10 : if( log_plot )
1041 [ # # ]: 0 : num_graph = GRAPHW * (int)log10( (double)( 1 + new_initial_histogram[i] ) ) / max_interval_num;
1042 : : else
1043 [ + - ]: 10 : num_graph = GRAPHW * new_initial_histogram[i] / max_interval_num;
1044 : :
1045 : : // print num_graph characters using array of fill characters.
1046 [ + - ]: 10 : graph_chars[num_graph] = '\0';
1047 [ + - ][ + - ]: 10 : outputStream << arrptr( graph_chars );
1048 [ + - ]: 10 : graph_chars[num_graph] = GRAPH_CHAR;
1049 : :
1050 : : // Print interval count.
1051 [ + - ][ + - ]: 10 : outputStream << new_initial_histogram[i] << std::endl;
[ + - ]
1052 : : }
1053 : :
1054 [ + - ][ + - ]: 1 : outputStream << " metric was evaluated " << ( *initial )->count << " times." << std::endl << std::endl;
[ + - ][ + - ]
[ + - ][ + - ]
1055 : :
1056 : : // output the 'after' histogram
1057 [ + - ][ + - ]: 1 : outputStream << std::endl << indent << ( *optimal )->get_label() << " histogram (optimal mesh):";
[ + - ][ + - ]
[ + - ][ + - ]
1058 [ - + ][ # # ]: 1 : if( log_plot ) outputStream << " (log10 plot)";
1059 [ + - ]: 1 : outputStream << std::endl;
1060 : :
1061 : : // For each interval of histogram
1062 [ + + ]: 13 : for( i = 0; i < new_optimal_histogram.size(); ++i )
1063 : : {
1064 : : // First value is the count of the number of values that
1065 : : // were below the minimum value of the histogram.
1066 [ + + ]: 12 : if( 0 == i )
1067 : : {
1068 [ + - ][ + - ]: 1 : if( 0 == new_optimal_histogram[i] ) continue;
1069 [ # # ][ # # ]: 0 : outputStream << indent << std::setw( max_interval_width ) << "under min";
[ # # ][ # # ]
1070 : : }
1071 : : // Last value is the count of the number of values that
1072 : : // were above the maximum value of the histogram.
1073 [ + + ]: 11 : else if( i + 1 == new_optimal_histogram.size() )
1074 : : {
1075 [ + - ][ + - ]: 1 : if( 0 == new_optimal_histogram[i] ) continue;
1076 [ # # ][ # # ]: 0 : outputStream << indent << std::setw( max_interval_width ) << "over max";
[ # # ][ # # ]
1077 : : }
1078 : : // Anything else is a valid interval of the histogram.
1079 : : // Print the range for each interval.
1080 : : else
1081 : : {
1082 : 10 : double start_value = combined_min + ( i - 1 ) * combined_step;
1083 : 10 : double end_value = combined_min + (i)*combined_step;
1084 : :
1085 [ + - ]: 10 : if( combined_step >= 0.001 )
1086 : : {
1087 [ + - ]: 10 : start_value = round_to_3_significant_digits( start_value );
1088 [ + - ]: 10 : end_value = round_to_3_significant_digits( end_value );
1089 : : }
1090 : :
1091 [ + - ][ + - ]: 10 : outputStream << indent << "(" << std::setw( max_interval_width ) << std::right << start_value << "-"
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
1092 [ + - ][ + - ]: 20 : << std::setw( max_interval_width ) << std::left << end_value << ") |";
[ + - ][ + - ]
[ + - ]
1093 : : }
1094 : :
1095 : : // Print bar graph
1096 : :
1097 : : // First calculate the number of characters to output
1098 : : int num_graph;
1099 [ - + ]: 10 : if( log_plot )
1100 [ # # ]: 0 : num_graph = GRAPHW * (int)log10( (double)( 1 + new_optimal_histogram[i] ) ) / max_interval_num;
1101 : : else
1102 [ + - ]: 10 : num_graph = GRAPHW * new_optimal_histogram[i] / max_interval_num;
1103 : :
1104 : : // print num_graph characters using array of fill characters.
1105 [ + - ]: 10 : graph_chars[num_graph] = '\0';
1106 [ + - ][ + - ]: 10 : outputStream << arrptr( graph_chars );
1107 [ + - ]: 10 : graph_chars[num_graph] = GRAPH_CHAR;
1108 : :
1109 : : // Print interval count.
1110 [ + - ][ + - ]: 10 : outputStream << new_optimal_histogram[i] << std::endl;
[ + - ]
1111 : : }
1112 : :
1113 [ + - ][ + - ]: 1 : outputStream << " metric was evaluated " << ( *optimal )->count << " times." << std::endl << std::endl;
[ + - ][ + - ]
[ + - ][ + - ]
1114 : :
1115 : 2 : return;
1116 : : }
1117 : :
1118 : 78 : QualityAssessor::Assessor::Assessor( QualityMetric* metric, const char* label )
1119 : 78 : : qualMetric( metric ), mLabel( label ? std::string( label ) : metric->get_name() ), pMean( 0.0 ),
1120 : : haveHistRange( false ), histMin( 1.0 ), histMax( 0.0 ), tagHandle( 0 ), stoppingFunction( false ),
1121 [ - + ][ # # ]: 78 : referenceCount( 0 ), assessScheme( NO_SCHEME )
[ + - ][ - + ]
[ + - ]
[ + - # # ]
1122 : : {
1123 [ + - ]: 78 : reset_data();
1124 : 78 : }
1125 : :
1126 : 3 : const QualityAssessor::Assessor* QualityAssessor::get_results( QualityMetric* metric ) const
1127 : : {
1128 [ + - ]: 3 : list_type::const_iterator iter;
1129 [ + - ][ + - ]: 4 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + - ]
1130 [ + - ][ + - ]: 4 : if( ( *iter )->get_metric() == metric ) return *iter;
[ + + ][ + - ]
1131 : 3 : return 0;
1132 : : }
1133 : :
1134 : 0 : const QualityAssessor::Assessor* QualityAssessor::get_results( const char* name ) const
1135 : : {
1136 [ # # ]: 0 : list_type::const_iterator iter;
1137 [ # # ][ # # ]: 0 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ # # ]
1138 [ # # ][ # # ]: 0 : if( ( *iter )->get_label() == name ) return *iter;
[ # # ][ # # ]
[ # # ]
1139 : 0 : return 0;
1140 : : }
1141 : :
1142 : 0 : void QualityAssessor::Assessor::get_histogram( double& lower_bound_out, double& upper_bound_out,
1143 : : std::vector< int >& counts_out, MsqError& err ) const
1144 : : {
1145 [ # # ]: 0 : if( !have_histogram() )
1146 : : {
1147 [ # # ]: 0 : MSQ_SETERR( err )( "No histogram calculated.", MsqError::INVALID_STATE );
1148 : 0 : return;
1149 : : }
1150 : :
1151 : 0 : lower_bound_out = histMin;
1152 : 0 : upper_bound_out = histMax;
1153 : 0 : counts_out = histogram;
1154 : : }
1155 : :
1156 : 224 : void QualityAssessor::Assessor::reset_data()
1157 : : {
1158 : 224 : count = 0;
1159 : 224 : sum = 0;
1160 : 224 : maximum = -HUGE_VAL;
1161 : 224 : minimum = HUGE_VAL;
1162 : 224 : sqrSum = 0;
1163 : 224 : pSum = 0;
1164 : 224 : numInvalid = 0;
1165 : 224 : assessScheme = NO_SCHEME;
1166 : : // zero histogram data
1167 : 224 : size_t hist_size = histogram.size();
1168 : 224 : histogram.clear();
1169 [ + - ]: 224 : histogram.resize( hist_size, 0 );
1170 : 224 : }
1171 : :
1172 : 491199 : void QualityAssessor::Assessor::add_value( double metric_value )
1173 : : {
1174 : 491199 : sum += metric_value;
1175 : 491199 : sqrSum += metric_value * metric_value;
1176 [ + + ]: 491199 : if( metric_value > maximum ) maximum = metric_value;
1177 [ + + ]: 491199 : if( metric_value < minimum ) minimum = metric_value;
1178 : : // Only add value to histogram data from this function if
1179 : : // the user has specified the range. If user has not
1180 : : // specified the range, QualityAssessor will call add_hist_value()
1181 : : // directly once the range has been calculated.
1182 [ + + ][ - + ]: 491199 : if( have_histogram() && haveHistRange ) add_hist_value( metric_value );
[ - + ]
1183 : :
1184 [ - + ]: 491199 : if( have_power_mean() ) pSum += pow( metric_value, pMean );
1185 : :
1186 : 491199 : ++count;
1187 : 491199 : }
1188 : :
1189 : 38 : void QualityAssessor::Assessor::add_invalid_value()
1190 : : {
1191 : 38 : ++numInvalid;
1192 : 38 : }
1193 : :
1194 : 264 : void QualityAssessor::Assessor::add_hist_value( double metric_value )
1195 : : {
1196 : : // First and last values in array are counts of values
1197 : : // outside the user-specified range of the histogram
1198 : : // (below and above, respectively.)
1199 [ - + ]: 264 : if( metric_value < histMin )
1200 : 0 : ++histogram[0];
1201 [ - + ]: 264 : else if( metric_value > histMax )
1202 : 0 : ++histogram[histogram.size() - 1];
1203 : : else
1204 : : {
1205 : : // Calculate which interval the value is in. Add one
1206 : : // because first entry is for values below user-specifed
1207 : : // minimum value for histogram.
1208 : 264 : double range = histMax - histMin;
1209 : : double fract;
1210 [ + - ]: 264 : if( range > DBL_EPSILON )
1211 : 264 : fract = ( metric_value - histMin ) / range;
1212 : : else
1213 : 0 : fract = 0.0;
1214 : : unsigned cell;
1215 [ - + ]: 264 : if( fabs( fract - 1.0 ) < histMax * DBL_EPSILON )
1216 : 0 : cell = histogram.size() - 1;
1217 : : else
1218 : 264 : cell = 1 + (int)( ( fract * ( histogram.size() - 2 ) ) );
1219 : :
1220 : : // Add value to interval.
1221 : 264 : ++histogram[cell];
1222 : : }
1223 : 264 : }
1224 : :
1225 : 9 : void QualityAssessor::Assessor::calculate_histogram_range()
1226 : : {
1227 : 9 : double lower_bound = minimum;
1228 : 9 : int num_intervals = histogram.size();
1229 : 9 : double step = ( maximum - lower_bound ) / num_intervals;
1230 [ - + ]: 9 : if( step == 0 ) step = 1.0;
1231 : 9 : double size = pow( 10.0, floor( log10( step / ( num_intervals - 1 ) ) ) );
1232 [ + + ]: 9 : if( size < 1e-6 ) size = 1.0;
1233 : 9 : histMin = lower_bound;
1234 : 9 : histMax = lower_bound + num_intervals * size * ceil( step / size );
1235 : 9 : }
1236 : :
1237 : 115 : void QualityAssessor::print_summary( std::ostream& stream ) const
1238 : : {
1239 : 115 : const int NAMEW = 19; // Width of name column in table output
1240 : 115 : const int NUMW = 12; // Width of value columns in table output
1241 : :
1242 : : // Print title
1243 [ + - ]: 115 : stream << std::endl
1244 [ + - ][ + - ]: 115 : << "************** " << qualityAssessorName << " Summary **************" << std::endl
[ + - ][ + - ]
1245 [ + - ]: 115 : << std::endl;
1246 : :
1247 [ + + ]: 115 : if( myData->freeElementCount != myData->elementCount )
1248 [ + - ][ + - ]: 9 : stream << " Evaluating quality for " << myData->freeElementCount << " free elements of "
[ + - ]
1249 [ + - ][ + - ]: 9 : << myData->elementCount << " total elements." << std::endl;
[ + - ]
1250 : : else
1251 [ + - ][ + - ]: 106 : stream << " Evaluating quality for " << myData->elementCount << " elements." << std::endl;
[ + - ][ + - ]
1252 : :
1253 : : // Print element type totals
1254 [ + - ]: 115 : std::string str_value = "";
1255 [ + + ]: 1265 : for( int i = POLYGON; i <= MIXED; i++ )
1256 : : {
1257 [ + + ]: 1150 : if( elementTypeCount[i - POLYGON] )
1258 : : {
1259 [ + - ][ + - ]: 123 : str_value = element_name_as_string( i );
1260 [ + - ][ + - ]: 123 : if( str_value != "" )
1261 [ + - ][ + - ]: 123 : stream << " This mesh had " << elementTypeCount[i - POLYGON] << " " << str_value << " elements."
[ + - ][ + - ]
[ + - ]
1262 [ + - ]: 123 : << std::endl;
1263 : : }
1264 : : }
1265 : :
1266 [ + + ]: 115 : if( myData->invertedElementCount )
1267 : : {
1268 [ + - ][ + - ]: 31 : stream << " THERE ARE " << myData->invertedElementCount << " INVERTED ELEMENTS. " << std::endl
[ + - ][ + - ]
1269 [ + - ][ + - ]: 31 : << " (Elements invalid at " << myData->invertedSampleCount << " of " << myData->sampleCount
[ + - ][ + - ]
1270 [ + - ][ + - ]: 31 : << " sample locations.)" << std::endl
1271 [ + - ]: 31 : << std::endl;
1272 : : }
1273 : : else
1274 : : {
1275 [ + - ][ + - ]: 84 : stream << " There were no inverted elements detected. " << std::endl;
1276 : : }
1277 : :
1278 : : // Check if there are invalid values for any metric
1279 [ + - ]: 115 : list_type::const_iterator iter;
1280 : 115 : bool some_invalid = false;
1281 [ + - ][ + - ]: 257 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + + ]
1282 : : {
1283 [ + - ][ + - ]: 142 : if( ( *iter )->get_invalid_element_count() )
[ + + ]
1284 : : {
1285 : 3 : some_invalid = true;
1286 [ + - ][ + - ]: 3 : stream << " " << ( *iter )->get_invalid_element_count() << " OF " << ( *iter )->get_count()
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
1287 [ + - ][ + - ]: 6 : << " ENTITIES EVALUATED TO AN UNDEFINED VALUE FOR " << ( *iter )->get_label() << std::endl
[ + - ][ + - ]
[ + - ]
1288 [ + - ]: 3 : << std::endl;
1289 : : }
1290 : : }
1291 [ + + ]: 115 : if( !some_invalid )
1292 [ + - ][ + - ]: 112 : { stream << " No entities had undefined values for any computed metric." << std::endl << std::endl; }
[ + - ]
1293 : :
1294 [ + + ]: 115 : if( !invalid_values )
1295 : : {
1296 : : // Check if a user-define power-mean was calculated for any of the metrics
1297 [ + - ]: 114 : std::set< double > pmeans;
1298 [ + - ][ + - ]: 255 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + + ]
1299 [ + - ][ + - ]: 141 : if( ( *iter )->have_power_mean() ) pmeans.insert( ( *iter )->get_power() );
[ - + ][ # # ]
[ # # ][ # # ]
1300 : :
1301 : : // If power-mean of 1 or 2 was requested, change titles rather
1302 : : // than printing redundant values
1303 [ + - ][ + - ]: 228 : std::string average_str( "average" ), rms_str( "rms" );
1304 [ + - ][ + - ]: 114 : if( pmeans.find( 1.0 ) != pmeans.end() )
[ - + ]
1305 : : {
1306 [ # # ][ # # ]: 0 : pmeans.erase( pmeans.find( 1.0 ) );
1307 [ # # ]: 0 : average_str = "1-mean";
1308 : : }
1309 [ + - ][ + - ]: 114 : if( pmeans.find( 2.0 ) != pmeans.end() )
[ - + ]
1310 : : {
1311 [ # # ][ # # ]: 0 : pmeans.erase( pmeans.find( 2.0 ) );
1312 [ # # ]: 0 : rms_str = "2-mean";
1313 : : }
1314 : :
1315 : : // Number of values in table
1316 : 114 : unsigned num_values = pmeans.size() + 5;
1317 : :
1318 : : // Decide how wide of a table field should be used for the metric name
1319 [ + - ]: 114 : unsigned twidth = get_terminal_width();
1320 : 114 : unsigned maxnwidth = NAMEW;
1321 [ - + ]: 114 : if( twidth )
1322 : : {
1323 : 0 : unsigned valwidth = NUMW * num_values;
1324 [ # # ]: 0 : maxnwidth = valwidth < twidth ? twidth - valwidth : 0;
1325 : : }
1326 : 114 : unsigned namewidth = 0;
1327 [ + - ][ + - ]: 255 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + + ]
1328 [ + - ][ + - ]: 141 : if( ( *iter )->get_label().size() > namewidth ) namewidth = ( *iter )->get_label().size();
[ + + ][ + - ]
[ + - ]
1329 [ + + ]: 114 : if( namewidth > maxnwidth ) namewidth = maxnwidth;
1330 [ - + ]: 114 : if( namewidth < 7 ) // at least enough width for the column header
1331 : 0 : namewidth = 7;
1332 : :
1333 : 114 : int number_of_assessments = 0;
1334 : :
1335 : : // print metric values
1336 [ + - ][ + - ]: 255 : for( iter = assessList.begin(); iter != assessList.end(); ++iter )
[ + + ]
1337 : : {
1338 [ + + ][ + - ]: 141 : if( number_of_assessments > 0 ) stream << " -------------------------------------------" << std::endl;
[ + - ]
1339 : :
1340 : : // print assessment method used to calculate the statistics
1341 [ + - ][ + + ]: 141 : if( ( *iter )->assessScheme == TMP_QUALITY_METRIC )
1342 [ + - ][ + - ]: 14 : stream << " Sample Point Quality Statistics" << std::endl << std::endl;
[ + - ]
1343 : : else
1344 [ + - ][ + - ]: 127 : stream << " Element Quality Statistics" << std::endl << std::endl;
[ + - ]
1345 : :
1346 : : // print comlumn label line
1347 [ + - ]: 141 : std::set< double >::const_iterator piter;
1348 [ + - ][ + - ]: 141 : stream << std::setw( NUMW ) << "minimum";
[ + - ]
1349 [ # # ][ + - ]: 141 : for( piter = pmeans.begin(); piter != pmeans.end() && *piter < 1.0; ++piter )
[ - + ][ # # ]
[ # # ][ + - ]
[ - + # # ]
1350 [ # # ][ # # ]: 0 : stream << std::setw( NUMW - 6 ) << *piter << "-mean ";
[ # # ][ # # ]
[ # # ]
1351 [ + - ][ + - ]: 141 : stream << std::setw( NUMW ) << average_str;
[ + - ]
1352 [ # # ][ + - ]: 141 : for( ; piter != pmeans.end() && *piter < 2.0; ++piter )
[ - + ][ # # ]
[ # # ][ + - ]
[ - + # # ]
1353 [ # # ][ # # ]: 0 : stream << std::setw( NUMW - 6 ) << *piter << "-mean ";
[ # # ][ # # ]
[ # # ]
1354 [ + - ][ + - ]: 141 : stream << std::setw( NUMW ) << rms_str;
[ + - ]
1355 [ # # ][ + - ]: 141 : for( ; piter != pmeans.end(); ++piter )
[ - + ]
1356 [ # # ][ # # ]: 0 : stream << std::setw( NUMW - 6 ) << *piter << "-mean ";
[ # # ][ # # ]
[ # # ]
1357 [ + - ][ + - ]: 141 : stream << std::setw( NUMW ) << "maximum";
[ + - ]
1358 [ + - ][ + - ]: 141 : stream << std::setw( NUMW ) << "std.dev.";
[ + - ]
1359 [ + - ]: 141 : stream << std::endl;
1360 : :
1361 [ + - ][ + - ]: 141 : stream << std::setw( NUMW ) << ( *iter )->get_minimum();
[ + - ][ + - ]
[ + - ]
1362 : : // print power-means with P less than 1.0
1363 [ # # ][ + - ]: 141 : for( piter = pmeans.begin(); piter != pmeans.end() && *piter < 1.0; ++piter )
[ - + ][ # # ]
[ # # ][ + - ]
[ - + # # ]
1364 : : {
1365 [ # # ][ # # ]: 0 : if( ( *iter )->have_power_mean() && ( *iter )->get_power() == *piter )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1366 [ # # ][ # # ]: 0 : stream << std::setw( NUMW ) << ( *iter )->get_power_mean();
[ # # ][ # # ]
[ # # ]
1367 : : else
1368 [ # # ][ # # ]: 0 : stream << std::setw( NUMW ) << " ";
[ # # ]
1369 : : }
1370 : : // print average
1371 [ + - ][ + - ]: 141 : stream << std::setw( NUMW ) << ( *iter )->get_average();
[ + - ][ + - ]
[ + - ]
1372 : : // print power-means with P less than 2.0
1373 [ # # ][ + - ]: 141 : for( ; piter != pmeans.end() && *piter < 2.0; ++piter )
[ - + ][ # # ]
[ # # ][ + - ]
[ - + # # ]
1374 : : {
1375 [ # # ][ # # ]: 0 : if( ( *iter )->have_power_mean() && ( *iter )->get_power() == *piter )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1376 [ # # ][ # # ]: 0 : stream << std::setw( NUMW ) << ( *iter )->get_power_mean();
[ # # ][ # # ]
[ # # ]
1377 : : else
1378 [ # # ][ # # ]: 0 : stream << std::setw( NUMW ) << " ";
[ # # ]
1379 : : }
1380 : : // print RMS
1381 [ + - ][ + - ]: 141 : stream << std::setw( NUMW ) << ( *iter )->get_rms();
[ + - ][ + - ]
[ + - ]
1382 : : // print power-means with P greater than 2.0
1383 [ # # ][ + - ]: 141 : for( ; piter != pmeans.end(); ++piter )
[ - + ]
1384 : : {
1385 [ # # ][ # # ]: 0 : if( ( *iter )->have_power_mean() && ( *iter )->get_power() == *piter )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1386 [ # # ][ # # ]: 0 : stream << std::setw( NUMW ) << ( *iter )->get_power_mean();
[ # # ][ # # ]
[ # # ]
1387 : : else
1388 [ # # ][ # # ]: 0 : stream << std::setw( NUMW ) << " ";
[ # # ]
1389 : : }
1390 : : // print maximum and standard deviation
1391 [ + - ][ + - ]: 141 : stream << std::setw( NUMW ) << ( *iter )->get_maximum();
[ + - ][ + - ]
[ + - ]
1392 [ + - ][ + - ]: 141 : stream << std::setw( NUMW ) << ( *iter )->get_stddev();
[ + - ][ + - ]
[ + - ]
1393 [ + - ][ + - ]: 141 : stream << std::endl << std::endl;
1394 : :
1395 [ + - ][ + - ]: 141 : stream << " Number of statistics = " << ( *iter )->get_count() << std::endl;
[ + - ][ + - ]
[ + - ]
1396 : :
1397 : : // print name
1398 [ + - ][ + - ]: 141 : stream << " Metric = " << ( *iter )->get_label() << std::endl;
[ + - ][ + - ]
[ + - ]
1399 : :
1400 : : // Output the method used to calcualte the quality values
1401 [ + - ][ - + : 141 : switch( ( *iter )->assessScheme )
+ + - ]
1402 : : {
1403 : : case ELEMENT_AVG_QM:
1404 : : stream << " Element Quality = average over metric values at the elements' "
1405 [ # # ]: 0 : "sample points"
1406 [ # # ]: 0 : << std::endl
1407 [ # # ]: 0 : << std::endl;
1408 : 0 : break;
1409 : : case ELEMENT_MAX_QM:
1410 : : stream << " Element Quality = maximum over metric values at the elements' "
1411 [ + - ]: 2 : "sample points"
1412 [ + - ]: 2 : << std::endl
1413 [ + - ]: 2 : << std::endl;
1414 : 2 : break;
1415 : : case TMP_QUALITY_METRIC:
1416 [ + - ][ + - ]: 14 : stream << std::endl << std::endl;
1417 : 14 : break;
1418 : : case QUALITY_METRIC:
1419 [ + - ][ + - ]: 125 : stream << " Element Quality not based on sample points." << std::endl << std::endl;
[ + - ]
1420 : 125 : break;
1421 : : default:
1422 [ # # ][ # # ]: 0 : stream << " Scheme used for deriving qualitiy values unknown" << std::endl << std::endl;
[ # # ]
1423 : : }
1424 [ + - ][ + - ]: 141 : if( ( *iter )->have_histogram() ) ( *iter )->print_histogram( stream, get_terminal_width() );
[ + + ][ + - ]
[ + - ][ + - ]
1425 : 141 : number_of_assessments++;
1426 : 114 : }
1427 : : }
1428 : : else
1429 : : {
1430 [ + - ][ + - ]: 1 : stream << " Element Quality Statistics are Undefined for this Metric because" << std::endl
1431 [ + - ][ + - ]: 1 : << " there are Inverted Elements" << std::endl
1432 [ + - ]: 1 : << std::endl;
1433 : 115 : }
1434 : 115 : }
1435 : :
1436 : 8 : void QualityAssessor::Assessor::print_histogram( std::ostream& stream, int termwidth ) const
1437 : : {
1438 : : // Portability notes:
1439 : : // Use log10 rather than log10f because the float variations require
1440 : : // including platform-dependent headers on some platforms.
1441 : : // Explicitly cast log10 argument to double because some platforms
1442 : : // have overloaded float and double variations in C++ making an
1443 : : // implicit cast from an integer ambiguous.
1444 : :
1445 : 8 : const char indent[] = " ";
1446 : 8 : const char GRAPH_CHAR = '='; // Character used to create bar graphs
1447 [ - + ]: 8 : const int TOTAL_WIDTH = termwidth > 30 ? termwidth : 70; // Width of histogram
1448 : 8 : int GRAPHW = TOTAL_WIDTH - sizeof( indent );
1449 : :
1450 : : // range is either user-specified (histMin & histMax) or
1451 : : // calculated (minimum & maximum)
1452 : : double min, max;
1453 : 8 : min = histMin;
1454 : 8 : max = histMax;
1455 : : // Witdh of one interval of histogram
1456 : 8 : double step = ( max - min ) / ( histogram.size() - 2 );
1457 : : // round step to 3 significant digits
1458 : :
1459 [ + + ][ + - ]: 8 : if( step >= 0.001 ) step = round_to_3_significant_digits( step );
1460 : :
1461 : : // Find maximum value for an interval bin of the histogram
1462 : : unsigned i;
1463 : 8 : int max_bin_value = 1;
1464 [ + + ]: 104 : for( i = 0; i < histogram.size(); ++i )
1465 [ + - ][ + + ]: 96 : if( histogram[i] > max_bin_value ) max_bin_value = histogram[i];
[ + - ]
1466 : :
1467 [ - + ]: 16 : if( 0 == max_bin_value ) return; // no data
1468 : :
1469 : : // Calculate width of field containing counts for
1470 : : // histogram intervals (log10(max_bin_value)).
1471 : 8 : int num_width = 1;
1472 [ + + ]: 20 : for( int temp = max_bin_value; temp > 0; temp /= 10 )
1473 : 12 : ++num_width;
1474 : 8 : GRAPHW -= num_width;
1475 : :
1476 : : // Create an array of bar graph characters for use in output
1477 [ + - ]: 8 : std::vector< char > graph_chars( GRAPHW + 1, GRAPH_CHAR );
1478 : :
1479 : : // Check if bar-graph should be linear or log10 plot
1480 : : // Do log plot if standard deviation is less that 1.5
1481 : : // histogram intervals.
1482 : 8 : bool log_plot = false;
1483 [ + - ]: 8 : double stddev = get_stddev();
1484 [ + + ][ + + ]: 8 : if( stddev > 0 && stddev < 2.0 * step )
1485 : : {
1486 : 1 : int new_interval = (int)( log10( (double)( 1 + max_bin_value ) ) );
1487 [ + - ]: 1 : if( new_interval > 0 )
1488 : : {
1489 : 1 : log_plot = true;
1490 : 1 : max_bin_value = new_interval;
1491 : : }
1492 : : }
1493 : :
1494 : : // Write title
1495 [ + - ][ + - ]: 8 : stream << indent << get_label() << " histogram:";
[ + - ][ + - ]
1496 [ + + ][ + - ]: 8 : if( log_plot ) stream << " (log10 plot)";
1497 [ + - ]: 8 : stream << std::endl;
1498 : :
1499 : : // Calculate width of a single quality interval value
1500 : :
1501 : 8 : double interval_value = 0.0;
1502 : 8 : int max_interval_width = 0;
1503 [ + - ][ + - ]: 16 : std::stringstream str_stream;
1504 [ + - ]: 16 : std::string interval_string;
1505 [ + + ]: 104 : for( i = 0; i < histogram.size(); ++i )
1506 : : {
1507 : 96 : interval_value = min + (i)*step;
1508 [ + + ][ + - ]: 96 : if( step >= 0.001 ) interval_value = round_to_3_significant_digits( interval_value );
1509 [ + - ]: 96 : str_stream.clear();
1510 [ + - ][ + - ]: 96 : str_stream.str( "" );
1511 [ + - ]: 96 : interval_string = "";
1512 [ + - ]: 96 : str_stream << interval_value;
1513 [ + - ][ + - ]: 96 : interval_string = str_stream.str();
1514 [ + + ]: 96 : if( interval_string.length() > (size_t)max_interval_width ) max_interval_width = interval_string.length();
1515 : : }
1516 : :
1517 : : // adjust graph width for actual size of interval values
1518 : 8 : GRAPHW = GRAPHW - ( max_interval_width * 2 ) - 5;
1519 : :
1520 : : // For each interval of histogram
1521 [ + + ]: 104 : for( i = 0; i < histogram.size(); ++i )
1522 : : {
1523 : : // First value is the count of the number of values that
1524 : : // were below the minimum value of the histogram.
1525 [ + + ]: 96 : if( 0 == i )
1526 : : {
1527 [ + - ][ + - ]: 8 : if( 0 == histogram[i] ) continue;
1528 [ # # ][ # # ]: 0 : stream << indent << std::setw( max_interval_width ) << "under min";
[ # # ][ # # ]
1529 : : }
1530 : : // Last value is the count of the number of values that
1531 : : // were above the maximum value of the histogram.
1532 [ + + ]: 88 : else if( i + 1 == histogram.size() )
1533 : : {
1534 [ + - ][ + - ]: 8 : if( 0 == histogram[i] ) continue;
1535 [ # # ][ # # ]: 0 : stream << indent << std::setw( max_interval_width ) << "over max";
[ # # ][ # # ]
1536 : : }
1537 : : // Anything else is a valid interval of the histogram.
1538 : : // Print the range for each interval.
1539 : : else
1540 : : {
1541 : 80 : double start_value = min + ( i - 1 ) * step;
1542 : 80 : double end_value = min + (i)*step;
1543 [ + + ]: 80 : if( step >= 0.001 )
1544 : : {
1545 [ + - ]: 70 : start_value = round_to_3_significant_digits( start_value );
1546 [ + - ]: 70 : end_value = round_to_3_significant_digits( end_value );
1547 : : }
1548 : :
1549 [ + - ][ + - ]: 80 : stream << indent << "(" << std::setw( max_interval_width ) << std::right << start_value << "-"
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
1550 [ + - ][ + - ]: 160 : << std::setw( max_interval_width ) << std::left << end_value << ") |";
[ + - ][ + - ]
[ + - ]
1551 : :
1552 : : // reset stream alignment to right (the default)
1553 [ + - ]: 80 : stream << std::right;
1554 : : }
1555 : :
1556 : : // Print bar graph
1557 : :
1558 : : // First calculate the number of characters to output
1559 : : int num_graph;
1560 [ + + ]: 80 : if( log_plot )
1561 [ + - ]: 10 : num_graph = GRAPHW * (int)log10( (double)( 1 + histogram[i] ) ) / max_bin_value;
1562 : : else
1563 [ + - ]: 70 : num_graph = GRAPHW * histogram[i] / max_bin_value;
1564 : :
1565 : : // print num_graph characters using array of fill characters.
1566 [ + - ]: 80 : graph_chars[num_graph] = '\0';
1567 [ + - ][ + - ]: 80 : stream << arrptr( graph_chars );
1568 [ + - ]: 80 : graph_chars[num_graph] = GRAPH_CHAR;
1569 : :
1570 : : // Print interval count.
1571 [ + - ][ + - ]: 80 : stream << histogram[i] << std::endl;
[ + - ]
1572 : : }
1573 [ + - ][ + - ]: 16 : stream << " metric was evaluated " << count << " times." << std::endl << std::endl;
[ + - ][ + - ]
[ + - ]
1574 : : }
1575 : :
1576 : : #ifdef _WIN32
1577 : : #define fileno( A ) _fileno( ( A ) )
1578 : : #endif
1579 : 123 : int QualityAssessor::get_terminal_width() const
1580 : : {
1581 : : #ifdef TIOCGWINSZ
1582 : : int fd = -1;
1583 : : if( &outputStream == &std::cout )
1584 : : fd = fileno( stdout );
1585 : : else if( &outputStream == &std::cerr )
1586 : : fd = fileno( stderr );
1587 : : #ifdef FSTREAM_HAS_FD
1588 : : else if( std::ofstream* f = dynamic_cast< std::ofstream* >( &outputStream ) )
1589 : : fd = f->rdbuf()->fd();
1590 : : #endif
1591 : :
1592 : : if( fd >= 0 )
1593 : : {
1594 : : struct winsize ws;
1595 : : if( ioctl( fd, TIOCGWINSZ, &ws ) >= 0 ) return ws.ws_col;
1596 : : }
1597 : : #endif
1598 : :
1599 : 123 : return 0;
1600 : : }
1601 : :
1602 : 123 : std::string QualityAssessor::element_name_as_string( int enum_name )
1603 : : {
1604 [ + - ]: 123 : std::string str_value = "";
1605 : :
1606 [ - + + - : 123 : switch( enum_name )
+ + - - -
+ - ]
1607 : : {
1608 : : case POLYGON:
1609 [ # # ]: 0 : str_value.assign( "polygon" );
1610 : 0 : break;
1611 : : case TRIANGLE:
1612 [ + - ]: 12 : str_value.assign( "triangle" );
1613 : 12 : break;
1614 : : case QUADRILATERAL:
1615 [ + - ]: 82 : str_value.assign( "quadrilateral" );
1616 : 82 : break;
1617 : : case POLYHEDRON:
1618 [ # # ]: 0 : str_value.assign( "polyhedron" );
1619 : 0 : break;
1620 : : case TETRAHEDRON:
1621 [ + - ]: 13 : str_value.assign( "tetrahedron" );
1622 : 13 : break;
1623 : : case HEXAHEDRON:
1624 [ + - ]: 13 : str_value.assign( "hexahedron" );
1625 : 13 : break;
1626 : : case PRISM:
1627 [ # # ]: 0 : str_value.assign( "prism" );
1628 : 0 : break;
1629 : : case SEPTAHEDRON:
1630 [ # # ]: 0 : str_value.assign( "septahedron" );
1631 : 0 : break;
1632 : : case MIXED:
1633 [ # # ]: 0 : str_value.assign( "mixed" );
1634 : 0 : break;
1635 : : case PYRAMID:
1636 [ + - ]: 3 : str_value.assign( "pyramid" );
1637 : 3 : break;
1638 : : }
1639 : :
1640 : 123 : return str_value;
1641 : : }
1642 : :
1643 : 285 : double QualityAssessor::round_to_3_significant_digits( double number )
1644 : : {
1645 : 285 : double result = number;
1646 : 285 : double p = 1.0;
1647 : :
1648 [ + - ][ + - ]: 285 : if( number > 0 && number < 1000 )
1649 : : {
1650 [ + - ]: 285 : if( number < 1000 )
1651 : : {
1652 [ + + ]: 993 : while( number < 100 )
1653 : : {
1654 : 708 : number *= 10;
1655 : 708 : p *= 10;
1656 : : }
1657 : : }
1658 : : else
1659 : : {
1660 [ # # ]: 0 : while( number >= 1000 )
1661 : : {
1662 : 0 : number /= 10;
1663 : 0 : p /= 10;
1664 : : }
1665 : : }
1666 : 285 : int z = int( number + 0.5 );
1667 : 285 : result = z / p;
1668 : : }
1669 : :
1670 : 285 : return result;
1671 : : }
1672 : :
1673 : 35 : double QualityAssessor::Assessor::stopping_function_value() const
1674 : : {
1675 [ - + ]: 35 : return have_power_mean() ? get_power_mean() : get_average();
1676 : : }
1677 : :
1678 [ + - ][ + - ]: 120 : } // namespace MBMesquite
|