Skip to content

Commit

Permalink
exists -> active
Browse files Browse the repository at this point in the history
  • Loading branch information
brynpickering committed Oct 24, 2023
1 parent a01d4bb commit 8ee9e95
Show file tree
Hide file tree
Showing 11 changed files with 59 additions and 56 deletions.
12 changes: 6 additions & 6 deletions doc/user/advanced_features.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,15 @@ None of the ``tech_groups`` appear in model results, they are only used to group
Removing techs, locations and links
-----------------------------------

By specifying :yaml:`exists: false` in the model configuration, which can be done for example through overrides, model components can be removed for debugging or scenario analysis.
By specifying :yaml:`active: false` in the model configuration, which can be done for example through overrides, model components can be removed for debugging or scenario analysis.

This works for:

* Techs: :yaml:`techs.tech_name.exists: false`
* Locations: :yaml:`locations.location_name.exists: false`
* Links: :yaml:`links.location1,location2.exists: false`
* Techs at a specific location: :yaml:`locations.location_name.techs.tech_name.exists: false`
* Transmission techs at a specific location: :yaml:`links.location1,location2.techs.transmission_tech.exists: false`
* Techs: :yaml:`techs.tech_name.active: false`
* Locations: :yaml:`locations.location_name.active: false`
* Links: :yaml:`links.location1,location2.active: false`
* Techs at a specific location: :yaml:`locations.location_name.techs.tech_name.active: false`
* Transmission techs at a specific location: :yaml:`links.location1,location2.techs.transmission_tech.active: false`

.. _operational_mode:

Expand Down
6 changes: 3 additions & 3 deletions src/calliope/config/defaults.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -456,20 +456,20 @@ techs:
source_cap: 0 # name: Cost of source flow capacity ¦ unit: kW :sup:`-1` ¦
storage_cap: 0 # name: Cost of storage capacity ¦ unit: kWh :sup:`-1` ¦
depreciation_rate: 1 # name: Depreciation rate for annualisation of investment costs ¦ unit: fraction ¦
exists: true
active: true

nodes:
default_node:
transmission_node: false # true only if no techs are defined (including complete omission of the `techs` key). Automatically added during processing if not defined by user.
coordinates: {} # The node's x-y coordinates for distance calculations and plotting: {lat: ..., lon: ...} or {x: ..., y: ...}
available_area: .inf # This node's available land area (required if constraining technology deployment by area).
techs: null # A list of technologies, optionally with node-specific settings overriding the technology's global settings.
exists: true
active: true

links:
default_node_from,default_node_to:
techs:
default_tech:
distance: null # Used for per_distance constraints, but automatically inferred from coordinates of nodes in a link if not given directly

exists: true
active: true
2 changes: 1 addition & 1 deletion src/calliope/preprocess/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ def _check_tech_final(
"""
if tech_id not in model_run.techs:
model_warnings.append(
"Tech {} was removed by setting ``exists: False`` - not checking "
"Tech {} was removed by setting ``active: False`` - not checking "
"the consistency of its constraints at node {}.".format(tech_id, loc_id)
)
return model_warnings, errors
Expand Down
4 changes: 2 additions & 2 deletions src/calliope/preprocess/model_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,8 @@ def process_techs(config_model):
debug_comments = AttrDict()

for tech_id, tech_config in config_model.techs.items():
# If a tech specifies ``exists: false``, we skip it entirely
if not tech_config.get("exists", True):
# If a tech specifies ``active: false``, we skip it entirely
if not tech_config.get("active", True):
continue

tech_result = AttrDict()
Expand Down
14 changes: 7 additions & 7 deletions src/calliope/preprocess/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,15 @@ def process_nodes(model_config, modelrun_techs):
# Kill any nodes that the modeller does not want to exist
##
for loc in list(nodes.keys()):
if not nodes[loc].get("exists", True):
if not nodes[loc].get("active", True):
nodes.del_key(loc)

##
# Process technologies
##
techs_to_delete = []
for tech_name in techs_in:
if not techs_in[tech_name].get("exists", True):
if not techs_in[tech_name].get("active", True):
techs_to_delete.append(tech_name)
continue
# Get inheritance chain generated in process_techs()
Expand Down Expand Up @@ -165,9 +165,9 @@ def process_nodes(model_config, modelrun_techs):
)

# Now merge the tech settings into the node-specific
# tech dict -- but if a tech specifies ``exists: false``,
# tech dict -- but if a tech specifies ``active: false``,
# we kill it at this node
if not tech_settings.get("exists", True):
if not tech_settings.get("active", True):
node_techs_to_delete.append("{}.techs.{}".format(loc_name, tech_name))
else:
nodes[loc_name].techs[tech_name].union(
Expand All @@ -182,22 +182,22 @@ def process_nodes(model_config, modelrun_techs):
for link in links_in:
loc_from, loc_to = [i.strip() for i in link.split(",")]
# Skip this link entirely if it has been told not to exist
if not links_in[link].get("exists", True):
if not links_in[link].get("active", True):
continue
# Also skip this link - and warn about it - if it links to a
# now-inexistant (because removed) node
if loc_from not in nodes.keys() or loc_to not in nodes.keys():
warnings.append(
"Not building the link {},{} because one or both of its "
"nodes have been removed from the model by setting "
"``exists: false``".format(loc_from, loc_to)
"``active: false``".format(loc_from, loc_to)
)
continue
processed_transmission_techs = AttrDict()
for tech_name in links_in[link].techs:
# Skip techs that have been told not to exist
# for this particular link
if not links_in[link].get_key("techs.{}.exists".format(tech_name), True):
if not links_in[link].get_key("techs.{}.active".format(tech_name), True):
continue
if tech_name not in processed_transmission_techs:
tech_settings = AttrDict()
Expand Down
20 changes: 10 additions & 10 deletions tests/common/test_model/scenarios.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ overrides:
costs.monetary: { purchase: 1, flow_cap: 0 }
test_demand_elec:

links.a,b.exists: false
links.a,b.active: false

supply_purchase:
nodes:
Expand All @@ -84,7 +84,7 @@ overrides:
costs.monetary.flow_cap: 0
test_demand_elec:

links.a,b.exists: false
links.a,b.active: false

supply_milp:
nodes:
Expand All @@ -96,8 +96,8 @@ overrides:
units_max: 1
flow_cap_per_unit: 15
test_demand_elec:
b.exists: false
links.a,b.exists: false
b.active: false
links.a,b.active: false

supply_export:
techs:
Expand Down Expand Up @@ -146,7 +146,7 @@ overrides:
test_demand_elec:
test_demand_heat:

links.a,b.exists: false
links.a,b.active: false

conversion_plus_milp:
nodes:
Expand All @@ -162,7 +162,7 @@ overrides:
test_demand_elec:
test_demand_heat:

links.a,b.exists: false
links.a,b.active: false

conversion_plus_purchase:
nodes:
Expand All @@ -178,7 +178,7 @@ overrides:
test_demand_elec:
test_demand_heat:

links.a,b.exists: false
links.a,b.active: false

simple_conversion_plus:
nodes:
Expand All @@ -191,7 +191,7 @@ overrides:
test_demand_elec:
test_demand_heat:

links.a,b.exists: false
links.a,b.active: false

simple_storage:
nodes:
Expand Down Expand Up @@ -226,7 +226,7 @@ overrides:
storage_cap_per_unit: 15
test_demand_elec:

links.a,b.exists: false
links.a,b.active: false

storage_purchase:
nodes:
Expand All @@ -238,7 +238,7 @@ overrides:
costs.monetary: { purchase: 1 }
test_demand_elec:

links.a,b.exists: false
links.a,b.active: false

clustering:
model.time:
Expand Down
5 changes: 3 additions & 2 deletions tests/test_constraint_results.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import calliope
import pytest
from pytest import approx

import calliope

from .common.util import build_test_model as build_model


Expand Down Expand Up @@ -111,7 +112,7 @@ def run_model(self):
def _run_model(feasibility, cap_val):
override_dict = {
"nodes.a.techs": {"test_supply_elec": {}, "test_demand_elec": {}},
"links.a,b.exists": False,
"links.a,b.active": False,
# pick a time subset where demand is uniformally -10 throughout
"model.subset_time": ["2005-01-01 06:00:00", "2005-01-01 08:00:00"],
"run.ensure_feasibility": feasibility,
Expand Down
9 changes: 5 additions & 4 deletions tests/test_core_preprocess.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import os

import calliope
import calliope.exceptions as exceptions
import numpy as np
import pandas as pd
import pytest
from calliope.core.attrdict import AttrDict
from pytest import approx

import calliope
import calliope.exceptions as exceptions
from calliope.core.attrdict import AttrDict

from .common.util import build_test_model as build_model
from .common.util import check_error_or_warning, defaults

Expand Down Expand Up @@ -764,7 +765,7 @@ def test_inexistent_group_constraint_empty_loc_tech(self):
excinfo, "Constraint group `mygroup` will be completely ignored"
)

assert m._model_run.group_constraints.mygroup.get("exists", True) is False
assert m._model_run.group_constraints.mygroup.get("active", True) is False

@pytest.mark.filterwarnings(
"ignore:(?s).*Not building the link a,b:calliope.exceptions.ModelWarning"
Expand Down
5 changes: 3 additions & 2 deletions tests/test_core_time.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import calliope
import numpy as np
import pandas as pd
import pytest # noqa: F401

import calliope
from calliope import exceptions
from calliope.time import funcs, masks

Expand Down Expand Up @@ -1051,7 +1052,7 @@ def test_invalid_csv_columns(self):
"d.techs": {"test_supply_elec": None, "test_demand_elec": None},
},
"links": {
"a,b": {"exists": False},
"a,b": {"active": False},
"c,d.techs": {"test_transmission_elec": None},
},
}
Expand Down
9 changes: 4 additions & 5 deletions tests/test_example_models.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import shutil

import calliope
import numpy as np
import pandas as pd
import pytest
from calliope import exceptions
from pytest import approx

import calliope
from calliope import exceptions

from .common.util import check_error_or_warning


Expand Down Expand Up @@ -430,9 +431,7 @@ def model_runner(
"run.cyclic_storage": cyclic,
}
if storage is False:
override.update({"techs.battery.exists": False, "techs.csp.exists": False})
if solver_io is not None:
override["run.solver_io"] = solver_io
override.update({"techs.battery.active": False, "techs.csp.active": False})
if storage_inter_cluster and backend_runner == "solve":
override["model.custom_math"] = ["storage_inter_cluster"]

Expand Down
29 changes: 15 additions & 14 deletions tests/test_model_manipulation.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import pytest # noqa: F401

from calliope import exceptions

from .common.util import build_test_model as build_model
from .common.util import check_error_or_warning


class TestExistsFalse:
class TestActiveFalse:
"""
Test removal of techs, nodes, links, and transmission techs
with the ``exists: False`` configuration option.
with the ``active: False`` configuration option.
"""

def test_tech_exists_false(self):
overrides = {"techs.test_storage.exists": False}
def test_tech_active_false(self):
overrides = {"techs.test_storage.active": False}
with pytest.warns(exceptions.ModelWarning) as excinfo:
model = build_model(overrides, "simple_storage,two_hours,investment_costs")

Expand All @@ -23,11 +24,11 @@ def test_tech_exists_false(self):
# Ensure warnings were raised
assert check_error_or_warning(
excinfo,
"Tech test_storage was removed by setting ``exists: False`` - not checking the consistency of its constraints at node a.",
"Tech test_storage was removed by setting ``active: False`` - not checking the consistency of its constraints at node a.",
)

def test_node_exists_false(self):
overrides = {"nodes.b.exists": False}
def test_node_active_false(self):
overrides = {"nodes.b.active": False}
with pytest.warns(exceptions.ModelWarning) as excinfo:
model = build_model(overrides, "simple_storage,two_hours,investment_costs")

Expand All @@ -37,11 +38,11 @@ def test_node_exists_false(self):
# Ensure warnings were raised
assert check_error_or_warning(
excinfo,
"Not building the link a,b because one or both of its nodes have been removed from the model by setting ``exists: false``",
"Not building the link a,b because one or both of its nodes have been removed from the model by setting ``active: false``",
)

def test_node_tech_exists_false(self):
overrides = {"nodes.b.techs.test_storage.exists": False}
def test_node_tech_active_false(self):
overrides = {"nodes.b.techs.test_storage.active": False}
model = build_model(overrides, "simple_storage,two_hours,investment_costs")

# Ensure what should be gone is gone
Expand All @@ -51,15 +52,15 @@ def test_node_tech_exists_false(self):
.item()
)

def test_link_exists_false(self):
overrides = {"links.a,b.exists": False}
def test_link_active_false(self):
overrides = {"links.a,b.active": False}
model = build_model(overrides, "simple_storage,two_hours,investment_costs")

# Ensure what should be gone is gone
assert not model._model_data.inheritance.str.endswith("transmission").any()

def test_link_tech_exists_false(self):
overrides = {"links.a,b.techs.test_transmission_elec.exists": False}
def test_link_tech_active_false(self):
overrides = {"links.a,b.techs.test_transmission_elec.active": False}
model = build_model(overrides, "simple_storage,two_hours,investment_costs")

# Ensure what should be gone is gone
Expand Down

0 comments on commit 8ee9e95

Please sign in to comment.