-
Notifications
You must be signed in to change notification settings - Fork 94
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
Introduce SPORES in v0.7.0 as a generalisable mode #716
Open
FLomb
wants to merge
22
commits into
main
Choose a base branch
from
feature-spores-generalised
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 5 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
325ab50
Add `broadcast_param_data` config option and default it to False.
brynpickering 6180cf1
Add spores scenarios to example and add notebook
FLomb 1d22193
Update spores_run.py
FLomb c45b082
Update model.yaml
FLomb 872ca93
Update spores_run.py
FLomb a2b4965
Merge branch 'main' into feature-spores-generalised
brynpickering 379dac1
Merge branch 'main' into feature-spores-generalised
brynpickering 8e534e7
Working SPORES model
brynpickering 42925b3
Update method to rely less on user input
brynpickering e6c9b56
Add tests; update example notebook
brynpickering d61e65f
Remove additional math
brynpickering 3e97ec8
Update latex math test
brynpickering 9c3d467
Add tests; minor fixes & renaming
brynpickering ba5638d
H -> h
brynpickering 45d2b7b
Merge branch 'main' into feature-spores-generalised
brynpickering f0feabc
Post merge fixes
brynpickering 77808df
Changes in response to review
brynpickering cbfaedc
Rename spores score threshold factor
brynpickering 86af532
Merge branch 'main' into feature-spores-generalised
brynpickering 3611d75
Update SPORES objective; update math docs
brynpickering 2ef3380
Fix `math math`
brynpickering 9818b70
re-introduce unmet demand in spores objective; remove hardcoded spore…
brynpickering File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
# --- | ||
# jupyter: | ||
# jupytext: | ||
# text_representation: | ||
# extension: .py | ||
# format_name: percent | ||
# format_version: '1.3' | ||
# jupytext_version: 1.16.4 | ||
# kernelspec: | ||
# display_name: Python 3 (ipykernel) | ||
# language: python | ||
# name: python3 | ||
# --- | ||
|
||
# %% [markdown] | ||
# # Generating SPORES | ||
# An interactive example of how to generate near-optimal system designs (or SPORES) out of a Calliope v0.7.0 model. This example relies solely on default software functionality and a custom Python function to determine how to assign penalties (scores) to previously explored system design options. | ||
|
||
# %% | ||
# Importing the required packages | ||
import calliope | ||
import xarray as xr | ||
|
||
# %% [markdown] | ||
# ## Cost-optimal model run and extraction of SPORES-relevant outputs | ||
|
||
# %% | ||
# Loading model files and building the model | ||
model = calliope.examples.national_scale(scenario="spores") | ||
model.build() | ||
|
||
# Solving | ||
model.solve() | ||
|
||
# Extracting SPORES-relevant data | ||
least_feasible_cost = model.results.cost.loc[{"costs": "monetary"}].sum().sum() | ||
print("The minimum cost for a feasible system design is {}".format(least_feasible_cost.values)) | ||
|
||
|
||
# %% [markdown] | ||
# ## SPORES model run | ||
# ### Definition of the penalty-assignment methods | ||
|
||
# %% | ||
def scoring_integer(results, backend): | ||
# Filter for technologies of interest | ||
spores_techs = backend.inputs["spores_tracker"].notnull() | ||
# Look at capacity deployment in the previous iteration | ||
previous_cap = results.flow_cap | ||
# Make sure that penalties are applied only to non-negligible deployments of capacity | ||
min_relevant_size = 0.1 * previous_cap.where(spores_techs).max( | ||
["nodes", "carriers", "techs"] | ||
) | ||
# Where capacity was deployed more than the minimal relevant size, assign an integer penalty (score) | ||
new_score = previous_cap.copy() | ||
new_score = new_score.where(spores_techs, other=0) | ||
new_score = new_score.where(new_score > min_relevant_size, other=0) | ||
new_score = new_score.where(new_score == 0, other=1000) | ||
# Transform the score into a "cost" parameter | ||
new_score.rename("cost_flow_cap") | ||
new_score = new_score.expand_dims(costs=["spores_score"]).copy() | ||
new_score = new_score.sum("carriers") | ||
# Extract the existing cost parameters from the backend | ||
all_costs = backend.get_parameter("cost_flow_cap", as_backend_objs=False) | ||
try: | ||
all_costs = all_costs.expand_dims(nodes=results.nodes).copy() | ||
except: | ||
pass | ||
# Create a new version of the cost parameters by adding up the calculated scores | ||
new_all_costs = all_costs | ||
new_all_costs.loc[{"costs":"spores_score"}] += new_score.loc[{"costs":"spores_score"}] | ||
|
||
return new_all_costs | ||
|
||
|
||
# %% [markdown] | ||
# ### Iterating over the desired number of alternatives | ||
|
||
# %% | ||
# Create some lists to store results as they get generated | ||
spores = [] # full results | ||
scores = [] # scores only | ||
spores_counter = 1 | ||
number_of_spores = 5 | ||
|
||
# %% | ||
for i in range(spores_counter, spores_counter + number_of_spores): | ||
|
||
if spores_counter == 1: | ||
# Store the cost-optimal results | ||
spores.append(model.results.expand_dims(spores=[0])) | ||
scores.append( | ||
model.backend.get_parameter("cost_flow_cap", as_backend_objs=False) | ||
.sel(costs="spores_score") | ||
.expand_dims(spores=[0]) | ||
) | ||
# Update the slack-cost backend parameter based on the calculated minimum feasible system design cost | ||
model.backend.update_parameter("spores_cost_max", least_feasible_cost) | ||
# Update the objective_cost_weights to reflect the ones defined for the SPORES mode | ||
model.backend.update_parameter( | ||
"objective_cost_weights", model.inputs.spores_objective_cost_weights | ||
) | ||
else: | ||
pass | ||
|
||
# Calculate weights based on a scoring method | ||
spores_score = scoring_integer(model.results, model.backend) | ||
# Assign a new score based on the calculated penalties | ||
model.backend.update_parameter( | ||
"cost_flow_cap", spores_score.reindex_like(model.inputs.cost_flow_cap) | ||
) | ||
# Run the model again to get a solution that reflects the new penalties | ||
model.solve(force=True) | ||
# Store the results | ||
spores.append(model.results.expand_dims(spores=[i])) | ||
scores.append( | ||
model.backend.get_parameter("cost_flow_cap", as_backend_objs=False) | ||
.sel(costs="spores_score") | ||
.expand_dims(spores=[i]) | ||
) | ||
|
||
spores_counter += 1 | ||
|
||
# Concatenate the results in the storage lists into xarray objects | ||
spore_ds = xr.concat(spores, dim="spores") | ||
score_da = xr.concat(scores, dim="spores") | ||
|
||
# %% [markdown] | ||
# ## Sense-check | ||
|
||
# %% | ||
# Extract the deployed capacities across SPORES, which we want to inspect | ||
flow_caps = spore_ds.flow_cap.where( | ||
model.backend.inputs["spores_tracker"].notnull()).sel( | ||
carriers='power').to_series().dropna().unstack("spores") | ||
flow_caps |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
src/calliope/example_models/national_scale/additional_math.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
constraints: | ||
total_system_cost_max: | ||
description: > | ||
Limit total system cost. Conceived for use in SPORES mode to apply a maximum | ||
relaxation to the system cost compared to the least-cost feasible option. | ||
equations: | ||
- expression: sum(cost[costs=monetary], over=[nodes, techs]) <= spores_cost_max * (1 + spores_slack) |
6 changes: 6 additions & 0 deletions
6
src/calliope/example_models/national_scale/data_tables/costs.csv
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
parameters,cost_flow_cap,cost_storage_cap,cost_area_use,cost_source_cap,cost_flow_in,cost_flow_out | ||
comment,USD per kW,USD per kWh storage capacity,USD per m2,USD per kW,USD per kWh,USD per kWh | ||
ccgt,750,,,,0.02, | ||
csp,1000,50,200,200,,0.002 | ||
battery,,200,,,, | ||
region1_to_region2,200,,,,,0.002 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no doubt that this function can be majorly shortened by someone with deeper experience of these data structures