Skip to content

Commit

Permalink
Merge pull request NREL#126 from softwareengineerprogrammer/main
Browse files Browse the repository at this point in the history
Hydrostatic-aware vapor pressure; >7km simple well cost correlation; other fixes (v3.4.4)

* NREL#118
* NREL#65
  • Loading branch information
softwareengineerprogrammer authored Feb 18, 2024
2 parents ed16813 + 7171142 commit d04896c
Show file tree
Hide file tree
Showing 34 changed files with 1,752 additions and 1,178 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 3.4.3
current_version = 3.4.4
commit = True
tag = True

Expand Down
2 changes: 1 addition & 1 deletion .cookiecutterrc
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ default_context:
sphinx_doctest: "no"
sphinx_theme: "sphinx-py3doc-enhanced-theme"
test_matrix_separate_coverage: "no"
version: 3.4.3
version: 3.4.4
version_manager: "bump2version"
website: "https://github.com/NREL"
year_from: "2023"
Expand Down
17 changes: 10 additions & 7 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,38 @@ GEOPHIRES-X (2023-2024)

3.4
^^^
Monte Carlo moved to dedicated module

`diff <https://github.com/NREL/GEOPHIRES-X/compare/v3.3.0...v3.4.0>`__
`release <https://github.com/NREL/GEOPHIRES-X/releases/tag/v3.4.0>`__ | `diff <https://github.com/NREL/GEOPHIRES-X/compare/v3.3.0...v3.4.0>`__

Monte Carlo moved to dedicated module

3.3
^^^

`release <https://github.com/NREL/GEOPHIRES-X/releases/tag/v3.3.0>`__ | `diff <https://github.com/NREL/GEOPHIRES-X/compare/v3.2.0...v3.3.0>`__

- Surface plant objectification. Note: some input values of ``End-Use Option`` will need to be updated to ``Plant Type``, see `SUTRAExample1.txt update for example <https://github.com/softwareengineerprogrammer/GEOPHIRES-X/commit/c7ded3dbf01577d9f92fe39ee8cc921e0cf4b9e2#diff-2defdec554de21ee27fb205f3418b138d8c55fa74ea49281f536e9453df4c973R30-R32>`__
- Introduction of HIP-RA-X

`diff <https://github.com/NREL/GEOPHIRES-X/compare/v3.2.0...v3.3.0>`__


3.2
^^^
Bug fixes
`release <https://github.com/NREL/GEOPHIRES-X/releases/tag/v3.2.0>`__ | `diff <https://github.com/NREL/GEOPHIRES-X/compare/v3.1.0...v3.2.0>`__

`diff <https://github.com/NREL/GEOPHIRES-X/compare/v3.1.0...v3.2.0>`__
Bug fixes

3.1
^^^
Internal changes to support unit testing
`release <https://github.com/NREL/GEOPHIRES-X/releases/tag/v3.1.0>`__ | `diff <https://github.com/NREL/GEOPHIRES-X/compare/v3.0.0...v3.1.0>`__

`diff <https://github.com/NREL/GEOPHIRES-X/compare/v3.0.0...v3.1.0>`__
Internal changes to support unit testing


3.0
^^^
`release <https://github.com/NREL/GEOPHIRES-X/releases/tag/v3.0.0>`__

- New repository: https://github.com/NREL/GEOPHIRES-X (Originally https://github.com/NREL/python-geophires-x, renamed to GEOPHIRES-X 2023-12-15 per https://github.com/NREL/GEOPHIRES-X/issues/48.)
- Ported from `malcolm-dsider/GEOPHIRES-X <https://github.com/malcolm-dsider/GEOPHIRES-X>`__ and `softwareengineerprogrammer/python-geophires-x <https://github.com/softwareengineerprogrammer/python-geophires-x>`__ using `ionelmc/cookiecutter-pylibrary <https://github.com/ionelmc/cookiecutter-pylibrary/>`__.
- Releases now marked with tags/version metadata generated with ``bumpversion``
Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ Free software: `MIT license <LICENSE>`__
:alt: Supported implementations
:target: https://pypi.org/project/geophires-x

.. |commits-since| image:: https://img.shields.io/github/commits-since/NREL/GEOPHIRES-X/v3.4.3.svg
.. |commits-since| image:: https://img.shields.io/github/commits-since/NREL/GEOPHIRES-X/v3.4.4.svg
:alt: Commits since latest release
:target: https://github.com/NREL/GEOPHIRES-X/compare/v3.4.3...main
:target: https://github.com/NREL/GEOPHIRES-X/compare/v3.4.4...main

.. |docs| image:: https://readthedocs.org/projects/GEOPHIRES-X/badge/?style=flat
:target: https://nrel.github.io/GEOPHIRES-X
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
year = '2023'
author = 'NREL'
copyright = f'{year}, {author}'
version = release = '3.4.3'
version = release = '3.4.4'

pygments_style = 'trac'
templates_path = ['./templates']
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def read(*names, **kwargs):

setup(
name='geophires-x',
version='3.4.3',
version='3.4.4',
license='MIT',
description='GEOPHIRES is a free and open-source geothermal techno-economic simulator.',
long_description='{}\n{}'.format(
Expand Down
12 changes: 6 additions & 6 deletions src/geophires_x/AGSWellBores.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,10 @@ def interp_outlet_states(self, point):
Pout = interpn(self.ivars, self.Pout, points)

except BaseException as ex:
tb = sys.exc_info()[2]
print(str(ex))
print("Error: AGS Wellbores: interp_outlet_states failed. Exiting....Line %i" % tb.tb_lineno)
sys.exit()
msg = 'Error: AGSWellBores: interp_outlet_states failed.'
print(msg)
raise RuntimeError(msg) from ex
return Tout, Pout

def interp_kWe_avg(self, point):
Expand Down Expand Up @@ -635,10 +635,10 @@ def __init__(self, model: Model):
CurrentUnits=PressureUnit.KPASCAL
)

model.logger.info("complete " + str(__class__) + ": " + sys._getframe().f_code.co_name)
model.logger.info(f'complete {__class__!s}: {sys._getframe().f_code.co_name}')

def __str__(self):
return "AGSWellBores"
return 'AGSWellBores'

def read_parameters(self, model: Model) -> None:
"""
Expand Down Expand Up @@ -734,7 +734,7 @@ def initialize(self, model: Model) -> None:
:type model: :class:`~geophires_x.Model.Model`
:return: None
"""
model.logger.info("Init " + str(__class__) + ": " + sys._getframe().f_code.co_name)
model.logger.info(f'Init {__class__!s}: {sys._getframe().f_code.co_name}')

if self.Fluid.value == WorkingFluid.WATER:
if self.Configuration.value == Configuration.ULOOP:
Expand Down
38 changes: 21 additions & 17 deletions src/geophires_x/Economics.py
Original file line number Diff line number Diff line change
Expand Up @@ -1756,7 +1756,7 @@ def Calculate(self, model: Model) -> None:
:type model: :class:`~geophires_x.Model.Model`
:return: Nothing, but it does make calculations and set values in the model
"""
model.logger.info("Init " + str(__class__) + ": " + sys._getframe().f_code.co_name)
model.logger.info(f'Init {__class__!s}: {sys._getframe().f_code.co_name}')

# capital costs
# well costs (using GeoVision drilling correlations). These are calculated whether totalcapcostvalid = 1
Expand All @@ -1766,40 +1766,44 @@ def Calculate(self, model: Model) -> None:
self.Cwell.value = self.C1well * (model.wellbores.nprod.value + model.wellbores.ninj.value)
else:
# if depth is > 7000 m, we don't have a correlation for it, so we must use the SIMPLE logic
checkdepth = model.reserv.depth.value
if model.reserv.depth.CurrentUnits != LengthUnit.METERS:
checkdepth = checkdepth * 1000.0
checkdepth = model.reserv.depth.quantity().to('m').magnitude
if (
checkdepth > 7000.0 or checkdepth < 500) and not self.wellcorrelation.value == WellDrillingCostCorrelation.SIMPLE:
print("Warning: simple user-specified cost per meter used for drilling depth < 500 or > 7000 m")
model.logger.warning(
"Warning: simple user-specified cost per meter used for drilling depth < 500 or > 7000 m")
msg = f'Simple user-specified cost per meter used for drilling depth <500 or >7000 m ({checkdepth}m)'
print(f'Warning: {msg}')
model.logger.warning(msg)
self.wellcorrelation.value = WellDrillingCostCorrelation.SIMPLE
if self.wellcorrelation.value == WellDrillingCostCorrelation.SIMPLE: # use SIMPLE approach

if self.wellcorrelation.value == WellDrillingCostCorrelation.SIMPLE:
# use SIMPLE approach
if hasattr(model.wellbores, 'Configuration'):
if model.wellbores.Configuration.value == Configuration.ULOOP:
if hasattr(model.reserv,
'InputDepth'): # must be using simple cylindrical model, which has an Input and Output Depth
if hasattr(model.reserv, 'InputDepth'):
# must be using simple cylindrical model, which has an Input and Output Depth
self.C1well = ((self.Vertical_drilling_cost_per_m.value *
(model.reserv.InputDepth.value * 1000.0)) +
(model.reserv.InputDepth.quantity().to('m').magnitude)) +
(self.Vertical_drilling_cost_per_m.value * (
model.reserv.OutputDepth.value * 1000.0)) +
model.reserv.OutputDepth.quantity().to('m').magnitude)) +
(
self.Nonvertical_drilling_cost_per_m.value * model.wellbores.Nonvertical_length.value)) * 1E-6
else:
if hasattr(model.wellbores, 'Nonvertical_length'):
self.C1well = ((2 * self.Vertical_drilling_cost_per_m.value *
(model.reserv.depth.value * 1000.0)) +
(model.reserv.depth.quantity().to('m').magnitude)) +
(
self.Nonvertical_drilling_cost_per_m.value * model.wellbores.Nonvertical_length.value)) * 1E-6
else:
self.C1well = (2 * self.Vertical_drilling_cost_per_m.value * (
model.reserv.depth.value * 1000.0)) * 1E-6
else: # Coaxial
self.C1well = ((self.Vertical_drilling_cost_per_m.value * (model.reserv.depth.value * 1000.0)) +
model.reserv.depth.value.quantity().to('m').magnitude)) * 1E-6
else:
# Coaxial
self.C1well = ((self.Vertical_drilling_cost_per_m.value * (model.reserv.depth.quantity().to('m').magnitude)) +
(
self.Nonvertical_drilling_cost_per_m.value * model.wellbores.Nonvertical_length.value)) * 1E-6

else:
self.C1well = self.Vertical_drilling_cost_per_m.value * model.reserv.depth.quantity().to(
'm').magnitude * 1E-6
elif self.wellcorrelation.value == WellDrillingCostCorrelation.VERTICAL_SMALL:
self.C1well = (
0.3021 * checkdepth ** 2 + 584.9112 * checkdepth + 751368.) * 1E-6 # well drilling and completion cost in M$/well
Expand Down Expand Up @@ -2279,7 +2283,7 @@ def Calculate(self, model: Model) -> None:
# Calculate LCOE/LCOH
self.LCOE.value, self.LCOH.value, self.LCOC.value = CalculateLCOELCOH(self, model)

model.logger.info("complete " + str(__class__) + ": " + sys._getframe().f_code.co_name)
model.logger.info(f'complete {__class__!s}: {sys._getframe().f_code.co_name}')

def __str__(self):
return "Economics"
6 changes: 3 additions & 3 deletions src/geophires_x/Model.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def __init__(self, enable_geophires_logging_config=True, input_file=None):
self.reserv: Reservoir = SUTRAReservoir(self) # SUTRA output is created

# initialize the default objects
self.wellbores = WellBores(self)
self.wellbores: WellBores = WellBores(self)
self.surfaceplant = SurfacePlant(self)
self.economics = Economics(self)

Expand All @@ -117,7 +117,7 @@ def __init__(self, enable_geophires_logging_config=True, input_file=None):
if 'Reservoir Model' in self.InputParameters:
if self.InputParameters['Reservoir Model'].sValue == '7':
# if we use SUTRA output for simulating reservoir thermal energy storage, we use a special wellbore object that can handle SUTRA data
self.wellbores = SUTRAWellBores(self)
self.wellbores: WellBores = SUTRAWellBores(self)
self.surfaceplant = SurfacePlantSUTRA(self)
self.economics = SUTRAEconomics(self)
self.outputs = SUTRAOutputs(self, output_file=output_file)
Expand All @@ -130,7 +130,7 @@ def __init__(self, enable_geophires_logging_config=True, input_file=None):
# that means importing them, initializing them, then reading their parameters
# use the simple cylindrical reservoir for all AGS systems.
self.reserv: Reservoir = CylindricalReservoir(self)
self.wellbores = AGSWellBores(self)
self.wellbores: WellBores = AGSWellBores(self)
self.surfaceplant = SurfacePlantAGS(self)
self.economics = AGSEconomics(self)
self.outputs = AGSOutputs(self, output_file=output_file)
Expand Down
6 changes: 5 additions & 1 deletion src/geophires_x/Outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,11 @@ def PrintOutputs(self, model: Model):
f.write(f" Initial Net Electricity Generation: {model.surfaceplant.NetElectricityProduced.value[0]:10.2f} " + model.surfaceplant.NetElectricityProduced.PreferredUnits.value + NL)
f.write(f" Average Annual Total Electricity Generation: {np.average(model.surfaceplant.TotalkWhProduced.value/1E6):10.2f} GWh" + NL)
f.write(f" Average Annual Net Electricity Generation: {np.average(model.surfaceplant.NetkWhProduced.value/1E6):10.2f} GWh" + NL)
if model.wellbores.PumpingPower.value[0] > 0.0: f.write(f" Initial pumping power/net installed power: {(model.wellbores.PumpingPower.value[0]/model.wellbores.PumpingPower.value[0]*100):10.2f} %" + NL)

if model.wellbores.PumpingPower.value[0] > 0.0:
ipp_nip = model.wellbores.PumpingPower.value[0] / model.surfaceplant.NetElectricityProduced.value[0]
f.write(f' Initial pumping power/net installed power: {(ipp_nip*100):10.2f} %\n')

if model.surfaceplant.enduse_option.value in [EndUseOptions.HEAT, PlantType.ABSORPTION_CHILLER, PlantType.HEAT_PUMP, EndUseOptions.COGENERATION_TOPPING_EXTRA_HEAT, EndUseOptions.COGENERATION_TOPPING_EXTRA_ELECTRICITY, EndUseOptions.COGENERATION_BOTTOMING_EXTRA_ELECTRICITY, EndUseOptions.COGENERATION_BOTTOMING_EXTRA_HEAT, EndUseOptions.COGENERATION_PARALLEL_EXTRA_HEAT, EndUseOptions.COGENERATION_PARALLEL_EXTRA_ELECTRICITY]: # geothermal heating component:
f.write(f" Maximum Net Heat Production: {np.max(model.surfaceplant.HeatProduced.value):10.2f} " + model.surfaceplant.HeatProduced.PreferredUnits.value + NL)
f.write(f" Average Net Heat Production: {np.average(model.surfaceplant.HeatProduced.value):10.2f} " + model.surfaceplant.HeatProduced.PreferredUnits.value + NL)
Expand Down
6 changes: 5 additions & 1 deletion src/geophires_x/Parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,11 @@ class listParameter(Parameter):
which means that any value is valid by default
"""

value: List[float] = field(default_factory=list) # FIXME set from DefaultValue
def __post_init__(self):
if self.value is None:
self.value:str = self.DefaultValue

value: List[float] = None
DefaultValue: List[float] = field(default_factory=list)
Min: float = -1.8e308
Max: float = 1.8e308
Expand Down
10 changes: 6 additions & 4 deletions src/geophires_x/WellBores.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ def ProdPressureDropAndPumpingPowerUsingIndexes(
# Minimum production pump inlet pressure and minimum wellhead pressure
Pminimum_kPa = vapor_pressure_water_kPa(
Trock_degC,
# TODO pass pressure https://github.com/NREL/GEOPHIRES-X/issues/118
pressure=quantity(Phydrostaticcalc_kPa, 'kPa'),
) + Pexcess_kPa

if usebuiltinppwellheadcorrelation:
Expand Down Expand Up @@ -496,7 +496,7 @@ def InjPressureDropAndPumpingPowerUsingIndexes(
# Minimum production pump inlet pressure and minimum wellhead pressure
Pminimum_kPa = vapor_pressure_water_kPa(
Trock_degC,
# TODO pass pressure https://github.com/NREL/GEOPHIRES-X/issues/118
pressure=quantity(Phydrostaticcalc_kPa, 'kPa'),
) + Pexcess_kPa

if usebuiltinppwellheadcorrelation:
Expand Down Expand Up @@ -1029,7 +1029,8 @@ def Calculate(self, model: Model) -> None:
model, self.Tinj.value, self.prodwellflowrate.value, self.injwelldiam.value, self.impedancemodelused.value,
model.reserv.depth.value, self.nprod.value, self.ninj.value, model.reserv.waterloss.value)

if self.impedancemodelused.value: # assumed everything stays liquid throughout, based on TARB in Geophires v1.2
if self.impedancemodelused.value:
# assumed everything stays liquid throughout, based on TARB in Geophires v1.2
self.DPOverall.value, self.PumpingPower.value, self.DPProdWell.value, self.DPReserv.value, self.DPBouyancy.value = \
ProdPressureDropsAndPumpingPowerUsingImpedenceModel(f3, vprod, self.rhowaterinj, self.rhowaterprod,
model.reserv.rhowater.value,
Expand All @@ -1046,7 +1047,8 @@ def Calculate(self, model: Model) -> None:
model.surfaceplant.pump_efficiency.value,
self.DPOverall.value)

else: # PI and II are used
else:
# PI and II are used
self.PumpingPower.value, self.PumpingPowerProd.value, self.DPProdWell.value, self.Pprodwellhead.value = \
ProdPressureDropAndPumpingPowerUsingIndexes(model,
self.productionwellpumping.value,
Expand Down
2 changes: 1 addition & 1 deletion src/geophires_x/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '3.4.3'
__version__ = '3.4.4'
1 change: 1 addition & 0 deletions src/geophires_x_client/geophires_x_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ class GeophiresXResult:
'Minimum Peaking Boiler Heat Production',
# AGS/CLGS
'Surface Plant Cost',
'Initial pumping power/net installed power',
# SUTRA
'Average RTES Heating Production',
'Average Auxiliary Heating Production',
Expand Down
Loading

0 comments on commit d04896c

Please sign in to comment.