MOAB: Mesh Oriented datABase  (version 5.4.1)
AWQualityMetric.cpp
Go to the documentation of this file.
00001 /* *****************************************************************
00002     MESQUITE -- The Mesh Quality Improvement Toolkit
00003 
00004     Copyright 2006 Sandia National Laboratories.  Developed at the
00005     University of Wisconsin--Madison under SNL contract number
00006     624796.  The U.S. Government and the University of Wisconsin
00007     retain certain rights to this software.
00008 
00009     This library is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU Lesser General Public
00011     License as published by the Free Software Foundation; either
00012     version 2.1 of the License, or (at your option) any later version.
00013 
00014     This library is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017     Lesser General Public License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public License
00020     (lgpl.txt) along with this library; if not, write to the Free Software
00021     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 
00023     (2006) [email protected]
00024 
00025   ***************************************************************** */
00026 
00027 /** \file AWQualityMetric.cpp
00028  *  \brief
00029  *  \author Jason Kraftcheck
00030  */
00031 
00032 #undef PRINT_INFO
00033 
00034 #include "Mesquite.hpp"
00035 #include "AWQualityMetric.hpp"
00036 #include "MsqMatrix.hpp"
00037 #include "ElementQM.hpp"
00038 #include "MsqError.hpp"
00039 #include "Vector3D.hpp"
00040 #include "PatchData.hpp"
00041 #include "MappingFunction.hpp"
00042 #include "WeightCalculator.hpp"
00043 #include "TargetCalculator.hpp"
00044 #include "AWMetric.hpp"
00045 #include "TargetMetricUtil.hpp"
00046 
00047 #ifdef PRINT_INFO
00048 #include <iostream>
00049 #endif
00050 
00051 #include <functional>
00052 #include <algorithm>
00053 
00054 #define NUMERICAL_2D_HESSIAN
00055 
00056 namespace MBMesquite
00057 {
00058 
00059 std::string AWQualityMetric::get_name() const
00060 {
00061     return targetMetric->get_name();
00062 }
00063 
00064 bool AWQualityMetric::evaluate_internal( PatchData& pd,
00065                                          size_t p_handle,
00066                                          double& value,
00067                                          size_t* indices,
00068                                          size_t& num_indices,
00069                                          MsqError& err )
00070 {
00071     const Sample s        = ElemSampleQM::sample( p_handle );
00072     const size_t e        = ElemSampleQM::elem( p_handle );
00073     MsqMeshEntity& p_elem = pd.element_by_index( e );
00074     EntityTopology type   = p_elem.get_element_type();
00075     unsigned edim         = TopologyInfo::dimension( type );
00076     const NodeSet bits    = pd.non_slave_node_set( e );
00077 
00078     bool rval;
00079     if( edim == 3 )
00080     {  // 3x3 or 3x2 targets ?
00081         const MappingFunction3D* mf = pd.get_mapping_function_3D( type );
00082         if( !mf )
00083         {
00084             MSQ_SETERR( err )
00085             ( "No mapping function for element type", MsqError::UNSUPPORTED_ELEMENT );
00086             return false;
00087         }
00088 
00089         MsqMatrix< 3, 3 > A, W;
00090         mf->jacobian( pd, e, bits, s, indices, mDerivs3D, num_indices, A, err );
00091         MSQ_ERRZERO( err );
00092         targetCalc->get_3D_target( pd, e, s, W, err );
00093         MSQ_ERRZERO( err );
00094         rval = targetMetric->evaluate( A, W, value, err );
00095         MSQ_ERRZERO( err );
00096 #ifdef PRINT_INFO
00097         print_info< 3 >( e, s, A, W, A * inverse( W ) );
00098 #endif
00099     }
00100     else if( edim == 2 )
00101     {
00102         MsqMatrix< 2, 2 > W, A;
00103         MsqMatrix< 3, 2 > S_a_transpose_Theta;
00104         rval =
00105             evaluate_surface_common( pd, s, e, bits, indices, num_indices, mDerivs2D, W, A, S_a_transpose_Theta, err );
00106         if( MSQ_CHKERR( err ) || !rval ) return false;
00107         rval = targetMetric->evaluate( A, W, value, err );
00108         MSQ_ERRZERO( err );
00109 #ifdef PRINT_INFO
00110         print_info< 2 >( e, s, J, Wp, A * inverse( W ) );
00111 #endif
00112     }
00113     else
00114     {
00115         assert( false );
00116         return false;
00117     }
00118 
00119     return rval;
00120 }
00121 
00122 bool AWQualityMetric::evaluate_with_gradient( PatchData& pd,
00123                                               size_t p_handle,
00124                                               double& value,
00125                                               std::vector< size_t >& indices,
00126                                               std::vector< Vector3D >& grad,
00127                                               MsqError& err )
00128 {
00129     const Sample s        = ElemSampleQM::sample( p_handle );
00130     const size_t e        = ElemSampleQM::elem( p_handle );
00131     MsqMeshEntity& p_elem = pd.element_by_index( e );
00132     EntityTopology type   = p_elem.get_element_type();
00133     unsigned edim         = TopologyInfo::dimension( type );
00134     size_t num_idx        = 0;
00135     const NodeSet bits    = pd.non_slave_node_set( e );
00136 
00137     bool rval;
00138     if( edim == 3 )
00139     {  // 3x3 or 3x2 targets ?
00140         const MappingFunction3D* mf = pd.get_mapping_function_3D( type );
00141         if( !mf )
00142         {
00143             MSQ_SETERR( err )
00144             ( "No mapping function for element type", MsqError::UNSUPPORTED_ELEMENT );
00145             return false;
00146         }
00147 
00148         MsqMatrix< 3, 3 > A, W, dmdA;
00149         mf->jacobian( pd, e, bits, s, mIndices, mDerivs3D, num_idx, A, err );
00150         MSQ_ERRZERO( err );
00151         targetCalc->get_3D_target( pd, e, s, W, err );
00152         MSQ_ERRZERO( err );
00153         rval = targetMetric->evaluate_with_grad( A, W, value, dmdA, err );
00154         MSQ_ERRZERO( err );
00155         gradient< 3 >( num_idx, mDerivs3D, dmdA, grad );
00156 #ifdef PRINT_INFO
00157         print_info< 3 >( e, s, A, W, A * inverse( W ) );
00158 #endif
00159     }
00160     else if( edim == 2 )
00161     {
00162         MsqMatrix< 2, 2 > W, A, dmdA;
00163         MsqMatrix< 3, 2 > S_a_transpose_Theta;
00164         rval = evaluate_surface_common( pd, s, e, bits, mIndices, num_idx, mDerivs2D, W, A, S_a_transpose_Theta, err );
00165         if( MSQ_CHKERR( err ) || !rval ) return false;
00166         rval = targetMetric->evaluate_with_grad( A, W, value, dmdA, err );
00167         MSQ_ERRZERO( err );
00168         gradient< 2 >( num_idx, mDerivs2D, S_a_transpose_Theta * dmdA, grad );
00169 #ifdef PRINT_INFO
00170         print_info< 2 >( e, s, J, Wp, A * inverse( W ) );
00171 #endif
00172     }
00173     else
00174     {
00175         assert( false );
00176         return false;
00177     }
00178 
00179     // pass back index list
00180     indices.resize( num_idx );
00181     std::copy( mIndices, mIndices + num_idx, indices.begin() );
00182 
00183     // apply target weight to value
00184     weight( pd, s, e, num_idx, value, grad.empty() ? 0 : arrptr( grad ), 0, 0, err );
00185     MSQ_ERRZERO( err );
00186     return rval;
00187 }
00188 
00189 bool AWQualityMetric::evaluate_with_Hessian( PatchData& pd,
00190                                              size_t p_handle,
00191                                              double& value,
00192                                              std::vector< size_t >& indices,
00193                                              std::vector< Vector3D >& grad,
00194                                              std::vector< Matrix3D >& Hessian,
00195                                              MsqError& err )
00196 {
00197     const Sample s        = ElemSampleQM::sample( p_handle );
00198     const size_t e        = ElemSampleQM::elem( p_handle );
00199     MsqMeshEntity& p_elem = pd.element_by_index( e );
00200     EntityTopology type   = p_elem.get_element_type();
00201     unsigned edim         = TopologyInfo::dimension( type );
00202     size_t num_idx        = 0;
00203     const NodeSet bits    = pd.non_slave_node_set( e );
00204 
00205     bool rval;
00206     if( edim == 3 )
00207     {  // 3x3 or 3x2 targets ?
00208         const MappingFunction3D* mf = pd.get_mapping_function_3D( type );
00209         if( !mf )
00210         {
00211             MSQ_SETERR( err )
00212             ( "No mapping function for element type", MsqError::UNSUPPORTED_ELEMENT );
00213             return false;
00214         }
00215 
00216         MsqMatrix< 3, 3 > A, W, dmdA, d2mdA2[6];
00217         mf->jacobian( pd, e, bits, s, mIndices, mDerivs3D, num_idx, A, err );
00218         MSQ_ERRZERO( err );
00219         targetCalc->get_3D_target( pd, e, s, W, err );
00220         MSQ_ERRZERO( err );
00221         rval = targetMetric->evaluate_with_hess( A, W, value, dmdA, d2mdA2, err );
00222         MSQ_ERRZERO( err );
00223         gradient< 3 >( num_idx, mDerivs3D, dmdA, grad );
00224         Hessian.resize( num_idx * ( num_idx + 1 ) / 2 );
00225         if( num_idx ) hessian< 3 >( num_idx, mDerivs3D, d2mdA2, arrptr( Hessian ) );
00226 
00227 #ifdef PRINT_INFO
00228         print_info< 3 >( e, s, A, W, A * inverse( W ) );
00229 #endif
00230     }
00231     else if( edim == 2 )
00232     {
00233 #ifdef NUMERICAL_2D_HESSIAN
00234         // return finite difference approximation for now
00235 
00236         return QualityMetric::evaluate_with_Hessian( pd, p_handle, value, indices, grad, Hessian, err );
00237 #else
00238         MsqMatrix< 2, 2 > W, A, dmdA, d2mdA2[3];
00239         MsqMatrix< 3, 2 > M;
00240         rval = evaluate_surface_common( pd, s, e, bits, mIndices, num_idx, mDerivs2D, W, A, M, err );
00241         if( MSQ_CHKERR( err ) || !rval ) return false;
00242         rval = targetMetric->evaluate_with_hess( A, W, value, dmdA, d2mdA2, err );
00243         MSQ_ERRZERO( err );
00244         gradient< 2 >( num_idx, mDerivs2D, M * dmdA, grad );
00245         const size_t n = num_idx * ( num_idx + 1 ) / 2;
00246         // calculate 2D hessian
00247         hess2d.resize( n );
00248         if( n ) hessian< 2 >( num_idx, mDerivs2D, d2mdA2, arrptr( hess2d ) );
00249         // calculate surface hessian as transform of 2D hessian
00250         Hessian.resize( n );
00251         for( size_t i = 0; i < n; ++i )
00252             Hessian[i] = Matrix3D( ( M * hess2d[i] * transpose( M ) ).data() );
00253 #ifdef PRINT_INFO
00254         print_info< 2 >( e, s, J, Wp, A * inverse( W ) );
00255 #endif
00256 #endif
00257     }
00258     else
00259     {
00260         assert( 0 );
00261         return false;
00262     }
00263 
00264     // pass back index list
00265     indices.resize( num_idx );
00266     std::copy( mIndices, mIndices + num_idx, indices.begin() );
00267 
00268     // apply target weight to value
00269     if( !num_idx )
00270         weight( pd, s, e, num_idx, value, 0, 0, 0, err );
00271     else
00272         weight( pd, s, e, num_idx, value, arrptr( grad ), 0, arrptr( Hessian ), err );
00273     MSQ_ERRZERO( err );
00274     return rval;
00275 }
00276 
00277 bool AWQualityMetric::evaluate_with_Hessian_diagonal( PatchData& pd,
00278                                                       size_t p_handle,
00279                                                       double& value,
00280                                                       std::vector< size_t >& indices,
00281                                                       std::vector< Vector3D >& grad,
00282                                                       std::vector< SymMatrix3D >& diagonal,
00283                                                       MsqError& err )
00284 {
00285     const Sample s        = ElemSampleQM::sample( p_handle );
00286     const size_t e        = ElemSampleQM::elem( p_handle );
00287     MsqMeshEntity& p_elem = pd.element_by_index( e );
00288     EntityTopology type   = p_elem.get_element_type();
00289     unsigned edim         = TopologyInfo::dimension( type );
00290     size_t num_idx        = 0;
00291     const NodeSet bits    = pd.non_slave_node_set( e );
00292 
00293     bool rval;
00294     if( edim == 3 )
00295     {  // 3x3 or 3x2 targets ?
00296         const MappingFunction3D* mf = pd.get_mapping_function_3D( type );
00297         if( !mf )
00298         {
00299             MSQ_SETERR( err )
00300             ( "No mapping function for element type", MsqError::UNSUPPORTED_ELEMENT );
00301             return false;
00302         }
00303 
00304         MsqMatrix< 3, 3 > A, W, dmdA, d2mdA2[6];
00305         mf->jacobian( pd, e, bits, s, mIndices, mDerivs3D, num_idx, A, err );
00306         MSQ_ERRZERO( err );
00307         targetCalc->get_3D_target( pd, e, s, W, err );
00308         MSQ_ERRZERO( err );
00309         rval = targetMetric->evaluate_with_hess( A, W, value, dmdA, d2mdA2, err );
00310         MSQ_ERRZERO( err );
00311         gradient< 3 >( num_idx, mDerivs3D, dmdA, grad );
00312 
00313         diagonal.resize( num_idx );
00314         hessian_diagonal< 3 >( num_idx, mDerivs3D, d2mdA2, arrptr( diagonal ) );
00315 #ifdef PRINT_INFO
00316         print_info< 3 >( e, s, A, W, A * inverse( W ) );
00317 #endif
00318     }
00319     else if( edim == 2 )
00320     {
00321 #ifdef NUMERICAL_2D_HESSIAN
00322         // use finite diference approximation for now
00323         return QualityMetric::evaluate_with_Hessian_diagonal( pd, p_handle, value, indices, grad, diagonal, err );
00324 #else
00325         MsqMatrix< 2, 2 > W, A, dmdA, d2mdA2[3];
00326         MsqMatrix< 3, 2 > M;
00327         rval = evaluate_surface_common( pd, s, e, bits, mIndices, num_idx, mDerivs2D, W, A, M, err );
00328         if( MSQ_CHKERR( err ) || !rval ) return false;
00329         rval = targetMetric->evaluate_with_hess( A, W, value, dmdA, d2mdA2, err );
00330         MSQ_ERRZERO( err );
00331         gradient< 2 >( num_idx, mDerivs2D, M * dmdA, grad );
00332 
00333         diagonal.resize( num_idx );
00334         for( size_t i = 0; i < num_idx; ++i )
00335         {
00336             MsqMatrix< 2, 2 > block2d;
00337             block2d( 0, 0 )     = transpose( mDerivs2D[i] ) * d2mdA2[0] * mDerivs2D[i];
00338             block2d( 0, 1 )     = transpose( mDerivs2D[i] ) * d2mdA2[1] * mDerivs2D[i];
00339             block2d( 1, 0 )     = block2d( 0, 1 );
00340             block2d( 1, 1 )     = transpose( mDerivs2D[i] ) * d2mdA2[2] * mDerivs2D[i];
00341             MsqMatrix< 3, 2 > p = M * block2d;
00342 
00343             SymMatrix3D& H = diagonal[i];
00344             H[0]           = p.row( 0 ) * transpose( M.row( 0 ) );
00345             H[1]           = p.row( 0 ) * transpose( M.row( 1 ) );
00346             H[2]           = p.row( 0 ) * transpose( M.row( 2 ) );
00347             H[3]           = p.row( 1 ) * transpose( M.row( 1 ) );
00348             H[4]           = p.row( 1 ) * transpose( M.row( 2 ) );
00349             H[5]           = p.row( 2 ) * transpose( M.row( 2 ) );
00350         }
00351 #ifdef PRINT_INFO
00352         print_info< 2 >( e, s, J, Wp, A * inverse( W ) );
00353 #endif
00354 #endif
00355     }
00356     else
00357     {
00358         assert( 0 );
00359         return false;
00360     }
00361 
00362     // pass back index list
00363     indices.resize( num_idx );
00364     std::copy( mIndices, mIndices + num_idx, indices.begin() );
00365 
00366     // apply target weight to value
00367     if( !num_idx )
00368         weight( pd, s, e, num_idx, value, 0, 0, 0, err );
00369     else
00370         weight( pd, s, e, num_idx, value, arrptr( grad ), arrptr( diagonal ), 0, err );MSQ_CHKERR( err );
00371     return rval;
00372 }
00373 
00374 }  // namespace MBMesquite
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines