@@ -1044,6 +1044,21 @@ def __init__(self, model: Model):
1044
1044
ErrMessage = "assume default inflation rate during construction (0)" ,
1045
1045
ToolTipText = 'For SAM Economic Models, this value is treated as an indirect EPC capital cost percentage.'
1046
1046
)
1047
+
1048
+ self .contingency_percentage = self .ParameterDict [self .contingency_percentage .Name ] = floatParameter (
1049
+ 'Contingency Percentage' ,
1050
+ DefaultValue = 15. ,
1051
+ Min = 0. ,
1052
+ Max = 100. ,
1053
+ UnitType = Units .PERCENT ,
1054
+ PreferredUnits = PercentUnit .PERCENT ,
1055
+ CurrentUnits = PercentUnit .PERCENT ,
1056
+ ToolTipText = 'The contingency percentage applied to the direct capital costs for stimulation, '
1057
+ 'field gathering system, exploration, and surface plant. '
1058
+ '(Note: well drilling and completion costs do not have contingency applied and are not '
1059
+ 'affected by this parameter.)'
1060
+ )
1061
+
1047
1062
self .wellcorrelation = self .ParameterDict [self .wellcorrelation .Name ] = intParameter (
1048
1063
"Well Drilling Cost Correlation" ,
1049
1064
DefaultValue = WellDrillingCostCorrelation .VERTICAL_LARGE_INT1 .int_value ,
@@ -2366,8 +2381,8 @@ def Calculate(self, model: Model) -> None:
2366
2381
if self .ccexplfixed .Valid :
2367
2382
self .Cexpl .value = self .ccexplfixed .value
2368
2383
else :
2369
- self .Cexpl .value = 1.15 * self .ccexpladjfactor .value * self ._indirect_cost_factor * (
2370
- 1. + self .cost_one_production_well .value * 0.6 ) # 1.15 for 15% contingency TODO https://github.com/NREL/GEOPHIRES-X/issues/383
2384
+ self .Cexpl .value = self . _contingency_factor * self .ccexpladjfactor .value * self ._indirect_cost_factor * (
2385
+ 1. + self .cost_one_production_well .value * 0.6 )
2371
2386
2372
2387
# Surface Piping Length Costs (M$) #assumed $750k/km
2373
2388
self .Cpiping .value = 750 / 1000 * model .surfaceplant .piping_length .value
@@ -2635,6 +2650,10 @@ def _wellfield_indirect_cost_factor(self) -> float:
2635
2650
def _stimulation_indirect_cost_factor (self ) -> float :
2636
2651
return 1 + self .stimulation_indirect_capital_cost_percentage .quantity ().to ('dimensionless' ).magnitude
2637
2652
2653
+ @property
2654
+ def _contingency_factor (self ) -> float :
2655
+ return 1 + self .contingency_percentage .quantity ().to ('dimensionless' ).magnitude
2656
+
2638
2657
def calculate_wellfield_costs (self , model : Model ) -> None :
2639
2658
if self .per_production_well_cost .Valid :
2640
2659
self .cost_one_production_well .value = self .per_production_well_cost .value
@@ -2727,7 +2746,7 @@ def calculate_stimulation_costs(self, model: Model) -> PlainQuantity:
2727
2746
)
2728
2747
* self .ccstimadjfactor .value
2729
2748
* self ._stimulation_indirect_cost_factor
2730
- * 1.15 # 15% contingency TODO https://github.com/NREL/GEOPHIRES-X/issues/383
2749
+ * self . _contingency_factor
2731
2750
)
2732
2751
2733
2752
return quantity (stimulation_costs , self .Cstim .CurrentUnits )
@@ -2766,8 +2785,8 @@ def calculate_field_gathering_costs(self, model: Model) -> None:
2766
2785
1750 * injpumphpcorrected ** 0.7 ) * 3 * injpumphpcorrected ** (- 0.11 )
2767
2786
self .Cpumps = Cpumpsinj + Cpumpsprod
2768
2787
2769
- # Based on GETEM 2016: 1.15 for 15% contingency TODO https://github.com/NREL/GEOPHIRES-X/issues/383
2770
- self .Cgath .value = 1.15 * self .ccgathadjfactor .value * self ._indirect_cost_factor * (
2788
+ # Based on GETEM 2016
2789
+ self .Cgath .value = self . _contingency_factor * self .ccgathadjfactor .value * self ._indirect_cost_factor * (
2771
2790
(model .wellbores .nprod .value + model .wellbores .ninj .value ) * 750 * 500. + self .Cpumps ) / 1E6
2772
2791
2773
2792
def calculate_plant_costs (self , model : Model ) -> None :
@@ -2777,21 +2796,32 @@ def calculate_plant_costs(self, model: Model) -> None:
2777
2796
if self .ccplantfixed .Valid :
2778
2797
self .Cplant .value = self .ccplantfixed .value
2779
2798
else :
2780
- # 1.15 for 15% contingency TODO https://github.com/NREL/GEOPHIRES-X/issues/383
2781
- self .Cplant .value = self ._indirect_cost_factor * 1.15 * self .ccplantadjfactor .value * 250E-6 * np .max (
2782
- model .surfaceplant .HeatExtracted .value ) * 1000.
2799
+ self .Cplant .value = (self ._indirect_cost_factor
2800
+ * self ._contingency_factor
2801
+ * self .ccplantadjfactor .value
2802
+ * 250E-6
2803
+ * np .max (model .surfaceplant .HeatExtracted .value )
2804
+ * 1000. )
2783
2805
2784
2806
# absorption chiller
2785
2807
elif model .surfaceplant .enduse_option .value == EndUseOptions .HEAT and model .surfaceplant .plant_type .value == PlantType .ABSORPTION_CHILLER : # absorption chiller
2786
2808
if self .ccplantfixed .Valid :
2787
2809
self .Cplant .value = self .ccplantfixed .value
2788
2810
else :
2789
2811
# this is for the direct-use part all the way up to the absorption chiller
2790
- self .Cplant .value = self ._indirect_cost_factor * 1.15 * self .ccplantadjfactor .value * 250E-6 * np .max (
2791
- model .surfaceplant .HeatExtracted .value ) * 1000. # 1.15 for 15% contingency TODO https://github.com/NREL/GEOPHIRES-X/issues/383
2812
+ self .Cplant .value = (self ._indirect_cost_factor
2813
+ * self ._contingency_factor
2814
+ * self .ccplantadjfactor .value
2815
+ * 250E-6
2816
+ * np .max (model .surfaceplant .HeatExtracted .value )
2817
+ * 1000. )
2792
2818
if self .chillercapex .value == - 1 : # no value provided by user, use built-in correlation ($2500/ton)
2793
- self .chillercapex .value = self ._indirect_cost_factor * 1.15 * np .max (
2794
- model .surfaceplant .cooling_produced .value ) * 1000 / 3.517 * 2500 / 1e6 # $2,500/ton of cooling. 1.15 for 15% contingency TODO https://github.com/NREL/GEOPHIRES-X/issues/383
2819
+ self .chillercapex .value = (
2820
+ self ._indirect_cost_factor
2821
+ * self ._contingency_factor
2822
+ * np .max (model .surfaceplant .cooling_produced .value )
2823
+ * 1000 / 3.517 * 2500 / 1e6 # $2,500/ton of cooling.
2824
+ )
2795
2825
2796
2826
# now add chiller cost to surface plant cost
2797
2827
self .Cplant .value += self .chillercapex .value
@@ -2802,11 +2832,11 @@ def calculate_plant_costs(self, model: Model) -> None:
2802
2832
self .Cplant .value = self .ccplantfixed .value
2803
2833
else :
2804
2834
# this is for the direct-use part all the way up to the heat pump
2805
- self .Cplant .value = self ._indirect_cost_factor * 1.15 * self .ccplantadjfactor .value * 250E-6 * np .max (
2806
- model .surfaceplant .HeatExtracted .value ) * 1000. # 1.15 for 15% contingency
2835
+ self .Cplant .value = self ._indirect_cost_factor * self . _contingency_factor * self .ccplantadjfactor .value * 250E-6 * np .max (
2836
+ model .surfaceplant .HeatExtracted .value ) * 1000.
2807
2837
if self .heatpumpcapex .value == - 1 : # no value provided by user, use built-in correlation ($150/kWth)
2808
- self .heatpumpcapex .value = self ._indirect_cost_factor * 1.15 * np .max (
2809
- model .surfaceplant .HeatProduced .value ) * 1000 * 150 / 1e6 # $150/kW. 1.15 for 15% contingency TODO https://github.com/NREL/GEOPHIRES-X/issues/383
2838
+ self .heatpumpcapex .value = self ._indirect_cost_factor * self . _contingency_factor * np .max (
2839
+ model .surfaceplant .HeatProduced .value ) * 1000 * 150 / 1e6 # $150/kW - TODO parameterize
2810
2840
2811
2841
# now add heat pump cost to surface plant cost
2812
2842
self .Cplant .value += self .heatpumpcapex .value
@@ -2816,8 +2846,7 @@ def calculate_plant_costs(self, model: Model) -> None:
2816
2846
if self .ccplantfixed .Valid :
2817
2847
self .Cplant .value = self .ccplantfixed .value
2818
2848
else :
2819
- # 1.15 for 15% contingency TODO https://github.com/NREL/GEOPHIRES-X/issues/383
2820
- self .Cplant .value = self ._indirect_cost_factor * 1.15 * self .ccplantadjfactor .value * 250E-6 * np .max (
2849
+ self .Cplant .value = self ._indirect_cost_factor * self ._contingency_factor * self .ccplantadjfactor .value * 250E-6 * np .max (
2821
2850
model .surfaceplant .HeatExtracted .value ) * 1000.
2822
2851
2823
2852
# add 65$/KW for peaking boiler
@@ -2986,23 +3015,28 @@ def calculate_plant_costs(self, model: Model) -> None:
2986
3015
# factor 1.10 to convert from 2016 to 2022
2987
3016
direct_plant_cost_MUSD = self .ccplantadjfactor .value * self .Cplantcorrelation * 1.02 * 1.10
2988
3017
2989
- # factor 1.15 for 15% contingency TODO https://github.com/NREL/GEOPHIRES-X/issues/383
2990
- self .Cplant .value = self ._indirect_cost_factor * 1.15 * direct_plant_cost_MUSD
3018
+ self .Cplant .value = self ._indirect_cost_factor * self ._contingency_factor * direct_plant_cost_MUSD
2991
3019
self .CAPEX_cost_electricity_plant = self .Cplant .value
2992
3020
2993
3021
# add direct-use plant cost of co-gen system to Cplant (only of no total Cplant was provided)
2994
- if not self .ccplantfixed .Valid : # 1.15 below for contingency TODO https://github.com/NREL/GEOPHIRES-X/issues/383
3022
+ if not self .ccplantfixed .Valid :
2995
3023
if model .surfaceplant .enduse_option .value in [EndUseOptions .COGENERATION_TOPPING_EXTRA_ELECTRICITY ,
2996
3024
EndUseOptions .COGENERATION_TOPPING_EXTRA_HEAT ]: # enduse_option = 3: cogen topping cycle
2997
- self .CAPEX_cost_heat_plant = self ._indirect_cost_factor * 1.15 * self .ccplantadjfactor .value * 250E-6 * np .max (
2998
- model .surfaceplant .HeatProduced .value / model .surfaceplant .enduse_efficiency_factor .value ) * 1000.
3025
+ self .CAPEX_cost_heat_plant = (
3026
+ self ._indirect_cost_factor
3027
+ * self ._contingency_factor
3028
+ * self .ccplantadjfactor .value
3029
+ * 250E-6
3030
+ * np .max (model .surfaceplant .HeatProduced .value / model .surfaceplant .enduse_efficiency_factor .value )
3031
+ * 1000.
3032
+ )
2999
3033
elif model .surfaceplant .enduse_option .value in [EndUseOptions .COGENERATION_BOTTOMING_EXTRA_HEAT ,
3000
3034
EndUseOptions .COGENERATION_BOTTOMING_EXTRA_ELECTRICITY ]: # enduse_option = 4: cogen bottoming cycle
3001
- self .CAPEX_cost_heat_plant = self ._indirect_cost_factor * 1.15 * self .ccplantadjfactor .value * 250E-6 * np .max (
3035
+ self .CAPEX_cost_heat_plant = self ._indirect_cost_factor * self . _contingency_factor * self .ccplantadjfactor .value * 250E-6 * np .max (
3002
3036
model .surfaceplant .HeatProduced .value / model .surfaceplant .enduse_efficiency_factor .value ) * 1000.
3003
3037
elif model .surfaceplant .enduse_option .value in [EndUseOptions .COGENERATION_PARALLEL_EXTRA_ELECTRICITY ,
3004
3038
EndUseOptions .COGENERATION_PARALLEL_EXTRA_HEAT ]: # cogen parallel cycle
3005
- self .CAPEX_cost_heat_plant = self ._indirect_cost_factor * 1.15 * self .ccplantadjfactor .value * 250E-6 * np .max (
3039
+ self .CAPEX_cost_heat_plant = self ._indirect_cost_factor * self . _contingency_factor * self .ccplantadjfactor .value * 250E-6 * np .max (
3006
3040
model .surfaceplant .HeatProduced .value / model .surfaceplant .enduse_efficiency_factor .value ) * 1000.
3007
3041
3008
3042
self .Cplant .value = self .Cplant .value + self .CAPEX_cost_heat_plant
0 commit comments