Interoperability with Other Discretization Packages¶
Functionality in this subpackage helps import and export data to/from other pieces of software, typically PDE solvers.
Nodal DG¶
Provides interoperability with the Matlab/Octave Codes complementing the book “Nodal Discontinuous Galerkin Methods” by Jan Hesthaven and Tim Warburton (Springer, 2008).
- class meshmode.interop.nodal_dg.NodalDGContext(path)[source]¶
Should be used as a context manager to ensure proper cleanup.
- set_mesh(mesh: Mesh, order)[source]¶
Set the mesh information in the nodal DG Octave instance to the one given by mesh.
The mesh must only have a single element group of simplices.
Warning
High-order geometry information is currently silently ignored.
- get_discr(actx) Discretization[source]¶
Get a discretization with nodes exactly matching the ones used by the nodal-DG code.
The returned discretization contains a new
Meshobject constructed from the global Octave state.
- pull_dof_array(actx: arraycontext.ArrayContext, name) meshmode.dof_array.DOFArray[source]¶
Firedrake¶
Function Spaces/Discretizations¶
Users wishing to interact with meshmode from firedrake
will create a
FiredrakeConnection
using build_connection_from_firedrake(),
while users wishing
to interact with firedrake from meshmode will use
will create a
FiredrakeConnection
using build_connection_to_firedrake().
It is not recommended to create a
FiredrakeConnection directly.
- class meshmode.interop.firedrake.connection.FiredrakeConnection(discr, fdrake_fspace, mm2fd_node_mapping, group_nr=None)[source]¶
A connection between one group of a meshmode discretization and a firedrake “DG” function space.
Users should instantiate this using
build_connection_to_firedrake()orbuild_connection_from_firedrake()- group_nr¶
The group number identifying which element group of
discris being connected to a firedrake function space
- mm2fd_node_mapping¶
Letting element_grp = self.discr.groups[self.group_nr], mm2fd_node_mapping is a numpy array of shape (element_grp.nelements, element_grp.nunit_dofs) whose (i, j)th entry is the
firedrakenode index associated to the jth degree of freedom of the ith element in element_grp.mm2fd_node_mappingmust encode an embedding into thefiredrakemesh, i.e. no twomeshmodenodes may be associated to the samefiredrakenodeDegrees of freedom should be associated so that the implicit mapping from a reference element to element i which maps meshmode unit dofs 0,1,…,n-1 to actual dofs (i, 0), (i, 1), …, (i, n-1) is the same mapping which maps firedrake unit dofs 0,1,…,n-1 to firedrake dofs mm2fd_node_mapping[i,0], mm2fd_node_mapping[i,1],…, mm2fd_node_mapping[i,n-1].
- (See
meshmode.interop.firedrake.reference_cellto obtain firedrake unit dofs on the meshmode reference cell)
- (See
- __init__(discr, fdrake_fspace, mm2fd_node_mapping, group_nr=None)[source]¶
- Parameters:
discr – A
meshmode.discretization.Discretizationfdrake_fspace – A
firedrake.functionspaceimpl.WithGeometry. Must use ufl family"Discontinuous Lagrange".mm2fd_node_mapping – Used as attribute
mm2fd_node_mapping. A 2-D numpy integer array with the same dtype asfdrake_fspace.cell_node_list.dtypegroup_nr – The index of the group in discr which is being connected to fdrake_fspace. The group must be a
InterpolatoryElementGroupBaseof the same topological dimension as fdrake_fspace. If discr has only one group, group_nr=None may be supplied.
- Raises:
TypeError – If any input arguments are of the wrong type, if the designated group is of the wrong type, or if fdrake_fspace is of the wrong family.
ValueError – If mm2fd_node_mapping is of the wrong shape or dtype, if group_nr is an invalid index, or if group_nr is None when discr has more than one group.
- from_meshmode(mm_field, out=None)[source]¶
Transport meshmode field from
discrinto an appropriate firedrake function space.If out is None, values at any firedrake nodes associated to NO meshmode nodes are zeroed out. If out is supplied, values at nodes associated to NO meshmode nodes are not modified.
- Parameters:
mm_field –
Either
A
numpy.ndarrayof dtype “object” with entries of classDOFArrayrepresenting a field of shape mm_field.shape ondiscr
See
DOFArrayfor further requirements. Thegroup_nrentry of eachDOFArraymust be of shape (nelements, nunit_dofs) and the element_dtype must match that used forfiredrake.function.Functionsout – If None then ignored, otherwise a
firedrake.function.Functionof the right function space for the transported data to be stored in. The shape of its function space must match the shape of mm_field
- Returns:
a
firedrake.function.Functionholding the transported data (out, if out was not None)
- from_firedrake(function, out=None, actx=None)[source]¶
Transport firedrake function onto
discr- Parameters:
function – A
firedrake.function.Functionto transfer ontodiscr. Its function space must have the same family, degree, and mesh asself.from_fspace().out –
Either
A
DOFArrayA
numpy.ndarrayobject array, each of whose entries is aDOFArrayNone
In the case of (1.), function must be in a scalar function space (i.e. function.function_space().shape == (,)). In the case of (2.), the shape of out must match function.function_space().shape.
In either case, each
DOFArraymust be aDOFArraydefined ondiscr(as described in the documentation forDOFArray). Also, eachDOFArray’s entry_dtype must match the function.dat.data.dtype, and be of shape (nelements, nunit_dofs).In case (3.), an array is created satisfying the above requirements.
The data in function is transported to
discrand stored in out, which is then returned.actx –
If out is None, then actx is a
ArrayContexton which to create theDOFArrayIf out is not None, actx must be None or out’s
array_context.
- Returns:
out, with the converted data from function stored in it
- firedrake_fspace(shape=None)[source]¶
Return a firedrake function space that self.discr.groups[self.group_nr] is connected to of the appropriate vector dimension
- Parameters:
shape – Either None, in which case a function space which maps to scalar values is returned, a positive integer n, in which case a function space which maps into R^n is returned, or a tuple of integers defining the shape of values in a tensor function space, in which case a tensor function space is returned
- Returns:
A
firedrake.functionspaceimpl.WithGeometrywhich corresponds to self.discr.groups[self.group_nr] of the appropriate vector dimension- Raises:
TypeError – If shape is of the wrong type
- meshmode.interop.firedrake.connection.build_connection_to_firedrake(discr, group_nr=None, comm=None)[source]¶
Create a connection from a meshmode discretization into firedrake. Create a corresponding “DG” function space and allow for conversion back and forth by resampling at the nodes.
- Parameters:
discr – A
Discretizationto initialize the connection withgroup_nr – The group number of the discretization to convert. If None there must be only one group. The selected group must be of type
InterpolatoryQuadratureSimplexElementGroup.comm – Communicator to build a dmplex object on for the created firedrake mesh
- meshmode.interop.firedrake.connection.build_connection_from_firedrake(actx, fdrake_fspace, grp_factory=None, restrict_to_boundary=None)[source]¶
Create a
FiredrakeConnectionfrom afiredrake"DG"function space by creates a corresponding meshmode discretization and facilitating transfer of functions to and fromfiredrake.- Parameters:
actx – A
ArrayContextused to instantiateFiredrakeConnection.discr.fdrake_fspace – A
firedrake"DG"function space (of classWithGeometry) built on a mesh which is importable byimport_firedrake_mesh().grp_factory – (optional) If not None, should be a
ElementGroupFactorywhose group class is a subclass ofInterpolatoryElementGroupBase. If None, and a default factory is automatically selected.restrict_to_boundary –
(optional) If not None, then must be one of the following:
A valid boundary marker for
fdrake_fspace.mesh()A tuple of valid boundary markers for
fdrake_fspace.mesh()The string
"on_boundary"(firedrakeequivalent toBTAG_ALL).
If not None, creates a
Discretizationon a submesh offdrake_fspace.mesh()created from the cells with at least one vertex on a facet marked with the marker restrict_to_boundary.
Meshes¶
- meshmode.interop.firedrake.mesh.import_firedrake_mesh(fdrake_mesh, cells_to_use=None, normals=None, no_normals_warn=None)[source]¶
Create a
meshmode.mesh.Meshfrom a firedrake.mesh.MeshGeometry with the same cells/elements, vertices, nodes, mesh order, and facial adjacency.The vertex and node coordinates will be the same, as well as the cell/element ordering. However,
firedrakedoes not require elements to be positively oriented, so any negative elements are flipped.The flipped cells/elements are identified by the returned firedrake_orient array
- Parameters:
fdrake_mesh –
firedrake.mesh.MeshGeometry. This mesh must be in a space of ambient dimension 1, 2, or 3 and have co-dimension of 0 or 1. It must use a simplex as a reference element.
In the case of a 2-dimensional mesh embedded in 3-space, the method
fdrake_mesh.init_cell_orientationsmust have been called.In the case of a 1-dimensional mesh embedded in 2-space, see parameters normals and no_normals_warn.
Finally, the
coordinatesattribute must have a function space whose finat_element associates a degree of freedom with each vertex. In particular, this means that the vertices of the mesh must have well-defined coordinates. For those unfamiliar withfiredrake, you can verify this by looking atcoords_fspace = fdrake_mesh.coordinates.function_space() vertex_entity_dofs = coords_fspace.finat_element.entity_dofs()[0] for entity, dof_list in vertex_entity_dofs.items(): assert len(dof_list) > 0
cells_to_use –
cells_to_use is primarily intended for use internally by
build_connection_from_firedrake(). cells_to_use must be eitherNone, in which case this argument is ignored, or
a numpy array of unique firedrake cell indexes.
In case (2.), only cells whose index appears in cells_to_use are included in the resultant mesh, and their index in cells_to_use becomes the element index in the resultant mesh element group. Any faces or vertices which do not touch a cell in cells_to_use are also ignored. Note that in this latter case, some faces that are not boundaries in fdrake_mesh may become boundaries in the returned mesh. These “induced” boundaries are marked with
BTAG_INDUCED_BOUNDARY.normals –
Only used if fdrake_mesh is a 1-surface embedded in 2-space. In this case,
If None then all elements are assumed to be positively oriented.
Else, should be a list/array whose ith entry is the normal for the ith element (ith in mesh.coordinate.function_space()’s cell_node_list)
no_normals_warn – If True (the default), raises a warning if fdrake_mesh is a 1-surface embedded in 2-space and normals is None.
- Returns:
A tuple (meshmode mesh, firedrake_orient).
firedrake_orient < 0is True for any negatively oriented firedrake cell (which was flipped by meshmode) and False for any positively oriented firedrake cell (which was not flipped by meshmode).
- meshmode.interop.firedrake.mesh.export_mesh_to_firedrake(mesh, group_nr=None, comm=None)[source]¶
Create a firedrake mesh corresponding to one
Mesh’sSimplexElementGroup.- Parameters:
mesh – A
Meshto convert with at least oneSimplexElementGroup. ‘mesh.is_conforming’ must evaluate to True. ‘mesh’ must have vertices supplied, i.e. ‘mesh.vertices’ must not be None.group_nr – The group number to be converted into a firedrake mesh. The corresponding group must be of type
SimplexElementGroup. If None and mesh has only one group, that group is used. Otherwise, a ValueError is raised.comm – The communicator to build the dmplex mesh on
- Returns:
A tuple (fdrake_mesh, fdrake_cell_ordering, perm2cell) where
fdrake_mesh is a
firedrakefiredrake.mesh.MeshGeometry corresponding to meshfdrake_cell_ordering is a numpy array whose ith element in mesh (i.e. the ith element in mesh.groups[group_nr].vertex_indices) corresponds to the fdrake_cell_ordering[i]th
firedrakecellperm2cell is a dictionary, mapping tuples to 1-D numpy arrays of meshmode element indices. Each meshmode element index appears in exactly one of these arrays. The corresponding tuple describes how firedrake reordered the local vertex indices on that cell. In particular, if c is in the list perm2cell[p] for a tuple p, then the p[i]th local vertex of the fdrake_cell_ordering[c]th firedrake cell corresponds to the ith local vertex of the cth meshmode element.
Reference Cells¶
- meshmode.interop.firedrake.reference_cell.get_affine_reference_simplex_mapping(ambient_dim, firedrake_to_meshmode=True)[source]¶
Returns a function which takes a numpy array points on one reference cell and maps each point to another using a positive affine map.
- Parameters:
ambient_dim – The spatial dimension
firedrake_to_meshmode – If true, the returned function maps from the firedrake reference element to meshmode, if false maps from meshmode to firedrake. More specifically,
firedrakeuses the standardFIATsimplex andmeshmodeusesmodepy’s unit coordinates.
- Returns:
A function which takes a numpy array of n points with shape (dim, n) on one reference cell and maps each point to another using a positive affine map. Note that the returned function performs no input validation.
- meshmode.interop.firedrake.reference_cell.get_finat_element_unit_nodes(finat_element)[source]¶
Returns the unit nodes used by the
finatelement in firedrake’s (equivalently,finat/FIAT’s) reference coordinates- Parameters:
finat_element –
An instance of one of the following
finatelements- Returns:
A numpy array of shape (dim, nunit_dofs) holding the unit nodes used by this element. dim is the dimension spanned by the finat element’s reference element (see its
cellattribute)
Implementation Details¶
Converting between firedrake and meshmode is in general
straightforward. Some language is different:
A
Discretizationis afiredrakeWithGeometry, usually created by calling the functionFunctionSpace()and referred to as a “function space”In a mesh, any vertices, faces, cells, etc. are
firedrake“entities” (see the PETSc documentation on DMPLEX for more info on how topological mesh information is stored infiredrake).
Other than carefully tabulating how and which vertices/faces correspond to other vertices/faces/cells, there are two main difficulties.
meshmodehas discontinuous polynomial function spaces which may use different unit nodes thanfiredrake.meshmoderequires that all mesh elements be positively oriented,firedrakedoes not. Meanwhile, whenfiredrakecreates a mesh, it changes the element ordering and the local vertex ordering.
(1.) is easily handled by insisting that the firedrake
WithGeometry uses polynomial elements
and that the group of the Discretization
being converted is a
InterpolatoryQuadratureSimplexElementGroup
of the same order. Then, on each element, the function space being
represented is the same in firedrake and meshmode.
We may simply resample to one system or another’s unit nodes.
To handle (2.),
once we associate a meshmode
element to the correct firedrake cell, we have something
like this picture:
![digraph{
// created with graphviz2.38 dot
// NODES
mmNodes [label="Meshmode\nnodes"];
mmRef [label="Meshmode\nunit nodes"];
fdRef [label="Firedrake\nunit nodes"];
fdNodes [label="Firedrake\nnodes"];
// EDGES
mmRef -> mmNodes [label=" f "];
fdRef -> fdNodes [label=" g "];
}](_images/graphviz-d28eef67e65db78e6d1f63049d36cbe394f8b3e9.png)
(Assume we have already
ensured that meshmode and firedrake use the
same reference element by mapping firedrake’s reference
element onto meshmode’s).
If \(f=g\), then we can resample function values from
one node set to the other. However, if firedrake
has reordered the vertices or if we flipped their order to
ensure meshmode has positively-oriented elements,
there is some map \(A\) applied to the reference element
which implements this permutation of barycentric coordinates.
In this case, \(f=g\circ A\). Now, we have a connected diagram:
![digraph{
// created with graphviz2.38 dot
// NODES
mmNodes [label="Meshmode\nnodes"];
mmRef [label="Meshmode\nunit nodes"];
fdRef [label="Firedrake\nunit nodes"];
fdRef2 [label="Firedrake\nunit nodes"];
fdNodes [label="Firedrake\nnodes"];
// EDGES
{rank=same; mmRef; fdRef;}
{rank=same; mmNodes; fdNodes;}
mmRef -> fdRef [label="Resampling", dir="both"];
mmRef -> mmNodes [label=" f "];
fdRef -> fdRef2 [label=" A "];
fdRef2 -> fdNodes [label=" g "];
}](_images/graphviz-db9471188c095b1e2bd253ee5c7a2f563461be2f.png)
In short, once we reorder the firedrake nodes so
that the mapping from the meshmode and firedrake
reference elements are the same, we can resample function values
at nodes from one set of unit nodes to another (and then undo
the reordering if converting function values
from meshmode to firedrake). The
information for this whole reordering process is
stored in
mm2fd_node_mapping,
an array which associates each meshmode node
to the firedrake node found by tracing the
above diagram (i.e. it stores
\(g\circ A\circ \text{Resampling} \circ f^{-1}\)).
For Developers: Firedrake Function Space Design Crash Course¶
In Firedrake, meshes and function spaces have a close relationship.
In particular, this is due to some structure described in this
Firedrake pull request.
If you wish to develop on / add to the implementation of conversion
between meshmode and firedrake, you will need
to understand their design style. Below is a crash course.
In short, it is the idea that every function space should have a mesh, and the coordinates of the mesh should be representable as a function on that same mesh, which must live on some function space on the mesh… etc. Under the hood, we divide between topological and geometric objects, roughly as so:
A reference element defined using
finatandFIATis used to define what meshmode calls the unit nodes and unit vertices. It is worth noting thatfiredrakedoes not require a positive orientation of elements and that its reference triangle is different than specified inmodepy.A ~firedrake.mesh.MeshTopology which holds information about connectivity and other topological properties, but nothing about geometry/coordinates etc.
A class
FunctionSpacecreated from afinatelement and a ~firedrake.mesh.MeshTopology which allows us to define functions mapping the nodes (defined by thefinatelement) of each element in the ~firedrake.mesh.MeshTopology to some values. Note that the functionFunctionSpace()in the firedrake API is used to create objects of classFunctionSpaceandWithGeometry(see (6)).A ~firedrake.function.CoordinatelessFunction (in the sense that its domain has no coordinates) which is a function in a
FunctionSpace.A ~firedrake.mesh.MeshGeometry created from a
FunctionSpaceand a ~firedrake.function.CoordinatelessFunction in thatFunctionSpacewhich maps each dof to its geometric coordinates.A
WithGeometrywhich is aFunctionSpacetogether with a ~firedrake.mesh.MeshGeometry. This is the object returned usually returned to the user by a call to thefiredrakefunctionFunctionSpace().A
Functionis defined on aWithGeometry.
Thus, by the coordinates of a mesh geometry we mean
On the hidden back-end: a ~firedrake.function.CoordinatelessFunction f on some function space defined only on the mesh topology.
On the front-end: A
Functionwith the values of f but defined on aWithGeometrycreated from theFunctionSpacef lives in and the ~firedrake.mesh.MeshGeometry f defines.
Basically, it’s this picture (where \(a\to b\) if \(b\) depends on \(a\))
Warning
In general, the FunctionSpace
of the coordinates function
of a WithGeometry may not be the same
FunctionSpace
as for functions which live in the
WithGeometry.
This picture
only shows how the class definitions depend on each other.
![digraph{
// created with graphviz2.38 dot
// NODES
top [label="Topological\nMesh"];
ref [label="Reference\nElement"];
fspace [label="Function Space"];
coordless [label="Coordinateless\nFunction"];
geo [label="Geometric\nMesh"];
withgeo [label="With\nGeometry"];
// EDGES
top -> fspace;
ref -> fspace;
fspace -> coordless;
top -> geo;
coordless -> geo [label="Mesh\nCoordinates"];
fspace -> withgeo;
geo -> withgeo;
}](_images/graphviz-f3b51613812f449f08468a23dc901b6291fd2707.png)