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()) ); }
/* 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; }
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; }