Skip to content

Commit

Permalink
Merge pull request #37 from softwareengineerprogrammer/combine-discou…
Browse files Browse the repository at this point in the history
…nt-rate-and-fixed-internal-rate

Set fixed internal rate default value to same as discount rate
  • Loading branch information
softwareengineerprogrammer authored Oct 15, 2024
2 parents c1927fb + 04f9feb commit 381f796
Show file tree
Hide file tree
Showing 25 changed files with 157 additions and 146 deletions.
4 changes: 2 additions & 2 deletions src/geophires_x/AGSEconomics.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ def read_parameters(self, model: Model) -> None:
# including the ones that are specific to this class

# inputs we already have - needs to be set at ReadParameter time so values set at the latest possible time
self.Discount_rate = model.economics.discountrate.value # same units are GEOPHIRES
self.Electricity_rate = model.surfaceplant.electricity_cost_to_buy.value # same units are GEOPHIRES
self.Discount_rate = model.economics.discountrate.value # same units as GEOPHIRES
self.Electricity_rate = model.surfaceplant.electricity_cost_to_buy.value # same units as GEOPHIRES

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

Expand Down
30 changes: 6 additions & 24 deletions src/geophires_x/AGSOutputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@

import geophires_x

from .Parameter import ConvertUnitsBack, ConvertOutputUnits
from .OptionList import EndUseOptions, EconomicModel
from .Units import *
from geophires_x.OptionList import EndUseOptions, EconomicModel

import geophires_x.Model as Model
import geophires_x.Outputs as Outputs
import numpy as np

from geophires_x.Units import TemperatureUnit

NL = "\n"


Expand All @@ -28,27 +29,8 @@ def PrintOutputs(self, model: Model):
:return: None
"""
model.logger.info(f'Init {str(__class__)}: {sys._getframe().f_code.co_name}')
# Deal with converting Units back to PreferredUnits, if required.
# before we write the outputs, we go thru all the parameters for all of the objects and set the values
# back to the units that the user entered the data in
# We do this because the value may be displayed in the output, and we want the user to recognize their value,
# not some converted value
for obj in [model.reserv, model.wellbores, model.surfaceplant, model.economics]:
for key in obj.ParameterDict:
param = obj.ParameterDict[key]
if not param.UnitsMatch:
ConvertUnitsBack(param, model)

# now we need to loop thru all the output parameters to update their units to whatever units the user has specified.
# i.e., they may have specified that all LENGTH results must be in feet, so we need to convert
# those from whatever LENGTH unit they are to feet.
# same for all the other classes of units (TEMPERATURE, DENSITY, etc).

for obj in [model.reserv, model.wellbores, model.surfaceplant, model.economics]:
for key in obj.OutputParameterDict:
if key in self.ParameterDict:
if self.ParameterDict[key] != obj.OutputParameterDict[key].CurrentUnits:
ConvertOutputUnits(obj.OutputParameterDict[key], self.ParameterDict[key], model)

self._convert_units(model)

# ---------------------------------------
# write results to output file and screen
Expand Down
17 changes: 11 additions & 6 deletions src/geophires_x/Economics.py
Original file line number Diff line number Diff line change
Expand Up @@ -837,15 +837,17 @@ def __init__(self, model: Model):
ErrMessage="assume default fixed charge rate (0.1)",
ToolTipText="Fixed charge rate (FCR) used in the Fixed Charge Rate Model"
)

discount_rate_default_val = 0.0625
self.discountrate = self.ParameterDict[self.discountrate.Name] = floatParameter(
"Discount Rate",
DefaultValue=0.07,
DefaultValue=discount_rate_default_val,
Min=0.0,
Max=1.0,
UnitType=Units.PERCENT,
PreferredUnits=PercentUnit.TENTH,
PreferredUnits=PercentUnit.PERCENT,
CurrentUnits=PercentUnit.TENTH,
ErrMessage="assume default discount rate (0.07)",
ErrMessage=f'assume default discount rate ({discount_rate_default_val})',
ToolTipText="Discount rate used in the Standard Levelized Cost Model"
)
self.FIB = self.ParameterDict[self.FIB.Name] = floatParameter(
Expand Down Expand Up @@ -1379,15 +1381,18 @@ def __init__(self, model: Model):
PreferredUnits=CurrencyUnit.MDOLLARS,
CurrentUnits=CurrencyUnit.MDOLLARS
)

fir_default_unit = PercentUnit.PERCENT
fir_default_val = self.discountrate.quantity().to(convertible_unit(fir_default_unit)).magnitude
self.FixedInternalRate = self.ParameterDict[self.FixedInternalRate.Name] = floatParameter(
"Fixed Internal Rate",
DefaultValue=6.25,
DefaultValue=fir_default_val,
Min=0.0,
Max=100.0,
UnitType=Units.PERCENT,
PreferredUnits=PercentUnit.PERCENT,
CurrentUnits=PercentUnit.PERCENT,
ErrMessage="assume default for fixed internal rate (6.25%)",
CurrentUnits=fir_default_unit,
ErrMessage=f'assume default for fixed internal rate ({fir_default_val}%)',
ToolTipText="Fixed Internal Rate (used in NPV calculation)"
)
self.CAPEX_heat_electricity_plant_ratio = self.ParameterDict[self.CAPEX_heat_electricity_plant_ratio.Name] = floatParameter(
Expand Down
2 changes: 2 additions & 0 deletions src/geophires_x/GEOPHIRES3_newunits.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
USD = [currency]
cents = USD / 100
KUSD = USD * 1000
MMBTU = BTU * 1_000_000
4 changes: 2 additions & 2 deletions src/geophires_x/GeoPHIRESUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import CoolProp.CoolProp as CP

from geophires_x.Parameter import ParameterEntry, Parameter
from geophires_x.Units import get_unit_registry
from geophires_x.Units import get_unit_registry, convertible_unit

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

Expand Down Expand Up @@ -224,7 +224,7 @@ def quantity(value: float, unit: str) -> PlainQuantity:
:rtype: pint.registry.Quantity - note type annotation uses PlainQuantity due to issues with python 3.8 failing
to import the Quantity TypeAlias
"""
return _ureg.Quantity(value, unit)
return _ureg.Quantity(value, convertible_unit(unit))


@lru_cache
Expand Down
27 changes: 17 additions & 10 deletions src/geophires_x/Outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -744,15 +744,7 @@ def read_parameters(self, model: Model, default_output_path: Path = None) -> Non

model.logger.info(f'Complete {__class__!s}: {__name__}')

def PrintOutputs(self, model: Model):
"""
PrintOutputs writes the standard outputs to the output file.
:param model: The container class of the application, giving access to everything else, including the logger
:type model: :class:`~geophires_x.Model.Model`
:return: None
"""
model.logger.info(f'Init {str(__class__)}: {sys._getframe().f_code.co_name}')

def _convert_units(self, model: Model):
# Deal with converting Units back to PreferredUnits, if required.
# before we write the outputs, we go thru all the parameters for all of the objects and set the values back
# to the units that the user entered the data in
Expand All @@ -779,6 +771,17 @@ def PrintOutputs(self, model: Model):
elif not output_param.UnitsMatch:
obj.OutputParameterDict[key] = output_param.with_preferred_units()

def PrintOutputs(self, model: Model):
"""
PrintOutputs writes the standard outputs to the output file.
:param model: The container class of the application, giving access to everything else, including the logger
:type model: :class:`~geophires_x.Model.Model`
:return: None
"""
model.logger.info(f'Init {str(__class__)}: {sys._getframe().f_code.co_name}')

self._convert_units(model)

#data structures and assignments for HTML and Improved Text Output formats
simulation_metadata = []
summary = []
Expand Down Expand Up @@ -1634,7 +1637,11 @@ def PrintOutputs(self, model: Model):
f.write(f' Fixed Charge Rate (FCR): {model.economics.FCR.value*100.0:10.2f} ' + model.economics.FCR.CurrentUnits.value + NL)
elif model.economics.econmodel.value == EconomicModel.STANDARDIZED_LEVELIZED_COST:
f.write(' Economic Model = ' + model.economics.econmodel.value.value + NL)
f.write(f' Interest Rate: {model.economics.discountrate.value*100.0:10.2f} ' + model.economics.discountrate.CurrentUnits.value + NL)

# FIXME discountrate should not be multiplied by 100 here -
# it appears to be incorrectly claiming its units are percent when the actual value is in tenths.
f.write(f' Interest Rate: {model.economics.discountrate.value*100.0:10.2f} {model.economics.discountrate.CurrentUnits.value}\n')

elif model.economics.econmodel.value == EconomicModel.BICYCLE:
f.write(' Economic Model = ' + model.economics.econmodel.value.value + NL)
f.write(f' Accrued financing during construction: {model.economics.inflrateconstruction.value*100:10.2f} ' + model.economics.inflrateconstruction.CurrentUnits.value + NL)
Expand Down
2 changes: 2 additions & 0 deletions src/geophires_x/OutputsAddOns.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ def PrintOutputs(self, model) -> tuple:
"""
model.logger.info(f'Init {str(__class__)}: {__name__}')

self._convert_units(model)

# now do AddOn output, which will append to the original output
# write results to output file and screen
try:
Expand Down
4 changes: 3 additions & 1 deletion src/geophires_x/OutputsCCUS.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ def PrintOutputs(self, model):
:type model: :class:`~geophires_x.Model.Model`
:return: Nothing
"""
model.logger.info("Init " + str(__class__) + ": " + sys._getframe().f_code.co_name)
model.logger.info(f'Init {__class__!s}: sys._getframe().f_code.co_name')

self._convert_units(model)

if np.sum(model.ccuseconomics.CCUSRevenue.value) == 0:
return # don't bother if we have nothing to report.
Expand Down
2 changes: 2 additions & 0 deletions src/geophires_x/OutputsS_DAC_GT.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ def PrintOutputs(self, model) -> tuple:
"""
model.logger.info(f'Init {str(__class__)}: {__name__}')

self._convert_units(model)

# now do S_DAC_GT output, which will append to the original output
# write results to output file and screen
try:
Expand Down
6 changes: 3 additions & 3 deletions src/geophires_x/Parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def UnitsMatch(self) -> str:

def with_preferred_units(self) -> Any: # Any is a proxy for Self
ret: OutputParameter = dataclasses.replace(self)
ret.value = ret.quantity().to(ret.PreferredUnits).magnitude
ret.value = ret.quantity().to(convertible_unit(ret.PreferredUnits)).magnitude
ret.CurrentUnits = ret.PreferredUnits
return ret

Expand Down Expand Up @@ -609,7 +609,7 @@ def ConvertUnitsBack(ParamToModify: Parameter, model):
model.logger.info(f'Init {str(__name__)}: {sys._getframe().f_code.co_name} for {ParamToModify.Name}')

try:
ParamToModify.value = _ureg.Quantity(ParamToModify.value, ParamToModify.CurrentUnits.value).to(ParamToModify.PreferredUnits.value).magnitude
ParamToModify.value = _ureg.Quantity(ParamToModify.value, convertible_unit(ParamToModify.CurrentUnits)).to(convertible_unit(ParamToModify.PreferredUnits)).magnitude
ParamToModify.CurrentUnits = ParamToModify.PreferredUnits
except AttributeError as ae:
# TODO refactor to check for/convert currency instead of relying on try/except once currency conversion is
Expand Down Expand Up @@ -848,7 +848,7 @@ def ConvertOutputUnits(oparam: OutputParameter, newUnit: Units, model):
"""

try:
oparam.value = _ureg.Quantity(oparam.value, oparam.CurrentUnits.value).to(newUnit.value).magnitude
oparam.value = _ureg.Quantity(oparam.value, oparam.CurrentUnits.value).to(convertible_unit(newUnit.value)).magnitude
oparam.CurrentUnits = newUnit
return
except AttributeError as ae:
Expand Down
13 changes: 0 additions & 13 deletions src/geophires_x/SUTRAEconomics.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,19 +111,6 @@ def __init__(self, model: Model):
ToolTipText="Multiplier for built-in surface plant capital cost correlation",
)

self.discountrate = self.ParameterDict[self.discountrate.Name] = floatParameter(
"Discount Rate",
value=0.07,
DefaultValue=0.07,
Min=0.0,
Max=1.0,
UnitType=Units.PERCENT,
PreferredUnits=PercentUnit.PERCENT,
CurrentUnits=PercentUnit.TENTH,
ErrMessage="assume default discount rate (0.07)",
ToolTipText="Discount rate used in the Standard Levelized Cost Model",
)

self.inflrateconstruction = self.ParameterDict[self.inflrateconstruction.Name] = floatParameter(
"Inflation Rate During Construction",
value=0.0,
Expand Down
12 changes: 9 additions & 3 deletions src/geophires_x/SUTRAOutputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import sys

import geophires_x
import numpy as np
import geophires_x.Model as Model
from geophires_x.Outputs import Outputs
from .OptionList import EconomicModel
from geophires_x.OptionList import EconomicModel

import numpy as np

NL="\n"

Expand Down Expand Up @@ -47,6 +48,7 @@ def PrintOutputs(self, model: Model):
"""
model.logger.info(f'Init {str(__class__)}: {sys._getframe().f_code.co_name}')

self._convert_units(model)

# write results to output file and screen
try:
Expand Down Expand Up @@ -83,7 +85,11 @@ def PrintOutputs(self, model: Model):
f.write(f" Fixed Charge Rate (FCR): {model.economics.FCR.value*100.0:10.2f} " + model.economics.FCR.CurrentUnits.value + NL)
elif model.economics.econmodel.value == EconomicModel.STANDARDIZED_LEVELIZED_COST:
f.write(" Economic Model = " + model.economics.econmodel.value.value + NL)
f.write(f" Interest Rate: {model.economics.discountrate.value*100.0:10.2f} " + model.economics.discountrate.PreferredUnits.value + NL)

# FIXME discountrate should not be multiplied by 100 here -
# it appears to be incorrectly claiming its units are percent when the actual value is in tenths.
f.write(f" Interest Rate: {model.economics.discountrate.value*100.0:10.2f} {model.economics.discountrate.CurrentUnits.value}\n")

elif model.economics.econmodel.value == EconomicModel.BICYCLE:
f.write(" Economic Model = " + model.economics.econmodel.value.value + NL)
f.write(f" Accrued financing during construction: {model.economics.inflrateconstruction.value*100:10.2f} " + model.economics.inflrateconstruction.PreferredUnits.value + NL)
Expand Down
38 changes: 27 additions & 11 deletions src/geophires_x/Units.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# copyright, 2023, Malcolm I Ross
from enum import IntEnum, Enum, auto
from typing import Any

import pint
import os


_UREG = None


def get_unit_registry():
global _UREG
if _UREG is None:
Expand All @@ -14,6 +16,19 @@ def get_unit_registry():

return _UREG


def convertible_unit(unit: Any) -> Any:
"""
pint can't handle '%' as a unit in python 3.8, so use this method when constructing quantities
:type unit: str|Enum
"""
if unit == Units.PERCENT or unit == PercentUnit.PERCENT or unit == Units.PERCENT.value:
return 'percent'

return unit


class Units(IntEnum):
"""All possible systems of measure"""
NONE = auto()
Expand Down Expand Up @@ -59,8 +74,8 @@ class Units(IntEnum):
POWERPERUNITAREA = auto()
HEATPERUNITVOLUME = auto()
POWERPERUNITVOLUME = auto()
DECAY_RATE=auto()
INFLATION_RATE=auto()
DECAY_RATE = auto()
INFLATION_RATE = auto()
DYNAMIC_VISCOSITY = auto()


Expand Down Expand Up @@ -158,6 +173,7 @@ class EnergyFrequencyUnit(str, Enum):
MWhPERYEAR = "MWh/year"
GWhPERYEAR = "GWh/year"


class CurrencyUnit(str, Enum):
"""Currency Units"""
MDOLLARS = "MUSD"
Expand Down Expand Up @@ -327,41 +343,41 @@ class MassUnit(str, Enum):
OZ = "ounce"


class PopDensityUnit(str,Enum):
class PopDensityUnit(str, Enum):
"""Population Density Units"""
perkm2 = "Population per square km"


class HeatPerUnitAreaUnit(str,Enum):
class HeatPerUnitAreaUnit(str, Enum):
"""Population Density Units"""
KJPERSQKM = "kJ/km**2"


class PowerPerUnitAreaUnit(str,Enum):
class PowerPerUnitAreaUnit(str, Enum):
"""Population Density Units"""
MWPERSQKM = "MW/km**2"


class HeatPerUnitVolumeUnit(str,Enum):
class HeatPerUnitVolumeUnit(str, Enum):
"""Population Density Units"""
KJPERCUBICKM = "kJ/km**3"


class PowerPerUnitVolumeUnit(str,Enum):
class PowerPerUnitVolumeUnit(str, Enum):
"""Population Density Units"""
MWPERCUBICKM = "MW/km**3"


class Decay_RateUnit(str,Enum):
class Decay_RateUnit(str, Enum):
"""Decay rate Units"""
PERCENTPERYEAR = "%/yr"


class Inflation_RateUnit(str,Enum):
class Inflation_RateUnit(str, Enum):
"""Decay rate Units"""
KPASCALPERYEAR = "kPa/yr"


class Dynamic_ViscosityUnit(str,Enum):
class Dynamic_ViscosityUnit(str, Enum):
"""Dynamic Viscosity Units"""
PASCALSEC = "PaSec"
Loading

0 comments on commit 381f796

Please sign in to comment.