# -*- coding: utf-8 -*-
"""
Created on Tue Sep 13 15:50:52 2016
@author: Hector Nieto (hector.nieto@ica.csic.es)
DESCRIPTION
===========
This package contains the main routines for estimating the wind profile above and within a canopy.
It requires the following package.
* :doc:`MO_similarity` for the estimation of adiabatic correctors.
Wind profile functions
----------------------
* :func:`calc_u_C` [Norman1995]_ canopy wind speed.
* :func:`calc_u_C_star` MOST canopy wind speed.
* :func:`calc_u_Goudriaan` [Goudriaan1977]_ wind speed profile below the canopy.
* :func:`calc_A_Goudriaan` [Goudriaan1977]_ wind attenuation coefficient below the canopy.
"""
import numpy as np
from . import MO_similarity as MO
#==============================================================================
# List of constants used in wind_profile
#==============================================================================
# Drag coefficient (Goudriaan 1977)
c_d = 0.2
# Relative turbulence intensity (Goudriaan 1977)
i_w = 0.5
# Von Karman constant
KARMAN = 0.41
# Size of the normalized height bins in Massman wind profile
BIN_SIZE = 0.0001
[docs]def calc_u_C(u_friction, h_C, d_0, z_0M):
'''[Norman1995]_ wind speed at the canopy, reformulated to use u_friction
Parameters
----------
u_friction : float
Wind friction velocity (m s-1).
h_C : float
canopy height (m).
d_0 : float
zero-plane displacement height.
z_0M : float
aerodynamic roughness length for momentum transport (m).
Returns
-------
u_C : float
wind speed at the canop interface (m s-1).
References
----------
.. [Norman1995] J.M. Norman, W.P. Kustas, K.S. Humes, Source approach for estimating
soil and vegetation energy fluxes in observations of directional radiometric
surface temperature, Agricultural and Forest Meteorology, Volume 77, Issues 3-4,
Pages 263-293,
http://dx.doi.org/10.1016/0168-1923(95)02265-Y.
'''
# The original equation below has been refolmulated to use u_friction:
# u_C = u * log((h_C - d_0) / z_0M)/(log ((z_u - d_0) / z_0M)- Psi_M)
u_C = np.log((h_C - d_0) / z_0M) * u_friction / KARMAN
return np.asarray(u_C)
[docs]def calc_u_C_star(u_friction, h_C, d_0, z_0M, L=float('inf')):
''' MOST wind speed at the canopy
Parameters
----------
u_friction : float
friction velocity (m s-1).
h_C : float
canopy height (m).
d_0 : float
zero-plane displacement height.
z_0M : float
aerodynamic roughness length for momentum transport (m).
L : float, optional
Monin-Obukhov length (m).
Returns
-------
u_C : float
wind speed at the canop interface (m s-1).
'''
Psi_M = MO.calc_Psi_M((h_C - d_0) / L)
Psi_M0 = MO.calc_Psi_M(z_0M / L)
# calcualte u_C, wind speed at the top of (or above) the canopy
u_C = (u_friction * (np.log((h_C - d_0) / z_0M) - Psi_M + Psi_M0)) / KARMAN
return np.asarray(u_C)
[docs]def calc_u_Goudriaan(u_C, h_C, LAI, leaf_width, z):
'''Estimates the wind speed at a given height below the canopy.
Parameters
----------
U_C : float
Windspeed at the canopy interface (m s-1).
h_C : float
canopy height (m).
LAI : float
Efective Leaf (Plant) Area Index.
leaf_width : float
effective leaf width size (m).
z : float
heigh at which the windsped will be estimated.
Returns
-------
u_z : float
wind speed at height z (m s-1).
References
----------
.. [Norman1995] J.M. Norman, W.P. Kustas, K.S. Humes, Source approach for estimating
soil and vegetation energy fluxes in observations of directional radiometric
surface temperature, Agricultural and Forest Meteorology, Volume 77, Issues 3-4,
Pages 263-293,
http://dx.doi.org/10.1016/0168-1923(95)02265-Y.
.. [Goudriaan1977] Goudriaan (1977) Crop micrometeorology: a simulation study
'''
# extinction factor for wind speed
a = calc_A_Goudriaan(h_C, LAI, leaf_width)
del LAI, leaf_width
u_z = u_C * np.exp(-a * (1.0 - (z / h_C))) # Eq. 4.48 in Goudriaan 1977
return np.asarray(u_z)
[docs]def calc_A_Goudriaan(h_C, LAI, leaf_width):
''' Estimates the extinction coefficient factor for wind speed
Parameters
----------
h_C : float
canopy height (m)
LAI : float
Efective Leaf (Plant) Area Index
leaf_width : float
effective leaf width size (m)
Returns
-------
a : float
exctinction coefficient for wind speed through the canopy
References
----------
.. [Goudriaan1977] Goudriaan (1977) Crop micrometeorology: a simulation study
'''
# Equation in Norman et al. 1995
k3_prime = 0.28
a = k3_prime * LAI**(2. / 3.) * h_C**(1. / 3.) * leaf_width**(-1. / 3.)
return np.asarray(a)
[docs]def calc_u_Massman(u_c, h_c, lai, z, canopy_distribution, xi_soil=0.0001, c_d=0.2):
'''' Canopy wind speed. From Eq. 11 of [Massman2017]_ and implemented in TSEB by
[Nieto2019]_.
Parameters
----------
u_c : float
Wind speed at the top of the canopy.
h_c : float
canopy height
lai : float
Leaf Area Index
z : float
height above the ground
canopy_distribution : array_like
relative cummulative canopy distribution function
xi_soil : float
ground surface roughness length. Default = 0.00101m.
c_d : float
Equivalent drag coefficient of the individual foliage elements. Default = 0.2.
Returns
-------
u_z : float
Canopy wind speed.
References
----------
.. [Nieto2019] Nieto, HĂ©ctor, et al.
"Impact of different within-canopy wind attenuation formulations on
modelling sensible heat flux using TSEB."
Irrigation Science 37.3 (2019): 315-331.
https://doi.org/10.1007/s00271-018-0611-y
.. [Massman2017] W. J. Massman, J. M. Forthofer, M. A. Finney. An Improved
Canopy Wind Model for Predicting Wind Adjustment Factors
and Wildland Fire Behavior, Canadian Journal of Forest Research,
Pages 594-603, http://dx.doi.org/10.1139/cjfr-2016-0354
'''
u_c, h_c, lai, z = map(np.asarray, [u_c, h_c, lai, z])
U_b = calc_U_b(z, h_c, xi_soil) # Eq.6
U_t = calc_U_t(z, lai, h_c, canopy_distribution, xi_soil, c_d_equiv=c_d) #
# Eq. 7
u_z = u_c * U_b * U_t
return u_z
[docs]def calc_U_b(z, h_c, xi_soil=0.0025):
'''' Logarithmic wind profile. Dominant near the ground
From Eq. 6 of [Massman2017]_.
Parameters
----------
z : float
height above the ground
h_c : float
canopy height
xi_soil : float
ground surface roughness length. Default = 0.00101m.
Returns
-------
U_b : float
Non dimensional logarithmic wind profile.
References
----------
.. [Massman2017] W. J. Massman, J. M. Forthofer, M. A. Finney. An Improved
Canopy Wind Model for Predicting Wind Adjustment Factors
and Wildland Fire Behavior, Canadian Journal of Forest Research,
Pages 594-603, http://dx.doi.org/10.1139/cjfr-2016-0354
'''
z = np.asarray(z)
h_c = np.asarray(h_c)
z0_soil = xi_soil * h_c
u_b = np.zeros(z0_soil.shape)
u_b[z > z0_soil] = (np.log(z[z > z0_soil] / z0_soil[z > z0_soil]) /
np.log(h_c[z > z0_soil] / z0_soil[z > z0_soil]))
return u_b
[docs]def calc_U_t(z, lai, h_c, canopy_distribution, xi_soil=0.0025, c_d_equiv=0.2):
'''' hyperbolic cosine wind profile. Dominant near the top of the canopy
From Eq. 7 of [Massman2017]_.
Parameters
----------
z : float
height above the ground
lai : float
Leaf Area Index
h_c : float
canopy height
canopy_distribution : array_like
relative cummulative canopy distribution function
xi_soil : float
ground surface roughness length. Default = 0.00101m.
c_d_equiv : float
Equivalent drag coefficient of the individual foliage elements. Default = 0.2.
Returns
-------
u_t : float
Non dimensional hyperbolic cosine wind profile.
References
----------
.. [Massman2017] W. J. Massman, J. M. Forthofer, M. A. Finney. An Improved
Canopy Wind Model for Predicting Wind Adjustment Factors
and Wildland Fire Behavior, Canadian Journal of Forest Research,
Pages 594-603, http://dx.doi.org/10.1139/cjfr-2016-0354
'''
upper_limit = z / h_c
zeta_h = drag_area_index(lai, c_d_equiv=c_d_equiv)
zeta_xi = cummulative_drag_area(lai, canopy_distribution, upper_limit,
c_d_equiv=c_d_equiv)
u_star_ratio = calc_u_star_ratio(zeta_h, xi_soil)
c_surf = 2.0 * u_star_ratio ** 2 # Eq. 9
n = zeta_h / c_surf # Eq. 8
u_t = np.cosh(n * zeta_xi / zeta_h) / np.cosh(n)
return u_t
[docs]def calc_u_star_ratio(zeta_h, xi_0_soil):
''' Ratio of friction velocity and wind speed at the canopy height.
From Eq. 10 of [Massman2017]_.
Parameters
----------
zeta_h : float or array
Drag area index
xi_0_soil : float or array
ground surface roughness length. Default = 0.00101m.
Returns
-------
u_star_ratio : float or array
Ratio of friction velocity and wind speed at the canopy height.
References
----------
.. [Massman2017] W. J. Massman, J. M. Forthofer, M. A. Finney. An Improved
Canopy Wind Model for Predicting Wind Adjustment Factors
and Wildland Fire Behavior, Canadian Journal of Forest Research,
Pages 594-603, http://dx.doi.org/10.1139/cjfr-2016-0354
'''
c1 = 0.38
c3 = 15.0
c2 = c1 + KARMAN / np.log(xi_0_soil)
u_star_ratio = c1 - c2 * np.exp(-c3 * zeta_h) # Eq 10.
return u_star_ratio
[docs]def cummulative_drag_area(lai, foliage_distribution, upper_limit, c_d_equiv=0.2):
''' Cummulative drag area below a normzalized height,
from Eq. 4 or 5 in [Massman2017]_.
Parameters
----------
lai : array_like
Leaf Area Index
foliage_distribution : array_like
cummulative canopy distribution function
upper_limit : array_like
Upper heigh normalized value below which the drag area drag_area_distribution
will be computed. Default=1, i.e. top of the canopy.
c_d_equiv : float
drag coefficient Cd described in Eq. 3 of [MassmanXX]_.
Default 0.2, 0, 0
Returns
-------
zeta_xi : float
Cummulative drag area. By default returns the drag area index,
see Eq. 4 of [MassmanXX]_.
References
----------
.. [Massman2017] W. J. Massman, J. M. Forthofer, M. A. Finney. An Improved
Canopy Wind Model for Predicting Wind Adjustment Factors
and Wildland Fire Behavior, Canadian Journal of Forest Research,
Pages 594-603, http://dx.doi.org/10.1139/cjfr-2016-0354
'''
upper_limit = np.asarray(upper_limit)
upper_limit[upper_limit < 0] = 0
upper_limit[upper_limit > 1] = 1
upper_limit = upper_limit / BIN_SIZE
upper_limit = np.round(upper_limit).astype(np.int32)
zeta_xi = lai * c_d_equiv * foliage_distribution[upper_limit - 1]
return np.asarray(zeta_xi)
[docs]def drag_area_index(lai, c_d_equiv=0.2):
''' Cummulative drag area below a normzalized height,
from Eq. 4 or 5 in [Massman2017]_.
Parameters
----------
lai : float or array
Leaf Area Index
c_d_equiv : float
drag coefficient Cd described in Eq. 3 of [MassmanXX]_.
Default 0.2, 0, 0
Returns
-------
Zeta_h : float or array
Cummulative drag area. By default returns the drag area index,
see Eq. 4 of [MassmanXX]_.
References
----------
.. [Massman2017] W. J. Massman, J. M. Forthofer, M. A. Finney. An Improved
Canopy Wind Model for Predicting Wind Adjustment Factors
and Wildland Fire Behavior, Canadian Journal of Forest Research,
Pages 594-603, http://dx.doi.org/10.1139/cjfr-2016-0354
'''
zeta_h = lai * c_d_equiv
return zeta_h
[docs]def calc_cummulative_canopy_distribution(f_a):
'''Calculates the non-dimensional cummulative canopy distribution.
From Eq. 1 in [Massman2017]_.
Parameters
----------
f_a : float
Non-dimensional canopy distribution at a normalized height.
Returns
-------
f_a : float
cummulative canopy density.
References
----------
.. [Massman2017] W. J. Massman, J. M. Forthofer, M. A. Finney. An Improved
Canopy Wind Model for Predicting Wind Adjustment Factors
and Wildland Fire Behavior, Canadian Journal of Forest Research,
Pages 594-603, http://dx.doi.org/10.1139/cjfr-2016-0354
'''
f_a = np.asarray(f_a).reshape(-1)
f_a_cum = np.zeros(f_a.shape)
for i in range(np.size(f_a)):
f_a_cum[i] = (np.sum(f_a[:i + 1]))
return f_a_cum
[docs]def calc_canopy_distribution(Xi_max, sigma_u, sigma_l):
'''Calculates the non-dimensional canopy distribution at a normalized height.
From Eq. 1 in [Massman2017]_.
Parameters
----------
Xi_max : float
Value of the peak distribution.
sigma_u : float
upper standard deviation.
sigma_l : float
lower standard deviation.
Returns
-------
f_a : float
non-dimensional foliage density at a normalized height Xi.
References
----------
.. [Massman2017] W. J. Massman, J. M. Forthofer, M. A. Finney. An Improved
Canopy Wind Model for Predicting Wind Adjustment Factors
and Wildland Fire Behavior, Canadian Journal of Forest Research,
Pages 594-603, http://dx.doi.org/10.1139/cjfr-2016-0354
'''
f_a = assimetrical_gaussian_distribution(Xi_max, sigma_u, sigma_l)
f_a = f_a / np.sum(f_a)
return f_a
[docs]def assimetrical_gaussian_distribution(Xi_max, sigma_u, sigma_l, upper_Xi=1):
''' Double assimetrical Gaussian distribution function.
From Eq. 2 of [Massman2017]_.
Parameters
----------
Xi_max : float
Value of the peak distribution.
sigma_u : float
upper standard deviation.
sigma_l : float
lower standard deviation.
upper_Xi : float
Upper heigh normalized value below which the density distribution
will be computed. Default=1, i.e. top of the canopy.
Returns
-------
f_a : array
Distribution function at equidisitant bins between 0 and upper_Xi.
References
----------
.. [Massman2017] W. J. Massman, J. M. Forthofer, M. A. Finney. An Improved
Canopy Wind Model for Predicting Wind Adjustment Factors
and Wildland Fire Behavior, Canadian Journal of Forest Research,
Pages 594-603, http://dx.doi.org/10.1139/cjfr-2016-0354
'''
heights = np.arange(0, upper_Xi, BIN_SIZE)
f_a = np.zeros(heights.shape)
upper_dist = np.logical_and(heights >= Xi_max, heights <= 1)
f_a[upper_dist] = np.exp(-(heights[upper_dist] - Xi_max) ** 2 / sigma_u ** 2)
f_a[~upper_dist] = np.exp(-(Xi_max - heights[~upper_dist]) ** 2 / sigma_l ** 2)
return f_a
[docs]def canopy_shape(h_c, h_b, h_max=0.5):
''' Asymmetrical Gaussian foliage distribution.
Parameters
----------
h_c : float
Top of the canopy height
h_b : float
Height of the first living branch.
h_max: float
Relative position between h_c and h_b where the maximum foliage density occurs,
default=0-5, i.e. peak occurs at the middle of the canopy (~spherical canopy)
Returns
-------
Xi_max : float
Value of the peak distribution
sigma_u : float
upper standard deviation.
sigma_l : float
lower standard deviation.
References
----------
.. [Massman2017] W. J. Massman, J. M. Forthofer, M. A. Finney. An Improved
Canopy Wind Model for Predicting Wind Adjustment Factors
and Wildland Fire Behavior, Canadian Journal of Forest Research,
Pages 594-603, http://dx.doi.org/10.1139/cjfr-2016-0354
'''
# Use relative units
xi_max = (h_max * (h_c - h_b) + h_b) / h_c
h_b = h_b / h_c
# Lower standar deviation
sigma_l = (xi_max - h_b) / 2.0
# Uper standar deviation
sigma_u = (1.0 - xi_max) / 2.0
return xi_max, sigma_u, sigma_l