Pipeline
One pipeline
Solver output is rarely ready to plot: stresses arrive piecewise-constant on elements, displacements on nodes, tensors as nine loose scalars, and every field carries discretisation noise. IST Vector treats all of it as one pipeline, so the view on screen and the exported file do not diverge.
.spp- Recovery is applied first. Switch on SPR and the colour bar, the iso-surfaces, the threshold mask and the deformation magnitudes all read the recovered field, so smoothed colour is not laid over unsmoothed data.
- One scene, four outputs. Screen, PDF, MP4 and saved state share the same scene object, so what the exporters write is what the viewport showed.
- Resolution-independent throughout. PDFs are shaded-triangle vector graphics rather than screenshots, MP4s capture the viewport’s physical pixel grid, and HiDPI displays are honoured end to end.
Screenshots
One model, several representations
The bundled Stanford Happy Buddha in three representations (colour field, streamlines, print-mode iso-lines) and the fracture field from a lattice-beam damage run. Click any image for the full-size version; each scene exports as it stands to PDF and MP4. The Happy Buddha model is © Stanford University Computer Graphics Laboratory, from the Stanford 3D Scanning Repository, credited as its terms require.
Formats
Reads what your solver writes
| Format | What it carries |
|---|---|
.case | EnSight Gold and EnSight 6, with .geo / .scl / .vec / .ens sidecars: multi-part topology, transient steps (wildcard and arithmetic time sets), scalar, vector and tensor fields (symmetric and asymmetric), ghost cells, iblanking. ASCII and binary, in the Gold per-axis and the EnSight 6 interleaved component layouts alike; the ASCII reader decodes on every core. |
.vtu | VTK XML UnstructuredGrid: topology plus per-point and per-cell fields. Inline ASCII, inline base64, and appended data in raw or base64 encoding, zlib-compressed or not, which covers what vtkXMLWriter and ParaView write by default. |
.vtp | VTK XML PolyData: verts, lines, polys and strips. |
.vtm | VTK XML MultiBlock: the block tree is walked, nested .vtm included, and every referenced .vtu / .vtp / .vtk block loads into one multi-part scene. |
.vtk | VTK legacy, ASCII or binary: UnstructuredGrid, PolyData, StructuredGrid, RectilinearGrid, StructuredPoints. Both CELLS layouts: the classic one, and the OFFSETS / CONNECTIVITY form written by VTK 9 and ParaView 5.9 onwards, with METADATA blocks read past. |
.pvd | ParaView collection: a time-series index of .vtu / .vtp / .vtm / .vtk files. timestep attributes are honoured, and per-step fields are stitched by name union across all steps, so a field that first appears mid-run still loads. |
.stl / .obj | Reference geometry only, no fields. OBJ triangles and quads load directly; longer faces are fan-triangulated. |
.spp | An IST Vector project: the whole scene state plus the mesh reference in one shareable file. Both an input and an output. |
Fields may be nodal or per-element; scalar, vector or tensor; steady or transient. Format detection reads the leading bytes of the file, so a mislabelled extension still reaches the right parser. Files open by drag-and-drop, by Ctrl+O, or from the recent-files flyout.
Element types
| Internal type | Nodes | Dim | Quadratic variant read |
|---|---|---|---|
point | 1 | 0-D | none |
bar2 | 2 | 1-D | bar3 |
tria3 | 3 | 2-D | tria6 |
quad4 | 4 | 2-D | quad8, quad9 |
tetra4 | 4 | 3-D | tetra10 |
pyramid5 | 5 | 3-D | pyramid13 |
penta6 | 6 | 3-D | penta15 (aliases prism6, wedge6) |
hexa8 | 8 | 3-D | hexa20 |
Every parsed cell collapses to one of these eight corner-only types; quadratic mid-edge and
mid-face nodes are read past and discarded. VTK strips are unrolled, polygons with five or more
vertices are fan-triangulated, VTK_VOXEL and VTK_PIXEL corner order is
corrected, and structured grids unroll to hexa8 (or quad4 for slabs).
General polygons and polyhedra (nsided, nfaced) are read but not
rendered, and ghost cells are skipped. A node-only point cloud draws its nodes as round dots at a
diameter you choose (the same in the live view, the PDF and the MP4), and the RBF
recovery filter smooths fields over it.
Your own data
Write your data in a compatible format
If your solver, script or notebook writes none of the formats above, it does not have to learn
one. ist_ensight_gold.py is a Python module shipped with IST Vector whose job
is exactly that conversion: hand it your nodes, your element connectivity and your fields, and
it writes a complete EnSight Gold data set (a .case file with its
.geo geometry and one sidecar per field) that the postprocessor opens
directly. EnSight and ParaView read the same output.
The whole interface is one function
from ist_ensight_gold import write_ensight_gold
write_ensight_gold(
"out/beam.case",
nodes=[(0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0)],
elements={"quad4": [(0, 1, 2, 3)]},
node_data={"temperature": [20.0, 35.0, 50.0, 35.0]},
)
That writes out/beam.case, out/beam.geo and one file per field. Open
the .case in IST Vector. Everything beyond this (several element blocks,
several parts, transient steps, binary output) is another keyword on the same call.
What it accepts
| Argument | What you may hand it |
|---|---|
nodes | An (nnodes, 3) coordinate table: rows, one flat sequence, or a NumPy array. Two columns are accepted for planar meshes and padded with z = 0. |
elements | A mapping {type: connectivity} over the 15 EnSight Gold types (point, bar2/3, tria3/6, quad4/8, tetra4/10, pyramid5/13, penta6/15, hexa8/20), mixed freely in one mesh. Connectivity is 0-based; pass node_index_base=1 for solver numbering. |
node_dataelement_data | {name: values}. The component count follows the shape: (n,) is a scalar, (n, 3) a vector, (n, 6) a symmetric tensor in the 11 22 33 12 13 23 order, (n, 9) an asymmetric tensor, row-major. Element values are indexed over the connectivity blocks in declaration order. |
steps | Transient output, as an iterable of one dict per step; a generator is fine, since steps are written as they arrive rather than held in memory. A step may carry its own deformed nodes, which makes the geometry transient; that case is emitted with change_coords_only, so GPU morph playback stays available. |
parts | Multi-part output, replacing elements. Each part is written with only the nodes its own elements reference, renumbered locally as Gold requires, and node fields are sliced to match, so the bookkeeping the format demands is done for you. |
binary | True writes EnSight “C Binary” (float32, the form EnSight itself stores). The default is ASCII, in exponential notation with precision digits (6 by default, which round-trips float32 exactly). |
Non-finite values (NaN, ±∞) are written as 0.0, since EnSight Gold
cannot represent them; field and part names are sanitised, because the format cannot parse a
name containing whitespace. Bad input raises EnSightError naming the offending
field rather than producing a file that will not load. Run
python ist_ensight_gold.py <directory> with no code of your own to write a
small transient two-part demo data set and open that first.
Capabilities
From loaded field to finished figure
Ordered roughly as they are met in a session, from the recovery filter applied at load to the probes and camera tours used once a figure is ready.
Field recovery
Six methods sit on one card: Zienkiewicz–Zhu SPR (linear least-squares patch fit), quadratic least squares Z2 (ten-term basis, which reproduces quadratic fields exactly), moving least squares with a Wendland-C2 kernel, Taubin λ|μ smoothing (no shrinkage), Perona–Malik anisotropic diffusion (edge-preserving, so fracture fronts and material boundaries survive), and, for node-only point clouds, which have no element patches to fit over, a Gaussian-weighted RBF average. The kernel radius starts at 1/200 of the longest side of the mesh bounding box, and a shared uniform grid keeps neighbour lookup O(K) per point.
Fields derived at load
Every vector field arrives with its three components and its ℓ² and
ℓ∞ norms already there. Every tensor arrives with von Mises and
Frobenius invariants, hydrostatic pressure, its nine components and its column vectors.
Matched nodal and element pairs also seed the a-posteriori Absolute_E
error estimator described below.
Scalar fields
Plain shading, banded contours, or 3–30 labelled iso-lines whose labels are placed with a collision check. Dashed separation lines can mark up to eight colour-band boundaries of the fill. They are log-aware and baked into the geometry, so screen, PDF and MP4 dash identically. There is log10 mapping for fields spanning decades, and a black-and-white mode for print figures, with pure black lines and the field name set as a caption. The Turbo colour map runs through a 256-entry lookup table; NaN samples draw magenta rather than passing into the range. Auto-range can leave out values that never reach the screen, and per-element fields colour whole elements: contours are never invented from element data, so recover to nodes first if you want to contour them.
Vector fields
Arrows, steady streamlines, and transient pathlines and streaklines, integrated with the adaptive Dormand–Prince DOP853 controller (8th order, with embedded 5th and 3rd-order error estimation). Colour by speed: the speed scale gets its own bar, stacked beside the field’s in the same gutter, on screen, in the PDF and in the video. Element vectors anchor at centroids.
Tensor fields
Principal-axis ellipsoid glyphs. The nine components are assembled into a symmetric 3×3 matrix at each node and decomposed by Jacobi eigendecomposition, so each glyph aligns with the principal directions and its radii scale with the eigenvalues. Asymmetric input is symmetrised first, so any 3×3 field is admissible. Scale sets glyph size as a fraction of mesh diameter and sparsity thins them on a uniform grid, while the derived invariants, components and column vectors feed every scalar and vector representation.
Error estimator
When the solver writes a field both ways, smooth on nodes and piecewise on elements,
IST Vector pairs the two by longest common name prefix and forms
Absolute_E = |fnodal − proj(felem)|,
the gap between the nodal field and its element projection. That gap is the familiar
a-posteriori error indicator: pick a pair and a projection direction and it becomes a
scalar field like any other: coloured, thresholded, iso-lined, and taken from the
recovered field whenever a recovery filter is on.
Deformed configuration
Warp by any vector field, magnification 0–20. The scrub drives a single shader uniform, so it is O(1) in mesh size. An undeformed outline keeps the reference shape visible, and mesh-quality statistics can be recomputed on the deformed configuration.
Visibility composition
Threshold erosion (mean, max or min node→element reduction; >, <, =, ≠ relations, with a ±0.5%-of-range tolerance for continuous fields and exact matching for integer material IDs), X/Y/Z section planes with flip, and part or material masks, all composed in a single element-visibility pass.
Iso-surfaces
Volume cells are decomposed to tetrahedra and marched in 3-D, with a per-cell range test to skip elements that cannot bracket the level. A slider scrubs the iso-value live, and a count of 1–10 extracts nested equispaced surfaces in one pass, optionally keeping the part outline for reference.
Symmetry expansion
X/Y/Z mirrors and 1–16 rotational copies about any axis rebuild a whole body from the sector you modelled. Colour fields, and the undeformed outline, are carried onto every copy, and the mirrored silhouette can render in neutral grey or polished steel. Expansion stops at 100 million expanded nodes.
Transient playback
60 Hz interpolation between solver steps, by monotone cubic with the Fritsch–Carlson limiter: an interpolated frame stays inside the bracket of the two solver steps around it, so the colour bar, the threshold mask and the deformed shape stay within values the solver produced, and two identical steps hold still. Where the topology is fixed the GPU morph carries the wireframe, bar segments, node dots and the iso and contour ribbons along with the surface. On adaptive remeshes, where no node correspondence exists, a self-timed offscreen cross-fade of 32–250 ms dissolves every visible layer together. There are playback sub-ranges, ease-in and ease-out envelopes, and a badge showing the solver’s own step numbers; the interpolation allocates nothing per tick. Disk-backed transients stream through a field-major background preloader (only the fields you are displaying, across all steps), so a resident step swaps in by pointer assignment instead of a disk read.
Camera and tours
Best View maximises Vázquez viewpoint entropy over 192 Fibonacci-sphere candidate directions; Pack View runs the same search for the tightest frame fill, scoring silhouette area × zoom-to-fit scale² with the colour-bar gutter reserved. View Tour runs a scripted ten-second pass: an eased arrival at the chosen pose, one full 360° orbit with elevation change and dolly-in, and an exact return to where the camera started, under a material sheen and a travelling key light. Waypoint tours follow subject-locked paths (centripetal Catmull–Rom pan and zoom, squad quaternion rotation, level horizon, arc-length reparameterised for constant visual speed), and the recorder replays that same flight into the MP4, frame for frame.
Probes and mesh statistics
Ctrl+click reports a node’s coordinates and every active field value; Ctrl+Shift+click reports an element’s type, centroid and field values. The mesh-quality card gives per-type counts, edge-length statistics, aspect-ratio extrema, signed area and volume distributions, and inverted-element counts.
Exports
What the scene can produce
| Output | Details |
|---|---|
| Scene PDF | Surfaces are written as PDF Type-4 (free-form) Gouraud-shaded triangles; contour and feature lines as stroked polylines; colour bar, axis triad, labels and dimension callouts keep their on-screen relative positions. Text is set in Latin Modern Roman Bold with the CFF font program embedded in every file (Type1C) and a ToUnicode CMap, so figures match a LaTeX document, pass journal archival preflight, and let values be copied out of the figure. An ultra-fine mode re-evaluates Lambert + GGX shading on an N2 barycentric subdivision of each lit face, keeping hotspots and gradients below element size. |
| Batch contour PDFs | One contour figure per scalar field that varies at the current step, written in a single pass, with uniform fields skipped. Also a two-up geometry reference page, and a one-sheet collage of your saved-views library. |
| MP4 | H.264 through FFmpeg / libx264, with Windows Media Foundation as a fallback. Frames are captured at the viewport’s physical pixel size and the stream is tagged BT.709, so players decode the colour space the same way. The recorder is driven by the same camera closure as the live tours, so the clip reproduces the on-screen motion frame for frame. There is an optional cinematic pass: FXAA, soft-knee bloom, Reinhard tone-mapping, vignette, grain. |
Project .spp |
The complete scene state (active fields, ranges, recovery filter, iso, threshold and section state, symmetry, hidden parts, probes, time, camera) plus the mesh reference, resolved relative to the project when you reopen it. It round-trips losslessly. |
Figure recipe .json |
Camera and every display setting, without the mesh binding: a portable figure specification you can apply to other data (absent fields are simply skipped) or ship beside a paper. Saved views keep the same snapshot as named entries in a per-user library. |
Examples
Example exports
Dataset credits: Happy Buddha and Armadillo models © Stanford University Computer Graphics Laboratory, from the Stanford 3D Scanning Repository. Stanford permits research use and published images provided credit is given to the Stanford Computer Graphics Laboratory; commercial use of the models requires Stanford’s permission. 2-D pressure field: pyvista/vtk-data (Apache-2.0), originally from VTK’s test suite (BSD-3-Clause). Everything else is the author’s own finite-element results and procedurally generated surfaces.
Performance
Scale and performance
Strategy is selected from the mesh size, not configured. The tiers, and what changes at each:
| Tier | Nodes / elements | Behaviour |
|---|---|---|
| Standard | ≤ 500,000 | Every derived field computed eagerly at load. |
| Optimized | ≤ 2,000,000 | Still eager; the element-centroid cache turns lazy. |
| Large | ≤ 10,000,000 | Components, norms and invariants are built on demand (there is a force-derive control) to keep memory bounded. |
| Very large | ≤ 50,000,000 | Also skips jagged-node materialisation, and a warning chip appears in the status bar. |
| Above that | > 50,000,000 | Declined at load, with the reason stated. |
Case bundles load fully into memory when the file total fits in 85% of available RAM; larger transients stream lazily: step 0 up front, while a field-major background preloader brings in the displayed fields across every step, so playback swaps in resident arrays instead of parsing from disk.
Representative costs
| Operation | Typical |
|---|---|
| Open EnSight case, ASCII or binary (parallel parser) | 0.2–3 s / 100 MB |
| Transient step swap | 5–20 ms |
| Field switch (min/max memoised per array) | 10–50 ms |
| Deformation or iso-value scrub (shader-side) | independent of mesh size |
| Contour regeneration (cached per state key) | 15–40 ms |
| Scene PDF export | 0.5–3 s |
| MP4 export, 1080p, 8 s clip | 5–15 s |
Mostly from the Reference Manual §7.2. ASCII .case decoding is newer than the
manual: byte-level kernels, chunk-parallel across cores, put a 271 MB transient of 239 files
(7 steps × 33 variables) at about 0.2 s of parsing rather than 2.2 s. During
rotation and zoom the viewport renders to a half-resolution buffer and upscales, returning to
full resolution on release. NaN and ±∞ are skipped in every reduction, so one bad
sample does not collapse a colour range or hide the mesh.
Limitations
Limitations and requirements
Stated here rather than left to be discovered; most carry their workaround in the same sentence.
- Windows only. Windows 10 21H2 or Windows 11, x64, on a CPU meeting the x86-64-v2 baseline (SSE 4.2 and POPCNT); a startup preflight checks this and reports a failure. There is no macOS or Linux build. Displays from 1280×768 to 7680×4320 are supported.
- 15 GB of RAM or more recommended. Below that the application says so at startup and runs large transients in lazy-streaming mode rather than refusing them.
- A postprocessor, not a solver. It displays results; it does not compute them. Bring output from your own solver, or start from one of the bundled example datasets.
- Contours need nodal data. Per-element fields colour whole elements, and contours are never invented from them. Apply a recovery filter to move the field to nodes first, and everything downstream follows.
- Corner nodes only. Quadratic elements load, but mid-edge and mid-face nodes
are read past, so display and export use the corner-only element. General polygons and polyhedra
(
nsided,nfaced) load but are not rendered. - Meshes above 50 million nodes are declined at load, with the reason stated, rather than accepted and then thrashing.
- STL and OBJ carry geometry only. Useful as reference shapes; fields must come from an EnSight or VTK file.
Engineering
Engineering notes
- A headless core. The parsers, the recovery mathematics, the scene builder, the software rasteriser and the PDF writer live in a library that needs neither a window nor a GPU, so the whole pipeline can run, and be tested, without a display. The vector writer is written here rather than delegated to GL2PS or a similar OpenGL feedback-buffer library.
- Reproducible output. Depth sorting and shading are byte-stable, so PDF and frame output reproduce across runs and thread counts, and regression tests compare against pinned baselines.
- Tested against real solver output. The suite runs a corpus of EnSight, VTK, OBJ and STL files on every push, alongside fuzz fixtures: truncated, mislabelled and non-finite input.
- Playback allocates nothing per tick. Field interpolation alternates two scratch buffers, and coordinates are stored structure-of-arrays so hot loops stream one component at a time.
- Native AOT. A self-contained, fully trimmed executable, with source-generated JSON for all persistence, written atomically. OpenGL calls stay on the UI thread, and GPU caches rebuild from generation counters rather than explicit invalidation.
- Signed and timestamped. Release builds are Authenticode-signed with an Individual
Validation (IV) code-signing certificate through
signtool(SHA-256 file digest) and RFC 3161 countersigned, with DigiCert, Sectigo and GlobalSign timestamp fallback. The desktop executable, the first-party DLLs and the installer are each signed, so the signature still verifies after the certificate expires and SmartScreen passes the download without a warning.
Documentation
Manuals
| Document | Download |
|---|---|
| Reference Manual · 20 pages The pipeline; the recovery mathematics (SPR, Z2, MLS, Taubin, Perona–Malik); every representation card with its control ranges and defaults; camera, tours and saved state; export internals; the element catalogue; performance tables and system requirements. |
PDF · 1.0 MB |
| Inputs & Outputs · 3 pages The file contract: each input format and what it carries, the fields derived at load, the four outputs, and the reproducible-state formats ( .spp, saved views, figure
recipes). |
PDF · 310 KB |
| Architecture & Developer Guide · 8 pages Solution layout; the mesh and field data model; the load-to-render pipeline; concurrency and caching contracts; Native AOT constraints; test strategy; extension recipes. |
PDF · 380 KB |
How to cite
If figures made with IST Vector appear in a publication, cite the software itself and give the build date, so the version that produced them stays identifiable:
IST Vector Postprocessor, build of . Instituto Superior Técnico, Universidade de Lisboa, 2026. https://web.tecnico.ulisboa.pt/ist24806/
Or, in an acknowledgement: “Figures were produced with the IST Vector Postprocessor, Instituto Superior Técnico.” For correspondence about the software, pedro.areias@tecnico.ulisboa.pt.
Datasets carry their own terms independently of this: scenes built on the Stanford models must keep the attribution the Stanford 3D Scanning Repository requires, which the PDF exporter prints with the figure.
Get IST Vector Postprocessor
Download the Windows installer and open your first .case, .vtu or
.vtk file, or start from a bundled example dataset. The installer and every
executable it carries are signed with an Authenticode Individual Validation (IV) code-signing
certificate and RFC 3161 timestamped, so Windows SmartScreen runs them without a warning.
Verify the download against its
SHA-256 checksum.
Current build: 1 September 2026. Performance updates and fixes were applied on this date, and this build is the first to carry the Python writer beside the executable.
Writing your own data? ist_ensight_gold.py turns a mesh and its fields into
an EnSight Gold .case from any Python script, with no dependencies:
download the writer (40 KB) or read
what it does.
Questions, a file that will not open, or a missing feature: pedro.areias@tecnico.ulisboa.pt.