I-DEAS Universal — UNV (.unv)
The I-DEAS Universal File format is an ASCII interchange format used by SDRC I-DEAS, Salome, Code-Aster and many FE tools. A file is a sequence of datasets, each delimited by a line containing only -1, followed by a dataset-id line and the dataset's records.
| Format name | unv |
| Extensions | .unv |
| Read / Write | ✓ / ✓ |
| Extra dependencies | — |
Reading & writing
import meshioplusplus
mesh = meshioplusplus.read("mesh.unv") # or meshioplusplus.unv.read("mesh.unv")
meshioplusplus.unv.write("out.unv", mesh)write accepts two optional keyword arguments:
code_aster=False— whenTrue, field data is written as the legacy datasets 55 (node data) and 57 (element data) instead of dataset 2414, matching the Code-Aster convention.node_dataset=2411— the node dataset id to emit;781is also accepted.
read takes no keyword arguments.
File structure
-1
2411
<node records>
-1
-1
2412
<element records>
-1
-1
2467
<group records>
-1Datasets are split by scanning for lines that strip to exactly "-1"; the line right after such a delimiter is the numeric dataset id, and everything up to the next -1 is the dataset body.
2411 / 781 — nodes
Two-line records: label CS1 CS2 color (only label, field 0, is used), followed by a coordinate line. Coordinates may use Fortran exponent notation (D/d instead of E/e), which is normalized before float() parsing. Node labels are arbitrary integers (not necessarily 1..N or contiguous); a label → 0-based index map is built while reading so later datasets (elements, groups) can resolve them.
2412 — elements
Record 1 is 6 integers: label fedesc pid ... ... num_nodes (fields 0, 1, 2, 5 are used; fields 3-4 are ignored). If fedesc is one of the four beam descriptors (11, 21, 22, 24), an extra 3-integer orientation record follows immediately and is discarded on read, always rewritten as 0 0 0 on write — beam orientation data does not round-trip through meshioplusplus. Node-label records follow, gathered (possibly across several lines) until num_nodes labels have been collected.
2467 / 2477 / 2452 / 2435 / 2432 / 2430 — permanent groups
All six of these dataset ids share the same record layout and are accepted on read (FEconv parity); dataset 2467 is used on write. Record 1 has ≥8 integers; field 7 is the entity count n. The next line is the group name. Then 4*n integers follow, laid out as (entity_type, tag, 0, 0) quadruples (typically 2 quadruples — 8 integers — per line). Entity type 8 = node → the group becomes a point_sets entry; entity type 7 = element → cell_sets. Other entity types are collected internally but never emitted.
2414 / 55 / 56 / 57 — field (results) data
Result fields map to point_data (data at nodes) and cell_data (data on elements). The 2414 dataset (the default on write) carries a dataset name (→ the data key, de-duplicated on collision), a location code (1 = nodes, 2 = elements, 3 = nodes-on-elements), and a data characteristic / value count that gives the number of components: 1 (scalar), 3 (vector), 6 (symmetric tensor) or 9 (general tensor), stored as the array's inner dimension. The legacy datasets 55 (nodes) and 57 (elements) carry the same information in a shorter header and are what write(..., code_aster=True) emits; 56 (nodes-on-elements) is read but, like 2414 location 3, is skipped with a warning (barycenter averaging is not implemented). Complex data is likewise skipped. The reserved key unv:pid is never written as a field (it is the element property id carried by dataset 2412).
Cell types & node ordering
The FE descriptor id (record-1 field 1 of a 2412 dataset) selects the element type:
| descriptor(s) | meshio++ type | descriptor(s) | meshio++ type |
|---|---|---|---|
| 11, 21 | line | 112 | wedge |
| 22, 24 | line3 | 113 | wedge15 |
| 41, 81, 91 | triangle | 115 | hexahedron |
| 42, 82, 92 | triangle6 | 116 | hexahedron20 |
| 44, 84, 94, 122 | quad | 111 | tetra |
| 45, 85, 95 | quad8 | 118 | tetra10 |
On write, one canonical descriptor is chosen per meshio++ type: line→21 (beam), line3→24 (beam), triangle→91, triangle6→92, quad→94, quad8→95, tetra→111, tetra10→118, wedge→112, wedge15→113, hexahedron→115, hexahedron20→116.
Cell types with no standard UNV descriptor (e.g. pyramid, quad9, 0-D vertex) are skipped with a warning on write rather than emitted with an invented, non-interoperable descriptor; an unrecognized descriptor on read is likewise skipped with a warning rather than being a fatal error.
Parabolic (second-order) elements use the Salome/Code-Aster mid-node "sandwich" ordering — corner, mid-node, corner, mid-node, … — which differs from meshio++'s "all corners, then all edge nodes" convention. The full permutation table (meshio_position[i] = unv_position[table[i]] on read; inverse applied on write) is:
| type | permutation |
|---|---|
line3 | [0, 2, 1] |
triangle6 | [0, 3, 1, 4, 2, 5] |
quad8 | [0, 4, 1, 5, 2, 6, 3, 7] |
tetra10 | [0, 4, 1, 5, 2, 6, 7, 8, 9, 3] |
wedge15 | [0, 6, 1, 7, 2, 8, 9, 10, 11, 3, 12, 4, 13, 5, 14] |
hexahedron20 | [0, 8, 1, 9, 2, 10, 3, 11, 12, 13, 14, 15, 4, 16, 5, 17, 6, 18, 7, 19] |
Data mapping
cell_data["unv:pid"]— the element's physical/material property id (record-1 field 2 of the 2412 dataset); defaults to1on write if absent.point_sets/cell_sets— from permanent-group datasets, keyed by group name (node groups →point_sets, element groups →cell_sets).point_data/cell_data(other thanunv:pid) — from / to field datasets 2414 (or 55/57), keyed by the field name.
Quirks & limitations
- Beam-type orientation data (the extra record after beam elements) is read and discarded; the writer always emits a placeholder
0 0 0record — this is a genuinely lossy round-trip for beam-oriented meshes. - Node/element labels need not be contiguous or 1-based; meshio++ maintains explicit label→index maps throughout so groups referencing raw labels resolve correctly regardless of numbering gaps.
- The C++ core implements nodes (2411/781), elements (2412), permanent groups (2467 and its aliases, via the
UnvInfoside-channel) and field datasets (2414 + legacy 55/57); the shim only falls back to the Python reference for buffer targets. Groups (point_sets/cell_sets) travel out of band because they are not part of the numpy conversion layer — see theUnvInfoside-channel, analogous toAnsysInfo. - Nodes-on-elements field data (2414 location 3, dataset 56) and complex field data are read but skipped with a warning (barycenter averaging / complex values are not implemented).
Notes
- Implemented against the FEconv format documentation and its FE-descriptor table.
- No reference fixture exists under
tests/meshes/unv/; tests round-trip synthetic meshes covering every supported linear and parabolic type, plus an explicittest_groupsexercisingpoint_sets/cell_sets.