This section links the core concepts, presented in the MeshRepresentation
and MeshTypes
sections, to the underlying implementation of the Mint mesh data model. The Architecture
of Mint's mesh data model consists of a class hierarchy that follows directly the taxonomy of MeshTypes
discussed earlier. The constituent classes of the mesh data model are combined using a mix of class inheritance and composition, as illustrated in the class diagram depicted in figs/classDiagram
.
Architecture
of the Mint mesh data model, depicting the core mesh classes and the inter-relationship between them. The solid arrows indicate an inheritance relationship, while the dashed arrows indicate an ownership relationship between two classes.
At the top level, TheMeshBaseClass
, implemented in mint::Mesh
, stores common mesh attributes and fields. Moreover, it defines a unified Application Programming Interface (API) for the various MeshTypes
. See the Mint Doxygen API Documentation for a complete specification of the API. The ConcreteMeshClasses
extend TheMeshBaseClass
and implement the MeshRepresentation
for each of the MeshTypes
respectively. The mint::ConnectivityArray
and mint::MeshCoordinates
classes, are the two main internal support classes that underpin the implementation of the ConcreteMeshClasses
and facilitate the representation of the constituent Geometry
and Topology
of the mesh.
Note
All Mint classes and functions are encapsulated in the axom::mint
namespace.
TheMeshBaseClass
stores common attributes associated with a mesh. Irrespective of the mesh type, a Mint mesh has two identifiers. The mesh BlockID and mesh DomainID, which are assigned by domain decomposition. Notably, the computational domain can consist of one or more blocks, which are usually defined by the user or application. Each block is then subsequently partitioned to multiple domains that are distributed across processing units for parallel computation. For example, a sample block and domain decomposition is depicted in figs/decomp
. Each of the constituent domains is represented by a corresponding mint::Mesh
instance, which in aggregate define the entire problem domain.
Sample block & domain decomposition of the computational domain. The computational domain is defined using 3 blocks (left). Each block is further partitioned into two or more domains(right). A
mint::Mesh
instance represents one of the constituent domains used to define the overall problem domain.
Note
A mint::Mesh
instance provides the means to store the mesh BlockID and DomainID respectively. However, Mint does not impose a numbering or partitioning scheme. Assignment of the BlockID and DomainID is handled at the application level and by the underlying mesh partitioner that is being employed.
Moreover, each mint::Mesh
instance has associated MeshFieldData
, represented by the mint::FieldData
class. Each of the constituent topological mesh entities, i.e. the Cells
, Faces
and Nodes
comprising the mesh, has a handle to a corresponding mint::FieldData
instance. The mint::FieldData
object essentialy provides a container to store and manage a collection of fields, defined over the corresponding mesh entity.
Warning
Since a ParticleMesh
is defined by a set of Nodes
, it can only store FieldData
at its constituent Nodes
. All other supported MeshTypes
can have FieldData
associated with their constituent Cells
, Faces
and Nodes
.
A mint::FieldData
instance typically stores multiple fields. Each field is represented by an instance of a mint::Field
object and defines a named numerical quantity, such as mass, velocity, temperature, etc., defined on a given mesh. Moreover, a field can be either single-component, i.e. a scalar quantity, or, multi-component, e.g. a vector or tensor quantity. Typically, a field represents some physical quantity that is being modeled, or, an auxiliary quantity that is needed to perform a particular calculation.
In addition, each mint::Field
instance can be of different data type. The mint::FieldData
object can store different types of fields. For example, floating point quantities i.e., float
or double
, as well as, integral quantities, i.e. int32_t
, int64_t
, etc. This is accomplished using a combination of C++ templates and inheritance. The mint::Field
object is an abstract base class that defines a type-agnostic interface to encapsulate a field. Since mint::Field
is an abstract base class, it is not instantiated directly. Instead, all fields are created by instantiating a mint::FieldVariable
object, a class templated on data type, that derives from the mint::Field
base class. For example, the code snippet below illustrates how fields of different type can be instantiated.
...
// create a scalar field to store mass as a single precision quantity
mint::Field* mass = new mint::FieldVariable< float >( "mass", size );
// create a velocity vector field as a double precision floating point quantity
constexpr int NUM_COMPONENTS = 3;
mint::Field* vel = new mint::FieldVariable< double >( "vel", size, NUM_COMPONENTS );
...
Generally, in application code, it is not necessary to create fields using the mint::FieldVariable
class directly. The mint::Mesh
object provides convenience methods for adding, removing and accessing fields on a mesh. Consult the sections/tutorial
for more details on workingWithFields
on a Mesh.
The ConcreteMeshClasses
, extend TheMeshBaseClass
and implement the underlying MeshRepresentation
of the various MeshTypes
, depicted in figs/meshtypes
.
Depiction of the supported
MeshTypes
with labels of the corresponding Mint class used for the underlyingMeshRepresentation
.
All StructuredMesh
types in Mint can be represented by an instance of the mint::StructuredMesh
class, which derives directly from TheMeshBaseClass
, mint::Mesh
. The mint::StructuredMesh
class is also an abstract base class that encapsulates the implementation of the implicit, ordered and regular Topology
that is common to all StructuredMesh
types. The distinguishing characteristic of the different StructuredMesh
types is the representation of the constituent Geometry
. Mint implements each of the different StructuredMesh
types by a corresponding class, which derives directly from mint::StructuredMesh
and thereby inherit its implicit Topology
representation.
Consequently, support for the UniformMesh
is implemented in mint::UniformMesh
. The Geometry
of a UniformMesh
is implicit, given by two attributes, the mesh origin and spacing. Consequently, the mint::UniformMesh
consists of two data members to store the origin and spacing of the UniformMesh
and provides functionality for evaluating the spatial coordinates of a node given its corresponding IJK lattice coordinates.
Similarly, support for the RectilinearMesh
is implemented in mint::RectilinearMesh
. The constituent Geometry
representation of the RectilinearMesh
is semi-implicit. The spatial coordinates of the Nodes
along each axis are specified explicitly while the coordinates of the interior Nodes
are evaluated by taking the Cartesian product of the corresponding coordinate along each coordinate axis. The mint::RectilinearMesh
consists of seperate arrays to store the coordinates along each axis for the semi-implicit Geometry
representation of the RectilinearMesh
.
Support for the CurvilinearMesh
is implemented by the mint::CurvilinearMesh
class. The CurvilinearMesh
requires explicit representation of its constituent Geometry
. The mint::CurvilinearMesh
makes use of the mint::MeshCoordinates
class to explicitly represent the spatial coordinates associated with the constituent Nodes
of the mesh.
Mint's UnstructuredMesh
representation is provided by the mint::UnstructuredMesh
class, which derives directly from the TheMeshBaseClass
, mint::Mesh
. An UnstructuredMesh
has both explicit Geometry
and Topology
. As with the mint::CurvilinearMesh
class, the explicit Geometry
representation of the UnstructuredMesh
employs the mint::MeshCoordinates
. The constituent Topology
is handled by the mint::ConnectivityArray
, which is employed for the representation of all the topological Connectivity
information, i.e. cell-to-node, face-to-node, face-to-cell, etc.
Note
Upon construction, a mint::UnstructuredMesh
instance consists of the minimum sufficient representation for an UnstructuredMesh
comprised of the cell-to-node Connectivity
information. Applications that require face Connectivity
information must explicitly call the initializeFaceConnectivity()
method on the corresponding UnstructuredMesh
object.
Depending on the cell Topology
being employed, an UnstructuredMesh
can be classified as either a SingleCellTopology
UnstructuredMesh
or a MixedCellTopology
UnstructuredMesh
. To accomodate these two different representations, the mint::UnstructuredMesh
class, is templated on CELL_TOPOLOGY
. Internally, the template argument is used to indicate the type of mint::ConnectivityArray
to use, i.e. whether, stride access addressing or indirect addressing is used, for SingleCellTopology
and MixedCellTopology
respectively.
Support for the ParticleMesh
representation is implemented in mint::ParticleMesh
, which derives directly from TheMeshBaseClass
, mint::Mesh
. A ParticleMesh
discretizes the domain by a set of particles, which correspond to the constituent Nodes
of the mesh. The Nodes
of a ParticleMesh
can also be thought of as Cells
, however, since this information is trivially obtrained, there is not need to be stored explicitly, e.g. using a SingleCellTopology
UnstructuredMesh
representation. Consequently, the ParticleMesh
representation consists of explicit Geometry
and implicit Topology
. As with the mint::CurvilinearMesh
and mint::UnstructuredMesh
, the explicit Geometry
of the ParticleMesh
is represented by employing the mint::MeshCoordinates
as an internal class member.
The following code snippet provides a simple examples illustrating how to construct and operate on a ParticleMesh
.
../../../examples/mint_particle_mesh.cpp
Mint provides a flexible MeshStorageManagement
system that can optionally interoperate with Sidre as the underlying, in-memory, hierarchichal datastore. This enables Mint to natively conform to Conduit's Blueprint protocol for representing a computational mesh in memory and thereby, facilitate with the integration across different physics packages.
Mint's MeshStorageManagement
substrate supports three storage options. The applicable operations and ownership state of each storage option are summarized in the table below, followed by a brief description of each option.
Modify | Reallocate | Ownership | |
---|---|---|---|
NativeStorage |
✓ |
|
Mint |
ExternalStorage |
✓ | Application | |
SidreStorage |
✓ |
|
A Mint object using NativeStorage
owns all memory and associated data. The data can be modified and the associated memory space can be reallocated to grow and shrink as needed. However, once the Mint object goes out-of-scope, all data is deleted and the memory is returned to the system.
See the sections/tutorial
for more information and a set of concrete examples on how to create a mesh using NativeStorage
.
A Mint object using ExternalStorage
has a pointer to a supplied application buffer. In this case, the data can be modified, but the application maintains ownership of the underlying memory. Consequently, the memory space cannot be reallocated and once the Mint object goes out-of-scope, the data is not deleted. The data remains persistent in the application buffers until it is deleted by the application.
See the sections/tutorial
for more information on usingExternalStorage
.
A Mint object using SidreStorage
is associated with a Sidre Group object which has owneship of the mesh data. In this case the data can be modified and the associated memory can be reallocated to grow and shrink as needed. However, when the Mint object goes out-of-scope, the data remains persistent in Sidre.
See the sections/tutorial
for more information and a set of concrete examples on usingSidre
.