-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Create iam.py, consistent naming for IAM functions #783
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
Changes from 1 commit
73f4638
a89cc01
0f1c90c
0a55b54
8505a0d
f48742c
1bcde31
c51bc08
5e01712
e5bebe1
549fc2c
42210e4
1475db6
006768d
c10af4c
b9e39ac
ab1fbbc
4dadd4b
7f14c95
9164592
2fe7396
3d6bcf5
64a6b3c
152ef7a
46db9d7
ea6fe81
2529351
f641cd0
f331949
ec723c6
cf998ea
23f2677
1e63f04
5fb7cc8
b43b28c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
…i_loss
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,17 @@ | |
from pvlib.tools import cosd, sind, tand, asind | ||
|
||
|
||
# a dict of required parameter names for each IAM model | ||
# keys are the function names for the IAM models | ||
IAM_MODEL_PARAMS = { | ||
'ashrae': set(['b']), | ||
'physical': set(['n', 'K', 'L']), | ||
'martin_ruiz': set(['a_r']), | ||
'sapm': set(['B0', 'B1', 'B2', 'B3', 'B4', 'B5']), | ||
'interp': set([]) | ||
} | ||
|
||
|
||
def ashrae(aoi, b=0.05): | ||
r""" | ||
Determine the incidence angle modifier using the ASHRAE transmission | ||
8000
|
@@ -347,7 +358,7 @@ def sapm(aoi, module, upper=None): | |
zeros. | ||
|
||
module : dict-like | ||
A dict, Series, or DataFrame defining the SAPM performance | ||
A dict or Series with the SAPM IAM model parameters. | ||
parameters. See the :py:func:`sapm` notes section for more | ||
details. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -316,72 +316,65 @@ def get_irradiance(self, solar_zenith, solar_azimuth, dni, ghi, dhi, | |
albedo=self.albedo, | ||
**kwargs) | ||
|
||
def iam_ashrae(self, aoi): | ||
def get_iam(self, aoi, iam_model='physical'): | ||
""" | ||
Determine the incidence angle modifier using | ||
``self.module_parameters['b']``, ``aoi``, | ||
and the :py:func:`iam.ashrae` function. | ||
Determine the incidence angle modifier using the method specified by | ||
``iam_model``. | ||
|
||
Uses default arguments if keys not in module_parameters. | ||
Parameters for the selected IAM model are expected to be in | ||
``PVSystem.module_parameters``. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should add something about defaults like "... otherwise default values will be used." |
||
|
||
Parameters | ||
---------- | ||
aoi : numeric | ||
The angle of incidence in degrees. | ||
|
||
aoi_model : string, default 'physical' | ||
The IAM model to be used. Valid strings are 'physical', 'ashrae', | ||
'martin_ruiz' and 'sapm'. | ||
|
||
Returns | ||
------- | ||
modifier : numeric | ||
iam : numeric | ||
The AOI modifier. | ||
""" | ||
kwargs = _build_kwargs(['b'], self.module_parameters) | ||
|
||
return iam.ashrae(aoi, **kwargs) | ||
Raises | ||
------ | ||
ValueError if `iam_model` is not a valid model name. | ||
""" | ||
model = iam_model.lower() | ||
if model in ['ashrae', 'physical', 'martin_ruiz']: | ||
param_names = iam.IAM_MODEL_PARAMS[model] | ||
kwargs = _build_kwargs(param_names, self.module_parameters) | ||
func = iam.__getattribute__(model) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's usually preferable to call the |
||
return func(aoi, **kwargs) | ||
elif model=='sapm': | ||
return iam.sapm(aoi, self.module_parameters) | ||
elif model=='interp': | ||
raise ValueError(model + ' is not implemented as an IAM model' | ||
'option for PVSystem') | ||
else: | ||
raise ValueError(model + ' is not a valid IAM model') | ||
|
||
def ashraeiam(self, aoi): | ||
""" | ||
Deprecated. Use ``PVSystem.iam_ashrae`` instead. | ||
Deprecated. Use ``PVSystem.iam`` instead. | ||
""" | ||
import warnings | ||
warnings.warn('PVSystem.ashraeiam is deprecated and will be removed in' | ||
'v0.8, use PVSystem.iam_ashrae instead', | ||
'v0.8, use PVSystem.get_iam instead', | ||
pvlibDeprecationWarning) | ||
return PVSystem.iam_ashrae(self, aoi) | ||
|
||
def iam_physical(self, aoi): | ||
""" | ||
Determine the incidence angle modifier using ``aoi``, | ||
``self.module_parameters['K']``, | ||
``self.module_parameters['L']``, | ||
``self.module_parameters['n']``, | ||
and the | ||
:py:func:`iam.physical` function. | ||
|
||
Uses default arguments if keys not in module_parameters. | ||
|
||
Parameters | ||
---------- | ||
aoi : numeric | ||
The angle of incidence in degrees. | ||
|
||
Returns | ||
------- | ||
modifier : numeric | ||
The AOI modifier. | ||
""" | ||
kwargs = _build_kwargs(['K', 'L', 'n'], self.module_parameters) | ||
|
||
return iam.physical(aoi, **kwargs) | ||
return PVSystem.get_iam(self, aoi, iam_model='ashrae') | ||
|
||
def physicaliam(self, aoi): | ||
""" | ||
Deprecated. Use ``PVSystem.iam_physical`` instead. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this and similar docstring below need to be updated to point to |
||
""" | ||
import warnings | ||
warnings.warn('PVSystem.physicaliam is deprecated and will be removed' | ||
' in v0.8, use PVSystem.iam_physical instead', | ||
' in v0.8, use PVSystem.get_iam instead', | ||
pvlibDeprecationWarning) | ||
return PVSystem.iam_physical(self, aoi) | ||
return PVSystem.get_iam(self, aoi, iam_model='physical') | ||
|
||
def calcparams_desoto(self, effective_irradiance, temp_cell, **kwargs): | ||
""" | ||
|
@@ -550,30 +543,13 @@ def sapm_spectral_loss(self, airmass_absolute): | |
|
||
def sapm_aoi_loss(self, aoi): | ||
""" | ||
Deprecated. Use ``PVSystem.iam_sapm`` instead. | ||
Deprecated. Use ``PVSystem.iam`` instead. | ||
""" | ||
import warnings | ||
warnings.warn('PVSystem.sapm_aoi_loss is deprecated and will be' | ||
' removed in v0.8, use PVSystem.iam_sapm instead', | ||
' removed in v0.8, use PVSystem.get_iam instead', | ||
pvlibDeprecationWarning) | ||
return PVSystem.iam_sapm(self, aoi) | ||
|
||
def iam_sapm(self, aoi): | ||
""" | ||
Use the :py:func:`iam.sapm` function, the input parameters, | ||
and ``self.module_parameters`` to calculate iam. | ||
|
||
Parameters | ||
---------- | ||
aoi : numeric | ||
Angle of incidence in degrees. | ||
|
||
Returns | ||
------- | ||
iam : numeric | ||
The SAPM angle of incidence loss coefficient F2. | ||
""" | ||
return iam.sapm(aoi, self.module_parameters) | ||
return PVSystem.get_iam(self, aoi, iam_model='sapm') | ||
|
||
def sapm_effective_irradiance(self, poa_direct, poa_diffuse, | ||
airmass_absolute, aoi, | ||
|
@@ -2779,3 +2755,7 @@ def pvwatts_ac(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): | |
|
||
physicaliam = deprecated('0.7', alternative='iam.physical', name='physicaliam', | ||
removal='0.8')(iam.physical) | ||
|
||
|
||
sapm_aoi_loss = deprecated('0.7', alternative='iam.sapm', name='sapm_aoi_loss', | ||
removal='0.8')(iam.sapm) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,24 +79,28 @@ def test_systemdef_dict(): | |
assert expected == pvsystem.systemdef(meta, 5, 0, .1, 5, 5) | ||
|
||
|
||
def test_PVSystem_iam_ashrae(mocker): | ||
mocker.spy(_iam, 'ashrae') | ||
module_parameters = pd.Series({'b': 0.05}) | ||
@pytest.mark.parametrize('iam_model','model_params', [ | ||
('ashrae', {'b': 0.05}), | ||
('physical', {'K': 4, 'L': 0.002, 'n': 1.526}), | ||
('martin_ruiz', {'a_r': 0.16}), | ||
]) | ||
def test_PVSystem_get_iam(mocker, iam_model, model_params): | ||
mocker.spy(_iam, iam_model) | ||
module_parameters = pd.Series(model_params) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest leaving this as a dict instead of converting to a Series. |
||
system = pvsystem.PVSystem(module_parameters=module_parameters) | ||
thetas = 1 | ||
iam = system.iam_ashrae(thetas) | ||
_iam.ashrae.assert_called_once_with(thetas, b=0.05) | ||
iam = system.get_iam(thetas, iam_model=iam_model) | ||
_iam.ashrae.assert_called_once_with(thetas, **module_parameters) | ||
assert iam < 1. | ||
|
||
|
||
def test_PVSystem_iam_physical(mocker): | ||
module_parameters = pd.Series({'K': 4, 'L': 0.002, 'n': 1.526}) | ||
system = pvsystem.PVSystem(module_parameters=module_parameters) | ||
mocker.spy(_iam, 'physical') | ||
thetas = 1 | ||
iam = system.iam_physical(thetas) | ||
_iam.physical.assert_called_once_with(thetas, **module_parameters) | ||
assert iam < 1. | ||
def test_PVSystem_get_iam_sapm(sapm_module_params, mocker): | ||
system = pvsystem.PVSystem(module_parameters=sapm_module_params) | ||
mocker.spy(_iam, 'sapm') | ||
aoi = 0 | ||
out = system.get_iam(aoi, 'sapm') | ||
_iam.sapm.assert_called_once_with(aoi, sapm_module_params) | ||
assert_allclose(out, 1.0, atol=0.01) | ||
|
||
|
||
def test_retrieve_sam_raise_no_parameters(): | ||
|
@@ -279,15 +283,6 @@ def test_PVSystem_first_solar_spectral_loss(module_parameters, module_type, | |
assert_allclose(out, 1, atol=0.5) | ||
|
||
|
||
def test_PVSystem_iam_sapm(sapm_module_params, mocker): | ||
system = pvsystem.PVSystem(module_parameters=sapm_module_params) | ||
mocker.spy(_iam, 'sapm') | ||
aoi = 0 | ||
out = system.iam_sapm(aoi) | ||
_iam.sapm.assert_called_once_with(aoi, sapm_module_params) | ||
assert_allclose(out, 1.0, atol=0.01) | ||
|
||
|
||
@pytest.mark.parametrize('test_input,expected', [ | ||
([1000, 100, 5, 45, 1000], 1.1400510967821877), | ||
([np.array([np.nan, 1000, 1000]), | ||
|
@@ -1453,7 +1448,7 @@ def test_PVSystem_pvwatts_ac_kwargs(mocker): | |
|
||
|
||
@fail_on_pvlib_version('0.8') | ||
def test_deprecated_08(): | ||
def test_deprecated_08(sapm_module_params): | ||
with pytest.warns(pvlibDeprecationWarning): | ||
pvsystem.sapm_celltemp(1000, 25, 1) | ||
with pytest.warns(pvlibDeprecationWarning): | ||
|
@@ -1467,6 +1462,8 @@ def test_deprecated_08(): | |
pvsystem.ashraeiam(45) | ||
with pytest.warns(pvlibDeprecationWarning): | ||
pvsystem.physicaliam(45) | ||
with pytest.warns(pvlibDeprecationWarning): | ||
pvsystem.sapm_aoi_loss(45, sapm_module_params) | ||
|
||
|
||
@fail_on_pvlib_version('0.8') | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what to think of this emerging pattern in pvlib. It will be a lot to maintain in the long run as it expands to more and more classes of models. While we make use of it internally (for now), I think the added benefit for users is not very big. At this moment, I don't want to put the effort into implementing a solution with something like
inspect
, but I wonder if we should rethink making these attributes public instead of private.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also uneasy about continued use of constants following this pattern. I think it's valuable to have lists of model parameter names somewhere, perhaps not in this form. A data model encompassing a system's physical and model parameters would help here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created #789 to track this. I'm ok leaving it alone for this PR.