diff --git a/Makefile b/Makefile index 9d2f5fea5..d31e8655a 100755 --- a/Makefile +++ b/Makefile @@ -54,11 +54,11 @@ install-pinned-macos: _conda_check # Run default tests test: set -e - snakemake solve_elec_networks --configfile config/test/config.electricity.yaml --rerun-triggers=mtime - snakemake --configfile config/test/config.overnight.yaml --rerun-triggers=mtime - snakemake --configfile config/test/config.myopic.yaml --rerun-triggers=mtime - snakemake make_summary_perfect --configfile config/test/config.perfect.yaml --rerun-triggers=mtime - snakemake --configfile config/test/config.scenarios.yaml --rerun-triggers=mtime -n + snakemake solve_elec_networks --configfile config/test/config.electricity.yaml + snakemake --configfile config/test/config.overnight.yaml + snakemake --configfile config/test/config.myopic.yaml + snakemake make_summary_perfect --configfile config/test/config.perfect.yaml + snakemake --configfile config/test/config.scenarios.yaml -n echo "All tests completed successfully." unit-test: @@ -66,11 +66,11 @@ unit-test: # Cleans all output files from tests clean-tests: - snakemake solve_elec_networks --configfile config/test/config.electricity.yaml --rerun-triggers=mtime --delete-all-output - snakemake --configfile config/test/config.overnight.yaml --rerun-triggers=mtime --delete-all-output - snakemake --configfile config/test/config.myopic.yaml --rerun-triggers=mtime --delete-all-output - snakemake make_summary_perfect --configfile config/test/config.perfect.yaml --rerun-triggers=mtime --delete-all-output - snakemake --configfile config/test/config.scenarios.yaml --rerun-triggers=mtime -n --delete-all-output + snakemake solve_elec_networks --configfile config/test/config.electricity.yaml --delete-all-output + snakemake --configfile config/test/config.overnight.yaml --delete-all-output + snakemake --configfile config/test/config.myopic.yaml --delete-all-output + snakemake make_summary_perfect --configfile config/test/config.perfect.yaml --delete-all-output + snakemake --configfile config/test/config.scenarios.yaml -n --delete-all-output # Removes all created files except for large cutout files (similar to fresh clone) reset: diff --git a/config/config.default.yaml b/config/config.default.yaml index 64197dbbe..150166679 100644 --- a/config/config.default.yaml +++ b/config/config.default.yaml @@ -1012,6 +1012,12 @@ solving: cbc-default: {} # Used in CI glpk-default: {} # Used in CI + check_objective: + enable: false + expected_value: None + atol: 1000 + rtol: 0.001 + mem_mb: 30000 #memory in MB; 20 GB enough for 50+B+I+H2; 100 GB for 181+B+I+H2 runtime: 6h #runtime in humanfriendly style https://humanfriendly.readthedocs.io/en/latest/ diff --git a/config/test/config.electricity.yaml b/config/test/config.electricity.yaml index 147d735f3..4e05a3808 100644 --- a/config/test/config.electricity.yaml +++ b/config/test/config.electricity.yaml @@ -82,6 +82,9 @@ solving: name: highs options: highs-default + check_objective: + enable: true + expected_value: 39541845.44 plotting: map: diff --git a/config/test/config.overnight.yaml b/config/test/config.overnight.yaml index e14ff86ba..b0a234cee 100644 --- a/config/test/config.overnight.yaml +++ b/config/test/config.overnight.yaml @@ -84,6 +84,10 @@ solving: options: highs-default mem: 4000 + check_objective: + enable: true + expected_value: 7.1040937763e+08 + plotting: map: boundaries: diff --git a/config/test/config.perfect.yaml b/config/test/config.perfect.yaml index 742b30124..c8337c529 100644 --- a/config/test/config.perfect.yaml +++ b/config/test/config.perfect.yaml @@ -89,6 +89,10 @@ solving: options: highs-default mem: 4000 + check_objective: + enable: true + expected_value: 14385130476 + plotting: map: boundaries: diff --git a/matplotlibrc b/matplotlibrc index bf667fb18..5db18d521 100644 --- a/matplotlibrc +++ b/matplotlibrc @@ -2,6 +2,5 @@ # # SPDX-License-Identifier: CC0-1.0 font.family: sans-serif -font.sans-serif: Ubuntu, DejaVu Sans image.cmap: viridis figure.autolayout : True diff --git a/scripts/solve_network.py b/scripts/solve_network.py index 4b197385d..15a9d9e4f 100644 --- a/scripts/solve_network.py +++ b/scripts/solve_network.py @@ -52,6 +52,10 @@ pypsa.pf.logger.setLevel(logging.WARNING) +class ObjectiveValueError(Exception): + pass + + def add_land_use_constraint_perfect(n): """ Add global constraints for tech capacity limit. @@ -986,6 +990,19 @@ def extra_functionality(n, snapshots): custom_extra_functionality(n, snapshots, snakemake) +def check_objective_value(n, solving): + check_objective = solving["check_objective"] + if check_objective["enable"]: + atol = check_objective["atol"] + rtol = check_objective["rtol"] + expected_value = check_objective["expected_value"] + if not np.isclose(n.objective, expected_value, atol=atol, rtol=rtol): + raise ObjectiveValueError( + f"Objective value {n.objective} differs from expected value " + f"{expected_value} by more than {atol}." + ) + + def solve_network(n, config, params, solving, **kwargs): set_of_options = solving["solver"]["options"] cf_solving = solving["options"] @@ -1034,10 +1051,13 @@ def solve_network(n, config, params, solving, **kwargs): **kwargs ) - if status != "ok" and not rolling_horizon: - logger.warning( - f"Solving status '{status}' with termination condition '{condition}'" - ) + if not rolling_horizon: + if status != "ok": + logger.warning( + f"Solving status '{status}' with termination condition '{condition}'" + ) + check_objective_value(n, solving) + if "infeasible" in condition: labels = n.model.compute_infeasibilities() logger.info(f"Labels:\n{labels}")