Skip to content
Snippets Groups Projects
Select Git revision
  • f55633bad0503ecf844c3a10072aaf1d9e92e2f8
  • master default protected
  • hierarchical-basis
  • revert-ef4a3a4f
  • patch_releases_4_14
  • overlaps_tags_and_distributed_export
  • overlaps_tags_and_distributed_export_rebased
  • relaying
  • alphashapes
  • steplayer
  • bl
  • pluginMeshQuality
  • fixBugsAmaury
  • new_export_boris
  • oras_vs_osm
  • reassign_partitions
  • distributed_fwi
  • rename-classes
  • fix/fortran-api-example-t4
  • robust_partitions
  • reducing_files
  • gmsh_4_14_0
  • gmsh_4_13_1
  • gmsh_4_13_0
  • gmsh_4_12_2
  • gmsh_4_12_1
  • gmsh_4_12_0
  • gmsh_4_11_1
  • gmsh_4_11_0
  • gmsh_4_10_5
  • gmsh_4_10_4
  • gmsh_4_10_3
  • gmsh_4_10_2
  • gmsh_4_10_1
  • gmsh_4_10_0
  • gmsh_4_9_5
  • gmsh_4_9_4
  • gmsh_4_9_3
  • gmsh_4_9_2
  • gmsh_4_9_1
  • gmsh_4_9_0
41 results

MPyramid.cpp

Blame
  • MPyramid.cpp 16.30 KiB
    // Gmsh - Copyright (C) 1997-2019 C. Geuzaine, J.-F. Remacle
    //
    // See the LICENSE.txt file for license information. Please report all
    // issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
    
    #include "MPyramid.h"
    #include "Numeric.h"
    #include "Context.h"
    #include "BergotBasis.h"
    #include "BasisFactory.h"
    #include "pointsGenerators.h"
    
    std::map<int, IndicesReversed> MPyramidN::_order2indicesReversedPyr;
    
    int MPyramid::getVolumeSign()
    {
      double mat[3][3];
      mat[0][0] = _v[1]->x() - _v[0]->x();
      mat[0][1] = _v[3]->x() - _v[0]->x();
      mat[0][2] = _v[4]->x() - _v[0]->x();
      mat[1][0] = _v[1]->y() - _v[0]->y();
      mat[1][1] = _v[3]->y() - _v[0]->y();
      mat[1][2] = _v[4]->y() - _v[0]->y();
      mat[2][0] = _v[1]->z() - _v[0]->z();
      mat[2][1] = _v[3]->z() - _v[0]->z();
      mat[2][2] = _v[4]->z() - _v[0]->z();
      double d = det3x3(mat);
      if(d < 0.)
        return -1;
      else if(d > 0.)
        return 1;
      else
        return 0;
    }
    
    void MPyramid::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
    {
      *npts = getNGQPyrPts(pOrder);
      *pts = getGQPyrPts(pOrder);
    }
    
    bool MPyramid::getFaceInfo(const MFace &face, int &ithFace, int &sign,
                               int &rot) const
    {
      for(ithFace = 0; ithFace < 5; ++ithFace) {
        if(_getFaceInfo(getFace(ithFace), face, sign, rot)) return true;
      }
      Msg::Error("Could not get face information for pyramid %d", getNum());
      return false;
    }
    
    MPyramidN::~MPyramidN() {}
    
    int MPyramidN::getNumEdgesRep(bool curved)
    {
      // FIXME: remove !getIsAssimilatedSerendipity() when serendip are implemented
      return (curved && !getIsAssimilatedSerendipity()) ?
               8 * CTX::instance()->mesh.numSubEdges :
               8;
    }
    
    void MPyramidN::getEdgeRep(bool curved, int num, double *x, double *y,
                               double *z, SVector3 *n)
    {
      // FIXME: remove !getIsAssimilatedSerendipity() when serendip are implemented
      if(curved && !getIsAssimilatedSerendipity()) {
        int numSubEdges = CTX::instance()->mesh.numSubEdges;
        static double pp[5][3] = {
          {-1, -1, 0}, {1, -1, 0}, {1, 1, 0}, {-1, 1, 0}, {0, 0, 1}};
        static int ed[8][2] = {{0, 1}, {0, 3}, {0, 4}, {1, 2},
                               {1, 4}, {2, 3}, {2, 4}, {3, 4}};
        int iEdge = num / numSubEdges;
        int iSubEdge = num % numSubEdges;
    
        int iVertex1 = ed[iEdge][0];
        int iVertex2 = ed[iEdge][1];
        double t1 = (double)iSubEdge / (double)numSubEdges;
        double u1 = pp[iVertex1][0] * (1. - t1) + pp[iVertex2][0] * t1;
        double v1 = pp[iVertex1][1] * (1. - t1) + pp[iVertex2][1] * t1;
        double w1 = pp[iVertex1][2] * (1. - t1) + pp[iVertex2][2] * t1;
    
        double t2 = (double)(iSubEdge + 1) / (double)numSubEdges;
        double u2 = pp[iVertex1][0] * (1. - t2) + pp[iVertex2][0] * t2;
        double v2 = pp[iVertex1][1] * (1. - t2) + pp[iVertex2][1] * t2;
        double w2 = pp[iVertex1][2] * (1. - t2) + pp[iVertex2][2] * t2;
    
        SPoint3 pnt1, pnt2;
        pnt(u1, v1, w1, pnt1);
        pnt(u2, v2, w2, pnt2);
        x[0] = pnt1.x();
        x[1] = pnt2.x();
        y[0] = pnt1.y();
        y[1] = pnt2.y();
        z[0] = pnt1.z();
        z[1] = pnt2.z();
    
        // not great, but better than nothing
        static const int f[8] = {0, 1, 0, 2, 2, 3, 2, 3};
        n[0] = n[1] = getFace(f[iEdge]).normal();
      }
      else
        MPyramid::getEdgeRep(false, num, x, y, z, n);
    }
    
    int MPyramid::getNumFacesRep(bool curved)
    {
    #if defined(HAVE_VISUDEV)
      if(CTX::instance()->heavyVisu) {
        if(CTX::instance()->mesh.numSubEdges == 1) return 8;
        return 6 * std::pow(CTX::instance()->mesh.numSubEdges, 2);
      }
    #endif
      return 6;
    }
    
    int MPyramidN::getNumFacesRep(bool curved)
    {
      // FIXME: remove !getIsAssimilatedSerendipity() when serendip are implemented
      return (curved && !getIsAssimilatedSerendipity()) ?
               6 * std::pow(CTX::instance()->mesh.numSubEdges, 2) :
               MPyramid::getNumFacesRep(curved);
    }
    
    static void _myGetFaceRep(MPyramid *pyr, int num, double *x, double *y,
                              double *z, SVector3 *n, int numSubEdges)
    {
      static double pp[5][3] = {
        {-1, -1, 0}, {1, -1, 0}, {1, 1, 0}, {-1, 1, 0}, {0, 0, 1}};
      int iFace = num / (numSubEdges * numSubEdges);
      int iSubFace = num % (numSubEdges * numSubEdges);
    
      if(iFace > 3) {
        iFace = 4;
        iSubFace = num % (2 * numSubEdges * numSubEdges);
      }
    
      int iVertex1, iVertex2, iVertex3, iVertex4;
    
      if(iFace < 4) {
        iVertex1 = pyr->faces_pyramid(iFace, 0);
        iVertex2 = pyr->faces_pyramid(iFace, 1);
        iVertex3 = pyr->faces_pyramid(iFace, 2);
      }
      else {
        iVertex1 = 0;
        iVertex2 = 1;
        iVertex3 = 2;
        iVertex4 = 3;
      }
    
      SPoint3 pnt1, pnt2, pnt3;
    
      if(iFace < 4) {
        int ix = 0, iy = 0;
        int nbt = 0;
        for(int i = 0; i < numSubEdges; i++) {
          int nbl = (numSubEdges - i - 1) * 2 + 1;
          nbt += nbl;
          if(nbt > iSubFace) {
            iy = i;
            ix = nbl - (nbt - iSubFace);
            break;
          }
        }
    
        const double d = 1. / numSubEdges;
    
        double u1, v1, u2, v2, u3, v3;
        if(ix % 2 == 0) {
          u1 = ix / 2 * d;
          v1 = iy * d;
          u2 = (ix / 2 + 1) * d;
          v2 = iy * d;
          u3 = ix / 2 * d;
          v3 = (iy + 1) * d;
        }
        else {
          u1 = (ix / 2 + 1) * d;
          v1 = iy * d;
          u2 = (ix / 2 + 1) * d;
          v2 = (iy + 1) * d;
          u3 = ix / 2 * d;
          v3 = (iy + 1) * d;
        }
    
        double U1 = pp[iVertex1][0] * (1. - u1 - v1) + pp[iVertex2][0] * u1 +
                    pp[iVertex3][0] * v1;
        double U2 = pp[iVertex1][0] * (1. - u2 - v2) + pp[iVertex2][0] * u2 +
                    pp[iVertex3][0] * v2;
        double U3 = pp[iVertex1][0] * (1. - u3 - v3) + pp[iVertex2][0] * u3 +
                    pp[iVertex3][0] * v3;
    
        double V1 = pp[iVertex1][1] * (1. - u1 - v1) + pp[iVertex2][1] * u1 +
                    pp[iVertex3][1] * v1;
        double V2 = pp[iVertex1][1] * (1. - u2 - v2) + pp[iVertex2][1] * u2 +
                    pp[iVertex3][1] * v2;
        double V3 = pp[iVertex1][1] * (1. - u3 - v3) + pp[iVertex2][1] * u3 +
                    pp[iVertex3][1] * v3;
    
        double W1 = pp[iVertex1][2] * (1. - u1 - v1) + pp[iVertex2][2] * u1 +
                    pp[iVertex3][2] * v1;
        double W2 = pp[iVertex1][2] * (1. - u2 - v2) + pp[iVertex2][2] * u2 +
                    pp[iVertex3][2] * v2;
        double W3 = pp[iVertex1][2] * (1. - u3 - v3) + pp[iVertex2][2] * u3 +
                    pp[iVertex3][2] * v3;
    
        pyr->pnt(U1, V1, W1, pnt1);
        pyr->pnt(U2, V2, W2, pnt2);
        pyr->pnt(U3, V3, W3, pnt3);
      }
      else {
        /*
        0
        0 1
        0 1 2
        0 1 2 3
        0 1 2 3 4
        0 1 2 3 4 5
        */
    
        // on each layer, we have (numSubEdges) * 2 triangles
        // ix and iy are the coordinates of the sub-quadrangle
    
        int io = iSubFace % 2;
        int ix = (iSubFace / 2) / numSubEdges;
        int iy = (iSubFace / 2) % numSubEdges;
    
        const double d = 2. / numSubEdges;
        double ox = -1. + d * ix;
        double oy = -1. + d * iy;
    
        if(io == 0) {
          double U1 = pp[iVertex1][0] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][0] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][0] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][0] * (1. - ox) * (1 + oy) * .25;
          double V1 = pp[iVertex1][1] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][1] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][1] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][1] * (1. - ox) * (1 + oy) * .25;
          double W1 = pp[iVertex1][2] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][2] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][2] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][2] * (1. - ox) * (1 + oy) * .25;
    
          ox += d;
    
          double U2 = pp[iVertex1][0] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][0] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][0] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][0] * (1. - ox) * (1 + oy) * .25;
          double V2 = pp[iVertex1][1] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][1] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][1] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][1] * (1. - ox) * (1 + oy) * .25;
          double W2 = pp[iVertex1][2] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][2] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][2] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][2] * (1. - ox) * (1 + oy) * .25;
    
          oy += d;
    
          double U3 = pp[iVertex1][0] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][0] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][0] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][0] * (1. - ox) * (1 + oy) * .25;
          double V3 = pp[iVertex1][1] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][1] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][1] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][1] * (1. - ox) * (1 + oy) * .25;
          double W3 = pp[iVertex1][2] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][2] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][2] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][2] * (1. - ox) * (1 + oy) * .25;
    
          pyr->pnt(U1, V1, W1, pnt1);
          pyr->pnt(U2, V2, W2, pnt2);
          pyr->pnt(U3, V3, W3, pnt3);
        }
        else {
          double U1 = pp[iVertex1][0] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][0] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][0] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][0] * (1. - ox) * (1 + oy) * .25;
          double V1 = pp[iVertex1][1] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][1] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][1] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][1] * (1. - ox) * (1 + oy) * .25;
          double W1 = pp[iVertex1][2] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][2] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][2] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][2] * (1. - ox) * (1 + oy) * .25;
    
          ox += d;
          oy += d;
    
          double U2 = pp[iVertex1][0] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][0] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][0] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][0] * (1. - ox) * (1 + oy) * .25;
          double V2 = pp[iVertex1][1] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][1] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][1] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][1] * (1. - ox) * (1 + oy) * .25;
          double W2 = pp[iVertex1][2] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][2] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][2] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][2] * (1. - ox) * (1 + oy) * .25;
    
          ox -= d;
    
          double U3 = pp[iVertex1][0] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][0] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][0] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][0] * (1. - ox) * (1 + oy) * .25;
          double V3 = pp[iVertex1][1] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][1] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][1] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][1] * (1. - ox) * (1 + oy) * .25;
          double W3 = pp[iVertex1][2] * (1. - ox) * (1 - oy) * .25 +
                      pp[iVertex2][2] * (1. + ox) * (1 - oy) * .25 +
                      pp[iVertex3][2] * (1. + ox) * (1 + oy) * .25 +
                      pp[iVertex4][2] * (1. - ox) * (1 + oy) * .25;
    
          pyr->pnt(U1, V1, W1, pnt1);
          pyr->pnt(U2, V2, W2, pnt2);
          pyr->pnt(U3, V3, W3, pnt3);
        }
      }
    
      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();
    
      SVector3 d1(x[1] - x[0], y[1] - y[0], z[1] - z[0]);
      SVector3 d2(x[2] - x[0], y[2] - y[0], z[2] - z[0]);
      n[0] = crossprod(d1, d2);
      n[0].normalize();
      n[1] = n[0];
      n[2] = n[0];
    }
    
    void MPyramid::getFaceRep(bool curved, int num, double *x, double *y, double *z,
                              SVector3 *n)
    {
    #if defined(HAVE_VISUDEV)
      static const int fquad[4][4] = {
        {0, 3, 2, 1}, {3, 2, 1, 0}, {2, 1, 0, 3}, {1, 0, 3, 2}};
      if(CTX::instance()->heavyVisu) {
        if(CTX::instance()->mesh.numSubEdges > 1) {
          _myGetFaceRep(this, num, x, y, z, n, CTX::instance()->mesh.numSubEdges);
          return;
        }
        if(num > 3) {
          int i = num - 4;
          _getFaceRepQuad(getVertex(fquad[i][0]), getVertex(fquad[i][1]),
                          getVertex(fquad[i][2]), getVertex(fquad[i][3]), x, y, z,
                          n);
          return;
        }
      }
    #endif
      static const int f[6][3] = {{0, 1, 4}, {3, 0, 4}, {1, 2, 4},
                                  {2, 3, 4}, {0, 3, 2}, {0, 2, 1}};
      _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
                  x, y, z, n);
    }
    
    int MPyramid::numCommonNodesInDualGraph(const MElement *const other) const
    {
      switch(other->getType()) {
      case TYPE_PNT: return 1;
      case TYPE_LIN: return 2;
      case TYPE_QUA: return 4;
      case TYPE_HEX: return 4;
      default: return 3;
      }
    }
    
    void MPyramidN::getFaceRep(bool curved, int num, double *x, double *y,
                               double *z, SVector3 *n)
    {
      // FIXME: remove !getIsAssimilatedSerendipity() when serendip are implemented
      if(curved && !getIsAssimilatedSerendipity())
        _myGetFaceRep(this, num, x, y, z, n, CTX::instance()->mesh.numSubEdges);
      else
        MPyramid::getFaceRep(false, num, x, y, z, n);
    }
    
    void _getIndicesReversedPyr(int order, IndicesReversed &indices)
    {
      fullMatrix<double> ref = gmshGenerateMonomialsPyramid(order);
    
      indices.resize(ref.size1());
      for(int i = 0; i < ref.size1(); ++i) {
        const double u = ref(i, 0);
        const double v = ref(i, 1);
        const double w = ref(i, 2);
        for(int j = 0; j < ref.size1(); ++j) {
          if(u == ref(j, 1) && v == ref(j, 0) && w == ref(j, 2)) {
            indices[i] = j;
            break;
          }
        }
      }
    }
    
    void MPyramidN::reverse()
    {
      std::map<int, IndicesReversed>::iterator it;
      it = _order2indicesReversedPyr.find(_order);
      if(it == _order2indicesReversedPyr.end()) {
        IndicesReversed indices;
        _getIndicesReversedPyr(_order, indices);
        _order2indicesReversedPyr[_order] = indices;
        it = _order2indicesReversedPyr.find(_order);
      }
    
      IndicesReversed &indices = it->second;
    
      // copy vertices
      std::vector<MVertex *> oldv(5 + _vs.size());
      std::copy(_v, _v + 5, oldv.begin());
      std::copy(_vs.begin(), _vs.end(), oldv.begin() + 5);
    
      // reverse
      for(int i = 0; i < 5; ++i) {
        _v[i] = oldv[indices[i]];
      }
      for(std::size_t i = 0; i < _vs.size(); ++i) {
        _vs[i] = oldv[indices[5 + i]];
      }
    }
    
    void MPyramidN::_addHOEdgePoints(int num, std::vector<MVertex *> &v,
                                     bool fwd) const
    {
      int minVtx = num * (_order - 1);
      int maxVtx = (num + 1) * (_order - 1) - 1;
    
      if(fwd)
        for(int i = minVtx; i <= maxVtx; i++) v.push_back(_vs[i]);
      else
        for(int i = maxVtx; i >= minVtx; i--) v.push_back(_vs[i]);
    }
    
    void MPyramidN::getFaceVertices(const int num, std::vector<MVertex *> &v) const
    {
      bool complete = !getIsAssimilatedSerendipity();
    
      int nbQ = (_order - 1) * (_order - 1);
      int nbT = (_order - 1) * (_order - 2) / 2;
    
      int nb = ((num == 4) ? 4 : 3) * _order;
      if(complete) nb += (num == 4) ? nbQ : nbT;
    
      v.reserve(nb);
    
      if(num < 4) {
        v.push_back(_v[faces_pyramid(num, 0)]);
        v.push_back(_v[faces_pyramid(num, 1)]);
        v.push_back(_v[faces_pyramid(num, 2)]);
      }
      else {
        v.push_back(_v[0]);
        v.push_back(_v[3]);
        v.push_back(_v[2]);
        v.push_back(_v[1]);
      }
    
      switch(num) {
      case 0: // 0 1 4
      {
        _addHOEdgePoints(0, v);
        _addHOEdgePoints(4, v);
        _addHOEdgePoints(2, v, false);
        break;
      }
      case 1: // 3 0 4
      {
        _addHOEdgePoints(1, v, false);
        _addHOEdgePoints(2, v);
        _addHOEdgePoints(7, v, false);
        break;
      }
      case 2: // 1 2 4
      {
        _addHOEdgePoints(3, v);
        _addHOEdgePoints(6, v);
        _addHOEdgePoints(4, v, false);
        break;
      }
      case 3: // 2 3 4
      {
        _addHOEdgePoints(5, v);
        _addHOEdgePoints(7, v);
        _addHOEdgePoints(6, v, false);
        break;
      }
      case 4: // 0 3 2 1
      {
        _addHOEdgePoints(1, v);
        _addHOEdgePoints(5, v, false);
        _addHOEdgePoints(3, v, false);
        _addHOEdgePoints(0, v, false);
        break;
      }
      }
    
      if(complete) {
        int start = 8 * (_order - 1) + num * nbT;
        int nbPoints = (num == 4) ? nbQ : nbT;
        for(int i = start; i < start + nbPoints; i++) v.push_back(_vs[i]);
      }
    }