Skip to content
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

JEDI project skeleton #1

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
fc58cfe
inital work on fervo style - economics
malcolm-dsider Apr 29, 2024
6a7bec7
Small changes to make Economics calculation cleaer and more correct; …
malcolm-dsider May 2, 2024
6654be6
Small changes to make Economics calculation cleaer and more correct; …
malcolm-dsider May 2, 2024
05e990a
Delete PTCandITCinGEOPHIRES.docx
malcolm-dsider May 7, 2024
9b81fb2
Delete PTCandITCinGEOPHIRES.md
malcolm-dsider May 7, 2024
0cd834c
Delete PTCandITCinGEOPHIRES2.md
malcolm-dsider May 7, 2024
4e1c763
Delete tests.7z
malcolm-dsider May 7, 2024
a9d10db
Delete media/a9833e5843d1a0259953a57b76de61df.png
malcolm-dsider May 7, 2024
c12f1e9
Delete References/01d-jedi-geothermal-model-rel-gt12-23-16.xlsm
malcolm-dsider May 7, 2024
a69f48d
Delete References/JEDI.pdf
malcolm-dsider May 7, 2024
90ba8c0
Merge branch 'main' into fervo-case-study
malcolm-dsider May 7, 2024
39aa781
Continued work on Fervo model; more complete reporting of costs, and …
malcolm-dsider May 7, 2024
5970474
Merge remote-tracking branch 'origin/fervo-case-study' into fervo-cas…
malcolm-dsider May 7, 2024
8cf4ee9
Include all reservoir classes in parameter generation per https://git…
softwareengineerprogrammer May 8, 2024
f6c4a8e
Continued work on Fervo model; updating tests and results to match cu…
malcolm-dsider May 8, 2024
0568ba7
Remove build date from output as it's both inaccurate and redundant w…
softwareengineerprogrammer May 8, 2024
6925254
Continued work on Fervo model; made changes per reviewer.
malcolm-dsider May 8, 2024
2cab2d0
Merge pull request #204 from malcolm-dsider/fervo-case-study
malcolm-dsider May 8, 2024
f043ca5
example_SHR-{1,2} comments, including reference to thermosiphoning di…
softwareengineerprogrammer May 9, 2024
8beb7c4
Addressing Monte-Carlo suggestion: INPUT variograms #197. Variograms …
malcolm-dsider May 10, 2024
7b9619b
Support combining input file and params object in GeophiresInputParam…
softwareengineerprogrammer May 10, 2024
0489a70
Put combined params in new input file instead of existing input file
softwareengineerprogrammer May 10, 2024
85a388e
Adjust test that was assuming same parameters = same input file (no l…
softwareengineerprogrammer May 10, 2024
70483b8
Use test-specific filenames to avoid potential confusion with examples
softwareengineerprogrammer May 10, 2024
93d9479
Clarify status of hashing/caching
softwareengineerprogrammer May 10, 2024
90737ae
Unit test for FCR sensitivity - https://github.com/NREL/GEOPHIRES-X/i…
softwareengineerprogrammer May 10, 2024
7102210
Merge pull request #24 from softwareengineerprogrammer/geophires-inpu…
softwareengineerprogrammer May 10, 2024
d72254c
Update setup.py
malcolm-dsider May 10, 2024
96a1e09
Update MC_GeoPHIRES3.py
malcolm-dsider May 11, 2024
140f19d
Merge remote-tracking branch 'origin/main'
softwareengineerprogrammer May 13, 2024
703c967
Merge pull request #212 from malcolm-dsider/main
malcolm-dsider May 13, 2024
a2331f2
Replace fervo_energy_white_paper.pdf with .md with link to pdf
softwareengineerprogrammer May 14, 2024
c6c01c3
Merge branch 'NREL:main' into main
softwareengineerprogrammer May 14, 2024
da0fdd4
Bump version: 3.4.28 → 3.4.29
softwareengineerprogrammer May 14, 2024
7e0a7b1
Provide both long and short URLs for web interface in README
softwareengineerprogrammer May 14, 2024
d72d04f
Fix message formatting
softwareengineerprogrammer May 14, 2024
94ddec5
Stub implementation of JEDI geothermal https://github.com/NREL/GEOPHI…
softwareengineerprogrammer May 14, 2024
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
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ requirements.txt
*~
*.bak
.DS_Store
.lock

# C extensions
*.so
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)
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
112 changes: 7 additions & 105 deletions src/geophires_x/AGSWellBores.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,67 +515,6 @@ def __init__(self, model: Model):
# NB: inputs we already have ("already have it") need to be set at ReadParameter time so values are set at the
# last possible time

self.Fluid = self.ParameterDict[self.Fluid.Name] = intParameter(
"Heat Transfer Fluid",
DefaultValue=WorkingFluid.WATER,
AllowableRange=[1, 2],
UnitType=Units.NONE,
Required=True,
ErrMessage="assume default Heat transfer fluid is water (1)"
)
self.Configuration = self.ParameterDict[self.Configuration.Name] = intParameter(
"Closed-loop Configuration",
DefaultValue=Configuration.COAXIAL,
AllowableRange=[1, 2],
UnitType=Units.NONE,
Required=True,
ErrMessage="assume default closed-loop configuration is co-axial with injection in annulus (2)"
)

# Input data for subsurface condition
self.Nonvertical_length = self.ParameterDict[self.Nonvertical_length.Name] = floatParameter(
"Total Nonvertical Length",
DefaultValue=1000.0,
Min=1000.0,
Max=20000.0,
UnitType=Units.LENGTH,
PreferredUnits=LengthUnit.METERS,
CurrentUnits=LengthUnit.METERS,
Required=True,
ErrMessage="assume default Total nonvertical length (1000 m)"
)

self.WaterThermalConductivity = self.ParameterDict[self.WaterThermalConductivity.Name] = floatParameter(
"Water Thermal Conductivity",
DefaultValue=0.6,
Min=0.0,
Max=100.0,
UnitType=Units.THERMAL_CONDUCTIVITY,
PreferredUnits=ThermalConductivityUnit.WPERMPERK,
CurrentUnits=ThermalConductivityUnit.WPERMPERK,
ErrMessage="assume default for water thermal conductivity (0.6 W/m/K)",
ToolTipText="Water Thermal Conductivity"
)

self.nonverticalwellborediameter = self.ParameterDict[self.nonverticalwellborediameter.Name] = floatParameter(
"Nonvertical Wellbore Diameter",
DefaultValue=0.156,
Min=0.01,
Max=100.0,
UnitType=Units.LENGTH,
PreferredUnits=LengthUnit.METERS,
CurrentUnits=LengthUnit.METERS,
ErrMessage="assume default for Non-vertical Wellbore Diameter (0.156 m)",
ToolTipText="Non-vertical Wellbore Diameter"
)
self.numnonverticalsections = self.ParameterDict[self.numnonverticalsections.Name] = intParameter(
"Number of Multilateral Sections",
DefaultValue=1,
AllowableRange=list(range(0, 101, 1)),
UnitType=Units.NONE,
ErrMessage="assume default for Number of Nonvertical Wellbore Sections (1)",
ToolTipText="Number of Nonvertical Wellbore Sections"
)
self.time_operation = self.ParameterDict[self.time_operation.Name] = floatParameter(
"Closed Loop Calculation Start Year",
DefaultValue=0.01,
Expand All @@ -587,14 +526,6 @@ def __init__(self, model: Model):
ErrMessage="assume default for Closed Loop Calculation Start Year (0.01)",
ToolTipText="Closed Loop Calculation Start Year"
)
self.NonverticalsCased = self.ParameterDict[self.NonverticalsCased.Name] = boolParameter(
"Multilaterals Cased",
DefaultValue=False,
Required=False,
Provided=False,
Valid=True,
ErrMessage="assume default value (False)"
)

# local variable initiation
# code from Koenraad
Expand All @@ -612,20 +543,6 @@ def __init__(self, model: Model):

# results are stored here and in the parent ProducedTemperature array
self.Tini = 0.0
self.NonverticalProducedTemperature = self.OutputParameterDict[self.ProducedTemperature.Name] = OutputParameter(
Name="Nonvertical Produced Temperature",
value=[0.0],
UnitType=Units.TEMPERATURE,
PreferredUnits=TemperatureUnit.CELSIUS,
CurrentUnits=TemperatureUnit.CELSIUS
)
self.NonverticalPressureDrop = self.OutputParameterDict[self.NonverticalPressureDrop.Name] = OutputParameter(
Name="Nonvertical Pressure Drop",
value=[0.0],
UnitType=Units.PRESSURE,
PreferredUnits=PressureUnit.KPASCAL,
CurrentUnits=PressureUnit.KPASCAL
)

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

Expand Down Expand Up @@ -656,41 +573,26 @@ def read_parameters(self, model: Model) -> None:
ParameterReadIn = model.InputParameters[key]
# just handle special cases for this class - the call to super set all the values,
# including the value unique to this class
if ParameterToModify.Name == "Multilaterals Cased":
if ParameterReadIn.sValue == str(1):
self.NonverticalsCased.value = True
else:
self.NonverticalsCased.value = False
elif ParameterToModify.Name == "Heat Transfer Fluid":
if ParameterReadIn.sValue == str(1):
self.Fluid.value = WorkingFluid.WATER
else:
self.Fluid.value = WorkingFluid.SCO2
elif ParameterToModify.Name == "Closed-loop Configuration":
if ParameterReadIn.sValue == str(1):
self.Configuration.value = Configuration.ULOOP
else:
self.Configuration.value = Configuration.COAXIAL
else:
model.logger.info("No parameters read because no content provided")

# 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 All @@ -699,7 +601,7 @@ def read_parameters(self, model: Model) -> None:

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

# code from Koenraad

def calculatedrillinglengths(self, model) -> tuple:
"""
returns the total length, vertical length, and horizontal lengths, depending on the configuration
Expand Down
Loading