diff --git a/meshmode/interop/firedrake/connection.py b/meshmode/interop/firedrake/connection.py index 936e87323fd0f820b0de6742436fbf05e91f7111..e2f202a0a836d2aecc2eb33acb96add1f9201832 100644 --- a/meshmode/interop/firedrake/connection.py +++ b/meshmode/interop/firedrake/connection.py @@ -74,6 +74,9 @@ def _reorder_nodes(orient, nodes, flip_matrix, unflip=False): flip_mat, nodes[orient < 0]) +# {{{ Create connection from firedrake into meshmode + + class FromFiredrakeConnection: """ A connection created from a :mod:`firedrake` @@ -358,3 +361,22 @@ class FromFiredrakeConnection: dist, continuity_tolerance)) return out + +# }}} + + +# {{{ Create connection to firedrake from meshmode + + +# TODO : implement this (should be easy using export_mesh_to_firedrake +# and similar styles) +class ToFiredrakeConnection: + def __init__(self, discr, group_nr=None): + """ + Create a connection from a firedrake discretization + into firedrake. Create a corresponding "DG" function + space and allow for conversion back and forth + by resampling at the nodes. + """ + +# }}} diff --git a/meshmode/interop/firedrake/mesh.py b/meshmode/interop/firedrake/mesh.py index a0c8cb0ddc85aa4501c71ae164e50bafdf174714..49e87408da0a9ab7684bc33de5d28eabcfe3221e 100644 --- a/meshmode/interop/firedrake/mesh.py +++ b/meshmode/interop/firedrake/mesh.py @@ -28,6 +28,13 @@ from warnings import warn # noqa import numpy as np import six +from modepy import resampling_matrix + +from meshmode.mesh import (BTAG_ALL, BTAG_REALLY_ALL, FacialAdjacencyGroup, + Mesh, NodalAdjacency, SimplexElementGroup) +from meshmode.interop.firedrake.reference_cell import ( + get_affine_reference_simplex_mapping, get_finat_element_unit_nodes) + # {{{ functions to extract information from Mesh Topology @@ -128,7 +135,6 @@ def _get_firedrake_nodal_info(fdrake_mesh_topology): neighbors = np.array(neighbors, dtype=np.int32) - from meshmode.mesh import NodalAdjacency nodal_adjacency = NodalAdjacency(neighbors_starts=neighbors_starts, neighbors=neighbors) @@ -150,7 +156,6 @@ def _get_firedrake_boundary_tags(fdrake_mesh): :return: A tuple of boundary tags """ - from meshmode.mesh import BTAG_ALL, BTAG_REALLY_ALL bdy_tags = [BTAG_ALL, BTAG_REALLY_ALL] unique_markers = fdrake_mesh.topology.exterior_facets.unique_markers @@ -179,7 +184,6 @@ def _get_firedrake_facial_adjacency_groups(fdrake_mesh_topology): # (ordered lexicographically by the vertex excluded from the face) # and meshmode's facet ordering: obtained from a simplex element # group - from meshmode.mesh import SimplexElementGroup mm_simp_group = SimplexElementGroup(1, None, None, dim=top.cell_dimension()) mm_face_vertex_indices = mm_simp_group.face_vertex_indices() @@ -205,7 +209,6 @@ def _get_firedrake_facial_adjacency_groups(fdrake_mesh_topology): for fac_nrs in int_fac_loc_nr]) # elements neighbors element_faces neighbor_faces are as required # for a :class:`FacialAdjacencyGroup`. - from meshmode.mesh import Mesh int_elements = int_facet_cell.flatten() int_neighbors = np.concatenate((int_facet_cell[:, 1], int_facet_cell[:, 0])) @@ -214,7 +217,6 @@ def _get_firedrake_facial_adjacency_groups(fdrake_mesh_topology): int_fac_loc_nr[:, 0])) int_neighbor_faces = int_neighbor_faces.astype(Mesh.face_id_dtype) - from meshmode.mesh import FacialAdjacencyGroup interconnectivity_grp = FacialAdjacencyGroup(igroup=0, ineighbor_group=0, elements=int_elements, neighbors=int_neighbors, @@ -241,7 +243,6 @@ def _get_firedrake_facial_adjacency_groups(fdrake_mesh_topology): except KeyError: raise 0 - from meshmode.mesh import BTAG_ALL, BTAG_REALLY_ALL ext_neighbors = np.zeros(ext_elements.shape, dtype=np.int32) for ifac, marker in enumerate(top.exterior_facets.markers): ext_neighbors[ifac] = -(boundary_tag_bit(BTAG_ALL) @@ -323,7 +324,7 @@ def _get_firedrake_orientations(fdrake_mesh, unflipped_group, vertices, # }}} -# {{{ Mesh conversion +# {{{ Mesh importing from firedrake def import_firedrake_mesh(fdrake_mesh, normals=None, no_normals_warn=None): """ @@ -424,7 +425,6 @@ def import_firedrake_mesh(fdrake_mesh, normals=None, no_normals_warn=None): nodes = np.transpose(nodes, (2, 0, 1)) # make a group (possibly with some elements that need to be flipped) - from meshmode.mesh import SimplexElementGroup unflipped_group = SimplexElementGroup(coord_finat_elt.degree, vertex_indices, nodes, @@ -472,7 +472,6 @@ def import_firedrake_mesh(fdrake_mesh, normals=None, no_normals_warn=None): # This changes the local facet nr, so we need to create and then # fix our facial adjacency groups. To do that, we need to figure # out which local facet numbers switched. - from meshmode.mesh import SimplexElementGroup mm_simp_group = SimplexElementGroup(1, None, None, dim=fdrake_mesh.cell_dimension()) face_vertex_indices = mm_simp_group.face_vertex_indices() @@ -498,7 +497,6 @@ def import_firedrake_mesh(fdrake_mesh, normals=None, no_normals_warn=None): return faces facial_adjacency_groups = [] - from meshmode.mesh import FacialAdjacencyGroup for igroup, fagrps in enumerate(unflipped_facial_adjacency_groups): facial_adjacency_groups.append({}) for ineighbor_group, fagrp in six.iteritems(fagrps): @@ -518,7 +516,6 @@ def import_firedrake_mesh(fdrake_mesh, normals=None, no_normals_warn=None): neighbor_faces=new_neighbor_faces) facial_adjacency_groups[igroup][ineighbor_group] = new_fagrp - from meshmode.mesh import Mesh return (Mesh(vertices, [group], boundary_tags=bdy_tags, nodal_adjacency=nodal_adjacency, @@ -526,3 +523,74 @@ def import_firedrake_mesh(fdrake_mesh, normals=None, no_normals_warn=None): orient) # }}} + + +# {{{ Mesh exporting to firedrake + +def export_mesh_to_firedrake(mesh, group_nr=None, comm=None): + """ + Create a firedrake mesh corresponding to one :class:`Mesh`'s + :class:`SimplexElementGroup`. + + :param mesh: A :class:`meshmode.mesh.Mesh` to convert with + at least one :class:`SimplexElementGroup` + :param group_nr: The group number to be converted into a firedrake + mesh. The corresponding group must be of type + :class:`SimplexElementGroup`. If *None* and + *mesh* has only one group, that group is used. Otherwise, + a *ValueError* is raised. + :param comm: The communicator to build the dmplex mesh on + """ + if not isinstance(mesh, Mesh): + raise TypeError(":arg:`mesh` must of type :class:`meshmode.mesh.Mesh`," + " not %s." % type(mesh)) + if group_nr is None: + if len(mesh.groups) != 1: + raise ValueError(":arg:`group_nr` is *None* but :arg:`mesh` has " + "more than one group.") + else: + group_nr = 0 + assert group_nr >= 0 and group_nr < len(mesh.groups) + assert isinstance(mesh.groups[group_nr], SimplexElementGroup) + assert mesh.vertices is not None + + # Get a dmplex object and then a mesh topology + group = mesh.groups[group_nr] + mm2fd_indices = np.unique(group.vertex_indices.flatten()) + coords = mesh.vertices[:, mm2fd_indices].T + cells = mm2fd_indices[group.vertex_indices] + + if comm is None: + from pyop2.mpi import COMM_WORLD + comm = COMM_WORLD + # FIXME : this is a private member... + import firedrake.mesh as fd_mesh + plex = fd_mesh._from_cell_list(group.dim, cells, coords, comm) + + topology = fd_mesh.Mesh(plex, dim=mesh.ambient_dim, reorder=False) + + # Now make a coordinates function + from firedrake import VectorFunctionSpace, Function + coords_fspace = VectorFunctionSpace(topology, 'CG', group.order, + dim=mesh.ambient_dim) + coords = Function(coords_fspace) + + # get firedrake unit nodes and map onto meshmode reference element + fd_ref_cell_to_mm = get_affine_reference_simplex_mapping(group.dim, True) + fd_unit_nodes = get_finat_element_unit_nodes(coords_fspace.finat_element) + fd_unit_nodes = fd_ref_cell_to_mm(fd_unit_nodes) + + from meshmode.discretization.poly_element import ( + InterpolatoryQuadratureSimplexElementGroup) + el_group = InterpolatoryQuadratureSimplexElementGroup(group, group.order, + group.node_nr_base) + resampling_mat = resampling_matrix(el_group.basis(), + new_nodes=fd_unit_nodes, + old_nodes=group.unit_nodes) + # nodes is shaped *(ambient dim, nelements, nunit nodes) + coords.dat.data[coords_fspace.cell_node_list, :] = \ + np.matmul(group.nodes, resampling_mat.T).transpose((1, 2, 0)) + + return fd_mesh.Mesh(coords, reorder=False) + +# }}}