XDMF (.xdmf, .xmf)
The XDMF format: an XML "light data" description of topology/geometry/attributes, whose "heavy data" lives inline in the XML, in external raw binary files, or in a companion HDF5 file. Both XDMF2 and XDMF3 are read natively, including absolute DataItem references and embedded Information field data; writing emits XDMF3.
| Format name | xdmf |
| Extensions | .xdmf, .xmf |
| Read / Write | ✓ / ✓ |
| Extra dependencies | h5py (for data_format="HDF") |
Reading & writing
import meshioplusplus
mesh = meshioplusplus.read("mesh.xdmf")
meshioplusplus.xdmf.write("out.xdmf", mesh,
data_format="HDF", # "HDF", "XML", or "Binary"
compression="gzip", # HDF only
compression_opts=4,
)data_format— where DataItem payloads are stored:"XML"(inline text),"Binary"(external.binfiles, one per array), or"HDF"(a companion.h5file).compression/compression_opts— gzip filter for HDF data.- Reading compressed HDF data with the native core verifies each chunk a read reaches before libhdf5 reads it, because libhdf5 1.10 can over-read a chunk that delivers fewer bytes than its elements take: a stored chunk must hold its full size, a deflated chunk must inflate to it, and a trailing fletcher32 checksum is left out of those sizes and checked by libhdf5 on the read. The shuffle and deflate filters are verified, alone or as shuffle then deflate. Any other pipeline is read unverified, so the over-read stays possible in those files. That covers deflate then shuffle (the order MSC Nastran writes), szip and lzf, a residual risk this check does not close. Builds without zlib read deflated chunks unverified, and HDF5 older than 1.10.5 is not checked. Python readers that open HDF data through h5py (XDMF, VTKHDF, H5M, HMF, CGNS and Nastran H5) read through their own libhdf5 and are not covered by this check yet.
File structure
<Xdmf Version="2.x"|"3.x">
<Domain>
<Grid Name="Grid" [GridType="Uniform"]>
<Topology Type|TopologyType="<xdmf type>|Mixed" NumberOfElements=".." [NodesPerElement=".."]>
<DataItem DataType|NumberType="Int|UInt|Float" Precision="1|2|4|8"
Dimensions=".. .." Format="XML|Binary|HDF">...</DataItem>
</Topology>
<Geometry Type|GeometryType="X|XY|XYZ"><DataItem .../></Geometry>
<Attribute Name=".." AttributeType="Scalar|Vector|Tensor|Tensor6|Matrix" Center="Node|Cell|Grid">
<DataItem .../>
</Attribute>
</Grid>
</Domain>
</Xdmf>Format="HDF" DataItem text is "<file.h5>:/path/to/dataset" (the HDF5 file path is resolved relative to the .xdmf file, not the CWD). Format="Binary" text is a raw-binary sibling file path. Format="XML" is whitespace- separated inline numbers.
Mixed topology encodes a flat array of (xdmf_type_index, node0, node1, ...) tuples concatenated across all cells; the numeric type-index table is shared with the per-type TopologyType names (below). A line (Polyline) entry in a Mixed array carries an extra "number of points in this polyline" field immediately after its type index, which meshio++ requires to equal exactly 2.
Cell types
meshio++ ↔ XDMF TopologyType names (each accepts one or more spellings on read; the first is used on write):
| meshio++ | XDMF | meshio++ | XDMF |
|---|---|---|---|
vertex | Polyvertex | tetra | Tetrahedron |
line | Polyline | tetra10 | Tetrahedron_10 / Tet_10 |
line3 | Edge_3 | wedge | Wedge |
quad | Quadrilateral | wedge15 | Wedge_15 |
quad8 | Quadrilateral_8 / Quad_8 | wedge18 | Wedge_18 |
quad9 | Quadrilateral_9 / Quad_9 | hexahedron | Hexahedron |
pyramid | Pyramid | hexahedron20 | Hexahedron_20 / Hex_20 |
pyramid13 | Pyramid_13 | hexahedron27 | Hexahedron_27 / Hex_27 |
triangle | Triangle | hexahedron64..1331 | Hexahedron_{64..1331} / Hex_{64..1331} (high-order) |
triangle6 | Triangle_6 / Tri_6 |
Numeric Mixed-topology type indices (a subset shared with the per-type names): 0x1=vertex, 0x2=line, 0x4=triangle, 0x5=quad, 0x6=tetra, 0x7=pyramid, 0x8=wedge, 0x9=hexahedron, 0x22=line3, 0x23=quad9, 0x24=triangle6, 0x25=quad8, 0x26=tetra10, 0x27=pyramid13, 0x28=wedge15, 0x29=wedge18, 0x30=hexahedron20, 0x31=hexahedron24, 0x32=hexahedron27 (and further codes 0x33..0x40 for the higher-order hexahedra, in both engines).
Data mapping
Attribute Name="..." maps generically to point_data/cell_data; field_data travels in an Information element holding [num_tag, dim] per key, read from XDMF2 and XDMF3 files and, since the parity work (roadmap 3.3.7), written by both engines: the payload is the XML <main><map key=".." dim="..">tag</map></main>, escaped as text (not CDATA, which ElementTree cannot emit; every XML parser hands the two back identically). Only integer [tag, dim] pairs have this form; any other field_data array is skipped with a warning.
<Set> elements ↔ named regions (v16.27.0): SetType Node → point, Cell → cell, Face/Edge → side. A side region spanning 3-D and 2-D cells is written as one Face and one Edge set and read back as one region; dim and tag ride in <Information> children. Read by both engines.
Time-series writers use the same encoding for regions on the shared static mesh, including empty named groups. Every time step inherits them through XInclude, and native reads retain them even with points_only=True or an array filter. Python's array-based series writer takes regions= in write_points_cells, and TimeSeriesReader.regions is populated by read_points_cells. Region membership is fixed for the series; step-local or time-varying sets are not implemented. See shared named regions.
Quirks & limitations
- XDMF2 vs XDMF3: the native reader accepts both major versions through the same topology, geometry and array decoder, including selective reads and metadata summaries. Unsupported major versions fail by name.
- XDMF2 uses
TopologyType/GeometryType; XDMF3 accepts either that or the shorterType, but errors if both are given on the same element simultaneously. - A
Reference="XML"/Reference="<xpath>"attribute on aDataItemresolves anotherDataItemin the same document.XMLtakes the absolute XPath from element text; the other spelling takes it from the attribute. Native full, selective and metadata reads share target validation: relative paths, missing/ambiguous targets, non-DataItem targets and cycles raiseReadError. General XInclude expansion and cross-document references are not implemented. - The only supported node count for a Mixed-topology
line(Polyline) entry is exactly 2 — anything else raisesReadError. - Both engines cover the same type table, through the higher-order
hexahedron64..hexahedron1331. data_format="HDF"is handled by the C++ core only when built withMESHIO_WITH_HDF5andcompression in (None, "gzip"); otherwise Python handles it viah5py.- Points are restricted to dimension ≤3 on write (
WriteErrorotherwise).
Time series
Temporal XDMF is written/read with the TimeSeriesWriter/TimeSeriesReader classes — see XDMF time series. The write side also exists natively as meshioplusplus::XdmfTimeSeriesWriter (C++) and mio_xdmf_series_* (C API); it is deliberately absent from the shared format registry, since a series is a stateful multi-call object rather than a (path, mesh) call. On the read side, read_xdmf resolves a temporal collection structurally and honours ReadOptions::mTimeStep, and read_metadata reports every step's <Time Value> in mTimeValues — so meshioplusplus.read() on a series no longer fails with "only supports one grid", it returns the first step.
Notes
- No reference fixture exists under
tests/python/meshes/xdmf/; tests use synthetic meshes across all threedata_formatvalues.