"""The radiation module contains functions of radiation PET methods
"""
from numpy import sqrt, log
from xarray import DataArray
from pandas import Series
from .meteo_utils import extraterrestrial_r, calc_press, calc_psy, calc_vpc, calc_lambda
from .utils import get_index, check_rad, clip_zeros, pet_out, check_rh
[docs]
def turc(tmean, rs, rh, k=0.013, clip_zero=True):
"""Potential evapotranspiration calculated according to
:cite:t:`turc_estimation_1961`.
Parameters
----------
tmean: pandas.Series or xarray.DataArray
average day temperature [°C].
rs: pandas.Series or xarray.DataArray
incoming solar radiation [MJ m-2 d-1].
rh: pandas.Series or xarray.DataArray
mean daily relative humidity [%].
k: float, optional
calibration coefficient [-].
clip_zero: bool, optional
if True, replace all negative values with 0.
Returns
-------
pandas.Series or xarray.DataArray containing the calculated
Potential evapotranspiration [mm d-1].
Examples
--------
>>> pet_turc = turc(tmean, rs, rh)
Notes
-----
Based on equation S9.10 and S9.11 in :cite:t:`mcmahon_estimating_2013`.
.. math:: PET=k(\\frac{T_{mean}}{T_{mean}+15})(23.88R_s+50)0.013;
for RH>50
.. math:: PET=k(1+\\frac{50-RH}{70})(\\frac{T_{mean}}{T_{mean}+15})
(23.88R_s+50)0.013; for RH<50
"""
c = tmean / tmean
c = c.where(check_rh(rh) >= 50, 1 + (50 - rh) / 70)
pet = k * c * tmean / (tmean + 15) * (check_rad(rs) * 23.88 + 50)
pet = clip_zeros(pet, clip_zero)
return pet_out(tmean, pet, "Turc")
[docs]
def jensen_haise(tmean, rs=None, cr=0.025, tx=-3, lat=None, method=0, clip_zero=True):
"""Potential evapotranspiration calculated accordinf to
:cite:t:`jensen_estimating_1963`.
Parameters
----------
tmean: pandas.Series orxarray.DataArray
average day temperature [°C].
rs: pandas.Series or xarray.DataArray, optional
incoming solar radiation [MJ m-2 d-1].
cr: float, optional
temperature coefficient [-].
tx: float, optional
intercept of the temperature axis [°C].
lat: float/xarray.DataArray
the site latitude [rad].
method: float, optional
0 => after :cite:t:`jensen_evaporation_2016`
1 => after :cite:t:`oudin_which_2005`.
clip_zero: bool, optional
if True, replace all negative values with 0.
Returns
-------
pandas.Series or xarray.DataArray containing the calculated potential
evapotranspiration [mm d-1].
Examples
--------
>>> pet_jh = jensen_haise(tmean, lat)
Notes
-----
Method = 0: Based on :cite:t:`jensen_evaporation_2016`.
.. math:: PET = \\frac{C_r(T_{mean}-T_x)R_s}{\\lambda}
Method = 1: Based on :cite:t:`oudin_which_2005`.
.. math:: PET = \\frac{R_a(T_{mean}+5)}{68\\lambda}
"""
lambd = calc_lambda(tmean)
if method == 0:
if rs is None:
raise Exception("If you choose method == 0, provide rs!")
pet = check_rad(rs) / lambd * cr * (tmean - tx)
elif method == 1:
if lat is None:
raise Exception("If you choose method == 1, provide lat!")
index = get_index(tmean)
ra = extraterrestrial_r(index, lat)
pet = ra * (tmean + 5) / 68 / lambd
else:
raise Exception("Method can be either 0 or 1.")
pet = clip_zeros(pet, clip_zero)
return pet_out(tmean, pet, "Jensen_Haise")
[docs]
def mcguinness_bordne(tmean, lat, k=0.0147, clip_zero=True):
"""Potential evapotranspiration calculated according to
:cite:t:`mcguinness_comparison_1972`.
Parameters
----------
tmean: pandas.Series or xarray.DataArray
average day temperature [°C].
lat: float/xarray.DataArray, optional
the site latitude [rad].
k: float, optional
calibration coefficient [-].
clip_zero: bool, optional
if True, replace all negative values with 0.
Returns
-------
pandas.Series or xarray.DataArray containing the calculated potential
evapotranspiration [mm d-1].
Examples
--------
>>> pet_mcguinness_bordne = mcguinness_bordne(tmean, lat)
Notes
-----
Based on equation 13 in :cite:t:`xu_evaluation_2000`.
.. math:: PET = k\\frac{R_a (T_{mean} + 5)}{\\lambda}
"""
lambd = calc_lambda(tmean)
index = get_index(tmean)
ra = extraterrestrial_r(index, lat)
if isinstance(tmean, DataArray) and isinstance(ra, Series):
ra = ra.values[:, None, None]
pet = k * ra * (tmean + 5) / lambd
pet = clip_zeros(pet, clip_zero)
return pet_out(tmean, pet, "Mcguinness_Bordne")
[docs]
def hargreaves(tmean, tmax, tmin, lat, k=0.0135, method=0, clip_zero=True):
"""Potential evapotranspiration calculated according to
:cite:t:`hargreaves_estimating_1982`.
Parameters
----------
tmean: pandas.Series or xarray.DataArray
average day temperature [°C].
tmax: pandas.Series or xarray.DataArray
maximum day temperature [°C].
tmin: pandas.Series or xarray.DataArray
minimum day temperature [°C].
lat: float/xarray.DataArray
the site latitude [rad].
k: float, optional
calibration coefficient [-].
method: float, optional
0 => after :cite:t:`jensen_evaporation_2016`
1 => after :cite:t:`mcmahon_estimating_2013`.
clip_zero: bool, optional
if True, replace all negative values with 0.
Returns
-------
pandas.Series or xarray.DataArray containing the calculated potential
evapotranspiration [mm d-1].
Examples
--------
>>> pet_har = hargreaves(tmean, tmax, tmin, lat)
Notes
-----
Method = 0; Based on equation (8-16) in :cite:t:`jensen_evaporation_2016`.
.. math:: PET = k \\frac{R_a (T_{mean}+17.8)\\sqrt{(T_{max}-T_{min})}}\
{\\lambda}
Method = 1; Based on :cite:t:`mcmahon_estimating_2013`.
.. math:: PET = chs k \\frac{R_a (T_{mean}+17.8)\\sqrt{(T_{max}-T_{min})}}\
{\\lambda}
, where
.. math:: chs=0.00185*(T_{max}-T_{min})^2-0.0433*(T_{max}-T_{min})+0.4023
"""
lambd = calc_lambda(tmean)
index = get_index(tmean)
ra = extraterrestrial_r(index, lat)
if isinstance(tmean, DataArray) and isinstance(ra, Series):
ra = ra.values[:, None, None]
else:
ra = ra.values
if method == 0:
pet = k / 0.0135 * 0.0023 * (tmean + 17.8) * sqrt(tmax - tmin) * ra / lambd
elif method == 1:
chs = 0.00185 * (tmax - tmin) ** 2 - 0.0433 * (tmax - tmin) + 0.4023
pet = k * chs * sqrt(tmax - tmin) * ra / lambd * (tmean + 17.8)
else:
raise Exception("Method can be either 0 or 1.")
pet = clip_zeros(pet, clip_zero)
return pet_out(tmean, pet, "Hargreaves")
[docs]
def fao_24(
tmean, wind, rs, rh, pressure=None, elevation=None, albedo=0.23, clip_zero=True
):
"""Potential evapotranspiration calculated according to
:cite:t:`jensen_evapotranspiration_1990`.
Parameters
----------
tmean: pandas.Series or xarray.DataArray
average day temperature [°C].
wind: pandas.Series xarray.DataArray
mean day wind speed [m/s].
rs: pandas.Series xarray.DataArray
incoming solar radiation [MJ m-2 d-1].
rh: pandas.Series or xarray.DataArray
mean daily relative humidity [%].
pressure: pandas.Series or xarray.DataArray, optional
atmospheric pressure [kPa].
elevation: float/xarray.DataArray, optional
the site elevation [m].
albedo: float/xarray.DataArray, optional
surface albedo [-].
clip_zero: bool, optional
if True, replace all negative values with 0.
Returns
-------
pandas.Series or xarray.DataArray containing the calculated potential
evapotranspiration [mm d-1].
Examples
--------
>>> pet_fao24 = fao_24(tmean, wind, rs, rh, elevation=elevation)
.. math:: PE = \\frac{- 0.3 \\Delta + R_s (1-\\alpha) w}\
{\\lambda(\\Delta +\\gamma)}
.. math:: w = 1.066-0.13*\\frac{rh}{100}+0.045*u_2-0.02*\\frac{rh}{100}\
*u_2-3.15*(\\frac{rh}{100})^2-0.0011*u_2
"""
pressure = calc_press(elevation, pressure)
gamma = calc_psy(pressure)
dlt = calc_vpc(tmean)
lambd = calc_lambda(tmean)
w = (
1.066
- 0.13 * check_rh(rh) / 100
+ 0.045 * wind
- 0.02 * rh / 100 * wind
- 0.315 * (rh / 100) ** 2
- 0.0011 * wind
)
pet = -0.3 + dlt / (dlt + gamma) * check_rad(rs) * (1 - albedo) * w / lambd
pet = clip_zeros(pet, clip_zero)
return pet_out(tmean, pet, "FAO_24")
[docs]
def abtew(tmean, rs, k=0.53, clip_zero=True):
"""Potential evapotranspiration calculated according to
:cite:t:`abtew_evapotranspiration_1996`.
Parameters
----------
tmean: pandas.Series or xarray.DataArray
average day temperature [°C].
rs: pandas.Series or xarray.DataArray
incoming solar radiation [MJ m-2 d-1].
k: float, optional
calibration coefficient [-].
clip_zero: bool, optional
if True, replace all negative values with 0.
Returns
-------
pandas.Series or xarray.DataArray containing the calculated potential
evapotranspiration [mm d-1].
Examples
--------
>>> pet_abtew = abtew(tmean, rs)
Notes
-----
Based on equation 14 in :cite:t:`xu_evaluation_2000`.
.. math:: PE = \\frac{k R_s}{\\lambda}
"""
lambd = calc_lambda(tmean)
pet = k * check_rad(rs) / lambd
pet = clip_zeros(pet, clip_zero)
return pet_out(tmean, pet, "Abtew")
[docs]
def makkink(tmean, rs, pressure=None, elevation=None, k=0.65, clip_zero=True):
"""Potential evapotranspiration calculated according to
:cite:t:`makkink_testing_1957`.
Parameters
----------
tmean: pandas.Series or xarray.DataArray
average day temperature [°C].
rs: pandas.Series or xarray.DataArray
incoming solar radiation [MJ m-2 d-1].
pressure: pandas.Series or xarray.DataArray, optional
atmospheric pressure [kPa].
elevation: float/xarray.DataArray, optional
the site elevation [m].
k: float, optional
calibration coefficient [-].
clip_zero: bool, optional
if True, replace all negative values with 0.
Returns
-------
pandas.Series or xarray.DataArray containing the calculated potential
evapotranspiration [mm d-1].
Examples
--------
>>> pet_mak = makkink(tmean, rs, elevation=elevation)
Notes
-----
.. math:: PET = \\frac{0.65 \\Delta (R_s)}{\\lambda(\\Delta +\\gamma)}
"""
pressure = calc_press(elevation, pressure)
gamma = calc_psy(pressure)
dlt = calc_vpc(tmean)
lambd = calc_lambda(tmean)
pet = k * dlt / (dlt + gamma) * check_rad(rs) / lambd
pet = clip_zeros(pet, clip_zero)
return pet_out(tmean, pet, "Makkink")
[docs]
def makkink_knmi(tmean, rs, clip_zero=True):
"""Potential evapotranspiration calculated according to The Royal Netherlands
Meteorological Institute (KNMI)
Parameters
----------
tmean : pandas.Series or xarray.DataArray
average day temperature [°C].
rs : pandas.Series or xarray.DataArray
incoming solar radiation [MJ m-2 d-1].
clip_zero: bool, optional
if True, replace all negative values with 0.
Returns
-------
pandas.Series or xarray.DataArray containing the calculated potential
evapotranspiration [mm d-1].
Examples
--------
>>> pet_mak = makkink_knmi(tmean, rs)
Notes
----
This method is only applicable to the Netherlands (~sea level) due to some
emperical values. Calculating the Makkink evaporation with the original
formula is more suitable for general purposes. To obtain the same value as
EV24 round the value up to one decimal.
"""
pet = (
650
* (
1
- (0.646 + 0.0006 * tmean)
/ (
7.5
* log(10)
* 6.107
* 10 ** (7.5 * (1 - 1 / (1 + tmean / 237.3)))
/ (237.3 * (1 + tmean / 237.3) * (1 + tmean / 237.3))
+ 0.646
+ 0.0006 * tmean
)
)
/ (2501 - 2.38 * tmean)
* rs
)
pet = clip_zeros(pet, clip_zero)
return pet_out(tmean, pet, "Makkink_KNMI")
[docs]
def oudin(tmean, lat, k1=100, k2=5, clip_zero=True):
"""Potential evapotranspiration calculated according to :cite:t:`oudin_which_2005`.
Parameters
----------
tmean: pandas.Series or xarray.DataArray
average day temperature [°C].
lat: float or xarray.DataArray
the site latitude [rad].
k1: float, optional
calibration coefficient [-].
k2: float, optional
calibration coefficient [-].
clip_zero: bool, optional
if True, replace all negative values with 0.
Returns
-------
pandas.Series or xarray.DataArray containing the calculated potential
evapotranspiration [mm d-1].
clip_zero: bool, optional
if True, replace all negative values with 0.
Examples
--------
>>> pet_oudin = oudin(tmean, lat)
Notes
-----
Based on equation 3 in :cite:t:`oudin_which_2005`.
.. math:: PET = \\frac{R_a (T_{mean} +5)}{\\lambda 100}; if T_{mean}+5>0
else: PET = 0
"""
lambd = calc_lambda(tmean)
index = get_index(tmean)
ra = extraterrestrial_r(index, lat)
pet = ra * (tmean + k2) / lambd / k1
pet = pet.where((tmean + k2) >= 0, 0)
pet = clip_zeros(pet, clip_zero)
return pet_out(tmean, pet, "Oudin")