Next Article in Journal
Thermal Effusivity Tester (TET)—A New Device to Determine Thermal Effusivity of Textiles
Previous Article in Journal
Implementation of Machine Learning and Deep Learning Techniques for the Detection of Epileptic Seizures Using Intracranial Electroencephalography
 
 
Font Type:
Arial Georgia Verdana
Font Size:
Aa Aa Aa
Line Spacing:
Column Width:
Background:
Article

GTMesh: A Highly Efficient C++ Template Library for Numerical Schemes on General Topology Meshes

Department of Mathematics, Faculty of Nuclear Science and Physical Engineering, Czech Technical University in Prague, Trojanova 13, 120 00 Praha 2, Czech Republic
*
Author to whom correspondence should be addressed.
Appl. Sci. 2023, 13(15), 8748; https://doi.org/10.3390/app13158748
Submission received: 13 May 2023 / Revised: 13 July 2023 / Accepted: 24 July 2023 / Published: 28 July 2023
(This article belongs to the Topic Software Engineering and Applications)

Abstract

:
This article introduces GTMesh, an open-source C++ library providing data structures and algorithms that facilitate the development of numerical schemes on general polytopal meshes. After discussing the features and limitations of the existing open-source alternatives, we focus on the theoretical description of geometry and the topology of conforming polytopal meshes in an arbitrary-dimensional space, using elements from graph theory. The data structure for mesh representation is explained. The main part of the article focuses on the implementation of data structures and algorithms (computation of measures, centers, normals, cell coloring) by using State-of-the-Art template metaprogramming techniques for maximum performance. The geometrical algorithms are designed to be valid regardless of the dimension of the underlying space. As an integral part of the library, a template implementation of class reflection in C++ has been created, which is sufficiently versatile and suitable for the development of numerical and data I/O algorithms working with generic data types. Finally, the use of GTMesh is demonstrated on a simple example of solving the heat equation by the finite volume method.

1. Introduction

Numerical algorithms for the solution of problems for partial differential equations often rely on meshes covering the computational domain. The prominent representatives of mesh-based methods are the finite element method (FEM) [1,2,3,4] and the finite volume method (FVM) [5,6,7]. In order to tackle domains with nontrivial geometries, efficient tools for unstructured mesh representation and manipulation are needed. In particular, using general polygonal or polyhedral meshes comprising a relatively small number of highly complex cells can be beneficial in several situations.
Using FVM to solve problems involving, e.g., reacting multiphase flows [8,9], the number of necessary evaluations of computationally costly terms in the governing equations can be reduced by using polyhedral meshes. In the CFD domain, the properties of polyhedral meshes and their possible advantages, in terms of convergence rate and computational costs, have recently started to be investigated systematically [10,11,12,13], and their support is available in popular packages, such as ANSYS Fluent, OpenFOAM [14] or AVL FIRE. Efficient finite volume schemes, specifically tailored to polyhedral meshes, are in active development [15,16].
FEM traditionally uses tetrahedral or hexahedral meshes (in 3D). However, FEM has recently been successfully generalized to meshes of convex polyhedrons, which has brought about significant advantages [17,18,19,20]. Their applications also extend to computer graphics [21].
For developers of numerical codes, several open-source projects offer mesh handling support, but none of them can provide the complete set of features required by high-performance parallel FVM and FEM codes. Notable examples are outlined below:
  • OpenMesh [22] is aimed at applications in computer graphics, and provides tools for mesh modification. However, it only supports polygonal meshes for the representation of surfaces in 3D.
  • PUMI (Parallel Unstructured Mesh Infrastructure) [23] is a complex library supporting distributed mesh storage and processing via MPI [24]. By default, the mesh representation by means of the MDS (Mesh Data Structure) submodule only accepts a limited set of topological types known a priori at compile time, in order to achieve high performance.
  • ViennaGrid [25] is a modern library leveraging the concepts of template metaprogramming and iterators available in C++. It provides data structures for arbitrary-dimensional meshes and also a number of specialized data types and mesh algorithms that are often limited to certain dimensions or mesh types.
  • MOAB (Mesh-Oriented datABase) [26] is an extensive library that allows general topology meshes and supports mesh refinement, decomposition, parallel I/O and other features. Despite being written in C++, it does not take advantage of templates, and its performance has been shown to be relatively poor when processing polyhedral meshes [27]. MOAB always represents mesh geometry in a 3D coordinate system.
  • DUNE (Distributed and Unified Numerics Environment) [28] is a framework for numerical computations primarily (but not exclusively) aimed at FEM. It is a mature and very complex project with incomplete documentation, which also supports general topology meshes.
  • TNL (Template Numerical Library) [29] is a dynamically evolving framework for implementing efficient numerical algorithms in C++, taking advantage of State-of-the-Art C++ programming paradigms and exposing both CPU and GPU programming through a unified interface. Recently, support for general topology polytopal meshes [27] has been added.
With all the above in mind, we introduce GTMesh, a library created to facilitate rapid development of numerical schemes and data postprocessing algorithms on general polytopal meshes in an arbitrary dimension. GTMesh is implemented as a modern C++ header-only library (compliant with the C++14 standard [30]). GTMesh makes extensive use of template metaprogramming, together with advanced concepts, such as SFINAE [31], on account of which it can provide generic data structures and mesh algorithms that compile for the desired use case and provide maximum run time performance. Using GTMesh, it is possible to write the dimension-agnostic code of a complete numerical solver, including the numerical scheme, the data association with the mesh and the data I/O. The dimension of the problem is then specified as a template parameter at a single point in the code. Currently, GTMesh is a relatively small open-source project, which is publicly available, together with introductory documentation (see Data Availability Statement at the end).
This paper serves as an introduction to the concepts used in GTMesh. In Section 2, the theoretical description of general topology meshes in R d , d N , is laid out. Section 3 presents the general data structure for the mesh representation used in this project. The implementation details are explained in Section 4, including the data structures (Section 4.1 and Section 4.2) and the mesh algorithms (Section 4.3). In this section, the ideas are often presented in the context of FVM schemes. For simplicity, geometrical considerations are demonstrated on 2D polygons or 3D polyhedra, despite the possibility of generalization into R d , d > 3 . Section 5 is devoted to a useful concept of class reflection, which finds utility in generic numerical and data I/O algorithms. Its implementation is based on original ideas combining C++ class templates and preprocessor macros, in order to create a transparent and comfortable interface for the user. Finally, a simple example program that solves heat conduction in 3D, by the FVM scheme, is demonstrated in Section 6.

2. Geometry and Topology of Unstructured Meshes

The following definitions are motivated by meshing computational domains for the purpose of finite volume schemes. For an arbitrary set, S R d , denoted by m S , the d-dimensional Lebesgue measure of S, and by m ˜ S , the d 1 -dimensional Hausdorff measure of S.
Definition 1.
Let the spatial domain Ω be a bounded polytope in R d , d N . Let T be a set of polytopal cells, and denote by E the set of all faces that constitute the boundaries of all elements of T . T is called a d-dimensional conforming mesh on Ω, if the following properties are satisfied:
  • K T K ¯ = Ω ¯ .
  • K T E K E K = σ E K σ ¯ .
  • K , L T K L m ˜ K ¯ L ¯ = 0 σ E σ = K ¯ L ¯ .
Next, we introduce the notation for the sets of elements of different dimensions that form the geometry of the mesh. For example, in a 3D mesh, the boundaries of the 3D cells consist of 2D faces, which in turn represent flat surfaces bounded by 1D edges, which in turn span between their two 0D vertices. In order to avoid confusion with the notion of element in FEM, these objects are also called entities [27].
Definition 2.
Let  T be a d-dimensional mesh, where  d N . The set of elements of dimension  k 0 , 1 , , d is denoted by  T k . N T k = T k is the number of elements of dimension k in T . Finally, the complete system of geometrical elements is defined as
T * = k = 0 d T k .
By Definition 2, we have E = T d 1 . In terms of the mutual inclusion of elements of various dimensions, we define the relation of connection on T * :
Definition 3.
e , f T * are connected ⟺ e f ¯ f e ¯ .
An example of mesh connections can be seen in Figure 1.
Figure 1. Example of connections in a simple 2D mesh. Vertices connected to element c 1 are v 3 , v 2 , v 4 . The cells connected to element v 1 are c 1 , c 2 .
Figure 1. Example of connections in a simple 2D mesh. Vertices connected to element c 1 are v 3 , v 2 , v 4 . The cells connected to element v 1 are c 1 , c 2 .
Applsci 13 08748 g001
In a similar intuitive way, the neighborhood of elements is defined:
Definition 4.
Let  e T * . Then, the neighborhood of e is defined as
N e = e T * e is connected to e .
Moreover, we denote the subset of the connected elements with the given dimension  k 0 , 1 , , d as
N k e = N e T k .

Graph Description of a General Topology Mesh

All connections in the mesh can be represented by means of a graph  G T * = ( V T * , E T * ) , where the vertices of the graph match the elements of the mesh, and where the edges of the graph correspond to the connections between them. The vertices  V T * of  G T * are grouped into layers by dimensions of elements:
V T * T * = T 0 T 1 T d ;
V T * k T k .
The edges of  G T * are defined as
E T * = e , e V T * 2 e , e are connected .
For an example, see Figure 2.
The graph  G T * contains all information about the topology of the mesh. As the connection of elements is a symmetrical relation, the graph  G T * is de facto undirected, i.e.,  e , e E T * e , e E T * e , e V T * . Additionally, for a simpler description of the connections, i.e., of the graph edges, we denote a subset of graph edges from dimension  d 1 to dimension  d 2 as
E T * d 1 , d 2 = e , e E T * e V T * d 1 , e V T * d 2 .
Definition 5.
Let  G = V , E be a graph. The adjacency matrix of the graph G is matrix  A G R V × V , defined as
A G i j = 1 if v i , v j E , 0 if v i , v j E ,
where  i ,   j V v i ,   v j V .
Furthermore, to investigate certain types of connections and properties of the graph mesh representation, we introduce the idea of a connection matrix, closely related to the adjacency matrix. The connection matrix from dimension  d 1 to dimension  d 2 reads
A G T * d 1 , d 2 i j = 1 if v i , v j E , v i V T * d 1 , v j V T * d 2 , 0 if v i , v j E , v i V T * d 1 , v j V T * d 2 , ,
where  A G T * d 1 , d 2 R N T d 1 × N T d 2 . The connection matrix is a rectangular block of  A G T * .
The primary aim of the data structure representing any unstructured mesh is to store all connections of the elements in the mesh. Equivalently, it must contain enough information for the reconstruction of the whole G T * . The graph is fully described by its adjacency matrix. Due to certain properties of the adjacency matrix of G T * , it is possible to reduce the amount of connections stored. First, it holds that
A G T * d 1 , d 2 T = A G T * d 2 , d 1 ,
where the A G T * d 1 , d 2 0 , 1 V T * d 1 × V T * d 2 is a rectangular submatrix of A G T * reflecting the connections from T d 1 to T d 2 . The second property is the dependence between adjacency matrices between specified dimensions. The relation reads
A G T * d 1 , d 2 i j = connect A G T * d 1 , d 3 , A G T * d 3 , d 2 = 1 if k 1 , 2 , , N T * d 3 A G T * d 1 , d 3 i k A G T * d 3 , d 2 k j = 1 , 0 else ,
where the dimensions  d 1 , d 2 , d 3 satisfy  d 1 > d 3 > d 2 d 1 < d 3 < d 2 . In other words, the Formula (8) represents the chaining of the connections in the graph. The condition for the dimensions of the connection matrices consists in finding the correct paths in the graph that are consistent with the mesh topology.

3. Abstract Data Structure for Mesh Representation in R d

This section describes the system of connections used in this work for storing an unstructured mesh with general topology and dimensions.
According to (7) and (8), it is necessary to store either connections from  V T * k to  V T * k 1 or from  V T * k 1 to  V T * k , because those connections cannot be correctly obtained otherwise. Therefore, we introduce a basic data structure as a sub-system of connections suitable to represent any unstructured mesh in any dimension. Let us first consider the case d = 3 . The chosen data structure in 3D stores the connections
E T * * = E T * * 3 , 2 E T * * 2 , 2 E T * 2 , 3 E T * 2 , 1 E T * 1 , 0 ,
where the E T * * 3 , 2 and E T * * 2 , 2 are auxiliary connections enabling direct iteration over cell boundaries. The E T * * 3 , 2 are pointers from each cell to one of its faces, while the references E T * * 2 , 2 are between the faces, and they connect the faces making up the boundary of each single cell. Other connections are defined according to Equation (4). For better understanding of the connections between the elements, see Figure 3 presenting connections in a 3D mesh.
This concept is extensible to any dimension. The formula describing the system of connections stored in d-dimensional unstructured mesh is
E T * * = E T * * d , d 1 E T * * d 1 , d 1 E T * d 1 , d E T * d 1 , d 2 E T * 2 , 1 E T * 1 , 0 .
The system of connections E T * * is presented in Figure 4.

4. The GTMesh Library

The GTMesh library is a C++ project designed for efficient work with polytopal meshes. In order to achieve both user friendliness and computational efficiency, it utilizes modern C++ paradigms. The architecture of GTMesh aims at maintainability and extensibility, using, e.g., the open–closed principle [32].
From the construction point of view, the internal structure of the mesh storing the chosen system of connections (10) is very similar to formats of sparse matrices. However, the structures representing elements are designed to be more convenient for the user.
The library provides commonly used mesh algorithms determining, e.g., connections between elements of any desired dimensions, neighborhood of elements, measures of all elements of a mesh of an arbitrary dimension and normals to cell faces.
The architecture of GTMesh is split into four main parts:
  • storing the mesh topology;
  • associating data with the mesh;
  • calculating various properties of the mesh;
  • exporting and importing mesh-related data.
The construction parts of GTMesh are described in the following sections. Section 4.1 discusses the structure storing the mesh topology. Section 4.2 presents the system of data mapping to the mesh. This data mapping system significantly contributes to the user friendliness of GTMesh. Next, the auxiliary functions for calculating, e.g., elements centers and measures are described in Section 4.3. Section 5 describes a unique system of class reflection, developed to automate basic operations with C++ structures or classes such as serialization, deserialization or arithmetical operations. This concept improves the development efficiency, as it reduces the amount of routine work on data interface coding.

4.1. Mesh Data Structure

The complete C++ data structure storing a mesh consists of arrays containing the mesh elements. The representation of a mesh element is to be understood as a simple C++ data structure containing the respective references from (10). An example for the dimension d = 3 is depicted in Figure 5. In addition, the structures for cells and faces contain two auxiliary data elements: center (see Section 4.3) and flag.
The elements are collected in a data structure called MeshElements, which is de facto the unstructured mesh itself. Due to the template implementation of the mesh element data structure, it is possible to automatically generate the system of elements based on the template arguments, i.e., only one definition of the MeshElements class is required, e.g., for definitions of 2D or 3D mesh. The dimension of the mesh is given by a template parameter.
Additionally, it is possible to prescribe the maximum number of sub-elements of faces and other elements which have references represented by blue arrows in Figure 4. This number is called Reserve. When Reserve is defined, it is possible to embed the references directly into the corresponding mesh element data structure, avoiding dynamic memory allocation. For example, when the number of sub-elements of faces in a 3D mesh is prescribed to three, the stored mesh can only have triangular faces. Note that, due to the chosen representation, the number of faces of one cell is unlimited in any dimension.

4.2. Associating Data with the Mesh

Any numerical method for solving a system of partial differential equations on a domain tessellated by the mesh needs to store data associated with the individual mesh elements. The data can represent the values of the solution, auxiliary pre-calculated space-dependent quantities or implementation-specific storage for intermediate results. The purpose (and hence the type) of data associated with mesh elements is specific to their dimension. For example, finite volume methods use solution values for the computationally significant elements, i.e., cell centers, cell faces or both. However, additional data storage may be allocated, for each vertex to hold the results of intermediate calculations.
GTMesh provides a data container, named MeshDataContainer, to conveniently store data associated with mesh elements. Once the mesh geometry and topology has been provided, MeshDataContainer provides a flexible interface for allocating and accessing the mesh-associated data. In the most generic case, a single instance of MeshDataContainer is capable of holding data represented by types  T 1 T 2 , …,  T n associated with all mesh elements of dimensions  d 1 d 2 , …,  d n , respectively. The dimensions specifiers ( d 1 d 2 , …,  d n ) need not be unique, i.e., there can be more than one data type associated with elements of the given dimension.
Internally, MeshDataContainer contains n arrays with interfaces similar to std::vector< T 1 >std::vector< T n >. For each  i 1 , , n , the length of the vector is the same as the number of mesh elements of dimension  d i .
The vectors within MeshDataContainer can be addressed in two ways:
  • By position i of the dimension  d i within the ordered list ( d 1 d 2 , …,  d n );
  • By dimension d. In this case, the ith vector is returned, where i is the first integer in the sequence ( 1 , 2 , , n ), such that  d i = d .
In addition, the data within MeshDataContainer can also be indexed directly by the instances of MeshElement, i.e., the MeshDataContainer provides a subscript operator for instances of the MeshElement class (see Listing 1). This establishes a mapping between mesh elements and data instances. The data vector in MeshDataContainer is given by the dimension of the mesh element (by using the rule explained above). The component of the vector is given by element dimension and index, present in every MeshElement data structure.
Listing 1. Presentation of the usage of the MeshDataContainer class. The data container allocates four different data types to dimensions of the mesh. Upon construction, the MeshDataContainer class allocates data according to the dimensions of the provided mesh. Then, the example presents the possibility of accessing data, using elements of the mesh or the underlying data collections, by explicitly specifying the dimension or position template parameter.
Listing 1. Presentation of the usage of the MeshDataContainer class. The data container allocates four different data types to dimensions of the mesh. Upon construction, the MeshDataContainer class allocates data according to the dimensions of the provided mesh. Then, the example presents the possibility of accessing data, using elements of the mesh or the underlying data collections, by explicitly specifying the dimension or position template parameter.
Applsci 13 08748 i001

4.3. Algorithms

This section presents mesh algorithms provided by the GTMesh library. Each algorithm is implemented in a member function of a separate class template. The respective member function accepts a reference to a MeshElements instance as a parameter: thus, the set of functions may be extended without modifying the MeshElements structure. Therefore, the data structures presented in Section 4.1 do not have any calculation methods, in contrast to, e.g., OpenFOAM [14]. Generally, each external function aims to calculate the respective property for the whole mesh at once, e.g., calculating measures of all elements (of all dimensions) in the mesh. Note that function templates cannot generally be used for this purpose instead of class templates, as C++ does not support partial specialization of function templates. Whenever possible, the functionality of the respective class is wrapped in a function template, to simplify the user interface.

4.3.1. Iteration Over Mesh Structure

The first realized algorithm, MeshApply::apply(), provides a unified approach to iterating the connections in the mesh (i.e., MeshElements) according to Figure 4: for example, it is able to perform an operation for each vertex (target element dimension) connected to a cell (source element dimension), which would require three nested loops. The dimensions of the source and target elements are prescribed by template parameters StartDim and TargetDim. The operation to be performed is provided by a reference to a callable object (e.g., lambda function, function pointer).
This functionality guarantees that the desired operation will be performed with the indices of each element of the source element dimension and all the elements of the target element dimension connected to it. However, it is not guaranteed that the function will be called exactly once for each pair of elements: if this is a concern, multiple calls have to be handled by the user-defined algorithm itself.
Due to the symmetry of the connection relation (Definition 3), the iterations where the target element dimension is higher than the source element dimension (e.g., loop over cells connected to vertices) can be realized by looping with swapped dimensions and by only providing the correct indices of the target and source elements. Hence, GTMesh is able to realize such loops, even though the connections from lower-dimension elements to the ones with higher dimension are not stored in memory.

4.3.2. Determining the Elements’ Connections

By means of MeshConnections::connections(), the connection matrix  A G T * d 1 , d 2 is calculated. The dimensions  d 1 , d 2 are given by the template parameters StartDim and TargetDim. The result is a MeshDataContainer mapping a vector of indices of the connected elements of the TargetDim dimension for each element of the StartDim dimension. For an example of using MeshConnections, see Listing 2. MeshConnections provides the functionality of the map “connect” introduced in Equation (8).
Listing 2. An example of using MeshConnections. The MeshConnections::connections() member function returns a MeshDataContainer, mapping to each element the indexes of the connected elements of the requested dimension. The sequence of indexes does not contain duplicities, and the connections can optionally be returned in ascending order.
Listing 2. An example of using MeshConnections. The MeshConnections::connections() member function returns a MeshDataContainer, mapping to each element the indexes of the connected elements of the requested dimension. The sequence of indexes does not contain duplicities, and the connections can optionally be returned in ascending order.
Applsci 13 08748 i002
Using MeshApply, the implementation of MeshConnections is very simple. The only problem to be solved is that the connected elements are visited more than once, because the function MeshApply does not care whether a connected element has already been visited. The solution consists of utilizing the standard template library class std::set, which prevents insertion of multiple keys (in our case, the element indexes).

4.3.3. Determining the Elements’ Neighborhood

MeshNeighborhood::neighbors() determines the neighborhood of elements. In terms of graph theory, the neighborhood of a vertex v is a set of graph vertices that are connected to v by an edge. We adapt the definition of neighborhood to respect the mesh geometry. This neighborhood is defined by two dimensions: the first is the connecting dimension  d 1 , and the second is the connected dimension  d 2 . For any element  e V T * d , the set of neighboring elements of dimension  d 2 connected by elements of dimension  d 1 reads
N G T * d 1 , d 2 e = f V T * d 2 g V T * d 1 g , f E T * g , e E T * e f ,
where  d , d 1 , d 2 0 , 1 , , d T . In the MeshNeighborhood class, the parameters d , d 1 , d 2 are named StartDim, ConnectingDim and ConnectedDim, respectively. This algorithm returns a vector of indices of neighboring elements according to (11) for each element of dimension d. If a broader neighborhood is needed, the neighborhoods of neighboring elements can be combined, using the std::set_union() function.

4.3.4. Calculation of Proper Coloring of a Mesh

The last of the algorithms related to graph representation of the mesh topology is the coloring algorithm ColorMesh::color(). The problem consists of the proper coloring of the elements of dimension d according to the connections of dimension  d 1  [33]. This algorithm can be used to advantage, to prevent race conditions during multi-threaded parallel computation.
The template parameters of the ColorMesh class are as follows:  d as ColoredDim; d 1 as ConnectingDim; and Method, to select one of the two supported coloring methods. The greedy method utilizes the first free color index when determining the color index for an element. Obviously, this approach may lead to uneven distribution of color indices in the mesh. If this turns out to be a limiting factor for parallel performance, random update strategy can be used instead: first, a proper coloring is obtained, using the greedy algorithm; then, a second phase is launched, which rebalances the color indices randomly, while still maintaining the proper coloring in each step.

4.3.5. Calculation of Element Centers

The previous algorithms work with the mesh as a topological object, i.e., they do not use the coordinates of vertices. Now, we will describe the algorithms that calculate some significant geometrical properties of the mesh. We begin with an algorithm calculating the center points of all objects in the mesh, which is crucial for implementing cell-centered FVM schemes.
The center of each element is calculated as an average of the positions of the centers of all the connected sub-elements. For example, the center of a cell is an average of the centers of the cell’s faces. The advantage of this approach is the reduction of the depth of iteration over the mesh (see the example of the algorithm in Figure 6). Because the algorithm uses the previously calculated values, the computation may speed up against the calculation of the center as the average of the positions of the connected vertices. For example, in the case of dimension d T = 2 , it is sufficient to visit the sub-elements of dimension 1. The scheme of the algorithm is as follows:
  • set the dimension  d = 1 ;
  • for all elements  e T d , calculate the center of e as  x e = 1 N d 1 e f N d 1 e x f by a loop over sub-elements of e;
  • if  d < d T then  d = d + 1 , and go to step 2; else, stop the algorithm and return the result.
Figure 6. An example of the algorithm for calculating the element centers in a simple 3D mesh. The center point of an element is calculated as an average of the center points of its sub-elements. For example, the cell center point denoted x c is the average of the centers of all connected faces, denoted x f i .
Figure 6. An example of the algorithm for calculating the element centers in a simple 3D mesh. The center point of an element is calculated as an average of the center points of its sub-elements. For example, the cell center point denoted x c is the average of the centers of all connected faces, denoted x f i .
Applsci 13 08748 g006
In a 2D mesh, this algorithm returns the same result as the average of the positions of the connected vertices. However, in a 3D mesh, the results of both algorithms may differ if there are faces with different numbers of vertices. The computeCenters() function calculates the centers of all elements in the mesh, using the algorithm presented above.

4.3.6. Calculation of Element Measures

The next algorithm calculates the Hausdorff measures of elements, with respect to their dimension 1 < d d T , where d T is the dimension of the mesh. We assume that every polytope e T d is a star domain, with respect to its center x e  [34]. For d > 1 , such polytopes can be subdivided into pyramids P e , e with (planar) bases formed by their sub-elements e T d 1 and a common top x e . An example of subdivision of an element into pyramids is presented in Figure 7. This can be expressed as
e = e N d 1 e P e , e
(see Definition 4). The d-dimensional Hausdorff measure of e is then given by
m e = e N d 1 e m P e , e .
Let us denote by  v the geometrical position of each vertex v T 0 . Then, the measure of the pyramid  P e , e reads
m P e , e = 1 d m e dist V e , x e ,
where  V e is a linear manifold of dimension  d 1 , containing the element  e , and   m e is the d 1 -dimensional measure of the pyramid base, calculated recursively by the same algorithm. To find the height of the pyramid dist V e , x e , the Gram–Schmidt process is applied to the system of linearly independent vectors:
v e , 2 v e , 1 , v e , 3 v e , 1 , , v e , d v e , 1 , x e v e , 1 ,
where v e , i T 0 e are unique vertices of e . Note that an element of dimension d 1 has at least d vertices. This results in an orthogonal system:
y 2 , y 3 , , y d , y ˜ ,
where the last vector, y ˜ , is not normalized. Finally, we calculate
dist V e , x e = y ˜ .
For d = 1 , the 1D measure (length) of an edge   e T 1 is calculated by
m e = v A v B ,
where  v A , v B = N 0 e .
The above algorithm is implemented by the computeMeasures() function, and it returns a MeshDataContainer with measures of all elements in the mesh (except vertices). The computeMeasures() function calculates the measures from lower dimensions to higher ones, and it utilizes, to advantage, the already-calculated measures of lower-dimensional elements. This function also supports the compensation for non-planar elements [35].
Figure 7. An example of the computation of a 2D Hausdorff measure of a polygonal element, e T 2 , and of a 3D measure of a polyhedron, e T 3 .
Figure 7. An example of the computation of a 2D Hausdorff measure of a polygonal element, e T 2 , and of a 3D measure of a polyhedron, e T 3 .
Applsci 13 08748 g007

4.3.7. Calculation of Face Normal Vectors

Another common operation is to calculate the outward-pointing normal vector n e to each face e N d T 1 e of each cell e T d T . After constructing the system of vectors (14) and applying the Gram–Schmidt process, to obtain (14), the normal vector is calculated as
n e = y ˜ y ˜ .
The function responsible for the calculation of normal vectors is computeFaceNormals(). This function calculates a normal vector for each face in the mesh. The calculated normal vector points from the right cell (CellRightIndex) to the left cell (CellLeftIndex) are given by the data structure.

4.3.8. Import and Export of the Mesh

GTMesh provides tools for importing and exporting the mesh and the data associated with the mesh. The supported formats are VTK [36] for 2D and 3D meshes and FPMA for 3D meshes. The loading of meshes is realized by the VTKMeshReader and FPMAMeshReader classes, which accept the dimension of the source mesh as a template parameter. Similarly, there are classes for exporting meshes to the respective formats, i.e., VTKMeshWriter and FPMAMeshWriter. As the export operation is expensive, both mesh writers support a caching mechanism. If a mesh with the same topology is exported repeatedly via the same writer instance, the previously cached data are used. Note that VTKMeshWriter needs to know the types of cells to be exported. This information is not stored in the mesh directly, but it can be obtained from the reader instance that loaded the mesh. If the cell type is identified as a generic polyhedron, the cell is tessellated into tetrahedrons constructed from cell center, face center and edge vertices.
Support for other popular formats used, e.g., by ANSYS Fluent or CFX can be added in future, by implementing the respective classes. In addition, the readily available conversion tools provided by OpenFOAM [14] have been successfully tested.

4.3.9. Import and Export of Mesh Data

As the FPMA format does not support storing data, the only currently supported mesh data export is to the VTK format. The classes responsible for reading and writing data associated with a mesh are VTKMeshDataReader and VTKMeshDataWriter. The aim is to export data in a format that can be directly visualized using, e.g., ParaView.
The VTKMeshDataWriter::writeToStream() member function accepts a reference to an std::ostream to which the data will be appended, MeshDataContainer, with data associated with cells and a VTKMeshWriter instance utilized to export the mesh, as it contains metadata related to the tessellation of cells. The data must have the I/O Traits defined (see Section 5 below), in order to be exported. If a cell tesselation is performed, the data associated with the original cell is exported for all the resulting tetrahedrons.
The VTKMeshDataReader::readFromStream() member function accepts an std::istream from which the data will be loaded and a MeshDataContainer instance with corresponding data types associated with cells in which to store the data. The data types must have I/O Traits defined, in order to be loaded. The data array is allocated according to the length of the loaded array, regardless of the size of the actual mesh.
GTMesh provides other tools for data analysis, especially the DBGVAR_JSON debugging macro defined in debug.h. This macro prints JSON-formatted logs into a .json file. This file can subsequently be analyzed by a number of readily available tools, e.g., using the features and scientific packages in the Python ecosystem.
Finally, GTMesh provides the BinarySerializer class to save/load raw data in binary form without any information loss due to rounding. This is useful for creating snapshots of a numerical simulation that can serve as starting points for later continued computation. The endianness is not guaranteed, and depends on the architecture of the host system.

4.4. The UnstructuredMesh Wrapper Class

As described in the project architecture (Section 4), GTMesh aims at providing a single compact class exposing both the mesh structure and the mesh algorithms by means of its member functions, to simplify the work with the mesh. This construction makes the work with the mesh much more convenient. This wrapper class is called UnstructuredMesh. It inherits the MeshElements class, and it has no further structure. The only purpose of UnstructuredMesh is to provide the algorithms from Section 4.3 as its public member functions. The provided functions are constructed with as few template parameters as possible, because most of the parameters of the mesh functions can be deduced from the setup of UnstructuredMesh. For example, the member function computeElementMeasures() has only one template parameter Method, because the rest of the parameters of the function computeMeasures() are deduced. An example of UnstructuredMesh wrapper usage is shown in Listing 3.
Listing 3. An example of use of the UnstructuredMesh wrapper class. This listing illustrates calculating mesh properties, exporting them into a VTK file and loading them back. The exported three quantities associated with the cells are coloring with respect to connections over vertices, center point and inverse measure of cells. The process of calculation of the exported properties illustrates the fundamental design of the function calculating the properties of the UnstructuredMesh object.
Listing 3. An example of use of the UnstructuredMesh wrapper class. This listing illustrates calculating mesh properties, exporting them into a VTK file and loading them back. The exported three quantities associated with the cells are coloring with respect to connections over vertices, center point and inverse measure of cells. The process of calculation of the exported properties illustrates the fundamental design of the function calculating the properties of the UnstructuredMesh object.
Applsci 13 08748 i003

5. Class Reflection in C++ Optimized for High-Performance Computing

As part of the GTMesh library, a support tool providing advanced reflection (introspection) of C++ structures and classes has been developed. In general, the aim of this tool is to provide a unified interface for data contained in user-defined structures or classes similar to std::tuple. As a result, the data members can be accessed based on an integer index resolved at compile time. As C++14 provides no direct way to introspect objects at run time or compile time, the data access mechanism has to be defined manually by the user. However, GTMesh provides tools that allow to do this in a single line of code.
The data accessed by this mechanism can be arbitrarily related to the data actually stored in the data structure, as demonstrated in Listing 4. Both real and “virtual” data members calculated from the actually stored data have names accessible at run time. In the context of numerical algorithms, this tool makes it possible to write generic code that implements the following functionalities:
  • Data stored in user-defined data structures can be exported/imported to/from VTK, JSON or binary formats.
  • Arithmetic or other mathematical operations (such as norm calculation) can be performed on the user-defined data structures.
As the above (and possibly other) use cases have different requirements, multiple reflections designed for different purposes can exist for a single class. The iteration over data members is done via static for loops, i.e., resolved at compile time by means of template function recursion. Hence, the generated code is as efficient as manually written code.
At the time of writing, there exist several other open-source projects that aim for data serialization and/or class reflection in C++. A very recent and elegant solution is Cista++ (https://cista.rocks),which implements class reflection with the help of C++17 structured bindings [37]. However, this approach suffers from substantial limitations that prevent using Cista++ with GTMesh: in particular, it does not allow data transformations to create “virtual” data members, and it only works with plain structures without constructors.

5.1. Member Access

A data member denotes any information calculated from the data stored in a data structure. Data members are obtained by their getter and are set by their setter functions. These functions might be arbitrary.
The first part of the architecture is the method for data access. This is realized by the MemberAccess template class with several template specializations. This class then provides a unified interface to getting and setting the member data values. MemberAccess may be constructed in different ways:
  • Member reference, i.e., &data_structure::member, which defines the get, constant get and set operations. These operations are, thus, accessing the member data directly.
  • Pair of getter and setter, where each of these may be a member function or global function (callable object, e.g., lambda function) accepting the data structure instance as a parameter.

5.2. Class Traits

The MemberAccess classes are then grouped in the Traits class template, which manages their association with the names of the data members. Traits has member functions returning the data accessed by MemberAccess based on an integer template parameter (see Listing 4).

5.3. Default Traits

In order for the algorithms in GTMesh to be able to access the class reflection functionalities, there has to be a standard mechanism of globally exposing Traits for the given user-defined data structures. The solution is based on the DefaultTraits class template, which accepts the reflected class as its template parameter. The generic declaration of DefaultTraits has no methods or parameters. Traits for a particular class are exposed by defining DefaultTraits template specialization with a single static member function getTraits(), which returns the corresponding Traits instance. From DefaultTraits, GTMesh derives DefaultIOTraits for mesh data I/O and DefaultArithmeticTraits for arithmetics (see Listing 5). Both of them inherit the DefaultTraits functionality, but a specialization of each template can be provided by the user. The SFINAE paradigm [31] is used to detect whether a particular class has the respective type of Traits defined.
Finally, to simplify the definition of default class traits, GTMesh offers several preprocessor macros expanding to the specializations of the above classes. For example, MAKE_DEFAULT_ATTRIBUTE_TRAITS expands to DefaultTraits, etc., with the expected static member functions and type definitions. As a result, the definition of the default class traits for a data structure requires a single line of code, as demonstrated in Listing 4.
Listing 4. Example of class reflection. There are two types of class traits defined for the Data class: the first is generic DefaultTraits, which is used as a fallback if a specific traits class is not defined; the other is DefaultIOTraits, which provides access to the primary members density and momentum of the class Data, whereas the DefaulIOTraits considers the Data class to consist of density and velocity, where velocity is calculated upon request from the primary members.
Listing 4. Example of class reflection. There are two types of class traits defined for the Data class: the first is generic DefaultTraits, which is used as a fallback if a specific traits class is not defined; the other is DefaultIOTraits, which provides access to the primary members density and momentum of the class Data, whereas the DefaulIOTraits considers the Data class to consist of density and velocity, where velocity is calculated upon request from the primary members.
Applsci 13 08748 i004
Listing 5. Example implementation of operator + for any type with DefaultArithmeticTraits or DefaultTraits defined, e.g., application of this operator on the data class from Listing 4 would sum up the density and momentum members. This approach allows us to define all common mathematical operations for the classes with traits defined. It is even possible to define maximum value among the members, if the members of the class are comparable.
Listing 5. Example implementation of operator + for any type with DefaultArithmeticTraits or DefaultTraits defined, e.g., application of this operator on the data class from Listing 4 would sum up the density and momentum members. This approach allows us to define all common mathematical operations for the classes with traits defined. It is even possible to define maximum value among the members, if the members of the class are comparable.
Applsci 13 08748 i005

5.4. Example of Use

By using the concept of class traits, it is possible to generalize complex computational methods to be independent of the data structures utilized by the solved problem, which simplifies their development and debugging. We demonstrate an implementation of a generic version of the fourth-order Runge–Kutta–Merson (RKM) solver, with adaptive time stepping for numerical integration of ordinary differential equation (ODE) systems [38].
Considering the ODE system in the form
x ˙ = f t , x ,
where the  x R N N N and  f : J × R N R N , the RKM solver works as presented in Algorithm 1:
Algorithm 1 Pseudo-code of the Runge–Kutta–Merson ODE solver [38].
1 τ = τ ini ; x τ = x ini τ ; t = T ini ;
2while( T ini t < T ini T ){
3   if ( T t < τ ) {
4      τ = T t );
5   }
6    K 1 = f t , x τ ;
7    K 2 = f t + τ 3 , x τ + τ 3 K 1 ;
8    K 3 = f t + τ 3 , x τ + τ 6 K 1 + K 2 ;
9    K 4 = f t + τ 2 , x τ + τ 8 K 1 + 3 K 3 ;
10    K 5 = f t + τ , x τ + τ 1 2 K 1 3 2 K 3 + 2 K 4 ;
11    ε =  max_element τ 3 0.2 K 1 0.9 K 3 + 0.8 K 4 0.1 K 5
12   if ( ε < τ ) {
13      x τ = x τ + τ 1 6 K 1 + K 5 + 2 3 K 4 ;
14      t = t + τ );
15     if ( ε ) == 0) continue;
16   }
17    τ = δ ε 0.2 · ω τ );
18}
The symbols used there are summarized in Table 1:
For more information, see [38,39]. This algorithm is utilized in the example application presented in Section 6 below. Finally, the implementation of the algorithm is illustrated in Listing 6.
Listing 6. Implementation of the Runge–Kutta–Merson [38] algorithm. This algorithm accepts an instance of Problem class, which has several properties, such as computational mesh, ResultType and mainly calculateRHS member function, which accepts MeshDataContainer associated with cells of the mesh of the problem and returns f t , x as defined in (17). The implementation relies on the fact that the ResultType data type has defined (e.g., by the arithmetic traits) arithmetical  operations.
Listing 6. Implementation of the Runge–Kutta–Merson [38] algorithm. This algorithm accepts an instance of Problem class, which has several properties, such as computational mesh, ResultType and mainly calculateRHS member function, which accepts MeshDataContainer associated with cells of the mesh of the problem and returns f t , x as defined in (17). The implementation relies on the fact that the ResultType data type has defined (e.g., by the arithmetic traits) arithmetical  operations.
Applsci 13 08748 i006

6. Example Application

To introduce GTMesh in action, and to provide a starting point for numerical solver development, an example application has been created (see Data Availability Statement). The numerical solution of the heat equation is demonstrated, using a finite volume scheme for spatial discretization, and using the RKM solver (see Algorithm 1) for temporal discretization. The algorithm works both with 2D and 3D meshes, and is provided in three variants, in terms of parallelization: single-threaded (Section 6.2); OpenMP utilizing graph coloring to avoid race conditions (Section 6.3); and OpenMP utilizing auxiliary computational data values to avoid race conditions (Section 4.2).

6.1. Problem Formulation and Discretization

Let Ω R d , d 2 , 3 be a bounded polyhedral domain and  J = 0 , T end be the time interval, where  T end is the final time. The evolution of temperature T in J ¯ × Ω ¯ is governed by the problem
T t = Δ T in J × Ω ,
T Ω = T wall on J × Ω ,
T t = 0 = T ini in Ω ,
where (18) is the heat equation (with heat conductivity equal to 1, for simplicity), (19) is a constant Dirichlet boundary condition and (20) is the initial condition. Given a mesh T covering Ω (recall Definition 1), we integrate (18) over each control volume K T , apply the Gauss–Green theorem and use FVM approximations to arrive at
K T t t , x d x = E K T t , x · n d S K T , = = = = = = = =
m K d T K d t t = σ E K m σ F K , σ K T ,
where:
  • T K is the approximation of T t , x K ;
  • F K , σ is the approximation of T t , y σ · n defined as
    F K , σ = T L T K x L x K σ = K ¯ L ¯ ,   L T , T wall T K y σ x K σ Ω ;
  • x K , x L are the centers of the volumes K, L, respectively;
  • y σ is the center of σ .
The semidiscrete scheme (22) represents a system of ODEs in the form (17), which is solved by the RKM solver described in Section 5.4.

6.2. Single-Threaded Version

The aim of the single-threaded application is to provide a general overview of the necessary steps related to the generic use of the GTMesh library. The application consists of two main parts: the RKMSolver() function and the HeatConductionProblem class. The HeatConductionProblem has three member functions:
  • loadMesh(), responsible for loading an unstructured mesh into the UnstructuredMesh structure mesh;
  • exportMeshAndData(), responsible for exporting the computational mesh together with the data;
  • calculateRHS(), responsible for calculating the right-hand side of (22), which is in the form (17). This function is called from within the RKMSolver() function.

6.3. OpenMP Multi-Threaded Version Using Graph Coloring

When using OpenMP for multi-threaded execution, the parallel version of the algorithm can take advantage of edge coloring (see Section 4.3). This approach requires the identification of the operations that access the same memory at the same time. In this particular problem, it is the addition or subtraction of the temperature delta, as shown on lines 37, 38 in Listing 7. Hence, the coloring has to be calculated for the edges, with respect to the connection to the cells. Then, iterating over the edges with the same color index eliminates the risk of accessing the same cell by multiple threads at the same time, because the edges with the same color do not share any cell. The corresponding logic is incorporated in the calculateRHS() function, which is called from within the parallel version of RKMSolver().
Listing 7. Implementation of the heat conduction equation, as introduced in (22). The defined problem object is then passed to RKMSolver(), depicted in Listing 6. Note the definition of class traits for the ComputationData class in line 4: due to this feature, the data can be serialized/deserialized to/from the VTK format. In addition, RKMSolver() can be applied to this problem, as the definition of all necessary arithmetical operations is guaranteed. Lines 55–58 demonstrate that the changes required for transition between 2D and 3D problems are minimal.
Listing 7. Implementation of the heat conduction equation, as introduced in (22). The defined problem object is then passed to RKMSolver(), depicted in Listing 6. Note the definition of class traits for the ComputationData class in line 4: due to this feature, the data can be serialized/deserialized to/from the VTK format. In addition, RKMSolver() can be applied to this problem, as the definition of all necessary arithmetical operations is guaranteed. Lines 55–58 demonstrate that the changes required for transition between 2D and 3D problems are minimal.
Applsci 13 08748 i007

6.4. OpenMP Multi-Threaded Version Using Auxiliary Data

This variant avoids race conditions in cell data access, by introducing auxiliary data structures storing temporary results. As discussed in Section 6.3, the risk of conflict occurs while adding deltas to cell data. Hence, this approach stores the deltas in an auxiliary data structure mapped to the edges. Then, in a separate parallel cycle, the deltas are summed over the cells’ boundaries.

7. Conclusions

GTMesh is a C++ library providing data structures and algorithms that facilitate the development of numerical schemes working with general polytopal meshes. In this paper, an overview of the features and design of GTMesh is presented. Aside from the software point of view, the description of general-topology polytopal meshes in arbitrary spatial dimensions is based on the elements of graph theory, which allow for devising the most suitable data structure for mesh representation.
From bottom to top, GTMesh is built upon template metaprogramming principles, using template recursion, specialization, SFINAE and other advanced techniques. Compared to the several alternative projects dealing with similar topics, we believe that GTMesh offers a unique combination of generality, simplicity, efficiency, innovation and elegance that could be beneficial for the developers of numerical software. In particular:
  • Despite being a relatively compact project, GTMesh provides the tools for developing complete numerical solvers in a dimension-agnostic manner.
  • The code generated by template instantiation for the particular situation is equivalent to a direct implementation with no additional overhead.
  • GTMesh not only includes data structures for arbitrary-dimensional meshes but also provides robust algorithms related to mesh geometry.
  • The implementation of class reflection in C++ using the Traits mechanism is sufficiently versatile and suitable for development of numerical and data I/O algorithms working with generic data types.
  • GTMesh algorithms provide support for multi-threaded (OpenMP) parallelization.
On the other hand, the current implementation of GTMesh has several limitations, in comparison to other much larger projects, such as PUMI, MOAB or TNL:
  • Only conforming meshes are supported. Other types of mesh topology, such as recursively refined non-conforming meshes based on quadtree/octree structures, would require a separate implementation.
  • GTMesh does not offer support for distributed computing. However, the architecture of GTMesh could be extended in this manner, without the need to redesign its core data structures.
  • The authors of GTMesh and this article also collaborate with the developers of TNL [29], opening up the possibility of introducing GPU support, which is currently missing. Some preliminary steps have already been made in this direction.
GTMesh is open-source. Its source code, the code of the sample solver presented in Section 6 and an introductory documentation are publicly available (see Data Availability Statement below). It has also been successfully utilized in the numerical solver for multiphase flow problems [40].

Author Contributions

Conceptualization, T.J. and P.S.; methodology, T.J. and P.S.; software, T.J.; validation, T.J. and P.S.; formal analysis, T.J. and P.S.; investigation, T.J. and P.S.; writing—original draft preparation, T.J. and P.S.; writing—review and editing, T.J. and P.S.; visualization, T.J. All authors have read and agreed to the published version of the manuscript.

Funding

This work has been supported by the projects Research Centre for Low-Carbon Energy Technologies (Reg. No. CZ.02.1.01/0.0/0.0/16_019/0000753) and Centre of Advanced Applied Sciences (Reg. No. CZ.02.1.01/0.0/0.0/16_019/0000778), co-financed by the European Union, and by Grant No. SGS23/188/OHK4/3T/14 of the Grant Agency of the Czech Technical University in Prague.

Institutional Review Board Statement

Not applicable.

Informed Consent Statement

Not applicable.

Data Availability Statement

The GTMesh library source code is publicly available under the MIT License at https://github.com/Tomas-Jakubec/GTMesh. The example application presented in Section 6 can be obtained from https://github.com/Tomas-Jakubec/GTMesh-examples. Basic documentation is readily available through the project website at GitHub. In addition, a more detailed explanation of GTMesh design is available in the master’s thesis [40] available for download at http://hdl.handle.net/10467/98466.

Conflicts of Interest

The authors declare no conflict of interest. The funders had no role in the following: the design of the study; the collection, analyses or interpretation of data; the writing of the manuscript; the decision to publish the results.

Nomenclature

 Important notation used throughout this manuscript:
A G adjacency matrix of the graph G (Definition 5)
A G T * d 1 , d 2 connection matrix of the graph G T * from dimension  d 1 to dimension  d 2
E a set of faces of all cells in the mesh T (Definition 1)
E K a set of faces constituting the boundary of K T (Definition 1)
E T * edges of G T * , given by (3)
E T * d 1 , d 2 a subset of edges of G T * from dimension  d 1 to dimension  d 2 , given by (4)
G T * graph representation of T *
J time interval (Section 6)
m S d-dimensional Lebesgue measure of S R d (Section 2)
m ˜ S d 1 -dimensional Hausdorff measure of S R d (Section 2)
N T k number of elements of dimension k 0 , 1 , , d in T *
N e neighborhood of the mesh element e T *
N k e elements with dimension k 0 , 1 , , d connected to e T *
N G T * d 1 , d 2 e set of neighbors of dimension  d 2 connected by elements of dim.  d 1 , given by (11)
Ω spatial domain discretized by the mesh T
T the mesh, i.e., the set of cells covering Ω (Definition 1)
T * the system of geometrical elements of T (Definition 2)
T k system of geometrical elements of T with dimension k (Definition 2)
Ttemperature (in the example problem in Section 6)
V T * vertices of G T * , given by (1)
x e geometrical center of the element e T *
   Acronyms used in this manuscript:
CFDComputational Fluid Dynamics
DUNEDistributed and Unified Numerics Environment [28]
FEMFinite Element Method
FVMFinite Volume Method
I/OInput/Output
JSONJavaScript Object Notation, a lightweight data-interchange format (www.json.org)
MOABMesh-Oriented datABase [26]
ODEOrdinary Differential Equation
OpenMPOpen Multi-Processing, a parallel programming API (www.openmp.org)
PUMIParallel Unstructured Mesh Infrastructure [23]
RKMRunge–Kutta–Merson, an ODE solver with adaptive time step [38]
SFINAESubstitution Failure Is Not An Error [31]
TNLTemplate Numerical Library [29]
VTKVisualization Toolkit [36]

References

  1. Johnson, C. Numerical Solution of Partial Differential Equations by the Finite Element Method; Cambridge University Press: Cambridge, UK, 1987. [Google Scholar]
  2. Szabó, B.; Babuška, I. Finite Element Analysis—Method, Verification, and Validation, 2nd ed.; Wiley Series in Computational Mechanics; Wiley: Hoboken, NJ, USA, 2021. [Google Scholar]
  3. Larson, M.G.; Bengzon, F. The Finite Element Method: Theory, Implementation, and Applications, 6th ed.; Number 10 in Texts in Computational Science and Engineering; SI Version; Springer: Berlin/Heidelberg, Germany, 2013. [Google Scholar]
  4. Logan, D.L. A First Course in the Finite Element Method; CENGAGE: Boston, MA, USA, 2021. [Google Scholar]
  5. Eymard, R.; Gallouët, T.; Herbin, R. Finite Volume Methods. In Handbook of Numerical Analysis; Ciarlet, P.G., Lions, J.L., Eds.; Elsevier: Amsterdam, The Netherlands, 2000; Volume 7, pp. 715–1022. [Google Scholar]
  6. Moukalled, F.; Mangani, L.; Darwish, M. The Finite Volume Method in Computational Fluid Dynamics: An Advanced Introduction with OpenFOAM and Matlab; Springer: Berlin/Heidelberg, Germany, 2016. [Google Scholar]
  7. Blazek, J. Computational Fluid Dynamics: Principles and Applications; Butterworth-Heinemann: Oxford, UK, 2015. [Google Scholar]
  8. Vítek, O.; Macek, J.; Doleček, V.; Syrovátka, Z.; Pavlovic, Z.; Priesching, P.; Tap, F.; Goryntsev, D. Application of advanced combustion models in internal combustion engines based on 3-D CFD LES approach. Acta Polytech. 2021, 61, 14–32. [Google Scholar] [CrossRef]
  9. Beneš, M.; Strachota, P.; Máca, R.; Havlena, V.; Mach, J. A Quasi-1D Model of Biomass Co-Firing in a Circulating Fluidized Bed Boiler. In Finite Volumes for Complex Applications VII—Elliptic, Parabolic, and Hyperbolic Problems, Proceedings of the FVCA 7, Berlin, Germany, 15–20 June 2014; Springer Proceedings in Mathematics & Statistics; Fuhrmann, J., Ohlberger, M., Rohde, C., Eds.; Springer: Berlin/Heidelberg, Germany, 2014; Volume 78, pp. 791–799. [Google Scholar]
  10. Wang, W.; Cao, Y.; Okaze, T. Comparison of hexahedral, tetrahedral and polyhedral cells for reproducing the wind field around an isolated building by LES. Build. Environ. 2021, 195, 107717. [Google Scholar] [CrossRef]
  11. Sosnowski, M.; Krzywanski, J.; Gnatowska, R. Polyhedral meshing as an innovative approach to computational domain discretization of a cyclone in a fluidized bed CLC unit. ES3 Web Conf. 2017, 14, 01027. [Google Scholar] [CrossRef]
  12. Sosnowski, M.; Krzywanski, J.; Grabowska, K.; Gnatowska, R. Polyhedral meshing in numerical analysis of conjugate heat transfer. EPJ Web Conf. 2018, 180, 02096. [Google Scholar] [CrossRef]
  13. Thomas, M.L.; Longest, P.W. Evaluation of the polyhedral mesh style for predicting aerosol deposition in representative models of the conducting airways. J. Aerosol Sci. 2022, 159, 105851. [Google Scholar] [CrossRef] [PubMed]
  14. Jasak, H.; Jemcov, A.; Tukovic, Z. OpenFOAM: A C++ library for complex physics simulations. In Proceedings of the International Workshop on Coupled Methods in Numerical Dynamics, Dubrovnik, Croatia, 19–21 September 2007; IUC Dubrovnik: Dubrovnik, Croatia, 2007; Volume 1000, pp. 1–20. [Google Scholar]
  15. Hahn, J.; Mikula, K.; Frolkovič, P.; Basara, B. Finite volume method with the Soner boundary condition for computing the signed distance function on polyhedral meshes. Int. J. Numer. Methods Eng. 2022, 123, 1057–1077. [Google Scholar] [CrossRef]
  16. Hahn, J.; Mikula, K.; Frolkovič, P.; Basara, B. Inflow-Based Gradient Finite Volume Method for a Propagation in a Normal Direction in a Polyhedron Mesh. J. Sci. Comput. 2017, 72, 442–465. [Google Scholar] [CrossRef]
  17. Perumal, L. A Brief Review on Polygonal/Polyhedral Finite Element Methods. Math. Prob. Eng. 2018, 2018, 5792372. [Google Scholar] [CrossRef] [Green Version]
  18. Rashid, M.M.; Selimotic, M. A three-dimensional finite element method with arbitrary polyhedral elements. Int. J. Numer. Methods Eng. 2006, 67, 226–252. [Google Scholar] [CrossRef]
  19. Bishop, J.E.; Sukumar, N. Polyhedral finite elements for nonlinear solid mechanics using tetrahedral subdivisions and dual-cell aggregation. Comput. Aided Geom. Des. 2020, 77, 101812. [Google Scholar] [CrossRef]
  20. Nguyen-Ngoc, H.; Cuong-Le, T.; Nguyen, K.D.; Nguyen-Xuan, H.; Abdel-Wahab, M. Three-dimensional polyhedral finite element method for the analysis of multi-directional functionally graded solid shells. Compos. Struct. 2023, 305, 116538. [Google Scholar] [CrossRef]
  21. Wicke, M.; Botsch, M.; Gross, M. A Finite Element Method on Convex Polyhedra. Comput. Graph. Forum 2007, 26, 355–364. [Google Scholar] [CrossRef]
  22. Botsch, M.; Steinberg, S.; Bischoff, S.; Kobbelt, L. OpenMesh—A generic and efficient polygon mesh data structure. In Proceedings of the 1st OpenSG Symposium, Darmstadt, Germany, 29 January 2002; IEEE Press: Manhattan, NY, USA, 2002. [Google Scholar]
  23. Ibanez, D.A.; Seol, E.S.; Smith, C.W.; Shephard, M.S. PUMI: Parallel unstructured mesh infrastructure. ACM Trans. Math. Softw. 2016, 42, 1–28. [Google Scholar] [CrossRef]
  24. Message Passing Interface Forum. MPI: A Message-Passing Interface Standard Version 4.0. 2021. Available online: https://www.mpi-forum.org/docs/mpi-4.0/mpi40-report.pdf (accessed on 13 July 2023).
  25. Rudolf, F.; Rupp, K.; Weinbub, J. ViennaGrid 2.1.0—User Manual; Techreport; Vienna University of Technology: Vienna, Austria, 2014. [Google Scholar]
  26. Tautges, T.J.; Ernst, C.; Stimpson, C.; Meyers, R.J.; Merkley, K. MOAB: A Mesh-Oriented Database; Technical Report; Sandia National Laboratories: Albuquerque, NM, USA, 2004. [CrossRef] [Green Version]
  27. Klinkovský, J.; Oberhuber, T.; Fučík, R.; Žabka, V. Configurable Open-source Data Structure for Distributed Conforming Unstructured Homogeneous Meshes with GPU Support. ACM Trans. Math. Softw. 2022, 48, 1–30. [Google Scholar] [CrossRef]
  28. Bastian, P.; Blatt, M.; Dedner, A.; Engwer, C.; Klöfkorn, R.; Kornhuber, R.; Ohlberger, M.; Sander, O. A generic grid interface for parallel and adaptive scientific computing. Part II: Implementation and tests in DUNE. Computing 2008, 82, 121–138. [Google Scholar] [CrossRef]
  29. Oberhuber, T.; Klinkovský, J.; Fučík, R. TNL: Numerical Library for Modern Parallel Architectures. Acta Polytech. 2021, 61, 122–134. [Google Scholar] [CrossRef]
  30. ISO/IEC 14882:2014; Information Technology—Programming Languages—C++, 4th ed. ISO: London, UK, 2017; p. 1358.
  31. Vandevoorde, D.; Josuttis, N.M.; Gregor, D. C++ Templates: The Complete Guide, 2nd ed.; Addison-Wesley: Boston, MA, USA, 2017. [Google Scholar]
  32. Meyer, B. Object-Oriented Software Construction; Prentice Hall: Upper Saddle River, NJ, USA, 1988. [Google Scholar]
  33. Bondy, J.A.; Murty, U.S.R. Graph Theory with Applications; Macmillan London: London, UK, 1976; Volume 290. [Google Scholar]
  34. Brenner, S.; Scott, R. The Mathematical Theory of Finite Element Methods; Springer Science & Business Media: Berlin, Germany, 2007; Volume 15. [Google Scholar]
  35. Hahn, J.; Mikula, K.; Frolkovič, P.; Medl’a, M.; Basara, B. Iterative inflow-implicit outflow-explicit finite volume scheme for level-set equations on polyhedron meshes. Comput. Math. Appl. 2019, 77, 1639–1654. [Google Scholar]
  36. Schroeder, W.; Martin, K.; Lorensen, B. The Visualization Toolkit, 4th ed.; Kitware: New York, NY, USA, 2006. [Google Scholar]
  37. ISO/IEC 14882:2017; Information Technology—Programming Languages—C++, 5th ed. ISO: London, UK, 2017; p. 1605.
  38. Butcher, J.C. Numerical Methods for Ordinary Differential Equations, 2nd ed.; Wiley: Chichester, UK, 2008. [Google Scholar] [CrossRef]
  39. Christiansen, J. Numerical solution of ordinary simultaneous differential equations of the 1st order using a method for automatic step change. Numer. Math. 1970, 14, 317–324. [Google Scholar] [CrossRef]
  40. Jakubec, T. Numerical Simulation of Multiphase Flow on 3D Unstructured Meshes with an Arbitrary Topology. Master’s Thesis, Czech Technical University in Prague, Prague, Czech Republic, 2021. [Google Scholar]
Figure 2. Example of the graph G T * associated with the mesh shown in Figure 1. The edges in the graph are presented by black or red lines. The edges between cells and vertices are highlighted in red.
Figure 2. Example of the graph G T * associated with the mesh shown in Figure 1. The edges in the graph are presented by black or red lines. The edges between cells and vertices are highlighted in red.
Applsci 13 08748 g002
Figure 3. Connections on an example 3D mesh corresponding to the graph presented in Figure 4.
Figure 3. Connections on an example 3D mesh corresponding to the graph presented in Figure 4.
Applsci 13 08748 g003
Figure 4. An example of a graph representing the topology of a generic d-dimensional mesh. If d > 3 , one or more violet layers of generic elements with dimensions k 2 , 3 , , d 2 appear. Each of these generic elements refers to the elements of its boundary, using blue arrows E T * k , k 1 . In the last column of the table, the numbers of connections of the given type from each element are reported.
Figure 4. An example of a graph representing the topology of a generic d-dimensional mesh. If d > 3 , one or more violet layers of generic elements with dimensions k 2 , 3 , , d 2 appear. Each of these generic elements refers to the elements of its boundary, using blue arrows E T * k , k 1 . In the last column of the table, the numbers of connections of the given type from each element are reported.
Applsci 13 08748 g004
Figure 5. Scheme of the chosen representation demonstrated on a 3D unstructured mesh.
Figure 5. Scheme of the chosen representation demonstrated on a 3D unstructured mesh.
Applsci 13 08748 g005
Table 1. Symbols used in the Runge–Kutta–Merson pseudo-code (Algorithm 1).
Table 1. Symbols used in the Runge–Kutta–Merson pseudo-code (Algorithm 1).
SymbolMeaning
tcurrent time level
Tfinal time
T ini initial time
τ time step
τ ini initial time step
x τ numerical solution
x ini τ initial condition for the numerical solution  x τ
δ tolerance parameter
ω time step adjustment parameter ( ω = 0.8 is recommended)
Disclaimer/Publisher’s Note: The statements, opinions and data contained in all publications are solely those of the individual author(s) and contributor(s) and not of MDPI and/or the editor(s). MDPI and/or the editor(s) disclaim responsibility for any injury to people or property resulting from any ideas, methods, instructions or products referred to in the content.

Share and Cite

MDPI and ACS Style

Jakubec, T.; Strachota, P. GTMesh: A Highly Efficient C++ Template Library for Numerical Schemes on General Topology Meshes. Appl. Sci. 2023, 13, 8748. https://doi.org/10.3390/app13158748

AMA Style

Jakubec T, Strachota P. GTMesh: A Highly Efficient C++ Template Library for Numerical Schemes on General Topology Meshes. Applied Sciences. 2023; 13(15):8748. https://doi.org/10.3390/app13158748

Chicago/Turabian Style

Jakubec, Tomáš, and Pavel Strachota. 2023. "GTMesh: A Highly Efficient C++ Template Library for Numerical Schemes on General Topology Meshes" Applied Sciences 13, no. 15: 8748. https://doi.org/10.3390/app13158748

Note that from the first issue of 2016, this journal uses article numbers instead of page numbers. See further details here.

Article Metrics

Back to TopTop