PERMAS (.post, .dato)
The PERMAS data-file format: $-delimited keyword sections in plain text, optionally gzip-compressed.
| Format name | permas |
| Extensions | .post, .post.gz, .dato, .dato.gz |
| Read / Write | ✓ / ✓ |
| Extra dependencies | — |
Reading & writing
import meshioplusplus
mesh = meshioplusplus.read("model.post")
meshioplusplus.permas.write("out.post", mesh)write takes no keyword arguments.
File structure
Lines starting ! are comments and are skipped. A keyword line is $KEYWORD[=...] (leading $ stripped, upper-cased for matching).
$COOR...→ node block: lines<gid> <x> <y> <z...>(split on single spaces — multiple consecutive spaces create empty tokens, which are not filtered here), read until a$/!line, building agid → running indexmap.$ELEMENT TYPE=<permas type>→ element block: lines are<running_index> <node gid> <node gid> ..., resolved through the node-gid map. PERMAS uses a trailing!as a line-continuation marker: node ids accumulate across lines until one does not end in!, at which point the accumulated ids are emitted as one completed cell.$NSET/$ESETblocks are parsed (includingGENERATE, expanding exactly 3 idsstart,end,stepvianp.arangewith an exclusive stop, i.e. literal Pythonrangesemantics rather than an inclusive PERMAS/Abaqus- style generate) but the parsed sets are never attached to the returned Mesh — this is a currently-dead read path.- Everything else is silently ignored ("too many PERMAS keywords to explicitly skip").
Write emits: !PERMAS DataFile Version 18.0, a header line crediting meshio++ (!written by meshio++ v<version> from the Python writer, !written by meshio++ (C++ core) from the C++ writer), $ENTER COMPONENT NAME=DFLT_COMP, $STRUCTURE, $COOR, then node rows (sequential 1-based index, not the original PERMAS gid — none is tracked on write), then per element type a ! separator + $ELEMENT TYPE=... + rows (<running_id> <n1+1> ..., id counting continuously across all cell blocks), then $END STRUCTURE / $EXIT COMPONENT / $FIN.
Cell types
| PERMAS | meshio++ | PERMAS | meshio++ |
|---|---|---|---|
PLOT1 | vertex | HEXFO8 | hexahedron |
FSCPIPE2 (and 10 other beam/rod names) | line | HEXE20 | hexahedron20 |
PLOTL3 | line3 | HEXE27 | hexahedron27 |
TRIMS3 (and 6 other names) | triangle | TET4 | tetra |
TRIMS6 | triangle6 | TET10 | tetra10 |
SHELL4 (and 5 other names) | quad | PYRA5 | pyramid |
QUAMS8 | quad8 | PENTA6 | wedge |
QUAMS9 | quad9 | PENTA15 | wedge15 |
(Several PERMAS names collapse onto one meshio++ type on read; the write-side reverse map picks one canonical name per meshio++ type as shown, determined by Python dict-insertion-order "last wins" — the C++ port hardcodes the resulting map directly to guarantee it matches.)
Write-only node-order permutation for second-order elements (no analogous reorder exists on read — see quirks):
| type | permutation |
|---|---|
triangle6 | [0, 3, 1, 4, 2, 5] |
tetra10 | [0, 4, 1, 5, 2, 6, 7, 8, 9, 3] |
quad9 | [0, 4, 1, 7, 8, 5, 3, 6, 2] |
wedge15 | [0, 6, 1, 7, 2, 8, 9, 10, 11, 3, 12, 4, 13, 5, 14] |
Data mapping
None — PERMAS produces no point_data/cell_data/field_data at all; $NSET/$ESET are parsed but discarded (see above).
Quirks & limitations
- Asymmetric quadratic-element round-trip: the four second-order node reorder tables above are applied only on write — there is no inverse permutation on read. A file written by meshio++ and read back by meshio++'s own reader would therefore not restore the original meshio++ node order for
triangle6/tetra10/quad9/wedge15without external correction. $NSET/$ESETsets are read into local dicts but never surface on the returnedMesh— effectively dead code in the current reader.- The
!-continuation parsing is essential to get right: a standalone!separator line between element blocks must yield no cell (not an empty one) — getting this wrong previously caused an out-of-bounds crash on a multi-block mesh during development of the C++ port, now fixed and covered by tests. GENERATEset expansion uses exclusive-stopnp.arange(start, end, step)semantics, not an inclusive range — a possible off-by-one relative to true PERMAS/Abaqus-styleGENERATE(moot in practice since sets are discarded regardless).
Notes
- The C++ core handles the plain-text
.post/.datofiles. The gzip.gzcontainers fall back to the Python implementation. - No reference fixture exists under
tests/meshes/permas/; tests round-trip synthetic meshes and check.post/.post.gz/.0.post/.0.post.gzextension/suffix dispatch.