diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp index a9fc13c6bd4b4db88c5d8c82a7108417ffc8bec5..dcc9c52a2ebb2c603f93284d02a6b1f03f01225f 100644 --- a/Geo/MElement.cpp +++ b/Geo/MElement.cpp @@ -22,7 +22,7 @@ #include "GEntity.h" #include "StringUtils.h" #include "Numeric.h" -#include "MetricBasis.h" +#include "CondNumBasis.h" #include "Context.h" #define SQU(a) ((a)*(a)) @@ -322,6 +322,52 @@ void MElement::idealJacRange(double &jmin, double &jmax, GEntity *ge) #endif } +void MElement::invCondNumRange(double &iCNMin, double &iCNMax, GEntity *ge) +{ + iCNMin = iCNMax = 1.0; +#if defined(HAVE_MESH) + const CondNumBasis *cnb = BasisFactory::getCondNumBasis(getTypeForMSH()); + const int numCNNodes = cnb->getNumCondNumNodes(); + fullMatrix<double> nodesXYZ(cnb->getNumMapNodes(), 3), normals; + getNodesCoord(nodesXYZ); + if (getDim() == 2.) { + SVector3 nVec = getFace(0).normal(); + normals.resize(1, 3); + normals(0, 0) = nVec[0]; normals(0, 1) = nVec[1]; normals(0, 2) = nVec[2]; + } + if (ge && (ge->dim() == 2) && ge->haveParametrization()) { + // If parametrized surface entity provided... + SVector3 geoNorm(0., 0., 0.); + // ... correct Jacobian sign with geometrical normal + for (int i=0; i<getNumPrimaryVertices(); i++) { + const MVertex *vert = getVertex(i); + if (vert->onWhat() == ge) { + double u, v; + vert->getParameter(0, u); + vert->getParameter(1, v); + geoNorm += ((GFace*)ge)->normal(SPoint2(u, v)); + } + } + if (geoNorm.normSq() == 0.) { + // If no vertex on surface or average is zero, take normal at barycenter + SPoint2 param = ((GFace*)ge)->parFromPoint(barycenter(true), false); + geoNorm = ((GFace*)ge)->normal(param); + } + const double dp = geoNorm(0) * normals(0, 0) + geoNorm(1) * normals(0, 1) + + geoNorm(2) * normals(0, 2); + if (dp < 0.) { + normals(0, 0) = -normals(0, 0); + normals(0, 1) = -normals(0, 1); + normals(0, 2) = -normals(0, 2); + } + } + fullVector<double> invCondNum(numCNNodes); + cnb->getSignedInvCondNum(nodesXYZ, normals, invCondNum); + iCNMin = *std::min_element(invCondNum.getDataPtr(), invCondNum.getDataPtr()+numCNNodes); + iCNMax = *std::max_element(invCondNum.getDataPtr(), invCondNum.getDataPtr()+numCNNodes); +#endif +} + void MElement::getNode(int num, double &u, double &v, double &w) const { // only for MElements that don't have a lookup table for this diff --git a/Geo/MElement.h b/Geo/MElement.h index 5b92db8693879d5d932fa0b1347b3211e6a04636..1ce7cfdeb6e6a5dfa6bc8bbfa45234f14f3b2da2 100644 --- a/Geo/MElement.h +++ b/Geo/MElement.h @@ -17,6 +17,7 @@ #include "nodalBasis.h" #include "polynomialBasis.h" #include "JacobianBasis.h" +#include "MetricBasis.h" #include "GaussIntegration.h" class GModel; @@ -204,6 +205,7 @@ class MElement virtual double angleShapeMeasure() { return 1.0; } virtual void scaledJacRange(double &jmin, double &jmax, GEntity *ge = 0) const; virtual void idealJacRange(double &jmin, double &jmax, GEntity *ge = 0); + virtual void invCondNumRange(double &iCNMin, double &iCNMax, GEntity *ge = 0); virtual double metricShapeMeasure(); virtual double metricShapeMeasure2(); diff --git a/Numeric/BasisFactory.cpp b/Numeric/BasisFactory.cpp index d5678f959dd998ca1ce1148913954ee97269fc0e..d2ea64588dfc226611ac108f1a6856915bb3a290 100644 --- a/Numeric/BasisFactory.cpp +++ b/Numeric/BasisFactory.cpp @@ -9,11 +9,13 @@ #include "pyramidalBasis.h" #include "miniBasis.h" #include "MetricBasis.h" +#include "CondNumBasis.h" #include <map> #include <cstddef> std::map<int, nodalBasis*> BasisFactory::fs; std::map<int, MetricBasis*> BasisFactory::ms; +std::map<int, CondNumBasis*> BasisFactory::cs; std::map<FuncSpaceData, JacobianBasis*> BasisFactory::js; std::map<FuncSpaceData, bezierBasis*> BasisFactory::bs; std::map<FuncSpaceData, GradientBasis*> BasisFactory::gs; @@ -89,6 +91,16 @@ const MetricBasis* BasisFactory::getMetricBasis(int tag) return M; } +const CondNumBasis* BasisFactory::getCondNumBasis(int tag) +{ + std::map<int, CondNumBasis*>::const_iterator it = cs.find(tag); + if (it != cs.end()) return it->second; + + CondNumBasis* M = new CondNumBasis(tag); + cs.insert(std::make_pair(tag, M)); + return M; +} + const GradientBasis* BasisFactory::getGradientBasis(FuncSpaceData data) { std::map<FuncSpaceData, GradientBasis*>::const_iterator it = gs.find(data); diff --git a/Numeric/BasisFactory.h b/Numeric/BasisFactory.h index 9d5ac2accac357c525db645a07f8a4c59a24d80e..ad408f48b7397b3819fc02078dca533e7188c4cf 100644 --- a/Numeric/BasisFactory.h +++ b/Numeric/BasisFactory.h @@ -12,12 +12,14 @@ class nodalBasis; class MetricBasis; class GradientBasis; class bezierBasis; +class CondNumBasis; class BasisFactory { private: static std::map<int, nodalBasis*> fs; static std::map<int, MetricBasis*> ms; + static std::map<int, CondNumBasis*> cs; static std::map<FuncSpaceData, JacobianBasis*> js; static std::map<FuncSpaceData, bezierBasis*> bs; static std::map<FuncSpaceData, GradientBasis*> gs; @@ -51,6 +53,9 @@ class BasisFactory // Metric static const MetricBasis* getMetricBasis(int tag); + // Condition number + static const CondNumBasis* getCondNumBasis(int tag); + // Gradients static const GradientBasis* getGradientBasis(FuncSpaceData); static const GradientBasis* getGradientBasis(int tag, int order) { diff --git a/Numeric/CMakeLists.txt b/Numeric/CMakeLists.txt index a865d9416e241c08fc6e9a934147d0bf846ba9dd..0cc2843650854b7a223a489eb8beed6e2bd09e43 100644 --- a/Numeric/CMakeLists.txt +++ b/Numeric/CMakeLists.txt @@ -19,6 +19,7 @@ set(SRC bezierBasis.cpp JacobianBasis.cpp MetricBasis.cpp + CondNumBasis.cpp pointsGenerators.cpp ElementType.cpp GaussIntegration.cpp diff --git a/Numeric/CondNumBasis.cpp b/Numeric/CondNumBasis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce48ccef9902f8062aedd6edcca2274cf337fa9d --- /dev/null +++ b/Numeric/CondNumBasis.cpp @@ -0,0 +1,584 @@ +// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to the public mailing list <gmsh@geuz.org>. + +#include "CondNumBasis.h" + +#include "GmshDefines.h" +#include "GmshMessage.h" + +#include <vector> +#include "polynomialBasis.h" +#include "pyramidalBasis.h" +#include "pointsGenerators.h" +#include "BasisFactory.h" +#include "Numeric.h" + + +namespace { + + +// Compute the determinant of a 3x3 matrix +inline double calcDet3x3(double M11, double M12, double M13, + double M21, double M22, double M23, + double M31, double M32, double M33) +{ + return M11 * (M22*M33 - M23*M32) + - M12 * (M21*M33 - M23*M31) + + M13 * (M21*M32 - M22*M31); +} + + +// Compute the squared Frobenius norm of the inverse of a matrix +template<bool sign> +inline double calcInvCondNum2D(double dxdX, double dxdY, + double dydX, double dydY, + double dzdX, double dzdY, + double nx, double ny, double nz) +{ + static const double Eps = 1e-10; + const double dxdXSq = dxdX*dxdX, dydXSq = dydX*dydX, dzdXSq = dzdX*dzdX; + const double dxdYSq = dxdY*dxdY, dydYSq = dydY*dydY, dzdYSq = dzdY*dzdY; + const double Dx = dxdXSq - dxdYSq, Dy = dydXSq - dydYSq; + const double Cx = dxdX * dxdY, Cy = dydX * dydY; + const double S1 = dzdYSq * dzdYSq; + const double S2 = (dzdXSq - Dy - Dx) * dzdYSq; + const double S3 = (Cy + Cx) * dzdX * dzdY; + const double S4 = dzdXSq * dzdXSq; + const double S5 = (Dy + Dx) * dzdXSq; + const double S6 = Cx * Cy; + const double S7 = dydXSq * dydXSq; + const double S8 = Dy*dydXSq; + const double S9 = dxdXSq * dxdXSq; + const double S10 = Dx*dxdXSq; + const double S11 = Dy*Dy; + const double S12 = Dx*Dy; + const double S13 = Dx*Dx; + const double S = 2.*(S2+S5+S12)+ 4.*(S7-S8+S9-S10) + 8.*(S3+S6) + S1+S4+S11+S13; + const double N = dxdXSq + dxdYSq + dydXSq + dydYSq + dzdXSq + dzdYSq; + const double sqrtS = sqrt(S); + const double sigma1Sq = 0.5 * (N + sqrtS), sigma2Sq = 0.5 * (N - sqrtS); + if (sigma2Sq < Eps) return 0.; + const double iCN = 2. / sqrt((sigma1Sq + sigma2Sq) * (1./sigma1Sq + 1./sigma2Sq)); + if (sign) { + const double lnx = dydX*dzdY - dzdX*dydY, lny = dzdX*dxdY - dxdX*dzdY, // Local normal from mapping gradients + lnz = dxdX*dydY - dydX*dxdY; + const double dp = lnx*nx + lny*ny + lnz*nz; // Dot product to determine element validity + if (dp == 0.) return 0.; + return (dp > 0.) ? iCN : -iCN; + } + else + return iCN; +// return std::min(sqrt(sigma1Sq), sqrt(sigma2Sq)) / std::max(sqrt(sigma1Sq), sqrt(sigma2Sq)); +} + + +// Compute the squared Frobenius norm of the inverse of a matrix +template<bool sign> +inline double calcInvCondNum3D(double J11, double J12, double J13, + double J21, double J22, double J23, + double J31, double J32, double J33) +{ + const double D = calcDet3x3(J11, J12, J13, J21, J22, J23, J31, J32, J33); + if (D == 0.) return 0.; + const double I11 = J22*J33-J23*J32, I12 = J13*J32-J12*J33, I13 = J12*J23-J13*J22, + I21 = J23*J31-J21*J33, I22 = J11*J33-J13*J31, I23 = J13*J21-J11*J23, + I31 = J21*J32-J22*J31, I32 = J12*J31-J11*J32, I33 = J11*J22-J12*J21; + const double nSqJ = J11*J11 + J12*J12 + J13*J13 + + J21*J21 + J22*J22 + J23*J23 + + J31*J31 + J32*J32 + J33*J33; + const double nSqDInvJ = I11*I11 + I12*I12 + I13*I13 + + I21*I21 + I22*I22 + I23*I23 + + I31*I31 + I32*I32 + I33*I33; + if (sign) + return 3.*D/sqrt(nSqJ*nSqDInvJ); + else + return 3.*std::fabs(D)/sqrt(nSqJ*nSqDInvJ); +} + + +// Compute condition number and its gradients +// w.r.t. node positions, at one location in a 2D element +template<bool sign> +inline void calcGradInvCondNum2D(double dxdX, double dxdY, + double dydX, double dydY, + double dzdX, double dzdY, + double nx, double ny, double nz, + int i, int numMapNodes, + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + fullMatrix<double> &IDI) +{ + static const double Eps = 1e-10; + + bool posJac = true; + if (sign) { + const double lnx = dydX*dzdY - dzdX*dydY, lny = dzdX*dxdY - dxdX*dzdY, // Local normal from mapping gradients + lnz = dxdX*dydY - dydX*dxdY; + const double dp = lnx*nx + lny*ny + lnz*nz; // Dot product to determine element validity + posJac = (dp > 0.); + } + + const double dxdXSq = dxdX*dxdX, dydXSq = dydX*dydX, dzdXSq = dzdX*dzdX; + const double dxdYSq = dxdY*dxdY, dydYSq = dydY*dydY, dzdYSq = dzdY*dzdY; + const double Dx = dxdXSq - dxdYSq, Dy = dydXSq - dydYSq; + const double Cx = dxdX * dxdY, Cy = dydX * dydY; + const double S1 = dzdYSq * dzdYSq; + const double S2 = (dzdXSq - Dy - Dx) * dzdYSq; + const double S3 = (Cy + Cx) * dzdX * dzdY; + const double S4 = dzdXSq * dzdXSq; + const double S5 = (Dy + Dx) * dzdXSq; + const double S6 = Cx * Cy; + const double S7 = dydXSq * dydXSq; + const double S8 = Dy*dydXSq; + const double S9 = dxdXSq * dxdXSq; + const double S10 = Dx*dxdXSq; + const double S11 = Dy*Dy; + const double S12 = Dx*Dy; + const double S13 = Dx*Dx; + const double S = 2.*(S2+S5+S12)+ 4.*(S7-S8+S9-S10) + 8.*(S3+S6) + S1+S4+S11+S13; + if (S < Eps) { // S == 0. -> Ideal element + for (int j = 0; j<3*numMapNodes; j++) IDI(i, j) = 0.; + IDI(i, 3*numMapNodes) = posJac ? 1. : -1.; + return; + } + const double N = dxdXSq + dxdYSq + dydXSq + dydYSq + dzdXSq + dzdYSq; + const double sqrtS = sqrt(S), invSqrtS = 1./sqrtS; + const double sigma1Sq = 0.5 * (N + sqrtS), sigma2Sq = 0.5 * (N - sqrtS); +// if (sigma2Sq < Eps) { // TODO: Degenerate element (sigma2 == 0.) +// const double dnx = dydX*nz - dzdX*ny, dny = dzdX*nx - dxdX*nz, +// dnz = dxdX*ny - dydX*nx; +// +// } + const double invSigma1Sq = 1./sigma1Sq; + const double invSigma2Sq = 1./sigma2Sq; + const double invProd = 1. / ((sigma1Sq + sigma2Sq) * (invSigma1Sq + invSigma2Sq)); + const double invSqrtProd = sqrt(invProd); + IDI(i, 3*numMapNodes) = posJac ? 2. * invSqrtProd : -2. * invSqrtProd; +// std::cout << "DBGTT: Value " << i << "\n"; +// std::cout << "DBGTT: -> I = " << IDI(i, 3*numMapNodes) << "\n"; +// std::cout << "DBGTT: -> S = " << S << ", sqrt(S) = " << sqrtS << "\n"; +// std::cout << "DBGTT: -> N = " << N << "\n"; +// std::cout << "DBGTT: -> sigma1Sq, sigma2Sq = (" << sigma1Sq << ", " << sigma2Sq << ")\n"; + + for (int j = 0; j < numMapNodes; j++) { + const double &dPhidX = gSMatX(i, j); + const double &dPhidY = gSMatY(i, j); +// std::cout << "DBGTT: -> Node " << j << ":\n"; + + const double ddxdXSqdxj = 2.*dPhidX*dxdX, ddxdYSqdxj = 2.*dPhidY*dxdY; + const double dDxdxj = ddxdXSqdxj - ddxdYSqdxj; + const double dCxdxj = dPhidX*dxdY + dxdX*dPhidY; + const double dS2dxj = -dDxdxj * dzdYSq; + const double dS3dxj = dCxdxj * dzdX * dzdY; + const double dS5dxj = dDxdxj * dzdXSq; + const double dS6dxj = dCxdxj * Cy; + const double dS9dxj = 2. * ddxdXSqdxj * dxdXSq; + const double dS10dxj = dDxdxj*dxdXSq + Dx*ddxdXSqdxj; + const double dS12dxj = dDxdxj * Dy; + const double dS13dxj = 2. * dDxdxj* Dx; + const double dSdxj = 2.*(dS2dxj+dS5dxj+dS12dxj)+ 4.*(dS9dxj-dS10dxj) + + 8.*(dS3dxj+dS6dxj) + dS13dxj; + const double dNdxj = ddxdXSqdxj + ddxdYSqdxj; + const double dsqrtSdxj = 0.5*dSdxj*invSqrtS; + const double dsigma1Sqdxj = 0.5 * (dNdxj + dsqrtSdxj), + dsigma2Sqdxj = 0.5 * (dNdxj - dsqrtSdxj); + const double dinvSigma1Sqdxj = -dsigma1Sqdxj*invSigma1Sq*invSigma1Sq, + dinvSigma2Sqdxj = -dsigma2Sqdxj*invSigma2Sq*invSigma2Sq; + const double dProddxj = (dsigma1Sqdxj + dsigma2Sqdxj) * (invSigma1Sq + invSigma2Sq) + + (sigma1Sq + sigma2Sq) * (dinvSigma1Sqdxj + dinvSigma2Sqdxj); + const double mdiCNdxj = dProddxj*invProd*invSqrtProd; + IDI(i, j) = posJac ? -mdiCNdxj : mdiCNdxj; +// std::cout << "DBGTT: -> d(dxdX)dxj = " << dPhidX << ", d(dxdY)dxj = " << dPhidY << "\n"; +// std::cout << "DBGTT: -> dNdxj = " << dNdxj << ", dSdxj = " << dSdxj << "\n"; +// std::cout << "DBGTT: -> dsigma1Sqdxj = " << dsigma1Sqdxj << ", dsigma2Sqdxj = " << dsigma2Sqdxj << "\n"; +// std::cout << "DBGTT: -> dinvSigma1Sqdxj = " << dinvSigma1Sqdxj << ", dinvSigma2Sqdxj = " << dinvSigma2Sqdxj << "\n"; +// std::cout << "DBGTT: -> mdiCNdxj = " << mdiCNdxj +// << ", -dsigma2Sqdxj/sqrt(sigma1Sq*sigma2Sq) = " << -dsigma2Sqdxj/sqrt(sigma1Sq*sigma2Sq) +// << ", T1 = " << -dNdxj/sqrt(N*N-S) << ", T21 = " << (0.5*dSdxj/sqrtS)/sqrt(N*N-S) << "\n"; + + const double ddydXSqdyj = 2.*dPhidX*dydX, ddydYSqdyj = 2.*dPhidY*dydY; + const double dDydyj = ddydXSqdyj - ddydYSqdyj; + const double dCydyj = dPhidX*dydY + dydX*dPhidY; + const double dS2dyj = -dDydyj * dzdYSq; + const double dS3dyj = dCydyj * dzdX * dzdY; + const double dS5dyj = dDydyj * dzdXSq; + const double dS6dyj = Cx * dCydyj; + const double dS7dyj = 2. * ddydXSqdyj * dydXSq; + const double dS8dyj = dDydyj*dydXSq + Dy*ddydXSqdyj; + const double dS11dyj = 2. * dDydyj * Dy; + const double dS12dyj = Dx* dDydyj; + const double dSdyj = 2.*(dS2dyj+dS5dyj+dS12dyj)+ 4.*(dS7dyj-dS8dyj) + + 8.*(dS3dyj+dS6dyj) + dS11dyj; + const double dNdyj = ddydXSqdyj + ddydYSqdyj; + const double dsqrtSdyj = 0.5*dSdyj*invSqrtS; + const double dsigma1Sqdyj = 0.5 * (dNdyj + dsqrtSdyj), + dsigma2Sqdyj = 0.5 * (dNdyj - dsqrtSdyj); + const double dinvSigma1Sqdyj = -dsigma1Sqdyj*invSigma1Sq*invSigma1Sq, + dinvSigma2Sqdyj = -dsigma2Sqdyj*invSigma2Sq*invSigma2Sq; + const double dProddyj = (dsigma1Sqdyj + dsigma2Sqdyj) * (invSigma1Sq + invSigma2Sq) + + (sigma1Sq + sigma2Sq) * (dinvSigma1Sqdyj + dinvSigma2Sqdyj); + const double mdiCNdyj = dProddyj*invProd*invSqrtProd; + IDI(i, j+numMapNodes) = posJac ? -mdiCNdyj : mdiCNdyj; +// std::cout << "DBGTT: -> d(dydX)dyj = " << dPhidX << ", d(dydY)dyj = " << dPhidY << "\n"; +// std::cout << "DBGTT: -> dNdyj = " << dNdyj << ", dSdyj = " << dSdyj << "\n"; +// std::cout << "DBGTT: -> dsigma1Sqdyj = " << dsigma1Sqdyj << ", dsigma2Sqdyj = " << dsigma2Sqdyj << "\n"; +// std::cout << "DBGTT: -> dinvSigma1Sqdyj = " << dinvSigma1Sqdyj << ", dinvSigma2Sqdyj = " << dinvSigma2Sqdyj << "\n"; + + const double ddzdXSqdzj = 2.*dPhidX*dzdX, ddzdYSqdzj = 2.*dPhidY*dzdY; + const double dS1dzj = 2. * ddzdYSqdzj * dzdYSq; + const double dS2dzj = (dzdXSq - Dy - Dx) * ddzdYSqdzj; + const double dS3dzj = (Cy + Cx) * + (ddzdXSqdzj*dzdY + dzdX*ddzdYSqdzj); + const double dS4dzj = 2. * ddzdXSqdzj * dzdXSq; + const double dS5dzj = (Dy + Dx) * ddzdXSqdzj; + const double dSdzj = 2.*(dS2dzj+dS5dzj) + 8.*dS3dzj + dS1dzj+dS4dzj; + const double dNdzj = ddzdXSqdzj + ddzdYSqdzj; + const double dsqrtSdzj = 0.5*dSdzj*invSqrtS; + const double dsigma1Sqdzj = 0.5 * (dNdzj + dsqrtSdzj), + dsigma2Sqdzj = 0.5 * (dNdzj - dsqrtSdzj); + const double dinvSigma1Sqdzj = -dsigma1Sqdzj*invSigma1Sq*invSigma1Sq, + dinvSigma2Sqdzj = -dsigma2Sqdzj*invSigma2Sq*invSigma2Sq; + const double dProddzj = (dsigma1Sqdzj + dsigma2Sqdzj) * (invSigma1Sq + invSigma2Sq) + + (sigma1Sq + sigma2Sq) * (dinvSigma1Sqdzj + dinvSigma2Sqdzj); + const double mdiCNdzj = dProddzj*invProd*invSqrtProd; + IDI(i, j+2*numMapNodes) = posJac ? -mdiCNdzj : mdiCNdzj; +// std::cout << "DBGTT: -> d(dzdX)dzj = " << dPhidX << ", d(dzdY)dzj = " << dPhidY << "\n"; +// std::cout << "DBGTT: -> dNdzj = " << dNdzj << ", dSdzj = " << dSdzj << "\n"; +// std::cout << "DBGTT: -> dsigma1Sqdzj = " << dsigma1Sqdzj << ", dsigma2Sqdzj = " << dsigma2Sqdzj << "\n"; +// std::cout << "DBGTT: -> dinvSigma1Sqdzj = " << dinvSigma1Sqdzj << ", dinvSigma2Sqdzj = " << dinvSigma2Sqdzj << "\n"; +// std::cout << "DBGTT: -> dId{x,y,z} = (" << IDI(i, j) << ", " +// << IDI(i, j+numMapNodes) << ", " << IDI(i, j+2*numMapNodes) << ")\n"; + } +} + + +// Compute condition number and its gradients +// w.r.t. node positions, at one location in a 3D element +template<bool sign> +inline void calcGradInvCondNum3D(double dxdX, double dxdY, double dxdZ, + double dydX, double dydY, double dydZ, + double dzdX, double dzdY, double dzdZ, + int i, int numMapNodes, + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + const fullMatrix<double> &gSMatZ, + fullMatrix<double> &IDI) +{ + const double normJSq = dxdX*dxdX + dxdY*dxdY + dxdZ*dxdZ + + dydX*dydX + dydY*dydY + dydZ*dydZ + + dzdX*dzdX + dzdY*dzdY + dzdZ*dzdZ; + const double I11 = dydY*dzdZ - dydZ*dzdY, I12 = dxdZ*dzdY - dxdY*dzdZ, + I13 = dxdY*dydZ - dxdZ*dydY, I21 = dydZ*dzdX - dydX*dzdZ, + I22 = dxdX*dzdZ - dxdZ*dzdX, I23 = dxdZ*dydX - dxdX*dydZ, + I31 = dydX*dzdY - dydY*dzdX, I32 = dxdY*dzdX - dxdX*dzdY, + I33 = dxdX*dydY - dxdY*dydX; + const double normISq = I11*I11 + I12*I12 + I13*I13 + + I21*I21 + I22*I22 + I23*I23 + + I31*I31 + I32*I32 + I33*I33; + const double invProd = 1./(normJSq*normISq), invSqrtProd = sqrt(invProd); + const double D = calcDet3x3(dxdX, dxdY, dxdZ, + dydX, dydY, dydZ, + dzdX, dzdY, dzdZ); + const bool reverse = (!sign && (D < 0.)); + const double sICN = 3.*D*invSqrtProd; + IDI(i, 3*numMapNodes) = reverse ? -sICN : sICN; + + for (int j = 0; j < numMapNodes; j++) { + const double &dPhidX = gSMatX(i, j); + const double &dPhidY = gSMatY(i, j); + const double &dPhidZ = gSMatZ(i, j); + + const double dNormJSqdxj = 2.*(dPhidX*dxdX + dPhidY*dxdY + dPhidZ*dxdZ); + const double dNormISqdxj = 2.*((dPhidZ*dzdY - dPhidY*dzdZ)*I12 + (dPhidY*dydZ - dPhidZ*dydY)*I13 + + (dPhidX*dzdZ - dPhidZ*dzdX)*I22 + (dPhidZ*dydX - dPhidX*dydZ)*I23 + + (dPhidY*dzdX - dPhidX*dzdY)*I32 + (dPhidX*dydY - dPhidY*dydX)*I33); + const double dProddxj = dNormJSqdxj*normISq + dNormISqdxj*normJSq; + const double dDdxj = dPhidX * dydY * dzdZ + dzdX * dPhidY * dydZ + + dydX * dzdY * dPhidZ - dzdX * dydY * dPhidZ - + dPhidX * dzdY * dydZ - dydX * dPhidY * dzdZ; + const double dsICNdxj = 3. * (dDdxj*invSqrtProd - 0.5*D*dProddxj*invProd*invSqrtProd); + IDI(i, j) = reverse ? -dsICNdxj : dsICNdxj; + + const double dNormJSqdyj = 2.*(dPhidX*dydX + dPhidY*dydY + dPhidZ*dydZ); + const double dNormISqdyj = 2.*((dPhidY*dzdZ - dPhidZ*dzdY)*I11 + (dxdY*dPhidZ - dxdZ*dPhidY)*I13 + + (dPhidZ*dzdX - dPhidX*dzdZ)*I21 + (dxdZ*dPhidX - dxdX*dPhidZ)*I23 + + (dPhidX*dzdY - dPhidY*dzdX)*I31 + (dxdX*dPhidY - dxdY*dPhidX)*I33); + const double dProddyj = dNormJSqdyj*normISq + dNormISqdyj*normJSq; + const double dDdyj = dxdX * dPhidY * dzdZ + dzdX * dxdY * dPhidZ + + dPhidX * dzdY * dxdZ - dzdX * dPhidY * dxdZ - + dxdX * dzdY * dPhidZ - dPhidX * dxdY * dzdZ; + const double dsICNdyj = 3. * (dDdyj*invSqrtProd - 0.5*D*dProddyj*invProd*invSqrtProd); + IDI(i, j+numMapNodes) = reverse ? -dsICNdyj : dsICNdyj; + + const double dNormJSqdzj = 2.*(dPhidX*dzdX + dPhidY*dzdY + dPhidZ*dzdZ); + const double dNormISqdzj = 2.*((dydY*dPhidZ - dydZ*dPhidY)*I11 + (dxdZ*dPhidY - dxdY*dPhidZ)*I12 + + (dydZ*dPhidX - dydX*dPhidZ)*I21 + (dxdX*dPhidZ - dxdZ*dPhidX)*I22 + + (dydX*dPhidY - dydY*dPhidX)*I31 + (dxdY*dPhidX - dxdX*dPhidY)*I32); + const double dProddzj = dNormJSqdzj*normISq + dNormISqdzj*normJSq; + const double dDdzj = dxdX * dydY * dPhidZ + dPhidX * dxdY * dydZ + + dydX * dPhidY * dxdZ - dPhidX * dydY * dxdZ - + dxdX * dPhidY * dydZ - dydX * dxdY * dPhidZ; + const double dsICNdzj = 3. * (dDdzj*invSqrtProd - 0.5*D*dProddzj*invProd*invSqrtProd); + IDI(i, j+2*numMapNodes) = reverse ? -dsICNdzj : dsICNdzj; + } +} + + +} + + +CondNumBasis::CondNumBasis(int tag, int cnOrder) : + _tag(tag), _dim(ElementType::DimensionFromTag(tag)), + _condNumOrder(cnOrder >= 0 ? cnOrder : condNumOrder(tag)) +{ + const bool serendip = false; + FuncSpaceData data(true, tag, _condNumOrder, &serendip); + + _gradBasis = BasisFactory::getGradientBasis(data); + + fullMatrix<double> lagPoints; // Sampling points + gmshGeneratePoints(data, lagPoints); + _nCondNumNodes = lagPoints.size1(); + _nMapNodes = BasisFactory::getNodalBasis(tag)->getNumShapeFunctions(); + + // Store shape function gradients of mapping at condition number nodes + _gradBasis = BasisFactory::getGradientBasis(tag, _condNumOrder); + + // Compute shape function gradients of primary mapping at barycenter, + // in order to compute normal to straight element + const int parentType = ElementType::ParentTypeFromTag(tag); + const int primMapType = ElementType::getTag(parentType, 1, false); + const nodalBasis *primMapBasis = BasisFactory::getNodalBasis(primMapType); + _nPrimMapNodes = primMapBasis->getNumShapeFunctions(); + + double xBar = 0., yBar = 0., zBar = 0.; + double barycenter[3] = {0., 0., 0.}; + for (int i = 0; i < _nPrimMapNodes; i++) { + for (int j = 0; j < primMapBasis->points.size2(); ++j) { + barycenter[j] += primMapBasis->points(i, j); + } + } + barycenter[0] /= _nPrimMapNodes; + barycenter[1] /= _nPrimMapNodes; + barycenter[2] /= _nPrimMapNodes; + + double (*barDPsi)[3] = new double[_nPrimMapNodes][3]; + primMapBasis->df(xBar, yBar, zBar, barDPsi); + + // TODO: Make primGradShape from ideal element + primGradShapeBarycenterX.resize(_nPrimMapNodes); + primGradShapeBarycenterY.resize(_nPrimMapNodes); + primGradShapeBarycenterZ.resize(_nPrimMapNodes); + for (int j=0; j<_nPrimMapNodes; j++) { + primGradShapeBarycenterX(j) = barDPsi[j][0]; + primGradShapeBarycenterY(j) = barDPsi[j][1]; + primGradShapeBarycenterZ(j) = barDPsi[j][2]; + } + + delete[] barDPsi; +} + + +int CondNumBasis::condNumOrder(int tag) +{ + const int parentType = ElementType::ParentTypeFromTag(tag); + const int order = ElementType::OrderFromTag(tag); + return condNumOrder(parentType, order); +} + + +int CondNumBasis::condNumOrder(int parentType, int order) +{ + switch (parentType) { + case TYPE_PNT : return 0; + case TYPE_LIN : return order - 1; + case TYPE_TRI : return 2*order - 2; + case TYPE_QUA : return 2*order - 1; + case TYPE_TET : return 3*order - 3; + case TYPE_PRI : return 3*order - 1; + case TYPE_HEX : return 3*order - 1; + case TYPE_PYR : return 3*order - 3; + default : + Msg::Error("Unknown element type %d, return order 0", parentType); + return 0; + } +} + + +// Calculate the inverse condition number in Frobenius norm for one element, with normal vectors to straight +// element for regularization. Evaluation points depend on the given matrices for shape function gradients. +template<bool sign> +inline void CondNumBasis::getInvCondNumGeneral(int nCondNumNodes, + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + const fullMatrix<double> &gSMatZ, + const fullMatrix<double> &nodesXYZ, + const fullMatrix<double> &normals, + fullVector<double> &condNum) const +{ + switch (_dim) { + + case 0 : { + for (int i = 0; i < nCondNumNodes; i++) condNum(i) = 1.; + break; + } + + case 1 : { + Msg::Warning("Inverse condition number not implemented in 1D"); + condNum.setAll(0.); + break; + } + + case 2 : { + fullMatrix<double> dxyzdX(nCondNumNodes,3), dxyzdY(nCondNumNodes,3); + gSMatX.mult(nodesXYZ, dxyzdX); + gSMatY.mult(nodesXYZ, dxyzdY); + for (int i = 0; i < nCondNumNodes; i++) { + const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2); + const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2); + const double &nx = normals(0,0), &ny = normals(0,1), &nz = normals(0,2); + condNum(i) = calcInvCondNum2D<sign>(dxdX, dxdY, dydX, dydY, dzdX, dzdY, nx, ny, nz); + } + break; + } + + case 3 : { + fullMatrix<double> dxyzdX(nCondNumNodes, 3), dxyzdY(nCondNumNodes, 3), dxyzdZ(nCondNumNodes, 3); + gSMatX.mult(nodesXYZ, dxyzdX); + gSMatY.mult(nodesXYZ, dxyzdY); + gSMatZ.mult(nodesXYZ, dxyzdZ); + for (int i = 0; i < nCondNumNodes; i++) { + const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2); + const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2); + const double &dxdZ = dxyzdZ(i,0), &dydZ = dxyzdZ(i,1), &dzdZ = dxyzdZ(i,2); + condNum(i) = calcInvCondNum3D<sign>(dxdX, dxdY, dxdZ, + dydX, dydY, dydZ, + dzdX, dzdY, dzdZ); + } + break; + } + } +} + + +void CondNumBasis::getInvCondNumGeneral(int nCondNumNodes, + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + const fullMatrix<double> &gSMatZ, + const fullMatrix<double> &nodesXYZ, + fullVector<double> &invCond) const +{ + fullMatrix<double> dumNormals; + getInvCondNumGeneral<false>(nCondNumNodes, gSMatX, gSMatY, gSMatZ, + nodesXYZ, dumNormals, invCond); +} + + +void CondNumBasis::getSignedInvCondNumGeneral(int nCondNumNodes, + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + const fullMatrix<double> &gSMatZ, + const fullMatrix<double> &nodesXYZ, + const fullMatrix<double> &normals, + fullVector<double> &invCond) const +{ + getInvCondNumGeneral<true>(nCondNumNodes, gSMatX, gSMatY, gSMatZ, + nodesXYZ, normals, invCond); +} + + +// Calculate the inverse condition number in Frobenius norm and its gradients w.r.t. node position, +// with normal vectors to straight element for regularization. Evaluation points depend on the +// given matrices for shape function gradients. +template<bool sign> +inline void CondNumBasis::getInvCondNumAndGradientsGeneral(int nCondNumNodes, + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + const fullMatrix<double> &gSMatZ, + const fullMatrix<double> &nodesXYZ, + const fullMatrix<double> &normals, + fullMatrix<double> &IDI) const +{ + fullMatrix<double> JDJ(nCondNumNodes, 3*_nMapNodes+1); + + switch (_dim) { + + case 0 : { + for (int i = 0; i < nCondNumNodes; i++) { + for (int j = 0; j < _nMapNodes; j++) { + IDI(i,j) = 0.; + IDI(i,j+1*_nMapNodes) = 0.; + IDI(i,j+2*_nMapNodes) = 0.; + } + IDI(i,3*_nMapNodes) = 1.; + } + break; + } + + case 1 : { + Msg::Warning("Inverse condition number not implemented in 1D"); + IDI.setAll(0.); + break; + } + + case 2 : { + fullMatrix<double> dxyzdX(nCondNumNodes,3), dxyzdY(nCondNumNodes,3); + gSMatX.mult(nodesXYZ, dxyzdX); + gSMatY.mult(nodesXYZ, dxyzdY); + for (int i = 0; i < nCondNumNodes; i++) { + const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2); + const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2); + const double &nx = normals(0,0), &ny = normals(0,1), &nz = normals(0,2); + calcGradInvCondNum2D<sign>(dxdX, dxdY, dydX, dydY, dzdX, dzdY, + nx, ny, nz, i, _nMapNodes, gSMatX, gSMatY, IDI); + } + break; + } + + case 3 : { + fullMatrix<double> dxyzdX(nCondNumNodes,3), dxyzdY(nCondNumNodes,3), dxyzdZ(nCondNumNodes,3); + gSMatX.mult(nodesXYZ, dxyzdX); + gSMatY.mult(nodesXYZ, dxyzdY); + gSMatZ.mult(nodesXYZ, dxyzdZ); + for (int i = 0; i < nCondNumNodes; i++) { + const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2); + const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2); + const double &dxdZ = dxyzdZ(i,0), &dydZ = dxyzdZ(i,1), &dzdZ = dxyzdZ(i,2); + calcGradInvCondNum3D<sign>(dxdX, dxdY, dxdZ, + dydX, dydY, dydZ, + dzdX, dzdY, dzdZ, + i, _nMapNodes, + gSMatX, gSMatY, gSMatZ, IDI); + } + break; + } + } +} + + +void CondNumBasis::getInvCondNumAndGradientsGeneral(int nCondNumNodes, + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + const fullMatrix<double> &gSMatZ, + const fullMatrix<double> &nodesXYZ, + fullMatrix<double> &IDI) const +{ + fullMatrix<double> dumNormals; + getInvCondNumAndGradientsGeneral<false>(nCondNumNodes, gSMatX, gSMatY, gSMatZ, + nodesXYZ, dumNormals, IDI); +} + + +void CondNumBasis::getSignedInvCondNumAndGradientsGeneral(int nCondNumNodes, + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + const fullMatrix<double> &gSMatZ, + const fullMatrix<double> &nodesXYZ, + const fullMatrix<double> &normals, + fullMatrix<double> &IDI) const +{ + getInvCondNumAndGradientsGeneral<true>(nCondNumNodes, gSMatX, gSMatY, gSMatZ, + nodesXYZ, normals, IDI); +} diff --git a/Numeric/CondNumBasis.h b/Numeric/CondNumBasis.h new file mode 100644 index 0000000000000000000000000000000000000000..bcbd98d8ac8351ef9068ac2d7c971d5fddfd7824 --- /dev/null +++ b/Numeric/CondNumBasis.h @@ -0,0 +1,125 @@ +// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to the public mailing list <gmsh@geuz.org>. + +#ifndef _CONDNUMBASIS_H_ +#define _CONDNUMBASIS_H_ + +#include <map> +#include <vector> +#include "JacobianBasis.h" +#include "fullMatrix.h" + + +class CondNumBasis { + private: + const GradientBasis *_gradBasis; + + const int _tag, _dim, _condNumOrder; + + fullVector<double> primGradShapeBarycenterX, primGradShapeBarycenterY, + primGradShapeBarycenterZ; + + int _nCondNumNodes; + int _nMapNodes, _nPrimMapNodes; + + public : + CondNumBasis(int tag, int cnOrder = -1); + + // Get methods + inline int getCondNumOrder() const { return _condNumOrder; } + inline int getNumCondNumNodes() const { return _nCondNumNodes; } + inline int getNumMapNodes() const { return _nMapNodes; } + inline int getNumPrimMapNodes() const { return _nPrimMapNodes; } + + // Order calculation + static int condNumOrder(int tag); + static int condNumOrder(int parentType, int order); + + // Condition number evaluation methods + inline void getInvCondNum(const fullMatrix<double> &nodesXYZ, + fullVector<double> &invCond) const { + getInvCondNumGeneral(_nCondNumNodes, + _gradBasis->gradShapeIdealMatX, + _gradBasis->gradShapeIdealMatY, + _gradBasis->gradShapeIdealMatZ, + nodesXYZ, invCond); + } + inline void getSignedInvCondNum(const fullMatrix<double> &nodesXYZ, + const fullMatrix<double> &normals, + fullVector<double> &invCond) const { + getSignedInvCondNumGeneral(_nCondNumNodes, + _gradBasis->gradShapeIdealMatX, + _gradBasis->gradShapeIdealMatY, + _gradBasis->gradShapeIdealMatZ, + nodesXYZ, normals, invCond); + } + inline void getInvCondNumAndGradients(const fullMatrix<double> &nodesXYZ, + fullMatrix<double> &IDI) const { + getInvCondNumAndGradientsGeneral(_nCondNumNodes, + _gradBasis->gradShapeIdealMatX, + _gradBasis->gradShapeIdealMatY, + _gradBasis->gradShapeIdealMatZ, + nodesXYZ, IDI); + } + inline void getSignedInvCondNumAndGradients(const fullMatrix<double> &nodesXYZ, + const fullMatrix<double> &normals, + fullMatrix<double> &IDI) const { + getSignedInvCondNumAndGradientsGeneral(_nCondNumNodes, + _gradBasis->gradShapeIdealMatX, + _gradBasis->gradShapeIdealMatY, + _gradBasis->gradShapeIdealMatZ, + nodesXYZ, normals, IDI); + } + + + private : + template<bool sign> + void getInvCondNumGeneral(int nCondNumNodes, + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + const fullMatrix<double> &gSMatZ, + const fullMatrix<double> &nodesXYZ, + const fullMatrix<double> &normals, + fullVector<double> &invCond) const; + void getInvCondNumGeneral(int nCondNumNodes, + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + const fullMatrix<double> &gSMatZ, + const fullMatrix<double> &nodesXYZ, + fullVector<double> &invCond) const; + void getSignedInvCondNumGeneral(int nCondNumNodes, + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + const fullMatrix<double> &gSMatZ, + const fullMatrix<double> &nodesXYZ, + const fullMatrix<double> &normals, + fullVector<double> &invCond) const; + + template<bool sign> + void getInvCondNumAndGradientsGeneral(int nCondNumNodes, + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + const fullMatrix<double> &gSMatZ, + const fullMatrix<double> &nodesXYZ, + const fullMatrix<double> &normals, + fullMatrix<double> &IDI) const; + void getInvCondNumAndGradientsGeneral(int nCondNumNodes, // No normal given -> unsigned measure + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + const fullMatrix<double> &gSMatZ, + const fullMatrix<double> &nodesXYZ, + fullMatrix<double> &IDI) const; + void getSignedInvCondNumAndGradientsGeneral(int nCondNumNodes, // Normals given -> signed measure + const fullMatrix<double> &gSMatX, + const fullMatrix<double> &gSMatY, + const fullMatrix<double> &gSMatZ, + const fullMatrix<double> &nodesXYZ, + const fullMatrix<double> &normals, + fullMatrix<double> &IDI) const; + + +}; + +#endif diff --git a/Numeric/JacobianBasis.cpp b/Numeric/JacobianBasis.cpp index 6a57c6313474276f7d75fc1b5dc476c2aa49376a..d67dcad36f4b4a2e2decb8fd059982fa1d46ebf5 100644 --- a/Numeric/JacobianBasis.cpp +++ b/Numeric/JacobianBasis.cpp @@ -22,30 +22,6 @@ inline double calcDet3D(double M11, double M12, double M13, + M13 * (M21*M32 - M22*M31); } -// Compute the squared Frobenius norm a matrix -inline double calcFrobNormSq3D(double M11, double M12, double M13, - double M21, double M22, double M23, - double M31, double M32, double M33) -{ - return M11*M11 + M12*M12 + M13*M13 - + M21*M21 + M22*M22 + M23*M23 - + M31*M31 + M32*M32 + M33*M33; -} - -// Compute the squared Frobenius norm of the inverse of a matrix -inline double calcFrobNormSqInv3D(double M11, double M12, double M13, - double M21, double M22, double M23, - double M31, double M32, double M33) -{ - const double invD = 1./calcDet3D(M11, M12, M13, M21, M22, M23, M31, M32, M33); - const double I11 = M22*M33-M23*M32, I12 = M13*M32-M12*M33, I13 = M12*M23-M13*M22, - I21 = M23*M31-M21*M33, I22 = M11*M33-M13*M31, I23 = M13*M21-M11*M23, - I31 = M21*M32-M22*M31, I32 = M12*M31-M11*M32, I33 = M11*M22-M12*M21; - return (I11*I11 + I12*I12 + I13*I13 - + I21*I21 + I22*I22 + I23*I23 - + I31*I31 + I32*I32 + I33*I33)*invD*invD; -} - // Compute signed Jacobian and its gradients w.r.t. // node positions, at one location in a 1D element inline void calcJDJ1D(double dxdX, double dxdY, double dxdZ, @@ -129,156 +105,6 @@ inline void calcJDJ3D(double dxdX, double dxdY, double dxdZ, dzdX, dzdY, dzdZ); } -// Compute condition number and its gradients -// w.r.t. node positions, at one location in a 1D element -// FIXME: TO BE UPDATED -inline void calcIDI1D(double dxdX, double dxdY, double dxdZ, - double dydX, double dydY, double dydZ, - double dzdX, double dzdY, double dzdZ, - int i, int numMapNodes, - const fullMatrix<double> &gSMatX, - const fullMatrix<double> &JDJ, - fullMatrix<double> &IDI) -{ - const double &J = JDJ(i, 3*numMapNodes), JSq = J*J, JQuadInv = 1./(JSq*JSq); - const double A1 = dydY*dzdZ - dydZ*dzdY, A2 = dydX*dzdZ - dydZ*dzdX, - A3 = dxdY*dzdZ - dxdZ*dzdY, A4 = dxdX*dzdZ - dxdZ*dzdX, - A5 = dydX*dzdY - dydY*dzdX, A6 = dxdX*dzdY - dxdY*dzdX, - A7 = dxdY*dydZ - dxdZ*dydY, A8 = dxdX*dydZ - dxdZ*dydX, - A9 = dxdX*dydY - dxdY*dydX; - const double A = A1*A1 + A2*A2 + A3*A3 + A4*A4 + A5*A5 + A6*A6 + A7*A7 + A8*A8 + A9*A9; - const double nInvJSq = A/JSq; - const double nJSq = dxdX*dxdX + dxdY*dxdY + dxdZ*dxdZ - + dydX*dydX + dydY*dydY + dydZ*dydZ - + dzdX*dzdX + dzdY*dzdY + dzdZ*dzdZ; - const double invProd = 1./(nJSq*nInvJSq), sqrtInvProd = sqrt(invProd); - IDI(i, 3*numMapNodes) = 3.*sqrtInvProd; - for (int j = 0; j < numMapNodes; j++) { - const double &dPhidX = gSMatX(i, j); - const double &dJdxj = JDJ(i, j), &dJdyj = JDJ(i, j+numMapNodes), - &dJdzj = JDJ(i, j+2*numMapNodes); - const double dAdxj = 2.*(dPhidX*dzdZ * A4 + dPhidX*dzdY * A6 - + dPhidX*dydZ * A8 + dPhidX*dydY * A9); - const double dnInvJSqdxj = (dAdxj*JSq-2.*dJdxj*J*A)*JQuadInv; - const double dnJSqdxj = 2.*dPhidX*dxdX; - IDI(i, j) = -1.5 * (dnJSqdxj*nInvJSq+nJSq*dnInvJSqdxj)*invProd*sqrtInvProd; - const double dAdyj = 2.*(dPhidX*dzdZ * A2 + dPhidX*dzdY * A5 - - dxdZ*dPhidX * A8 - dxdY*dPhidX * A9); - const double dnInvJSqdyj = (dAdyj*JSq-2.*dJdyj*J*A)*JQuadInv; - const double dnJSqdyj = 2.*dPhidX*dydX; - IDI(i, j+numMapNodes) = -1.5 * (dnJSqdyj*nInvJSq+nJSq*dnInvJSqdyj)*invProd*sqrtInvProd; - const double dAdzj = 2.*(-dydZ*dPhidX * A2 - dxdZ*dPhidX * A4 - - dydY*dPhidX * A5 - dxdY*dPhidX * A6); - const double dnInvJSqdzj = (dAdzj*JSq-2.*dJdzj*J*A)*JQuadInv; - const double dnJSqdzj = 2.*dPhidX*dzdX; - IDI(i, j+2*numMapNodes) = -1.5 * (dnJSqdzj*nInvJSq + nJSq*dnInvJSqdzj) * invProd*sqrtInvProd; - } -} - -// Compute condition number and its gradients -// w.r.t. node positions, at one location in a 2D element -// FIXME: TO BE UPDATED -inline void calcIDI2D(double dxdX, double dxdY, double dxdZ, - double dydX, double dydY, double dydZ, - double dzdX, double dzdY, double dzdZ, - int i, int numMapNodes, - const fullMatrix<double> &gSMatX, - const fullMatrix<double> &gSMatY, - const fullMatrix<double> &JDJ, - fullMatrix<double> &IDI) -{ - const double &J = JDJ(i, 3*numMapNodes), JSq = J*J, JQuadInv = 1./(JSq*JSq); - const double A1 = dydY*dzdZ - dydZ*dzdY, A2 = dydX*dzdZ - dydZ*dzdX, - A3 = dxdY*dzdZ - dxdZ*dzdY, A4 = dxdX*dzdZ - dxdZ*dzdX, - A5 = dydX*dzdY - dydY*dzdX, A6 = dxdX*dzdY - dxdY*dzdX, - A7 = dxdY*dydZ - dxdZ*dydY, A8 = dxdX*dydZ - dxdZ*dydX, - A9 = dxdX*dydY - dxdY*dydX; - const double A = A1*A1 + A2*A2 + A3*A3 + A4*A4 + A5*A5 + A6*A6 + A7*A7 + A8*A8 + A9*A9; - const double nInvJSq = A/JSq; - const double nJSq = dxdX*dxdX + dxdY*dxdY + dxdZ*dxdZ - + dydX*dydX + dydY*dydY + dydZ*dydZ - + dzdX*dzdX + dzdY*dzdY + dzdZ*dzdZ; - const double invProd = 1./(nJSq*nInvJSq), sqrtInvProd = sqrt(invProd); - IDI(i, 3*numMapNodes) = 3.*sqrtInvProd; - for (int j = 0; j < numMapNodes; j++) { - const double &dPhidX = gSMatX(i, j); - const double &dPhidY = gSMatY(i, j); - const double &dJdxj = JDJ(i, j), &dJdyj = JDJ(i, j+numMapNodes), - &dJdzj = JDJ(i, j+2*numMapNodes); - const double dAdxj = 2.*(dPhidY*dzdZ * A3 + dPhidX*dzdZ * A4 - + (dPhidX*dzdY - dPhidY*dzdX) * A6 + dPhidY*dydZ * A7 - + dPhidX*dydZ * A8 + (dPhidX*dydY - dPhidY*dydX) * A9); - const double dnInvJSqdxj = (dAdxj*JSq-2.*dJdxj*J*A)*JQuadInv; - const double dnJSqdxj = 2.*(dPhidX*dxdX + dPhidY*dxdY); - IDI(i, j) = -1.5 * (dnJSqdxj*nInvJSq+nJSq*dnInvJSqdxj)*invProd*sqrtInvProd; - const double dAdyj = 2.*(dPhidY*dzdZ * A1 + dPhidX*dzdZ * A2 - + (dPhidX*dzdY - dPhidY*dzdX) * A5 - dxdZ*dPhidY * A7 - - dxdZ*dPhidX * A8 + (dxdX*dPhidY - dxdY*dPhidX) * A9); - const double dnInvJSqdyj = (dAdyj*JSq-2.*dJdyj*J*A)*JQuadInv; - const double dnJSqdyj = 2.*(dPhidX*dydX + dPhidY*dydY); - IDI(i, j+numMapNodes) = -1.5 * (dnJSqdyj*nInvJSq+nJSq*dnInvJSqdyj)*invProd*sqrtInvProd; - const double dAdzj = 2.*(-dydZ*dPhidY * A1 - dydZ*dPhidX * A2 - - dxdZ*dPhidY * A3 - dxdZ*dPhidX * A4 - + (dydX*dPhidY - dydY*dPhidX) * A5 + (dxdX*dPhidY - dxdY*dPhidX) * A6); - const double dnInvJSqdzj = (dAdzj*JSq-2.*dJdzj*J*A)*JQuadInv; - const double dnJSqdzj = 2.*(dPhidX*dzdX + dPhidY*dzdY); - IDI(i, j+2*numMapNodes) = -1.5 * (dnJSqdzj*nInvJSq + nJSq*dnInvJSqdzj) * invProd*sqrtInvProd; - } -} - -// Compute condition number and its gradients -// w.r.t. node positions, at one location in a 3D element -// FIXME: TO BE UPDATED -inline void calcIDI3D(double dxdX, double dxdY, double dxdZ, - double dydX, double dydY, double dydZ, - double dzdX, double dzdY, double dzdZ, - int i, int numMapNodes, - const fullMatrix<double> &gSMatX, - const fullMatrix<double> &gSMatY, - const fullMatrix<double> &gSMatZ, - const fullMatrix<double> &JDJ, - fullMatrix<double> &IDI) -{ - const double &J = JDJ(i, 3*numMapNodes), JSq = J*J, JQuadInv = 1./(JSq*JSq); - const double A1 = dydY*dzdZ - dydZ*dzdY, A2 = dydX*dzdZ - dydZ*dzdX, - A3 = dxdY*dzdZ - dxdZ*dzdY, A4 = dxdX*dzdZ - dxdZ*dzdX, - A5 = dydX*dzdY - dydY*dzdX, A6 = dxdX*dzdY - dxdY*dzdX, - A7 = dxdY*dydZ - dxdZ*dydY, A8 = dxdX*dydZ - dxdZ*dydX, - A9 = dxdX*dydY - dxdY*dydX; - const double A = A1*A1 + A2*A2 + A3*A3 + A4*A4 + A5*A5 + A6*A6 + A7*A7 + A8*A8 + A9*A9; - const double nInvJSq = A/JSq; - const double nJSq = dxdX*dxdX + dxdY*dxdY + dxdZ*dxdZ - + dydX*dydX + dydY*dydY + dydZ*dydZ - + dzdX*dzdX + dzdY*dzdY + dzdZ*dzdZ; - const double invProd = 1./(nJSq*nInvJSq), sqrtInvProd = sqrt(invProd); - IDI(i, 3*numMapNodes) = 3.*sqrtInvProd; - for (int j = 0; j < numMapNodes; j++) { - const double &dPhidX = gSMatX(i, j); - const double &dPhidY = gSMatY(i, j); - const double &dPhidZ = gSMatZ(i, j); - const double &dJdxj = JDJ(i, j), &dJdyj = JDJ(i, j+numMapNodes), - &dJdzj = JDJ(i, j+2*numMapNodes); - const double dAdxj = 2.*((dPhidY*dzdZ - dPhidZ*dzdY) * A3 + (dPhidX*dzdZ - dPhidZ*dzdX) * A4 - + (dPhidX*dzdY - dPhidY*dzdX) * A6 + (dPhidY*dydZ - dPhidZ*dydY) * A7 - + (dPhidX*dydZ - dPhidZ*dydX) * A8 + (dPhidX*dydY - dPhidY*dydX) * A9); - const double dnInvJSqdxj = (dAdxj*JSq-2.*dJdxj*J*A)*JQuadInv; - const double dnJSqdxj = 2.*(dPhidX*dxdX + dPhidY*dxdY + dPhidZ*dxdZ); - IDI(i, j) = -1.5*(dnJSqdxj*nInvJSq+nJSq*dnInvJSqdxj)*invProd*sqrtInvProd; - const double dAdyj = 2.*((dPhidY*dzdZ - dPhidZ*dzdY) * A1 + (dPhidX*dzdZ - dPhidZ*dzdX) * A2 - + (dPhidX*dzdY - dPhidY*dzdX) * A5 + (dxdY*dPhidZ - dxdZ*dPhidY) * A7 - + (dxdX*dPhidZ - dxdZ*dPhidX) * A8 + (dxdX*dPhidY - dxdY*dPhidX) * A9); - const double dnInvJSqdyj = (dAdyj*JSq-2.*dJdyj*J*A)*JQuadInv; - const double dnJSqdyj = 2.*(dPhidX*dydX + dPhidY*dydY + dPhidZ*dydZ); - IDI(i, j+numMapNodes) = -1.5*(dnJSqdyj*nInvJSq+nJSq*dnInvJSqdyj)*invProd*sqrtInvProd; - const double dAdzj = 2.*((dydY*dPhidZ - dydZ*dPhidY) * A1 + (dydX*dPhidZ - dydZ*dPhidX) * A2 - + (dxdY*dPhidZ - dxdZ*dPhidY) * A3 + (dxdX*dPhidZ - dxdZ*dPhidX) * A4 - + (dydX*dPhidY - dydY*dPhidX) * A5 + (dxdX*dPhidY - dxdY*dPhidX) * A6); - const double dnInvJSqdzj = (dAdzj*JSq-2.*dJdzj*J*A)*JQuadInv; - const double dnJSqdzj = 2.*(dPhidX*dzdX + dPhidY*dzdY + dPhidZ*dzdZ); - IDI(i, j+2*numMapNodes) = -1.5 * (dnJSqdzj*nInvJSq + nJSq*dnInvJSqdzj) * invProd*sqrtInvProd; - } -} - } GradientBasis::GradientBasis(FuncSpaceData data) @@ -304,6 +130,12 @@ GradientBasis::GradientBasis(FuncSpaceData data) gradShapeMatZ(i, j) = allDPsi(j, 3*i+2); } } + + gradShapeIdealMatX = gradShapeMatX; + gradShapeIdealMatY = gradShapeMatY; + gradShapeIdealMatZ = gradShapeMatZ; + mapFromIdealElement(_data.elementType(), &gradShapeIdealMatX, + &gradShapeIdealMatY, &gradShapeIdealMatZ); } void GradientBasis::getGradientsFromNodes(const fullMatrix<double> &nodes, @@ -316,6 +148,16 @@ void GradientBasis::getGradientsFromNodes(const fullMatrix<double> &nodes, if (dxyzdZ) gradShapeMatZ.mult(nodes, *dxyzdZ); } +void GradientBasis::getIdealGradientsFromNodes(const fullMatrix<double> &nodes, + fullMatrix<double> *dxyzdX, + fullMatrix<double> *dxyzdY, + fullMatrix<double> *dxyzdZ) const +{ + if (dxyzdX) gradShapeIdealMatX.mult(nodes, *dxyzdX); + if (dxyzdY) gradShapeIdealMatY.mult(nodes, *dxyzdY); + if (dxyzdZ) gradShapeIdealMatZ.mult(nodes, *dxyzdZ); +} + void GradientBasis::mapFromIdealElement(int type, fullMatrix<double> *dxyzdX, fullMatrix<double> *dxyzdY, @@ -358,6 +200,7 @@ void GradientBasis::mapFromIdealElement(int type, dxyzdZ->scale(cTet[2]); dxyzdZ->axpy(*dxyzdX, cTet[0]); dxyzdZ->axpy(*dxyzdY, cTet[1]); + break; } } } @@ -868,211 +711,6 @@ inline void JacobianBasis::getSignedJacAndGradientsGeneral(int nJacNodes, } -// Calculate the inverse condition number in Frobenius norm for one element, with normal vectors to straight -// element for regularization. Evaluation points depend on the given matrices for shape function gradients. -template<bool ideal> -inline void JacobianBasis::getCondNumGeneral(int nJacNodes, const fullMatrix<double> &gSMatX, - const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ, - const fullMatrix<double> &nodesXYZ, fullVector<double> &invCond) const -{ - switch (_dim) { - - case 0 : { - for (int i = 0; i < nJacNodes; i++) invCond(i) = 1.; - break; - } - - case 1 : { - fullMatrix<double> normals(2,3); - getPrimNormals1D(nodesXYZ,normals); - fullMatrix<double> dxyzdX(nJacNodes,3); - gSMatX.mult(nodesXYZ, dxyzdX); - for (int i = 0; i < nJacNodes; i++) { - const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2); - const double &dxdY = normals(0,0), &dydY = normals(0,1), &dzdY = normals(0,2); - const double &dxdZ = normals(1,0), &dydZ = normals(1,1), &dzdZ = normals(1,2); - const double nJSq = calcFrobNormSq3D(dxdX, dxdY, dxdZ, - dydX, dydY, dydZ, - dzdX, dzdY, dzdZ); - const double nInvJSq = calcFrobNormSqInv3D(dxdX, dxdY, dxdZ, - dydX, dydY, dydZ, - dzdX, dzdY, dzdZ); - invCond(i) = 3./sqrt(nJSq*nInvJSq); - } - break; - } - - case 2 : { - fullMatrix<double> normal(1,3); - const double scaleSq = getPrimNormal2D(nodesXYZ, normal, ideal), scale = sqrt(scaleSq); - normal(0, 0) *= scale; normal(0, 1) *= scale; normal(0, 2) *= scale; - fullMatrix<double> dxyzdX(nJacNodes,3), dxyzdY(nJacNodes,3); - gSMatX.mult(nodesXYZ, dxyzdX); - gSMatY.mult(nodesXYZ, dxyzdY); - if (ideal) _gradBasis->mapFromIdealElement(&dxyzdX, &dxyzdY, NULL); - for (int i = 0; i < nJacNodes; i++) { - const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2); - const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2); - const double &dxdZ = normal(0,0), &dydZ = normal(0,1), &dzdZ = normal(0,2); - const double nJSq = calcFrobNormSq3D(dxdX, dxdY, dxdZ, - dydX, dydY, dydZ, - dzdX, dzdY, dzdZ); - const double nInvJSq = calcFrobNormSqInv3D(dxdX, dxdY, dxdZ, - dydX, dydY, dydZ, - dzdX, dzdY, dzdZ); - invCond(i) = 3./sqrt(nJSq*nInvJSq); - } - break; - } - - case 3 : { - fullMatrix<double> dum; - fullMatrix<double> dxyzdX(nJacNodes,3), dxyzdY(nJacNodes,3), dxyzdZ(nJacNodes,3); - gSMatX.mult(nodesXYZ, dxyzdX); - gSMatY.mult(nodesXYZ, dxyzdY); - gSMatZ.mult(nodesXYZ, dxyzdZ); - if (ideal) _gradBasis->mapFromIdealElement(&dxyzdX, &dxyzdY, &dxyzdZ); - for (int i = 0; i < nJacNodes; i++) { - const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2); - const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2); - const double &dxdZ = dxyzdZ(i,0), &dydZ = dxyzdZ(i,1), &dzdZ = dxyzdZ(i,2); - const double nJSq = calcFrobNormSq3D(dxdX, dxdY, dxdZ, - dydX, dydY, dydZ, - dzdX, dzdY, dzdZ); - const double nInvJSq = calcFrobNormSqInv3D(dxdX, dxdY, dxdZ, - dydX, dydY, dydZ, - dzdX, dzdY, dzdZ); - invCond(i) = 3./sqrt(nJSq*nInvJSq); - } - break; - } - } -} - -void JacobianBasis::getCondNumGeneral(int nJacNodes, const fullMatrix<double> &gSMatX, - const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ, - const fullMatrix<double> &nodesXYZ, fullVector<double> &invCond) const -{ - getCondNumGeneral<true>(nJacNodes, gSMatX, gSMatY, gSMatZ, nodesXYZ, invCond); -} - -// Calculate the inverse condition number in Frobenius norm and its gradients w.r.t. node position, -// with normal vectors to straight element for regularization. Evaluation points depend on the -// given matrices for shape function gradients. -template<bool ideal> -inline void JacobianBasis::getCondNumAndGradientsGeneral(int nJacNodes, - const fullMatrix<double> &gSMatX, - const fullMatrix<double> &gSMatY, - const fullMatrix<double> &gSMatZ, - const fullMatrix<double> &nodesXYZ, - const fullMatrix<double> &normals, - fullMatrix<double> &IDI) const -{ - fullMatrix<double> JDJ(nJacNodes, 3*numMapNodes+1); - - switch (_dim) { - - case 0 : { - for (int i = 0; i < nJacNodes; i++) { - for (int j = 0; j < numMapNodes; j++) { - IDI(i,j) = 0.; - IDI(i,j+1*numMapNodes) = 0.; - IDI(i,j+2*numMapNodes) = 0.; - } - IDI(i,3*numMapNodes) = 1.; - } - break; - } - - case 1 : { - fullMatrix<double> dxyzdX(nJacNodes,3), dxyzdY(nJacNodes,3); - gSMatX.mult(nodesXYZ, dxyzdX); - for (int i = 0; i < nJacNodes; i++) { - const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2); - const double &dxdY = normals(0,0), &dydY = normals(0,1), &dzdY = normals(0,2); - const double &dxdZ = normals(1,0), &dydZ = normals(1,1), &dzdZ = normals(1,2); - calcJDJ1D(dxdX, dxdY, dxdZ, - dydX, dydY, dydZ, - dzdX, dzdY, dzdZ, - i, numMapNodes, - gSMatX, JDJ); - calcIDI1D(dxdX, dxdY, dxdZ, - dydX, dydY, dydZ, - dzdX, dzdY, dzdZ, - i, numMapNodes, - gSMatX, JDJ, IDI); - } - break; - } - - case 2 : { - fullMatrix<double> dxyzdX(nJacNodes,3), dxyzdY(nJacNodes,3); - gSMatX.mult(nodesXYZ, dxyzdX); - gSMatY.mult(nodesXYZ, dxyzdY); - if (ideal) _gradBasis->mapFromIdealElement(&dxyzdX, &dxyzdY, NULL); - for (int i = 0; i < nJacNodes; i++) { - const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2); - const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2); - const double &dxdZ = normals(0,0), &dydZ = normals(0,1), &dzdZ = normals(0,2); - calcJDJ2D(dxdX, dxdY, dxdZ, - dydX, dydY, dydZ, - dzdX, dzdY, dzdZ, - i, numMapNodes, - gSMatX, gSMatY, JDJ); - calcIDI2D(dxdX, dxdY, dxdZ, - dydX, dydY, dydZ, - dzdX, dzdY, dzdZ, - i, numMapNodes, - gSMatX, gSMatY, JDJ, IDI); - } - break; - } - - case 3 : { - fullMatrix<double> dxyzdX(nJacNodes,3), dxyzdY(nJacNodes,3), dxyzdZ(nJacNodes,3); - gSMatX.mult(nodesXYZ, dxyzdX); - gSMatY.mult(nodesXYZ, dxyzdY); - gSMatZ.mult(nodesXYZ, dxyzdZ); - if (ideal) _gradBasis->mapFromIdealElement(&dxyzdX, &dxyzdY, &dxyzdZ); - for (int i = 0; i < nJacNodes; i++) { - const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2); - const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2); - const double &dxdZ = dxyzdZ(i,0), &dydZ = dxyzdZ(i,1), &dzdZ = dxyzdZ(i,2); - calcJDJ3D(dxdX, dxdY, dxdZ, - dydX, dydY, dydZ, - dzdX, dzdY, dzdZ, - i, numMapNodes, - gSMatX, gSMatY, gSMatZ, JDJ); - calcIDI3D(dxdX, dxdY, dxdZ, - dydX, dydY, dydZ, - dzdX, dzdY, dzdZ, - i, numMapNodes, - gSMatX, gSMatY, gSMatZ, JDJ, IDI); -// std::cout << "DBGTT: Jac. node " << i << ":\n"; -// std::cout << "DBGTT: -> g = " << IDI(i, 3*getNumMapNodes()) << ":\n"; -// for (int j=0; j<getNumMapNodes(); j++) -// std::cout << "DBGTT: -> djd{x,y,z}" << j << " = (" << JDJ(i, j) -// << ", " << JDJ(i, j+getNumMapNodes()) << ", " << JDJ(i, j+2*getNumMapNodes()) << ")\n"; -// for (int j=0; j<getNumMapNodes(); j++) -// std::cout << "DBGTT: -> dgd{x,y,z}" << j << " = (" << IDI(i, j) -// << ", " << IDI(i, j+getNumMapNodes()) << ", " << IDI(i, j+2*getNumMapNodes()) << ")\n"; - } - break; - } - } -} - -void JacobianBasis::getCondNumAndGradientsGeneral(int nJacNodes, - const fullMatrix<double> &gSMatX, - const fullMatrix<double> &gSMatY, - const fullMatrix<double> &gSMatZ, - const fullMatrix<double> &nodesXYZ, - const fullMatrix<double> &normals, - fullMatrix<double> &IDI) const -{ - getCondNumAndGradientsGeneral<true>(nJacNodes, gSMatX, gSMatY, gSMatZ, nodesXYZ, normals, IDI); -} - void JacobianBasis::getSignedJacAndGradientsGeneral(int nJacNodes, const fullMatrix<double> &gSMatX, const fullMatrix<double> &gSMatY, diff --git a/Numeric/JacobianBasis.h b/Numeric/JacobianBasis.h index ace52e9907cd7474cebe56135987020b2846bea2..978e0cd1e43dd739f080e23f183441d295d95ac1 100644 --- a/Numeric/JacobianBasis.h +++ b/Numeric/JacobianBasis.h @@ -13,6 +13,7 @@ class GradientBasis { public: fullMatrix<double> gradShapeMatX, gradShapeMatY, gradShapeMatZ; + fullMatrix<double> gradShapeIdealMatX, gradShapeIdealMatY, gradShapeIdealMatZ; private: const FuncSpaceData _data; @@ -27,6 +28,10 @@ public: fullMatrix<double> *dxyzdX, fullMatrix<double> *dxyzdY, fullMatrix<double> *dxyzdZ) const; + void getIdealGradientsFromNodes(const fullMatrix<double> &nodes, + fullMatrix<double> *dxyzdX, + fullMatrix<double> *dxyzdY, + fullMatrix<double> *dxyzdZ) const; void mapFromIdealElement(fullMatrix<double> *dxyzdX, fullMatrix<double> *dxyzdY, fullMatrix<double> *dxyzdZ) const { @@ -91,16 +96,6 @@ public: getSignedIdealJacAndGradientsGeneral(numJacNodesFast,gradShapeMatXFast,gradShapeMatYFast, gradShapeMatZFast,nodesXYZ,normals,JDJ); } - inline void getCondNumAndGradients(const fullMatrix<double> &nodesXYZ, - const fullMatrix<double> &normals, fullMatrix<double> &IDI) const { - getCondNumAndGradientsGeneral(numJacNodes, _gradBasis->gradShapeMatX, - _gradBasis->gradShapeMatY, _gradBasis->gradShapeMatZ, nodesXYZ, normals, IDI); - } - inline void getCondNumAndGradientsFast(const fullMatrix<double> &nodesXYZ, - const fullMatrix<double> &normals, fullMatrix<double> &IDI) const { - getCondNumAndGradientsGeneral(numJacNodesFast,gradShapeMatXFast,gradShapeMatYFast, - gradShapeMatZFast,nodesXYZ,normals,IDI); - } void getMetricMinAndGradients(const fullMatrix<double> &nodesXYZ, const fullMatrix<double> &nodesXYZStraight, fullVector<double> &lambdaJ , fullMatrix<double> &gradLambdaJ) const; @@ -140,13 +135,6 @@ public: inline void getScaledJacobianFast(const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const { getScaledJacobianGeneral(numJacNodesFast,gradShapeMatXFast,gradShapeMatYFast,gradShapeMatZFast,nodesXYZ,jacobian); } - inline void getCondNum(const fullMatrix<double> &nodesXYZ, fullVector<double> &invCond) const { - getCondNumGeneral(numJacNodes, _gradBasis->gradShapeMatX, - _gradBasis->gradShapeMatY, _gradBasis->gradShapeMatZ, nodesXYZ, invCond); - } - inline void getCondNumFast(const fullMatrix<double> &nodesXYZ, fullVector<double> &invCond) const { - getCondNumGeneral(numJacNodesFast,gradShapeMatXFast,gradShapeMatYFast,gradShapeMatZFast,nodesXYZ,invCond); - } // inline void lag2Bez(const fullVector<double> &jac, fullVector<double> &bez) const { getBezier()->matrixLag2Bez.mult(jac,bez); @@ -212,26 +200,6 @@ public: const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ, const fullMatrix<double> &nodesXYZ, const fullMatrix<double> &normals, fullMatrix<double> &JDJ) const; - - template<bool ideal> - void getCondNumGeneral(int nJacNodes, const fullMatrix<double> &gSMatX, - const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ, - const fullMatrix<double> &nodesXYZ, fullVector<double> &invCond) const; - void getCondNumGeneral(int nJacNodes, const fullMatrix<double> &gSMatX, - const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ, - const fullMatrix<double> &nodesXYZ, fullVector<double> &invCond) const; - - template<bool ideal> - void getCondNumAndGradientsGeneral(int nJacNodes, const fullMatrix<double> &gSMatX, - const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ, - const fullMatrix<double> &nodesXYZ, const fullMatrix<double> &normals, - fullMatrix<double> &IDI) const; - void getCondNumAndGradientsGeneral(int nJacNodes, const fullMatrix<double> &gSMatX, - const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ, - const fullMatrix<double> &nodesXYZ, const fullMatrix<double> &normals, - fullMatrix<double> &IDI) const; - - }; #endif diff --git a/contrib/MeshOptimizer/MeshOptPatch.cpp b/contrib/MeshOptimizer/MeshOptPatch.cpp index 0debf3111a64cd336ddb187dd8e0060f04a80bee..f36799e280577ac86dca922fb28cc2711909dfe5 100644 --- a/contrib/MeshOptimizer/MeshOptPatch.cpp +++ b/contrib/MeshOptimizer/MeshOptPatch.cpp @@ -34,6 +34,7 @@ #include "MQuadrangle.h" #include "MTetrahedron.h" #include "BasisFactory.h" +#include "CondNumBasis.h" #include "OptHomIntegralBoundaryDist.h" #include "qualityMeasures.h" #include "MeshOptPatch.h" @@ -614,36 +615,38 @@ void Patch::idealJacAndGradients(int iEl, std::vector<double> &iJ, std::vector<d } -void Patch::initCondNum() +void Patch::initInvCondNum() { // Initialize _nBezEl - if (_nBezEl.empty()) { - _nBezEl.resize(nEl()); - for (int iEl=0; iEl<nEl(); iEl++) - _nBezEl[iEl] = _el[iEl]->getJacobianFuncSpace()->getNumJacNodes(); + if (_nICNEl.empty()) { + _nICNEl.resize(nEl()); + for (int iEl=0; iEl<nEl(); iEl++) { + const CondNumBasis *cnBasis = BasisFactory::getCondNumBasis(_el[iEl]->getTypeForMSH()); + _nICNEl[iEl] = cnBasis->getNumCondNumNodes(); + } } - // Set normals to 2D elements (with magnitude of inverse Jacobian) or initial - // Jacobians of 3D elements - if ((_dim == 2) && _condNormEl.empty()) { - _condNormEl.resize(nEl()); -// for (int iEl = 0; iEl < nEl(); iEl++) calcScaledNormalEl2D(element2entity,iEl); - for (int iEl = 0; iEl < nEl(); iEl++) - calcNormalEl2D(iEl, NS_SQRTNORM, _condNormEl[iEl], true); - } +// // Set normals to 2D elements (with magnitude of inverse Jacobian) or initial +// // Jacobians of 3D elements +// if ((_dim == 2) && _condNormEl.empty()) { +// _condNormEl.resize(nEl()); +//// for (int iEl = 0; iEl < nEl(); iEl++) calcScaledNormalEl2D(element2entity,iEl); +// for (int iEl = 0; iEl < nEl(); iEl++) +// calcNormalEl2D(iEl, NS_SQRTNORM, _condNormEl[iEl], true); +// } } -void Patch::condNumAndGradients(int iEl, std::vector<double> &condNum, +void Patch::invCondNumAndGradients(int iEl, std::vector<double> &condNum, std::vector<double> &gCondNum) { - const JacobianBasis *jacBasis = _el[iEl]->getJacobianFuncSpace(); - const int &numJacNodes = _nBezEl[iEl]; + const CondNumBasis *cnBasis = BasisFactory::getCondNumBasis(_el[iEl]->getTypeForMSH()); + const int &numICN = _nICNEl[iEl]; const int &numMapNodes = _nNodEl[iEl]; - fullMatrix<double> IDI(numJacNodes,3*numMapNodes+1); + fullMatrix<double> IDI(numICN, 3*numMapNodes+1); // Coordinates of nodes - fullMatrix<double> nodesXYZ(numMapNodes,3), normals(_dim,3); + fullMatrix<double> nodesXYZ(numMapNodes,3), normals; for (int i = 0; i < numMapNodes; i++) { int &iVi = _el2V[iEl][i]; nodesXYZ(i,0) = _xyz[iVi].x(); @@ -651,28 +654,32 @@ void Patch::condNumAndGradients(int iEl, std::vector<double> &condNum, nodesXYZ(i,2) = _xyz[iVi].z(); } - // Calculate Jacobian and gradients, scale if 3D (already scaled by - // regularization normals in 2D) - jacBasis->getCondNumAndGradients(nodesXYZ, _condNormEl[iEl], IDI); + // Calculate ICN and gradients + // TODO: Use signed measure for 2D as well + if (_dim == 3) { + cnBasis->getSignedInvCondNumAndGradients(nodesXYZ, normals, IDI); + } + else + cnBasis->getInvCondNumAndGradients(nodesXYZ, IDI); // Inverse condition number - for (int l = 0; l < numJacNodes; l++) condNum[l] = IDI(l, 3*numMapNodes); + for (int l = 0; l < numICN; l++) condNum[l] = IDI(l, 3*numMapNodes); // Gradients of the inverse condition number int iPC = 0; - std::vector<SPoint3> gXyzV(numJacNodes); - std::vector<SPoint3> gUvwV(numJacNodes); + std::vector<SPoint3> gXyzV(numICN); + std::vector<SPoint3> gUvwV(numICN); for (int i = 0; i < numMapNodes; i++) { int &iFVi = _el2FV[iEl][i]; if (iFVi >= 0) { - for (int l = 0; l < numJacNodes; l++) + for (int l = 0; l < numICN; l++) gXyzV[l] = SPoint3(IDI(l, i), IDI(l, i+numMapNodes), IDI(l, i+2*numMapNodes)); - _coordFV[iFVi]->gXyz2gUvw(_uvw[iFVi],gXyzV,gUvwV); - for (int l = 0; l < numJacNodes; l++) { - gCondNum[indGSJ(iEl,l,iPC)] = gUvwV[l][0]; - if (_nPCFV[iFVi] >= 2) gCondNum[indGSJ(iEl,l,iPC+1)] = gUvwV[l][1]; - if (_nPCFV[iFVi] == 3) gCondNum[indGSJ(iEl,l,iPC+2)] = gUvwV[l][2]; + _coordFV[iFVi]->gXyz2gUvw(_uvw[iFVi], gXyzV, gUvwV); + for (int l = 0; l < numICN; l++) { + gCondNum[indGICN(iEl, l, iPC)] = gUvwV[l][0]; + if (_nPCFV[iFVi] >= 2) gCondNum[indGICN(iEl, l, iPC+1)] = gUvwV[l][1]; + if (_nPCFV[iFVi] == 3) gCondNum[indGICN(iEl, l, iPC+2)] = gUvwV[l][2]; } iPC += _nPCFV[iFVi]; } diff --git a/contrib/MeshOptimizer/MeshOptPatch.h b/contrib/MeshOptimizer/MeshOptPatch.h index d9b477f27770d51e26f370937b0cfb4ba3c9ef7b..cc5d2bd327b27d2f75c22c77b3f7341826e9132b 100644 --- a/contrib/MeshOptimizer/MeshOptPatch.h +++ b/contrib/MeshOptimizer/MeshOptPatch.h @@ -95,11 +95,13 @@ public: // Mesh quality inline const int &nIJacEl(int iEl) { return _nIJacEl[iEl]; } + inline const int &nICNEl(int iEl) { return _nICNEl[iEl]; } inline int indGIJac(int iEl, int l, int iPC) { return iPC*_nIJacEl[iEl]+l; } + inline int indGICN(int iEl, int l, int iPC) { return iPC*_nICNEl[iEl]+l; } void initIdealJac(); void idealJacAndGradients(int iEl, std::vector<double> &NCJ, std::vector<double> &gNCJ); - void initCondNum(); - void condNumAndGradients(int iEl, std::vector<double> &condNum, std::vector<double> &gCondNum); + void initInvCondNum(); + void invCondNumAndGradients(int iEl, std::vector<double> &condNum, std::vector<double> &gCondNum); private: @@ -155,7 +157,8 @@ private: std::vector<int> _nIJacEl; // Number of NCJ values for an el std::vector<fullMatrix<double> > _IJacNormEl; // Normals to 2D elements for Jacobian regularization and scaling std::vector<double> _invIJac; // Initial Jacobians for 3D elements - std::vector<fullMatrix<double> > _condNormEl; // Normals to 2D elements for inverse conditioning computation + std::vector<int> _nICNEl; // Number of inv. cond. number values for an el. +// std::vector<fullMatrix<double> > _condNormEl; // Normals to 2D elements for inverse conditioning computation }; diff --git a/contrib/MeshQualityOptimizer/MeshQualityObjContribInvCond.h b/contrib/MeshQualityOptimizer/MeshQualityObjContribInvCond.h index 65b758fb3f0d91c9f8e5daa85bea529845d39a6d..3ef5bde3c2bcf7fb5bf87dfbc0e694c9429c0636 100644 --- a/contrib/MeshQualityOptimizer/MeshQualityObjContribInvCond.h +++ b/contrib/MeshQualityOptimizer/MeshQualityObjContribInvCond.h @@ -8,11 +8,11 @@ template<class FuncType> -class ObjContribInvCond : public ObjContrib, public FuncType +class ObjContribInvCondNum : public ObjContrib, public FuncType { public: - ObjContribInvCond(double weight); - virtual ~ObjContribInvCond() {} + ObjContribInvCondNum(double weight); + virtual ~ObjContribInvCondNum() {} virtual ObjContrib *copy() const; virtual void initialize(Patch *mesh); virtual bool fail() { return false; } @@ -29,45 +29,45 @@ protected: template<class FuncType> -ObjContribInvCond<FuncType>::ObjContribInvCond(double weight) : - ObjContrib("InvCond", FuncType::getNamePrefix()+"InvCond"), +ObjContribInvCondNum<FuncType>::ObjContribInvCondNum(double weight) : + ObjContrib("InvCondNum", FuncType::getNamePrefix()+"InvCondNum"), _mesh(0), _weight(weight) { } template<class FuncType> -ObjContrib *ObjContribInvCond<FuncType>::copy() const +ObjContrib *ObjContribInvCondNum<FuncType>::copy() const { - return new ObjContribInvCond<FuncType>(*this); + return new ObjContribInvCondNum<FuncType>(*this); } template<class FuncType> -void ObjContribInvCond<FuncType>::initialize(Patch *mesh) +void ObjContribInvCondNum<FuncType>::initialize(Patch *mesh) { _mesh = mesh; - _mesh->initCondNum(); + _mesh->initInvCondNum(); updateMinMax(); FuncType::initialize(_min, _max); } template<class FuncType> -bool ObjContribInvCond<FuncType>::addContrib(double &Obj, alglib::real_1d_array &gradObj) +bool ObjContribInvCondNum<FuncType>::addContrib(double &Obj, alglib::real_1d_array &gradObj) { _min = BIGVAL; _max = -BIGVAL; for (int iEl = 0; iEl < _mesh->nEl(); iEl++) { - std::vector<double> invCond(_mesh->nBezEl(iEl)); // Min. of Metric - std::vector<double> gInvCond(_mesh->nBezEl(iEl)*_mesh->nPCEl(iEl)); // Dummy gradients of metric min. - _mesh->condNumAndGradients(iEl, invCond, gInvCond); - for (int l = 0; l < _mesh->nBezEl(iEl); l++) { // Add contribution for each Bezier coeff. + std::vector<double> invCond(_mesh->nICNEl(iEl)); // Min. of Metric + std::vector<double> gInvCond(_mesh->nICNEl(iEl)*_mesh->nPCEl(iEl)); // Dummy gradients of metric min. + _mesh->invCondNumAndGradients(iEl, invCond, gInvCond); + for (int l = 0; l < _mesh->nICNEl(iEl); l++) { // Add contribution for each Bezier coeff. Obj += _weight * FuncType::compute(invCond[l]); const double dfact = _weight * FuncType::computeDiff(invCond[l]); for (int iPC = 0; iPC < _mesh->nPCEl(iEl); iPC++) - gradObj[_mesh->indPCEl(iEl,iPC)] += dfact * gInvCond[_mesh->indGSJ(iEl, l, iPC)]; + gradObj[_mesh->indPCEl(iEl,iPC)] += dfact * gInvCond[_mesh->indGICN(iEl, l, iPC)]; _min = std::min(_min, invCond[l]); _max = std::max(_max, invCond[l]); } @@ -78,16 +78,16 @@ bool ObjContribInvCond<FuncType>::addContrib(double &Obj, alglib::real_1d_array template<class FuncType> -void ObjContribInvCond<FuncType>::updateMinMax() +void ObjContribInvCondNum<FuncType>::updateMinMax() { _min = BIGVAL; _max = -BIGVAL; for (int iEl = 0; iEl < _mesh->nEl(); iEl++) { - std::vector<double> invCond(_mesh->nBezEl(iEl)); // Min. of Metric - std::vector<double> dumGInvCond(_mesh->nBezEl(iEl)*_mesh->nPCEl(iEl)); // Dummy gradients of metric min. - _mesh->condNumAndGradients(iEl, invCond, dumGInvCond); - for (int l = 0; l < _mesh->nBezEl(iEl); l++) { // Add contribution for each Bezier coeff. + std::vector<double> invCond(_mesh->nICNEl(iEl)); // Min. of Metric + std::vector<double> dumGInvCond(_mesh->nICNEl(iEl)*_mesh->nPCEl(iEl)); // Dummy gradients of metric min. + _mesh->invCondNumAndGradients(iEl, invCond, dumGInvCond); + for (int l = 0; l < _mesh->nICNEl(iEl); l++) { // Add contribution for each Bezier coeff. _min = std::min(_min, invCond[l]); _max = std::max(_max, invCond[l]); } diff --git a/contrib/MeshQualityOptimizer/MeshQualityOptimizer.cpp b/contrib/MeshQualityOptimizer/MeshQualityOptimizer.cpp index db96312c383c825b9d9800d987aaa2737a6c4934..8c47078ea457c9e38562c2c7fe11d029f5f483d1 100644 --- a/contrib/MeshQualityOptimizer/MeshQualityOptimizer.cpp +++ b/contrib/MeshQualityOptimizer/MeshQualityOptimizer.cpp @@ -26,7 +26,7 @@ struct QualPatchDefParameters : public MeshOptPatchDef double limDist, MElement *el) const; private: bool _excludeHex, _excludePrism; - double _idealJacMin; + double _idealJacMin, _invCondNumMin; double _distanceFactor; }; @@ -36,6 +36,7 @@ QualPatchDefParameters::QualPatchDefParameters(const MeshQualOptParameters &p) _excludeHex = p.excludeHex; _excludePrism = p.excludePrism; _idealJacMin = p.minTargetIdealJac; + _invCondNumMin = p.minTargetInvCondNum; strategy = (p.strategy == 1) ? MeshOptParameters::STRAT_ONEBYONE : MeshOptParameters::STRAT_CONNECTED; minLayers = (p.dim == 3) ? 1 : 0; @@ -56,9 +57,12 @@ double QualPatchDefParameters::elBadness(MElement *el) const const int typ = el->getType(); if (_excludeHex && (typ == TYPE_HEX)) return 1.; if (_excludePrism && (typ == TYPE_PRI)) return 1.; - double jMin, jMax; - el->idealJacRange(jMin, jMax); - return jMin-_idealJacMin; +// double jMin, jMax; +// el->idealJacRange(jMin, jMax); +// return jMin-_idealJacMin; + double iCNMin, iCNMax; + el->invCondNumRange(iCNMin, iCNMax); + return iCNMin-_invCondNumMin; } @@ -94,6 +98,8 @@ void MeshQualityOptimizer(GModel *gm, MeshQualOptParameters &p) Patch::LS_MINEDGELENGTH); ObjContribIdealJac<ObjContribFuncBarrierMovMin> minIdealJacBarFunc(1.); minIdealJacBarFunc.setTarget(p.minTargetIdealJac, 1.); + ObjContribInvCondNum<ObjContribFuncBarrierMovMin> minInvCondNumBarFunc(1.); + minInvCondNumBarFunc.setTarget(p.minTargetInvCondNum, 1.); MeshOptPass minJacPass; minJacPass.barrierIterMax = p.optPassMax; @@ -102,9 +108,18 @@ void MeshQualityOptimizer(GModel *gm, MeshQualOptParameters &p) minJacPass.contrib.push_back(&minIdealJacBarFunc); par.pass.push_back(minJacPass); + MeshOptPass minInvCondNumPass; + minInvCondNumPass.barrierIterMax = p.optPassMax; + minInvCondNumPass.optIterMax = p.itMax; + minInvCondNumPass.contrib.push_back(&nodeDistFunc); + minInvCondNumPass.contrib.push_back(&minInvCondNumBarFunc); + par.pass.push_back(minInvCondNumPass); + meshOptimizer(gm, par); p.CPU = par.CPU; - p.minIdealJac = minIdealJacBarFunc.getMin(); - p.maxIdealJac = minIdealJacBarFunc.getMax(); +// p.minIdealJac = minIdealJacBarFunc.getMin(); +// p.maxIdealJac = minIdealJacBarFunc.getMax(); + p.minInvCondNum = minInvCondNumBarFunc.getMin(); + p.maxInvCondNum = minInvCondNumBarFunc.getMax(); } diff --git a/contrib/MeshQualityOptimizer/MeshQualityOptimizer.h b/contrib/MeshQualityOptimizer/MeshQualityOptimizer.h index 36722f0a453d634a96f480992703533d7841cbe8..052addc17207b99cd4b77e0d30e0be39453c36c9 100644 --- a/contrib/MeshQualityOptimizer/MeshQualityOptimizer.h +++ b/contrib/MeshQualityOptimizer/MeshQualityOptimizer.h @@ -35,6 +35,7 @@ class GModel; struct MeshQualOptParameters { bool excludeHex, excludePrism; double minTargetIdealJac; + double minTargetInvCondNum; double weightFixed; // weight of the energy for fixed nodes double weightFree; // weight of the energy for free nodes int nbLayers; // number of layers taken around a bad element @@ -52,15 +53,18 @@ struct MeshQualOptParameters { double adaptBlobDistFact; // Growth factor in distance factor for blob adaptation int SUCCESS ; // 0 --> success , 1 --> Not converged - double minIdealJac, maxIdealJac; // after optimization, range of jacobians +// double minIdealJac, maxIdealJac; // after optimization, range of jacobians + double minInvCondNum, maxInvCondNum; // after optimization, range of jacobians double CPU; // Time for optimization MeshQualOptParameters () - : excludeHex(false), excludePrism(false), minTargetIdealJac(0.1), weightFixed(1000.), + : excludeHex(false), excludePrism(false), minTargetIdealJac(0.1), + minTargetInvCondNum(0.1), weightFixed(1000.), weightFree (1.), nbLayers (6) , dim(3) , itMax(300), optPassMax(50), onlyVisible(true), distanceFactor(12), fixBndNodes(false), strategy(0), maxAdaptBlob(3), adaptBlobLayerFact(2.), adaptBlobDistFact(2.), CPU(0.), - minIdealJac(0.), maxIdealJac(0.), SUCCESS(-1) +// minIdealJac(0.), maxIdealJac(0.), SUCCESS(-1) + minInvCondNum(0.), maxInvCondNum(0.), SUCCESS(-1) { } };