Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ scratch.py
ispypsa_runs/**/*.csv
ispypsa_runs/**/*.parquet
ispypsa_runs/**/*.hdf5
ispypsa_runs/**/results/**

# ignore doit database
.doit*
32 changes: 31 additions & 1 deletion dodo.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
add_lines_to_network,
initialise_network,
run,
save_results,
)
from ispypsa.results import load_results, save_results
from ispypsa.results.plotting import plot_map_of_energy_generation_by_carrier
from ispypsa.templater.dynamic_generator_properties import (
template_generator_dynamic_properties,
)
Expand Down Expand Up @@ -57,6 +58,7 @@
_PYPSA_FRIENDLY_DIRECTORY = Path(run_folder, "pypsa_friendly")
_PARSED_TRACE_DIRECTORY = Path(config.traces.path_to_parsed_traces)
_PYPSA_OUTPUTS_DIRECTORY = Path(run_folder, "outputs")
_RESULTS_DIRECTORY = Path(run_folder, "results")

configure_logging()

Expand Down Expand Up @@ -203,6 +205,19 @@ def create_and_run_pypsa_model(
save_results(network, pypsa_outputs_location)


def create_results(
config: ModelConfig, pypsa_outputs_location: Path, results_location: Path
) -> None:
create_or_clean_task_output_folder(results_location)
network = load_results(pypsa_outputs_location)
fig, ax = plot_map_of_energy_generation_by_carrier(
network, config, figure_size_inches=(6.5, 8), figure_kwargs=dict(dpi=600)
)
fig.savefig(
Path(results_location, "map_of_total_generation_by_carrier.png"), dpi=600
)


def task_cache_required_tables():
return {
"actions": [(build_parsed_workbook_cache, [_PARSED_WORKBOOK_CACHE])],
Expand Down Expand Up @@ -288,3 +303,18 @@ def task_create_and_run_pypsa_model():
],
"targets": [Path(_PYPSA_OUTPUTS_DIRECTORY, "network.hdf5")],
}


def task_produce_results():
return {
"actions": [
(
create_results,
[config, _PYPSA_OUTPUTS_DIRECTORY, _RESULTS_DIRECTORY],
)
],
"file_dep": [
Path(_PYPSA_OUTPUTS_DIRECTORY, "network.hdf5"),
],
"targets": [Path(_RESULTS_DIRECTORY, "map_of_total_generation_by_carrier.png")],
}
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dependencies = [
"isp-trace-parser>=1.0.0",
"pyarrow>=18.0.0",
"tables>=3.10.1",
"cartopy>=0.24.1",
]
readme = "README.md"
requires-python = ">= 3.10"
Expand Down
2 changes: 0 additions & 2 deletions src/ispypsa/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from ispypsa.model.initialise import initialise_network
from ispypsa.model.lines import add_lines_to_network
from ispypsa.model.run import run
from ispypsa.model.save_results import save_results

__all__ = [
"add_buses_to_network",
Expand All @@ -13,5 +12,4 @@
"add_carriers_to_network",
"add_lines_to_network",
"run",
"save_results",
]
12 changes: 7 additions & 5 deletions src/ispypsa/model/buses.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@


def _add_bus_to_network(
bus_name: str, network: pypsa.Network, path_to_demand_traces: Path
bus_definition: dict, network: pypsa.Network, path_to_demand_traces: Path
) -> None:
"""
Adds a Bus to the network and if a demand trace for the Bus exists, also adds the
Expand All @@ -19,8 +19,9 @@ def _add_bus_to_network(

Returns: None
"""
network.add(class_name="Bus", name=bus_name)

bus_definition["class_name"] = "Bus"
network.add(**bus_definition)
bus_name = bus_definition["name"]
demand_trace_path = path_to_demand_traces / Path(f"{bus_name}.parquet")
if demand_trace_path.exists():
demand = pd.read_parquet(demand_trace_path)
Expand Down Expand Up @@ -48,6 +49,7 @@ def add_buses_to_network(network: pypsa.Network, path_pypsa_inputs: Path) -> Non
"""
buses = pd.read_csv(path_pypsa_inputs / Path("buses.csv"))
path_to_demand_traces = path_pypsa_inputs / Path("demand_traces")
buses["name"].apply(
lambda x: _add_bus_to_network(x, network, path_to_demand_traces)
buses.apply(
lambda row: _add_bus_to_network(row.to_dict(), network, path_to_demand_traces),
axis=1,
)
7 changes: 0 additions & 7 deletions src/ispypsa/model/save_results.py

This file was deleted.

3 changes: 3 additions & 0 deletions src/ispypsa/results/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from ispypsa.results.io import load_results, save_results

__all__ = ["load_results", "save_results"]
13 changes: 13 additions & 0 deletions src/ispypsa/results/io.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from pathlib import Path

import pypsa


def save_results(network: pypsa.Network, pypsa_outputs_location: Path) -> None:
network.export_to_hdf5(Path(pypsa_outputs_location, "network.hdf5"))


def load_results(pypsa_outputs_location: str | Path) -> pypsa.Network:
network = pypsa.Network()
network.import_from_hdf5(Path(pypsa_outputs_location, "network.hdf5"))
return network
86 changes: 86 additions & 0 deletions src/ispypsa/results/plot_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import matplotlib.figure
from matplotlib.patches import Patch

from ispypsa.config.validators import ModelConfig

_DEFAULT_CARRIER_COLOUR_MAPPING = {
# corresponds to distillate in OpenElectricity
"Liquid Fuel": "#E46E56",
"Black Coal": "#251C00",
"Brown Coal": "#675B42",
"Gas": "#E78114",
"Water": "#ACE9FE",
"Solar": "#FECE00",
"Wind": "#2A7E3F",
# corresponds to gas_hydrogen in OpenElectricity
"Hyblend": "#C75338",
}
"""Colour mapping for carriers/fuel types. Same colour scheme as OpenElectricity"""

_DEFAULT_GEOMAP_COLOURS = dict(ocean="#dbdbdd", land="#fdfdfe")
"""Colour mapping for ocean and land in the map plot"""

_DEFAULT_FACECOLOR = "#faf9f6"
"""Facecolour to use in Figures (from OpenElectricity)"""


def _determine_title_year_range(config: ModelConfig) -> str:
"""
Determines the year range string for use in plot titles based on
ISPyPSA configuration options.
"""
(start, end) = (config.traces.start_year, config.traces.end_year)
year_type = config.traces.year_type
if year_type == "fy" and start != end:
year_range = f"FY{str(start)[-2:]}-{str(end)[-2:]}"
elif start == end:
year_range = f"{start}"
else:
year_range = f"{start}-{end}"
return year_range


def _add_figure_fuel_type_legend(
fig: matplotlib.figure.Figure,
carrier_colour_mapping: dict[str, str],
legend_kwargs=dict(),
) -> None:
"""Adds a legend that maps fuel types to their patch colours to a
`matplotlib.figure.Figure`.

Args:
fig: `matplotlib.figure.Figure`
carrier_colour_mapping: Dictionary that maps each carrier to a colour
legend_kwargs (optional): Keyword arguments for
`matplotlib.figure.Figure.legend()`. Anything specified in this dict will
overwrite ISPyPSA defaults. Defaults to dict().
"""
legend_patches = [
Patch(color=color, label=carrier)
for carrier, color in carrier_colour_mapping.items()
]
fig.legend(
handles=legend_patches,
**_consolidate_plot_kwargs(
dict(
title="Fuel Type",
loc="lower center",
fontsize=8,
title_fontsize=10,
ncol=4,
frameon=False,
),
legend_kwargs,
),
)


def _consolidate_plot_kwargs(
predefined_kwargs: dict, user_specified_kwargs: dict
) -> dict:
"""Adds to or replaces ISPyPSA's keyword arguments for plot functions using those
provided by the user in the function call.
"""
kwargs = predefined_kwargs
kwargs.update(user_specified_kwargs)
return kwargs
Loading