From 07ae57e1309d03e676fcc93f993ab8f645f10649 Mon Sep 17 00:00:00 2001 From: Rodrigo Amaro e Silva Date: Sun, 3 Aug 2025 21:28:38 +0100 Subject: [PATCH 1/6] Adapts irradiance.isotropic to return_components framework. --- pvlib/irradiance.py | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index 2e1ed35cb5..445d231a86 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -587,7 +587,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. @@ -613,10 +613,23 @@ def isotropic(surface_tilt, dhi): dhi : numeric Diffuse horizontal irradiance. [Wm⁻²] DHI must be >=0. + return_components : bool, default False + Flag used to decide whether to return the calculated diffuse components + or not. If `False`, ``sky_diffuse`` is returned. If `True`, + ``diffuse_components`` is returned. + Returns ------- - diffuse : numeric - The sky diffuse component of the solar radiation. + poa_sky_diffuse : numeric + The sky diffuse component of the solar radiation on a tilted + surface. + + diffuse_components : OrderedDict (array input) or DataFrame (Series input) + Keys/columns are: + * sky_diffuse: Total sky diffuse + * isotropic + * circumsolar + * horizon References ---------- @@ -630,9 +643,20 @@ def isotropic(surface_tilt, dhi): Energy vol. 201. pp. 8-12 :doi:`10.1016/j.solener.2020.02.067` ''' - sky_diffuse = dhi * (1 + tools.cosd(surface_tilt)) * 0.5 + poa_sky_diffuse = dhi * (1 + tools.cosd(surface_tilt)) * 0.5 - return sky_diffuse + if return_components: + diffuse_components = OrderedDict() + diffuse_components['poa_sky_diffuse'] = poa_sky_diffuse + + # Calculate the different components + diffuse_components['poa_isotropic'] = poa_sky_diffuse + diffuse_components['poa_circumsolar'] = 0 + diffuse_components['poa_horizon'] = 0 + + return diffuse_components + else: + return poa_sky_diffuse def klucher(surface_tilt, surface_azimuth, dhi, ghi, solar_zenith, @@ -782,8 +806,9 @@ def haydavies(surface_tilt, surface_azimuth, dhi, dni, dni_extra, or supply ``projection_ratio``. return_components : bool, default `False` - If `False`, ``sky_diffuse`` is returned. - If `True`, ``diffuse_components`` is returned. + Flag used to decide whether to return the calculated diffuse components + or not. If `False`, ``sky_diffuse`` is returned. If `True`, + ``diffuse_components`` is returned. Returns -------- From a2916b37e33f1bffbeb568b91a61b951cade5275 Mon Sep 17 00:00:00 2001 From: Rodrigo Amaro e Silva Date: Fri, 8 Aug 2025 00:02:15 +0100 Subject: [PATCH 2/6] Implements new strategy for output formatting. --- pvlib/irradiance.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index 445d231a86..ab30067d12 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -624,12 +624,18 @@ def isotropic(surface_tilt, dhi, return_components=False): The sky diffuse component of the solar radiation on a tilted surface. - diffuse_components : OrderedDict (array input) or DataFrame (Series input) + diffuse_components : dict (array input) or DataFrame (Series input) Keys/columns are: - * sky_diffuse: Total sky diffuse + * sky_diffuse (the sum of the components below) * isotropic * circumsolar * horizon + * poa_sky_diffuse (the sum of the components below) + * poa_isotropic + * poa_circumsolar + * poa_horizon + The first four elements will be deprecated in v0.14.0 and are kept + to avoit breaking changes. References ---------- @@ -646,14 +652,25 @@ def isotropic(surface_tilt, dhi, return_components=False): poa_sky_diffuse = dhi * (1 + tools.cosd(surface_tilt)) * 0.5 if return_components: - diffuse_components = OrderedDict() + diffuse_components = dict() + + # original formatting (to be deprecated in v0.14.0) + diffuse_components['sky_diffuse'] = poa_sky_diffuse # total + diffuse_components['isotropic'] = poa_sky_diffuse + diffuse_components['circumsolar'] = 0 + diffuse_components['horizon'] = 0 + + # new formatting diffuse_components['poa_sky_diffuse'] = poa_sky_diffuse - - # Calculate the different components diffuse_components['poa_isotropic'] = poa_sky_diffuse diffuse_components['poa_circumsolar'] = 0 diffuse_components['poa_horizon'] = 0 + if isinstance(poa_sky_diffuse, pd.Series): + # follows `perez` worfklow + # shouldn't it include an argument `index=dhi.index`? + diffuse_components = pd.DataFrame(diffuse_components) + return diffuse_components else: return poa_sky_diffuse From c633188809269b2e45a136700bcc532b704c83b3 Mon Sep 17 00:00:00 2001 From: Rodrigo Amaro e Silva Date: Fri, 8 Aug 2025 00:04:51 +0100 Subject: [PATCH 3/6] Adjusts flake8 formatting. --- pvlib/irradiance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index ab30067d12..eac770a48a 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -653,7 +653,7 @@ def isotropic(surface_tilt, dhi, return_components=False): if return_components: diffuse_components = dict() - + # original formatting (to be deprecated in v0.14.0) diffuse_components['sky_diffuse'] = poa_sky_diffuse # total diffuse_components['isotropic'] = poa_sky_diffuse From 796ef8b8f4044e3e820966fc343ee06626493e7a Mon Sep 17 00:00:00 2001 From: ramaroesilva Date: Sun, 21 Dec 2025 13:39:57 +0000 Subject: [PATCH 4/6] Minor change in docstring. --- pvlib/irradiance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index eac770a48a..af1977f203 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -615,7 +615,7 @@ def isotropic(surface_tilt, dhi, return_components=False): return_components : bool, default False Flag used to decide whether to return the calculated diffuse components - or not. If `False`, ``sky_diffuse`` is returned. If `True`, + or not. If `False`, ``poa_sky_diffuse`` is returned. If `True`, ``diffuse_components`` is returned. Returns From b4f779a7850607c48c91fedcb13e6150bded432d Mon Sep 17 00:00:00 2001 From: ramaroesilva Date: Thu, 15 Jan 2026 08:09:33 +0000 Subject: [PATCH 5/6] Cleans dict create + forces output as dataframe. --- pvlib/irradiance.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index af1977f203..af4af2ded4 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -649,29 +649,29 @@ def isotropic(surface_tilt, dhi, return_components=False): Energy vol. 201. pp. 8-12 :doi:`10.1016/j.solener.2020.02.067` ''' - poa_sky_diffuse = dhi * (1 + tools.cosd(surface_tilt)) * 0.5 + poa_sky_diffuse = dhi * (1 + tools.cosd(surface_tilt)) * 0.5 + if return_components: - diffuse_components = dict() - - # original formatting (to be deprecated in v0.14.0) - diffuse_components['sky_diffuse'] = poa_sky_diffuse # total - diffuse_components['isotropic'] = poa_sky_diffuse - diffuse_components['circumsolar'] = 0 - diffuse_components['horizon'] = 0 - - # new formatting - diffuse_components['poa_sky_diffuse'] = poa_sky_diffuse - diffuse_components['poa_isotropic'] = poa_sky_diffuse - diffuse_components['poa_circumsolar'] = 0 - diffuse_components['poa_horizon'] = 0 - - if isinstance(poa_sky_diffuse, pd.Series): - # follows `perez` worfklow - # shouldn't it include an argument `index=dhi.index`? - diffuse_components = pd.DataFrame(diffuse_components) - + is_pandas = isinstance(dhi, (pd.DataFrame,pd.Series)) + + if is_pandas: + poa_sky_diffuse = poa_sky_diffuse.values + + diffuse_components = { + 'poa_sky_diffuse': poa_sky_diffuse, + 'poa_isotropic': poa_sky_diffuse, + 'poa_circumsolar': 0, + 'poa_horizon': 0, + } + + poa_sky_diffuse = pd.DataFrame(poa_sky_diffuse) + if is_pandas: + # keeps original index + poa_sky_diffuse.index = dhi.index + return diffuse_components + else: return poa_sky_diffuse From 6350b3c7aa44c2ee29716240431ecbfbfa9f5bea Mon Sep 17 00:00:00 2001 From: ramaroesilva Date: Fri, 16 Jan 2026 01:53:30 +0000 Subject: [PATCH 6/6] Updates commits, further restructures isotropic. --- pvlib/irradiance.py | 67 +++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index af4af2ded4..30fffe8b60 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -615,27 +615,17 @@ def isotropic(surface_tilt, dhi, return_components=False): return_components : bool, default False Flag used to decide whether to return the calculated diffuse components - or not. If `False`, ``poa_sky_diffuse`` is returned. If `True`, - ``diffuse_components`` is returned. + or not. If `True`, the resulting dataframe will include three more + columns. If not, only ``poa_sky_diffuse`` column is returned. Returns ------- - poa_sky_diffuse : numeric + poa_sky_diffuse : DataFrame The sky diffuse component of the solar radiation on a tilted - surface. - - diffuse_components : dict (array input) or DataFrame (Series input) - Keys/columns are: - * sky_diffuse (the sum of the components below) - * isotropic - * circumsolar - * horizon - * poa_sky_diffuse (the sum of the components below) - * poa_isotropic - * poa_circumsolar - * poa_horizon - The first four elements will be deprecated in v0.14.0 and are kept - to avoit breaking changes. + surface. Columns provided controlled by ``return_components`` argument. + If `False`, ``total`` is returned. + If `True`, ``isotropic``, ``circumsolar`` and ``horizon``. + Index is either inherited from dhi or default. References ---------- @@ -650,30 +640,29 @@ def isotropic(surface_tilt, dhi, return_components=False): :doi:`10.1016/j.solener.2020.02.067` ''' - poa_sky_diffuse = dhi * (1 + tools.cosd(surface_tilt)) * 0.5 - - if return_components: - is_pandas = isinstance(dhi, (pd.DataFrame,pd.Series)) - - if is_pandas: - poa_sky_diffuse = poa_sky_diffuse.values - - diffuse_components = { - 'poa_sky_diffuse': poa_sky_diffuse, - 'poa_isotropic': poa_sky_diffuse, - 'poa_circumsolar': 0, - 'poa_horizon': 0, - } - - poa_sky_diffuse = pd.DataFrame(poa_sky_diffuse) - if is_pandas: - # keeps original index - poa_sky_diffuse.index = dhi.index - - return diffuse_components + poa_isotropic = dhi * (1 + tools.cosd(surface_tilt)) * 0.5 + + # if pd.DataFrame or Series handles first output as numerical + is_pandas = isinstance(dhi, (pd.DataFrame,pd.Series)) + if is_pandas: + poa_isotropic = poa_isotropic.values + poa_sky_diffuse = poa_isotropic + + if not return_components: + poa_sky_diffuse = {'total': poa_sky_diffuse} else: - return poa_sky_diffuse + poa_sky_diffuse = {'isotropic': poa_isotropic, + 'circumsolar': 0, + 'horizon': 0} + + poa_sky_diffuse = pd.DataFrame(poa_sky_diffuse) + + # if dhi was pandas, out_df inherits index + if is_pandas: + poa_sky_diffuse.index = dhi.index + + return poa_sky_diffuse def klucher(surface_tilt, surface_azimuth, dhi, ghi, solar_zenith,