Skip to content

Commit 349b50d

Browse files
Merge pull request #91 from softwareengineerprogrammer/sam-em-add-ons
SAM-EM Add-Ons support [v3.9.47]
2 parents 4b6bc22 + ff7ca58 commit 349b50d

28 files changed

+901
-86
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.43
2+
current_version = 3.9.47
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.43
57+
version: 3.9.47
5858
version_manager: "bump2version"
5959
website: "https://github.com/NREL"
6060
year_from: "2023"

CHANGELOG.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ GEOPHIRES v3 (2023-2025)
1010

1111
`release <https://github.com/NREL/GEOPHIRES-X/releases/tag/v3.9.7>`__
1212

13-
v3.9 adds the `SAM Single Owner PPA Economic Model <https://nrel.github.io/GEOPHIRES-X/SAM-Economic-Models.html>`__
13+
v3.9.47 adds `Add-Ons support for SAM Economic Models <https://nrel.github.io/GEOPHIRES-X/SAM-Economic-Models.html#add-ons>`__
1414

15+
v3.9 adds the `SAM Single Owner PPA Economic Model <https://nrel.github.io/GEOPHIRES-X/SAM-Economic-Models.html>`__
1516

1617
3.8
1718
^^^

README.rst

Lines changed: 6 additions & 3 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.43.svg
61+
.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.9.47.svg
6262
:alt: Commits since latest release
63-
:target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.9.43...main
63+
:target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.9.47...main
6464

6565
.. |docs| image:: https://readthedocs.org/projects/GEOPHIRES-X/badge/?style=flat
6666
:target: https://nrel.github.io/GEOPHIRES-X
@@ -308,7 +308,10 @@ Example-specific web interface deeplinks are listed in the Link column.
308308
- `example_SAM-single-owner-PPA-2.txt <tests/examples/example_SAM-single-owner-PPA-2.txt>`__
309309
- `.out <tests/examples/example_SAM-single-owner-PPA-2.out>`__
310310
- `link <https://gtp.scientificwebservices.com/geophires?geophires-example-id=example_SAM-single-owner-PPA-2>`__
311-
311+
* - SAM Single Owner PPA: 50 MWe with Add-on
312+
- `example_SAM-single-owner-PPA-3.txt <tests/examples/example_SAM-single-owner-PPA-3.txt>`__
313+
- `.out <tests/examples/example_SAM-single-owner-PPA-3.out>`__
314+
- `link <https://gtp.scientificwebservices.com/geophires?geophires-example-id=example_SAM-single-owner-PPA-3>`__
312315
.. raw:: html
313316

314317
<embed>

docs/SAM-Economic-Models.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ The following table describes how GEOPHIRES parameters are transformed into SAM
3030
| `Fraction of Investment in Bonds` | Financial Parameters → Project Term Debt | `Debt percent` | `Singleowner` | `debt_percent` | .. N/A |
3131
| `Inflated Bond Interest Rate` | Financial Parameters → Project Term Debt | `Annual interest rate` | `Singleowner` | `term_int_rate` | .. N/A |
3232
| `Starting Electricity Sale Price`, `Ending Electricity Sale Price`, `Electricity Escalation Rate Per Year`, `Electricity Escalation Start Year` | Revenue | `PPA price` | `Singleowner` | `ppa_price_input` | GEOPHIRES's pricing model is used to create a PPA price schedule that is passed to SAM. |
33+
| `Total AddOn Profit Gained` | Revenue → Capacity Payments | `Fixed amount`, `Capacity payment amount` | `Singleowner` | `cp_capacity_payment_type = 1`, `cp_capacity_payment_amount` | |
3334
| `Investment Tax Credit Rate` | Incentives → Investment Tax Credit (ITC) | `Federal``Percentage (%)` | `Singleowner` | `itc_fed_percent` | Note that unlike the BICYCLE Economic Model's `Total capital costs`, SAM Economic Model's `Total CAPEX` is the total installed cost and does not subtract ITC value (if present). |
3435
| `Production Tax Credit Electricity` | Incentives → Production Tax Credit (PTC) | `Federal``Amount ($/kWh)` | `Singleowner` | `ptc_fed_amount` | .. N/A |
3536
| `Production Tax Credit Duration` | Incentives → Production Tax Credit (PTC) | `Federal``Term (years)` | `Singleowner` | `ptc_fed_term` | .. N/A |
@@ -48,7 +49,9 @@ The following table describes how GEOPHIRES parameters are transformed into SAM
4849
### Limitations
4950

5051
1. Only Electricity end-use is supported
51-
2. Only 1 construction year is supported. Note that the `Inflation Rate During Construction` parameter can be used to partially account for longer construction periods.
52+
2. Only 1 construction year is supported. Note that the `Inflation Rate During Construction` parameter can be used to
53+
partially account for longer construction periods.
54+
3. Add-ons with electricity and heat are not currently supported. (Add-ons CAPEX, OPEX, and profit are supported.)
5255

5356
## Using SAM Economic Models with Existing GEOPHIRES Inputs
5457

@@ -135,6 +138,17 @@ You can then manually enter the parameters from the logged mapping into the SAM
135138

136139
![](sam-desktop-app-manually-enter-system-capacity-from-geophires-log.png)
137140

141+
## Add-Ons
142+
143+
SAM Economic Models incorporate add-ons directly, unlike other GEOPHIRES economic models, which calculate separate
144+
extended economics.
145+
Total Add-on CAPEX is added to Total CAPEX.
146+
Total Add-on OPEX is added to Total operating and maintenance costs.
147+
Total AddOn Profit Gained per year is treated as fixed amount Capacity payment revenue.
148+
149+
Add-ons CAPEX, OPEX, and profit are supported.
150+
Add-ons with electricity and heat are not currently supported, but may be supported in the future.
151+
138152
## Examples
139153

140154
### SAM Single Owner PPA: 50 MWe

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.43'
21+
version = release = '3.9.47'
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.43',
16+
version='3.9.47',
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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2334,7 +2334,7 @@ def _warn(_msg: str) -> None:
23342334

23352335
# we can determine on-the-fly if Addons, CCUS, or S-DAC-GT are being used in the user input file
23362336
for key in model.InputParameters.keys():
2337-
if key.startswith("AddOn"):
2337+
if key.startswith("AddOn") and not self.DoAddOnCalculations.Provided:
23382338
self.DoAddOnCalculations.value = True
23392339
break
23402340

src/geophires_x/EconomicsAddOns.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import numpy_financial as npf
66
import geophires_x.Economics as Economics
77
import geophires_x.Model as Model
8-
from geophires_x.OptionList import EndUseOptions
8+
from geophires_x.OptionList import EndUseOptions, EconomicModel
99
from geophires_x.Parameter import listParameter, OutputParameter
1010
from geophires_x.Units import *
1111

@@ -108,12 +108,14 @@ def multi_addon_tooltip_text(param_name: str) -> str:
108108
# results
109109
self.AddOnCAPEXTotal = self.OutputParameterDict[self.AddOnCAPEXTotal.Name] = OutputParameter(
110110
"AddOn CAPEX Total",
111+
display_name='Total Add-on CAPEX',
111112
UnitType=Units.CURRENCY,
112113
PreferredUnits=CurrencyUnit.MDOLLARS,
113114
CurrentUnits=CurrencyUnit.MDOLLARS,
114115
)
115116
self.AddOnOPEXTotalPerYear = self.OutputParameterDict[self.AddOnOPEXTotalPerYear.Name] = OutputParameter(
116117
"AddOn OPEX Total Per Year",
118+
display_name='Total Add-on OPEX',
117119
UnitType=Units.CURRENCYFREQUENCY,
118120
PreferredUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR,
119121
CurrentUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR
@@ -222,6 +224,8 @@ def read_parameters(self, model: Model) -> None:
222224
model.logger.info(f'Init {str(__class__)}: {sys._getframe().f_code.co_name}')
223225
super().read_parameters(model) # read the parameters for the parent.
224226

227+
is_sam_econ_model = model.economics.econmodel.value == EconomicModel.SAM_SINGLE_OWNER_PPA
228+
225229
# Deal with all the parameter values that the user has provided that relate to this extension.
226230
# super.read_parameter will have already dealt with all the regular values, but anything unusual
227231
# may not be dealt with, so check.
@@ -244,12 +248,21 @@ def read_parameters(self, model: Model) -> None:
244248
if key.startswith("AddOn OPEX"):
245249
val = float(model.InputParameters[key].sValue)
246250
self.AddOnOPEXPerYear.value.append(val) # this assumes they put the values in the file in consecutive fashion
251+
247252
if key.startswith("AddOn Electricity Gained"):
253+
if is_sam_econ_model:
254+
raise NotImplementedError('AddOn Electricity is not supported for SAM Economic Models')
255+
248256
val = float(model.InputParameters[key].sValue)
249257
self.AddOnElecGainedPerYear.value.append(val) # this assumes they put the values in the file in consecutive fashion
258+
250259
if key.startswith("AddOn Heat Gained"):
260+
if is_sam_econ_model:
261+
raise NotImplementedError('AddOn Heat is not supported for SAM Economic Models')
262+
251263
val = float(model.InputParameters[key].sValue)
252264
self.AddOnHeatGainedPerYear.value.append(val) # this assumes they put the values in the file in consecutive fashion
265+
253266
if key.startswith("AddOn Profit Gained"):
254267
val = float(model.InputParameters[key].sValue)
255268
self.AddOnProfitGainedPerYear.value.append(val) # this assumes they put the values in the file in consecutive fashion
@@ -271,7 +284,9 @@ def Calculate(self, model: Model) -> None:
271284
:type model: :class:`~geophires_x.Model.Model`
272285
:return: Nothing, but it does make calculations and set values in the model
273286
"""
274-
model.logger.info("Init " + str(__class__) + ": " + sys._getframe().f_code.co_name)
287+
model.logger.info(f"Init {str(__class__)}: {sys._getframe().f_code.co_name}")
288+
289+
is_sam_em = model.economics.econmodel.value == EconomicModel.SAM_SINGLE_OWNER_PPA
275290

276291
# sum all the AddOn values together, so we can treat all AddOns together. If an AddOn slot is not used,
277292
# it has zeros for the values, so this won't create problems
@@ -302,6 +317,12 @@ def Calculate(self, model: Model) -> None:
302317
# Calculate the adjusted OPEX and CAPEX
303318
self.AdjustedProjectCAPEX.value = model.economics.CCap.value + self.AddOnCAPEXTotal.value
304319
self.AdjustedProjectOPEX.value = model.economics.Coam.value + self.AddOnOPEXTotalPerYear.value
320+
321+
if is_sam_em:
322+
# SAM econ models incorporate add-ons into main economics, not as separate extended economics
323+
model.economics.CCap.value = self.AdjustedProjectCAPEX.value
324+
model.economics.Coam.value = self.AdjustedProjectOPEX.value
325+
305326
AddOnCapCostPerYear = self.AddOnCAPEXTotal.value / model.surfaceplant.construction_years.value
306327
ProjectCapCostPerYear = self.AdjustedProjectCAPEX.value / model.surfaceplant.construction_years.value
307328

@@ -386,8 +407,9 @@ def Calculate(self, model: Model) -> None:
386407
self.AdjustedProjectCAPEX.value + (
387408
self.AdjustedProjectOPEX.value * model.surfaceplant.plant_lifetime.value))
388409

389-
# recalculate LCOE/LCOH
390-
self.LCOE.value, self.LCOH.value, LCOC = Economics.CalculateLCOELCOHLCOC(self, model)
410+
if not is_sam_em:
411+
# recalculate LCOE/LCOH
412+
self.LCOE.value, self.LCOH.value, LCOC = Economics.CalculateLCOELCOHLCOC(self, model)
391413

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

src/geophires_x/EconomicsSam.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,12 @@ def _get_single_owner_parameters(model: Model) -> dict[str, Any]:
415415

416416
ret['ibi_oth_amount'] = (econ.OtherIncentives.quantity() + econ.TotalGrant.quantity()).to('USD').magnitude
417417

418+
if model.economics.DoAddOnCalculations.value:
419+
add_on_profit_per_year = np.sum(model.addeconomics.AddOnProfitGainedPerYear.quantity().to('USD/yr').magnitude)
420+
add_on_profit_series = [add_on_profit_per_year]
421+
ret['cp_capacity_payment_amount'] = add_on_profit_series
422+
ret['cp_capacity_payment_type'] = 1
423+
418424
return ret
419425

420426

0 commit comments

Comments
 (0)