Skip to content

Commit

Permalink
Merge pull request #561 from agoenergy/wingechr/issue553
Browse files Browse the repository at this point in the history
fix storage cost  (capacity) using CAP_F
  • Loading branch information
markushal authored Sep 16, 2024
2 parents 031e727 + 2a1b424 commit 824e4d9
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 8 deletions.
23 changes: 20 additions & 3 deletions ptxboa/api_calc.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ def calculate(data: CalculateDataType) -> pd.DataFrame:
# start main chain calculation
main_output_value = 1 # start with normalized value of 1

# pre-calculate main_output_value before transport
# for correct scaling of storeages.
# storage units use capacity factor CAP_F
# per produced unit (before transport losses)
main_output_value_before_transport = main_output_value
for step_data in data["main_process_chain"]:
main_output_value_before_transport *= step_data["EFF"]

# accumulate needed electric input
sum_el = main_output_value
results = []
Expand Down Expand Up @@ -51,10 +59,19 @@ def calculate(data: CalculateDataType) -> pd.DataFrame:
if not is_transport:
flh = step_data["FLH"]
liefetime = step_data["LIFETIME"]
capex = step_data["CAPEX"]
capex_rel = step_data["CAPEX"]
opex_f = step_data["OPEX-F"]
capacity = main_output_value / flh
capex = capacity * capex

if "CAP_F" in step_data:
# Storage unit: capacity
# TODO: double check units (division by 8760 h)?
capacity = (
main_output_value_before_transport * step_data["CAP_F"] / 8760
)
else:
capacity = main_output_value / flh

capex = capacity * capex_rel
capex_ann = annuity(wacc, liefetime, capex)
opex = opex_f * capacity + opex_o * main_output_value

Expand Down
7 changes: 5 additions & 2 deletions ptxboa/api_optimize.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,11 @@ def _merge_data(input_data: CalculateDataType, opt_output_data: OptOutputDataTyp
step["FLH"] = opt_output_data["ELY"]["FLH"] * 8760
elif step["step"] == "DERIV":
step["FLH"] = opt_output_data["DERIV"]["FLH"] * 8760
elif step["step"] == "EL_STR":
step["CAP_F"] = opt_output_data["EL_STR"]["CAP_F"]
elif step["step"] == "H2_STR":
step["CAP_F"] = opt_output_data["H2_STR"]["CAP_F"]

# secondary processes
for step, flow_code in [("H2O", "H2O-L"), ("CO2", "CO2-G")]:
sec_process_data = input_data["secondary_process"].get(flow_code)
Expand All @@ -389,8 +394,6 @@ def _merge_data(input_data: CalculateDataType, opt_output_data: OptOutputDataTyp
logger.warning(f"Solver status:{opt_output_data['model_status'][0]}")
logger.warning(f"Model status:{opt_output_data['model_status'][1]}")

# TODO: Storage: "CAP_F"

def _get_hashsum(self, data, opt_input_data):
src_reg = data["context"]["source_region_code"]
# find res
Expand Down
51 changes: 48 additions & 3 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
import unittest
from pathlib import Path
from tempfile import TemporaryDirectory

import numpy as np
import pytest
Expand All @@ -26,10 +27,19 @@ class TestApi(unittest.TestCase):
@classmethod
def setUpClass(cls):
"""Set up code for class."""
cls.api = PtxboaAPI(data_dir=ptxdata_dir_static)
cls.temp_dir = TemporaryDirectory()
# create cahce dir (start context)
cache_dir = cls.temp_dir.__enter__()
cls.api = PtxboaAPI(data_dir=ptxdata_dir_static, cache_dir=cache_dir)

def _test_api_call(self, settings):
res, _metadata = self.api.calculate(**settings, optimize_flh=False)
@classmethod
def tearDownClass(cls):
"""Tear down code for class."""
# cleanup cache dir
cls.temp_dir.__exit__(None, None, None)

def _test_api_call(self, settings, optimize_flh=False):
res, _metadata = self.api.calculate(**settings, optimize_flh=optimize_flh)
# test that settings are in results
for k, v in settings.items():
if k in ["ship_own_fuel", "output_unit"]: # skip some
Expand Down Expand Up @@ -344,6 +354,41 @@ def test_pmt(self):
self.assertAlmostEqual(annuity(0.5, 10, 1), 0.5088237828522)
self.assertAlmostEqual(annuity(1, 10, 1), 1.0009775171)

def test_issue_553_storage_cost(self):
"""See https://github.com/agoenergy/ptx-boa/issues/553."""
settings = {
"region": "United Arab Emirates",
"country": "Germany",
"chain": "Ammonia (AEL) + reconv. to H2",
"res_gen": "PV tilted",
"scenario": "2040 (medium)",
"secproc_co2": "Direct Air Capture",
"secproc_water": "Sea Water desalination",
"transport": "Ship",
"ship_own_fuel": False,
"output_unit": "USD/t",
}
res = self._test_api_call(settings, optimize_flh=False)
res_opt = self._test_api_call(settings, optimize_flh=True)
self.assertAlmostEqual(
res.at[("Electricity and H2 storage", "CAPEX"), "values"],
896.432599,
places=4,
)
self.assertAlmostEqual(
res.at[("Electricity and H2 storage", "OPEX"), "values"], 4.396162, places=4
)
self.assertAlmostEqual(
res_opt.at[("Electricity and H2 storage", "CAPEX"), "values"],
221.907535,
places=4,
)
self.assertAlmostEqual(
res_opt.at[("Electricity and H2 storage", "OPEX"), "values"],
6.732894,
places=4,
)


class TestRegression(unittest.TestCase):
def test_issue_355_unique_index(self):
Expand Down
2 changes: 2 additions & 0 deletions tests/test_api_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ def test_get_calculation_data_w_opt(ptxdata_dir, scenario, kwargs, request):
"CONV": {},
"step": "EL_STR",
"process_code": "EL-STR",
"CAP_F": 0.0,
},
{
"EFF": 0.715,
Expand All @@ -414,6 +415,7 @@ def test_get_calculation_data_w_opt(ptxdata_dir, scenario, kwargs, request):
"CONV": {},
"step": "H2_STR",
"process_code": "H2-STR",
"CAP_F": 0.6816605398116187,
},
{
"EFF": 0.819,
Expand Down

0 comments on commit 824e4d9

Please sign in to comment.