Skip to content

Commit bc86612

Browse files
Add Contingency Percentage parameter to Economics. (TODO to incorporate/consolidate SBTEconomics)
1 parent 40e108f commit bc86612

File tree

2 files changed

+68
-25
lines changed

2 files changed

+68
-25
lines changed

src/geophires_x/Economics.py

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,21 @@ def __init__(self, model: Model):
10441044
ErrMessage="assume default inflation rate during construction (0)",
10451045
ToolTipText='For SAM Economic Models, this value is treated as an indirect EPC capital cost percentage.'
10461046
)
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+
10471062
self.wellcorrelation = self.ParameterDict[self.wellcorrelation.Name] = intParameter(
10481063
"Well Drilling Cost Correlation",
10491064
DefaultValue=WellDrillingCostCorrelation.VERTICAL_LARGE_INT1.int_value,
@@ -2366,8 +2381,8 @@ def Calculate(self, model: Model) -> None:
23662381
if self.ccexplfixed.Valid:
23672382
self.Cexpl.value = self.ccexplfixed.value
23682383
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)
23712386

23722387
# Surface Piping Length Costs (M$) #assumed $750k/km
23732388
self.Cpiping.value = 750 / 1000 * model.surfaceplant.piping_length.value
@@ -2635,6 +2650,10 @@ def _wellfield_indirect_cost_factor(self) -> float:
26352650
def _stimulation_indirect_cost_factor(self) -> float:
26362651
return 1 + self.stimulation_indirect_capital_cost_percentage.quantity().to('dimensionless').magnitude
26372652

2653+
@property
2654+
def _contingency_factor(self) -> float:
2655+
return 1 + self.contingency_percentage.quantity().to('dimensionless').magnitude
2656+
26382657
def calculate_wellfield_costs(self, model: Model) -> None:
26392658
if self.per_production_well_cost.Valid:
26402659
self.cost_one_production_well.value = self.per_production_well_cost.value
@@ -2727,7 +2746,7 @@ def calculate_stimulation_costs(self, model: Model) -> PlainQuantity:
27272746
)
27282747
* self.ccstimadjfactor.value
27292748
* self._stimulation_indirect_cost_factor
2730-
* 1.15 # 15% contingency TODO https://github.com/NREL/GEOPHIRES-X/issues/383
2749+
* self._contingency_factor
27312750
)
27322751

27332752
return quantity(stimulation_costs, self.Cstim.CurrentUnits)
@@ -2766,8 +2785,8 @@ def calculate_field_gathering_costs(self, model: Model) -> None:
27662785
1750 * injpumphpcorrected ** 0.7) * 3 * injpumphpcorrected ** (-0.11)
27672786
self.Cpumps = Cpumpsinj + Cpumpsprod
27682787

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 * (
27712790
(model.wellbores.nprod.value + model.wellbores.ninj.value) * 750 * 500. + self.Cpumps) / 1E6
27722791

27732792
def calculate_plant_costs(self, model: Model) -> None:
@@ -2777,21 +2796,32 @@ def calculate_plant_costs(self, model: Model) -> None:
27772796
if self.ccplantfixed.Valid:
27782797
self.Cplant.value = self.ccplantfixed.value
27792798
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.)
27832805

27842806
# absorption chiller
27852807
elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: # absorption chiller
27862808
if self.ccplantfixed.Valid:
27872809
self.Cplant.value = self.ccplantfixed.value
27882810
else:
27892811
# 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.)
27922818
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+
)
27952825

27962826
# now add chiller cost to surface plant cost
27972827
self.Cplant.value += self.chillercapex.value
@@ -2802,11 +2832,11 @@ def calculate_plant_costs(self, model: Model) -> None:
28022832
self.Cplant.value = self.ccplantfixed.value
28032833
else:
28042834
# 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.
28072837
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
28102840

28112841
# now add heat pump cost to surface plant cost
28122842
self.Cplant.value += self.heatpumpcapex.value
@@ -2816,8 +2846,7 @@ def calculate_plant_costs(self, model: Model) -> None:
28162846
if self.ccplantfixed.Valid:
28172847
self.Cplant.value = self.ccplantfixed.value
28182848
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(
28212850
model.surfaceplant.HeatExtracted.value) * 1000.
28222851

28232852
# add 65$/KW for peaking boiler
@@ -2986,23 +3015,28 @@ def calculate_plant_costs(self, model: Model) -> None:
29863015
# factor 1.10 to convert from 2016 to 2022
29873016
direct_plant_cost_MUSD = self.ccplantadjfactor.value * self.Cplantcorrelation * 1.02 * 1.10
29883017

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
29913019
self.CAPEX_cost_electricity_plant = self.Cplant.value
29923020

29933021
# 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:
29953023
if model.surfaceplant.enduse_option.value in [EndUseOptions.COGENERATION_TOPPING_EXTRA_ELECTRICITY,
29963024
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+
)
29993033
elif model.surfaceplant.enduse_option.value in [EndUseOptions.COGENERATION_BOTTOMING_EXTRA_HEAT,
30003034
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(
30023036
model.surfaceplant.HeatProduced.value / model.surfaceplant.enduse_efficiency_factor.value) * 1000.
30033037
elif model.surfaceplant.enduse_option.value in [EndUseOptions.COGENERATION_PARALLEL_EXTRA_ELECTRICITY,
30043038
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(
30063040
model.surfaceplant.HeatProduced.value / model.surfaceplant.enduse_efficiency_factor.value) * 1000.
30073041

30083042
self.Cplant.value = self.Cplant.value + self.CAPEX_cost_heat_plant

src/geophires_x_schema_generator/geophires-request.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1719,6 +1719,15 @@
17191719
"minimum": 0.0,
17201720
"maximum": 1.0
17211721
},
1722+
"Contingency Percentage": {
1723+
"description": "The contingency percentage applied to the direct capital costs for stimulation, field gathering system, exploration, and surface plant. (Note: well drilling and completion costs do not have contingency applied and are not affected by this parameter.)",
1724+
"type": "number",
1725+
"units": "%",
1726+
"category": "Economics",
1727+
"default": 15.0,
1728+
"minimum": 0.0,
1729+
"maximum": 100.0
1730+
},
17221731
"Well Drilling Cost Correlation": {
17231732
"description": "Select the built-in well drilling and completion cost correlation: 1: vertical small diameter, baseline; 2: deviated small diameter, baseline; 3: vertical large diameter, baseline; 4: deviated large diameter, baseline; 5: Simple (per-meter cost); 6: vertical small diameter, intermediate1; 7: vertical small diameter, intermediate2; 8: deviated small diameter, intermediate1; 9: deviated small diameter, intermediate2; 10: vertical large diameter, intermediate1; 11: vertical large diameter, intermediate2; 12: deviated large diameter, intermediate1; 13: deviated large diameter, intermediate2; 14: vertical open-hole, small diameter, ideal; 15: deviated liner, small diameter, ideal; 16: vertical open-hole, large diameter, ideal; 17: deviated liner, large diameter, ideal. Baseline correlations (1-4) are from NREL's 2025 cost curve update. Intermediate and ideal correlations (6-17) are from GeoVision.",
17241733
"type": "integer",

0 commit comments

Comments
 (0)