Skip to content

Commit 9e5bb51

Browse files
Merge pull request #104 from softwareengineerprogrammer/list-parameter-read-fix
List parameter read fix [v3.9.54]
2 parents 8cbeeb7 + 7c8ec3b commit 9e5bb51

File tree

9 files changed

+124
-38
lines changed

9 files changed

+124
-38
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.53
2+
current_version = 3.9.54
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.53
57+
version: 3.9.54
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
@@ -58,9 +58,9 @@ Free software: `MIT license <LICENSE>`__
5858
:alt: Supported implementations
5959
:target: https://pypi.org/project/geophires-x
6060

61-
.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.9.53.svg
61+
.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.9.54.svg
6262
:alt: Commits since latest release
63-
:target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.9.53...main
63+
:target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.9.54...main
6464

6565
.. |docs| image:: https://readthedocs.org/projects/GEOPHIRES-X/badge/?style=flat
6666
: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.9.53'
21+
version = release = '3.9.54'
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.53',
16+
version='3.9.54',
1717
license='MIT',
1818
description='GEOPHIRES is a free and open-source geothermal techno-economic simulator.',
1919
long_description='{}\n{}'.format(

src/geophires_x/Parameter.py

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ def __post_init__(self):
281281
json_parameter_type: str = _JSON_PARAMETER_TYPE_ARRAY
282282

283283

284-
def ReadParameter(ParameterReadIn: ParameterEntry, ParamToModify, model):
284+
def ReadParameter(ParameterReadIn: ParameterEntry, ParamToModify, model) -> None:
285285
"""
286286
ReadParameter: A method to take a single ParameterEntry object and use it to update the associated Parameter.
287287
Does validation as well as Unit and Currency conversion
@@ -393,35 +393,8 @@ def default_parameter_value_message(new_val: Any, param_to_modify_name: str, def
393393
ParamToModify.Provided = True # set provided to true because we are using a user provide value now
394394
ParamToModify.Valid = True # set Valid to true because it passed the validation tests
395395
elif isinstance(ParamToModify, listParameter):
396-
New_val = float(ParameterReadIn.sValue)
397-
if (New_val < float(ParamToModify.Min)) or (New_val > float(ParamToModify.Max)):
398-
# user provided value is out of range, so announce it, leave set to whatever it was set to (default value)
399-
if len(ParamToModify.ErrMessage) > 0:
400-
msg = (
401-
f'Parameter given ({str(New_val)}) for {ParamToModify.Name} outside of valid range.'
402-
f'GEOPHIRES will {ParamToModify.ErrMessage}'
403-
)
404-
print(f'Warning: {msg}')
405-
model.logger.warning(msg)
406-
model.logger.info(f'Complete {str(__name__)}: {sys._getframe().f_code.co_name}')
407-
return
408-
else:
409-
if ' ' in ParamToModify.Name:
410-
# Some list parameters are read in with enumerated parameter names; in these cases we use the last
411-
# character of the description to get the position i.e., "Gradient 1" is position 0.
412-
parts = ParameterReadIn.Name.split(' ')
413-
position = int(parts[1]) - 1
414-
if position >= len(ParamToModify.value):
415-
ParamToModify.value.append(New_val) # we are adding to the list, so use append
416-
else: # we are replacing a value, so pop the value we want to replace, then insert a new one
417-
ParamToModify.value.pop(position)
418-
ParamToModify.value.insert(position, New_val)
419-
else:
420-
# In an ideal world this would be handled in ParameterEntry such that its sValue and Comment are
421-
# correct; however that would only be practical if ParameterEntry had typing information to know
422-
# whether to treat text after a second comma as a comment or list entry.
423-
ParamToModify.value = [float(x.strip()) for x in ParameterReadIn.raw_entry.split('--')[0].split(',')[1:]
424-
if x.strip() != '']
396+
_read_list_parameter(ParameterReadIn, ParamToModify, model)
397+
425398
elif isinstance(ParamToModify, boolParameter):
426399
if ParameterReadIn.sValue == "0":
427400
New_val = False
@@ -449,6 +422,47 @@ def default_parameter_value_message(new_val: Any, param_to_modify_name: str, def
449422
model.logger.info(f'Complete {str(__name__)}: {sys._getframe().f_code.co_name}')
450423

451424

425+
def _read_list_parameter(ParameterReadIn: ParameterEntry, ParamToModify, model) -> None:
426+
"""
427+
:type ParamToModify: :class:`~geophires_x.Parameter.Parameter`
428+
:type model: :class:`~geophires_x.Model.Model`
429+
"""
430+
431+
if ' ' in ParamToModify.Name:
432+
New_val = float(ParameterReadIn.sValue)
433+
# Some list parameters are read in with enumerated parameter names; in these cases we use the last
434+
# character of the description to get the position i.e., "Gradient 1" is position 0.
435+
parts = ParameterReadIn.Name.split(' ')
436+
position = int(parts[1]) - 1
437+
if position >= len(ParamToModify.value):
438+
ParamToModify.value.append(New_val) # we are adding to the list, so use append
439+
else: # we are replacing a value, so pop the value we want to replace, then insert a new one
440+
ParamToModify.value.pop(position)
441+
ParamToModify.value.insert(position, New_val)
442+
else:
443+
# In an ideal world this would be handled in ParameterEntry such that its sValue and Comment are
444+
# correct; however that would only be practical if ParameterEntry had typing information to know
445+
# whether to treat text after a second comma as a comment or list entry.
446+
ParamToModify.value = [float(x.strip()) for x in ParameterReadIn.raw_entry.split('--')[0].split(',')[1:]
447+
if x.strip() != '']
448+
449+
ParamToModify.Provided = True
450+
451+
valid = True
452+
for i in range(len(ParamToModify.value)):
453+
New_val = ParamToModify.value[i]
454+
if (New_val < float(ParamToModify.Min)) or (New_val > float(ParamToModify.Max)):
455+
msg = (
456+
f'Value given ({str(New_val)}) for {ParamToModify.Name} outside of valid range '
457+
f'({ParamToModify.Min}{ParamToModify.Max}).'
458+
)
459+
print(f'Warning: {msg}')
460+
model.logger.warning(msg)
461+
valid = False
462+
463+
ParamToModify.Valid = valid
464+
465+
452466
def ConvertUnits(ParamToModify, strUnit: str, model) -> str:
453467
"""
454468
ConvertUnits gets called if a unit version is needed: either currency or standard units like F to C or m to ft

src/geophires_x/Reservoir.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,14 @@ def read_parameters(self, model: Model) -> None:
606606
elif ParameterToModify.Name.startswith('Thickness '):
607607
parts = ParameterReadIn.Name.split(' ')
608608
position = int(parts[1]) - 1
609-
model.reserv.layerthickness.value[position] = ParameterToModify.value
609+
num_segments = len(model.reserv.layerthickness.value)
610+
if position < num_segments:
611+
model.reserv.layerthickness.value[position] = ParameterToModify.value
612+
else:
613+
model.logger.error(f'Cannot set {ParameterToModify.Name} to {ParameterToModify.value} '
614+
f'because only {num_segments} segments are defined.')
615+
# Don't raise exception since we can ignore and the user will see the incorrectly configured
616+
# segment(s) in the result.
610617

611618
elif ParameterToModify.Name.startswith("Fracture Separation"):
612619
self.fracsepcalc.value = self.fracsep.value

src/geophires_x/__init__.py

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

tests/geophires_x_tests/test_reservoir.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,68 @@ def _fractures_lcoe_net(r: GeophiresXResult) -> tuple[int, float, float]:
163163

164164
self.assertGreater(net_production, 0)
165165
self.assertLess(net_production, 500)
166+
167+
def test_thicknesses_param(self):
168+
def _get_result() -> GeophiresXResult:
169+
return GeophiresXClient().get_geophires_result(
170+
GeophiresInputParameters(
171+
from_file_path=self._get_test_file_path('generic-egs-case.txt'),
172+
params={
173+
'Number of Segments': 3,
174+
'Gradient 2': '40',
175+
'Gradient 3': '40',
176+
'Thicknesses': '2.5,0.49,0.87',
177+
},
178+
)
179+
)
180+
181+
r = _get_result()
182+
summary = r.result['SUMMARY OF RESULTS']
183+
184+
expected = {
185+
'Segment 1 Geothermal gradient': {'unit': 'degC/km', 'value': 36.7},
186+
'Segment 1 Thickness': {'unit': 'kilometer', 'value': 2.5},
187+
'Segment 2 Geothermal gradient': {'unit': 'degC/km', 'value': 40},
188+
'Segment 2 Thickness': {'unit': 'kilometer', 'value': 0.49},
189+
'Segment 3 Geothermal gradient': {'unit': 'degC/km', 'value': 40},
190+
'Segment 3 Thickness': None,
191+
'Segment 4 Geothermal gradient': None,
192+
}
193+
194+
for k, v in expected.items():
195+
self.assertEqual(summary[k], v)
196+
197+
def test_number_of_segments(self):
198+
def _get_result() -> GeophiresXResult:
199+
return GeophiresXClient().get_geophires_result(
200+
GeophiresInputParameters(
201+
from_file_path=self._get_test_file_path('generic-egs-case.txt'),
202+
params={
203+
'Number of Segments': 3,
204+
'Gradient 2': '40',
205+
'Gradient 3': '40',
206+
'Gradient 4': '40',
207+
'Thickness 1': '2.5',
208+
'Thickness 2': '0.49',
209+
'Thicknesses': '2.5,0.49,0.87',
210+
'Thickness 3': '0.65',
211+
'Thickness 4': '0.85',
212+
},
213+
)
214+
)
215+
216+
r = _get_result()
217+
summary = r.result['SUMMARY OF RESULTS']
218+
219+
expected = {
220+
'Segment 1 Geothermal gradient': {'unit': 'degC/km', 'value': 36.7},
221+
'Segment 1 Thickness': {'unit': 'kilometer', 'value': 2.5},
222+
'Segment 2 Geothermal gradient': {'unit': 'degC/km', 'value': 40},
223+
'Segment 2 Thickness': {'unit': 'kilometer', 'value': 0.49},
224+
'Segment 3 Geothermal gradient': {'unit': 'degC/km', 'value': 40},
225+
'Segment 3 Thickness': None,
226+
'Segment 4 Geothermal gradient': None,
227+
}
228+
229+
for k, v in expected.items():
230+
self.assertEqual(summary[k], v)

0 commit comments

Comments
 (0)