| import numpy as np
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Gsc = 0.0820
|
| sigma = 4.903e-9
|
|
|
|
|
| def calculate_extraterrestrial_radiation(latitude, doy):
|
| phi = np.radians(latitude)
|
| dr = 1 + 0.033 * np.cos(2 * np.pi / 365 * doy)
|
| delta = 0.409 * np.sin(2 * np.pi / 365 * doy - 1.39)
|
| omega = np.arccos(-np.tan(phi) * np.tan(delta))
|
| Ra = (24 * 60 / np.pi) * Gsc * dr * (omega * np.sin(phi) * np.sin(delta) + np.cos(phi) * np.cos(delta) * np.sin(omega))
|
| return Ra
|
|
|
| def calculate_clear_sky_radiation(Ra, elevation):
|
| return (0.75 + 2e-5 * elevation) * Ra
|
|
|
| def calculate_net_solar_radiation(Rs):
|
| return (1 - 0.23) * Rs
|
|
|
| def calculate_net_outgoing_longwave_radiation(T_max, T_min, Rs, Rso, ea):
|
| T_max_K = T_max + 273.15
|
| T_min_K = T_min + 273.15
|
| return sigma * ((T_max_K ** 4 + T_min_K ** 4) / 2) * (0.34 - 0.14 * np.sqrt(ea)) * (1.35 * Rs / Rso - 0.35)
|
|
|
| def calculate_slope_of_saturation_vapor_pressure_curve(T_mean):
|
| return 4098 * (0.6108 * np.exp(17.27 * T_mean / (T_mean + 237.3))) / (T_mean + 237.3) ** 2
|
|
|
| def calculate_psychrometric_constant(elevation):
|
| P = 101.3 * ((293 - 0.0065 * elevation) / 293) ** 5.26
|
| return 0.665e-3 * P
|
|
|
| def calculate_saturation_vapor_pressure(T):
|
| return 0.6108 * np.exp(17.27 * T / (T + 237.3))
|
|
|
| def calculate_mean_saturation_vapor_pressure(T_max, T_min):
|
| es_Tmax = calculate_saturation_vapor_pressure(T_max)
|
| es_Tmin = calculate_saturation_vapor_pressure(T_min)
|
| return (es_Tmax + es_Tmin) / 2
|
|
|
| def calculate_actual_vapor_pressure(T_min, T_max, RH_min, RH_max):
|
| es_min = calculate_saturation_vapor_pressure(T_min)
|
| es_max = calculate_saturation_vapor_pressure(T_max)
|
| ea = (es_min * RH_max / 100 + es_max * RH_min / 100) / 2
|
| return ea
|
|
|
| def calculate_reference_evapotranspiration(T_max, T_min, T_mean, RH_min, RH_max, u2, Rs, elevation, latitude, doy):
|
|
|
| Ra = calculate_extraterrestrial_radiation(latitude, doy)
|
| Rso = calculate_clear_sky_radiation(Ra, elevation)
|
| Rns = calculate_net_solar_radiation(Rs)
|
|
|
|
|
| es = calculate_mean_saturation_vapor_pressure(T_max, T_min)
|
| ea = calculate_actual_vapor_pressure(T_min, T_max, RH_min, RH_max)
|
|
|
|
|
| Rnl = calculate_net_outgoing_longwave_radiation(T_max, T_min, Rs, Rso, ea)
|
|
|
|
|
| Rn = Rns - Rnl
|
|
|
|
|
| Delta = calculate_slope_of_saturation_vapor_pressure_curve(T_mean)
|
|
|
|
|
| gamma = calculate_psychrometric_constant(elevation)
|
|
|
|
|
| G = 0
|
|
|
|
|
| ET0 = (0.408 * Delta * (Rn - G) + gamma * (900 / (T_mean + 273)) * u2 * (es - ea)) / (Delta + gamma * (1 + 0.34 * u2))
|
|
|
| return ET0
|
|
|
|
|
|
|
|
|
| def calculate_kc_fao(Kcini, Kcmid, Kcend, doy):
|
| """Calculate the Kc value based on the day of the year (doy)"""
|
|
|
|
|
| start_day = 90
|
| mid_day = start_day + 60
|
| full_cover_day = mid_day + 40
|
| harvest_day = full_cover_day + 70
|
| end_season_day = harvest_day + 40
|
|
|
| if doy < mid_day:
|
| return Kcini
|
| elif doy < full_cover_day:
|
| return Kcini + (Kcmid - Kcini) * (doy - mid_day) / (full_cover_day - mid_day)
|
| elif doy < harvest_day:
|
| return Kcmid
|
| elif doy < end_season_day:
|
| return Kcmid + (Kcend - Kcmid) * (doy - harvest_day) / (end_season_day - harvest_day)
|
| else:
|
| return Kcend
|
|
|
|
|
| def kc_generic(NDVI):
|
| return 1.457 * NDVI - 0.1725
|
|
|
|
|
| def kc_campos(NDVI):
|
| return 1.44 * NDVI - 0.10
|
|
|
|
|
| def kc_erraki(NDVI):
|
| return 0.1808 * np.exp(1.3138 * NDVI)
|
|
|
| def kc_tasumi(NDVI):
|
| return 1.18 * NDVI + 0.04
|
|
|
|
|
|
|
| def calculate_etc(T_max, T_min, T_mean, RH_min, RH_max, u2, Rs, elevation, latitude, doy, Kcini=0.30, Kcmid=0.70, Kcend=0.45):
|
| et0 = calculate_reference_evapotranspiration(T_max, T_min, T_mean, RH_min, RH_max, u2, Rs, elevation, latitude, doy)
|
|
|
| kc = calculate_kc_fao(Kcini, Kcmid, Kcend, doy)
|
| return et0*kc |