Skip to content

Commit 86af532

Browse files
committed
Merge branch 'main' into feature-spores-generalised
2 parents cbfaedc + 485b3d5 commit 86af532

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+9931
-9530
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ This change has occurred to avoid confusion between data "sources" and model ene
3535

3636
### Internal changes
3737

38-
|changed| Model configuration now uses `pydantic`.
38+
|changed| updated transmission technologies to/from -> link_to/link_from to avoid conflicts with protected `python` terminology.
39+
40+
|changed| Model configuration, data tables, techs/nodes data, math and general model definition now uses `pydantic`.
3941

4042
|changed| Model definition reading is now defined in a single place (preprocess/model_definition.py).
4143

docs/advanced/constraints.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,14 @@ To force unidirectionality for a given technology along a given link, you have t
133133
```yaml
134134
techs:
135135
region1_to_region2:
136-
from: region1
137-
to: region2
136+
link_from: region1
137+
link_to: region2
138138
base_tech: transmission
139139
one_way: true
140140
```
141141

142142
This will only allow transmission from `region1` to `region2`.
143-
To swap the direction, `to` and `from` must be swapped.
143+
To swap the direction, `link_to` and `link_from` must be swapped.
144144

145145
## Per-distance transmission constraints
146146

docs/creating/nodes.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ In the above example, `node_flow_out_max` at `region1` could be used to create [
3636
## Understanding node-level parameters
3737

3838
`techs` is the only required parameter in a node.
39-
This can be an empty dictionary (`techs: {}`), which you may use if your node is just a junction for transmission technologies (which you [**do not define in the `techs` of a node**](techs.md#transmission-technologies) - rather, you define them as separate technologies that connect `from` one node `to` another node).
39+
This can be an empty dictionary (`techs: {}`), which you may use if your node is just a junction for transmission technologies (which you [**do not define in the `techs` of a node**](techs.md#transmission-technologies) - rather, you define them as separate technologies that connect a `link_from` node with a `link_to` node).
4040

4141
!!! info "See also"
4242

docs/creating/techs.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,14 @@ Instead, you associate transmission technologies with nodes in `techs`:
8585
```yaml
8686
techs:
8787
ac_transmission:
88-
from: region1 # (1)!
89-
to: region2
88+
link_from: region1 # (1)!
89+
link_to: region2
9090
flow_cap_max: 100
9191
...
9292
```
9393

94-
1. The region you specify in `from` or `to` is interchangeable unless you set the parameter `one_way: true`.
95-
In that case, flow along the transmission line is only allowed from the `from` region to the `to` region.
94+
1. The region you specify in `link_from` or `link_to` is interchangeable unless you set the parameter `one_way: true`.
95+
In that case, flow along the transmission line is only allowed from the `link_from` node to the `link_to` node.
9696

9797
## Understanding tech-level parameters
9898

@@ -103,7 +103,7 @@ There are _required_ parameters according to the technology `base_tech`:
103103
* `supply`: `base_tech` and `carrier_out`.
104104
* `demand`: `base_tech` and `carrier_in`.
105105
* `storage`: `base_tech` and `carrier_out` and `carrier_in`.
106-
* `transmission`: `base_tech` and `carrier_out`, `carrier_in`, `to`, and `from`.
106+
* `transmission`: `base_tech` and `carrier_out`, `carrier_in`, `link_to`, and `link_from`.
107107
* `conversion`: `base_tech` and `carrier_out` and `carrier_in`.
108108

109109
For `storage` and `transmission`, it may seem like unnecessary repetition to define both `carrier_out` and `carrier_in` as they are likely the same value.

docs/examples/loading_tabular_data.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@
7777
# base_tech: transmission
7878
# carrier_in: electricity
7979
# carrier_out: electricity
80-
# from: A
81-
# to: B
80+
# link_from: A
81+
# link_to: B
8282
# flow_cap_max: 8
8383
#
8484
# nodes:
@@ -135,8 +135,8 @@
135135
base_tech: transmission
136136
carrier_in: electricity
137137
carrier_out: electricity
138-
from: A
139-
to: B
138+
link_from: A
139+
link_to: B
140140
flow_cap_max: 8
141141
142142
nodes:
@@ -214,8 +214,8 @@
214214
"demand_tech": {"base_tech": "demand"},
215215
"transmission_tech": {
216216
"base_tech": "transmission",
217-
"from": "A",
218-
"to": "B",
217+
"link_from": "A",
218+
"link_to": "B",
219219
"flow_cap_max": 8,
220220
},
221221
}
@@ -482,8 +482,8 @@
482482
# base_tech: transmission
483483
# carrier_in: electricity
484484
# carrier_out: electricity
485-
# from: A
486-
# to: B
485+
# link_from: A
486+
# link_to: B
487487
# flow_cap_max: 8
488488
#
489489
# nodes:
@@ -531,8 +531,8 @@
531531
# base_tech: transmission
532532
# carrier_in: electricity
533533
# carrier_out: electricity
534-
# from: A
535-
# to: B
534+
# link_from: A
535+
# link_to: B
536536
# flow_cap_max: 8
537537
#
538538
# nodes:

docs/hooks/dummy_model/model.yaml

+5-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@ nodes:
1414

1515
techs:
1616
tech_transmission:
17-
from: A
18-
to: B
17+
base_tech: transmission
18+
carrier_in: foo
19+
carrier_out: foo
20+
link_from: A
21+
link_to: B
1922

2023
data_tables:
2124
techs:

docs/hooks/dummy_model/techs.csv

+3-3
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ transmission_tech,lifetime,25
5454
transmission_tech,one_way,1.0
5555
transmission_tech,flow_cap_max,1.0
5656
transmission_tech,flow_cap_min,1.0
57-
transmission_tech,from,A
58-
transmission_tech,to,B
57+
transmission_tech,link_from,A
58+
transmission_tech,link_to,B
5959
demand_tech,sink_unit,per_cap
6060
conversion_tech,base_tech,conversion
6161
conversion_tech,cap_method,integer
@@ -64,4 +64,4 @@ supply_tech,cap_method,integer
6464
supply_tech,source_unit,per_area
6565
storage_tech,base_tech,storage
6666
transmission_tech,base_tech,transmission
67-
demand_tech,base_tech,demand
67+
demand_tech,base_tech,demand

docs/hooks/generate_readable_schema.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,17 @@
1414
import jsonschema2md
1515
from mkdocs.structure.files import File
1616

17-
from calliope import config
17+
from calliope.schemas import config_schema, data_table_schema, math_schema
1818
from calliope.util import schema
1919

2020
TEMPDIR = tempfile.TemporaryDirectory()
2121

22+
# FIXME: should only use pydantic models instead of YAML
2223
SCHEMAS = {
23-
"config_schema": config.CalliopeConfig().model_no_ref_schema(),
24+
"config_schema": config_schema.CalliopeConfig.model_no_ref_schema(),
2425
"model_schema": schema.MODEL_SCHEMA,
25-
"math_schema": schema.MATH_SCHEMA,
26-
"data_table_schema": schema.DATA_TABLE_SCHEMA,
26+
"math_schema": math_schema.CalliopeMathDef.model_no_ref_schema(),
27+
"data_table_schema": data_table_schema.CalliopeDataTable.model_no_ref_schema(),
2728
}
2829

2930

docs/installation.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Calliope is tested on Linux, macOS, and Windows.
77
Running Calliope requires four things:
88

99
1. The Python programming language, version {{ min_python_version }} to {{ max_python_version }}.
10-
2. A number of Python add-on modules including [Pyomo](https://www.pyomo.org/), [Pandas](https://pandas.pydata.org/) and [Xarray](https://xarray.dev/).
10+
2. A number of Python add-on modules including [Pyomo](https://www.pyomo.org/), [Pandas](https://pandas.pydata.org/) and [Xarray](https://docs.xarray.dev/).
1111
3. An optimisation solver: Calliope has been tested with CBC, GLPK, Gurobi, and CPLEX. Any other solver that is compatible with Pyomo should also work.
1212
4. The Calliope software itself.
1313

docs/migrating.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ We have changed the nesting structure for defining technology costs so they are
270270
### `links` → transmission links defined in `techs`
271271

272272
The top-level key `links` no longer exists.
273-
Instead, links are defined as separate transmission technologies in `techs`, including `to`/`from` keys:
273+
Instead, links are defined as separate transmission technologies in `techs`, including `link_to`/`link_from` keys:
274274

275275
=== "v0.6"
276276

@@ -298,13 +298,13 @@ Instead, links are defined as separate transmission technologies in `techs`, inc
298298
```yaml
299299
techs:
300300
x1_to_x2_ac_transmission:
301-
from: X1
302-
to: X2
301+
link_from: X1
302+
link_to: X2
303303
base_tech: transmission
304304
flow_cap_max: 10
305305
x1_to_x2_dc_transmission:
306-
from: X1
307-
to: X2
306+
link_from: X1
307+
link_to: X2
308308
base_tech: transmission
309309
flow_cap_max: 5
310310
```

docs/user_defined_math/components.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Without a `where` string, all valid members (according to the `definition_matrix
3636
If a value for a valid variable member is undefined in the referenced parameter, the decision variable will be unbounded for this member.
3737
1. It can be deactivated so that it does not appear in the built optimisation problem by setting `active: false`.
3838
1. It can take on a `default` value that will be used in math operations to avoid `NaN` values creeping in.
39-
The default value should be set such that it has no impact on the optimisation problem if it is included (most of the time, this means setting it to zero).
39+
The default value should be set such that it has no impact on the optimisation problem if it is included (most of the time, this means `NaN`).
4040

4141
## Global Expressions
4242

@@ -63,7 +63,7 @@ Without a `where` string, all valid members (according to the `definition_matrix
6363
The equation expressions do _not_ have comparison operators; those are reserved for [constraints](#constraints)
6464
1. It can be deactivated so that it does not appear in the built optimisation problem by setting `active: false`.
6565
1. It can take on a `default` value that will be used in math operations to avoid `NaN` values creeping in.
66-
The default value should be set such that it has no impact on the optimisation problem if it is included (most of the time, this means setting it to zero).
66+
The default value should be set such that it has no impact on the optimisation problem if it is included (most of the time, this means `NaN`).
6767

6868
## Constraints
6969

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ max-complexity = 10
5454

5555
# Ignore `E402` (import violations) and `F401` (unused imports) in all `__init__.py` files
5656
[tool.ruff.lint.per-file-ignores]
57-
"__init__.py" = ["E402", "F401"]
57+
"__init__.py" = ["E402", "F401", "D104"]
5858
"*.ipynb" = ["E402"]
5959
"tests/*" = ["D"]
6060
"docs/examples/*" = ["D"]

src/calliope/backend/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
from calliope.preprocess import CalliopeMath
1616

1717
if TYPE_CHECKING:
18-
from calliope import config
1918
from calliope.backend.backend_model import BackendModel
19+
from calliope.schemas import config_schema
2020

2121

2222
def get_model_backend(
23-
build_config: "config.Build", data: xr.Dataset, math: CalliopeMath
23+
build_config: "config_schema.Build", data: xr.Dataset, math: CalliopeMath
2424
) -> "BackendModel":
2525
"""Assign a backend using the given configuration.
2626

src/calliope/backend/backend_model.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@
2626
import numpy as np
2727
import xarray as xr
2828

29-
from calliope import config, exceptions
29+
from calliope import exceptions
3030
from calliope.attrdict import AttrDict
3131
from calliope.backend import helper_functions, parsing
3232
from calliope.exceptions import warn as model_warn
3333
from calliope.io import load_config, to_yaml
3434
from calliope.preprocess.model_math import ORDERED_COMPONENTS_T, CalliopeMath
35+
from calliope.schemas import config_schema
3536
from calliope.util.schema import MODEL_SCHEMA, extract_from_schema
3637

3738
if TYPE_CHECKING:
@@ -69,7 +70,7 @@ class BackendModelGenerator(ABC):
6970
"""Optimisation problem objective name."""
7071

7172
def __init__(
72-
self, inputs: xr.Dataset, math: CalliopeMath, build_config: config.Build
73+
self, inputs: xr.Dataset, math: CalliopeMath, build_config: config_schema.Build
7374
):
7475
"""Abstract base class to build a representation of the optimisation problem.
7576
@@ -617,7 +618,7 @@ def __init__(
617618
self,
618619
inputs: xr.Dataset,
619620
math: CalliopeMath,
620-
build_config: config.Build,
621+
build_config: config_schema.Build,
621622
instance: T,
622623
) -> None:
623624
"""Abstract base class to build backend models that interface with solvers.
@@ -937,15 +938,17 @@ def has_integer_or_binary_variables(self) -> bool:
937938
"""
938939

939940
@abstractmethod
940-
def _solve(self, solve_config: config.Solve, warmstart: bool = False) -> xr.Dataset:
941+
def _solve(
942+
self, solve_config: config_schema.Solve, warmstart: bool = False
943+
) -> xr.Dataset:
941944
"""Optimise built model.
942945
943946
If solution is optimal, interface objects (decision variables, global
944947
expressions, constraints, objective) can be successfully evaluated for their
945948
values at optimality.
946949
947950
Args:
948-
solve_config: (config.Solve): Calliope Solve configuration object.
951+
solve_config: (config_schema.Solve): Calliope Solve configuration object.
949952
warmstart (bool, optional): If True, and the chosen solver is capable of implementing it, an existing
950953
optimal solution will be used to warmstart the next solve run.
951954
Defaults to False.
@@ -1139,7 +1142,7 @@ def track_constraints(self, constraints_to_track: list):
11391142
valid_constraints = shadow_prices.intersection(self.available_constraints)
11401143
if invalid_constraints:
11411144
model_warn(
1142-
f"Invalid constraints {invalid_constraints} in `config.solve.shadow_prices`. "
1145+
f"Invalid constraints {invalid_constraints} in `config_schema.solve.shadow_prices`. "
11431146
"Their shadow prices will not be tracked."
11441147
)
11451148
# Only actually activate shadow price tracking if at least one valid

src/calliope/backend/gurobi_backend_model.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
import pandas as pd
1515
import xarray as xr
1616

17-
from calliope import config
1817
from calliope.backend import backend_model, parsing
1918
from calliope.exceptions import BackendError, BackendWarning
2019
from calliope.exceptions import warn as model_warn
2120
from calliope.preprocess import CalliopeMath
21+
from calliope.schemas import config_schema
2222

2323
if importlib.util.find_spec("gurobipy") is not None:
2424
import gurobipy
@@ -50,7 +50,7 @@ class GurobiBackendModel(backend_model.BackendModel):
5050
}
5151

5252
def __init__(
53-
self, inputs: xr.Dataset, math: CalliopeMath, build_config: config.Build
53+
self, inputs: xr.Dataset, math: CalliopeMath, build_config: config_schema.Build
5454
) -> None:
5555
"""Gurobi solver interface class.
5656
@@ -240,7 +240,9 @@ def get_global_expression( # noqa: D102, override
240240
else:
241241
return global_expression
242242

243-
def _solve(self, solve_config: config.Solve, warmstart: bool = False) -> xr.Dataset:
243+
def _solve(
244+
self, solve_config: config_schema.Solve, warmstart: bool = False
245+
) -> xr.Dataset:
244246
self._instance.resetParams()
245247

246248
if solve_config.solver_options is not None:

src/calliope/backend/latex_backend_model.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
import pandas as pd
1313
import xarray as xr
1414

15-
from calliope import config
1615
from calliope.backend import backend_model, parsing
1716
from calliope.exceptions import ModelError
1817
from calliope.preprocess import CalliopeMath
18+
from calliope.schemas import config_schema
1919

2020
ALLOWED_MATH_FILE_FORMATS = Literal["tex", "rst", "md"]
2121
LOGGER = logging.getLogger(__name__)
@@ -306,7 +306,7 @@ def __init__(
306306
self,
307307
inputs: xr.Dataset,
308308
math: CalliopeMath,
309-
build_config: config.Build,
309+
build_config: config_schema.Build,
310310
include: Literal["all", "valid"] = "all",
311311
) -> None:
312312
"""Interface to build a string representation of the mathematical formulation using LaTeX math notation.

src/calliope/backend/pyomo_backend_model.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727
from pyomo.opt import SolverFactory # type: ignore
2828
from pyomo.util.model_size import build_model_size_report # type: ignore
2929

30-
from calliope import config
3130
from calliope.exceptions import BackendError, BackendWarning
3231
from calliope.exceptions import warn as model_warn
3332
from calliope.preprocess import CalliopeMath
33+
from calliope.schemas import config_schema
3434
from calliope.util.logging import LogWriter
3535

3636
from . import backend_model, parsing
@@ -61,7 +61,7 @@ class PyomoBackendModel(backend_model.BackendModel):
6161
"""Pyomo-specific backend functionality."""
6262

6363
def __init__(
64-
self, inputs: xr.Dataset, math: CalliopeMath, build_config: config.Build
64+
self, inputs: xr.Dataset, math: CalliopeMath, build_config: config_schema.Build
6565
) -> None:
6666
"""Pyomo solver interface class.
6767
@@ -283,7 +283,7 @@ def get_global_expression( # noqa: D102, override
283283
return global_expression
284284

285285
def _solve( # noqa: D102, override
286-
self, solve_config: config.Solve, warmstart: bool = False
286+
self, solve_config: config_schema.Solve, warmstart: bool = False
287287
) -> xr.Dataset:
288288
if solve_config.solver == "cbc" and self.shadow_prices.is_active:
289289
model_warn(

0 commit comments

Comments
 (0)