Skip to content

Commit 0d9e122

Browse files
committed
Amend sky_diffuse_passias docstring and plot_passias_diffuse_shading (#2584)
1 parent 6553710 commit 0d9e122

File tree

3 files changed

+61
-12
lines changed

3 files changed

+61
-12
lines changed

docs/examples/shading/plot_passias_diffuse_shading.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,21 @@
2020
# :py:func:`pvlib.shading.masking_angle_passias` and
2121
# :py:func:`pvlib.shading.sky_diffuse_passias`.
2222
#
23+
# However, the pvlib-python authors believe that this approach is incorrect.
24+
# A correction is suggested and compared with the diffuse shading as obtained
25+
# with the view factor model.
26+
#
2327
# References
2428
# ----------
2529
# .. [1] D. Passias and B. Källbäck, "Shading effects in rows of solar cell
2630
# panels", Solar Cells, Volume 11, Pages 281-291. 1984.
2731
# DOI: 10.1016/0379-6787(84)90017-6
2832

29-
from pvlib import shading, irradiance
3033
import matplotlib.pyplot as plt
3134
import numpy as np
35+
from cycler import cycler
36+
37+
from pvlib import bifacial, shading, irradiance
3238

3339
# %%
3440
# First we'll recreate Figure 4, showing how the average masking angle varies
@@ -43,7 +49,7 @@
4349

4450
plt.figure()
4551
for k in [1, 1.5, 2, 2.5, 3, 4, 5, 7, 10]:
46-
gcr = 1/k
52+
gcr = 1 / k
4753
psi = shading.masking_angle_passias(surface_tilt, gcr)
4854
plt.plot(surface_tilt, psi, label=f'k={k}')
4955

@@ -60,17 +66,18 @@
6066
# diffuse plane of array irradiance (after accounting for shading) to diffuse
6167
# horizontal irradiance. This means that the deviation from 100% is due to the
6268
# combination of self-shading and the fact that being at a tilt blocks off
63-
# the portion of the sky behind the row. The first effect is modeled with
69+
# the portion of the sky behind the row. Following the approach detailed in
70+
# [1]_, the first effect would be modeled with
6471
# :py:func:`pvlib.shading.sky_diffuse_passias` and the second with
6572
# :py:func:`pvlib.irradiance.isotropic`.
6673

6774
plt.figure()
6875
for k in [1, 1.5, 2, 10]:
69-
gcr = 1/k
76+
gcr = 1 / k
7077
psi = shading.masking_angle_passias(surface_tilt, gcr)
7178
shading_loss = shading.sky_diffuse_passias(psi)
7279
transposition_ratio = irradiance.isotropic(surface_tilt, dhi=1.0)
73-
relative_diffuse = transposition_ratio * (1-shading_loss) * 100 # %
80+
relative_diffuse = transposition_ratio * (1 - shading_loss) * 100 # %
7481
plt.plot(surface_tilt, relative_diffuse, label=f'k={k}')
7582

7683
plt.xlabel('Inclination angle [degrees]')
@@ -82,3 +89,37 @@
8289
# %%
8390
# As ``k`` decreases, GCR increases, so self-shading loss increases and
8491
# collected diffuse irradiance decreases.
92+
#
93+
# However, the pvlib-python authors believe that this approach is incorrect.
94+
#
95+
# Instead, the combination of inter-row shading from the previous row and the
96+
# surface tilt blocking the portion of the sky behind the row is obtained by
97+
# applying :py:func:`pvlib.shading.sky_diffuse_passias` on the sum of the
98+
# masking and surface tilt angles (see dashed curves in below figure). The
99+
# difference with the above approach is marginal for a ground coverage ratio
100+
# of 10%, but becomes very significant for high ground coverage ratios.
101+
#
102+
# Alternatively, one can also use :py:func:`bifacial.utils.vf_row_sky_2d_integ`
103+
# (see dotted curve in below figure), with very similar results except for the
104+
# highest ground coverage ratio. It is believed that the deviation is a result
105+
# of an approximation in :py:func:`pvlib.shading.masking_angle_passias` and
106+
# that :py:func:`bifacial.utils.vf_row_sky_2d_integ` provides the most accurate
107+
# result.
108+
109+
color_cycler = cycler('color', ['blue', 'orange', 'green', 'red'])
110+
linestyle_cycler = cycler('linestyle', ['--', ':'])
111+
plt.rc('axes', prop_cycle=color_cycler * linestyle_cycler)
112+
plt.figure()
113+
for k in [1, 1.5, 2, 10]:
114+
gcr = 1 / k
115+
psi = shading.masking_angle_passias(surface_tilt, gcr)
116+
vf1 = (1 - shading.sky_diffuse_passias(surface_tilt + psi)) * 100 # %
117+
vf2 = bifacial.utils.vf_row_sky_2d_integ(surface_tilt, gcr) * 100 # %
118+
plt.plot(surface_tilt, vf1, label=f'k={k} passias corrected')
119+
plt.plot(surface_tilt, vf2, label=f'k={k} vf_row_sky_2d_integ')
120+
121+
plt.xlabel('Inclination angle [degrees]')
122+
plt.ylabel('Relative diffuse irradiance [%]')
123+
plt.ylim(0, 105)
124+
plt.legend()
125+
plt.show()

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Breaking Changes
1010

1111
Deprecations
1212
~~~~~~~~~~~~
13+
* Deprecate :py:func:`~pvlib.shading.sky_diffuse_passias` in favor of
14+
:py:func:`~pvlib.bifacial.utils.vf_row_sky_2d_integ`. (:pull:`2584`)
1315

1416

1517
Bug fixes
@@ -33,7 +35,7 @@ Enhancements
3335
Documentation
3436
~~~~~~~~~~~~~
3537
* Provide an overview of single-diode modeling functionality in :ref:`singlediode`. (:pull:`2565`)
36-
38+
* Update gallery example of modeling diffuse shading loss with correct usage. (:pull:`2584`)
3739

3840
Testing
3941
~~~~~~~

pvlib/shading.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
import numpy as np
77
import pandas as pd
8+
9+
from pvlib._deprecation import deprecated
810
from pvlib.tools import sind, cosd
911

1012

@@ -126,6 +128,7 @@ def masking_angle_passias(surface_tilt, gcr):
126128
--------
127129
masking_angle
128130
sky_diffuse_passias
131+
bifacial.utils.vf_row_sky_2d_integ
129132
130133
Notes
131134
-----
@@ -191,26 +194,28 @@ def masking_angle_passias(surface_tilt, gcr):
191194
return np.degrees(psi_avg)
192195

193196

197+
@deprecated("0.13.2", alternative="bifacial.utils.vf_row_sky_2d_integ")
194198
def sky_diffuse_passias(masking_angle):
195199
r"""
196200
The diffuse irradiance loss caused by row-to-row sky diffuse shading.
197201
198202
Even when the sun is high in the sky, a row's view of the sky dome will
199203
be partially blocked by the row in front. This causes a reduction in the
200204
diffuse irradiance incident on the module. The reduction depends on the
201-
masking angle, the elevation angle from a point on the shaded module to
202-
the top of the shading row. In [1]_ the masking angle is calculated as
203-
the average across the module height. SAM assumes the "worst-case" loss
204-
where the masking angle is calculated for the bottom of the array [2]_.
205+
masking angle, the surface tilt and the elevation angle from a point on
206+
the shaded module to the top of the shading row. In [1]_ the masking
207+
angle is calculated as the average across the module height. SAM assumes
208+
the "worst-case" loss where the masking angle is calculated for the
209+
bottom of the array [2]_.
205210
206211
This function, as in [1]_, makes the assumption that sky diffuse
207212
irradiance is isotropic.
208213
209214
Parameters
210215
----------
211216
masking_angle : numeric
212-
The elevation angle below which diffuse irradiance is blocked
213-
[degrees].
217+
The sum of the surface tilt and the elevation angle below which
218+
diffuse irradiance is blocked [degrees].
214219
215220
Returns
216221
-------
@@ -221,6 +226,7 @@ def sky_diffuse_passias(masking_angle):
221226
--------
222227
masking_angle
223228
masking_angle_passias
229+
bifacial.utils.vf_row_sky_2d_integ
224230
225231
References
226232
----------

0 commit comments

Comments
 (0)