Skip to content

Commit 64c6904

Browse files
Merge pull request #79 from softwareengineerprogrammer/immutable-geophires-input-parameters
Client caching fix (ImmutableGeophiresInputParameters); Fervo_Project_Cape-4 Multilaterals & Reservoir Volume
2 parents 370e136 + 3fdc98d commit 64c6904

28 files changed

+1708
-334
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.9.19
2+
current_version = 3.9.26
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.9.19
57+
version: 3.9.26
5858
version_manager: "bump2version"
5959
website: "https://github.com/NREL"
6060
year_from: "2023"

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.9.19.svg
59+
.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.9.26.svg
6060
:alt: Commits since latest release
61-
:target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.9.19...main
61+
:target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.9.26...main
6262

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

docs/Fervo_Project_Cape-4.md

Lines changed: 22 additions & 22 deletions
Large diffs are not rendered by default.

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.9.19'
21+
version = release = '3.9.26'
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.9.19',
16+
version='3.9.26',
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: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,17 +1125,17 @@ def __init__(self, model: Model):
11251125
ErrMessage="assume default peaking boiler efficiency (85%)",
11261126
ToolTipText="Peaking boiler efficiency"
11271127
)
1128-
self._default_peaking_boiler_cost_USD_per_kw = 65
1129-
self.peaking_boiler_cost_per_kw = self.ParameterDict[self.peaking_boiler_cost_per_kw.Name] = floatParameter(
1130-
"Peaking Boiler Cost per KW",
1131-
DefaultValue=self._default_peaking_boiler_cost_USD_per_kw,
1128+
self._default_peaking_boiler_cost_USD_per_kW = 65
1129+
self.peaking_boiler_cost_per_kW = self.ParameterDict[self.peaking_boiler_cost_per_kW.Name] = floatParameter(
1130+
"Peaking Boiler Cost per kW",
1131+
DefaultValue=self._default_peaking_boiler_cost_USD_per_kW,
11321132
Min=0,
11331133
Max=1000,
11341134
UnitType=Units.ENERGYCOST,
11351135
PreferredUnits=EnergyCostUnit.DOLLARSPERKW,
11361136
CurrentUnits=EnergyCostUnit.DOLLARSPERKW,
11371137
Required=False,
1138-
ToolTipText="Peaking boiler cost per KW of maximum peaking boiler demand"
1138+
ToolTipText="Peaking boiler cost per kW of maximum peaking boiler demand"
11391139
)
11401140
self.dhpipingcostrate = self.ParameterDict[self.dhpipingcostrate.Name] = floatParameter(
11411141
"District Heating Piping Cost Rate",
@@ -1633,18 +1633,29 @@ def __init__(self, model: Model):
16331633
f'Provide {self.ccexplfixed.Name} to override the default correlation and set your own cost.'
16341634
)
16351635

1636+
# noinspection SpellCheckingInspection
16361637
self.Cwell = self.OutputParameterDict[self.Cwell.Name] = OutputParameter(
16371638
Name="Wellfield cost",
16381639
display_name='Drilling and completion costs',
16391640
UnitType=Units.CURRENCY,
16401641
PreferredUnits=CurrencyUnit.MDOLLARS,
16411642
CurrentUnits=CurrencyUnit.MDOLLARS,
16421643

1643-
# See TODO re:parameterizing indirect costs at src/geophires_x/Economics.py:652
1644-
# (https://github.com/NREL/GEOPHIRES-X/issues/383)
1644+
# TODO https://github.com/NREL/GEOPHIRES-X/issues/383?title=Parameterize+indirect+cost+factor
16451645
ToolTipText="Includes total drilling and completion cost of all injection and production wells and "
16461646
"laterals, plus 5% indirect costs."
16471647
)
1648+
self.drilling_and_completion_costs_per_well = self.OutputParameterDict[
1649+
self.drilling_and_completion_costs_per_well.Name] = OutputParameter(
1650+
Name='Drilling and completion costs per well',
1651+
UnitType=Units.CURRENCY,
1652+
PreferredUnits=CurrencyUnit.MDOLLARS,
1653+
CurrentUnits=CurrencyUnit.MDOLLARS,
1654+
1655+
# TODO https://github.com/NREL/GEOPHIRES-X/issues/383?title=Parameterize+indirect+cost+factor
1656+
ToolTipText='Includes total drilling and completion cost per well, '
1657+
'including injection and production wells and laterals, plus 5% indirect costs.'
1658+
)
16481659
self.Coamwell = self.OutputParameterDict[self.Coamwell.Name] = OutputParameter(
16491660
Name="O&M Wellfield cost",
16501661
display_name='Wellfield maintenance costs',
@@ -1722,9 +1733,9 @@ def __init__(self, model: Model):
17221733
UnitType=Units.CURRENCY,
17231734
PreferredUnits=CurrencyUnit.MDOLLARS,
17241735
CurrentUnits=CurrencyUnit.MDOLLARS,
1725-
ToolTipText=f'Default cost: ${self._default_peaking_boiler_cost_USD_per_kw}/KW '
1736+
ToolTipText=f'Default cost: ${self._default_peaking_boiler_cost_USD_per_kW}/KW '
17261737
f'of maximum peaking boiler demand. '
1727-
f'Provide {self.peaking_boiler_cost_per_kw.Name} override the default.'
1738+
f'Provide {self.peaking_boiler_cost_per_kW.Name} override the default.'
17281739
)
17291740

17301741
self.dhdistrictcost = self.OutputParameterDict[self.dhdistrictcost.Name] = OutputParameter(
@@ -2313,7 +2324,9 @@ def Calculate(self, model: Model) -> None:
23132324
else:
23142325
self.cost_lateral_section.value = 0.0
23152326
# cost of the well field
2316-
# 1.05 for 5% indirect costs - see TODO re:parameterizing at src/geophires_x/Economics.py:652
2327+
2328+
# 1.05 for 5% indirect costs
2329+
# TODO https://github.com/NREL/GEOPHIRES-X/issues/383?title=Parameterize+indirect+cost+factor
23172330
self.Cwell.value = 1.05 * ((self.cost_one_production_well.value * model.wellbores.nprod.value) +
23182331
(self.cost_one_injection_well.value * model.wellbores.ninj.value) +
23192332
self.cost_lateral_section.value)
@@ -2685,7 +2698,7 @@ def calculate_plant_costs(self, model:Model) -> None:
26852698
model.surfaceplant.HeatExtracted.value) * 1000.
26862699

26872700
# add 65$/KW for peaking boiler
2688-
self.peakingboilercost.value = (self.peaking_boiler_cost_per_kw.quantity()
2701+
self.peakingboilercost.value = (self.peaking_boiler_cost_per_kW.quantity()
26892702
.to('USD / kilowatt').magnitude
26902703
* model.surfaceplant.max_peaking_boiler_demand.value / 1000)
26912704

@@ -2972,6 +2985,7 @@ def calculate_cashflow(self, model: Model) -> None:
29722985
for i in range(1, model.surfaceplant.plant_lifetime.value + model.surfaceplant.construction_years.value, 1):
29732986
self.TotalCummRevenue.value[i] = self.TotalCummRevenue.value[i-1] + self.TotalRevenue.value[i]
29742987

2988+
# noinspection SpellCheckingInspection
29752989
def _calculate_derived_outputs(self, model: Model) -> None:
29762990
"""
29772991
Subclasses should call _calculate_derived_outputs at the end of their Calculate methods to populate output
@@ -2988,5 +3002,11 @@ def _calculate_derived_outputs(self, model: Model) -> None:
29883002
self.real_discount_rate.value = self.discountrate.quantity().to(convertible_unit(
29893003
self.real_discount_rate.CurrentUnits)).magnitude
29903004

3005+
if hasattr(self, 'Cwell') and hasattr(model.wellbores, 'nprod') and hasattr(model.wellbores, 'ninj'):
3006+
self.drilling_and_completion_costs_per_well.value = (
3007+
self.Cwell.value /
3008+
(model.wellbores.nprod.value + model.wellbores.ninj.value)
3009+
)
3010+
29913011
def __str__(self):
29923012
return "Economics"

src/geophires_x/EconomicsSam.py

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@
3838
project_vir_parameter,
3939
project_payback_period_parameter,
4040
)
41-
from geophires_x.GeoPHIRESUtils import is_float, is_int
41+
from geophires_x.GeoPHIRESUtils import is_float, is_int, sig_figs
4242
from geophires_x.OptionList import EconomicModel, EndUseOptions
4343
from geophires_x.Parameter import Parameter, OutputParameter, floatParameter
44-
from geophires_x.Units import convertible_unit, EnergyCostUnit, CurrencyUnit, Units, PercentUnit
44+
from geophires_x.Units import convertible_unit, EnergyCostUnit, CurrencyUnit, Units
4545

4646

4747
@dataclass
@@ -162,7 +162,7 @@ def calculate_sam_economics(model: Model) -> SamEconomicsCalculations:
162162
cash_flow = _calculate_sam_economics_cash_flow(model, single_owner)
163163

164164
def sf(_v: float, num_sig_figs: int = 5) -> float:
165-
return _sig_figs(_v, num_sig_figs)
165+
return sig_figs(_v, num_sig_figs)
166166

167167
sam_economics: SamEconomicsCalculations = SamEconomicsCalculations(sam_cash_flow_profile=cash_flow)
168168
sam_economics.lcoe_nominal.value = sf(single_owner.Outputs.lcoe_nom)
@@ -435,21 +435,3 @@ def _ppa_pricing_model(
435435

436436
def _get_max_total_generation_kW(model: Model) -> float:
437437
return np.max(model.surfaceplant.ElectricityProduced.quantity().to(convertible_unit('kW')).magnitude)
438-
439-
440-
def _sig_figs(val: float | list | tuple, num_sig_figs: int) -> float:
441-
"""
442-
TODO move to utilities, probably
443-
"""
444-
445-
if val is None:
446-
return None
447-
448-
if isinstance(val, list) or isinstance(val, tuple):
449-
return [_sig_figs(v, num_sig_figs) for v in val]
450-
451-
try:
452-
return float('%s' % float(f'%.{num_sig_figs}g' % val)) # pylint: disable=consider-using-f-string
453-
except TypeError:
454-
# TODO warn
455-
return val

src/geophires_x/GeoPHIRESUtils.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,3 +642,16 @@ def is_float(o: Any) -> bool:
642642
else:
643643
return True
644644

645+
646+
def sig_figs(val: float | list | tuple, num_sig_figs: int) -> float:
647+
if val is None:
648+
return None
649+
650+
if isinstance(val, list) or isinstance(val, tuple):
651+
return [sig_figs(v, num_sig_figs) for v in val]
652+
653+
try:
654+
return float('%s' % float(f'%.{num_sig_figs}g' % val)) # pylint: disable=consider-using-f-string
655+
except TypeError:
656+
# TODO warn
657+
return val

src/geophires_x/Outputs.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,8 @@ def PrintOutputs(self, model: Model):
458458
f.write(f' Drilling and completion costs per production well: {econ.cost_one_production_well.value:10.2f} ' + econ.cost_one_production_well.CurrentUnits.value + NL)
459459
f.write(f' Drilling and completion costs per injection well: {econ.cost_one_injection_well.value:10.2f} ' + econ.cost_one_injection_well.CurrentUnits.value + NL)
460460
else:
461-
f.write(f' Drilling and completion costs per well: {model.economics.Cwell.value/(model.wellbores.nprod.value+model.wellbores.ninj.value):10.2f} ' + model.economics.Cwell.CurrentUnits.value + NL)
461+
cpw_label = Outputs._field_label(econ.drilling_and_completion_costs_per_well.display_name, 47)
462+
f.write(f' {cpw_label}{econ.drilling_and_completion_costs_per_well.value:10.2f} {econ.Cwell.CurrentUnits.value}\n')
462463
f.write(f' {econ.Cstim.display_name}: {econ.Cstim.value:10.2f} {econ.Cstim.CurrentUnits.value}\n')
463464
f.write(f' Surface power plant costs: {model.economics.Cplant.value:10.2f} ' + model.economics.Cplant.CurrentUnits.value + NL)
464465
if model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER:

0 commit comments

Comments
 (0)