shore.io.proc_input
Python API for the Xall proc.input writer / merger plus the BalanceSummary dataclass. The CLI wrappers (shore proc-input, shore proc-input-merge) are thin adapters around these functions.
The file format and use case are documented at shore proc-input.
Public exports
| Name | Role |
|---|---|
write_proc_input | Generate proc.input from a .grd with greedy weight-balanced rank assignment. |
merge_proc_input | Concatenate multiple proc.input files for a multi-component Xall run. |
BalanceSummary | Per-rank load summary returned by both writers. |
write_proc_input
def write_proc_input(
grd_path: str | Path,
out_path: str | Path,
*,
np: int = 1,
proc_assignment: dict[int, int] | None = None,
group_assignment: dict[int, int] | None = None,
body_assignment: dict[int, int] | None = None,
header_comment: str = "generated by SHORE",
) -> tuple[Path, BalanceSummary]Read the .grd header (block count + per-block (ni, nj, nk)), assign each block to an MPI rank (greedy weight-balanced by default), and write the proc.input file.
| Parameter | Description |
|---|---|
grd_path | Path to a SHORE / Xall .grd file. Only the header is read; the coordinate payload is not touched. |
out_path | Output proc.input path. |
np | Total MPI rank count. Default 1 (serial). Must be >= 1. |
proc_assignment | Optional {block_idx (1-based) → proc (0-based)} map. Pinned blocks stay fixed; unpinned blocks fill in by greedy assignment among the remaining weight pool. |
group_assignment | Optional {block_idx → group} map. Default 0 for every block. |
body_assignment | Optional {block_idx → body} map. Default 0 for every block. |
header_comment | Free-form text for header line 1. |
Returns (Path, BalanceSummary).
Raises
ParameterError—np < 1, an assignment dict references an unknown block index, orproc_assignmentreferences a rank outsiderange(np).FileNotFoundError,ValueError— forwarded fromread_grd_metadata.
Greedy weight-balanced assignment
When some or all blocks have no explicit proc_assignment, the unassigned blocks are placed via greedy descent: sort by weight (ni * nj * nk, descending), iteratively place each block on the currently-least-loaded rank. The pinned blocks' weights are counted toward their rank's running load before the greedy fill begins, so the algorithm respects the user's overrides without re-balancing them.
The greedy algorithm is the same one LoadBalance and overset-exploded use; for typical SHORE assemblies it converges to within ~5% of optimal.
merge_proc_input
def merge_proc_input(
inputs: list[str | Path],
out: str | Path,
*,
grd_path: str | Path | None = None,
header_comment: str = "merged by SHORE",
) -> tuple[Path, BalanceSummary]Concatenate two-or-more proc.input files. Block indices in inputs[1:] are shifted by the cumulative block count of the preceding inputs; group, body, and proc columns pass through verbatim — the merger does not re-run load balancing or renumber bodies / groups across components.
| Parameter | Description |
|---|---|
inputs | Two-or-more input proc.input paths in the desired output order. |
out | Output path. |
grd_path | Optional path to the merged .grd. When supplied, the returned BalanceSummary carries real cell counts and the meaningful imbalance figure (cells_known=True); otherwise the summary falls back to per-rank block counts only (cells_known=False). |
header_comment | Free-form text for header line 1 of the merged file. |
Returns (Path, BalanceSummary).
Raises
ValueError— fewer than 2 inputs.FileNotFoundError— missing input file.ParameterError— malformed input file.
Coordinated invocation
Always invoke merge_proc_input, merge_grd, and merge_cc_par as a triple, with the same input ordering — proc.input's block indices, cc.par's patch block fields, and the .grd's block list must agree.
BalanceSummary
@dataclass
class BalanceSummary:
n_blocks: int
np: int
per_rank_blocks: list[int]
per_rank_cells: list[int]
imbalance: float # (max - min) / mean, fractional
cells_known: bool = TrueReturned by both write_proc_input and merge_proc_input. Used by the CLI to print the per-rank load summary on stderr for parallel runs.
| Attribute | Description |
|---|---|
n_blocks | Total block count. |
np | Total MPI rank count. |
per_rank_blocks | Block count per rank, indexed by 0-based rank. |
per_rank_cells | Cell-count (work) per rank, indexed by 0-based rank. Set to all-zero by merge_proc_input. |
imbalance | (max - min) / mean of per_rank_cells, in fractional units. 0.0 for perfect balance and for serial runs. |
cells_known | True for write_proc_input (which reads weights from the .grd); False for merge_proc_input (which only sees block-to-rank assignments — proc.input doesn't store weights). When False, format() omits the cells / imbalance lines. |
BalanceSummary.format
def format(self) -> strMulti-line human-readable summary. With cell-count weights available (cells_known=True):
proc.input: 11 blocks across 4 ranks
rank 0: 3 blocks, 1.84M cells (28.1%)
rank 1: 3 blocks, 1.62M cells (24.7%)
rank 2: 3 blocks, 1.55M cells (23.6%)
rank 3: 2 blocks, 1.55M cells (23.6%)
imbalance: 4.5%Without (cells_known=False, e.g. the merger output):
proc.input: 11 blocks across 4 ranks
rank 0: 3 blocks
rank 1: 4 blocks
rank 2: 2 blocks
rank 3: 2 blocksFor serial runs (np == 1) the imbalance line is omitted.
Example
from shore.io.proc_input import write_proc_input
from shore.io.grd import write_grd
# 1) Pack the per-block .geo files into a binary .grd.
write_grd("wall.grd", [
"wall_sub0.geo", "wall_sub1.geo",
"wall_sub2.geo", "wall_sub3.geo",
"wall_cap_north.geo", "wall_cap_south.geo",
])
# 2) Generate proc.input for a 4-rank parallel run.
out_path, summary = write_proc_input(
"wall.grd",
"wall.proc.input",
np=4,
body_assignment={i: 1 for i in range(1, 7)}, # all 6 blocks → body 1
)
print(summary.format())See also
shore proc-inputCLI — wrapper forwrite_proc_input.shore.io.grd— companion binary mesh writer + theread_grd_metadatahelper used internally.shore.io.cc_par— companion chimera descriptor (read by overset, not Xall).- cc.par + boxes pipeline — end-to-end walkthrough.