5Create the plan-vs-run PNG of the tutorial 35_offline-load-balancing.ipynb
7The script computes the offline decomposition of the tutorial's regular mesh
8along Peano's space-filling curve, keeps the cells along the periodic
9boundary on tree 0, and hands out all splits bottom-up. It then builds the
10tutorial's Euler setup with this hardcoded load balancing, runs it with four
11threads, and draws the offline plan next to the subdomains that Peano
12actually builds. Cells which end up in a different subdomain than planned
13are crossed out. Call the script from anywhere:
15 python3 tutorials/exahype2/illustrations/35_offline-load-balancing-plan-vs-run.py
17All builds and outputs go into a temporary directory (or --work-directory).
18The script needs matplotlib, but no ParaView.
30import matplotlib.pyplot
as plt
31from matplotlib.colors
import ListedColormap
32from matplotlib.patches
import Patch
34Here = os.path.dirname(os.path.abspath(__file__))
37_specification = importlib.util.spec_from_file_location(
38 "split_modes_illustrations",
39 os.path.join(Here,
"35_offline-load-balancing-split-modes.py"),
41split_modes = importlib.util.module_from_spec(_specification)
42_specification.loader.exec_module(split_modes)
43domain_decomposition = split_modes.domain_decomposition
46import toolbox.loadbalancing.api.output.Hardcoded
as Hardcoded
47import toolbox.loadbalancing.api.strategies.Decomposition
as Decomposition
48import toolbox.loadbalancing.api.strategies.SFC
as SFC
49import toolbox.loadbalancing.api.strategies.SplitTrees
as SplitTrees
51PlanVsRunPicture = os.path.join(Here,
"35_offline-load-balancing-plan-vs-run.png")
53CellsPerAxis = split_modes.CellsPerAxis
54TreeColours = split_modes.TreeColours
58 """! Split tree and Hardcoded arguments of the tutorial's offline decomposition"""
63 peano_tree=tree, number_of_subtrees=domain_decomposition.NumberOfThreads
65 periodic_BC=[
True,
True],
67 destination_ranks = Hardcoded.assign_trees_to_ranks_round_Robin(
68 number_of_subtrees=tree.number_of_subtrees, max_ranks=1
70 configuration, mode = Hardcoded.create_constructor_initialisation_string(
71 tree, destination_ranks, modes=Hardcoded.BottomUp
73 owner = np.zeros((CellsPerAxis, CellsPerAxis), dtype=int)
74 for x
in range(CellsPerAxis):
75 for y
in range(CellsPerAxis):
76 owner[y, x] = tree._tree_arrays[2][x][y][1]
77 return owner, configuration
83 Number the subdomains of a run like the planned subdomains
85 The run does not tell us Peano's tree numbers (see
86 split_modes.read_subdomains()). We therefore give each subdomain of the
87 run the number of the planned subdomain with which it overlaps most.
90 result = -np.ones_like(built)
91 for subdomain
in range(domain_decomposition.NumberOfThreads):
92 mask = built == subdomain
94 int((planned[mask] == tree).sum())
95 for tree
in range(domain_decomposition.NumberOfThreads)
97 result[mask] = int(np.argmax(overlaps))
101def draw(axis, owner, title, show_curve=False, crosses=None):
105 cmap=ListedColormap(TreeColours),
108 extent=(0, CellsPerAxis, 0, CellsPerAxis),
110 for k
in range(0, CellsPerAxis + 1, 3):
111 width = 1.0
if k % 9 == 0
else 0.3
112 axis.axhline(k, color=
"black", lw=width)
113 axis.axvline(k, color=
"black", lw=width)
117 for i
in range(CellsPerAxis * CellsPerAxis)
120 [x + 0.5
for x, y
in curve],
121 [y + 0.5
for x, y
in curve],
125 if crosses
is not None:
126 ys, xs = np.nonzero(crosses)
127 axis.scatter(xs + 0.5, ys + 0.5, marker=
"x", color=
"black", s=14, lw=0.9)
129 int((owner == tree).sum())
130 for tree
in range(domain_decomposition.NumberOfThreads)
133 title +
"\ncells per subdomain: " +
" / ".join(str(c)
for c
in counts),
140def render(run_directory, picture=PlanVsRunPicture):
142 built =
match_subdomains(planned, split_modes.read_subdomains(run_directory))
143 differences = planned != built
145 figure, axes = plt.subplots(1, 2, figsize=(9.0, 5.6))
146 draw(axes[0], planned,
"Offline plan along Peano's curve", show_curve=
True)
150 "Run with bottom-up splits: {} cell(s) differ".format(int(differences.sum())),
154 handles=[Patch(color=TreeColours[0], label=
"tree 0 (keeps the periodic frame)")]
155 + [Patch(color=c, label=
"")
for c
in TreeColours[1:-1]]
156 + [Patch(color=TreeColours[-1], label=
"trees split off from tree 0")],
163 plt.tight_layout(rect=(0, 0.06, 1, 0.97))
164 plt.savefig(picture, dpi=130, bbox_inches=
"tight")
165 return int(differences.sum())
168if __name__ ==
"__main__":
169 parser = argparse.ArgumentParser(
170 description=
"Create the plan-vs-run PNG of the tutorial 35_offline-load-balancing.ipynb"
175 help=
"Directory for builds and outputs (default: temporary directory)",
179 default=domain_decomposition.PeanoRoot,
180 help=
"Peano installation with the compiled libraries (default: repository holding this script)",
182 args = parser.parse_args()
184 work_directory = args.work_directory
or tempfile.mkdtemp(
185 prefix=
"35_offline-load-balancing-plan-vs-run-"
187 print(
"build and run in {}".format(work_directory))
189 domain_decomposition.build_and_run(
191 os.path.abspath(args.peano_root),
192 tutorial=
"35_offline-load-balancing",
193 namespace=
"offlineloadbalancing",
194 load_balancer=
"toolbox::loadbalancing::strategies::Hardcoded",
195 load_balancer_arguments=configuration,
198 print(
"wrote {} ({} cell(s) differ)".format(PlanVsRunPicture, differences))
render(run_directory, picture=PlanVsRunPicture)
draw(axis, owner, title, show_curve=False, crosses=None)
offline_plan()
Split tree and Hardcoded arguments of the tutorial's offline decomposition.
match_subdomains(planned, built)
Number the subdomains of a run like the planned subdomains.
equidistant_splitting(Tree peano_tree, int number_of_subtrees, verbose=False)
RegularGridGenerator(name=None, max_level=None, dimensions=None)
Generate an artificial regular grid with uniform refinement for testing purposes.
tuple[int, int] Peano_to_Cartesian_2d(int peano_index, int size)
Inverse of Cartesian_to_Peano_2d.
tuple[str, str] split_tree(Tree peano_tree, decomposition, str traversal="bfs_finest_first", bool enable_propagate_bottom_up=False, bool enable_optimize_hierarchy=False, bool require_all_children_for_hierarchy_optimization=True, list[bool]|None periodic_BC=None, bool verbose=False)
Split a tree using a staged load-balancing workflow.