Skip to content

Commit 276a30d

Browse files
authored
Deprecate/raise error for PVSystem "pass-through" properties (#1196)
1 parent 7eae1fc commit 276a30d

File tree

8 files changed

+240
-95
lines changed

8 files changed

+240
-95
lines changed

docs/sphinx/source/pvsystem.rst

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ default value may be overridden by specifying the `temp_ref` key in the
9797

9898
.. ipython:: python
9999
100-
system.module_parameters['temp_ref'] = 0
100+
system.arrays[0].module_parameters['temp_ref'] = 0
101101
# lower temp_ref should lead to lower DC power than calculated above
102102
pdc = system.pvwatts_dc(1000, 30)
103103
print(pdc)
@@ -124,7 +124,7 @@ passed to `PVSystem.module_parameters`:
124124
inverter_parameters = {'pdc0': 5000, 'eta_inv_nom': 0.96}
125125
system = pvsystem.PVSystem(module_parameters=module_parameters,
126126
inverter_parameters=inverter_parameters)
127-
print(system.module_parameters)
127+
print(system.arrays[0].module_parameters)
128128
print(system.inverter_parameters)
129129
130130
@@ -142,12 +142,9 @@ provided for each array, and the arrays are provided to
142142
array_two = pvsystem.Array(module_parameters=module_parameters)
143143
system_two_arrays = pvsystem.PVSystem(arrays=[array_one, array_two],
144144
inverter_parameters=inverter_parameters)
145-
print(system_two_arrays.module_parameters)
145+
print([array.module_parameters for array in system_two_arrays.arrays])
146146
print(system_two_arrays.inverter_parameters)
147147
148-
Note that in the case of a PV system with multiple arrays, the
149-
:py:class:`~pvlib.pvsystem.PVSystem` attribute `module_parameters` contains
150-
a tuple with the `module_parameters` for each array.
151148
152149
The :py:class:`~pvlib.pvsystem.Array` class includes those
153150
:py:class:`~pvlib.pvsystem.PVSystem` attributes that may vary from array
@@ -188,7 +185,8 @@ these parameters can be specified using the `PVSystem.surface_tilt` and
188185
189186
# single south-facing array at 20 deg tilt
190187
system_one_array = pvsystem.PVSystem(surface_tilt=20, surface_azimuth=180)
191-
print(system_one_array.surface_tilt, system_one_array.surface_azimuth)
188+
print(system_one_array.arrays[0].surface_tilt,
189+
system_one_array.arrays[0].surface_azimuth)
192190
193191
194192
In the case of a PV system with several arrays, the parameters are specified
@@ -201,8 +199,7 @@ for each array using the attributes `Array.surface_tilt` and `Array.surface_azim
201199
array_two = pvsystem.Array(surface_tilt=30, surface_azimuth=220)
202200
system = pvsystem.PVSystem(arrays=[array_one, array_two])
203201
system.num_arrays
204-
system.surface_tilt
205-
system.surface_azimuth
202+
[(array.surface_tilt, array.surface_azimuth) for array in system.arrays]
206203
207204
208205
The `surface_tilt` and `surface_azimuth` attributes are used in PVSystem
@@ -218,7 +215,8 @@ and `solar_azimuth` as arguments.
218215
219216
# single south-facing array at 20 deg tilt
220217
system_one_array = pvsystem.PVSystem(surface_tilt=20, surface_azimuth=180)
221-
print(system_one_array.surface_tilt, system_one_array.surface_azimuth)
218+
print(system_one_array.arrays[0].surface_tilt,
219+
system_one_array.arrays[0].surface_azimuth)
222220
223221
# call get_aoi with solar_zenith, solar_azimuth
224222
aoi = system_one_array.get_aoi(solar_zenith=30, solar_azimuth=180)

docs/sphinx/source/whatsnew/v0.9.0.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,22 @@ Deprecations
8585
* The ``eta_m`` parameter for :py:func:`~pvlib.temperature.pvsyst_cell` is
8686
replaced by parameter ``module_efficiency``. (:issue:`1188`, :pull:`1218`)
8787

88+
* The following attributes of :py:class:`pvlib.pvsystem.PVSystem` and
89+
:py:class:`pvlib.tracking.SingleAxisTracker` have been deprecated in
90+
favor of the corresponding :py:class:`pvlib.pvsystem.Array` attributes:
91+
92+
* ``PVSystem.albedo``
93+
* ``PVSystem.module``
94+
* ``PVSystem.module_parameters``
95+
* ``PVSystem.module_type``
96+
* ``PVSystem.modules_per_string``
97+
* ``PVSystem.racking_model``
98+
* ``PVSystem.strings_per_inverter``
99+
* ``PVSystem.surface_tilt``
100+
* ``PVSystem.surface_azimuth``
101+
* ``PVSystem.temperature_model_parameters``
102+
103+
88104
Enhancements
89105
~~~~~~~~~~~~
90106
* Add :func:`~pvlib.iotools.read_bsrn` for reading BSRN solar radiation data

pvlib/modelchain.py

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -408,29 +408,32 @@ class ModelChain:
408408
Passed to location.get_airmass.
409409
410410
dc_model: None, str, or function, default None
411-
If None, the model will be inferred from the contents of
412-
system.module_parameters. Valid strings are 'sapm',
413-
'desoto', 'cec', 'pvsyst', 'pvwatts'. The ModelChain instance will
414-
be passed as the first argument to a user-defined function.
411+
If None, the model will be inferred from the parameters that
412+
are common to all of system.arrays[i].module_parameters.
413+
Valid strings are 'sapm', 'desoto', 'cec', 'pvsyst', 'pvwatts'.
414+
The ModelChain instance will be passed as the first argument
415+
to a user-defined function.
415416
416417
ac_model: None, str, or function, default None
417-
If None, the model will be inferred from the contents of
418-
system.inverter_parameters and system.module_parameters. Valid
419-
strings are 'sandia', 'adr', 'pvwatts'. The
418+
If None, the model will be inferred from the parameters that
419+
are common to all of system.inverter_parameters.
420+
Valid strings are 'sandia', 'adr', 'pvwatts'. The
420421
ModelChain instance will be passed as the first argument to a
421422
user-defined function.
422423
423424
aoi_model: None, str, or function, default None
424-
If None, the model will be inferred from the contents of
425-
system.module_parameters. Valid strings are 'physical',
426-
'ashrae', 'sapm', 'martin_ruiz', 'no_loss'. The ModelChain instance
427-
will be passed as the first argument to a user-defined function.
425+
If None, the model will be inferred from the parameters that
426+
are common to all of system.arrays[i].module_parameters.
427+
Valid strings are 'physical', 'ashrae', 'sapm', 'martin_ruiz',
428+
'no_loss'. The ModelChain instance will be passed as the
429+
first argument to a user-defined function.
428430
429431
spectral_model: None, str, or function, default None
430-
If None, the model will be inferred from the contents of
431-
system.module_parameters. Valid strings are 'sapm',
432-
'first_solar', 'no_loss'. The ModelChain instance will be passed
433-
as the first argument to a user-defined function.
432+
If None, the model will be inferred from the parameters that
433+
are common to all of system.arrays[i].module_parameters.
434+
Valid strings are 'sapm', 'first_solar', 'no_loss'.
435+
The ModelChain instance will be passed as the first argument to
436+
a user-defined function.
434437
435438
temperature_model: None, str or function, default None
436439
Valid strings are: 'sapm', 'pvsyst', 'faiman', 'fuentes', 'noct_sam'.
@@ -691,9 +694,10 @@ def dc_model(self, model):
691694
model = model.lower()
692695
if model in _DC_MODEL_PARAMS.keys():
693696
# validate module parameters
697+
module_parameters = tuple(
698+
array.module_parameters for array in self.system.arrays)
694699
missing_params = (
695-
_DC_MODEL_PARAMS[model] -
696-
_common_keys(self.system.module_parameters))
700+
_DC_MODEL_PARAMS[model] - _common_keys(module_parameters))
697701
if missing_params: # some parameters are not in module.keys()
698702
raise ValueError(model + ' selected for the DC model but '
699703
'one or more Arrays are missing '
@@ -716,7 +720,8 @@ def dc_model(self, model):
716720

717721
def infer_dc_model(self):
718722
"""Infer DC power model from Array module parameters."""
719-
params = _common_keys(self.system.module_parameters)
723+
params = _common_keys(
724+
tuple(array.module_parameters for array in self.system.arrays))
720725
if {'A0', 'A1', 'C7'} <= params:
721726
return self.sapm, 'sapm'
722727
elif {'a_ref', 'I_L_ref', 'I_o_ref', 'R_sh_ref', 'R_s',
@@ -730,10 +735,11 @@ def infer_dc_model(self):
730735
elif {'pdc0', 'gamma_pdc'} <= params:
731736
return self.pvwatts_dc, 'pvwatts'
732737
else:
733-
raise ValueError('could not infer DC model from '
734-
'system.module_parameters. Check '
735-
'system.module_parameters or explicitly '
736-
'set the model with the dc_model kwarg.')
738+
raise ValueError(
739+
'Could not infer DC model from the module_parameters '
740+
'attributes of system.arrays. Check the module_parameters '
741+
'attributes or explicitly set the model with the dc_model '
742+
'keyword argument.')
737743

738744
def sapm(self):
739745
dc = self.system.sapm(self.results.effective_irradiance,
@@ -782,7 +788,7 @@ def pvwatts_dc(self):
782788
"""Calculate DC power using the PVWatts model.
783789
784790
Results are stored in ModelChain.results.dc. DC power is computed
785-
from PVSystem.module_parameters['pdc0'] and then scaled by
791+
from PVSystem.arrays[i].module_parameters['pdc0'] and then scaled by
786792
PVSystem.modules_per_string and PVSystem.strings_per_inverter.
787793
788794
Returns
@@ -891,7 +897,9 @@ def aoi_model(self, model):
891897
self._aoi_model = partial(model, self)
892898

893899
def infer_aoi_model(self):
894-
params = _common_keys(self.system.module_parameters)
900+
module_parameters = tuple(
901+
array.module_parameters for array in self.system.arrays)
902+
params = _common_keys(module_parameters)
895903
if {'K', 'L', 'n'} <= params:
896904
return self.physical_aoi_loss
897905
elif {'B5', 'B4', 'B3', 'B2', 'B1', 'B0'} <= params:
@@ -902,8 +910,8 @@ def infer_aoi_model(self):
902910
return self.martin_ruiz_aoi_loss
903911
else:
904912
raise ValueError('could not infer AOI model from '
905-
'system.module_parameters. Check that the '
906-
'module_parameters for all Arrays in '
913+
'system.arrays[i].module_parameters. Check that '
914+
'the module_parameters for all Arrays in '
907915
'system.arrays contain parameters for '
908916
'the physical, aoi, ashrae or martin_ruiz model; '
909917
'explicitly set the model with the aoi_model '
@@ -966,7 +974,9 @@ def spectral_model(self, model):
966974

967975
def infer_spectral_model(self):
968976
"""Infer spectral model from system attributes."""
969-
params = _common_keys(self.system.module_parameters)
977+
module_parameters = tuple(
978+
array.module_parameters for array in self.system.arrays)
979+
params = _common_keys(module_parameters)
970980
if {'A4', 'A3', 'A2', 'A1', 'A0'} <= params:
971981
return self.sapm_spectral_loss
972982
elif ((('Technology' in params or
@@ -976,8 +986,8 @@ def infer_spectral_model(self):
976986
return self.first_solar_spectral_loss
977987
else:
978988
raise ValueError('could not infer spectral model from '
979-
'system.module_parameters. Check that the '
980-
'module_parameters for all Arrays in '
989+
'system.arrays[i].module_parameters. Check that '
990+
'the module_parameters for all Arrays in '
981991
'system.arrays contain valid '
982992
'first_solar_spectral_coefficients, a valid '
983993
'Material or Technology value, or set '
@@ -1028,20 +1038,24 @@ def temperature_model(self, model):
10281038
# check system.temperature_model_parameters for consistency
10291039
name_from_params = self.infer_temperature_model().__name__
10301040
if self._temperature_model.__name__ != name_from_params:
1041+
common_params = _common_keys(tuple(
1042+
array.temperature_model_parameters
1043+
for array in self.system.arrays))
10311044
raise ValueError(
10321045
f'Temperature model {self._temperature_model.__name__} is '
10331046
f'inconsistent with PVSystem temperature model '
10341047
f'parameters. All Arrays in system.arrays must have '
10351048
f'consistent parameters. Common temperature model '
1036-
f'parameters: '
1037-
f'{_common_keys(self.system.temperature_model_parameters)}'
1049+
f'parameters: {common_params}'
10381050
)
10391051
else:
10401052
self._temperature_model = partial(model, self)
10411053

10421054
def infer_temperature_model(self):
10431055
"""Infer temperature model from system attributes."""
1044-
params = _common_keys(self.system.temperature_model_parameters)
1056+
temperature_model_parameters = tuple(
1057+
array.temperature_model_parameters for array in self.system.arrays)
1058+
params = _common_keys(temperature_model_parameters)
10451059
# remove or statement in v0.9
10461060
if {'a', 'b', 'deltaT'} <= params or (
10471061
not params and self.system.racking_model is None
@@ -1195,7 +1209,7 @@ def _eff_irrad(module_parameters, total_irrad, spect_mod, aoi_mod):
11951209
self.results.spectral_modifier, self.results.aoi_modifier))
11961210
else:
11971211
self.results.effective_irradiance = _eff_irrad(
1198-
self.system.module_parameters,
1212+
self.system.arrays[0].module_parameters,
11991213
self.results.total_irrad,
12001214
self.results.spectral_modifier,
12011215
self.results.aoi_modifier
@@ -1629,7 +1643,7 @@ def _prepare_temperature_single_array(self, data, poa):
16291643
self.results.cell_temperature = self._get_cell_temperature(
16301644
data,
16311645
poa,
1632-
self.system.temperature_model_parameters
1646+
self.system.arrays[0].temperature_model_parameters
16331647
)
16341648
if self.results.cell_temperature is None:
16351649
self.temperature_model()

0 commit comments

Comments
 (0)