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

Adapt cost accounting for multi-year-periods #993

Draft
wants to merge 108 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
4f2b64c
Add minor bug fix
jokochems Oct 2, 2023
b61d11f
Replace "simulation" by "optimization"
jokochems Oct 2, 2023
de93c31
fix erroneous type and methods in multi-period usage docs; add hint t…
jokochems Oct 2, 2023
5ad6f86
Correct changelog information
jokochems Oct 2, 2023
aa15956
Account for remaining values and limit fixed costs to optimization ho…
jokochems Oct 2, 2023
ca93fb4
Adjust remaining value and fixed costs for generic storage accordingly
jokochems Oct 2, 2023
eb64a51
Add bug fix
jokochems Oct 2, 2023
0520abc
Include adjustments for SinkDSM investments
jokochems Oct 2, 2023
6ffe405
Add getter for period length in years
jokochems Oct 6, 2023
aa177eb
limit present values to optimization horizon and correct erroneous ca…
jokochems Oct 6, 2023
b99f231
Include proper discounting (from start year p) to year 0
jokochems Oct 6, 2023
6c6f3a0
Revise / correct fixed costs handling
jokochems Oct 6, 2023
6f999c0
Adjust generic storage objective alike
jokochems Oct 6, 2023
f29af6d
Adjust Sink DSM objective functions alike
jokochems Oct 6, 2023
bbe4d04
Revise formatting
jokochems Oct 6, 2023
dad4616
Stick to numpydoc code style
jokochems Oct 6, 2023
7400c9c
Adjust lp files to changes
jokochems Oct 6, 2023
787a4a9
Extend changelog for v0.5.2
jokochems Oct 6, 2023
f1845af
Adjust docs for invest flow
jokochems Oct 6, 2023
caf6cd6
Adjust storage docs and add minor fixes
jokochems Oct 6, 2023
f6f9a4d
Adjust docs for sink dsm
jokochems Oct 6, 2023
b4010c8
Alter identation
jokochems Oct 6, 2023
fe2a8c4
Fix erroneous return values in docs
jokochems Oct 6, 2023
c4f9365
Delete useless test
p-snft Oct 11, 2023
860b742
Disuse network.Bus in warnings test
p-snft Oct 11, 2023
55f3fdc
Disuse subclasses of oemof.network.Node
p-snft Oct 11, 2023
ecb8c25
Use pytest.approx(x) instead of int(round(x))
p-snft Oct 11, 2023
3e02fc5
Embrace conformity
p-snft Oct 11, 2023
962abb6
Use full_load_time_min instead of summed_min
p-snft Oct 11, 2023
aa43b30
Sort imports
p-snft Oct 11, 2023
0156477
Delete unused import
p-snft Oct 11, 2023
91b14c2
Merge branch 'dev' into fix/eliminate_warnings
p-snft Oct 12, 2023
b5b3a81
Merge branch 'dev' into fix/eliminate_warnings
p-snft Oct 12, 2023
63e699e
Change deprecated API calls
p-snft Oct 12, 2023
9d21452
Adapt get_period_duration for multi-year-periods
nailend Oct 12, 2023
bc1d808
Adapt variable costs for representative multi-year-periods
nailend Oct 12, 2023
fc403d3
Fix wrong replacement in TestsConstraint
p-snft Oct 12, 2023
01ebeaa
Fix implicit time step inference
p-snft Oct 12, 2023
f677ad9
Adhere to Black
p-snft Oct 12, 2023
f9c79ab
Adhere to Black
p-snft Oct 12, 2023
e54e8b2
Increment dev release counter
p-snft Oct 12, 2023
9fe9389
Merge branch 'dev' into fix/eliminate_warnings
p-snft Oct 12, 2023
2129b0a
Delete warning about timeincrement in EnergySystem
p-snft Oct 12, 2023
240746c
Fix include of example_genergic_invest
p-snft Oct 12, 2023
442c3a6
Avoid DataFrame.groupby(*args, axis=1, **kwargs)
p-snft Oct 12, 2023
1a681f0
Ignore ExperimentalFeatureWarning in pytest
p-snft Oct 12, 2023
b3ba6f2
Adhere to Black
p-snft Oct 12, 2023
98b5ada
Merge branch 'dev' into feature/account-for-remaining-values-of-multi…
jokochems Oct 13, 2023
2d51637
Make investment perspectives consistent
jokochems Oct 13, 2023
8c7ac0d
Refactor and make end_year_of_optimization an attribute of energy system
jokochems Oct 13, 2023
12d48a0
Black it real good
jokochems Oct 13, 2023
5b0a4d7
Adjust docs to changes made
jokochems Oct 13, 2023
91c5b55
Merge pull request #981 from oemof/docs/fix-outdated-multi-period-docs
jokochems Oct 13, 2023
ba638ee
Merge remote-tracking branch 'upstream/dev' into feature/account-for-…
jokochems Oct 13, 2023
92a2a1e
Make handling of fixed costs consistent for dispatch-related flows
jokochems Oct 13, 2023
a5892d1
Clarify that fixed costs are accounted for on a yearly basis.
jokochems Oct 13, 2023
334fce1
Implement 'use_representative_year' flag
nailend Oct 13, 2023
465ebe4
Adjust the docs to code changes and add missing docs
jokochems Oct 13, 2023
31c0e92
Add bug fix
jokochems Oct 13, 2023
0805362
Update lp files
jokochems Oct 13, 2023
c524097
Fix failing tests
jokochems Oct 13, 2023
758be20
Add missing contributor
jokochems Oct 13, 2023
2b7ab2c
Add some minor docs and code formatting fixes
jokochems Oct 13, 2023
8ef4c4c
Include pytest.ini in MANIFEST
p-snft Oct 13, 2023
27d677d
Remove obsolete fixed costs parameter
jokochems Oct 13, 2023
cfc6966
Revert "Ignore ExperimentalFeatureWarning in pytest"
p-snft Oct 13, 2023
99385e6
Revert "Include pytest.ini in MANIFEST"
p-snft Oct 13, 2023
42e52c9
Implement remaining value in investment flow
jokochems Oct 7, 2023
42967e7
Define attribute use_remaining_value
jokochems Oct 13, 2023
ebd183a
Update implementation for investment flow block
jokochems Oct 13, 2023
15b721a
Include remaining value for storage and DSM accordingly
jokochems Oct 13, 2023
b8d08f7
Extend changelog and usage docs
jokochems Oct 13, 2023
22b4519
Add new constraint tests
jokochems Oct 13, 2023
ceba43d
Delete tangling white space in docs
p-snft Oct 13, 2023
088a35f
Merge pull request #997 from oemof/feature/remaining-value
jokochems Oct 13, 2023
a849327
Merge branch 'dev' into fix/eliminate_warnings
p-snft Oct 13, 2023
723a77a
Add minor corrections in docs
jokochems Oct 13, 2023
c1b4bff
Add nonconvex investment tests to prevent coverage decrease
jokochems Oct 13, 2023
6cb4bbf
Test Future warning in Flow invenstment
p-snft Oct 13, 2023
0c1dca2
Fix if condition
nailend Oct 16, 2023
6155a69
Allow using [-1] to define last period
nailend Oct 16, 2023
321a35a
Revert "Delete warning about timeincrement in EnergySystem"
p-snft Oct 16, 2023
561688d
Tell about need for timeincrement in MP models
p-snft Oct 16, 2023
b5b098a
Merge pull request #995 from oemof/fix/generic-caes-unused-fixed_cost…
p-snft Oct 18, 2023
555234b
Rephrase & replace formula occurences of "whereby"
jokochems Oct 20, 2023
c75ecec
Remove code duplication
jokochems Oct 20, 2023
f542a7c
Fix formatting
jokochems Oct 20, 2023
119e9cb
Merge pull request #982 from oemof/feature/account-for-remaining-valu…
jokochems Oct 20, 2023
5cb5b72
Merge branch 'dev' into fix/eliminate_warnings
jokochems Oct 20, 2023
f73e7db
make BasicModel consider all constraint groups
lensum Oct 20, 2023
75e3627
Lean code and emove redundant discounting
nailend Oct 20, 2023
29822da
Merge pull request #990 from oemof/fix/eliminate_warnings
p-snft Oct 20, 2023
db87542
Specify time unit to be hours
p-snft Oct 23, 2023
54fac89
Speak of time steps in minimum "time" constraints
p-snft Oct 23, 2023
ab22716
Merge pull request #1004 from oemof/fix/specific_timeincrement_docs
p-snft Oct 23, 2023
87377e7
Specify RTD build OS
p-snft Oct 23, 2023
498d9a6
Specify tools in .readthedocs.yaml
p-snft Oct 23, 2023
16054ca
Update python version .readthedocs.yaml
p-snft Oct 23, 2023
39f59f5
Fix python version in .readthedocs.yaml
p-snft Oct 23, 2023
bf430f4
Merge branch 'oemof:dev' into features/cellular
lensum Oct 23, 2023
214ef46
Merge pull request #1003 from lensum/features/cellular
p-snft Oct 23, 2023
5d79728
Fix 0.0 replacement to fix test
SabineHaas May 23, 2024
e20a13d
Merge tag 'tags/v0.5.2.dev1' into fix/update-branch_adapt-costs-for-m…
SabineHaas May 28, 2024
b00174d
Fix get_period_duration()
SabineHaas May 28, 2024
95e373e
Fix usage of get_period_duration()
SabineHaas May 28, 2024
1e896ba
Fix indent after merge conflict
SabineHaas May 28, 2024
022d4f4
Apply black
SabineHaas May 28, 2024
411adb8
Merge pull request #1069 from oemof/fix/update-branch_adapt-costs-for…
SabineHaas May 29, 2024
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
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.5.2dev0
current_version = 0.5.2dev1
commit = True
tag = True

Expand Down
4 changes: 3 additions & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
version: 2
build:
os: ubuntu-22.04
tools:
python: "3.8"
apt_packages:
- coinor-cbc
sphinx:
configuration: docs/conf.py
formats: []
python:
version: "3.8"
install:
- requirements: docs/requirements.txt
- method: pip
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.5.2dev0"
__version__ = "0.5.2dev1"
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def setup(app):
year = "2014-2023"
author = "oemof-developer-group"
copyright = "{0}, {1}".format(year, author)
version = release = "0.5.2dev0"
version = release = "0.5.2dev1"

pygments_style = "trac"
templates_path = ["."]
Expand Down
47 changes: 26 additions & 21 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -643,8 +643,8 @@ The following example pictures a Pumped Hydroelectric Energy Storage (PHES). Bot

solph.components.GenericStorage(
label='PHES',
inputs={b_el: solph.flows.Flow(investment= solph.Investment(ep_costs=500))},
outputs={b_el: solph.flows.Flow(investment= solph.Investment(ep_costs=500)},
inputs={b_el: solph.flows.Flow(nominal_value=solph.Investment(ep_costs=500))},
outputs={b_el: solph.flows.Flow(nominal_value=solph.Investment(ep_costs=500)},
loss_rate=0.001,
inflow_conversion_factor=0.98, outflow_conversion_factor=0.8),
investment = solph.Investment(ep_costs=40))
Expand Down Expand Up @@ -912,7 +912,7 @@ turbines.

solph.components.Source(label='new_wind_pp', outputs={electricity: solph.flows.Flow(
fix=wind_power_time_series,
investment=solph.Investment(ep_costs=epc, maximum=50000))})
nominal_value=solph.Investment(ep_costs=epc, maximum=50000))})

Let's slightly alter the case and consider for already existing wind power
capacity of 20,000 kW. We're still expecting the total wind power capacity, thus we
Expand All @@ -922,7 +922,7 @@ allow for 30,000 kW of new installations and formulate as follows.

solph.components.Source(label='new_wind_pp', outputs={electricity: solph.flows.Flow(
fix=wind_power_time_series,
investment=solph.Investment(ep_costs=epc,
nominal_value=solph.Investment(ep_costs=epc,
maximum=30000,
existing=20000))})

Expand Down Expand Up @@ -957,7 +957,7 @@ example of a converter:
label='converter_nonconvex',
inputs={bus_0: solph.flows.Flow()},
outputs={bus_1: solph.flows.Flow(
investment=solph.Investment(
nominal_value=solph.Investment(
ep_costs=4,
maximum=100,
minimum=20,
Expand Down Expand Up @@ -1004,8 +1004,8 @@ mathematical background, like variables and constraints, which are used.

.. _multi_period_mode_label:

Using the multi-period (investment) mode (experimental)
-------------------------------------------------------
Multi-period (investment) mode (experimental)
---------------------------------------------
Sometimes you might be interested in how energy systems could evolve in the longer-term, e.g. until 2045 or 2050 to meet some
carbon neutrality and climate protection or RES and energy efficiency targets.

Expand All @@ -1020,18 +1020,18 @@ only unfolds if you look at long-term investments. Let's see how.
First, you start by defining your energy system as you might have done before, but you

* choose a longer-term time horizon (spanning multiple years, i.e. multiple periods) and
* explicitly define the `periods` attribute of your energy system which maps time steps to the simulated period.
* explicitly define the `periods` attribute of your energy system which lists the time steps for each period.

.. code-block:: python

import pandas as pd
import oemof.solph as solph

my_index = pd.date_range('1/1/2013', periods=17520, freq='H')
periods = {
0: pd.date_range('1/1/2013', periods=8760, freq='H'),
1: pd.date_range('1/1/2014', periods=8760, freq='H'),
}
periods = [
pd.date_range('1/1/2013', periods=8760, freq='H'),
pd.date_range('1/1/2014', periods=8760, freq='H'),
]
my_energysystem = solph.EnergySystem(timeindex=my_index, periods=periods)

If you want to use a multi-period model you have define periods of your energy system explicitly. This way,
Expand All @@ -1057,17 +1057,16 @@ and adjust to your needs:

Returns
-------
periods : dict
pd.date_ranges defining the time stamps for the respective period,
starting with period 0
periods : list
periods for the optimization run
"""
years = sorted(list(set(getattr(datetimeindex, "year"))))
periods = {}
periods = []
filter_series = datetimeindex.to_series()
for number, year in enumerate(years):
start = filter_series.loc[filter_series.index.year == year].min()
end = filter_series.loc[filter_series.index.year == year].max()
periods[number] = pd.date_range(start, end, freq=datetimeindex.freq)
periods.append(pd.date_range(start, end, freq=datetimeindex.freq))

return periods

Expand Down Expand Up @@ -1144,7 +1143,7 @@ Here is an example
inputs={hydrogen_bus: solph.flows.Flow()},
outputs={
electricity_bus: solph.flows.Flow(
investment=solph.Investment(
nominal_value=solph.Investment(
maximum=1000,
ep_costs=1e6,
lifetime=30,
Expand Down Expand Up @@ -1178,7 +1177,7 @@ This would mean that for investments in the particular period, these values woul
inputs={hydrogen_bus: solph.flows.Flow()},
outputs={
electricity_bus: solph.flows.Flow(
investment=solph.Investment(
nominal_value=solph.Investment(
maximum=1000,
ep_costs=[1e6, 1.1e6],
lifetime=30,
Expand Down Expand Up @@ -1269,6 +1268,13 @@ Besides the `invest` variable, new variables are introduced as well. These are:
* You can specify periods of different lengths, but the frequency of your timeindex needs to be consistent. Also,
you could use the `timeincrement` attribute of the energy system to model different weightings. Be aware that this
has not yet been tested.
* For now, both, the `timeindex` as well as the `timeincrement` of an energy system have to be defined since they
have to be of the same length for a multi-period model.
* You can choose whether to re-evaluate assets at the end of the optimization horizon. If you set attribute
`use_remaining_value` of the energy system to True (defaults to False), this leads to the model evaluating the
difference in the asset value at the end of the optimization horizon vs. at the time the investment was made.
The difference in value is added to or subtracted from the respective investment costs increment,
assuming assets are to be liquidated / re-evaluated at the end of the optimization horizon.
* Also please be aware, that periods correspond to years by default. You could also choose
monthly periods, but you would need to be very careful in parameterizing your energy system and your model and also,
this would mean monthly discounting (if applicable) as well as specifying your plants lifetimes in months.
Expand Down Expand Up @@ -1466,12 +1472,11 @@ This nonlinearity is linearised in the
inputs={b_diesel: solph.flows.Flow()},
outputs={
b_el: solph.flows.Flow(
nominal_value=None,
variable_costs=0.04,
min=0.2,
max=1,
nonconvex=solph.NonConvex(),
investment=solph.Investment(
nominal_value=solph.Investment(
ep_costs=90,
maximum=150, # required for the linearization
),
Expand Down
4 changes: 2 additions & 2 deletions docs/whatsnew/v0-5-1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ New features

* Add option to run multi-period (dynamic) investment models with oemof.solph as an experimental feature:
* You can change from standard model to multi-period model by defining the newly introduced `periods`
attribute of your energy system. Be aware that it is experimental as of now. `periods` is a dictionary
mapping the periods you want to model (usually years) to pandas.date_range objects.
attribute of your energy system. Be aware that it is experimental as of now. `periods` is a list
of the periods you want to model (usually years) given as pandas.date_range objects.
* Add attributes `periods` to :class:`oemof.solph._energy_system.EnergySystem`.
* Introduce new Pyomo Sets `PERIODS` and `TIMEINDEX` in :class:`oemof.solph.models.Model`.
* Index all investment-related variables with `PERIODS` and flow variable with `TIMEINDEX`, which
Expand Down
14 changes: 14 additions & 0 deletions docs/whatsnew/v0-5-2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,25 @@ v0.5.2 (????)
API changes
###########

* New bool attribute `use_remaining_value` of `oemof.solph.EnergySystem`

New features
############

* Allow for evaluating differences in the remaining vs. the original value
for multi-period investments.

Documentation
#############

Bug fixes
#########

* Fix handling of investment annuities and fixed costs for multi-period models:
Limit to costs that occur within the optimization horizon to prevent a
bias towards investments happening earlier in the optimization horizon.
* Fix bugs in multi-period documentation.

Testing
#######

Expand All @@ -25,3 +35,7 @@ Contributors
############

* Patrik Schönfeldt
* Johannes Kochems
* Julian Endres
* Hendrik Huyskens
* Raul Ciria Aylagas
2 changes: 1 addition & 1 deletion examples/electrical/lopf.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def main():
input=b_el0,
output=b_el1,
reactance=0.0001,
investment=Investment(ep_costs=10),
nominal_value=Investment(ep_costs=10),
min=-1,
max=1,
)
Expand Down
4 changes: 2 additions & 2 deletions examples/electrical/transshipment.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ def main():
label="line_0",
inputs={b_0: Flow(), b_1: Flow()},
outputs={
b_1: Flow(investment=Investment()),
b_0: Flow(investment=Investment()),
b_1: Flow(nominal_value=Investment()),
b_0: Flow(nominal_value=Investment()),
},
conversion_factors={(b_0, b_1): 0.95, (b_1, b_0): 0.9},
)
Expand Down
8 changes: 3 additions & 5 deletions examples/generic_invest_limit/example_generic_invest.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@

.. literalinclude:: /../examples/generic_invest_limit/example_generic_invest.py
:language: python
:lines: 62-219
:lines: 62-

Installation requirements
-------------------------
Expand Down Expand Up @@ -141,8 +141,7 @@ def main():
inputs={bus_a_0: solph.Flow()},
outputs={
bus_a_1: solph.Flow(
nominal_value=None,
investment=solph.Investment(
nominal_value=solph.Investment(
ep_costs=epc_invest,
custom_attributes={"space": 2},
),
Expand All @@ -159,8 +158,7 @@ def main():
inputs={bus_b_0: solph.Flow()},
outputs={
bus_b_1: solph.Flow(
nominal_value=None,
investment=solph.Investment(
nominal_value=solph.Investment(
ep_costs=epc_invest,
custom_attributes={"space": 1},
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,7 @@ def main():
outputs={
b_el_dc: solph.flows.Flow(
fix=solar_potential / peak_solar_potential,
nominal_value=None,
investment=solph.Investment(
nominal_value=solph.Investment(
ep_costs=epc_pv * n_days / n_days_in_year
),
variable_costs=0,
Expand All @@ -157,11 +156,10 @@ def main():
inputs={b_diesel: solph.flows.Flow()},
outputs={
b_el_ac: solph.flows.Flow(
nominal_value=None,
variable_costs=variable_cost_diesel_genset,
min=min_load,
max=max_load,
investment=solph.Investment(
nominal_value=solph.Investment(
ep_costs=epc_diesel_genset * n_days / n_days_in_year,
maximum=2 * peak_demand,
),
Expand All @@ -177,8 +175,7 @@ def main():
label="rectifier",
inputs={
b_el_ac: solph.flows.Flow(
nominal_value=None,
investment=solph.Investment(
nominal_value=solph.Investment(
ep_costs=epc_rectifier * n_days / n_days_in_year
),
variable_costs=0,
Expand All @@ -196,8 +193,7 @@ def main():
label="inverter",
inputs={
b_el_dc: solph.flows.Flow(
nominal_value=None,
investment=solph.Investment(
nominal_value=solph.Investment(
ep_costs=epc_inverter * n_days / n_days_in_year
),
variable_costs=0,
Expand All @@ -213,13 +209,14 @@ def main():
epc_battery = 101.00 # currency/kWh/year
battery = solph.components.GenericStorage(
label="battery",
nominal_storage_capacity=None,
investment=solph.Investment(
nominal_storage_capacity=solph.Investment(
ep_costs=epc_battery * n_days / n_days_in_year
),
inputs={b_el_dc: solph.flows.Flow(variable_costs=0)},
outputs={
b_el_dc: solph.flows.Flow(investment=solph.Investment(ep_costs=0))
b_el_dc: solph.flows.Flow(
nominal_value=solph.Investment(ep_costs=0)
)
},
initial_storage_level=0.0,
min_storage_level=0.0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def heat_demand(d):
minimum_uptime=5,
initial_status=1,
),
investment=solph.Investment(
nominal_value=solph.Investment(
ep_costs=epc,
minimum=1.0,
maximum=10.0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def solar_thermal(d):
outputs={
b_heat: solph.flows.Flow(
fix=[solar_thermal(day) for day in range(0, periods)],
investment=solph.Investment(
nominal_value=solph.Investment(
ep_costs=epc, minimum=1.0, maximum=5.0
),
)
Expand Down
3 changes: 1 addition & 2 deletions examples/investment_with_minimal_invest/minimal_invest.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ def main():
inputs={bus_0: solph.Flow()},
outputs={
bus_1: solph.Flow(
nominal_value=None,
investment=solph.Investment(
nominal_value=solph.Investment(
ep_costs=c_var,
maximum=p_install_max,
minimum=p_install_min,
Expand Down
Loading