Multi-year sell-price in ProFAST NPV#799
Conversation
vijay092
left a comment
There was a problem hiding this comment.
Thank you so much, Elenya!! This looks great to me! I had some minor comments about inflation rate.
|
|
||
| if isinstance(self.commodity_sell_price, float | int): | ||
| if self.commodity_sell_price is None: | ||
| raise ValueError("commodity_sell_price is missing as an input") |
There was a problem hiding this comment.
None is neither a float nor an int so if the self.commodity_sell_price is actually None, it won't enter the previous condition.
There was a problem hiding this comment.
Also worth adding as a test
There was a problem hiding this comment.
good catch! thank you!
There was a problem hiding this comment.
I fixed the logic and added in a test for it test_profast_npv_missing_sell_price
| "finance_parameters": {"model_inputs": profast_inputs_no2}, | ||
| } | ||
| pf = ProFastNPV( | ||
| driver_config={}, |
There was a problem hiding this comment.
Both test fixtures use inflation_rate: 0.0. Can you add a case with nonzero inflation to confirm the per-year array isn't getting escalated a second time by ProFAST's own calculation? If users are meant to supply already-nominal per-year prices, we may need to force infation_rate = 0 when an array is passed.
There was a problem hiding this comment.
Also, could we clarify in the docs whether commodity_sell_price should be real or nominal dollars? Per our discussion with @jaredthomas68, we need to set nominal prices with inflation_rate = 0 (since ProFAST would otherwise apply its own escalation on top). Worth spelling that out explicitly.
There was a problem hiding this comment.
Can you add a case with nonzero inflation to confirm the per-year array isn't getting escalated a second time by ProFAST's own calculation
I played around with ProFAST using a 2% inflation rate and have some info in case its useful:
pf.cash_flow(price=0.07)andpf.cash_flow(price=[0.7]*30)result in the same NPV- The NPV with an inflation rate of 2% is about 2.2x the NPV with 0 inflation (both using a sell price of 0.7)
I think ProFAST does escalate the sell price, it basically does this:
analysis_length = plant_life + (installation_period_months/12)
analysis_years = np.arange(0, analysis_length + 1)
sales_price = commodity_sell_price*(1.0+inflation)**(analysis_years-1)
revenue_from_sales = sales_price*annual_productionAka - the commodity sell price should provided
- in non-escalated dollars (I think this means real - if I'm interpreting Jared's helpful doc page properly)
- in the same cost year as set in
plant_config["finance_parameters"]["cost_adjustment_parameters"]["target_dollar_year"](the commodity_sell_price does not go through AdjustedCapexOpexComp)
I would be happy to update the docs! @jaredthomas68 - can you confirm that the commodity_sell_price should be input in real dollars?
There was a problem hiding this comment.
Can yall (@vijay092 and @jaredthomas68) tell me whether this is True or false:
- if using an inflation rate of 0 in ProFAST, then the commodity sell price should be provided in nominal dollars?
- if using a nonzero inflation rate in ProFAST, then the commodity sell price should be provided in real dollars since ProFAST will escalate the price?
Can y'all look at the test h2integrate/finances/test/test_profast_npv.py::test_profast_npv_with_inflation and let me know what y'all think?
| def setup(self): | ||
| """Set up inputs for the NPV calculation. | ||
|
|
||
| Retrieves the commodity sell price and its units from the plant configuration |
There was a problem hiding this comment.
Could we add here that commodity_sell_price could be an array?
|
|
||
| super().setup() | ||
|
|
||
| if isinstance(self.commodity_sell_price, float | int): |
There was a problem hiding this comment.
Nit: Good to check for an edge case when use user passes in [x] (a single element list).
There was a problem hiding this comment.
Clarifying question: do you think it should be OK if a user passes in a single-element list? So - if it's a list of length 1 then don't throw an error?
There was a problem hiding this comment.
I think it is ok to pass a list of length one. We can use the first element!
There was a problem hiding this comment.
understood! I think I'm torn on this. I see how it can be more user-friendly but I think that it maybe complicates the "checking" logic in a way that may make the "checking" code slightly harder to understand. If other folks have opinions on this - would love some additional thoughts (@johnjasa, @jaredthomas68)
Multi-year sell-price in ProFAST NPV
Updated
ProFastNPVso that the commodity sell price input is the same length as the plant life. This enables users to be able to set a sell price for the NPV calculation that is different per year.Shoutout to @vijay092 for bringing this up!
Question/Note: until PR #774 is merged, this change would prevent someone from being able to connect a single value to the sell price input (such as
[finance_subgroup_electricity,finance_subgroup_electricity_NPV,LCOE, .commodity_sell_price_electricity]). If we want to support this type of connection before #774 is merged in, then I could change the logic (it will be not as clean) so that the sell-price can be input with either a shape of 1 or a shape equal to the plant life. Please let me know whether the handling to enable this type of connection would be valuable in this PR, or if that doesn't need to be included here because it'll be easily enabled with PR #774.Section 1: Type of Contribution
Section 2: Draft PR Checklist
TODO:
Type of Reviewer Feedback Requested (on Draft PR)
Structural feedback:
see section 1
Implementation feedback:
Other feedback:
Section 3: General PR Checklist
docs/files are up-to-date, or added when necessaryCHANGELOG.md"A complete thought. [PR XYZ]((https://github.com/NatLabRockies/H2Integrate/pull/XYZ)", where
XYZshould be replaced with the actual number.Section 4: Related Issues
Section 5: Impacted Areas of the Software
Section 5.1: New Files
N/A
Section 5.2: Modified Files
h2integrate/finances/profast_npv.pyProFastNPV.setup(): made the length of the commodity sell price input equal to plant life. Also added more error messages when checking the commodity sell price input.ProFastNPV.compute(): added padding to the price profile input so that its the proper length for the profastcash_flowcalculationh2integrate/finances/test/test_profast_npv.py: added two tests:test_profast_npv_multi_year_sell_price: tests that NPV is output as expected if a list of sell prices are inputtest_profast_npv_multi_year_error: tests that an error is thrown if sell price is the wrong lengthSection 6: Additional Supporting Information
Section 7: Test Results, if applicable