From a29b84d6057eda129638cadf19aeb05ba184e1b3 Mon Sep 17 00:00:00 2001 From: Jean-Francois Remacle <jean-francois.remacle@uclouvain.be> Date: Fri, 2 Oct 2009 15:12:54 +0000 Subject: [PATCH] High order quads --- Common/GmshDefines.h | 7 ++ Geo/GModelIO_Mesh.cpp | 8 +- Geo/MElement.cpp | 11 ++- Geo/MQuadrangle.cpp | 145 +++++++++++++++++++++++++++++ Geo/MQuadrangle.h | 187 +++++++++++++++++++++++++++----------- Mesh/HighOrder.cpp | 176 +++++++++++++++-------------------- Numeric/functionSpace.cpp | 156 +++++++++++++++++++++++++++++++ 7 files changed, 529 insertions(+), 161 deletions(-) diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h index d4b66d6be4..bbd732ae8b 100644 --- a/Common/GmshDefines.h +++ b/Common/GmshDefines.h @@ -90,6 +90,13 @@ #define MSH_TET_52 33 #define MSH_POLYG_ 34 #define MSH_POLYH_ 35 +#define MSH_QUA_16 36 +#define MSH_QUA_25 37 +#define MSH_QUA_36 38 +#define MSH_QUA_12 39 +#define MSH_QUA_16I 40 +#define MSH_QUA_20 41 + #define MSH_NUM_TYPE 35 diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp index b7745f466a..78969fc777 100644 --- a/Geo/GModelIO_Mesh.cpp +++ b/Geo/GModelIO_Mesh.cpp @@ -477,7 +477,7 @@ int GModel::readMSH(const std::string &name) static void writeElementHeaderMSH(bool binary, FILE *fp, std::map<int,int> &elements, int t1, int t2=0, int t3=0, int t4=0, - int t5=0, int t6=0, int t7=0, int t8=0) + int t5=0, int t6=0, int t7=0, int t8=0, int t9=0) { if(!binary) return; @@ -515,6 +515,10 @@ static void writeElementHeaderMSH(bool binary, FILE *fp, std::map<int,int> &elem data[0] = t8; data[1] = elements[t8]; data[2] = numTags; fwrite(data, sizeof(int), 3, fp); } + else if(t9 && elements.count(t9)){ + data[0] = t9; data[1] = elements[t9]; data[2] = numTags; + fwrite(data, sizeof(int), 3, fp); + } } template<class T> @@ -704,7 +708,7 @@ int GModel::writeMSH(const std::string &name, double version, bool binary, for(fiter it = firstFace(); it != lastFace(); ++it) writeElementsMSH(fp, (*it)->triangles, saveAll, version, binary, num, (*it)->tag(), (*it)->physicals); - writeElementHeaderMSH(binary, fp, elements, MSH_QUA_4, MSH_QUA_9, MSH_QUA_8); + writeElementHeaderMSH(binary, fp, elements, MSH_QUA_4, MSH_QUA_9, MSH_QUA_8, MSH_QUA_16, MSH_QUA_25, MSH_QUA_36,MSH_QUA_12,MSH_QUA_16I,MSH_QUA_20); for(itP = parents[0].begin(); itP != parents[0].end(); itP++) if(itP->first->getType() == TYPE_QUA) { writeElementsMSH(fp, itP->first, saveAll, version, binary, num, diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp index 5231fff5e4..14c715ed05 100644 --- a/Geo/MElement.cpp +++ b/Geo/MElement.cpp @@ -684,7 +684,13 @@ int MElement::getInfoMSH(const int typeMSH, const char **const name) case MSH_TRI_21 : if(name) *name = "Triangle 21"; return 3 + 12 + 6; case MSH_QUA_4 : if(name) *name = "Quadrilateral 4"; return 4; case MSH_QUA_8 : if(name) *name = "Quadrilateral 8"; return 4 + 4; - case MSH_QUA_9 : if(name) *name = "Quadrilateral 9"; return 4 + 4 + 1; + case MSH_QUA_9 : if(name) *name = "Quadrilateral 9"; return 9; + case MSH_QUA_16 : if(name) *name = "Quadrilateral 16"; return 16; + case MSH_QUA_25 : if(name) *name = "Quadrilateral 25"; return 25; + case MSH_QUA_36 : if(name) *name = "Quadrilateral 36"; return 36; + case MSH_QUA_12 : if(name) *name = "Quadrilateral 12"; return 12; + case MSH_QUA_16I : if(name) *name = "Quadrilateral 16I"; return 16; + case MSH_QUA_20 : if(name) *name = "Quadrilateral 20"; return 20; case MSH_POLYG_ : if(name) *name = "Polygon"; return 0; case MSH_TET_4 : if(name) *name = "Tetrahedron 4"; return 4; case MSH_TET_10 : if(name) *name = "Tetrahedron 10"; return 4 + 6; @@ -731,6 +737,9 @@ MElement *MElementFactory::create(int type, std::vector<MVertex*> &v, case MSH_QUA_4: return new MQuadrangle(v, num, part); case MSH_QUA_8: return new MQuadrangle8(v, num, part); case MSH_QUA_9: return new MQuadrangle9(v, num, part); + case MSH_QUA_16: return new MQuadrangleN(v, 3, num, part); + case MSH_QUA_25: return new MQuadrangleN(v, 4, num, part); + case MSH_QUA_36: return new MQuadrangleN(v, 5, num, part); case MSH_POLYG_: return new MPolygon(v, num, part); case MSH_TET_4: return new MTetrahedron(v, num, part); case MSH_TET_10: return new MTetrahedron10(v, num, part); diff --git a/Geo/MQuadrangle.cpp b/Geo/MQuadrangle.cpp index 9c689220bc..6880925b40 100644 --- a/Geo/MQuadrangle.cpp +++ b/Geo/MQuadrangle.cpp @@ -7,6 +7,151 @@ #include "GaussLegendre1D.h" #include "Context.h" #include "qualityMeasures.h" +#define SQU(a) ((a)*(a)) +const functionSpace* MQuadrangle::getFunctionSpace(int o) const +{ + int order = (o == -1) ? getPolynomialOrder() : o; + + int nf = getNumFaceVertices(); + + if ((nf == 0) && (o == -1)) { + switch (order) { + case 1: return &functionSpaces::find(MSH_QUA_4); + case 2: return &functionSpaces::find(MSH_QUA_8); + case 3: return &functionSpaces::find(MSH_QUA_12); + case 4: return &functionSpaces::find(MSH_QUA_16I); + case 5: return &functionSpaces::find(MSH_QUA_20); + } + } + switch (order) { + case 1: return &functionSpaces::find(MSH_QUA_4); + case 2: return &functionSpaces::find(MSH_QUA_9); + case 3: return &functionSpaces::find(MSH_QUA_16); + case 4: return &functionSpaces::find(MSH_QUA_25); + case 5: return &functionSpaces::find(MSH_QUA_36); + default: Msg::Error("Order %d triangle function space not implemented", order); + } + return 0; +} + +int MQuadrangleN::getNumEdgesRep(){ return 4 * CTX::instance()->mesh.numSubEdges; } +int MQuadrangle8::getNumEdgesRep(){ return 4 * CTX::instance()->mesh.numSubEdges; } +int MQuadrangle9::getNumEdgesRep(){ return 4 * CTX::instance()->mesh.numSubEdges; } + +static void _myGetEdgeRep(MQuadrangle *q, int num, double *x, double *y, double *z, + SVector3 *n, int numSubEdges) +{ + n[0] = n[1] = n[2] = n[3] = q->getFace(0).normal(); + int ie = num/numSubEdges; + int isub = num%numSubEdges; + double xi1 = -1. + (2.*isub)/numSubEdges; + double xi2 = -1. + (2.*(isub+1))/numSubEdges; + SPoint3 pnt1, pnt2; + switch(ie){ + case 0: + q->pnt( xi1, -1., 0., pnt1); + q->pnt( xi2, -1., 0., pnt2); + break; + case 1: + q->pnt( 1., xi1, 0., pnt1); + q->pnt( 1., xi2, 0., pnt2); + break; + case 2: + q->pnt( xi1, 1., 0., pnt1); + q->pnt( xi2, 1., 0., pnt2); + break; + case 3: + q->pnt(-1., xi1, 0., pnt1); + q->pnt(-1., xi2, 0., pnt2); + break; + } + x[0] = pnt1.x(); x[1] = pnt2.x(); + y[0] = pnt1.y(); y[1] = pnt2.y(); + z[0] = pnt1.z(); z[1] = pnt2.z(); +} + +void MQuadrangleN::getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n) +{ + _myGetEdgeRep(this, num, x, y, z, n, CTX::instance()->mesh.numSubEdges); +} +void MQuadrangle8::getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n) +{ + _myGetEdgeRep(this, num, x, y, z, n, CTX::instance()->mesh.numSubEdges); +} +void MQuadrangle9::getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n) +{ + _myGetEdgeRep(this, num, x, y, z, n, CTX::instance()->mesh.numSubEdges); +} + + +int MQuadrangleN::getNumFacesRep(){ return 2*SQU(CTX::instance()->mesh.numSubEdges); } +int MQuadrangle8::getNumFacesRep(){ return 2*SQU(CTX::instance()->mesh.numSubEdges); } +int MQuadrangle9::getNumFacesRep(){ return 2*SQU(CTX::instance()->mesh.numSubEdges); } + +static void _myGetFaceRep(MQuadrangle *t, int num, double *x, double *y, double *z, + SVector3 *n, int numSubEdges) +{ + int io = num%2; + int ix = (num/2)/numSubEdges; + int iy = (num/2)%numSubEdges; + + const double d = 2. / numSubEdges; + const double ox = -1. + d*ix; + const double oy = -1. + d*iy; + + SPoint3 pnt1, pnt2, pnt3; + double J1[3][3], J2[3][3], J3[3][3]; + if (io == 0){ + t->pnt(ox, oy, 0, pnt1); + t->pnt(ox + d, oy, 0, pnt2); + t->pnt(ox + d, oy + d, 0, pnt3); + t->getJacobian(ox, oy, 0, J1); + t->getJacobian(ox + d, oy, 0, J2); + t->getJacobian(ox + d, oy + d, 0, J3); + } else{ + t->pnt(ox, oy, 0, pnt1); + t->pnt(ox + d, oy + d, 0, pnt2); + t->pnt(ox, oy + d, 0, pnt3); + t->getJacobian(ox, oy, 0, J1); + t->getJacobian(ox + d, oy + d, 0, J2); + t->getJacobian(ox, oy + d, 0, J3); + } + { + SVector3 d1(J1[0][0], J1[0][1], J1[0][2]); + SVector3 d2(J1[1][0], J1[1][1], J1[1][2]); + n[0] = crossprod(d1, d2); + n[0].normalize(); + } + { + SVector3 d1(J2[0][0], J2[0][1], J2[0][2]); + SVector3 d2(J2[1][0], J2[1][1], J2[1][2]); + n[1] = crossprod(d1, d2); + n[1].normalize(); + } + { + SVector3 d1(J3[0][0], J3[0][1], J3[0][2]); + SVector3 d2(J3[1][0], J3[1][1], J3[1][2]); + n[2] = crossprod(d1, d2); + n[2].normalize(); + } + + x[0] = pnt1.x(); x[1] = pnt2.x(); x[2] = pnt3.x(); + y[0] = pnt1.y(); y[1] = pnt2.y(); y[2] = pnt3.y(); + z[0] = pnt1.z(); z[1] = pnt2.z(); z[2] = pnt3.z(); +} + +void MQuadrangleN::getFaceRep(int num, double *x, double *y, double *z, SVector3 *n) +{ + _myGetFaceRep(this, num, x, y, z, n, CTX::instance()->mesh.numSubEdges); +} +void MQuadrangle8::getFaceRep(int num, double *x, double *y, double *z, SVector3 *n) +{ + _myGetFaceRep(this, num, x, y, z, n, CTX::instance()->mesh.numSubEdges); +} +void MQuadrangle9::getFaceRep(int num, double *x, double *y, double *z, SVector3 *n) +{ + _myGetFaceRep(this, num, x, y, z, n, CTX::instance()->mesh.numSubEdges); +} void MQuadrangle::getIntegrationPoints(int pOrder, int *npts, IntPt **pts) const { diff --git a/Geo/MQuadrangle.h b/Geo/MQuadrangle.h index 376265d3fb..62603daf10 100644 --- a/Geo/MQuadrangle.h +++ b/Geo/MQuadrangle.h @@ -115,24 +115,11 @@ class MQuadrangle : public MElement { virtual const char *getStringForPOS() const { return "SQ"; } virtual const char *getStringForBDF() const { return "CQUAD4"; } virtual const char *getStringForDIFF() const { return "ElmB4n2D"; } + virtual const functionSpace* getFunctionSpace(int o=-1) const; virtual void revert() { MVertex *tmp = _v[1]; _v[1] = _v[3]; _v[3] = tmp; } - virtual void getShapeFunctions(double u, double v, double w, double s[], int o) - { - s[0] = (1. - u) * (1. - v) * 0.25; - s[1] = (1. + u) * (1. - v) * 0.25; - s[2] = (1. + u) * (1. + v) * 0.25; - s[3] = (1. - u) * (1. + v) * 0.25; - } - virtual void getGradShapeFunctions(double u, double v, double w, double s[][3], int o) - { - s[0][0] = -0.25 * (1. - v); s[0][1] = -0.25 * (1. - u); s[0][2] = 0.; - s[1][0] = 0.25 * (1. - v); s[1][1] = -0.25 * (1. + u); s[1][2] = 0.; - s[2][0] = 0.25 * (1. + v); s[2][1] = 0.25 * (1. + u); s[2][2] = 0.; - s[3][0] = -0.25 * (1. + v); s[3][1] = 0.25 * (1. - u); s[3][2] = 0.; - } virtual bool isInside(double u, double v, double w) { double tol = _isInsideTolerance; @@ -203,32 +190,16 @@ class MQuadrangle8 : public MQuadrangle { return getVertex(map[num]); } virtual int getNumEdgeVertices() const { return 4; } - virtual int getNumEdgesRep(){ return 8; } - virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n) - { - static const int e[8][2] = { - {0, 4}, {4, 1}, - {1, 5}, {5, 2}, - {2, 6}, {6, 3}, - {3, 7}, {7, 0} - }; - _getEdgeRep(getVertex(e[num][0]), getVertex(e[num][1]), x, y, z, n, 0); - } + virtual int getNumEdgesRep(); + virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n); virtual void getEdgeVertices(const int num, std::vector<MVertex*> &v) const { v.resize(3); MQuadrangle::_getEdgeVertices(num, v); v[2] = _vs[num]; } - virtual int getNumFacesRep(){ return 6; } - virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n) - { - static const int f[6][3] = { - {0, 4, 7}, {1, 5, 4}, {2, 6, 5}, {3, 7, 6}, {4, 5, 6}, {4, 6, 7} - }; - _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]), - x, y, z, n); - } + virtual int getNumFacesRep(); + virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n); virtual void getFaceVertices(const int num, std::vector<MVertex*> &v) const { v.resize(8); @@ -292,33 +263,16 @@ class MQuadrangle9 : public MQuadrangle { } virtual int getNumEdgeVertices() const { return 4; } virtual int getNumFaceVertices() const { return 1; } - virtual int getNumEdgesRep(){ return 8; } - virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n) - { - static const int e[8][2] = { - {0, 4}, {4, 1}, - {1, 5}, {5, 2}, - {2, 6}, {6, 3}, - {3, 7}, {7, 0} - }; - _getEdgeRep(getVertex(e[num][0]), getVertex(e[num][1]), x, y, z, n, 0); - } + virtual int getNumEdgesRep(); + virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n); virtual void getEdgeVertices(const int num, std::vector<MVertex*> &v) const { v.resize(3); MQuadrangle::getEdgeVertices(num, v); v[2] = _vs[num]; } - virtual int getNumFacesRep(){ return 8; } - virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n) - { - static const int f[8][4] = { - {0, 4, 8}, {0, 8, 7}, {1, 5, 8}, {1, 8, 4}, - {2, 6, 8}, {2, 8, 5}, {3, 7, 8}, {3, 8, 6} - }; - _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]), - x, y, z, n); - } + virtual int getNumFacesRep(); + virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n); virtual void getFaceVertices(const int num, std::vector<MVertex*> &v) const { v.resize(9); @@ -341,4 +295,127 @@ class MQuadrangle9 : public MQuadrangle { } }; +/* + * MQuadrangle + * + * 3--3+3E-...--4+2E--2 + * | | E = order - 1; + * | | N = total number of vertices + * 4+3E 3+2E + * | | Interior vertex numbers + * ... 4+4e to N-1 ... for edge 0 <= i <= 3: 4+i*E to 3+(i+1)*E + * | | in volume : 4+4*E to N-1 + * 3+4E 4+E + * | | + * | | + * 0---4--...---3+E---1 + * + */ +class MQuadrangleN : public MQuadrangle { + protected: + std::vector<MVertex *> _vs; + const char _order; + public: + MQuadrangleN(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3, + std::vector<MVertex*> &v, char order, int num=0, int part=0) + : MQuadrangle(v0, v1, v2, v3, num, part), _vs(v), _order(order) + { + for(unsigned int i = 0; i < _vs.size(); i++) _vs[i]->setPolynomialOrder(_order); + } + MQuadrangleN(std::vector<MVertex*> &v, char order, int num=0, int part=0) + : MQuadrangle(v[0], v[1], v[2], v[3], num, part), _order(order) + { + for(unsigned int i = 4; i < v.size(); i++) _vs.push_back(v[i]); + for(unsigned int i = 0; i < _vs.size(); i++) _vs[i]->setPolynomialOrder(_order); + } + ~MQuadrangleN(){} + virtual int getPolynomialOrder() const { return _order; } + virtual int getNumVertices() const {return 4 + _vs.size(); } + virtual MVertex *getVertex(int num){ return num < 4 ? _v[num] : _vs[num - 4]; } + virtual int getNumFaceVertices() const + { + if( _order>1 && _vs.size()+4==(_order+1)*(_order+1)) + return (_order-1)*(_order-1); + else + return 0; + } + virtual int getNumEdgeVertices() const { return 4 * (_order - 1); } + virtual int getNumEdgesRep(); + virtual int getNumFacesRep(); + virtual void getEdgeRep(int num, double *x, double *y, double *z, SVector3 *n); + virtual void getEdgeVertices(const int num, std::vector<MVertex*> &v) const + { + v.resize(_order + 1); + MQuadrangle::_getEdgeVertices(num, v); + int j = 2; + const int ie = (num + 1) * (_order - 1); + for(int i = num * (_order-1); i != ie; ++i) + v[j++] = _vs[i]; + } + virtual void getFaceRep(int num, double *x, double *y, double *z, SVector3 *n); + virtual void getFaceVertices(const int num, std::vector<MVertex*> &v) const + { + v.resize(4 + _vs.size()); + MQuadrangle::_getFaceVertices(v); + for(unsigned int i = 0; i != _vs.size(); ++i) v[i + 4] = _vs[i]; + } + virtual int getTypeForMSH() const + { + if(_order==2 && _vs.size()+4==8) return MSH_QUA_8; + if(_order==3 && _vs.size()+4==12) return MSH_QUA_12; + if(_order==3 && _vs.size()+4==16) return MSH_QUA_16; + if(_order==4 && _vs.size()+4==16) return MSH_QUA_16I; + if(_order==4 && _vs.size()+4==25) return MSH_QUA_25; + if(_order==5 && _vs.size()+4==20) return MSH_QUA_20; + if(_order==5 && _vs.size()+4==36) return MSH_QUA_36; + return 0; + } + virtual void revert() + { + MVertex *tmp; + tmp = _v[1]; _v[1] = _v[3]; _v[3] = tmp; + std::vector<MVertex*> inv; + inv.insert(inv.begin(), _vs.rbegin(), _vs.rend()); + _vs = inv; + } +}; + +template <class T> +void inline sort2(T &a, T &b){ + if(b<a){ + T t=b; + b=a; + a=t; + } +} + +template <class T> +void sort4(T *t[3]) +{ + sort2<T*>(t[0],t[1]); + sort2<T*>(t[2],t[3]); + sort2<T*>(t[0],t[2]); + sort2<T*>(t[1],t[3]); + sort2<T*>(t[1],t[2]); +} + +struct compareMQuadrangleLexicographic +{ + bool operator () (MQuadrangle *t1, MQuadrangle *t2) const + { + MVertex *_v1[] = {t1->getVertex(0), t1->getVertex(1), t1->getVertex(2), t1->getVertex(3)}; + MVertex *_v2[] = {t2->getVertex(0), t2->getVertex(1), t2->getVertex(2), t2->getVertex(3)}; + sort4(_v1); + sort4(_v2); + if(_v1[0] < _v2[0]) return true; + if(_v1[0] > _v2[0]) return false; + if(_v1[1] < _v2[1]) return true; + if(_v1[1] > _v2[1]) return false; + if(_v1[2] < _v2[2]) return true; + if(_v1[2] > _v2[2]) return false; + if(_v1[3] < _v1[3]) return true; + return false; + } +}; + #endif diff --git a/Mesh/HighOrder.cpp b/Mesh/HighOrder.cpp index e5c10cbadd..cc2af1b450 100644 --- a/Mesh/HighOrder.cpp +++ b/Mesh/HighOrder.cpp @@ -408,28 +408,6 @@ static void getFaceVertices(GFace *gf, MElement *incomplete, MElement *ele, if(gf->geomType() == GEntity::DiscreteSurface || gf->geomType() == GEntity::BoundaryLayerSurface) linear = true; - - fullMatrix<double> points; - int start = 0; - - switch (nPts){ - case 2 : - points = functionSpaces::find(MSH_TRI_10).points; - start = 9; - break; - case 3 : - points = functionSpaces::find(MSH_TRI_15).points; - start = 12; - break; - case 4 : - points = functionSpaces::find(MSH_TRI_21).points; - start = 15; - break; - default : - // do nothing (e.g. for 2nd order tri faces or for quad faces) - break; - } - for(int i = 0; i < ele->getNumFaces(); i++){ MFace face = ele->getFace(i); faceContainer::iterator fIter = faceVertices.find(face); @@ -444,81 +422,54 @@ static void getFaceVertices(GFace *gf, MElement *incomplete, MElement *ele, for(int k = 0; k < incomplete->getNumVertices(); k++) reparamOK &= reparamMeshVertexOnFace(incomplete->getVertex(k), gf, pts[k]); } - if(face.getNumVertices() == 3 && nPts > 1){ // tri face - for(int k = start; k < points.size1(); k++){ - MVertex *v; - const double t1 = points(k, 0); - const double t2 = points(k, 1); - if(linear){ - SPoint3 pc = face.interpolate(t1, t2); - v = new MVertex(pc.x(), pc.y(), pc.z(), gf); - } - else{ - double X(0), Y(0), Z(0), GUESS[2] = {0, 0}; - double sf[256]; - incomplete->getShapeFunctions(t1, t2, 0, sf); - for (int j = 0; j < incomplete->getNumVertices(); j++){ - MVertex *vt = incomplete->getVertex(j); - X += sf[j] * vt->x(); - Y += sf[j] * vt->y(); - Z += sf[j] * vt->z(); - if (reparamOK){ - GUESS[0] += sf[j] * pts[j][0]; - GUESS[1] += sf[j] * pts[j][1]; - } + int start = face.getNumVertices()*(nPts+1); + const fullMatrix<double> &points = ele->getFunctionSpace(nPts+1)->points; + for(int k = start; k < points.size1(); k++){ + MVertex *v; + const double t1 = points(k, 0); + const double t2 = points(k, 1); + if(linear){ + SPoint3 pc = face.interpolate(t1, t2); + v = new MVertex(pc.x(), pc.y(), pc.z(), gf); + } + else{ + double X(0), Y(0), Z(0), GUESS[2] = {0, 0}; + double sf[256]; + incomplete->getShapeFunctions(-1., -1., 0, sf); + for (int j = 0; j < incomplete->getNumVertices(); j++) + incomplete->getShapeFunctions(t1, t2, 0, sf); + for (int j = 0; j < incomplete->getNumVertices(); j++){ + MVertex *vt = incomplete->getVertex(j); + X += sf[j] * vt->x(); + Y += sf[j] * vt->y(); + Z += sf[j] * vt->z(); + if (reparamOK){ + GUESS[0] += sf[j] * pts[j][0]; + GUESS[1] += sf[j] * pts[j][1]; } - if(reparamOK){ - GPoint gp = gf->closestPoint(SPoint3(X, Y, Z), GUESS); - if (gp.g()){ - v = new MFaceVertex(gp.x(), gp.y(), gp.z(), gf, gp.u(), gp.v()); - } - else{ - v = new MVertex(X, Y, Z, gf); - } + } + if(reparamOK){ + GPoint gp = gf->closestPoint(SPoint3(X, Y, Z), GUESS); + if (gp.g()){ + v = new MFaceVertex(gp.x(), gp.y(), gp.z(), gf, gp.u(), gp.v()); } else{ v = new MVertex(X, Y, Z, gf); } - if(displ3D || displ2D){ - SPoint3 pc2 = face.interpolate(t1, t2); - if(displ3D)displ3D->add(v, SVector3(pc2.x(), pc2.y(), pc2.z())); - if(displ2D)displ2D->add(v, SVector3(pc2.x(), pc2.y(), pc2.z())); - } } - // should be expensive -> induces a new search each time - vtcs.push_back(v); - gf->mesh_vertices.push_back(v); - vf.push_back(v); - } - } - else if(face.getNumVertices() == 4){ // quad face - for(int j = 0; j < nPts; j++){ - for(int k = 0; k < nPts; k++){ - MVertex *v; - // parameters are between -1 and 1 - double t1 = 2. * (double)(j + 1) / (nPts + 1) - 1.; - double t2 = 2. * (double)(k + 1) / (nPts + 1) - 1.; - if(linear || !reparamOK){ - SPoint3 pc = face.interpolate(t1, t2); - v = new MVertex(pc.x(), pc.y(), pc.z(), gf); - } - else{ - double uc = 0.25 * ((1 - t1) * (1 - t2) * pts[0][0] + - (1 + t1) * (1 - t2) * pts[1][0] + - (1 + t1) * (1 + t2) * pts[2][0] + - (1 - t1) * (1 + t2) * pts[3][0]); - double vc = 0.25 * ((1 - t1) * (1 - t2) * pts[0][1] + - (1 + t1) * (1 - t2) * pts[1][1] + - (1 + t1) * (1 + t2) * pts[2][1] + - (1 - t1) * (1 + t2) * pts[3][1]); - GPoint pc = gf->point(uc, vc); - v = new MFaceVertex(pc.x(), pc.y(), pc.z(), gf, uc, vc); - } - vtcs.push_back(v); - gf->mesh_vertices.push_back(v); - vf.push_back(v); + else{ + v = new MVertex(X, Y, Z, gf); } + if(displ3D || displ2D){ + SPoint3 pc2 = face.interpolate(t1, t2); + if(displ3D)displ3D->add(v, SVector3(pc2.x(), pc2.y(), pc2.z())); + if(displ2D)displ2D->add(v, SVector3(pc2.x(), pc2.y(), pc2.z())); + } } + // should be expensive -> induces a new search each time + vtcs.push_back(v); + gf->mesh_vertices.push_back(v); + vf.push_back(v); } } } @@ -737,6 +688,37 @@ MTriangle* setHighOrder(MTriangle *t, GFace *gf, } } } +MQuadrangle *setHighOrder(MQuadrangle *q, GFace *gf, + edgeContainer &edgeVertices, + faceContainer &faceVertices, + bool linear, bool incomplete, int nPts, + highOrderSmoother *displ2D, + highOrderSmoother *displ3D) +{ + std::vector<MVertex*> ve, vf; + getEdgeVertices(gf, q, ve, edgeVertices, linear, nPts, displ2D, displ3D); + if(incomplete){ + if(nPts==1){ + return new MQuadrangle8(q->getVertex(0), q->getVertex(1), q->getVertex(2),q->getVertex(3), ve[0],ve[1],ve[2],ve[3]); + }else{ + return new MQuadrangleN(q->getVertex(0), q->getVertex(1), q->getVertex(2), q->getVertex(3), ve, nPts + 1); + } + } else { + if (displ2D && gf->geomType() == GEntity::Plane){ + MQuadrangle incpl(q->getVertex(0), q->getVertex(1), q->getVertex(2), q->getVertex(3)); + getFaceVertices(gf, &incpl, q, vf, faceVertices, linear, nPts, displ2D, displ3D); + }else{ + MQuadrangleN incpl(q->getVertex(0), q->getVertex(1), q->getVertex(2), q->getVertex(3), ve, nPts + 1); + getFaceVertices(gf, &incpl, q, vf, faceVertices, linear, nPts, displ2D, displ3D); + } + ve.insert(ve.end(), vf.begin(), vf.end()); + if(nPts==1){ + return new MQuadrangle9(q->getVertex(0), q->getVertex(1), q->getVertex(2),q->getVertex(3), ve[0], ve[1], ve[2], ve[3], vf[0]); + }else{ + return new MQuadrangleN(q->getVertex(0), q->getVertex(1), q->getVertex(2), q->getVertex(3), ve, nPts + 1); + } + } +} static void setHighOrder(GFace *gf, edgeContainer &edgeVertices, faceContainer &faceVertices, bool linear, bool incomplete, @@ -752,23 +734,11 @@ static void setHighOrder(GFace *gf, edgeContainer &edgeVertices, delete t; } gf->triangles = triangles2; - std::vector<MQuadrangle*> quadrangles2; for(unsigned int i = 0; i < gf->quadrangles.size(); i++){ MQuadrangle *q = gf->quadrangles[i]; - std::vector<MVertex*> ve, vf; - getEdgeVertices(gf, q, ve, edgeVertices, linear, nPts, displ2D, displ3D); - if(incomplete){ - quadrangles2.push_back - (new MQuadrangle8(q->getVertex(0), q->getVertex(1), q->getVertex(2), - q->getVertex(3), ve[0], ve[1], ve[2], ve[3])); - } - else{ - getFaceVertices(gf, q, q, vf, faceVertices, linear, nPts); - quadrangles2.push_back - (new MQuadrangle9(q->getVertex(0), q->getVertex(1), q->getVertex(2), - q->getVertex(3), ve[0], ve[1], ve[2], ve[3], vf[0])); - } + MQuadrangle *qNew = setHighOrder(q,gf,edgeVertices,faceVertices,linear,incomplete,nPts,displ2D,displ3D); + quadrangles2.push_back(qNew); delete q; } gf->quadrangles = quadrangles2; diff --git a/Numeric/functionSpace.cpp b/Numeric/functionSpace.cpp index fe26349a3d..d54c96c461 100644 --- a/Numeric/functionSpace.cpp +++ b/Numeric/functionSpace.cpp @@ -72,6 +72,83 @@ static fullMatrix<double> generatePascalSerendipityTriangle(int order) return monomials; } +// generate all monomials xi^m * eta^n with n and m <= order +static fullMatrix<double> generatePascalQuad(int order) +{ + + fullMatrix<double> monomials( (order+1)*(order+1), 2); + int index = 0; + for (int p = 0; p <= order; p++) { + for(int i = 0; i < p; i++, index++) { + monomials(index, 0) = p; + monomials(index, 1) = i; + } + for(int i = 0; i <= p; i++, index++) { + monomials(index, 0) = p-i; + monomials(index, 1) = p; + } + } + return monomials; +} +/* +00 10 20 30 40 ⋯ +01 11 21 31 41 ⋯ +02 12 +03 13 +04 14 +⋮ ⋮ +*/ +static fullMatrix<double> generatePascalQuadSerendip(int order) +{ + fullMatrix<double> monomials( (order)*4, 2); + monomials(0,0)=0.; + monomials(0,1)=0.; + monomials(1,0)=1.; + monomials(1,1)=0.; + monomials(2,0)=0.; + monomials(2,1)=1.; + monomials(3,0)=1.; + monomials(3,1)=1.; + int index = 4; + for (int p = 2; p <= order; p++) { + monomials(index, 0) = p; + monomials(index, 1) = 0; + index++; + monomials(index, 0) = 0; + monomials(index, 1) = p; + index++; + monomials(index, 0) = p; + monomials(index, 1) = 1; + index++; + monomials(index, 0) = 1; + monomials(index, 1) = p; + index++; + } + return monomials; +} + +/*static fullMatrix<double> generatePascalQuadSerendip(int order) +{ + + fullMatrix<double> monomials( order*4, 2); + int index = 0; + for (int p = 0; p < order; p++) { + monomials(p, 0) = p; + monomials(p, 1) = 0; + + monomials(p+order, 0) = order; + monomials(p+order, 1) = p; + + monomials(p+3*order, 0) = order-p; + monomials(p+3*order, 1) = order; + + monomials(p+2*order, 0) = 0; + monomials(p+2*order, 1) = order-p; + } + monomials.print(); + return monomials; +}*/ + // generate the monomials subspace of all monomials of order exactly == p static fullMatrix<double> generateMonomialSubspace(int dim, int p) @@ -153,6 +230,8 @@ static fullMatrix<double> generatePascalTetrahedron(int order) return monomials; } + + static int nbdoftriangle(int order) { return (order + 1) * (order + 2) / 2; } //static int nbdoftriangleserendip(int order) { return 3 * order; } @@ -517,6 +596,47 @@ static fullMatrix<double> gmshGeneratePointsTriangle(int order, bool serendip) return point; } +static fullMatrix<double> gmshGeneratePointsQuad(int order, bool serendip) +{ + int nbPoints = serendip ? order*4 : (order+1)*(order+1); + fullMatrix<double> point(nbPoints, 2); + + double dd = 1. / order; + + if (order > 0) { + point(0, 0) = -1; + point(0, 1) = -1; + point(1, 0) = 1; + point(1, 1) = -1; + point(2, 0) = 1; + point(2, 1) = 1; + point(3, 0) = -1; + point(3, 1) = 1; + + if (order > 1) { + int index = 4; + const static int edges[4][2]={{0,1},{1,2},{2,3},{3,0}}; + for (int iedge=0; iedge<4; iedge++) { + int p0 = edges[iedge][0]; + int p1 = edges[iedge][1]; + for (int i = 1; i < order; i++, index++) { + point(index, 0) = point(p0, 0) + i*(point(p1,0)-point(p0,0))/order; + point(index, 1) = point(p0, 1) + i*(point(p1,1)-point(p0,1))/order; + } + } + if (order > 2 && !serendip) { + fullMatrix<double> inner = gmshGeneratePointsQuad(order - 2, false); + inner.scale(1. - 2./order); + point.copy(inner, 0, nbPoints - index, 0, 2, index, 0); + } + } + } else { + point(0, 0) = 0; + point(0, 1) = 0; + } + return point; +} + static fullMatrix<double> generateLagrangeMonomialCoefficients (const fullMatrix<double>& monomial, const fullMatrix<double>& point) { @@ -747,6 +867,42 @@ const functionSpace &functionSpaces::find(int tag) F.points = gmshGeneratePointsTetrahedron(5, false); generate3dFaceClosure (F.faceClosure,5); break; + case MSH_QUA_4 : + F.monomials = generatePascalQuad(1); + F.points = gmshGeneratePointsQuad(1,false); + break; + case MSH_QUA_9 : + F.monomials = generatePascalQuad(2); + F.points = gmshGeneratePointsQuad(2,false); + break; + case MSH_QUA_16 : + F.monomials = generatePascalQuad(3); + F.points = gmshGeneratePointsQuad(3,false); + break; + case MSH_QUA_25 : + F.monomials = generatePascalQuad(4); + F.points = gmshGeneratePointsQuad(4,false); + break; + case MSH_QUA_36 : + F.monomials = generatePascalQuad(5); + F.points = gmshGeneratePointsQuad(5,false); + break; + case MSH_QUA_8 : + F.monomials = generatePascalQuadSerendip(2); + F.points = gmshGeneratePointsQuad(2,true); + break; + case MSH_QUA_12 : + F.monomials = generatePascalQuadSerendip(3); + F.points = gmshGeneratePointsQuad(3,true); + break; + case MSH_QUA_16I : + F.monomials = generatePascalQuadSerendip(4); + F.points = gmshGeneratePointsQuad(4,true); + break; + case MSH_QUA_20 : + F.monomials = generatePascalQuadSerendip(5); + F.points = gmshGeneratePointsQuad(5,true); + break; default : Msg::Error("Unknown function space %d: reverting to TET_4", tag); F.monomials = generatePascalTetrahedron(1); -- GitLab