Skip to content

Commit

Permalink
Drop wake loss multiplier support (it's now in SAM)
Browse files Browse the repository at this point in the history
  • Loading branch information
ppinchuk committed May 10, 2024
1 parent 3fbe971 commit 5010d40
Show file tree
Hide file tree
Showing 4 changed files with 9 additions and 129 deletions.
38 changes: 5 additions & 33 deletions reV/bespoke/bespoke.py
Expand Up @@ -197,7 +197,7 @@ def __init__(self, gid, excl, res, tm_dset, sam_sys_inputs,
objective_function, capital_cost_function,
fixed_operating_cost_function,
variable_operating_cost_function,
min_spacing='5x', wake_loss_multiplier=1, ga_kwargs=None,
min_spacing='5x', ga_kwargs=None,
output_request=('system_capacity', 'cf_mean'),
ws_bins=(0.0, 20.0, 5.0), wd_bins=(0.0, 360.0, 45.0),
excl_dict=None, inclusion_mask=None, data_layers=None,
Expand Down Expand Up @@ -255,13 +255,6 @@ def __init__(self, gid, excl, res, tm_dset, sam_sys_inputs,
Minimum spacing between turbines in meters. Can also be a string
like "5x" (default) which is interpreted as 5 times the turbine
rotor diameter.
wake_loss_multiplier : float, optional
A multiplier used to scale the annual energy lost due to
wake losses.
.. WARNING:: This multiplier will ONLY be applied during the
optimization process and will NOT be come through in output
values such as the hourly profiles,
aep, any of the cost functions, or even the output objective.
ga_kwargs : dict | None
Dictionary of keyword arguments to pass to GA initialization.
If `None`, default initialization values are used.
Expand Down Expand Up @@ -360,8 +353,6 @@ def __init__(self, gid, excl, res, tm_dset, sam_sys_inputs,
logger.debug('Bespoke objective function: {}'
.format(objective_function))
logger.debug('Bespoke cost function: {}'.format(objective_function))
logger.debug('Bespoke wake loss multiplier: {}'
.format(wake_loss_multiplier))
logger.debug('Bespoke GA initialization kwargs: {}'.format(ga_kwargs))
logger.debug('Bespoke EOS multiplier baseline capacity: {:,} MW'
.format(eos_mult_baseline_cap_mw))
Expand All @@ -385,7 +376,6 @@ def __init__(self, gid, excl, res, tm_dset, sam_sys_inputs,
self.variable_operating_cost_function = \
variable_operating_cost_function
self.min_spacing = min_spacing
self.wake_loss_multiplier = wake_loss_multiplier
self.ga_kwargs = ga_kwargs or {}

self._sam_sys_inputs = sam_sys_inputs
Expand Down Expand Up @@ -937,8 +927,7 @@ def plant_optimizer(self):
self.variable_operating_cost_function,
self.include_mask,
self.pixel_side_length,
self.min_spacing,
self.wake_loss_multiplier)
self.min_spacing)

return self._plant_optm

Expand Down Expand Up @@ -1270,8 +1259,8 @@ class BespokeWindPlants(BaseAggregation):
def __init__(self, excl_fpath, res_fpath, tm_dset, objective_function,
capital_cost_function, fixed_operating_cost_function,
variable_operating_cost_function, project_points,
sam_files, min_spacing='5x', wake_loss_multiplier=1,
ga_kwargs=None, output_request=('system_capacity', 'cf_mean'),
sam_files, min_spacing='5x', ga_kwargs=None,
output_request=('system_capacity', 'cf_mean'),
ws_bins=(0.0, 20.0, 5.0), wd_bins=(0.0, 360.0, 45.0),
excl_dict=None, area_filter_kernel='queen', min_area=None,
resolution=64, excl_area=None, data_layers=None,
Expand Down Expand Up @@ -1463,16 +1452,6 @@ def __init__(self, excl_fpath, res_fpath, tm_dset, objective_function,
Minimum spacing between turbines (in meters). This input can
also be a string like "5x", which is interpreted as 5 times
the turbine rotor diameter. By default, ``"5x"``.
wake_loss_multiplier : float, optional
A multiplier used to scale the annual energy lost due to
wake losses.
.. WARNING:: This multiplier will ONLY be applied during the
optimization process and will NOT come through in output
values such as the hourly profiles, aep, any of the cost
functions, or even the output objective.
By default, ``1``.
ga_kwargs : dict, optional
Dictionary of keyword arguments to pass to GA
initialization. If ``None``, default initialization values
Expand Down Expand Up @@ -1697,8 +1676,6 @@ def __init__(self, excl_fpath, res_fpath, tm_dset, objective_function,
.format(fixed_operating_cost_function))
logger.info('Bespoke variable operating cost function: {}'
.format(variable_operating_cost_function))
logger.info('Bespoke wake loss multiplier: {}'
.format(wake_loss_multiplier))
logger.info('Bespoke GA initialization kwargs: {}'.format(ga_kwargs))

logger.info('Bespoke pre-extracting exclusions: {}'
Expand All @@ -1725,7 +1702,6 @@ def __init__(self, excl_fpath, res_fpath, tm_dset, objective_function,
self._foc_fun = fixed_operating_cost_function
self._voc_fun = variable_operating_cost_function
self._min_spacing = min_spacing
self._wake_loss_multiplier = wake_loss_multiplier
self._ga_kwargs = ga_kwargs or {}
self._output_request = SAMOutputRequest(output_request)
self._ws_bins = ws_bins
Expand Down Expand Up @@ -2158,7 +2134,7 @@ def run_serial(cls, excl_fpath, res_fpath, tm_dset,
capital_cost_function,
fixed_operating_cost_function,
variable_operating_cost_function,
min_spacing='5x', wake_loss_multiplier=1, ga_kwargs=None,
min_spacing='5x', ga_kwargs=None,
output_request=('system_capacity', 'cf_mean'),
ws_bins=(0.0, 20.0, 5.0), wd_bins=(0.0, 360.0, 45.0),
excl_dict=None, inclusion_mask=None,
Expand Down Expand Up @@ -2219,7 +2195,6 @@ def run_serial(cls, excl_fpath, res_fpath, tm_dset,
fixed_operating_cost_function,
variable_operating_cost_function,
min_spacing=min_spacing,
wake_loss_multiplier=wake_loss_multiplier,
ga_kwargs=ga_kwargs,
output_request=output_request,
ws_bins=ws_bins,
Expand Down Expand Up @@ -2299,7 +2274,6 @@ def run_parallel(self, max_workers=None):
self._foc_fun,
self._voc_fun,
self._min_spacing,
wake_loss_multiplier=self._wake_loss_multiplier,
ga_kwargs=self._ga_kwargs,
output_request=self._output_request,
ws_bins=self._ws_bins,
Expand Down Expand Up @@ -2371,7 +2345,6 @@ def run(self, out_fpath=None, max_workers=None):
prior_meta = self._get_prior_meta(gid)
pre_loaded_data = self._pre_loaded_data_for_sc_gid(gid)
afk = self._area_filter_kernel
wlm = self._wake_loss_multiplier
i_bc = self._get_bc_for_gid(gid)

si = self.run_serial(self._excl_fpath,
Expand All @@ -2383,7 +2356,6 @@ def run(self, out_fpath=None, max_workers=None):
self._foc_fun,
self._voc_fun,
min_spacing=self._min_spacing,
wake_loss_multiplier=wlm,
ga_kwargs=self._ga_kwargs,
output_request=self._output_request,
ws_bins=self._ws_bins,
Expand Down
2 changes: 0 additions & 2 deletions reV/bespoke/cli_bespoke.py
Expand Up @@ -54,8 +54,6 @@ def _log_bespoke_cli_inputs(config):
.format(config.get("fixed_operating_cost_function")))
logger.info('Bespoke variable operating cost function: "{}"'
.format(config.get("variable_operating_cost_function")))
logger.info('Bespoke wake loss multiplier: "{}"'
.format(config.get("wake_loss_multiplier", 1)))
logger.info('The following project points were specified: "{}"'
.format(config.get('project_points', None)))
logger.info('The following SAM configs are available to this run:\n{}'
Expand Down
27 changes: 2 additions & 25 deletions reV/bespoke/place_turbines.py
Expand Up @@ -49,8 +49,7 @@ def __init__(self, wind_plant, objective_function,
capital_cost_function,
fixed_operating_cost_function,
variable_operating_cost_function,
include_mask, pixel_side_length, min_spacing,
wake_loss_multiplier=1):
include_mask, pixel_side_length, min_spacing):
"""
Parameters
----------
Expand Down Expand Up @@ -96,12 +95,6 @@ def __init__(self, wind_plant, objective_function,
exclusions.latitude, exclusions.longitude, and exclusions.mask
min_spacing : float
The minimum spacing between turbines (in meters).
wake_loss_multiplier : float, optional
A multiplier used to scale the annual energy lost due to
wake losses. **IMPORTANT**: This multiplier will ONLY be
applied during the optimization process and will NOT be
come through in output values such as aep, any of the cost
functions, or even the output objective.
"""

# inputs
Expand All @@ -116,7 +109,6 @@ def __init__(self, wind_plant, objective_function,
self.include_mask = include_mask
self.pixel_side_length = pixel_side_length
self.min_spacing = min_spacing
self.wake_loss_multiplier = wake_loss_multiplier

# internal variables
self.nrows, self.ncols = np.shape(include_mask)
Expand Down Expand Up @@ -226,7 +218,7 @@ def optimization_objective(self, x):

self.wind_plant.assign_inputs()
self.wind_plant.execute()
aep = self._aep_after_scaled_wake_losses()
aep = self.wind_plant['annual_energy']
else:
n_turbines = system_capacity = aep = 0

Expand All @@ -249,21 +241,6 @@ def optimization_objective(self, x):

return objective

def _aep_after_scaled_wake_losses(self):
"""AEP after scaling the energy lost due to wake."""
wake_loss_pct = self.wind_plant['wake_losses']
aep = self.wind_plant['annual_energy']
agep = self.wind_plant['annual_gross_energy']

energy_lost_due_to_wake = wake_loss_pct / 100 * agep
aep_after_wake_losses = agep - energy_lost_due_to_wake
other_losses_multiplier = 1 - aep / aep_after_wake_losses

scaled_wake_losses = (self.wake_loss_multiplier
* energy_lost_due_to_wake)
aep_after_scaled_wake_losses = max(0, agep - scaled_wake_losses)
return aep_after_scaled_wake_losses * (1 - other_losses_multiplier)

def optimize(self, **kwargs):
"""Optimize wind farm layout.
Expand Down
71 changes: 2 additions & 69 deletions tests/test_bespoke.py
Expand Up @@ -676,72 +676,6 @@ def test_bespoke_supply_curve():
assert np.allclose(sc_baseline['total_lcoe'], sc_full['total_lcoe'])


@pytest.mark.parametrize('wlm', [2, 100])
def test_wake_loss_multiplier(wlm):
"""Test wake loss multiplier. """
output_request = ('system_capacity', 'cf_mean', 'cf_profile')
with tempfile.TemporaryDirectory() as td:
res_fp = os.path.join(td, 'ri_100_wtk_{}.h5')
excl_fp = os.path.join(td, 'ri_exclusions.h5')
shutil.copy(EXCL, excl_fp)
shutil.copy(RES.format(2012), res_fp.format(2012))
shutil.copy(RES.format(2013), res_fp.format(2013))
res_fp = res_fp.format('*')

TechMapping.run(excl_fp, RES.format(2012), dset=TM_DSET, max_workers=1)
bsp = BespokeSinglePlant(33, excl_fp, res_fp, TM_DSET,
SAM_SYS_INPUTS,
OBJECTIVE_FUNCTION,
CAP_COST_FUN,
FOC_FUN,
VOC_FUN,
excl_dict=EXCL_DICT,
output_request=output_request,
)

optimizer = bsp.plant_optimizer
optimizer.define_exclusions()
optimizer.initialize_packing()

optimizer.wind_plant["wind_farm_xCoordinates"] = optimizer.x_locations
optimizer.wind_plant["wind_farm_yCoordinates"] = optimizer.y_locations

system_capacity = (len(optimizer.x_locations)
* optimizer.turbine_capacity)
optimizer.wind_plant["system_capacity"] = system_capacity

optimizer.wind_plant.assign_inputs()
optimizer.wind_plant.execute()
aep = optimizer._aep_after_scaled_wake_losses()
bsp.close()

bsp = BespokeSinglePlant(33, excl_fp, res_fp, TM_DSET,
SAM_SYS_INPUTS,
OBJECTIVE_FUNCTION,
CAP_COST_FUN,
FOC_FUN,
VOC_FUN,
excl_dict=EXCL_DICT,
output_request=output_request,
wake_loss_multiplier=wlm)

optimizer2 = bsp.plant_optimizer
optimizer2.wind_plant["wind_farm_xCoordinates"] = optimizer.x_locations
optimizer2.wind_plant["wind_farm_yCoordinates"] = optimizer.y_locations

system_capacity = (len(optimizer.x_locations)
* optimizer.turbine_capacity)
optimizer2.wind_plant["system_capacity"] = system_capacity

optimizer2.wind_plant.assign_inputs()
optimizer2.wind_plant.execute()
aep_wlm = optimizer2._aep_after_scaled_wake_losses()
bsp.close()

assert aep > aep_wlm
assert aep_wlm >= 0


def test_bespoke_wind_plant_with_power_curve_losses():
"""Test bespoke ``wind_plant`` with power curve losses. """
output_request = ('system_capacity', 'cf_mean', 'cf_profile')
Expand Down Expand Up @@ -772,7 +706,7 @@ def test_bespoke_wind_plant_with_power_curve_losses():

optimizer.wind_plant.assign_inputs()
optimizer.wind_plant.execute()
aep = optimizer._aep_after_scaled_wake_losses()
aep = optimizer.wind_plant["annual_energy"]
bsp.close()

sam_inputs = copy.deepcopy(SAM_SYS_INPUTS)
Expand All @@ -797,7 +731,7 @@ def test_bespoke_wind_plant_with_power_curve_losses():

optimizer2.wind_plant.assign_inputs()
optimizer2.wind_plant.execute()
aep_losses = optimizer2._aep_after_scaled_wake_losses()
aep_losses = optimizer2.wind_plant["annual_energy"]
bsp.close()

assert aep > aep_losses, f"{aep}, {aep_losses}"
Expand Down Expand Up @@ -1223,7 +1157,6 @@ def test_cli(runner, clear_loggers):
"project_points": [33, 35],
"sam_files": SAM_CONFIGS,
"min_spacing": '5x',
"wake_loss_multiplier": 1,
"ga_kwargs": {'max_time': 5},
"output_request": output_request,
"ws_bins": (0, 20, 5),
Expand Down

0 comments on commit 5010d40

Please sign in to comment.