Skip to content

Commit b666520

Browse files
authored
fix run_model_from_effective_irradiance with iterable weather and excluding cell temperature (#1165)
* check for complete poa in _set_celltemp * test for new location of ValueError, add test for run_from_eff_irrad with iterable of length 1 * handle single data/arrays, fix test * remove old test * add _verify_df to run_from_effective_irradiance * remove ValueError from _set_celltemp * test for single, list tuple * edits from review
1 parent b40df75 commit b666520

File tree

2 files changed

+29
-41
lines changed

2 files changed

+29
-41
lines changed

pvlib/modelchain.py

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,11 +1572,13 @@ def _prepare_temperature(self, data=None):
15721572
"""
15731573
poa = _irrad_for_celltemp(self.results.total_irrad,
15741574
self.results.effective_irradiance)
1575-
if not isinstance(data, tuple) and self.system.num_arrays > 1:
1575+
# handle simple case first, single array, data not iterable
1576+
if not isinstance(data, tuple) and self.system.num_arrays == 1:
1577+
return self._prepare_temperature_single_array(data, poa)
1578+
if not isinstance(data, tuple):
15761579
# broadcast data to all arrays
15771580
data = (data,) * self.system.num_arrays
1578-
elif not isinstance(data, tuple):
1579-
return self._prepare_temperature_single_array(data, poa)
1581+
# find where cell or module temperature is specified in input data
15801582
given_cell_temperature = tuple(itertools.starmap(
15811583
self._get_cell_temperature,
15821584
zip(data, poa, self.system.temperature_model_parameters)
@@ -1587,23 +1589,7 @@ def _prepare_temperature(self, data=None):
15871589
self.results.cell_temperature = given_cell_temperature
15881590
return self
15891591
# Calculate cell temperature from weather data. If cell_temperature
1590-
# has not been provided for some arrays then it is computed with
1591-
# ModelChain.temperature_model(). Because this operates on all Arrays
1592-
# simultaneously, 'poa_global' must be known for all arrays, including
1593-
# those that have a known cell temperature.
1594-
try:
1595-
self._verify_df(self.results.total_irrad, ['poa_global'])
1596-
except ValueError:
1597-
# Provide a more informative error message. Because only
1598-
# run_model_from_effective_irradiance() can get to this point
1599-
# without known POA we can suggest a very specific remedy in the
1600-
# error message.
1601-
raise ValueError("Incomplete input data. Data must contain "
1602-
"'poa_global'. For systems with multiple Arrays "
1603-
"if you have provided 'cell_temperature' for "
1604-
"only a subset of Arrays you must provide "
1605-
"'poa_global' for all Arrays, including those "
1606-
"that have a known 'cell_temperature'.")
1592+
# has not been provided for some arrays then it is computed.
16071593
self.temperature_model()
16081594
# replace calculated cell temperature with temperature given in `data`
16091595
# where available.
@@ -1814,6 +1800,7 @@ def run_model_from_effective_irradiance(self, data=None):
18141800
"""
18151801
data = _to_tuple(data)
18161802
self._check_multiple_input(data)
1803+
self._verify_df(data, required=['effective_irradiance'])
18171804
self._assign_weather(data)
18181805
self._assign_total_irrad(data)
18191806
self.results.effective_irradiance = _tuple_from_dfs(

pvlib/tests/test_modelchain.py

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -985,26 +985,44 @@ def test_run_model_from_poa_tracking(sapm_dc_snl_ac_system, location,
985985
assert_series_equal(ac, expected)
986986

987987

988+
@pytest.mark.parametrize("input_type", [lambda x: x[0], tuple, list])
988989
def test_run_model_from_effective_irradiance(sapm_dc_snl_ac_system, location,
989-
weather, total_irrad):
990+
weather, total_irrad, input_type):
990991
data = weather.copy()
991992
data[['poa_global', 'poa_diffuse', 'poa_direct']] = total_irrad
992993
data['effective_irradiance'] = data['poa_global']
993994
mc = ModelChain(sapm_dc_snl_ac_system, location, aoi_model='no_loss',
994995
spectral_model='no_loss')
995-
ac = mc.run_model_from_effective_irradiance(data).results.ac
996+
ac = mc.run_model_from_effective_irradiance(input_type((data,))).results.ac
996997
expected = pd.Series(np.array([149.280238, 96.678385]),
997998
index=data.index)
998999
assert_series_equal(ac, expected)
9991000

10001001

1002+
@pytest.mark.parametrize("input_type", [tuple, list])
1003+
def test_run_model_from_effective_irradiance_multi_array(
1004+
sapm_dc_snl_ac_system_Array, location, weather, total_irrad,
1005+
input_type):
1006+
data = weather.copy()
1007+
data[['poa_global', 'poa_diffuse', 'poa_direct']] = total_irrad
1008+
data['effective_irradiance'] = data['poa_global']
1009+
mc = ModelChain(sapm_dc_snl_ac_system_Array, location, aoi_model='no_loss',
1010+
spectral_model='no_loss')
1011+
mc.run_model_from_effective_irradiance(input_type((data, data)))
1012+
# arrays have different orientation, but should give same dc power
1013+
# because we are the same passing POA irradiance and air
1014+
# temperature.
1015+
assert_frame_equal(mc.results.dc[0], mc.results.dc[1])
1016+
1017+
1018+
@pytest.mark.parametrize("input_type", [lambda x: x[0], tuple, list])
10011019
def test_run_model_from_effective_irradiance_no_poa_global(
1002-
sapm_dc_snl_ac_system, location, weather, total_irrad):
1020+
sapm_dc_snl_ac_system, location, weather, total_irrad, input_type):
10031021
data = weather.copy()
10041022
data['effective_irradiance'] = total_irrad['poa_global']
10051023
mc = ModelChain(sapm_dc_snl_ac_system, location, aoi_model='no_loss',
10061024
spectral_model='no_loss')
1007-
ac = mc.run_model_from_effective_irradiance(data).results.ac
1025+
ac = mc.run_model_from_effective_irradiance(input_type((data,))).results.ac
10081026
expected = pd.Series(np.array([149.280238, 96.678385]),
10091027
index=data.index)
10101028
assert_series_equal(ac, expected)
@@ -1087,23 +1105,6 @@ def test_run_model_from_effective_irradiance_minimal_input(
10871105
assert not mc.results.ac.empty
10881106

10891107

1090-
def test_run_model_from_effective_irradiance_missing_poa(
1091-
sapm_dc_snl_ac_system_Array, location, total_irrad):
1092-
data_incomplete = pd.DataFrame(
1093-
{'effective_irradiance': total_irrad['poa_global'],
1094-
'poa_global': total_irrad['poa_global']},
1095-
index=total_irrad.index)
1096-
data_complete = pd.DataFrame(
1097-
{'effective_irradiance': total_irrad['poa_global'],
1098-
'cell_temperature': 30},
1099-
index=total_irrad.index)
1100-
mc = ModelChain(sapm_dc_snl_ac_system_Array, location)
1101-
with pytest.raises(ValueError,
1102-
match="you must provide 'poa_global' for all Arrays"):
1103-
mc.run_model_from_effective_irradiance(
1104-
(data_complete, data_incomplete))
1105-
1106-
11071108
def test_run_model_singleton_weather_single_array(cec_dc_snl_ac_system,
11081109
location, weather):
11091110
mc = ModelChain(cec_dc_snl_ac_system, location,

0 commit comments

Comments
 (0)