multi-vector-simulator icon indicating copy to clipboard operation
multi-vector-simulator copied to clipboard

Faulty error message when installedCap of an energyProduction asset equal to maximumCap

Open Piranias opened this issue 4 years ago • 11 comments

Hi, I wanted to set the installedCap to maxCap to make sure the maximum capacity is installed. Turns out that before checking if the installed capacity is smaller than the maxCap, the maxCap is multiplied with the peak of the (normalized) timeseries (i guess to calculate the "real" maxCap. See here: https://github.com/rl-institut/multi-vector-simulator/blob/fb55bc2f0083dc0510af9da3f2076fb029f19543/src/multi_vector_simulator/C0_data_processing.py#L1770

Should't this calculation happen after the installedCapacity is checked? Or how is the user supposed to precalculate the correct installedCapacity? How can I make sure that the maxCap is installed?

Piranias avatar Mar 10 '21 16:03 Piranias

You`re right, this is not very intuitive and there is also an error message popping up when the user does it wrong. So we should document this better. @SabineHaas do you still have an overview? I think you implemented it in #562, #498, so maybe you have an better idea of where we need to change what if any.

As a quick fix: Why try to use maximumCap when you want to install a very specific capacity? You could define it with installedCap then. If it is because you still want to include the installation costs @TheOneAndra has a fix for that (set age_installed to lifetime of the asset, we could also mention that in the RTD tips&tricks).

smartie2076 avatar Mar 11 '21 08:03 smartie2076

You`re right, this is not very intuitive and there is also an error message popping up when the user does it wrong. So we should document this better. @SabineHaas do you still have an overview? I think you implemented it in #562, #498, so maybe you have an better idea of where we need to change what if any.

I don't have an overview - I only added one check in #562, @Bachibouzouk implemented #498. But from the description in the docstring I understand that the order should be: 1) maximumCap < installedCap? if yes --> 2) adapt maximumCap But I am confused now, what the overall expectation was towards this function. @Bachibouzouk could you comment on that? How would you adapt the function?

As a quick fix: Why try to use maximumCap when you want to install a very specific capacity? You could define it with installedCap then. If it is because you still want to include the installation costs @TheOneAndra has a fix for that (set age_installed to lifetime of the asset, we could also mention that in the RTD tips&tricks).

oh nice! thanks for mentioning :)

SabineHaas avatar Mar 11 '21 14:03 SabineHaas

@Bachibouzouk implemented #498.

I think I merged the PR but I don't see a single commit I signed in it. I only added a warning message if the maximum cap was smaller than the installed cap

If it is wished to install "whatever the max cap is", I would make it an option of installed cap value in the settings installedCap: "max_cap" or something similar, this would make it more intuitive for the user and also easier to track and test (if the swap don't happen, the simulation will crash as a str for installedCap will not be accepted)

Bachibouzouk avatar Mar 12 '21 07:03 Bachibouzouk

But from the description in the docstring I understand that the order should be: 1) maximumCap < installedCap? if yes --> 2) adapt maximumCap But I am confused now, what the overall expectation was towards this function. @Bachibouzouk could you comment on that? How would you adapt the function?

This is true! We only have a problem here with the order of the checks and the preprocessing: For the check

1) maximumCap < installedCap? if yes --> 2) adapt maximumCap

We need to consider the capacities provided in the file. For oemof, though, we need to normalize the specific generation timeseries of our asset to [0,1] (not [0,0.9]) for the optimization - and it seems this adaptation needed for D is performed before the test is executed (so, you are right @Piranias).

I think what also happens is that the maximumCap is adapted due to normalization for the optimization - and installedCap is not (otherwise, the test would run though). I am not sure that this is correct: Wouldnt our normalized timeseries be multiplied with the exising capacity (installedCap`) and therefore be overestimated?

@Piranias I am not quite sure how you got to notice the bug (maybe the error message in the log), so I am not sure we are working towards a solution for you here :D

If it is wished to install "whatever the max cap is", I would make it an option of installed cap value in the settings installedCap: "max_cap" or something similar, this would make it more intuitive for the user and also easier to track and test (if the swap don't happen, the simulation will crash as a str for installedCap will not be accepted)

Then I dont see the sense in the optimization anymore - because we set intalledCap to a specific value. Why define it over maximumCap, an parameter defining the bounds of the optimization variable? I think the key here was (@SabineHaas @Piranias?), that costs for the installedCap were to be considered, eventhough in the MVS exisiting capacities are considered as sunk costs. In that case, I think it makes more sense to implement a setting, eg. in economic_values that says drop_sunk_costs and is True (MVS default, no costs considered) or False (include sunk costs of installed assets). I guess the parameter should not be applied to the asset level? Would someone want to consider the sunk costs of one asset but not the other?

smartie2076 avatar Mar 12 '21 08:03 smartie2076

I think I merged the PR but I don't see a single commit I signed in it. I only added a warning message if the maximum cap was smaller than the installed cap

Sorry @Bachibouzouk I was mistaken by your name in the PR and cause I cannot remember much about it.

We need to consider the capacities provided in the file. For oemof, though, we need to normalize the specific generation timeseries of our asset to [0,1] (not [0,0.9]) for the optimization - and it seems this adaptation needed for D is performed before the test is executed (so, you are right @Piranias).

I think what also happens is that the maximumCap is adapted due to normalization for the optimization - and installedCap is not (otherwise, the test would run though). I am not sure that this is correct: Wouldnt our normalized timeseries be multiplied with the exising capacity (installedCap`) and therefore be overestimated?

I agree with both of your statements: as @Piranias said we should change the order of operations: 1) check 2) adaption (in any case! here the docstring description is misleading) and installedCap should be adapted if the normalized timeseries are multiplied with it --> is this the case? If installedCap is adapted, would this have to be revoked after the optimization (as installedCap is included in results scalar_matrix)?

Then I dont see the sense in the optimization anymore - because we set intalledCap to a specific value. Why define it over maximumCap, an parameter defining the bounds of the optimization variable? I think the key here was (@SabineHaas @Piranias?), that costs for the installedCap were to be considered, eventhough in the MVS exisiting capacities are considered as sunk costs. In that case, I think it makes more sense to implement a setting, eg. in economic_values that says drop_sunk_costs and is True (MVS default, no costs considered) or False (include sunk costs of installed assets). I guess the parameter should not be applied to the asset level? Would someone want to consider the sunk costs of one asset but not the other?

I think I even prefer the workaround via lifetime of the asset, this way it's applicable for single assets which makes it more flexible without having to add an additional parameter (there are a lot of parameters already).

SabineHaas avatar Mar 12 '21 09:03 SabineHaas

You`re right, this is not very intuitive and there is also an error message popping up when the user does it wrong. So we should document this better. @SabineHaas do you still have an overview? I think you implemented it in #562, #498, so maybe you have an better idea of where we need to change what if any.

As a quick fix: Why try to use maximumCap when you want to install a very specific capacity? You could define it with installedCap then. If it is because you still want to include the installation costs @TheOneAndra has a fix for that (set age_installed to lifetime of the asset, we could also mention that in the RTD tips&tricks).

So if I see it right the bug only concerns the warning message. If I un-comment it everything works fine (the maximum capacity is installed and no more). (Of course this might not make sense for the optimization, but I need it as a reference scenario.)

I do not quite understand the fix of @TheOneAndra: If I set age_installed = 0, the upfront_investment_costs are still calculated and added to the total_PV_costs. If I set age_installed = lifetime, it's: total_costs = upfront_investment_costs + replacement_costs + om_costs.

So the way I see it the upfront_investment_costs are added anyways, independent of the age_installed. Why does Andra need this fix then?

Here's an example scalars output for a simulation with installedCap = maxCap and age_installed = 25. scalars_age_installed_25.xlsx

Piranias avatar Mar 15 '21 10:03 Piranias

Another point @smartie2076 mentioned is that installedCap might have to be adapted, as well. I tried to find out via the lp file what is happening with installedCap, but I do not understand the output - the pv plant is not mentioned at all in the lp file, not even die maximumCap which should be mentioned in section bounds I guess.

@smartie2076 could you check whether we have to adapt installedCap as you have suggested above?

My inputs (sorry only json - there seems to be a bug in my zipping tool): mvs_csv_config.txt mvs_config.txt

  • I adapted AB_grid_PV by: evaluated_period=0.25 (6 time steps), removed starting zeros in pv time series to have pv production, added some costs, maximumCap=1200 instead of 1000. (installedCap is 1000)

Results into lp_file.txt

SabineHaas avatar Mar 15 '21 11:03 SabineHaas

I need to add another comment on this. I noticed in further simulations that appearently the installedCap and the maximumCap is decoupled. Setting the installedCap = maximumCap does not prevent the system to optimize the additional capacity up to the maxCap. So setting both equal leads to a usage of up to douple the maxCap. One trick that seems to do it now is to set the installedCap = initial maxCap and maxCap = 1. (This way there is a boundary for the optimization, but just a very small one.)

So eventually I assume that the warning message about the installedCap having to be smaller than the maxCap is misleading or wrong. I'm not sure how this is supposed to work, I just wanted to add this in case you would expect a different behavior (like I did).

Piranias avatar Mar 16 '21 08:03 Piranias

I do not quite understand the fix of @TheOneAndra: If I set age_installed = 0, the upfront_investment_costs are still calculated and added to the total_PV_costs. If I set age_installed = lifetime, it's: total_costs = upfront_investment_costs + replacement_costs + om_costs.

So the way I see it the upfront_investment_costs are added anyways, independent of the age_installed. Why does Andra need this fix then?

This trick was used for when I wanted to optimize my system with a fix capacity of a certain asset and still count for installation costs. Therefore with: optimizeCap = False , installedCap = specific capacity and aged_installed = lifetime I could optimize my system with a specific cap of a certain asset and still account for installation costs of this asset at the first timestep (in the idea of a greenfield optimization).

The upfront_investment_costs (output) you mention are the development_costs (input) which are independant of how much of the asset is installed or how many times it is replaced. It is just a single costs applied once.

TheOneAndra avatar Mar 16 '21 14:03 TheOneAndra

Today with @smartie2076 we discussed parts of this issue including hotfixes and longterm fixes. I'll summarize here and add new issues.

  • A fast fix for this issue will be:
    • [x] test installedCap * time_series == time series in output in benchmark test AB_grid_pv (see PR #831) :x: if test fails: adapt nominal_value of components that use TIMESERIES_NORMALIZED to installedCap*dict_asset[TIMESERIES_PEAK][VALUE] in D1 functions (add comment why this is done). This adaption should be done in D1 and not in C0 (adapting dict_values) as for further calculations (e.g. economics) installedCap needs to stay the original
    • [x] I did a quick check on installedCap processing with optimizeCap=True, see information in PR #831
    • [x] change order of check (maximumCap > installedCap) and adaption of maximumCap in C0.process_maximum_cap_constraint(), to avoid wrong warning message reported by @Piranias. --> in PR #833
  • Long term solutions/issues
    • it would be better not to adapt maximumCap but to change maximum of components that use TIMESERIES_NORMALIZED in D1 functions instead. --> #830
    • we also realized that there's no benchmark test for proper use of maximumCap; this should be added. --> #830
    • as @Piranias has stated: the check in C0 and the actual usage of maximumCap in D1 are differing --> a decision has to be taken whether installedCap and maximumCap should be decoupled or not, then either the check or the usage has to be adapted. --> #829
  • To use @TheOneAndra's workaround, one needs to set optimizedCap to False, which he already stated above. It would be nice to describe the workaround in RTD --> #828 Also handy: like this you do not have the insecurity of installedCap maybe being wrong (see above), as a component with fix capacity uses the original timeseries (TIMESERIES) (see e.g. source_non_dispatchable_fix().

SabineHaas avatar Mar 16 '21 15:03 SabineHaas

PR #824 will need to be adapted depending on how this solution is resolved. See comment for reference.

ciaradunks avatar Mar 23 '21 13:03 ciaradunks