Skip to content

Parallel and multipatch grids

Download notebookView on GitHubRun when the site was built.

Inspect decomposition metadata and combine named grid patches. The first section runs on one process; the same constructor accepts an MPI communicator for parallel runs.

Choose which axes may be split with domain_decomposition. On one process, the index bounds cover the full grid. num_ghost_points adds ghost nodes on both sides of each local axis.

from simgeometry.grid import Grid, MultiPatchGridComposite
grid = Grid(
ndim=2,
lower_bound=(0.0, 0.0),
upper_bound=(1.0, 1.0),
num_gridpoints=(18, 12),
domain_decomposition=(True, False),
num_ghost_points=1,
periodic=(True, False),
)
print("rank:", grid.mpi_rank)
print("process grid:", grid.proc_sizes)
print("global index bounds:", grid.proc_index_bounds)
print("local shape with ghosts:", grid.num_gridpoints_local_with_ghosts)
rank: 0
process grid: [1, 1]
global index bounds: [(0, 18), (0, 12)]
local shape with ghosts: (20, 14)

For a multi-process run, install simgeometry[mpi], pass comm=MPI.COMM_WORLD, and launch the script with mpiexec -n 4 python script.py:

from mpi4py import MPI
from simgeometry.grid import Grid
grid = Grid(
ndim=2,
lower_bound=(0.0, 0.0),
upper_bound=(1.0, 1.0),
num_gridpoints=(18, 12),
comm=MPI.COMM_WORLD,
domain_decomposition=(True, True),
num_ghost_points=1,
)
print(grid.mpi_rank, grid.proc_index_bounds, grid.num_gridpoints_local)

proc_index_bounds contains half-open global index ranges. neighbor_ranks gives lower and upper neighbors per axis, using MPI.PROC_NULL at nonperiodic walls. grid.domain_decomposition_class.layout(shape, halo=...) returns a matching mpiarray.Layout for field arrays.

Combine separate Grid instances of the same dimension. Here two patches form an L with a gap in the upper-right region.

patches = {
"vertical": Grid(2, (0.0, 0.5), (0.5, 2.0), (6, 16)),
"horizontal": Grid(2, (0.5, 0.0), (2.0, 0.5), (16, 6)),
}
composite = MultiPatchGridComposite(patches)
print("patches:", composite.patch_ids)
print("upper leg:", composite.find_patch((0.25, 1.0)))
print("lower leg:", composite.find_patch((1.0, 0.25)))
print("gap:", composite.find_patch((1.0, 1.0)))
patches: ('horizontal', 'vertical')
upper leg: vertical
lower leg: horizontal
gap: None

Patch coordinates are relative to that patch’s lower bound. global_to_local() can find the patch automatically, then local_to_global() converts back.

patch_id, local = composite.global_to_local((1.25, 0.25))
print("patch and local position:", patch_id, local)
print("back to global:", composite.local_to_global(local, patch_id))
assert patch_id == "horizontal"
assert local.tolist() == [0.75, 0.25]
patch and local position: horizontal [0.75 0.25]
back to global: [1.25 0.25]

Use get_patch(id) and get_patch_bounds(id) for each child grid. Inherited single-grid properties on the composite describe its first patch alphabetically. PatchLibrary in simgeometry.multipatch can create descriptors for single, L, T, and cross layouts; check descriptor bounds before composing them because some layouts overlap and find_patch() returns the first match.