Skip to content

Commit 26d952e

Browse files
Merge pull request #83 from softwareengineerprogrammer/parameterize-stimulation-cost-per-well
Parameterize stimulation cost per well
2 parents 0a92a7a + feefbf3 commit 26d952e

File tree

5 files changed

+110
-11
lines changed

5 files changed

+110
-11
lines changed

src/geophires_x/Economics.py

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,7 @@ def __init__(self, model: Model):
572572
ToolTipText="Specify the economic model to calculate the levelized cost of energy. " +
573573
'; '.join([f'{it.int_value}: {it.value}' for it in EconomicModel])
574574
)
575+
575576
self.ccstimfixed = self.ParameterDict[self.ccstimfixed.Name] = floatParameter(
576577
"Reservoir Stimulation Capital Cost",
577578
DefaultValue=-1.0,
@@ -584,6 +585,38 @@ def __init__(self, model: Model):
584585
Valid=False,
585586
ToolTipText="Total reservoir stimulation capital cost"
586587
)
588+
589+
max_stimulation_cost_per_well_MUSD = 100
590+
self.stimulation_cost_per_injection_well = \
591+
self.ParameterDict[self.stimulation_cost_per_injection_well.Name] = floatParameter(
592+
'Reservoir Stimulation Capital Cost per Injection Well',
593+
DefaultValue=1.25,
594+
Min=0,
595+
Max=max_stimulation_cost_per_well_MUSD,
596+
UnitType=Units.CURRENCY,
597+
PreferredUnits=CurrencyUnit.MDOLLARS,
598+
CurrentUnits=CurrencyUnit.MDOLLARS,
599+
Provided=False,
600+
ToolTipText='Reservoir stimulation capital cost per injection well'
601+
)
602+
603+
stimulation_cost_per_production_well_default_value_MUSD = 0
604+
stimulation_cost_per_production_well_default_value_note = \
605+
'. By default, only the injection wells are assumed to be stimulated unless this parameter is provided.' \
606+
if stimulation_cost_per_production_well_default_value_MUSD == 0 else ''
607+
self.stimulation_cost_per_production_well = \
608+
self.ParameterDict[self.stimulation_cost_per_production_well.Name] = floatParameter(
609+
'Reservoir Stimulation Capital Cost per Production Well',
610+
DefaultValue=stimulation_cost_per_production_well_default_value_MUSD,
611+
Min=0,
612+
Max=max_stimulation_cost_per_well_MUSD,
613+
UnitType=Units.CURRENCY,
614+
PreferredUnits=CurrencyUnit.MDOLLARS,
615+
CurrentUnits=CurrencyUnit.MDOLLARS,
616+
ToolTipText=f'Reservoir stimulation capital cost per production well'
617+
f'{stimulation_cost_per_production_well_default_value_note}'
618+
)
619+
587620
self.ccstimadjfactor = self.ParameterDict[self.ccstimadjfactor.Name] = floatParameter(
588621
"Reservoir Stimulation Capital Cost Adjustment Factor",
589622
DefaultValue=1.0,
@@ -594,7 +627,7 @@ def __init__(self, model: Model):
594627
CurrentUnits=PercentUnit.TENTH,
595628
Provided=False,
596629
Valid=True,
597-
ToolTipText="Multiplier for built-in reservoir stimulation capital cost correlation"
630+
ToolTipText="Multiplier for reservoir stimulation capital cost correlation"
598631
)
599632
self.ccexplfixed = self.ParameterDict[self.ccexplfixed.Name] = floatParameter(
600633
"Exploration Capital Cost",
@@ -1606,19 +1639,27 @@ def __init__(self, model: Model):
16061639
)
16071640

16081641
# TODO https://github.com/NREL/GEOPHIRES-X/issues/383?title=Parameterize+indirect+cost+factor
1609-
contingency_and_indirect_costs_tooltip = 'plus 15% contingency plus 12% indirect costs'
1642+
stimulation_contingency_and_indirect_costs_tooltip = 'plus 15% contingency plus 5% indirect costs'
16101643

16111644
# noinspection SpellCheckingInspection
16121645
self.Cstim = self.OutputParameterDict[self.Cstim.Name] = OutputParameter(
16131646
Name="Stimulation costs",
16141647
UnitType=Units.CURRENCY,
16151648
PreferredUnits=CurrencyUnit.MDOLLARS,
16161649
CurrentUnits=CurrencyUnit.MDOLLARS,
1617-
ToolTipText=f'Default correlation: $1.25M per injection well {contingency_and_indirect_costs_tooltip}. '
1618-
f'Provide {self.ccstimadjfactor.Name} to multiply the default correlation. '
1619-
f'Provide {self.ccstimfixed.Name} to override the default correlation and set your own cost.'
1650+
ToolTipText=f'Default correlation: ${self.stimulation_cost_per_injection_well.value}M '
1651+
f'per injection well {stimulation_contingency_and_indirect_costs_tooltip}. '
1652+
f'Provide {self.stimulation_cost_per_injection_well.Name} and '
1653+
f'{self.stimulation_cost_per_production_well.Name} to set the correlation '
1654+
f'costs per well. '
1655+
f'Provide {self.ccstimadjfactor.Name} to multiply the correlation-calculated cost. '
1656+
f'Provide {self.ccstimfixed.Name} to override the correlation and set your own '
1657+
f'total stimulation cost.'
16201658
)
16211659

1660+
# TODO https://github.com/NREL/GEOPHIRES-X/issues/383?title=Parameterize+indirect+cost+factor
1661+
contingency_and_indirect_costs_tooltip = 'plus 15% contingency plus 12% indirect costs'
1662+
16221663
# See TODO re:parameterizing indirect costs at src/geophires_x/Economics.py:652
16231664
# (https://github.com/NREL/GEOPHIRES-X/issues/383)
16241665
self.Cexpl = self.OutputParameterDict[self.Cexpl.Name] = OutputParameter(
@@ -2336,12 +2377,18 @@ def Calculate(self, model: Model) -> None:
23362377
if self.ccstimfixed.Valid:
23372378
self.Cstim.value = self.ccstimfixed.value
23382379
else:
2339-
base_stimulation_cost_MUSD_per_injection_well = 1.25 # TODO parameterize
2380+
stim_cost_per_injection_well = self.stimulation_cost_per_injection_well.quantity().to(
2381+
self.Cstim.CurrentUnits).magnitude
2382+
stim_cost_per_production_well = self.stimulation_cost_per_production_well.quantity().to(
2383+
self.Cstim.CurrentUnits).magnitude
23402384

23412385
# 1.15 for 15% contingency and 1.05 for 5% indirect costs
23422386
# TODO https://github.com/NREL/GEOPHIRES-X/issues/383?title=Parameterize+indirect+cost+factor
2343-
self.Cstim.value = (base_stimulation_cost_MUSD_per_injection_well * self.ccstimadjfactor.value
2344-
* model.wellbores.ninj.value
2387+
self.Cstim.value = ((
2388+
stim_cost_per_injection_well * model.wellbores.ninj.value
2389+
+ stim_cost_per_production_well * model.wellbores.nprod.value
2390+
)
2391+
* self.ccstimadjfactor.value
23452392
* 1.05 * 1.15)
23462393

23472394
# field gathering system costs (M$)

src/geophires_x/Outputs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ def PrintOutputs(self, model: Model):
478478
if model.economics.totalcapcost.Valid and model.wellbores.redrill.value > 0:
479479
f.write(f' Drilling and completion costs (for redrilling):{model.economics.Cwell.value:10.2f} ' + model.economics.Cwell.CurrentUnits.value + NL)
480480
f.write(f' Drilling and completion costs per redrilled well: {(model.economics.Cwell.value/(model.wellbores.nprod.value+model.wellbores.ninj.value)):10.2f} ' + model.economics.Cwell.CurrentUnits.value + NL)
481-
f.write(f' Stimulation costs (for redrilling): {model.economics.Cstim.value:10.2f} ' + model.economics.Cstim.CurrentUnits.value + NL)
481+
f.write(f' Stimulation costs (for redrilling): {econ.Cstim.value:10.2f} {econ.Cstim.CurrentUnits.value}\n')
482482
if model.economics.RITCValue.value:
483483
f.write(f' {model.economics.RITCValue.display_name}: {-1*model.economics.RITCValue.value:10.2f} {model.economics.RITCValue.CurrentUnits.value}\n')
484484

src/geophires_x_schema_generator/geophires-request.json

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1395,8 +1395,26 @@
13951395
"minimum": 0,
13961396
"maximum": 1000
13971397
},
1398+
"Reservoir Stimulation Capital Cost per Injection Well": {
1399+
"description": "Reservoir stimulation capital cost per injection well",
1400+
"type": "number",
1401+
"units": "MUSD",
1402+
"category": "Economics",
1403+
"default": 1.25,
1404+
"minimum": 0,
1405+
"maximum": 100
1406+
},
1407+
"Reservoir Stimulation Capital Cost per Production Well": {
1408+
"description": "Reservoir stimulation capital cost per production well. By default, only the injection wells are assumed to be stimulated unless this parameter is provided.",
1409+
"type": "number",
1410+
"units": "MUSD",
1411+
"category": "Economics",
1412+
"default": 0,
1413+
"minimum": 0,
1414+
"maximum": 100
1415+
},
13981416
"Reservoir Stimulation Capital Cost Adjustment Factor": {
1399-
"description": "Multiplier for built-in reservoir stimulation capital cost correlation",
1417+
"description": "Multiplier for reservoir stimulation capital cost correlation",
14001418
"type": "number",
14011419
"units": "",
14021420
"category": "Economics",

src/geophires_x_schema_generator/geophires-result.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@
351351
"Drilling and completion costs per redrilled well": {},
352352
"Stimulation costs": {
353353
"type": "number",
354-
"description": "Default correlation: $1.25M per injection well plus 15% contingency plus 12% indirect costs. Provide Reservoir Stimulation Capital Cost Adjustment Factor to multiply the default correlation. Provide Reservoir Stimulation Capital Cost to override the default correlation and set your own cost.",
354+
"description": "Default correlation: $1.25M per injection well plus 15% contingency plus 5% indirect costs. Provide Reservoir Stimulation Capital Cost per Injection Well and Reservoir Stimulation Capital Cost per Production Well to set the correlation costs per well. Provide Reservoir Stimulation Capital Cost Adjustment Factor to multiply the correlation-calculated cost. Provide Reservoir Stimulation Capital Cost to override the correlation and set your own total stimulation cost.",
355355
"units": "MUSD"
356356
},
357357
"Stimulation costs (for redrilling)": {},

tests/test_geophires_x.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from geophires_x_client import _get_logger
1313
from geophires_x_client.geophires_input_parameters import EndUseOption
1414
from geophires_x_client.geophires_input_parameters import GeophiresInputParameters
15+
from geophires_x_client.geophires_input_parameters import ImmutableGeophiresInputParameters
1516
from geophires_x_tests.test_options_list import WellDrillingCostCorrelationTestCase
1617
from tests.base_test_case import BaseTestCase
1718

@@ -941,3 +942,36 @@ def test_sbt_coaxial_raises_error(self):
941942
)
942943
client.get_geophires_result(params)
943944
self.assertIn('SBT with coaxial configuration is not implemented', str(e.exception))
945+
946+
def test_production_well_stimulation_cost(self):
947+
def _get_result(prod_well_stim_MUSD: Optional[int] = None) -> GeophiresXResult:
948+
p = {}
949+
if prod_well_stim_MUSD is not None:
950+
p['Reservoir Stimulation Capital Cost per Production Well'] = prod_well_stim_MUSD
951+
952+
return GeophiresXClient().get_geophires_result(
953+
ImmutableGeophiresInputParameters(
954+
from_file_path=self._get_test_file_path('geophires_x_tests/generic-egs-case.txt'),
955+
params=p,
956+
)
957+
)
958+
959+
result_no_prod_stim: GeophiresXResult = _get_result()
960+
961+
result_prod_stim: GeophiresXResult = _get_result(1.25)
962+
963+
# TODO https://github.com/NREL/GEOPHIRES-X/issues/383?title=Parameterize+indirect+cost+factor
964+
indirect_and_contingency = 1.05 * 1.15
965+
966+
self.assertAlmostEqual(
967+
(
968+
2
969+
* (
970+
result_no_prod_stim.result['CAPITAL COSTS (M$)']['Stimulation costs']['value']
971+
/ (indirect_and_contingency)
972+
)
973+
)
974+
* indirect_and_contingency,
975+
result_prod_stim.result['CAPITAL COSTS (M$)']['Stimulation costs']['value'],
976+
places=1,
977+
)

0 commit comments

Comments
 (0)