Skip to content

Commit

Permalink
Merge pull request #442 from NREL/gb/bespoke_bugs
Browse files Browse the repository at this point in the history
Gb/bespoke bugs
  • Loading branch information
grantbuster authored Feb 14, 2024
2 parents d351a84 + 97d28e1 commit be4151e
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 28 deletions.
45 changes: 30 additions & 15 deletions reV/bespoke/bespoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"""
reV bespoke wind plant analysis tools
"""
# pylint: disable=anomalous-backslash-in-string
from inspect import signature
import time
import logging
Expand Down Expand Up @@ -803,6 +804,11 @@ def res_df(self):
'pressure': pres,
'windspeed': ws,
'winddirection': wd}, index=ti)

if 'time_index_step' in self.original_sam_sys_inputs:
ti_step = self.original_sam_sys_inputs['time_index_step']
self._res_df = self._res_df.iloc[::ti_step]

return self._res_df

@property
Expand Down Expand Up @@ -969,27 +975,36 @@ def get_lcoe_kwargs(self):
updated based on the bespoke optimized system_capacity, includes
fixed_charge_rate, system_capacity (kW), capital_cost ($),
fixed_operating_cos ($), variable_operating_cost ($/kWh)
Data source priority: outputs, plant_optimizer,
original_sam_sys_inputs, meta
"""

if 'system_capacity' not in self.outputs:
msg = ('Could not find system_capacity in the outputs, need to '
'run_plant_optimization() to get the optimized '
'system_capacity before calculating LCOE!')
logger.error(msg)
raise RuntimeError(msg)

lcoe_kwargs = {
'fixed_charge_rate':
self.original_sam_sys_inputs['fixed_charge_rate'],
'system_capacity': self.plant_optimizer.capacity,
'capital_cost': self.plant_optimizer.capital_cost,
'fixed_operating_cost': self.plant_optimizer.fixed_operating_cost,
'variable_operating_cost':
self.plant_optimizer.variable_operating_cost}
kwargs_list = ['fixed_charge_rate', 'system_capacity', 'capital_cost',
'fixed_operating_cost', 'variable_operating_cost']
lcoe_kwargs = {}

for kwarg in kwargs_list:
if kwarg in self.outputs:
lcoe_kwargs[kwarg] = self.outputs[kwarg]
elif getattr(self.plant_optimizer, kwarg, None) is not None:
lcoe_kwargs[kwarg] = getattr(self.plant_optimizer, kwarg)
elif kwarg in self.original_sam_sys_inputs:
lcoe_kwargs[kwarg] = self.original_sam_sys_inputs[kwarg]
elif kwarg in self.meta:
value = float(self.meta[kwarg].values[0])
lcoe_kwargs[kwarg] = value

for k, v in lcoe_kwargs.items():
self._meta[k] = v

missing = [k for k in kwargs_list if k not in lcoe_kwargs]
if any(missing):
msg = ('Could not find these LCOE kwargs in outputs, '
'plant_optimizer, original_sam_sys_inputs, or meta: {}'
.format(missing))
logger.error(msg)
raise KeyError(msg)

return lcoe_kwargs

@staticmethod
Expand Down
49 changes: 46 additions & 3 deletions tests/test_bespoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -918,8 +918,11 @@ def test_bespoke_prior_run():
Also added another minor test with extrapolation of t/p datasets from a
single vertical level (e.g., with Sup3rCC data)
"""
sam_sys_inputs = copy.deepcopy(SAM_SYS_INPUTS)
sam_sys_inputs['fixed_charge_rate'] = 0.096
sam_configs = {'default': sam_sys_inputs}
output_request = ('system_capacity', 'cf_mean', 'cf_profile',
'extra_unused_data')
'extra_unused_data', 'lcoe_fcr')
with tempfile.TemporaryDirectory() as td:
out_fpath1 = os.path.join(td, 'bespoke_out2.h5')
out_fpath2 = os.path.join(td, 'bespoke_out1.h5')
Expand Down Expand Up @@ -950,7 +953,7 @@ def test_bespoke_prior_run():

bsp = BespokeWindPlants(excl_fp, res_fp_all, TM_DSET,
OBJECTIVE_FUNCTION, CAP_COST_FUN,
FOC_FUN, VOC_FUN, points, SAM_CONFIGS,
FOC_FUN, VOC_FUN, points, sam_configs,
ga_kwargs={'max_time': 1}, excl_dict=EXCL_DICT,
output_request=output_request)
bsp.run(max_workers=1, out_fpath=out_fpath1)
Expand All @@ -960,7 +963,7 @@ def test_bespoke_prior_run():

bsp = BespokeWindPlants(excl_fp, res_fp_2013, TM_DSET,
OBJECTIVE_FUNCTION, CAP_COST_FUN,
FOC_FUN, VOC_FUN, points, SAM_CONFIGS,
FOC_FUN, VOC_FUN, points, sam_configs,
ga_kwargs={'max_time': 1}, excl_dict=EXCL_DICT,
output_request=output_request,
prior_run=out_fpath1)
Expand Down Expand Up @@ -1236,3 +1239,43 @@ def test_cli(runner, clear_loggers):
assert f[dset].any() # not all zeros

clear_loggers()


def test_bespoke_5min_sample():
"""Sample a 5min resource dataset for 60min outputs in bespoke"""
output_request = ('system_capacity', 'cf_mean', 'cf_profile',
'extra_unused_data', 'winddirection', 'windspeed',
'ws_mean')
tm_dset = 'test_wtk_5min'

with tempfile.TemporaryDirectory() as td:
out_fpath = os.path.join(td, 'wind_bespoke.h5')
excl_fp = os.path.join(td, 'ri_exclusions.h5')
shutil.copy(EXCL, excl_fp)
res_fp = os.path.join(TESTDATADIR, 'wtk/wtk_2010_*m.h5')

points = pd.DataFrame({'gid': [33, 35], 'config': ['default'] * 2,
'extra_unused_data': [0, 42]})
sam_sys_inputs = copy.deepcopy(SAM_SYS_INPUTS)
sam_sys_inputs['time_index_step'] = 12
sam_configs = {'default': sam_sys_inputs}

# hack techmap because 5min data only has 10 wind resource pixels
with h5py.File(excl_fp, 'a') as excl_file:
arr = np.random.choice(10, size=excl_file['latitude'].shape)
excl_file.create_dataset(name=tm_dset, data=arr)

bsp = BespokeWindPlants(excl_fp, res_fp, tm_dset, OBJECTIVE_FUNCTION,
CAP_COST_FUN, FOC_FUN, VOC_FUN, points,
sam_configs, ga_kwargs={'max_time': 5},
excl_dict=EXCL_DICT,
output_request=output_request)
_ = bsp.run(max_workers=1, out_fpath=out_fpath)

with Resource(out_fpath) as f:
assert len(f.meta) == 2
assert len(f) == 8760
assert len(f['cf_profile-2010']) == 8760
assert len(f['time_index-2010']) == 8760
assert len(f['windspeed-2010']) == 8760
assert len(f['winddirection-2010']) == 8760
8 changes: 4 additions & 4 deletions tests/test_hybrids.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,13 +343,13 @@ def some_new_hybrid_func(__):
return [0]
HYBRID_METHODS['scaled_elevation'] = some_new_hybrid_func

with pytest.warns(OutputWarning) as record:
with pytest.warns(OutputWarning) as records:
h = Hybridization(SOLAR_FPATH, WIND_FPATH)
h.run()

warn_msg = record[0].message.args[0]
assert "Unable to add" in warn_msg
assert "column to hybrid meta" in warn_msg
messages = [r.message.args[0] for r in records]
assert any("Unable to add" in msg for msg in messages)
assert any("column to hybrid meta" in msg for msg in messages)

HYBRID_METHODS.pop('scaled_elevation')

Expand Down
12 changes: 6 additions & 6 deletions tests/test_sam.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,16 @@ def test_time_interval(dt):


def test_pysam_version_checker_pv():
"""Test that the pysam version checker passes through PV config untouched.
"""Test that the pysam version checker passes through PV config untouched
without warning.
"""
pv_config = {'gcr': 0.4, 'system_capacity': 1}

with pytest.warns(None) as record:
with warnings.catch_warnings():
warnings.simplefilter("error")
sam_sys_inputs = PySamVersionChecker.run('pvwattsv5', pv_config)

assert not any(record)
assert 'gcr' in sam_sys_inputs
assert 'system_capacity' in sam_sys_inputs
assert 'gcr' in sam_sys_inputs
assert 'system_capacity' in sam_sys_inputs


def test_pysam_version_checker_wind():
Expand Down

0 comments on commit be4151e

Please sign in to comment.