Files
mfem/mesh/mesh.hpp
T

1481 lines
63 KiB
C++

// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_MESH
#define MFEM_MESH
#include "../config/config.hpp"
#include "../general/stable3d.hpp"
#include "../general/globals.hpp"
#include "triangle.hpp"
#include "tetrahedron.hpp"
#include "vertex.hpp"
#include "vtk.hpp"
#include "ncmesh.hpp"
#include "../fem/eltrans.hpp"
#include "../fem/coefficient.hpp"
#include "../general/zstr.hpp"
#ifdef MFEM_USE_ADIOS2
#include "../general/adios2stream.hpp"
#endif
#include <iostream>
namespace mfem
{
// Data type mesh
class GeometricFactors;
class FaceGeometricFactors;
class KnotVector;
class NURBSExtension;
class FiniteElementSpace;
class GridFunction;
struct Refinement;
/** An enum type to specify if interior or boundary faces are desired. */
enum class FaceType : bool {Interior, Boundary};
#ifdef MFEM_USE_MPI
class ParMesh;
class ParNCMesh;
#endif
class Mesh
{
#ifdef MFEM_USE_MPI
friend class ParMesh;
friend class ParNCMesh;
#endif
friend class NCMesh;
friend class NURBSExtension;
#ifdef MFEM_USE_ADIOS2
friend class adios2stream;
#endif
protected:
int Dim;
int spaceDim;
int NumOfVertices, NumOfElements, NumOfBdrElements;
int NumOfEdges, NumOfFaces;
/** These variables store the number of Interior and Boundary faces. Calling
fes->GetMesh()->GetNBE() doesn't return the expected value in 3D because
periodic meshes in 3D have some of their faces marked as boundary for
visualization purpose in GLVis. */
mutable int nbInteriorFaces, nbBoundaryFaces;
int meshgen; // see MeshGenerator()
int mesh_geoms; // sum of (1 << geom) for all geom of all dimensions
// Counter for Mesh transformations: refinement, derefinement, rebalancing.
// Used for checking during Update operations on objects depending on the
// Mesh, such as FiniteElementSpace, GridFunction, etc.
long sequence;
Array<Element *> elements;
// Vertices are only at the corners of elements, where you would expect them
// in the lowest-order mesh. In some cases, e.g. in a Mesh that defines the
// patch topology for a NURBS mesh (see LoadPatchTopo()) the vertices may be
// empty while NumOfVertices is positive.
Array<Vertex> vertices;
Array<Element *> boundary;
Array<Element *> faces;
struct FaceInfo
{
// Inf = 64 * LocalFaceIndex + FaceOrientation
int Elem1No, Elem2No, Elem1Inf, Elem2Inf;
int NCFace; /* -1 if this is a regular conforming/boundary face;
index into 'nc_faces_info' if >= 0. */
};
// NOTE: in NC meshes, master faces have Elem2No == -1. Slave faces on the
// other hand have Elem2No and Elem2Inf set to the master face's element and
// its local face number.
//
// A local face is one generated from a local element and has index i in
// faces_info such that i < GetNumFaces(). Also, Elem1No always refers to the
// element (slave or master, in the non-conforming case) that generated the
// face.
// Classification of a local (non-ghost) face based on its FaceInfo:
// - Elem2No >= 0 --> local internal face; can be either:
// - NCFace == -1 --> conforming face, or
// - NCFace >= 0 --> non-conforming slave face.
// - Elem2No < 0 --> local "boundary" face; can be one of:
// - NCFace == -1 --> conforming face; can be either:
// - Elem2Inf < 0 --> true boundary face (no element on side 2)
// - Elem2Inf >= 0 --> shared face where element 2 is a face-neighbor
// element with index -1-Elem2No. This state is initialized by
// ParMesh::ExchangeFaceNbrData().
// - NCFace >= 0 --> non-conforming master face. Elem2No is -1 or, in the
// case of a shared face, -1-Elem2No is the index of one of the adjacent
// (the last one?) slave ghost elements. Elem2Inf is -1.
//
// A ghost face is a non-conforming face that is generated by a non-local,
// i.e. ghost, element. A ghost face has index i in faces_info such that
// i >= GetNumFaces().
// Classification of a ghost (non-local) face based on its FaceInfo:
// - Elem1No == -1 --> master ghost face? These ghost faces also have:
// Elem2No == -1, Elem1Inf == Elem2Inf == -1, and NCFace == -1.
// - Elem1No >= 0 --> slave ghost face; Elem1No is the index of the local
// master side element, i.e. side 1 IS NOT the side that generated the
// face. Elem2No is < 0 and -1-Elem2No is the index of the ghost
// face-neighbor element that generated this slave ghost face. In this
// case, Elem2Inf >= 0.
struct NCFaceInfo
{
bool Slave; // true if this is a slave face, false if master face
int MasterFace; // if Slave, this is the index of the master face
const DenseMatrix* PointMatrix; // if Slave, position within master face
// (NOTE: PointMatrix points to a matrix owned by NCMesh.)
NCFaceInfo() = default;
NCFaceInfo(bool slave, int master, const DenseMatrix* pm)
: Slave(slave), MasterFace(master), PointMatrix(pm) {}
};
Array<FaceInfo> faces_info;
Array<NCFaceInfo> nc_faces_info;
Table *el_to_edge;
Table *el_to_face;
Table *el_to_el;
Array<int> be_to_edge; // for 2D
Table *bel_to_edge; // for 3D
Array<int> be_to_face;
mutable Table *face_edge;
mutable Table *edge_vertex;
IsoparametricTransformation Transformation, Transformation2;
IsoparametricTransformation BdrTransformation;
IsoparametricTransformation FaceTransformation, EdgeTransformation;
FaceElementTransformations FaceElemTr;
// refinement embeddings for forward compatibility with NCMesh
CoarseFineTransformations CoarseFineTr;
// Nodes are only active for higher order meshes, and share locations with
// the vertices, plus all the higher- order control points within the
// element and along the edges and on the faces.
GridFunction *Nodes;
int own_nodes;
static const int vtk_quadratic_tet[10];
static const int vtk_quadratic_wedge[18];
static const int vtk_quadratic_hex[27];
#ifdef MFEM_USE_MEMALLOC
friend class Tetrahedron;
MemAlloc <Tetrahedron, 1024> TetMemory;
#endif
public:
typedef Geometry::Constants<Geometry::SEGMENT> seg_t;
typedef Geometry::Constants<Geometry::TRIANGLE> tri_t;
typedef Geometry::Constants<Geometry::SQUARE> quad_t;
typedef Geometry::Constants<Geometry::TETRAHEDRON> tet_t;
typedef Geometry::Constants<Geometry::CUBE> hex_t;
typedef Geometry::Constants<Geometry::PRISM> pri_t;
enum Operation { NONE, REFINE, DEREFINE, REBALANCE };
/// A list of all unique element attributes used by the Mesh.
Array<int> attributes;
/// A list of all unique boundary attributes used by the Mesh.
Array<int> bdr_attributes;
NURBSExtension *NURBSext; ///< Optional NURBS mesh extension.
NCMesh *ncmesh; ///< Optional non-conforming mesh extension.
Array<GeometricFactors*> geom_factors; ///< Optional geometric factors.
Array<FaceGeometricFactors*>
face_geom_factors; ///< Optional face geometric factors.
// Global parameter that can be used to control the removal of unused
// vertices performed when reading a mesh in MFEM format. The default value
// (true) is set in mesh_readers.cpp.
static bool remove_unused_vertices;
protected:
Operation last_operation;
void Init();
void InitTables();
void SetEmpty(); // Init all data members with empty values
void DestroyTables();
void DeleteTables() { DestroyTables(); InitTables(); }
void DestroyPointers(); // Delete data specifically allocated by class Mesh.
void Destroy(); // Delete all owned data.
void ResetLazyData();
Element *ReadElementWithoutAttr(std::istream &);
static void PrintElementWithoutAttr(const Element *, std::ostream &);
Element *ReadElement(std::istream &);
static void PrintElement(const Element *, std::ostream &);
// Readers for different mesh formats, used in the Load() method.
// The implementations of these methods are in mesh_readers.cpp.
void ReadMFEMMesh(std::istream &input, bool mfem_v11, int &curved);
void ReadLineMesh(std::istream &input);
void ReadNetgen2DMesh(std::istream &input, int &curved);
void ReadNetgen3DMesh(std::istream &input);
void ReadTrueGridMesh(std::istream &input);
void ReadVTKMesh(std::istream &input, int &curved, int &read_gf,
bool &finalize_topo);
void ReadNURBSMesh(std::istream &input, int &curved, int &read_gf);
void ReadInlineMesh(std::istream &input, bool generate_edges = false);
void ReadGmshMesh(std::istream &input, int &curved, int &read_gf);
/* Note NetCDF (optional library) is used for reading cubit files */
#ifdef MFEM_USE_NETCDF
void ReadCubit(const char *filename, int &curved, int &read_gf);
#endif
/// Determine the mesh generator bitmask #meshgen, see MeshGenerator().
/** Also, initializes #mesh_geoms. */
void SetMeshGen();
/// Return the length of the segment from node i to node j.
double GetLength(int i, int j) const;
/** Compute the Jacobian of the transformation from the perfect
reference element at the center of the element. */
void GetElementJacobian(int i, DenseMatrix &J);
void MarkForRefinement();
void MarkTriMeshForRefinement();
void GetEdgeOrdering(DSTable &v_to_v, Array<int> &order);
virtual void MarkTetMeshForRefinement(DSTable &v_to_v);
// Methods used to prepare and apply permutation of the mesh nodes assuming
// that the mesh elements may be rotated (e.g. to mark triangle or tet edges
// for refinement) between the two calls - PrepareNodeReorder() and
// DoNodeReorder(). The latter method assumes that the 'faces' have not been
// updated after the element rotations.
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert);
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert);
STable3D *GetFacesTable();
STable3D *GetElementToFaceTable(int ret_ftbl = 0);
/** Red refinement. Element with index i is refined. The default
red refinement for now is Uniform. */
void RedRefinement(int i, const DSTable &v_to_v,
int *edge1, int *edge2, int *middle)
{ UniformRefinement(i, v_to_v, edge1, edge2, middle); }
/** Green refinement. Element with index i is refined. The default
refinement for now is Bisection. */
void GreenRefinement(int i, const DSTable &v_to_v,
int *edge1, int *edge2, int *middle)
{ Bisection(i, v_to_v, edge1, edge2, middle); }
/// Bisect a triangle: element with index @a i is bisected.
void Bisection(int i, const DSTable &, int *, int *, int *);
/// Bisect a tetrahedron: element with index @a i is bisected.
void Bisection(int i, HashTable<Hashed2> &);
/// Bisect a boundary triangle: boundary element with index @a i is bisected.
void BdrBisection(int i, const HashTable<Hashed2> &);
/** Uniform Refinement. Element with index i is refined uniformly. */
void UniformRefinement(int i, const DSTable &, int *, int *, int *);
/** @brief Averages the vertices with given @a indexes and saves the result
in #vertices[result]. */
void AverageVertices(const int *indexes, int n, int result);
void InitRefinementTransforms();
int FindCoarseElement(int i);
/// Update the nodes of a curved mesh after refinement
void UpdateNodes();
void UniformRefinement2D_base(bool update_nodes = true);
/// Refine a mixed 2D mesh uniformly.
virtual void UniformRefinement2D() { UniformRefinement2D_base(); }
/* If @a f2qf is not NULL, adds all quadrilateral faces to @a f2qf which
represents a "face-to-quad-face" index map. When all faces are quads, the
array @a f2qf is kept empty since it is not needed. */
void UniformRefinement3D_base(Array<int> *f2qf = NULL,
DSTable *v_to_v_p = NULL,
bool update_nodes = true);
/// Refine a mixed 3D mesh uniformly.
virtual void UniformRefinement3D() { UniformRefinement3D_base(); }
/// Refine NURBS mesh.
virtual void NURBSUniformRefinement();
/// This function is not public anymore. Use GeneralRefinement instead.
virtual void LocalRefinement(const Array<int> &marked_el, int type = 3);
/// This function is not public anymore. Use GeneralRefinement instead.
virtual void NonconformingRefinement(const Array<Refinement> &refinements,
int nc_limit = 0);
/// NC version of GeneralDerefinement.
virtual bool NonconformingDerefinement(Array<double> &elem_error,
double threshold, int nc_limit = 0,
int op = 1);
/// Derefinement helper.
double AggregateError(const Array<double> &elem_error,
const int *fine, int nfine, int op);
/// Read NURBS patch/macro-element mesh
void LoadPatchTopo(std::istream &input, Array<int> &edge_to_knot);
void UpdateNURBS();
void PrintTopo(std::ostream &out, const Array<int> &e_to_k) const;
/// Used in GetFaceElementTransformations (...)
void GetLocalPtToSegTransformation(IsoparametricTransformation &, int);
void GetLocalSegToTriTransformation (IsoparametricTransformation &loc,
int i);
void GetLocalSegToQuadTransformation (IsoparametricTransformation &loc,
int i);
/// Used in GetFaceElementTransformations (...)
void GetLocalTriToTetTransformation (IsoparametricTransformation &loc,
int i);
/// Used in GetFaceElementTransformations (...)
void GetLocalTriToWdgTransformation (IsoparametricTransformation &loc,
int i);
/// Used in GetFaceElementTransformations (...)
void GetLocalQuadToHexTransformation (IsoparametricTransformation &loc,
int i);
/// Used in GetFaceElementTransformations (...)
void GetLocalQuadToWdgTransformation (IsoparametricTransformation &loc,
int i);
/** Used in GetFaceElementTransformations to account for the fact that a
slave face occupies only a portion of its master face. */
void ApplyLocalSlaveTransformation(IsoparametricTransformation &transf,
const FaceInfo &fi);
bool IsSlaveFace(const FaceInfo &fi) const;
/// Returns the orientation of "test" relative to "base"
static int GetTriOrientation (const int * base, const int * test);
/// Returns the orientation of "test" relative to "base"
static int GetQuadOrientation (const int * base, const int * test);
/// Returns the orientation of "test" relative to "base"
static int GetTetOrientation (const int * base, const int * test);
static void GetElementArrayEdgeTable(const Array<Element*> &elem_array,
const DSTable &v_to_v,
Table &el_to_edge);
/** Return vertex to vertex table. The connections stored in the table
are from smaller to bigger vertex index, i.e. if i<j and (i, j) is
in the table, then (j, i) is not stored. */
void GetVertexToVertexTable(DSTable &) const;
/** Return element to edge table and the indices for the boundary edges.
The entries in the table are ordered according to the order of the
nodes in the elements. For example, if T is the element to edge table
T(i, 0) gives the index of edge in element i that connects vertex 0
to vertex 1, etc. Returns the number of the edges. */
int GetElementToEdgeTable(Table &, Array<int> &);
/// Used in GenerateFaces()
void AddPointFaceElement(int lf, int gf, int el);
void AddSegmentFaceElement (int lf, int gf, int el, int v0, int v1);
void AddTriangleFaceElement (int lf, int gf, int el,
int v0, int v1, int v2);
void AddQuadFaceElement (int lf, int gf, int el,
int v0, int v1, int v2, int v3);
/** For a serial Mesh, return true if the face is interior. For a parallel
ParMesh return true if the face is interior or shared. In parallel, this
method only works if the face neighbor data is exchanged. */
bool FaceIsTrueInterior(int FaceNo) const
{
return FaceIsInterior(FaceNo) || (faces_info[FaceNo].Elem2Inf >= 0);
}
void FreeElement(Element *E);
void GenerateFaces();
void GenerateNCFaceInfo();
/// Begin construction of a mesh
void InitMesh(int _Dim, int _spaceDim, int NVert, int NElem, int NBdrElem);
// Used in the methods FinalizeXXXMesh() and FinalizeTopology()
void FinalizeCheck();
void Loader(std::istream &input, int generate_edges = 0,
std::string parse_tag = "");
// If NURBS mesh, write NURBS format. If NCMesh, write mfem v1.1 format.
// If section_delimiter is empty, write mfem v1.0 format. Otherwise, write
// mfem v1.2 format with the given section_delimiter at the end.
void Printer(std::ostream &out = mfem::out,
std::string section_delimiter = "") const;
/** Creates mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into
nx*ny*nz hexahedra if type=HEXAHEDRON or into 6*nx*ny*nz tetrahedrons if
type=TETRAHEDRON. The parameter @a sfc_ordering controls how the elements
(when type=HEXAHEDRON) are ordered: true - use space-filling curve
ordering, or false - use lexicographic ordering. */
void Make3D(int nx, int ny, int nz, Element::Type type,
double sx, double sy, double sz, bool sfc_ordering);
/** Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny
quadrilaterals if type = QUADRILATERAL or into 2*nx*ny triangles if
type = TRIANGLE. If generate_edges = 0 (default) edges are not generated,
if 1 edges are generated. The parameter @a sfc_ordering controls how the
elements (when type=QUADRILATERAL) are ordered: true - use space-filling
curve ordering, or false - use lexicographic ordering. */
void Make2D(int nx, int ny, Element::Type type, double sx, double sy,
bool generate_edges, bool sfc_ordering);
/// Creates a 1D mesh for the interval [0,sx] divided into n equal intervals.
void Make1D(int n, double sx = 1.0);
/// Initialize vertices/elements/boundary/tables from a nonconforming mesh.
void InitFromNCMesh(const NCMesh &ncmesh);
/// Create from a nonconforming mesh.
explicit Mesh(const NCMesh &ncmesh);
/// Swaps internal data with another mesh. By default, non-geometry members
/// like 'ncmesh' and 'NURBSExt' are only swapped when 'non_geometry' is set.
void Swap(Mesh& other, bool non_geometry);
// used in GetElementData() and GetBdrElementData()
void GetElementData(const Array<Element*> &elem_array, int geom,
Array<int> &elem_vtx, Array<int> &attr) const;
public:
Mesh() { SetEmpty(); }
/** Copy constructor. Performs a deep copy of (almost) all data, so that the
source mesh can be modified (e.g. deleted, refined) without affecting the
new mesh. If 'copy_nodes' is false, use a shallow (pointer) copy for the
nodes, if present. */
explicit Mesh(const Mesh &mesh, bool copy_nodes = true);
/// Construct a Mesh from the given primary data.
/** The array @a vertices is used as external data, i.e. the Mesh does not
copy the data and will not delete the pointer.
The data from the other arrays is copied into the internal Mesh data
structures.
This method calls the method FinalizeTopology(). The method Finalize()
may be called after this constructor and after optionally setting the
Mesh nodes. */
Mesh(double *vertices, int num_vertices,
int *element_indices, Geometry::Type element_type,
int *element_attributes, int num_elements,
int *boundary_indices, Geometry::Type boundary_type,
int *boundary_attributes, int num_boundary_elements,
int dimension, int space_dimension= -1);
/** @anchor mfem_Mesh_init_ctor
@brief _Init_ constructor: begin the construction of a Mesh object. */
Mesh(int _Dim, int NVert, int NElem, int NBdrElem = 0, int _spaceDim = -1)
{
if (_spaceDim == -1)
{
_spaceDim = _Dim;
}
InitMesh(_Dim, _spaceDim, NVert, NElem, NBdrElem);
}
/** @name Methods for Mesh construction.
These methods are intended to be used with the @ref mfem_Mesh_init_ctor
"init constructor". */
///@{
Element *NewElement(int geom);
void AddVertex(const double *);
void AddSegment(const int *vi, int attr = 1);
void AddTri(const int *vi, int attr = 1);
void AddTriangle(const int *vi, int attr = 1);
void AddQuad(const int *vi, int attr = 1);
void AddTet(const int *vi, int attr = 1);
void AddWedge(const int *vi, int attr = 1);
void AddHex(const int *vi, int attr = 1);
void AddHexAsTets(const int *vi, int attr = 1);
void AddHexAsWedges(const int *vi, int attr = 1);
/// The parameter @a elem should be allocated using the NewElement() method
void AddElement(Element *elem) { elements[NumOfElements++] = elem; }
void AddBdrElement(Element *elem) { boundary[NumOfBdrElements++] = elem; }
void AddBdrSegment(const int *vi, int attr = 1);
void AddBdrTriangle(const int *vi, int attr = 1);
void AddBdrQuad(const int *vi, int attr = 1);
void AddBdrQuadAsTriangles(const int *vi, int attr = 1);
void GenerateBoundaryElements();
/// Finalize the construction of a triangular Mesh.
void FinalizeTriMesh(int generate_edges = 0, int refine = 0,
bool fix_orientation = true);
/// Finalize the construction of a quadrilateral Mesh.
void FinalizeQuadMesh(int generate_edges = 0, int refine = 0,
bool fix_orientation = true);
/// Finalize the construction of a tetrahedral Mesh.
void FinalizeTetMesh(int generate_edges = 0, int refine = 0,
bool fix_orientation = true);
/// Finalize the construction of a wedge Mesh.
void FinalizeWedgeMesh(int generate_edges = 0, int refine = 0,
bool fix_orientation = true);
/// Finalize the construction of a hexahedral Mesh.
void FinalizeHexMesh(int generate_edges = 0, int refine = 0,
bool fix_orientation = true);
/// Finalize the construction of any type of Mesh.
/** This method calls FinalizeTopology() and Finalize(). */
void FinalizeMesh(int refine = 0, bool fix_orientation = true);
///@}
/** @brief Finalize the construction of the secondary topology (connectivity)
data of a Mesh. */
/** This method does not require any actual coordinate data (either vertex
coordinates for linear meshes or node coordinates for meshes with nodes)
to be available. However, the data generated by this method is generally
required by the FiniteElementSpace class.
After calling this method, setting the Mesh vertices or nodes, it may be
appropriate to call the method Finalize(). */
void FinalizeTopology(bool generate_bdr = true);
/// Finalize the construction of a general Mesh.
/** This method will:
- check and optionally fix the orientation of regular elements
- check and fix the orientation of boundary elements
- assume that #vertices are defined, if #Nodes == NULL
- assume that #Nodes are defined, if #Nodes != NULL.
@param[in] refine If true, prepare the Mesh for conforming refinement of
triangular or tetrahedral meshes.
@param[in] fix_orientation
If true, fix the orientation of inverted mesh elements
by permuting their vertices.
Before calling this method, call FinalizeTopology() and ensure that the
Mesh vertices or nodes are set. */
virtual void Finalize(bool refine = false, bool fix_orientation = false);
virtual void SetAttributes();
/** This is our integration with the Gecko library. The method finds an
element ordering that will increase memory coherency by putting elements
that are in physical proximity closer in memory. It can also be used to
obtain a space-filling curve ordering for ParNCMesh partitioning.
@param[out] ordering Output element ordering.
@param iterations Total number of V cycles. The ordering may improve with
more iterations. The best iteration is returned at the end.
@param window Initial window size. This determines the number of
permutations tested at each multigrid level and strongly influences the
quality of the result, but the cost of increasing 'window' is exponential.
@param period The window size is incremented every 'period' iterations.
@param seed Seed for initial random ordering (0 = skip random reorder).
@param verbose Print the progress of the optimization to mfem::out.
@param time_limit Optional time limit for the optimization, in seconds.
When reached, ordering from the best iteration so far is returned
(0 = no limit).
@return The final edge product cost of the ordering. The function may be
called in an external loop with different seeds, and the best ordering can
then be retained. */
double GetGeckoElementOrdering(Array<int> &ordering,
int iterations = 4, int window = 4,
int period = 2, int seed = 0,
bool verbose = false, double time_limit = 0);
/** Return an ordering of the elements that approximately follows the Hilbert
curve. The method performs a spatial (Hilbert) sort on the centers of all
elements and returns the resulting sequence, which can then be passed to
ReorderElements. This is a cheap alternative to GetGeckoElementOrdering.*/
void GetHilbertElementOrdering(Array<int> &ordering);
/** Rebuilds the mesh with a different order of elements. For each element i,
the array ordering[i] contains its desired new index. Note that the method
reorders vertices, edges and faces along with the elements. */
void ReorderElements(const Array<int> &ordering, bool reorder_vertices = true);
/** Creates mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into
nx*ny*nz hexahedra if type=HEXAHEDRON or into 6*nx*ny*nz tetrahedrons if
type=TETRAHEDRON. If sfc_ordering = true (default), elements are ordered
along a space-filling curve, instead of row by row and layer by layer.
The parameter @a generate_edges is ignored (for now, it is kept for
backward compatibility). */
Mesh(int nx, int ny, int nz, Element::Type type, bool generate_edges = false,
double sx = 1.0, double sy = 1.0, double sz = 1.0,
bool sfc_ordering = true)
{
Make3D(nx, ny, nz, type, sx, sy, sz, sfc_ordering);
Finalize(true); // refine = true
}
/** Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny
quadrilaterals if type = QUADRILATERAL or into 2*nx*ny triangles if
type = TRIANGLE. If generate_edges = 0 (default) edges are not generated,
if 1 edges are generated. If scf_ordering = true (default), elements are
ordered along a space-filling curve, instead of row by row. */
Mesh(int nx, int ny, Element::Type type, bool generate_edges = false,
double sx = 1.0, double sy = 1.0, bool sfc_ordering = true)
{
Make2D(nx, ny, type, sx, sy, generate_edges, sfc_ordering);
Finalize(true); // refine = true
}
/** Creates 1D mesh , divided into n equal intervals. */
explicit Mesh(int n, double sx = 1.0)
{
Make1D(n, sx);
// Finalize(); // reminder: not needed
}
/** Creates mesh by reading a file in MFEM, Netgen, or VTK format. If
generate_edges = 0 (default) edges are not generated, if 1 edges are
generated. */
explicit Mesh(const char *filename, int generate_edges = 0, int refine = 1,
bool fix_orientation = true);
/** Creates mesh by reading data stream in MFEM, Netgen, or VTK format. If
generate_edges = 0 (default) edges are not generated, if 1 edges are
generated. */
explicit Mesh(std::istream &input, int generate_edges = 0, int refine = 1,
bool fix_orientation = true);
/// Create a disjoint mesh from the given mesh array
Mesh(Mesh *mesh_array[], int num_pieces);
/// Create a uniformly refined (by any factor) version of @a orig_mesh.
/** @param[in] orig_mesh The starting coarse mesh.
@param[in] ref_factor The refinement factor, an integer > 1.
@param[in] ref_type Specify the positions of the new vertices. The
options are BasisType::ClosedUniform or
BasisType::GaussLobatto.
The refinement data which can be accessed with GetRefinementTransforms()
is set to reflect the performed refinements.
@note The constructed Mesh is linear, i.e. it does not have nodes. */
Mesh(Mesh *orig_mesh, int ref_factor, int ref_type);
/** This is similar to the mesh constructor with the same arguments, but here
the current mesh is destroyed and another one created based on the data
stream again given in MFEM, Netgen, or VTK format. If generate_edges = 0
(default) edges are not generated, if 1 edges are generated. */
/// \see mfem::ifgzstream() for on-the-fly decompression of compressed ascii
/// inputs.
virtual void Load(std::istream &input, int generate_edges = 0,
int refine = 1, bool fix_orientation = true)
{
Loader(input, generate_edges);
Finalize(refine, fix_orientation);
}
/// Clear the contents of the Mesh.
void Clear() { Destroy(); SetEmpty(); }
/** @brief Get the mesh generator/type.
@return A bitmask:
- bit 0 - simplices are present in the mesh (triangles, tets),
- bit 1 - tensor product elements are present in the mesh (quads, hexes),
- bit 2 - the mesh has wedge elements.
In parallel, the result takes into account elements on all processors.
*/
inline int MeshGenerator() { return meshgen; }
/** @brief Returns number of vertices. Vertices are only at the corners of
elements, where you would expect them in the lowest-order mesh. */
inline int GetNV() const { return NumOfVertices; }
/// Returns number of elements.
inline int GetNE() const { return NumOfElements; }
/// Returns number of boundary elements.
inline int GetNBE() const { return NumOfBdrElements; }
/// Return the number of edges.
inline int GetNEdges() const { return NumOfEdges; }
/// Return the number of faces in a 3D mesh.
inline int GetNFaces() const { return NumOfFaces; }
/// Return the number of faces (3D), edges (2D) or vertices (1D).
int GetNumFaces() const;
/// Returns the number of faces according to the requested type.
/** If type==Boundary returns only the "true" number of boundary faces
contrary to GetNBE() that returns "fake" boundary faces associated to
visualization for GLVis.
Similarly, if type==Interior, the "fake" boundary faces associated to
visualization are counted as interior faces. */
int GetNFbyType(FaceType type) const;
/// Utility function: sum integers from all processors (Allreduce).
virtual long ReduceInt(int value) const { return value; }
/// Return the total (global) number of elements.
long GetGlobalNE() const { return ReduceInt(NumOfElements); }
/** @brief Return the mesh geometric factors corresponding to the given
integration rule. */
const GeometricFactors* GetGeometricFactors(const IntegrationRule& ir,
const int flags);
/** @brief Return the mesh geometric factors for the faces corresponding
to the given integration rule. */
const FaceGeometricFactors* GetFaceGeometricFactors(const IntegrationRule& ir,
const int flags,
FaceType type);
/// Destroy all GeometricFactors stored by the Mesh.
/** This method can be used to force recomputation of the GeometricFactors,
for example, after the mesh nodes are modified externally. */
void DeleteGeometricFactors();
/// Equals 1 + num_holes - num_loops
inline int EulerNumber() const
{ return NumOfVertices - NumOfEdges + NumOfFaces - NumOfElements; }
/// Equals 1 - num_holes
inline int EulerNumber2D() const
{ return NumOfVertices - NumOfEdges + NumOfElements; }
int Dimension() const { return Dim; }
int SpaceDimension() const { return spaceDim; }
/// @brief Return pointer to vertex i's coordinates.
/// @warning For high-order meshes (when #Nodes != NULL) vertices may not be
/// updated and should not be used!
const double *GetVertex(int i) const { return vertices[i](); }
/// @brief Return pointer to vertex i's coordinates.
/// @warning For high-order meshes (when Nodes != NULL) vertices may not
/// being updated and should not be used!
double *GetVertex(int i) { return vertices[i](); }
void GetElementData(int geom, Array<int> &elem_vtx, Array<int> &attr) const
{ GetElementData(elements, geom, elem_vtx, attr); }
void GetBdrElementData(int geom, Array<int> &bdr_elem_vtx,
Array<int> &bdr_attr) const
{ GetElementData(boundary, geom, bdr_elem_vtx, bdr_attr); }
/** @brief Set the internal Vertex array to point to the given @a vertices
array without assuming ownership of the pointer. */
/** If @a zerocopy is `true`, the vertices must be given as an array of 3
doubles per vertex. If @a zerocopy is `false` then the current Vertex
data is first copied to the @a vertices array. */
void ChangeVertexDataOwnership(double *vertices, int len_vertices,
bool zerocopy = false);
const Element* const *GetElementsArray() const
{ return elements.GetData(); }
const Element *GetElement(int i) const { return elements[i]; }
Element *GetElement(int i) { return elements[i]; }
const Element *GetBdrElement(int i) const { return boundary[i]; }
Element *GetBdrElement(int i) { return boundary[i]; }
const Element *GetFace(int i) const { return faces[i]; }
Geometry::Type GetFaceBaseGeometry(int i) const
{
return faces[i]->GetGeometryType();
}
Geometry::Type GetElementBaseGeometry(int i) const
{
return elements[i]->GetGeometryType();
}
Geometry::Type GetBdrElementBaseGeometry(int i) const
{
return boundary[i]->GetGeometryType();
}
/** @brief Return true iff the given @a geom is encountered in the mesh.
Geometries of dimensions lower than Dimension() are counted as well. */
bool HasGeometry(Geometry::Type geom) const
{ return mesh_geoms & (1 << geom); }
/** @brief Return the number of geometries of the given dimension present in
the mesh. */
/** For a parallel mesh only the local geometries are counted. */
int GetNumGeometries(int dim) const;
/// Return all element geometries of the given dimension present in the mesh.
/** For a parallel mesh only the local geometries are returned.
The returned geometries are sorted. */
void GetGeometries(int dim, Array<Geometry::Type> &el_geoms) const;
/// List of mesh geometries stored as Array<Geometry::Type>.
class GeometryList : public Array<Geometry::Type>
{
protected:
Geometry::Type geom_buf[Geometry::NumGeom];
public:
/// Construct a GeometryList of all element geometries in @a mesh.
GeometryList(Mesh &mesh)
: Array<Geometry::Type>(geom_buf, Geometry::NumGeom)
{ mesh.GetGeometries(mesh.Dimension(), *this); }
/** @brief Construct a GeometryList of all geometries of dimension @a dim
in @a mesh. */
GeometryList(Mesh &mesh, int dim)
: Array<Geometry::Type>(geom_buf, Geometry::NumGeom)
{ mesh.GetGeometries(dim, *this); }
};
/// Returns the indices of the vertices of element i.
void GetElementVertices(int i, Array<int> &v) const
{ elements[i]->GetVertices(v); }
/// Returns the indices of the vertices of boundary element i.
void GetBdrElementVertices(int i, Array<int> &v) const
{ boundary[i]->GetVertices(v); }
/// Return the indices and the orientations of all edges of element i.
void GetElementEdges(int i, Array<int> &edges, Array<int> &cor) const;
/// Return the indices and the orientations of all edges of bdr element i.
void GetBdrElementEdges(int i, Array<int> &edges, Array<int> &cor) const;
/** Return the indices and the orientations of all edges of face i.
Works for both 2D (face=edge) and 3D faces. */
void GetFaceEdges(int i, Array<int> &, Array<int> &) const;
/// Returns the indices of the vertices of face i.
void GetFaceVertices(int i, Array<int> &vert) const
{
if (Dim == 1)
{
vert.SetSize(1); vert[0] = i;
}
else
{
faces[i]->GetVertices(vert);
}
}
/// Returns the indices of the vertices of edge i.
void GetEdgeVertices(int i, Array<int> &vert) const;
/// Returns the face-to-edge Table (3D)
Table *GetFaceEdgeTable() const;
/// Returns the edge-to-vertex Table (3D)
Table *GetEdgeVertexTable() const;
/// Return the indices and the orientations of all faces of element i.
void GetElementFaces(int i, Array<int> &, Array<int> &) const;
/// Return the index and the orientation of the face of bdr element i. (3D)
void GetBdrElementFace(int i, int *, int *) const;
/** Return the vertex index of boundary element i. (1D)
Return the edge index of boundary element i. (2D)
Return the face index of boundary element i. (3D) */
int GetBdrElementEdgeIndex(int i) const;
/** @brief For the given boundary element, bdr_el, return its adjacent
element and its info, i.e. 64*local_bdr_index+bdr_orientation. */
void GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const;
/// Returns the type of element i.
Element::Type GetElementType(int i) const;
/// Returns the type of boundary element i.
Element::Type GetBdrElementType(int i) const;
/* Return point matrix of element i of dimension Dim X #v, where for every
vertex we give its coordinates in space of dimension Dim. */
void GetPointMatrix(int i, DenseMatrix &pointmat) const;
/* Return point matrix of boundary element i of dimension Dim X #v, where for
every vertex we give its coordinates in space of dimension Dim. */
void GetBdrPointMatrix(int i, DenseMatrix &pointmat) const;
static FiniteElement *GetTransformationFEforElementType(Element::Type);
/** Builds the transformation defining the i-th element in the user-defined
variable. */
void GetElementTransformation(int i, IsoparametricTransformation *ElTr);
/// Returns the transformation defining the i-th element
ElementTransformation *GetElementTransformation(int i);
/** Return the transformation defining the i-th element assuming
the position of the vertices/nodes are given by 'nodes'. */
void GetElementTransformation(int i, const Vector &nodes,
IsoparametricTransformation *ElTr);
/// Returns the transformation defining the i-th boundary element
ElementTransformation * GetBdrElementTransformation(int i);
void GetBdrElementTransformation(int i, IsoparametricTransformation *ElTr);
/** @brief Returns the transformation defining the given face element in a
user-defined variable. */
void GetFaceTransformation(int i, IsoparametricTransformation *FTr);
/** @brief A helper method that constructs a transformation from the
reference space of a face to the reference space of an element. */
/** The local index of the face as a face in the element and its orientation
are given by the input parameter @a info, as @a info = 64*loc_face_idx +
loc_face_orientation. */
void GetLocalFaceTransformation(int face_type, int elem_type,
IsoparametricTransformation &Transf,
int info);
/// Returns the transformation defining the given face element
ElementTransformation *GetFaceTransformation(int FaceNo);
/** Returns the transformation defining the given edge element.
The transformation is stored in a user-defined variable. */
void GetEdgeTransformation(int i, IsoparametricTransformation *EdTr);
/// Returns the transformation defining the given face element
ElementTransformation *GetEdgeTransformation(int EdgeNo);
/// Returns (a pointer to a structure containing) the following data:
///
/// 1) Elem1No - the index of the first element that contains this face this
/// is the element that has the same outward unit normal vector as the
/// face;
///
/// 2) Elem2No - the index of the second element that contains this face this
/// element has outward unit normal vector as the face multiplied with -1;
///
/// 3) Elem1, Elem2 - pointers to the ElementTransformation's of the first
/// and the second element respectively;
///
/// 4) Face - pointer to the ElementTransformation of the face;
///
/// 5) Loc1, Loc2 - IntegrationPointTransformation's mapping the face
/// coordinate system to the element coordinate system (both in their
/// reference elements). Used to transform IntegrationPoints from face to
/// element. More formally, let:
/// TL1, TL2 be the transformations represented by Loc1, Loc2,
/// TE1, TE2 - the transformations represented by Elem1, Elem2,
/// TF - the transformation represented by Face, then
/// TF(x) = TE1(TL1(x)) = TE2(TL2(x)) for all x in the reference face.
///
/// 6) FaceGeom - the base geometry for the face.
///
/// The mask specifies which fields in the structure to return:
/// mask & 1 - Elem1, mask & 2 - Elem2
/// mask & 4 - Loc1, mask & 8 - Loc2, mask & 16 - Face.
FaceElementTransformations *GetFaceElementTransformations(int FaceNo,
int mask = 31);
FaceElementTransformations *GetInteriorFaceTransformations (int FaceNo)
{
if (faces_info[FaceNo].Elem2No < 0) { return NULL; }
return GetFaceElementTransformations (FaceNo);
}
FaceElementTransformations *GetBdrFaceTransformations (int BdrElemNo);
/// Return true if the given face is interior. @sa FaceIsTrueInterior().
bool FaceIsInterior(int FaceNo) const
{
return (faces_info[FaceNo].Elem2No >= 0);
}
void GetFaceElements (int Face, int *Elem1, int *Elem2) const;
void GetFaceInfos (int Face, int *Inf1, int *Inf2) const;
Geometry::Type GetFaceGeometryType(int Face) const;
Element::Type GetFaceElementType(int Face) const;
/// Check the orientation of the elements
/** @return The number of elements with wrong orientation. */
int CheckElementOrientation(bool fix_it = true);
/// Check the orientation of the boundary elements
/** @return The number of boundary elements with wrong orientation. */
int CheckBdrElementOrientation(bool fix_it = true);
/// Return the attribute of element i.
int GetAttribute(int i) const { return elements[i]->GetAttribute(); }
/// Set the attribute of element i.
void SetAttribute(int i, int attr) { elements[i]->SetAttribute(attr); }
/// Return the attribute of boundary element i.
int GetBdrAttribute(int i) const { return boundary[i]->GetAttribute(); }
const Table &ElementToElementTable();
const Table &ElementToFaceTable() const;
const Table &ElementToEdgeTable() const;
/// The returned Table must be destroyed by the caller
Table *GetVertexToElementTable();
/** Return the "face"-element Table. Here "face" refers to face (3D),
edge (2D), or vertex (1D).
The returned Table must be destroyed by the caller. */
Table *GetFaceToElementTable() const;
/** This method modifies a tetrahedral mesh so that Nedelec spaces of order
greater than 1 can be defined on the mesh. Specifically, we
1) rotate all tets in the mesh so that the vertices {v0, v1, v2, v3}
satisfy: v0 < v1 < min(v2, v3).
2) rotate all boundary triangles so that the vertices {v0, v1, v2}
satisfy: v0 < min(v1, v2).
@note Refinement does not work after a call to this method! */
virtual void ReorientTetMesh();
int *CartesianPartitioning(int nxyz[]);
int *GeneratePartitioning(int nparts, int part_method = 1);
void CheckPartitioning(int *partitioning);
void CheckDisplacements(const Vector &displacements, double &tmax);
// Vertices are only at the corners of elements, where you would expect them
// in the lowest-order mesh.
void MoveVertices(const Vector &displacements);
void GetVertices(Vector &vert_coord) const;
void SetVertices(const Vector &vert_coord);
// Nodes are only active for higher order meshes, and share locations with
// the vertices, plus all the higher- order control points within the element
// and along the edges and on the faces.
void GetNode(int i, double *coord) const;
void SetNode(int i, const double *coord);
// Node operations for curved mesh.
// They call the corresponding '...Vertices' method if the
// mesh is not curved (i.e. Nodes == NULL).
void MoveNodes(const Vector &displacements);
void GetNodes(Vector &node_coord) const;
void SetNodes(const Vector &node_coord);
/// Return a pointer to the internal node GridFunction (may be NULL).
GridFunction *GetNodes() { return Nodes; }
const GridFunction *GetNodes() const { return Nodes; }
/// Return the mesh nodes ownership flag.
bool OwnsNodes() const { return own_nodes; }
/// Set the mesh nodes ownership flag.
void SetNodesOwner(bool nodes_owner) { own_nodes = nodes_owner; }
/// Replace the internal node GridFunction with the given GridFunction.
void NewNodes(GridFunction &nodes, bool make_owner = false);
/** Swap the internal node GridFunction pointer and ownership flag members
with the given ones. */
void SwapNodes(GridFunction *&nodes, int &own_nodes_);
/// Return the mesh nodes/vertices projected on the given GridFunction.
void GetNodes(GridFunction &nodes) const;
/** Replace the internal node GridFunction with a new GridFunction defined
on the given FiniteElementSpace. The new node coordinates are projected
(derived) from the current nodes/vertices. */
void SetNodalFESpace(FiniteElementSpace *nfes);
/** Replace the internal node GridFunction with the given GridFunction. The
given GridFunction is updated with node coordinates projected (derived)
from the current nodes/vertices. */
void SetNodalGridFunction(GridFunction *nodes, bool make_owner = false);
/** Return the FiniteElementSpace on which the current mesh nodes are
defined or NULL if the mesh does not have nodes. */
const FiniteElementSpace *GetNodalFESpace() const;
/** Make sure that the mesh has valid nodes, i.e. its geometry is described
by a vector finite element grid function (even if it is a low-order mesh
with straight edges). */
void EnsureNodes();
/** Set the curvature of the mesh nodes using the given polynomial degree,
'order', and optionally: discontinuous or continuous FE space, 'discont',
new space dimension, 'space_dim' (if != -1), and 'ordering'. */
virtual void SetCurvature(int order, bool discont = false, int space_dim = -1,
int ordering = 1);
/// Refine all mesh elements.
/** @param[in] ref_algo %Refinement algorithm. Currently used only for pure
tetrahedral meshes. If set to zero (default), a tet mesh will be refined
using algorithm A, that produces elements with better quality compared to
algorithm B used when the parameter is non-zero.
For tetrahedral meshes, after using algorithm A, the mesh cannot be
refined locally using methods like GeneralRefinement() unless it is
re-finalized using Finalize() with the parameter @a refine set to true.
Note that calling Finalize() in this way will generally invalidate any
FiniteElementSpace%s and GridFunction%s defined on the mesh. */
void UniformRefinement(int ref_algo = 0);
/** Refine selected mesh elements. Refinement type can be specified for each
element. The function can do conforming refinement of triangles and
tetrahedra and non-conforming refinement (i.e., with hanging-nodes) of
triangles, quadrilaterals and hexahedra. If 'nonconforming' = -1,
suitable refinement method is selected automatically (namely, conforming
refinement for triangles). Use nonconforming = 0/1 to force the method.
For nonconforming refinements, nc_limit optionally specifies the maximum
level of hanging nodes (unlimited by default). */
void GeneralRefinement(const Array<Refinement> &refinements,
int nonconforming = -1, int nc_limit = 0);
/** Simplified version of GeneralRefinement taking a simple list of elements
to refine, without refinement types. */
void GeneralRefinement(const Array<int> &el_to_refine,
int nonconforming = -1, int nc_limit = 0);
/// Refine each element with given probability. Uses GeneralRefinement.
void RandomRefinement(double prob, bool aniso = false,
int nonconforming = -1, int nc_limit = 0);
/// Refine elements sharing the specified vertex. Uses GeneralRefinement.
void RefineAtVertex(const Vertex& vert,
double eps = 0.0, int nonconforming = -1);
/** Refine element i if elem_error[i] > threshold, for all i.
Returns true if at least one element was refined, false otherwise. */
bool RefineByError(const Array<double> &elem_error, double threshold,
int nonconforming = -1, int nc_limit = 0);
/** Refine element i if elem_error(i) > threshold, for all i.
Returns true if at least one element was refined, false otherwise. */
bool RefineByError(const Vector &elem_error, double threshold,
int nonconforming = -1, int nc_limit = 0);
/** Derefine the mesh based on an error measure associated with each
element. A derefinement is performed if the sum of errors of its fine
elements is smaller than 'threshold'. If 'nc_limit' > 0, derefinements
that would increase the maximum level of hanging nodes of the mesh are
skipped. Returns true if the mesh changed, false otherwise. */
bool DerefineByError(Array<double> &elem_error, double threshold,
int nc_limit = 0, int op = 1);
/// Same as DerefineByError for an error vector.
bool DerefineByError(const Vector &elem_error, double threshold,
int nc_limit = 0, int op = 1);
///@{ @name NURBS mesh refinement methods
void KnotInsert(Array<KnotVector *> &kv);
void KnotInsert(Array<Vector *> &kv);
/* For each knot vector:
new_degree = max(old_degree, min(old_degree + rel_degree, degree)). */
void DegreeElevate(int rel_degree, int degree = 16);
///@}
/** Make sure that a quad/hex mesh is considered to be non-conforming (i.e.,
has an associated NCMesh object). Simplex meshes can be both conforming
(default) or non-conforming. */
void EnsureNCMesh(bool simplices_nonconforming = false);
bool Conforming() const { return ncmesh == NULL; }
bool Nonconforming() const { return ncmesh != NULL; }
/** Return fine element transformations following a mesh refinement.
Space uses this to construct a global interpolation matrix. */
const CoarseFineTransformations &GetRefinementTransforms();
/// Return type of last modification of the mesh.
Operation GetLastOperation() const { return last_operation; }
/** Return update counter. The counter starts at zero and is incremented
each time refinement, derefinement, or rebalancing method is called.
It is used for checking proper sequence of Space:: and GridFunction::
Update() calls. */
long GetSequence() const { return sequence; }
/// Print the mesh to the given stream using Netgen/Truegrid format.
virtual void PrintXG(std::ostream &out = mfem::out) const;
/// Print the mesh to the given stream using the default MFEM mesh format.
/// \see mfem::ofgzstream() for on-the-fly compression of ascii outputs
virtual void Print(std::ostream &out = mfem::out) const { Printer(out); }
/// Print the mesh to the given stream using the adios2 bp format
#ifdef MFEM_USE_ADIOS2
virtual void Print(adios2stream &out) const;
#endif
/// Print the mesh in VTK format (linear and quadratic meshes only).
/// \see mfem::ofgzstream() for on-the-fly compression of ascii outputs
void PrintVTK(std::ostream &out);
/** Print the mesh in VTK format. The parameter ref > 0 specifies an element
subdivision number (useful for high order fields and curved meshes).
If the optional field_data is set, we also add a FIELD section in the
beginning of the file with additional dataset information. */
/// \see mfem::ofgzstream() for on-the-fly compression of ascii outputs
void PrintVTK(std::ostream &out, int ref, int field_data=0);
/** Print the mesh in VTU format. The parameter ref > 0 specifies an element
subdivision number (useful for high order fields and curved meshes). */
void PrintVTU(std::ostream &out,
int ref=1,
VTKFormat format=VTKFormat::ASCII,
bool high_order_output=false,
int compression_level=0);
/** Print the mesh in VTU format with file name fname. */
void PrintVTU(std::string fname,
VTKFormat format=VTKFormat::ASCII,
bool high_order_output=false,
int compression_level=0);
void GetElementColoring(Array<int> &colors, int el0 = 0);
/** @brief Prints the mesh with boundary elements given by the boundary of
the subdomains, so that the boundary of subdomain i has boundary
attribute i+1. */
/// \see mfem::ofgzstream() for on-the-fly compression of ascii outputs
void PrintWithPartitioning (int *partitioning,
std::ostream &out, int elem_attr = 0) const;
void PrintElementsWithPartitioning (int *partitioning,
std::ostream &out,
int interior_faces = 0);
/// Print set of disjoint surfaces:
/*!
* If Aface_face(i,j) != 0, print face j as a boundary
* element with attribute i+1.
*/
void PrintSurfaces(const Table &Aface_face, std::ostream &out) const;
void ScaleSubdomains (double sf);
void ScaleElements (double sf);
void Transform(void (*f)(const Vector&, Vector&));
void Transform(VectorCoefficient &deformation);
/// Remove unused vertices and rebuild mesh connectivity.
void RemoveUnusedVertices();
/** Remove boundary elements that lie in the interior of the mesh, i.e. that
have two adjacent faces in 3D, or edges in 2D. */
void RemoveInternalBoundaries();
/** @brief Get the size of the i-th element relative to the perfect
reference element. */
double GetElementSize(int i, int type = 0);
double GetElementSize(int i, const Vector &dir);
double GetElementVolume(int i);
void GetElementCenter(int i, Vector &center);
/// Returns the minimum and maximum corners of the mesh bounding box.
/** For high-order meshes, the geometry is first refined @a ref times. */
void GetBoundingBox(Vector &min, Vector &max, int ref = 2);
void GetCharacteristics(double &h_min, double &h_max,
double &kappa_min, double &kappa_max,
Vector *Vh = NULL, Vector *Vk = NULL);
/// Auxiliary method used by PrintCharacteristics().
/** It is also used in the `mesh-explorer` miniapp. */
static void PrintElementsByGeometry(int dim,
const Array<int> &num_elems_by_geom,
std::ostream &out);
/** @brief Compute and print mesh characteristics such as number of vertices,
number of elements, number of boundary elements, minimal and maximal
element sizes, minimal and maximal element aspect ratios, etc. */
/** If @a Vh or @a Vk are not NULL, return the element sizes and aspect
ratios for all elements in the given Vector%s. */
void PrintCharacteristics(Vector *Vh = NULL, Vector *Vk = NULL,
std::ostream &out = mfem::out);
/** @brief In serial, this method calls PrintCharacteristics(). In parallel,
additional information about the parallel decomposition is also printed.
*/
virtual void PrintInfo(std::ostream &out = mfem::out)
{
PrintCharacteristics(NULL, NULL, out);
}
void MesquiteSmooth(const int mesquite_option = 0);
/** @brief Find the ids of the elements that contain the given points, and
their corresponding reference coordinates.
The DenseMatrix @a point_mat describes the given points - one point for
each column; it should have SpaceDimension() rows.
The InverseElementTransformation object, @a inv_trans, is used to attempt
the element transformation inversion. If NULL pointer is given, the
method will use a default constructed InverseElementTransformation. Note
that the algorithms in the base class InverseElementTransformation can be
completely overwritten by deriving custom classes that override the
Transform() method.
If no element is found for the i-th point, elem_ids[i] is set to -1.
In the ParMesh implementation, the @a point_mat is expected to be the
same on all ranks. If the i-th point is found by multiple ranks, only one
of them will mark that point as found, i.e. set its elem_ids[i] to a
non-negative number; the other ranks will set their elem_ids[i] to -2 to
indicate that the point was found but assigned to another rank.
@returns The total number of points that were found.
@note This method is not 100 percent reliable, i.e. it is not guaranteed
to find a point, even if it lies inside a mesh element. */
virtual int FindPoints(DenseMatrix& point_mat, Array<int>& elem_ids,
Array<IntegrationPoint>& ips, bool warn = true,
InverseElementTransformation *inv_trans = NULL);
/// Destroys Mesh.
virtual ~Mesh() { DestroyPointers(); }
#ifdef MFEM_DEBUG
/// Output an NCMesh-compatible debug dump.
void DebugDump(std::ostream &out) const;
#endif
};
/** Overload operator<< for std::ostream and Mesh; valid also for the derived
class ParMesh */
std::ostream &operator<<(std::ostream &out, const Mesh &mesh);
/** @brief Structure for storing mesh geometric factors: coordinates, Jacobians,
and determinants of the Jacobians. */
/** Typically objects of this type are constructed and owned by objects of class
Mesh. See Mesh::GetGeometricFactors(). */
class GeometricFactors
{
public:
const Mesh *mesh;
const IntegrationRule *IntRule;
int computed_factors;
enum FactorFlags
{
COORDINATES = 1 << 0,
JACOBIANS = 1 << 1,
DETERMINANTS = 1 << 2,
};
GeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags);
/// Mapped (physical) coordinates of all quadrature points.
/** This array uses a column-major layout with dimensions (NQ x SDIM x NE)
where
- NQ = number of quadrature points per element,
- SDIM = space dimension of the mesh = mesh.SpaceDimension(), and
- NE = number of elements in the mesh. */
Vector X;
/// Jacobians of the element transformations at all quadrature points.
/** This array uses a column-major layout with dimensions (NQ x SDIM x DIM x
NE) where
- NQ = number of quadrature points per element,
- SDIM = space dimension of the mesh = mesh.SpaceDimension(),
- DIM = dimension of the mesh = mesh.Dimension(), and
- NE = number of elements in the mesh. */
Vector J;
/// Determinants of the Jacobians at all quadrature points.
/** This array uses a column-major layout with dimensions (NQ x NE) where
- NQ = number of quadrature points per element, and
- NE = number of elements in the mesh. */
Vector detJ;
};
/** @brief Structure for storing face geometric factors: coordinates, Jacobians,
determinants of the Jacobians, and normal vectors. */
/** Typically objects of this type are constructed and owned by objects of class
Mesh. See Mesh::GetFaceGeometricFactors(). */
class FaceGeometricFactors
{
public:
const Mesh *mesh;
const IntegrationRule *IntRule;
int computed_factors;
FaceType type;
enum FactorFlags
{
COORDINATES = 1 << 0,
JACOBIANS = 1 << 1,
DETERMINANTS = 1 << 2,
NORMALS = 1 << 3,
};
FaceGeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags,
FaceType type);
/// Mapped (physical) coordinates of all quadrature points.
/** This array uses a column-major layout with dimensions (NQ x SDIM x NF)
where
- NQ = number of quadrature points per face,
- SDIM = space dimension of the mesh = mesh.SpaceDimension(), and
- NF = number of faces in the mesh. */
Vector X;
/// Jacobians of the element transformations at all quadrature points.
/** This array uses a column-major layout with dimensions (NQ x SDIM x DIM x
NF) where
- NQ = number of quadrature points per face,
- SDIM = space dimension of the mesh = mesh.SpaceDimension(),
- DIM = dimension of the mesh = mesh.Dimension(), and
- NF = number of faces in the mesh. */
Vector J;
/// Determinants of the Jacobians at all quadrature points.
/** This array uses a column-major layout with dimensions (NQ x NF) where
- NQ = number of quadrature points per face, and
- NF = number of faces in the mesh. */
Vector detJ;
/// Normals at all quadrature points.
/** This array uses a column-major layout with dimensions (NQ x DIM x NF) where
- NQ = number of quadrature points per face,
- SDIM = space dimension of the mesh = mesh.SpaceDimension(), and
- NF = number of faces in the mesh. */
Vector normal;
};
/// Class used to extrude the nodes of a mesh
class NodeExtrudeCoefficient : public VectorCoefficient
{
private:
int n, layer;
double p[2], s;
Vector tip;
public:
NodeExtrudeCoefficient(const int dim, const int _n, const double _s);
void SetLayer(const int l) { layer = l; }
using VectorCoefficient::Eval;
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
virtual ~NodeExtrudeCoefficient() { }
};
/// Extrude a 1D mesh
Mesh *Extrude1D(Mesh *mesh, const int ny, const double sy,
const bool closed = false);
/// Extrude a 2D mesh
Mesh *Extrude2D(Mesh *mesh, const int nz, const double sz);
// shift cyclically 3 integers left-to-right
inline void ShiftRight(int &a, int &b, int &c)
{
int t = a;
a = c; c = b; b = t;
}
}
#endif