Visualisation and export#

femorph-solver builds on pyvista for geometry and rendering. Every Model carries its mesh as a pyvista.UnstructuredGrid at Model.grid; post-processing is a matter of attaching result arrays to that grid and using pyvista / VTK tools on it.

Attaching result arrays#

# Static analysis
static = m.solve()
m.grid["u"] = static.displacement.reshape(-1, 3)

# Modal analysis — pick a single mode.
modal = m.modal_solve(n_modes=10)
m.grid["mode_7"] = modal.mode_shapes[:, 7].reshape(-1, 3)

# Strain
eps = m.eel(static.displacement)
m.grid["eps_von_mises"] = _von_mises_from_voigt(eps)  # or a scalar field you compute

pyvista treats (n_nodes, 3) arrays as vector fields and (n_nodes, k) arrays (k > 3 or k == 1) as scalar / general fields. Naming is free — whatever you pass through as a dictionary key shows up as the field name in ParaView.

Deformed-shape plot#

import pyvista as pv

modal = m.modal_solve(n_modes=10)
grid = m.grid.copy()
grid["u"] = modal.mode_shapes[:, 7].reshape(-1, 3)

warped = grid.warp_by_vector("u", factor=0.1)    # 10% amplitude

plotter = pv.Plotter()
plotter.add_mesh(warped, scalars="u", component=2)   # z-component colouring
plotter.add_mesh(grid, style="wireframe", color="grey", opacity=0.3)
plotter.show()

Off-screen / CI plots#

For headless rendering in CI or docs build, set pyvista.OFF_SCREEN = True before the first plotter is constructed. femorph-solver’s Sphinx-gallery examples do this in a notebook-boilerplate cell; see doc/source/conf.py.

Writing to disk#

VTK writers are built into pyvista:

Target

File extension

Notes

VTK legacy

.vtk

Widely compatible but text-heavy; large files.

VTK XML unstructured

.vtu

ParaView / VisIt default; compact binary.

pyvista-zstd

.pv

femorph-solver’s preferred snapshot format (see pyvista_zstd); small, zstd-compressed, full fidelity.

m.grid["u"] = static.displacement.reshape(-1, 3)
m.grid.save("static.vtu")                  # ParaView-friendly
m.grid.save("snapshot.pv")                 # zstd-compressed

The femorph_solver.io module provides a thin convenience wrapper (write_modal_vtk) that writes one .vtu per mode with the mode shape attached — useful for animating modes downstream.

See also#