Skip to content

Commit 1ea8ee5

Browse files
IoannisSifnaioskandersolarAdamRJensenechedey-ls
authored
Add albedo function for inland water bodies (#2079)
* Albedo function * fixed test tolerance * fix linter * changed format of function description * update watsnew * Update test_albedo.py * Update test_albedo.py * Update pvlib/albedo.py Co-authored-by: Kevin Anderson <[email protected]> * Update pvlib/albedo.py Update table format Co-authored-by: Kevin Anderson <[email protected]> * Update pvlib/albedo.py Co-authored-by: Adam R. Jensen <[email protected]> * Reviewers' comments * Reviewer's comments vol.2 * Update v0.11.0.rst * fixed linter * fixed linter vol.2 * Added test raising a ValueError * Update pvlib/albedo.py Co-authored-by: Adam R. Jensen <[email protected]> * Update pvlib/albedo.py Co-authored-by: Adam R. Jensen <[email protected]> * Update pvlib/albedo.py Co-authored-by: Adam R. Jensen <[email protected]> * More review comments * Update pvlib/albedo.py Co-authored-by: Kevin Anderson <[email protected]> * Reviewers' comments vol.3 * Update pvlib/albedo.py Co-authored-by: Echedey Luis <[email protected]> * Update test_albedo.py * fixed linter * now I actually fixed linter * Reviewers' comments vol. 4 * renaming tests * Update pvlib/albedo.py Co-authored-by: Echedey Luis <[email protected]> * Update albedo.py --------- Co-authored-by: Kevin Anderson <[email protected]> Co-authored-by: Adam R. Jensen <[email protected]> Co-authored-by: Echedey Luis <[email protected]>
1 parent 1f36160 commit 1ea8ee5

File tree

6 files changed

+248
-0
lines changed

6 files changed

+248
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.. currentmodule:: pvlib
2+
3+
Albedo
4+
------
5+
6+
.. autosummary::
7+
:toctree: ../generated/
8+
9+
albedo.inland_water_dvoracek

docs/sphinx/source/reference/irradiance/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ Irradiance
1111
transposition
1212
decomposition
1313
clearness-index
14+
albedo

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ Enhancements
2828
shade perpendicular to ``axis_azimuth``. The function is applicable to both
2929
fixed-tilt and one-axis tracking systems.
3030
(:issue:`1689`, :pull:`1725`, :pull:`1962`)
31+
* Add function :py:func:`pvlib.albedo.inland_water_dvoracek`, to calculate the
32+
albedo for inland water bodies.
33+
(:pull:`2079`)
3134
* Added conversion functions from spectral response ([A/W]) to quantum
3235
efficiency ([unitless]) and vice versa. The conversion functions are
3336
:py:func:`pvlib.spectrum.sr_to_qe` and :py:func:`pvlib.spectrum.qe_to_sr`
@@ -55,4 +58,5 @@ Contributors
5558
* Cliff Hansen (:ghuser:`cwhanse`)
5659
* Mark Mikofski (:ghuser:`mikofski`)
5760
* Siddharth Kaul (:ghuser:`k10blogger`)
61+
* Ioannis Sifnaios (:ghuser:`IoannisSifnaios`)
5862
* Mark Campanelli (:ghuser:`markcampanelli`)

pvlib/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# list spectrum first so it's available for atmosphere & pvsystem (GH 1628)
55
spectrum,
66

7+
albedo,
78
atmosphere,
89
bifacial,
910
clearsky,

pvlib/albedo.py

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
"""
2+
The ``albedo`` module contains functions for modeling albedo.
3+
"""
4+
5+
from pvlib.tools import sind
6+
import numpy as np
7+
import pandas as pd
8+
9+
10+
WATER_COLOR_COEFFS = {
11+
'clear_water_no_waves': 0.13,
12+
'clear_water_ripples_up_to_2.5cm': 0.16,
13+
'clear_water_ripples_larger_than_2.5cm_occasional_whitecaps': 0.23,
14+
'clear_water_frequent_whitecaps': 0.3,
15+
'green_water_ripples_up_to_2.5cm': 0.22,
16+
'muddy_water_no_waves': 0.19
17+
}
18+
19+
WATER_ROUGHNESS_COEFFS = {
20+
'clear_water_no_waves': 0.29,
21+
'clear_water_ripples_up_to_2.5cm': 0.7,
22+
'clear_water_ripples_larger_than_2.5cm_occasional_whitecaps': 1.25,
23+
'clear_water_frequent_whitecaps': 2,
24+
'green_water_ripples_up_to_2.5cm': 0.7,
25+
'muddy_water_no_waves': 0.29
26+
}
27+
28+
29+
def inland_water_dvoracek(solar_elevation, surface_condition=None,
30+
color_coeff=None, wave_roughness_coeff=None):
31+
r"""
32+
Estimation of albedo for inland water bodies.
33+
34+
The available surface conditions are for inland water bodies, e.g., lakes
35+
and ponds. For ocean/open sea, see
36+
:const:`pvlib.irradiance.SURFACE_ALBEDOS`.
37+
38+
Parameters
39+
----------
40+
solar_elevation : numeric
41+
Sun elevation angle. [degrees]
42+
43+
surface_condition : string, optional
44+
If supplied, overrides ``color_coeff`` and ``wave_roughness_coeff``.
45+
``surface_condition`` can be one of the following:
46+
47+
* ``'clear_water_no_waves'``
48+
* ``'clear_water_ripples_up_to_2.5cm'``
49+
* ``'clear_water_ripples_larger_than_2.5cm_occasional_whitecaps'``
50+
* ``'clear_water_frequent_whitecaps'``
51+
* ``'green_water_ripples_up_to_2.5cm'``
52+
* ``'muddy_water_no_waves'``
53+
54+
color_coeff : float, optional
55+
Water color coefficient. [-]
56+
57+
wave_roughness_coeff : float, optional
58+
Water wave roughness coefficient. [-]
59+
60+
Returns
61+
-------
62+
albedo : numeric
63+
Albedo for inland water bodies. [-]
64+
65+
Raises
66+
------
67+
ValueError
68+
If neither of ``surface_condition`` nor a combination of
69+
``color_coeff`` and ``wave_roughness_coeff`` are given.
70+
If ``surface_condition`` and any of ``color_coeff`` or
71+
``wave_roughness_coeff`` are given. These parameters are
72+
mutually exclusive.
73+
74+
KeyError
75+
If ``surface_condition`` is invalid.
76+
77+
Notes
78+
-----
79+
The equation for calculating the albedo :math:`\rho` is given by
80+
81+
.. math::
82+
:label: albedo
83+
84+
\rho = c^{(r \cdot \sin(\alpha) + 1)}
85+
86+
Inputs to the model are the water color coefficient :math:`c` [-], the
87+
water wave roughness coefficient :math:`r` [-] and the solar elevation
88+
:math:`\alpha` [degrees]. Parameters are provided in [1]_ , and are coded
89+
for convenience in :data:`~pvlib.albedo.WATER_COLOR_COEFFS` and
90+
:data:`~pvlib.albedo.WATER_ROUGHNESS_COEFFS`. The values of these
91+
coefficients are experimentally determined.
92+
93+
+------------------------+-------------------+-------------------------+
94+
| Surface and condition | Color coefficient | Wave roughness |
95+
| | (:math:`c`) | coefficient (:math:`r`) |
96+
+========================+===================+=========================+
97+
| Clear water, no waves | 0.13 | 0.29 |
98+
+------------------------+-------------------+-------------------------+
99+
| Clear water, ripples | 0.16 | 0.70 |
100+
| up to 2.5 cm | | |
101+
+------------------------+-------------------+-------------------------+
102+
| Clear water, ripples | 0.23 | 1.25 |
103+
| larger than 2.5 cm | | |
104+
| (occasional whitecaps) | | |
105+
+------------------------+-------------------+-------------------------+
106+
| Clear water, | 0.30 | 2.00 |
107+
| frequent whitecaps | | |
108+
+------------------------+-------------------+-------------------------+
109+
| Green water, ripples | 0.22 | 0.70 |
110+
| up to 2.5cm | | |
111+
+------------------------+-------------------+-------------------------+
112+
| Muddy water, no waves | 0.19 | 0.29 |
113+
+------------------------+-------------------+-------------------------+
114+
115+
References
116+
----------
117+
.. [1] Dvoracek M.J., Hannabas B. (1990). "Prediction of albedo for use in
118+
evapotranspiration and irrigation scheduling." IN: Visions of the Future
119+
American Society of Agricultural Engineers 04-90: 692-699.
120+
"""
121+
122+
if surface_condition is not None and (
123+
color_coeff is None and wave_roughness_coeff is None
124+
):
125+
# use surface_condition
126+
color_coeff = WATER_COLOR_COEFFS[surface_condition]
127+
wave_roughness_coeff = WATER_ROUGHNESS_COEFFS[surface_condition]
128+
129+
elif surface_condition is None and not (
130+
color_coeff is None or wave_roughness_coeff is None
131+
):
132+
# use provided color_coeff and wave_roughness_coeff
133+
pass
134+
else:
135+
raise ValueError(
136+
"Either a `surface_condition` has to be chosen or"
137+
" a combination of `color_coeff` and"
138+
" `wave_roughness_coeff`.")
139+
140+
solar_elevation_positive = np.where(solar_elevation < 0, 0,
141+
solar_elevation)
142+
143+
albedo = color_coeff ** (wave_roughness_coeff *
144+
sind(solar_elevation_positive) + 1)
145+
146+
if isinstance(solar_elevation, pd.Series):
147+
albedo = pd.Series(albedo, index=solar_elevation.index)
148+
149+
return albedo

pvlib/tests/test_albedo.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import numpy as np
2+
import pandas as pd
3+
import pytest
4+
from pvlib import albedo
5+
6+
from .conftest import assert_series_equal
7+
from numpy.testing import assert_allclose
8+
9+
10+
def test_inland_water_dvoracek_default():
11+
result = albedo.inland_water_dvoracek(solar_elevation=90,
12+
color_coeff=0.13,
13+
wave_roughness_coeff=0.29)
14+
assert_allclose(result, 0.072, 0.001)
15+
16+
17+
def test_inland_water_dvoracek_negative_elevation():
18+
result = albedo.inland_water_dvoracek(solar_elevation=-60,
19+
color_coeff=0.13,
20+
wave_roughness_coeff=0.29)
21+
assert_allclose(result, 0.13, 0.01)
22+
23+
24+
def test_inland_water_dvoracek_string_surface_condition():
25+
result = albedo.inland_water_dvoracek(solar_elevation=90,
26+
surface_condition='clear_water_no_waves') # noqa: E501
27+
assert_allclose(result, 0.072, 0.001)
28+
29+
30+
def test_inland_water_dvoracek_ndarray():
31+
solar_elevs = np.array([-50, 0, 20, 60, 90])
32+
color_coeffs = np.array([0.1, 0.1, 0.2, 0.3, 0.4])
33+
roughness_coeffs = np.array([0.3, 0.3, 0.8, 1.5, 2])
34+
result = albedo.inland_water_dvoracek(solar_elevation=solar_elevs,
35+
color_coeff=color_coeffs,
36+
wave_roughness_coeff=roughness_coeffs) # noqa: E501
37+
expected = np.array([0.1, 0.1, 0.12875, 0.06278, 0.064])
38+
assert_allclose(expected, result, atol=1e-5)
39+
40+
41+
def test_inland_water_dvoracek_series():
42+
times = pd.date_range(start="2015-01-01 00:00", end="2015-01-02 00:00",
43+
freq="6h")
44+
solar_elevs = pd.Series([-50, 0, 20, 60, 90], index=times)
45+
color_coeffs = pd.Series([0.1, 0.1, 0.2, 0.3, 0.4], index=times)
46+
roughness_coeffs = pd.Series([0.1, 0.3, 0.8, 1.5, 2], index=times)
47+
result = albedo.inland_water_dvoracek(solar_elevation=solar_elevs,
48+
color_coeff=color_coeffs,
49+
wave_roughness_coeff=roughness_coeffs) # noqa: E501
50+
expected = pd.Series([0.1, 0.1, 0.12875, 0.06278, 0.064], index=times)
51+
assert_series_equal(expected, result, atol=1e-5)
52+
53+
54+
def test_inland_water_dvoracek_series_mix_with_array():
55+
times = pd.date_range(start="2015-01-01 00:00", end="2015-01-01 06:00",
56+
freq="6h")
57+
solar_elevs = pd.Series([45, 60], index=times)
58+
color_coeffs = 0.13
59+
roughness_coeffs = 0.29
60+
result = albedo.inland_water_dvoracek(solar_elevation=solar_elevs,
61+
color_coeff=color_coeffs,
62+
wave_roughness_coeff=roughness_coeffs) # noqa: E501
63+
expected = pd.Series([0.08555, 0.07787], index=times)
64+
assert_series_equal(expected, result, atol=1e-5)
65+
66+
67+
def test_inland_water_dvoracek_invalid():
68+
with pytest.raises(ValueError, match='Either a `surface_condition` has to '
69+
'be chosen or a combination of `color_coeff` and'
70+
' `wave_roughness_coeff`.'): # no surface info given
71+
albedo.inland_water_dvoracek(solar_elevation=45)
72+
with pytest.raises(KeyError, match='not_a_surface_type'): # invalid type
73+
albedo.inland_water_dvoracek(solar_elevation=45,
74+
surface_condition='not_a_surface_type')
75+
with pytest.raises(ValueError, match='Either a `surface_condition` has to '
76+
'be chosen or a combination of `color_coeff` and'
77+
' `wave_roughness_coeff`.'): # only one coeff given
78+
albedo.inland_water_dvoracek(solar_elevation=45,
79+
color_coeff=0.13)
80+
with pytest.raises(ValueError, match='Either a `surface_condition` has to '
81+
'be chosen or a combination of `color_coeff` and'
82+
' `wave_roughness_coeff`.'): # only one coeff given
83+
albedo.inland_water_dvoracek(solar_elevation=45,
84+
wave_roughness_coeff=0.29)

0 commit comments

Comments
 (0)