LCOV - code coverage report
Current view: top level - src/mesquite/QualityMetric - AveragingQM.cpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 98 426 23.0 %
Date: 2020-07-18 00:09:26 Functions: 7 22 31.8 %
Branches: 67 485 13.8 %

           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                 :            :     (2006) [email protected]
      27                 :            : 
      28                 :            :   ***************************************************************** */
      29                 :            : /*!
      30                 :            :   \file   AveragingQM.cpp
      31                 :            :   \brief
      32                 :            : 
      33                 :            :   \author Michael Brewer
      34                 :            :   \author Thomas Leurent
      35                 :            :   \author Jason Kraftcheck
      36                 :            :   \date   2002-05-14
      37                 :            : */
      38                 :            : 
      39                 :            : #include "AveragingQM.hpp"
      40                 :            : #include "MsqVertex.hpp"
      41                 :            : #include "MsqMeshEntity.hpp"
      42                 :            : #include "MsqDebug.hpp"
      43                 :            : #include "MsqTimer.hpp"
      44                 :            : #include "PatchData.hpp"
      45                 :            : 
      46                 :            : namespace MBMesquite
      47                 :            : {
      48                 :            : 
      49                 :      16620 : double AveragingQM::average_corner_gradients( EntityTopology type, uint32_t fixed_vertices, unsigned num_corner,
      50                 :            :                                               double corner_values[], const Vector3D corner_grads[],
      51                 :            :                                               Vector3D vertex_grads[], MsqError& err )
      52                 :            : {
      53         [ +  - ]:      16620 :     const unsigned num_vertex = TopologyInfo::corners( type );
      54         [ +  - ]:      16620 :     const unsigned dim        = TopologyInfo::dimension( type );
      55                 :      16620 :     const unsigned per_vertex = dim + 1;
      56                 :            : 
      57                 :            :     unsigned i, j, num_adj;
      58                 :            :     const unsigned *adj_idx, *rev_idx;
      59                 :            : 
      60                 :            :     // NOTE: This function changes the corner_values array such that
      61                 :            :     //       it contains the gradient coefficients.
      62         [ +  - ]:      16620 :     double avg = average_metric_and_weights( corner_values, num_corner, err );
      63 [ +  - ][ -  + ]:      16620 :     MSQ_ERRZERO( err );
         [ #  # ][ #  # ]
                 [ -  + ]
      64                 :            : 
      65         [ +  + ]:     140066 :     for( i = 0; i < num_vertex; ++i )
      66                 :            :     {
      67         [ +  + ]:     123446 :         if( fixed_vertices & ( 1 << i ) )  // skip fixed vertices
      68                 :      41754 :             continue;
      69                 :            : 
      70         [ +  - ]:      81692 :         adj_idx = TopologyInfo::adjacent_vertices( type, i, num_adj );
      71         [ +  - ]:      81692 :         rev_idx = TopologyInfo::reverse_vertex_adjacency_offsets( type, i, num_adj );
      72         [ +  + ]:      81692 :         if( i < num_corner )  // not all vertices are corners (e.g. pyramid)
      73 [ +  - ][ +  - ]:      79320 :             vertex_grads[i] = corner_values[i] * corner_grads[per_vertex * i];
      74                 :            :         else
      75         [ +  - ]:       2372 :             vertex_grads[i] = 0;
      76         [ +  + ]:     327022 :         for( j = 0; j < num_adj; ++j )
      77                 :            :         {
      78                 :     245330 :             const unsigned v = adj_idx[j], c = rev_idx[j] + 1;
      79         [ +  + ]:     245330 :             if( v >= num_corner )  // if less corners than vertices (e.g. pyramid apex)
      80                 :       5171 :                 continue;
      81 [ +  - ][ +  - ]:     240159 :             vertex_grads[i] += corner_values[v] * corner_grads[per_vertex * v + c];
      82                 :            :         }
      83                 :            :     }
      84                 :            : 
      85                 :      16620 :     return avg;
      86                 :            : }
      87                 :            : 
      88                 :            : /**\brief Iterate over only diagonal blocks of element corner Hessian data
      89                 :            :  *
      90                 :            :  * Given concatenation of corner Hessian data for an element, iterate
      91                 :            :  * over only the diagonal terms for each corner.  This class allows
      92                 :            :  * common code to be used to generate Hessian diagonal blocks from either
      93                 :            :  * the diagonal blocks for each corner or the full Hessian data for each
      94                 :            :  * corner, where this class is used for the latter.
      95                 :            :  */
      96                 :            : class CornerHessDiagIterator
      97                 :            : {
      98                 :            :   private:
      99                 :            :     const Matrix3D* cornerHess;     //!< Current location in concatenated Hessian data.
     100                 :            :     const EntityTopology elemType;  //!< Element topology for Hessian data
     101                 :            :     unsigned mCorner;               //!< The element corner for which cornerHess
     102                 :            :                                     //!< is pointing into the corresponding Hessian data.
     103                 :            :     unsigned mStep;                 //!< Amount to step to reach next diagonal block.
     104                 :            :   public:
     105                 :          0 :     CornerHessDiagIterator( const Matrix3D* corner_hessians, EntityTopology elem_type )
     106                 :          0 :         : cornerHess( corner_hessians ), elemType( elem_type ), mCorner( 0 )
     107                 :            :     {
     108                 :          0 :         TopologyInfo::adjacent_vertices( elemType, mCorner, mStep );
     109                 :          0 :         ++mStep;
     110                 :          0 :     }
     111                 :            : 
     112                 :          0 :     SymMatrix3D operator*() const
     113                 :            :     {
     114                 :          0 :         return cornerHess->upper();
     115                 :            :     }
     116                 :            : 
     117                 :          0 :     CornerHessDiagIterator& operator++()
     118                 :            :     {
     119                 :          0 :         cornerHess += mStep;
     120         [ #  # ]:          0 :         if( !--mStep )
     121                 :            :         {
     122                 :          0 :             TopologyInfo::adjacent_vertices( elemType, ++mCorner, mStep );
     123                 :          0 :             ++mStep;
     124                 :            :         }
     125                 :          0 :         return *this;
     126                 :            :     }
     127                 :            : 
     128                 :            :     CornerHessDiagIterator operator++( int )
     129                 :            :     {
     130                 :            :         CornerHessDiagIterator copy( *this );
     131                 :            :         operator++();
     132                 :            :         return copy;
     133                 :            :     }
     134                 :            : };
     135                 :            : 
     136                 :            : template < typename HessIter >
     137                 :          0 : static inline double sum_corner_diagonals( EntityTopology type, unsigned num_corner, const double corner_values[],
     138                 :            :                                            const Vector3D corner_grads[], HessIter corner_diag_blocks,
     139                 :            :                                            Vector3D vertex_grads[], SymMatrix3D vertex_hessians[] )
     140                 :            : {
     141                 :            :     unsigned i, n, r, R, idx[4];
     142                 :            :     const unsigned* adj_list;
     143                 :          0 :     double avg = 0.0;
     144                 :            : 
     145                 :            :     // calculate mean
     146 [ #  # ][ #  # ]:          0 :     for( i = 0; i < num_corner; ++i )
     147                 :          0 :         avg += corner_values[i];
     148                 :            : 
     149                 :          0 :     const Vector3D* grad = corner_grads;
     150                 :          0 :     HessIter hess        = corner_diag_blocks;
     151 [ #  # ][ #  # ]:          0 :     for( i = 0; i < num_corner; ++i )
     152                 :            :     {
     153 [ #  # ][ #  # ]:          0 :         adj_list = TopologyInfo::adjacent_vertices( type, i, n );
     154                 :          0 :         idx[0]   = i;
     155                 :          0 :         idx[1]   = adj_list[0];
     156                 :          0 :         idx[2]   = adj_list[1];
     157                 :          0 :         idx[3]   = adj_list[2 % n];  // %n so don't read off end if 2D
     158                 :            : 
     159 [ #  # ][ #  # ]:          0 :         for( r = 0; r <= n; ++r )
     160                 :            :         {
     161                 :          0 :             R = idx[r];
     162 [ #  # ][ #  # ]:          0 :             vertex_grads[R] += *grad;
     163 [ #  # ][ #  # ]:          0 :             vertex_hessians[R] += *hess;
                 [ #  # ]
     164                 :          0 :             ++grad;
     165         [ #  # ]:          0 :             ++hess;
     166                 :            :         }
     167                 :            :     }
     168                 :          0 :     return avg;
     169                 :            : }
     170                 :            : 
     171                 :            : template < typename HessIter >
     172                 :          0 : static inline double sum_sqr_corner_diagonals( EntityTopology type, unsigned num_corner, const double corner_values[],
     173                 :            :                                                const Vector3D corner_grads[], HessIter corner_diag_blocks,
     174                 :            :                                                Vector3D vertex_grads[], SymMatrix3D vertex_hessians[] )
     175                 :            : {
     176                 :            :     unsigned i, n, r, R, idx[4];
     177                 :            :     const unsigned* adj_list;
     178                 :          0 :     double v, avg = 0.0;
     179                 :            : 
     180                 :            :     // calculate mean
     181 [ #  # ][ #  # ]:          0 :     for( i = 0; i < num_corner; ++i )
     182                 :          0 :         avg += corner_values[i] * corner_values[i];
     183                 :            : 
     184                 :          0 :     const Vector3D* grad = corner_grads;
     185                 :          0 :     HessIter hess        = corner_diag_blocks;
     186 [ #  # ][ #  # ]:          0 :     for( i = 0; i < num_corner; ++i )
     187                 :            :     {
     188 [ #  # ][ #  # ]:          0 :         adj_list = TopologyInfo::adjacent_vertices( type, i, n );
     189                 :          0 :         idx[0]   = i;
     190                 :          0 :         idx[1]   = adj_list[0];
     191                 :          0 :         idx[2]   = adj_list[1];
     192                 :          0 :         idx[3]   = adj_list[2 % n];  // %n so don't read off end if 2D
     193                 :          0 :         ++n;
     194                 :            : 
     195                 :          0 :         v = 2.0 * corner_values[i];
     196 [ #  # ][ #  # ]:          0 :         for( r = 0; r < n; ++r )
     197                 :            :         {
     198                 :          0 :             R = idx[r];
     199 [ #  # ][ #  # ]:          0 :             vertex_grads[R] += v * *grad;
         [ #  # ][ #  # ]
     200 [ #  # ][ #  # ]:          0 :             vertex_hessians[R] += 2.0 * outer( *grad );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     201 [ #  # ][ #  # ]:          0 :             vertex_hessians[R] += v * *hess;
         [ #  # ][ #  # ]
                 [ #  # ]
     202                 :          0 :             ++grad;
     203         [ #  # ]:          0 :             ++hess;
     204                 :            :         }
     205                 :            :     }
     206                 :          0 :     return avg;
     207                 :            : }
     208                 :            : 
     209                 :            : template < typename HessIter >
     210                 :          0 : static inline double pmean_corner_diagonals( EntityTopology type, unsigned num_corner, const double corner_values[],
     211                 :            :                                              const Vector3D corner_grads[], HessIter corner_diag_blocks,
     212                 :            :                                              Vector3D vertex_grads[], SymMatrix3D vertex_hessians[], double p )
     213                 :            : {
     214 [ #  # ][ #  # ]:          0 :     const unsigned N = TopologyInfo::corners( type );
     215                 :            :     unsigned i, n, r, R, idx[4];
     216                 :            :     const unsigned* adj_list;
     217                 :          0 :     double m = 0.0, nm;
     218                 :            :     double gf[8], hf[8];
     219                 :          0 :     double inv = 1.0 / num_corner;
     220 [ #  # ][ #  # ]:          0 :     assert( num_corner <= 8 );
     221                 :            : 
     222                 :            :     // calculate mean
     223 [ #  # ][ #  # ]:          0 :     for( i = 0; i < num_corner; ++i )
     224                 :            :     {
     225                 :          0 :         nm = pow( corner_values[i], p );
     226                 :          0 :         m += nm;
     227                 :            : 
     228                 :          0 :         gf[i] = inv * p * nm / corner_values[i];
     229                 :          0 :         hf[i] = ( p - 1 ) * gf[i] / corner_values[i];
     230                 :            :     }
     231                 :          0 :     nm = inv * m;
     232                 :            : 
     233                 :          0 :     const Vector3D* grad = corner_grads;
     234                 :          0 :     HessIter hess        = corner_diag_blocks;
     235 [ #  # ][ #  # ]:          0 :     for( i = 0; i < num_corner; ++i )
     236                 :            :     {
     237 [ #  # ][ #  # ]:          0 :         adj_list = TopologyInfo::adjacent_vertices( type, i, n );
     238                 :          0 :         idx[0]   = i;
     239                 :          0 :         idx[1]   = adj_list[0];
     240                 :          0 :         idx[2]   = adj_list[1];
     241                 :          0 :         idx[3]   = adj_list[2 % n];  // %n so don't read off end if 2D
     242                 :          0 :         ++n;
     243                 :            : 
     244 [ #  # ][ #  # ]:          0 :         for( r = 0; r < n; ++r )
     245                 :            :         {
     246                 :          0 :             R = idx[r];
     247 [ #  # ][ #  # ]:          0 :             vertex_grads[R] += gf[i] * *grad;
         [ #  # ][ #  # ]
     248 [ #  # ][ #  # ]:          0 :             vertex_hessians[R] += hf[i] * outer( *grad );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     249 [ #  # ][ #  # ]:          0 :             vertex_hessians[R] += gf[i] * *hess;
         [ #  # ][ #  # ]
                 [ #  # ]
     250                 :          0 :             ++grad;
     251         [ #  # ]:          0 :             ++hess;
     252                 :            :         }
     253                 :            :     }
     254                 :            : 
     255                 :          0 :     m     = pow( nm, 1.0 / p );
     256                 :          0 :     gf[0] = m / ( p * nm );
     257                 :          0 :     hf[0] = ( 1.0 / p - 1 ) * gf[0] / nm;
     258 [ #  # ][ #  # ]:          0 :     for( r = 0; r < N; ++r )
     259                 :            :     {
     260 [ #  # ][ #  # ]:          0 :         vertex_hessians[r] *= gf[0];
     261 [ #  # ][ #  # ]:          0 :         vertex_hessians[r] += hf[0] * outer( vertex_grads[r] );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     262 [ #  # ][ #  # ]:          0 :         vertex_grads[r] *= gf[0];
     263                 :            :     }
     264                 :            : 
     265                 :          0 :     return m;
     266                 :            : }
     267                 :            : 
     268                 :            : template < typename HessIter >
     269                 :          0 : static inline double average_corner_diagonals( EntityTopology type, QualityMetric::AveragingMethod method,
     270                 :            :                                                unsigned num_corner, const double corner_values[],
     271                 :            :                                                const Vector3D corner_grads[], HessIter corner_diag_blocks,
     272                 :            :                                                Vector3D vertex_grads[], SymMatrix3D vertex_hessians[], MsqError& err )
     273                 :            : {
     274                 :            :     unsigned i;
     275                 :            :     double avg, inv;
     276                 :            : 
     277                 :            :     // Zero gradients and Hessians
     278                 :          0 :     const unsigned num_vertex = TopologyInfo::corners( type );
     279 [ #  # ][ #  # ]:          0 :     for( i = 0; i < num_vertex; ++i )
     280                 :            :     {
     281 [ #  # ][ #  # ]:          0 :         vertex_grads[i].set( 0.0 );
     282                 :          0 :         vertex_hessians[i] = SymMatrix3D( 0.0 );
     283                 :            :     }
     284                 :            : 
     285   [ #  #  #  #  :          0 :     switch( method )
           #  #  # ][ #  
          #  #  #  #  #  
                      # ]
     286                 :            :     {
     287                 :            :         case QualityMetric::SUM:
     288                 :          0 :             avg = sum_corner_diagonals( type, num_corner, corner_values, corner_grads, corner_diag_blocks, vertex_grads,
     289                 :            :                                         vertex_hessians );
     290                 :          0 :             break;
     291                 :            : 
     292                 :            :         case QualityMetric::LINEAR:
     293                 :          0 :             avg = sum_corner_diagonals( type, num_corner, corner_values, corner_grads, corner_diag_blocks, vertex_grads,
     294                 :            :                                         vertex_hessians );
     295                 :          0 :             inv = 1.0 / num_corner;
     296                 :          0 :             avg *= inv;
     297 [ #  # ][ #  # ]:          0 :             for( i = 0; i < num_vertex; ++i )
     298                 :            :             {
     299                 :          0 :                 vertex_grads[i] *= inv;
     300                 :          0 :                 vertex_hessians[i] *= inv;
     301                 :            :             }
     302                 :          0 :             break;
     303                 :            : 
     304                 :            :         case QualityMetric::SUM_SQUARED:
     305                 :          0 :             avg = sum_sqr_corner_diagonals( type, num_corner, corner_values, corner_grads, corner_diag_blocks,
     306                 :            :                                             vertex_grads, vertex_hessians );
     307                 :          0 :             break;
     308                 :            : 
     309                 :            :         case QualityMetric::RMS:
     310                 :          0 :             avg = pmean_corner_diagonals( type, num_corner, corner_values, corner_grads, corner_diag_blocks,
     311                 :            :                                           vertex_grads, vertex_hessians, 2.0 );
     312                 :          0 :             break;
     313                 :            : 
     314                 :            :         case QualityMetric::HARMONIC:
     315                 :          0 :             avg = pmean_corner_diagonals( type, num_corner, corner_values, corner_grads, corner_diag_blocks,
     316                 :            :                                           vertex_grads, vertex_hessians, -1.0 );
     317                 :          0 :             break;
     318                 :            : 
     319                 :            :         case QualityMetric::HMS:
     320                 :          0 :             avg = pmean_corner_diagonals( type, num_corner, corner_values, corner_grads, corner_diag_blocks,
     321                 :            :                                           vertex_grads, vertex_hessians, -2.0 );
     322                 :          0 :             break;
     323                 :            : 
     324                 :            :         default:
     325 [ #  # ][ #  # ]:          0 :             MSQ_SETERR( err )( "averaging method not available.", MsqError::INVALID_STATE );
     326                 :          0 :             return 0.0;
     327                 :            :     }
     328                 :            : 
     329                 :          0 :     return avg;
     330                 :            : }
     331                 :            : 
     332                 :          0 : double AveragingQM::average_corner_hessian_diagonals( EntityTopology element_type, uint32_t, unsigned num_corners,
     333                 :            :                                                       const double corner_values[], const Vector3D corner_grads[],
     334                 :            :                                                       const Matrix3D corner_hessians[], Vector3D vertex_grads[],
     335                 :            :                                                       SymMatrix3D vertex_hessians[], MsqError& err )
     336                 :            : {
     337                 :            :     return average_corner_diagonals( element_type, avgMethod, num_corners, corner_values, corner_grads,
     338                 :            :                                      CornerHessDiagIterator( corner_hessians, element_type ), vertex_grads,
     339         [ #  # ]:          0 :                                      vertex_hessians, err );
     340                 :            : }
     341                 :            : 
     342                 :          0 : double AveragingQM::average_corner_hessian_diagonals( EntityTopology element_type, uint32_t, unsigned num_corners,
     343                 :            :                                                       const double corner_values[], const Vector3D corner_grads[],
     344                 :            :                                                       const SymMatrix3D corner_hess_diag[], Vector3D vertex_grads[],
     345                 :            :                                                       SymMatrix3D vertex_hessians[], MsqError& err )
     346                 :            : {
     347                 :            :     return average_corner_diagonals( element_type, avgMethod, num_corners, corner_values, corner_grads,
     348                 :          0 :                                      corner_hess_diag, vertex_grads, vertex_hessians, err );
     349                 :            : }
     350                 :            : 
     351                 :      14793 : static inline double sum_corner_hessians( EntityTopology type, unsigned num_corner, const double corner_values[],
     352                 :            :                                           const Vector3D corner_grads[], const Matrix3D corner_hessians[],
     353                 :            :                                           Vector3D vertex_grads[], Matrix3D vertex_hessians[] )
     354                 :            : {
     355         [ +  - ]:      14793 :     const unsigned N = TopologyInfo::corners( type );
     356                 :            :     unsigned i, n, r, c, R, C, idx[4];
     357                 :            :     const unsigned* adj_list;
     358                 :      14793 :     double avg = 0.0;
     359                 :            : 
     360                 :            :     // calculate mean
     361         [ +  + ]:     123649 :     for( i = 0; i < num_corner; ++i )
     362                 :     108856 :         avg += corner_values[i];
     363                 :            : 
     364                 :      14793 :     const Vector3D* grad = corner_grads;
     365                 :      14793 :     const Matrix3D* hess = corner_hessians;
     366         [ +  + ]:     123649 :     for( i = 0; i < num_corner; ++i )
     367                 :            :     {
     368         [ +  - ]:     108856 :         adj_list = TopologyInfo::adjacent_vertices( type, i, n );
     369                 :     108856 :         idx[0]   = i;
     370                 :     108856 :         idx[1]   = adj_list[0];
     371                 :     108856 :         idx[2]   = adj_list[1];
     372                 :     108856 :         idx[3]   = adj_list[2 % n];  // %n so don't read off end if 2D
     373                 :            : 
     374         [ +  + ]:     544280 :         for( r = 0; r <= n; ++r )
     375                 :            :         {
     376                 :     435424 :             R = idx[r];
     377         [ +  - ]:     435424 :             vertex_grads[R] += *grad;
     378                 :     435424 :             ++grad;
     379         [ +  + ]:    1523984 :             for( c = r; c <= n; ++c )
     380                 :            :             {
     381                 :    1088560 :                 C = idx[c];
     382         [ +  + ]:    1088560 :                 if( R <= C )
     383         [ +  - ]:     775828 :                     vertex_hessians[N * R - R * ( R + 1 ) / 2 + C] += *hess;
     384                 :            :                 else
     385         [ +  - ]:     312732 :                     vertex_hessians[N * C - C * ( C + 1 ) / 2 + R].plus_transpose_equal( *hess );
     386                 :    1088560 :                 ++hess;
     387                 :            :             }
     388                 :            :         }
     389                 :            :     }
     390                 :      14793 :     return avg;
     391                 :            : }
     392                 :            : 
     393                 :          0 : static inline double sum_sqr_corner_hessians( EntityTopology type, unsigned num_corner, const double corner_values[],
     394                 :            :                                               const Vector3D corner_grads[], const Matrix3D corner_hessians[],
     395                 :            :                                               Vector3D vertex_grads[], Matrix3D vertex_hessians[] )
     396                 :            : {
     397         [ #  # ]:          0 :     const unsigned N = TopologyInfo::corners( type );
     398                 :            :     unsigned i, n, r, c, R, C, idx[4];
     399                 :            :     const unsigned* adj_list;
     400                 :          0 :     double v, avg = 0.0;
     401         [ #  # ]:          0 :     Matrix3D op;
     402                 :            : 
     403                 :            :     // calculate mean
     404         [ #  # ]:          0 :     for( i = 0; i < num_corner; ++i )
     405                 :          0 :         avg += corner_values[i] * corner_values[i];
     406                 :            : 
     407                 :          0 :     const Vector3D* grad = corner_grads;
     408                 :          0 :     const Matrix3D* hess = corner_hessians;
     409         [ #  # ]:          0 :     for( i = 0; i < num_corner; ++i )
     410                 :            :     {
     411         [ #  # ]:          0 :         adj_list = TopologyInfo::adjacent_vertices( type, i, n );
     412                 :          0 :         idx[0]   = i;
     413                 :          0 :         idx[1]   = adj_list[0];
     414                 :          0 :         idx[2]   = adj_list[1];
     415                 :          0 :         idx[3]   = adj_list[2 % n];  // %n so don't read off end if 2D
     416                 :          0 :         ++n;
     417                 :            : 
     418                 :          0 :         v = 2.0 * corner_values[i];
     419         [ #  # ]:          0 :         for( r = 0; r < n; ++r )
     420                 :            :         {
     421                 :          0 :             R = idx[r];
     422 [ #  # ][ #  # ]:          0 :             vertex_grads[R] += v * grad[r];
     423         [ #  # ]:          0 :             for( c = r; c < n; ++c )
     424                 :            :             {
     425                 :          0 :                 C = idx[c];
     426 [ #  # ][ #  # ]:          0 :                 op.outer_product( 2.0 * grad[r], grad[c] );
     427 [ #  # ][ #  # ]:          0 :                 op += v * *hess;
     428         [ #  # ]:          0 :                 if( R <= C )
     429         [ #  # ]:          0 :                     vertex_hessians[N * R - R * ( R + 1 ) / 2 + C] += op;
     430                 :            :                 else
     431         [ #  # ]:          0 :                     vertex_hessians[N * C - C * ( C + 1 ) / 2 + R].plus_transpose_equal( op );
     432                 :          0 :                 ++hess;
     433                 :            :             }
     434                 :            :         }
     435                 :          0 :         grad += n;
     436                 :            :     }
     437                 :          0 :     return avg;
     438                 :            : }
     439                 :            : 
     440                 :          0 : static inline double pmean_corner_hessians( EntityTopology type, unsigned num_corner, const double corner_values[],
     441                 :            :                                             const Vector3D corner_grads[], const Matrix3D corner_hessians[],
     442                 :            :                                             Vector3D vertex_grads[], Matrix3D vertex_hessians[], double p )
     443                 :            : {
     444         [ #  # ]:          0 :     const unsigned N = TopologyInfo::corners( type );
     445                 :            :     unsigned i, n, r, c, R, C, idx[4];
     446                 :            :     const unsigned* adj_list;
     447                 :          0 :     double m = 0.0, nm;
     448         [ #  # ]:          0 :     Matrix3D op;
     449                 :            :     double gf[8], hf[8];
     450                 :          0 :     double inv = 1.0 / num_corner;
     451         [ #  # ]:          0 :     assert( num_corner <= 8 );
     452                 :            : 
     453                 :            :     // calculate mean
     454         [ #  # ]:          0 :     for( i = 0; i < num_corner; ++i )
     455                 :            :     {
     456                 :          0 :         nm = pow( corner_values[i], p );
     457                 :          0 :         m += nm;
     458                 :            : 
     459                 :          0 :         gf[i] = inv * p * nm / corner_values[i];
     460                 :          0 :         hf[i] = ( p - 1 ) * gf[i] / corner_values[i];
     461                 :            :     }
     462                 :          0 :     nm = inv * m;
     463                 :            : 
     464                 :          0 :     const Vector3D* grad = corner_grads;
     465                 :          0 :     const Matrix3D* hess = corner_hessians;
     466         [ #  # ]:          0 :     for( i = 0; i < num_corner; ++i )
     467                 :            :     {
     468         [ #  # ]:          0 :         adj_list = TopologyInfo::adjacent_vertices( type, i, n );
     469                 :          0 :         idx[0]   = i;
     470                 :          0 :         idx[1]   = adj_list[0];
     471                 :          0 :         idx[2]   = adj_list[1];
     472                 :          0 :         idx[3]   = adj_list[2 % n];  // %n so don't read off end if 2D
     473                 :          0 :         ++n;
     474                 :            : 
     475         [ #  # ]:          0 :         for( r = 0; r < n; ++r )
     476                 :            :         {
     477                 :          0 :             R = idx[r];
     478 [ #  # ][ #  # ]:          0 :             vertex_grads[R] += gf[i] * grad[r];
     479         [ #  # ]:          0 :             for( c = r; c < n; ++c )
     480                 :            :             {
     481                 :          0 :                 C = idx[c];
     482         [ #  # ]:          0 :                 op.outer_product( grad[r], grad[c] );
     483         [ #  # ]:          0 :                 op *= hf[i];
     484 [ #  # ][ #  # ]:          0 :                 op += gf[i] * *hess;
     485         [ #  # ]:          0 :                 if( R <= C )
     486         [ #  # ]:          0 :                     vertex_hessians[N * R - R * ( R + 1 ) / 2 + C] += op;
     487                 :            :                 else
     488         [ #  # ]:          0 :                     vertex_hessians[N * C - C * ( C + 1 ) / 2 + R].plus_transpose_equal( op );
     489                 :          0 :                 ++hess;
     490                 :            :             }
     491                 :            :         }
     492                 :          0 :         grad += n;
     493                 :            :     }
     494                 :            : 
     495                 :          0 :     m     = pow( nm, 1.0 / p );
     496                 :          0 :     gf[0] = m / ( p * nm );
     497                 :          0 :     hf[0] = ( 1.0 / p - 1 ) * gf[0] / nm;
     498         [ #  # ]:          0 :     for( r = 0; r < N; ++r )
     499                 :            :     {
     500         [ #  # ]:          0 :         for( c = r; c < N; ++c )
     501                 :            :         {
     502         [ #  # ]:          0 :             op.outer_product( vertex_grads[r], vertex_grads[c] );
     503         [ #  # ]:          0 :             op *= hf[0];
     504         [ #  # ]:          0 :             *vertex_hessians *= gf[0];
     505         [ #  # ]:          0 :             *vertex_hessians += op;
     506                 :          0 :             ++vertex_hessians;
     507                 :            :         }
     508         [ #  # ]:          0 :         vertex_grads[r] *= gf[0];
     509                 :            :     }
     510                 :            : 
     511                 :          0 :     return m;
     512                 :            : }
     513                 :            : 
     514                 :      14793 : double AveragingQM::average_corner_hessians( EntityTopology type, uint32_t, unsigned num_corner,
     515                 :            :                                              const double corner_values[], const Vector3D corner_grads[],
     516                 :            :                                              const Matrix3D corner_hessians[], Vector3D vertex_grads[],
     517                 :            :                                              Matrix3D vertex_hessians[], MsqError& err )
     518                 :            : {
     519                 :            :     unsigned i;
     520                 :            :     double avg, inv;
     521                 :            : 
     522                 :            :     // Zero gradients and Hessians
     523                 :      14793 :     const unsigned num_vertex = TopologyInfo::corners( type );
     524         [ +  + ]:     125955 :     for( i = 0; i < num_vertex; ++i )
     525         [ +  - ]:     111162 :         vertex_grads[i].set( 0.0 );
     526                 :      14793 :     const unsigned num_hess = num_vertex * ( num_vertex + 1 ) / 2;
     527         [ +  + ]:     496935 :     for( i = 0; i < num_hess; ++i )
     528                 :     482142 :         vertex_hessians[i].zero();
     529                 :            : 
     530   [ +  +  -  -  :      14793 :     switch( avgMethod )
                -  -  - ]
     531                 :            :     {
     532                 :            :         case QualityMetric::SUM:
     533                 :            :             avg = sum_corner_hessians( type, num_corner, corner_values, corner_grads, corner_hessians, vertex_grads,
     534                 :       9000 :                                        vertex_hessians );
     535                 :       9000 :             break;
     536                 :            : 
     537                 :            :         case QualityMetric::LINEAR:
     538                 :            :             avg = sum_corner_hessians( type, num_corner, corner_values, corner_grads, corner_hessians, vertex_grads,
     539                 :       5793 :                                        vertex_hessians );
     540                 :       5793 :             inv = 1.0 / num_corner;
     541                 :       5793 :             avg *= inv;
     542         [ +  + ]:      44955 :             for( i = 0; i < num_vertex; ++i )
     543                 :      39162 :                 vertex_grads[i] *= inv;
     544         [ +  + ]:     163935 :             for( i = 0; i < num_hess; ++i )
     545                 :     158142 :                 vertex_hessians[i] *= inv;
     546                 :       5793 :             break;
     547                 :            : 
     548                 :            :         case QualityMetric::SUM_SQUARED:
     549                 :            :             avg = sum_sqr_corner_hessians( type, num_corner, corner_values, corner_grads, corner_hessians, vertex_grads,
     550                 :          0 :                                            vertex_hessians );
     551                 :          0 :             break;
     552                 :            : 
     553                 :            :         case QualityMetric::RMS:
     554                 :            :             avg = pmean_corner_hessians( type, num_corner, corner_values, corner_grads, corner_hessians, vertex_grads,
     555                 :          0 :                                          vertex_hessians, 2.0 );
     556                 :          0 :             break;
     557                 :            : 
     558                 :            :         case QualityMetric::HARMONIC:
     559                 :            :             avg = pmean_corner_hessians( type, num_corner, corner_values, corner_grads, corner_hessians, vertex_grads,
     560                 :          0 :                                          vertex_hessians, -1.0 );
     561                 :          0 :             break;
     562                 :            : 
     563                 :            :         case QualityMetric::HMS:
     564                 :            :             avg = pmean_corner_hessians( type, num_corner, corner_values, corner_grads, corner_hessians, vertex_grads,
     565                 :          0 :                                          vertex_hessians, -2.0 );
     566                 :          0 :             break;
     567                 :            : 
     568                 :            :         default:
     569         [ #  # ]:          0 :             MSQ_SETERR( err )( "averaging method not available.", MsqError::INVALID_STATE );
     570                 :          0 :             return 0.0;
     571                 :            :     }
     572                 :            : 
     573                 :      14793 :     return avg;
     574                 :            : }
     575                 :            : 
     576                 :      16620 : double AveragingQM::average_metric_and_weights( double metrics[], int count, MsqError& err )
     577                 :            : {
     578                 :            :     static bool min_max_warning = false;
     579                 :      16620 :     double avg                  = 0.0;
     580                 :            :     int i, tmp_count;
     581                 :            :     double f;
     582                 :            : 
     583   [ -  -  +  -  :      16620 :     switch( avgMethod )
          +  -  -  -  -  
                      - ]
     584                 :            :     {
     585                 :            : 
     586                 :            :         case QualityMetric::MINIMUM:
     587         [ #  # ]:          0 :             if( !min_max_warning )
     588                 :            :             {
     589                 :            :                 MSQ_DBGOUT( 1 ) << "Minimum and maximum not continuously differentiable.\n"
     590                 :            :                                    "Element of subdifferential will be returned.\n";
     591                 :          0 :                 min_max_warning = true;
     592                 :            :             }
     593                 :            : 
     594                 :          0 :             avg = metrics[0];
     595         [ #  # ]:          0 :             for( i = 1; i < count; ++i )
     596         [ #  # ]:          0 :                 if( metrics[i] < avg ) avg = metrics[i];
     597                 :            : 
     598                 :          0 :             tmp_count = 0;
     599         [ #  # ]:          0 :             for( i = 0; i < count; ++i )
     600                 :            :             {
     601         [ #  # ]:          0 :                 if( metrics[i] - avg <= MSQ_MIN )
     602                 :            :                 {
     603                 :          0 :                     metrics[i] = 1.0;
     604                 :          0 :                     ++tmp_count;
     605                 :            :                 }
     606                 :            :                 else
     607                 :            :                 {
     608                 :          0 :                     metrics[i] = 0.0;
     609                 :            :                 }
     610                 :            :             }
     611                 :            : 
     612                 :          0 :             f = 1.0 / tmp_count;
     613         [ #  # ]:          0 :             for( i = 0; i < count; ++i )
     614                 :          0 :                 metrics[i] *= f;
     615                 :            : 
     616                 :          0 :             break;
     617                 :            : 
     618                 :            :         case QualityMetric::MAXIMUM:
     619         [ #  # ]:          0 :             if( !min_max_warning )
     620                 :            :             {
     621                 :            :                 MSQ_DBGOUT( 1 ) << "Minimum and maximum not continuously differentiable.\n"
     622                 :            :                                    "Element of subdifferential will be returned.\n";
     623                 :          0 :                 min_max_warning = true;
     624                 :            :             }
     625                 :            : 
     626                 :          0 :             avg = metrics[0];
     627         [ #  # ]:          0 :             for( i = 1; i < count; ++i )
     628         [ #  # ]:          0 :                 if( metrics[i] > avg ) avg = metrics[i];
     629                 :            : 
     630                 :          0 :             tmp_count = 0;
     631         [ #  # ]:          0 :             for( i = 0; i < count; ++i )
     632                 :            :             {
     633         [ #  # ]:          0 :                 if( avg - metrics[i] <= MSQ_MIN )
     634                 :            :                 {
     635                 :          0 :                     metrics[i] = 1.0;
     636                 :          0 :                     ++tmp_count;
     637                 :            :                 }
     638                 :            :                 else
     639                 :            :                 {
     640                 :          0 :                     metrics[i] = 0.0;
     641                 :            :                 }
     642                 :            :             }
     643                 :            : 
     644                 :          0 :             f = 1.0 / tmp_count;
     645         [ #  # ]:          0 :             for( i = 0; i < count; ++i )
     646                 :          0 :                 metrics[i] *= f;
     647                 :            : 
     648                 :          0 :             break;
     649                 :            : 
     650                 :            :         case QualityMetric::SUM:
     651         [ +  + ]:      90000 :             for( i = 0; i < count; ++i )
     652                 :            :             {
     653                 :      80000 :                 avg += metrics[i];
     654                 :      80000 :                 metrics[i] = 1.0;
     655                 :            :             }
     656                 :            : 
     657                 :      10000 :             break;
     658                 :            : 
     659                 :            :         case QualityMetric::SUM_SQUARED:
     660         [ #  # ]:          0 :             for( i = 0; i < count; ++i )
     661                 :            :             {
     662                 :          0 :                 avg += ( metrics[i] * metrics[i] );
     663                 :          0 :                 metrics[i] *= 2;
     664                 :            :             }
     665                 :            : 
     666                 :          0 :             break;
     667                 :            : 
     668                 :            :         case QualityMetric::LINEAR:
     669                 :       6620 :             f = 1.0 / count;
     670         [ +  + ]:      47694 :             for( i = 0; i < count; ++i )
     671                 :            :             {
     672                 :      41074 :                 avg += metrics[i];
     673                 :      41074 :                 metrics[i] = f;
     674                 :            :             }
     675                 :       6620 :             avg *= f;
     676                 :            : 
     677                 :       6620 :             break;
     678                 :            : 
     679                 :            :         case QualityMetric::GEOMETRIC:
     680                 :          0 :             avg = 1.0;
     681         [ #  # ]:          0 :             for( i = 0; i < count; ++i )
     682                 :          0 :                 avg *= metrics[i];
     683                 :          0 :             avg = pow( avg, 1.0 / count );
     684                 :            : 
     685                 :          0 :             f = avg / count;
     686         [ #  # ]:          0 :             for( i = 0; i < count; ++i )
     687                 :          0 :                 metrics[i] = f / metrics[i];
     688                 :            : 
     689                 :          0 :             break;
     690                 :            : 
     691                 :            :         case QualityMetric::RMS:
     692         [ #  # ]:          0 :             for( i = 0; i < count; ++i )
     693                 :          0 :                 avg += metrics[i] * metrics[i];
     694                 :          0 :             avg = sqrt( avg / count );
     695                 :            : 
     696                 :          0 :             f = 1. / ( avg * count );
     697         [ #  # ]:          0 :             for( i = 0; i < count; ++i )
     698                 :          0 :                 metrics[i] *= f;
     699                 :            : 
     700                 :          0 :             break;
     701                 :            : 
     702                 :            :         case QualityMetric::HARMONIC:
     703         [ #  # ]:          0 :             for( i = 0; i < count; ++i )
     704                 :          0 :                 avg += 1.0 / metrics[i];
     705                 :          0 :             avg = count / avg;
     706                 :            : 
     707         [ #  # ]:          0 :             for( i = 0; i < count; ++i )
     708                 :          0 :                 metrics[i] = ( avg * avg ) / ( count * metrics[i] * metrics[i] );
     709                 :            : 
     710                 :          0 :             break;
     711                 :            : 
     712                 :            :         case QualityMetric::HMS:
     713         [ #  # ]:          0 :             for( i = 0; i < count; ++i )
     714                 :          0 :                 avg += 1. / ( metrics[i] * metrics[i] );
     715                 :          0 :             avg = sqrt( count / avg );
     716                 :            : 
     717                 :          0 :             f = avg * avg * avg / count;
     718         [ #  # ]:          0 :             for( i = 0; i < count; ++i )
     719                 :          0 :                 metrics[i] = f / ( metrics[i] * metrics[i] * metrics[i] );
     720                 :            : 
     721                 :          0 :             break;
     722                 :            : 
     723                 :            :         default:
     724         [ #  # ]:          0 :             MSQ_SETERR( err )( "averaging method not available.", MsqError::INVALID_STATE );
     725                 :            :     }
     726                 :            : 
     727                 :      16620 :     return avg;
     728                 :            : }
     729                 :            : 
     730                 :            : /*!
     731                 :            :   average_metrics takes an array of length num_value and averages the
     732                 :            :   contents using averaging method 'method'.
     733                 :            : */
     734                 :    1164539 : double AveragingQM::average_metrics( const double metric_values[], int num_values, MsqError& err )
     735                 :            : {
     736                 :            :     // MSQ_MAX needs to be made global?
     737                 :            :     // double MSQ_MAX=1e10;
     738                 :    1164539 :     double total_value = 0.0;
     739                 :    1164539 :     double temp_value  = 0.0;
     740                 :    1164539 :     int i              = 0;
     741                 :    1164539 :     int j              = 0;
     742                 :            :     // if no values, return zero
     743         [ -  + ]:    1164539 :     if( num_values <= 0 ) { return 0.0; }
     744                 :            : 
     745   [ -  -  +  -  :    1164539 :     switch( avgMethod )
          -  +  -  -  +  
             -  -  -  -  
                      - ]
     746                 :            :     {
     747                 :            :         case QualityMetric::GEOMETRIC:
     748                 :          0 :             total_value = 1.0;
     749         [ #  # ]:          0 :             for( i = 0; i < num_values; ++i )
     750                 :            :             {
     751                 :          0 :                 total_value *= ( metric_values[i] );
     752                 :            :             }
     753                 :          0 :             total_value = pow( total_value, 1.0 / num_values );
     754                 :          0 :             break;
     755                 :            : 
     756                 :            :         case QualityMetric::HARMONIC:
     757                 :            :             // ensure no divide by zero, return zero
     758         [ #  # ]:          0 :             for( i = 0; i < num_values; ++i )
     759                 :            :             {
     760         [ #  # ]:          0 :                 if( metric_values[i] < MSQ_MIN )
     761                 :            :                 {
     762         [ #  # ]:          0 :                     if( metric_values[i] > MSQ_MIN ) { return 0.0; }
     763                 :            :                 }
     764                 :          0 :                 total_value += ( 1 / metric_values[i] );
     765                 :            :             }
     766                 :            :             // ensure no divide by zero, return MSQ_MAX_CAP
     767         [ #  # ]:          0 :             if( total_value < MSQ_MIN )
     768                 :            :             {
     769         [ #  # ]:          0 :                 if( total_value > MSQ_MIN ) { return MSQ_MAX_CAP; }
     770                 :            :             }
     771                 :          0 :             total_value = num_values / total_value;
     772                 :          0 :             break;
     773                 :            : 
     774                 :            :         case QualityMetric::LINEAR:
     775         [ +  + ]:     159574 :             for( i = 0; i < num_values; ++i )
     776                 :            :             {
     777                 :     130956 :                 total_value += metric_values[i];
     778                 :            :             }
     779                 :      28618 :             total_value /= (double)num_values;
     780                 :      28618 :             break;
     781                 :            : 
     782                 :            :         case QualityMetric::MAXIMUM:
     783                 :          0 :             total_value = metric_values[0];
     784         [ #  # ]:          0 :             for( i = 1; i < num_values; ++i )
     785                 :            :             {
     786         [ #  # ]:          0 :                 if( metric_values[i] > total_value ) { total_value = metric_values[i]; }
     787                 :            :             }
     788                 :          0 :             break;
     789                 :            : 
     790                 :            :         case QualityMetric::MINIMUM:
     791                 :          0 :             total_value = metric_values[0];
     792         [ #  # ]:          0 :             for( i = 1; i < num_values; ++i )
     793                 :            :             {
     794         [ #  # ]:          0 :                 if( metric_values[i] < total_value ) { total_value = metric_values[i]; }
     795                 :            :             }
     796                 :          0 :             break;
     797                 :            : 
     798                 :            :         case QualityMetric::RMS:
     799         [ +  + ]:    8472945 :             for( i = 0; i < num_values; ++i )
     800                 :            :             {
     801                 :    7343024 :                 total_value += ( metric_values[i] * metric_values[i] );
     802                 :            :             }
     803                 :    1129921 :             total_value /= (double)num_values;
     804                 :    1129921 :             total_value = sqrt( total_value );
     805                 :    1129921 :             break;
     806                 :            : 
     807                 :            :         case QualityMetric::HMS:
     808                 :            :             // ensure no divide by zero, return zero
     809         [ #  # ]:          0 :             for( i = 0; i < num_values; ++i )
     810                 :            :             {
     811         [ #  # ]:          0 :                 if( metric_values[i] * metric_values[i] < MSQ_MIN ) { return 0.0; }
     812                 :          0 :                 total_value += ( 1.0 / ( metric_values[i] * metric_values[i] ) );
     813                 :            :             }
     814                 :            : 
     815                 :            :             // ensure no divide by zero, return MSQ_MAX_CAP
     816         [ #  # ]:          0 :             if( total_value < MSQ_MIN ) { return MSQ_MAX_CAP; }
     817                 :          0 :             total_value = sqrt( num_values / total_value );
     818                 :          0 :             break;
     819                 :            : 
     820                 :            :         case QualityMetric::STANDARD_DEVIATION:
     821                 :          0 :             total_value = 0;
     822                 :          0 :             temp_value  = 0;
     823         [ #  # ]:          0 :             for( i = 0; i < num_values; ++i )
     824                 :            :             {
     825                 :          0 :                 temp_value += metric_values[i];
     826                 :          0 :                 total_value += ( metric_values[i] * metric_values[i] );
     827                 :            :             }
     828                 :          0 :             temp_value /= (double)num_values;
     829                 :          0 :             temp_value *= temp_value;
     830                 :          0 :             total_value /= (double)num_values;
     831                 :          0 :             total_value = total_value - temp_value;
     832                 :          0 :             break;
     833                 :            : 
     834                 :            :         case QualityMetric::SUM:
     835         [ +  + ]:      54000 :             for( i = 0; i < num_values; ++i )
     836                 :            :             {
     837                 :      48000 :                 total_value += metric_values[i];
     838                 :            :             }
     839                 :       6000 :             break;
     840                 :            : 
     841                 :            :         case QualityMetric::SUM_SQUARED:
     842         [ #  # ]:          0 :             for( i = 0; i < num_values; ++i )
     843                 :            :             {
     844                 :          0 :                 total_value += ( metric_values[i] * metric_values[i] );
     845                 :            :             }
     846                 :          0 :             break;
     847                 :            : 
     848                 :            :         case QualityMetric::MAX_MINUS_MIN:
     849                 :            :             // total_value used to store the maximum
     850                 :            :             // temp_value used to store the minimum
     851                 :          0 :             temp_value = MSQ_MAX_CAP;
     852         [ #  # ]:          0 :             for( i = 0; i < num_values; ++i )
     853                 :            :             {
     854         [ #  # ]:          0 :                 if( metric_values[i] < temp_value ) { temp_value = metric_values[i]; }
     855         [ #  # ]:          0 :                 if( metric_values[i] > total_value ) { total_value = metric_values[i]; }
     856                 :            :             }
     857                 :            : 
     858                 :          0 :             total_value -= temp_value;
     859                 :          0 :             break;
     860                 :            : 
     861                 :            :         case QualityMetric::MAX_OVER_MIN:
     862                 :            :             // total_value used to store the maximum
     863                 :            :             // temp_value used to store the minimum
     864                 :          0 :             temp_value = MSQ_MAX_CAP;
     865         [ #  # ]:          0 :             for( i = 0; i < num_values; ++i )
     866                 :            :             {
     867         [ #  # ]:          0 :                 if( metric_values[i] < temp_value ) { temp_value = metric_values[i]; }
     868         [ #  # ]:          0 :                 if( metric_values[i] > total_value ) { total_value = metric_values[i]; }
     869                 :            :             }
     870                 :            : 
     871                 :            :             // ensure no divide by zero, return MSQ_MAX_CAP
     872         [ #  # ]:          0 :             if( fabs( temp_value ) < MSQ_MIN ) { return MSQ_MAX_CAP; }
     873                 :          0 :             total_value /= temp_value;
     874                 :          0 :             break;
     875                 :            : 
     876                 :            :         case QualityMetric::SUM_OF_RATIOS_SQUARED:
     877         [ #  # ]:          0 :             for( j = 0; j < num_values; ++j )
     878                 :            :             {
     879                 :            :                 // ensure no divide by zero, return MSQ_MAX_CAP
     880         [ #  # ]:          0 :                 if( fabs( metric_values[j] ) < MSQ_MIN ) { return MSQ_MAX_CAP; }
     881         [ #  # ]:          0 :                 for( i = 0; i < num_values; ++i )
     882                 :            :                 {
     883                 :            :                     total_value +=
     884                 :          0 :                         ( ( metric_values[i] / metric_values[j] ) * ( metric_values[i] / metric_values[j] ) );
     885                 :            :                 }
     886                 :            :             }
     887                 :          0 :             total_value /= (double)( num_values * num_values );
     888                 :          0 :             break;
     889                 :            : 
     890                 :            :         default:
     891                 :            :             // Return error saying Averaging Method mode not implemented
     892                 :            :             MSQ_SETERR( err )
     893         [ #  # ]:          0 :             ( "Requested Averaging Method Not Implemented", MsqError::NOT_IMPLEMENTED );
     894                 :          0 :             return 0;
     895                 :            :     }
     896                 :    1164539 :     return total_value;
     897                 :            : }
     898                 :            : 
     899 [ +  - ][ +  - ]:         76 : }  // namespace MBMesquite

Generated by: LCOV version 1.11