Skip to content

Commit 3c70802

Browse files
committed
Fix #2017
1 parent 8767004 commit 3c70802

File tree

1 file changed

+58
-18
lines changed

1 file changed

+58
-18
lines changed

pvlib/modelchain.py

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -330,10 +330,15 @@ class ModelChain:
330330
'interp' and 'no_loss'. The ModelChain instance will be passed as the
331331
first argument to a user-defined function.
332332
333-
spectral_model : str, or function, optional
333+
spectral_model : str or function, optional
334334
If not specified, the model will be inferred from the parameters that
335-
are common to all of system.arrays[i].module_parameters.
336-
Valid strings are 'sapm', 'first_solar', 'no_loss'.
335+
are common to all of system.arrays[i].module_parameters. Valid strings
336+
are:
337+
338+
- ``'sapm'``
339+
- ``'first_solar'``
340+
- ``'no_loss'``
341+
337342
The ModelChain instance will be passed as the first argument to
338343
a user-defined function.
339344
@@ -855,9 +860,7 @@ def spectral_model(self):
855860

856861
@spectral_model.setter
857862
def spectral_model(self, model):
858-
if model is None:
859-
self._spectral_model = self.infer_spectral_model()
860-
elif isinstance(model, str):
863+
if isinstance(model, str):
861864
model = model.lower()
862865
if model == 'first_solar':
863866
self._spectral_model = self.first_solar_spectral_loss
@@ -867,29 +870,60 @@ def spectral_model(self, model):
867870
self._spectral_model = self.no_spectral_loss
868871
else:
869872
raise ValueError(model + ' is not a valid spectral loss model')
873+
elif model is None:
874+
# None is a valid value, model inference will be done later
875+
self._spectral_model = None
870876
else:
871877
self._spectral_model = partial(model, self)
872878

873-
def infer_spectral_model(self):
879+
def infer_spectral_model(self): # TODO: support other spectral models?
874880
"""Infer spectral model from system attributes."""
875881
module_parameters = tuple(
876882
array.module_parameters for array in self.system.arrays)
877883
params = _common_keys(module_parameters)
878884
if {'A4', 'A3', 'A2', 'A1', 'A0'} <= params:
879885
return self.sapm_spectral_loss
880-
elif ((('Technology' in params or
881-
'Material' in params) and
882-
(self.system._infer_cell_type() is not None)) or
883-
'first_solar_spectral_coefficients' in params):
886+
elif "first_solar_spectral_coefficients" in params:
887+
# user explicitly sets spectral coefficients
884888
return self.first_solar_spectral_loss
889+
elif (
890+
# cell type is known or can be inferred
891+
("Technology" in params or "Material" in params)
892+
and (self.system._infer_cell_type() is not None)
893+
):
894+
# This suggests models that provide default parameters per cell
895+
# type can be used. However, some of them depend on other weather
896+
# parameters, so we need to check if they are available.
897+
# At this point, weather may not be available, so let's take that
898+
# into account.
899+
if self.results is not None and self.results.weather is not None:
900+
# weather is available
901+
if "precipitable_water" in self.results.weather:
902+
return self.first_solar_spectral_loss
903+
else:
904+
return self.no_spectral_loss
905+
else:
906+
# weather is not available, so it's unknown what model to use.
907+
# Warn user about this and default to no_spectral_loss.
908+
warnings.warn(
909+
"Weather data is not available to infer spectral model. "
910+
"Defaulting to 'no_loss'. Explicitly set the "
911+
"spectral model with the 'spectral_model' kwarg to "
912+
"suppress this warning."
913+
)
914+
return self.no_spectral_loss
885915
else:
886-
raise ValueError('could not infer spectral model from '
887-
'system.arrays[i].module_parameters. Check that '
888-
'the module_parameters for all Arrays in '
889-
'system.arrays contain valid '
890-
'first_solar_spectral_coefficients, a valid '
891-
'Material or Technology value, or set '
892-
'spectral_model="no_loss".')
916+
# TODO: list valid models in message down below
917+
raise ValueError(
918+
"could not infer spectral model from "
919+
"system.arrays[i].module_parameters. Check that "
920+
"the module_parameters for all Arrays in "
921+
"system.arrays contain valid "
922+
"valid spectral coefficients, a valid "
923+
"Material or Technology value, or a valid model "
924+
"string; explicitly set the model with the "
925+
"'spectral_model' kwarg."
926+
)
893927

894928
def first_solar_spectral_loss(self):
895929
self.results.spectral_modifier = self.system.first_solar_spectral_loss(
@@ -1678,7 +1712,13 @@ def run_model(self, weather):
16781712
weather = _to_tuple(weather)
16791713
self.prepare_inputs(weather)
16801714
self.aoi_model()
1715+
1716+
# spectral model is optional, and weather may impact model inference
1717+
# check if spectral model inference is requested by means of "None"
1718+
if self._spectral_model is None:
1719+
self._spectral_model = self.infer_spectral_model()
16811720
self.spectral_model()
1721+
16821722
self.effective_irradiance_model()
16831723

16841724
self._run_from_effective_irrad(weather)

0 commit comments

Comments
 (0)