Skip to content

Running Examples and Tests

This guide covers how to run SHORE's example scripts and the full test suite.

Prerequisites

Ensure SHORE is installed in development mode with all extras:

bash
git clone https://github.com/szaghi/shore.git
cd shore
python -m venv .venv && source .venv/bin/activate
make dev    # pip install -e ".[dev,vis]"

Running Examples

SHORE ships a set of standalone example scripts and a Jupyter notebook that serve as both documentation and sanity checks.

examples/01-body-fitted/visualize_cubed_sphere.py — cubed-sphere topology around a sphere

The script generates a unit-sphere body-fitted test case (always 6-block cubed-sphere topology) and optionally visualises it. When called without --generate, it acts as a generic .geo / .npz viewer.

bash
# Generate sphere.stl + 6 sphere_<label>.geo files and open the viewer
python examples/01-body-fitted/visualize_cubed_sphere.py --generate

# Generate and save a screenshot instead of opening a window
python examples/01-body-fitted/visualize_cubed_sphere.py --generate --screenshot sphere_preview.png

# Generate only (skip the viewer)
python examples/01-body-fitted/visualize_cubed_sphere.py --generate --no-view

# Export to a single VTK MultiBlock .vtm for ParaView
python examples/01-body-fitted/visualize_cubed_sphere.py --generate --vtk

Key parameters:

FlagDefaultDescription
--ni40Equator meridional resolution
--nj60Longitude resolution (multiple of 4)
--nk20Wall-normal layers
--ds0.02First-layer thickness (geometric)
--growth1.10Layer growth ratio (geometric)
--theta-capπ/6Polar exclusion angle in radians
--theta-cap-degPolar exclusion angle in degrees
--smooth0.2Laplacian blend strength [0–1]
--smooth-iters2Laplacian sweeps per layer
--surface-i-spacinguniformEquator meridional spacing law
--surface-i-beta3.0Clustering strength for tanh/tanh2 i-spacing
--surface-j-spacinguniformCap-edge tangent-plane spacing law
--surface-j-beta3.0Clustering strength for tanh2 j-spacing
--volume-k-spacinggeometricWall-normal spacing law
--volume-k-beta3.0Clustering strength for tanh/tanh2 k-spacing
--volume-k-thicknessTotal wall-normal thickness (required for tanh/tanh2)
--blend-normals-k0Layers over which to blend STL normals (0 = off)

Spacing examples:

bash
# Tanh wall-normal spacing — fixed far-field boundary
python examples/01-body-fitted/visualize_cubed_sphere.py --generate \
  --volume-k-spacing tanh --volume-k-beta 4.0 --volume-k-thickness 2.0

# Equator meridional clustering at the cap seams
python examples/01-body-fitted/visualize_cubed_sphere.py --generate \
  --surface-i-spacing tanh --surface-i-beta 4.0

# Cap-corner clustering (tanh2 j-spacing — inherited by equator seam)
python examples/01-body-fitted/visualize_cubed_sphere.py --generate \
  --surface-j-spacing tanh2 --surface-j-beta 5.0

See Spacing laws for an explanation of each distribution and what physical region it clusters toward.

Visualise an existing .geo or .npz file directly:

bash
python examples/01-body-fitted/visualize_cubed_sphere.py sphere_sub0.geo
python examples/01-body-fitted/visualize_cubed_sphere.py sphere_k0.npz
python examples/01-body-fitted/visualize_cubed_sphere.py sphere_sub0.geo --screenshot out.png --no-edges

Output: 6 .geo files per run

sphere_sub0.geo .. sphere_sub3.geo   # equatorial sub-blocks
sphere_cap_north.geo                 # north polar cap
sphere_cap_south.geo                 # south polar cap

examples/01-body-fitted/config_fuselage.toml — config-driven workflow

When the parameter set gets large enough that the CLI invocation becomes a wall of flags, switch to a TOML config file. Every CLI flag on shore mesh has an equivalent TOML key; the file is parsed, validated, and merged with any explicit CLI flags before the run starts (CLI flag > config value > built-in default).

bash
# bootstrap a fresh config from defaults
shore config template > shore.toml

# or start from the annotated example
cp examples/01-body-fitted/config_fuselage.toml my_case.toml

# parse-check before running (catches typos, version mismatches, etc.)
shore config validate my_case.toml

# run the full pipeline; INPUT is taken from the config's `input` key
shore mesh -c my_case.toml -v

# CLI overrides still apply: this picks up everything from the file
# but uses --nk 80 instead of the configured value.
shore mesh -c my_case.toml --nk 80

The example config (examples/01-body-fitted/config_fuselage.toml) demonstrates every section with a non-default choice — tanh wall-normal spacing with fixed thickness, equator clustering at the cap seams, blended STL normals in the near-wall region — so you can see how the knobs combine in a single recipe.

See the full schema and precedence rules in Config files.

Primitive examples

For the parametric primitives (box, annulus, flat-caps) there is one standalone script per primitive plus a matching annotated TOML config. Each script generates the primitive in-memory, writes a .geo (or several, for multi-block primitives) and a .vtm MultiBlock for ParaView, and optionally opens the PyVista viewer.

ScriptPrimitiveConfigOutput
examples/02-primitives/visualize_box.pyCartesian boxconfig_primitive_box.tomlbox.geo, box.vtm
examples/02-primitives/visualize_annulus.pyannular cylinderconfig_primitive_annulus.tomlannulus.geo, annulus.vtm
examples/02-primitives/visualize_flat_caps.py5-block flat-caps cylinderconfig_primitive_flat_caps.tomlflat_caps_<label>.geo ×5, flat_caps.vtm

Each script accepts the same shape of options:

bash
# Defaults — open the viewer
python examples/02-primitives/visualize_box.py

# Skip the viewer (CI-friendly)
python examples/02-primitives/visualize_box.py --no-view

# Save a screenshot instead of opening a window
python examples/02-primitives/visualize_box.py --screenshot box.png

# Drive the parameters from a TOML config (CLI flags still override)
python examples/02-primitives/visualize_annulus.py --config examples/02-primitives/config_primitive_annulus.toml --no-view
python examples/02-primitives/visualize_flat_caps.py --config examples/02-primitives/config_primitive_flat_caps.toml --no-view

# Skip the .vtm export (only .geo is written)
python examples/02-primitives/visualize_box.py --no-vtk --no-view

The .vtm file is a small XML manifest pointing at one .vts per block stored under a sister directory (box/, annulus/, or flat_caps/). Open the .vtm in ParaView; it pulls in every block automatically.

examples/05-chimera-assembly/assembly_sphere_in_cylinder.py — first-tentative assembly

The assembly example combines a near-body cubed-sphere mesh and a background flat-caps cylinder into a single overset stack that shares one world-coordinate domain. A 6-block sphere-mesh wraps a unit-radius (diameter 1.0) sphere body at the origin, marched outward to a wall-normal extent of ~0.2; a 5-block flat-caps cylinder spans [-10, 10]² × [-10, 50]. All 11 blocks are bundled into a single ParaView-friendly assembly.vtm.

bash
# Generate everything; open the viewer.
python examples/05-chimera-assembly/assembly_sphere_in_cylinder.py

# Generate only — skip the viewer.
python examples/05-chimera-assembly/assembly_sphere_in_cylinder.py --no-view

# Drive the two pieces from TOML configs.
python examples/05-chimera-assembly/assembly_sphere_in_cylinder.py \
    --near-body-config examples/05-chimera-assembly/config_assembly_near_body.toml \
    --background-config examples/05-chimera-assembly/config_assembly_background.toml \
    --no-view

Output:

examples_out/
  sphere.stl                        # in-memory icosphere
  wall_sub0..3.geo                  # 6 cubed-sphere blocks
  wall_cap_north/south.geo
  background_center.geo             # 5 flat-caps blocks
  background_sub_e/n/w/s.geo
  assembly.vtm                      # 11-block ParaView MultiBlock
  assembly/                         # 11 .vts files (manifest internals)

The walkthrough — including the rationale for the parameter choices, ParaView inspection workflow, and the explicit boundary between what SHORE produces and what the downstream solver does — lives in Assembly walkthrough.

examples/05-chimera-assembly/chimera_assembly.py — assembly + Xall cc.par generation

Extends the assembly example by adding adjacency JSON sidecars, VTK MultiBlock exports, and cc.par generation for both meshes. Viewer is off by default; pass --view to open it.

bash
# Generate everything headlessly.
python examples/05-chimera-assembly/chimera_assembly.py

# Custom output directory.
python examples/05-chimera-assembly/chimera_assembly.py -o my_run

# Open the interactive viewer after generation.
python examples/05-chimera-assembly/chimera_assembly.py --view

Output:

examples_out/
  sphere.stl
  wall_sub0..3.geo              # near-body cubed-sphere blocks
  wall_cap_north/south.geo
  wall.vtm                      # near-body ParaView MultiBlock
  wall.grd                      # near-body Xall binary grid
  background_center.geo         # background flat-caps blocks
  background_sub_e/n/w/s.geo
  background.vtm                # background ParaView MultiBlock
  background.grd                # background Xall binary grid
  wall.adjacency.json
  background.adjacency.json
  wall.cc.par                   # near-body Xall cc.par
  background.cc.par             # background Xall cc.par
  assembly.{grd,cc.par,proc.input}   # merged Xall job

CLI-only equivalent

examples/05-chimera-assembly/chimera_assembly.sh runs the same pipeline through shore subcommands alone — no Python imports. The Python and bash paths produce byte-identicalassembly.{grd, cc.par, proc.input} outputs:

bash
./examples/05-chimera-assembly/chimera_assembly.sh           # default examples_out/
./examples/05-chimera-assembly/chimera_assembly.sh -o my_run
./examples/05-chimera-assembly/chimera_assembly.sh --np 16

examples/06-c-grid/visualize_naca0012.py — C-grid around a NACA 0012 wing

Builds a NACA 0012 wing analytically (shore.profiles + shore.shapes), runs the C-grid pipeline (TE detection → span slice → C-curve build → hyperbolic march), and writes a ParaView .vtm.

bash
# Generate naca0012.{stl,geo,vtm}; opens the PyVista viewer at the end.
python examples/06-c-grid/visualize_naca0012.py --generate

# Larger C-grid, finer wake clustering, no viewer.
python examples/06-c-grid/visualize_naca0012.py --generate \
    --ni-body 160 --ni-wake 40 --n-stations 8 \
    --wake-length 25 --wake-growth 1.20 \
    --nk 30 --ds 5e-4 --growth 1.15 --no-view

Output:

examples_out/
  naca0012.stl     # extruded wing STL
  naca0012.geo    # marched C-grid block
  naca0012.vtm    # ParaView MultiBlock

CLI-only equivalent

examples/06-c-grid/visualize_naca0012.sh chains shore profile nacashore body extrudeshore mesh --topology cgridshore export to produce the same outputs (plus the intermediate naca0012.dat Selig section):

bash
./examples/06-c-grid/visualize_naca0012.sh
./examples/06-c-grid/visualize_naca0012.sh --ni-body 160 --nk 30

examples/01-body-fitted/tour.ipynb — Jupyter Notebook

A complete notebook covering mesh generation, Jacobian analysis, spacing-law comparison, and the C1 seam-matching demo:

  • Sections 0–7: generation, inspection, Jacobian profiles, VTK export
  • Sections 8–9: surface and volume spacing distributions
  • Section 10: cap/equator C1 seam matching, with side-by-side comparison of compatible and incompatible parameter regimes
bash
jupyter notebook examples/01-body-fitted/tour.ipynb

For headless CI environments:

python
import pyvista as pv
pv.set_jupyter_backend("static")   # no display required

Running the Test Suite

Full suite

bash
make test

Or directly via pytest:

bash
source .venv/bin/activate
python -m pytest tests/ -v

Running a specific test file

bash
python -m pytest tests/test_cap_gnomonic.py -v   # gnomonic cap construction + seam C1
python -m pytest tests/test_jacobian.py -v       # Jacobian calculations
python -m pytest tests/test_cli.py -v            # CLI commands
python -m pytest tests/test_vtk.py -v            # VTK export

Running a single test

bash
python -m pytest tests/test_cli.py::TestMesh::test_exit_code_ok -v

Test file descriptions

FileWhat it tests
tests/conftest.pyShared fixtures (sphere_stl, sphere_layer)
tests/test_geo.pyGeo file read/write round-trip fidelity
tests/test_grd.pyXall binary .grd writer — format structure, ordering, CLI
tests/test_vtk.pyVTK XML export correctness
tests/test_vis.pyPyVista conversion helpers
tests/test_jacobian.pyJacobian field calculations and inversion detection
tests/test_cap_gnomonic.pyGnomonic cap, seam C0/C1, volume seam continuity
tests/test_mesh.pyOOP Mesh API, CubedSphereTopology.build
tests/test_anchor.py / test_load_stl_hygiene.pyMesh preconditioning
tests/test_projector.py / test_projector_validation.pyRay-cast Projector
tests/test_cli.pyAll CLI commands end-to-end
tests/test_spacing.py1D spacing laws, domain builders, error cases

Filtering tests by keyword

bash
# Run only seam-related tests
python -m pytest tests/ -k seam -v

# Run only the gnomonic cap tests
python -m pytest tests/test_cap_gnomonic.py -v

Test parameters

The test suite uses small default grids to keep execution fast. The full suite runs in under 5 seconds on a modern laptop.

For coverage reporting:

bash
python -m pytest tests/ --cov=shore --cov-report=html -v

HTML coverage report is written to htmlcov/index.html.

Makefile Targets

All development tasks are available via make:

bash
make dev    # install package in editable mode with dev + vis extras
make test   # run test suite with pytest
make lint   # ruff check + format check (read-only)
make fmt    # ruff fix + format (destructive — auto-fixes issues)
make clean  # remove build artefacts, .ruff_cache, .pytest_cache

Troubleshooting

pytest collects no tests

If you see No tests collected, ensure:

  1. You are running from the project root (not inside tests/).
  2. The .venv is activated: source .venv/bin/activate.
  3. pytest is installed: pip show pytest.

Virtual environment issues (WSL2)

On WSL2 the system Python is externally managed. Always use .venv:

bash
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

Visualisation not available

The shore view command and the example script's interactive mode require pyvista:

bash
pip install shore-mesh[vis]

Without pyvista, --screenshot and --no-view still work for offline generation.

CI / Automated Environments

For headless CI (no display required):

bash
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

# Lint
make lint

# Test (headless)
export DISPLAY=
make test

# Smoke-generate the example mesh
python examples/01-body-fitted/visualize_cubed_sphere.py --generate --no-view
shore check sphere_sub0.geo
shore info sphere_sub0.geo

Released under the MIT License.