Skip to content

Implement iam.schlick, iam.schlick_diffuse #1562

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4911f16
initial code from Yu Xie
kandersolar Sep 29, 2022
d2c0758
edits for pvlib style
kandersolar Sep 29, 2022
bd0563a
API and whatsnew entries
kandersolar Sep 29, 2022
82ef3bb
tests
kandersolar Sep 29, 2022
f89cfb0
add a comment
kandersolar Sep 29, 2022
dfee454
add notes section
kandersolar Sep 30, 2022
51b5f01
Apply suggestions from code review
kandersolar Sep 30, 2022
ecebb05
other changes from review
kandersolar Sep 30, 2022
9644569
add iam.schlick
kandersolar Oct 7, 2022
5aa17b5
revise iam.fedis
kandersolar Oct 7, 2022
d35d57d
edits
kandersolar Oct 7, 2022
920305a
Update pv_modeling.rst
kandersolar Oct 10, 2022
bb7276e
clean up
kandersolar Oct 10, 2022
c1bbf35
better default behavior for n_ref
kandersolar Oct 10, 2022
b7704c3
Apply suggestions from code review
kandersolar Oct 10, 2022
5d22460
split up schlick/schlick_diffuse/fedis/fedis_diffuse
kandersolar Oct 14, 2022
70ac60c
Apply suggestions from code review
kandersolar Oct 14, 2022
948c8b3
follow up
kandersolar Oct 14, 2022
deded0d
use iam.physical in iam.fedis
kandersolar Oct 17, 2022
ebcf1f6
Apply suggestions from code review
kandersolar Oct 28, 2022
a7d4196
better comments, variable name
kandersolar Oct 28, 2022
4131bcf
Merge remote-tracking branch 'upstream/master' into iam.fedis
kandersolar Oct 28, 2022
1e3b886
revise docstrings
kandersolar Oct 31, 2022
78085c3
Merge remote-tracking branch 'upstream/master' into iam.fedis
kandersolar Oct 31, 2022
ae1fa18
clean up 0.9.4 whatsnew, include in whatsnew index
kandersolar Oct 31, 2022
c6f4a3c
fix typo
kandersolar Oct 31, 2022
65aad1c
Merge remote-tracking branch 'upstream/main' into iam.fedis
kandersolar Nov 16, 2022
0c87df5
Apply suggestions from code review
kandersolar Nov 16, 2022
4f3afed
Merge branch 'iam.fedis' of github.com:kanderso-nrel/pvlib-python int…
kandersolar Nov 16, 2022
db27aa1
stickler
kandersolar Nov 16, 2022
a6ec2d0
fix missed variable rename
kandersolar Nov 16, 2022
39a28e2
remove fedis functions
kandersolar Nov 17, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/sphinx/source/reference/pv_modeling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ Incident angle modifiers
iam.interp
iam.marion_diffuse
iam.marion_integrate
iam.schlick
iam.schlick_diffuse
iam.fedis
iam.fedis_diffuse

PV temperature models
---------------------
Expand Down
11 changes: 10 additions & 1 deletion docs/sphinx/source/whatsnew/v0.9.4.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ Deprecations
Enhancements
~~~~~~~~~~~~
* Multiple code style issues fixed that were reported by LGTM analysis. (:issue:`1275`, :pull:`1559`)
* Added two direct IAM models :py:func:`pvlib.iam.schlick` and :py:func:`pvlib.iam.fedis`,
both of which can be used with :py:func:`~pvlib.iam.marion_diffuse` (:pull:`1562`, :issue:`1564`)
* Added two diffuse IAM models :py:func:`pvlib.iam.schlick_diffuse` and
:py:func:`pvlib.iam.fedis_diffuse` (:pull:`1562`)


Bug fixes
~~~~~~~~~
Expand All @@ -34,4 +39,8 @@ Requirements

Contributors
~~~~~~~~~~~~
* Christian Orner (:ghuser:`chrisorner`)
* Christian Orner (:ghuser:`chrisorner`)
* Yu Xie (:ghuser:`xieyupku`)
* Anton Driesse (:ghuser:`adriesse`)
* Cliff Hansen (:ghuser:`cwhanse`)
* Kevin Anderson (:ghuser:`kanderso-nrel`)
256 changes: 255 additions & 1 deletion pvlib/iam.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ def marion_diffuse(model, surface_tilt, **kwargs):
----------
model : str
The IAM function to evaluate across solid angle. Must be one of
`'ashrae', 'physical', 'martin_ruiz', 'sapm'`.
`'ashrae', 'physical', 'martin_ruiz', 'sapm', 'schlick', 'fedis'`.

surface_tilt : numeric
Surface tilt angles in decimal degrees.
Expand Down Expand Up @@ -592,6 +592,8 @@ def marion_diffuse(model, surface_tilt, **kwargs):
'ashrae': ashrae,
'sapm': sapm,
'martin_ruiz': martin_ruiz,
'schlick': schlick,
'fedis': fedis,
}

try:
Expand Down Expand Up @@ -748,3 +750,255 @@ def marion_integrate(function, surface_tilt, region, num=None):
Fd = pd.Series(Fd, surface_tilt.index)

return Fd


def schlick(aoi):
"""
Determine incidence angle modifier (IAM) using the Schlick approximation
to the Fresnel equations.

The Schlick approximation was proposed in [1]_ as a computationally
efficient alternative to computing the Fresnel factor in computer
graphics contexts. This implementation is a normalized form of the
equation in [1]_ so that it can be used as a PV IAM model.
Unlike other IAM models, this model has no ability to describe
different reflection profiles.

In PV contexts, the Schlick approximation has been used as an analytically
integrable alternative to the Fresnel equations for estimating IAM
for diffuse irradiance [2]_.

Parameters
----------
aoi : numeric
The angle of incidence (AOI) between the module normal vector and the
sun-beam vector. Angles of nan will result in nan. [degrees]

Returns
-------
iam : numeric
The incident angle modifier

References
----------
.. [1] Schlick, C. An inexpensive BRDF model for physically-based
rendering. Computer graphics forum 13 (1994).

.. [2] Xie, Y., M. Sengupta, A. Habte, A. Andreas, "The 'Fresnel Equations'
for Diffuse radiation on Inclined photovoltaic Surfaces (FEDIS)",
Renewable and Sustainable Energy Reviews, vol. 161, 112362. June 2022.
:doi:`10.1016/j.rser.2022.112362`

See Also
--------
pvlib.iam.fedis
pvlib.iam.schlick_diffuse
"""
iam = 1 - (1 - cosd(aoi)) ** 5
iam = np.where(np.abs(aoi) >= 90.0, 0.0, iam)

# preserve input type
if np.isscalar(aoi):
iam = iam.item()
elif isinstance(aoi, pd.Series):
iam = pd.Series(iam, aoi.index)

return iam


def schlick_diffuse(surface_tilt):
"""
Determine the incidence angle modifiers (IAM) for diffuse sky and
ground-reflected irradiance on a tilted surface using the Schlick
incident angle model.

The diffuse iam values are calculated using an analytical integration
of the Schlick equation [1]_ over the portion of an isotropic sky and
isotropic foreground that is visible from the tilted surface [2]_.

Parameters
----------
surface_tilt : numeric
Surface tilt angle measured from horizontal (e.g. surface facing
up = 0, surface facing horizon = 90). [degrees]

Returns
-------
iam_sky : numeric
The incident angle modifier for sky diffuse

iam_ground : numeric
The incident angle modifier for ground-reflected diffuse

References
----------
.. [1] Schlick, C. An inexpensive BRDF model for physically-based
rendering. Computer graphics forum 13 (1994).

.. [2] Xie, Y., M. Sengupta, A. Habte, A. Andreas, "The 'Fresnel Equations'
for Diffuse radiation on Inclined photovoltaic Surfaces (FEDIS)",
Renewable and Sustainable Energy Reviews, vol. 161, 112362. June 2022.
:doi:`10.1016/j.rser.2022.112362`

See Also
--------
pvlib.iam.schlick
pvlib.iam.fedis_diffuse
"""
# these calculations are as in [2]_, but with the refractive index
# weighting coefficient w set to 1.0 (so it is omitted)

# relative transmittance of sky diffuse radiation by PV cover:
cosB = cosd(surface_tilt)
sinB = sind(surface_tilt)
cuk = (2 / (np.pi * (1 + cosB))) * (
(30/7)*np.pi - (160/21)*np.radians(surface_tilt) - (10/3)*np.pi*cosB
+ (160/21)*cosB*sinB - (5/3)*np.pi*cosB*sinB**2 + (20/7)*cosB*sinB**3
- (5/16)*np.pi*cosB*sinB**4 + (16/105)*cosB*sinB**5
) # Eq 4 in [2]

# relative transmittance of ground-reflected radiation by PV cover:
with np.errstate(divide='ignore', invalid='ignore'): # Eq 6 in [2]
cug = 40 / (21 * (1 - cosB)) - (1 + cosB) / (1 - cosB) * cuk

cug = np.where(surface_tilt < 1e-6, 0, cug)

# respect input types:
if np.isscalar(surface_tilt):
cuk = cuk.item()
cug = cug.item()
elif isinstance(surface_tilt, pd.Series):
cuk = pd.Series(cuk, surface_tilt.index)
cug = pd.Series(cug, surface_tilt.index)

return cuk, cug


def fedis(aoi, n=1.5, n_ref=None):
"""
Determine the incidence angle modifier (IAM) for direct irradiance
using the FEDIS transmittance model.

Note that FEDIS [1]_ calculates direct IAM using the Fresnel equations
without extinction, thus in the default case of ``n_ref=None``, this is
equivalent to calling :py:func:`physical` with ``K=0``.

Parameters
----------
aoi : numeric
Angle of incidence. [degrees]

n : float, default 1.5
Refractive index of the PV front surface material. The default value
of 1.5 was used for an IMT reference cell in [1]_. [unitless]

n_ref : float, optional
Reference refractive index. If None (default), set equal to ``n``.
In [1]_ ``n_ref`` was set to 1.4585 for
a fused silica dome over a CMP22, but in conventional
PV applications it is appropriate to set ``n_ref=n`` (the default
behavior).

Returns
-------
iam : numeric
The incident angle modifier

References
----------
.. [1] Xie, Y., M. Sengupta, A. Habte, A. Andreas, "The 'Fresnel Equations'
for Diffuse radiation on Inclined photovoltaic Surfaces (FEDIS)",
Renewable and Sustainable Energy Reviews, vol. 161, 112362. June 2022.
:doi:`10.1016/j.rser.2022.112362`

See Also
--------
pvlib.iam.physical
"""
iam_physical = physical(aoi, n, K=0, L=0)

if n_ref is None:
return iam_physical

else:
# reflectance for normal incidence with refractive index n:
rd0 = ((n - 1) / (n + 1)) ** 2

# reflectance for normal incidence with refractive index n_ref:
r0 = ((n_ref - 1) / (n_ref + 1)) ** 2

# weighting function
w = (1 - rd0) / (1 - r0)

return w * iam_physical


def fedis_diffuse(surface_tilt, n=1.5, n_ref=None):
"""
Determine the incidence angle modifiers (IAM) for diffuse sky and
and ground-reflected radiation using the FEDIS transmittance model.

The "Fresnel Equations" for Diffuse radiation on Inclined photovoltaic
Surfaces (FEDIS) [1]_ is the result of analytical integration
the Schlick approximation [2]_ to the Fresnel equations.

Parameters
----------
surface_tilt : numeric
Surface tilt angle measured from horizontal (e.g. surface facing
up = 0, surface facing horizon = 90). [degrees]

n : float, default 1.5
Refractive index of the PV front surface material. The default value
of 1.5 was used for an IMT reference cell in [1]_. [unitless]

n_ref : float, optional
Reference refractive index. If None (default), set equal to ``n``.
In [1]_ ``n_ref`` was set to 1.4585 for
a fused silica dome over a CMP22, but in conventional
PV applications it is appropriate to set ``n_ref=n`` (the default
behavior).

Returns
-------
iam_sky : numeric
The incident angle modifier for sky diffuse

iam_ground : numeric
The incident angle modifier for ground-reflected diffuse

Notes
-----
This implementation corrects a typo in [1]_ regarding the sign
of the last polynomial term in Equation 5.

References
----------
.. [1] Xie, Y., M. Sengupta, A. Habte, A. Andreas, "The 'Fresnel Equations'
for Diffuse radiation on Inclined photovoltaic Surfaces (FEDIS)",
Renewable and Sustainable Energy Reviews, vol. 161, 112362. June 2022.
:doi:`10.1016/j.rser.2022.112362`

.. [2] Schlick, C. An inexpensive BRDF model for physically-based
rendering. Computer graphics forum 13 (1994).

See Also
--------
pvlib.iam.schlick_diffuse
"""
if n_ref is None:
n_ref = n

cuk, cug = schlick_diffuse(surface_tilt)

# weighting function
term1 = n*(n_ref+1)**2 / (n_ref*(n+1)**2)
# note: the last coefficient here differs in sign from the reference
polycoeffs = [2.77526e-09, 3.74953, -5.18727, 3.41186, -1.08794, 0.136060]
term2 = np.polynomial.polynomial.polyval(n, polycoeffs)
w = term1 * term2 # Eq 5

cuk = cuk * w
cug = cug * w

return cuk, cug
Loading