Skip to content

CLI Reference ​

The meshioplusplus command-line tool is installed alongside the Python package.

meshioplusplus --version
meshioplusplus --help
meshioplusplus <subcommand> --help

The same verbs are also available as a standalone native C++ binary that needs no Python interpreter and no pybind11 extension — see Native CLI (C API) for how to build it (build/configure.sh --cli --build), or download a ready-to-run, statically-linked build for Linux/macOS/Windows from the GitHub Releases page. It has no Python fallback for formats whose C++ reader raises. Named sets are regions in the core: info prints them, diff compares them, and single-mesh convert -s/-d converts point/cell sets↔scalar integer data. Neither conversion flag combines with selective reads or sequences; use the pipeline SetsToData / DataToSets steps instead. Everything below otherwise applies identically to both, except for the verbs each section marks Python only: the grid-* family, subsample, proximity-graph, predict, guard-fit/guard-check and dataset have no native binary counterpart (the native binary does have a surface alias for extract-surface, not documented as its own section since it behaves identically).


meshioplusplus convert ​

Convert a mesh file from one format to another.

meshioplusplus convert [options] INFILE OUTFILE
OptionShortDescription
--input-format FORMAT-iForce input format (skip extension detection)
--output-format FORMAT-oForce output format
--ascii-aWrite ASCII variant (default: binary where available)
--appendedWrite a .vtu's arrays as raw binary in one <AppendedData> section, no base64 (see VTU); any other output format is an error (a series output such as .pvd/.pvtu/.pvtp included, since its pieces are not named vtu), and it is mutually exclusive with --ascii
--float-format FMT-fFloat format string for ASCII output (default: .16e)
--sets-to-int-data-sConvert point/cell sets to integer data arrays
--int-data-to-sets-dConvert integer data arrays to point/cell sets
--jsonPrint a JSON summary of what was written (see JSON output)

CAD geometry — a Kratos CAD JSON, STEP or IGES input converted to a .cad.json output carries its B-rep (the NURBS faces, trimming loops and edges) rather than its sampling, in both CLIs: meshioplusplus convert part.step part.cad.json turns a CAD model into Kratos IGA geometry (STEP and IGES reading needs the OpenCASCADE backend).

Transient sequences — treat a set of files, or the steps inside one file, as one dataset (see sequences):

OptionDescription
--input FILEAn extra input file, appended after INFILE; repeatable
--times T1,T2,...Explicit per-step times; the count must match
--time-from WHICHauto (default), file, filename or index
--sequenceForce sequence handling
--no-sequenceForce single-file handling (for a filename containing * or {step})
bash
meshioplusplus convert 'out_*.vtu' series.xdmf          # fan-in (quote the glob!)
meshioplusplus convert series.xdmf 'step_{step}.vtu'    # fan-out
meshioplusplus convert a.vtu --input b.vtu out.xdmf     # pre-expanded argv

Quote the pattern. A shell expands out_*.vtu before the CLI sees it, so the unquoted form arrives as a dozen positionals and fails on the argument count; use --input when something else has already expanded the glob.

Ordering is natural-numeric, so out_10.vtu follows out_9.vtu. A multi-step input aimed at a single-step output is an error naming {step} and --time-step, never a silent write of step 0 — pass --time-step=N when you genuinely want one step.

Data-driven colouring (SVG/TikZ/glTF output only):

OptionDescription
--color-by NAMEpoint_data or cell_data array to colour the faces by
--component IComponent of a multi-component array (default: its magnitude)
--cmap NAMEviridis (default), coolwarm, turbo, magma, inferno, plasma, grey or synthwave (an original neon palette for the synthwave theme, not perceptually uniform), or a reversed _r variant of any
--vmin V / --vmax VColour range (default: the drawn faces' finite range)
--nan-color CColour for NaN/infinite values (default: #808080 / gray)
--colorbarAppend a gradient bar with min/max labels (SVG/TikZ only)

Point data colours a face by the mean of its corner values, cell data by its owning cell's value — for a volume mesh, found through the skin's surface:parent_cell provenance. For glTF output the array is baked into the linear COLOR_0 vertex colour of the exported surface — point data per vertex, cell data per triangle — and the material becomes unlit; see glTF. --color-by with any other output format is an error, as is any of the modifier flags without --color-by. See the SVG and TikZ format pages for the full semantics.

glTF output options (.glb/.gltf only; either is an error for any other output format):

OptionDescription
--split-angle DEGDuplicate vertices where the surface creases by more than DEG degrees, 0 to 180 (default 30)
--up-axis {auto,x,y,z}The source axis that points up (default auto: y for a flat mesh, else z)

Examples:

sh
meshioplusplus convert mesh.msh mesh.vtu
meshioplusplus convert -i gmsh -o vtk mesh.msh mesh.vtk
meshioplusplus convert --ascii mesh.msh mesh.vtu
meshioplusplus convert --sets-to-int-data mesh.inp mesh.xdmf
meshioplusplus convert mesh.msh skin.stl   # volume mesh -> boundary-skin STL

# colour a vector figure by a field
meshioplusplus convert mesh.vtu figure.svg --color-by temperature --colorbar
meshioplusplus convert mesh.vtu figure.tikz --color-by damage --cmap coolwarm \
    --vmin 0 --vmax 1

# a web-native surface (glTF), coloured by a field
meshioplusplus convert result.vtu result.glb --color-by temperature --cmap turbo
meshioplusplus convert part.vtu part.glb --split-angle 45 --up-axis z

Converting a 3D volume mesh to STL, PLY or glTF writes its extracted boundary skin (the writers' default — see Skin extraction); converting to SVG or TikZ renders it with the default isometric camera.

JSON output ​

Every verb that prints a report takes --json: info (with or without --fast), quality, check, diff, convert, stats, regions, data info, data integrate, pipeline, feature-edges, segment, fit-primitives, tessellate, region-adjacency, find-interface, contact-pairs, split-interface, hausdorff, periodic, agglomerate and resample, and the Python-only guard-check, grid-spectrum and dataset list. The output is always strict JSON — a non-finite number is null, never a bare NaN — and both CLIs print the same shape for every verb they share: the same keys, strings, integers, booleans and nulls, and floats that round-trip (tests/python/test_cli_json.py holds the shared reports to it). The shapes are the Python API's own reports:

VerbJSON
info --fastread_metadata's dict: num_points, point_dim, num_cells, cell_blocks (type, num_cells, nodes_per_cell, ragged), the three *_data_names, format, time_values, regions, provenance, provenance_recognised, fell_back_to_full_read, and bbox_min/bbox_max when the header gives them
infothe same counts and names from a full read, plus consistent and num_unused_points (null when inconsistent)
qualitycompute_quality's dict without the per-cell arrays
checkcheck_quality's dict: passed, the counts and checks
diffdiff's report plus equal (the exit-code decision); the Python CLI adds its sets section
convertinput, output, num_points, num_cells, cell_blocks, the data names and num_regions; for a sequence, mode, num_steps and num_files
agglomeratecells_in, cells_out, num_faces_merged and num_rejected
resamplemethod, num_steps and the target times
segmentnum_patches, num_merged, num_feature_edges, num_boundary_edges and num_non_manifold_edges
fit-primitivesnum_patches, one count per type (num_plane … num_torus) and num_unfitted
iga-refine, iga-sampleoperation, model (nurbs or brep), num_patches, num_points, num_cells and cell_blocks
iga-evaluatenum_points, space_dim, points, fields (components, values), and with --derivatives 1 derivatives and normals; for a B-rep face inside; arrays flattened row-major
tessellateTessellation.schema without version: levels, curved, the source and output counts, stencil_width and the watertight facet counts
to-cadvalid, tolerance, the volumes and their ratio, max_deviation, the faces by type (num_bspline, num_fillet and num_helical among them, and of those num_variable_fillet, num_blend and num_rounded_thread), num_vertex_blend and num_chamfer (v17.2.0) and, of the fillets and threads, num_conic_blend, num_tapered_thread and num_variable_pitch_thread, num_faceted_faces, num_patches, num_demoted, the exact and approximated edges, num_solids and num_split_patches
region-adjacencyfacets and measure
find-interfacepair counts, area, maximum gap, unmatched counts and both Side-entry lists
contact-pairsnum_pairs, the pair table and unmatched slave-point ids
split-interfaceduplicated-point and cohesive-cell counts

The exit codes are unchanged by --json.


meshioplusplus info ​

Print a summary of a mesh file.

meshioplusplus info [options] INFILE
OptionShortDescription
--input-format FORMAT-iForce input format
--fastSummarize from the file header instead of loading it
--jsonPrint the summary as JSON (see JSON output)

Output includes: number of points, cell blocks and their types/counts, point/cell/side sets (see Named regions), point/cell data names, field data names. It also warns if cells reference nonexistent points or if there are unused points.

Example:

sh
meshioplusplus info mesh.msh

meshioplusplus quality ​

Print a per-cell mesh quality report (min/mean/max and counts of inverted/degenerate cells).

meshioplusplus quality [options] INFILE
OptionShortDescription
--input-format FORMAT-iForce input format
--output FILE-oAlso write the metrics into FILE as cell_data
--jsonPrint the report as JSON

Examples:

sh
meshioplusplus quality part.vtu
meshioplusplus quality part.vtu -o part_quality.vtu

meshioplusplus check ​

The quality gate: score every cell and test thresholds on the per-cell values. Exits 0 when every check passes, 1 when one fails, 2 when the check could not run (an unreadable file, a malformed specification).

meshioplusplus check [options] INFILE
OptionShortDescription
--require SPEC-rThresholds, e.g. "scaled_jacobian >= 0.2; aspect_ratio <= 5 @ 1%" (repeatable)
--gate FILERead thresholds from FILE, one clause per line, # comments
--max-inverted NThe most inverted cells allowed; negative disables (default 0)
--max-degenerate NThe most degenerate cells allowed; negative disables (default 0)
--jsonPrint every check as JSON
--input-format FORMAT-iForce input format

Example — a CI step:

sh
meshioplusplus check part.vtu -r "scaled_jacobian >= 0.2" -r "aspect_ratio <= 5 @ 1%" \
    || { echo "mesh failed its quality gate"; exit 1; }

meshioplusplus extract-surface ​

Extract the boundary surface/edges of a mesh (volume → faces, 2D surface → edges) and write it out.

meshioplusplus extract-surface [options] INFILE OUTFILE
OptionShortDescription
--input-format FORMAT-iForce input format
--output-format FORMAT-oForce output format
--parent-ids-pRecord each facet's parent cell id as cell_data

Examples:

sh
meshioplusplus extract-surface part.vtu surface.stl
meshioplusplus extract-surface --parent-ids part.vtu surface.vtu

The native binary also accepts surface as an alias for this verb; the Python CLI does not.


meshioplusplus reorder ​

Renumber a mesh's nodes/elements to reduce matrix bandwidth (RCM) or improve cache locality (Morton / Hilbert), as a pure permutation.

meshioplusplus reorder [options] INFILE OUTFILE
OptionShortDescription
--method METHOD-mrcm (default), morton, or hilbert
--report-rPrint the connectivity bandwidth before and after
--input-format FORMAT-iForce input format
--output-format FORMAT-oForce output format

Examples:

sh
meshioplusplus reorder part.vtu reordered.vtu
meshioplusplus reorder part.vtu reordered.vtu --method hilbert
meshioplusplus reorder part.vtu reordered.vtu --method rcm --report

Interface and contact commands ​

region-adjacency writes conforming shared facets for named Cell regions (or cell blocks when fewer than two Cell regions exist). find-interface matches boundary facets by shared node ids or geometric proximity; contact-pairs projects a Point region to master facets and prints a CSV table unless --json is requested; split-interface duplicates point fans along an existing Side region or explicit Side-entry pairs. See Interfaces and contact for matching, index and cohesive-element conventions.

sh
meshioplusplus region-adjacency parts.vtu shared.vtu --regions upper,lower --json
meshioplusplus find-interface parts.vtu interface.vtu --region-a upper --region-b lower --mode proximity --gap-tolerance 0.01 --json
meshioplusplus contact-pairs slave.vtu master.vtu --slave-region nodes --master-region skin --output pairs.csv
meshioplusplus split-interface parts.vtu split.vtu --side-region crack --add-cohesive --json
meshioplusplus split-interface parts.vtu split.vtu --side-entries '[[4,2],[7,0]]'

find-interface and contact-pairs accept separate input files; their region selectors are Cell regions for facets and a Point region for slave nodes, respectively. region-adjacency --regions accepts comma-separated names (repeat the option to append groups; the Python CLI also accepts space-separated names). In split-interface, side-entry cell ids are zero-based global cell ids and local-facet ordinals are zero-based.


meshioplusplus diff ​

Compare two meshes and report whether they are equivalent within a tolerance. The exit code is nonzero when the meshes differ and zero when they are equal, so it drops straight into CI / shell scripts / Makefiles.

meshioplusplus diff [options] INFILE_A INFILE_B
OptionShortDescription
--atol ATOLAbsolute tolerance in `abs_err <= atol + rtol*
--rtol RTOLRelative tolerance (default 1e-9)
--unorderedMatch points by spatial proximity (tolerant to a shuffled node order)
--exactOnly a bitwise-identical result passes (tolerated drift exits nonzero)
--quiet-qPrint nothing; communicate equality only via the exit code
--jsonPrint the report as JSON, plus equal
--input-format-a FORMATForce the format of the first file
--input-format-b FORMATForce the format of the second file

Examples:

sh
meshioplusplus diff a.vtu b.vtu
meshioplusplus diff a.vtu b.vtu --atol 1e-8 --rtol 1e-6
meshioplusplus diff a.msh b.vtu --unordered
meshioplusplus diff expected.vtu actual.vtu --quiet || echo "regression!"

meshioplusplus merge ​

Merge two or more mesh files into one.

meshioplusplus merge [options] FILE... OUTFILE

Takes two or more input meshes followed by the output file.

OptionShortDescription
--input-format FORMAT-iForce input format (applied to every input)
--output-format FORMAT-oForce output format
--weldMerge coincident nodes within --atol
--atol ATOLCoincidence tolerance for --weld (default 1e-8)
--data-policy POLICYintersection (default, keep only data keys present in every input) or fill (keep every key, filling missing rows with NaN)
--drop-duplicate-cellsWith --weld, drop cells that become identical after welding
--no-source-tagDo not add the per-cell source_mesh_id tag
--quiet-qDo not print the merge summary

Prints a summary of points/cells in and out (and points welded, with --weld) unless --quiet is given.

Examples:

sh
meshioplusplus merge a.vtu b.vtu merged.vtu
meshioplusplus merge a.vtu b.vtu c.vtu merged.vtu --weld --atol 1e-6
meshioplusplus merge a.vtu b.vtu merged.vtu --data-policy fill

meshioplusplus transform ​

Apply an affine transform to a mesh's point coordinates (see transform).

meshioplusplus transform [options] INFILE OUTFILE
OptionDescription
--translate x,y,zTranslation
--scale sx,sy,szPer-axis scale (or a single scalar for uniform)
--rotate axis,degRotation; axis is x/y/z or nx,ny,nz (angle in degrees)
--matrix m00,...,m33A row-major 4×4 affine matrix (16 values)
--scale-units FACTORUniform unit-scale factor (e.g. 0.001)
--rotate-dataAlso rotate vector/tensor point_data by the transform
--input-format / --output-format (-i/-o)Force input/output format

Give exactly one transform source. Values starting with - need the = form (--translate=-1,0,0).

Examples:

sh
meshioplusplus transform in.vtu out.vtu --translate 1,2,3
meshioplusplus transform in.vtu out.vtu --rotate z,90
meshioplusplus transform in.vtu out.vtu --scale-units 0.001

meshioplusplus clean ​

Weld / prune / de-dup a mesh in one pass (see clean).

meshioplusplus clean [options] INFILE OUTFILE
OptionDescription
--weldFuse coincident points within --atol
--atol ATOLWeld tolerance (default 1e-8)
--remove-orphansDrop unused points
--drop-degenerateDrop degenerate cells
--drop-duplicatesDrop exact-duplicate cells
--input-format / --output-format (-i/-o)Force input/output format

With no step flags, the default set runs (remove-orphans + drop-degenerate + drop-duplicates, no weld). A removal summary is printed.

Examples:

sh
meshioplusplus clean in.vtu out.vtu
meshioplusplus clean in.vtu out.vtu --weld --atol 1e-6

meshioplusplus crop ​

Extract part of a mesh — inside a bounding box, inside a half-space, or the cells a cell_data comparison selects (see crop).

meshioplusplus crop [options] INFILE OUTFILE
OptionDescription
--bbox xmin,ymin,zmin,xmax,ymax,zmaxAxis-aligned bounding box
--plane px,py,pz,nx,ny,nzHalf-space (point + normal), keep (p−point)·normal ≥ 0
--where 'NAME OP VALUE'A scalar cell_data predicate, OP one of <, <=, >, >=, ==, !=. A non-finite cell value never matches
--mode all|anyKeep a cell if ALL (default) or ANY node is inside. --bbox/--plane only
--record-idsAttach original point/cell ids as data arrays
--input-format / --output-format (-i/-o)Force input/output format

Give exactly one of --bbox/--plane/--where. Negative values need the = form (--bbox=-1,-1,-1,1,1,1). --mode alongside --where is an error rather than being ignored: a per-cell value has nothing for an all/any rule to reduce.

Examples:

sh
meshioplusplus crop in.vtu out.vtu --bbox 0,0,0,1,1,1
meshioplusplus crop in.vtu out.vtu --plane 0.5,0,0,1,0,0 --mode any
meshioplusplus crop in.vtu out.vtu --where 'quality:scaled_jacobian < 0.3'

# inside a surface, composed:
meshioplusplus sdf shell.stl field.vtu --resolution 64,64,64 --location center
meshioplusplus crop field.vtu inside.vtu --where 'sdf:distance < 0'

meshioplusplus slice ​

Compute the planar cross-section of a mesh — the intersection with a plane, one dimension below the cut cells (a volume mesh → a triangle/quad surface, a 2D surface → a line mesh). See slice.

meshioplusplus slice [options] INFILE OUTFILE
OptionDescription
--origin x,y,zA point on the cutting plane (default 0,0,0)
--normal x,y,zThe plane normal (default 0,0,1; non-zero)
--record-parent-idsAttach slice:parent_cell (the input cell each section cell was cut from)
--input-format / --output-format (-i/-o)Force input/output format

Negative components need the = form (--normal=0,0,-1). Unlike crop, which keeps whole cells on one side, slice computes the intersection itself.

Examples:

sh
meshioplusplus slice in.vtu section.vtu --origin 0,0,0.5 --normal 0,0,1
meshioplusplus slice part.msh section.vtu --normal=0,0,-1 --record-parent-ids

meshioplusplus isosurface ​

Compute the level set(s) of a scalar point_data field — the data-driven sibling of slice, and like it one dimension below the cut cells (a volume mesh → a triangle/quad surface, a 2D surface → a line contour). See isosurface.

meshioplusplus isosurface [options] INFILE OUTFILE
OptionDescription
--array NAMEThe point_data array to contour (required)
--values v1,v2,…The isovalues (required); sorted ascending, duplicates dropped
--component IComponent of a multi-component array; the row magnitude by default
--record-parent-idsAttach iso:parent_cell (the input cell each contour cell was cut from)
--input-format / --output-format (-i/-o)Force input/output format

Negative isovalues need the = form (--values=-1.5). A cell_data name is rejected: cell data is piecewise constant and has no level set — convert it with meshioplusplus data to-point first. Every contour cell is tagged with iso:value (Float64) and iso:index (Int64, the ordinal — the integer tag split --by region --tag … needs).

Examples:

sh
meshioplusplus isosurface part.vtu shell.vtu --array T --values 350
meshioplusplus isosurface part.vtu shells.vtu --array T --values 300,350,400
meshioplusplus isosurface part.vtu shell.vtu --array v --values=-1.5 --component 2

# one file per contour, via the integer ordinal tag
meshioplusplus split shells.vtu 'contour_{key}.vtu' --by region --tag iso:index

meshioplusplus split ​

Partition a mesh into several files by type, region, named Cell regions, or connected component (see split).

meshioplusplus split [options] INFILE OUTPATTERN

OUTPATTERN must contain {key}, replaced by each piece's key.

OptionDescription
--by type|region|regions|componentSplit criterion (default type)
--tag NAMEFor --by region: the integer cell_data name to split on (unused by regions)
--input-format / --output-format (-i/-o)Force input/output format

Prints how many pieces were produced and their sizes. --by regions (plural) is one piece per named Cell region and is not a partition — a cell in several regions lands in several pieces, and Point/Side regions produce no piece at all. Run meshioplusplus regions first to see what a mesh's regions are.

Examples:

sh
meshioplusplus split in.vtu 'out_{key}.vtu' --by type
meshioplusplus split in.vtu 'out_{key}.vtu' --by component
meshioplusplus split in.inp 'part_{key}.vtu' --by regions

meshioplusplus regions ​

List a mesh's named regions — name, kind, dimension, tag, and entry count (not the entries themselves).

meshioplusplus regions [options] INFILE [OUTFILE]
OptionDescription
--input-format (-i)Force input format
--output-format (-o)Force output format (with edits)
--jsonEmit the regions as JSON
--union OUT=A,B[,...]Add OUT, the union of regions A, B, ...
--intersection OUT=A,B[,...]Add OUT, the entries in every one of them
--difference OUT=A,B[,...]Add OUT, the entries of A in none of the others
--rename OLD=NEWRename a region
--retag NAME=TAG[:DIM]Set a region's tag (and dimension); NAME=:DIM keeps the tag
--delete NAMERemove a region
--drop-inputsThe set operations remove their input regions

With any edit flag it edits the regions instead of listing them: the edits apply in command-line order to the mesh read from INFILE, the result is written to OUTFILE, and the resulting region list is printed. A region name may be prefixed point:, cell: or side: to pick one of several regions sharing a name; a name that still matches several, or none, is an error.

Goes through the same cheap path info --fast/read_metadata use rather than a full read: whenever the summary already comes from an in-memory mesh (every format lacking a native metadata path, plus Exodus, which always falls back), regions cost nothing extra to report; the native metadata paths of VTU/VTP/XDMF (since v16.27.0) and Gmsh 4.1 read them from their headers and array sizes.

Example:

sh
meshioplusplus regions bracket.inp
# <meshio++ mesh regions> (2)
#   fixed (point, 12 entries, tag=1)
#   solid (cell, 340 entries, dim=3, tag=2)
sh
meshioplusplus regions model.msh bc.msh --union inlet=inlet_a,inlet_b \
    --difference wall=skin,inlet,outlet --retag side:wall=10 --delete scratch

meshioplusplus stats ​

Print geometric statistics of a mesh (see stats).

meshioplusplus stats [options] INFILE
OptionDescription
--jsonEmit the statistics as JSON
--input-format (-i)Force input format

Prints the bounding box, extent, centroid, per-cell-type counts, total area, signed/unsigned volume, and inverted-cell count. This complements info (which is topological) with geometric measures.

Examples:

sh
meshioplusplus stats mesh.vtu
meshioplusplus stats mesh.vtu --json

meshioplusplus convert-cells ​

Convert a mesh's element representation (see convert_cells). Distinct from convert, which changes the file format.

meshioplusplus convert-cells [options] INFILE OUTFILE
OptionDescription
--mode linearize|simplexify|elevateConversion to perform (default linearize)
--record-parent-idsAttach convert:parent_cell cell_data of the source cell indices
--input-format / --output-format (-i/-o)Force input/output format

linearize drops higher-order nodes (tetra10 → tetra) and prunes the points that become unreferenced; simplexify decomposes cells into simplices of the same dimension (hexahedron → 6 tetra); elevate promotes linear cells to serendipity quadratic (triangle → triangle6), adding a node per unique edge. A polyhedron block under simplexify, and quad9/hexahedron27 under elevate, are errors.

Examples:

sh
meshioplusplus convert-cells in.msh out.vtu --mode linearize
meshioplusplus convert-cells in.msh out.vtu --mode simplexify --record-parent-ids
meshioplusplus convert-cells in.msh out.vtu --mode elevate

meshioplusplus tessellate ​

Isoparametric subdivision of a mesh's five higher-order cell types onto a refinement lattice, so a curved cell becomes a set of ordinary linear ones a downstream tool can render or mesh further (see curved tessellation).

meshioplusplus tessellate [options] INFILE OUTFILE
OptionDescription
--levels NDivisions per axis of the reference lattice (default 2)
--no-curvedDisable curved-cell handling entirely (a full no-op)
--no-fieldsDo not interpolate point_data/cell_data onto the output
--record-stencilAlso attach tessellate:stencil/weights as real point_data (expensive; needed to reconstruct a Tessellation after a file round trip)
--jsonPrint the report as JSON instead of the summary
--quiet (-q)Suppress the summary output
--input-format / --output-format (-i/-o)Force input/output format

A provenance map (Tessellation.gather/.scatter/.aggregate) moves data between the tessellated mesh and its source; the summary reports num_curved_source_cells/num_pass_through_source_cells and whether the output is watertight. --json prints the full report, the same keys from both CLIs: levels, curved, num_source_points, num_source_cells, num_curved_source_cells, num_pass_through_source_cells, num_points, num_cells, stencil_width and a watertight object with num_boundary_facets, num_interior_facets and num_facets_with_bad_count (zero for a conforming tessellation) — Tessellation.schema without its version.

Examples:

sh
meshioplusplus tessellate curved.msh flat.vtu
meshioplusplus tessellate curved.msh flat.vtu --levels 4 --record-stencil
meshioplusplus tessellate curved.msh flat.vtu --json

meshioplusplus subdivide ​

Polyhedrally refine a mesh: split every eligible 3D cell into one polyhedral child per face, connected to a new interior point (see subdivide). Distinct from refine, which is built on fixed same-type templates and raises by name on a polyhedron.

meshioplusplus subdivide [options] INFILE OUTFILE
OptionDescription
--record-parent-idsAttach subdivide:parent_cell cell_data of the source cell indices
--input-format / --output-format (-i/-o)Force input/output format

No per-type template table is needed: tabulated types (reduced to corners for a quadratic variant) and existing polyhedron blocks are handled uniformly. Automatically conforming — no closure flag, unlike refine. Non-3D blocks and the full-Lagrange family (no face table) pass through unchanged.

Example:

sh
meshioplusplus subdivide bracket.msh bracket_subdivided.vtu --record-parent-ids

meshioplusplus agglomerate ​

Polyhedrally coarsen a mesh: merge groups of cells into single larger polyhedral cells via greedy seed-and-grow over the shared-face dual (see agglomerate). Distinct from decimate, whose fixed-template QEM edge collapse has no analogue for merging arbitrary polyhedral cells.

meshioplusplus agglomerate [options] INFILE OUTFILE
OptionDescription
--target-group-size NApproximate member cells per output group (default 8)
--merge-coplanar-facesFuse the coplanar faces two groups (or a group and the boundary) share into one polygon
--coplanar-angle DEGLargest normal deviation still coplanar (default 1)
--min-sphericity SRefuse an absorption that would drop a group's sphericity below S (default 0, off)
--jsonPrint cells_in, cells_out, num_faces_merged and num_rejected as JSON
--input-format / --output-format (-i/-o)Force input/output format

Non-volume blocks pass through unchanged; points are never pruned or renumbered (clean --remove-orphans is the follow-up for a minimal point set). Conserves volume exactly. --target-group-size 1 groups every cell by itself.

Example:

sh
meshioplusplus agglomerate fine.vtu coarse.vtu --target-group-size 8
meshioplusplus agglomerate fine.vtu coarse.vtu --merge-coplanar-faces --min-sphericity 0.7 --json

meshioplusplus resample ​

Resample a transient sequence onto new times, holding at most two source steps in memory (see Resampling onto new times).

meshioplusplus resample [options] INPUT OUTPUT (--times SPEC | --times-from PATTERN)

INPUT is a quoted glob ('out_*.vtu') or the first file, with --input for each further one. OUTPUT is a {step}/{index} pattern (one file per target time) or a series file of a format that carries time.

OptionDescription
--times SPECThe target times: START:STOP:STEP (STOP included) or a comma list T1,T2,...
--times-from PATTERNTake the target times from another sequence (a quoted glob), resolved with the same --time-from
--method Mlinear (default; blend the bracketing steps), nearest or previous
--clampA target outside the source range takes the end step instead of failing
--blend-pointsBlend the point coordinates too (a moving mesh)
--time-from SRCWhere the source times come from: auto (default), file, filename or index
--input FILEAn extra input file, appended after INPUT; repeatable
--input-format (-i)Force the input format
--jsonPrint method, num_steps and the target times as JSON

Examples:

sh
meshioplusplus resample 'run/out_*.vtu' 'uniform/u_{index}.vtu' --times 0:2:0.1
meshioplusplus resample 'fine/out_*.vtu' fine_on_coarse.xdmf --times-from 'coarse/out_*.vtu'

meshioplusplus refine ​

Refine a mesh, subdividing cells into same-type children — every cell, or a selected subset with a conforming closure (see refine).

meshioplusplus refine [options] INFILE OUTFILE
OptionDescription
--levels NHow many times to subdivide (default 1)
--record-parent-idsAttach refine:parent_cell cell_data of the original cell indices
--cells i,j,kRefine only these global (block-major) cells
--region NAMERefine a named region (a cell region selects its cells, a point region every cell touching it; a side region is an error)
--where "EXPR"Refine the cells satisfying a threshold on a scalar cell_data array, e.g. "quality:scaled_jacobian < 0.3"
--closure redgreen|propagate|balancedHow to resolve hanging nodes (default redgreen)
--record-levelsAttach refine:level cell_data of each cell's refinement depth
--record-hierarchyAttach refine:cell_id/refine:parent_id cell_data — the persistent parent/child hierarchy a multigrid caller resolves across the sequence of meshes it keeps; also forces refine:entity to be attached even when the closure leaves no hanging node
--input-format / --output-format (-i/-o)Force input/output format

At most one of --cells, --region and --where may be given; with none, every cell is refined. --closure redgreen keeps the extra refinement local — a single refined quadrilateral costs one row of a structured grid, a hexahedron one dual sheet. --closure propagate is defined for every cell type but reaches the whole edge-connected component, so on a connected mesh it is the uniform refinement. --closure balanced does not close at all: it keeps the hanging nodes and only enforces 2:1 balance, so the output is not conforming (the constrained nodes are listed in refine:hanging) but the cost is bounded by the selection — one cell of a 4×4×4 block costs 7 extra cells, against 61 and 448.

One level splits a triangle/quad into 4 and a tetra/wedge/hexahedron into 8, inserting nodes at edge, quad-face and body midpoints. Those nodes are shared between neighbouring cells, so the result has no hanging nodes, and point_data is interpolated onto them. Higher-order cells, pyramid, and ragged polygon/polyhedron blocks have no same-type subdivision and are errors — convert-cells --mode linearize (or --mode simplexify) first.

Note the cell count grows as 4^levels (2D) or 8^levels (3D), so --levels 3 is already a 512× increase on a volume mesh.

Examples:

sh
meshioplusplus refine in.msh out.vtu
meshioplusplus refine in.msh out.vtu --levels 2
meshioplusplus refine coarse.vtu fine.vtu --levels 2 --record-parent-ids
meshioplusplus refine coarse.vtu graded.vtu --cells 12,13,44 --record-levels
meshioplusplus refine coarse.vtu graded.vtu --where "quality:scaled_jacobian < 0.3"
meshioplusplus refine coarse.vtu fine.vtu --cells 12,13 --record-hierarchy

meshioplusplus undo-green ​

Restore a transitional (green) cell back to its coarse parent, read verbatim from the COARSE mesh — the standard "restore and re-split from scratch" rule for a selective refinement pass over a region a prior pass already closed up (see green-element undo). A two-mesh verb, like interpolate.

meshioplusplus undo-green [options] COARSE FINE OUTFILE
OptionDescription
--quiet (-q)Suppress the undo summary
--input-format / --output-format (-i/-o)Force input (both files) / output format

FINE must be the output of a prior refine COARSE FINE --record-hierarchy --record-levels call (both flags — --record-hierarchy alone does not imply --record-levels); it fails by name otherwise, or when a refine:parent_id cannot be resolved against COARSE's id space. The six reserved refine:* arrays are dropped from the output. Only a single-pass (--levels 1) hierarchy is supported.

Examples:

sh
meshioplusplus refine coarse.vtu fine.vtu --cells 12,13 --record-hierarchy --record-levels
meshioplusplus undo-green coarse.vtu fine.vtu restored.vtu
meshioplusplus refine restored.vtu regraded.vtu --cells 44,58 --record-hierarchy --record-levels

meshioplusplus decimate ​

Reduce a surface mesh's face count by quadric-error-metric edge collapse — the resolution-reducing inverse of refine (see decimation).

meshioplusplus decimate [options] INFILE OUTFILE
OptionDescription
--ratio RFraction of the (triangulated) faces to KEEP, in (0, 1]
--target-faces NAbsolute face count to stop at (within one collapse)
--max-error ECollapse only while the cheapest quadric error is at most E
--placement Poptimal (default), midpoint, or endpoint
--no-preserve-boundaryAllow boundary vertices to collapse (the outline may change)
--no-preserve-featuresAllow sharp corners/creases to collapse
--feature-angle ADegrees between face normals above which a vertex is a feature (default 30)
--quiet (-q)Do not print the collapse summary
--input-format / --output-format (-i/-o)Force input/output format

Exactly one of --ratio, --target-faces and --max-error must be given. Surface meshes only: quad/polygon blocks are triangulated first (the output is all-triangle), and a volume mesh is an error — run extract-surface first. Boundary and feature vertices are pinned by default, and the link condition plus a normal-flip guard reject any collapse that would change topology or fold the surface.

Examples:

sh
meshioplusplus decimate scan.stl coarse.stl --ratio 0.25
meshioplusplus decimate skin.vtu coarse.vtu --target-faces 5000
meshioplusplus decimate skin.vtu coarse.vtu --max-error 1e-6 --placement midpoint
meshioplusplus decimate open_patch.vtu out.vtu --ratio 0.1 --no-preserve-features -q

meshioplusplus decimate-volume ​

Reduce a tetrahedral mesh's cell count by quadric-error-metric tet-edge collapse — the volume-mesh sibling of decimate, a separate verb rather than a mode on it (see volume decimation).

meshioplusplus decimate-volume [options] INFILE OUTFILE
OptionDescription
--ratio RFraction of the tets to KEEP, in (0, 1]
--target-cells NAbsolute tet count to stop at (within one collapse)
--max-error ECollapse only while the cheapest boundary-touching quadric error is at most E
--placement Poptimal (default), midpoint, or endpoint
--preserve-boundaryPin every boundary vertex outright, reproducing decimate's own default instead of letting boundary vertices participate
--no-preserve-featuresAllow sharp boundary corners/creases to collapse
--feature-angle ADegrees between boundary-triangle normals above which a vertex is a feature (default 30)
--quiet (-q)Do not print the collapse summary
--input-format / --output-format (-i/-o)Force input/output format

Exactly one of --ratio, --target-cells and --max-error must be given. Tet meshes only: a non-tetra 3D block is an error — run convert-cells --mode simplexify first. Note --preserve-boundary is opt-in here, the mirror image of decimate's opt-out --no-preserve-boundary — boundary vertices participate in decimation by real quadric error by default. Validity guards reject any collapse that would change topology, invert a tet, or (for boundary-touching collapses) fold the outer surface.

Examples:

sh
meshioplusplus decimate-volume solid.vtu coarse.vtu --ratio 0.25
meshioplusplus decimate-volume solid.vtu coarse.vtu --target-cells 5000
meshioplusplus decimate-volume solid.vtu coarse.vtu --max-error 1e-6 --placement midpoint
meshioplusplus decimate-volume solid.vtu coarse.vtu --ratio 0.1 --preserve-boundary -q

meshioplusplus remesh ​

Replace a surface mesh's own triangulation with a new, near-uniformly-sized, well-shaped one at a caller-chosen vertex count, by approximated centroidal Voronoi diagram (ACVD) clustering (see remeshing).

meshioplusplus remesh [options] INFILE OUTFILE
OptionDescription
--num-clusters NTarget output vertex count (required)
--subdivide NUniform refine passes applied before clustering; -1 (default) auto-picks from --subsample-ratio
--subsample-ratio RTarget items per cluster driving the auto-subdivide pick (default 10)
--max-subdivide NCap on the auto-picked subdivide count (default 4)
--iterations NEnergy-minimisation sweeps (default 10)
--repair-passes NMax repair passes for disconnected/non-manifold clusters (default 3)
--metric isotropic|quadric|anisotropicClustering metric (default isotropic)
--gradation GCurvature-weighting exponent; 0 (default) disables curvature weighting entirely
--no-preserve-boundaryLet boundary-adjacent triangles drop from the dual instead of emitting a boundary line block
--max-anisotropy Ametric anisotropic only: cap on a vertex's principal-curvature-length ratio (default 4)
--quiet (-q)Do not print the clustering summary
--input-format / --output-format (-i/-o)Force input/output format

The output is a brand-new mesh with new points and new connectivity — there is no point/cell map, and point_data/cell_data/named regions are dropped (field_data passes through); transfer a field with interpolate/conservative-interpolate afterwards. --metric anisotropic shapes clusters with a per-vertex curvature tensor rather than isotropic distance, so elongated features (a fillet, a pipe, a rib) get elongated elements; --max-anisotropy is an error under any other --metric.

Examples:

sh
meshioplusplus remesh bracket.stl out.vtu --num-clusters 5000
meshioplusplus remesh bracket.stl out.vtu --num-clusters 5000 --metric quadric
meshioplusplus remesh bracket.stl out.vtu --num-clusters 5000 --metric anisotropic --max-anisotropy 4
meshioplusplus remesh bracket.stl out.vtu --num-clusters 2000 --gradation 1.5 --no-preserve-boundary -q

meshioplusplus remesh-volume ​

Retetrahedralize a volume mesh (or a closed surface) at a caller-chosen resolution by isosurface stuffing over a body-centered cubic (BCC) lattice — the volumetric sibling of remesh (see volumetric remeshing). Unlike remesh, this accepts a volume mesh directly; its boundary is extracted internally.

meshioplusplus remesh-volume [options] INFILE OUTFILE
OptionDescription
--resolution nx,ny,nzCell counts of the root lattice (exactly one of --resolution/--cell-size)
--cell-size SCubic cell size of the root lattice
--bounds xlo,ylo,zlo,xhi,yhi,zhiExplicit bounds; the mesh's own bounding box by default (negatives need the --bounds= form)
--padding PGrow the box by this on every side, in world units
--padding-relative RGrow the box by this fraction of its diagonal (default 0.1)
--max-cells NRefuse to generate a root lattice above this many cells
--max-tets NRefuse an output with more tets than this (checked after cutting; unlike --max-cells, has no "lifts the limit" value)
--warp-fraction FFraction of a lattice vertex's shortest incident edge within which it may be warped onto the surface; 0 disables warping (default 0.35; negatives need the --warp-fraction= form)
--sign pseudonormal|winding-numberHow lattice vertices are classified inside/outside
--watertight-check off|warn|errorWhat to do about a non-watertight input surface (default warn)
--quiet (-q)Do not print the run summary
--input-format / --output-format (-i/-o)Force input/output format

The output is a brand-new single-tetra-block mesh with new points and new connectivity — there is no point/cell map, and point_data/cell_data/named regions are dropped (field_data passes through); transfer a field with interpolate/conservative-interpolate afterwards. Warping (--warp-fraction) trades a small, measured chance of non-manifold boundary edges (reported as non-manifold edges in the summary) for substantially better boundary tet quality; --warp-fraction 0 gives an exactly watertight but lower-quality boundary. See the measured tradeoff.

Examples:

sh
meshioplusplus remesh-volume part.vtu out.vtu --cell-size 0.5
meshioplusplus remesh-volume part.vtu out.vtu --resolution 64,64,64 --warp-fraction 0.2
meshioplusplus remesh-volume surface.stl out.vtu --cell-size 0.3 --watertight-check error

meshioplusplus optimize-volume ​

ODT-remesh a tetrahedral mesh: raise its worst element quality by relocating vertices AND flipping connectivity (2-3/3-2, predicate-free) — the genuine "ODT remeshing" sibling of remesh-volume (which generates a fresh lattice mesh) and of smooth --method odt (which only moves points on fixed connectivity). See ODT remeshing.

sh
meshioplusplus optimize-volume [options] INFILE OUTFILE
OptionDescription
--max-iterations Noptimisation sweeps (relocation + flips); stops early at a fixed point (default: 10)
--no-relocateskip the ODT vertex-relocation half (flips only)
--no-flipskip the topological-flip half (reduces to ODT smoothing)
--no-preserve-boundaryallow boundary vertices to move during relocation (may drift off the surface)
--min-improvement Estrict scaled-Jacobian gain a flip must deliver to be accepted (default: 1e-6)
--quiet, -qsuppress the summary

The point set is invariant, so point_data/field_data and named Point regions carry through; cell_data and Cell/Side regions are dropped (a flip has no cell correspondence). With --no-preserve-boundary off (the default) the boundary surface is exactly preserved. Tet-only: a non-tetra block errors pointing at convert-cells --mode simplexify.

Examples:

sh
meshioplusplus optimize-volume volume.vtu optimized.vtu
meshioplusplus optimize-volume volume.vtu optimized.vtu --max-iterations 20

meshioplusplus curvature ​

Per-vertex mean and Gaussian curvature of a surface, by the angle defect and the cotangent Laplace-Beltrami operator (see curvature).

meshioplusplus curvature [options] INFILE OUTFILE
OptionDescription
--no-meanDo not attach curvature:mean
--no-gaussianDo not attach curvature:gaussian
--dual-area mixed-voronoi|barycentricDual area each curvature is divided by (default mixed-voronoi)
--include-boundaryCompute a biased value at boundary vertices instead of leaving them NaN
--record-areaAlso attach curvature:area, the dual area each curvature was divided by
--record-principalAlso attach curvature:principal, the (n, 2) pair k1 >= k2
--region NAMERestrict to this named cell region (default: every surface cell)
--quiet (-q)Suppress the summary output
--input-format / --output-format (-i/-o)Force input/output format

Runs over no input array at all, like quality/stats. The summary reports the total angle defect against its Gauss-Bonnet expectation (2*pi*chi, 4*pi for a closed genus-0 surface), the boundary/isolated/degenerate counts, and the input's surface quality.

Examples:

sh
meshioplusplus curvature scan.stl scan_k.vtu
meshioplusplus curvature part.vtu part_k.vtu --record-principal --include-boundary

meshioplusplus normals ​

Attach the point and cell normals of a surface, optionally splitting vertices at creases so every point carries exactly one normal (see normals).

meshioplusplus normals [options] INFILE OUTFILE
OptionDescription
--cellAlso attach the cell normals
--no-pointDo not attach the point normals
--weight angle|areaHow incident faces are weighted into a point normal (default angle)
--split-angle DEGDuplicate points where the surface creases by more than DEG degrees, 0 to 180 (default: no split)
--record-parent-idsAttach normals:parent_point, the input point each output point came from
--region NAMERestrict to this named cell region (default: every surface cell)
--quiet (-q)Suppress the summary output
--input-format / --output-format (-i/-o)Force input/output format

The arrays are named normals, so writing to .pcd or .xyz emits the normal columns. Points added by a split are appended after the original points and cells keep their numbering. The operation never reorients: the summary reports the input's edge defects, and a nonzero inconsistent-edge count means some normals average faces that disagree about which side is out — run repair first. A volume block is refused by name pointing at extract-surface.

Examples:

sh
meshioplusplus normals scan.stl scan_n.vtu
meshioplusplus normals part.vtu part_split.vtu --split-angle 30 --cell
meshioplusplus normals part.vtu cloud.xyz --record-parent-ids

meshioplusplus feature-edges ​

Write the sharp, open, non-manifold and inconsistently wound edges of a surface — or of a volume mesh's skin — as a mesh of line cells (see feature edges).

meshioplusplus feature-edges [options] INFILE OUTFILE
OptionDescription
--angle DEGLargest dihedral angle still treated as smooth, 0 to 180 (default 30)
--no-feature / --no-boundary / --no-non-manifold / --no-inconsistentDo not report that category
--region NAMERestrict to this named cell region
--jsonEmit the edge count and per-category counts as JSON
--quiet (-q)Suppress the summary output
--input-format / --output-format (-i/-o)Force input/output format

The output keeps the input's points and carries cell data feature:kind (1 feature, 2 boundary, 3 non-manifold, 4 inconsistent) and feature:angle.

sh
meshioplusplus feature-edges part.stl part_edges.vtp --angle 45

meshioplusplus segment ​

Split a surface into smooth patches bounded by its feature edges, written as cell data segment:patch, field data segment:adjacency and one cell region per patch (see segment).

text
meshioplusplus segment [options] INFILE OUTFILE
OptionDescription
-i/--input-format, -o/--output-formatExplicit formats
--angle DEGLargest dihedral angle still crossed, [0, 180] (default 30)
--normal-tolerance DEGLargest angle between a cell's normal and its patch seed's (default off)
--curvature-tolerance KLargest curvature-estimate difference from the patch mean, 1/length (default off)
--min-patch-cells NMerge smaller patches into a neighbour (default 1)
--region NAMERestrict to a named cell region
--prefix NAMEPatch regions are named NAME:k (default patch)
--json, -q/--quietMachine-readable counts, or no summary
sh
meshioplusplus segment part.stl part_patches.vtu --curvature-tolerance 1.0 --min-patch-cells 20

meshioplusplus fit-primitives ​

Fit a plane, sphere, cylinder, cone or torus to each patch and write the input with fit:* cell data and fit:patch_* field data (see fit primitives).

text
meshioplusplus fit-primitives [options] INFILE OUTFILE
OptionDescription
-i/--input-format, -o/--output-formatExplicit formats
--patch-data NAMEInteger cell-data patch label (default segment:patch); '' fits the whole surface
--tolerance TAcceptance tolerance on the orthogonal distance (default 1e-3)
--absoluteT is a length, not a fraction of each patch's bounding-box diagonal
--min-inlier-fraction FShare of points that must lie within tolerance (default 0.9)
--types LISTComma-separated candidates from plane,sphere,cylinder,cone,torus (default all)
--max-iterations NLevenberg-Marquardt cap per fit (default 50)
--json, -q/--quietMachine-readable counts, or no summary
sh
meshioplusplus fit-primitives part_patches.vtu part_fits.vtu --tolerance 2e-3 --json

meshioplusplus iga-refine ​

Refine every patch of a NURBS model exactly (degree elevation, then knot insertion) and write the refined model sampled; an MFEM NURBS mesh (-o mfem) or CAD JSON output keeps the refined patches (see isogeometric layer). The input is an MFEM NURBS mesh, CAD JSON, STEP or IGES.

text
meshioplusplus iga-refine [options] INFILE OUTFILE
OptionDescription
-i/--input-format, -o/--output-formatExplicit formats (an MFEM mesh needs -o mfem; .mesh alone means Medit)
-s/--subdivisions N[,M[,L]]Parts every knot span is split into, per direction (default 1; an MFEM model refines every direction alike)
-e/--elevate N[,M[,L]]Degrees to add, per direction, before the knots are inserted (default 0)
--sample-subdivisions NCells per knot span of the sampling (default 0, automatic)
--trim-samples N, --no-edges, --no-trimB-rep sampling: trim curve samples per span (default 16), skip the edge curves, keep cells outside the trimming loops
--json, -q/--quietMachine-readable summary, or no summary
sh
meshioplusplus iga-refine pipe.mesh fine.mesh -o mfem --subdivisions 2 --elevate 1
meshioplusplus iga-refine plate.cad.json fine.cad.json -s 2,3 -e 0,1

meshioplusplus iga-sample ​

Sample a NURBS model into Lagrange cells (see isogeometric layer). Takes iga-refine's input, format, sampling and summary options, with -s/--subdivisions N the cells per knot span and direction (default 0, automatic).

sh
meshioplusplus iga-sample plate.cad.json plate.vtu -s 8

meshioplusplus iga-evaluate ​

Evaluate a patch (a B-rep's face) at parametric coordinates and print the result as JSON (see isogeometric layer).

text
meshioplusplus iga-evaluate [options] INFILE
OptionDescription
-i/--input-formatExplicit input format
-p/--param u[,v[,w]]A parametric point, one number per direction of the patch; repeat for more points
--patch NThe patch (face), 0-based (default 0)
--derivatives 0|11 adds the first derivatives and the surface normals
--trim-samples NB-rep: points per knot span a trimming curve is sampled at (default 16)
sh
meshioplusplus iga-evaluate plate.cad.json -p 0.5,0.5 -p 2,2 --derivatives 1

meshioplusplus to-cad ​

Turn the fitted patches of a closed skin into a CAD solid with analytic faces (and rolling-ball fillet and blend, helical thread and freeform B-spline faces for what no primitive explains) and write it as STEP (see fit CAD). Needs a build with -DMESHIOPLUSPLUS_WITH_OCCT=ON; elsewhere both CLIs fail naming the flag, and the release binaries are such a build. A skin without segment:patch or the fit:patch_* table is segmented and fitted first. Exits with 2 when the solid fails OpenCASCADE's B-rep check.

text
meshioplusplus to-cad [options] INFILE OUTFILE.step
OptionDescription
-i/--input-formatExplicit input format
--curvature-tolerance Csegment's curvature test, for an unsegmented skin (default off)
--min-patch-cells Nsegment's smallest patch, for an unsegmented skin (default 1; a noisy scan wants tens)
--fit-tolerance Tfit_primitives' relative tolerance, for an unfitted skin (default 1e-3)
--tolerance TThe largest distance a face may lie from the skin (default three times the largest accepted patch tolerance)
--no-exact-edgesApproximate every edge between analytic faces with a B-spline
--types LISTFitted types kept as analytic faces, from plane,sphere,cylinder,cone,torus (default all)
--mesh-deflection DChordal deflection of the re-meshed solid (default a quarter of the tolerance)
--max-demotion-rounds NRounds of demoting failed faces before every patch is faceted (default 8)
--no-freeformKeep the patches no primitive explains faceted instead of fitting B-spline faces
--freeform-degree PHighest degree of a freeform face, 3–8 (default 3)
--freeform-max-control NLargest freeform sample grid per direction, 4–1024 (default 64)
--no-freeform-splitLeave a freeform patch that folds over every flattening faceted instead of splitting it into pieces
--no-filletsDo not try a patch between two fitted faces as a rolling-ball fillet or blend
--no-threadsDo not try a patch as a helical thread face
--mesh-out FILEAlso write the re-meshed solid
--cad-json FILEAlso write the solid as Kratos CAD JSON (its faces as trimmed NURBS)
--json, -q/--quietMachine-readable report, or no summary
sh
meshioplusplus to-cad part.stl part.step --curvature-tolerance 1 --min-patch-cells 20 --fit-tolerance 2e-3

meshioplusplus snapshot ​

Draw a mesh with the software rasterizer: in this terminal, or into a .png, .txt, .ansi, .html or .cast file. It needs no display, GPU or browser, so it works over SSH, in a container and in a CI log, in the native release binaries as well as the Python CLI. The two CLIs take the same flags and write the same bytes.

meshioplusplus snapshot [options] INFILE OUTFILE

OUTFILE is - for this terminal; otherwise its extension picks the form.

OptionDescription
--width N / --height NPNG size in pixels (default 800 x 600)
--cols N / --rows NText size in cells (this terminal's, less one row, for -; otherwise 100 x 40)
--encoding NAMEhalfblock (default), quadrant, sextant, braille, ascii, or the graphics protocols kitty, iterm2, sixel
--color-depth NAMEauto (from NO_COLOR, COLORTERM, TERM; the default for -), truecolor (the default for files), 256, 16 or mono
--cell-aspect RHeight over width of a terminal cell (default 2, or the terminal's own when it reports its pixel size)
--tmuxWrap a graphics protocol for tmux passthrough; one is refused inside tmux without it
--no-notesDo not print the colour range and scale bar under a text picture
--view NAMEiso, +x, -x, +y, -y, +z, -z: the side the camera sits on
--azimuth DEG / --elevation DEG / --roll DEGThe camera direction (default: isometric); exclusive with --view
--perspective / --fov DEGA pinhole camera, and its vertical field of view (default 30)
--zoom R / --pan-x R / --pan-y RMagnify the fitted view; shift it by a fraction of the frame
--shading NAMEnone, flat (default) or smooth; --one-sided, --ambient R (default 0.25), --split-angle DEG (default 30)
--edges NAMEnone (default), all element edges, or the feature edges (--feature-angle DEG)
--edge-color / --fill / --line-color / --background#rrggbb, #rrggbbaa or none (transparent)
--point-radius RDisc radius of drawn points, in pixels
--supersample N1 (default), 2 or 4 samples per pixel along each axis
--axes / --scale-barDraw the world axes; a scale bar (orthographic only)
--color-by NAMEColour by a point or cell data array; with --component, --cmap, --vmin, --vmax, --nan-color, --colorbar as for convert
--expr TEXT / --reduce NAMEColour by a data_calc expression, or by mises/hydrostatic/principal of the --color-by tensor array
--clip LOW,HIGH / --symmetricBound the automatic range by percentiles (either end may be empty); make it symmetric about zero
--scale NAME / --scale-threshold Tlinear (default), log or symlog, the last linear within T of zero
--categorical / --color-regions / --category-edgesColour integer data, or the named cell regions, from a fixed palette with a key; draw the edges where categories meet
--isolines N / --iso-levels A,B,... / --iso-colorContour lines of the point array --color-by
--vectors NAME / --vector-count N / --vector-length L / --vector-colorArrows for a vector point array
--streamlines NAME / --stream-seeds N / --stream-length L / --stream-colorStreamlines of a vector point array: about N seeds (default 40) spread at equal area or volume, each line at most L model diagonals (default 0.5) in each direction, over the mesh's own cells; on a volume they run inside it, so add a --cutaway
--warp NAME / --warp-scale S / --warp-outline / --outline-colorMove the points by a displacement array; draw the undeformed outline
--diagnostic NAME / --quality-metric Mquality, inverted, degenerate, orientation, free-edges or edge-length
--cutaway PLANE / --cutaway-tintClip a half-space away (twice at most): PX,PY,PZ,NX,NY,NZ (a point and the normal of the side kept) or AXIS:OFFSET, AXIS one of +x -x +y -y +z -z (+x:0.5 keeps x ≥ 0.5); the back faces then in view are drawn in the tint (default #e88034)
--theme synthwave / --grid-floorAn optional 1980s look: a banded sunset behind the model, neon defaults and the synthwave colormap; a perspective grid under it (see the theme)
--bloom / --fringe / --scanlinesPost-processes on the final frame, in that order, with or without a theme
--png-compress 1..9Compress a PNG through zlib (default: stored blocks, the same bytes everywhere)
--cast-frames N / --cast-fps R / --cast-degrees DEGAn asciicast orbit: frame count (36), rate (12), sweep (360)
--input-format (-i)Force the input format
sh
meshioplusplus snapshot part.vtu -                                   # in this terminal
meshioplusplus snapshot part.vtu part.png --edges feature --axes
meshioplusplus snapshot result.vtu - --color-by temperature --colorbar --cmap turbo --encoding braille
meshioplusplus snapshot part.vtu orbit.cast --cast-frames 72        # asciinema play orbit.cast

--cmap, --vmin, --vmax, --nan-color, --colorbar and --symmetric also apply to --expr and to the quality and edge-length diagnostics; without any of those they are refused by name. See terminal rendering for each option.

Without Polyscope (always, in the release binaries) screenshot draws its PNG through the same rasterizer, and view points at snapshot.


meshioplusplus tui ​

Orbit, zoom and pan a mesh inside this terminal, with no display, GPU or browser: the interactive viewer around the software rasterizer. It needs a terminal on standard input and output, and refuses by name otherwise (use snapshot for one frame to a file or a pipe).

meshioplusplus tui [options] INFILE

The interactive viewer

Drag to orbit, the wheel or + - to zoom, the arrow keys to pan, 1…7 for the named views, p perspective, e edges, s shading, a b c axes, scale bar and colour bar, a click to probe a cell (i pins it), x y z to cut the model away at the middle (, . slide the plane), [ ] to step a series, : for a command line that takes the flags of snapshot, r reset, ? help, q quit. The terminal is restored however it ends; a signal ends it with exit code 128 plus the signal number.

It takes every render option of snapshot (the camera, shading, edges, colouring and field options listed there; the frame size is the terminal's), and:

OptionDescription
--encoding NAMEhalfblock (default), quadrant, sextant, braille, ascii, or kitty, iterm2, sixel (these redraw the whole image on every change)
--color-depth NAMEauto (from NO_COLOR, COLORTERM, TERM; the default), truecolor, 256, 16 or mono
--cell-aspect RHeight over width of a terminal cell (default: the terminal's own when it reports its pixel size, else 2)
--tmuxWrap a graphics protocol for tmux passthrough; one is refused inside tmux without it
INFILE...Several files, or a quoted glob ('out_*.vtu'), make a time series: [ ] step, space plays
--compare FILE / --diff / --separate-rangesDraw a second mesh beside the first under one camera and one colour range; --diff draws |B − A| of the --color-by point array instead of B
--follow / --follow-interval MS / --settle MSWatch the series (or the file) for a new step and show it once its file has stopped changing for --settle ms (default 300)
--fps RSteps per second when playing (default 4)
--session FILERead a session if the file exists and write it when the viewer ends
--replay FILEPlay a recorded input stream on a --cols by --rows screen (default 100 x 40) and print what the viewer writes, instead of using the terminal
--music / --music-out FILE.wavPlay a generated synthwave loop on an external player (silent in CI and over SSH unless --music-over-ssh); or write it to a file for your own player. m mutes, < > change the volume (the soundtrack)
--volume V / --tempo BPM / --music-seed N / --music-key KThe loop's loudness (0.05 to 0.9, default 0.3), tempo (60 to 140, default 100), variation and tonic (C…B or 0 to 11)
--pulse / --reduced-motionWith a theme: step the grid on every beat of --tempo (--music implies it); never, whatever else is asked (also REDUCED_MOTION in the environment)
--input-format (-i)Force the input format
sh
meshioplusplus tui part.vtu
meshioplusplus tui part.vtu --theme synthwave --grid-floor --bloom --music
meshioplusplus tui result.vtu --color-by temperature --colorbar --cmap magma --edges feature
meshioplusplus tui part.vtu --encoding braille --color-depth 256

The Python CLI has the same verb, and meshioplusplus view --backend terminal (Python and native) runs it.


meshioplusplus hausdorff ​

Print the Hausdorff distance between the surfaces of two meshes — how far apart they are at their worst (see Hausdorff distance).

meshioplusplus hausdorff [options] INFILE_A INFILE_B
OptionDescription
--face-samples SAlso sample the centroids of the S*S sub-triangles of every triangle (default 0: vertices only, a lower bound)
--region-a NAME / --region-b NAMERestrict a side to this named cell region of surface cells
--input-format-a FMT / --input-format-b FMTForce a side's input format
--max DExit with status 1 when the distance exceeds D
--jsonEmit the report as JSON (with --max, also max and passed)
sh
meshioplusplus hausdorff part.stl part_decimated.stl --face-samples 4 --max 1e-3

meshioplusplus periodic ​

Match the nodes of two regions that an affine transform maps onto each other — the node pairs of a periodic boundary condition (see periodic node pairs).

meshioplusplus periodic [options] INFILE --slave NAME --master NAME
OptionDescription
--slave NAME / --master NAMEThe region whose nodes are mapped, and the one they map onto
--translate DX,DY,DZSlave-to-master translation
--rotate AXIS,DEGRotation by DEG degrees about AXIS (x, y, z, or AX,AY,AZ), applied before --translate
--origin X,Y,ZThe point the rotation turns about (default: the origin)
--matrix M00,...,M33A row-major 4x4 affine matrix, overriding --translate/--rotate
--atol TOLMatch tolerance (default 1e-8)
--allow-incompleteReport unmatched slave nodes instead of failing
--output FILE (-o)Write the pairs as slave,master CSV rows (0-based ids)
--jsonEmit the pairs as JSON
--input-format (-i)Force input format

Numbers are comma-separated; write a value with a leading minus as --translate=-2,0,0.

sh
meshioplusplus periodic channel.msh --slave inlet --master outlet --translate 2,0,0 -o pairs.csv
meshioplusplus periodic rotor.msh --slave cut_a --master cut_b --rotate z,60 --json

meshioplusplus repair ​

Fix a surface's orientation, holes and pinched vertices — the three defects clean does not touch (see surface repair).

meshioplusplus repair [options] INFILE OUTFILE
OptionDescription
--no-fix-orientationDo not rewind triangles so neighbours across a manifold edge agree
--no-orient-outwardDo not flip closed components whose signed volume is negative
--no-fill-holesDo not fan-fill boundary loops
--no-split-non-manifoldDo not duplicate bowtie (pinched) vertices
--max-hole-edges NLongest boundary loop still filled; <= 0 means no limit (default 10)
--weld-tolerance TWeld coincident points within this distance first, through clean (default 0, off)
--record-provenanceAttach repair:parent_point (point) and repair:hole (cell)
--quiet (-q)Suppress the summary output
--input-format / --output-format (-i/-o)Force input/output format

The passes run in the order weld → triangulate → split bowties → orient → fill holes → orient outward, and the summary reports both the input's and the output's defect counts, so what was fixed and what remains are both visible. Orientation uses the topological half-edge rule — two triangles sharing an edge agree iff they traverse it in opposite directions — which is exact where a normal-angle test mis-orients across a sharp crease. Output is all-triangle at the surface with blocks 1:1 with the input, lower-dimensional blocks carried verbatim, and fill triangles in one trailing triangle block. Non-manifold edges are counted, never split.

Examples:

sh
meshioplusplus repair scan.stl fixed.vtu
meshioplusplus repair scan.stl fixed.vtu --max-hole-edges 0
meshioplusplus repair scan.stl fixed.vtu --weld-tolerance 1e-9
meshioplusplus repair in.vtu out.vtu --no-fill-holes --record-provenance

meshioplusplus shrinkwrap ​

Project a mesh's points onto a target triangle surface (see shrinkwrap).

meshioplusplus shrinkwrap [options] INFILE TARGET OUTFILE
OptionDescription
--offset=XSigned offset along the hit feature's unit pseudonormal (a negative value needs the --offset= form)
--max-distance DLeave points farther than this from the target alone; <= 0 means unlimited
--weights NAMEScalar point_data array on the source: integer/bool selects, float blends (unclamped)
--target-region NAMERestrict the target to this named cell region
--normal-weight angle|areaVertex-pseudonormal weighting of the target (default angle)
--record-distanceAttach shrinkwrap:distance (NaN where not queried)
--record-closest-cellAttach shrinkwrap:closest_cell (-1 where not queried)
--quiet (-q)Suppress the summary output
--target-formatForce the target's format
--input-format / --output-format (-i/-o)Force input/output format

One projection, not an iteration: there is no self-intersection or inversion guard. Every point of the source moves whatever cells it carries — a volume mesh's interior points too — and only the target must be a surface. The offset goes along the hit feature's pseudonormal, which at a crease is the bisector rather than either face's normal.

Examples:

sh
meshioplusplus shrinkwrap template.vtu scan.stl wrapped.vtu
meshioplusplus shrinkwrap template.vtu scan.stl wrapped.vtu --offset=0.5
meshioplusplus shrinkwrap template.vtu scan.stl wrapped.vtu --max-distance 2.0
meshioplusplus shrinkwrap template.vtu scan.stl out.vtu --weights mask --record-distance

meshioplusplus sobolev-deform ​

Filter a raw displacement field through the mesh's own P1 operators, then move the points by it (see Sobolev deformation).

meshioplusplus sobolev-deform [options] INFILE OUTFILE
OptionDescription
--array NAMERequired. The point_data array holding the raw displacement, (n, dim)
--length-scale LRequired. The smoothing length in mesh units; 0 applies the raw field at the free points
--fixed-points-array NAMEAn integer/bool point_data array whose nonzero entries pin their point
--fix-boundaryAlso pin every point on a boundary facet of the top-dimensional cells
--record-filteredAttach sobolev:displacement, the filtered field
--max-iterations NConjugate-gradient iteration cap (default 128)
--tolerance TRelative residual tolerance (default 1e-10)
--quiet (-q)Suppress the summary output
--input-format / --output-format (-i/-o)Force input/output format

Solves (M + l^2 K) u = M d and sets x' = x + u — a screened-Poisson low-pass filter whose cutoff wavelength is the length scale. Every block at the mesh's top topological dimension must be a linear simplex (line, triangle, tetra); lower-dimensional blocks ride along. Nothing is pinned by default, so a constant displacement is preserved exactly in zero iterations. Non-convergence is reported rather than raised, with the last iterate returned.

Examples:

sh
meshioplusplus sobolev-deform in.vtu out.vtu --array d --length-scale 0.5
meshioplusplus sobolev-deform in.vtu out.vtu --array d --length-scale 0.5 --fix-boundary
meshioplusplus sobolev-deform in.vtu out.vtu --array d --length-scale 1.0 --record-filtered

meshioplusplus smooth ​

Relax point coordinates toward their edge-neighbour centroids to improve element shape (see smoothing).

meshioplusplus smooth [options] INFILE OUTFILE
OptionDescription
--method taubin|laplacian|odtSmoothing operator (default taubin, which does not shrink; laplacian is stronger per pass but shrinks; odt is optimal-Delaunay-triangulation smoothing, tet-only and C++-core only, moving each free interior vertex toward the volume-weighted average of its incident tets' circumcenters)
--iterations NHow many iterations to run; for taubin one iteration is two passes (default 10)
--lambda LRelaxation factor of the smoothing pass, in (0, 1); the default depends on --method (0.5 laplacian, 0.33 taubin, 0.9 odt)
--mu=Mtaubin only: un-shrinking factor, must satisfy mu < -lambda < 0 (default -0.34; the negative value needs the --mu= form); silently ignored by laplacian and odt
--no-fix-boundaryLet boundary nodes move too (they are pinned by default)
--no-preserve-featuresDo not pin feature nodes (sharp corners/creases are kept by default)
--feature-angle AAngle in degrees between boundary facet normals above which their shared nodes are pinned as features (default 30)
--no-guard-inversionDo not reject moves that would invert an incident cell
--quiet (-q)Suppress the summary output
--input-format / --output-format (-i/-o)Force input/output format

Only the point coordinates move: connectivity, cell_data, field_data and point_data values come through unchanged, the point and cell counts are unchanged, and the points array keeps its input dtype. Neighbours are the nodes joined by an actual cell edge, so a structured hex block is a fixed point. Nodes of blocks whose edge topology is unknown — the higher-order family, the VTK-Lagrange types, custom — are pinned rather than guessed at. Unless suppressed, the summary reports the number of nodes moved, the largest net displacement, and how many moves the inversion guard rejected.

Examples:

sh
meshioplusplus smooth noisy.vtu smooth.vtu
meshioplusplus smooth noisy.vtu smooth.vtu --iterations 40
meshioplusplus smooth in.msh out.vtu --method laplacian --lambda 0.4
meshioplusplus smooth in.msh out.vtu --mu=-0.4 --feature-angle 45
meshioplusplus smooth in.msh out.vtu --no-fix-boundary --no-guard-inversion -q
meshioplusplus smooth tangled.vtu out.vtu --method odt --iterations 10

meshioplusplus interpolate ​

Sample data arrays from a SOURCE mesh onto a TARGET mesh (see interpolation). The output is a copy of the target — geometry, connectivity and its own data preserved exactly — with the requested source arrays sampled onto it.

meshioplusplus interpolate [options] SOURCE TARGET OUTFILE
OptionDescription
--method nearest|barycentricNearest source point (default; dtype-preserving) or linear interpolation in a simplexified source (exact on a linear field; Float64)
--arrays a,bComma-separated source array names to transfer (default: every source point_data array; cell_data transfers only when named)
--extrapolatebarycentric only: give a target point outside the source domain the nearest source point's value instead of the default value
--default-value=Vbarycentric only: fill value for target points outside the source domain (default 0; negative values need the --default-value= form)
--on-conflict error|overwrite|suffixWhat to do when a transferred name already exists on the target (default error; suffix writes to NAME_interp)
--quiet (-q)Suppress the transfer summary
--input-format / --output-format (-i/-o)Force input (both files) / output format

Source point_data is sampled at the target's points, source cell_data at the target's cell centroids — always by nearest source-cell centroid, whatever the method. Under barycentric the source is simplexified first, so on a quad/hex source the result is the simplex-linear interpolant, and triangle sources are evaluated in the xy-plane (use nearest for a curved surface embedded in 3D).

Examples:

sh
meshioplusplus interpolate coarse.vtu fine.vtu out.vtu
meshioplusplus interpolate coarse.vtu fine.vtu out.vtu --method barycentric
meshioplusplus interpolate a.msh b.msh out.vtu --arrays T,v --on-conflict suffix
meshioplusplus interpolate a.msh b.msh out.vtu --method barycentric --extrapolate

meshioplusplus partition ​

Decompose a mesh into N balanced parts for domain decomposition (see partitioning) — the count-driven complement to split.

meshioplusplus partition [options] INFILE OUTPATTERN

OUTPATTERN must contain {part} (e.g. out_{part}.vtu), expanded once per piece — or be a .pvtu/.pvtp path (or name --output-format pvtu|pvtp) with no {part}, which writes one parallel index over every part plus one piece file each (see PVTU); a {part} token wins over an index extension. With --labels-only it is a single plain path.

OptionDescription
--nparts N (-n)Number of parts (required, >= 1)
--method Msfc (Hilbert curve cut, always available), kahip (KaHIP kaffpa; needs a KaHIP-enabled build, fails by name otherwise), or auto (default: kahip when available, else sfc)
--imbalance FKaHIP only: allowed imbalance fraction in (0, 1) (default 0.03)
--mode MKaHIP only: fast / eco / strong (default eco)
--seed NKaHIP only: random seed (deterministic per seed; default 0)
--weights NAMEScalar cell_data array of per-cell weights to balance instead of the cell count
--record-idsAttach partition:original_point_id / partition:original_cell_id arrays to every piece
--labels-onlyWrite the input once with the Int64 partition:part cell_data attached instead of writing pieces
--ghost-layers NGrow each piece by N shared-node BFS layers of other parts' cells (a halo), tagged partition:ghost (0 = owned). Written to a .pvtu/.pvtp output they become vtkGhostType cells and points and the index's GhostLevel
--input-format / --output-format (-i/-o)Force input/output format

Every piece keeps the input's cell-block structure 1:1 (empty blocks included, unlike split), so the pieces recombine into the input — each cell lands in exactly one piece.

Examples:

sh
meshioplusplus partition domain.msh 'domain_{part}.vtu' --nparts 4
meshioplusplus partition domain.msh 'domain_{part}.vtu' -n 16 --method kahip --mode strong
meshioplusplus partition domain.msh labelled.vtu --nparts 4 --labels-only
meshioplusplus partition domain.msh 'p_{part}.vtu' -n 8 --weights cost --record-ids
meshioplusplus partition domain.msh domain.pvtu -n 4 --ghost-layers 1   # one index over four parts, halo kept as vtkGhostType

meshioplusplus data ​

A nested group of eleven verbs operating on a mesh's point_data / cell_data / field_data arrays (see data operations). The geometry is never modified by any of them — points, connectivity, block order and block types come through bit-identical.

meshioplusplus data <subcommand> [options]
SubcommandDescription
infoSummarize every data array (see data summary)
renameRename data arrays (see array management)
dropDrop data arrays by name
keepKeep only the named data arrays
to-cellAverage point_data onto the cells (see averaging)
to-pointAverage cell_data onto the points
calcDerive an array from an expression (see expressions)
clampClamp values into a range (see conditioning)
normalizeRescale values to a target range
invariantsvon Mises / principal / hydrostatic / deviatoric of a tensor array (see tensor invariants)
gradientDifferentiate a point_data field (see field derivatives)
hessianSecond derivative of a scalar point_data field (see second derivatives)
estimate-errorZZ recovery-based error indicator, plus marking (see error estimation)
integrateCell-measure-weighted total/mean over cells, per region (see field integration)
exportExport the arrays to Parquet (see interoperability)
export-datasetExport a set of meshes as one mesh_id-keyed dataset (see ML data handling)
export-caeExport a set of meshes as one .npz per case in the CAE sample layout PhysicsNeMo's DoMINO/Transolver datapipes read

Every verb takes --input-format (-i), and every verb but info and integrate takes an OUTFILE and --output-format (-o) — the mesh is never modified by either of those two, so there is nothing to write. export and export-dataset are the exceptions on the output side: they write Parquet / zarr / hdf5, so they take no --output-format (export-dataset has --format parquet|zarr|hdf5 instead, plus --mesh-id stem|index, and its input is several paths, one quoted glob, or one multi-step file — the sequence source language). All three are Python CLI only; export and export-dataset need the matching optional extra, while export-cae needs none — it is pure numpy.

export-cae takes the same sequence source (several paths, one quoted glob, or one multi-step file) plus a target directory, and writes case_{index}.npz into it. --surface-fields/--volume-fields name and order the columns of the two concatenated field blocks (default: every numeric array, sorted); --global NAME=VALUE and --global-reference NAME=VALUE are repeatable case parameters and --global-order fixes their stacking order, which DoMINO is sensitive to. One mesh is alive at a time.

sh
meshioplusplus data export-cae 'run_*.vtu' dataset/ \
    --surface-fields p --global stream_velocity=30 --global-order stream_velocity

data gradient, data hessian, data estimate-error and data integrate are mesh operations

Every other verb in this group belongs to the data_* family, which by definition never touches geometry. gradient consumes and produces data arrays but reads geometry and topology (face areas, cell volumes, cell adjacency), so it lives in the mesh-operations layer; hessian is gradient's companion one order further, a composition of two gradient calls; estimate-error composes gradient itself; integrate reads the same cell measures to weight its totals. All four are grouped here because that is where a user looks for them. See field derivatives, second derivatives, error estimation and field integration.

data export is not a mesh conversion

It writes point_data / cell_data to Parquet for analytics (pandas, polars, DuckDB) and does not round-trip geometry — Parquet is deliberately not in the format registry, so meshioplusplus convert mesh.vtu out.parquet does not work. It needs pip install meshioplusplus[arrow], and it exists in the Python CLI only: the native binary has no counterpart.

Colons in names

Data names routinely contain colons (gmsh:physical). data rename therefore splits its OLD:NEW value on the last colon — --point gmsh:physical:tag renames gmsh:physical to tag. data calc splits NAME = EXPR on the first =. drop/keep take a comma-separated name list with no prefix, so colons there are unambiguous. The Python CLI and the native binary implement identical rules.

data info ​

OptionDescription
--jsonEmit the summary as JSON

Prints location, name, dtype, component count, entry count, min/max/mean and NaN/inf counts for every array. Read-only.

data rename / drop / keep ​

OptionDescription
--point, --cell, --fieldOLD:NEW for rename (repeatable); a comma-separated name list for drop/keep
--ignore-missingSkip names that do not exist instead of failing (drop/keep)

For keep, a location that is not named at all is left untouched; naming it with an empty list drops everything there.

data to-cell / to-point ​

OptionDescription
--keysComma-separated names to convert (default: all at the source location)
--target-suffixAppend this to each output name (default: keep the same name)
--weightedto-point only: weight by cell measure (area/volume) instead of counting cells equally

The output is always float64 — the mean of an integer field is not an integer.

data calc ​

OptionDescription
--point, --cell, --fieldNAME = EXPRESSION (repeatable)
--overwriteAllow replacing an array that already exists

The expression grammar accepts + - * /, unary minus, parentheses, numeric literals, array names, and abs/sqrt/min/max/norm — nothing else is evaluated.

data export ​

OptionDescription
--locationpoint (default) or cell

data clamp / normalize ​

OptionDescription
--point, --cell, --fieldComma-separated names (default: all at that location)
--min, --maxclamp only: the bounds (both required)
--to LO,HInormalize only: target range (default 0,1)
--zero-meannormalize only: standardize to zero mean / unit std instead
--magnitudeCondition by row magnitude instead of per component
--nanignore (default), replace or fail
--nan-valueReplacement used with --nan replace
--suffixStore as NAME+SUFFIX instead of replacing in place

data invariants ​

OptionDescription
--point, --cellComma-separated names (default: every 6- or 9-component array at that location); exactly one of the two is required
--outputsComma-separated mises/principal/hydrostatic/deviatoric (default: all four)
--prefixPrepended to every output array's name
--suffixAppended after the invariant's own name segment
--no-overwriteFail instead of silently overwriting an existing array of the target name

data gradient ​

OptionDescription
--array NAMEThe point_data array to differentiate (required)
--opgradient (default), divergence or curl
--methodgreen-gauss (default) or least-squares
--locationcell (default) or point
--output NAMEOutput array name (default <array>:<op>)
--component IDifferentiate only this component (gradient only; default all)
--overwriteReplace an existing array of the output name instead of failing
--quiet, -qSuppress the summary

Naming a cell_data array is an error pointing at data to-point: a piecewise constant field has no derivative. Divergence and curl need a 2- or 3-component field. Cells that cannot be differentiated are reported as cells skipped (NaN); least-squares cells with a degenerate neighbourhood fall back to Green-Gauss and are reported separately. See field derivatives for the exactness guarantees and caveats.

data hessian ​

OptionDescription
--array NAMEThe scalar point_data array to differentiate twice (required)
--methodgreen-gauss (default) or least-squares, forwarded to both internal gradient passes
--locationcell (default) or point
--output NAMEOutput array name (default <array>:hessian)
--overwriteReplace an existing array of the output name instead of failing
--quiet, -qSuppress the summary

The Hessian (second derivative) of a scalar point_data field — gradient's companion one order further, a composition of two gradient calls, not a new kernel. Naming a cell_data array is an error pointing at data to-point, for the same reason data gradient rejects one; a multi-component array is an error naming the per-component workaround (Hessian is scalar-only). Cells that cannot be evaluated are reported as cells skipped (NaN). See second derivatives for the exactness guarantees and the curvature-driven refinement composition.

data estimate-error ​

OptionDescription
--array NAMEThe point_data array to estimate the error of (required)
--methodzz (default; the only estimator family today)
--markingnone (default), absolute, fraction or dorfler
--marking-value VMeaning depends on --marking: an absolute threshold, a fraction in (0, 1] of cells, or the Dörfler bulk fraction theta in (0, 1] (ignored for none)
--output NAMEIndicator array name (default error:zz)
--marked NAMEMarking array name (default error:marked; ignored when --marking none)
--overwriteReplace an existing array of an output name instead of failing
--quiet, -qSuppress the summary

The Zienkiewicz-Zhu recovery-based error indicator of a point_data field: a composition of gradient and the point↔cell averaging round trip, not a new kernel. Naming a cell_data array is an error pointing at data to-point, for the same reason data gradient rejects one. Cells that cannot be evaluated are reported as cells skipped (NaN) and read NaN in error:zz, 0 in error:marked. With --marking not none, a second cell_data array is attached so refine's own --where selector needs no change at all — the intended use is meshioplusplus refine estimated.vtu adapted.vtu --where "error:marked > 0.5". See error estimation for the composition, the marking policies and the byte-identity tolerance.

data integrate ​

OptionDescription
--array NAMEcell_data array to integrate (repeatable; default all cell_data arrays)
--jsonEmit the report as JSON

Cell-measure-weighted total and mean of one or more cell_data arrays — gradient's integration counterpart. Every sum is weighted by the cell's own length/area/volume; a cell whose measure is not computable, or a component whose value is non-finite, is excluded from that component's numerator and denominator, never given a fallback weight of 1. Reported for the whole mesh and independently for every named Cell region — a cell in two regions contributes fully to both, one in none contributes to neither. Naming a point_data array is an error pointing at data to-cell. Read-only, like data info: there is no OUTFILE. See field integration.

Examples:

sh
meshioplusplus data info mesh.vtu
meshioplusplus data info mesh.vtu --json

meshioplusplus data gradient in.vtu out.vtu --array T
meshioplusplus data gradient in.vtu out.vtu --array u --op curl --location point
meshioplusplus data gradient in.vtu out.vtu --array T --method least-squares --output dT

meshioplusplus data hessian in.vtu out.vtu --array T
meshioplusplus data hessian in.vtu out.vtu --array T --location point

meshioplusplus data estimate-error in.vtu out.vtu --array T
meshioplusplus data estimate-error in.vtu out.vtu --array T --marking dorfler --marking-value 0.6

meshioplusplus data integrate mesh.vtu --array density
meshioplusplus data integrate mesh.vtu --array density --array pressure --json

meshioplusplus data rename in.vtu out.vtu --point T:temperature
meshioplusplus data drop   in.vtu out.vtu --point a,b --cell c
meshioplusplus data keep   in.vtu out.vtu --point T,p --cell mat

meshioplusplus data to-cell  in.vtu out.vtu --keys T,p --target-suffix _c
meshioplusplus data to-point in.vtu out.vtu --keys stress --weighted

meshioplusplus data calc in.vtu out.vtu --point "speed = norm(velocity)"
meshioplusplus data calc in.vtu out.vtu --cell  "dp = p_new - p_old"

meshioplusplus data clamp     in.vtu out.vtu --point T --min 0 --max 100
meshioplusplus data normalize in.vtu out.vtu --cell damage --to 0,1
meshioplusplus data normalize in.vtu out.vtu --point T --zero-mean

meshioplusplus data export in.vtu points.parquet
meshioplusplus data export in.vtu cells.parquet --location cell

meshioplusplus dataset ​

The second nested group: curate a hand-editable dataset manifest — the JSON cataloguing many cases (each possibly a time series) with splits, tags, groups and notes. Python CLI only, like data export. Every mutating verb is load → mutate → save against the same file a text editor uses, so hand edits made between two CLI calls survive; sources given on the command line are stored relative to the manifest's directory (absolute paths stay absolute), keeping the manifest portable.

meshioplusplus dataset <subcommand> [options]
verbdoes
add MANIFEST SOURCE...add a case — one quoted glob, one file, or several paths; --id (default: the stem), --format, --times T,T, --time-from, --sort, plus curation --split/--tag (repeatable)/--group/--notes/--meta K=V (repeatable; V parses as JSON when it can). The source is expanded once so an empty glob fails now, by name (--no-validate skips). Creates the manifest file if absent. --target SOURCE (repeatable) records a paired coarse/fine series, with its own --target-format/--target-times/--target-time-from/--target-sort; the two must have the same steps at the same instants, checked here. Omit it for the ordinary self-supervised case ; --thumbnail PNG records a picture of the case, --render-thumbnail draws one
list MANIFESTentries filtered by --split/--tag/--group; --resolve expands each plan (checks files exist, reads no mesh); --json emits the entries (plus Resolved plans) as JSON
split MANIFEST--set S on --id (repeatable) or --all; or --assign train=0.8,valid=0.1,test=0.1 over every entry — deterministic (--seed), --by-group keeps entries sharing a Group together
tag MANIFEST--add T,T / --remove T,T on --id (repeatable) or --all
annotate MANIFEST --id IDset --notes, --group, merge --meta K=V, drop --del-meta K
thumbnail MANIFESTa picture of the cases on --id (repeatable) or --all: draws step --step (default 0) with the software rasterizer at --width×--height (default 256×192; --color-by, --cmap, --view, --shading) to --path (one id; default thumbnails/<id>.png beside the manifest), or records an existing picture with --set PNG (one id), or --clears it
sh
meshioplusplus dataset add m.json 'runs/c42/out_*.vtu' --split train --meta Re=100
meshioplusplus dataset add m.json a.vtu b.vtu --id pair --tag coarse
meshioplusplus dataset add m.json 'coarse/*.vtu' --target 'fine/*.vtu' --id sr
meshioplusplus dataset split m.json --assign train=0.8,valid=0.1,test=0.1 --seed 0
meshioplusplus dataset list m.json --split train --resolve
meshioplusplus dataset annotate m.json --id pair --notes "restarted at t=0.3"
meshioplusplus dataset add m.json 'runs/c43/out_*.vtu' --render-thumbnail
meshioplusplus dataset thumbnail m.json --all --color-by pressure --cmap coolwarm

meshioplusplus pipeline ​

Run a whole settings pipeline: read Input.Path, apply the Operations chain, write Output.Path — one settings.json instead of N verb invocations with intermediate files.

bash
meshioplusplus pipeline settings.json
meshioplusplus pipeline settings.json --input other.msh --output out.vtu
meshioplusplus pipeline settings.json --json          # machine-readable report
meshioplusplus pipeline settings.json --quiet

A document whose Input is a Pattern/Paths, or whose Output.Path carries {step}/{index}, runs the chain per step over a whole transient dataset — see sequences. The verb routes it automatically; a plain single-file document takes the unchanged path.

  • --input / --output override the two paths in the settings file (the document itself is untouched).
  • The report lists each step with its counters (step 3: Clean (PointsWelded=12, ...)) plus any warnings; --json prints the same as JSON.
  • Parsing is strict: an unknown op, an unknown key, or an Output option the format cannot honour is an error naming the offender.
  • The exit code is nonzero on any error, so the verb composes with make/CI.

The verb exists in both CLIs. The Python CLI runs the pure-Python engine (and so inherits the per-format Python fallbacks); the native CLI needs a build with the JSON parser (-DMESHIOPLUSPLUS_WITH_JSON=ON, the default when the src/cpp/third_party/json submodule is checked out — release binaries carry it) and otherwise reports the flag by name. See the settings pipeline for the schema and the full op table.


meshioplusplus compress ​

Compress the data in a mesh file (formats that support compression, e.g. VTU). A .pcd file is rewritten in place as DATA binary_compressed (LZF) at the file's own coordinate precision; decompress turns it back into DATA binary, and ascii/binary rewrite it as those encodings, in both CLIs.

meshioplusplus compress [options] INFILE
OptionShortDescription
--input-format FORMAT-iForce input format

meshioplusplus decompress ​

Decompress the data in a mesh file.

meshioplusplus decompress [options] INFILE
OptionShortDescription
--input-format FORMAT-iForce input format

meshioplusplus ascii ​

Convert a mesh file to its ASCII representation (in-place). A CalculiX .frd is rewritten in the long ASCII layout; like every in-place verb it keeps only the first increment of a multi-step file.

meshioplusplus ascii [options] INFILE
OptionShortDescription
--input-format FORMAT-iForce input format

meshioplusplus binary ​

Convert a mesh file to its binary representation (in-place). A CalculiX .frd is rewritten in the binary layout ccx writes for *NODE OUTPUT (float64 points, float32 results; see CalculiX results), keeping only the first increment of a multi-step file.

meshioplusplus binary [options] INFILE
OptionShortDescription
--input-format FORMAT-iForce input format

Format names ​

The --input-format and --output-format options accept any of the registered format names. The full list is shown by meshioplusplus convert --help. Common values:

abaqus, abaqus_fil, ansys, ansys_rst, ansys_rst_cyclic, ansysinp, avsucd, cgns, code_aster, dolfin-xml, elmer, exodus, febio, femap, flac3d, gmsh, gmsh22, h5m, hmf, libmesh, lsdyna, lsdyna_binout, lsdyna_d3plot, marc, marc_t19, mdpa, med, medit, mfem, mphbin, mphtxt, nastran, nastran_op2, neuroglancer, netgen, obj, off, patran, pcd, permas, ply, pvd, pvtp, pvtu, radioss, radioss_anim, radioss_th, stl, su2, svg, szplt (needs TecIO), tecplot, tetgen, ugrid, vtk, vtk42, vtk51, vtkhdf, vtu, vtx (needs ADIOS2), wkt, xdmf, xplt, xyz, z88

An input with no recognised extension is sniffed by content, a .mesh file whose first line names an MFEM mesh is read as mfem rather than Medit (v16.5.0), Z88's fixed file names (z88i1.txt, z88structure.txt, z88o2.txt, z88o3.txt) are z88 rather than xyz, as input and as output (v16.7.0), a .dat file that opens as an MSC Marc input deck is read as marc rather than Tecplot (v16.8.0), a file named d3plot is LS-DYNA's state database, lsdyna_d3plot, and its numbered members (d3plot01...) are refused with the base file's name (v16.9.0), a file named like crashA001 (a stem, A and three or more digits) is an OpenRadioss animation file, radioss_anim, whose run is a sequence (convert 'crashA*' crash.vtkhdf, v16.11.0), a file named binout (or binout0000…) is LS-DYNA's lsdyna_binout and one named like crashT01 an OpenRadioss time-history file, radioss_th (both v16.12.0, both also found by content; radioss_th is also written, from the radioss_th:* field data, to an output named like that or given -o radioss_th, and convert 'in_*.vtu' runT01 of a sequence writes one output per step; nastran_op2 is written too, to a .op2 file, and convert 'in_*.vtu' run.op2 of a sequence writes one file with a block per step; lsdyna_binout is written to an output named binout or given -o lsdyna_binout, and a sequence writes one file with an output folder per step; abaqus_fil is written to a .fil file, and a sequence writes the model once and an increment per step), and a directory by the files it holds (v16.2.0): an Elmer mesh directory, an OpenFOAM case or a DOLFINx VTX .bp directory (v16.13.0) needs no -i (meshioplusplus convert box box.vtu). An output is never sniffed: since v16.17.0, resolving a write goes through resolve_write_format, a name-and-extension-only function, so a .dat output is always tecplot (never marc, even though a .dat input can read as one) and a Marc deck needs -o marc explicitly; writing a directory format to an extension-less path needs -o the same way (meshioplusplus convert box.msh box -o elmer). Naming a read-only format as the output says so directly ("can be read but not written"), rather than failing as an unknown format. The ascii, binary, compress and decompress verbs take the format from the extension alone, so they do not accept a directory.

Selective reads and fast summaries ​

info --fast summarizes a file from its header instead of loading it, and convert can narrow what it reads:

bash
meshioplusplus info --fast big.vtu
meshioplusplus convert --points-only in.vtu out.vtu     # geometry, no data arrays
meshioplusplus convert --arrays u,p in.vtu out.vtu      # only these data arrays
meshioplusplus convert --time-step=-1 run.exo last.vtu  # the last step of a time series

--points-only keeps connectivity — it narrows data, not topology. arrays with an empty list keeps no arrays; omitting the flag keeps every array.

--time-step=N picks one step of a multi-step file: 0 (the default) is the first, negative counts from the end. A negative value needs the --time-step=-1 form, as with the other negative-valued options. Out of range is an error naming the available count, never a silent clamp; info --fast prints Time steps: N [...] when a file records more than one. Honoured by formats carrying a time series (currently exodus); a format whose reader has no time concept refuses rather than quietly returning the first step.

--drop-ghosts (both CLIs) removes the ghost cells (halo) of a partitioned .pvtu, .pvtp or .pvd — every cell with a vtkGhostType bit set, and the points only they used — so a partition written with partition --ghost-layers reads back as the original mesh; every other reader ignores it, and by default ghost cells are kept.

--piece=N keeps one piece of a partitioned file (VTKHDF partitions or composite blocks, the pieces of a .pvtu/.pvtp, or one part of a .pvd step) instead of the merged mesh: 0 is the first, negative counts from the end (--piece=-1). Out of range is an error naming the piece count, and a format with no pieces refuses rather than quietly merging. compress/decompress deliberately do not handle vtkhdf: they rewrite in place from one merged read, which would drop every step but the first from a transient file — use convert to a new file instead.

--lenient (native CLI only) downgrades "this reader cannot represent construct X" errors to a warning plus a skip — currently MDPA's Table, Geometries, Mesh and Constraints blocks, which nearly every production .mdpa carries, and the missing meshio++ marker of an .svg or .tikz drawing. It is not "ignore all errors": a malformed row, a bad node reference or a duplicate node id still fail, because continuing past those returns a mesh that is quietly wrong rather than merely incomplete. The Python CLI has no such flag, deliberately: its MDPA reader is the pure-Python reference, which already accepts every construct the flag covers.

Formats without a header-only path are read in full and info --fast says so explicitly (no header-only path for this format; the file was read in full) rather than implying a saving that did not happen. See Selective reads.

--points-only/--arrays are rejected alongside -s/-d, which convert exactly the data arrays that were skipped.

Compression codecs ​

bash
meshioplusplus compress --codec lz4 mesh.vtu

--codec zlib|lz4|zstd selects the VTK XML block codec for .vtu/.vtp. zlib is the default; lz4 stays ParaView-readable, zstd is a meshio++ extension that ParaView cannot read. The flag is rejected for formats with no block codec rather than silently ignored. See Compression codecs.

Both CLIs — the Python one and the native meshioplusplus binary — accept these identically.

view / screenshot — the native viewer ​

sh
meshioplusplus view part.msh
meshioplusplus view part.msh --kind surface --color-by material
meshioplusplus screenshot part.msh out.png --size 1600x1200

Options: --input-format/-i, --kind {auto,surface,volume,curve,points}, --color-by NAME, --name NAME; view adds --backend {auto,polyscope,terminal} (auto is Polyscope when the build has it, else the terminal viewer when standard input and output are terminals); screenshot adds --size WIDTHxHEIGHT and --transparent.

These mirror the Python CLI's verbs, but in the native binary they are only functional in a build configured with Polyscope:

sh
git submodule update --init --recursive     # Polyscope vendors its own submodules
build/configure.sh --cli --with-polyscope --build

They are listed in --help in every build; without the flag view reports it (and points at snapshot, which draws in a terminal with no viewer), and screenshot draws its PNG with the same software rasterizer instead of failing, noting that on stderr. The prebuilt release binaries do not include the viewer — they are deliberately dependency-free single files, and Polyscope needs OpenGL, GLFW and X11 — so they use snapshot. Use the Python CLI (pip install meshioplusplus[viewer]) or the browser viewer if you want an interactive window without building from source.

voxelize ​

bash
meshioplusplus voxelize bunny.stl shell.vtu --resolution 64,64,64 --fill surface
meshioplusplus voxelize bunny.stl solid.vtu --cell-size 0.5 --fill inside
flagmeaning
--resolution nx,ny,nzcell counts; give exactly one of this and --cell-size
--cell-size Scubic cell size
--bounds=xlo,...,zhiexplicit bounds; the mesh's own by default (negatives need the = form)
--padding / --padding-relativegrow the box on every side
--fill all|surface|insidewhich cells to keep
--sign pseudonormal|winding-numberhow --fill=inside decides what is inside
--attach-occupancyattach the voxel:occupancy array
--max-cells Nrefuse above this many cells (default ~256³)

See doc/voxelize.md and doc/sdf.md.

grid-sample, grid-scatter, grid-resample, grid-spectrum ​

(Python only — no native equivalent.) The mesh-to-grid data path a convolutional or superresolution model needs.

bash
meshioplusplus grid-sample   case.vtu grid.vti --resolution 64,64,64
meshioplusplus grid-resample grid.vti fine.vti --factor 2
meshioplusplus grid-scatter  fine.vti case.vtu predicted.vtu
meshioplusplus grid-spectrum grid.vti --field T --json

Write grids as .vti: it stores the lattice as origin/spacing/extent and regenerates the points arithmetically, so the grid is recovered exactly on the way back in. A grid written to .vtu is a lossy round trip for this purpose and reading one back as a grid fails by name.

flagverbmeaning
--resolution nx,ny,nz / --cell-size Ssamplethe lattice; exactly one, the same six-field vocabulary as voxelize and sdf
--bounds=xlo,...,zhisampleexplicit bounds. For a coarse/fine pair take the box from the fine mesh, so every fine node is inside the coarse grid
--padding / --padding-relativesamplegrow the box on every side
--fields a,ballwhich point data to carry; every array by default
--extrapolatesamplegive a grid point outside the mesh its nearest value instead of the fill
--fill-value=Vsamplewhat an outside point gets (nan makes the fill visible downstream)
--factor N / --resolution nx,ny,nzresampleinteger upscale, or explicit counts, over the same box; exactly one
--on-conflict error|overwrite|suffixscatterwhen the target already has an array of that name
--field NAMEspectrumrequired; a multi-component array's components are summed
--max-bins N / --jsonspectrumtruncate the printed table / emit JSON

grid-sample reports the coverage, the fraction of grid points inside the mesh — a grid around a concave domain is mostly fill, and a model trained on it learns the fill. cell_data is refused in both directions: convert it with data to-point first.

subsample ​

(Python only — no native equivalent.) Reduce a mesh to a point cloud of exactly --count points, so a large surface fits a transformer's token budget.

bash
meshioplusplus subsample wing.stl wing_4096.vtp --count 4096                 # farthest-point sampling
meshioplusplus subsample wing.stl wing_4096.vtp --count 4096 --method grid   # O(N + count^2), for big clouds
meshioplusplus subsample wing.stl tip.vtp --count 512 --bounds=0.8,-1,-1,1,1,1 --record-ids
flagmeaning
--count Nrequired; how many points to keep
--method farthest|grid|randomexact farthest-point sampling (O(N*count), the most uniform coverage), lattice representatives then farthest-point sampling (O(N + count^2), the scalable choice above a few hundred thousand points), or a uniform draw
--start N / --start randomthe first selected point for farthest/grid; random draws it from --seed
--seed Sdrives random, and --start random
--bounds=xlo,...,zhionly points inside this box are candidates
--record-idsattach budget:original_point_id, each point's index in the source

The output keeps the selected points, their point_data and Point regions, and gets a vertex block so every format can hold it; cells, cell_data and Cell/Side regions are dropped with a warning naming what went. See point-cloud budgets.

See doc/grids.md.

proximity-graph ​

(Python only — no native CLI verb; the underlying pair search itself runs in the C++ core since v16.18.0, see proximity graphs.) Build a graph from geometry rather than connectivity: the neighbourhoods a particle method needs, where the interaction radius and not a shared element is what links two points.

bash
meshioplusplus proximity-graph particles.vtu graph.vtu --radius 0.015
meshioplusplus proximity-graph particles.vtu graph.vtu --knn 16
meshioplusplus proximity-graph particles.vtu graph.vtu --radius 0.015 --box 2.0   # periodic
flagmeaning
--radius Rlink every pair closer than R; one of --radius/--knn is required
--knn Klink each point to its K nearest, then symmetrize (near-constant degree)
--box L / --box Lx,Ly,Lza periodic box: pairs are linked by their minimum image, and a radius past half the smallest side is refused
--kind node|cellvertices are mesh points (default) or block-major cell centroids

The graph is written as line cells over those positions with a degree point array, and the summary prints the vertex and edge counts, the degree spread and how many vertices came out isolated — the numbers that say whether the radius was well chosen. See proximity graphs.

predict ​

(Python only — no native equivalent.) Run a trained PhysicsNeMo checkpoint on one mesh file — no manifest, no split, no entry.

bash
meshioplusplus predict runs/example/checkpoints/best.mdlus part.vtu part_pred.vtu
meshioplusplus predict best.mdlus series.xdmf step_pred.vtu --time-step 4
flagmeaning
--time-step Nwhich step of a multi-step input to predict on (default the first)
--target PATHthe paired mesh a t→t+n or coarse/fine checkpoint compares against
--device auto|cpu|cuda[:N]where to run (default auto)

Everything else comes from the checkpoint's own model card, including which model family wrote it. A mesh carrying no truth predicts anyway, and the summary says the error was not measured rather than reporting one against the input itself. Needs nvidia-physicsnemo (and torch_geometric for a graph checkpoint); without them the verb fails by name and returns 1. See PhysicsNeMo integration.

guard-fit, guard-check ​

(Python only — no native equivalent.) Fit a description of the shapes a dataset contains, and score a new mesh against it — the check a trained surrogate cannot make for itself.

bash
meshioplusplus guard-fit dataset_manifest.json guard.json --split train --margin 1.5
meshioplusplus guard-check guard.json new_part.vtu
meshioplusplus guard-check runs/example/checkpoints/best.mdlus.card.json new_part.vtu --json
flagmeaning
--split Swhich split to fit on (default train)
--margin Mthreshold = M × the worst training score (default 1.5)
--no-qualityskip the quality descriptors (faster on large meshes)
--top Nhow many descriptors guard-check names (default 3)
--jsonemit the raw report

guard-check accepts a fitted guard or a model card carrying one, and prints the verdict, the score against the threshold and the descriptors that put it there. The descriptors are deliberately not scale- or position-invariant: a scaled part is a different part. See geometry guardrails.

sdf ​

bash
meshioplusplus sdf bunny.stl field.vti --resolution 128,128,128
meshioplusplus sdf bunny.stl tree.vtu  --structure octree --max-depth 5
flagmeaning
--structure voxel|octreea dense lattice, or one refined near the surface
--resolution nx,ny,nz / --cell-size Ssize a voxel grid; exactly one, and an error with --structure octree
--root-resolution N / --max-depth N / --band-cells Roctree: the root lattice, how many halving passes, and the band width in cell diagonals
--bounds=xlo,...,zhiexplicit bounds; the surface's own by default
--padding / --padding-relativegrow the box on every side (relative defaults to 0.1)
--sign / --location / --band / --watertight-checkas distance_to_surface
--max-cells Nrefuse above this many cells, re-checked after every octree pass

Write the result as .vti to keep the grid header — no other format carries it. The octree's output is 1-irregular (it has hanging nodes). See doc/sdf.md.

Released under the MIT License.