Cutting

Marching cubes algorithm and 3D structured grid cutting utilities.

This module implements the marching cubes algorithm for extracting isosurfaces from 3D structured grids, along with utilities for creating both structured meridional cuts and unstructured triangulated cuts. The marching cubes implementation uses precomputed lookup tables (EDGETABLE and TRITABLE) to efficiently determine which cell edges intersect an isosurface and how to triangulate those intersections. Key functionality includes extracting unstructured triangular cuts using signed distance fields, creating structured 2D meridional slices by interpolating along grid lines, and converting between structured quad meshes and unstructured triangle meshes. The module supports both direct marching cubes output and subsequent interpolation of unstructured data back onto structured grids for easier analysis.

Cuts along grid surfaces by index

The functions here extract cuts along an arbitrary meridional curve. To take a cut along a grid surface of constant index, none of them are needed: a Block supports numpy-style indexing, so block[i] or block[:, j] returns a lower-dimensional structured cut that shares the parent’s data as a zero-copy view. See the indexing section of ember.block for the full rules.

ember.cut.unstructured(grid, xr_cut)[source]

Take an unstructured cut through a grid using marching cubes.

Extracts a triangulated isosurface where the meridional cut curve intersects the grid, by running the marching cubes algorithm on the signed distance field of each block. Triangles from all intersected blocks are concatenated into a single unstructured block.

Parameters:
  • grid (Grid or Block) – Grid containing blocks to cut, or a single block.

  • xr_cut (array_like, shape (n_segments, 2)) – Meridional \((x, r)\) curve segments defining the cut surface.

Returns:

cut – Unstructured triangulated cut, or None if the curve does not intersect any block.

Return type:

Block, shape (ntri, 3) or None

ember.cut.structured_meridional(grid, xr_cut)[source]

Slice a grid along a meridional curve into structured 2D cuts.

For each block, walks every \((i, k)\) grid line and linearly interpolates to the first j location where the signed distance to the cut curve changes sign, producing one structured (ni, nk) cut per intersected block.

Parameters:
  • grid (Grid or Block) – Grid containing blocks to cut, or a single block.

  • xr_cut (array_like, shape (n_segments, 2)) – Meridional \((x, r)\) curve segments defining the cut surface.

Returns:

cut – Grid of 2D structured blocks, each shape (ni, nk), holding the cut data. Blocks that the curve does not intersect are omitted, so the grid is empty when there is no intersection.

Return type:

Grid

ember.cut.interpolate_to_structured(unstructured_block, interp_shape, Beta=0.0, periodic=True, rtol=0.05)[source]

Interpolate an unstructured triangular cut onto a structured grid.

Builds a structured (ni, nj) grid that conforms to the meridional line of the cut and resolves the circumferential direction, then interpolates the triangle-vertex point cloud onto it:

  • index i runs along the meridional line. A constant-i gridline has (x, r) = const and varies only in theta. Nodes are cosine-clustered along the normalised arc length \(\zeta \in [0, 1]\) (double-sided cosine clustering), resolving both extremities of the line.

  • index j runs in theta. A constant-j gridline has theta = const (straight lines), laid out uniformly over one full pitch.

Straight constant-theta lines rely on the solution being periodic in theta with period pitch = 2*pi/Nb: source points are wrapped modulo the pitch so a single uniform theta window is fully covered however the cut’s theta band skews along the line. Flow variables are interpolated in the unfolded \((\zeta, \theta)\) unit space using linear interpolation with a nearest-neighbour fallback at the arc-length ends.

Parameters:
  • unstructured_block (Block, shape (ntri, 3)) – Unstructured triangulated cut, for example from unstructured().

  • interp_shape (tuple of int) – Target structured grid shape (ni, nj).

  • Beta (float, optional) – Pitch angle in degrees fixing the meridional travel direction: the arc-length-zero end is the one with the smallest projection onto d = (-sin Beta, cos Beta). Beta = 0 puts arc length 0 at minimum r; Beta = +/-90 at maximum / minimum x. Default 0.

  • periodic (bool, optional) – If True (default), wrap theta modulo the pitch so the uniform theta window is fully populated. If False, span the raw cloud theta range and rely on the nearest-neighbour fallback outside the data hull.

  • rtol (float, optional) – Relative tolerance for the periodic coverage check. With periodic=True the cloud theta span must be at least (1 - rtol) * pitch or a ValueError is raised. Default 0.05.

Returns:

cut – Structured block with data interpolated onto the line-conforming grid.

Return type:

Block, shape (ni, nj)

ember.cut.triangulate_to_unstructured(block)[source]

Convert a structured 2D cut into a triangulated unstructured cut.

Splits every structured quad face into two triangles, producing an unstructured block with ntri = 2 (ni - 1) (nj - 1) triangles.

Parameters:

block (Block, shape (ni, nj)) – 2D structured block to triangulate.

Returns:

cut – Unstructured block with triangle-vertex data.

Return type:

Block, shape (ntri, 3)