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

Account for remaining values in multi-period models #982

Merged
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
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
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
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
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
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
088a35f
Merge pull request #997 from oemof/feature/remaining-value
jokochems 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
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
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
5 changes: 5 additions & 0 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,11 @@ Besides the `invest` variable, new variables are introduced as well. These are:
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.
jokochems marked this conversation as resolved.
Show resolved Hide resolved
* 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
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
68 changes: 51 additions & 17 deletions src/oemof/solph/_energy_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ class EnergySystem(es.EnergySystem):
For a standard model, periods are not (to be) declared, i.e. None.
A list with one entry is derived, i.e. [0].

use_remaining_value : bool
If True, compare the remaining value of an investment to the
original value (only applicable for multi-period models)

kwargs
"""

Expand All @@ -71,6 +75,7 @@ def __init__(
timeincrement=None,
infer_last_interval=None,
periods=None,
use_remaining_value=False,
**kwargs,
):
# Doing imports at runtime is generally frowned upon, but should work
Expand Down Expand Up @@ -160,7 +165,8 @@ def __init__(
timeindex=timeindex, timeincrement=timeincrement, **kwargs
)

if periods is not None:
self.periods = periods
if self.periods is not None:
msg = (
"CAUTION! You specified the 'periods' attribute for your "
"energy system.\n This will lead to creating "
Expand All @@ -171,9 +177,10 @@ def __init__(
"please report them."
)
warnings.warn(msg, debugging.SuspiciousUsageWarning)
self.periods = periods
self._extract_periods_years()
self._extract_periods_matrix()
self._extract_periods_years()
self._extract_periods_matrix()
self._extract_end_year_of_optimization()
self.use_remaining_value = use_remaining_value

def _extract_periods_years(self):
"""Map years in optimization to respective period based on time indices
Expand All @@ -183,13 +190,12 @@ def _extract_periods_years(self):
start of the optimization run and starting with 0.
"""
periods_years = [0]
if self.periods is not None:
start_year = self.periods[0].min().year
for k, v in enumerate(self.periods):
if k >= 1:
periods_years.append(v.min().year - start_year)
start_year = self.periods[0].min().year
for k, v in enumerate(self.periods):
if k >= 1:
periods_years.append(v.min().year - start_year)

self.periods_years = periods_years
self.periods_years = periods_years

def _extract_periods_matrix(self):
"""Determines a matrix describing the temporal distance to each period.
Expand All @@ -200,13 +206,41 @@ def _extract_periods_matrix(self):
between each investment period to each decommissioning period.
"""
periods_matrix = []
if self.periods is not None:
period_years = np.array(self.periods_years)
for v in period_years:
row = period_years - v
row = np.where(row < 0, 0, row)
periods_matrix.append(row)
self.periods_matrix = np.array(periods_matrix)
period_years = np.array(self.periods_years)
for v in period_years:
row = period_years - v
row = np.where(row < 0, 0, row)
periods_matrix.append(row)
self.periods_matrix = np.array(periods_matrix)

def _extract_end_year_of_optimization(self):
"""Extract the end of the optimization in years

Attribute `end_year_of_optimization` of int is set.
"""
duration_last_period = self.get_period_duration(-1)
self.end_year_of_optimization = (
self.periods_years[-1] + duration_last_period
)

def get_period_duration(self, period):
"""Get duration of a period in full years

Parameters
----------
period : int
Period for which the duration in years shall be obtained

Returns
-------
int
Duration of the period
"""
return (
self.periods[period].max().year
- self.periods[period].min().year
+ 1
)


def create_time_index(
Expand Down
Loading
Loading