Skip to content

Commit

Permalink
Merge pull request #454 from NREL/pp/tline_updates
Browse files Browse the repository at this point in the history
New LCP cost integration
  • Loading branch information
ppinchuk authored May 31, 2024
2 parents 43e22ac + 2b8c2a1 commit 0417633
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 11 deletions.
36 changes: 25 additions & 11 deletions reV/supply_curve/supply_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -919,7 +919,9 @@ def compute_total_lcoe(
Flag to consider friction layer on LCOE when "mean_lcoe_friction"
is in the sc points input, by default True
"""
if "trans_cap_cost" not in self._trans_table:
if "trans_cap_cost_per_mw" in self._trans_table:
cost = self._trans_table["trans_cap_cost_per_mw"].values.copy()
elif "trans_cap_cost" not in self._trans_table:
scc = self._sc_capacity_col
cost = self._compute_trans_cap_cost(
self._trans_table,
Expand All @@ -939,30 +941,42 @@ def compute_total_lcoe(
cost *= self._trans_table[self._sc_capacity_col]
# align with "mean_cf"
cost /= self._trans_table[SupplyCurveField.CAPACITY]
cf_mean_arr = self._trans_table[SupplyCurveField.MEAN_CF].values
resource_lcoe = self._trans_table[SupplyCurveField.MEAN_LCOE]

if 'reinforcement_cost_floored_per_mw' in self._trans_table:
logger.info("'reinforcement_cost_floored_per_mw' column found in "
"transmission table. Adding floored reinforcement "
"cost LCOE as sorting option.")
fr_cost = (self._trans_table['reinforcement_cost_floored_per_mw']
.values.copy())
fr_cost *= self._trans_table[self._sc_capacity_col]
# align with "mean_cf"
fr_cost /= self._trans_table[SupplyCurveField.CAPACITY]

lcot_fr = ((cost + fr_cost) * fcr) / (cf_mean_arr * 8760)
lcoe_fr = lcot_fr + resource_lcoe
self._trans_table['lcot_floored_reinforcement'] = lcot_fr
self._trans_table['lcoe_floored_reinforcement'] = lcoe_fr

if 'reinforcement_cost_per_mw' in self._trans_table:
logger.info("'reinforcement_cost_per_mw' column found in "
"transmission table. Adding reinforcement costs "
"to total LCOE.")
cf_mean_arr = self._trans_table[SupplyCurveField.MEAN_CF].values
lcot = (cost * fcr) / (cf_mean_arr * 8760)
lcoe = lcot + self._trans_table[SupplyCurveField.MEAN_LCOE]
self._trans_table['lcot_no_reinforcement'] = lcot
self._trans_table['lcoe_no_reinforcement'] = lcoe
lcot_nr = (cost * fcr) / (cf_mean_arr * 8760)
lcoe_nr = lcot_nr + resource_lcoe
self._trans_table['lcot_no_reinforcement'] = lcot_nr
self._trans_table['lcoe_no_reinforcement'] = lcoe_nr
r_cost = (self._trans_table['reinforcement_cost_per_mw']
.values.copy())
r_cost *= self._trans_table[self._sc_capacity_col]
# align with "mean_cf"
r_cost /= self._trans_table[SupplyCurveField.CAPACITY]
cost += r_cost # $/MW

cf_mean_arr = self._trans_table[SupplyCurveField.MEAN_CF].values
lcot = (cost * fcr) / (cf_mean_arr * 8760)

self._trans_table['lcot'] = lcot
self._trans_table['total_lcoe'] = (
self._trans_table['lcot']
+ self._trans_table[SupplyCurveField.MEAN_LCOE])
self._trans_table['total_lcoe'] = lcot + resource_lcoe

if consider_friction:
self._calculate_total_lcoe_friction()
Expand Down
95 changes: 95 additions & 0 deletions tests/test_supply_curve_compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,101 @@ def test_least_cost_simple_with_reinforcement():
sc_simple_r.total_lcoe)


# pylint: disable=no-member
@pytest.mark.parametrize("r_costs", [True, False])
def test_least_cost_simple_with_trans_cap_cost_per_mw(r_costs):
"""
Test simple supply curve with only "trans_cap_cost_per_mw" entry
"""

with tempfile.TemporaryDirectory() as td:
trans_tables = []
for cap in [100, 200, 400, 1000]:
in_table = os.path.join(
TESTDATADIR, "trans_tables", f"costs_RI_{cap}MW.csv"
)
in_table = pd.read_csv(in_table)
out_fp = os.path.join(td, f"costs_RI_{cap}MW.csv")
t_gids = in_table["trans_gid"].values
if r_costs:
sort_on = "lcoe_no_reinforcement"
in_table["reinforcement_cost_per_mw"] = t_gids[::-1]
else:
sort_on = "total_lcoe"
in_table["reinforcement_cost_per_mw"] = 0
in_table["reinforcement_dist_km"] = 0
in_table["trans_cap_cost_per_mw"] = t_gids
in_table = in_table.drop(columns=["trans_cap_cost", "max_cap"])
in_table.to_csv(out_fp, index=False)
trans_tables.append(out_fp)

out_fpath = os.path.join(td, "sc")
sc = SupplyCurve(SC_POINTS, trans_tables)
sc_simple = sc.run(out_fpath, fixed_charge_rate=0.1,
simple=True, sort_on=sort_on)
sc_simple = pd.read_csv(sc_simple)
assert (sc_simple["trans_gid"] == 42445).all()

if not r_costs:
lcot = 4244.5 / (sc_simple[SupplyCurveField.MEAN_CF] * 8760)
assert np.allclose(lcot, sc_simple["lcot"], atol=0.001)


# pylint: disable=no-member
def test_least_cost_simple_with_reinforcement_floor():
"""
Test simple supply curve sorting with reinforcement costs in the
least-cost path transmission tables
"""

with tempfile.TemporaryDirectory() as td:
trans_tables = []
for cap in [100, 200, 400, 1000]:
in_table = os.path.join(
TESTDATADIR, "trans_tables", f"costs_RI_{cap}MW.csv"
)
in_table = pd.read_csv(in_table)
out_fp = os.path.join(td, f"costs_RI_{cap}MW.csv")
in_table["reinforcement_cost_per_mw"] = 0
in_table["reinforcement_dist_km"] = 0
in_table["reinforcement_cost_floored_per_mw"] = 0
in_table.to_csv(out_fp, index=False)
trans_tables.append(out_fp)

out_fpath = os.path.join(td, "sc")
sc = SupplyCurve(SC_POINTS, trans_tables)
sc_simple = sc.run(out_fpath, fixed_charge_rate=0.1,
simple=True)
sc_simple = pd.read_csv(sc_simple)

fpath_baseline = os.path.join(TESTDATADIR,
'sc_out/sc_simple_lc.csv')
baseline_verify(sc_simple, fpath_baseline)
verify_trans_cap(sc_simple, trans_tables)

trans_tables = []
for cap in [100, 200, 400, 1000]:
in_table = os.path.join(
TESTDATADIR, "trans_tables", f"costs_RI_{cap}MW.csv"
)
in_table = pd.read_csv(in_table)
out_fp = os.path.join(td, f"costs_RI_{cap}MW.csv")
in_table["reinforcement_cost_per_mw"] = 0
in_table["reinforcement_dist_km"] = 0
in_table["reinforcement_cost_floored_per_mw"] = 2000
in_table.to_csv(out_fp, index=False)
trans_tables.append(out_fp)

out_fpath = os.path.join(td, "sc_r")
sc = SupplyCurve(SC_POINTS, trans_tables)
sc_simple_r = sc.run(out_fpath, fixed_charge_rate=0.1, simple=True,
sort_on="lcot_floored_reinforcement")
sc_simple_r = pd.read_csv(sc_simple_r)

baseline_verify(sc_simple, fpath_baseline)
verify_trans_cap(sc_simple, trans_tables)


def test_least_cost_full_pass_through():
"""
Test the full supply curve sorting passes through variables correctly
Expand Down

0 comments on commit 0417633

Please sign in to comment.