Skip to content

Commit

Permalink
Updated cost outputs
Browse files Browse the repository at this point in the history
  • Loading branch information
ppinchuk committed Jun 12, 2024
1 parent f319e97 commit c43b8d8
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 90 deletions.
83 changes: 9 additions & 74 deletions reV/supply_curve/points.py
Original file line number Diff line number Diff line change
Expand Up @@ -2074,61 +2074,6 @@ def capacity_dc(self):

return self.area * self.power_density

@property
def sc_point_capital_cost(self):
"""Get the capital cost for the entire SC point.
This method scales the capital cost based on the included-area
capacity. The calculation requires 'capital_cost' and
'system_capacity' in the generation file and passed through as
`h5_dsets`, otherwise it returns `None`.
Returns
-------
sc_point_capital_cost : float | None
Total supply curve point capital cost ($).
"""
if self.mean_h5_dsets_data is None:
return None

required = ("capital_cost", "system_capacity")
if not all(k in self.mean_h5_dsets_data for k in required):
return None

cap_cost_per_mw = (
self.mean_h5_dsets_data["capital_cost"]
/ self.mean_h5_dsets_data["system_capacity"]
)
return cap_cost_per_mw * self.capacity

@property
def sc_point_fixed_operating_cost(self):
"""Get the fixed operating cost for the entire SC point.
This method scales the fixed operating cost based on the
included-area capacity. The calculation requires
'fixed_operating_cost' and 'system_capacity' in the generation
file and passed through as `h5_dsets`, otherwise it returns
`None`.
Returns
-------
sc_point_fixed_operating_cost : float | None
Total supply curve point fixed operating cost ($).
"""
if self.mean_h5_dsets_data is None:
return None

required = ("fixed_operating_cost", "system_capacity")
if not all(k in self.mean_h5_dsets_data for k in required):
return None

fixed_cost_per_mw = (
self.mean_h5_dsets_data["fixed_operating_cost"]
/ self.mean_h5_dsets_data["system_capacity"]
)
return fixed_cost_per_mw * self.capacity

@property
def sc_point_annual_energy(self):
"""Get the total annual energy (MWh) for the entire SC point.
Expand Down Expand Up @@ -2190,6 +2135,14 @@ def regional_multiplier(self):
multipliers = self.gen["capital_cost_multiplier"]
return self.exclusion_weighted_mean(multipliers)

@property
def fixed_charge_rate(self):
"""float: Mean fixed_charge_rate, defaults to 0."""
if "fixed_charge_rate" not in self.gen.datasets:
return 0

return self.exclusion_weighted_mean(self.gen["fixed_charge_rate"])

@property
def _sam_system_capacity(self):
"""float: Mean SAM generation system capacity input, defaults to 0. """
Expand Down Expand Up @@ -2375,18 +2328,9 @@ def point_summary(self, args=None):
),
SupplyCurveField.COST_BASE_VOC_USD_PER_AC_MW: (
self._compute_cost_per_ac_mw("base_variable_operating_cost")
)
}

extra_atts = {
SupplyCurveField.SC_POINT_CAPITAL_COST: self.sc_point_capital_cost,
SupplyCurveField.SC_POINT_FIXED_OPERATING_COST: (
self.sc_point_fixed_operating_cost
),
SupplyCurveField.FIXED_CHARGE_RATE: self.fixed_charge_rate,
}
for attr, value in extra_atts.items():
if value is not None:
ARGS[attr] = value

if self._friction_layer is not None:
ARGS[SupplyCurveField.MEAN_FRICTION] = self.mean_friction
Expand Down Expand Up @@ -2441,15 +2385,6 @@ def economies_of_scale(cap_cost_scale, summary):
summary[SupplyCurveField.COST_SITE_OCC_USD_PER_AC_MW]
* summary[SupplyCurveField.EOS_MULT]
)
if SupplyCurveField.SC_POINT_CAPITAL_COST in summary:
scaled_costs = (
summary[SupplyCurveField.SC_POINT_CAPITAL_COST]
* eos.capital_cost_scalar
)
summary[SupplyCurveField.SCALED_SC_POINT_CAPITAL_COST] = (
scaled_costs
)

return summary

@classmethod
Expand Down
6 changes: 1 addition & 5 deletions reV/utilities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,13 @@ class SupplyCurveField(FieldEnum):
CONVEX_HULL_AREA = "convex_hull_area"
CONVEX_HULL_CAPACITY_DENSITY = "convex_hull_capacity_density"
FULL_CELL_CAPACITY_DENSITY = "full_cell_capacity_density"

COST_BASE_OCC_USD_PER_AC_MW = "cost_base_occ_usd_per_ac_mw"
COST_SITE_OCC_USD_PER_AC_MW = "cost_site_occ_usd_per_ac_mw"
COST_BASE_FOC_USD_PER_AC_MW = "cost_base_foc_usd_per_ac_mw"
COST_SITE_FOC_USD_PER_AC_MW = "cost_site_foc_usd_per_ac_mw"
COST_BASE_VOC_USD_PER_AC_MW = "cost_base_voc_usd_per_ac_mw"
COST_SITE_VOC_USD_PER_AC_MW = "cost_site_voc_usd_per_ac_mw"

SC_POINT_CAPITAL_COST = "sc_point_capital_cost"
SC_POINT_FIXED_OPERATING_COST = "sc_point_fixed_operating_cost"
SCALED_SC_POINT_CAPITAL_COST = "scaled_sc_point_capital_cost"
FIXED_CHARGE_RATE = "fixed_charge_rate"

@classmethod
def map_from_legacy(cls):
Expand Down
48 changes: 37 additions & 11 deletions tests/test_supply_curve_sc_aggregation.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,19 @@ def test_recalc_lcoe(cap_cost_scale):
for k, v in data.items():
arr = np.full(res["meta"].shape, v)
res.create_dataset(k, res["meta"].shape, data=arr)

arr = np.full(res["meta"].shape, data["capital_cost"])
res.create_dataset("base_capital_cost", res["meta"].shape,
data=arr)

arr = np.full(res["meta"].shape, data["fixed_operating_cost"])
res.create_dataset("base_fixed_operating_cost", res["meta"].shape,
data=arr)

arr = np.full(res["meta"].shape, data["variable_operating_cost"])
res.create_dataset("base_variable_operating_cost",
res["meta"].shape, data=arr)

for year, cf in zip(years, annual_cf):
lcoe = lcoe_fcr(data["fixed_charge_rate"],
data["capital_cost"],
Expand Down Expand Up @@ -565,18 +578,31 @@ def test_recalc_lcoe(cap_cost_scale):
summary[SupplyCurveField.MEAN_LCOE])

assert np.allclose(summary[SupplyCurveField.EOS_MULT],
summary[SupplyCurveField.SCALED_SC_POINT_CAPITAL_COST]
/ summary[SupplyCurveField.SC_POINT_CAPITAL_COST])
summary[SupplyCurveField.COST_SITE_OCC_USD_PER_AC_MW]
/ summary[SupplyCurveField.COST_BASE_OCC_USD_PER_AC_MW])

fcr = summary[SupplyCurveField.FIXED_CHARGE_RATE]
cap_cost = (summary[SupplyCurveField.COST_SITE_OCC_USD_PER_AC_MW]
* summary[SupplyCurveField.CAPACITY_AC_MW])
foc = (summary[SupplyCurveField.COST_SITE_FOC_USD_PER_AC_MW]
* summary[SupplyCurveField.CAPACITY_AC_MW])
voc = (summary[SupplyCurveField.COST_SITE_VOC_USD_PER_AC_MW]
* summary[SupplyCurveField.CAPACITY_AC_MW])
aep = summary[SupplyCurveField.SC_POINT_ANNUAL_ENERGY_MW]

lcoe = lcoe_fcr(fcr, cap_cost, foc, aep, voc)
assert np.allclose(lcoe, summary[SupplyCurveField.MEAN_LCOE])

if cap_cost_scale == '1':
cc_dset = SupplyCurveField.SC_POINT_CAPITAL_COST
else:
cc_dset = SupplyCurveField.SCALED_SC_POINT_CAPITAL_COST
lcoe = lcoe_fcr(summary['mean_fixed_charge_rate'],
summary[cc_dset],
summary[SupplyCurveField.SC_POINT_FIXED_OPERATING_COST],
summary[SupplyCurveField.SC_POINT_ANNUAL_ENERGY_MW],
summary['mean_variable_operating_cost'])
cap_cost = (summary[SupplyCurveField.COST_BASE_OCC_USD_PER_AC_MW]
* summary[SupplyCurveField.CAPACITY_AC_MW]
* summary[SupplyCurveField.REG_MULT]
* summary[SupplyCurveField.EOS_MULT])
foc = (summary[SupplyCurveField.COST_BASE_FOC_USD_PER_AC_MW]
* summary[SupplyCurveField.CAPACITY_AC_MW])
voc = (summary[SupplyCurveField.COST_BASE_VOC_USD_PER_AC_MW]
* summary[SupplyCurveField.CAPACITY_AC_MW])

lcoe = lcoe_fcr(fcr, cap_cost, foc, aep, voc)
assert np.allclose(lcoe, summary[SupplyCurveField.MEAN_LCOE])


Expand Down

0 comments on commit c43b8d8

Please sign in to comment.