#ifndef GEOM_FILE #define GEOM_FILE #include #include // function; C++11 #include #include // shared_ptr #include #include /** * Basis class for finite element meshes. */ class Mesh { public: /** * Constructor initializing the members with default values. * * @param[in] ndim space dimensions (dimension for coordinates) * @param[in] nvert_e number of vertices per element (dimension for connectivity) * @param[in] ndof_e degrees of freedom per element (= @p nvert_e for linear elements) * @param[in] nedge_e number of edges per element (= @p nvert_e for linear elements in 2D) */ explicit Mesh(int ndim, int nvert_e = 0, int ndof_e = 0, int nedge_e = 0); __attribute__((noinline)) Mesh(Mesh const &) = default; Mesh &operator=(Mesh const &) = delete; /** * Destructor. * * See clang warning on * weak-vtables. */ virtual ~Mesh(); /** * Reads mesh data from a binary file. * * File format, see ascii_write_mesh.m * * @param[in] fname file name */ explicit Mesh(std::string const &fname); /** * Reads mesh data from a binary file. * * File format, see ascii_write_mesh.m * * @param[in] fname file name */ void ReadVertexBasedMesh(std::string const &fname); /** * Number of finite elements in (sub)domain. * @return number of elements. */ int Nelems() const { return _nelem; } /** * Global number of vertices for each finite element. * @return number of vertices per element. */ int NverticesElements() const { return _nvert_e; } /** * Global number of degrees of freedom (dof) for each finite element. * @return degrees of freedom per element. */ int NdofsElement() const { return _ndof_e; } /** * Number of vertices in mesh. * @return number of vertices. */ int Nnodes() const { return _nnode; } /** * Space dimension. * @return number of dimensions. */ int Ndims() const { return _ndim; } /** * (Re-)Allocates memory for the element connectivity and redefines the appropriate dimensions. * * @param[in] nelem number of elements * @param[in] nvert_e number of vertices per element */ void Resize_Connectivity(int nelem, int nvert_e) { SetNelem(nelem); // number of elements SetNverticesElement(nvert_e); // vertices per element _ia.resize(nelem * nvert_e); } /** * Read connectivity information (g1,g2,g3)_i. * @return connectivity vector [nelems*ndofs]. */ const std::vector &GetConnectivity() const { return _ia; } /** * Access/Change connectivity information (g1,g2,g3)_i. * @return connectivity vector [nelems*ndofs]. */ std::vector &GetConnectivity() { return _ia; } /** * (Re-)Allocates memory for the element connectivity and redefines the appropriate dimensions. * * @param[in] nnodes number of nodes * @param[in] ndim space dimension */ void Resize_Coords(int nnodes, int ndim) { SetNnode(nnodes); // number of nodes SetNdim(ndim); // space dimension _xc.resize(nnodes * ndim); } /** * Read coordinates of vertices (x,y)_i. * @return coordinates vector [nnodes*2]. */ const std::vector &GetCoords() const { return _xc; } /** * Access/Change coordinates of vertices (x,y)_i. * @return coordinates vector [nnodes*2]. */ std::vector &GetCoords() { return _xc; } /** * Calculate values in vector @p v via function @p func(x,y) * @param[in] v vector * @param[in] func function of (x,y) returning a double value. */ void SetValues(std::vector &v, const std::function &func) const; void SetBoundaryValues(std::vector &v, const std::function &func) const; void SetDirchletValues(std::vector &v, const std::function &func) const; /** * Prints the information for a finite element mesh */ void Debug() const; /** * Prints the edge based information for a finite element mesh */ void DebugEdgeBased() const; /** * Determines the indices of those vertices with Dirichlet boundary conditions * @return index vector. */ virtual std::vector Index_DirichletNodes() const; virtual std::vector Index_BoundaryNodes() const; /** * Write vector @p v together with its mesh information to an ASCii file @p fname. * * The data are written in C-style. * * @param[in] fname file name * @param[in] v vector */ void Write_ascii_matlab(std::string const &fname, std::vector const &v) const; /** * Exports the mesh information to ASCii files @p basename + {_coords|_elements}.txt. * * The data are written in C-style. * * @param[in] basename first part of file names */ void Export_scicomp(std::string const &basename) const; /** * Visualize @p v together with its mesh information via matlab or octave. * * Comment/uncomment those code lines in method Mesh:Visualize (geom.cpp) * that are supported on your system. * * @param[in] v vector * * @warning matlab files ascii_read_meshvector.m visualize_results.m * must be in the executing directory. */ void Visualize(std::vector const &v) const; /** * Global number of edges. * @return number of edges in mesh. */ int Nedges() const { return _nedge; } /** * Global number of edges for each finite element. * @return number of edges per element. */ int NedgesElements() const { return _nedge_e; } /** * Read edge connectivity information (e1,e2,e3)_i. * @return edge connectivity vector [nelems*_nedge_e]. */ const std::vector &GetEdgeConnectivity() const { return _ea; } /** * Access/Change edge connectivity information (e1,e2,e3)_i. * @return edge connectivity vector [nelems*_nedge_e]. */ std::vector &GetEdgeConnectivity() { return _ea; } /** * Read edge information (v1,v2)_i. * @return edge connectivity vector [_nedge*2]. */ const std::vector &GetEdges() const { return _edges; } /** * Access/Change edge information (v1,v2)_i. * @return edge connectivity vector [_nedge*2]. */ std::vector &GetEdges() { return _edges; } /** * Determines all node to node connections from the vertex based mesh. * * @return vector[k][] containing all connections of vertex k, including to itself. */ std::vector> Node2NodeGraph() const { //// Check version 2 wrt. version 1 //auto v1=Node2NodeGraph_1(); //auto v2=Node2NodeGraph_2(); //if ( equal(v1.cbegin(),v1.cend(),v2.begin()) ) //{ //std::cout << "\nidentical Versions\n"; //} //else //{ //std::cout << "\nE R R O R in Versions\n"; //} //return Node2NodeGraph_1(); return Node2NodeGraph_2(); // 2 times faster than version 1 } /** * Accesses the father-of-nodes relation. * * @return vector of length 0 because no relation available. * */ virtual std::vector const &GetFathersOfVertices() const { return _dummy; } /** * Deletes all edge connectivity information (saves memory). */ void Del_EdgeConnectivity(); protected: //public: void SetNelem(int nelem) { _nelem = nelem; } void SetNverticesElement(int nvert) { _nvert_e = nvert; } void SetNdofsElement(int ndof) { _ndof_e = ndof; } void SetNnode(int nnode) { _nnode = nnode; } void SetNdim(int ndim) { _ndim = ndim; } void SetNedge(int nedge) { _nedge = nedge; } /** * Reads vertex based mesh data from a binary file. * * File format, see ascii_write_mesh.m * * @param[in] fname file name */ void ReadVectexBasedMesh(std::string const &fname); /** * The vertex based mesh data are used to derive the edge based data. * * @warning Exactly 3 vertices, 3 edges per element are assumed (linear triangle in 2D) */ void DeriveEdgeFromVertexBased() { //DeriveEdgeFromVertexBased_slow(); //DeriveEdgeFromVertexBased_fast(); DeriveEdgeFromVertexBased_fast_2(); } void DeriveEdgeFromVertexBased_slow(); void DeriveEdgeFromVertexBased_fast(); void DeriveEdgeFromVertexBased_fast_2(); /** * The edge based mesh data are used to derive the vertex based data. * * @warning Exactly 3 vertices, 3 edges per element are assumed (linear triangle in 2D) */ void DeriveVertexFromEdgeBased(); /** * Determines the indices of those vertices with Dirichlet boundary conditions * @return index vector. */ int Nnbedges() const { return static_cast(_bedges.size()); } /** * Checks whether the array dimensions fit to their appropriate size parameters * @return index vector. */ virtual bool Check_array_dimensions() const; /** * Permutes the vertex information in an edge based mesh. * * @param[in] old2new new indices of original vertices. */ void PermuteVertices_EdgeBased(std::vector const &old2new); private: /** * Determines all node to node connections from the vertex based mesh. * * @return vector[k][] containing all connections of vertex k, including to itself. */ std::vector> Node2NodeGraph_1() const; // is correct /** * Determines all node to node connections from the vertex based mesh. * * Faster than @p Node2NodeGraph_1(). * * @return vector[k][] containing all connections of vertex k, including to itself. */ std::vector> Node2NodeGraph_2() const; // is correct //private: protected: int _nelem; //!< number elements int _nvert_e; //!< number of vertices per element int _ndof_e; //!< degrees of freedom (d.o.f.) per element int _nnode; //!< number nodes/vertices int _ndim; //!< space dimension of the problem (1, 2, or 3) std::vector _ia; //!< element connectivity std::vector _xc; //!< coordinates protected: // B.C. std::vector _bedges; //!< boundary edges [nbedges][2] storing start/end vertex // 2020-01-08 std::vector _sdedges; //!< boundary edges [nbedges][2] with left/right subdomain number //private: protected: // edge based connectivity int _nedge; //!< number of edges in mesh int _nedge_e; //!< number of edges per element std::vector _edges; //!< edges of mesh (vertices ordered ascending) std::vector _ea; //!< edge based element connectivity // B.C. std::vector _ebedges; //!< boundary edges [nbedges] private: const std::vector _dummy; //!< empty dummy vector }; // ********************************************************************* class RefinedMesh: public Mesh { public: /** * Constructs a refined mesh according to the marked elements in @p ibref. * * If the vector @p ibref has size 0 then all elements will be refined. * * @param[in] cmesh original mesh for coarsening. * @param[in] ibref vector containing True/False regarding refinement for each element * */ //explicit RefinedMesh(Mesh const &cmesh, std::vector const &ibref = std::vector(0)); RefinedMesh(Mesh const &cmesh, std::vector const &ibref); //RefinedMesh(Mesh const &cmesh, std::vector const &ibref); /** * Constructs a refined mesh by regulare refinement of all elements. * * @param[in] cmesh original mesh for coarsening. * */ explicit RefinedMesh(Mesh const &cmesh) : RefinedMesh(cmesh, std::vector(0)) {} RefinedMesh(RefinedMesh const &) = delete; //RefinedMesh(RefinedMesh const&&) = delete; RefinedMesh &operator=(RefinedMesh const &) = delete; //RefinedMesh& operator=(RefinedMesh const&&) = delete; /** * Destructor. */ virtual ~RefinedMesh() override; /** * Refines the mesh according to the marked elements. * * @param[in] ibref vector containing True/False regarding refinement for each element * * @return the refined mesh * */ Mesh RefineElements(std::vector const &ibref); /** * Refines all elements in the actual mesh. * * @param[in] nref number of regular refinements to perform * */ void RefineAllElements(int nref = 1); /** * Accesses the father-of-nodes relation. * * @return father-of-nodes relation [nnodes][2] * */ std::vector const &GetFathersOfVertices() const override { return _vfathers; } protected: /** * Checks whether the array dimensions fit to their appropriate size parameters * @return index vector. */ bool Check_array_dimensions() const override; /** * Permutes the vertex information in an edge based mesh. * * @param[in] old2new new indices of original vertices. */ void PermuteVertices_EdgeBased(std::vector const &old2new); private: //Mesh const & _cmesh; //!< coarse mesh std::vector const _ibref; //!< refinement info int _nref; //!< number of regular refinements performed std::vector _vfathers; //!< stores the 2 fathers of each vertex (equal fathers denote original coarse vertex) }; // ********************************************************************* class gMesh_Hierarchy { public: /** * Constructs mesh hierarchy of @p nlevel levels starting with coarse mesh @p cmesh. * The coarse mesh @p cmesh will be @p nlevel-1 times geometrically refined. * * @param[in] cmesh initial coarse mesh * @param[in] nlevel number levels in mesh hierarchy * */ gMesh_Hierarchy(Mesh const &cmesh, int nlevel); size_t size() const { return _gmesh.size(); } /** * Access to mesh @p lev from mesh hierarchy. * * @return mesh @p lev * @warning An out_of_range exception might be thrown. * */ Mesh const &operator[](int lev) const { return *_gmesh.at(lev); } /** * Access to finest mesh in mesh hierarchy. * * @return finest mesh * */ Mesh const &finest() const { return *_gmesh.back(); } /** * Access to coarest mesh in mesh hierarchy. * * @return coarsest mesh * */ Mesh const &coarsest() const { return *_gmesh.front(); } private: std::vector> _gmesh; //!< mesh hierarchy from coarse ([0]) to fine. }; // ********************************************************************* /** * 2D finite element mesh of the square consisting of linear triangular elements. */ class Mesh_2d_3_square: public Mesh { public: /** * Generates the f.e. mesh for the unit square. * * @param[in] nx number of discretization intervals in x-direction * @param[in] ny number of discretization intervals in y-direction * @param[in] myid my MPI-rank / subdomain * @param[in] procx number of ranks/subdomains in x-direction * @param[in] procy number of processes in y-direction */ Mesh_2d_3_square(int nx, int ny, int myid = 0, int procx = 1, int procy = 1); /** * Destructor */ ~Mesh_2d_3_square() override; /** * Set solution vector based on a tensor product grid in the rectangle. * @param[in] u solution vector */ void SetU(std::vector &u) const; /** * Set right hand side (rhs) vector on a tensor product grid in the rectangle. * @param[in] f rhs vector */ void SetF(std::vector &f) const; /** * Determines the indices of those vertices with Dirichlet boundary conditions * @return index vector. */ std::vector Index_DirichletNodes() const override; std::vector Index_BoundaryNodes() const override; /** * Stores the values of vector @p u of (sub)domain into a file @p name for further processing in gnuplot. * The file stores rowise the x- and y- coordinates together with the value from @p u . * The domain [@p xl, @p xr] x [@p yb, @p yt] is discretized into @p nx x @p ny intervals. * * @param[in] name basename of file name (file name will be extended by the rank number) * @param[in] u local vector * * @warning Assumes tensor product grid in unit square; rowise numbered * (as generated in class constructor). * The output is provided for tensor product grid visualization * ( similar to Matlab-surf() ). * * @see Mesh_2d_3_square */ void SaveVectorP(std::string const &name, std::vector const &u) const; // here will still need to implement in the class // GetBound(), AddBound() // or better a generalized way with indices and their appropriate ranks for MPI communication private: /** * Determines the coordinates of the discretization nodes of the domain [@p xl, @p xr] x [@p yb, @p yt] * which is discretized into @p nx x @p ny intervals. * @param[in] nx number of discretization intervals in x-direction * @param[in] ny number of discretization intervals in y-direction * @param[in] xl x-coordinate of left boundary * @param[in] xr x-coordinate of right boundary * @param[in] yb y-coordinate of lower boundary * @param[in] yt y-coordinate of upper boundary * @param[out] xc coordinate vector of length 2n with x(2*k,2*k+1) as coordinates of node k */ void GetCoordsInRectangle(int nx, int ny, double xl, double xr, double yb, double yt, double xc[]); /** * Determines the element connectivity of linear triangular elements of a FEM discretization * of a rectangle using @p nx x @p ny equidistant intervals for discretization. * @param[in] nx number of discretization intervals in x-direction * @param[in] ny number of discretization intervals in y-direction * @param[out] ia element connectivity matrix with ia(3*s,3*s+1,3*s+2) as node numbers od element s */ void GetConnectivityInRectangle(int nx, int ny, int ia[]); private: int _myid; //!< my MPI rank int _procx; //!< number of MPI ranks in x-direction int _procy; //!< number of MPI ranks in y-direction std::array _neigh; //!< MPI ranks of neighbors (negative: no neighbor but b.c.) int _color; //!< red/black coloring (checker board) of subdomains double _xl; //!< x coordinate of lower left corner of square double _xr; //!< x coordinate of lower right corner of square double _yb; //!< y coordinate or lower left corner of square double _yt; //!< y coordinate of upper right corner of square int _nx; //!< number of intervals in x-direction int _ny; //!< number of intervals in y-direction }; // ********************************************************************* #endif