Skip to content

Kratos / MDPA (.mdpa)

The Kratos Multiphysics model-part data format: block-structured ASCII (Begin ... / End ...). This is the largest and most feature-rich format meshio++ supports — it has no C++ implementation.

Format namemdpa
Extensions.mdpa
Read / Write✓ / ✓
Extra dependencies

Reading & writing

python
import meshioplusplus

mesh = meshioplusplus.read("model.mdpa")
meshioplusplus.mdpa.write("out.mdpa", mesh, float_fmt=".16e", binary=False)
  • float_fmt — coordinate format.
  • binary — MDPA is ASCII-only; passing binary=True raises WriteError unconditionally.

File structure

A single pass over Begin <X> ... End <X> blocks:

  • ModelPartDatakey value pairs (// comments stripped) → field_data[key] (parsed as float when possible, else kept as a string).
  • Nodes — rows of either id x y z or bare x y z (auto-detected by column count).
  • Elements <KratosType> / Conditions <KratosType> — the header's Kratos type name is matched by exact match first, then by longest-substring match (to avoid e.g. "Line" ambiguously matching inside "Line3D2"); each row is id property_id node_ids.... If the type can't be resolved from the header at all, it's inferred purely from node count. Property ids become gmsh:physical/gmsh:geometrical-style tags (MDPA reuses gmsh's tag-key convention here).
  • Geometries <Type> — like Elements/Conditions but with no property id column; stored separately as mesh.geometries_block (not part of mesh.cells), a non-standard mesh-level attribute.
  • Table <id> <var1> <var2> ... — rows until End Table; a malformed header (too few parts, non-integer id, no variables) is warned-and- skipped; stored as field_data[f"table_{id}"] = {"variables": [...], "data": ndarray}.
  • Properties <id> — key/value pairs (auto-typed float → int-if-integer → else string) plus any nested Table blocks, stored under field_data[f"properties_{id}"].
  • NodalData <VAR[n]> / ElementalData/ConditionalData <VAR> — values per entity; missing entities are densified with NaN. An optional leading "fixed" flag column (0/1) is heuristically detected (only treated as a flag if the value is exactly 0/1 and more numeric values follow on the same row) — if any fixed-status is seen, a parallel {var}_fixed_status array is produced (sentinel -1 = "not specified"). Scalar (0-component) variables are treated as boolean-by-presence: listed ids get 1, unlisted get 0.
  • SubModelPart <Name> (nestable, joined with / for a hierarchical key e.g. "Outer/Inner") — sub-blocks SubModelPartData, SubModelPartTables, SubModelPartNodes (0-based, validated against the point count), SubModelPartElements/Conditions (raw 1-based ids kept unconverted, explicitly to preserve exact round-trip values). Not implemented: SubModelPartGeometries, Constraints sub-blocks.
  • Mesh <id> [name] — an alternate/coarser mesh representation; id=0 is invalid per Kratos convention and skipped with a warning. Sub-blocks: MeshData, MeshNodes (0-based, validated), MeshElements/Conditions (raw 1-based ids kept as-is).

All of the round-trip-only bookkeeping above (element/condition/geometry id maps, SubModelPart hierarchy, alternate-mesh data) accumulates in mesh.misc_data — a non-standard mesh attribute specific to this format.

Cell types & node ordering

The Kratos type tables (Geometries/Elements/Conditions) are large; a representative slice:

Kratosmeshio++Kratosmeshio++
Line2D2, Element3D2NlineTetrahedra3D4, Element3D4Ntetra
Line2D3, LineElement3D3Nline3Tetrahedra3D10tetra10
Triangle2D3, Element3D3NtriangleHexahedra3D8, Element3D8Nhexahedron
Triangle2D6, Element2D6Ntriangle6Hexahedra3D20hexahedron20
Quadrilateral2D4, Element2D4NquadHexahedra3D27hexahedron27
Quadrilateral2D8quad8Prism3D6, Element3D6Nwedge
Quadrilateral2D9quad9Element3D5Npyramid
Point2D, Element2D1NvertexElement3D13N/15Nwedge15

Quadratic hexahedron node-order permutation (the format's key gotcha, applied only for hexahedron20/hexahedron27) — read applies the argsort of the Kratos-order array below; write applies the array itself directly (a true inverse pair):

hex20 kratos order: [0,1,2,3,4,5,6,7,8,11,10,9,16,19,18,17,12,13,14,15]
hex27 kratos order: [0,1,2,3,4,5,6,7,8,11,10,9,16,19,18,17,12,15,14,13,
                      20,23,21,24,22,25,26]

All other cell types are assumed to already share meshio++'s VTK-style ordering (no permutation applied).

Data mapping

MDPA has an unusually rich set of data keys, several structured differently from every other format meshio++ supports:

  • field_data[key]ModelPartData scalars.
  • field_data[f"table_{id}"]{"variables": [...], "data": ndarray}.
  • field_data[f"properties_{id}"] — a dict, possibly containing nested table_<id> entries.
  • point_data[VAR] — Kratos variable names verbatim (e.g. TEMPERATURE, DISPLACEMENT as an (n,3) array from a DISPLACEMENT[3] header).
  • point_data[f"{VAR}_fixed_status"] — sentinel -1/0/1.
  • cell_data[<meshio_type>]["gmsh:physical"]/["gmsh:geometrical"]/[VAR] — unlike every other meshio++ format, MDPA's cell_data is nested by cell type name as an inner dict ({cell_type: {var: array}}), not the usual flat {var: [array_per_block]} convention.
  • mesh.misc_data — non-standard attribute: reader_element_ids_info, reader_condition_ids_info, mdpa_geometry_ids_info, submodelpart_info, meshes.
  • mesh.geometries_block — non-standard attribute, a list of CellBlocks from Begin Geometries.

Quirks & limitations

  • The cell_data nested-by-type structure ({cell_type: {var: array}}) is a genuine structural departure from meshio++'s usual flat convention — code consuming MDPA-read meshes needs to account for this specifically.
  • The h20/h27 permutation tables are applied directly on write (not their inverse) and via argsort on read — this is intentional and correct (the two operations really are exact inverses of each other), but worth internalizing since it looks asymmetric at first glance.
  • SubModelPartElements/Conditions and MeshElements/Conditions store raw, unconverted 1-based ids rather than remapped local indices — this assumes element/condition ids are stable across a read→write cycle (true unless entities are reordered in between).
  • Malformed rows in almost every block type (bad Table headers, data-row/variable-count mismatches, out-of-range SubModelPartNodes entries) are warned-and-skipped rather than raising — MDPA parsing is deliberately lenient/best-effort given how varied real Kratos input decks are.
  • Writing ElementalData/ConditionalData omits any entity that was entirely NaN (never had data) rather than writing NaN literally.
  • No C++ implementation exists for this format at all.

Notes

  • tests/meshes/mdpa/test_small_cube.mdpa — a small unit-cube tet mesh.
  • tests/meshes/mdpa/test_submodelpart.mdpa — a 2D quad mesh with a nested SubModelPart containing Nodes/Elements/Conditions/empty-Geometries/ empty-Constraints sub-blocks.
  • Additional tests/input/mdpa/test_*.mdpa fixtures target node-order permutation edge cases, minimal/degenerate geometries, hierarchical SubModelParts, and varied Table layouts.
  • tests/test_mdpa.py also builds many MDPA snippets inline (not as files) covering nearly every block type, including a test_roundtrip_all_blocks exercising almost all of them at once with a NaN-aware comparison helper.

Released under the MIT License.