Skip to content

Commit 5cf24e2

Browse files
Bump version to 1.2.0 (#61)
* chore: update version * docs: small docs improvements * docs: changelog update * docs: changelog for 1.2.0 * fix: update custom objective doc name in tests * docs: changelog fun
1 parent 269204f commit 5cf24e2

File tree

5 files changed

+115
-24
lines changed

5 files changed

+115
-24
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ test: setup-test test-docs
5151
create-test-docs: setup-test clean-test-docs
5252
mkdir -p ./tests/phmdoctest
5353
python -m phmdoctest README.md --outfile tests/phmdoctest/test_readme.py
54-
python -m phmdoctest ./docs/docs/how-to/custom-objective.md --outfile tests/phmdoctest/test_custom_objective.py
54+
python -m phmdoctest ./docs/docs/how-to/custom-objectives.md --outfile tests/phmdoctest/test_custom_objectives.py
5555
python -m phmdoctest ./docs/docs/validation/battery.md --outfile tests/phmdoctest/test_validate_battery.py
5656
python -m phmdoctest ./docs/docs/validation/evs.md --outfile tests/phmdoctest/test_validate_evs.py
5757
python -m phmdoctest ./docs/docs/validation/heat-pump.md --outfile tests/phmdoctest/test_validate_heat-pump.py

docs/docs/changelog.md

+96-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,101 @@
11
# Changelog
22

3-
## [1.1.1](https://github.com/ADGEfficiency/energy-py-linear/releases/tag/v1.1.0)
3+
## [1.2.0](https://github.com/ADGEfficiency/energy-py-linear/releases/tag/v1.2.0)
4+
5+
### Custom Objective Functions
6+
7+
A custom objective function allows users to create their own objective functions in the linear program.
8+
9+
This allows users to optimize for a custom set of revenues and costs. The objective function can target assets by type or name, and can include multiplication by interval data and/or a coefficient.
10+
11+
The example below shows how to include a cost for battery use (a cycle cost) applied to the battery discharge:
12+
13+
```python
14+
import numpy as np
15+
import energypylinear as epl
16+
17+
assets = [
18+
epl.Battery(power_mw=20, capacity_mwh=20)
19+
]
20+
site = epl.Site(
21+
assets=assets,
22+
electricity_prices=np.random.normal(0, 1000, 48)
23+
)
24+
terms=[
25+
{
26+
"asset_type":"site",
27+
"variable":"import_power_mwh",
28+
"interval_data":"electricity_prices"
29+
},
30+
{
31+
"asset_type":"site",
32+
"variable":"export_power_mwh",
33+
"interval_data":"electricity_prices",
34+
"coefficient":-1
35+
},
36+
{
37+
"asset_type": "battery",
38+
"variable": "electric_discharge_mwh",
39+
"interval_data": "electricity_prices",
40+
"coefficient": 0.25
41+
}
42+
]
43+
site.optimize(objective={"terms": terms})
44+
```
45+
46+
See [Custom Objectives](https://energypylinear.adgefficiency.com/latest/how-to/custom-objectives/) in the documentation for more examples.
47+
48+
### Logging Improvements
49+
50+
The dependency on `structlog` has been removed - we now only use `rich.logging.Console` to log to STDOUT. The ability to log to a file has been removed.
51+
52+
The `verbose` flag now accepts either a `bool` or an `int`. The mapping of `verbose` to log levels is as follows:
53+
54+
| `verbose` | Log Level |
55+
|-----------|-----------|
56+
| True | INFO |
57+
| False | ERROR |
58+
| 1 | DEBUG |
59+
| 2 | INFO |
60+
| 3 | WARNING |
61+
| 4 | ERROR |
62+
63+
```python
64+
import energypylinear as epl
65+
asset = epl.Battery(electricity_prices=[10, -50, 200, -50, 200])
66+
simulation = asset.optimize(verbose=2)
67+
```
68+
69+
```
70+
INFO assets.site.optimize: cfg=<SiteConfig name=site, freq_mins=60,
71+
import_limit_mw=10000.0, export_limit_mw=10000.0>
72+
INFO assets.site.optimize: cfg=<SiteConfig name=site, freq_mins=60,
73+
import_limit_mw=10000.0, export_limit_mw=10000.0>
74+
INFO assets.site.optimize: assets=['battery', 'spill']
75+
INFO assets.site.optimize: assets=['battery', 'spill']
76+
INFO optimizer.solve: status='Optimal'
77+
INFO optimizer.solve: status='Optimal'
78+
```
79+
80+
### Tighten Optimizer Tolerance
81+
82+
The default relative tolerance of the CBC optimizer has been reduced to `0.0`.
83+
84+
### Optimizer Config can be a Dictionary
85+
86+
It's now possible to use a dictionary in place of the `epl.OptimizerConfig` object:
87+
88+
```python
89+
asset.optimize(optimizer_config={"timeout": 2, "relative_tolerance": 0.1})
90+
```
91+
92+
### Other Changes
93+
94+
We have upgraded Poetry to 1.7.0 and Mypy to 1.7.0.
95+
96+
Plausible analytics added to the documentation.
97+
98+
## [1.1.1](https://github.com/ADGEfficiency/energy-py-linear/releases/tag/v1.1.1)
499

5100
### Bugs
6101

docs/docs/how-to/custom-objective.md docs/docs/how-to/custom-objectives.md

+16-20
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
## Custom Objective Functions
1+
`energypylinear` has two different objective functions (price or carbon) built into the library.
22

3-
`energypylinear` can optimize for two different objective functions (price or carbon) built into the library.
3+
However you may want to optimize for a different objective function in the linear program. You may have a business problem with a different set of revenues and costs than are included by default.
44

5-
However you may want to optimize for a different objective function in the linear program.
6-
7-
**A custom objective function allows you to construct an objective function as you see fit** - allowing you to optimize a site and assets for the incentives and costs that are important to you.
5+
**A custom objective function allows you to construct an objective function as you see fit** - allowing you to optimize a site and assets for the revenues and costs that are important to you.
86

97
Core to the custom objective function is the `epl.Term` - representing a single term in the objective function:
108

@@ -21,9 +19,9 @@ class Term:
2119
coefficient: float = 1.0
2220
```
2321

24-
Each term can target either many assets by type or one asset by name. It can also include multiplication by interval data or by a coefficient.
22+
A term can target either many assets by type or one asset by name. It can also include multiplication by interval data or by a coefficient.
2523

26-
A custom objective function is a list of `epl.Term` - the sum of these terms becomes the objective function.
24+
A custom objective function is a list of terms:
2725

2826
<!--phmdoctest-share-names-->
2927
```python
@@ -32,11 +30,13 @@ class CustomObjectiveFunction:
3230
terms: list[Term]
3331
```
3432

33+
The objective function used in the linear program is the sum of these terms.
34+
3535
### Price and Carbon
3636

37-
In this example we will show how to optimize a battery for an objective optimizes for both profit and carbon at the same time.
37+
This example shows how to optimize a battery for an objective that includes terms for both price and carbon.
3838

39-
The example below creates an objective function where we incentive a site to:
39+
Below we create an objective function where we incentive a site to:
4040

4141
- reduce import when the electricity price or carbon intensity is high,
4242
- increase export when the electricity price or carbon intensity is low.
@@ -52,9 +52,9 @@ def simulate(
5252
carbon_price: int,
5353
seed: int,
5454
n: int,
55-
verbose: int = 2
55+
verbose: int = 3
5656
) -> epl.SimulationResult:
57-
"""Runs one battery simulation at a given carbon price with a custom objective function."""
57+
"""Run a battery simulation with a custom objective function."""
5858
np.random.seed(seed)
5959
site = epl.Site(
6060
assets=[epl.Battery(power_mw=10, capacity_mwh=20)],
@@ -100,14 +100,10 @@ print(simulate(carbon_price=50, seed=42, n=72))
100100
```
101101

102102
```
103-
INFO assets.site.optimize: cfg=<SiteConfig name=site, freq_mins=60,
104-
import_limit_mw=10000.0, export_limit_mw=10000.0>
105-
INFO assets.site.optimize: assets=['battery']
106-
INFO optimizer.solve: status='Optimal'
107103
<energypylinear.SimulationResult feasible:True, rows:72, cols:28>
108104
```
109105

110-
We can validate that our custom objective function is working as expected by running simulations across many carbon prices, and see the effect on the profit and emissions of our site:
106+
We can validate that our custom objective function is working as expected by running simulations across many carbon prices:
111107

112108
<!--phmdoctest-share-names-->
113109
```python
@@ -148,7 +144,7 @@ In the previous example we used a custom objective function to apply incentives
148144

149145
An example of this is a renewable energy certificate scheme, where the generation from one asset receives additional income for each MWh generated.
150146

151-
In the example below, our `solar` asset receives additional income for each MWh generated.
147+
In the example below, our `solar` asset receives additional income for each MWh generated.
152148

153149
The site has a constrained export limit, which limits how much both generators can output. The site electric load increases in each interval, which allows us to see which generator is called first:
154150

@@ -213,15 +209,15 @@ print(
213209
4 50.0 50.0
214210
```
215211

216-
As expected, the first generator that is called is the `solar` generator, as it receives additional income for it's output.
212+
As expected, the first generator that is called is the `solar` generator, as it receives additional income for it's output.
217213

218214
As the site demand increases, the `wind` generator is called to make up the remaining demand.
219215

220216
### Synthetic PPA
221217

222218
A synthetic PPA is a financial instrument that allows swapping of the output of a wholesale exposed generator to a fixed price.
223219

224-
This can be modelled as a custom objective function.
220+
This can be modelled as a custom objective function.
225221

226222
In the example below, we model a site with wholesale exposed import and export, and swap the output of our `wind` generator from the wholesale to a fixed price:
227223

@@ -356,7 +352,7 @@ terms=[
356352
]
357353
```
358354

359-
We can validate that this works by applying a stronger cycle cost and seeing the battery use descrease:
355+
We can validate that this works by applying a stronger cycle cost and seeing the battery use decrease:
360356

361357
<!--phmdoctest-share-names-->
362358
```python

docs/mkdocs.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ nav:
6363
- Optimize Multiple Assets: how-to/dispatch-site.md
6464
- Optimize for Carbon: how-to/price-carbon.md
6565
- Optimize for a Forecast: how-to/dispatch-forecast.md
66-
- Use a Custom Objective Function: how-to/custom-objective.md
66+
- Custom Objective Functions: how-to/custom-objectives.md
6767
- Validation:
6868
- Battery: validation/battery.md
6969
# - Combined Heat & Power: validation/chp.md

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "energypylinear"
3-
version = "1.1.1"
3+
version = "1.2.0"
44
description = "Optimizing energy assets with mixed-integer linear programming."
55
authors = ["Adam Green <[email protected]>"]
66
license = "MIT"

0 commit comments

Comments
 (0)