dolfinx icon indicating copy to clipboard operation
dolfinx copied to clipboard

Add `transfer_meshtags_to_submesh`

Open jorgensd opened this issue 1 year ago • 1 comments

Describe new/missing feature

With the new co-dim 0 submesh support, it would be beneficial to have a function that transfers meshtags to the submesh (similar to what happens for mesh refinement). Interface (here written in Python for illustration purposes) is described below. It should be written in C++ as it involves alot of looping.

Suggested user interface

def transfer_meshtags_to_submesh(mesh, entity_tag, submesh, sub_vertex_to_parent, sub_cell_to_parent):
    """
    Transfer a meshtag from a parent mesh to a sub-mesh.
    """

    tdim = mesh.topology.dim
    cell_imap = mesh.topology.index_map(tdim)
    num_cells = cell_imap.size_local + cell_imap.num_ghosts
    mesh_to_submesh = np.full(num_cells, -1)
    mesh_to_submesh[sub_cell_to_parent] = np.arange(len(sub_cell_to_parent), dtype=np.int32)
    sub_vertex_to_parent = np.asarray(sub_vertex_to_parent)

    submesh.topology.create_connectivity(entity_tag.dim, 0)

    num_child_entities = submesh.topology.index_map(
        entity_tag.dim).size_local + submesh.topology.index_map(entity_tag.dim).num_ghosts
    submesh.topology.create_connectivity(submesh.topology.dim, entity_tag.dim)

    c_c_to_e = submesh.topology.connectivity(submesh.topology.dim, entity_tag.dim)
    c_e_to_v = submesh.topology.connectivity(entity_tag.dim, 0)

    child_markers = np.full(num_child_entities, 0, dtype=np.int32)

    mesh.topology.create_connectivity(entity_tag.dim, 0)
    mesh.topology.create_connectivity(entity_tag.dim, mesh.topology.dim)
    p_f_to_v = mesh.topology.connectivity(entity_tag.dim, 0)
    p_f_to_c = mesh.topology.connectivity(entity_tag.dim, mesh.topology.dim)
    for facet, value in zip(entity_tag.indices, entity_tag.values):
        facet_found = False
        for cell in p_f_to_c.links(facet):
            if facet_found:
                break
            if (child_cell := mesh_to_submesh[cell]) != -1:
                for child_facet in c_c_to_e.links(child_cell):
                    child_vertices = c_e_to_v.links(child_facet)
                    child_vertices_as_parent = sub_vertex_to_parent[child_vertices]
                    is_facet = np.isin(child_vertices_as_parent, p_f_to_v.links(facet)).all()
                    if is_facet:
                        child_markers[child_facet] = value
                        facet_found = True
    tags =  dolfinx.mesh.meshtags(submesh, entity_tag.dim,
                                 np.arange(num_child_entities, dtype=np.int32), child_markers)
    tags.name = entity_tag.name
    return tags

Minor edits: Some extra connectivity calls and variable renaming have taken place after testing this with @ottarph

jorgensd avatar Mar 09 '24 11:03 jorgensd

A C++ implementation of this has been prototyped at: https://github.com/scientificcomputing/scifem/pull/73 Any feedback on how it should be altered to be part of DOLFINx is appreciated.

jorgensd avatar Nov 20 '24 12:11 jorgensd

Is this feature on the horizon?

dajuno avatar Sep 09 '25 09:09 dajuno

Is this feature on the horizon?

As I haven't gotten any feedback, I haven't moved it to DOLFINx yet. You can use the scifem version, as scifem is on conda, spack and pip.

jorgensd avatar Sep 09 '25 09:09 jorgensd