Skip to content

add orgill hollands decomposition #1730

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

Merged
merged 15 commits into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
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/decomposition.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ DNI estimation models
irradiance.dirint
irradiance.dirindex
irradiance.erbs
irradiance.orgill_hollands
irradiance.boland
irradiance.campbell_norman
irradiance.gti_dirint
Expand Down
90 changes: 90 additions & 0 deletions pvlib/irradiance.py
Original file line number Diff line number Diff line change
Expand Up @@ -2227,6 +2227,8 @@ def erbs(ghi, zenith, datetime_or_doy, min_cos_zenith=0.065, max_zenith=87):
--------
dirint
disc
orgill_hollands
boland
"""

dni_extra = get_extra_radiation(datetime_or_doy)
Expand Down Expand Up @@ -2265,6 +2267,93 @@ def erbs(ghi, zenith, datetime_or_doy, min_cos_zenith=0.065, max_zenith=87):
return data


def orgill_hollands(ghi, zenith, datetime_or_doy, dni_extra=None,
min_cos_zenith=0.065, max_zenith=87):
"""Estimate DNI and DHI from GHI using the Orgill and Hollands model.

The Orgill and Hollands model [1]_ estimates the diffuse fraction DF from
global horizontal irradiance through an empirical relationship between
hourly DF observations (in Toronto, Canada) and the ratio of GHI to
extraterrestrial irradiance, Kt.

Parameters
----------
ghi: numeric
Global horizontal irradiance in W/m^2.
zenith: numeric
True (not refraction-corrected) zenith angles in decimal degrees.
datetime_or_doy : int, float, array, pd.DatetimeIndex
Day of year or array of days of year e.g.
pd.DatetimeIndex.dayofyear, or pd.DatetimeIndex.
dni_extra : None or numeric, default None
Extraterrestrial direct normal irradiance. [W/m2]
min_cos_zenith : numeric, default 0.065
Minimum value of cos(zenith) to allow when calculating global
clearness index `kt`. Equivalent to zenith = 86.273 degrees.
max_zenith : numeric, default 87
Maximum value of zenith to allow in DNI calculation. DNI will be
set to 0 for times with zenith values greater than `max_zenith`.

Returns
-------
data : OrderedDict or DataFrame
Contains the following keys/columns:

* ``dni``: the modeled direct normal irradiance in W/m^2.
* ``dhi``: the modeled diffuse horizontal irradiance in
W/m^2.
* ``kt``: Ratio of global to extraterrestrial irradiance
on a horizontal plane.

References
----------
.. [1] Orgill, J.F., Hollands, K.G.T., Correlation equation for hourly
diffuse radiation on a horizontal surface, Solar Energy 19(4), pp 357–359,
1977. Eqs. 3(a), 3(b) and 3(c)
:doi:`10.1016/0038-092X(77)90006-8`

See Also
--------
dirint
disc
erbs
boland
"""
if dni_extra is None:
dni_extra = get_extra_radiation(datetime_or_doy)

kt = clearness_index(ghi, zenith, dni_extra, min_cos_zenith=min_cos_zenith,
max_clearness_index=1)

# For Kt < 0.35, set the diffuse fraction
df = 1 - 0.249*kt

# For Kt >= 0.35 and Kt <= 0.75, set the diffuse fraction
df = np.where((kt >= 0.35) & (kt <= 0.75),
1.557 - 1.84*kt, df)

# For Kt > 0.75, set the diffuse fraction
df = np.where(kt > 0.75, 0.177, df)

dhi = df * ghi

dni = (ghi - dhi) / tools.cosd(zenith)
bad_values = (zenith > max_zenith) | (ghi < 0) | (dni < 0)
dni = np.where(bad_values, 0, dni)
# ensure that closure relationship remains valid
dhi = np.where(bad_values, ghi, dhi)

data = OrderedDict()
data['dni'] = dni
data['dhi'] = dhi
data['kt'] = kt

if isinstance(datetime_or_doy, pd.DatetimeIndex):
data = pd.DataFrame(data, index=datetime_or_doy)

return data


def boland(ghi, solar_zenith, datetime_or_doy, a_coeff=8.645, b_coeff=0.613,
min_cos_zenith=0.065, max_zenith=87):
r"""
Expand Down Expand Up @@ -2326,6 +2415,7 @@ def boland(ghi, solar_zenith, datetime_or_doy, a_coeff=8.645, b_coeff=0.613,
dirint
disc
erbs
orgill_hollands

Notes
-----
Expand Down
16 changes: 16 additions & 0 deletions pvlib/tests/test_irradiance.py
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,22 @@ def test_boland():
assert np.allclose(out, expected)


def test_orgill_hollands():
index = pd.DatetimeIndex(['20190101']*3 + ['20190620'])
ghi = pd.Series([0, 50, 1000, 1000], index=index)
zenith = pd.Series([120, 85, 10, 10], index=index)
expected = pd.DataFrame(np.array(
[[0.0, 0.0, 0.0],
[108.731366, 40.5234370, 0.405723511],
[776.155771, 235.635779, 0.718132729],
[835.696102, 177.000000, 0.768214312]]),
columns=['dni', 'dhi', 'kt'], index=index)

out = irradiance.orgill_hollands(ghi, zenith, index)

assert np.allclose(out, expected)


def test_erbs_min_cos_zenith_max_zenith():
# map out behavior under difficult conditions with various
# limiting kwargs settings
Expand Down