bool get_surface_target( PatchData& pd, size_t element, Sample sample, MsqMatrix<3,2>& W_out, MsqError& err ) { MsqMatrix<2,2> W; bool rval = get_2D_target( pd, element, sample, W, err ); W_out.set_row( 0, W.row(0) ); W_out.set_row( 1, W.row(1) ); W_out.set_row( 2, MsqMatrix<1,2>(0.0) ); return rval; }
bool InverseMeanRatio2D::evaluate_with_hess( const MsqMatrix<2,2>& A, const MsqMatrix<2,2>& W, double& result, MsqMatrix<2,2>& dA, MsqMatrix<2,2> d2A[3], MsqError& err ) { const MsqMatrix<2,2> Winv = inverse(W); const MsqMatrix<2,2> T = A * Winv; const double d = det( T ); if (invalid_determinant(d)) { result = 0.0; dA = d2A[0] = d2A[1] = d2A[2] = MsqMatrix<2,2>(0.0); return false; } else { const double inv_det = 1.0/d; result = sqr_Frobenius(T) * 0.5 * inv_det; const MsqMatrix<2,2> AT = transpose_adj(T); dA = AT; dA *= -result; dA += T; dA *= inv_det; dA = dA * transpose(Winv); const double p3 = -result * inv_det; const double p1 = -2.0 * p3 * inv_det; const double p2 = -inv_det * inv_det; const MsqMatrix<2,2> AT_T_op_00 = outer( AT.row(0), T.row(0)); const MsqMatrix<2,2> AT_T_op_11 = outer( AT.row(1), T.row(1)); d2A[0] = p1 * outer( AT.row(0), AT.row(0)) + p2 * (AT_T_op_00 + transpose(AT_T_op_00)); d2A[1] = p1 * outer( AT.row(0), AT.row(1)) + p2 * (outer( AT.row(0), T.row(1)) + outer( T.row(0), AT.row(1) )); d2A[2] = p1 * outer( AT.row(1), AT.row(1)) + p2 * (AT_T_op_11 + transpose(AT_T_op_11)); d2A[0](0,0) += inv_det; d2A[0](1,1) += inv_det; d2A[1](0,1) += p3; d2A[1](1,0) -= p3; d2A[2](0,0) += inv_det; d2A[2](1,1) += inv_det; d2A[0] = Winv * d2A[0] * transpose(Winv); d2A[1] = Winv * d2A[1] * transpose(Winv); d2A[2] = Winv * d2A[2] * transpose(Winv); result -= 1.0; return true; } }
bool TQualityMetric::evaluate_with_Hessian_diagonal( PatchData& pd, size_t handle, double& value, std::vector<size_t>& indices, std::vector<Vector3D>& grad, std::vector<SymMatrix3D>& diagonal, MsqError& err ) { const Sample s = ElemSampleQM::sample( handle ); const size_t e = ElemSampleQM:: elem( handle ); MsqMeshEntity& elem = pd.element_by_index( e ); EntityTopology type = elem.get_element_type(); unsigned edim = TopologyInfo::dimension( type ); size_t num_idx = 0; const NodeSet bits = pd.non_slave_node_set( e ); bool rval; if (edim == 3) { // 3x3 or 3x2 targets ? const MappingFunction3D* mf = pd.get_mapping_function_3D( type ); if (!mf) { MSQ_SETERR(err)( "No mapping function for element type", MsqError::UNSUPPORTED_ELEMENT ); return false; } MsqMatrix<3,3> A, W, dmdT, d2mdT2[6]; mf->jacobian( pd, e, bits, s, mIndices, mDerivs3D, num_idx, A, err ); MSQ_ERRZERO(err); targetCalc->get_3D_target( pd, e, s, W, err ); MSQ_ERRZERO(err); const MsqMatrix<3,3> Winv = inverse(W); const MsqMatrix<3,3> T = A*Winv; rval = targetMetric->evaluate_with_hess( T, value, dmdT, d2mdT2, err ); MSQ_ERRZERO(err); gradient<3>( num_idx, mDerivs3D, dmdT * transpose(Winv), grad ); second_deriv_wrt_product_factor( d2mdT2, Winv ); diagonal.resize( num_idx ); hessian_diagonal<3>(num_idx, mDerivs3D, d2mdT2, arrptr(diagonal) ); #ifdef PRINT_INFO print_info<3>( e, s, A, W, A * inverse(W) ); #endif } else if (edim == 2) { #ifdef NUMERICAL_2D_HESSIAN // use finite diference approximation for now return QualityMetric::evaluate_with_Hessian_diagonal( pd, handle, value, indices, grad, diagonal, err ); #else MsqMatrix<2,2> W, A, dmdT, d2mdT2[3]; MsqMatrix<3,2> M; rval = evaluate_surface_common( pd, s, e, bits, mIndices, num_idx, mDerivs2D, W, A, M, err ); if (MSQ_CHKERR(err) || !rval) return false; const MsqMatrix<2,2> Winv = inverse(W); const MsqMatrix<2,2> T = A*Winv; rval = targetMetric->evaluate_with_hess( T, value, dmdT, d2mdT2, err ); MSQ_ERRZERO(err); gradient<2>( num_idx, mDerivs2D, M * dmdT * transpose(Winv), grad ); second_deriv_wrt_product_factor( d2mdT2, Winv ); diagonal.resize( num_idx ); for (size_t i = 0; i < num_idx; ++i) { MsqMatrix<2,2> block2d; block2d(0,0) = transpose(mDerivs2D[i]) * d2mdT2[0] * mDerivs2D[i]; block2d(0,1) = transpose(mDerivs2D[i]) * d2mdT2[1] * mDerivs2D[i]; block2d(1,0) = block2d(0,1); block2d(1,1) = transpose(mDerivs2D[i]) * d2mdT2[2] * mDerivs2D[i]; MsqMatrix<3,2> p = M * block2d; SymMatrix3D& H = diagonal[i]; H[0] = p.row(0) * transpose(M.row(0)); H[1] = p.row(0) * transpose(M.row(1)); H[2] = p.row(0) * transpose(M.row(2)); H[3] = p.row(1) * transpose(M.row(1)); H[4] = p.row(1) * transpose(M.row(2)); H[5] = p.row(2) * transpose(M.row(2)); } #ifdef PRINT_INFO print_info<2>( e, s, J, Wp, A * inverse(W) ); #endif #endif } else { assert(0); return false; } // pass back index list indices.resize( num_idx ); std::copy( mIndices, mIndices+num_idx, indices.begin() ); // apply target weight to value if (!num_idx) weight( pd, s, e, num_idx, value, 0, 0, 0, err ); else weight( pd, s, e, num_idx, value, arrptr(grad), arrptr(diagonal), 0, err ); MSQ_ERRZERO(err); return rval; }