Faulty error message when installedCap of an energyProduction asset equal to maximumCap
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?
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).
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
maximumCapwhen you want to install a very specific capacity? You could define it withinstalledCapthen. If it is because you still want to include the installation costs @TheOneAndra has a fix for that (setage_installedtolifetimeof the asset, we could also mention that in the RTD tips&tricks).
oh nice! thanks for mentioning :)
@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)
But from the description in the docstring I understand that the order should be:
1) maximumCap < installedCap? if yes --> 2) adapt maximumCapBut 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?
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 forDis performed before the test is executed (so, you are right @Piranias).I think what also happens is that the
maximumCapis adapted due to normalization for the optimization - andinstalledCapis 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
intalledCapto a specific value. Why define it overmaximumCap, an parameter defining the bounds of the optimization variable? I think the key here was (@SabineHaas @Piranias?), that costs for theinstalledCapwere 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. ineconomic_valuesthat saysdrop_sunk_costsand isTrue(MVS default, no costs considered) orFalse(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).
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
maximumCapwhen you want to install a very specific capacity? You could define it withinstalledCapthen. If it is because you still want to include the installation costs @TheOneAndra has a fix for that (setage_installedtolifetimeof 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
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_PVby:evaluated_period=0.25(6 time steps), removed starting zeros in pv time series to have pv production, added some costs,maximumCap=1200instead of 1000. (installedCap is 1000)
Results into lp_file.txt
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).
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.
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 outputin benchmark test AB_grid_pv (see PR #831) :x: if test fails: adaptnominal_valueof components that useTIMESERIES_NORMALIZEDtoinstalledCap*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 (adaptingdict_values) as for further calculations (e.g. economics)installedCapneeds to stay the original - [x] I did a quick check on
installedCapprocessing 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
- [x] test
- Long term solutions/issues
- it would be better not to adapt
maximumCapbut to changemaximumof components that useTIMESERIES_NORMALIZEDin 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
maximumCapin D1 are differing --> a decision has to be taken whetherinstalledCapandmaximumCapshould be decoupled or not, then either the check or the usage has to be adapted. --> #829
- it would be better not to adapt
- To use @TheOneAndra's workaround, one needs to set
optimizedCapto 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 ofinstalledCapmaybe being wrong (see above), as a component with fix capacity uses the original timeseries (TIMESERIES) (see e.g.source_non_dispatchable_fix().
PR #824 will need to be adapted depending on how this solution is resolved. See comment for reference.