optimize_splitting_mask() moves every cell of a lake into one model after metis has
balanced the partition, so a balanced partition is returned unbalanced and nothing reports
that it happened.
model_splitter.py:750:
if laks:
for lak in laks:
idx = np.asarray(lak_array == lak).nonzero()[0]
mnum = np.unique(membership[idx])[0]
membership[idx] = mnum
On test045_lake2tr split into four with pymetis.Options(seed=42, contig=1), two lakes and
90 lake connection cells:
|
active cells per model |
largest / mean |
cells moved |
| A, current from metis |
552, 559, 559, 557 |
1.004 |
|
| B, current after adjustment |
666, 445, 641, 475 |
1.196 |
46 |
| C, adjusted to the majority model |
475, 636, 641, 475 |
1.151 |
37 |
| D, proposed enhancement |
550, 566, 566, 545 |
1.017 |
0 |
The letters are the panels of the figure below.
One model ends up with 20 percent more work than the mean.
Consolidating a lake is necessary, a lake has one stage and cannot be divided between models.
What costs the balance is doing it after the partition is built.
Proposed
Contract each lake to a single vertex before calling metis, carrying the summed vertex weight
and the union of its adjacency, and expand after partitioning (D). Each lake is then in one model
by construction, metis accounts for its weight while balancing, and no cell is moved
afterward. Metis also routes the partition boundaries around the lakes rather than through
them, so the result is not the original partition with the lakes patched, it is a different
and better partition. This is the same idea as weighting the barrier faces in #2826, state
the constraint before partitioning rather than repairing the result.
np.unique(...)[0] is the lowest numbered model the lake touches rather than the model that
holds most of it, so the loop also moves more cells than it needs to and biases toward the
low numbered models. Adjusting each lake to the majority model, the one that already holds
most of it, was measured (C) and recovers about a quarter of the lost balance, because it
changes which models are overloaded rather than whether they are. It is worth applying only
as the destination rule if the loop is kept as a fallback, and it is not a step toward the
contraction.
SFR and UZF are not affected. They are not consolidated, only weighted at
model_splitter.py:695, and reaches are allowed to span models.
optimize_splitting_mask()moves every cell of a lake into one model after metis hasbalanced the partition, so a balanced partition is returned unbalanced and nothing reports
that it happened.
model_splitter.py:750:On
test045_lake2trsplit into four withpymetis.Options(seed=42, contig=1), two lakes and90 lake connection cells:
The letters are the panels of the figure below.
One model ends up with 20 percent more work than the mean.
Consolidating a lake is necessary, a lake has one stage and cannot be divided between models.
What costs the balance is doing it after the partition is built.
Proposed
Contract each lake to a single vertex before calling metis, carrying the summed vertex weight
and the union of its adjacency, and expand after partitioning (D). Each lake is then in one model
by construction, metis accounts for its weight while balancing, and no cell is moved
afterward. Metis also routes the partition boundaries around the lakes rather than through
them, so the result is not the original partition with the lakes patched, it is a different
and better partition. This is the same idea as weighting the barrier faces in #2826, state
the constraint before partitioning rather than repairing the result.
np.unique(...)[0]is the lowest numbered model the lake touches rather than the model thatholds most of it, so the loop also moves more cells than it needs to and biases toward the
low numbered models. Adjusting each lake to the majority model, the one that already holds
most of it, was measured (C) and recovers about a quarter of the lost balance, because it
changes which models are overloaded rather than whether they are. It is worth applying only
as the destination rule if the loop is kept as a fallback, and it is not a step toward the
contraction.
SFR and UZF are not affected. They are not consolidated, only weighted at
model_splitter.py:695, and reaches are allowed to span models.