Skip to content

Commit dd6062a

Browse files
spanejakandersolar
andauthored
Add optional return_components parameter to irradiance.haydavies (#1568)
* haydavies_return_components Update the Hay Davies sky transposition model to return individual components by user request. * updating_return_components Added in horizon component, which defaults to 0 or NaN. Also updating some stickler issues. * stickler_stickler Updating formatting in file to be in line with stickler. Updating contributors list and corresponding information. * testing_update adding in test for when pandas is not being used. * docstring update * cleaning_updates * testing_updates updated tests for various data types. Co-authored-by: Kevin Anderson <[email protected]>
1 parent b7768b4 commit dd6062a

File tree

3 files changed

+81
-6
lines changed

3 files changed

+81
-6
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Deprecations
1010
Enhancements
1111
~~~~~~~~~~~~
1212
* Multiple code style issues fixed that were reported by LGTM analysis. (:issue:`1275`, :pull:`1559`)
13+
* Add optional ``return_components`` parameter to :py:func:`pvlib.irradiance.haydavies` to return
14+
individual diffuse irradiance components (:issue:`1553`, :pull:`1568`)
1315

1416
Bug fixes
1517
~~~~~~~~~
@@ -35,4 +37,5 @@ Requirements
3537
Contributors
3638
~~~~~~~~~~~~
3739
* Christian Orner (:ghuser:`chrisorner`)
38-
* Marcus Boumans (:ghuser:`bowie2211`)
40+
* Saurabh Aneja (:ghuser:`spaneja`)
41+
* Marcus Boumans (:ghuser:`bowie2211`)

pvlib/irradiance.py

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,8 @@ def klucher(surface_tilt, surface_azimuth, dhi, ghi, solar_zenith,
739739

740740

741741
def haydavies(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
742-
solar_zenith=None, solar_azimuth=None, projection_ratio=None):
742+
solar_zenith=None, solar_azimuth=None, projection_ratio=None,
743+
return_components=False):
743744
r'''
744745
Determine diffuse irradiance from the sky on a tilted surface using
745746
Hay & Davies' 1980 model
@@ -790,10 +791,27 @@ def haydavies(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
790791
projection. Must supply ``solar_zenith`` and ``solar_azimuth``
791792
or supply ``projection_ratio``.
792793
794+
return_components : bool, default False
795+
Flag used to decide whether to return the calculated diffuse components
796+
or not.
797+
793798
Returns
794799
--------
800+
numeric, OrderedDict, or DataFrame
801+
Return type controlled by `return_components` argument.
802+
If ``return_components=False``, `sky_diffuse` is returned.
803+
If ``return_components=True``, `diffuse_components` is returned.
804+
795805
sky_diffuse : numeric
796-
The sky diffuse component of the solar radiation.
806+
The sky diffuse component of the solar radiation on a tilted
807+
surface.
808+
809+
diffuse_components : OrderedDict (array input) or DataFrame (Series input)
810+
Keys/columns are:
811+
* sky_diffuse: Total sky diffuse
812+
* isotropic
813+
* circumsolar
814+
* horizon
797815
798816
Notes
799817
------
@@ -830,10 +848,25 @@ def haydavies(surface_tilt, surface_azimuth, dhi, dni, dni_extra,
830848
term1 = 1 - AI
831849
term2 = 0.5 * (1 + tools.cosd(surface_tilt))
832850

833-
sky_diffuse = dhi * (AI * Rb + term1 * term2)
834-
sky_diffuse = np.maximum(sky_diffuse, 0)
851+
poa_isotropic = np.maximum(dhi * term1 * term2, 0)
852+
poa_circumsolar = np.maximum(dhi * (AI * Rb), 0)
853+
sky_diffuse = poa_isotropic + poa_circumsolar
835854

836-
return sky_diffuse
855+
if return_components:
856+
diffuse_components = OrderedDict()
857+
diffuse_components['sky_diffuse'] = sky_diffuse
858+
859+
# Calculate the individual components
860+
diffuse_components['isotropic'] = poa_isotropic
861+
diffuse_components['circumsolar'] = poa_circumsolar
862+
diffuse_components['horizon'] = np.where(
863+
np.isnan(diffuse_components['isotropic']), np.nan, 0.)
864+
865+
if isinstance(sky_diffuse, pd.Series):
866+
diffuse_components = pd.DataFrame(diffuse_components)
867+
return diffuse_components
868+
else:
869+
return sky_diffuse
837870

838871

839872
def reindl(surface_tilt, surface_azimuth, dhi, dni, ghi, dni_extra,

pvlib/tests/test_irradiance.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,45 @@ def test_haydavies(irrad_data, ephem_data, dni_et):
207207
assert_allclose(result, [0, 27.1775, 102.9949, 33.1909], atol=1e-4)
208208

209209

210+
def test_haydavies_components(irrad_data, ephem_data, dni_et):
211+
expected = pd.DataFrame(np.array(
212+
[[0, 27.1775, 102.9949, 33.1909],
213+
[0, 27.1775, 30.1818, 27.9837],
214+
[0, 0, 72.8130, 5.2071],
215+
[0, 0, 0, 0]]).T,
216+
columns=['sky_diffuse', 'isotropic', 'circumsolar', 'horizon'],
217+
index=irrad_data.index
218+
)
219+
# pandas
220+
result = irradiance.haydavies(
221+
40, 180, irrad_data['dhi'], irrad_data['dni'], dni_et,
222+
ephem_data['apparent_zenith'], ephem_data['azimuth'],
223+
return_components=True)
224+
assert_frame_equal(result, expected, check_less_precise=4)
225+
# numpy
226+
result = irradiance.haydavies(
227+
40, 180, irrad_data['dhi'].values, irrad_data['dni'].values, dni_et,
228+
ephem_data['apparent_zenith'].values, ephem_data['azimuth'].values,
229+
return_components=True)
230+
assert_allclose(result['sky_diffuse'], expected['sky_diffuse'], atol=1e-4)
231+
assert_allclose(result['isotropic'], expected['isotropic'], atol=1e-4)
232+
assert_allclose(result['circumsolar'], expected['circumsolar'], atol=1e-4)
233+
assert_allclose(result['horizon'], expected['horizon'], atol=1e-4)
234+
assert isinstance(result, dict)
235+
# scalar
236+
result = irradiance.haydavies(
237+
40, 180, irrad_data['dhi'].values[-1], irrad_data['dni'].values[-1],
238+
dni_et[-1], ephem_data['apparent_zenith'].values[-1],
239+
ephem_data['azimuth'].values[-1], return_components=True)
240+
assert_allclose(result['sky_diffuse'], expected['sky_diffuse'][-1],
241+
atol=1e-4)
242+
assert_allclose(result['isotropic'], expected['isotropic'][-1],
243+
atol=1e-4)
244+
assert_allclose(result['circumsolar'], expected['circumsolar'][-1],
245+
atol=1e-4)
246+
assert_allclose(result['horizon'], expected['horizon'][-1], atol=1e-4)
247+
assert isinstance(result, dict)
248+
210249
def test_reindl(irrad_data, ephem_data, dni_et):
211250
result = irradiance.reindl(
212251
40, 180, irrad_data['dhi'], irrad_data['dni'], irrad_data['ghi'],

0 commit comments

Comments
 (0)