Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

solve_network: option to inject custom extra functionalities from sou… #824

Merged
merged 13 commits into from
Jan 4, 2024
Merged
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 config/config.default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ solving:
skip_iterations: true
rolling_horizon: false
seed: 123
custom_extra_functionality: "../data/custom_extra_functionality.py"
# options that go into the optimize function
track_iterations: false
min_iterations: 4
Expand Down
11 changes: 11 additions & 0 deletions data/custom_extra_functionality.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: : 2023- The PyPSA-Eur Authors
#
# SPDX-License-Identifier: MIT


def custom_extra_functionality(n, snapshots):
"""
Add custom extra functionality constraints.
"""
pass
1 change: 1 addition & 0 deletions doc/configtables/solving.csv
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ options,,,
-- skip_iterations,bool,"{'true','false'}","Skip iterating, do not update impedances of branches. Defaults to true."
-- rolling_horizon,bool,"{'true','false'}","Whether to optimize the network in a rolling horizon manner, where the snapshot range is split into slices of size `horizon` which are solved consecutively."
-- seed,--,int,Random seed for increased deterministic behaviour.
-- custom_extra_functionality,--,str,Path to a Python file with custom extra functionality code to be injected into the solving rules of the workflow relative to ``rules`` directory.
-- track_iterations,bool,"{'true','false'}",Flag whether to store the intermediate branch capacities and objective function values are recorded for each iteration in ``network.lines['s_nom_opt_X']`` (where ``X`` labels the iteration)
-- min_iterations,--,int,Minimum number of solving iterations in between which resistance and reactence (``x/r``) are updated for branches according to ``s_nom_opt`` of the previous run.
-- max_iterations,--,int,Maximum number of solving iterations in between which resistance and reactence (``x/r``) are updated for branches according to ``s_nom_opt`` of the previous run.
Expand Down
5 changes: 5 additions & 0 deletions doc/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ Upcoming Release
reconnected to the main Ukrainian grid with the configuration option
`reconnect_crimea`.

* Add option to reference an additional source file where users can specify
custom ``extra_functionality`` constraints in the configuration file. The
default setting points to an empty hull at
``data/custom_extra_functionality.py``.

* Validate downloads from Zenodo using MD5 checksums. This identifies corrupted
or incomplete downloads.

Expand Down
7 changes: 7 additions & 0 deletions rules/common.smk
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ def memory(w):
return int(factor * (10000 + 195 * int(w.clusters)))


def input_custom_extra_functionality(w):
path = config["solving"]["options"].get("custom_extra_functionality", False)
if path:
return workflow.source_path(path)
return []


# Check if the workflow has access to the internet by trying to access the HEAD of specified url
def has_internet_access(url="www.zenodo.org") -> bool:
import http.client as http_client
Expand Down
1 change: 1 addition & 0 deletions rules/solve_electricity.smk
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ rule solve_network:
co2_sequestration_potential=config["sector"].get(
"co2_sequestration_potential", 200
),
custom_extra_functionality=input_custom_extra_functionality,
input:
network=RESOURCES + "networks/elec_s{simpl}_{clusters}_ec_l{ll}_{opts}.nc",
config=RESULTS + "config.yaml",
Expand Down
1 change: 1 addition & 0 deletions rules/solve_myopic.smk
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ rule solve_sector_network_myopic:
co2_sequestration_potential=config["sector"].get(
"co2_sequestration_potential", 200
),
custom_extra_functionality=input_custom_extra_functionality,
input:
network=RESULTS
+ "prenetworks-brownfield/elec_s{simpl}_{clusters}_l{ll}_{opts}_{sector_opts}_{planning_horizons}.nc",
Expand Down
1 change: 1 addition & 0 deletions rules/solve_overnight.smk
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ rule solve_sector_network:
co2_sequestration_potential=config["sector"].get(
"co2_sequestration_potential", 200
),
custom_extra_functionality=input_custom_extra_functionality,
input:
network=RESULTS
+ "prenetworks/elec_s{simpl}_{clusters}_l{ll}_{opts}_{sector_opts}_{planning_horizons}.nc",
Expand Down
1 change: 1 addition & 0 deletions rules/solve_perfect.smk
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ rule solve_sector_network_perfect:
co2_sequestration_potential=config["sector"].get(
"co2_sequestration_potential", 200
),
custom_extra_functionality=input_custom_extra_functionality,
input:
network=RESULTS
+ "prenetworks-brownfield/elec_s{simpl}_{clusters}_l{ll}_{opts}_{sector_opts}_brownfield_all_years.nc",
Expand Down
11 changes: 11 additions & 0 deletions scripts/solve_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@
the workflow for all scenarios in the configuration file (``scenario:``)
based on the rule :mod:`solve_network`.
"""
import importlib
import logging
import os
import re
import sys

import numpy as np
import pandas as pd
Expand Down Expand Up @@ -826,6 +829,14 @@ def extra_functionality(n, snapshots):
add_carbon_budget_constraint(n, snapshots)
add_retrofit_gas_boiler_constraint(n, snapshots)

if snakemake.params.custom_extra_functionality:
source_path = snakemake.params.custom_extra_functionality
assert os.path.exists(source_path), f"{source_path} does not exist"
sys.path.append(os.path.dirname(source_path))
module_name = os.path.splitext(os.path.basename(source_path))[0]
module = importlib.import_module(module_name)
module.custom_extra_functionality(n, snapshots)


def solve_network(n, config, solving, opts="", **kwargs):
set_of_options = solving["solver"]["options"]
Expand Down