oemof / oemof-solph

A model generator for energy system modelling and optimisation (LP/MILP).
https://oemof.org
MIT License
302 stars 132 forks source link

Parameter 'balanced' is neglected for GenericInvestmentStorageBlock #1129

Open bdietermann opened 1 month ago

bdietermann commented 1 month ago

For GenericInvestmentStorageBlock the parameter balanced has no effect and the behavior is always what you would expect to observe for balanced=False.

To reproduce this behavior run the following code where a system with

is specified.

All storages are emptied using a loss rate and can be refilled by a source. The expected behavior is, that balanced storages are refilled while unbalanced storages are not to minimize the system's costs. As you can see this behavior differs for the invest balanced storage (Storage 4), showing that the parameter balanced is neglected here.

import pandas as pd
import oemof.solph as solph

# --------- Description -------------------
# In oemof-solph v.0.6.0a2 the balanced parameter is neglected for GenericInvestmentStorageBlocks.
# To demonstrate this, four storages with different settings are created.

es = solph.EnergySystem(timeindex=pd.date_range('1/1/2017', periods=4, freq='15min'), infer_last_interval=True)
bus = solph.Bus(label='bus')
es.add(bus)
storage_size = 3000

source = solph.components.Source(label='source',
                                 outputs={bus: solph.Flow(variable_costs=1)})
es.add(source)

storage1 = solph.components.GenericStorage(label='storage1',
                                           inputs={bus: solph.Flow()},
                                           outputs={bus: solph.Flow(nominal_value=1,
                                                                    max=0)},
                                           loss_rate=0.001,
                                           balanced=False,
                                           initial_storage_level=0.5,
                                           nominal_storage_capacity=storage_size)
es.add(storage1)

storage2 = solph.components.GenericStorage(label='storage2',
                                           inputs={bus: solph.Flow()},
                                           outputs={bus: solph.Flow(nominal_value=1,
                                                                    max=0)},
                                           loss_rate=0.001,
                                           balanced=True,
                                           initial_storage_level=0.5,
                                           nominal_storage_capacity=storage_size)
es.add(storage2)

storage3 = solph.components.GenericStorage(label='storage3',
                                           inputs={bus: solph.Flow()},
                                           outputs={bus: solph.Flow(nominal_value=1,
                                                                    max=0)},
                                           loss_rate=0.001,
                                           balanced=False,
                                           initial_storage_level=0.5,
                                           nominal_storage_capacity=solph.Investment(ep_costs=1,
                                                                                     existing=storage_size,
                                                                                     maximum=0)
                                           )
es.add(storage3)

storage4 = solph.components.GenericStorage(label='storage4',
                                           inputs={bus: solph.Flow()},
                                           outputs={bus: solph.Flow(nominal_value=1,
                                                                    max=0)},
                                           loss_rate=0.001,
                                           balanced=True,
                                           initial_storage_level=0.5,
                                           nominal_storage_capacity=solph.Investment(ep_costs=1,
                                                                                     existing=storage_size,
                                                                                     maximum=0)
                                           )
es.add(storage4)

om = solph.Model(energysystem=es)
om.solve(solver='gurobi', solve_kwargs={'tee': False})
results = solph.processing.results(om)

soc = pd.DataFrame()
for idx in range(4):
    soc[f'Storage {idx + 1}'] = solph.views.node(results, f'storage{idx + 1}')['sequences'][
                            ((f'storage{idx + 1}', 'None'), 'storage_content')] / storage_size
print(soc)

print('Storage 1:\tnon-invest,\tbalanced=False')
print('Storage 2:\tnon-invest,\tbalanced=True')
print('Storage 3:\tinvest,\t\tbalanced=False')
print('Storage 4:\tinvest,\t\tbalanced=True')

Console output:

                     Storage 1  Storage 2  Storage 3  Storage 4
2017-01-01 00:00:00   0.500000   0.500000   0.500000   0.500000
2017-01-01 00:15:00   0.499875   0.499875   0.499875   0.499875
2017-01-01 00:30:00   0.499750   0.499750   0.499750   0.499750
2017-01-01 00:45:00   0.499625   0.499625   0.499625   0.499625
2017-01-01 01:00:00   0.499500   0.500000   0.499500   0.499500
Storage 1:  non-invest, balanced=False
Storage 2:  non-invest, balanced=True
Storage 3:  invest,     balanced=False
Storage 4:  invest,     balanced=True
bdietermann commented 1 month ago

Forgot to mention: the behavior was observed in v0.6.0a2