Module src.impacts.water
None
None
View Source
# -*- coding: utf-8 -*-
# Water retention related implementation.
# Based on Notebook implemenation created by Marko Petrovic
# Numerical data processing
import pandas as pd
import numpy as np
from scipy import stats
# Time series operations
import glob
from datetime import datetime
class Calibration():
"""Water retention and impact estimate related parameters setting."""
# Conversion coefficient meter to millimeter
m_to_mm = 1
# Extinction coefficient =0.7 for trees and 0.3 for shrubs (Wang et al. 2008)
kappa = 0.7
# Shade factor, is the percentage of sky covered by foliage and branches within
# the perimeter of individual tree crowns, can vary by species from about
# 60% to 95% when trees are in-leaf (McPherson, 1984).
# The value below is set according to Glasgow mean
avg_shade_factor = 0.85
# Specific leaf storage of water (sl =0.0002 m).
leaf_storage = 0.0002 * m_to_mm
# Leaf-on leaf_off transition days (Wang_et_al_2008).
leaf_transition_days = 28
# Specific impervious cover storage of water (=0.0015 m).
maximum_impervious_cover_storage = 0.0015 * m_to_mm
# Specific pervious cover storage of water (=0.001 m).
maximum_pervious_cover_storage = 0.001 * m_to_mm
def __init__(
self,
leaf_transition_days = 28,
leaf_storage = 0.0002,
pervios_storage_max = 0.0010,
impervios_storage_max = 0.0015
):
"""The constructor method.
Args:
leaf_transition_days: (:obj:`int`): Leaf-on leaf_off transition days
leaf_storage: (:obj:`float`): Specific leaf storage of water.
pervios_storage_max: (:obj:`float`): Specific pervious cover storage of water
impervios_storage_max: (:obj:`float`): Specific impervious cover storage of water
Returns:
None
Note:
TODO:
* pass optional settings as key word parameters.
"""
self.leaf_storage = leaf_storage * Calibration.m_to_mm
self.leaf_transition_days = leaf_transition_days
self.maximum_impervious_cover_storage = impervios_storage_max * Calibration.m_to_mm
self.maximum_pervious_cover_storage = pervios_storage_max * Calibration.m_to_mm
def set_surface_storage_rates(
self, leaf_storage=None,
pervios_storage_max=None,
impervios_storage_max=None):
"""Setting specific water storage rates.
Args:
leaf_storage: (:obj:`float`): Specific leaf storage of water.
pervios_storage_max: (:obj:`float`): Specific pervious cover storage of water
impervios_storage_max: (:obj:`float`): Specific impervious cover storage of water
Returns:
None
Note:
Todo:
"""
if leaf_storage:
self.leaf_storage = leaf_storage * Calibration.m_to_mm
if impervios_storage_max:
self.maximum_impervious_cover_storage = impervios_storage_max * Calibration.m_to_mm
if pervios_storage_max:
self.maximum_pervious_cover_storage = pervios_storage_max * Calibration.m_to_mm
def compute_leaf_area_index(
dbh,
tree_height,
crown_height,
crown_width,
crown_missing = 0,
shade_factor = Calibration.avg_shade_factor):
"""The function given allometrics of a tree computes its leaf, bark and plant area indices.
Args:
dbh: (:obj:`float`): the diameter in cm of the trunk usually measured at 1.3m from the ground.
tree_height: (:obj:`float`): The tree height in meters.
crown_height: (:obj:`float`): The vertical length of tree crown in meters.
crown_width: (:obj:`float`): The horizontal length (diameter) of tree crown in meters.
crown_missing: (:obj:`float`): The percentage loss of the crown.
shade_factor: (:obj:`float`): The percentage of sky covered by foliage and branches.
Returns:
(:obj:`tuple`): the tuple returns the tree indices (LAI,BAI,PAI)
Note:
The beta multipliers and the main equation is based on Nowak (1996).
TODO:
Parametrize beta multipliers.
"""
loss = crown_missing
th = tree_height
cw = crown_width
ch = crown_height
sf = shade_factor
beta_0 = -4.3309
beta_1 = 0.2942
beta_2 = 0.7312
beta_3 = 5.7217
beta_4 = 0.0148
def compute_under_canopy_area(crown_width):
return pow((crown_width/2),2) * np.pi
def compute_bark_area(dbh, tree_height, crown_height):
# * 0.01 converts DBH(cm) into meter.
return np.pi * (dbh * 0.01) * (tree_height - crown_height)
# Outer surface area estimate below is based on Gacka-Grzesikiewicz (1980).
under_canopy = compute_under_canopy_area(cw)
crown_surface = np.pi * crown_width * (crown_height + crown_width)/2
bark_area = compute_bark_area(dbh,th,ch)
leaf_area = (1-loss) * np.exp(beta_0 + beta_1 * th + beta_2 * cw + beta_3 * sf - beta_4 * crown_surface)
leaf_area_index = leaf_area / under_canopy
bark_area_index = bark_area / under_canopy
plant_area_index = leaf_area_index + bark_area_index
return (leaf_area_index, bark_area_index, plant_area_index)
def pai_seasons(x, leaf_on_start, leaf_off_start, leaf_transition_days):
"""The method updates Plant Area Index (PAI) with respect to leaf on-off seasons.
Args:
A data frame "x" with following variables:
Date_time: (:obj:`time`): date and time
BAI: Bark Area Index
LAI: Leaf Area Index
conifers: it taks value "true" if conifers and "false" otherwise
leaf_on_start: a day in the year when the leaf on season starts. In the case of Glasgow it is April 14 (day 105).
See also other sources: https://weatherspark.com/y/147740/Average-Weather-at-Glasgow-Airport-United-Kingdom-Year-Round
leaf_off_start: a day in the year when the leaf off season starts. In the case of Glasgow it is November 2 (day 307).
leaf_transition_days: the number of days that the leaf on-off transition last.
Returns:
An array of values of Plant Area Indexes (PAI) over time.
Note:
The function is built upon the following paper:
Wang, Jun, Theodore A. Endreny, and David J. Nowak. “Mechanistic Simulation of Tree
Effects in an Urban Water Balance Model 1.” JAWRA Journal of the American Water Resources
Association 44, no. 1 (February 2008): 75–85. https://doi.org/10.1111/j.1752-1688.2007.00139.x
Todo:
"""
x = x.assign(PAI = np.where(x['Conifers'], x['BAI']+x['LAI'],
np.where(x.Date_time.dt.day_of_year < leaf_on_start, x['BAI'],
np.where(((x.Date_time.dt.day_of_year >= leaf_on_start) & (x.Date_time.dt.day_of_year < leaf_off_start)),
x['LAI']/(1+np.exp(-0.37*(x.Date_time.dt.day_of_year-(leaf_on_start+leaf_transition_days/2)))) + x['BAI'],
x['LAI']/(1+np.exp(-0.37*((leaf_off_start+leaf_transition_days/2)-x.Date_time.dt.day_of_year))) + x['BAI'])))
)
return x['PAI']
def lmbd(temperature):
"""The method calculates latent heat of vaporization.
Args:
Temperature in [C]
Returns:
latent heat of vaporization in [MJ/Kg]
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 2.501-0.002361*temperature
def e_s(temperature):
"""The method calculates saturated vapor pressure.
Args:
Temperature in [C]
Returns:
Saturated vapor pressure in [kPa]
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 0.6108*np.exp(17.27*temperature/(237.3+temperature))
def e(dew_point_temperature):
"""The method calculates vapor pressure.
Args:
Dew point temperature in [C]
Returns:
Vapor pressure in [kPa]
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 0.6108*np.exp(17.27*dew_point_temperature/(237.3+dew_point_temperature))
def DELTA(temperature):
"""The method calculates the slope of vapor pressure temperature curve.
Args:
Temperature in [C]
Returns:
Slope of vapor pressure temperature curve in [kPa/C]
Note:
It includes in calculation saturated vapor pressure in [kPa] which is calculated with function e_s()!
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 4098*e_s(temperature)/(237.3+temperature)**2
def rho_a(temperature, surface_pressure):
"""The method calculates the density of air.
Args:
Temperature in [C]
Surface preasure in [kPa]
Returns:
The density of air in [kg/m^3]
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 3.486 * surface_pressure/(275+temperature)
def rho_w(temperature):
"""The method calculates the density of water.
Args:
Temperature in [C]
Returns:
The density of water in [kg/m^3]
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 999.88 + 0.018*temperature - 0.0051*temperature**2
def D(temperature, dew_point_temperature):
"""The method calculates vapor pressure deficit.
Args:
Temperature in [C]
Dew point temperature in [C]
Returns:
Vapor pressure deficit in [kPa]
Note:
It includes in calculation vapor pressure as well as saturated vapor pressure, both in [kPa], which
are calculated with functions e() e_s().
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return np.maximum(e_s(temperature)-e(dew_point_temperature),0)
def U_t(wind_speed, wind_estimate_height):
"""The method estimates wind speed at the tree top.
Args:
Measured wind speed [m/s]
Wind estimate height (tree height) [m]
Returns:
Wind speed at the tree top in [m/s]
Note:
The method is using two other parameters:
Wind measurement height Z_u (usually 10m) and roughness height for water d_w which are set as constants.
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return wind_speed*np.log(wind_estimate_height/d_w)/np.log(Z_u/d_w)
def r_a(wind_speed, wind_estimate_height, roughness_height):
"""The method calculates aerodynamic resistance.
Args:
Measured wind speed [m/s]
Wind estimate height (tree height) [m]
Roughness_height [m]
Returns:
Aerodynamic resistance in [m/s]
Note:
It includes in calculation wind speed at the tree top U_t.
If roughness height is negative, a new equation is applied to calculate aerodynamic resistance for
the evapotranspiration from the soil.
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
if roughness_height >= 0:
return 4.72*np.log(wind_estimate_height/(Z_ov*roughness_height))/(1+0.53*U_t(wind_speed, wind_estimate_height))
else:
return 208/U_t(wind_speed, wind_estimate_height)
def gamma(temperature,surface_pressure):
"""The method calculates psychrometric constant.
Args:
Temperature [C]
Surface pressure [kPa]
Returns:
Psychrometric constant in [kPA/C]
Note:
It includes in calculation latent heat of vaporization lmbd().
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
#return 10**(-3)*c_p*surface_pressure*10/(lmbd(temperature)*0.622)# pressure in mbar
return 10**(-3)*c_p*surface_pressure/(lmbd(temperature)*0.622)# pressure in kPa
def r_s(pai):
"""The method calculates stomatal resistance.
Args:
Plant area index (PAI)
Returns:
Stomatal resistance in [s/m]
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 200/pai
def C_leaf(temperature):
"""The method calculates water vapor concentration at the evaporating surfaces within the leaf.
Args:
Temperature [C]
Returns:
Water vapor concentration at the evaporating surfaces within the leaf in [g/m^3]
Note:
Temerature in celsius [C] is converted to kelvins [K] such that T(K) = T(C)+273.15.
The formula also includes saturated vapor pressure e_s() in [kPa].
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 2165*e_s(temperature)/(temperature+273.15)
def C_air(dew_point_temperature, temperature):
"""The method calculates water vapor concentration in the air.
Args:
Temperature [C]
Dew point temperature [C]
Returns:
Water vapor concentration in the air in [g/m^3]
Note:
Temerature in celsius [C] is converted to kelvins [K] such that T(K) = T(C)+273.15.
The formula also includes vapor pressure e() in [kPa].
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 2165*e(dew_point_temperature)/(temperature+273.15)
def potential_evaporation(temperature, dew_point, solar_radiation, sea_level_pressure, pai, wind_speed, wind_estimate_height, roughness_height):
"""The method calculate potential evaporation.
Args: a data frame
Returns: the updated ata frame
Note:
Todo:
"""
potential_evaporation = M_TO_MM*(1/(lmbd(temperature)*rho_w(temperature)))*(DELTA(temperature)*solar_radiation+(rho_a(temperature, sea_level_pressure)*c_p*D(temperature, dew_point))/r_a(wind_speed, wind_estimate_height, roughness_height))/(DELTA(temperature)+gamma(temperature, sea_level_pressure)*(1+(r_s(pai)/r_a(wind_speed, wind_estimate_height, roughness_height))))
return potential_evaporation
def potential_evapotranspiration(df):
"""The method calculate potential evapotranspiration.
Args: a data frame
Returns: the updated ata frame
Note:
Todo:
"""
df = df.assign(
Potential_evaporation_v = lambda x: potential_evaporation(x.Temperature, x.Dew_Point, x.Solar_Radiation, x.Sea_Level_Pressure, x.PAI, x.Wind_Speed, x.height, roughness_height_trees),
Potential_evaporation_g = lambda x: potential_evaporation(x.Temperature, x.Dew_Point, x.Solar_Radiation, x.Sea_Level_Pressure, 1 , x.Wind_Speed, 1 , roughness_height_bare_soil),
PET = lambda x: potential_evaporation(x.Temperature, x.Dew_Point, x.Solar_Radiation, x.Sea_Level_Pressure, x.PAI, x.Wind_Speed, x.height, -1),
Transpiration = lambda x: 10**(-6)*(3600/x.PAI)*np.maximum((C_leaf(x.Temperature)-C_air(x.Dew_Point, x.Temperature)),0)/(r_s(x.PAI)+r_a(x.Wind_Speed, x.height, roughness_height_trees))
)
df = df.assign(
TF_average_ratio = lambda x: np.where(((x.PET>x.Transpiration) & (x.PET>0)), x.Transpiration/x.PET, np.nan)
)
df['TF_average_ratio'] = df.groupby(['AgentID','Step'])['TF_average_ratio'].transform('mean')
df = df.assign(
Transpiration = lambda x: np.where(((x.PAI<(x.LAI+x.BAI)) | (x.Transpiration > x.PET)), x.TF_average_ratio*x.PET, x.Transpiration)
)
df = df.drop(columns='TF_average_ratio')
return df
def ped1(Date_time, Precipitation, Potential_evaporation, Maximum_storage, evp):
"""The method computes precipitation-evaporation dynamics for one type at a time, which can be trees, pervious cover, impervious cover...
Args:
Date_time [time identifier]
Precipitation [amount of water hitting the surface area of the type]
Potential_evaporation [of the type for the given weather conditions]
Maximum_storage [parameter: maximum storage of the type]
evp [evaporation coefficient for the type]
Returns:
Precipitation storage of the type for each hour.
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
df=pd.DataFrame({'Date_time':Date_time, 'Precipitation':Precipitation,
'Potential_evaporation':Potential_evaporation})
df["Storage"] = 0
df['Potential_evaporation_lag1'] = df.Potential_evaporation.shift(1).interpolate(limit_direction ='backward')
x = 0
def func2(row):
# non local variable ==> will use pre_value from the ped function
nonlocal x
new_value = new_value = np.maximum(0,(np.minimum(Maximum_storage,x) + row['Precipitation']-
np.minimum(np.minimum(Maximum_storage,x),((np.minimum(Maximum_storage,x)/
Maximum_storage)**(evp)*row['Potential_evaporation_lag1']))))
x = new_value
return new_value
# This line might throw a SettingWithCopyWarning warning
df.loc[0:,'Storage'] = df.loc[0:,:].apply(func2, axis=1)
return df["Storage"]
def ped3(df, evp_v, evp_g):
"""The method computes precipitation-evaporation dynamics for each tree as well as the impervious and pervious covers.
Args:
A data frame including the following variables:
Evaporation coefficient for trees: evp_v
Evaporation coefficient for ground: evp_g
Returns:
A data frame with new variables: Vegetation_storage, Impervious_cover_storage_v, Pervious_cover_storage_v for each hour.
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
df['Storage'] = 0
df['Potential_evaporation_v_lag1'] = df.Potential_evaporation_v.shift(1).interpolate(limit_direction ='backward')
df['Potential_evaporation_g_lag1'] = df.Potential_evaporation_g.shift(1).interpolate(limit_direction ='backward')
x = 0
y = 0
z = 0
def func2(row):
# non local variable ==> will use pre_value from the ped function
nonlocal x
nonlocal y
nonlocal z
new_value_x = np.maximum(0,(np.minimum(row['Maximum_vegetation_storage'],x) + row['Canopy_interception']-
np.minimum(np.minimum(row['Maximum_vegetation_storage'],x),((np.minimum(row['Maximum_vegetation_storage'],x)/
row['Maximum_vegetation_storage'])**(evp_v)*row['Potential_evaporation_v_lag1']))))
Precipitation_on_the_ground_with_vegetation = np.maximum(0,(new_value_x-row['Maximum_vegetation_storage']))+row['Through_canopy_precipitation']
new_value_y = np.maximum(0,(np.minimum(MAXIMUM_IMPERVIOUS_COVER_STORAGE,y) + Precipitation_on_the_ground_with_vegetation-
np.minimum(np.minimum(MAXIMUM_IMPERVIOUS_COVER_STORAGE,y),((np.minimum(MAXIMUM_IMPERVIOUS_COVER_STORAGE,y)/
MAXIMUM_IMPERVIOUS_COVER_STORAGE)**(evp_g)*row['Potential_evaporation_g_lag1']))))
new_value_z = np.maximum(0,(np.minimum(MAXIMUM_PERVIOUS_COVER_STORAGE,z) + Precipitation_on_the_ground_with_vegetation-
np.minimum(np.minimum(MAXIMUM_PERVIOUS_COVER_STORAGE,z),((np.minimum(MAXIMUM_PERVIOUS_COVER_STORAGE,z)/
MAXIMUM_PERVIOUS_COVER_STORAGE)**(evp_g)*row['Potential_evaporation_g_lag1']))))
x = new_value_x
y = new_value_y
z = new_value_z
return [new_value_x, new_value_y, new_value_z]
# This line might throw a SettingWithCopyWarning warning
df.loc[0:,'Storage'] = df.loc[0:,:].apply(func2, axis=1)
df['Vegetation_storage'] = pd.DataFrame(df['Storage'].tolist())[0]
df['Impervious_cover_storage_v'] = pd.DataFrame(df['Storage'].tolist())[1]
df['Pervious_cover_storage_v'] = pd.DataFrame(df['Storage'].tolist())[2]
df = df.drop(columns='Storage')
return df
def ecosystem_services(i):
"""The method parallelize the computation of water retention benefits.
Args: agent index "i"
Returns: water retention benefits for each agent [data frame]
Note:
Todo:
"""
output = df_scenario[tree_population.AgentID == AGENTS[i]]
output = output[['Step', 'AgentID', 'height','BAI', 'LA','LAI', 'PAI', 'Conifers', 'Under_canopy_area', 'Total_under_canopy_area','Scenario', 'Precipitation_scale',
'SAMPLE_AREA', 'IMPERVIOUS_COVER_SHARE', 'PERVIOUS_COVER_SHARE', 'POPULATION_AREA', 'POPULATION_SAMPLE_TREE_RATIO']]
output = pd.merge(output, weather_forcast, on=['Step'], how='left').sort_values(['Step', 'AgentID'])
# Calculate plant area index (PAI) in leaf-on and leaf-off seasons
output['PAI'] = pai_seasons(output[['Date_time', 'BAI', 'LAI', 'Conifers']],
Leaf_on_transition_day_start, Leaf_off_transition_day_start,
LEAF_TRANSITION_DAYS)
# Calculate potential evapotranspiration over the vegetation and ground areas
output = potential_evapotranspiration(output)
output = output.assign(
Canopy_cover_fraction = lambda x: 1-np.exp(-KAPPA*x.PAI),
Maximum_vegetation_storage = lambda x: SL*x.PAI,
Through_canopy_precipitation = lambda x: x.Precipitation*(1-x.Canopy_cover_fraction),
Canopy_interception = lambda x: x.Precipitation-x.Through_canopy_precipitation
)
output = ped3(output,
evp_v = 2/3,
evp_g = 1
)
output = output.assign(
Canopy_drip = lambda x: np.maximum(0,(x.Vegetation_storage-x.Maximum_vegetation_storage)),
Evaporation_from_vegetation = lambda x: np.maximum(0,(x.Canopy_interception-x.Canopy_drip)),
Precipitation_on_the_ground_with_vegetation = lambda x: x.Canopy_drip + x.Through_canopy_precipitation,
Vegetation_storage = lambda x: np.minimum(x.Vegetation_storage, x.Maximum_vegetation_storage),
Run_off_v = lambda x: np.maximum(0,(x.Impervious_cover_storage_v-MAXIMUM_IMPERVIOUS_COVER_STORAGE)),
Evaporation_from_impervious_cover_v = lambda x: np.maximum(0,(x.Precipitation_on_the_ground_with_vegetation-x.Run_off_v)),
Impervious_cover_storage_v = lambda x: np.minimum(x.Impervious_cover_storage_v, MAXIMUM_IMPERVIOUS_COVER_STORAGE),
Infiltration_v = lambda x: np.maximum(0,(x.Pervious_cover_storage_v-MAXIMUM_PERVIOUS_COVER_STORAGE)),
Evaporation_from_pervious_cover_v = lambda x: np.maximum(0,(x.Precipitation_on_the_ground_with_vegetation-x.Infiltration_v)),
Pervious_cover_storage_v = lambda x: np.minimum(x.Pervious_cover_storage_v, MAXIMUM_PERVIOUS_COVER_STORAGE)
)
# Annual aggregation
output = output.groupby(['Scenario','Precipitation_scale','AgentID','Step']).agg(
Leaf_area = pd.NamedAgg(column='LA', aggfunc=np.mean),
Under_canopy_area = pd.NamedAgg(column='Under_canopy_area', aggfunc=np.mean),
SAMPLE_AREA = pd.NamedAgg(column='SAMPLE_AREA', aggfunc=np.mean),
IMPERVIOUS_COVER_SHARE = pd.NamedAgg(column='IMPERVIOUS_COVER_SHARE', aggfunc=np.mean),
PERVIOUS_COVER_SHARE = pd.NamedAgg(column='PERVIOUS_COVER_SHARE', aggfunc=np.mean),
POPULATION_AREA = pd.NamedAgg(column='POPULATION_AREA', aggfunc=np.mean),
POPULATION_SAMPLE_TREE_RATIO = pd.NamedAgg(column='POPULATION_SAMPLE_TREE_RATIO', aggfunc=np.mean),
Annual_precipitation = pd.NamedAgg(column='Precipitation', aggfunc=np.sum),
Annual_canopy_interception_loss = pd.NamedAgg(column='Evaporation_from_vegetation', aggfunc=np.sum),
Annual_run_off_v = pd.NamedAgg(column='Run_off_v', aggfunc=np.sum),
Annual_evaporation_from_impervious_cover_v = pd.NamedAgg(column='Evaporation_from_impervious_cover_v', aggfunc=np.sum),
Annual_infiltration_v=pd.NamedAgg(column="Infiltration_v", aggfunc=np.sum),
Annual_evaporation_from_pervious_cover_v=pd.NamedAgg(column="Evaporation_from_pervious_cover_v", aggfunc=np.sum),
Annual_transpiration=pd.NamedAgg(column="Transpiration", aggfunc=np.sum),
Total_under_canopy_area = pd.NamedAgg(column='Total_under_canopy_area', aggfunc=np.mean),
).reset_index()
output['Annual_stormwater_retention'] = output.Annual_transpiration + output.Annual_canopy_interception_loss + output.Annual_evaporation_from_impervious_cover_v*output.IMPERVIOUS_COVER_SHARE + output.Annual_evaporation_from_pervious_cover_v*output.PERVIOUS_COVER_SHARE
return output
Functions
C_air
def C_air(
dew_point_temperature,
temperature
)
The method calculates water vapor concentration in the air.
Args: Temperature [C] Dew point temperature [C]
Returns: Water vapor concentration in the air in [g/m^3]
Note: Temerature in celsius [C] is converted to kelvins [K] such that T(K) = T(C)+273.15. The formula also includes vapor pressure e() in [kPa].
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def C_air(dew_point_temperature, temperature):
"""The method calculates water vapor concentration in the air.
Args:
Temperature [C]
Dew point temperature [C]
Returns:
Water vapor concentration in the air in [g/m^3]
Note:
Temerature in celsius [C] is converted to kelvins [K] such that T(K) = T(C)+273.15.
The formula also includes vapor pressure e() in [kPa].
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 2165*e(dew_point_temperature)/(temperature+273.15)
C_leaf
def C_leaf(
temperature
)
The method calculates water vapor concentration at the evaporating surfaces within the leaf.
Args: Temperature [C]
Returns: Water vapor concentration at the evaporating surfaces within the leaf in [g/m^3]
Note: Temerature in celsius [C] is converted to kelvins [K] such that T(K) = T(C)+273.15. The formula also includes saturated vapor pressure e_s() in [kPa].
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def C_leaf(temperature):
"""The method calculates water vapor concentration at the evaporating surfaces within the leaf.
Args:
Temperature [C]
Returns:
Water vapor concentration at the evaporating surfaces within the leaf in [g/m^3]
Note:
Temerature in celsius [C] is converted to kelvins [K] such that T(K) = T(C)+273.15.
The formula also includes saturated vapor pressure e_s() in [kPa].
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 2165*e_s(temperature)/(temperature+273.15)
D
def D(
temperature,
dew_point_temperature
)
The method calculates vapor pressure deficit.
Args: Temperature in [C] Dew point temperature in [C]
Returns: Vapor pressure deficit in [kPa]
Note: It includes in calculation vapor pressure as well as saturated vapor pressure, both in [kPa], which are calculated with functions e() e_s().
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def D(temperature, dew_point_temperature):
"""The method calculates vapor pressure deficit.
Args:
Temperature in [C]
Dew point temperature in [C]
Returns:
Vapor pressure deficit in [kPa]
Note:
It includes in calculation vapor pressure as well as saturated vapor pressure, both in [kPa], which
are calculated with functions e() e_s().
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return np.maximum(e_s(temperature)-e(dew_point_temperature),0)
DELTA
def DELTA(
temperature
)
The method calculates the slope of vapor pressure temperature curve.
Args: Temperature in [C]
Returns: Slope of vapor pressure temperature curve in [kPa/C]
Note: It includes in calculation saturated vapor pressure in [kPa] which is calculated with function e_s()!
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def DELTA(temperature):
"""The method calculates the slope of vapor pressure temperature curve.
Args:
Temperature in [C]
Returns:
Slope of vapor pressure temperature curve in [kPa/C]
Note:
It includes in calculation saturated vapor pressure in [kPa] which is calculated with function e_s()!
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 4098*e_s(temperature)/(237.3+temperature)**2
U_t
def U_t(
wind_speed,
wind_estimate_height
)
The method estimates wind speed at the tree top.
Args: Measured wind speed [m/s] Wind estimate height (tree height) [m]
Returns: Wind speed at the tree top in [m/s]
Note: The method is using two other parameters: Wind measurement height Z_u (usually 10m) and roughness height for water d_w which are set as constants.
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def U_t(wind_speed, wind_estimate_height):
"""The method estimates wind speed at the tree top.
Args:
Measured wind speed [m/s]
Wind estimate height (tree height) [m]
Returns:
Wind speed at the tree top in [m/s]
Note:
The method is using two other parameters:
Wind measurement height Z_u (usually 10m) and roughness height for water d_w which are set as constants.
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return wind_speed*np.log(wind_estimate_height/d_w)/np.log(Z_u/d_w)
compute_leaf_area_index
def compute_leaf_area_index(
dbh,
tree_height,
crown_height,
crown_width,
crown_missing=0,
shade_factor=0.85
)
The function given allometrics of a tree computes its leaf, bark and plant area indices.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
dbh | None | (:obj:float ): the diameter in cm of the trunk usually measured at 1.3m from the ground. |
None |
tree_height | None | (:obj:float ): The tree height in meters. |
None |
crown_height | None | (:obj:float ): The vertical length of tree crown in meters. |
None |
crown_width | None | (:obj:float ): The horizontal length (diameter) of tree crown in meters. |
None |
crown_missing | None | (:obj:float ): The percentage loss of the crown. |
None |
shade_factor | None | (:obj:float ): The percentage of sky covered by foliage and branches. |
None |
Returns:
Type | Description |
---|---|
( | obj:tuple ): the tuple returns the tree indices (LAI,BAI,PAI) |
Note: | |
The beta multipliers and the main equation is based on Nowak (1996). |
TODO: Parametrize beta multipliers. |
View Source
def compute_leaf_area_index(
dbh,
tree_height,
crown_height,
crown_width,
crown_missing = 0,
shade_factor = Calibration.avg_shade_factor):
"""The function given allometrics of a tree computes its leaf, bark and plant area indices.
Args:
dbh: (:obj:`float`): the diameter in cm of the trunk usually measured at 1.3m from the ground.
tree_height: (:obj:`float`): The tree height in meters.
crown_height: (:obj:`float`): The vertical length of tree crown in meters.
crown_width: (:obj:`float`): The horizontal length (diameter) of tree crown in meters.
crown_missing: (:obj:`float`): The percentage loss of the crown.
shade_factor: (:obj:`float`): The percentage of sky covered by foliage and branches.
Returns:
(:obj:`tuple`): the tuple returns the tree indices (LAI,BAI,PAI)
Note:
The beta multipliers and the main equation is based on Nowak (1996).
TODO:
Parametrize beta multipliers.
"""
loss = crown_missing
th = tree_height
cw = crown_width
ch = crown_height
sf = shade_factor
beta_0 = -4.3309
beta_1 = 0.2942
beta_2 = 0.7312
beta_3 = 5.7217
beta_4 = 0.0148
def compute_under_canopy_area(crown_width):
return pow((crown_width/2),2) * np.pi
def compute_bark_area(dbh, tree_height, crown_height):
# * 0.01 converts DBH(cm) into meter.
return np.pi * (dbh * 0.01) * (tree_height - crown_height)
# Outer surface area estimate below is based on Gacka-Grzesikiewicz (1980).
under_canopy = compute_under_canopy_area(cw)
crown_surface = np.pi * crown_width * (crown_height + crown_width)/2
bark_area = compute_bark_area(dbh,th,ch)
leaf_area = (1-loss) * np.exp(beta_0 + beta_1 * th + beta_2 * cw + beta_3 * sf - beta_4 * crown_surface)
leaf_area_index = leaf_area / under_canopy
bark_area_index = bark_area / under_canopy
plant_area_index = leaf_area_index + bark_area_index
return (leaf_area_index, bark_area_index, plant_area_index)
e
def e(
dew_point_temperature
)
The method calculates vapor pressure.
Args: Dew point temperature in [C]
Returns: Vapor pressure in [kPa]
Note: The function is built upon the following book: Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def e(dew_point_temperature):
"""The method calculates vapor pressure.
Args:
Dew point temperature in [C]
Returns:
Vapor pressure in [kPa]
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 0.6108*np.exp(17.27*dew_point_temperature/(237.3+dew_point_temperature))
e_s
def e_s(
temperature
)
The method calculates saturated vapor pressure.
Args: Temperature in [C]
Returns: Saturated vapor pressure in [kPa]
Note: The function is built upon the following book: Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def e_s(temperature):
"""The method calculates saturated vapor pressure.
Args:
Temperature in [C]
Returns:
Saturated vapor pressure in [kPa]
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 0.6108*np.exp(17.27*temperature/(237.3+temperature))
ecosystem_services
def ecosystem_services(
i
)
The method parallelize the computation of water retention benefits.
Args: agent index "i"
Returns: water retention benefits for each agent [data frame]
Note:
Todo:
View Source
def ecosystem_services(i):
"""The method parallelize the computation of water retention benefits.
Args: agent index "i"
Returns: water retention benefits for each agent [data frame]
Note:
Todo:
"""
output = df_scenario[tree_population.AgentID == AGENTS[i]]
output = output[['Step', 'AgentID', 'height','BAI', 'LA','LAI', 'PAI', 'Conifers', 'Under_canopy_area', 'Total_under_canopy_area','Scenario', 'Precipitation_scale',
'SAMPLE_AREA', 'IMPERVIOUS_COVER_SHARE', 'PERVIOUS_COVER_SHARE', 'POPULATION_AREA', 'POPULATION_SAMPLE_TREE_RATIO']]
output = pd.merge(output, weather_forcast, on=['Step'], how='left').sort_values(['Step', 'AgentID'])
# Calculate plant area index (PAI) in leaf-on and leaf-off seasons
output['PAI'] = pai_seasons(output[['Date_time', 'BAI', 'LAI', 'Conifers']],
Leaf_on_transition_day_start, Leaf_off_transition_day_start,
LEAF_TRANSITION_DAYS)
# Calculate potential evapotranspiration over the vegetation and ground areas
output = potential_evapotranspiration(output)
output = output.assign(
Canopy_cover_fraction = lambda x: 1-np.exp(-KAPPA*x.PAI),
Maximum_vegetation_storage = lambda x: SL*x.PAI,
Through_canopy_precipitation = lambda x: x.Precipitation*(1-x.Canopy_cover_fraction),
Canopy_interception = lambda x: x.Precipitation-x.Through_canopy_precipitation
)
output = ped3(output,
evp_v = 2/3,
evp_g = 1
)
output = output.assign(
Canopy_drip = lambda x: np.maximum(0,(x.Vegetation_storage-x.Maximum_vegetation_storage)),
Evaporation_from_vegetation = lambda x: np.maximum(0,(x.Canopy_interception-x.Canopy_drip)),
Precipitation_on_the_ground_with_vegetation = lambda x: x.Canopy_drip + x.Through_canopy_precipitation,
Vegetation_storage = lambda x: np.minimum(x.Vegetation_storage, x.Maximum_vegetation_storage),
Run_off_v = lambda x: np.maximum(0,(x.Impervious_cover_storage_v-MAXIMUM_IMPERVIOUS_COVER_STORAGE)),
Evaporation_from_impervious_cover_v = lambda x: np.maximum(0,(x.Precipitation_on_the_ground_with_vegetation-x.Run_off_v)),
Impervious_cover_storage_v = lambda x: np.minimum(x.Impervious_cover_storage_v, MAXIMUM_IMPERVIOUS_COVER_STORAGE),
Infiltration_v = lambda x: np.maximum(0,(x.Pervious_cover_storage_v-MAXIMUM_PERVIOUS_COVER_STORAGE)),
Evaporation_from_pervious_cover_v = lambda x: np.maximum(0,(x.Precipitation_on_the_ground_with_vegetation-x.Infiltration_v)),
Pervious_cover_storage_v = lambda x: np.minimum(x.Pervious_cover_storage_v, MAXIMUM_PERVIOUS_COVER_STORAGE)
)
# Annual aggregation
output = output.groupby(['Scenario','Precipitation_scale','AgentID','Step']).agg(
Leaf_area = pd.NamedAgg(column='LA', aggfunc=np.mean),
Under_canopy_area = pd.NamedAgg(column='Under_canopy_area', aggfunc=np.mean),
SAMPLE_AREA = pd.NamedAgg(column='SAMPLE_AREA', aggfunc=np.mean),
IMPERVIOUS_COVER_SHARE = pd.NamedAgg(column='IMPERVIOUS_COVER_SHARE', aggfunc=np.mean),
PERVIOUS_COVER_SHARE = pd.NamedAgg(column='PERVIOUS_COVER_SHARE', aggfunc=np.mean),
POPULATION_AREA = pd.NamedAgg(column='POPULATION_AREA', aggfunc=np.mean),
POPULATION_SAMPLE_TREE_RATIO = pd.NamedAgg(column='POPULATION_SAMPLE_TREE_RATIO', aggfunc=np.mean),
Annual_precipitation = pd.NamedAgg(column='Precipitation', aggfunc=np.sum),
Annual_canopy_interception_loss = pd.NamedAgg(column='Evaporation_from_vegetation', aggfunc=np.sum),
Annual_run_off_v = pd.NamedAgg(column='Run_off_v', aggfunc=np.sum),
Annual_evaporation_from_impervious_cover_v = pd.NamedAgg(column='Evaporation_from_impervious_cover_v', aggfunc=np.sum),
Annual_infiltration_v=pd.NamedAgg(column="Infiltration_v", aggfunc=np.sum),
Annual_evaporation_from_pervious_cover_v=pd.NamedAgg(column="Evaporation_from_pervious_cover_v", aggfunc=np.sum),
Annual_transpiration=pd.NamedAgg(column="Transpiration", aggfunc=np.sum),
Total_under_canopy_area = pd.NamedAgg(column='Total_under_canopy_area', aggfunc=np.mean),
).reset_index()
output['Annual_stormwater_retention'] = output.Annual_transpiration + output.Annual_canopy_interception_loss + output.Annual_evaporation_from_impervious_cover_v*output.IMPERVIOUS_COVER_SHARE + output.Annual_evaporation_from_pervious_cover_v*output.PERVIOUS_COVER_SHARE
return output
gamma
def gamma(
temperature,
surface_pressure
)
The method calculates psychrometric constant.
Args: Temperature [C] Surface pressure [kPa]
Returns: Psychrometric constant in [kPA/C]
Note: It includes in calculation latent heat of vaporization lmbd().
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def gamma(temperature,surface_pressure):
"""The method calculates psychrometric constant.
Args:
Temperature [C]
Surface pressure [kPa]
Returns:
Psychrometric constant in [kPA/C]
Note:
It includes in calculation latent heat of vaporization lmbd().
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
#return 10**(-3)*c_p*surface_pressure*10/(lmbd(temperature)*0.622)# pressure in mbar
return 10**(-3)*c_p*surface_pressure/(lmbd(temperature)*0.622)# pressure in kPa
lmbd
def lmbd(
temperature
)
The method calculates latent heat of vaporization.
Args: Temperature in [C]
Returns: latent heat of vaporization in [MJ/Kg]
Note: The function is built upon the following book: Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def lmbd(temperature):
"""The method calculates latent heat of vaporization.
Args:
Temperature in [C]
Returns:
latent heat of vaporization in [MJ/Kg]
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 2.501-0.002361*temperature
pai_seasons
def pai_seasons(
x,
leaf_on_start,
leaf_off_start,
leaf_transition_days
)
The method updates Plant Area Index (PAI) with respect to leaf on-off seasons.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
A data frame "x" with following variables | None | None | |
Date_time | None | (:obj:time ): date and time |
None |
BAI | None | Bark Area Index | None |
LAI | None | Leaf Area Index | None |
conifers | None | it taks value "true" if conifers and "false" otherwise | None |
leaf_on_start | None | a day in the year when the leaf on season starts. In the case of Glasgow it is April 14 (day 105). | |
See also other sources: https://weatherspark.com/y/147740/Average-Weather-at-Glasgow-Airport-United-Kingdom-Year-Round | None | ||
leaf_off_start | None | a day in the year when the leaf off season starts. In the case of Glasgow it is November 2 (day 307). | None |
leaf_transition_days | None | the number of days that the leaf on-off transition last. | None |
Returns:
Type | Description |
---|---|
None | An array of values of Plant Area Indexes (PAI) over time. |
Note: The function is built upon the following paper: Wang, Jun, Theodore A. Endreny, and David J. Nowak. “Mechanistic Simulation of Tree Effects in an Urban Water Balance Model 1.” JAWRA Journal of the American Water Resources Association 44, no. 1 (February 2008): 75–85. https://doi.org/10.1111/j.1752-1688.2007.00139.x
Todo: |
View Source
def pai_seasons(x, leaf_on_start, leaf_off_start, leaf_transition_days):
"""The method updates Plant Area Index (PAI) with respect to leaf on-off seasons.
Args:
A data frame "x" with following variables:
Date_time: (:obj:`time`): date and time
BAI: Bark Area Index
LAI: Leaf Area Index
conifers: it taks value "true" if conifers and "false" otherwise
leaf_on_start: a day in the year when the leaf on season starts. In the case of Glasgow it is April 14 (day 105).
See also other sources: https://weatherspark.com/y/147740/Average-Weather-at-Glasgow-Airport-United-Kingdom-Year-Round
leaf_off_start: a day in the year when the leaf off season starts. In the case of Glasgow it is November 2 (day 307).
leaf_transition_days: the number of days that the leaf on-off transition last.
Returns:
An array of values of Plant Area Indexes (PAI) over time.
Note:
The function is built upon the following paper:
Wang, Jun, Theodore A. Endreny, and David J. Nowak. “Mechanistic Simulation of Tree
Effects in an Urban Water Balance Model 1.” JAWRA Journal of the American Water Resources
Association 44, no. 1 (February 2008): 75–85. https://doi.org/10.1111/j.1752-1688.2007.00139.x
Todo:
"""
x = x.assign(PAI = np.where(x['Conifers'], x['BAI']+x['LAI'],
np.where(x.Date_time.dt.day_of_year < leaf_on_start, x['BAI'],
np.where(((x.Date_time.dt.day_of_year >= leaf_on_start) & (x.Date_time.dt.day_of_year < leaf_off_start)),
x['LAI']/(1+np.exp(-0.37*(x.Date_time.dt.day_of_year-(leaf_on_start+leaf_transition_days/2)))) + x['BAI'],
x['LAI']/(1+np.exp(-0.37*((leaf_off_start+leaf_transition_days/2)-x.Date_time.dt.day_of_year))) + x['BAI'])))
)
return x['PAI']
ped1
def ped1(
Date_time,
Precipitation,
Potential_evaporation,
Maximum_storage,
evp
)
The method computes precipitation-evaporation dynamics for one type at a time, which can be trees, pervious cover, impervious cover...
Args: Date_time [time identifier] Precipitation [amount of water hitting the surface area of the type] Potential_evaporation [of the type for the given weather conditions] Maximum_storage [parameter: maximum storage of the type] evp [evaporation coefficient for the type]
Returns: Precipitation storage of the type for each hour.
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def ped1(Date_time, Precipitation, Potential_evaporation, Maximum_storage, evp):
"""The method computes precipitation-evaporation dynamics for one type at a time, which can be trees, pervious cover, impervious cover...
Args:
Date_time [time identifier]
Precipitation [amount of water hitting the surface area of the type]
Potential_evaporation [of the type for the given weather conditions]
Maximum_storage [parameter: maximum storage of the type]
evp [evaporation coefficient for the type]
Returns:
Precipitation storage of the type for each hour.
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
df=pd.DataFrame({'Date_time':Date_time, 'Precipitation':Precipitation,
'Potential_evaporation':Potential_evaporation})
df["Storage"] = 0
df['Potential_evaporation_lag1'] = df.Potential_evaporation.shift(1).interpolate(limit_direction ='backward')
x = 0
def func2(row):
# non local variable ==> will use pre_value from the ped function
nonlocal x
new_value = new_value = np.maximum(0,(np.minimum(Maximum_storage,x) + row['Precipitation']-
np.minimum(np.minimum(Maximum_storage,x),((np.minimum(Maximum_storage,x)/
Maximum_storage)**(evp)*row['Potential_evaporation_lag1']))))
x = new_value
return new_value
# This line might throw a SettingWithCopyWarning warning
df.loc[0:,'Storage'] = df.loc[0:,:].apply(func2, axis=1)
return df["Storage"]
ped3
def ped3(
df,
evp_v,
evp_g
)
The method computes precipitation-evaporation dynamics for each tree as well as the impervious and pervious covers.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
A data frame including the following variables | None | None | |
Evaporation coefficient for trees | None | evp_v | None |
Evaporation coefficient for ground | None | evp_g | None |
Returns:
Type | Description |
---|---|
None | A data frame with new variables: Vegetation_storage, Impervious_cover_storage_v, Pervious_cover_storage_v for each hour. |
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo: |
View Source
def ped3(df, evp_v, evp_g):
"""The method computes precipitation-evaporation dynamics for each tree as well as the impervious and pervious covers.
Args:
A data frame including the following variables:
Evaporation coefficient for trees: evp_v
Evaporation coefficient for ground: evp_g
Returns:
A data frame with new variables: Vegetation_storage, Impervious_cover_storage_v, Pervious_cover_storage_v for each hour.
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
df['Storage'] = 0
df['Potential_evaporation_v_lag1'] = df.Potential_evaporation_v.shift(1).interpolate(limit_direction ='backward')
df['Potential_evaporation_g_lag1'] = df.Potential_evaporation_g.shift(1).interpolate(limit_direction ='backward')
x = 0
y = 0
z = 0
def func2(row):
# non local variable ==> will use pre_value from the ped function
nonlocal x
nonlocal y
nonlocal z
new_value_x = np.maximum(0,(np.minimum(row['Maximum_vegetation_storage'],x) + row['Canopy_interception']-
np.minimum(np.minimum(row['Maximum_vegetation_storage'],x),((np.minimum(row['Maximum_vegetation_storage'],x)/
row['Maximum_vegetation_storage'])**(evp_v)*row['Potential_evaporation_v_lag1']))))
Precipitation_on_the_ground_with_vegetation = np.maximum(0,(new_value_x-row['Maximum_vegetation_storage']))+row['Through_canopy_precipitation']
new_value_y = np.maximum(0,(np.minimum(MAXIMUM_IMPERVIOUS_COVER_STORAGE,y) + Precipitation_on_the_ground_with_vegetation-
np.minimum(np.minimum(MAXIMUM_IMPERVIOUS_COVER_STORAGE,y),((np.minimum(MAXIMUM_IMPERVIOUS_COVER_STORAGE,y)/
MAXIMUM_IMPERVIOUS_COVER_STORAGE)**(evp_g)*row['Potential_evaporation_g_lag1']))))
new_value_z = np.maximum(0,(np.minimum(MAXIMUM_PERVIOUS_COVER_STORAGE,z) + Precipitation_on_the_ground_with_vegetation-
np.minimum(np.minimum(MAXIMUM_PERVIOUS_COVER_STORAGE,z),((np.minimum(MAXIMUM_PERVIOUS_COVER_STORAGE,z)/
MAXIMUM_PERVIOUS_COVER_STORAGE)**(evp_g)*row['Potential_evaporation_g_lag1']))))
x = new_value_x
y = new_value_y
z = new_value_z
return [new_value_x, new_value_y, new_value_z]
# This line might throw a SettingWithCopyWarning warning
df.loc[0:,'Storage'] = df.loc[0:,:].apply(func2, axis=1)
df['Vegetation_storage'] = pd.DataFrame(df['Storage'].tolist())[0]
df['Impervious_cover_storage_v'] = pd.DataFrame(df['Storage'].tolist())[1]
df['Pervious_cover_storage_v'] = pd.DataFrame(df['Storage'].tolist())[2]
df = df.drop(columns='Storage')
return df
potential_evaporation
def potential_evaporation(
temperature,
dew_point,
solar_radiation,
sea_level_pressure,
pai,
wind_speed,
wind_estimate_height,
roughness_height
)
The method calculate potential evaporation.
Args: a data frame
Returns: the updated ata frame
Note:
Todo:
View Source
def potential_evaporation(temperature, dew_point, solar_radiation, sea_level_pressure, pai, wind_speed, wind_estimate_height, roughness_height):
"""The method calculate potential evaporation.
Args: a data frame
Returns: the updated ata frame
Note:
Todo:
"""
potential_evaporation = M_TO_MM*(1/(lmbd(temperature)*rho_w(temperature)))*(DELTA(temperature)*solar_radiation+(rho_a(temperature, sea_level_pressure)*c_p*D(temperature, dew_point))/r_a(wind_speed, wind_estimate_height, roughness_height))/(DELTA(temperature)+gamma(temperature, sea_level_pressure)*(1+(r_s(pai)/r_a(wind_speed, wind_estimate_height, roughness_height))))
return potential_evaporation
potential_evapotranspiration
def potential_evapotranspiration(
df
)
The method calculate potential evapotranspiration.
Args: a data frame
Returns: the updated ata frame
Note:
Todo:
View Source
def potential_evapotranspiration(df):
"""The method calculate potential evapotranspiration.
Args: a data frame
Returns: the updated ata frame
Note:
Todo:
"""
df = df.assign(
Potential_evaporation_v = lambda x: potential_evaporation(x.Temperature, x.Dew_Point, x.Solar_Radiation, x.Sea_Level_Pressure, x.PAI, x.Wind_Speed, x.height, roughness_height_trees),
Potential_evaporation_g = lambda x: potential_evaporation(x.Temperature, x.Dew_Point, x.Solar_Radiation, x.Sea_Level_Pressure, 1 , x.Wind_Speed, 1 , roughness_height_bare_soil),
PET = lambda x: potential_evaporation(x.Temperature, x.Dew_Point, x.Solar_Radiation, x.Sea_Level_Pressure, x.PAI, x.Wind_Speed, x.height, -1),
Transpiration = lambda x: 10**(-6)*(3600/x.PAI)*np.maximum((C_leaf(x.Temperature)-C_air(x.Dew_Point, x.Temperature)),0)/(r_s(x.PAI)+r_a(x.Wind_Speed, x.height, roughness_height_trees))
)
df = df.assign(
TF_average_ratio = lambda x: np.where(((x.PET>x.Transpiration) & (x.PET>0)), x.Transpiration/x.PET, np.nan)
)
df['TF_average_ratio'] = df.groupby(['AgentID','Step'])['TF_average_ratio'].transform('mean')
df = df.assign(
Transpiration = lambda x: np.where(((x.PAI<(x.LAI+x.BAI)) | (x.Transpiration > x.PET)), x.TF_average_ratio*x.PET, x.Transpiration)
)
df = df.drop(columns='TF_average_ratio')
return df
r_a
def r_a(
wind_speed,
wind_estimate_height,
roughness_height
)
The method calculates aerodynamic resistance.
Args: Measured wind speed [m/s] Wind estimate height (tree height) [m] Roughness_height [m]
Returns: Aerodynamic resistance in [m/s]
Note: It includes in calculation wind speed at the tree top U_t. If roughness height is negative, a new equation is applied to calculate aerodynamic resistance for the evapotranspiration from the soil.
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def r_a(wind_speed, wind_estimate_height, roughness_height):
"""The method calculates aerodynamic resistance.
Args:
Measured wind speed [m/s]
Wind estimate height (tree height) [m]
Roughness_height [m]
Returns:
Aerodynamic resistance in [m/s]
Note:
It includes in calculation wind speed at the tree top U_t.
If roughness height is negative, a new equation is applied to calculate aerodynamic resistance for
the evapotranspiration from the soil.
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
if roughness_height >= 0:
return 4.72*np.log(wind_estimate_height/(Z_ov*roughness_height))/(1+0.53*U_t(wind_speed, wind_estimate_height))
else:
return 208/U_t(wind_speed, wind_estimate_height)
r_s
def r_s(
pai
)
The method calculates stomatal resistance.
Args: Plant area index (PAI)
Returns: Stomatal resistance in [s/m]
Note: The function is built upon the following book: Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def r_s(pai):
"""The method calculates stomatal resistance.
Args:
Plant area index (PAI)
Returns:
Stomatal resistance in [s/m]
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 200/pai
rho_a
def rho_a(
temperature,
surface_pressure
)
The method calculates the density of air.
Args: Temperature in [C] Surface preasure in [kPa]
Returns: The density of air in [kg/m^3]
Note: The function is built upon the following book: Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def rho_a(temperature, surface_pressure):
"""The method calculates the density of air.
Args:
Temperature in [C]
Surface preasure in [kPa]
Returns:
The density of air in [kg/m^3]
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 3.486 * surface_pressure/(275+temperature)
rho_w
def rho_w(
temperature
)
The method calculates the density of water.
Args: Temperature in [C]
Returns: The density of water in [kg/m^3]
Note: The function is built upon the following book: Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
View Source
def rho_w(temperature):
"""The method calculates the density of water.
Args:
Temperature in [C]
Returns:
The density of water in [kg/m^3]
Note:
The function is built upon the following book:
Maidment, David R and others. “Handbook of Hydrology, McGraw-Hil.” Inc., New York, NY, 1992.
And a paper:
Hirabayashi, Satoshi. “I-Tree Eco United States County-Based Hydrologic Estimates.”
Washington, DC: US Department of Agriculture, Forest Service, 2015.
Todo:
"""
return 999.88 + 0.018*temperature - 0.0051*temperature**2
Classes
Calibration
class Calibration(
leaf_transition_days=28,
leaf_storage=0.0002,
pervios_storage_max=0.001,
impervios_storage_max=0.0015
)
View Source
class Calibration():
"""Water retention and impact estimate related parameters setting."""
# Conversion coefficient meter to millimeter
m_to_mm = 1
# Extinction coefficient =0.7 for trees and 0.3 for shrubs (Wang et al. 2008)
kappa = 0.7
# Shade factor, is the percentage of sky covered by foliage and branches within
# the perimeter of individual tree crowns, can vary by species from about
# 60% to 95% when trees are in-leaf (McPherson, 1984).
# The value below is set according to Glasgow mean
avg_shade_factor = 0.85
# Specific leaf storage of water (sl =0.0002 m).
leaf_storage = 0.0002 * m_to_mm
# Leaf-on leaf_off transition days (Wang_et_al_2008).
leaf_transition_days = 28
# Specific impervious cover storage of water (=0.0015 m).
maximum_impervious_cover_storage = 0.0015 * m_to_mm
# Specific pervious cover storage of water (=0.001 m).
maximum_pervious_cover_storage = 0.001 * m_to_mm
def __init__(
self,
leaf_transition_days = 28,
leaf_storage = 0.0002,
pervios_storage_max = 0.0010,
impervios_storage_max = 0.0015
):
"""The constructor method.
Args:
leaf_transition_days: (:obj:`int`): Leaf-on leaf_off transition days
leaf_storage: (:obj:`float`): Specific leaf storage of water.
pervios_storage_max: (:obj:`float`): Specific pervious cover storage of water
impervios_storage_max: (:obj:`float`): Specific impervious cover storage of water
Returns:
None
Note:
TODO:
* pass optional settings as key word parameters.
"""
self.leaf_storage = leaf_storage * Calibration.m_to_mm
self.leaf_transition_days = leaf_transition_days
self.maximum_impervious_cover_storage = impervios_storage_max * Calibration.m_to_mm
self.maximum_pervious_cover_storage = pervios_storage_max * Calibration.m_to_mm
def set_surface_storage_rates(
self, leaf_storage=None,
pervios_storage_max=None,
impervios_storage_max=None):
"""Setting specific water storage rates.
Args:
leaf_storage: (:obj:`float`): Specific leaf storage of water.
pervios_storage_max: (:obj:`float`): Specific pervious cover storage of water
impervios_storage_max: (:obj:`float`): Specific impervious cover storage of water
Returns:
None
Note:
Todo:
"""
if leaf_storage:
self.leaf_storage = leaf_storage * Calibration.m_to_mm
if impervios_storage_max:
self.maximum_impervious_cover_storage = impervios_storage_max * Calibration.m_to_mm
if pervios_storage_max:
self.maximum_pervious_cover_storage = pervios_storage_max * Calibration.m_to_mm
Class variables
avg_shade_factor
kappa
leaf_storage
leaf_transition_days
m_to_mm
maximum_impervious_cover_storage
maximum_pervious_cover_storage
Methods
set_surface_storage_rates
def set_surface_storage_rates(
self,
leaf_storage=None,
pervios_storage_max=None,
impervios_storage_max=None
)
Setting specific water storage rates.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
leaf_storage | None | (:obj:float ): Specific leaf storage of water. |
None |
pervios_storage_max | None | (:obj:float ): Specific pervious cover storage of water |
None |
impervios_storage_max | None | (:obj:float ): Specific impervious cover storage of water |
None |
Returns:
Type | Description |
---|---|
None | None |
Note: |
Todo: |
View Source
def set_surface_storage_rates(
self, leaf_storage=None,
pervios_storage_max=None,
impervios_storage_max=None):
"""Setting specific water storage rates.
Args:
leaf_storage: (:obj:`float`): Specific leaf storage of water.
pervios_storage_max: (:obj:`float`): Specific pervious cover storage of water
impervios_storage_max: (:obj:`float`): Specific impervious cover storage of water
Returns:
None
Note:
Todo:
"""
if leaf_storage:
self.leaf_storage = leaf_storage * Calibration.m_to_mm
if impervios_storage_max:
self.maximum_impervious_cover_storage = impervios_storage_max * Calibration.m_to_mm
if pervios_storage_max:
self.maximum_pervious_cover_storage = pervios_storage_max * Calibration.m_to_mm