Skip to content

Commit 2d0208c

Browse files
Merge pull request NREL#366 from softwareengineerprogrammer/main
2025 Geothermal Drilling Cost Curves Update [v3.8.6]
2 parents 6cdd8ec + 68368d1 commit 2d0208c

35 files changed

+1297
-1173
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 3.8.4
2+
current_version = 3.8.6
33
commit = True
44
tag = True
55

.cookiecutterrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ default_context:
5454
sphinx_doctest: "no"
5555
sphinx_theme: "sphinx-py3doc-enhanced-theme"
5656
test_matrix_separate_coverage: "no"
57-
version: 3.8.4
57+
version: 3.8.6
5858
version_manager: "bump2version"
5959
website: "https://github.com/NREL"
6060
year_from: "2023"

CHANGELOG.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ GEOPHIRES-X (2023-2025)
1313
Revenue & Cashflow Profile period output aligned with NREL convention used to calculate NPV.
1414
See https://github.com/NREL/GEOPHIRES-X/discussions/344
1515

16+
3.8.6: Baseline well drilling cost curves updated to NREL's 2025 cost curve update:
17+
Akindipe, D. and Witter. E. 2025. "2025 Geothermal Drilling Cost Curves Update". https://pangea.stanford.edu/ERE/db/GeoConf/papers/SGW/2025/Akindipe.pdf?t=1740084555.
18+
19+
Intermediate and ideal correlations retain existing values from GeoVision:
20+
DOE 2019. "GeoVision" p. 163. https://www.energy.gov/sites/prod/files/2019/06/f63/GeoVision-full-report-opt.pdf.
21+
1622
3.7
1723
^^^
1824

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ Free software: `MIT license <LICENSE>`__
5656
:alt: Supported implementations
5757
:target: https://pypi.org/project/geophires-x
5858

59-
.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.8.4.svg
59+
.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.8.6.svg
6060
:alt: Commits since latest release
61-
:target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.8.4...main
61+
:target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.8.6...main
6262

6363
.. |docs| image:: https://readthedocs.org/projects/GEOPHIRES-X/badge/?style=flat
6464
:target: https://nrel.github.io/GEOPHIRES-X

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
year = '2025'
1919
author = 'NREL'
2020
copyright = f'{year}, {author}'
21-
version = release = '3.8.4'
21+
version = release = '3.8.6'
2222

2323
pygments_style = 'trac'
2424
templates_path = ['./templates']

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def read(*names, **kwargs):
1313

1414
setup(
1515
name='geophires-x',
16-
version='3.8.4',
16+
version='3.8.6',
1717
license='MIT',
1818
description='GEOPHIRES is a free and open-source geothermal techno-economic simulator.',
1919
long_description='{}\n{}'.format(

src/geophires_x/Economics.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import numpy as np
55
import numpy_financial as npf
66
import geophires_x.Model as Model
7-
from geophires_x.OptionList import Configuration, WellDrillingCostCorrelation, EconomicModel, EndUseOptions, PlantType
7+
from geophires_x.OptionList import Configuration, WellDrillingCostCorrelation, EconomicModel, EndUseOptions, PlantType, \
8+
_WellDrillingCostCorrelationCitation
89
from geophires_x.Parameter import intParameter, floatParameter, OutputParameter, ReadParameter, boolParameter, \
910
coerce_int_params_to_enum_values
1011
from geophires_x.Units import *
@@ -1004,9 +1005,15 @@ def __init__(self, model: Model):
10041005
UnitType=Units.NONE,
10051006
ErrMessage="assume default well drilling cost correlation (10)",
10061007
ToolTipText="Select the built-in well drilling and completion cost correlation: " +
1007-
'; '.join([f'{it.int_value}: {it.value}' for it in WellDrillingCostCorrelation])
1008-
)
1008+
'; '.join([f'{it.int_value}: {it.value}'
1009+
for it in WellDrillingCostCorrelation]) +
1010+
f'. '
1011+
f'Baseline correlations (1-4) are from '
1012+
f'{_WellDrillingCostCorrelationCitation.NREL_COST_CURVE_2025.value}.'
1013+
f' Intermediate and ideal correlations (6-17) are from '
1014+
f'{_WellDrillingCostCorrelationCitation.GEOVISION.value}.'
10091015

1016+
)
10101017
self.DoAddOnCalculations = self.ParameterDict[self.DoAddOnCalculations.Name] = boolParameter(
10111018
"Do AddOn Calculations",
10121019
DefaultValue=False,

src/geophires_x/GeoPHIRESUtils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ def density_water_kg_per_m3(Twater_degC: float, pressure: Optional[PlainQuantity
252252

253253
except (NotImplementedError, ValueError) as e:
254254
raise ValueError(f'Input temperature & pressure ({Twater_degC}, {pressure}) '
255-
f'are out of range or otherwise could not be used to calculate') from e
255+
f'are out of range or otherwise could not be used to calculate water density.') from e
256256

257257

258258
def celsius_to_kelvin(celsius: float) -> float:
@@ -298,7 +298,7 @@ def viscosity_water_Pa_sec(
298298

299299
except (NotImplementedError, ValueError) as e:
300300
raise ValueError(f'Input temperature & pressure ({Twater_degC}, {pressure}) '
301-
f'are out of range or otherwise could not be used to calculate') from e
301+
f'are out of range or otherwise could not be used to calculate water viscosity.') from e
302302

303303

304304
@lru_cache
@@ -334,7 +334,7 @@ def heat_capacity_water_J_per_kg_per_K(
334334

335335
except (NotImplementedError, ValueError) as e:
336336
raise ValueError(f'Input temperature & pressure ({Twater_degC}, {pressure}) '
337-
f'are out of range or otherwise could not be used to calculate') from e
337+
f'are out of range or otherwise could not be used to calculate heat capacity of water.') from e
338338

339339

340340
@lru_cache

src/geophires_x/OptionList.py

Lines changed: 78 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class EndUseOptions(GeophiresInputEnum):
3636
COGENERATION_PARALLEL_EXTRA_ELECTRICITY = 52, "Cogeneration Parallel Cycle, Electricity sales considered as extra income"
3737

3838
@staticmethod
39-
def from_input_string(input_string:str):
39+
def from_input_string(input_string: str):
4040
"""
4141
:rtype: EndUseOptions
4242
"""
@@ -66,7 +66,7 @@ class PlantType(GeophiresInputEnum):
6666
INDUSTRIAL = 9, "Industrial"
6767

6868
@staticmethod
69-
def from_input_string(input_string:str):
69+
def from_input_string(input_string: str):
7070
"""
7171
:rtype: PlantType
7272
"""
@@ -97,7 +97,7 @@ def from_int(int_val):
9797
return member
9898

9999
@staticmethod
100-
def from_input_string(input_string:str):
100+
def from_input_string(input_string: str):
101101
for member in __class__:
102102
if input_string == str(member.int_value):
103103
return member
@@ -117,7 +117,7 @@ class ReservoirModel(GeophiresInputEnum):
117117
SBT = 8, "SBT"
118118

119119
@staticmethod
120-
def get_reservoir_model_from_input_string(input_string:str):
120+
def get_reservoir_model_from_input_string(input_string: str):
121121
"""
122122
:rtype: ReservoirModel
123123
"""
@@ -148,41 +148,89 @@ def from_int(int_val):
148148
return member
149149

150150
@staticmethod
151-
def from_input_string(input_string:str):
151+
def from_input_string(input_string: str):
152152
for member in __class__:
153153
if input_string == str(member.int_value):
154154
return member
155155

156156
raise ValueError(f'Unknown Reservoir Volume input value: {input_string}')
157157

158158

159+
class _WellDrillingCostCorrelationCitation(str, Enum):
160+
"""
161+
Values are abbreviated citations used in tooltip text.
162+
Commented full citations are present in CHANGELOG and could also be used in future documentation.
163+
"""
164+
165+
NREL_COST_CURVE_2025 = 'NREL\'s 2025 cost curve update'
166+
# ('Akindipe, D. and Witter. E. 2025. '
167+
# '"2025 Geothermal Drilling Cost Curves Update". '
168+
# 'https://pangea.stanford.edu/ERE/db/GeoConf/papers/SGW/2025/Akindipe.pdf?t=1740084555')
169+
170+
SIMPLE = 'Based on Fervo Project Cape cost per meter (~$1846/m)'
171+
172+
GEOVISION = 'GeoVision'
173+
# ('DOE 2019. '
174+
# '"GeoVision" p. 163. '
175+
# 'https://www.energy.gov/sites/prod/files/2019/06/f63/GeoVision-full-report-opt.pdf')
176+
177+
159178
class WellDrillingCostCorrelation(GeophiresInputEnum):
160-
"""Note: order must be retained since input is read as an int; first int arg is duplicative of order"""
161-
162-
VERTICAL_SMALL = 1, "vertical small diameter, baseline", 0.30212, 584.91124, 751368.47270
163-
DEVIATED_SMALL = 2, "deviated small diameter, baseline", 0.28977, 882.15067, 680562.50150
164-
VERTICAL_LARGE = 3, "vertical large diameter, baseline", 0.28180, 1275.52130, 632315.12640
165-
DEVIATED_LARGE = 4, "deviated large diameter, baseline", 0.25528, 1716.71568, 500866.89110
166-
167-
SIMPLE = 5, "Simple", 0, 1846*1E6, 0 # Based on Fervo Project Cape cost per meter (~$1846/m)
168-
169-
VERTICAL_SMALL_INT1 = 6, "vertical small diameter, intermediate1", 0.13710, 129.61033, 1205587.57100
170-
VERTICAL_SMALL_INT2 = 7, "vertical small diameter, intermediate2", 0.00804, 455.60507, 921007.68680
171-
DEVIATED_SMALL_INT1 = 8, "deviated small diameter, intermediate1", 0.15340, 120.31700, 1431801.54400
172-
DEVIATED_SMALL_INT2 = 9, "deviated small diameter, intermediate2", 0.00854, 506.08357, 1057330.39000
173-
VERTICAL_LARGE_INT1 = 10, "vertical large diameter, intermediate1", 0.18927, 293.45174, 1326526.31300
174-
VERTICAL_LARGE_INT2 = 11, "vertical large diameter, intermediate2", 0.00315, 782.69676, 983620.25270
175-
DEVIATED_LARGE_INT1 = 12, "deviated large diameter, intermediate1", 0.19950, 296.13011, 1697867.70900
176-
DEVIATED_LARGE_INT2 = 13, "deviated large diameter, intermediate2", 0.00380, 838.90249, 1181947.04400
177-
VERTICAL_SMALL_IDEAL = 14, "vertical open-hole, small diameter, ideal", 0.00252, 439.44503, 590611.90110
178-
DEVIATED_SMALL_IDEAL = 15, "deviated liner, small diameter, ideal", 0.00719, 455.85233, 753377.73080
179-
VERTICAL_LARGE_IDEAL = 16, "vertical open-hole, large diameter, ideal", -0.00240, 752.93946, 524337.65380
180-
DEVIATED_LARGE_IDEAL = 17, "deviated liner, large diameter, ideal", 0.00376, 762.52696, 765103.07690
181-
182-
def __init__(self, int_value: int, _: str, c2: float, c1: float, c0: float):
179+
"""
180+
Akindipe, D. and Witter. E. 2025.
181+
"2025 Geothermal Drilling Cost Curves Update".
182+
https://pangea.stanford.edu/ERE/db/GeoConf/papers/SGW/2025/Akindipe.pdf?t=1740084555
183+
184+
Robins, J.C., Kesseli, D., Witter, E. and Rhodes, G. 2022.
185+
"2022 GETEM Geothermal Drilling Cost Curve Update."
186+
https://www.nrel.gov/docs/fy23osti/82771.pdf
187+
188+
Note: order should be retained since input is read as an int; first int arg is duplicative of order
189+
"""
190+
191+
VERTICAL_SMALL = 1, "vertical small diameter, baseline", 0.258496, 357.967, 738531.58, \
192+
_WellDrillingCostCorrelationCitation.NREL_COST_CURVE_2025
193+
DEVIATED_SMALL = 2, "deviated small diameter, baseline", 0.240624, 646.1621, 503625.06, \
194+
_WellDrillingCostCorrelationCitation.NREL_COST_CURVE_2025
195+
VERTICAL_LARGE = 3, "vertical large diameter, baseline", 0.248458, 935.8985, 626586.68, \
196+
_WellDrillingCostCorrelationCitation.NREL_COST_CURVE_2025
197+
DEVIATED_LARGE = 4, "deviated large diameter, baseline", 0.217333, 1362.93, 301066.16, \
198+
_WellDrillingCostCorrelationCitation.NREL_COST_CURVE_2025
199+
200+
SIMPLE = 5, "Simple (per-meter cost)", 0, 1846 * 1E6, 0, \
201+
_WellDrillingCostCorrelationCitation.SIMPLE
202+
203+
VERTICAL_SMALL_INT1 = 6, "vertical small diameter, intermediate1", 0.13710, 129.61033, 1205587.57100, \
204+
_WellDrillingCostCorrelationCitation.GEOVISION
205+
VERTICAL_SMALL_INT2 = 7, "vertical small diameter, intermediate2", 0.00804, 455.60507, 921007.68680, \
206+
_WellDrillingCostCorrelationCitation.GEOVISION
207+
DEVIATED_SMALL_INT1 = 8, "deviated small diameter, intermediate1", 0.15340, 120.31700, 1431801.54400, \
208+
_WellDrillingCostCorrelationCitation.GEOVISION
209+
DEVIATED_SMALL_INT2 = 9, "deviated small diameter, intermediate2", 0.00854, 506.08357, 1057330.39000, \
210+
_WellDrillingCostCorrelationCitation.GEOVISION
211+
VERTICAL_LARGE_INT1 = 10, "vertical large diameter, intermediate1", 0.18927, 293.45174, 1326526.31300, \
212+
_WellDrillingCostCorrelationCitation.GEOVISION
213+
VERTICAL_LARGE_INT2 = 11, "vertical large diameter, intermediate2", 0.00315, 782.69676, 983620.25270, \
214+
_WellDrillingCostCorrelationCitation.GEOVISION
215+
DEVIATED_LARGE_INT1 = 12, "deviated large diameter, intermediate1", 0.19950, 296.13011, 1697867.70900, \
216+
_WellDrillingCostCorrelationCitation.GEOVISION
217+
DEVIATED_LARGE_INT2 = 13, "deviated large diameter, intermediate2", 0.00380, 838.90249, 1181947.04400, \
218+
_WellDrillingCostCorrelationCitation.GEOVISION
219+
VERTICAL_SMALL_IDEAL = 14, "vertical open-hole, small diameter, ideal", 0.00252, 439.44503, 590611.90110, \
220+
_WellDrillingCostCorrelationCitation.GEOVISION
221+
DEVIATED_SMALL_IDEAL = 15, "deviated liner, small diameter, ideal", 0.00719, 455.85233, 753377.73080, \
222+
_WellDrillingCostCorrelationCitation.GEOVISION
223+
VERTICAL_LARGE_IDEAL = 16, "vertical open-hole, large diameter, ideal", -0.00240, 752.93946, 524337.65380, \
224+
_WellDrillingCostCorrelationCitation.GEOVISION
225+
DEVIATED_LARGE_IDEAL = 17, "deviated liner, large diameter, ideal", 0.00376, 762.52696, 765103.07690, \
226+
_WellDrillingCostCorrelationCitation.GEOVISION
227+
228+
def __init__(self, int_value: int, _: str, c2: float, c1: float, c0: float,
229+
citation: _WellDrillingCostCorrelationCitation):
183230
self._c2 = c2
184231
self._c1 = c1
185232
self._c0 = c0
233+
self.citation: _WellDrillingCostCorrelationCitation = citation
186234
super().__init__(int_value, _)
187235

188236
def calculate_cost_MUSD(self, meters) -> float:
@@ -216,7 +264,7 @@ def from_int(int_val):
216264
return member
217265

218266
@staticmethod
219-
def from_input_string(input_string:str):
267+
def from_input_string(input_string: str):
220268
for member in __class__:
221269
if input_string == str(member.int_value):
222270
return member
@@ -243,8 +291,6 @@ def from_input_string(input_string: str):
243291
raise ValueError(f'Unknown Working Fluid input value: {input_string}')
244292

245293

246-
247-
248294
class Configuration(GeophiresInputEnum):
249295
ULOOP = 1, "utube"
250296
COAXIAL = 2, "coaxial"
@@ -285,6 +331,7 @@ def from_input_string(input_string: str):
285331

286332
raise ValueError(f'Unknown Flow Rate Model input value: {input_string}')
287333

334+
288335
class InjectionTemperatureModel(GeophiresInputEnum):
289336
USER_SUPPLIED = 1, "user supplied"
290337
FILE_SUPPLIED = 2, "file supplied"

src/geophires_x/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '3.8.4'
1+
__version__ = '3.8.6'

0 commit comments

Comments
 (0)