LCOV - code coverage report
Current view: top level - src/mesquite/QualityAssessor - QualityAssessor.cpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 627 828 75.7 %
Date: 2020-07-18 00:09:26 Functions: 34 43 79.1 %
Branches: 993 2664 37.3 %

           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

Generated by: LCOV version 1.11