From 97b6de61c4694d18897adfc43d7fe3dd31f68ee5 Mon Sep 17 00:00:00 2001 From: EdmundGoodman Date: Sun, 7 Apr 2024 18:23:09 +0100 Subject: [PATCH] Add support for exporting data --- poetry.lock | 2 +- pyproject.toml | 1 + src/hpc_multibench/plot/export_data.py | 42 ++++++++++++++++++++++ src/hpc_multibench/plot/plot_matplotlib.py | 4 +-- src/hpc_multibench/test_bench.py | 11 +++--- src/hpc_multibench/yaml_model.py | 11 +++--- 6 files changed, 57 insertions(+), 14 deletions(-) create mode 100755 src/hpc_multibench/plot/export_data.py diff --git a/poetry.lock b/poetry.lock index 0e8059e..0138151 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2217,4 +2217,4 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "ea702bbac9344368a96b5da6a28ca66ebbd3be7ad17daf7e80fd1d34025b618e" +content-hash = "f69f2921f19115d4b57493f6208e29aca65b0fd78dec3f98792cf48bad590dcf" diff --git a/pyproject.toml b/pyproject.toml index c6228bf..051814a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ matplotlib = "^3.8.3" matplotlib-label-lines = "^0.7.0" seaborn = "^0.13.2" plotext = "^5.2.8" +pandas = "^2.2.1" [tool.bandit] exclude_dirs = [".venv/"] diff --git a/src/hpc_multibench/plot/export_data.py b/src/hpc_multibench/plot/export_data.py new file mode 100755 index 0000000..7385ffc --- /dev/null +++ b/src/hpc_multibench/plot/export_data.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""A set of functions to export the results of a test bench run.""" + +import pandas as pd + +from hpc_multibench.plot.plot_data import split_metric_uncertainty +from hpc_multibench.run_configuration import RunConfiguration +from hpc_multibench.uncertainties import UFloat +from hpc_multibench.yaml_model import ExportModel + + +def export_data( + plot: ExportModel, + all_metrics: list[tuple[RunConfiguration, dict[str, str | UFloat]]], +) -> None: + """Construct and export a pandas data frame from the metrics.""" + df_data: dict[str, list[float | str]] = {} + for run_configuration, metrics in all_metrics: + row_data: dict[str, float | str] = {"Run configuration": run_configuration.name} + + for metric in metrics: + value, error = split_metric_uncertainty(metrics, metric) + row_data[metric] = value + if error is not None: + row_data[f"{metric} error"] = error + + for column, cell in row_data.items(): + if column not in df_data: + df_data[column] = [] + df_data[column].append(cell) + + export_df = pd.DataFrame(df_data) + + if plot.export_path is None: + print(export_df.to_string()) + elif plot.export_format == "csv": + export_df.to_csv(plot.export_path) + else: + raise NotImplementedError( + f"Export format '{plot.export_format}' not supported!" + ) diff --git a/src/hpc_multibench/plot/plot_matplotlib.py b/src/hpc_multibench/plot/plot_matplotlib.py index 3ded549..e7f8cdb 100755 --- a/src/hpc_multibench/plot/plot_matplotlib.py +++ b/src/hpc_multibench/plot/plot_matplotlib.py @@ -14,9 +14,6 @@ from hpc_multibench.uncertainties import UFloat from hpc_multibench.yaml_model import BarChartModel, LinePlotModel, RooflinePlotModel -# from labellines import labelLines - - sns.set_theme() @@ -78,6 +75,7 @@ def draw_roofline_plot( plt.plot(x, y, label=label) for label, (x, y) in roofline.compute_bound_ceilings.items(): plt.plot(x, y, label=label) + # from labellines import labelLines # for ax in plt.gcf().axes: # labelLines(ax.get_lines()) for name, (x_point, y_point, x_err, y_err) in data.items(): diff --git a/src/hpc_multibench/test_bench.py b/src/hpc_multibench/test_bench.py index 7fe153f..a2b065c 100755 --- a/src/hpc_multibench/test_bench.py +++ b/src/hpc_multibench/test_bench.py @@ -18,6 +18,7 @@ from typing_extensions import Self +from hpc_multibench.plot.export_data import export_data from hpc_multibench.plot.plot_matplotlib import ( draw_bar_chart, draw_line_plot, @@ -82,7 +83,7 @@ def __init__( # Validate that all configurations named in the test bench are defined # in the test plan for run_configuration_name in bench_model.run_configurations: - if run_configuration_name not in self.run_configuration_models.keys(): + if run_configuration_name not in self.run_configuration_models: raise RuntimeError( f"'{run_configuration_name}' not in list of" " defined run configurations!" @@ -100,10 +101,7 @@ def instantiations(self) -> list[dict[str, Any]]: ( [[(key, value)] for value in values] if isinstance(key, str) - else [ - [(k, v) for k, v in zip(key, setting, strict=True)] - for setting in values - ] + else [list(zip(key, setting, strict=True)) for setting in values] ) for key, values in self.bench_model.matrix.items() ] @@ -424,3 +422,6 @@ def report(self) -> None: for roofline_plot in self.bench_model.analysis.roofline_plots: draw_roofline_plot(roofline_plot, aggregated_metrics) + + for export_schema in self.bench_model.analysis.data_exports: + export_data(export_schema, aggregated_metrics) diff --git a/src/hpc_multibench/yaml_model.py b/src/hpc_multibench/yaml_model.py index dd74c30..c6c3dad 100755 --- a/src/hpc_multibench/yaml_model.py +++ b/src/hpc_multibench/yaml_model.py @@ -82,11 +82,12 @@ class RooflinePlotModel(BaseModel): ert_json: Path -# class ExportModel(BaseModel): -# """A Pydantic model for a exporting a set of metrics.""" +class ExportModel(BaseModel): + """A Pydantic model for a exporting a set of metrics.""" -# metrics: list[str] -# filename: Path | None = None + export_path: Path | None + export_format: str = "csv" + # metrics: list[str] | None = None class AnalysisModel(BaseModel): @@ -98,7 +99,7 @@ class AnalysisModel(BaseModel): line_plots: list[LinePlotModel] = [] bar_charts: list[BarChartModel] = [] roofline_plots: list[RooflinePlotModel] = [] - # exports: list[BarChartModel] = [] + data_exports: list[ExportModel] = [] class RerunModel(BaseModel):