Skip to content

fix run_model_from_effective_irradiance with iterable weather and excluding cell temperature #1165

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Feb 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 7 additions & 20 deletions pvlib/modelchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -1572,11 +1572,13 @@ def _prepare_temperature(self, data=None):
"""
poa = _irrad_for_celltemp(self.results.total_irrad,
self.results.effective_irradiance)
if not isinstance(data, tuple) and self.system.num_arrays > 1:
# handle simple case first, single array, data not iterable
if not isinstance(data, tuple) and self.system.num_arrays == 1:
return self._prepare_temperature_single_array(data, poa)
if not isinstance(data, tuple):
# broadcast data to all arrays
data = (data,) * self.system.num_arrays
elif not isinstance(data, tuple):
return self._prepare_temperature_single_array(data, poa)
# find where cell or module temperature is specified in input data
given_cell_temperature = tuple(itertools.starmap(
self._get_cell_temperature,
zip(data, poa, self.system.temperature_model_parameters)
Expand All @@ -1587,23 +1589,7 @@ def _prepare_temperature(self, data=None):
self.results.cell_temperature = given_cell_temperature
return self
# Calculate cell temperature from weather data. If cell_temperature
# has not been provided for some arrays then it is computed with
# ModelChain.temperature_model(). Because this operates on all Arrays
# simultaneously, 'poa_global' must be known for all arrays, including
# those that have a known cell temperature.
try:
self._verify_df(self.results.total_irrad, ['poa_global'])
except ValueError:
# Provide a more informative error message. Because only
# run_model_from_effective_irradiance() can get to this point
# without known POA we can suggest a very specific remedy in the
# error message.
raise ValueError("Incomplete input data. Data must contain "
"'poa_global'. For systems with multiple Arrays "
"if you have provided 'cell_temperature' for "
"only a subset of Arrays you must provide "
"'poa_global' for all Arrays, including those "
"that have a known 'cell_temperature'.")
# has not been provided for some arrays then it is computed.
self.temperature_model()
# replace calculated cell temperature with temperature given in `data`
# where available.
Expand Down Expand Up @@ -1814,6 +1800,7 @@ def run_model_from_effective_irradiance(self, data=None):
"""
data = _to_tuple(data)
self._check_multiple_input(data)
self._verify_df(data, required=['effective_irradiance'])
self._assign_weather(data)
self._assign_total_irrad(data)
self.results.effective_irradiance = _tuple_from_dfs(
Expand Down
43 changes: 22 additions & 21 deletions pvlib/tests/test_modelchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -985,26 +985,44 @@ def test_run_model_from_poa_tracking(sapm_dc_snl_ac_system, location,
assert_series_equal(ac, expected)


@pytest.mark.parametrize("input_type", [lambda x: x[0], tuple, list])
def test_run_model_from_effective_irradiance(sapm_dc_snl_ac_system, location,
weather, total_irrad):
weather, total_irrad, input_type):
data = weather.copy()
data[['poa_global', 'poa_diffuse', 'poa_direct']] = total_irrad
data['effective_irradiance'] = data['poa_global']
mc = ModelChain(sapm_dc_snl_ac_system, location, aoi_model='no_loss',
spectral_model='no_loss')
ac = mc.run_model_from_effective_irradiance(data).results.ac
ac = mc.run_model_from_effective_irradiance(input_type((data,))).results.ac
expected = pd.Series(np.array([149.280238, 96.678385]),
index=data.index)
assert_series_equal(ac, expected)


@pytest.mark.parametrize("input_type", [tuple, list])
def test_run_model_from_effective_irradiance_multi_array(
sapm_dc_snl_ac_system_Array, location, weather, total_irrad,
input_type):
data = weather.copy()
data[['poa_global', 'poa_diffuse', 'poa_direct']] = total_irrad
data['effective_irradiance'] = data['poa_global']
mc = ModelChain(sapm_dc_snl_ac_system_Array, location, aoi_model='no_loss',
spectral_model='no_loss')
mc.run_model_from_effective_irradiance(input_type((data, data)))
# arrays have different orientation, but should give same dc power
# because we are the same passing POA irradiance and air
# temperature.
assert_frame_equal(mc.results.dc[0], mc.results.dc[1])


@pytest.mark.parametrize("input_type", [lambda x: x[0], tuple, list])
def test_run_model_from_effective_irradiance_no_poa_global(
sapm_dc_snl_ac_system, location, weather, total_irrad):
sapm_dc_snl_ac_system, location, weather, total_irrad, input_type):
data = weather.copy()
data['effective_irradiance'] = total_irrad['poa_global']
mc = ModelChain(sapm_dc_snl_ac_system, location, aoi_model='no_loss',
spectral_model='no_loss')
ac = mc.run_model_from_effective_irradiance(data).results.ac
ac = mc.run_model_from_effective_irradiance(input_type((data,))).results.ac
expected = pd.Series(np.array([149.280238, 96.678385]),
index=data.index)
assert_series_equal(ac, expected)
Expand Down Expand Up @@ -1087,23 +1105,6 @@ def test_run_model_from_effective_irradiance_minimal_input(
assert not mc.results.ac.empty


def test_run_model_from_effective_irradiance_missing_poa(
sapm_dc_snl_ac_system_Array, location, total_irrad):
data_incomplete = pd.DataFrame(
{'effective_irradiance': total_irrad['poa_global'],
'poa_global': total_irrad['poa_global']},
index=total_irrad.index)
data_complete = pd.DataFrame(
{'effective_irradiance': total_irrad['poa_global'],
'cell_temperature': 30},
index=total_irrad.index)
mc = ModelChain(sapm_dc_snl_ac_system_Array, location)
with pytest.raises(ValueError,
match="you must provide 'poa_global' for all Arrays"):
mc.run_model_from_effective_irradiance(
(data_complete, data_incomplete))


def test_run_model_singleton_weather_single_array(cec_dc_snl_ac_system,
location, weather):
mc = ModelChain(cec_dc_snl_ac_system, location,
Expand Down