Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/fervo-case-study' into fervo-cas…
Browse files Browse the repository at this point in the history
…e-study
  • Loading branch information
malcolm-dsider committed May 15, 2024
2 parents 0086c8f + 222c7db commit b83df0b
Show file tree
Hide file tree
Showing 62 changed files with 330 additions and 90 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.28
current_version = 3.4.29
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.28
version: 3.4.29
version_manager: "bump2version"
website: "https://github.com/NREL"
year_from: "2023"
Expand Down
8 changes: 5 additions & 3 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/softwareengineerprogrammer/GEOPHIRES-X/v3.4.28.svg
.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.4.29.svg
:alt: Commits since latest release
:target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.4.28...main
:target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.4.29...main

.. |docs| image:: https://readthedocs.org/projects/GEOPHIRES-X/badge/?style=flat
:target: https://nrel.github.io/GEOPHIRES-X
Expand All @@ -65,7 +65,9 @@ Getting Started
Web Interface
-------------

A web interface is available at `bit.ly/GEOPHIRES <https://bit.ly/GEOPHIRES>`__
A web interface is available at `scientificwebservices.com/tools/geophires <https://scientificwebservices.com/tools/geophires>`__.

The short URL `bit.ly/GEOPHIRES <https://bit.ly/GEOPHIRES>`__ redirects to the same location.

Installation
------------
Expand Down
1 change: 1 addition & 0 deletions References/fervo_energy_white_paper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[fervo_energy_white_paper.pdf](https://github.com/NREL/GEOPHIRES-X/blob/703c967b0b1fe9f6d619b1e786686ba07fb0fe59/References/fervo_energy_white_paper.pdf)
Binary file removed References/fervo_energy_white_paper.pdf
Binary file not shown.
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.28'
version = release = '3.4.29'

pygments_style = 'trac'
templates_path = ['./templates']
Expand Down
9 changes: 9 additions & 0 deletions docs/reference/geophires_x.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ geophires_x
.. automodule:: geophires_x.TDPReservoir
:members:

.. automodule:: geophires_x.LHSReservoir
:members:

.. automodule:: geophires_x.MPFReservoir
:members:

.. automodule:: geophires_x.SFReservoir
:members:

.. automodule:: geophires_x.CylindricalReservoir
:members:

Expand Down
3 changes: 2 additions & 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.28',
version='3.4.29',
license='MIT',
description='GEOPHIRES is a free and open-source geothermal techno-economic simulator.',
long_description='{}\n{}'.format(
Expand Down Expand Up @@ -78,6 +78,7 @@ def read(*names, **kwargs):
'iapws',
'coolprop',
'rich',
'pylocker',
],
extras_require={
# eg:
Expand Down
85 changes: 67 additions & 18 deletions src/geophires_monte_carlo/MC_GeoPHIRES3.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from pylocker import Locker
from rich.console import Console
from rich.table import Table

Expand Down Expand Up @@ -291,8 +292,13 @@ def get_output(output):
result_s = result_s.strip(' ').strip(',') # get rid of last space and comma
result_s += '\n'

with open(output_file, 'a') as f:
f.write(result_s)
# write the result to a file in a concurrent thread safe way
lock_pass = str(uuid.uuid1())
FL = Locker(filePath=output_file, lockPass=lock_pass, timeout=10, mode='a')
with FL as r:
acquired, code, fd = r
if fd is not None:
fd.write(result_s)


def main(command_line_args=None):
Expand Down Expand Up @@ -440,19 +446,14 @@ def main(command_line_args=None):
result_count = result_count + 1
if '-9999.0' not in line and len(s) > 1:
line = line.strip()
if len(line) > 3:
if len(line) > 10:
line, sep, tail = line.partition(', (') # strip off the Input Variable Values
line = line.replace('(', '').replace(')', '') # strip off the ()
results.append([float(y) for y in line.split(',')])
else:
logger.warning(f'-9999.0 or space found in line {result_count!s}')

actual_records_count = len(results)

# Load the results into a pandas dataframe
results_pd = pd.read_csv(output_file)
df = pd.DataFrame(results_pd)

if len(results) < 1:
# TODO surface actual exceptions instead of giving this generic message
raise RuntimeError(
Expand All @@ -469,25 +470,72 @@ def main(command_line_args=None):
means = np.nanmean(results, 0)
std = np.nanstd(results, 0)

# Load the results into a pandas dataframe
results_pd = pd.read_csv(output_file)
df = pd.DataFrame(results_pd)

# Build a second dataframe to contain the input data. In the df dataframe, it is too encoded to be useful
input_df = pd.DataFrame()

# add the columns
input_row = df[df.columns[len(outputs)]].tolist()[0]
input_row = input_row.replace('(', '').replace(')', '')
input_row = input_row.strip().strip(';')
input_columns_data = input_row.split(';')
for input_column_data in input_columns_data:
input_column_name, input_column_value = input_column_data.split(':')
input_df[input_column_name] = []

# add the data
for i in range(actual_records_count):
input_row = str(df[df.columns[len(outputs)]].tolist()[i])
if len(input_row) < 10:
continue
input_row = input_row.replace('(', '').replace(')', '')
input_row = input_row.strip().strip(';')
input_columns_data = input_row.split(';')
data = []
for input_column_data in input_columns_data:
input_column_name, input_column_value = input_column_data.split(':')
data.append(float(input_column_value))
input_df.loc[i] = data

logger.info(f'Calculation Time: {time.time() - tic:10.3f} sec')
logger.info(f'Calculation Time per iteration: {(time.time() - tic) / actual_records_count:10.3f} sec')
if iterations != actual_records_count:
logger.warning(
f'NOTE: {actual_records_count!s} iterations finished successfully and were used to calculate the '
f'statistics.'
)
msg = f'NOTE: {actual_records_count!s} iterations finished successfully and were used to calculate the statistics.'
logger.warning(msg)

# write them out
# write them out and make the graphs
annotations = ''
outputs_result: dict[str, dict] = {}

input = ''
full_names: set = set()
short_names: set = set()
with open(output_file, 'a') as f:
if iterations != actual_records_count:
f.write(
f'\n\n{actual_records_count!s} iterations finished successfully and were used to calculate the '
f'statistics\n\n'
)

# First do the input graphs
for i in range(len(inputs)):
input = inputs[i][0]
plt.figure(figsize=(8, 6))
ax = plt.subplot()
ax.set_title(input)
ax.set_xlabel('Random Values')
ax.set_ylabel('Probability')

plt.figtext(0.11, 0.74, annotations, fontsize=8)
ret = plt.hist(input_df[input_df.columns[i]].tolist(), bins=50, density=True)
fname = input_df.columns[i].strip().replace('/', '-')
save_path = Path(Path(output_file).parent, f'{fname}.png')
if html_path:
save_path = Path(Path(html_path).parent, f'{fname}.png')
plt.savefig(save_path)
plt.close()
full_names.add(save_path)
short_names.add(fname)

# Now do the output graphs
for i in range(len(outputs)):
output = outputs[i]
f.write(f'{output}:\n')
Expand Down Expand Up @@ -519,6 +567,7 @@ def main(command_line_args=None):
if html_path:
save_path = Path(Path(html_path).parent, f'{fname}.png')
plt.savefig(save_path)
plt.close()
full_names.add(save_path)
short_names.add(fname)
annotations = ''
Expand Down
1 change: 0 additions & 1 deletion src/geophires_x/AGSOutputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ def PrintOutputs(self, model: Model):
f.write("Simulation Metadata\n")
f.write("----------------------\n")
f.write(f' GEOPHIRES Version: {geophires_x.__version__}\n')
f.write(" GEOPHIRES Build Date: 2022-06-30\n")
f.write(" Simulation Date: " + datetime.datetime.now().strftime("%Y-%m-%d\n"))
f.write(" Simulation Time: " + datetime.datetime.now().strftime("%H:%M\n"))
f.write(" Calculation Time: " + "{0:10.3f}".format((time.time() - model.tic)) + " sec\n")
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 @@ -578,21 +578,21 @@ def read_parameters(self, model: Model) -> None:

# handle error checking and special cases:
if model.reserv.numseg.value > 1:
msg = "Warning: CLGS model can only handle a single layer gradient segment. Number of Segments set to 1, \
Gradient set to Gradient[0], and Depth set to Reservoir Depth."
msg = ('Warning: CLGS model can only handle a single layer gradient segment. '
'Number of Segments set to 1, Gradient set to Gradient[0], and Depth set to Reservoir Depth.')
print(msg)
model.logger.warning(msg)
model.reserv.numseg.value = 1

if self.ninj.value > 0:
msg = "Warning: CLGS model considers the only the production wellbore parameters. Anything related to the \
injection wellbore is ignored."
msg = ('Warning: CLGS model considers the only the production wellbore parameters. '
'Anything related to the injection wellbore is ignored.')
print(msg)
model.logger.warning(msg)

if self.nprod.value != 1:
msg = "Warning: CLGS model considers the only a single production wellbore (coaxial or uloop). \
Number of production wellboreset set 1."
msg = ('Warning: CLGS model considers the only a single production wellbore (coaxial or uloop). '
'Number of production wellboreset set 1.')
print(msg)
model.logger.warning(msg)

Expand Down
2 changes: 0 additions & 2 deletions src/geophires_x/Outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,6 @@ def PrintOutputs(self, model: Model):
pumping_power_results = []

simulation_metadata.append(OutputTableItem('GEOPHIRES Version', geophires_x.__version__))
simulation_metadata.append(OutputTableItem('GEOPHIRES Build Date', '2024-03-05'))
simulation_metadata.append(OutputTableItem('Simulation Date', datetime.datetime.now().strftime('%Y-%m-%d')))
simulation_metadata.append(OutputTableItem('Simulation Time', datetime.datetime.now().strftime('%H:%M')))
simulation_metadata.append(OutputTableItem('Calculation Time', '{0:10.3f}'.format((time.time() - model.tic)) + ' sec'))
Expand Down Expand Up @@ -1554,7 +1553,6 @@ def PrintOutputs(self, model: Model):
f.write('Simulation Metadata\n')
f.write('----------------------\n')
f.write(f' GEOPHIRES Version: {geophires_x.__version__}\n')
f.write(' GEOPHIRES Build Date: 2024-03-05\n') # FIXME TODO https://github.com/NREL/GEOPHIRES-X/issues/139
f.write(' Simulation Date: '+ datetime.datetime.now().strftime('%Y-%m-%d\n'))
f.write(' Simulation Time: '+ datetime.datetime.now().strftime('%H:%M\n'))
f.write(' Calculation Time: '+'{0:10.3f}'.format((time.time()-model.tic)) + ' sec\n')
Expand Down
2 changes: 1 addition & 1 deletion src/geophires_x/SFReservoir.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def __init__(self, model:Model):
model.logger.info("Complete " + str(__class__) + ": " + sys._getframe().f_code.co_name)

def __str__(self):
return "LHSReservoir"
return 'SFReservoir'

def read_parameters(self, model: Model) -> None:
"""
Expand Down
1 change: 0 additions & 1 deletion src/geophires_x/SUTRAOutputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ def PrintOutputs(self, model: Model):
f.write("Simulation Metadata\n")
f.write("----------------------\n")
f.write(f' GEOPHIRES Version: {geophires_x.__version__}\n')
f.write(" GEOPHIRES Build Date: 2023-11-06\n")
f.write(" Simulation Date: "+ datetime.datetime.now().strftime("%Y-%m-%d\n"))
f.write(" Simulation Time: "+ datetime.datetime.now().strftime("%H:%M\n"))
f.write(" Calculation Time: "+"{0:10.3f}".format((time.time()-model.tic)) + " sec\n")
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.28'
__version__ = '3.4.29'
32 changes: 21 additions & 11 deletions src/geophires_x_client/geophires_input_parameters.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import tempfile
import uuid
from enum import Enum
from pathlib import Path
from types import MappingProxyType
Expand Down Expand Up @@ -34,25 +35,33 @@ class PowerPlantType(Enum):


class GeophiresInputParameters:

def __init__(self, params: Optional[MappingProxyType] = None, from_file_path: Optional[Path] = None):
assert (params is None) ^ (from_file_path is None), 'Only one of params or from_file_path may be provided'
"""
Note that params will override any duplicate entries in from_file_path
"""

assert (params is not None) or (from_file_path is not None), 'One of params or from_file_path must be provided'

if params is not None:
self._params = dict(params)
self._id = abs(hash(frozenset(self._params.items())))
self._file_path = Path(tempfile.gettempdir(), f'geophires-input-params_{uuid.uuid4()!s}.txt')

if from_file_path is not None:
with open(from_file_path, encoding='UTF-8') as base_file:
with open(self._file_path, 'a', encoding='UTF-8') as f:
f.writelines(base_file.readlines())
else:
self._file_path = from_file_path

if params is not None:
# TODO validate params - i.e. that all names are accepted by simulation, values don't exceed max allowed,
# etc.

tmp_file_path = Path(tempfile.gettempdir(), f'geophires-input-params_{self._id}.txt')
f = Path.open(tmp_file_path, 'w')
with open(self._file_path, 'a', encoding='UTF-8') as f:
f.writelines([', '.join([str(p) for p in param_item]) + '\n' for param_item in self._params.items()])

f.writelines([','.join([str(p) for p in param_item]) + '\n' for param_item in self._params.items()])
f.close()
self._file_path = tmp_file_path

if from_file_path is not None:
self._file_path = from_file_path
self._id = hash(from_file_path)
self._id = hash(self._file_path)

def as_file_path(self):
return self._file_path
Expand All @@ -61,4 +70,5 @@ def get_output_file_path(self):
return Path(tempfile.gettempdir(), f'geophires-result_{self._id}.out')

def __hash__(self):
"""TODO make hashes for equivalent parameters equal"""
return self._id
8 changes: 8 additions & 0 deletions src/geophires_x_schema_generator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
# ruff: noqa: I001
from geophires_x.Model import Model

from geophires_x.SFReservoir import SFReservoir
from geophires_x.LHSReservoir import LHSReservoir
from geophires_x.MPFReservoir import MPFReservoir
from geophires_x.AGSEconomics import AGSEconomics
from geophires_x.AGSWellBores import AGSWellBores
from geophires_x.CylindricalReservoir import CylindricalReservoir
Expand All @@ -20,6 +23,7 @@
from geophires_x.SUTRAEconomics import SUTRAEconomics
from geophires_x.SUTRAReservoir import SUTRAReservoir
from geophires_x.SUTRAWellBores import SUTRAWellBores
from geophires_x.TDPReservoir import TDPReservoir


class GeophiresXSchemaGenerator:
Expand Down Expand Up @@ -49,6 +53,10 @@ def _with_cat(p: Parameter, cat: str):

parameter_sources = [
(dummy_model.reserv, 'Reservoir'),
(TDPReservoir(dummy_model), 'Reservoir'),
(LHSReservoir(dummy_model), 'Reservoir'),
(MPFReservoir(dummy_model), 'Reservoir'),
(SFReservoir(dummy_model), 'Reservoir'),
(CylindricalReservoir(dummy_model), 'Reservoir'),
(SUTRAReservoir(dummy_model), 'Reservoir'),
(dummy_model.wellbores, 'Well Bores'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
Simulation Metadata
----------------------
GEOPHIRES Version: 3.4.4
GEOPHIRES Build Date: 2022-06-30
Simulation Date: 2024-03-02
Simulation Time: 14:11
Calculation Time: 1.178 sec
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
Simulation Metadata
----------------------
GEOPHIRES Version: 3.4.4
GEOPHIRES Build Date: 2022-06-30
Simulation Date: 2024-03-02
Simulation Time: 14:12
Calculation Time: 1.004 sec
Expand Down
Loading

0 comments on commit b83df0b

Please sign in to comment.