Skip to content

Commit 926dda3

Browse files
Merge pull request NREL#146 from softwareengineerprogrammer/main
Fix Revenue & Cashflow Profile Units, Update Utilization Efficiency (v3.4.16)
2 parents e94df0e + 81e2ff1 commit 926dda3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1040
-946
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.4.14
2+
current_version = 3.4.16
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.4.14
57+
version: 3.4.16
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
@@ -47,9 +47,9 @@ Free software: `MIT license <LICENSE>`__
4747
:alt: Supported implementations
4848
:target: https://pypi.org/project/geophires-x
4949

50-
.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.4.14.svg
50+
.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.4.16.svg
5151
:alt: Commits since latest release
52-
:target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.4.14...main
52+
:target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.4.16...main
5353

5454
.. |docs| image:: https://readthedocs.org/projects/GEOPHIRES-X/badge/?style=flat
5555
: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 = '2023'
1919
author = 'NREL'
2020
copyright = f'{year}, {author}'
21-
version = release = '3.4.14'
21+
version = release = '3.4.16'
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.4.14',
16+
version='3.4.16',
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: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,6 @@ def __init__(self, model: Model):
811811
)
812812
self.DoAddOnCalculations = self.ParameterDict[self.DoAddOnCalculations.Name] = boolParameter(
813813
"Do AddOn Calculations",
814-
value=False,
815814
DefaultValue=False,
816815
UnitType=Units.NONE,
817816
Required=False,
@@ -820,7 +819,6 @@ def __init__(self, model: Model):
820819
)
821820
self.DoCarbonCalculations = self.ParameterDict[self.DoCarbonCalculations.Name] = boolParameter(
822821
"Do Carbon Price Calculations",
823-
value=False,
824822
DefaultValue=False,
825823
UnitType=Units.NONE,
826824
Required=False,
@@ -1301,19 +1299,19 @@ def __init__(self, model: Model):
13011299
"Electricity Sale Price Model",
13021300
UnitType=Units.ENERGYCOST,
13031301
PreferredUnits=EnergyCostUnit.CENTSSPERKWH,
1304-
CurrentUnits=EnergyCostUnit.CENTSSPERKWH
1302+
CurrentUnits=EnergyCostUnit.DOLLARSPERKWH,
13051303
)
13061304
self.HeatPrice = self.OutputParameterDict[self.HeatPrice.Name] = OutputParameter(
13071305
"Heat Sale Price Model",
13081306
UnitType=Units.ENERGYCOST,
13091307
PreferredUnits=EnergyCostUnit.CENTSSPERKWH,
1310-
CurrentUnits=EnergyCostUnit.CENTSSPERKWH
1308+
CurrentUnits=EnergyCostUnit.DOLLARSPERKWH,
13111309
)
13121310
self.CoolingPrice = self.OutputParameterDict[self.CoolingPrice.Name] = OutputParameter(
13131311
"Heat Sale Price Model",
13141312
UnitType=Units.ENERGYCOST,
13151313
PreferredUnits=EnergyCostUnit.CENTSSPERKWH,
1316-
CurrentUnits=EnergyCostUnit.CENTSSPERKWH
1314+
CurrentUnits=EnergyCostUnit.DOLLARSPERKWH,
13171315
)
13181316
self.CarbonPrice = self.OutputParameterDict[self.CarbonPrice.Name] = OutputParameter(
13191317
"Carbon Price Model",
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
USD = [currency]
2+
cents = USD / 100

src/geophires_x/GeoPHIRESUtils.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from functools import lru_cache
1111
from typing import Optional
1212

13-
import pint
1413
import scipy
1514
from pint.facets.plain import PlainQuantity
1615
from scipy.interpolate import interp1d
@@ -19,6 +18,7 @@
1918
import CoolProp.CoolProp as CP
2019

2120
from geophires_x.Parameter import ParameterEntry
21+
from geophires_x.Units import get_unit_registry
2222

2323
_logger = logging.getLogger('root') # TODO use __name__ instead of root
2424

@@ -85,14 +85,13 @@
8585
0.4,
8686
0.4,
8787
0.4,
88-
0.4,
88+
0.5, # Extrapolate from fig 2 in https://geothermal-energy-journal.springeropen.com/articles/10.1186/s40517-019-0119-6
8989
]
9090
)
9191

9292
_interp_util_eff_func = interp1d(_T, _UtilEff)
9393

94-
_ureg = pint.get_application_registry()
95-
_ureg.load_definitions(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'GEOPHIRES3_newunits.txt'))
94+
_ureg = get_unit_registry()
9695

9796

9897
def quantity(value: float, unit: str) -> PlainQuantity:

src/geophires_x/Outputs.py

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
import numpy as np
66
from matplotlib import pyplot as plt
77
import geophires_x.Model as Model
8-
from geophires_x.Parameter import ConvertUnitsBack, ConvertOutputUnits, LookupUnits
8+
from geophires_x.Economics import Economics
9+
from geophires_x.Parameter import ConvertUnitsBack, ConvertOutputUnits, LookupUnits, OutputParameter
910
from geophires_x.OptionList import EndUseOptions, EconomicModel, ReservoirModel, FractureShape, ReservoirVolume, \
1011
PlantType
1112

@@ -87,17 +88,21 @@ def PrintOutputs(self, model: Model):
8788
param = obj.ParameterDict[key]
8889
if not param.UnitsMatch: ConvertUnitsBack(param, model)
8990

90-
# now we need to loop through all thw output parameters to update their units to
91+
# now we need to loop through all the output parameters to update their units to
9192
# whatever units the user has specified.
9293
# i.e., they may have specified that all LENGTH results must be in feet, so we need to convert those
9394
# from whatever LENGTH unit they are to feet.
9495
# same for all the other classes of units (TEMPERATURE, DENSITY, etc).
9596

9697
for obj in [model.reserv, model.wellbores, model.surfaceplant, model.economics]:
9798
for key in obj.OutputParameterDict:
99+
output_param:OutputParameter = obj.OutputParameterDict[key]
98100
if key in self.ParameterDict:
99-
if self.ParameterDict[key] != obj.OutputParameterDict[key].CurrentUnits:
100-
ConvertOutputUnits(obj.OutputParameterDict[key], self.ParameterDict[key], model)
101+
if self.ParameterDict[key].PreferredUnits != output_param.CurrentUnits:
102+
ConvertOutputUnits(output_param, self.ParameterDict[key].PreferredUnits, model)
103+
elif not output_param.UnitsMatch:
104+
obj.OutputParameterDict[key] = output_param.with_preferred_units()
105+
101106

102107
# write results to output file and screen
103108

@@ -110,7 +115,7 @@ def PrintOutputs(self, model: Model):
110115
f.write("Simulation Metadata\n")
111116
f.write("----------------------\n")
112117
f.write(f' GEOPHIRES Version: {geophires_x.__version__}\n')
113-
f.write(" GEOPHIRES Build Date: 2022-06-30\n")
118+
f.write(" GEOPHIRES Build Date: 2024-03-05\n") # FIXME TODO https://github.com/NREL/GEOPHIRES-X/issues/139
114119
f.write(" Simulation Date: "+ datetime.datetime.now().strftime("%Y-%m-%d\n"))
115120
f.write(" Simulation Time: "+ datetime.datetime.now().strftime("%H:%M\n"))
116121
f.write(" Calculation Time: "+"{0:10.3f}".format((time.time()-model.tic)) + " sec\n")
@@ -185,7 +190,7 @@ def PrintOutputs(self, model: Model):
185190
payback_period_val = model.economics.ProjectPaybackPeriod.value
186191
project_payback_period_display = f'{payback_period_val:10.2f} {model.economics.ProjectPaybackPeriod.PreferredUnits.value}' \
187192
if payback_period_val > 0.0 else 'N/A'
188-
f.write(f' Project Payback Period: {project_payback_period_display}\n')
193+
f.write(f' Project Payback Period: {project_payback_period_display}\n')
189194

190195
if model.surfaceplant.enduse_option.value in [EndUseOptions.COGENERATION_TOPPING_EXTRA_HEAT,
191196
EndUseOptions.COGENERATION_BOTTOMING_EXTRA_HEAT,
@@ -621,48 +626,58 @@ def PrintOutputs(self, model: Model):
621626
"Year Electricity | Heat | Cooling | Carbon | Project" + NL)
622627
f.write(
623628
"Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow" + NL)
624-
econ = model.economics
629+
econ:Economics = model.economics
630+
631+
def o(output_param: OutputParameter):
632+
# TODO generalize this and/or FIXME make it unnecessary
633+
if output_param.Name in econ.OutputParameterDict:
634+
return econ.OutputParameterDict[output_param.Name]
635+
else:
636+
return o
637+
625638
f.write("Start ("
626-
+ econ.ElecPrice.PreferredUnits.value +
627-
")(" + econ.ElecRevenue.PreferredUnits.value +
628-
") (" + econ.ElecCummRevenue.PreferredUnits.value +
629-
") |(" + econ.HeatPrice.PreferredUnits.value +
630-
") (" + econ.HeatRevenue.PreferredUnits.value +
631-
") (" + econ.HeatCummRevenue.PreferredUnits.value +
632-
") |(" + econ.CoolingPrice.PreferredUnits.value +
633-
") (" + econ.CoolingRevenue.PreferredUnits.value +
634-
") (" + econ.CoolingCummRevenue.PreferredUnits.value +
635-
") |(" + econ.CarbonPrice.PreferredUnits.value +
636-
") (" + econ.CarbonRevenue.PreferredUnits.value +
637-
") (" + econ.CarbonCummCashFlow.PreferredUnits.value +
638-
") |(" + econ.Coam.PreferredUnits.value +
639-
") (" + econ.TotalRevenue.PreferredUnits.value +
640-
") (" + econ.TotalCummRevenue.PreferredUnits.value + ")\n")
639+
+ o(econ.ElecPrice).CurrentUnits.value +
640+
")(" + o(econ.ElecRevenue).CurrentUnits.value +
641+
") (" + o(econ.ElecCummRevenue).CurrentUnits.value +
642+
") |(" + o(econ.HeatPrice).CurrentUnits.value +
643+
") (" + o(econ.HeatRevenue).CurrentUnits.value +
644+
") (" + o(econ.HeatCummRevenue).CurrentUnits.value +
645+
") |(" + o(econ.CoolingPrice).CurrentUnits.value +
646+
") (" + o(econ.CoolingRevenue).CurrentUnits.value +
647+
") (" + o(econ.CoolingCummRevenue).CurrentUnits.value +
648+
") |(" + o(econ.CarbonPrice).CurrentUnits.value +
649+
") (" + o(econ.CarbonRevenue).CurrentUnits.value +
650+
") (" + o(econ.CarbonCummCashFlow).CurrentUnits.value +
651+
") |(" + o(econ.Coam).CurrentUnits.value +
652+
") (" + o(econ.TotalRevenue).CurrentUnits.value +
653+
") (" + o(econ.TotalCummRevenue).CurrentUnits.value + ")\n")
641654
f.write(
642655
"________________________________________________________________________________________________________________________________________________________________________________________" + NL)
643656
# running years...
644657
for ii in range(0, (
645658
model.surfaceplant.construction_years.value + model.surfaceplant.plant_lifetime.value - 1), 1):
659+
646660
if ii < model.surfaceplant.construction_years.value:
647661
OPEX = 0.0 # zero out the OPEX during construction years
648662
else:
649-
OPEX = econ.Coam.value
663+
OPEX = o(econ.Coam).value
650664
f.write(
651-
f"{ii + 1:3.0f} {econ.ElecPrice.value[ii]:5.2f} {econ.ElecRevenue.value[ii]:5.2f} {econ.ElecCummRevenue.value[ii]:5.2f} | {econ.HeatPrice.value[ii]:5.2f} {econ.HeatRevenue.value[ii]:5.2f} {econ.HeatCummRevenue.value[ii]:5.2f} | {econ.CoolingPrice.value[ii]:5.2f} {econ.CoolingRevenue.value[ii]:5.2f} {econ.CoolingCummRevenue.value[ii]:5.2f} | {econ.CarbonPrice.value[ii]:5.2f} {econ.CarbonRevenue.value[ii]:5.2f} {econ.CarbonCummCashFlow.value[ii]:5.2f} | {OPEX:5.2f} {econ.TotalRevenue.value[ii]:5.2f} {econ.TotalCummRevenue.value[ii]:5.2f}\n")
665+
f"{ii + 1:3.0f} {o(econ.ElecPrice).value[ii]:5.2f} {o(econ.ElecRevenue).value[ii]:5.2f} {o(econ.ElecCummRevenue).value[ii]:5.2f} | {o(econ.HeatPrice).value[ii]:5.2f} {o(econ.HeatRevenue).value[ii]:5.2f} {o(econ.HeatCummRevenue).value[ii]:5.2f} | {o(econ.CoolingPrice).value[ii]:5.2f} {o(econ.CoolingRevenue).value[ii]:5.2f} {o(econ.CoolingCummRevenue).value[ii]:5.2f} | {o(econ.CarbonPrice).value[ii]:5.2f} {o(econ.CarbonRevenue).value[ii]:5.2f} {o(econ.CarbonCummCashFlow).value[ii]:5.2f} | {OPEX:5.2f} {o(econ.TotalRevenue).value[ii]:5.2f} {o(econ.TotalCummRevenue).value[ii]:5.2f}\n")
652666
f.write(NL)
653667

654668
if model.economics.DoAddOnCalculations.value: model.addoutputs.PrintOutputs(model)
655669
if model.economics.DoSDACGTCalculations.value: model.sdacgtoutputs.PrintOutputs(model)
656670

657671
except BaseException as ex:
658672
tb = sys.exc_info()[2]
659-
print (str(ex))
660-
print("Error: GEOPHIRES Failed to write the output file. Exiting....Line %i" % tb.tb_lineno)
673+
msg = "Error: GEOPHIRES Failed to write the output file. Exiting....Line %i" % tb.tb_lineno
674+
print(str(ex))
675+
print(msg)
661676
model.logger.critical(str(ex))
662-
model.logger.critical("Error: GEOPHIRES Failed to write the output file. Exiting....Line %i" % tb.tb_lineno)
663-
sys.exit()
677+
model.logger.critical(msg)
678+
raise RuntimeError(msg) from ex
664679

665-
model.logger.info("Complete "+ str(__class__) + ": " + sys._getframe().f_code.co_name)
680+
model.logger.info(f'Complete {__class__!s}: {sys._getframe().f_code.co_name}')
666681

667682
def MakeDistrictHeatingPlot(self, model: Model):
668683
"""

src/geophires_x/Parameter.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
# copyright, 2023, Malcolm I Ross
22
import copy
3-
import os.path
3+
import dataclasses
4+
45
import sys
56
from array import array
67
from typing import List, Optional, Any
78
from dataclasses import dataclass, field
89
from enum import IntEnum
910
from forex_python.converter import CurrencyRates, CurrencyCodes
10-
import pint
1111

1212
from abc import ABC
1313

1414
from pint.facets.plain import PlainQuantity
15-
1615
from geophires_x.Units import *
1716

18-
ureg = pint.get_application_registry()
19-
ureg.load_definitions(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'GEOPHIRES3_newunits.txt'))
20-
17+
_ureg = get_unit_registry()
2118

2219
class HasQuantity(ABC):
2320

@@ -26,7 +23,7 @@ def quantity(self) -> PlainQuantity:
2623
:rtype: pint.registry.Quantity - note type annotation uses PlainQuantity due to issues with python 3.8 failing
2724
to import the Quantity TypeAlias
2825
"""
29-
return ureg.Quantity(self.value, str(self.CurrentUnits.value))
26+
return _ureg.Quantity(self.value, str(self.CurrentUnits.value))
3027

3128

3229
@dataclass
@@ -67,7 +64,17 @@ class OutputParameter(HasQuantity):
6764
# set to PreferredUnits by default assuming that the current units are the preferred units -
6865
# they will only change if the read function reads a different unit associated with a parameter
6966
CurrentUnits: Enum = PreferredUnits
70-
UnitsMatch: bool = True
67+
68+
@property
69+
def UnitsMatch(self) -> str:
70+
return self.CurrentUnits == self.PreferredUnits
71+
72+
def with_preferred_units(self) -> Any: # Any is a proxy for Self
73+
ret: OutputParameter = dataclasses.replace(self)
74+
ret.value = ret.quantity().to(ret.PreferredUnits).magnitude
75+
ret.CurrentUnits = ret.PreferredUnits
76+
return ret
77+
7178

7279

7380
@dataclass
@@ -511,8 +518,8 @@ def ConvertUnits(ParamToModify, strUnit: str, model) -> str:
511518
try:
512519
# Make a Pint Quantity out of the old value: the amount of the unit doesn't matter,
513520
# just the units, so I set the amount to 0
514-
Old_valQ = ureg.Quantity(0.000, str(ParamToModify.CurrentUnits.value))
515-
New_valQ = ureg.Quantity(float(val), currType) # Make a Pint Quantity out of the new value
521+
Old_valQ = _ureg.Quantity(0.000, str(ParamToModify.CurrentUnits.value))
522+
New_valQ = _ureg.Quantity(float(val), currType) # Make a Pint Quantity out of the new value
516523
except BaseException as ex:
517524
print(str(ex))
518525
msg = (
@@ -696,7 +703,7 @@ def parameter_with_units_converted_back_to_preferred_units(param: Parameter, mod
696703
if isinstance(param.CurrentUnits, pint.Quantity):
697704
currQ = param.CurrentUnits
698705
else:
699-
currQ = ureg.Quantity(float(val), currType) # Make a Pint Quantity out of the new value
706+
currQ = _ureg.Quantity(float(val), currType) # Make a Pint Quantity out of the new value
700707
except BaseException as ex:
701708
print(str(ex))
702709
msg = (
@@ -856,10 +863,10 @@ def ConvertOutputUnits(oparam: OutputParameter, newUnit: Units, model):
856863
# this is a simple unit conversion: it could be just units (meters->feet) or simple currency ($->EUR)
857864
# or compound Currency (MUSD-EUR)
858865
try:
859-
fromQ = ureg.Quantity(
866+
fromQ = _ureg.Quantity(
860867
oparam.value, str(oparam.PreferredUnits.value)
861868
) # Make a Pint Quantity out of the value
862-
toQ = ureg.Quantity(0, str(newUnit.value)) # Make a Pint Quantity out of the new value
869+
toQ = _ureg.Quantity(0, str(newUnit.value)) # Make a Pint Quantity out of the new value
863870
except BaseException as ex:
864871
print(str(ex))
865872
msg = (
@@ -900,10 +907,10 @@ def ConvertOutputUnits(oparam: OutputParameter, newUnit: Units, model):
900907
i = 0
901908
for arrayval in oparam.value:
902909
try:
903-
fromQ = ureg.Quantity(
910+
fromQ = _ureg.Quantity(
904911
oparam.value[i], str(oparam.PreferredUnits.value)
905912
) # Make a Pint Quantity out of from the value
906-
toQ = ureg.Quantity(0, str(newUnit.value)) # Make a Pint Quantity out of the new value
913+
toQ = _ureg.Quantity(0, str(newUnit.value)) # Make a Pint Quantity out of the new value
907914
except BaseException as ex:
908915
print(str(ex))
909916
msg = (
@@ -997,7 +1004,7 @@ def ConvertOutputUnits(oparam: OutputParameter, newUnit: Units, model):
9971004
# so just do the simple factor conversion and exit
9981005
oparam.value = oparam.value * Factor
9991006
oparam.CurrentUnits = DefUnit
1000-
oparam.UnitsMatch = False
1007+
# oparam.UnitsMatch = False
10011008
return
10021009

10031010
# start the currency conversion process

0 commit comments

Comments
 (0)