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

No investment optimization of stratified thermal storage without non-zero investment.minimum possible #174

Open
MaGering opened this issue Jan 7, 2021 · 5 comments

Comments

@MaGering
Copy link
Contributor

MaGering commented Jan 7, 2021

I recently discovered working on a simulation of a sector-coupled energy system with a stratified thermal storage in pvcompare, that it is not possible to run an investment optimization without passing a non-zero value either with investment.existing (installed capacity) or investment.minimum (minimal capacity). I would like to do an investment optimization in which it is possible to not invest into a stratified thermal storage at all in case it is too expansive and hence to model the storage for example like this:

thermal_storage = GenericStorage(
    label='thermal_storage',
    inputs={bus_heat: Flow(
        investment=Investment(ep_costs=50))},
    outputs={bus_heat: Flow(
        investment=Investment(),
        variable_costs=0.0001)},
    min_storage_level=input_data['min_storage_level'],
    max_storage_level=input_data['max_storage_level'],
    loss_rate=loss_rate,
    fixed_losses_relative=fixed_losses_relative,
    fixed_losses_absolute=fixed_losses_absolute,
    inflow_conversion_factor=input_data['inflow_conversion_factor'],
    outflow_conversion_factor=input_data['outflow_conversion_factor'],
    invest_relation_input_output=1,
    investment=Investment(ep_costs=400, minimum=0, existing=0)

The reason I have to pass a non-zero value either with investment.existing or investment.minimum is this e3 RaiseAttributeError in oemof.solph's components.py. Talking about it to @jnnr, he explained to me that the parameter fixed_losses_absolute is not dependent on the storage's capacity and hence enter the energysystem even if no storage is installed (in case it is too expensive). This I could validate with the simulations in pvcompare developed in this PR.
The idea behind the e3 RaiseAttributeError, he further explained, is to avoid fixed_losses_absolute in case of a too expensive stratified thermal storage, which were incorrectly passed to the energysystem by forcing the user to install the storage. However, so far I couldn't find a reference value or an explanation how to choose investment.existing or investment.minimum in this case. I also wonder if the value of minimum=1 does not cause a larger error than with minimum=0.

An other observation, I have made, is that the e3 RaiseAttributeError seems not to work if a float is passed. The passed data of fixed_losses_relative and fixed_losses_absolute require a time series so that e3 RaiseAttributeError takes effect. You can observe this running the oemof.thermal examples 03_investment_fixed_ratio_generic_storage.py and 05_investment_independent_generic_storage.py if you delete minimum=1. Passing a time series however with fixed_losses_relative and fixed_losses_absolute leads to e3 RaiseAttributeError.

The two parameters fixed_losses_relative and fixed_losses_absolute were implemented in oemof.solph with this PR

Related PRs are:
greco-project/pvcompare#148
rl-institut/multi-vector-simulator#718

@MaGering
Copy link
Contributor Author

MaGering commented Jan 7, 2021

@oemof-developer, anyone want to take on this exciting challenge? :)
Perhaps you'll find a way to intercept fixed_losses_absolute before building the energysystem in the case described above.

@p-snft
Copy link
Member

p-snft commented Jan 12, 2021

The problem is as follows: fixed_losses_absolute models losses through the top and bottom side of a storage. In a stratified storage, these are independent from the energy currently stored. (Thus, they are "fixed" losses.) However, this type of losses does not make any sense at all if there is no storage. So, it makes sense to not allow for the desired combination of settings.

The only solution would be to introduce a binary variable: This way, the losses can be considered only if the storage has a non-zero size.

@MaGering
Copy link
Contributor Author

The only solution would be to introduce a binary variable: This way, the losses can be considered only if the storage has a non-zero size.

Thank you for your answer and the explanation, @p-snft! This is also what @jnnr mentioned as a solution. Unfortunately I couldn't figure out where I should place this binary variable and decided also due to time constraints to work with investment.minimum instead. I'll leave this issue open however. Maybe someone will like to implement a solution someday. :)

@joroeder
Copy link
Member

The binary investment variable should be already there, if you set nonconvex=True in the solph option Investment, which creates an nonconvex investment storage (namly here ;)). You could check the heatpipeline component, I made for the DHNx optimisation part. Please see the following constraint: https://github.com/oemof/DHNx/blob/d17df4c124b85676e2984e2726954cccf013ad3f/dhnx/optimization_oemof_heatpipe.py#L355 - I think such a constraint must be added to the investment storage. - Maybe that helps for now :)

If you apply the investment.minimum, the optimisation does not decide on if there should be a storage. But if you want to build a storage anyway, that's fine, and your problem will also remain convex :)

@MaGering
Copy link
Contributor Author

The binary investment variable should be already there, if you set nonconvex=True in the solph option Investment, which creates an nonconvex investment storage (namly here ;)). You could check the heatpipeline component, I made for the DHNx optimisation part. Please see the following constraint: https://github.com/oemof/DHNx/blob/d17df4c124b85676e2984e2726954cccf013ad3f/dhnx/optimization_oemof_heatpipe.py#L355 - I think such a constraint must be added to the investment storage. - Maybe that helps for now :)

If you apply the investment.minimum, the optimisation does not decide on if there should be a storage. But if you want to build a storage anyway, that's fine, and your problem will also remain convex :)

Thanks for your answer, @joroeder! Oh wow, I was not aware of nonconvex so far and I'm afraid I still don't quite understand what exactly it does. Do I also need to set investment.offset in addition to the minimum and nonconvex parameters? I have read about this in Investment's docstring...

So, did you had something like this in mind in regard to my problem?

investment=Investment(ep_costs=400, minimum=1, maximum=50000, nonconvex=True, offset=1)

The good news is, my simulation runs through with this adjustment. The bad news is, the invested capacity of the storage is still not equal to zero (but much smaller than the result without nonconvex=True and offset=1) in case of a too expansive storage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants