@@ -968,7 +968,7 @@ def __init__(self, model: Model):
968
968
)
969
969
970
970
self .royalty_rate = self .ParameterDict [self .royalty_rate .Name ] = floatParameter (
971
- " Royalty Rate" ,
971
+ ' Royalty Rate' ,
972
972
DefaultValue = 0. ,
973
973
Min = 0.0 ,
974
974
Max = 1.0 ,
@@ -978,6 +978,18 @@ def __init__(self, model: Model):
978
978
ToolTipText = "Royalty rate used in SAM Economic Models." # FIXME WIP TODO documentation
979
979
)
980
980
981
+ self .royalty_holder_discount_rate = self .ParameterDict [self .royalty_holder_discount_rate .Name ] = floatParameter (
982
+ 'Royalty Holder Discount Rate' ,
983
+ DefaultValue = 0.05 ,
984
+ Min = 0.0 ,
985
+ Max = 1.0 ,
986
+ UnitType = Units .PERCENT ,
987
+ PreferredUnits = PercentUnit .TENTH ,
988
+ CurrentUnits = PercentUnit .TENTH ,
989
+ ToolTipText = "Royalty holder discount rate used in SAM Economic Models." # FIXME WIP TODO documentation
990
+ )
991
+
992
+
981
993
self .discount_initial_year_cashflow = self .ParameterDict [self .discount_initial_year_cashflow .Name ] = boolParameter (
982
994
'Discount Initial Year Cashflow' ,
983
995
DefaultValue = False ,
@@ -2134,6 +2146,33 @@ def __init__(self, model: Model):
2134
2146
UnitType = Units .NONE ,
2135
2147
)
2136
2148
2149
+ # Results for the Royalty Holder
2150
+ self .royalty_holder_npv = self .OutputParameterDict [self .royalty_holder_npv .Name ] = OutputParameter (
2151
+ 'Royalty Holder NPV' ,
2152
+ UnitType = Units .CURRENCY ,
2153
+ PreferredUnits = CurrencyUnit .MDOLLARS ,
2154
+ CurrentUnits = CurrencyUnit .MDOLLARS ,
2155
+ ToolTipText = "Net Present Value (NPV) of the royalty holder's cash flow stream."
2156
+ )
2157
+ self .royalty_holder_annual_revenue = self .OutputParameterDict [
2158
+ self .royalty_holder_annual_revenue .Name
2159
+ ] = OutputParameter (
2160
+ 'Royalty Holder Annual Revenue' ,
2161
+ UnitType = Units .CURRENCYFREQUENCY ,
2162
+ PreferredUnits = CurrencyFrequencyUnit .MDOLLARSPERYEAR ,
2163
+ CurrentUnits = CurrencyFrequencyUnit .MDOLLARSPERYEAR ,
2164
+ ToolTipText = "The royalty holder's annual revenue stream from the royalty agreement."
2165
+ )
2166
+ self .royalty_holder_total_revenue = self .OutputParameterDict [
2167
+ self .royalty_holder_total_revenue .Name
2168
+ ] = OutputParameter (
2169
+ 'Royalty Holder Total Revenue' ,
2170
+ UnitType = Units .CURRENCY ,
2171
+ PreferredUnits = CurrencyUnit .MDOLLARS ,
2172
+ CurrentUnits = CurrencyUnit .MDOLLARS ,
2173
+ ToolTipText = 'The total (undiscounted) revenue received by the royalty holder over the project lifetime.'
2174
+ )
2175
+
2137
2176
model .logger .info (f'Complete { __class__ !s} : { sys ._getframe ().f_code .co_name } ' )
2138
2177
2139
2178
def read_parameters (self , model : Model ) -> None :
@@ -2504,38 +2543,8 @@ def Calculate(self, model: Model) -> None:
2504
2543
self .discount_initial_year_cashflow .value
2505
2544
)
2506
2545
2507
- non_calculated_output_placeholder_val = - 1
2508
2546
if self .econmodel .value == EconomicModel .SAM_SINGLE_OWNER_PPA :
2509
- self .sam_economics_calculations = calculate_sam_economics (model )
2510
-
2511
- # Setting capex_total distinguishes capex from CCap's display name of 'Total capital costs',
2512
- # since SAM Economic Model doesn't subtract ITC from this value.
2513
- self .capex_total .value = (self .sam_economics_calculations .capex .quantity ()
2514
- .to (self .capex_total .CurrentUnits .value ).magnitude )
2515
- self .CCap .value = (self .sam_economics_calculations .capex .quantity ()
2516
- .to (self .CCap .CurrentUnits .value ).magnitude )
2517
-
2518
- average_annual_royalties = np .average (
2519
- self .sam_economics_calculations .royalties_opex .value [1 :] # ignore pre-revenue year(s) (Year 0)
2520
- )
2521
- if average_annual_royalties > 0 :
2522
- self .royalties_average_annual_cost .value = average_annual_royalties
2523
- self .Coam .value += self .royalties_average_annual_cost .quantity ().to (self .Coam .CurrentUnits .value ).magnitude
2524
-
2525
- self .wacc .value = self .sam_economics_calculations .wacc .value
2526
- self .nominal_discount_rate .value = self .sam_economics_calculations .nominal_discount_rate .value
2527
- self .ProjectNPV .value = self .sam_economics_calculations .project_npv .quantity ().to (
2528
- convertible_unit (self .ProjectNPV .CurrentUnits )).magnitude
2529
-
2530
- self .ProjectIRR .value = non_calculated_output_placeholder_val # SAM calculates After-Tax IRR instead
2531
- self .after_tax_irr .value = self .sam_economics_calculations .after_tax_irr .quantity ().to (
2532
- convertible_unit (self .ProjectIRR .CurrentUnits )).magnitude
2533
-
2534
- self .ProjectMOIC .value = self .sam_economics_calculations .moic .value
2535
- self .ProjectVIR .value = self .sam_economics_calculations .project_vir .value
2536
-
2537
- # TODO remove or clarify project payback period: https://github.com/NREL/GEOPHIRES-X/issues/413
2538
- self .ProjectPaybackPeriod .value = self .sam_economics_calculations .project_payback_period .value
2547
+ self ._calculate_sam_economics (model )
2539
2548
2540
2549
# Calculate the project payback period
2541
2550
if self .econmodel .value != EconomicModel .SAM_SINGLE_OWNER_PPA :
@@ -3267,6 +3276,51 @@ def calculate_cashflow(self, model: Model) -> None:
3267
3276
for i in range (1 , model .surfaceplant .plant_lifetime .value + model .surfaceplant .construction_years .value , 1 ):
3268
3277
self .TotalCummRevenue .value [i ] = self .TotalCummRevenue .value [i - 1 ] + self .TotalRevenue .value [i ]
3269
3278
3279
+ def _calculate_sam_economics (self , model : Model ) -> None :
3280
+ non_calculated_output_placeholder_val = - 1
3281
+ self .sam_economics_calculations = calculate_sam_economics (model )
3282
+
3283
+ # Setting capex_total distinguishes capex from CCap's display name of 'Total capital costs',
3284
+ # since SAM Economic Model doesn't subtract ITC from this value.
3285
+ self .capex_total .value = (self .sam_economics_calculations .capex .quantity ()
3286
+ .to (self .capex_total .CurrentUnits .value ).magnitude )
3287
+ self .CCap .value = (self .sam_economics_calculations .capex .quantity ()
3288
+ .to (self .CCap .CurrentUnits .value ).magnitude )
3289
+
3290
+
3291
+ if self .royalty_rate .Provided :
3292
+ average_annual_royalties = np .average (
3293
+ self .sam_economics_calculations .royalties_opex .value [1 :] # ignore pre-revenue year(s) (Year 0)
3294
+ )
3295
+
3296
+ self .royalties_average_annual_cost .value = average_annual_royalties
3297
+ self .Coam .value += self .royalties_average_annual_cost .quantity ().to (self .Coam .CurrentUnits .value ).magnitude
3298
+
3299
+ self .royalty_holder_npv .value = calculate_npv (
3300
+ self .royalty_holder_discount_rate .value ,
3301
+ self .sam_economics_calculations .royalties_opex .value ,
3302
+ self .discount_initial_year_cashflow .value
3303
+ )
3304
+ # FIXME WIP
3305
+ # self.royalty_holder_annual_revenue
3306
+ # self.royalty_holder_total_revenue
3307
+
3308
+
3309
+ self .wacc .value = self .sam_economics_calculations .wacc .value
3310
+ self .nominal_discount_rate .value = self .sam_economics_calculations .nominal_discount_rate .value
3311
+ self .ProjectNPV .value = self .sam_economics_calculations .project_npv .quantity ().to (
3312
+ convertible_unit (self .ProjectNPV .CurrentUnits )).magnitude
3313
+
3314
+ self .ProjectIRR .value = non_calculated_output_placeholder_val # SAM calculates After-Tax IRR instead
3315
+ self .after_tax_irr .value = self .sam_economics_calculations .after_tax_irr .quantity ().to (
3316
+ convertible_unit (self .ProjectIRR .CurrentUnits )).magnitude
3317
+
3318
+ self .ProjectMOIC .value = self .sam_economics_calculations .moic .value
3319
+ self .ProjectVIR .value = self .sam_economics_calculations .project_vir .value
3320
+
3321
+ # TODO remove or clarify project payback period: https://github.com/NREL/GEOPHIRES-X/issues/413
3322
+ self .ProjectPaybackPeriod .value = self .sam_economics_calculations .project_payback_period .value
3323
+
3270
3324
# noinspection SpellCheckingInspection
3271
3325
def _calculate_derived_outputs (self , model : Model ) -> None :
3272
3326
"""
0 commit comments