MOAB: Mesh Oriented datABase
(version 5.4.1)
|
00001 /* ***************************************************************** 00002 MESQUITE -- The Mesh Quality Improvement Toolkit 00003 00004 Copyright 2004 Sandia Corporation and Argonne National 00005 Laboratory. Under the terms of Contract DE-AC04-94AL85000 00006 with Sandia Corporation, the U.S. Government retains certain 00007 rights in 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 [email protected], [email protected], [email protected], 00024 [email protected], [email protected], [email protected] 00025 00026 ***************************************************************** */ 00027 /*! 00028 \file MultiplyQualityMetric.cpp 00029 \brief 00030 00031 \author Michael Brewer 00032 \date 2002-05-09 00033 */ 00034 00035 #include "MultiplyQualityMetric.hpp" 00036 #include "Vector3D.hpp" 00037 #include "Matrix3D.hpp" 00038 #include "MsqError.hpp" 00039 00040 using namespace MBMesquite; 00041 00042 MultiplyQualityMetric::MultiplyQualityMetric( QualityMetric* qm1, QualityMetric* qm2, MsqError& err ) 00043 : metric1( *qm1 ), metric2( *qm2 ) 00044 { 00045 if( qm1->get_metric_type() != qm2->get_metric_type() || qm1->get_negate_flag() != qm2->get_negate_flag() ) 00046 { 00047 MSQ_SETERR( err )( "Incompatible metrics", MsqError::INVALID_ARG ); 00048 } 00049 } 00050 00051 MultiplyQualityMetric::~MultiplyQualityMetric() {} 00052 00053 QualityMetric::MetricType MultiplyQualityMetric::get_metric_type() const 00054 { 00055 return metric1.get_metric_type(); 00056 } 00057 00058 std::string MultiplyQualityMetric::get_name() const 00059 { 00060 return metric1.get_name() + "*" + metric2.get_name(); 00061 } 00062 00063 int MultiplyQualityMetric::get_negate_flag() const 00064 { 00065 return metric1.get_negate_flag(); 00066 } 00067 00068 void MultiplyQualityMetric::get_evaluations( PatchData& pd, 00069 std::vector< size_t >& handles, 00070 bool free_only, 00071 MsqError& err ) 00072 { 00073 metric1.get_evaluations( pd, handles, free_only, err );MSQ_ERRRTN( err ); 00074 metric2.get_evaluations( pd, mHandles, free_only, err );MSQ_ERRRTN( err ); 00075 if( handles != mHandles ) 00076 { 00077 MSQ_SETERR( err )( "Incompatible metrics", MsqError::INVALID_STATE ); 00078 } 00079 } 00080 00081 bool MultiplyQualityMetric::evaluate( PatchData& pd, size_t handle, double& value, MsqError& err ) 00082 { 00083 double val1, val2; 00084 bool rval1, rval2; 00085 rval1 = metric1.evaluate( pd, handle, val1, err ); 00086 MSQ_ERRZERO( err ); 00087 rval2 = metric2.evaluate( pd, handle, val2, err ); 00088 MSQ_ERRZERO( err ); 00089 value = val1 * val2; 00090 return rval1 && rval2; 00091 } 00092 00093 bool MultiplyQualityMetric::evaluate_with_indices( PatchData& pd, 00094 size_t handle, 00095 double& value, 00096 std::vector< size_t >& indices, 00097 MsqError& err ) 00098 { 00099 double val1, val2; 00100 bool rval1, rval2; 00101 rval1 = metric1.evaluate_with_indices( pd, handle, val1, indices1, err ); 00102 MSQ_ERRZERO( err ); 00103 rval2 = metric2.evaluate_with_indices( pd, handle, val2, indices2, err ); 00104 MSQ_ERRZERO( err ); 00105 00106 indices.clear(); 00107 std::sort( indices1.begin(), indices1.end() ); 00108 std::sort( indices2.begin(), indices2.end() ); 00109 std::set_union( indices1.begin(), indices1.end(), indices2.begin(), indices2.end(), std::back_inserter( indices ) ); 00110 00111 value = val1 * val2; 00112 return rval1 && rval2; 00113 } 00114 00115 bool MultiplyQualityMetric::evaluate_with_gradient( PatchData& pd, 00116 size_t handle, 00117 double& value, 00118 std::vector< size_t >& indices, 00119 std::vector< Vector3D >& gradient, 00120 MsqError& err ) 00121 { 00122 std::vector< size_t >::iterator i; 00123 size_t j; 00124 double val1, val2; 00125 bool rval1, rval2; 00126 rval1 = metric1.evaluate_with_gradient( pd, handle, val1, indices1, grad1, err ); 00127 MSQ_ERRZERO( err ); 00128 rval2 = metric2.evaluate_with_gradient( pd, handle, val2, indices2, grad2, err ); 00129 MSQ_ERRZERO( err ); 00130 00131 indices.resize( indices1.size() + indices2.size() ); 00132 i = std::copy( indices1.begin(), indices1.end(), indices.begin() ); 00133 std::copy( indices2.begin(), indices2.end(), i ); 00134 std::sort( indices.begin(), indices.end() ); 00135 indices.erase( std::unique( indices.begin(), indices.end() ), indices.end() ); 00136 00137 gradient.clear(); 00138 gradient.resize( indices.size(), Vector3D( 0.0 ) ); 00139 for( j = 0; j < indices1.size(); ++j ) 00140 { 00141 i = std::lower_bound( indices.begin(), indices.end(), indices1[j] ); 00142 size_t k = i - indices.begin(); 00143 gradient[k] += val2 * grad1[j]; 00144 } 00145 for( j = 0; j < indices2.size(); ++j ) 00146 { 00147 i = std::lower_bound( indices.begin(), indices.end(), indices2[j] ); 00148 size_t k = i - indices.begin(); 00149 gradient[k] += val1 * grad2[j]; 00150 } 00151 00152 value = val1 * val2; 00153 return rval1 && rval2; 00154 } 00155 00156 bool MultiplyQualityMetric::evaluate_with_Hessian( PatchData& pd, 00157 size_t handle, 00158 double& value, 00159 std::vector< size_t >& indices, 00160 std::vector< Vector3D >& gradient, 00161 std::vector< Matrix3D >& Hessian, 00162 MsqError& err ) 00163 { 00164 std::vector< size_t >::iterator i; 00165 size_t j, r, c, n, h; 00166 double val1, val2; 00167 bool rval1, rval2; 00168 rval1 = metric1.evaluate_with_Hessian( pd, handle, val1, indices1, grad1, Hess1, err ); 00169 MSQ_ERRZERO( err ); 00170 rval2 = metric2.evaluate_with_Hessian( pd, handle, val2, indices2, grad2, Hess2, err ); 00171 MSQ_ERRZERO( err ); 00172 // merge index lists 00173 indices.resize( indices1.size() + indices2.size() ); 00174 i = std::copy( indices1.begin(), indices1.end(), indices.begin() ); 00175 std::copy( indices2.begin(), indices2.end(), i ); 00176 std::sort( indices.begin(), indices.end() ); 00177 indices.erase( std::unique( indices.begin(), indices.end() ), indices.end() ); 00178 // calculate grads and convert index lists to indices into output list 00179 gradient.clear(); 00180 gradient.resize( indices.size(), Vector3D( 0.0 ) ); 00181 for( j = 0; j < indices1.size(); ++j ) 00182 { 00183 i = std::lower_bound( indices.begin(), indices.end(), indices1[j] ); 00184 indices1[j] = i - indices.begin(); 00185 gradient[indices1[j]] += val2 * grad1[j]; 00186 } 00187 for( j = 0; j < indices2.size(); ++j ) 00188 { 00189 i = std::lower_bound( indices.begin(), indices.end(), indices2[j] ); 00190 indices2[j] = i - indices.begin(); 00191 gradient[indices2[j]] += val1 * grad2[j]; 00192 } 00193 // allocate space for hessians, and zero it 00194 const size_t N = indices.size(); 00195 Hessian.clear(); 00196 Hessian.resize( N * ( N + 1 ) / 2, Matrix3D( 0.0 ) ); 00197 // add hessian terms from first metric 00198 n = indices1.size(); 00199 h = 0; 00200 for( r = 0; r < n; ++r ) 00201 { 00202 const size_t nr = indices1[r]; 00203 for( c = r; c < n; ++c ) 00204 { 00205 const size_t nc = indices1[c]; 00206 Hess1[h] *= val2; 00207 if( nr <= nc ) 00208 Hessian[N * nr - nr * ( nr + 1 ) / 2 + nc] += Hess1[h]; 00209 else 00210 Hessian[N * nc - nc * ( nc + 1 ) / 2 + nr].plus_transpose_equal( Hess1[h] ); 00211 ++h; 00212 } 00213 } 00214 // add hessian terms from second metric 00215 n = indices2.size(); 00216 h = 0; 00217 for( r = 0; r < n; ++r ) 00218 { 00219 const size_t nr = indices2[r]; 00220 for( c = r; c < n; ++c ) 00221 { 00222 const size_t nc = indices2[c]; 00223 Hess2[h] *= val1; 00224 if( nr <= nc ) 00225 Hessian[N * nr - nr * ( nr + 1 ) / 2 + nc] += Hess2[h]; 00226 else 00227 Hessian[N * nc - nc * ( nc + 1 ) / 2 + nr].plus_transpose_equal( Hess2[h] ); 00228 ++h; 00229 } 00230 } 00231 // add gradient outer products 00232 n = indices1.size(); 00233 size_t m = indices2.size(); 00234 Matrix3D outer; 00235 for( r = 0; r < n; ++r ) 00236 { 00237 const size_t nr = indices1[r]; 00238 for( c = 0; c < m; ++c ) 00239 { 00240 const size_t nc = indices2[c]; 00241 outer.outer_product( grad1[r], grad2[c] ); 00242 if( nr == nc ) 00243 Hessian[N * nr - nr * ( nr + 1 ) / 2 + nc] += outer.plus_transpose_equal( outer ); 00244 else if( nr < nc ) 00245 Hessian[N * nr - nr * ( nr + 1 ) / 2 + nc] += outer; 00246 else 00247 Hessian[N * nc - nc * ( nc + 1 ) / 2 + nr].plus_transpose_equal( outer ); 00248 } 00249 } 00250 00251 value = val1 * val2; 00252 return rval1 && rval2; 00253 }