Skip to content

Parameterize stimulation cost per well #83

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 55 additions & 8 deletions src/geophires_x/Economics.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,7 @@ def __init__(self, model: Model):
ToolTipText="Specify the economic model to calculate the levelized cost of energy. " +
'; '.join([f'{it.int_value}: {it.value}' for it in EconomicModel])
)

self.ccstimfixed = self.ParameterDict[self.ccstimfixed.Name] = floatParameter(
"Reservoir Stimulation Capital Cost",
DefaultValue=-1.0,
Expand All @@ -584,6 +585,38 @@ def __init__(self, model: Model):
Valid=False,
ToolTipText="Total reservoir stimulation capital cost"
)

max_stimulation_cost_per_well_MUSD = 100
self.stimulation_cost_per_injection_well = \
self.ParameterDict[self.stimulation_cost_per_injection_well.Name] = floatParameter(
'Reservoir Stimulation Capital Cost per Injection Well',
DefaultValue=1.25,
Min=0,
Max=max_stimulation_cost_per_well_MUSD,
UnitType=Units.CURRENCY,
PreferredUnits=CurrencyUnit.MDOLLARS,
CurrentUnits=CurrencyUnit.MDOLLARS,
Provided=False,
ToolTipText='Reservoir stimulation capital cost per injection well'
)

stimulation_cost_per_production_well_default_value_MUSD = 0
stimulation_cost_per_production_well_default_value_note = \
'. By default, only the injection wells are assumed to be stimulated unless this parameter is provided.' \
if stimulation_cost_per_production_well_default_value_MUSD == 0 else ''
self.stimulation_cost_per_production_well = \
self.ParameterDict[self.stimulation_cost_per_production_well.Name] = floatParameter(
'Reservoir Stimulation Capital Cost per Production Well',
DefaultValue=stimulation_cost_per_production_well_default_value_MUSD,
Min=0,
Max=max_stimulation_cost_per_well_MUSD,
UnitType=Units.CURRENCY,
PreferredUnits=CurrencyUnit.MDOLLARS,
CurrentUnits=CurrencyUnit.MDOLLARS,
ToolTipText=f'Reservoir stimulation capital cost per production well'
f'{stimulation_cost_per_production_well_default_value_note}'
)

self.ccstimadjfactor = self.ParameterDict[self.ccstimadjfactor.Name] = floatParameter(
"Reservoir Stimulation Capital Cost Adjustment Factor",
DefaultValue=1.0,
Expand All @@ -594,7 +627,7 @@ def __init__(self, model: Model):
CurrentUnits=PercentUnit.TENTH,
Provided=False,
Valid=True,
ToolTipText="Multiplier for built-in reservoir stimulation capital cost correlation"
ToolTipText="Multiplier for reservoir stimulation capital cost correlation"
)
self.ccexplfixed = self.ParameterDict[self.ccexplfixed.Name] = floatParameter(
"Exploration Capital Cost",
Expand Down Expand Up @@ -1606,19 +1639,27 @@ def __init__(self, model: Model):
)

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

# noinspection SpellCheckingInspection
self.Cstim = self.OutputParameterDict[self.Cstim.Name] = OutputParameter(
Name="Stimulation costs",
UnitType=Units.CURRENCY,
PreferredUnits=CurrencyUnit.MDOLLARS,
CurrentUnits=CurrencyUnit.MDOLLARS,
ToolTipText=f'Default correlation: $1.25M per injection well {contingency_and_indirect_costs_tooltip}. '
f'Provide {self.ccstimadjfactor.Name} to multiply the default correlation. '
f'Provide {self.ccstimfixed.Name} to override the default correlation and set your own cost.'
ToolTipText=f'Default correlation: ${self.stimulation_cost_per_injection_well.value}M '
f'per injection well {stimulation_contingency_and_indirect_costs_tooltip}. '
f'Provide {self.stimulation_cost_per_injection_well.Name} and '
f'{self.stimulation_cost_per_production_well.Name} to set the correlation '
f'costs per well. '
f'Provide {self.ccstimadjfactor.Name} to multiply the correlation-calculated cost. '
f'Provide {self.ccstimfixed.Name} to override the correlation and set your own '
f'total stimulation cost.'
)

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

# See TODO re:parameterizing indirect costs at src/geophires_x/Economics.py:652
# (https://github.com/NREL/GEOPHIRES-X/issues/383)
self.Cexpl = self.OutputParameterDict[self.Cexpl.Name] = OutputParameter(
Expand Down Expand Up @@ -2336,12 +2377,18 @@ def Calculate(self, model: Model) -> None:
if self.ccstimfixed.Valid:
self.Cstim.value = self.ccstimfixed.value
else:
base_stimulation_cost_MUSD_per_injection_well = 1.25 # TODO parameterize
stim_cost_per_injection_well = self.stimulation_cost_per_injection_well.quantity().to(
self.Cstim.CurrentUnits).magnitude
stim_cost_per_production_well = self.stimulation_cost_per_production_well.quantity().to(
self.Cstim.CurrentUnits).magnitude

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

# field gathering system costs (M$)
Expand Down
2 changes: 1 addition & 1 deletion src/geophires_x/Outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ def PrintOutputs(self, model: Model):
if model.economics.totalcapcost.Valid and model.wellbores.redrill.value > 0:
f.write(f' Drilling and completion costs (for redrilling):{model.economics.Cwell.value:10.2f} ' + model.economics.Cwell.CurrentUnits.value + NL)
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)
f.write(f' Stimulation costs (for redrilling): {model.economics.Cstim.value:10.2f} ' + model.economics.Cstim.CurrentUnits.value + NL)
f.write(f' Stimulation costs (for redrilling): {econ.Cstim.value:10.2f} {econ.Cstim.CurrentUnits.value}\n')
if model.economics.RITCValue.value:
f.write(f' {model.economics.RITCValue.display_name}: {-1*model.economics.RITCValue.value:10.2f} {model.economics.RITCValue.CurrentUnits.value}\n')

Expand Down
20 changes: 19 additions & 1 deletion src/geophires_x_schema_generator/geophires-request.json
Original file line number Diff line number Diff line change
Expand Up @@ -1395,8 +1395,26 @@
"minimum": 0,
"maximum": 1000
},
"Reservoir Stimulation Capital Cost per Injection Well": {
"description": "Reservoir stimulation capital cost per injection well",
"type": "number",
"units": "MUSD",
"category": "Economics",
"default": 1.25,
"minimum": 0,
"maximum": 100
},
"Reservoir Stimulation Capital Cost per Production Well": {
"description": "Reservoir stimulation capital cost per production well. By default, only the injection wells are assumed to be stimulated unless this parameter is provided.",
"type": "number",
"units": "MUSD",
"category": "Economics",
"default": 0,
"minimum": 0,
"maximum": 100
},
"Reservoir Stimulation Capital Cost Adjustment Factor": {
"description": "Multiplier for built-in reservoir stimulation capital cost correlation",
"description": "Multiplier for reservoir stimulation capital cost correlation",
"type": "number",
"units": "",
"category": "Economics",
Expand Down
2 changes: 1 addition & 1 deletion src/geophires_x_schema_generator/geophires-result.json
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@
"Drilling and completion costs per redrilled well": {},
"Stimulation costs": {
"type": "number",
"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.",
"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.",
"units": "MUSD"
},
"Stimulation costs (for redrilling)": {},
Expand Down
34 changes: 34 additions & 0 deletions tests/test_geophires_x.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from geophires_x_client import _get_logger
from geophires_x_client.geophires_input_parameters import EndUseOption
from geophires_x_client.geophires_input_parameters import GeophiresInputParameters
from geophires_x_client.geophires_input_parameters import ImmutableGeophiresInputParameters
from geophires_x_tests.test_options_list import WellDrillingCostCorrelationTestCase
from tests.base_test_case import BaseTestCase

Expand Down Expand Up @@ -941,3 +942,36 @@ def test_sbt_coaxial_raises_error(self):
)
client.get_geophires_result(params)
self.assertIn('SBT with coaxial configuration is not implemented', str(e.exception))

def test_production_well_stimulation_cost(self):
def _get_result(prod_well_stim_MUSD: Optional[int] = None) -> GeophiresXResult:
p = {}
if prod_well_stim_MUSD is not None:
p['Reservoir Stimulation Capital Cost per Production Well'] = prod_well_stim_MUSD

return GeophiresXClient().get_geophires_result(
ImmutableGeophiresInputParameters(
from_file_path=self._get_test_file_path('geophires_x_tests/generic-egs-case.txt'),
params=p,
)
)

result_no_prod_stim: GeophiresXResult = _get_result()

result_prod_stim: GeophiresXResult = _get_result(1.25)

# TODO https://github.com/NREL/GEOPHIRES-X/issues/383?title=Parameterize+indirect+cost+factor
indirect_and_contingency = 1.05 * 1.15

self.assertAlmostEqual(
(
2
* (
result_no_prod_stim.result['CAPITAL COSTS (M$)']['Stimulation costs']['value']
/ (indirect_and_contingency)
)
)
* indirect_and_contingency,
result_prod_stim.result['CAPITAL COSTS (M$)']['Stimulation costs']['value'],
places=1,
)
Loading