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 TMPQualityMetric.cpp 00028 * \brief 00029 * \author Jason Kraftcheck 00030 */ 00031 00032 #undef PRINT_INFO 00033 00034 #include "Mesquite.hpp" 00035 #include "TMPQualityMetric.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 "TargetMetricUtil.hpp" 00045 00046 #ifdef PRINT_INFO 00047 #include <iostream> 00048 #endif 00049 00050 #include <functional> 00051 #include <algorithm> 00052 00053 namespace MBMesquite 00054 { 00055 00056 int TMPQualityMetric::get_negate_flag() const 00057 { 00058 return 1; 00059 } 00060 00061 void TMPQualityMetric::get_evaluations( PatchData& pd, std::vector< size_t >& handles, bool free, MsqError& err ) 00062 { 00063 get_sample_pt_evaluations( pd, handles, free, err ); 00064 } 00065 00066 void TMPQualityMetric::get_patch_evaluations( PatchData& pd, std::vector< size_t >& handles, bool free, MsqError& err ) 00067 { 00068 get_sample_pt_evaluations( pd, handles, free, err ); 00069 } 00070 00071 void TMPQualityMetric::get_element_evaluations( PatchData& pd, 00072 size_t p_elem, 00073 std::vector< size_t >& handles, 00074 MsqError& err ) 00075 { 00076 get_elem_sample_points( pd, p_elem, handles, err ); 00077 } 00078 00079 bool TMPQualityMetric::evaluate( PatchData& pd, size_t p_handle, double& value, MsqError& err ) 00080 { 00081 size_t num_idx; 00082 bool valid = evaluate_internal( pd, p_handle, value, mIndices, num_idx, err ); 00083 if( MSQ_CHKERR( err ) || !valid ) return false; 00084 00085 // apply target weight to value 00086 if( weightCalc ) 00087 { 00088 const Sample s = ElemSampleQM::sample( p_handle ); 00089 const size_t e = ElemSampleQM::elem( p_handle ); 00090 double ck = weightCalc->get_weight( pd, e, s, err ); 00091 MSQ_ERRZERO( err ); 00092 value *= ck; 00093 } 00094 return true; 00095 } 00096 00097 bool TMPQualityMetric::evaluate_with_indices( PatchData& pd, 00098 size_t p_handle, 00099 double& value, 00100 std::vector< size_t >& indices, 00101 MsqError& err ) 00102 { 00103 indices.resize( MAX_ELEM_NODES ); 00104 size_t num_idx = 0; 00105 bool result = evaluate_internal( pd, p_handle, value, arrptr( indices ), num_idx, err ); 00106 if( MSQ_CHKERR( err ) || !result ) return false; 00107 00108 indices.resize( num_idx ); 00109 00110 // apply target weight to value 00111 if( weightCalc ) 00112 { 00113 const Sample s = ElemSampleQM::sample( p_handle ); 00114 const size_t e = ElemSampleQM::elem( p_handle ); 00115 double ck = weightCalc->get_weight( pd, e, s, err ); 00116 MSQ_ERRZERO( err ); 00117 value *= ck; 00118 } 00119 00120 return true; 00121 } 00122 00123 static void get_u_perp( const MsqVector< 3 >& u, MsqVector< 3 >& u_perp ) 00124 { 00125 double a = sqrt( u[0] * u[0] + u[1] * u[1] ); 00126 if( a < 1e-10 ) 00127 { 00128 u_perp[0] = 1.0; 00129 u_perp[1] = u_perp[2] = 0.0; 00130 } 00131 else 00132 { 00133 double b = -u[2] / a; 00134 u_perp[0] = u[0] * b; 00135 u_perp[1] = u[1] * b; 00136 u_perp[2] = a; 00137 } 00138 } 00139 00140 /* Do transform M_hat = S_a M_{3x2}, M_{2x2} Theta^-1 M_hat 00141 * where the plane into which we are projecting is orthogonal 00142 * to the passed u vector. 00143 */ 00144 static inline bool project_to_perp_plane( MsqMatrix< 3, 2 > J, 00145 const MsqVector< 3 >& u, 00146 const MsqVector< 3 >& u_perp, 00147 MsqMatrix< 2, 2 >& A, 00148 MsqMatrix< 3, 2 >& S_a_transpose_Theta ) 00149 { 00150 MsqVector< 3 > n_a = J.column( 0 ) * J.column( 1 ); 00151 double sc, len = length( n_a ); 00152 if( !divide( 1.0, len, sc ) ) return false; 00153 n_a *= sc; 00154 double ndot = n_a % u; 00155 double sigma = ( ndot < 0.0 ) ? -1 : 1; 00156 double cosphi = sigma * ndot; 00157 MsqVector< 3 > cross = n_a * u; 00158 double sinphi = length( cross ); 00159 00160 MsqMatrix< 3, 2 > Theta; 00161 Theta.set_column( 0, u_perp ); 00162 Theta.set_column( 1, u * u_perp ); 00163 00164 // If columns of J are not in plane orthogonal to u, then 00165 // rotate J such that they are. 00166 if( sinphi > 1e-12 ) 00167 { 00168 MsqVector< 3 > m = sigma * cross; 00169 MsqVector< 3 > n = ( 1 / sinphi ) * m; 00170 MsqVector< 3 > p = ( 1 - cosphi ) * n; 00171 double s_a[] = { p[0] * n[0] + cosphi, p[0] * n[1] - m[2], p[0] * n[2] + m[1], 00172 p[1] * n[0] + m[2], p[1] * n[1] + cosphi, p[1] * n[2] - m[0], 00173 p[2] * n[0] - m[1], p[2] * n[1] + m[0], p[2] * n[2] + cosphi }; 00174 MsqMatrix< 3, 3 > S_a( s_a ); 00175 J = S_a * J; 00176 S_a_transpose_Theta = transpose( S_a ) * Theta; 00177 } 00178 else 00179 { 00180 S_a_transpose_Theta = Theta; 00181 // J *= sigma; 00182 } 00183 00184 // Project to get 2x2 A from A_hat (which might be equal to J) 00185 A = transpose( Theta ) * J; 00186 return true; 00187 } 00188 00189 /* Do transform M_hat = S_a M_{3x2}, M_{2x2} Theta^-1 M_hat 00190 * where the plane into which we are projecting is the cross 00191 * product of the columns of M, such that S_a is I. Use the 00192 * first column of M as u_perp. 00193 * 00194 * Also pass back the cross product of the columns of M as u, 00195 * and the first column of M as u_perp, both normalized. 00196 */ 00197 static inline void project_to_matrix_plane( const MsqMatrix< 3, 2 >& M_in, 00198 MsqMatrix< 2, 2 >& M_out, 00199 MsqVector< 3 >& u, 00200 MsqVector< 3 >& u_perp ) 00201 { 00202 u = M_in.column( 0 ) * M_in.column( 1 ); 00203 u_perp = M_in.column( 0 ); 00204 double len0 = length( u_perp ); 00205 double u_len = length( u ); 00206 double d_perp, d_u; 00207 if( !divide( 1.0, len0, d_perp ) ) 00208 { 00209 // try the other column 00210 u_perp = M_in.column( 1 ); 00211 len0 = length( u_perp ); 00212 if( !divide( 1.0, len0, d_perp ) ) 00213 { 00214 // matrix is all zeros 00215 u[0] = 0; 00216 u[1] = 0; 00217 u[2] = 1; 00218 u_perp[0] = 1; 00219 u_perp[1] = 0; 00220 u_perp[2] = 0; 00221 M_out = MsqMatrix< 2, 2 >( 0.0 ); 00222 } 00223 else 00224 { 00225 MsqMatrix< 3, 2 > junk; 00226 get_u_perp( u_perp, u ); 00227 project_to_perp_plane( M_in, u, u_perp, M_out, junk ); 00228 } 00229 } 00230 else if( !divide( 1.0, u_len, d_u ) ) 00231 { 00232 MsqMatrix< 3, 2 > junk; 00233 get_u_perp( u_perp, u ); 00234 project_to_perp_plane( M_in, u, u_perp, M_out, junk ); 00235 } 00236 else 00237 { // the normal case (neither column is zero) 00238 u *= d_u; 00239 u_perp *= d_perp; 00240 00241 // M_out = transpose(theta)*M_in 00242 M_out( 0, 0 ) = len0; 00243 M_out( 0, 1 ) = u_perp % M_in.column( 1 ); 00244 M_out( 1, 0 ) = 0.0; 00245 M_out( 1, 1 ) = u_len / len0; 00246 } 00247 } 00248 00249 bool TMPQualityMetric::evaluate_surface_common( PatchData& pd, 00250 Sample s, 00251 size_t e, 00252 const NodeSet& bits, 00253 size_t* indices, 00254 size_t& num_indices, 00255 MsqVector< 2 >* derivs, 00256 MsqMatrix< 2, 2 >& W, 00257 MsqMatrix< 2, 2 >& A, 00258 MsqMatrix< 3, 2 >& S_a_transpose_Theta, 00259 MsqError& err ) 00260 { 00261 EntityTopology type = pd.element_by_index( e ).get_element_type(); 00262 00263 const MappingFunction2D* mf = pd.get_mapping_function_2D( type ); 00264 if( !mf ) 00265 { 00266 MSQ_SETERR( err )( "No mapping function for element type", MsqError::UNSUPPORTED_ELEMENT ); 00267 return false; 00268 } 00269 00270 MsqMatrix< 3, 2 > J; 00271 mf->jacobian( pd, e, bits, s, indices, derivs, num_indices, J, err ); 00272 00273 // If we have a 3x2 target matrix 00274 if( targetCalc->have_surface_orient() ) 00275 { 00276 MsqVector< 3 > u, u_perp; 00277 MsqMatrix< 3, 2 > W_hat; 00278 targetCalc->get_surface_target( pd, e, s, W_hat, err ); 00279 MSQ_ERRZERO( err ); 00280 // Use the cross product of the columns of W as the normal of the 00281 // plane to work in (i.e. u.). W should have been constructed such 00282 // that said cross product is in the direction of (n_s)_init. And if 00283 // for some reason it as not, then using something other than said 00284 // cross product is likely to produce very wrong results. 00285 project_to_matrix_plane( W_hat, W, u, u_perp ); 00286 // Do the transforms on A to align it with W and project into the plane. 00287 if( !project_to_perp_plane( J, u, u_perp, A, S_a_transpose_Theta ) ) return false; 00288 } 00289 // Otherwise if we have a 2x2 target matrix (i.e. the target does 00290 // not contain orientation information), project into the plane 00291 // tangent to J. 00292 else 00293 { 00294 MsqVector< 3 > u, u_perp; 00295 targetCalc->get_2D_target( pd, e, s, W, err ); 00296 MSQ_ERRZERO( err ); 00297 project_to_matrix_plane( J, A, u, u_perp ); 00298 S_a_transpose_Theta.set_column( 0, u_perp ); 00299 S_a_transpose_Theta.set_column( 1, u * u_perp ); 00300 // If the domain is set, adjust the sign of things correctly 00301 // for the case where the element is inverted with respect 00302 // to the domain. 00303 if( pd.domain_set() ) 00304 { 00305 Vector3D n; 00306 pd.get_domain_normal_at_sample( e, s, n, err ); 00307 MSQ_ERRZERO( err ); 00308 // if sigma == -1 00309 if( Vector3D( u.data() ) % n < 0.0 ) 00310 { 00311 // flip u 00312 u = -u; 00313 // S_a_transpose_Theta == Theta, because S_a == I here. 00314 // u_perp is unaffected by flipping u, so only the second 00315 // column of S_a_transpose_Theta and the second row of A 00316 // are flipped because u x u_perp will be flipped. 00317 S_a_transpose_Theta.set_column( 1, -S_a_transpose_Theta.column( 1 ) ); 00318 A.set_row( 1, -A.row( 1 ) ); 00319 } 00320 } 00321 } 00322 00323 return true; 00324 } 00325 00326 void TMPQualityMetric::weight( PatchData& pd, 00327 Sample p_sample, 00328 size_t p_elem, 00329 int num_idx, 00330 double& value, 00331 Vector3D* grad, 00332 SymMatrix3D* diag, 00333 Matrix3D* hess, 00334 MsqError& err ) 00335 { 00336 if( !weightCalc ) return; 00337 00338 double ck = weightCalc->get_weight( pd, p_elem, p_sample, err );MSQ_ERRRTN( err ); 00339 value *= ck; 00340 if( grad ) 00341 { 00342 for( int i = 0; i < num_idx; ++i ) 00343 grad[i] *= ck; 00344 } 00345 if( diag ) 00346 { 00347 for( int i = 0; i < num_idx; ++i ) 00348 diag[i] *= ck; 00349 } 00350 if( hess ) 00351 { 00352 const int n = num_idx * ( num_idx + 1 ) / 2; 00353 for( int i = 0; i < n; ++i ) 00354 hess[i] *= ck; 00355 } 00356 } 00357 00358 void TMPQualityMetric::initialize_queue( MeshDomainAssoc* mesh_and_domain, const Settings* settings, MsqError& err ) 00359 { 00360 targetCalc->initialize_queue( mesh_and_domain, settings, err );MSQ_ERRRTN( err ); 00361 if( weightCalc ) 00362 { 00363 weightCalc->initialize_queue( mesh_and_domain, settings, err );MSQ_ERRRTN( err ); 00364 } 00365 } 00366 00367 } // namespace MBMesquite