oemof / oemof-solph

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

Multi-period investment optmization: no investment in first period #1029

Open SabineHaas opened 10 months ago

SabineHaas commented 10 months ago

Describe the bug Multi-period investment optimization does not solve as expected. There's no investment into wind and storage in the first period, while the expensive shortage is used to cover the demand. In the second period investment is done as expected into wind and storage, no shortage is used.

Checkout my small example: multi_period.txt

Energy system consists of: el-bus, wind source, el-demand, el-storage, excess, shortage

Also interesting: in the example I run the optimization twice:

  1. wind profile (fix) = [1, 0, 0] --> the result is as described above:
    • only in the second period there's investment into wind and storage
    • in the first period the expensive shortage is being used
  2. wind profile (fix) = [0, 1, 0] --> result as I would expect it: in first and second period investment into wind and storage and no usage of shortage

To Reproduce Rund the example code, multi_period.txt

Expected behavior Investment into wind and storage also in the first period and avoidance of expensive shortage (as in case 2, wind profile = [0, 1, 0]).

Screenshots Results:

1. wind time series [1, 0, 0]:
wind
variable_name  invest  old  old_end  old_exo  total
period                                             
2020              0.0  0.0      0.0      0.0    0.0
2030            250.0  0.0      0.0      0.0  250.0

 storage
variable_name  invest  old  old_end  old_exo   total
period                                              
2020              0.0  0.0      0.0      0.0     0.0
2030           1500.0  0.0      0.0      0.0  1500.0

 shortage total usage: 
200.0
2. wind time series [0, 1, 0]:
wind
variable_name  invest    old  old_end  old_exo  total
period                                               
2020            225.0    0.0      0.0      0.0  225.0
2030            225.0  225.0    225.0      0.0  225.0

 storage
variable_name  invest    old  old_end  old_exo  total
period                                               
2020            750.0    0.0      0.0      0.0  750.0
2030            750.0  750.0    750.0      0.0  750.0

 shortage total usage: 
0.0

Desktop (please complete the following information):


@jokochems do you know this behaviour?

This might be interesting for you, @nailend

jokochems commented 10 months ago

Ouch, that's quite bad, I have to admit. Thanks for pointing this out, @SabineHaas!

I haven't come across this issue, yet, as I have been working with brownfield scenarios, mostly.

I am pretty sure that it relates to the multi-period storage implementation and the definition of the 0th storage state, to be more precise, this code section.

My idea here was to force storage levels to equal 0 until an investment happens. But what the rule effectively does is to prevent storage investments for the 0th (i.e. the very first TIMESTEP).

I commented out the lines mentioned above and the optimization yielded results as you'd have expected them, i.e. no shortage is activated and investment results for both cases are identical.

I haven't given it enough thought yet, but my gut feeling is that the respective rule might be safely removed.

@nailend: Would you second that opinion of mine?

nailend commented 9 months ago

I tried to wrap my head around, but I didn't really understand why this constraint doesn't work. But this is a direct consequence of #1030 isn't it? In multi-period, the distinction between TIMESTEPS and TIMEPOINTS don't exist?

jokochems commented 9 months ago

I tried to wrap my head around, but I didn't really understand why this constraint doesn't work. But this is a direct consequence of #1030 isn't it? In multi-period, the distinction between TIMESTEPS and TIMEPOINTS don't exist?

Yes, you are right. The two issues are interrelated and there only is the TIMESTEPS set for multi-period models.

As I see it, there would be three options:

  1. Simply remove the constraint. This would allow to freely choose a storage level. You'd have to think about whether this might create the model artefact of filling a storage for free, though ...
  2. Adjust the constraint to recreate the behabiour of the previous solph version.
  3. Align with the current version of solph.

I think option 3 is clearly preferrable. In that course, also the investment storage implementation in general should be revised, see #1030.

p-snft commented 9 months ago

Simply remove the constraint. This would allow to freely choose a storage level. You'd have to think about whether this might create the model artefact of filling a storage for free, though ...

In fact, the assumption that a newly installed storage is always empty is not valid in all cases. Think of rechargeable batteries: If receive them at 0 % capacity, they are probably broken.

jokochems commented 9 months ago

Thanks, @p-snft. You are totally right about this. I also thought about pumped storage which will probably come with some filling level initially.

@nailend and @SabineHaas: Look what I found: https://github.com/oemof/oemof-solph/pull/965 The constraint was not always there. I added it as sort of a hotfix after I have been informed by a user facing trouble with storages that were initially filled "for free".

@nailend I also had some trouble with proper storage roundtrip conditions (there actually are none yet), but that was before your sophisticated lifetime tracking thing. It might be worth a shot tackling this as well - maybe in a dedicated issue/PR.

nailend commented 9 months ago

Thanks, @p-snft. You are totally right about this. I also thought about pumped storage which will probably come with some filling level initially.

Not sure, what's the better solution to be honest, but I prefer to set the initial content per component.

Look what I found: #965

well I confirmed, haha

@nailend I also had some trouble with proper storage roundtrip conditions (there actually are none yet), but that was before your sophisticated lifetime tracking thing. It might be worth a shot tackling this as well - maybe in a dedicated issue/PR.

you mean roundtrips within a period?

At the dev-meeting, we shared the common interest to somehow replace single-period with multi-period. For this to happen, there are a few things to be done before. I will open an issue, where we can collect the necessary changes/improvements.