void MSubTriangle::getGradShapeFunctions(double u, double v, double w, double s[][3], int order) const { if(!_orig) return; if (_orig->getDim()==getDim()) return _orig->getGradShapeFunctions(u, v, w, s, order); int nsf = getNumShapeFunctions(); double gradsuvw[1256][3]; _orig->getGradShapeFunctions(u, v, w, gradsuvw, order); // work in the parametric space of the parent element double jac[3][3]; double invjac[3][3]; _orig->getJacobian(u, v, w, jac); inv3x3(jac, invjac); MEdge edge[2]; edge[0] = getBaseElement()->getEdge(0); edge[1] = getBaseElement()->getEdge(1); SVector3 tang[2]; tang[0] = edge[0].tangent(); tang[1] = edge[1].tangent(); SVector3 vect = crossprod(tang[0],tang[1]); tang[1] = crossprod(vect,tang[0]); double gradxyz[3]; double projgradxyz[3]; for (int i=0; i<nsf; ++i) { // (i) get the cartesian coordinates of the gradient gradxyz[0] = invjac[0][0] * gradsuvw[i][0] + invjac[0][1] * gradsuvw[i][1] + invjac[0][2] * gradsuvw[i][2]; gradxyz[1] = invjac[1][0] * gradsuvw[i][0] + invjac[1][1] * gradsuvw[i][1] + invjac[1][2] * gradsuvw[i][2]; gradxyz[2] = invjac[2][0] * gradsuvw[i][0] + invjac[2][1] * gradsuvw[i][1] + invjac[2][2] * gradsuvw[i][2]; // (ii) projection of the gradient on edges in the cartesian space SVector3 grad(&gradxyz[0]); double prodscal[2]; prodscal[0] = dot(tang[0],grad); prodscal[1] = dot(tang[1],grad); projgradxyz[0] = prodscal[0]*tang[0].x() + prodscal[1]*tang[1].x(); projgradxyz[1] = prodscal[0]*tang[0].y() + prodscal[1]*tang[1].y(); projgradxyz[2] = prodscal[0]*tang[0].z() + prodscal[1]*tang[1].z(); // (iii) get the parametric coordinates of the projection in the parametric space of the parent element s[i][0] = jac[0][0] * projgradxyz[0] + jac[0][1] * projgradxyz[1] + jac[0][2] * projgradxyz[2]; s[i][1] = jac[1][0] * projgradxyz[0] + jac[1][1] * projgradxyz[1] + jac[1][2] * projgradxyz[2]; s[i][2] = jac[2][0] * projgradxyz[0] + jac[2][1] * projgradxyz[1] + jac[2][2] * projgradxyz[2]; } }
double qmTet(const double &x1, const double &y1, const double &z1, const double &x2, const double &y2, const double &z2, const double &x3, const double &y3, const double &z3, const double &x4, const double &y4, const double &z4, const qualityMeasure4Tet &cr, double *volume) { switch(cr){ case QMTET_ONE: return 1.0; case QMTET_3: { double mat[3][3]; mat[0][0] = x2 - x1; mat[0][1] = x3 - x1; mat[0][2] = x4 - x1; mat[1][0] = y2 - y1; mat[1][1] = y3 - y1; mat[1][2] = y4 - y1; mat[2][0] = z2 - z1; mat[2][1] = z3 - z1; mat[2][2] = z4 - z1; *volume = fabs(det3x3(mat)) / 6.; double l = ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1)); l += ((x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1) + (z3 - z1) * (z3 - z1)); l += ((x4 - x1) * (x4 - x1) + (y4 - y1) * (y4 - y1) + (z4 - z1) * (z4 - z1)); l += ((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2) + (z3 - z2) * (z3 - z2)); l += ((x4 - x2) * (x4 - x2) + (y4 - y2) * (y4 - y2) + (z4 - z2) * (z4 - z2)); l += ((x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4) + (z3 - z4) * (z3 - z4)); return 12. * pow(3 * fabs(*volume), 2. / 3.) / l; } case QMTET_2: { double mat[3][3]; mat[0][0] = x2 - x1; mat[0][1] = x3 - x1; mat[0][2] = x4 - x1; mat[1][0] = y2 - y1; mat[1][1] = y3 - y1; mat[1][2] = y4 - y1; mat[2][0] = z2 - z1; mat[2][1] = z3 - z1; mat[2][2] = z4 - z1; *volume = fabs(det3x3(mat)) / 6.; double p0[3] = {x1, y1, z1}; double p1[3] = {x2, y2, z2}; double p2[3] = {x3, y3, z3}; double p3[3] = {x4, y4, z4}; double s1 = fabs(triangle_area(p0, p1, p2)); double s2 = fabs(triangle_area(p0, p2, p3)); double s3 = fabs(triangle_area(p0, p1, p3)); double s4 = fabs(triangle_area(p1, p2, p3)); double rhoin = 3. * fabs(*volume) / (s1 + s2 + s3 + s4); double l = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1)); l = std::max(l, sqrt((x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1) + (z3 - z1) * (z3 - z1))); l = std::max(l, sqrt((x4 - x1) * (x4 - x1) + (y4 - y1) * (y4 - y1) + (z4 - z1) * (z4 - z1))); l = std::max(l, sqrt((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2) + (z3 - z2) * (z3 - z2))); l = std::max(l, sqrt((x4 - x2) * (x4 - x2) + (y4 - y2) * (y4 - y2) + (z4 - z2) * (z4 - z2))); l = std::max(l, sqrt((x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4) + (z3 - z4) * (z3 - z4))); return 2. * sqrt(6.) * rhoin / l; } break; case QMTET_COND: { /// condition number is defined as (see Knupp & Freitag in IJNME) double INVW[3][3] = {{1,-1./sqrt(3.),-1./sqrt(6.)},{0,2/sqrt(3.),-1./sqrt(6.)},{0,0,sqrt(1.5)}}; double A[3][3] = {{x2-x1,y2-y1,z2-z1},{x3-x1,y3-y1,z3-z1},{x4-x1,y4-y1,z4-z1}}; double S[3][3],INVS[3][3]; matmat(A,INVW,S); *volume = inv3x3(S,INVS) * 0.70710678118654762;//2/sqrt(2); double normS = norm2 (S); double normINVS = norm2 (INVS); return normS * normINVS; } default: Msg::Error("Unknown quality measure"); return 0.; } }