示例#1
0
MsqMatrix<3,2> LVQDTargetTest::target( const double* L, 
                                       const MsqMatrix<3,2>* V, 
                                       const MsqMatrix<2,2>* Q, 
                                       const MsqMatrix<2,2>* D )
{
  ConstantTarget W_size  ( L ? *L : 1.0, true );
  ConstantTarget W_orient( V ? *V : I32 );
  ConstantTarget W_skew  ( Q ? *Q : I22 );
  ConstantTarget W_aspect( D ? *D : I22 );
  LVQDTargetCalculator LVQD( L ? &W_size   : NULL,
                             V ? &W_orient : NULL,
                             Q ? &W_skew   : NULL,
                             D ? &W_aspect : NULL );
  MsqError err;
  MsqMatrix<3,2> W;
  bool v;
  if (!V) {
    MsqMatrix<2,2> W_2D;
    v = LVQD.get_2D_target( pd2D, 0, Sample(0,0), W_2D, err );
    W.set_row( 0, W_2D.row(0) );
    W.set_row( 1, W_2D.row(1) );
    W.set_row( 2, MsqMatrix<1,2>(0.0) );
  }
  else {
    v = LVQD.get_surface_target( pd2D, 0, Sample(0,0), W, err );
  }
  ASSERT_NO_ERROR(err);
  CPPUNIT_ASSERT(v);
  return W;
}
示例#2
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;
 }
void MappingFunction3D::ideal( Sample location,
                               MsqMatrix<3,3>& J,
                               MsqError& err ) const
{
  const Vector3D* coords = unit_element( element_topology(), true );
  if (!coords) {
     MSQ_SETERR(err)(MsqError::UNSUPPORTED_ELEMENT);
     return;
  }

  const unsigned MAX_VERTS = 8;
  MsqVector<3> d_coeff_d_xi[MAX_VERTS];
  size_t indices[MAX_VERTS], num_vtx = 0;
  derivatives( location, NodeSet(), indices,
               d_coeff_d_xi, num_vtx, err ); MSQ_ERRRTN(err);
  assert(num_vtx > 0 && num_vtx <= MAX_VERTS);
  
  J.zero();
  for (size_t r = 0; r < num_vtx; ++r) {
    MsqMatrix<3,1> c( coords[indices[r]].to_array() );
    J += c * transpose(d_coeff_d_xi[r]);
  }
  
  double size = Mesquite::cbrt(fabs(det(J)));
  assert(size > -1e-15); // no negative jacobians for ideal elements!
  divide( 1.0, size, size );
  J *= size;
}
示例#4
0
/* Do transform M_hat = S_a M_{3x2}, M_{2x2} Theta^-1 M_hat
 * where the plane into which we are projecting is orthogonal
 * to the passed u vector.
 */
static inline bool
project_to_perp_plane(  MsqMatrix<3,2> J,
                        const MsqVector<3>& u,
                        const MsqVector<3>& u_perp,
                        MsqMatrix<2,2>& A,
                        MsqMatrix<3,2>& S_a_transpose_Theta )
{
    MsqVector<3> n_a = J.column(0) * J.column(1);
    double sc, len = length(n_a);
    if (!divide(1.0, len, sc))
        return false;
    n_a *= sc;
    double ndot = n_a % u;
    double sigma = (ndot < 0.0) ? -1 : 1;
    double cosphi = sigma * ndot;
    MsqVector<3> cross = n_a * u;
    double sinphi = length(cross);

    MsqMatrix<3,2> Theta;
    Theta.set_column(0,   u_perp);
    Theta.set_column(1, u*u_perp);

    // If columns of J are not in plane orthogonal to u, then
    // rotate J such that they are.
    if (sinphi > 1e-12) {
        MsqVector<3> m = sigma * cross;
        MsqVector<3> n = (1/sinphi) * m;
        MsqVector<3> p = (1-cosphi) * n;
        double s_a[] =
        {   p[0]*n[0] + cosphi, p[0]*n[1] - m[2],   p[0]*n[2] + m[1],
            p[1]*n[0] + m[2],   p[1]*n[1] + cosphi, p[1]*n[2] - m[0],
            p[2]*n[0] - m[1],   p[2]*n[1] + m[0],   p[2]*n[2] + cosphi
        };
        MsqMatrix<3,3> S_a(s_a);
        J = S_a * J;
        S_a_transpose_Theta = transpose(S_a) * Theta;
    }
    else {
        S_a_transpose_Theta = Theta;
//    J *= sigma;
    }

    // Project to get 2x2 A from A_hat (which might be equal to J)
    A = transpose(Theta) * J;
    return true;
}
示例#5
0
template <class QMType> inline
void TMPQualityMetricTest<QMType>::test_evaluate_3D()
{
  MsqPrintError err(cout);
  PatchData pd;
  bool rval;
  double value;
  
  QMType m( &ideal, &faux_two );
  
    // test with aligned elements
  faux_two.count = 0;
  tester.get_ideal_element( HEXAHEDRON, true, pd );
  rval = m.evaluate( pd, 0, value, err );
  CPPUNIT_ASSERT(!MSQ_CHKERR(err));
  CPPUNIT_ASSERT(rval);
  CPPUNIT_ASSERT_DOUBLES_EQUAL( faux_two.value, value, DBL_EPSILON );
  CPPUNIT_ASSERT_EQUAL( 1, faux_two.count );
  
    // test that columns are orthogonal for ideal hex element
  MsqMatrix<3,3> A = faux_two.last_A_3D;
  CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, A.column(0) % A.column(1), 1e-6 );
  CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, A.column(0) % A.column(2), 1e-6 );
  CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, A.column(1) % A.column(2), 1e-6 );
  
    // test with rotated element
  faux_two.count = 0;
  tester.get_ideal_element( TETRAHEDRON, true, pd );
  // rotate by 90-degrees about X axis
  for (size_t i = 0; i < pd.num_nodes(); ++i) {
    Vector3D orig = pd.vertex_by_index(i);
    Vector3D newp( orig[0], -orig[2], orig[1] );
    pd.set_vertex_coordinates( newp, i, err );
  }
  rval = m.evaluate( pd, 0, value, err );
  CPPUNIT_ASSERT(!MSQ_CHKERR(err));
  CPPUNIT_ASSERT(rval);
  CPPUNIT_ASSERT_DOUBLES_EQUAL( faux_two.value, value, DBL_EPSILON );
  CPPUNIT_ASSERT_EQUAL( 1, faux_two.count );
}
示例#6
0
  void test_3d_eval_ortho_hex()
    {
      MsqPrintError err(cout);
      PatchData pd;
      bool rval;
      double value;

      QMType m( &ideal, &faux_zero );
      faux_zero.count = 0;

      tester.get_ideal_element( HEXAHEDRON, true, pd );
      rval = m.evaluate( pd, 0, value, err );
      CPPUNIT_ASSERT(!MSQ_CHKERR(err));
      CPPUNIT_ASSERT(rval);
      CPPUNIT_ASSERT_EQUAL( 1, faux_zero.count );

        // test that columns are orthogonal for ideal hex element
      MsqMatrix<3,3> A = faux_zero.last_A_3D;
      CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, A.column(0) % A.column(1), 1e-6 );
      CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, A.column(0) % A.column(2), 1e-6 );
      CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, A.column(1) % A.column(2), 1e-6 );
    }  
void JacobianCalculator::get_Jacobian_3D( const MappingFunction3D* mf,
                                          NodeSet ho_bits,
                                          Sample location,
                                          const Vector3D* verts,
                                          size_t num_type_vert,
                                          MsqMatrix<3,3>& J_out,
                                          MsqError& err )
{
  size_t num_vtx = 0;
  mf->derivatives( location, ho_bits, mIndices, mDerivs3D, num_vtx, err ); MSQ_ERRRTN(err);
  mf->convert_connectivity_indices( num_type_vert, mIndices, num_vtx, err ); MSQ_ERRRTN(err);
  const MsqVector<3>* d = mDerivs3D;
  const size_t* const e = mIndices + num_vtx;
  Vector3D c[3] = {Vector3D(0,0,0), Vector3D(0,0,0), Vector3D(0,0,0)};
  for (const size_t* i = mIndices; i != e; ++i, ++d) {
    c[0] += (*d)[0] * verts[*i];;
    c[1] += (*d)[1] * verts[*i];;
    c[2] += (*d)[2] * verts[*i];;
  }
  J_out.set_column( 0, MsqMatrix<3,1>(c[0].to_array()) );
  J_out.set_column( 1, MsqMatrix<3,1>(c[1].to_array()) );
  J_out.set_column( 2, MsqMatrix<3,1>(c[2].to_array()) );
}
示例#8
0
bool LambdaTarget::get_surface_target( PatchData& pd,
                                       size_t element,
                                       Sample sample,
                                       MsqMatrix<3,2>& W_out,
                                       MsqError& err )
{
    bool valid = lambdaSource->get_surface_target( pd, element, sample, W_out, err );
    if (MSQ_CHKERR(err) && !valid)
        return false;
    MsqVector<3> cross = W_out.column(0) * W_out.column(1);
    double det1 = cross % cross; // length squared

    valid = compositeSource->get_surface_target( pd, element, sample, W_out, err );
    if (MSQ_CHKERR(err) && !valid)
        return false;
    cross = W_out.column(0) * W_out.column(1);
    double det2 = cross % cross; // length squared

    if (det2 < 1e-15)
        return false;

    W_out *= sqrt( sqrt( det1/det2 ) );
    return true;
}
示例#9
0
bool AffineMapMetric::evaluate( PatchData& pd, size_t handle, double& value, MsqError& err )
{
  Sample s = ElemSampleQM::sample( handle );
  size_t e = ElemSampleQM::  elem( handle );
  MsqMeshEntity& elem = pd.element_by_index( e );
  EntityTopology type = elem.get_element_type();
  unsigned edim = TopologyInfo::dimension( type );
  const size_t* conn = elem.get_vertex_index_array();
  
    // This metric only supports sampling at corners, except for simplices.
    // If element is a simpex, then the Jacobian is constant over a linear 
    // element.  In this case, always evaluate at any vertex.
  //unsigned corner = s.number;
  if (s.dimension != 0) {
    if (type == TRIANGLE || type == TETRAHEDRON)
      /*corner = 0*/;
    else {
      MSQ_SETERR(err)("Invalid sample point for AffineMapMetric", MsqError::UNSUPPORTED_ELEMENT );
      return false;
    }
  }
  
  bool rval;
  if (edim == 3) { // 3x3 or 3x2 targets ?
    Vector3D c[3] = { Vector3D(0,0,0), Vector3D(0,0,0), Vector3D(0,0,0) };
    unsigned n;
    const unsigned* adj = TopologyInfo::adjacent_vertices( type, s.number, n );
    c[0] = pd.vertex_by_index( conn[adj[0]] ) - pd.vertex_by_index( conn[s.number] );
    c[1] = pd.vertex_by_index( conn[adj[1]] ) - pd.vertex_by_index( conn[s.number] );
    c[2] = pd.vertex_by_index( conn[adj[2]] ) - pd.vertex_by_index( conn[s.number] );
    MsqMatrix<3,3> A;
    A.set_column( 0, MsqMatrix<3,1>(c[0].to_array()) );
    A.set_column( 1, MsqMatrix<3,1>(c[1].to_array()) );
    A.set_column( 2, MsqMatrix<3,1>(c[2].to_array()) );
    if (type == TETRAHEDRON)
      A = A * TET_XFORM;

    MsqMatrix<3,3> W;
    targetCalc->get_3D_target( pd, e, s, W, err ); MSQ_ERRZERO(err);
    rval = targetMetric->evaluate( A * inverse(W), value, err ); MSQ_ERRZERO(err);
  }
  else {
    Vector3D c[2] = { Vector3D(0,0,0), Vector3D(0,0,0) };
    unsigned n;
    const unsigned* adj = TopologyInfo::adjacent_vertices( type, s.number, n );
    c[0] = pd.vertex_by_index( conn[adj[0]] ) - pd.vertex_by_index( conn[s.number] );
    c[1] = pd.vertex_by_index( conn[adj[1]] ) - pd.vertex_by_index( conn[s.number] );
    MsqMatrix<3,2> App;
    App.set_column( 0, MsqMatrix<3,1>(c[0].to_array()) );
    App.set_column( 1, MsqMatrix<3,1>(c[1].to_array()) );
    
    MsqMatrix<3,2> Wp;
    targetCalc->get_surface_target( pd, e, s, Wp, err ); MSQ_ERRZERO(err);

    MsqMatrix<2,2> A, W;
    MsqMatrix<3,2> RZ;
    surface_to_2d( App, Wp, W, RZ );
    A = transpose(RZ) * App;
    if (type == TRIANGLE)
      A = A * TRI_XFORM;
    
    rval = targetMetric->evaluate( A*inverse(W), value, err ); MSQ_ERRZERO(err);
  }
  
    // apply target weight to value
  if (weightCalc) {
    double ck = weightCalc->get_weight( pd, e, s, err ); MSQ_ERRZERO(err);
    value *= ck;
  }
  return rval;
}
示例#10
0
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;
}