Skip to content

Submesh IO and storage of multiple meshes per checkpoint file - #78

Merged
jorgensd merged 12 commits into
mainfrom
dokken/submesh-io
Sep 24, 2026
Merged

jorgensd merged 12 commits into
mainfrom
dokken/submesh-io

Conversation

@jorgensd

@jorgensd jorgensd commented Sep 13, 2026 •

Copy link
Copy Markdown
Member

Following the plan in #42.

Submesh checkpointing + named meshes

Checkpoint a dolfinx.mesh.create_submesh submesh and functions on it, and re-derive it
from a re-partitioned parent with EntityMaps usable in mixed-dimensional forms.

New public API

A submesh is never read onto a create_submesh-derived mesh: it is stored as an
ordinary named mesh, read back as one, and the data is then transferred.

Writing

parent and cell_map are the mesh the submesh was built from and the map
create_submesh returned for it.

io4dolfinx.write_mesh(path, parent)
io4dolfinx.write_submesh(path, submesh, parent, cell_map, mesh_name="wall",
                         mode=FileMode.append)
io4dolfinx.write_function(path, u, time=0.0, mode=FileMode.append, mesh_name="wall")

Several submeshes of one parent can share a file, including several of the same dimension.
parent_filename= keeps the submesh in its own file; the post codes always go to the
parent's, since they tag parent entities.

Reading

A separate run, typically at a different process count and therefore a different partition.
Nothing from the writing session is in scope: every mesh here comes out of the file.

parent = io4dolfinx.read_mesh(path, comm)                      # the parent, re-partitioned
stored = io4dolfinx.read_mesh(path, comm, mesh_name="wall")    # the submesh, as a plain mesh
u_stored = dolfinx.fem.Function(dolfinx.fem.functionspace(stored, ("Lagrange", 2)), name="u")
io4dolfinx.read_function(path, u_stored, time=0.0, name="u", mesh_name="wall")

Stop there if you only want the data. To assemble a mixed-dimensional form over the parent
and the submesh you need a submesh DOLFINx recognises as derived from that parent object,
which is what read_submesh builds — so the parent it is given is the one read on the
line above, not a mesh carried over from writing:

chk = io4dolfinx.read_submesh(path, parent, mesh_name="wall")   # re-derived from `parent`
u_sub = dolfinx.fem.Function(dolfinx.fem.functionspace(chk.submesh, ("Lagrange", 2)))
io4dolfinx.transfer_submesh_function(u_stored, u_sub, chk.post_code)

SubmeshCheckpoint carries submesh, cell_map, vertex_map, node_map exactly as
create_submesh returns them — so chk.cell_map goes straight into
dolfinx.fem.form(..., entity_maps=[...]) against parent — plus post_code, the index
each cell had in the stored submesh, which is how transfer_submesh_function routes the
data from stored onto chk.submesh.

Full signatures:

io4dolfinx.write_submesh(filename, submesh, parent, cell_map, mesh_name,
                         parent_mesh_name=None, parent_filename=None,
                         time=0.0, mode=FileMode.append, backend_args=None, backend=None)

io4dolfinx.read_submesh(filename, parent, mesh_name,
                        parent_mesh_name=None, backend_args=None, backend=None) -> SubmeshCheckpoint

io4dolfinx.transfer_submesh_function(u_source, u_dest, post_code)

mesh_name= on every mesh-associated call

write_mesh, read_mesh, write_function, read_function, write_meshtags,
read_meshtags, write_point_data, read_point_data, write_cell_data,
read_cell_data, read_timestamps, read_function_names. Several meshes per checkpoint.
Omitting it selects the default mesh, stored exactly as before, so existing checkpoints
stay readable
.

Backend support

backend mesh + submesh + read_submesh function checkpoints transfer route
adios2 yes yes read_function → transfer_submesh_function, any space
h5py yes yes same
vtkhdf yes no read_point_data / read_cell_data → transfer_submesh_function
xdmf no (cannot write meshes) no —
pyvista no (cannot write meshes) no —
exodus no (cannot write meshes or meshtags) no —

adios2 and h5py are the full-feature backends. vtkhdf stores the mesh, the submesh and its
post codes, so read_submesh works; it cannot checkpoint a general function, but point and
cell data can be read back and transferred. Point data follows the mesh's coordinate
element, so on a degree-4 mesh that transfers a degree-4 field, not a linear one.

Higher-order and curved geometry

Verified on a curved ball with degree-2 and degree-4 geometry (built with
dolfinx.fem.interpolate_geometry), whose boundary submesh is a genuinely curved manifold:
parent degree, submesh degree and Lagrange variant all survive the round-trip, and the
transfer is exact to ~1e-14, at one and three processes.

Not supported

H(div)/H(curl) on a submesh with tdim < gdim write and read exactly, but
transfer_submesh_function raises NotImplementedError: DOLFINx returns silently wrong
values there (FEniCS/dolfinx#3619). Use
read_mesh/read_function with the submesh's mesh_name and stop before re-deriving.

Restrictions at an interface follow the facet-to-cell connectivity, so jump() is not
orientation-stable across a re-partition — that is a DOLFINx property, not an IO one, and
it is equally unstable without any IO. Use abs(jump(...)), or pin the restrictions by
cell marker (scifem.compute_interface_data).

Tests

tests/test_submesh.py, 110 tests, green at np=1 and np=3 on both writable backends.

@jorgensd

Copy link
Copy Markdown
Member Author

Thoughts while trying to sleep; use interpolate geometry and curve the mesh (square-> circle) to test read /write point data on submeshes

@jorgensd
jorgensd marked this pull request as ready for review September 22, 2026 21:20
@jorgensd
jorgensd requested a review from finsberg September 22, 2026 21:20
@jorgensd jorgensd changed the title Submesh IO Submesh IO and storage of multiple meshes per checkpoint file Sep 22, 2026
@jorgensd
jorgensd merged commit 78cc28f into main Sep 24, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants