Skip to content

shore.balance

Python API for the iterative split planner. The CLI wrapper shore balance is a thin adapter around plan_balance.

The algorithm and limitations are documented at shore balance.

Public exports

NameRole
plan_balanceThe planner. Reads a .grd (and optionally an .adjacency.json) and returns a BalancePlan.
BalancePlanDataclass holding the planned splits + before/after summaries. to_toml() renders a shore split-compatible config.

plan_balance

python
def plan_balance(
    grd_path: str | Path,
    *,
    np: int,
    tolerance: float = 0.05,
    max_iterations: int = 100,
    adjacency_path: str | Path | None = None,
) -> BalancePlan

Plan the splits needed to bring the load imbalance below tolerance.

ParameterDescription
grd_pathPath to the input .grd.
npTotal MPI rank count (>= 1).
toleranceTarget fractional imbalance (max - min) / mean. Default 0.05 (5%).
max_iterationsCap on planning iterations. Default 100 for the Python API; the CLI defaults to 200.
adjacency_pathOptional path to a .adjacency.json sidecar. When supplied, the planner refuses to break SHARED / DIRICHLET seams without paired co-splits and prefers axes free of seam coupling.

Returns a BalancePlan.

Raises

  • ParameterErrornp < 1, tolerance <= 0, or max_iterations < 1.
  • FileNotFoundError, ValueError — forwarded from read_grd_metadata and the adjacency reader.

BalancePlan

python
@dataclass
class BalancePlan:
    splits:           list[tuple[str, str, int]]  # (label, axis, vertex_index)
    iterations:       int
    converged:        bool
    initial_summary:  BalanceSummary
    final_summary:    BalanceSummary
    tolerance:        float
AttributeDescription
splitsCuts in decision order: (original_block_label, axis, original_block_vertex_index). Vertex indices are relative to the original block, not any intermediate chunk — this is what shore split's TOML schema expects.
iterationsNumber of split iterations the planner actually ran.
convergedTrue iff the final imbalance is within tolerance.
initial_summaryBalanceSummary before any splits.
final_summaryBalanceSummary after the last split.
toleranceThe tolerance the planner targeted.

BalancePlan.to_toml

python
def to_toml(self) -> str

Render the plan as a shore split config TOML (version = 1, kind = "split", one [[splits]] per (label, axis) pair with a sorted at = [...] list). Same schema as the example in the shore split reference.

Example

python
from shore.balance import plan_balance

plan = plan_balance(
    "wall.grd",
    np=16,
    tolerance=0.05,
    adjacency_path="wall.adjacency.json",
)

print(f"converged: {plan.converged}")
print(f"initial: {plan.initial_summary.imbalance * 100:.1f}%")
print(f"final:   {plan.final_summary.imbalance * 100:.1f}%")
print(f"splits:  {len(plan.splits)} cuts across "
      f"{len({s[0] for s in plan.splits})} blocks")

with open("wall.splits.toml", "w") as f:
    f.write(plan.to_toml())

See also

Released under the MIT License.