Skip to content
Snippets Groups Projects
Select Git revision
  • 2f28ec80fb3452b0df28cda404d2fc6d290a5152
  • master default protected
  • alphashapes
  • quadMeshingTools
  • cygwin_conv_path
  • macos_arm64
  • add-transfiniteautomatic-to-geo
  • patch_releases_4_10
  • HierarchicalHDiv
  • isuruf-master-patch-63355
  • hyperbolic
  • hexdom
  • hxt_update
  • jf
  • 1618-pythonocc-and-gmsh-api-integration
  • octreeSizeField
  • hexbl
  • alignIrregularVertices
  • getEdges
  • patch_releases_4_8
  • isuruf-master-patch-51992
  • 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
  • gmsh_4_8_4
  • gmsh_4_8_3
  • gmsh_4_8_2
  • gmsh_4_8_1
  • gmsh_4_8_0
  • gmsh_4_7_1
  • gmsh_4_7_0
41 results

MetaEl.cpp

Blame
  • Forked from gmsh / gmsh
    Source project has a limited visibility.
    MetaEl.cpp 15.05 KiB
    // Copyright (C) 2013 ULg-UCL
    //
    // Permission is hereby granted, free of charge, to any person
    // obtaining a copy of this software and associated documentation
    // files (the "Software"), to deal in the Software without
    // restriction, including without limitation the rights to use, copy,
    // modify, merge, publish, distribute, and/or sell copies of the
    // Software, and to permit persons to whom the Software is furnished
    // to do so, provided that the above copyright notice(s) and this
    // permission notice appear in all copies of the Software and that
    // both the above copyright notice(s) and this permission notice
    // appear in supporting documentation.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    // NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
    // COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
    // ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
    // DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
    // WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
    // ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
    // OF THIS SOFTWARE.
    //
    // Please report all bugs and problems to the public mailing list
    // <gmsh@onelab.info>.
    //
    // Contributor: Thomas Toulorge
    
    #include <iostream>
    #include <sstream>
    #include "GmshMessage.h"
    #include "GEdge.h"
    #include "MLine.h"
    #include "MQuadrangle.h"
    #include "MPrism.h"
    #include "MHexahedron.h"
    #include "BasisFactory.h"
    #include "MetaEl.h"
    
    
    std::map<int, MetaEl::metaInfoType> MetaEl::_metaInfo;
    
    
    
    MetaEl::metaInfoType::metaInfoType(int type, int order)
    {
      static const double TOL = 1e-10;
      typedef std::vector<int>::iterator VIntIter;
    
      // Get basic info on dimension, faces and vertices
      int iBaseFace = 0, iTopFace = 0, nbEdVert = 0, nbPrimTopVert = 0;
      int baseFaceType = 0;
      switch (type) {
        case TYPE_QUA:
          dim = 2;
          iBaseFace = 0; iTopFace = 2;
          nbEdVert = 4 + 4*(order-1); nbPrimTopVert = 2;
          baseFaceType = TYPE_LIN;
          break;
        case TYPE_PRI:
          dim = 3;
          iBaseFace = 0; iTopFace = 1; nbEdVert = 6 + 9*(order-1);
          nbPrimTopVert = 3;
          baseFaceType = TYPE_TRI;
          break;
        case TYPE_HEX:
          dim = 3;
          iBaseFace = 0; iTopFace = 5; nbEdVert = 8 + 12*(order-1);
          nbPrimTopVert = 4;
          baseFaceType = TYPE_QUA;
          break;
        default:
          Msg::Error("MetaEl not implemented for element of type %d", type);
          dim = 0;
          nbVert = 0;
          return;
      }
    
      // Get HO nodal base
      const int tag = ElementType::getTag(type, order);                             // Get tag for complete element type
      if (!tag) return;
      const nodalBasis *basis = BasisFactory::getNodalBasis(tag);
      nbVert = basis->getNumShapeFunctions();
      points = basis->points;
    
      // Get nodal bases (HO and linear) on base face
      const int baseFaceTag = ElementType::getTag(baseFaceType, order);                       // Get tag for base face basis
      if (!baseFaceTag) return;
      baseFaceBasis = BasisFactory::getNodalBasis(baseFaceTag);
      const int nbBaseVert = baseFaceBasis->getNumShapeFunctions();
      baseGradShapeFuncVal.resize(nbBaseVert, 3*nbBaseVert);
      const int linBaseFaceTag = ElementType::getTag(baseFaceType, 1);                        // Get tag for base face linear basis
      if (!linBaseFaceTag) return;
      linBaseFaceBasis = BasisFactory::getNodalBasis(linBaseFaceTag);
      const int nbLinBaseShapeFunc = linBaseFaceBasis->getNumShapeFunctions();
      baseLinShapeFuncVal.resize(nbBaseVert, nbLinBaseShapeFunc);
    
      // Compute value of nodal bases of base face at base vertices
      const fullMatrix<double> basePoints = baseFaceBasis->getReferenceNodes();
      for (int iV = 0; iV < baseFaceBasis->getNumShapeFunctions(); iV++) {
        const double &u = basePoints(iV, 0), &v = basePoints(iV, 1);
        double linShapeFunc[1256];
        linBaseFaceBasis->f(u, v, 0., linShapeFunc);
        for (int iSF = 0; iSF < nbLinBaseShapeFunc; iSF++)
          baseLinShapeFuncVal(iV, iSF) = linShapeFunc[iSF];
        double gradShapeFunc[1256][3];
        baseFaceBasis->df(u, v, 0., gradShapeFunc);
        for (int iSF = 0; iSF < nbBaseVert; iSF++) {
          baseGradShapeFuncVal(iV, 3*iSF) = gradShapeFunc[iSF][0];
          baseGradShapeFuncVal(iV, 3*iSF+1) = gradShapeFunc[iSF][1];
          baseGradShapeFuncVal(iV, 3*iSF+2) = gradShapeFunc[iSF][2];
        }
      }
    
      // Indices of vertices on base face
      std::set<int> foundVerts;
      baseInd = basis->getClosure(basis->getClosureId(iBaseFace, 1, 0));
      foundVerts.insert(baseInd.begin(), baseInd.end());
    
      // Indices of vertices on top face
      topInd = basis->getClosure(basis->getClosureId(iTopFace, 0, 0));
      foundVerts.insert(topInd.begin(), topInd.end());
      freeTopInd = std::vector<int>(topInd.begin()+nbPrimTopVert, topInd.end());
      freeTop2Base.resize(freeTopInd.size());
      for(int iVFT = 0; iVFT < freeTopInd.size(); iVFT++) {
        const int &indFT = freeTopInd[iVFT];
        const double &uTop = points(indFT, 0);
        const double &vTop = points(indFT, 1);
        for (int iVB = 0; iVB < baseInd.size(); iVB++) {                            // Find corresponding base vertex
          const int &indB = baseInd[iVB];
          const double diffU = uTop - points(indB, 0);
          const double diffV = (dim == 3) ? vTop - points(indB, 1) : 0.;
          if (diffU*diffU+diffV*diffV < TOL) {
            freeTop2Base[iVFT] = iVB;
            break;
          }
        }
      }
    
      // Indices of vertices on edges (excluding base and top faces)
      for (int iV = 0; iV < nbEdVert; iV++)
        if (foundVerts.find(iV) == foundVerts.end()) {
          edgeInd.push_back(iV);
          foundVerts.insert(iV);
        }
    
      // Indices of remaining face and interior vertices
      for(int iV = 0; iV < nbVert; iV++) {
        if (foundVerts.find(iV) == foundVerts.end()) {
          otherInd.push_back(iV);
          foundVerts.insert(iV);
          const double &uFree = points(iV, 0);
          const double &vFree = points(iV, 1);
          for (int iVB = 0; iVB < baseInd.size(); iVB++) {                          // Find corresponding base vertex
            const int &indB = baseInd[iVB];
            const double diffU = uFree - points(indB, 0);
            const double diffV = (dim == 3) ? vFree - points(indB, 1) : 0.;
            if (diffU*diffU+diffV*diffV < TOL) {
              other2Base.push_back(iVB);
              break;
            }
          }
          for (int iVT = 0; iVT < baseInd.size(); iVT++) {                          // Find corresponding top vertex
            const int &indT = topInd[iVT];
            const double diffU = uFree - points(indT, 0);
            const double diffV = (dim == 3) ? vFree - points(indT, 1) : 0.;
            if (diffU*diffU+diffV*diffV < TOL) {
              other2Top.push_back(iVT);
              break;
            }
          }
        }
      }
    }
    
    
    
    const MetaEl::metaInfoType &MetaEl::getMetaInfo(int elType, int order)
    {
      std::map<int, MetaEl::metaInfoType>::iterator itMInfo = _metaInfo.find(elType);
      if (itMInfo == _metaInfo.end()) {
        const metaInfoType mInfo(elType, order);
        itMInfo = _metaInfo.insert(std::pair<int, metaInfoType>(elType, mInfo)).first;
      }
      return itMInfo->second;
    }
    
    
    
    void MetaEl::computeBaseNorm(const SVector3 &metaNorm,
                                 const std::vector<MVertex*> &baseVert,
                                 const std::vector<MVertex*> &topPrimVert,
                                 std::vector<SVector3> &baseNorm)
    {
      const int nbFaceNodes = baseVert.size(), nbPrimFaceNodes = topPrimVert.size();
    
      // Compute thickness at each primary vertex
      std::vector<double> linThick(nbPrimFaceNodes);
      for (int iV = 0; iV < nbPrimFaceNodes; iV++)
        linThick[iV] = topPrimVert[iV]->distance(baseVert[iV]);
    
      // Compute normal at each base vertex
      std::vector<double> thick(nbFaceNodes, 0.);
      baseNorm.resize(nbFaceNodes);
      for (int iV = 0; iV < nbFaceNodes; iV++) {
        for (int iSF = 0; iSF < nbPrimFaceNodes; iSF++)
          thick[iV] += linThick[iSF] * _mInfo.baseLinShapeFuncVal(iV, iSF);
        double jac[3][2] = {0., 0., 0., 0., 0., 0.};
        for (int iSF = 0; iSF < nbFaceNodes; iSF++) {
          MVertex *vert = baseVert[iSF];
          const double xyz[3] = {vert->x(), vert->y(), vert->z()};
          for (int iXYZ = 0; iXYZ < 3; iXYZ++) {
            jac[iXYZ][0] += xyz[iXYZ] * _mInfo.baseGradShapeFuncVal(iV, 3*iSF);
            jac[iXYZ][1] += xyz[iXYZ] * _mInfo.baseGradShapeFuncVal(iV, 3*iSF+1);
          }
        }
        SVector3 dXYZdU(jac[0][0], jac[1][0], jac[2][0]);
        SVector3 dXYZdV = (_mInfo.dim == 2) ? metaNorm :
                          SVector3(jac[0][1], jac[1][1], jac[2][1]);
        baseNorm[iV] = crossprod(dXYZdV, dXYZdU);
        baseNorm[iV].normalize();
        baseNorm[iV] *= thick[iV];
      }
    }
    
    
    
    MetaEl::MetaEl(int type, int order, const std::vector<MVertex*> &baseVert,
                   const std::vector<MVertex*> &topPrimVert) :
        _mInfo(getMetaInfo(type, order)), _metaEl(0), _metaEl0(0)
    {
      // Get info on meta-element type
      if (_mInfo.nbVert == 0) return;
      const int &nbVert = _mInfo.nbVert;
      const fullMatrix<double> &points = _mInfo.points;
      const std::vector<int> &baseInd = _mInfo.baseInd;
      const std::vector<int> &topInd = _mInfo.topInd;
      const std::vector<int> &edgeInd = _mInfo.edgeInd;
      const std::vector<int> &otherInd = _mInfo.otherInd;
    
      // Add copies of vertices in base & top faces (only first-order vertices for top face)
      _metaVert.resize(nbVert);
      for (int iV = 0; iV < baseInd.size(); iV++) {
        const MVertex* const &bVert = baseVert[iV];
        GEntity *geomEnt = bVert->onWhat();
        if (geomEnt->dim() == 0)
          _metaVert[baseInd[iV]] = new MVertex(*bVert);
        else if (geomEnt->dim() == 1) {
          double u;
          bVert->getParameter(0, u);
          _metaVert[baseInd[iV]] = new MEdgeVertex(bVert->x(), bVert->y(),
                                                   bVert->z(), geomEnt, u);
        }
        else if (geomEnt->dim() == 2) {
          double u, v;
          bVert->getParameter(0, u);
          bVert->getParameter(1, v);
          _metaVert[baseInd[iV]] = new MFaceVertex(bVert->x(), bVert->y(),
                                                   bVert->z(), geomEnt, u, v);
        }
      }
      for (int iV = 0; iV < topPrimVert.size(); iV++)
        _metaVert[topInd[iV]] = new MVertex(*topPrimVert[iV]);
    
      // Create first-order meta-element and normals to base face
      int faceType;
      SVector3 metaNorm;
      switch (type) {
        case TYPE_QUA: {
          _metaEl0 = new MQuadrangle(_metaVert);
          SVector3 v01(_metaVert[0]->point(), _metaVert[1]->point());
          SVector3 v03(_metaVert[0]->point(), _metaVert[3]->point());
          metaNorm = crossprod(v01, v03);
          faceType = TYPE_LIN;
          break;
        }
        case TYPE_PRI: {
          _metaEl0 = new MPrism(_metaVert);
          metaNorm = SVector3(0.);
          faceType = TYPE_TRI;
          break;
        }
        case TYPE_HEX: {
          _metaEl0 = new MHexahedron(_metaVert);
          metaNorm = SVector3(0.);
          faceType = TYPE_QUA;
          break;
        }
        default: {
          Msg::Error("SuperEl not implemented for element of type %d", type);
          return;
        }
      }
      computeBaseNorm(metaNorm, baseVert, topPrimVert, _baseNorm);
    
      // Add HO vertices in top face
      for (int iV = topPrimVert.size(); iV < topInd.size(); iV++) {
        SPoint3 p;
        const int ind = topInd[iV];
        _metaEl0->pnt(points(ind, 0), points(ind, 1), points(ind, 2), p);
        _metaVert[ind] = new MVertex(p.x(), p.y(), p.z());
      }
    
      // Add vertices on edges (excluding base and top faces)
      for (int iV = 0; iV < edgeInd.size(); iV++) {
        SPoint3 p;
        const int ind = edgeInd[iV];
        _metaEl0->pnt(points(ind, 0), points(ind, 1), points(ind, 2), p);
        _metaVert[ind] = new MVertex(p.x(), p.y(), p.z());
      }
    
      // Add remaining face and interior points
      for (int iV = 0; iV < otherInd.size(); iV++)
        _metaVert[otherInd[iV]] = new MVertex(0., 0., 0.);
      placeOtherNodes();
    
      // Create high-order meta-element
      switch (type) {
        case TYPE_QUA:
          _metaEl = new MQuadrangleN(_metaVert, order);
          break;
        case TYPE_PRI:
          _metaEl = new MPrismN(_metaVert, order);
          break;
        case TYPE_HEX:
          _metaEl = new MHexahedronN(_metaVert, order);
          break;
      }
    }
    
    
    
    MetaEl::~MetaEl()
    {
      for (int i = 0; i < _metaVert.size(); i++) delete _metaVert[i];
      _metaVert.clear();
      if (_metaEl) delete _metaEl;
      if (_metaEl0) delete _metaEl0;
    }
    
    
    
    // Place free interior and face vertices equidistantly between top and base faces
    void MetaEl::placeOtherNodes()
    {
      for (int iVO = 0; iVO < _mInfo.otherInd.size(); iVO++) {
        const int &indF = _mInfo.otherInd[iVO];
        const int &iVB = _mInfo.other2Base[iVO], indB = _mInfo.baseInd[iVB];
        const int &iVT = _mInfo.other2Top[iVO], indT = _mInfo.topInd[iVT];
        const int iUVWNorm = _mInfo.dim - 1;
        const double fact = 0.5 * (_mInfo.points(indF, iUVWNorm)+1.);
        SPoint3 pB = _metaVert[indB]->point(), pT = _metaVert[indT]->point();
        const double newX = (1.-fact)*pB.x() + fact*pT.x();
        const double newY = (1.-fact)*pB.y() + fact*pT.y();
        const double newZ = (1.-fact)*pB.z() + fact*pT.z();
        _metaVert[indF]->setXYZ(newX, newY, newZ);
      }
    }
    
    
    
    void MetaEl::setCurvedTop(double factor)
    {
      // Place HO vertices of top face so that meta-elemnt has almost uniform thickness
      for (int iVFT = 0; iVFT < _mInfo.freeTopInd.size(); iVFT++) {
        const int &indFT = _mInfo.freeTopInd[iVFT];
        const int &iVB = _mInfo.freeTop2Base[iVFT], indB = _mInfo.baseInd[iVB];
        const int iUVWNorm = _mInfo.dim - 1;
        const SPoint3 pB = _metaVert[indB]->point();
        const SVector3 &norm = _baseNorm[iVB];
        const double newX = pB.x() + factor*norm.x();
        const double newY = pB.y() + factor*norm.y();
        const double newZ = pB.z() + factor*norm.z();
        _metaVert[indFT]->setXYZ(newX, newY, newZ);
      }
    
      // Place the other free nodes equidistantly between base and top faces
      placeOtherNodes();
    }
    
    
    
    void MetaEl::setFlatTop()
    {
      // Get info on meta-element type
      const fullMatrix<double> &points = _mInfo.points;
      const std::vector<int> &freeTopInd = _mInfo.topInd;
    
      // Put top vertices on straight meta-element
      for (int iVFT = 0; iVFT < freeTopInd.size(); iVFT++) {
        const int &indFT = freeTopInd[iVFT];
        SPoint3 p;
        _metaEl0->pnt(points(indFT, 0), points(indFT, 1), points(indFT, 2), p);
        _metaVert[indFT]->setXYZ(p.x(), p.y(), p.z());
      }
    
      // Place the other free nodes equidistantly between base and top faces
      placeOtherNodes();
    }
    
    
    
    bool MetaEl::isPointIn(const SPoint3 p) const
    {
      double xyz[3] = {p.x(), p.y(), p.z()}, uvw[3];
      _metaEl0->xyz2uvw(xyz, uvw);
      return _metaEl0->isInside(uvw[0], uvw[1], uvw[2]);
    }
    
    
    
    bool MetaEl::straightToCurved(double *xyzS, double *xyzC) const
    {
      double uvw[3];
      _metaEl0->xyz2uvw(xyzS, uvw);
      if (!_metaEl0->isInside(uvw[0], uvw[1], uvw[2])) return false;
    
      SPoint3 pC;
      _metaEl->pnt(uvw[0], uvw[1], uvw[2], pC);
      xyzC[0] = pC[0];
      xyzC[1] = pC[1];
      xyzC[2] = pC[2];
    
      return true;
    }
    
    
    
    std::string MetaEl::printPOS()
    {
      std::vector<MVertex*> verts;
      _metaEl->getVertices(verts);
      std::string posStr = _metaEl0->getStringForPOS();
      int n = (posStr[posStr.size()-1] == '2' ?
              _metaEl : _metaEl0)->getNumVertices();
    
      std::ostringstream oss;
    
      oss << posStr << "(";
      for(int i = 0; i < n; i++){
        if(i) oss << ",";
        oss << _metaVert[i]->x() << "," <<  _metaVert[i]->y() << ","
            <<  _metaVert[i]->z();
      }
      oss << "){0.";
      for(int i = 1; i < n; i++) oss << ",0.";
      oss << "};\n";
    
      return oss.str();
    }