bool Target2DUntangle::evaluate_with_hess( const MsqMatrix<2,2>& A, const MsqMatrix<2,2>& W, double& result, MsqMatrix<2,2>& deriv_wrt_A, MsqMatrix<2,2> second_wrt_A[3], MsqError& err ) { const MsqMatrix<2,2> Winv = inverse(W); const MsqMatrix<2,2> T = A * Winv; double tau = det(T); if (tau < mGamma) { double d = tau - mGamma; result = 16 * d*d*d*d; const MsqMatrix<2,2> adjt = transpose_adj(T); deriv_wrt_A = 64 * d*d*d * adjt; deriv_wrt_A = deriv_wrt_A * transpose(Winv); set_scaled_outer_product( second_wrt_A, 192*d*d, adjt ); pluseq_scaled_2nd_deriv_of_det( second_wrt_A, 64*d*d*d ); second_deriv_wrt_product_factor( second_wrt_A, Winv ); } else { result = 0.0; second_wrt_A[0] = second_wrt_A[1] = second_wrt_A[2] = deriv_wrt_A = MsqMatrix<2,2>(0.0); } return true; }
bool Target3DShape::evaluate_with_hess( const MsqMatrix<3,3>& A, const MsqMatrix<3,3>& W, double& result, MsqMatrix<3,3>& deriv_wrt_A, MsqMatrix<3,3> second_wrt_A[6], MsqError& err ) { MsqMatrix<3,3> Winv = inverse(W); MsqMatrix<3,3> T = A * Winv; double f = Frobenius(T); double d = det(T); result = f*f*f - 3*MSQ_SQRT_THREE*d; deriv_wrt_A = T; deriv_wrt_A *= f; deriv_wrt_A -= MSQ_SQRT_THREE*transpose_adj(T); deriv_wrt_A *= 3; deriv_wrt_A = deriv_wrt_A * transpose(Winv); set_scaled_2nd_deriv_of_det( second_wrt_A, -3 * MSQ_SQRT_THREE, T ); pluseq_scaled_outer_product( second_wrt_A, 3.0/f, T ); pluseq_scaled_I( second_wrt_A, 3.0*f ); second_deriv_wrt_product_factor( second_wrt_A, Winv ); return true; }
/** \f$ \frac{\partial^2 \mu}{\partial T^2} = \frac{1}{\tau} I_4 - \frac{1}{\tau^2} \left( T \otimes \frac{\partial \tau}{\partial T} + \frac{\partial \tau}{\partial T} \otimes T \right) + \frac{|T|^2}{\tau^3} \left( \frac{\partial \tau}{\partial T} \otimes \frac{\partial \tau}{\partial T} \right) - \frac{|T|^2}{2 \tau^3} \frac{\partial^2 \tau}{\partial T^2} \f$ */ bool Target2DShapeBarrier::evaluate_with_hess( const MsqMatrix<2,2>& A, const MsqMatrix<2,2>& W, double& result, MsqMatrix<2,2>& deriv_wrt_A, MsqMatrix<2,2> second_wrt_A[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)) { // barrier result = 0.0; return false; } double inv_d = 1.0/d; double f1 = sqr_Frobenius(T) * inv_d; result = 0.5 * f1; const MsqMatrix<2,2> adjt = transpose_adj(T); deriv_wrt_A = T; deriv_wrt_A -= result * adjt; deriv_wrt_A *= inv_d; deriv_wrt_A = deriv_wrt_A * transpose(Winv); set_scaled_outer_product( second_wrt_A, f1 * inv_d * inv_d, adjt ); pluseq_scaled_sum_outer_product( second_wrt_A, -inv_d*inv_d, T, adjt ); pluseq_scaled_I( second_wrt_A, inv_d ); pluseq_scaled_2nd_deriv_of_det( second_wrt_A, -result * inv_d ); second_deriv_wrt_product_factor( second_wrt_A, Winv ); result -= 1.0; return true; }
bool Target3DShapeOrientBarrierAlt1::evaluate_with_Hess( const MsqMatrix<3,3>& A, const MsqMatrix<3,3>& W, double& result, MsqMatrix<3,3>& deriv_wrt_A, MsqMatrix<3,3> second_wrt_A[6], MsqError& err ) { MsqMatrix<3,3> Winv = inverse(W); MsqMatrix<3,3> T = A * Winv; double tau = det(T); if (invalid_determinant(tau)) { result = 0.0; return false; } const double b = 0.5/tau; // calculate non-barrier value (ShapeOrientAlt1) const double tr = trace(T); const double f = MSQ_ONE_THIRD * fabs(tr); result = sqr_Frobenius( T ) - f * tr; // calculate non-barrier first derivatives deriv_wrt_A = T; deriv_wrt_A(0,0) -= f; deriv_wrt_A(1,1) -= f; deriv_wrt_A(2,2) -= f; deriv_wrt_A *= 2; // calculate barrier second derivs const MsqMatrix<3,3> adjt = transpose_adj(T); set_scaled_sum_outer_product( second_wrt_A, -b/tau, deriv_wrt_A, adjt ); pluseq_scaled_outer_product( second_wrt_A, result/(tau*tau*tau), adjt ); pluseq_scaled_2nd_deriv_of_det( second_wrt_A, -result * b / tau, T ); // calculate non-barrier barrier portion of second derivs pluseq_scaled_I( second_wrt_A, 1/tau ); pluseq_scaled_outer_product_I_I( second_wrt_A, MSQ_ONE_THIRD/tau * (tr < 0 ? 1 : -1) ); // calculate barrier derivs from non-barrier deriv_wrt_A *= tau; deriv_wrt_A -= result * adjt; deriv_wrt_A *= b/tau; // barrier value from non-barrier result *= b; // convert from derivs wrt T to derivs wrt A deriv_wrt_A = deriv_wrt_A * transpose(Winv); second_deriv_wrt_product_factor( second_wrt_A, Winv ); return true; }
bool Target3DShapeSizeBarrierAlt1::evaluate_with_hess( const MsqMatrix<3,3>& A, const MsqMatrix<3,3>& W, double& result, MsqMatrix<3,3>& wrt_A, MsqMatrix<3,3> second[6], MsqError& err ) { const MsqMatrix<3,3> Winv = inverse(W); const MsqMatrix<3,3> T = A * Winv; const double tau = det(T); if (invalid_determinant(tau)) { // barrier result = 0.0; return false; } const double f = sqr_Frobenius(T); const double g = sqr_Frobenius(adj(T)); result = (f + g)/(6 * tau); MsqMatrix<3,3> dtau = transpose_adj(T); MsqMatrix<3,3> dg = -transpose(T) * T; dg(0,0) += f; dg(1,1) += f; dg(2,2) += f; dg = T * dg; dg *= 2; wrt_A = T; wrt_A += 0.5*dg; wrt_A *= 1.0/3.0; wrt_A -= result * dtau; wrt_A *= 1.0/tau; wrt_A = wrt_A * transpose(Winv); set_scaled_2nd_deriv_norm_sqr_adj( second, 1.0/6.0, T ); pluseq_scaled_I( second, 1.0/3.0 ); pluseq_scaled_sum_outer_product( second, -1./3./tau, T, dtau ); pluseq_scaled_sum_outer_product( second, -1./6./tau, dg, dtau ); pluseq_scaled_outer_product( second, 2*result/tau, dtau ); pluseq_scaled_2nd_deriv_of_det( second, -result, T ); hess_scale( second, 1.0/tau ); second_deriv_wrt_product_factor( second, Winv ); result -= 1.0; return true; }
bool Target2DShapeOrientBarrier::evaluate_with_hess( const MsqMatrix<2,2>& A, const MsqMatrix<2,2>& W, double& result, MsqMatrix<2,2>& deriv, MsqMatrix<2,2> second[3], MsqError& err ) { const MsqMatrix<2,2> Winv = inverse(W); const MsqMatrix<2,2> T = A * Winv; const double norm = Frobenius(T); const double invroot = 1.0/MSQ_SQRT_TWO; const double tau = det(T); if (invalid_determinant(tau)) { // barrier result = 0.0; return false; } const double inv_tau = 1.0/tau; const double invnorm = 1.0/norm; const double f = norm - invroot * trace(T); result = 0.5 * inv_tau * f; const MsqMatrix<2,2> adjt = transpose_adj(T); deriv = invnorm * T; deriv(0,0) -= invroot; deriv(1,1) -= invroot; deriv *= 0.5; deriv -= result * adjt; deriv *= inv_tau; deriv = deriv * transpose(Winv); const double a = 0.5 * inv_tau * invnorm; set_scaled_outer_product( second, -a*invnorm*invnorm, T ); pluseq_scaled_I( second, a ); pluseq_scaled_outer_product( second, f*inv_tau*inv_tau*inv_tau, adjt ); pluseq_scaled_2nd_deriv_of_det( second, -0.5*f*inv_tau*inv_tau ); pluseq_scaled_sum_outer_product( second, -0.5*inv_tau*inv_tau*invnorm, T, adjt ); pluseq_scaled_sum_outer_product_I( second, 0.5*inv_tau*inv_tau*invroot, adjt ); second_deriv_wrt_product_factor( second, Winv ); 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; }
bool TQualityMetric::evaluate_with_Hessian( PatchData& pd, size_t handle, double& value, std::vector<size_t>& indices, std::vector<Vector3D>& grad, std::vector<Matrix3D>& Hessian, 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 ); Hessian.resize( num_idx*(num_idx+1)/2 ); if (num_idx) hessian<3>( num_idx, mDerivs3D, d2mdT2, arrptr(Hessian) ); #ifdef PRINT_INFO print_info<3>( e, s, A, W, A * inverse(W) ); #endif } else if (edim == 2) { #ifdef NUMERICAL_2D_HESSIAN // return finite difference approximation for now return QualityMetric::evaluate_with_Hessian( pd, handle, value, indices, grad, Hessian, 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 ); // calculate 2D hessian second_deriv_wrt_product_factor( d2mdT2, Winv ); const size_t n = num_idx*(num_idx+1)/2; hess2d.resize(n); if (n) hessian<2>( num_idx, mDerivs2D, d2mdT2, arrptr(hess2d) ); // calculate surface hessian as transform of 2D hessian Hessian.resize(n); for (size_t i = 0; i < n; ++i) Hessian[i] = Matrix3D( (M * hess2d[i] * transpose(M)).data() ); #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), 0, arrptr(Hessian), err ); MSQ_ERRZERO(err); return rval; }