From 1c459d3e4e39cc2bf36327d410224ed46970a1b1 Mon Sep 17 00:00:00 2001 From: cbcrespo Date: Tue, 9 Jun 2026 10:50:12 +0100 Subject: [PATCH 1/3] Add return_components to isotropic --- pvlib/irradiance.py | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index 50f02426de..b2bd3c4076 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -595,7 +595,7 @@ def get_ground_diffuse(surface_tilt, ghi, albedo=.25, surface_type=None): return diffuse_irrad -def isotropic(surface_tilt, dhi): +def isotropic(surface_tilt, dhi, return_components=False): r''' Determine diffuse irradiance from the sky on a tilted surface using the isotropic sky model. @@ -619,11 +619,27 @@ def isotropic(surface_tilt, dhi): dhi : numeric Diffuse horizontal irradiance, must be >=0. See :term:`dhi`. + return_components : bool, default `False` + If `False`, ``sky_diffuse`` is returned. + If `True`, ``diffuse_components`` is returned. + For this model, return_components does not add more information, + but it is included for consistency with the other sky diffuse models. + Returns ------- - diffuse : numeric + numeric, OrderedDict, or DataFrame + Return type controlled by ``return_components`` argument. + If `False`, ``sky_diffuse`` is returned. + If `True`, ``diffuse_components`` is returned. + + sky_diffuse : numeric The sky diffuse component of the solar radiation. [Wm⁻²] + diffuse_components : OrderedDict (array input) or DataFrame (Series input) + Keys/columns are: + * poa_sky_diffuse: Total sky diffuse + * poa_isotropic + References ---------- .. [1] Loutzenhiser P.G. et al. "Empirical validation of models to @@ -638,7 +654,17 @@ def isotropic(surface_tilt, dhi): ''' sky_diffuse = dhi * (1 + tools.cosd(surface_tilt)) * 0.5 - return sky_diffuse + if return_components: + diffuse_components = OrderedDict() + diffuse_components['poa_sky_diffuse'] = sky_diffuse + diffuse_components['poa_isotropic'] = sky_diffuse + + if isinstance(sky_diffuse, pd.Series): + diffuse_components = pd.DataFrame(diffuse_components) + + return diffuse_components + else: + return sky_diffuse def klucher(surface_tilt, surface_azimuth, dhi, ghi, solar_zenith, From 4148c5327371fda1653a3599e29bf9f96199341e Mon Sep 17 00:00:00 2001 From: cbcrespo Date: Wed, 17 Jun 2026 11:36:52 +0100 Subject: [PATCH 2/3] Change OrderedDict to dict --- pvlib/irradiance.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index b2bd3c4076..6a4238ddf0 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -627,7 +627,7 @@ def isotropic(surface_tilt, dhi, return_components=False): Returns ------- - numeric, OrderedDict, or DataFrame + numeric, Dict, or DataFrame Return type controlled by ``return_components`` argument. If `False`, ``sky_diffuse`` is returned. If `True`, ``diffuse_components`` is returned. @@ -635,7 +635,7 @@ def isotropic(surface_tilt, dhi, return_components=False): sky_diffuse : numeric The sky diffuse component of the solar radiation. [Wm⁻²] - diffuse_components : OrderedDict (array input) or DataFrame (Series input) + diffuse_components : Dict (array input) or DataFrame (Series input) Keys/columns are: * poa_sky_diffuse: Total sky diffuse * poa_isotropic @@ -655,9 +655,10 @@ def isotropic(surface_tilt, dhi, return_components=False): sky_diffuse = dhi * (1 + tools.cosd(surface_tilt)) * 0.5 if return_components: - diffuse_components = OrderedDict() - diffuse_components['poa_sky_diffuse'] = sky_diffuse - diffuse_components['poa_isotropic'] = sky_diffuse + diffuse_components = { + 'poa_sky_diffuse': sky_diffuse, + 'poa_isotropic': sky_diffuse + } if isinstance(sky_diffuse, pd.Series): diffuse_components = pd.DataFrame(diffuse_components) From f3e69b3eb4e23199e75d6cf7af7e2413d05ee2a9 Mon Sep 17 00:00:00 2001 From: cbcrespo Date: Wed, 17 Jun 2026 12:06:11 +0100 Subject: [PATCH 3/3] Add tests for isotropic with return_components=True --- pvlib/irradiance.py | 2 +- tests/test_irradiance.py | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index 6a4238ddf0..82b144cbe9 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -631,7 +631,7 @@ def isotropic(surface_tilt, dhi, return_components=False): Return type controlled by ``return_components`` argument. If `False`, ``sky_diffuse`` is returned. If `True`, ``diffuse_components`` is returned. - + sky_diffuse : numeric The sky diffuse component of the solar radiation. [Wm⁻²] diff --git a/tests/test_irradiance.py b/tests/test_irradiance.py index a416636ae9..ce7878fdbc 100644 --- a/tests/test_irradiance.py +++ b/tests/test_irradiance.py @@ -168,6 +168,32 @@ def test_isotropic_series(irrad_data): assert_allclose(result, [0, 35.728402, 104.601328, 54.777191], atol=1e-4) +def test_isotropic_components(irrad_data): + keys = ['poa_sky_diffuse', 'poa_isotropic'] + expected = pd.DataFrame(np.array( + [[0, 35.728402, 104.601328, 54.777191], + [0, 35.728402, 104.601328, 54.777191]]).T, + columns=keys, + index=irrad_data.index + ) + # pandas + result = irradiance.isotropic( + 40, irrad_data['dhi'], return_components=True) + assert_frame_equal(result, expected, check_less_precise=4) + # numpy + result = irradiance.isotropic( + 40, irrad_data['dhi'].values, return_components=True) + for key in keys: + assert_allclose(result[key], expected[key], atol=1e-4) + assert isinstance(result, dict) + # scalar + result = irradiance.isotropic( + 40, irrad_data['dhi'].values[-1], return_components=True) + for key in keys: + assert_allclose(result[key], expected[key].iloc[-1], atol=1e-4) + assert isinstance(result, dict) + + def test_klucher_series_float(): # klucher inputs surface_tilt, surface_azimuth = 40.0, 180.0