diff --git a/docs/sphinx/source/reference/irradiance/decomposition.rst b/docs/sphinx/source/reference/irradiance/decomposition.rst index 0677d6ac95..08724be38e 100644 --- a/docs/sphinx/source/reference/irradiance/decomposition.rst +++ b/docs/sphinx/source/reference/irradiance/decomposition.rst @@ -12,6 +12,7 @@ DNI estimation models irradiance.dirint irradiance.dirindex irradiance.erbs + irradiance.orgill_hollands irradiance.boland irradiance.campbell_norman irradiance.gti_dirint diff --git a/docs/sphinx/source/whatsnew/v0.10.0.rst b/docs/sphinx/source/whatsnew/v0.10.0.rst index c5e02ffbc3..80c6d9a3f3 100644 --- a/docs/sphinx/source/whatsnew/v0.10.0.rst +++ b/docs/sphinx/source/whatsnew/v0.10.0.rst @@ -29,11 +29,11 @@ Deprecations Enhancements ~~~~~~~~~~~~ +* Added a new irradiance decomposition model :py:func:`pvlib.irradiance.orgill_hollands`. (:pull:`1730`) * The return values of :py:func:`pvlib.pvsystem.calcparams_desoto`, :py:func:`pvlib.pvsystem.calcparams_cec`, and :py:func:`pvlib.pvsystem.calcparams_pvsyst` are all numeric types and have the same Python type as the `effective_irradiance` and `temp_cell` parameters. (:issue:`1626`, :pull:`1700`) - * Added `map_variables` parameter to :py:func:`pvlib.iotools.read_srml` and :py:func:`pvlib.iotools.read_srml_month_from_solardat` (:pull:`1773`) * Allow passing keyword arguments to :py:func:`scipy:scipy.optimize.brentq` and @@ -45,7 +45,6 @@ Enhancements (:issue:`1249`, :pull:`1764`) * Improved `ModelChainResult.__repr__` (:pull:`1236`) - Bug fixes ~~~~~~~~~ @@ -71,6 +70,7 @@ Requirements Contributors ~~~~~~~~~~~~ * Taos Transue (:ghuser:`reepoi`) +* Nicholas Riedel-Lyngskær (:ghuser:`nicorie`) * Adam R. Jensen (:ghuser:`AdamRJensen`) * Echedey Luis (:ghuser:`echedey-ls`) * Cliff Hansen (:ghuser:`cwhanse`) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index af983e47b9..beec6dd0b2 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -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) @@ -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""" @@ -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 ----- diff --git a/pvlib/tests/test_irradiance.py b/pvlib/tests/test_irradiance.py index d0158dad1a..ab1af612a7 100644 --- a/pvlib/tests/test_irradiance.py +++ b/pvlib/tests/test_irradiance.py @@ -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