diff --git a/Common/Gmsh.cpp b/Common/Gmsh.cpp index 251674c8d4581d33c9e005a0cfdb1d1c5d58cee9..c17b913e65caf5c6d276fdaf934bb1c5c4a642d1 100644 --- a/Common/Gmsh.cpp +++ b/Common/Gmsh.cpp @@ -275,8 +275,12 @@ int GmshBatch() Msg::Warning("ignoring xfem %d", i); continue; } + const nodalBasis *fs = BasisFactory::getNodalBasis(i); - if (fs) fs->compareNewAlgoPointsWithOld(); + + if (fs && !fs->compareNewAlgoPointsWithOld() && !fs->serendip) { + fs->compareNewAlgoBaseFunctionsWithOld(); + } } } diff --git a/Numeric/nodalBasis.cpp b/Numeric/nodalBasis.cpp index 8fb9be5916ba7239fdb1e3ace21f95734f152546..5856ae2a099b5a7b357546aeac7c8534edd43ed1 100644 --- a/Numeric/nodalBasis.cpp +++ b/Numeric/nodalBasis.cpp @@ -15,11 +15,11 @@ int nodalBasis::compareNewAlgoPointsWithOld() const const char **name = new const char*[1]; MElement::getInfoMSH(type, name); if (points_newAlgo.size1() == 0) { - Msg::Warning("%d: pas de points (%d, %d, %d) %s", type, parentType, order, serendip, *name); + Msg::Warning("%d: pas de points (%d, %d, %d) %s", type, parentType, serendip, order, *name); return 1; } if (points_newAlgo.size1() != points.size1()) { - Msg::Error("%d: pas meme taille (%d, %d, %d) %s", type, parentType, order, serendip, *name); + Msg::Error("%d: pas meme taille (%d, %d, %d) %s", type, parentType, serendip, order, *name); Msg::Error(" |--> points[%d, %d] vs newPoints[%d, %d]", points.size1(), points.size2(), points_newAlgo.size1(), points_newAlgo.size2()); return 2; } @@ -28,7 +28,7 @@ int nodalBasis::compareNewAlgoPointsWithOld() const //Msg::Info("(i, j) = (%d, %d)", i, j); //Msg::Info(" "); if (std::abs(points(i, j) - points_newAlgo(i, j)) > 1e-15) { - Msg::Error("%d: correspond pas (%d, %d, %d) %s", type, parentType, order, serendip, *name); + Msg::Error("%d: correspond pas (%d, %d, %d) %s", type, parentType, serendip, order, *name); for (int i = 0; i < points.size1(); ++i) { for (int j = 0; j < points.size2(); ++j) { if(std::abs(points(i, j) - points_newAlgo(i, j)) <= 1e-15) @@ -42,7 +42,73 @@ int nodalBasis::compareNewAlgoPointsWithOld() const } } } - Msg::Info("%d: ok (%d, %d, %d) %s", type, parentType, order, serendip, *name); + Msg::Info("%d: ok (%d, %d, %d) %s", type, parentType, serendip, order, *name); + return 0; +} + +int nodalBasis::compareNewAlgoBaseFunctionsWithOld() const +{ + const char **name = new const char*[1]; + MElement::getInfoMSH(type, name); + int ndof = points.size1(); + int P[3]; + double oldVal[ndof], newVal[ndof]; + for (int i = 0; i < 10; ++i) { + if (i == 0) { + P[0] = 0; + P[1] = 0; + P[2] = 0; + } + else if (i == 1) { + P[0] = 0; + P[1] = 0; + P[2] = 1000; + } + else if (i == 2) { + P[0] = 1000; + P[1] = 0; + P[2] = 0; + } + else { + P[0] = std::rand() % 1001; + P[1] = std::rand() % (1001 - P[0]); + P[2] = std::rand() % (1001 - P[0] - P[1]); + } + + f(P[0] / 1000., P[1] / 1000., P[2] / 1000., oldVal); + fnew(P[0] / 1000., P[1] / 1000., P[2] / 1000., newVal); + + double sumError = .0; + double sumOne[2]; + sumOne[0] = .0; + sumOne[1] = .0; + for (int j = 0; j < ndof; ++j) { + double diff = std::abs(oldVal[j] - newVal[j]); + //double mean = std::sqrt(.5 * (oldVal[j]*oldVal[j] + newVal[j]*newVal[j])); + //double error = diff/(mean + 1e-15); + double error = diff; + sumError += error*error; + sumOne[0] += oldVal[j]; + sumOne[1] += newVal[j]; + } + sumError = std::sqrt(sumError/ndof); + /*if (sumError > 1e-4) { + Msg::Error("(%.2f, %.2f, %.2f) -> fold=%.2e / fnew=%.2e", P[0] / 1000., P[1] / 1000., P[2] / 1000., sumOne[0], sumOne[1]); + //for (int j = 0; j < ndof; ++j) { + // Msg::Info("old %.3e vs %.3e new", oldVal[j], newVal[j]); + //} + }*/ + if (sumError > 1e-13) { + if (type < 10) Msg::Warning(" f(%.2f, %.2f, %.2f) bad precision diff %.2e", P[0] / 1000., P[1] / 1000., P[2] / 1000., sumError); + else if (type < 100) Msg::Warning(" f(%.2f, %.2f, %.2f) bad precision diff %.2e", P[0] / 1000., P[1] / 1000., P[2] / 1000., sumError); + else Msg::Warning(" f(%.2f, %.2f, %.2f) bad precision diff %.2e", P[0] / 1000., P[1] / 1000., P[2] / 1000., sumError); + return 1; + } + /*else if (type < 10) Msg::Info(" f(%.2f, %.2f, %.2f) ok", P[0] / 1000., P[1] / 1000., P[2] / 1000.); + else if (type < 100) Msg::Info(" f(%.2f, %.2f, %.2f) ok", P[0] / 1000., P[1] / 1000., P[2] / 1000.); + else Msg::Info(" f(%.2f, %.2f, %.2f) ok", P[0] / 1000., P[1] / 1000., P[2] / 1000.); + */ + } return 0; } diff --git a/Numeric/nodalBasis.h b/Numeric/nodalBasis.h index 1957fdc3bb9211dc39d3a23206c30b74851c5553..c7339acca791daeb6f1f5bcdfeadc80bb98d0009 100644 --- a/Numeric/nodalBasis.h +++ b/Numeric/nodalBasis.h @@ -16,6 +16,7 @@ class nodalBasis { fullMatrix<double> points; fullMatrix<double> points_newAlgo; fullMatrix<int> monomials_newAlgo; + fullMatrix<double> coefficients_newAlgo; nodalBasis(int tag); virtual ~nodalBasis() {} @@ -24,6 +25,7 @@ class nodalBasis { // Basis functions & gradients evaluation virtual void f(double u, double v, double w, double *sf) const = 0; + virtual void fnew(double u, double v, double w, double *sf) const = 0; virtual void f(const fullMatrix<double> &coord, fullMatrix<double> &sf) const = 0; virtual void df(double u, double v, double w, double grads[][3]) const = 0; virtual void df(const fullMatrix<double> &coord, fullMatrix<double> &dfm) const = 0; @@ -31,6 +33,7 @@ class nodalBasis { virtual void dddf(double u, double v, double w, double grads[][3][3][3]) const {Msg::Fatal("Not implemented");}; int compareNewAlgoPointsWithOld() const; + int compareNewAlgoBaseFunctionsWithOld() const; // closures is the list of the nodes of each face, in the order of // the polynomialBasis of the face; fullClosures is mapping of the diff --git a/Numeric/pointsGenerators.cpp b/Numeric/pointsGenerators.cpp index 4d12d058af3f39c868b4564399e5abd6ef369840..2b6365b1273740875c05df2e13783e783449b4ea 100644 --- a/Numeric/pointsGenerators.cpp +++ b/Numeric/pointsGenerators.cpp @@ -826,9 +826,11 @@ fullMatrix<int> gmshGenerateMonomialsTriangle(int order, bool serendip) monomials(index, 1) = monomials(i0, 1) + u_1 * i; } } - fullMatrix<int> inner = gmshGenerateMonomialsTriangle(order-3); - inner.add(1); - monomials.copy(inner, 0, nbMonomials - index, 0, 2, index, 0); + if (!serendip) { + fullMatrix<int> inner = gmshGenerateMonomialsTriangle(order-3); + inner.add(1); + monomials.copy(inner, 0, nbMonomials - index, 0, 2, index, 0); + } } } return monomials; diff --git a/Numeric/polynomialBasis.cpp b/Numeric/polynomialBasis.cpp index d4cef22282809c3f54f24709ec9ba66c3f8f83af..27717851935b57674a330ea10ddfe4d78770e484 100644 --- a/Numeric/polynomialBasis.cpp +++ b/Numeric/polynomialBasis.cpp @@ -9,6 +9,7 @@ // #include <stdlib.h> +#include <cmath> #include "GmshDefines.h" #include "GmshMessage.h" #include "polynomialBasis.h" @@ -137,6 +138,87 @@ static fullMatrix<double> generatePascalQuad(int order) static fullMatrix<double> generatePascalHex(int order, bool serendip) { + if (false && serendip) { + fullMatrix<double> monomials( 8+(order-1)*12, 3); + monomials(0,0)=0.; + monomials(0,1)=0.; + monomials(0,2)=0.; + monomials(1,0)=1.; + monomials(1,1)=0.; + monomials(1,2)=0.; + monomials(2,0)=0.; + monomials(2,1)=1.; + monomials(2,2)=0.; + monomials(3,0)=1.; + monomials(3,1)=1.; + monomials(3,2)=0.; + + monomials(4,0)=0.; + monomials(4,1)=0.; + monomials(4,2)=1.; + monomials(5,0)=1.; + monomials(5,1)=0.; + monomials(5,2)=1.; + monomials(6,0)=0.; + monomials(6,1)=1.; + monomials(6,2)=1.; + monomials(7,0)=1.; + monomials(7,1)=1.; + monomials(7,2)=1.; + int index = 8; + for (int p = 2; p <= order; p++) { + monomials(index, 0) = p; + monomials(index, 1) = 0; + monomials(index, 2) = 0; + index++; + monomials(index, 0) = p; + monomials(index, 1) = 1; + monomials(index, 2) = 0; + index++; + monomials(index, 0) = p; + monomials(index, 1) = 1; + monomials(index, 2) = 1; + index++; + monomials(index, 0) = p; + monomials(index, 1) = 0; + monomials(index, 2) = 1; + index++; + monomials(index, 0) = 0; + monomials(index, 1) = p; + monomials(index, 2) = 0; + index++; + monomials(index, 0) = 1; + monomials(index, 1) = p; + monomials(index, 2) = 0; + index++; + monomials(index, 0) = 1; + monomials(index, 1) = p; + monomials(index, 2) = 1; + index++; + monomials(index, 0) = 0; + monomials(index, 1) = p; + monomials(index, 2) = 1; + index++; + monomials(index, 0) = 0; + monomials(index, 1) = 0; + monomials(index, 2) = p; + index++; + monomials(index, 0) = 1; + monomials(index, 1) = 0; + monomials(index, 2) = p; + index++; + monomials(index, 0) = 1; + monomials(index, 1) = 1; + monomials(index, 2) = p; + index++; + monomials(index, 0) = 0; + monomials(index, 1) = 1; + monomials(index, 2) = p; + index++; + } + return monomials; + } + int siz = (order+1)*(order+1)*(order+1); if (serendip) siz -= (order-1)*(order-1)*(order-1); fullMatrix<double> monomials( siz, 3); @@ -340,6 +422,19 @@ static fullMatrix<double> generateLagrangeMonomialCoefficients fullMatrix<double> coefficient(ndofs, ndofs); Vandermonde.invert(coefficient); + + fullMatrix<double> unity(ndofs, ndofs); + Vandermonde.mult(coefficient, unity); + double max = .0; + for (int i = 0; i < ndofs; i++) { + for (int j = 0; j < ndofs; j++) { + if (i == j) unity(i, j) -= 1.; + //Msg::Info(" unity(%d, %d) = %.3e", i, j, unity(i, j)); + max = std::max(max, std::abs(unity(i, j))); + } + } + if (max > 1e-10) Msg::Info(" max unity = %.3e", max); + return coefficient; } @@ -417,7 +512,7 @@ polynomialBasis::polynomialBasis(int tag) : nodalBasis(tag) break; } copy(monomials_newAlgo, points_newAlgo); - if (order == 0) return; + //if (order == 0) return; switch (rescale) { case 0 : points_newAlgo.scale(1./order); @@ -440,6 +535,23 @@ polynomialBasis::polynomialBasis(int tag) : nodalBasis(tag) default : break; } + + fullMatrix<double> monDouble; + switch (parentType) { + case TYPE_PNT : + case TYPE_LIN : + case TYPE_TRI : + case TYPE_TET : + copy(monomials_newAlgo, monDouble); + break; + case TYPE_QUA : + case TYPE_HEX : + case TYPE_PRI : + //if (serendip) monDouble = monomials; + /*else*/ copy(monomials_newAlgo, monDouble); + break; + } + coefficients_newAlgo = generateLagrangeMonomialCoefficients(monDouble, points_newAlgo); } @@ -451,6 +563,23 @@ polynomialBasis::~polynomialBasis() +inline void polynomialBasis::evaluateMonomialsNew(double u, double v, double w, double p[]) const +{ + for (int j = 0; j < monomials_newAlgo.size1(); ++j) { + p[j] = 1.; + switch (dimension) { + case 3 : + p[j] *= pow_int(w, monomials_newAlgo(j, 2)); + case 2 : + p[j] *= pow_int(v, monomials_newAlgo(j, 1)); + case 1 : + p[j] *= pow_int(u, monomials_newAlgo(j, 0)); + default : + break; + } + } +} + void polynomialBasis::f(double u, double v, double w, double *sf) const @@ -464,6 +593,17 @@ void polynomialBasis::f(double u, double v, double w, double *sf) const } } } +void polynomialBasis::fnew(double u, double v, double w, double *sf) const +{ + double p[1256]; + evaluateMonomialsNew(u, v, w, p); + for (int i = 0; i < coefficients_newAlgo.size1(); i++) { + sf[i] = 0.0; + for (int j = 0; j < coefficients_newAlgo.size2(); j++) { + sf[i] += coefficients_newAlgo(i, j) * p[j]; + } + } +} diff --git a/Numeric/polynomialBasis.h b/Numeric/polynomialBasis.h index 5c67c3580b3ef1f9548cbfed20be1bbefea358a1..da48cc29cfe9901a17ab42f1809e37ed6f49cf9f 100644 --- a/Numeric/polynomialBasis.h +++ b/Numeric/polynomialBasis.h @@ -78,6 +78,7 @@ class polynomialBasis : public nodalBasis virtual inline int getNumShapeFunctions() const {return coefficients.size1();} virtual void f(double u, double v, double w, double *sf) const; + virtual void fnew(double u, double v, double w, double *sf) const; virtual void f(const fullMatrix<double> &coord, fullMatrix<double> &sf) const; virtual void df(const fullMatrix<double> &coord, fullMatrix<double> &dfm) const; virtual void df(double u, double v, double w, double grads[][3]) const; @@ -91,6 +92,7 @@ class polynomialBasis : public nodalBasis if (monomials.size2() > 2) p[j] *= pow_int(w, (int)monomials(j, 2)); } } + inline void evaluateMonomialsNew(double u, double v, double w, double p[]) const; }; #endif diff --git a/Numeric/pyramidalBasis.cpp b/Numeric/pyramidalBasis.cpp index 13c030b81b6c5d5c9e432d4f3fe855f9c05324e7..888752d749e907a55c55fd94f7d54bd4cf7ddc2d 100644 --- a/Numeric/pyramidalBasis.cpp +++ b/Numeric/pyramidalBasis.cpp @@ -5,6 +5,7 @@ #include "pyramidalBasis.h" #include "pointsGenerators.h" +#include <cmath> static void copy(const fullMatrix<int> &orig, fullMatrix<double> &b) @@ -17,6 +18,55 @@ static void copy(const fullMatrix<int> &orig, fullMatrix<double> &b) } } +static fullMatrix<double> generateLagrangeMonomialCoefficientsPyr + (const fullMatrix<double>& monomial, const fullMatrix<double>& point) +{ + if(monomial.size1() != point.size1() || monomial.size2() != point.size2()){ + Msg::Fatal("Wrong sizes for Lagrange coefficients generation %d %d -- %d %d", + monomial.size1(),point.size1(), + monomial.size2(),point.size2() ); + return fullMatrix<double>(1, 1); + } + + int ndofs = monomial.size1(); + int dim = monomial.size2(); + fullMatrix<double> ppoint(point.size1(), point.size2()); + + for (int i = 0; i < ndofs; ++i) { + ppoint(i, 2) = 1. - point(i, 2); + if (ppoint(i, 2) != .0) { + ppoint(i, 0) = point(i, 0) / ppoint(i, 2); + ppoint(i, 1) = point(i, 1) / ppoint(i, 2); + } + } + + fullMatrix<double> Vandermonde(ndofs, ndofs); + for (int i = 0; i < ndofs; i++) { + for (int j = 0; j < ndofs; j++) { + double dd = 1.; + for (int k = 0; k < dim; k++) dd *= pow(ppoint(j, k), monomial(i, k)); + Vandermonde(i, j) = dd; + } + } + + fullMatrix<double> coefficient(ndofs, ndofs); + Vandermonde.invert(coefficient); + + fullMatrix<double> unity(ndofs, ndofs); + Vandermonde.mult(coefficient, unity); + double max = .0; + for (int i = 0; i < ndofs; i++) { + for (int j = 0; j < ndofs; j++) { + if (i == j) unity(i, j) -= 1.; + //Msg::Info(" unity(%d, %d) = %.3e", i, j, unity(i, j)); + max = std::max(max, std::abs(unity(i, j))); + } + } + if (max > 1e-10) Msg::Info("mon max unity = %.3e", max); + + return coefficient; +} + pyramidalBasis::pyramidalBasis(int tag) : nodalBasis(tag) { @@ -38,6 +88,19 @@ pyramidalBasis::pyramidalBasis(int tag) : nodalBasis(tag) delete[] fval; + fullMatrix<double> unity(num_points, num_points); + VDM.mult(VDMinv, unity); + double max = .0; + for (int i = 0; i < num_points; i++) { + for (int j = 0; j < num_points; j++) { + if (i == j) unity(i, j) -= 1.; + //Msg::Info(" unity(%d, %d) = %.3e", i, j, unity(i, j)); + max = std::max(max, std::abs(unity(i, j))); + } + } + if (max > 1e-10) Msg::Info("leg max unity = %.3e", max); + + // TEST NEW ALGO POINTS / MONOMIAL monomials_newAlgo = gmshGenerateMonomialsPyramid(order, serendip); @@ -52,6 +115,10 @@ pyramidalBasis::pyramidalBasis(int tag) : nodalBasis(tag) points_newAlgo(i, 1) = duv + points_newAlgo(i, 1) * 2. / order; } } + + fullMatrix<double> monDouble; + copy(monomials_newAlgo, monDouble); + coefficients_newAlgo = generateLagrangeMonomialCoefficientsPyr(monDouble, points_newAlgo); } @@ -83,6 +150,17 @@ void pyramidalBasis::f(double u, double v, double w, double *val) const delete[] fval; } +void pyramidalBasis::fnew(double u, double v, double w, double *sf) const +{ + double p[1256]; + evaluateMonomialsNew(u, v, w, p); + for (int i = 0; i < coefficients_newAlgo.size1(); i++) { + sf[i] = 0.0; + for (int j = 0; j < coefficients_newAlgo.size2(); j++) { + sf[i] += coefficients_newAlgo(i, j) * p[j]; + } + } +} diff --git a/Numeric/pyramidalBasis.h b/Numeric/pyramidalBasis.h index b570a9b1e1d311269de84021c117341ef230d1f9..998f49d4d757affa77b395ac0ae5fdc13f2b9f4a 100644 --- a/Numeric/pyramidalBasis.h +++ b/Numeric/pyramidalBasis.h @@ -27,12 +27,25 @@ class pyramidalBasis: public nodalBasis ~pyramidalBasis(); virtual void f(double u, double v, double w, double *val) const; + virtual void fnew(double u, double v, double w, double *val) const; virtual void f(const fullMatrix<double> &coord, fullMatrix<double> &sf) const; virtual void df(double u, double v, double w, double grads[][3]) const; virtual void df(const fullMatrix<double> &coord, fullMatrix<double> &dfm) const; virtual int getNumShapeFunctions() const; + inline void evaluateMonomialsNew(double u, double v, double w, double p[]) const { + w = 1-w; + if (w != .0) { + u = u/w; + v = v/w; + } + for (int j = 0; j < monomials_newAlgo.size1(); j++) { + p[j] = pow_int(u, monomials_newAlgo(j, 0)); + if (dimension > 1) p[j] *= pow_int(v, monomials_newAlgo(j, 1)); + if (dimension > 2) p[j] *= pow_int(w, monomials_newAlgo(j, 2)); + } + } };