Skip to content

Node ordering ​

meshio++ stores every cell in the VTK node order. A format that numbers the nodes of an element differently needs a permutation on the way in and its inverse on the way out. Since v16.0.0 those permutations live in one registry, keyed by (format, cell type):

  • C++: detail/node_order.hpp, node_order(format, cell_type);
  • Python: meshioplusplus._node_order, node_order(fmt, cell_type), to_meshio(...) and from_meshio(...).

A type with no entry uses the identity. Every entry holds both directions as gather tables:

  • to_meshio[k] is the file slot meshio++ node k comes from on read: meshio[k] = file[to_meshio[k]];
  • from_meshio[j] is the meshio++ node written to file slot j: file[j] = meshio[from_meshio[j]].

Most tables are their own inverse, but not all. MED's hexahedron27 is not, and a writer that reused its read table would scramble the face centres, so a format never has to know.

What is in the registry ​

FormatCell types with a permutationPinned against
medtetra, pyramid, wedge, hexahedron and their quadratic forms up to wedge18/hexahedron27MEDCoupling's CellModel.cxx edge and face tables (orientation and mid-edges); hexahedron27/wedge18 (v16.0.0) against a file written by MED-fichier itself and Code_Aster's MED reader
code_asterwedge15, wedge18, hexahedron20, hexahedron27Code_Aster's gmsh reader (inigms.F90) exactly, and its MED reader (lrmtyp.F90) up to a symmetry of the reference cell; see Code_Aster
elmerhexahedron20, hexahedron27ElmerSolver's elements.def reference coordinates and its own VTU writer's Elmer2VtkIndexes permutation; gmsh meshes converted by ElmerGrid read back node for node as meshio++'s gmsh reader reads them (v16.2.0); see Elmer
febio (.feb and .xplt)hexahedron27the shape functions of FEHex27 in FEBio's FECore/FESolidElementShape.cpp (the mid-height face centres run y−, x+, y+, x−); FEBio's own parsers and plot files, read against FEBio 4.12 (v16.2.0); see FEBio
fluxtetra, tetra10, pyramid, wedge, wedge15, hexahedron, hexahedron20FEconv's FLUX samples: every solid is VTK's element mirrored (base face clockwise); read through these tables all have positive Jacobians and mid-edge nodes at edge midpoints, and equal their I-DEAS UNV twins row for row. wedge15 has no sample and follows the same rule
frdhexahedron20, wedge15, line3ccx 2.23 output for the same .inp
patranhexahedron20, wedge15the Patran Reference Manual's Element Library (the vertical mid-edges come before the top ring), with fixtures written from its edge lists (v16.5.0); see Patran
libmeshhexahedron20, hexahedron27, wedge15, wedge18libMesh's own VTK connectivity (cell_hex20.C, cell_hex27.C, cell_prism15.C, cell_prism18.C); every element type of libMesh's tests/meshes/xdrio_elements samples reads with positive volumes and its higher-order nodes where meshio++'s tables put them (v16.7.0); see libMesh
radiosshexahedron20gmsh's getVertexRAD for /BRIC20 (bottom ring, vertical mid-edges, top ring), confirmed by OpenRadioss users (discussion #2809) (v16.7.0); see Radioss
z88hexahedron, hexahedron20, tetra10Z88's hexahedra list the face its manual draws on top first (read as-is, every hexahedron of the Z88OS examples has a negative volume), and its tet10 mid-edges run 2-4, 3-4, 1-4 (the mid-edge positions of Z88OS example b11); Z88R solves the decks written through these tables (v16.7.0); see Z88
mphtxt (also mphbin)quad, pyramid, hexahedron, triangle6, quad9, tetra10, pyramid14, wedge18, hexahedron27COMSOL's "Mesh Element Numbering Conventions" (corners in tensor order, then the quadratic lattice in lexicographic order), real COMSOL files (deal.II, FEconv, Wolfram FEMAddOns), and AWS Palace's COMSOL-to-gmsh tables composed with the gmsh ones (v16.1.0)
unvline3, triangle6, quad8, quad9, tetra10, pyramid13, wedge15, hexahedron20gmsh's .unv/.msh twins and Salome's SMESH driver

The gmsh, CGNS, GiD, Exodus and Kratos tables still live in their own readers. They move here when those formats are next touched (roadmap §1.8).

MSC Marc (v16.8.0) has no entry because it needs none: every Marc element type meshio++ reads, quadratic ones included, numbers its nodes in meshio++'s order (checked on real Marc Mentat decks: every cell positively oriented, every mid-edge node at its edge's midpoint). See Marc.

Self-test ​

tests/cpp/test_node_order.cpp and tests/python/test_node_order.py check every entry the same way:

  • it is a permutation of its cell type's node count, and its two directions are inverses;
  • a reference element (mid-edge nodes on midpoints, face and body centres on centroids) written through from_meshio and read back through to_meshio is again a valid, positively oriented element;
  • the C++ and Python tables are identical;
  • the code_aster tables equal Code_Aster's gmsh reader composed with the gmsh tables, and agree with its MED reader composed with the med tables.

Released under the MIT License.