Skip to content

Commit 1f120e5

Browse files
print tsv SAM cash flow profile in output file
1 parent a007576 commit 1f120e5

File tree

5 files changed

+55
-17
lines changed

5 files changed

+55
-17
lines changed

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,12 @@ def read(*names, **kwargs):
8181
'rich',
8282
'pylocker',
8383
'nrel-pysam',
84+
'tabulate',
8485
],
8586
extras_require={
8687
# eg:
8788
# "rst": ["docutils>=0.11"],
8889
# ":python_version=="2.6"": ["argparse"],
89-
'development': ['bumpversion', 'tabulate']
90+
'development': ['bumpversion']
9091
},
9192
)

src/geophires_x/Economics.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import numpy as np
55
import numpy_financial as npf
66
import geophires_x.Model as Model
7-
from geophires_x.EconomicsSam import calculate_sam_economics
7+
from geophires_x.EconomicsSam import calculate_sam_economics, _SAM_CASH_FLOW_PROFILE_KEY
88
from geophires_x.OptionList import Configuration, WellDrillingCostCorrelation, EconomicModel, EndUseOptions, PlantType, \
99
_WellDrillingCostCorrelationCitation
1010
from geophires_x.Parameter import intParameter, floatParameter, OutputParameter, ReadParameter, boolParameter, \
@@ -472,7 +472,7 @@ def CalculateLCOELCOHLCOC(econ, model: Model) -> tuple:
472472
LCOH = LCOH * 2.931 # $/Million Btu
473473
elif econ.econmodel.value == EconomicModel.SAM_SINGLE_OWNER_PPA:
474474
# FIXME TODO designate nominal (as opposed to real) in client result
475-
LCOE = calculate_sam_economics(model)['LCOE (nominal)']['value']
475+
LCOE = econ.sam_economics.value['LCOE (nominal)']['value']
476476
else:
477477
# must be BICYCLE
478478
# average return on investment (tax and inflation adjusted)
@@ -1858,6 +1858,14 @@ def __init__(self, model: Model):
18581858
PreferredUnits=TimeUnit.YEAR,
18591859
CurrentUnits=TimeUnit.YEAR
18601860
)
1861+
1862+
# FIXME TODO/WIP representation in schema...
1863+
self.sam_economics = self.OutputParameterDict[self.sam_economics.Name] = OutputParameter(
1864+
'SAM Economics',
1865+
UnitType=Units.NONE,
1866+
json_parameter_type='object',
1867+
)
1868+
18611869
self.RITCValue = self.OutputParameterDict[self.RITCValue.Name] = OutputParameter(
18621870
Name="Investment Tax Credit Value",
18631871
display_name='Investment Tax Credit',
@@ -2785,23 +2793,27 @@ def Calculate(self, model: Model) -> None:
27852793
)
27862794

27872795
if self.econmodel.value == EconomicModel.SAM_SINGLE_OWNER_PPA:
2788-
sam_economics = calculate_sam_economics(model)
2789-
self.ProjectNPV.value = sam_economics['NPV']['value']
2790-
self.ProjectIRR.value = sam_economics['IRR']['value']
2796+
self.sam_economics.value = calculate_sam_economics(model)
2797+
self.ProjectNPV.value = self.sam_economics.value['NPV']['value']
2798+
self.ProjectIRR.value = self.sam_economics.value['IRR']['value']
27912799
# FIXME WIP VIR + MOIC
27922800
self.ProjectVIR.value, self.ProjectMOIC.value = -1, -1
27932801

27942802
# Calculate the project payback period
2795-
self.ProjectPaybackPeriod.value = 0.0 # start by assuming the project never pays back
2796-
for i in range(0, len(self.TotalCummRevenue.value), 1):
2803+
2804+
if self.econmodel.value == EconomicModel.SAM_SINGLE_OWNER_PPA:
2805+
self.ProjectPaybackPeriod.value = -1 # FIXME WIP
2806+
else:
2807+
self.ProjectPaybackPeriod.value = 0.0 # start by assuming the project never pays back
2808+
for i in range(0, len(self.TotalCummRevenue.value), 1):
27972809
# find out when the cumm cashflow goes from negative to positive
27982810
if self.TotalCummRevenue.value[i] > 0 >= self.TotalCummRevenue.value[i - 1]:
2799-
# we just crossed the threshold into positive project cummcashflow, so we can calculate payback period
2811+
# we just crossed the threshold into positive project cummcashflow,
2812+
# so we can calculate payback period
28002813
dFullDiff = self.TotalCummRevenue.value[i] + math.fabs(self.TotalCummRevenue.value[(i - 1)])
28012814
dPerc = math.fabs(self.TotalCummRevenue.value[(i - 1)]) / dFullDiff
28022815
self.ProjectPaybackPeriod.value = i + dPerc
28032816

2804-
28052817
# Calculate LCOE/LCOH
28062818
self.LCOE.value, self.LCOH.value, self.LCOC.value = CalculateLCOELCOHLCOC(self, model)
28072819

@@ -2817,7 +2829,9 @@ def Calculate(self, model: Model) -> None:
28172829
def calculate_cashflow(self, model: Model) -> None:
28182830
"""
28192831
Calculate cashflow and cumulative cash flow
2832+
TODO/WIP adjust/skip for SAM economic model(s)
28202833
"""
2834+
28212835
total_duration = model.surfaceplant.plant_lifetime.value + model.surfaceplant.construction_years.value
28222836
self.ElecRevenue.value = [0.0] * total_duration
28232837
self.ElecCummRevenue.value = [0.0] * total_duration

src/geophires_x/EconomicsSam.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
import geophires_x.Model as Model
2626

27-
_CASH_FLOW_PROFILE_KEY = 'Cash Flow'
27+
_SAM_CASH_FLOW_PROFILE_KEY = 'Cash Flow'
2828

2929

3030
@lru_cache(maxsize=12)
@@ -62,7 +62,7 @@ def calculate_sam_economics(model: Model) -> dict[str, dict[str, Any]]:
6262
('CAPEX', single_owner.Outputs.adjusted_installed_cost * 1e-6, 'MUSD'),
6363
# ('Gross Output', gt.Outputs.gross_output, 'MW'),
6464
# ('Net Output', gt.Outputs.gross_output - gt.Outputs.pump_work, 'MW')
65-
(_CASH_FLOW_PROFILE_KEY, cash_flow, None),
65+
(_SAM_CASH_FLOW_PROFILE_KEY, cash_flow, None),
6666
]
6767

6868
# max_field_name_len = max(len(x[0]) for x in display_data)
@@ -74,7 +74,7 @@ def calculate_sam_economics(model: Model) -> dict[str, dict[str, Any]]:
7474
# print(f'{field_display}\t{sig_figs(e[1], 5)} {e[2]}')
7575

7676
as_val = e[1]
77-
if key != _CASH_FLOW_PROFILE_KEY:
77+
if key != _SAM_CASH_FLOW_PROFILE_KEY:
7878
as_val = {'value': _sig_figs(e[1], 5), 'unit': e[2]}
7979

8080
ret[key] = as_val

src/geophires_x/Outputs.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
from pathlib import Path
55

66
import numpy as np
7+
from tabulate import tabulate
78

89
import geophires_x
910
import geophires_x.Model as Model
1011
from geophires_x.Economics import Economics
12+
from geophires_x.EconomicsSam import _SAM_CASH_FLOW_PROFILE_KEY
1113
from geophires_x.OutputsRich import print_outputs_rich
1214
from geophires_x.Parameter import ConvertUnitsBack, ConvertOutputUnits, LookupUnits, strParameter, boolParameter, \
1315
OutputParameter, ReadParameter
@@ -736,7 +738,10 @@ def o(output_param: OutputParameter):
736738
model.wellbores.PumpingPowerInj.value[i*model.economics.timestepsperyear.value],
737739
model.wellbores.PumpingPower.value[i*model.economics.timestepsperyear.value]))
738740
f.write(NL)
739-
f.write(NL)\
741+
f.write(NL)
742+
743+
if econ.econmodel.value == EconomicModel.SAM_SINGLE_OWNER_PPA:
744+
f.write(self.get_sam_cash_flow_profile_output(model))
740745

741746
except BaseException as ex:
742747
tb = sys.exc_info()[2]
@@ -751,9 +756,27 @@ def o(output_param: OutputParameter):
751756

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

759+
# noinspection PyMethodMayBeStatic
760+
def get_sam_cash_flow_profile_output(self, model):
761+
ret = '\n'
762+
ret += ' ***************************\n'
763+
ret += ' * SAM CASH FLOW PROFILE *\n'
764+
ret += ' ***************************\n'
765+
766+
ret += tabulate(
767+
model.economics.sam_economics.value[_SAM_CASH_FLOW_PROFILE_KEY],
768+
# tablefmt='pretty',
769+
# tablefmt='psql',
770+
# tablefmt='simple_grid',
771+
#tablefmt='fancy_grid',
772+
tablefmt='tsv',
773+
floatfmt='.2f',
774+
# headers='keys'
775+
)
776+
777+
return ret
754778

755779
@staticmethod
756780
def _field_label(field_name: str, print_width_before_value: int) -> str:
757781
return f'{field_name}:{" " * (print_width_before_value - len(field_name) - 1)}'
758782

759-

tests/geophires_x_tests/test_economics_sam.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
# ruff: noqa: I001 # Successful module initialization is dependent on this specific import order.
1212
from geophires_x.Model import Model
1313

14-
from geophires_x.EconomicsSam import calculate_sam_economics, _sig_figs, _CASH_FLOW_PROFILE_KEY
14+
from geophires_x.EconomicsSam import calculate_sam_economics, _sig_figs, _SAM_CASH_FLOW_PROFILE_KEY
1515
from geophires_x_client import GeophiresInputParameters
1616
from geophires_x_client import GeophiresXClient
1717
from geophires_x_client import GeophiresXResult
@@ -51,7 +51,7 @@ def test_cash_flow(self):
5151
m.Calculate()
5252

5353
sam_econ = calculate_sam_economics(m)
54-
cash_flow = sam_econ[_CASH_FLOW_PROFILE_KEY]
54+
cash_flow = sam_econ[_SAM_CASH_FLOW_PROFILE_KEY]
5555
self.assertIsNotNone(cash_flow)
5656

5757
print(

0 commit comments

Comments
 (0)