Beispiel #1
0
 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;
}