MOAB: Mesh Oriented datABase
(version 5.4.1)
|
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