From 9e2b924c568fc83a53e2988c70a7ccf77e325673 Mon Sep 17 00:00:00 2001 From: Kursat Yurt Date: Mon, 12 Dec 2022 15:57:06 +0100 Subject: [PATCH 1/6] Refactor using snake style naming --- examples/mapping_tester/run.sh | 6 +- .../{plotconv.py => create_plots.py} | 91 +++++-------- .../{gatherstats.py => gather_stats.py} | 32 ++--- .../{generate.py => generate_mapping_test.py} | 122 ++++++------------ tools/mapping-tester/local_rbf.py | 12 +- ...shes.py => prepare_mapping_test_meshes.py} | 58 ++++----- 6 files changed, 123 insertions(+), 198 deletions(-) rename tools/mapping-tester/{plotconv.py => create_plots.py} (79%) rename tools/mapping-tester/{gatherstats.py => gather_stats.py} (79%) rename tools/mapping-tester/{generate.py => generate_mapping_test.py} (72%) rename tools/mapping-tester/{preparemeshes.py => prepare_mapping_test_meshes.py} (63%) diff --git a/examples/mapping_tester/run.sh b/examples/mapping_tester/run.sh index 62b2c4e6..4d0d6a75 100755 --- a/examples/mapping_tester/run.sh +++ b/examples/mapping_tester/run.sh @@ -12,10 +12,10 @@ MAPPING_TESTER="${TEST_LOCATION}"/../../tools/mapping-tester/ TEST_CASE_LOCATION="${TEST_LOCATION}"/case # Generate the run scripts -python3 "${MAPPING_TESTER}"/generate.py --setup "${TEST_LOCATION}"/setup-test.json --outdir "${TEST_CASE_LOCATION}" --template "${MAPPING_TESTER}"/config-template.xml +python3 "${MAPPING_TESTER}"/generate_mapping_test.py --setup "${TEST_LOCATION}"/setup-test.json --outdir "${TEST_CASE_LOCATION}" --template "${MAPPING_TESTER}"/config-template.xml # Prepare the meshes -python3 "${MAPPING_TESTER}"/preparemeshes.py --setup "${TEST_LOCATION}"/setup-test.json --outdir "${TEST_CASE_LOCATION}" --force +python3 "${MAPPING_TESTER}"/prepare_mapping_teest_meshes.py --setup "${TEST_LOCATION}"/setup-test.json --outdir "${TEST_CASE_LOCATION}" --force export ASTE_A_MPIARGS="" export ASTE_B_MPIARGS="" @@ -29,4 +29,4 @@ bash ./postprocessall.sh cd "${TEST_LOCATION}" # Gather the generated statistics -python3 "${MAPPING_TESTER}"/gatherstats.py --outdir "${TEST_CASE_LOCATION}" --file test-statistics.csv +python3 "${MAPPING_TESTER}"/gather_stats.py --outdir "${TEST_CASE_LOCATION}" --file test-statistics.csv diff --git a/tools/mapping-tester/plotconv.py b/tools/mapping-tester/create_plots.py similarity index 79% rename from tools/mapping-tester/plotconv.py rename to tools/mapping-tester/create_plots.py index 8e20201e..0a3bd0dc 100755 --- a/tools/mapping-tester/plotconv.py +++ b/tools/mapping-tester/create_plots.py @@ -2,16 +2,29 @@ import argparse import math - import matplotlib.pyplot as plt -import numpy as np import pandas +import sys -def parseArguments(args): - parser = argparse.ArgumentParser( - description="Creates convergence plots from gathered stats" - ) +style_colours = [ + "#0173b2", + "#de8f05", + "#029e73", + "#d55e00", + "#cc78bc", + "#ca9161", + "#fbafe4", + "#949494", + "#ece133", + "#56b4e9", +] +style_markers = ["o", "D", "s"] +styles = [(c, m) for m in style_markers for c in style_colours] + + +def parse_arguments(args): + parser = argparse.ArgumentParser(description="Creates convergence plots from gathered stats") parser.add_argument( "-f", "--file", @@ -32,55 +45,31 @@ def lavg(l): return math.exp(sum(map(math.log, l)) / len(l)) -# seaborn.color_palette("colorblind", 10).as_hex() -style_colours = [ - "#0173b2", - "#de8f05", - "#029e73", - "#d55e00", - "#cc78bc", - "#ca9161", - "#fbafe4", - "#949494", - "#ece133", - "#56b4e9", -] -style_markers = ["o", "D", "s"] -styles = [(c, m) for m in style_markers for c in style_colours] - - -def plotConv(ax, df, yname): +def plot_convergence(ax, df, yname): xmin = df["mesh A"].min() xmax = df["mesh A"].max() ymin = df[yname].min() ymax = df[yname].max() - print(xmin, xmax) - print(ymin, ymax) - # 1st order line fox = [xmax, xmin] foy1 = ymax foy2 = foy1 * (fox[1] / fox[0]) foy = [foy1, foy2] - ax.axline( - (fox[0], foy[0]), (fox[1], foy[1]), color="lightgray", linewidth=1.0, zorder=-1 - ) + ax.axline((fox[0], foy[0]), (fox[1], foy[1]), color="lightgray", linewidth=1.0, zorder=-1) ax.annotate("1st order", xy=(lavg(fox), lavg(foy)), color="gray", zorder=-1) - # # 2nd order line + # 2nd order line sox = [xmin, xmax] soy1 = ymin soy2 = soy1 * ((sox[1] / sox[0]) ** 2) soy = [soy1, soy2] print(sox, soy) - ax.axline( - (sox[0], soy[0]), (sox[1], soy[1]), color="lightgray", linewidth=1.0, zorder=-1 - ) + ax.axline((sox[0], soy[0]), (sox[1], soy[1]), color="lightgray", linewidth=1.0, zorder=-1) ax.annotate("2nd order", xy=(lavg(sox), lavg(soy)), color="gray", zorder=-1) -def plotError(df, prefix): +def plot_error(df, prefix): yname = "relative-l2" fig, ax = plt.subplots(sharex=True, sharey=True) series = df.groupby("mapping") @@ -102,14 +91,14 @@ def plotError(df, prefix): ax.set_xlabel("edge length(h) of mesh A") ax.set_ylabel("relative-l2 error mapping to mesh B") - plotConv(ax, df, yname) + plot_convergence(ax, df, yname) plt.gca().invert_xaxis() plt.grid() plt.savefig(prefix + "-error.pdf") -def plotMemory(df, prefix): +def plot_memory_usage(df, prefix): yname = "peakMemB" fig, ax = plt.subplots(sharex=True, sharey=True) series = df.groupby("mapping") @@ -131,14 +120,12 @@ def plotMemory(df, prefix): ax.set_xlabel("edge length(h) of mesh A") ax.set_ylabel("peak memory of participant B [bytes]") - # plotConv(ax, df, yname) - plt.gca().invert_xaxis() plt.grid() plt.savefig(prefix + "-peakMemB.pdf") -def plotComputeMappingTime(df, prefix): +def plot_compute_mapping_time(df, prefix): yname = "computeMappingTime" fig, ax = plt.subplots(sharex=True, sharey=True) series = df.groupby("mapping") @@ -161,14 +148,12 @@ def plotComputeMappingTime(df, prefix): ax.set_xlabel("edge length(h) of mesh A") ax.set_ylabel("time to compute mapping [ms]") - # plotConv(ax, df, yname) - plt.gca().invert_xaxis() plt.grid() plt.savefig(prefix + "-computet.pdf") -def plotMapDataTime(df, prefix): +def plot_map_data_time(df, prefix): yname = "mapDataTime" fig, ax = plt.subplots(sharex=True, sharey=True) series = df.groupby("mapping") @@ -191,34 +176,28 @@ def plotMapDataTime(df, prefix): ax.set_xlabel("edge length(h) of mesh A") ax.set_ylabel("time to map Data [ms]") - # plotConv(ax, df, yname) - plt.gca().invert_xaxis() plt.grid() plt.savefig(prefix + "-mapt.pdf") def main(argv): - args = parseArguments(argv[1:]) + args = parse_arguments(argv[1:]) plt.rcParams["legend.fontsize"] = "small" plt.rcParams["figure.figsize"] = "8, 8" plt.rcParams["figure.autolayout"] = "true" df = pandas.read_csv(args.file) - toMeshes = df["mesh B"].unique() - assert ( - len(toMeshes) == 1 - ), f"There are {len(toMeshes)} to-meshes but only 1 is allowed. Fix your dataset!" + to_meshes = df["mesh B"].unique() + assert len(to_meshes) == 1, f"There are {len(to_meshes)} to-meshes but only 1 is allowed. Fix your dataset!" df.sort_values("mesh A", inplace=True) - plotError(df, args.prefix) - plotMemory(df, args.prefix) - plotMapDataTime(df, args.prefix) - plotComputeMappingTime(df, args.prefix) + plot_error(df, args.prefix) + plot_memory_usage(df, args.prefix) + plot_map_data_time(df, args.prefix) + plot_compute_mapping_time(df, args.prefix) return 0 if __name__ == "__main__": - import sys - sys.exit(main(sys.argv)) diff --git a/tools/mapping-tester/gatherstats.py b/tools/mapping-tester/gather_stats.py similarity index 79% rename from tools/mapping-tester/gatherstats.py rename to tools/mapping-tester/gather_stats.py index 24397c13..09f42746 100755 --- a/tools/mapping-tester/gatherstats.py +++ b/tools/mapping-tester/gather_stats.py @@ -5,9 +5,10 @@ import glob import json import os +import sys -def parseArguments(args): +def parse_arguments(args): parser = argparse.ArgumentParser(description="Gathers stats after a run") parser.add_argument( "-o", @@ -25,7 +26,7 @@ def parseArguments(args): return parser.parse_args(args) -def statsFromTimings(dir): +def stats_from_timings(dir): stats = {} assert os.path.isdir(dir) file = os.path.join(dir, "precice-B-events.json") @@ -39,14 +40,10 @@ def statsFromTimings(dir): computeMappingName = [ x for x in timings.keys() - if x.startswith("advance/map") - and x.endswith("computeMapping.FromA-MeshToB-Mesh") + if x.startswith("advance/map") and x.endswith("computeMapping.FromA-MeshToB-Mesh") ][0] mapDataName = [ - x - for x in timings.keys() - if x.startswith("advance/map") - and x.endswith("mapData.FromA-MeshToB-Mesh") + x for x in timings.keys() if x.startswith("advance/map") and x.endswith("mapData.FromA-MeshToB-Mesh") ][0] stats["computeMappingTime"] = timings[computeMappingName]["Max"] stats["mapDataTime"] = timings[mapDataName]["Max"] @@ -55,7 +52,7 @@ def statsFromTimings(dir): return stats -def memoryStats(dir): +def memory_stats(dir): stats = {} assert os.path.isdir(dir) for P in "A", "B": @@ -73,23 +70,20 @@ def memoryStats(dir): def main(argv): - args = parseArguments(argv[1:]) + args = parse_arguments(argv[1:]) globber = os.path.join(args.outdir, "**", "*.stats.json") - statFiles = [ - os.path.relpath(path, args.outdir) - for path in glob.iglob(globber, recursive=True) - ] + stat_files = [os.path.relpath(path, args.outdir) for path in glob.iglob(globber, recursive=True)] allstats = [] fields = [] - for file in statFiles: + for file in stat_files: print("Found: " + file) casedir = os.path.join(args.outdir, os.path.dirname(file)) parts = os.path.normpath(file).split(os.sep) assert len(parts) >= 5 mapping, constraint, meshes, ranks, _ = parts[-5:] meshA, meshB = meshes.split("-") - ranksA, ranksB = meshes.split("-") + ranksA, ranksB = ranks.split("-") with open(os.path.join(args.outdir, file), "r") as jsonfile: stats = json.load(jsonfile) @@ -99,8 +93,8 @@ def main(argv): stats["mesh B"] = meshB stats["ranks A"] = ranksA stats["ranks B"] = ranksB - stats.update(statsFromTimings(casedir)) - stats.update(memoryStats(casedir)) + stats.update(stats_from_timings(casedir)) + stats.update(memory_stats(casedir)) allstats.append(stats) if not fields: fields += stats.keys() @@ -113,6 +107,4 @@ def main(argv): if __name__ == "__main__": - import sys - sys.exit(main(sys.argv)) diff --git a/tools/mapping-tester/generate.py b/tools/mapping-tester/generate_mapping_test.py similarity index 72% rename from tools/mapping-tester/generate.py rename to tools/mapping-tester/generate_mapping_test.py index 747599b3..7bc9e566 100755 --- a/tools/mapping-tester/generate.py +++ b/tools/mapping-tester/generate_mapping_test.py @@ -3,11 +3,11 @@ import argparse import json import os - +import sys from jinja2 import Template -def generateConfig(template, setup): +def generate_config(template, setup): template = Template(template) return template.render(setup) @@ -20,7 +20,7 @@ def as_iter(something): return [something] -def generateCases(setup): +def generate_cases(setup): meshes = setup["general"]["meshes"] network = setup["general"].get("network", "lo") syncmode = setup["general"].get("syncmode", "false") @@ -68,7 +68,7 @@ def generateCases(setup): return cases -def getCaseFolders(case): +def get_case_folder(case): return [ case["mapping"]["name"], case["mapping"]["constraint"], @@ -77,21 +77,21 @@ def getCaseFolders(case): ] -def caseToSortable(case): +def case_to_sortable(case): parts = case.split(os.path.sep) kind = parts[0] mesha, meshb = map(float, parts[-2].split("-")) - kindCost = 0 + kind_cost = 0 if kind.startswith("gaussian"): - kindCost = 1 + kind_cost = 1 elif kind.startswith("tps"): - kindCost = 2 + kind_cost = 2 - return (kindCost, -mesha, -meshb) + return (kind_cost, -mesha, -meshb) -def createMasterRunScripts(casemap, dir): +def create_master_run_scripts(casemap, dir): common = [ "#!/bin/bash", "", @@ -101,63 +101,43 @@ def createMasterRunScripts(casemap, dir): ] # Generate master runner script - content = common + [ - "${RUNNER} " + os.path.join(case, "runall.sh") for case in casemap.keys() - ] - open(os.path.join(dir, "runall.sh"), "w").writelines( - [line + "\n" for line in content] - ) + content = common + ["${RUNNER} " + os.path.join(case, "runall.sh") for case in casemap.keys()] + open(os.path.join(dir, "runall.sh"), "w").writelines([line + "\n" for line in content]) # Generate master postprocessing script - post = common + [ - "${RUNNER} " + os.path.join(case, "postprocessall.sh") - for case in casemap.keys() - ] - open(os.path.join(dir, "postprocessall.sh"), "w").writelines( - [line + "\n" for line in post] - ) + post = common + ["${RUNNER} " + os.path.join(case, "postprocessall.sh") for case in casemap.keys()] + open(os.path.join(dir, "postprocessall.sh"), "w").writelines([line + "\n" for line in post]) for case, instances in casemap.items(): # Generate master runner script - content = common + [ - "${RUNNER} " + os.path.join(*instance, "run-wrapper.sh") - for instance in instances - ] - open(os.path.join(dir, case, "runall.sh"), "w").writelines( - [line + "\n" for line in content] - ) + content = common + ["${RUNNER} " + os.path.join(*instance, "run-wrapper.sh") for instance in instances] + open(os.path.join(dir, case, "runall.sh"), "w").writelines([line + "\n" for line in content]) # Generate master postprocessing script - post = common + [ - "${RUNNER} " + os.path.join(*instance, "post.sh") for instance in instances - ] - open(os.path.join(dir, case, "postprocessall.sh"), "w").writelines( - [line + "\n" for line in post] - ) + post = common + ["${RUNNER} " + os.path.join(*instance, "post.sh") for instance in instances] + open(os.path.join(dir, case, "postprocessall.sh"), "w").writelines([line + "\n" for line in post]) -def createRunScript(outdir, path, case): +def create_run_script(outdir, path, case): amesh = case["A"]["mesh"]["name"] aranks = case["A"]["ranks"] - ameshLocation = os.path.relpath( - os.path.join(outdir, "meshes", amesh, str(aranks), amesh), path - ) + amesh_location = os.path.relpath(os.path.join(outdir, "meshes", amesh, str(aranks), amesh), path) # Generate runner script - acmd = '/usr/bin/time -f %M -a -o memory-A.log precice-aste-run -v -a -p A --data "{}" --mesh {} || kill 0 &'.format( - case["function"], ameshLocation + acmd = ( + '/usr/bin/time -f %M -a -o memory-A.log precice-aste-run -v -a -p A --data "{}" --mesh {} || kill 0 &'.format( + case["function"], amesh_location + ) ) if aranks > 1: acmd = "mpirun -n {} $ASTE_A_MPIARGS {}".format(aranks, acmd) bmesh = case["B"]["mesh"]["name"] branks = case["B"]["ranks"] - bmeshLocation = os.path.relpath( - os.path.join(outdir, "meshes", bmesh, str(branks), bmesh), path - ) + bmesh_location = os.path.relpath(os.path.join(outdir, "meshes", bmesh, str(branks), bmesh), path) mapped_data_name = case["function"] + "(mapped)" bcmd = '/usr/bin/time -f %M -a -o memory-B.log precice-aste-run -v -a -p B --data "{}" --mesh {} --output mapped || kill 0 &'.format( - mapped_data_name, bmeshLocation + mapped_data_name, bmesh_location ) if branks > 1: bcmd = "mpirun -n {} $ASTE_B_MPIARGS {}".format(branks, bcmd) @@ -170,9 +150,7 @@ def createRunScript(outdir, path, case): "rm -f memory-A.log memory-B.log done running failed", "rm -fr mapped && mkdir mapped", "touch running", - "echo '= {} ({}) {} - {}'".format( - case["mapping"]["name"], case["mapping"]["constraint"], amesh, bmesh - ), + "echo '= {} ({}) {} - {}'".format(case["mapping"]["name"], case["mapping"]["constraint"], amesh, bmesh), "echo '=========='", "", "set -m", @@ -188,9 +166,7 @@ def createRunScript(outdir, path, case): "fi", "rm -f running", ] - open(os.path.join(path, "run.sh"), "w").writelines( - [line + "\n" for line in content] - ) + open(os.path.join(path, "run.sh"), "w").writelines([line + "\n" for line in content]) # Generate wrapper script for runner wrapper = [ @@ -198,18 +174,14 @@ def createRunScript(outdir, path, case): 'cd "$( dirname "${BASH_SOURCE[0]}" )"', "/bin/bash run.sh 2>&1 | tee run.log", ] - open(os.path.join(path, "run-wrapper.sh"), "w").writelines( - [line + "\n" for line in wrapper] - ) + open(os.path.join(path, "run-wrapper.sh"), "w").writelines([line + "\n" for line in wrapper]) # Generate post processing script post_content = [ "#!/bin/bash", "set -e -u", 'cd "$( dirname "${BASH_SOURCE[0]}" )"', - "echo '= {} ({}) {} - {}'".format( - case["mapping"]["name"], case["mapping"]["constraint"], amesh, bmesh - ), + "echo '= {} ({}) {} - {}'".format(case["mapping"]["name"], case["mapping"]["constraint"], amesh, bmesh), ] if branks == 1: joincmd = "[ ! -f mapped.vtu ] || mv --update mapped.vtu mapped.vtk" @@ -218,26 +190,20 @@ def createRunScript(outdir, path, case): ) post_content += [joincmd, diffcmd] else: - [recoveryFileLocation, tmpPrefix] = os.path.split( - os.path.normpath(bmeshLocation) - ) - tmprecoveryFile = recoveryFileLocation + "/{}_recovery.json".format(bmesh) - joincmd = "precice-aste-join --mesh mapped -r {} -o result.vtk".format( - tmprecoveryFile - ) + [recovery_file_location, _] = os.path.split(os.path.normpath(bmesh_location)) + tmp_recovery_file = recovery_file_location + "/{}_recovery.json".format(bmesh) + joincmd = "precice-aste-join --mesh mapped -r {} -o result.vtk".format(tmp_recovery_file) diffcmd = 'precice-aste-evaluate --data error --diffdata "{1}" --diff --stats --mesh result.vtk --function "{0}" | tee diff.log'.format( case["function"], mapped_data_name ) post_content += [joincmd, diffcmd] - open(os.path.join(path, "post.sh"), "w").writelines( - [line + "\n" for line in post_content] - ) + open(os.path.join(path, "post.sh"), "w").writelines([line + "\n" for line in post_content]) -def setupCases(outdir, template, cases): +def setup_cases(outdir, template, cases): casemap = {} for case in cases: - folders = getCaseFolders(case) + folders = get_case_folder(case) casemap.setdefault(folders[0], []).append(folders[1:]) name = [outdir] + folders path = os.path.join(*name) @@ -246,15 +212,15 @@ def setupCases(outdir, template, cases): print(f"Generating {path}") os.makedirs(path, exist_ok=True) with open(config, "w") as config: - config.write(generateConfig(template, case)) - createRunScript(outdir, path, case) + config.write(generate_config(template, case)) + create_run_script(outdir, path, case) print(f"Generated {len(cases)} cases") print(f"Generating master scripts") - createMasterRunScripts(casemap, outdir) + create_master_run_scripts(casemap, outdir) -def parseArguments(args): +def parse_arguments(args): parser = argparse.ArgumentParser(description="Generator for a mapping test suite") parser.add_argument( "-o", @@ -281,23 +247,21 @@ def parseArguments(args): def main(argv): # Parse the input arguments - args = parseArguments(argv[1:]) + args = parse_arguments(argv[1:]) # Parse the json file using the json module setup = json.load(args.setup) # Read the xml-template file template = args.template.read() # Generate the actual cases - cases = generateCases(setup) + cases = generate_cases(setup) outdir = os.path.normpath(args.outdir) if os.path.isdir(outdir): print('Warning: outdir "{}" already exisits.'.format(outdir)) - setupCases(outdir, template, cases) + setup_cases(outdir, template, cases) return 0 if __name__ == "__main__": - import sys - sys.exit(main(sys.argv)) diff --git a/tools/mapping-tester/local_rbf.py b/tools/mapping-tester/local_rbf.py index 7c1b745f..51fe3479 100755 --- a/tools/mapping-tester/local_rbf.py +++ b/tools/mapping-tester/local_rbf.py @@ -46,9 +46,7 @@ def parseArguments(argv): parser.add_argument("-p", "--polynomials", default=default_polynomials, type=str) parser.add_argument("-t", "--types", default=default_types, type=str) parser.add_argument("-n", "--coverage", default="3,5,10,15", type=str) - parser.add_argument( - "-o", "--output", default=sys.stdout, type=argparse.FileType("w") - ) + parser.add_argument("-o", "--output", default=sys.stdout, type=argparse.FileType("w")) parser.add_argument("-r", "--solver-rtol", default=1e-9, type=float) args = parser.parse_args(argv[1:]) @@ -56,9 +54,7 @@ def parseArguments(argv): # Sanitize arguments args.a = [float(e.strip()) for e in args.a.split(",")] args.b = [float(e.strip()) for e in args.b.split(",")] - args.polynomials = [ - sanitize(e, valid_polynomials) for e in args.polynomials.split(",") - ] + args.polynomials = [sanitize(e, valid_polynomials) for e in args.polynomials.split(",")] args.types = [sanitize(e, valid_types) for e in args.types.split(",")] args.coverage = [int(e.strip()) for e in args.coverage.split(",")] @@ -104,9 +100,7 @@ def main(argv): # of mesh a. for a in args.a: cases = {} - for polynomial, coverage, type in itertools.product( - args.polynomials, args.coverage, args.types - ): + for polynomial, coverage, type in itertools.product(args.polynomials, args.coverage, args.types): name = f"{type}-n{coverage}-{polynomial}" assert name not in cases config = getConfigurator(type)(a, coverage) diff --git a/tools/mapping-tester/preparemeshes.py b/tools/mapping-tester/prepare_mapping_test_meshes.py similarity index 63% rename from tools/mapping-tester/preparemeshes.py rename to tools/mapping-tester/prepare_mapping_test_meshes.py index 78e77d99..54a43cd7 100755 --- a/tools/mapping-tester/preparemeshes.py +++ b/tools/mapping-tester/prepare_mapping_test_meshes.py @@ -8,7 +8,7 @@ import subprocess -def parseArguments(args): +def parse_arguments(args): parser = argparse.ArgumentParser(description="Prepares meshes for a test suite") parser.add_argument( "-o", @@ -23,30 +23,28 @@ def parseArguments(args): default="setup.json", help="The test setup file to use.", ) - parser.add_argument( - "-f", "--force", action="store_true", help="Remove existing meshes." - ) + parser.add_argument("-f", "--force", action="store_true", help="Remove existing meshes.") return parser.parse_args(args) -def prepareMainMesh(meshdir, name, file, function, force=False): - mainDir = os.path.join(meshdir, name, "1") - mainMesh = os.path.join(mainDir, name + ".vtu") - print("Preparing Mesh {} in {}".format(name, mainDir)) +def prepare_main_mesh(meshdir, name, file, function, force=False): + main_dir = os.path.join(meshdir, name, "1") + main_mesh = os.path.join(main_dir, name + ".vtu") + print("Preparing Mesh {} in {}".format(name, main_dir)) - if os.path.isdir(mainDir): + if os.path.isdir(main_dir): if force: print(" Regenerating the mesh.") - shutil.rmtree(mainDir) + shutil.rmtree(main_dir) else: print(" Mesh already exists.") return - os.makedirs(mainDir, exist_ok=True) + os.makedirs(main_dir, exist_ok=True) data_name = "{}".format(function) - [pathName, tmpfilename] = os.path.split(os.path.normpath(mainMesh)) + [path_name, tmpfilename] = os.path.split(os.path.normpath(main_mesh)) subprocess.run( [ "precice-aste-evaluate", @@ -57,45 +55,45 @@ def prepareMainMesh(meshdir, name, file, function, force=False): "--data", data_name, "--directory", - pathName, + path_name, "-o", tmpfilename, ] ) -def preparePartMesh(meshdir, name, p, force=False): +def prepare_part_mesh(meshdir, name, p, force=False): if p == 1: return - mainMesh = os.path.join(meshdir, name, "1", name + ".vtu") - partDir = os.path.join(meshdir, name, str(p)) - partMesh = os.path.join(partDir, name) - print("Preparing Mesh {} with {} paritions in {}".format(name, p, partDir)) + main_mesh = os.path.join(meshdir, name, "1", name + ".vtu") + part_dir = os.path.join(meshdir, name, str(p)) + part_mesh = os.path.join(part_dir, name) + print("Preparing Mesh {} with {} paritions in {}".format(name, p, part_dir)) - if os.path.isdir(partDir): + if os.path.isdir(part_dir): if force: print(" Regenerating the partitioned mesh.") - shutil.rmtree(partDir) + shutil.rmtree(part_dir) else: print(" Partitioned mesh already exists.") return - os.makedirs(partDir, exist_ok=True) - [pathName, tmpfilename] = os.path.split(os.path.normpath(partMesh)) + os.makedirs(part_dir, exist_ok=True) + [path_name, tmpfilename] = os.path.split(os.path.normpath(part_mesh)) subprocess.run( [ "precice-aste-partition", "--mesh", - mainMesh, + main_mesh, "--algorithm", "meshfree", "-o", - partMesh, + part_mesh, "--directory", - pathName, + path_name, "-n", str(p), ] @@ -103,7 +101,7 @@ def preparePartMesh(meshdir, name, p, force=False): def main(argv): - args = parseArguments(argv[1:]) + args = parse_arguments(argv[1:]) setup = json.load(args.setup) outdir = os.path.normpath(args.outdir) @@ -112,9 +110,7 @@ def main(argv): meshdir = os.path.join(outdir, "meshes") function = setup["general"]["function"] - partitions = set( - [int(rank) for pranks in setup["general"]["ranks"].values() for rank in pranks] - ) + partitions = set([int(rank) for pranks in setup["general"]["ranks"].values() for rank in pranks]) for name, file in set( itertools.chain( @@ -125,10 +121,10 @@ def main(argv): if not os.path.isfile(os.path.expandvars(file)): raise Exception(f'\033[91m Unable to open file called "{file}".\033[0m') - prepareMainMesh(meshdir, name, file, function, args.force) + prepare_main_mesh(meshdir, name, file, function, args.force) for p in partitions: - preparePartMesh(meshdir, name, p, args.force) + prepare_part_mesh(meshdir, name, p, args.force) return 0 From dbebf71f0e7f2c00cf50c0e71f40adedcd6f81cc Mon Sep 17 00:00:00 2001 From: Kursat Yurt Date: Mon, 12 Dec 2022 15:58:08 +0100 Subject: [PATCH 2/6] Reformat --- tools/mapping-tester/create_plots.py | 20 +++-- tools/mapping-tester/gather_stats.py | 13 +++- tools/mapping-tester/generate_mapping_test.py | 73 ++++++++++++++----- tools/mapping-tester/local_rbf.py | 12 ++- .../prepare_mapping_test_meshes.py | 8 +- 5 files changed, 92 insertions(+), 34 deletions(-) diff --git a/tools/mapping-tester/create_plots.py b/tools/mapping-tester/create_plots.py index 0a3bd0dc..ddada802 100755 --- a/tools/mapping-tester/create_plots.py +++ b/tools/mapping-tester/create_plots.py @@ -2,10 +2,10 @@ import argparse import math -import matplotlib.pyplot as plt -import pandas import sys +import matplotlib.pyplot as plt +import pandas style_colours = [ "#0173b2", @@ -24,7 +24,9 @@ def parse_arguments(args): - parser = argparse.ArgumentParser(description="Creates convergence plots from gathered stats") + parser = argparse.ArgumentParser( + description="Creates convergence plots from gathered stats" + ) parser.add_argument( "-f", "--file", @@ -56,7 +58,9 @@ def plot_convergence(ax, df, yname): foy1 = ymax foy2 = foy1 * (fox[1] / fox[0]) foy = [foy1, foy2] - ax.axline((fox[0], foy[0]), (fox[1], foy[1]), color="lightgray", linewidth=1.0, zorder=-1) + ax.axline( + (fox[0], foy[0]), (fox[1], foy[1]), color="lightgray", linewidth=1.0, zorder=-1 + ) ax.annotate("1st order", xy=(lavg(fox), lavg(foy)), color="gray", zorder=-1) # 2nd order line @@ -65,7 +69,9 @@ def plot_convergence(ax, df, yname): soy2 = soy1 * ((sox[1] / sox[0]) ** 2) soy = [soy1, soy2] print(sox, soy) - ax.axline((sox[0], soy[0]), (sox[1], soy[1]), color="lightgray", linewidth=1.0, zorder=-1) + ax.axline( + (sox[0], soy[0]), (sox[1], soy[1]), color="lightgray", linewidth=1.0, zorder=-1 + ) ax.annotate("2nd order", xy=(lavg(sox), lavg(soy)), color="gray", zorder=-1) @@ -190,7 +196,9 @@ def main(argv): df = pandas.read_csv(args.file) to_meshes = df["mesh B"].unique() - assert len(to_meshes) == 1, f"There are {len(to_meshes)} to-meshes but only 1 is allowed. Fix your dataset!" + assert ( + len(to_meshes) == 1 + ), f"There are {len(to_meshes)} to-meshes but only 1 is allowed. Fix your dataset!" df.sort_values("mesh A", inplace=True) plot_error(df, args.prefix) plot_memory_usage(df, args.prefix) diff --git a/tools/mapping-tester/gather_stats.py b/tools/mapping-tester/gather_stats.py index 09f42746..3d33adce 100755 --- a/tools/mapping-tester/gather_stats.py +++ b/tools/mapping-tester/gather_stats.py @@ -40,10 +40,14 @@ def stats_from_timings(dir): computeMappingName = [ x for x in timings.keys() - if x.startswith("advance/map") and x.endswith("computeMapping.FromA-MeshToB-Mesh") + if x.startswith("advance/map") + and x.endswith("computeMapping.FromA-MeshToB-Mesh") ][0] mapDataName = [ - x for x in timings.keys() if x.startswith("advance/map") and x.endswith("mapData.FromA-MeshToB-Mesh") + x + for x in timings.keys() + if x.startswith("advance/map") + and x.endswith("mapData.FromA-MeshToB-Mesh") ][0] stats["computeMappingTime"] = timings[computeMappingName]["Max"] stats["mapDataTime"] = timings[mapDataName]["Max"] @@ -73,7 +77,10 @@ def main(argv): args = parse_arguments(argv[1:]) globber = os.path.join(args.outdir, "**", "*.stats.json") - stat_files = [os.path.relpath(path, args.outdir) for path in glob.iglob(globber, recursive=True)] + stat_files = [ + os.path.relpath(path, args.outdir) + for path in glob.iglob(globber, recursive=True) + ] allstats = [] fields = [] for file in stat_files: diff --git a/tools/mapping-tester/generate_mapping_test.py b/tools/mapping-tester/generate_mapping_test.py index 7bc9e566..79f1ba6a 100755 --- a/tools/mapping-tester/generate_mapping_test.py +++ b/tools/mapping-tester/generate_mapping_test.py @@ -4,6 +4,7 @@ import json import os import sys + from jinja2 import Template @@ -101,40 +102,60 @@ def create_master_run_scripts(casemap, dir): ] # Generate master runner script - content = common + ["${RUNNER} " + os.path.join(case, "runall.sh") for case in casemap.keys()] - open(os.path.join(dir, "runall.sh"), "w").writelines([line + "\n" for line in content]) + content = common + [ + "${RUNNER} " + os.path.join(case, "runall.sh") for case in casemap.keys() + ] + open(os.path.join(dir, "runall.sh"), "w").writelines( + [line + "\n" for line in content] + ) # Generate master postprocessing script - post = common + ["${RUNNER} " + os.path.join(case, "postprocessall.sh") for case in casemap.keys()] - open(os.path.join(dir, "postprocessall.sh"), "w").writelines([line + "\n" for line in post]) + post = common + [ + "${RUNNER} " + os.path.join(case, "postprocessall.sh") + for case in casemap.keys() + ] + open(os.path.join(dir, "postprocessall.sh"), "w").writelines( + [line + "\n" for line in post] + ) for case, instances in casemap.items(): # Generate master runner script - content = common + ["${RUNNER} " + os.path.join(*instance, "run-wrapper.sh") for instance in instances] - open(os.path.join(dir, case, "runall.sh"), "w").writelines([line + "\n" for line in content]) + content = common + [ + "${RUNNER} " + os.path.join(*instance, "run-wrapper.sh") + for instance in instances + ] + open(os.path.join(dir, case, "runall.sh"), "w").writelines( + [line + "\n" for line in content] + ) # Generate master postprocessing script - post = common + ["${RUNNER} " + os.path.join(*instance, "post.sh") for instance in instances] - open(os.path.join(dir, case, "postprocessall.sh"), "w").writelines([line + "\n" for line in post]) + post = common + [ + "${RUNNER} " + os.path.join(*instance, "post.sh") for instance in instances + ] + open(os.path.join(dir, case, "postprocessall.sh"), "w").writelines( + [line + "\n" for line in post] + ) def create_run_script(outdir, path, case): amesh = case["A"]["mesh"]["name"] aranks = case["A"]["ranks"] - amesh_location = os.path.relpath(os.path.join(outdir, "meshes", amesh, str(aranks), amesh), path) + amesh_location = os.path.relpath( + os.path.join(outdir, "meshes", amesh, str(aranks), amesh), path + ) # Generate runner script - acmd = ( - '/usr/bin/time -f %M -a -o memory-A.log precice-aste-run -v -a -p A --data "{}" --mesh {} || kill 0 &'.format( - case["function"], amesh_location - ) + acmd = '/usr/bin/time -f %M -a -o memory-A.log precice-aste-run -v -a -p A --data "{}" --mesh {} || kill 0 &'.format( + case["function"], amesh_location ) if aranks > 1: acmd = "mpirun -n {} $ASTE_A_MPIARGS {}".format(aranks, acmd) bmesh = case["B"]["mesh"]["name"] branks = case["B"]["ranks"] - bmesh_location = os.path.relpath(os.path.join(outdir, "meshes", bmesh, str(branks), bmesh), path) + bmesh_location = os.path.relpath( + os.path.join(outdir, "meshes", bmesh, str(branks), bmesh), path + ) mapped_data_name = case["function"] + "(mapped)" bcmd = '/usr/bin/time -f %M -a -o memory-B.log precice-aste-run -v -a -p B --data "{}" --mesh {} --output mapped || kill 0 &'.format( mapped_data_name, bmesh_location @@ -150,7 +171,9 @@ def create_run_script(outdir, path, case): "rm -f memory-A.log memory-B.log done running failed", "rm -fr mapped && mkdir mapped", "touch running", - "echo '= {} ({}) {} - {}'".format(case["mapping"]["name"], case["mapping"]["constraint"], amesh, bmesh), + "echo '= {} ({}) {} - {}'".format( + case["mapping"]["name"], case["mapping"]["constraint"], amesh, bmesh + ), "echo '=========='", "", "set -m", @@ -166,7 +189,9 @@ def create_run_script(outdir, path, case): "fi", "rm -f running", ] - open(os.path.join(path, "run.sh"), "w").writelines([line + "\n" for line in content]) + open(os.path.join(path, "run.sh"), "w").writelines( + [line + "\n" for line in content] + ) # Generate wrapper script for runner wrapper = [ @@ -174,14 +199,18 @@ def create_run_script(outdir, path, case): 'cd "$( dirname "${BASH_SOURCE[0]}" )"', "/bin/bash run.sh 2>&1 | tee run.log", ] - open(os.path.join(path, "run-wrapper.sh"), "w").writelines([line + "\n" for line in wrapper]) + open(os.path.join(path, "run-wrapper.sh"), "w").writelines( + [line + "\n" for line in wrapper] + ) # Generate post processing script post_content = [ "#!/bin/bash", "set -e -u", 'cd "$( dirname "${BASH_SOURCE[0]}" )"', - "echo '= {} ({}) {} - {}'".format(case["mapping"]["name"], case["mapping"]["constraint"], amesh, bmesh), + "echo '= {} ({}) {} - {}'".format( + case["mapping"]["name"], case["mapping"]["constraint"], amesh, bmesh + ), ] if branks == 1: joincmd = "[ ! -f mapped.vtu ] || mv --update mapped.vtu mapped.vtk" @@ -192,12 +221,16 @@ def create_run_script(outdir, path, case): else: [recovery_file_location, _] = os.path.split(os.path.normpath(bmesh_location)) tmp_recovery_file = recovery_file_location + "/{}_recovery.json".format(bmesh) - joincmd = "precice-aste-join --mesh mapped -r {} -o result.vtk".format(tmp_recovery_file) + joincmd = "precice-aste-join --mesh mapped -r {} -o result.vtk".format( + tmp_recovery_file + ) diffcmd = 'precice-aste-evaluate --data error --diffdata "{1}" --diff --stats --mesh result.vtk --function "{0}" | tee diff.log'.format( case["function"], mapped_data_name ) post_content += [joincmd, diffcmd] - open(os.path.join(path, "post.sh"), "w").writelines([line + "\n" for line in post_content]) + open(os.path.join(path, "post.sh"), "w").writelines( + [line + "\n" for line in post_content] + ) def setup_cases(outdir, template, cases): diff --git a/tools/mapping-tester/local_rbf.py b/tools/mapping-tester/local_rbf.py index 51fe3479..7c1b745f 100755 --- a/tools/mapping-tester/local_rbf.py +++ b/tools/mapping-tester/local_rbf.py @@ -46,7 +46,9 @@ def parseArguments(argv): parser.add_argument("-p", "--polynomials", default=default_polynomials, type=str) parser.add_argument("-t", "--types", default=default_types, type=str) parser.add_argument("-n", "--coverage", default="3,5,10,15", type=str) - parser.add_argument("-o", "--output", default=sys.stdout, type=argparse.FileType("w")) + parser.add_argument( + "-o", "--output", default=sys.stdout, type=argparse.FileType("w") + ) parser.add_argument("-r", "--solver-rtol", default=1e-9, type=float) args = parser.parse_args(argv[1:]) @@ -54,7 +56,9 @@ def parseArguments(argv): # Sanitize arguments args.a = [float(e.strip()) for e in args.a.split(",")] args.b = [float(e.strip()) for e in args.b.split(",")] - args.polynomials = [sanitize(e, valid_polynomials) for e in args.polynomials.split(",")] + args.polynomials = [ + sanitize(e, valid_polynomials) for e in args.polynomials.split(",") + ] args.types = [sanitize(e, valid_types) for e in args.types.split(",")] args.coverage = [int(e.strip()) for e in args.coverage.split(",")] @@ -100,7 +104,9 @@ def main(argv): # of mesh a. for a in args.a: cases = {} - for polynomial, coverage, type in itertools.product(args.polynomials, args.coverage, args.types): + for polynomial, coverage, type in itertools.product( + args.polynomials, args.coverage, args.types + ): name = f"{type}-n{coverage}-{polynomial}" assert name not in cases config = getConfigurator(type)(a, coverage) diff --git a/tools/mapping-tester/prepare_mapping_test_meshes.py b/tools/mapping-tester/prepare_mapping_test_meshes.py index 54a43cd7..0481a0ac 100755 --- a/tools/mapping-tester/prepare_mapping_test_meshes.py +++ b/tools/mapping-tester/prepare_mapping_test_meshes.py @@ -23,7 +23,9 @@ def parse_arguments(args): default="setup.json", help="The test setup file to use.", ) - parser.add_argument("-f", "--force", action="store_true", help="Remove existing meshes.") + parser.add_argument( + "-f", "--force", action="store_true", help="Remove existing meshes." + ) return parser.parse_args(args) @@ -110,7 +112,9 @@ def main(argv): meshdir = os.path.join(outdir, "meshes") function = setup["general"]["function"] - partitions = set([int(rank) for pranks in setup["general"]["ranks"].values() for rank in pranks]) + partitions = set( + [int(rank) for pranks in setup["general"]["ranks"].values() for rank in pranks] + ) for name, file in set( itertools.chain( From b0af705be6de5d7a215e0ad29fddce08e9f2d5c4 Mon Sep 17 00:00:00 2001 From: Kursat Yurt Date: Mon, 12 Dec 2022 16:05:39 +0100 Subject: [PATCH 3/6] Rename directory --- .../config-template.xml | 0 tools/{mapping-tester => mapping-scaling-tester}/create_plots.py | 0 tools/{mapping-tester => mapping-scaling-tester}/gather_stats.py | 0 .../generate_mapping_test.py | 0 tools/{mapping-tester => mapping-scaling-tester}/local_rbf.py | 0 .../{mapping-tester => mapping-scaling-tester}/plots/paperplot.py | 0 tools/{mapping-tester => mapping-scaling-tester}/plots/plot.py | 0 .../prepare_mapping_test_meshes.py | 0 .../setup-turbine-big.json | 0 .../setup-turbine-small-tps.json | 0 .../setup-turbine-small.json | 0 tools/{mapping-tester => mapping-scaling-tester}/setup.json | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename tools/{mapping-tester => mapping-scaling-tester}/config-template.xml (100%) rename tools/{mapping-tester => mapping-scaling-tester}/create_plots.py (100%) rename tools/{mapping-tester => mapping-scaling-tester}/gather_stats.py (100%) rename tools/{mapping-tester => mapping-scaling-tester}/generate_mapping_test.py (100%) rename tools/{mapping-tester => mapping-scaling-tester}/local_rbf.py (100%) rename tools/{mapping-tester => mapping-scaling-tester}/plots/paperplot.py (100%) rename tools/{mapping-tester => mapping-scaling-tester}/plots/plot.py (100%) rename tools/{mapping-tester => mapping-scaling-tester}/prepare_mapping_test_meshes.py (100%) rename tools/{mapping-tester => mapping-scaling-tester}/setup-turbine-big.json (100%) rename tools/{mapping-tester => mapping-scaling-tester}/setup-turbine-small-tps.json (100%) rename tools/{mapping-tester => mapping-scaling-tester}/setup-turbine-small.json (100%) rename tools/{mapping-tester => mapping-scaling-tester}/setup.json (100%) diff --git a/tools/mapping-tester/config-template.xml b/tools/mapping-scaling-tester/config-template.xml similarity index 100% rename from tools/mapping-tester/config-template.xml rename to tools/mapping-scaling-tester/config-template.xml diff --git a/tools/mapping-tester/create_plots.py b/tools/mapping-scaling-tester/create_plots.py similarity index 100% rename from tools/mapping-tester/create_plots.py rename to tools/mapping-scaling-tester/create_plots.py diff --git a/tools/mapping-tester/gather_stats.py b/tools/mapping-scaling-tester/gather_stats.py similarity index 100% rename from tools/mapping-tester/gather_stats.py rename to tools/mapping-scaling-tester/gather_stats.py diff --git a/tools/mapping-tester/generate_mapping_test.py b/tools/mapping-scaling-tester/generate_mapping_test.py similarity index 100% rename from tools/mapping-tester/generate_mapping_test.py rename to tools/mapping-scaling-tester/generate_mapping_test.py diff --git a/tools/mapping-tester/local_rbf.py b/tools/mapping-scaling-tester/local_rbf.py similarity index 100% rename from tools/mapping-tester/local_rbf.py rename to tools/mapping-scaling-tester/local_rbf.py diff --git a/tools/mapping-tester/plots/paperplot.py b/tools/mapping-scaling-tester/plots/paperplot.py similarity index 100% rename from tools/mapping-tester/plots/paperplot.py rename to tools/mapping-scaling-tester/plots/paperplot.py diff --git a/tools/mapping-tester/plots/plot.py b/tools/mapping-scaling-tester/plots/plot.py similarity index 100% rename from tools/mapping-tester/plots/plot.py rename to tools/mapping-scaling-tester/plots/plot.py diff --git a/tools/mapping-tester/prepare_mapping_test_meshes.py b/tools/mapping-scaling-tester/prepare_mapping_test_meshes.py similarity index 100% rename from tools/mapping-tester/prepare_mapping_test_meshes.py rename to tools/mapping-scaling-tester/prepare_mapping_test_meshes.py diff --git a/tools/mapping-tester/setup-turbine-big.json b/tools/mapping-scaling-tester/setup-turbine-big.json similarity index 100% rename from tools/mapping-tester/setup-turbine-big.json rename to tools/mapping-scaling-tester/setup-turbine-big.json diff --git a/tools/mapping-tester/setup-turbine-small-tps.json b/tools/mapping-scaling-tester/setup-turbine-small-tps.json similarity index 100% rename from tools/mapping-tester/setup-turbine-small-tps.json rename to tools/mapping-scaling-tester/setup-turbine-small-tps.json diff --git a/tools/mapping-tester/setup-turbine-small.json b/tools/mapping-scaling-tester/setup-turbine-small.json similarity index 100% rename from tools/mapping-tester/setup-turbine-small.json rename to tools/mapping-scaling-tester/setup-turbine-small.json diff --git a/tools/mapping-tester/setup.json b/tools/mapping-scaling-tester/setup.json similarity index 100% rename from tools/mapping-tester/setup.json rename to tools/mapping-scaling-tester/setup.json From 4e0e7c52565a70b8f42626c676c89f71283e8417 Mon Sep 17 00:00:00 2001 From: Kursat Yurt Date: Mon, 12 Dec 2022 16:17:59 +0100 Subject: [PATCH 4/6] Add scale mapping scripts --- tools/mapping-scaling-tester/common.py | 197 +++++++++++++++++ tools/mapping-scaling-tester/create_plots.py | 114 ++++++++-- .../generate_mapping_test.py | 199 +----------------- .../generate_scale_test.py | 113 ++++++++++ .../prepare_scale_meshes.py | 164 +++++++++++++++ 5 files changed, 577 insertions(+), 210 deletions(-) create mode 100644 tools/mapping-scaling-tester/common.py create mode 100644 tools/mapping-scaling-tester/generate_scale_test.py create mode 100644 tools/mapping-scaling-tester/prepare_scale_meshes.py diff --git a/tools/mapping-scaling-tester/common.py b/tools/mapping-scaling-tester/common.py new file mode 100644 index 00000000..c39ee29f --- /dev/null +++ b/tools/mapping-scaling-tester/common.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 + +import os +from jinja2 import Template + + +def generate_config(template, setup): + template = Template(template) + return template.render(setup) + + +def as_iter(something): + try: + iter(something) + return something + except TypeError: + return [something] + +def get_case_folder(case): + return [ + case["mapping"]["name"], + case["mapping"]["constraint"], + "{}-{}".format(case["A"]["mesh"]["name"], case["B"]["mesh"]["name"]), + "{}-{}".format(case["A"]["ranks"], case["B"]["ranks"]), + ] + +def case_to_sortable(case): + parts = case.split(os.path.sep) + kind = parts[0] + mesha, meshb = map(float, parts[-2].split("-")) + + kind_cost = 0 + if kind.startswith("gaussian"): + kind_cost = 1 + elif kind.startswith("tps"): + kind_cost = 2 + + return (kind_cost, -mesha, -meshb) + + +def create_master_run_scripts(casemap, dir): + common = [ + "#!/bin/bash", + "", + 'cd "$( dirname "${BASH_SOURCE[0]}" )"', + "RUNNER=/bin/bash", + "", + ] + + # Generate master runner script + content = common + [ + "${RUNNER} " + os.path.join(case, "runall.sh") for case in casemap.keys() + ] + open(os.path.join(dir, "runall.sh"), "w").writelines( + [line + "\n" for line in content] + ) + + # Generate master postprocessing script + post = common + [ + "${RUNNER} " + os.path.join(case, "postprocessall.sh") + for case in casemap.keys() + ] + open(os.path.join(dir, "postprocessall.sh"), "w").writelines( + [line + "\n" for line in post] + ) + + for case, instances in casemap.items(): + # Generate master runner script + content = common + [ + "${RUNNER} " + os.path.join(*instance, "run-wrapper.sh") + for instance in instances + ] + open(os.path.join(dir, case, "runall.sh"), "w").writelines( + [line + "\n" for line in content] + ) + + # Generate master postprocessing script + post = common + [ + "${RUNNER} " + os.path.join(*instance, "post.sh") for instance in instances + ] + open(os.path.join(dir, case, "postprocessall.sh"), "w").writelines( + [line + "\n" for line in post] + ) + +def create_run_script(outdir, path, case): + amesh = case["A"]["mesh"]["name"] + aranks = case["A"]["ranks"] + amesh_location = os.path.relpath( + os.path.join(outdir, "meshes", amesh, str(aranks), amesh), path + ) + + # Generate runner script + acmd = '/usr/bin/time -f %M -a -o memory-A.log precice-aste-run -v -a -p A --data "{}" --mesh {} || kill 0 &'.format( + case["function"], amesh_location + ) + if aranks > 1: + acmd = "mpirun -n {} $ASTE_A_MPIARGS {}".format(aranks, acmd) + + bmesh = case["B"]["mesh"]["name"] + branks = case["B"]["ranks"] + bmesh_location = os.path.relpath( + os.path.join(outdir, "meshes", bmesh, str(branks), bmesh), path + ) + mapped_data_name = case["function"] + "(mapped)" + bcmd = '/usr/bin/time -f %M -a -o memory-B.log precice-aste-run -v -a -p B --data "{}" --mesh {} --output mapped || kill 0 &'.format( + mapped_data_name, bmesh_location + ) + if branks > 1: + bcmd = "mpirun -n {} $ASTE_B_MPIARGS {}".format(branks, bcmd) + + content = [ + "#!/bin/bash", + "set -e -u", + 'cd "$( dirname "${BASH_SOURCE[0]}" )"', + "echo '=========='", + "rm -f memory-A.log memory-B.log done running failed", + "rm -fr mapped && mkdir mapped", + "touch running", + "echo '= {} ({}) {} - {}'".format( + case["mapping"]["name"], case["mapping"]["constraint"], amesh, bmesh + ), + "echo '=========='", + "", + "set -m", + "(", + acmd, + bcmd, + "wait", + ")", + 'if [[ "$?" -eq 0 ]]; then', + "touch done", + "else", + "touch failed", + "fi", + "rm -f running", + ] + open(os.path.join(path, "run.sh"), "w").writelines( + [line + "\n" for line in content] + ) + + # Generate wrapper script for runner + wrapper = [ + "#!/bin/bash", + 'cd "$( dirname "${BASH_SOURCE[0]}" )"', + "/bin/bash run.sh 2>&1 | tee run.log", + ] + open(os.path.join(path, "run-wrapper.sh"), "w").writelines( + [line + "\n" for line in wrapper] + ) + + # Generate post processing script + post_content = [ + "#!/bin/bash", + "set -e -u", + 'cd "$( dirname "${BASH_SOURCE[0]}" )"', + "echo '= {} ({}) {} - {}'".format( + case["mapping"]["name"], case["mapping"]["constraint"], amesh, bmesh + ), + ] + if branks == 1: + joincmd = "[ ! -f mapped.vtu ] || mv --update mapped.vtu mapped.vtk" + diffcmd = 'precice-aste-evaluate --data error --diffdata "{1}" --diff --stats --mesh mapped.vtk --function "{0}" | tee diff.log'.format( + case["function"], mapped_data_name + ) + post_content += [joincmd, diffcmd] + else: + [recovery_file_location, _] = os.path.split(os.path.normpath(bmesh_location)) + tmp_recovery_file = recovery_file_location + "/{}_recovery.json".format(bmesh) + joincmd = "precice-aste-join --mesh mapped -r {} -o result.vtk".format( + tmp_recovery_file + ) + diffcmd = 'precice-aste-evaluate --data error --diffdata "{1}" --diff --stats --mesh result.vtk --function "{0}" | tee diff.log'.format( + case["function"], mapped_data_name + ) + post_content += [joincmd, diffcmd] + open(os.path.join(path, "post.sh"), "w").writelines( + [line + "\n" for line in post_content] + ) + +def setup_cases(outdir, template, cases): + casemap = {} + for case in cases: + folders = get_case_folder(case) + casemap.setdefault(folders[0], []).append(folders[1:]) + name = [outdir] + folders + path = os.path.join(*name) + config = os.path.join(path, "precice-config.xml") + + print(f"Generating {path}") + os.makedirs(path, exist_ok=True) + with open(config, "w") as config: + config.write(generate_config(template, case)) + create_run_script(outdir, path, case) + print(f"Generated {len(cases)} cases") + + print(f"Generating master scripts") + create_master_run_scripts(casemap, outdir) \ No newline at end of file diff --git a/tools/mapping-scaling-tester/create_plots.py b/tools/mapping-scaling-tester/create_plots.py index ddada802..b4017cfa 100755 --- a/tools/mapping-scaling-tester/create_plots.py +++ b/tools/mapping-scaling-tester/create_plots.py @@ -24,9 +24,7 @@ def parse_arguments(args): - parser = argparse.ArgumentParser( - description="Creates convergence plots from gathered stats" - ) + parser = argparse.ArgumentParser(description="Creates plots from gathered stats") parser.add_argument( "-f", "--file", @@ -40,6 +38,13 @@ def parse_arguments(args): default="result", help="The prefix for all generated PDF plots.", ) + parser.add_argument( + "-m", + "--mode", + default="mapping", + choices=["weak_scale", "mapping"], + help="The test mode to plot", + ) return parser.parse_args(args) @@ -187,6 +192,84 @@ def plot_map_data_time(df, prefix): plt.savefig(prefix + "-mapt.pdf") +def plot_scale_memory(df, prefix, participant): + yname = "peakMem" + participant + _, ax = plt.subplots(sharex=True, sharey=True) + series = df.groupby("mapping") + + for grouped, style in zip(series, styles): + name, group = grouped + if group[yname].max() == 0: + print(f"Dropping {yname}-series {name} as all 0") + continue + color, marker = style + group.plot( + ax=ax, + x=f"mesh {participant}", + y=yname, + label=name, + marker=marker, + color=color, + ) + ax.set_xlabel(f"ranks {participant}") + ax.set_ylabel(f"peak memory of participant {participant} [bytes]") + + plt.grid() + plt.savefig(f"{prefix}-peakMem{participant}.pdf") + + +def plot_scale_map_time(df, prefix, participant): + yname = "mapDataTime" + _, ax = plt.subplots(sharex=True, sharey=True) + series = df.groupby("mapping") + for grouped, style in zip(series, styles): + name, group = grouped + if group[yname].max() == 0: + print(f"Dropping {yname}-series {name} as all 0") + continue + color, marker = style + group.plot( + ax=ax, + x=f"ranks {participant}", + y=yname, + label=name, + marker=marker, + color=color, + ) + + ax.set_xlabel(f"ranks {participant}") + ax.set_ylabel("time to map Data [ms]") + + plt.grid() + plt.savefig(f"{prefix}-mapt-{participant}.pdf") + + +def plot_scale_compute_mapping_time(df, prefix, participant): + yname = "computeMappingTime" + _, ax = plt.subplots(sharex=True, sharey=True) + series = df.groupby("mapping") + for grouped, style in zip(series, styles): + name, group = grouped + if group[yname].max() == 0: + print(f"Dropping {yname}-series {name} as all 0") + continue + color, marker = style + group.plot( + ax=ax, + x=f"ranks {participant}", + y=yname, + label=name, + marker=marker, + color=color, + ) + + ax.set_xlabel(f"ranks {participant}") + ax.set_ylabel("time to compute mapping [ms]") + + plt.grid() + plt.savefig(f"{prefix}-computet-{participant}.pdf") + + def main(argv): args = parse_arguments(argv[1:]) @@ -195,15 +278,22 @@ def main(argv): plt.rcParams["figure.autolayout"] = "true" df = pandas.read_csv(args.file) - to_meshes = df["mesh B"].unique() - assert ( - len(to_meshes) == 1 - ), f"There are {len(to_meshes)} to-meshes but only 1 is allowed. Fix your dataset!" - df.sort_values("mesh A", inplace=True) - plot_error(df, args.prefix) - plot_memory_usage(df, args.prefix) - plot_map_data_time(df, args.prefix) - plot_compute_mapping_time(df, args.prefix) + if args.mode == "mapping": + to_meshes = df["mesh B"].unique() + assert ( + len(to_meshes) == 1 + ), f"There are {len(to_meshes)} to-meshes but only 1 is allowed. Fix your dataset!" + df.sort_values("mesh A", inplace=True) + plot_error(df, args.prefix) + plot_memory_usage(df, args.prefix) + plot_map_data_time(df, args.prefix) + plot_compute_mapping_time(df, args.prefix) + elif args.mode == "weak_scale": + for participant in ["A", "B"]: + df.sort_values(f"ranks {participant}", inplace=True) + plot_scale_memory(df, args.prefix, participant) + plot_scale_map_time(df, args.prefix, participant) + plot_scale_compute_mapping_time(df, args.prefix, participant) return 0 diff --git a/tools/mapping-scaling-tester/generate_mapping_test.py b/tools/mapping-scaling-tester/generate_mapping_test.py index 79f1ba6a..3b17f06c 100755 --- a/tools/mapping-scaling-tester/generate_mapping_test.py +++ b/tools/mapping-scaling-tester/generate_mapping_test.py @@ -5,20 +5,7 @@ import os import sys -from jinja2 import Template - - -def generate_config(template, setup): - template = Template(template) - return template.render(setup) - - -def as_iter(something): - try: - iter(something) - return something - except TypeError: - return [something] +from common import * def generate_cases(setup): @@ -69,190 +56,6 @@ def generate_cases(setup): return cases -def get_case_folder(case): - return [ - case["mapping"]["name"], - case["mapping"]["constraint"], - "{}-{}".format(case["A"]["mesh"]["name"], case["B"]["mesh"]["name"]), - "{}-{}".format(case["A"]["ranks"], case["B"]["ranks"]), - ] - - -def case_to_sortable(case): - parts = case.split(os.path.sep) - kind = parts[0] - mesha, meshb = map(float, parts[-2].split("-")) - - kind_cost = 0 - if kind.startswith("gaussian"): - kind_cost = 1 - elif kind.startswith("tps"): - kind_cost = 2 - - return (kind_cost, -mesha, -meshb) - - -def create_master_run_scripts(casemap, dir): - common = [ - "#!/bin/bash", - "", - 'cd "$( dirname "${BASH_SOURCE[0]}" )"', - "RUNNER=/bin/bash", - "", - ] - - # Generate master runner script - content = common + [ - "${RUNNER} " + os.path.join(case, "runall.sh") for case in casemap.keys() - ] - open(os.path.join(dir, "runall.sh"), "w").writelines( - [line + "\n" for line in content] - ) - - # Generate master postprocessing script - post = common + [ - "${RUNNER} " + os.path.join(case, "postprocessall.sh") - for case in casemap.keys() - ] - open(os.path.join(dir, "postprocessall.sh"), "w").writelines( - [line + "\n" for line in post] - ) - - for case, instances in casemap.items(): - # Generate master runner script - content = common + [ - "${RUNNER} " + os.path.join(*instance, "run-wrapper.sh") - for instance in instances - ] - open(os.path.join(dir, case, "runall.sh"), "w").writelines( - [line + "\n" for line in content] - ) - - # Generate master postprocessing script - post = common + [ - "${RUNNER} " + os.path.join(*instance, "post.sh") for instance in instances - ] - open(os.path.join(dir, case, "postprocessall.sh"), "w").writelines( - [line + "\n" for line in post] - ) - - -def create_run_script(outdir, path, case): - amesh = case["A"]["mesh"]["name"] - aranks = case["A"]["ranks"] - amesh_location = os.path.relpath( - os.path.join(outdir, "meshes", amesh, str(aranks), amesh), path - ) - - # Generate runner script - acmd = '/usr/bin/time -f %M -a -o memory-A.log precice-aste-run -v -a -p A --data "{}" --mesh {} || kill 0 &'.format( - case["function"], amesh_location - ) - if aranks > 1: - acmd = "mpirun -n {} $ASTE_A_MPIARGS {}".format(aranks, acmd) - - bmesh = case["B"]["mesh"]["name"] - branks = case["B"]["ranks"] - bmesh_location = os.path.relpath( - os.path.join(outdir, "meshes", bmesh, str(branks), bmesh), path - ) - mapped_data_name = case["function"] + "(mapped)" - bcmd = '/usr/bin/time -f %M -a -o memory-B.log precice-aste-run -v -a -p B --data "{}" --mesh {} --output mapped || kill 0 &'.format( - mapped_data_name, bmesh_location - ) - if branks > 1: - bcmd = "mpirun -n {} $ASTE_B_MPIARGS {}".format(branks, bcmd) - - content = [ - "#!/bin/bash", - "set -e -u", - 'cd "$( dirname "${BASH_SOURCE[0]}" )"', - "echo '=========='", - "rm -f memory-A.log memory-B.log done running failed", - "rm -fr mapped && mkdir mapped", - "touch running", - "echo '= {} ({}) {} - {}'".format( - case["mapping"]["name"], case["mapping"]["constraint"], amesh, bmesh - ), - "echo '=========='", - "", - "set -m", - "(", - acmd, - bcmd, - "wait", - ")", - 'if [[ "$?" -eq 0 ]]; then', - "touch done", - "else", - "touch failed", - "fi", - "rm -f running", - ] - open(os.path.join(path, "run.sh"), "w").writelines( - [line + "\n" for line in content] - ) - - # Generate wrapper script for runner - wrapper = [ - "#!/bin/bash", - 'cd "$( dirname "${BASH_SOURCE[0]}" )"', - "/bin/bash run.sh 2>&1 | tee run.log", - ] - open(os.path.join(path, "run-wrapper.sh"), "w").writelines( - [line + "\n" for line in wrapper] - ) - - # Generate post processing script - post_content = [ - "#!/bin/bash", - "set -e -u", - 'cd "$( dirname "${BASH_SOURCE[0]}" )"', - "echo '= {} ({}) {} - {}'".format( - case["mapping"]["name"], case["mapping"]["constraint"], amesh, bmesh - ), - ] - if branks == 1: - joincmd = "[ ! -f mapped.vtu ] || mv --update mapped.vtu mapped.vtk" - diffcmd = 'precice-aste-evaluate --data error --diffdata "{1}" --diff --stats --mesh mapped.vtk --function "{0}" | tee diff.log'.format( - case["function"], mapped_data_name - ) - post_content += [joincmd, diffcmd] - else: - [recovery_file_location, _] = os.path.split(os.path.normpath(bmesh_location)) - tmp_recovery_file = recovery_file_location + "/{}_recovery.json".format(bmesh) - joincmd = "precice-aste-join --mesh mapped -r {} -o result.vtk".format( - tmp_recovery_file - ) - diffcmd = 'precice-aste-evaluate --data error --diffdata "{1}" --diff --stats --mesh result.vtk --function "{0}" | tee diff.log'.format( - case["function"], mapped_data_name - ) - post_content += [joincmd, diffcmd] - open(os.path.join(path, "post.sh"), "w").writelines( - [line + "\n" for line in post_content] - ) - - -def setup_cases(outdir, template, cases): - casemap = {} - for case in cases: - folders = get_case_folder(case) - casemap.setdefault(folders[0], []).append(folders[1:]) - name = [outdir] + folders - path = os.path.join(*name) - config = os.path.join(path, "precice-config.xml") - - print(f"Generating {path}") - os.makedirs(path, exist_ok=True) - with open(config, "w") as config: - config.write(generate_config(template, case)) - create_run_script(outdir, path, case) - print(f"Generated {len(cases)} cases") - - print(f"Generating master scripts") - create_master_run_scripts(casemap, outdir) - - def parse_arguments(args): parser = argparse.ArgumentParser(description="Generator for a mapping test suite") parser.add_argument( diff --git a/tools/mapping-scaling-tester/generate_scale_test.py b/tools/mapping-scaling-tester/generate_scale_test.py new file mode 100644 index 00000000..cf385381 --- /dev/null +++ b/tools/mapping-scaling-tester/generate_scale_test.py @@ -0,0 +1,113 @@ +#! /usr/bin/env python3 + +import argparse +import json +import os +import sys +from common import * + + +def generate_cases(setup): + network = setup["general"].get("network", "lo") + syncmode = setup["general"].get("syncmode", "false") + test_location = setup["general"]["testlocation"] + cases = [] + for group in setup["groups"]: + for name, mapping in group["mapping"]["cases"].items(): + for constraint in group["mapping"]["constraints"]: + for number_of_points_per_rank_A in as_iter( + setup["general"]["numberofpointsperrank"]["A"] + ): + for number_of_points_per_rankB in as_iter( + setup["general"]["numberofpointsperrank"]["B"] + ): + for ranksA, ranksB in zip( + as_iter(setup["general"]["ranks"].get("A", 1)), + as_iter(setup["general"]["ranks"].get("B", 1)), + ): + cases.append( + { + "function": setup["general"]["function"], + "mapping": { + "name": name, + "kind": mapping["kind"], + "constraint": constraint, + "options": mapping.get("options", ""), + }, + "A": { + "ranks": ranksA, + "mesh": { + "name": str( + number_of_points_per_rank_A * ranksA + ), + "file": os.path.join( + test_location, + f"meshA-{number_of_points_per_rank_A*ranksA}.vtk", + ), + }, + }, + "B": { + "ranks": ranksB, + "mesh": { + "name": str( + number_of_points_per_rankB * ranksB + ), + "file": os.path.join( + test_location, + f"meshB-{number_of_points_per_rankB*ranksB}.vtk", + ), + }, + }, + "network": network, + "syncmode": syncmode, + } + ) + + return cases + + +def parse_arguments(args): + parser = argparse.ArgumentParser(description="Generator for a mapping test suite") + parser.add_argument( + "-o", + "--outdir", + default="cases", + help="Directory to generate the test suite in.", + ) + parser.add_argument( + "-s", + "--setup", + type=argparse.FileType("r"), + default="setup.json", + help="The test setup file to use.", + ) + parser.add_argument( + "-t", + "--template", + type=argparse.FileType("r"), + default="config-template.xml", + help="The precice config template to use.", + ) + return parser.parse_args(args) + + +def main(argv): + # Parse the input arguments + args = parse_arguments(argv[1:]) + # Parse the json file using the json module + setup = json.load(args.setup) + # Read the xml-template file + template = args.template.read() + # Generate the actual cases + cases = generate_cases(setup) + outdir = os.path.normpath(args.outdir) + if os.path.isdir(outdir): + print('Warning: outdir "{}" already exisits.'.format(outdir)) + + setup_cases(outdir, template, cases) + + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv)) diff --git a/tools/mapping-scaling-tester/prepare_scale_meshes.py b/tools/mapping-scaling-tester/prepare_scale_meshes.py new file mode 100644 index 00000000..00bc1ac3 --- /dev/null +++ b/tools/mapping-scaling-tester/prepare_scale_meshes.py @@ -0,0 +1,164 @@ +#! /usr/bin/env python3 + +import argparse +import json +import os +import shutil +import subprocess +import sys + + +def parse_arguments(args): + parser = argparse.ArgumentParser(description="Prepares meshes for a test suite") + parser.add_argument( + "-o", + "--outdir", + default="cases", + help="Directory to generate the test suite in.", + ) + parser.add_argument( + "-s", + "--setup", + type=argparse.FileType("r"), + default="setup.json", + help="The test setup file to use.", + ) + parser.add_argument( + "-f", "--force", action="store_true", help="Remove existing meshes." + ) + parser.add_argument("-g", "--generator", help="The generator to use.") + parser.add_argument("-d", "--dim", default=3, help="The dimension of the mesh.") + parser.add_argument("--seed", default=0, help="The seed for the mesh generator.") + return parser.parse_args(args) + + +def prepare_main_mesh(meshdir, name, file, function, force=False): + main_dir = os.path.join(meshdir, name, "1") + main_mesh = os.path.join(main_dir, name + ".vtu") + print("Preparing Mesh {} in {}".format(name, main_dir)) + + if os.path.isdir(main_dir): + if force: + print(" Regenerating the mesh.") + shutil.rmtree(main_dir) + else: + print(" Mesh already exists.") + + return + + os.makedirs(main_dir, exist_ok=True) + data_name = "{}".format(function) + [path_name, tmpfilename] = os.path.split(os.path.normpath(main_mesh)) + subprocess.run( + [ + "precice-aste-evaluate", + "--mesh", + os.path.expandvars(file), + "--function", + function, + "--data", + data_name, + "--directory", + path_name, + "-o", + tmpfilename, + ] + ) + + +def prepare_part_mesh(meshdir, name, p, force=False): + + if p == 1: + return + + main_mesh = os.path.join(meshdir, name, "1", name + ".vtu") + part_dir = os.path.join(meshdir, name, str(p)) + part_mesh = os.path.join(part_dir, name) + print("Preparing Mesh {} with {} paritions in {}".format(name, p, part_dir)) + + if os.path.isdir(part_dir): + if force: + print(" Regenerating the partitioned mesh.") + shutil.rmtree(part_dir) + else: + print(" Partitioned mesh already exists.") + + return + + os.makedirs(part_dir, exist_ok=True) + [path_name, _] = os.path.split(os.path.normpath(part_mesh)) + subprocess.run( + [ + "precice-aste-partition", + "--mesh", + main_mesh, + "--algorithm", + "meshfree", + "-o", + part_mesh, + "--directory", + path_name, + "-n", + str(p), + ] + ) + + +def create_mesh(halton_generator_script, file, points, dim=3, seed=0): + # Ensure the output directory exists + directory = os.path.dirname(file) + if not os.path.exists(directory): + os.mkdir(directory) + + subprocess.run( + [ + "python3", + os.path.abspath(halton_generator_script), + "--mesh", + file, + "--numpoints", + str(points), + "--dimension", + str(dim), + "--seed", + str(seed), + ] + ) + + +def main(argv): + args = parse_arguments(argv[1:]) + setup = json.load(args.setup) + outdir = os.path.normpath(args.outdir) + + if os.path.isdir(outdir): + print('Warning: outdir "{}" already exisits.'.format(outdir)) + meshdir = os.path.join(outdir, "meshes") + function = setup["general"]["function"] + + partitions = set( + [int(rank) for pranks in setup["general"]["ranks"].values() for rank in pranks] + ) + for points in set( + [ + setup["general"]["numberofpointsperrank"]["A"], + setup["general"]["numberofpointsperrank"]["B"], + ] + ): + for partition in partitions: + filepoints = int(points) * int(partition) + file = os.path.join(meshdir, f"{filepoints}.vtk") + + create_mesh(args.generator, file, points, args.dim, args.seed) + + if not os.path.isfile(os.path.expandvars(file)): + raise Exception(f'\033[91m Unable to open file called "{file}".\033[0m') + prepare_main_mesh(meshdir, str(filepoints), file, function, args.force) + + prepare_part_mesh(meshdir, str(filepoints), partition, args.force) + + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv)) From 766d3b1076131fcd7fff126c4350f46b1d463dbf Mon Sep 17 00:00:00 2001 From: Kursat Yurt Date: Mon, 12 Dec 2022 16:20:24 +0100 Subject: [PATCH 5/6] Add example scale test --- examples/weak_scaling_tester/clean.sh | 4 +++ examples/weak_scaling_tester/run.sh | 36 ++++++++++++++++++++ examples/weak_scaling_tester/setup-test.json | 35 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100755 examples/weak_scaling_tester/clean.sh create mode 100755 examples/weak_scaling_tester/run.sh create mode 100644 examples/weak_scaling_tester/setup-test.json diff --git a/examples/weak_scaling_tester/clean.sh b/examples/weak_scaling_tester/clean.sh new file mode 100755 index 00000000..5e2369c5 --- /dev/null +++ b/examples/weak_scaling_tester/clean.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +rm -f test-statistics.csv +rm -fr ./case/ diff --git a/examples/weak_scaling_tester/run.sh b/examples/weak_scaling_tester/run.sh new file mode 100755 index 00000000..d2e4b2ce --- /dev/null +++ b/examples/weak_scaling_tester/run.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -e -x + +# Get the test location +TEST_LOCATION="$(pwd)" +export TEST_LOCATION + +# The mapping-tester location +WEAK_SCALING_TESTER="${TEST_LOCATION}"/../../tools/mapping-scaling-tester/ + +GENERATOR="${TEST_LOCATION}"/../../tools/mesh-generators/generate_halton_mesh.py + +# The case directory +TEST_CASE_LOCATION="${TEST_LOCATION}"/case + +# Generate the run scripts +python3 "${WEAK_SCALING_TESTER}"/generate_scale_test.py --setup "${TEST_LOCATION}"/setup-test.json --outdir "${TEST_CASE_LOCATION}" --template "${WEAK_SCALING_TESTER}"/config-template.xml + +# Prepare the meshes +python3 "${WEAK_SCALING_TESTER}"/prepare_scale_meshes.py --setup "${TEST_LOCATION}"/setup-test.json --outdir "${TEST_CASE_LOCATION}" --force -g "${GENERATOR}" +export ASTE_A_MPIARGS="" +export ASTE_B_MPIARGS="" + +# Run the actual cases +cd "${TEST_CASE_LOCATION}" && bash ./runall.sh + +# Postprocess the test cases +bash ./postprocessall.sh + +cd "${TEST_LOCATION}" + +# Gather the generated statistics +python3 "${WEAK_SCALING_TESTER}"/gather_stats.py --outdir "${TEST_CASE_LOCATION}" --file test-statistics.csv + +# Plot the results +python3 "${WEAK_SCALING_TESTER}"/prepare_plots.py --file test-statistics.csv --mode weak_scale diff --git a/examples/weak_scaling_tester/setup-test.json b/examples/weak_scaling_tester/setup-test.json new file mode 100644 index 00000000..f21a8a18 --- /dev/null +++ b/examples/weak_scaling_tester/setup-test.json @@ -0,0 +1,35 @@ +{ + "general": { + "testlocation": "${TEST_LOCATION}", + "function": "x+y^2+z^3", + "ranks": { + "A": [ + 1,2,3,4 + ], + "B": [ + 1,2,3,4 + ] + }, + "network": "lo0", + "syncmode": false, + "numberofpointsperrank": { + "A": 1000, + "B": 1200 + } + }, + "groups": [ + { + "mapping": { + "constraints": [ + "consistent" + ], + "cases": { + "tps": { + "kind": "rbf-thin-plate-splines", + "options": "use-qr-decomposition=\"1\"" + } + } + } + } + ] +} From 01c9acaaf202f527bfdc0d58f03ec90b17106d12 Mon Sep 17 00:00:00 2001 From: Kursat Yurt Date: Mon, 12 Dec 2022 16:41:01 +0100 Subject: [PATCH 6/6] pre-commit run --- tools/mapping-scaling-tester/common.py | 7 ++++++- tools/mapping-scaling-tester/generate_scale_test.py | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/mapping-scaling-tester/common.py b/tools/mapping-scaling-tester/common.py index c39ee29f..d331f9e1 100644 --- a/tools/mapping-scaling-tester/common.py +++ b/tools/mapping-scaling-tester/common.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import os + from jinja2 import Template @@ -16,6 +17,7 @@ def as_iter(something): except TypeError: return [something] + def get_case_folder(case): return [ case["mapping"]["name"], @@ -24,6 +26,7 @@ def get_case_folder(case): "{}-{}".format(case["A"]["ranks"], case["B"]["ranks"]), ] + def case_to_sortable(case): parts = case.split(os.path.sep) kind = parts[0] @@ -82,6 +85,7 @@ def create_master_run_scripts(casemap, dir): [line + "\n" for line in post] ) + def create_run_script(outdir, path, case): amesh = case["A"]["mesh"]["name"] aranks = case["A"]["ranks"] @@ -177,6 +181,7 @@ def create_run_script(outdir, path, case): [line + "\n" for line in post_content] ) + def setup_cases(outdir, template, cases): casemap = {} for case in cases: @@ -194,4 +199,4 @@ def setup_cases(outdir, template, cases): print(f"Generated {len(cases)} cases") print(f"Generating master scripts") - create_master_run_scripts(casemap, outdir) \ No newline at end of file + create_master_run_scripts(casemap, outdir) diff --git a/tools/mapping-scaling-tester/generate_scale_test.py b/tools/mapping-scaling-tester/generate_scale_test.py index cf385381..fd2ad72b 100644 --- a/tools/mapping-scaling-tester/generate_scale_test.py +++ b/tools/mapping-scaling-tester/generate_scale_test.py @@ -4,6 +4,7 @@ import json import os import sys + from common import *