From 0c242e1ff00cf333d23d6324617a01a447a8b237 Mon Sep 17 00:00:00 2001 From: IGUCHI Masato <67450288+iguchi-lab@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:05:17 +0900 Subject: [PATCH] Show annual APF on system COP graph --- apps/gradio/src/verification_app/graphs.py | 41 ++++++++++++++++++++-- tests/test_result_graphs.py | 15 ++++++-- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/apps/gradio/src/verification_app/graphs.py b/apps/gradio/src/verification_app/graphs.py index 829b6be7..e2c7aac4 100644 --- a/apps/gradio/src/verification_app/graphs.py +++ b/apps/gradio/src/verification_app/graphs.py @@ -51,7 +51,7 @@ def build_result_graphs( _load_duration(heating_sorted, heating=True), _season_timeseries(summer, summer_detail, heating=False), _load_duration(cooling_sorted, heating=False), - _scop(winter, summer), + _scop(output2, winter, summer), ) @@ -164,7 +164,11 @@ def _load_duration(output2: pd.DataFrame, *, heating: bool) -> Figure: return figure -def _scop(winter: pd.DataFrame, summer: pd.DataFrame) -> Figure: +def _scop( + annual: pd.DataFrame, + winter: pd.DataFrame, + summer: pd.DataFrame, +) -> Figure: figure = Figure(figsize=(18, 7), layout="constrained") axes = figure.subplots(1, 2) heating_heat = winter["q_hs_H_d_t [Wh/h]"] / 1000 @@ -194,7 +198,27 @@ def _scop(winter: pd.DataFrame, summer: pd.DataFrame) -> Figure: legend=True, ) axis.set_title(title) - figure.suptitle("部分負荷効率(sCOP)") + annual_heating_heat = annual["q_hs_H_d_t [Wh/h]"] / 1000 + annual_cooling_heat = ( + annual["q_hs_CS_d_t [Wh/h]"] + annual["q_hs_CL_d_t [Wh/h]"] + ) / 1000 + heating_apf = _ratio_of_sums( + annual_heating_heat, + annual["E_E_H_d_t [kWh/h]"], + ) + cooling_apf = _ratio_of_sums( + annual_cooling_heat, + annual["E_E_C_d_t [kWh/h]"], + ) + annual_apf = _ratio_of_sums( + annual_heating_heat + annual_cooling_heat, + annual["E_E_H_d_t [kWh/h]"] + annual["E_E_C_d_t [kWh/h]"], + ) + figure.suptitle( + "部分負荷効率(sCOP)\n" + f"年間APF = {_format_apf(annual_apf)}" + f"(暖房 {_format_apf(heating_apf)}/冷房 {_format_apf(cooling_apf)})" + ) return figure @@ -202,6 +226,17 @@ def _safe_ratio(numerator: pd.Series, denominator: pd.Series) -> pd.Series: return numerator / denominator.replace(0, np.nan) +def _ratio_of_sums(numerator: pd.Series, denominator: pd.Series) -> float: + denominator_sum = float(denominator.sum()) + if denominator_sum <= 0.0: + return float("nan") + return float(numerator.sum()) / denominator_sum + + +def _format_apf(value: float) -> str: + return "算定不能" if not np.isfinite(value) else f"{value:.2f}" + + def _style_axis( axis: Any, ylabel: str, diff --git a/tests/test_result_graphs.py b/tests/test_result_graphs.py index 8620da0c..9cd6b079 100644 --- a/tests/test_result_graphs.py +++ b/tests/test_result_graphs.py @@ -4,7 +4,12 @@ import pandas as pd from matplotlib.figure import Figure -from verification_app.graphs import GRAPH_LABELS, build_result_graphs +from verification_app.graphs import ( + GRAPH_LABELS, + _format_apf, + _ratio_of_sums, + build_result_graphs, +) def test_build_result_graphs_recreates_the_five_legacy_views(tmp_path: Path) -> None: @@ -55,9 +60,15 @@ def test_build_result_graphs_recreates_the_five_legacy_views(tmp_path: Path) -> "暖房負荷順", "冷房代表期間", "冷房負荷順", - "部分負荷効率(sCOP)", + "部分負荷効率(sCOP)\n年間APF = 2.81(暖房 2.78/冷房 2.84)", ] plot_data = gr.Plot().postprocess(figures[0]) assert plot_data is not None assert plot_data.type == "matplotlib" assert plot_data.plot.startswith("data:image/") + + +def test_annual_apf_is_unavailable_without_electricity() -> None: + apf = _ratio_of_sums(pd.Series([1.0, 2.0]), pd.Series([0.0, 0.0])) + + assert _format_apf(apf) == "算定不能"