Skip to content
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

Add Muneer transposition model #2184

Draft
wants to merge 55 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
02ae568
muneer transposition model
bernatnic Aug 26, 2024
ea15728
Update pvlib/irradiance.py
BernatNicolau Aug 26, 2024
feafcea
Update pvlib/irradiance.py
BernatNicolau Aug 26, 2024
e4646d4
Update pvlib/irradiance.py
BernatNicolau Aug 26, 2024
8066458
Update pvlib/irradiance.py
BernatNicolau Aug 26, 2024
1798da8
Update pvlib/irradiance.py
BernatNicolau Aug 26, 2024
4281d61
Update pvlib/irradiance.py
BernatNicolau Aug 26, 2024
8b13595
references modified and doi added
BernatNicolau Aug 26, 2024
6cd63a8
removed unwanted file
BernatNicolau Aug 26, 2024
fa4d8e6
formating autopep8
BernatNicolau Aug 26, 2024
8318d5b
formatting
BernatNicolau Aug 26, 2024
d5c8bc3
avoid references first paragraph
BernatNicolau Aug 27, 2024
8cbee57
updated wording
BernatNicolau Aug 27, 2024
20c8fae
function finished
BernatNicolau Aug 27, 2024
a326e94
Merge branch 'muneer' of https://github.com/BernatNicolau/pvlib-pytho…
BernatNicolau Aug 27, 2024
e0d85c0
pvlib.irradiance update (muneer)
BernatNicolau Aug 28, 2024
30fb33a
documentation, tests and flake8
BernatNicolau Aug 28, 2024
e1a7f74
flake8 update
BernatNicolau Aug 28, 2024
618ca91
test_added
BernatNicolau Aug 28, 2024
373d3e0
flake8
BernatNicolau Aug 28, 2024
e517a84
E501
BernatNicolau Aug 28, 2024
9452248
update whatsnew
BernatNicolau Aug 28, 2024
b2d5239
Merge branch 'main' into muneer
BernatNicolau Aug 28, 2024
36f633e
Update docs/sphinx/source/whatsnew/v0.11.1.rst
BernatNicolau Aug 28, 2024
982d2f9
documentation improvement
BernatNicolau Aug 28, 2024
eecc05e
documentation improvement
BernatNicolau Aug 28, 2024
83b5036
documentation improvement
BernatNicolau Aug 28, 2024
6bd1d51
Merge branch 'main' into muneer
BernatNicolau Aug 28, 2024
4fb4bae
b added to `get_total_irradiance`
BernatNicolau Aug 29, 2024
4c69d6f
Apply suggestions from code review (documentation)
BernatNicolau Sep 2, 2024
b93aa05
flake8-linter
BernatNicolau Sep 2, 2024
c2248f1
Update DOI
BernatNicolau Sep 3, 2024
91fd117
create scenario with low solar altitude (<0.1rad)
BernatNicolau Sep 3, 2024
b8910de
avoid zero in denominator
BernatNicolau Sep 3, 2024
0591323
division by zero fix
BernatNicolau Sep 3, 2024
aed0e6d
solar_azimuth is not optional anymore + test updated
BernatNicolau Sep 3, 2024
2d4b10f
# GH 432
BernatNicolau Sep 3, 2024
bec7412
test_update
BernatNicolau Sep 3, 2024
a3e3e3c
replace np.where by .where to keep the pd.Series type
BernatNicolau Sep 3, 2024
927c8a8
revert np.where and modify type if needed
BernatNicolau Sep 3, 2024
7cfd605
typo when converting sky_diffuse
BernatNicolau Sep 3, 2024
5298cb2
improvement # GH 432
BernatNicolau Sep 3, 2024
ce6f5c0
np.array and float tests added
BernatNicolau Sep 4, 2024
ce42241
updated expected to np.array as it should be
BernatNicolau Sep 4, 2024
5632bda
assert_series_equal to assert_almost_equal
BernatNicolau Sep 4, 2024
b2128cf
documentation improvement
BernatNicolau Sep 4, 2024
f9fb65c
linter
BernatNicolau Sep 4, 2024
c0caf04
Apply suggestions from code review
BernatNicolau Sep 4, 2024
2142559
unify irradiation unit format
BernatNicolau Sep 4, 2024
4e58192
Merge branch 'muneer' of https://github.com/BernatNicolau/pvlib-pytho…
BernatNicolau Sep 4, 2024
bedd18b
linter
BernatNicolau Sep 4, 2024
b5e4aec
muneer2004
BernatNicolau Sep 5, 2024
1bcf20d
overcast condition
BernatNicolau Sep 5, 2024
c9b9214
update clearness index
BernatNicolau Sep 6, 2024
519861e
Merge pull request #1 from BernatNicolau/muneer-book
BernatNicolau Sep 27, 2024
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
1 change: 1 addition & 0 deletions docs/sphinx/source/reference/irradiance/transposition.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ Transposition models
irradiance.klucher
irradiance.reindl
irradiance.king
irradiance.muneer
irradiance.ghi_from_poa_driesse_2023
5 changes: 4 additions & 1 deletion docs/sphinx/source/whatsnew/v0.11.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ Enhancements
* Added function for calculating wind speed at different heights,
:py:func:`pvlib.atmosphere.windspeed_powerlaw`.
(:issue:`2118`, :pull:`2124`)
* Added function for determine sky diffuse irradiance on a tilted surface
BernatNicolau marked this conversation as resolved.
Show resolved Hide resolved
using the Muneer model,
:py:func:`pvlib.irradiance.muneer`.
(:issue:`2117`, :pull:`2184`)

Bug fixes
~~~~~~~~~
Expand Down Expand Up @@ -71,4 +75,3 @@ Contributors
* Jose Meza (:ghuser:`JoseMezaMendieta`)
* Bernat Nicolau (:ghuser:`BernatNicolau`)
* Eduardo Sarquis (:ghuser:`EduardoSarquis`)

135 changes: 122 additions & 13 deletions pvlib/irradiance.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ def get_total_irradiance(surface_tilt, surface_azimuth,
dni, ghi, dhi, dni_extra=None, airmass=None,
albedo=0.25, surface_type=None,
model='isotropic',
model_perez='allsitescomposite1990'):
model_perez='allsitescomposite1990', b=5.73):
r"""
Determine total in-plane irradiance and its beam, sky diffuse and ground
reflected components, using the specified sky diffuse irradiance model.
Expand All @@ -280,6 +280,7 @@ def get_total_irradiance(surface_tilt, surface_azimuth,
* king
* perez
* perez-driesse
* muneer

Parameters
----------
Expand Down Expand Up @@ -309,9 +310,12 @@ def get_total_irradiance(surface_tilt, surface_azimuth,
model : str, default 'isotropic'
Irradiance model. Can be one of ``'isotropic'``, ``'klucher'``,
``'haydavies'``, ``'reindl'``, ``'king'``, ``'perez'``,
``'perez-driesse'``.
``'perez-driesse'`` and ``'muneer
model_perez : str, default 'allsitescomposite1990'
Used only if ``model='perez'``. See :py:func:`~pvlib.irradiance.perez`.
b : numeric, default 5.73
Used only if ``model='muneer'``.
See :py:func:`~pvlib.irradiance.muneer`.

Returns
-------
Expand All @@ -321,9 +325,9 @@ def get_total_irradiance(surface_tilt, surface_azimuth,

Notes
-----
Models ``'haydavies'``, ``'reindl'``, ``'perez'`` and ``'perez-driesse'``
require ``'dni_extra'``. Values can be calculated using
:py:func:`~pvlib.irradiance.get_extra_radiation`.
Models ``'haydavies'``, ``'reindl'``, ``'perez'``, ``'perez-driesse'``,
and ``'muneer'`` require ``'dni_extra'``. Values can be calculated
BernatNicolau marked this conversation as resolved.
Show resolved Hide resolved
using :py:func:`~pvlib.irradiance.get_extra_radiation`.

The ``'perez'`` and ``'perez-driesse'`` models require relative airmass
(``airmass``) as input. If ``airmass`` is not provided, it is calculated
BernatNicolau marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -333,7 +337,7 @@ def get_total_irradiance(surface_tilt, surface_azimuth,
poa_sky_diffuse = get_sky_diffuse(
surface_tilt, surface_azimuth, solar_zenith, solar_azimuth,
dni, ghi, dhi, dni_extra=dni_extra, airmass=airmass, model=model,
model_perez=model_perez)
model_perez=model_perez, b=b)

poa_ground_diffuse = get_ground_diffuse(surface_tilt, ghi, albedo,
surface_type)
Expand All @@ -346,7 +350,7 @@ def get_sky_diffuse(surface_tilt, surface_azimuth,
solar_zenith, solar_azimuth,
dni, ghi, dhi, dni_extra=None, airmass=None,
model='isotropic',
model_perez='allsitescomposite1990'):
model_perez='allsitescomposite1990', b=5.73):
r"""
Determine in-plane sky diffuse irradiance component
using the specified sky diffuse irradiance model.
Expand All @@ -359,6 +363,7 @@ def get_sky_diffuse(surface_tilt, surface_azimuth,
* king
* perez
* perez-driesse
* muneer

Parameters
----------
Expand All @@ -383,9 +388,12 @@ def get_sky_diffuse(surface_tilt, surface_azimuth,
model : str, default 'isotropic'
Irradiance model. Can be one of ``'isotropic'``, ``'klucher'``,
``'haydavies'``, ``'reindl'``, ``'king'``, ``'perez'``,
``'perez-driesse'``.
``'perez-driesse'``, ``'muneer'``.
model_perez : str, default 'allsitescomposite1990'
Used only if ``model='perez'``. See :py:func:`~pvlib.irradiance.perez`.
b : numeric, default 5.73
Used only if ``model='muneer'``.
See :py:func:`~pvlib.irradiance.muneer`.

Returns
-------
Expand All @@ -395,14 +403,15 @@ def get_sky_diffuse(surface_tilt, surface_azimuth,
Raises
------
ValueError
If model is one of ``'haydavies'``, ``'reindl'``, ``'perez'``, or
``'perez_driesse'`` and ``dni_extra`` is not specified.
If model is one of ``'haydavies'``, ``'reindl'``, ``'perez'``,
``'perez_driesse'``, or ``'muneer'`` and ``dni_extra`` is not
specified.

Notes
-----
Models ``'haydavies'``, ``'reindl'``, ``'perez'`` and ``'perez-driesse'``
require ``'dni_extra'``. Values can be calculated using
:py:func:`~pvlib.irradiance.get_extra_radiation`.
Models ``'haydavies'``, ``'reindl'``, ``'perez'``, ``'perez-driesse'``
and ``'muneer'`` require ``'dni_extra'``. Values can be calculated
using :py:func:`~pvlib.irradiance.get_extra_radiation`.

The ``'Perez'`` transposition model features discontinuities in the
predicted tilted diffuse irradiance due to relying on discrete input
Expand Down Expand Up @@ -443,6 +452,9 @@ def get_sky_diffuse(surface_tilt, surface_azimuth,
# perez_driesse will calculate its own airmass if needed
sky = perez_driesse(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
solar_zenith, solar_azimuth, airmass)
elif model == 'muneer':
sky = muneer(surface_tilt, surface_azimuth, dhi, ghi, dni_extra,
b, solar_zenith, solar_azimuth)
else:
raise ValueError(f'invalid model selection {model}')

Expand Down Expand Up @@ -994,6 +1006,103 @@ def king(surface_tilt, dhi, ghi, solar_zenith):
return sky_diffuse


def muneer(surface_tilt, surface_azimuth, dhi, ghi, dni_extra, b=5.73,
solar_zenith=None, solar_azimuth=None, projection_ratio=None):
'''
Determine sky diffuse irradiance on a tilted surface using the
Muneer model.

This Muneer transposition model is described in [1]_.
BernatNicolau marked this conversation as resolved.
Show resolved Hide resolved

Parameters
----------
surface_tilt : numeric
Surface tilt angles in decimal degrees. surface_tilt must be >=0
BernatNicolau marked this conversation as resolved.
Show resolved Hide resolved
and <=180. The tilt angle is defined as degrees from horizontal
(e.g. surface facing up = 0, surface facing horizon = 90)

surface_azimuth : numeric
Surface azimuth angles in decimal degrees. surface_azimuth must
be >=0 and <=360. The azimuth convention is defined as degrees
BernatNicolau marked this conversation as resolved.
Show resolved Hide resolved
east of north (e.g. North = 0, South=180 East = 90, West = 270).

dhi : numeric
Diffuse horizontal irradiance. [W/m^2]
BernatNicolau marked this conversation as resolved.
Show resolved Hide resolved

ghi : numeric
Global horizontal irradiance in W/m^2.

dni_extra : numeric
Extraterrestrial normal irradiance in W/m^2.
BernatNicolau marked this conversation as resolved.
Show resolved Hide resolved

b : numeric, default 5.73
Radiance distribution index, introduced by Moon and Spencer [2]_
to model luminance distribution of overcast sky. [unitless]
Recommended values from [1]_:

- isotropic: b = 0
- shaded surface: b = 5.73 (default)
- sunlit surface, overcast sky: b = 1.68
- sunlit surface, non-overcast sky: b = -0.62

solar_zenith : numeric
Solar apparent (refraction-corrected) zenith angles in decimal
degrees. Must supply ``solar_zenith`` and ``solar_azimuth`` or
supply ``projection_ratio``.

solar_azimuth : numeric, optional
Solar azimuth angles in decimal degrees. Must supply
``solar_zenith`` and ``solar_azimuth`` or supply
``projection_ratio``.

projection_ratio : numeric, optional
Ratio of angle of incidence projection to solar zenith angle
projection. Must supply ``solar_zenith`` and ``solar_azimuth``
or supply ``projection_ratio``.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest leaving this out for simplicity and being consistent with the other transposition models in pvlib.

Returns
-------
poa_sky_diffuse : numeric
In-plane diffuse irradiance from the sky. [W/m^2]
BernatNicolau marked this conversation as resolved.
Show resolved Hide resolved

References
----------
.. [1] Muneer, T., 1990. Solar radiation model for Europe. Building
Services Engineering Research and Technology 11, 153-163.
:doi:`10.1177/014362449001100405`

.. [2] Moon, P., Spencer, D.E., 1942. Illumination from a non-uniform sky.
BernatNicolau marked this conversation as resolved.
Show resolved Hide resolved
Trans. Illum. Eng. Soc. (London) 37, 707-725.
:doi:`10.1177/096032719302500301`
BernatNicolau marked this conversation as resolved.
Show resolved Hide resolved
'''

cos_solar_zenith = tools.cosd(solar_zenith)
# if necessary, calculate ratio of titled and horizontal beam irradiance
if projection_ratio is None:
cos_tt = aoi_projection(surface_tilt, surface_azimuth,
solar_zenith, solar_azimuth)
cos_tt = np.maximum(cos_tt, 0) # GH 526
Rb = cos_tt / np.maximum(cos_solar_zenith, 0.01745) # GH 432
else:
Rb = projection_ratio

T_term1 = (1 + tools.cosd(surface_tilt)) * 0.5
T_term2 = 2 * b / (np.pi * (3 + 2 * b))
T_term3 = (
tools.sind(surface_tilt)
- np.radians(surface_tilt) * tools.cosd(surface_tilt)
- np.pi * (1 - tools.cosd(surface_tilt)) * 0.5
)
T = T_term1 + T_term2 * T_term3

horizontal_extra = dni_extra * np.maximum(cos_solar_zenith, 0.01745)
F = (ghi - dhi) / horizontal_extra

sky_diffuse = dhi*(T*(1-F) + F*Rb)

return sky_diffuse


def perez(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
solar_zenith, solar_azimuth, airmass,
model='allsitescomposite1990', return_components=False):
Expand Down
29 changes: 25 additions & 4 deletions pvlib/tests/test_irradiance.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,23 @@ def test_perez_driesse(irrad_data, ephem_data, dni_et, relative_airmass):
assert_series_equal(out, expected, check_less_precise=2)


def test_muneer(irrad_data, ephem_data, dni_et):
projection_ratio = np.array(
[0, 0, 0.8639607552973, 0.1716097049224])
out = irradiance.muneer(40, 180, irrad_data['dhi'], irrad_data['ghi'],
dni_et, solar_zenith=ephem_data['apparent_zenith'],
solar_azimuth=ephem_data['azimuth'])
out_Rb = irradiance.muneer(40, 180, irrad_data['dhi'], irrad_data['ghi'],
dni_et,
solar_zenith=ephem_data['apparent_zenith'],
projection_ratio=projection_ratio)
expected = pd.Series(np.array(
[0., 25.173, 100.757, 31.121]),
index=irrad_data.index)
assert_series_equal(out, expected, check_less_precise=2)
assert_series_equal(out_Rb, expected, check_less_precise=2)

BernatNicolau marked this conversation as resolved.
Show resolved Hide resolved

def test_perez_driesse_airmass(irrad_data, ephem_data, dni_et):
dni = irrad_data['dni'].copy()
dni.iloc[2] = np.nan
Expand Down Expand Up @@ -443,7 +460,8 @@ def test_perez_driesse_scalar():


@pytest.mark.parametrize('model', ['isotropic', 'klucher', 'haydavies',
'reindl', 'king', 'perez', 'perez-driesse'])
'reindl', 'king', 'perez', 'perez-driesse',
'muneer'])
def test_sky_diffuse_zenith_close_to_90(model):
# GH 432
sky_diffuse = irradiance.get_sky_diffuse(
Expand Down Expand Up @@ -495,7 +513,8 @@ def test_campbell_norman():
def test_get_total_irradiance(irrad_data, ephem_data, dni_et,
relative_airmass):
models = ['isotropic', 'klucher',
'haydavies', 'reindl', 'king', 'perez', 'perez-driesse']
'haydavies', 'reindl', 'king', 'perez', 'perez-driesse',
'muneer']

for model in models:
total = irradiance.get_total_irradiance(
Expand All @@ -514,7 +533,8 @@ def test_get_total_irradiance(irrad_data, ephem_data, dni_et,

@pytest.mark.parametrize('model', ['isotropic', 'klucher',
'haydavies', 'reindl', 'king',
'perez', 'perez-driesse'])
'perez', 'perez-driesse',
'muneer'])
def test_get_total_irradiance_albedo(
irrad_data, ephem_data, dni_et, relative_airmass, model):
albedo = pd.Series(0.2, index=ephem_data.index)
Expand All @@ -534,7 +554,8 @@ def test_get_total_irradiance_albedo(

@pytest.mark.parametrize('model', ['isotropic', 'klucher',
'haydavies', 'reindl', 'king',
'perez', 'perez-driesse'])
'perez', 'perez-driesse',
'muneer'])
def test_get_total_irradiance_scalars(model):
total = irradiance.get_total_irradiance(
32, 180,
Expand Down
Loading