Skip to content

Commit

Permalink
[pre-commit.ci] auto fixes from pre-commit.com hooks
Browse files Browse the repository at this point in the history
for more information, see https://pre-commit.ci
  • Loading branch information
pre-commit-ci[bot] committed Feb 5, 2024
1 parent 53a6d10 commit 3286360
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 62 deletions.
6 changes: 3 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
version: 2
updates:
- package-ecosystem: 'github-actions'
directory: '/'
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: 'monthly'
interval: "monthly"
135 changes: 94 additions & 41 deletions dac_costing/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@
import numpy_financial as npf
import pandas as pd

VALID_ENERGYSOURCES = ["NGCC w/ CCS", "Advanced NGCC", "Solar", "Wind", "Advanced Nuclear"]
VALID_ENERGYSOURCES = [
"NGCC w/ CCS",
"Advanced NGCC",
"Solar",
"Wind",
"Advanced Nuclear",
]

# Constants
HOURS_PER_DAY = 24
Expand All @@ -21,7 +27,7 @@


def default_params() -> Dict:
""" load default parameters """
"""load default parameters"""
dir_path = os.path.dirname(os.path.realpath(__file__))
with open(os.path.join(dir_path, "data", "parameters.json")) as f:
return json.load(f)
Expand All @@ -36,7 +42,7 @@ def values_factory() -> DefaultDict:


@dataclass
class DacComponent(object):
class DacComponent:
"""
Base DAC Component Class
Expand All @@ -48,21 +54,23 @@ class DacComponent(object):

params: Dict[str, Any] = field(default_factory=dict, repr=False)

values: DefaultDict[str, float] = field(default_factory=values_factory, init=False, repr=False)
values: DefaultDict[str, float] = field(
default_factory=values_factory, init=False, repr=False
)

def __post_init__(self):
# update default parameters with those supplied by init
self.params = {**default_params(), **self.params}

@property
def series(self):
""" return a pandas.Series view of the components values """
"""return a pandas.Series view of the components values"""
if not self.values:
self.compute()
return pd.Series(self.values)

def compute(self):
""" compute this components values """
"""compute this components values"""
raise NotImplementedError()
return self

Expand All @@ -80,8 +88,10 @@ def lead_time_mult(self, time) -> float:
return np.array(values).sum()

def recovery_factor(self):
""" calculate the capital recovery factor """
return -npf.pmt(self.params["WACC [%]"], self.params["Economic Lifetime [years]"], 1)
"""calculate the capital recovery factor"""
return -npf.pmt(
self.params["WACC [%]"], self.params["Economic Lifetime [years]"], 1
)


@dataclass
Expand All @@ -107,12 +117,14 @@ def compute(self, e_vals):
tech = self.params["Technology"]["Battery Storage"]

# Battery Capacity [MWh]
self.values["Battery Capacity [MWh]"] = e_vals["Base Energy Requirement [MW]"] * (
HOURS_PER_DAY * (1 - e_vals["Planned Capacity Factor"])
)
self.values["Battery Capacity [MWh]"] = e_vals[
"Base Energy Requirement [MW]"
] * (HOURS_PER_DAY * (1 - e_vals["Planned Capacity Factor"]))

# Round Trip Efficiency
self.values["Round Trip Efficiency"] = tech["Efficiency (Thermal or Round Trip)"]
self.values["Round Trip Efficiency"] = tech[
"Efficiency (Thermal or Round Trip)"
]

# Battery Capacity Needed [MWh]
self.values["Battery Capacity Needed [MWh]"] = (
Expand All @@ -121,7 +133,8 @@ def compute(self, e_vals):

# Increased [MWh]
self.values["Increased [MWh]"] = (
self.values["Battery Capacity Needed [MWh]"] - self.values["Battery Capacity [MWh]"]
self.values["Battery Capacity Needed [MWh]"]
- self.values["Battery Capacity [MWh]"]
)

# Increased Solar/Wind Need
Expand All @@ -132,15 +145,21 @@ def compute(self, e_vals):
# Battery Capital Cost [M$]
self.values["Battery Capital Cost [M$]"] = (
tech["Base Plant Cost [M$]"]
* (self.values["Battery Capacity Needed [MWh]"] / tech["Battery Capacity [MWhr]"])
* (
self.values["Battery Capacity Needed [MWh]"]
/ tech["Battery Capacity [MWhr]"]
)
** tech["Scaling Factor"]
)

# Battery Fixed O&M [$/tCO2eq]
self.values["Battery Fixed O&M [$/tCO2eq]"] = (
(
tech["Base Plant Annual Fixed O&M [$M]"]
* (self.values["Battery Capacity Needed [MWh]"] / tech["Battery Capacity [MWhr]"])
* (
self.values["Battery Capacity Needed [MWh]"]
/ tech["Battery Capacity [MWhr]"]
)
** tech["Scaling Factor"]
)
* MILLION
Expand Down Expand Up @@ -187,7 +206,7 @@ def __post_init__(self):
super().__post_init__()

def compute(self):
""" compute the energy section values """
"""compute the energy section values"""

tech = self.params["Technology"][self.source]

Expand All @@ -198,7 +217,9 @@ def compute(self):
self.values["Planned Capacity Factor"] = tech["Availability"]

# Electric Power Requirement [MW] (aka low value case in C1)
self.values["Base Energy Requirement [MW]"] = self.params["Base Energy Requirement [MW]"]
self.values["Base Energy Requirement [MW]"] = self.params[
"Base Energy Requirement [MW]"
]

# calculate battery params now
if self.battery:
Expand All @@ -207,19 +228,23 @@ def compute(self):

# Plant Size [MW]
self.values["Plant Size [MW]"] = (
self.values["Base Energy Requirement [MW]"] / self.values["Planned Capacity Factor"]
self.values["Base Energy Requirement [MW]"]
/ self.values["Planned Capacity Factor"]
)
if self.battery:
self.values["Plant Size [MW]"] += self.values["Increased Need [MW]"]

# Overnight Cost [M$]
self.values["Overnight Cost [M$]"] = (
tech["Base Plant Cost [M$]"]
* (self.values["Plant Size [MW]"] / tech["Plant Size [MW]"]) ** tech["Scaling Factor"]
* (self.values["Plant Size [MW]"] / tech["Plant Size [MW]"])
** tech["Scaling Factor"]
)

# Lead Time Multiplier
self.values["Lead Time Multiplier"] = self.lead_time_mult(tech["Lead Time [Years]"])
self.values["Lead Time Multiplier"] = self.lead_time_mult(
tech["Lead Time [Years]"]
)

# Capital Cost [M$]
self.values["Capital Cost [M$]"] = (
Expand All @@ -229,7 +254,9 @@ def compute(self):
# Total Capital Cost [M$]
self.values["Total Capital Cost [M$]"] = self.values["Capital Cost [M$]"]
if self.battery:
self.values["Total Capital Cost [M$]"] += self.values["Battery Capital Cost [M$]"]
self.values["Total Capital Cost [M$]"] += self.values[
"Battery Capital Cost [M$]"
]

# Annual Capital Recovery Factor
annual_capital_recovery_factor = self.recovery_factor()
Expand Down Expand Up @@ -262,12 +289,18 @@ def compute(self):
)

# Total Fixed O&M [$/tCO2eq]
self.values["Total Fixed O&M [$/tCO2eq]"] = self.values["Power Fixed O&M [$/tCO2eq]"]
self.values["Total Fixed O&M [$/tCO2eq]"] = self.values[
"Power Fixed O&M [$/tCO2eq]"
]
if self.battery:
self.values["Total Fixed O&M [$/tCO2eq]"] += self.values["Battery Fixed O&M [$/tCO2eq]"]
self.values["Total Fixed O&M [$/tCO2eq]"] += self.values[
"Battery Fixed O&M [$/tCO2eq]"
]

# Total Variable O&M [$/tCO2eq]
self.values["Total Variable O&M [$/tCO2eq]"] = self.values["Power Variable O&M [$/tCO2eq]"]
self.values["Total Variable O&M [$/tCO2eq]"] = self.values[
"Power Variable O&M [$/tCO2eq]"
]
if self.battery:
self.values["Total Variable O&M [$/tCO2eq]"] += self.values[
"Battery Variable O&M [$/tCO2eq]"
Expand Down Expand Up @@ -310,9 +343,9 @@ def compute(self):
)

# Total Cost [$/tCO2eq net]
self.values["Total Cost [$/tCO2eq net]"] = self.values["Total Cost [$/tCO2eq gross]"] / (
1 - self.values["Emitted [tCO2eq/tCO2]"]
)
self.values["Total Cost [$/tCO2eq net]"] = self.values[
"Total Cost [$/tCO2eq gross]"
] / (1 - self.values["Emitted [tCO2eq/tCO2]"])

return self

Expand Down Expand Up @@ -372,7 +405,7 @@ class DacSection(DacComponent):
"""

def compute(self):
""" compute the DAC section values """
"""compute the DAC section values"""

# Total Overnight Capital Cost [M$]
self.values["Total Capital Cost [M$]"] = self.params["Total Capex [$]"]
Expand All @@ -399,7 +432,9 @@ def compute(self):
self.values["Fixed O&M [$/tCO2eq]"] = self.params["Fixed O&M Costs [$/tCO2]"]

# Variable O&M [$/tCO2eq]
self.values["Variable O&M [$/tCO2eq]"] = self.params["Variable O&M Cost [$/tCO2]"]
self.values["Variable O&M [$/tCO2eq]"] = self.params[
"Variable O&M Cost [$/tCO2]"
]

# Total Cost [$/tCO2]
self.values["Total Cost [$/tCO2]"] = (
Expand Down Expand Up @@ -437,7 +472,9 @@ class DacModel(DacComponent):
thermal: Optional[Type[EnergySection]] = None
dac: Optional[Type[DacSection]] = None

def _combined_power_block_requirements(self, source, ev, tv) -> DefaultDict[str, float]:
def _combined_power_block_requirements(
self, source, ev, tv
) -> DefaultDict[str, float]:
"""compute the combined power block requirements
Parameters
Expand Down Expand Up @@ -481,7 +518,8 @@ def _combined_power_block_requirements(self, source, ev, tv) -> DefaultDict[str,
v["Power Fixed O&M [$/tCO2eq]"] = (
(
tech["Base Plant Annual Fixed O&M [$M]"]
* (v["Plant Size [MW]"] / tech["Plant Size [MW]"]) ** tech["Scaling Factor"]
* (v["Plant Size [MW]"] / tech["Plant Size [MW]"])
** tech["Scaling Factor"]
)
* MILLION
/ self.params["Scale [tCO2/year]"]
Expand All @@ -498,7 +536,8 @@ def _combined_power_block_requirements(self, source, ev, tv) -> DefaultDict[str,
if "Battery Capacity Needed [MWh]" in ev:
# Battery Capacity [MWh]
v["Battery Capacity [MWh]"] = (
ev["Battery Capacity Needed [MWh]"] + tv["Battery Capacity Needed [MWh]"]
ev["Battery Capacity Needed [MWh]"]
+ tv["Battery Capacity Needed [MWh]"]
)

# Battery Capital Cost [M$]
Expand All @@ -512,7 +551,10 @@ def _combined_power_block_requirements(self, source, ev, tv) -> DefaultDict[str,
v["Battery Fixed O&M [$/tCO2eq]"] = (
(
bat_tech["Base Plant Annual Fixed O&M [$M]"]
* (v["Battery Capacity [MWh]"] / bat_tech["Battery Capacity [MWhr]"])
* (
v["Battery Capacity [MWh]"]
/ bat_tech["Battery Capacity [MWhr]"]
)
** bat_tech["Scaling Factor"]
)
* MILLION
Expand All @@ -533,7 +575,9 @@ def _combined_power_block_requirements(self, source, ev, tv) -> DefaultDict[str,
v["Battery Variable O&M [$/tCO2eq]"] = 0

# Total Capital Cost [M$]
v["Total Capital Cost [M$]"] = v["Capital Cost [M$]"] + v["Battery Capital Cost [M$]"]
v["Total Capital Cost [M$]"] = (
v["Capital Cost [M$]"] + v["Battery Capital Cost [M$]"]
)

# Capital Recovery [$/tCO2eq]
v["Capital Recovery [$/tCO2eq]"] = (
Expand Down Expand Up @@ -573,18 +617,23 @@ def _total_energy_block_costs(self, ev, tv) -> DefaultDict[str, float]:
v = values_factory()

# Total Power Capacity Required [MW]
v["Total Power Capacity Required [MW]"] = ev["Plant Size [MW]"] + tv["Plant Size [MW]"]
v["Total Power Capacity Required [MW]"] = (
ev["Plant Size [MW]"] + tv["Plant Size [MW]"]
)

# Total Battery Capacity Required [MWh]
if "Battery Capacity Needed [MWh]" in ev:
v["Total Battery Capacity Required [MWh]"] = (
ev["Battery Capacity Needed [MWh]"] + tv["Battery Capacity Needed [MWh]"]
ev["Battery Capacity Needed [MWh]"]
+ tv["Battery Capacity Needed [MWh]"]
)
else:
v["Total Battery Capacity Required [MWh]"] = 0.0

# Total Capital Cost [M$]
v["Total Capital Cost [M$]"] = ev["Total Capital Cost [M$]"] + tv["Total Capital Cost [M$]"]
v["Total Capital Cost [M$]"] = (
ev["Total Capital Cost [M$]"] + tv["Total Capital Cost [M$]"]
)

# Capital Recovery [$/tCO2eq]
v["Capital Recovery [$/tCO2eq]"] = (
Expand Down Expand Up @@ -646,12 +695,15 @@ def _total_energy_block_costs_combined(self, ev, tv, cv) -> DefaultDict[str, flo
v = values_factory()

# Total Power Capacity Required [MW]
v["Total Power Capacity Required [MW]"] = ev["Plant Size [MW]"] + tv["Plant Size [MW]"]
v["Total Power Capacity Required [MW]"] = (
ev["Plant Size [MW]"] + tv["Plant Size [MW]"]
)

# Total Battery Capacity Required [MWh]
if "Battery Capacity Needed [MWh]" in ev:
v["Total Battery Capacity Required [MWh]"] = (
ev["Battery Capacity Needed [MWh]"] + tv["Battery Capacity Needed [MWh]"]
ev["Battery Capacity Needed [MWh]"]
+ tv["Battery Capacity Needed [MWh]"]
)
else:
v["Total Battery Capacity Required [MWh]"] = 0
Expand Down Expand Up @@ -694,7 +746,7 @@ def _total_energy_block_costs_combined(self, ev, tv, cv) -> DefaultDict[str, flo
return v

def compute(self):
""" compute the composite DAC model's values """
"""compute the composite DAC model's values"""

ev = self.electric.compute().values
tv = self.thermal.compute().values
Expand All @@ -708,7 +760,8 @@ def compute(self):

# Total Capital Cost [M$]
self.values["Total Capital Cost [M$]"] = (
tev["Total Capital Cost [M$]"] + dv["Capital Cost (including Lead Time) [M$]"]
tev["Total Capital Cost [M$]"]
+ dv["Capital Cost (including Lead Time) [M$]"]
)

# Capital Recovery [$/tCO2eq]
Expand Down
12 changes: 10 additions & 2 deletions dac_costing/tests/test_hypothesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
from hypothesis import given
from hypothesis.strategies import fixed_dictionaries, floats

from dac_costing.model import BatterySection, DacModel, DacSection, EnergySection, NgThermalSection
from dac_costing.model import (
BatterySection,
DacModel,
DacSection,
EnergySection,
NgThermalSection,
)

strats = {
"Base Energy Requirement [MW]": floats(
Expand All @@ -11,7 +17,9 @@
"Required Thermal Energy [GJ/tCO2]": floats(
min_value=0, max_value=100, allow_infinity=False, allow_nan=False
),
"Total Capex [$]": floats(min_value=1, max_value=1e12, allow_infinity=False, allow_nan=False),
"Total Capex [$]": floats(
min_value=1, max_value=1e12, allow_infinity=False, allow_nan=False
),
}


Expand Down
Loading

0 comments on commit 3286360

Please sign in to comment.