LCOV - code coverage report
Current view: top level - src/mesquite/QualityMetric - QualityMetric.cpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 135 181 74.6 %
Date: 2020-07-18 00:09:26 Functions: 10 13 76.9 %
Branches: 147 338 43.5 %

           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                 :            :     [email protected]
      26                 :            : 
      27                 :            :   ***************************************************************** */
      28                 :            : /*!
      29                 :            :   \file   QualityMetric.cpp
      30                 :            :   \brief
      31                 :            : 
      32                 :            :   \author Michael Brewer
      33                 :            :   \author Thomas Leurent
      34                 :            :   \date   2002-05-14
      35                 :            :   \author Jason Kraftcheck
      36                 :            :   \date   2006-04-20
      37                 :            : */
      38                 :            : 
      39                 :            : #include "QualityMetric.hpp"
      40                 :            : #include "MsqVertex.hpp"
      41                 :            : #include "PatchData.hpp"
      42                 :            : 
      43                 :            : namespace MBMesquite
      44                 :            : {
      45                 :            : 
      46                 :        209 : void QualityMetric::initialize_queue( MeshDomainAssoc*, const Settings*, MsqError& ) {}
      47                 :            : 
      48                 :     343959 : void QualityMetric::get_single_pass( PatchData& pd, std::vector< size_t >& handles, bool free_vertices_only,
      49                 :            :                                      MsqError& err )
      50                 :            : {
      51                 :     343959 :     get_evaluations( pd, handles, free_vertices_only, err );
      52                 :     343959 : }
      53                 :            : 
      54                 :     986140 : static inline double get_delta_C( const PatchData& pd, const std::vector< size_t >& indices, MsqError& err )
      55                 :            : {
      56         [ -  + ]:     986140 :     if( indices.empty() )
      57                 :            :     {
      58 [ #  # ][ #  # ]:          0 :         MSQ_SETERR( err )( MsqError::INVALID_ARG );
      59                 :          0 :         return 0.0;
      60                 :            :     }
      61                 :            : 
      62                 :     986140 :     std::vector< size_t >::const_iterator beg, iter, iter2, end;
      63                 :            : 
      64         [ +  - ]:     986140 :     std::vector< size_t > tmp_vect;
      65         [ +  + ]:     986140 :     if( indices.size() == 1u )
      66                 :            :     {
      67 [ +  - ][ +  - ]:     362937 :         pd.get_adjacent_vertex_indices( indices.front(), tmp_vect, err );
      68 [ +  - ][ -  + ]:     362937 :         MSQ_ERRZERO( err );
         [ #  # ][ #  # ]
                 [ -  + ]
      69         [ -  + ]:     362937 :         assert( !tmp_vect.empty() );
      70 [ +  - ][ +  - ]:     362937 :         tmp_vect.push_back( indices.front() );
      71         [ +  - ]:     362937 :         beg = tmp_vect.begin();
      72         [ +  - ]:     362937 :         end = tmp_vect.end();
      73                 :            :     }
      74                 :            :     else
      75                 :            :     {
      76                 :     623203 :         beg = indices.begin();
      77                 :     623203 :         end = indices.end();
      78                 :            :     }
      79                 :            : 
      80                 :     986140 :     double min_dist_sqr = HUGE_VAL, sum_dist_sqr = 0.0;
      81 [ +  - ][ +  - ]:    7962343 :     for( iter = beg; iter != end; ++iter )
                 [ +  + ]
      82                 :            :     {
      83 [ +  - ][ +  - ]:   45425677 :         for( iter2 = iter + 1; iter2 != end; ++iter2 )
         [ +  - ][ +  + ]
      84                 :            :         {
      85 [ +  - ][ +  - ]:   38449474 :             Vector3D diff = pd.vertex_by_index( *iter );
                 [ +  - ]
      86 [ +  - ][ +  - ]:   38449474 :             diff -= pd.vertex_by_index( *iter2 );
                 [ +  - ]
      87         [ +  - ]:   38449474 :             double dist_sqr = diff % diff;
      88         [ +  + ]:   38449474 :             if( dist_sqr < min_dist_sqr ) min_dist_sqr = dist_sqr;
      89                 :   38449474 :             sum_dist_sqr += dist_sqr;
      90                 :            :         }
      91                 :            :     }
      92                 :            : 
      93         [ +  - ]:     986140 :     return 3e-6 * sqrt( min_dist_sqr ) + 5e-7 * sqrt( sum_dist_sqr / ( end - beg ) );
      94                 :            : }
      95                 :            : 
      96                 :     441653 : bool QualityMetric::evaluate_with_gradient( PatchData& pd, size_t handle, double& value, std::vector< size_t >& indices,
      97                 :            :                                             std::vector< Vector3D >& gradient, MsqError& err )
      98                 :            : {
      99                 :     441653 :     indices.clear();
     100                 :     441653 :     bool valid = evaluate_with_indices( pd, handle, value, indices, err );
     101 [ -  + ][ #  # ]:     441653 :     if( MSQ_CHKERR( err ) || !valid ) return false;
         [ -  + ][ -  + ]
     102         [ +  + ]:     441653 :     if( indices.empty() ) return true;
     103                 :            : 
     104                 :            :     // get initial pertubation amount
     105                 :     441284 :     double delta_C = finiteDiffEps;
     106         [ +  + ]:     441284 :     if( !haveFiniteDiffEps )
     107                 :            :     {
     108                 :     440384 :         delta_C = get_delta_C( pd, indices, err );
     109 [ -  + ][ #  # ]:     440384 :         MSQ_ERRZERO( err );
                 [ -  + ]
     110         [ +  + ]:     440384 :         if( keepFiniteDiffEps )
     111                 :            :         {
     112                 :        222 :             finiteDiffEps     = delta_C;
     113                 :        222 :             haveFiniteDiffEps = true;
     114                 :            :         }
     115                 :            :     }
     116                 :     441284 :     const double delta_inv_C  = 1.0 / delta_C;
     117                 :     441284 :     const int reduction_limit = 15;
     118                 :            : 
     119                 :     441284 :     gradient.resize( indices.size() );
     120         [ +  + ]:    1049290 :     for( size_t v = 0; v < indices.size(); ++v )
     121                 :            :     {
     122 [ +  - ][ +  - ]:     608006 :         const Vector3D pos = pd.vertex_by_index( indices[v] );
                 [ +  - ]
     123                 :            : 
     124                 :            :         /* gradient in the x, y, z direction */
     125         [ +  + ]:    2432024 :         for( int j = 0; j < 3; ++j )
     126                 :            :         {
     127                 :    1824018 :             double delta     = delta_C;
     128                 :    1824018 :             double delta_inv = delta_inv_C;
     129                 :            :             double metric_value;
     130         [ +  - ]:    1824018 :             Vector3D delta_v( 0, 0, 0 );
     131                 :            : 
     132                 :            :             // perturb the node and calculate gradient.  The while loop is a
     133                 :            :             // safety net to make sure the epsilon perturbation does not take
     134                 :            :             // the element out of the feasible region.
     135                 :    1824018 :             int counter = 0;
     136                 :            :             for( ;; )
     137                 :            :             {
     138                 :            :                 // perturb the coordinates of the free vertex in the j direction
     139                 :            :                 // by delta
     140         [ +  - ]:    1824018 :                 delta_v[j] = delta;
     141 [ +  - ][ +  - ]:    1824018 :                 pd.set_vertex_coordinates( pos + delta_v, indices[v], err );
                 [ +  - ]
     142 [ +  - ][ -  + ]:    1824018 :                 MSQ_ERRZERO( err );
         [ #  # ][ #  # ]
                 [ -  + ]
     143                 :            : 
     144                 :            :                 // compute the function at the perturbed point location
     145         [ +  - ]:    1824018 :                 valid = evaluate( pd, handle, metric_value, err );
     146 [ +  - ][ -  + ]:    1824018 :                 if( !MSQ_CHKERR( err ) && valid ) break;
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
     147                 :            : 
     148         [ #  # ]:          0 :                 if( ++counter >= reduction_limit )
     149                 :            :                 {
     150                 :            :                     MSQ_SETERR( err )
     151 [ #  # ][ #  # ]:          0 :                     ( "Perturbing vertex by delta caused an inverted element.", MsqError::INTERNAL_ERROR );
     152                 :          0 :                     return false;
     153                 :            :                 }
     154                 :            : 
     155                 :          0 :                 delta *= 0.1;
     156                 :          0 :                 delta_inv *= 10.;
     157                 :            :             }
     158                 :            :             // put the coordinates back where they belong
     159 [ +  - ][ +  - ]:    1824018 :             pd.set_vertex_coordinates( pos, indices[v], err );
     160                 :            :             // compute the numerical gradient
     161 [ +  - ][ +  - ]:    1824018 :             gradient[v][j] = ( metric_value - value ) * delta_inv;
     162                 :          0 :         }  // for(j)
     163                 :            :     }      // for(indices)
     164                 :     441653 :     return true;
     165                 :            : }
     166                 :            : 
     167                 :     546922 : bool QualityMetric::evaluate_with_Hessian( PatchData& pd, size_t handle, double& value, std::vector< size_t >& indices,
     168                 :            :                                            std::vector< Vector3D >& gradient, std::vector< Matrix3D >& Hessian,
     169                 :            :                                            MsqError& err )
     170                 :            : {
     171                 :     546922 :     indices.clear();
     172                 :     546922 :     gradient.clear();
     173                 :     546922 :     keepFiniteDiffEps = true;
     174         [ +  - ]:     546922 :     bool valid        = evaluate_with_gradient( pd, handle, value, indices, gradient, err );
     175                 :     546922 :     keepFiniteDiffEps = false;
     176 [ +  - ][ -  + ]:     546922 :     if( MSQ_CHKERR( err ) || !valid )
         [ #  # ][ #  # ]
         [ -  + ][ -  + ]
     177                 :            :     {
     178                 :          0 :         haveFiniteDiffEps = false;
     179                 :          0 :         return false;
     180                 :            :     }
     181         [ +  + ]:     546922 :     if( indices.empty() )
     182                 :            :     {
     183                 :        944 :         haveFiniteDiffEps = false;
     184                 :        944 :         return true;
     185                 :            :     }
     186                 :            : 
     187                 :            :     // get initial pertubation amount
     188                 :            :     double delta_C;
     189         [ +  + ]:     545978 :     if( haveFiniteDiffEps ) { delta_C = finiteDiffEps; }
     190                 :            :     else
     191                 :            :     {
     192         [ +  - ]:     545756 :         delta_C = get_delta_C( pd, indices, err );
     193 [ +  - ][ -  + ]:     545756 :         MSQ_ERRZERO( err );
         [ #  # ][ #  # ]
                 [ -  + ]
     194                 :            :     }
     195         [ -  + ]:     545978 :     assert( delta_C < 1e30 );
     196                 :     545978 :     const double delta_inv_C  = 1.0 / delta_C;
     197                 :     545978 :     const int reduction_limit = 15;
     198                 :            : 
     199         [ +  - ]:     545978 :     std::vector< Vector3D > temp_gradient( indices.size() );
     200                 :     545978 :     const int num_hess = indices.size() * ( indices.size() + 1 ) / 2;
     201         [ +  - ]:     545978 :     Hessian.resize( num_hess );
     202                 :            : 
     203         [ +  + ]:    2141134 :     for( unsigned v = 0; v < indices.size(); ++v )
     204                 :            :     {
     205 [ +  - ][ +  - ]:    1595156 :         const Vector3D pos = pd.vertex_by_index( indices[v] );
                 [ +  - ]
     206         [ +  + ]:    6380624 :         for( int j = 0; j < 3; ++j )
     207                 :            :         {  // x, y, and z
     208                 :    4785468 :             double delta     = delta_C;
     209                 :    4785468 :             double delta_inv = delta_inv_C;
     210                 :            :             double metric_value;
     211         [ +  - ]:    4785468 :             Vector3D delta_v( 0, 0, 0 );
     212                 :            : 
     213                 :            :             // find finite difference for gradient
     214                 :    4785468 :             int counter = 0;
     215                 :            :             for( ;; )
     216                 :            :             {
     217         [ +  - ]:    4785468 :                 delta_v[j] = delta;
     218 [ +  - ][ +  - ]:    4785468 :                 pd.set_vertex_coordinates( pos + delta_v, indices[v], err );
                 [ +  - ]
     219 [ +  - ][ -  + ]:    4785468 :                 MSQ_ERRZERO( err );
         [ #  # ][ #  # ]
                 [ -  + ]
     220         [ +  - ]:    4785468 :                 valid = evaluate_with_gradient( pd, handle, metric_value, indices, temp_gradient, err );
     221 [ +  - ][ -  + ]:    4785468 :                 if( !MSQ_CHKERR( err ) && valid ) break;
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
     222                 :            : 
     223         [ #  # ]:          0 :                 if( ++counter >= reduction_limit )
     224                 :            :                 {
     225                 :            :                     MSQ_SETERR( err )
     226                 :            :                     ( "Algorithm did not successfully compute element's "
     227                 :            :                       "Hessian.\n",
     228 [ #  # ][ #  # ]:          0 :                       MsqError::INTERNAL_ERROR );
     229                 :          0 :                     haveFiniteDiffEps = false;
     230                 :          0 :                     return false;
     231                 :            :                 }
     232                 :            : 
     233                 :          0 :                 delta *= 0.1;
     234                 :          0 :                 delta_inv *= 10.0;
     235                 :            :             }
     236 [ +  - ][ +  - ]:    4785468 :             pd.set_vertex_coordinates( pos, indices[v], err );
     237 [ +  - ][ -  + ]:    4785468 :             MSQ_ERRZERO( err );
         [ #  # ][ #  # ]
                 [ -  + ]
     238                 :            : 
     239                 :            :             // compute the numerical Hessian
     240         [ +  + ]:   14273523 :             for( unsigned w = 0; w <= v; ++w )
     241                 :            :             {
     242                 :            :                 // finite difference to get some entries of the Hessian
     243 [ +  - ][ +  - ]:    9488055 :                 Vector3D fd( temp_gradient[w] );
     244 [ +  - ][ +  - ]:    9488055 :                 fd -= gradient[w];
     245         [ +  - ]:    9488055 :                 fd *= delta_inv;
     246                 :            :                 // For the block at position w,v in a matrix, we need the corresponding index
     247                 :            :                 // (mat_index) in a 1D array containing only upper triangular blocks.
     248                 :    9488055 :                 unsigned sum_w           = w * ( w + 1 ) / 2;  // 1+2+3+...+w
     249                 :    9488055 :                 unsigned mat_index       = w * indices.size() + v - sum_w;
     250 [ +  - ][ +  - ]:    9488055 :                 Hessian[mat_index][0][j] = fd[0];
                 [ +  - ]
     251 [ +  - ][ +  - ]:    9488055 :                 Hessian[mat_index][1][j] = fd[1];
                 [ +  - ]
     252 [ +  - ][ +  - ]:    9488055 :                 Hessian[mat_index][2][j] = fd[2];
                 [ +  - ]
     253                 :            :             }
     254                 :          0 :         }  // for(j)
     255                 :            :     }      // for(indices)
     256                 :     545978 :     haveFiniteDiffEps = false;
     257                 :     546922 :     return true;
     258                 :            : }
     259                 :            : 
     260                 :          0 : bool QualityMetric::evaluate_with_Hessian_diagonal( PatchData& pd, size_t handle, double& value,
     261                 :            :                                                     std::vector< size_t >& indices, std::vector< Vector3D >& gradient,
     262                 :            :                                                     std::vector< SymMatrix3D >& Hessian_diagonal, MsqError& err )
     263                 :            : {
     264         [ #  # ]:          0 :     bool rval = evaluate_with_Hessian( pd, handle, value, indices, gradient, tmpHess, err );
     265 [ #  # ][ #  # ]:          0 :     if( MSQ_CHKERR( err ) || !rval ) return rval;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     266                 :          0 :     size_t s = indices.size();
     267         [ #  # ]:          0 :     Hessian_diagonal.resize( s );
     268         [ #  # ]:          0 :     std::vector< Matrix3D >::const_iterator h = tmpHess.begin();
     269         [ #  # ]:          0 :     for( size_t i = 0; i < indices.size(); ++i )
     270                 :            :     {
     271 [ #  # ][ #  # ]:          0 :         Hessian_diagonal[i] = h->upper();
                 [ #  # ]
     272         [ #  # ]:          0 :         h += s--;
     273                 :            :     }
     274                 :          0 :     return rval;
     275                 :            : }
     276                 :            : 
     277                 :     292591 : uint32_t QualityMetric::fixed_vertex_bitmap( PatchData& pd, const MsqMeshEntity* elem, std::vector< size_t >& indices )
     278                 :            : {
     279                 :     292591 :     indices.clear();
     280                 :     292591 :     uint32_t result        = ~(uint32_t)0;
     281                 :     292591 :     unsigned num_vtx       = elem->vertex_count();
     282                 :     292591 :     const size_t* vertices = elem->get_vertex_index_array();
     283                 :     292591 :     indices.clear();
     284         [ +  + ]:    1571814 :     for( unsigned i = 0; i < num_vtx; ++i )
     285                 :            :     {
     286         [ +  + ]:    1279223 :         if( vertices[i] < pd.num_free_vertices() )
     287                 :            :         {
     288                 :     865973 :             indices.push_back( vertices[i] );
     289                 :     865973 :             result &= ~( uint32_t )( 1 << i );
     290                 :            :         }
     291                 :            :     }
     292                 :     292591 :     return result;
     293                 :            : }
     294                 :            : 
     295                 :     292588 : void QualityMetric::remove_fixed_gradients( EntityTopology elem_type, uint32_t fixed, std::vector< Vector3D >& grads )
     296                 :            : {
     297                 :     292588 :     const unsigned num_vertex = TopologyInfo::corners( elem_type );
     298                 :            :     unsigned r, w;
     299 [ +  + ][ +  + ]:     912233 :     for( r = 0; r < num_vertex && !( fixed & ( 1 << r ) ); ++r )
     300                 :            :         ;
     301         [ +  + ]:     766921 :     for( w = r++; r < num_vertex; ++r )
     302                 :            :     {
     303         [ +  + ]:     474333 :         if( !( fixed & ( 1 << r ) ) )
     304                 :            :         {
     305                 :     246316 :             grads[w] = grads[r];
     306                 :     246316 :             ++w;
     307                 :            :         }
     308                 :            :     }
     309                 :     292588 :     grads.resize( w );
     310                 :     292588 : }
     311                 :            : 
     312                 :          0 : void QualityMetric::remove_fixed_diagonals( EntityTopology type, uint32_t fixed, std::vector< Vector3D >& grads,
     313                 :            :                                             std::vector< SymMatrix3D >& diags )
     314                 :            : {
     315                 :          0 :     const unsigned num_vertex = TopologyInfo::corners( type );
     316                 :            :     unsigned r, w;
     317 [ #  # ][ #  # ]:          0 :     for( r = 0; r < num_vertex && !( fixed & ( 1 << r ) ); ++r )
     318                 :            :         ;
     319         [ #  # ]:          0 :     for( w = r++; r < num_vertex; ++r )
     320                 :            :     {
     321         [ #  # ]:          0 :         if( !( fixed & ( 1 << r ) ) )
     322                 :            :         {
     323                 :          0 :             grads[w] = grads[r];
     324                 :          0 :             diags[w] = diags[r];
     325                 :          0 :             ++w;
     326                 :            :         }
     327                 :            :     }
     328                 :          0 :     grads.resize( w );
     329                 :          0 :     diags.resize( w );
     330                 :          0 : }
     331                 :            : 
     332                 :     139808 : void QualityMetric::remove_fixed_hessians( EntityTopology elem_type, uint32_t fixed, std::vector< Matrix3D >& hessians )
     333                 :            : {
     334                 :     139808 :     const unsigned num_vertex = TopologyInfo::corners( elem_type );
     335                 :     139808 :     unsigned r, c, i = 0, w = 0;
     336         [ +  + ]:     751030 :     for( r = 0; r < num_vertex; ++r )
     337                 :            :     {
     338         [ +  + ]:     611222 :         if( fixed & ( 1 << r ) )
     339                 :            :         {
     340                 :     197674 :             i += num_vertex - r;
     341                 :     197674 :             continue;
     342                 :            :         }
     343         [ +  + ]:    1562124 :         for( c = r; c < num_vertex; ++c )
     344                 :            :         {
     345         [ +  + ]:    1148576 :             if( !( fixed & ( 1 << c ) ) )
     346                 :            :             {
     347                 :     977442 :                 hessians[w] = hessians[i];
     348                 :     977442 :                 ++w;
     349                 :            :             }
     350                 :    1148576 :             ++i;
     351                 :            :         }
     352                 :            :     }
     353                 :     139808 :     hessians.resize( w );
     354                 :     139808 : }
     355                 :            : 
     356                 :          0 : double QualityMetric::weighted_average_metrics( const double coef[], const double metric_values[],
     357                 :            :                                                 const int& num_values, MsqError& /*err*/ )
     358                 :            : {
     359                 :            :     // MSQ_MAX needs to be made global?
     360                 :            :     // double MSQ_MAX=1e10;
     361                 :          0 :     double total_value = 0.0;
     362                 :          0 :     int i              = 0;
     363                 :            :     // if no values, return zero
     364         [ #  # ]:          0 :     if( num_values <= 0 ) { return 0.0; }
     365                 :            : 
     366         [ #  # ]:          0 :     for( i = 0; i < num_values; ++i )
     367                 :            :     {
     368                 :          0 :         total_value += coef[i] * metric_values[i];
     369                 :            :     }
     370                 :          0 :     total_value /= (double)num_values;
     371                 :            : 
     372                 :          0 :     return total_value;
     373                 :            : }
     374                 :            : 
     375 [ +  - ][ +  - ]:        120 : }  // namespace MBMesquite

Generated by: LCOV version 1.11