Files
irrigation-model/irrgiation/dailyEvaporation.py
2025-12-23 08:38:08 +08:00

365 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from datetime import datetime, timedelta
from pyeto import fao,convert
from pyeto.fao import svp_from_t, avp_from_rhmean, delta_svp, psy_const,atm_pressure
import pandas as pd
#1、计算日参考蒸散量
def calculateET0(tmean, tmax, tmin, rh_mean, wind_speed, solar_rad, elevation, lat, doy):
# 计算饱和水汽压和实际水汽压
svp_max = svp_from_t(tmax)
svp_min = svp_from_t(tmin)
svp_mean =(svp_max+svp_min)/2
avp = avp_from_rhmean(svp_max, svp_min, rh_mean)
# 计算净辐射(简化版)
# 将纬度从度转换为弧度
lat_rad = convert.deg2rad(lat)
sol_dec = fao.sol_dec(doy)
sha = fao.sunset_hour_angle(lat_rad, sol_dec)
ird = fao.inv_rel_dist_earth_sun(doy)
et_rad = fao.et_rad(lat_rad, sol_dec, sha, ird)
cs_rad = fao.cs_rad(elevation, et_rad)
nisr = fao.net_in_sol_rad(solar_rad)
nolr = fao.net_out_lw_rad(tmin, tmax, solar_rad, cs_rad, avp)
rn = fao.net_rad(nisr, nolr)
deltasvp= delta_svp(tmean)
psy = psy_const(atm_pressure(elevation))
# 计算ET₀
et0 = fao.fao56_penman_monteith(
net_rad=rn,
t=tmean,
ws=wind_speed,
svp=svp_mean,
avp=avp,
delta_svp=deltasvp,
psy=psy
)
return et0
def cal_et0_List(planting_date,monitor_date,date_params):
et0_list = []
current_date = planting_date
while current_date < monitor_date:
result_params=date_params[current_date.strftime("%Y-%m-%d")]
et0=calculateET0(result_params['tmean'], result_params['tmax'], result_params['tmin'], result_params['rh_mean'], result_params['wind_speed'],
result_params['solar_rad'], result_params['elevation'],result_params['lat'], result_params['doy'])
et0_list.append(et0)
current_date += timedelta(days=1) # 增加一天
return et0_list
#计算实际每天作物蒸散量
# 1. 定义甘草生育阶段与作物系数(参考苜蓿)
# growth_stages = {
# "initial": {"duration_days": 20, "kc": 0.40}, # 生长初期
# "development": {"duration_days": 40, "kc": 0.90}, #生长快速期
# "mid": {"duration_days": 20, "kc": 1.1}, # 生长缓慢期
# "growth_slowly": {"duration_days": 30, "kc": 0.6}, # 生长缓慢期
# "dormant_period": {"duration_days": 150, "kc": 0.40}, # 营养储备期
# "fanqing_year2":{"duration_days": 30, "kc": 0.35},#返青期
# "development_year2":{"duration_days": 90, "kc": 0.9}, #第二年快速生长期
# "maturity _year2": {"duration_days": 40, "kc": 0.6}, # 第二年成熟期
# }
growth_stages_roots1 = {
'initial': {
'root_length': {5: 0.8, 10: 0.2}, # 主根长80%概率在0-15cm平均约8cm
'duration_days': 23, # 6月播种后1-2周
'kc': 0.40, # 作物系数
'time_range': '2025-06-17至2025-07-10',
'hight':0.03,#m
'k_rain':0.25
},
'development': {
'root_length': {20: 0.6, 45: 0.4}, # 主根长60%概率在20cm40%概率在45cm平均约30cm
'duration_days': 40, # 发芽后-8月20日左右约2个月
'kc': 0.9, # 作物系数
'time_range': '2025-07-10至2025-08-20',
'hight':0.15,
'k_rain':0.25
},
'mid': {
'root_length': {30: 0.5, 80: 0.5}, # 主根长50%概率在30cm50%概率在80cm平均约55cm
'duration_days': 30, # 8月20日-9月下旬
'kc': 1.1, # 作物系数
'time_range': '2025-08-21至2025-09-20',
'hight':0.45,
'soil_evaporation_depth': 0.65,
'k_rain':0.4
},
'growth_slowly': {
'root_length':{40: 0.4,60:0.4, 80: 0.2}, # 根据数据估算平均主根长
'duration_days': 30, # 9月下旬-10月下旬
'kc': 0.6,
'time_range': '2025-09-21至2025-10-20',
'hight':0.6
},
'dormant_period': {
'root_length': {40: 0.3,60:0.4, 80: 0.2}, # 冬季休眠,主根基本停止生长
'duration_days': 160, # 11月-次年3月
'kc': 0.4,
'time_range': '2025-10-21至2026-03-30',
'hight':0.8,
'k_rain':0.5
},
'fanqing_year2': {
'root_length': {40: 0.2,60:0.6, 80: 0.2}, # 返青期主根长变化不大
'duration_days': 30, # 3月下旬-4月下旬
'kc': 0.35,
'time_range': '2026-04-01至2026-04-30',
'hight':0.5,
'k_rain':0.5
},
'development_year2': {
'root_length': {40: 0.1,60:0.7, 80: 0.2}, # 根据数据估算平均主根长
'duration_days': 90, # 4月下旬-7月下旬
'kc': 0.9,
'time_range': '2026-05-01至2026-07-30',
'hight':0.45,
'k_rain':0.65
},
'maturity_year2': {
'root_length':{40: 0.1,60:0.6, 80: 0.3}, # 根据数据估算平均主根长
'duration_days': 40, # 7月下旬-8月下旬
'kc': 0.6,
'time_range': '2026-08-01至2026-09-10',
'hight':0.65,
'k_rain':0.5
}
}
# growth_stages_roots = {
# 'initial': {
# 'root_length': {5: 0.8, 10: 0.2}, # 主根长80%概率在0-15cm平均约8cm
# 'duration_days': 20, # 6月播种后1-2周
# 'kc': 0.40, # 作物系数
# 'time_range': '2025-07-08至2025-07-28',
# 'hight':0.03,#m
# 'k_rain':0.25
# },
# 'development': {
# 'root_length': {20: 0.6, 45: 0.4}, # 主根长60%概率在20cm40%概率在45cm平均约30cm
# 'duration_days': 42, # 发芽后-8月20日左右约2个月
# 'kc': 0.9, # 作物系数
# 'time_range': '2025-07-29至2025-09-10',
# 'hight':0.15,
# 'k_rain':0.25
# },
# 'mid': {
# 'root_length': {30: 0.5, 80: 0.5}, # 主根长50%概率在30cm50%概率在80cm平均约55cm
# 'duration_days': 30, # 8月20日-9月下旬
# 'kc': 1.1, # 作物系数
# 'time_range': '2025-09-11至2025-10-10',
# 'hight':0.45,
# 'soil_evaporation_depth': 0.65,
# 'k_rain':0.4
# },
# 'growth_slowly': {
# 'root_length':{40: 0.4,60:0.4, 80: 0.2}, # 根据数据估算平均主根长
# 'duration_days': 31, # 9月下旬-10月下旬
# 'kc': 0.6,
# 'time_range': '2025-10-11至2025-11-10',
# 'hight':0.6
# },
# 'dormant_period': {
# 'root_length': {40: 0.3,60:0.4, 80: 0.2}, # 冬季休眠,主根基本停止生长
# 'duration_days': 140, # 11月-次年3月
# 'kc': 0.4,
# 'time_range': '2025-11-11至2026-03-31',
# 'hight':0.8,
# 'k_rain':0.5
# },
# 'fanqing_year2': {
# 'root_length': {40: 0.2,60:0.6, 80: 0.2}, # 返青期主根长变化不大
# 'duration_days': 30, # 3月下旬-4月下旬
# 'kc': 0.35,
# 'time_range': '2026-04-01至2026-04-30',
# 'hight':0.5,
# 'k_rain':0.5
# },
# 'development_year2': {
# 'root_length': {40: 0.1,60:0.7, 80: 0.2}, # 根据数据估算平均主根长
# 'duration_days': 90, # 4月下旬-7月下旬
# 'kc': 0.9,
# 'time_range': '2026-05-01至2026-07-30',
# 'hight':0.45,
# 'k_rain':0.65
# },
# 'maturity_year2': {
# 'root_length':{40: 0.1,60:0.6, 80: 0.3}, # 根据数据估算平均主根长
# 'duration_days': 40, # 7月下旬-8月下旬
# 'kc': 0.6,
# 'time_range': '2026-08-01至2026-09-10',
# 'hight':0.65,
# 'k_rain':0.5
# }
# }
# ---------------------------
# 2. 计算每日Kc值根据生育阶段动态分配
# ---------------------------
def get_daily_kc(growth_stages, total_days=423):
daily_kc = []
for stage in growth_stages.values():
daily_kc.extend([stage["kc"]] * stage["duration_days"])
# 如果总天数超出定义用末期Kc填充剩余天数
if len(daily_kc) < total_days:
daily_kc.extend([growth_stages["maturity_year2"]["kc"]] * (total_days - len(daily_kc)))
return daily_kc[:total_days] # 截断至总天数
# ---------------------------
# 3. 计算每日实际蒸散量ETc(得到历史列表)
# ---------------------------
def calculate_etc_List(et0_daily, planting_date,monitor_date, kc_daily):
"""
计算每日ETc实际蒸散量
:param eto_daily: 每日参考蒸散量列表单位cm/d
:param planting_date: 播种日期,格式"YYYY-MM-DD"
:param kc_daily: 每日Kc值列表
:return: 日期列表、ETc列表
"""
start_date = planting_date
delta=monitor_date-start_date
days = delta.days
dates = [start_date + timedelta(days=i) for i in range(days)]
date_strings = [date.strftime("%Y-%m-%d") for date in dates]
kc_daily = kc_daily[:days]
etc = [eto * kc for eto, kc in zip(et0_daily, kc_daily)]
return etc,date_strings,kc_daily
#基于作物蒸散和土壤蒸发计算实际蒸散量
def calculate_etc_List_new(et0_daily, planting_date,monitor_date, kc_daily,ke_daily):
"""
计算每日ETc实际蒸散量
:param eto_daily: 每日参考蒸散量列表单位cm/d
:param planting_date: 播种日期,格式"YYYY-MM-DD"
:param kc_daily: 每日Kc值列表
:return: 日期列表、ETc列表
"""
start_date = planting_date
delta=monitor_date-start_date
days = delta.days
dates = [start_date + timedelta(days=i) for i in range(days)]
date_strings = [date.strftime("%Y-%m-%d") for date in dates]
kc_daily = kc_daily[:days]
etc = [eto * (kc+ke) for eto, kc,ke in zip(et0_daily, kc_daily,ke_daily)]
return etc,date_strings,kc_daily
def calculate_etc_dayily(et0_daily, planting_date,monitor_date, kc_daily):
"""
计算每日ETc实际蒸散量
:param eto_daily: 每日参考蒸散量列表单位cm/d
:param planting_date: 播种日期,格式"YYYY-MM-DD"
:param kc_daily: 每日Kc值列表
:return: 日期列表、ETc列表
"""
start_date = planting_date
delta=monitor_date-start_date
days = delta.days
# dates = [start_date + timedelta(days=i) for i in range(len(kc_daily))]
kc_daily = kc_daily[days]
etc = et0_daily*kc_daily
return etc
def export_etc_et0_date(et0_list,etc_list,dates,kc_list,ke_daily,soil_data,rain_daily,irrigate_daily,dk_name):
df = pd.DataFrame({
"Date": dates,
"ET0": [float(f"{x:.3f}") for x in et0_list],
"KC": kc_list,
"KE":ke_daily,
"ETc": [float(f"{x:.3f}") for x in etc_list],
"rain_effective":rain_daily,
"I_effective":irrigate_daily,
"VWC_fc":0.2884,
"VWC_wp":0.1086,
"dkbm":dk_name
})
df['VWC_SUR'] = 0.0
df['VWC_MID'] = 0.0
df['VWC_BOT'] = 0.0
for i in range(len(df)):
date=df.at[i, 'Date']
df.at[i, 'VWC_SUR']=round(float(soil_data["SOIL_MOISTURE_SURFACE"][date]),3)
df.at[i, 'VWC_MID'] = round(float(soil_data["SOIL_MOISTURE_MIDDLE"][date]),3)
df.at[i, 'VWC_BOT'] = round(float(soil_data["SOIL_MOISTURE_BOTTOM"][date]),3)
return df
def estimate_mad_from_et(max_et):
# 根据最大日蒸散量查表确定MAD值
if max_et < 2:
mad = 0.68
elif 2 <= max_et < 3:
mad = 0.58
elif 3 <= max_et < 4:
mad = 0.48
elif 4 <= max_et < 5:
mad = 0.4
elif 5 <= max_et < 6:
mad = 0.35
elif 6 <= max_et < 7:
mad = 0.33
elif 7 <= max_et < 8:
mad = 0.28
elif 8 <= max_et < 9:
mad = 0.25
else: # max_et >= 8
mad = 0.23
return mad
def calculate_weighted_soil_parameters(root_distribution, soil_layers):
# 初始化累计变量
sum_fc = 0.0
sum_wp = 0.0
# 处理每个根系分布层
for root_depth, root_ratio in root_distribution['root_length'].items():
# 找到包含该深度的土壤层
for layer in soil_layers:
min_depth, max_depth = layer['depth_range']
if min_depth <= root_depth < max_depth:
# 计算该层贡献 (简单比例分配)
layer_thickness = max_depth - min_depth
depth_in_layer = min(root_depth, max_depth) - min_depth
contribution_ratio = depth_in_layer / layer_thickness * root_ratio
sum_fc += layer['theta_33'] * contribution_ratio
sum_wp += layer['theta_1500'] * contribution_ratio
break
return sum_fc, sum_wp
def cal_stagebyDate(monitor_date,zwlx_growth_stages):
for stage, details in zwlx_growth_stages.items():
time_range_str = details['time_range']
if type(monitor_date) is str:
monitor_date= datetime.strptime(monitor_date, '%Y-%m-%d')
if '-' in time_range_str:
start_str, end_str = time_range_str.split('')
start_date = datetime.strptime(start_str, '%Y-%m-%d')
end_date = datetime.strptime(end_str, '%Y-%m-%d')
if start_date <= monitor_date <= end_date:
return stage,details['root_length'],details['hight'],details['k_rain']
raise ValueError(f"监测日期 {monitor_date.strftime('%Y-%m-%d')} 不在任何生育阶段范围内")
#根据日期计算主根长度
def calculate_average_root_length(root_length_dist):
return sum(length * prob for length, prob in root_length_dist.items())
def cal_soil_fc_wp():
# 土壤分层数据 (33kPa和1500kPa对应的含水率)
soil_data = [
{'depth_range': (0, 5), 'theta_33': 0.296, 'theta_1500': 0.103},
{'depth_range': (5, 15), 'theta_33': 0.284, 'theta_1500': 0.104},
{'depth_range': (15, 30), 'theta_33': 0.286, 'theta_1500': 0.105},
{'depth_range': (30, 60), 'theta_33': 0.290, 'theta_1500': 0.114},
{'depth_range': (60, 100), 'theta_33': 0.286, 'theta_1500': 0.117},
{'depth_range': (100, 200), 'theta_33': 0.284, 'theta_1500': 0.114}
]
# theta_fc, theta_wp = calculate_weighted_soil_parameters(
# growth_stages_roots[stage],
# soil_data
# )
theta_fc=0.2884
theta_wp=0.1086
return theta_fc,theta_wp
if __name__ == "__main__":
# #cal_et0_List(datetime(2026, 6, 18),datetime(2026, 6, 22))
et0_daily=[23,45,67,89]
# etc,dates,kc_daily=calculate_etc_List(et0_daily, datetime(2026, 6, 18),datetime(2026, 6, 22), get_daily_kc(growth_stages_roots))
# calculate_etc_dayily(45, datetime(2026, 6, 18), datetime(2026, 6, 22), get_daily_kc(growth_stages))
# df=export_etc_et0_date(et0_daily,etc,dates,kc_daily)
# print(df)
# cal_soil_fc_wp('initial')
# stage,details = cal_stagebyDate(datetime(2025, 7, 18))
# print(details)
# rd=calculate_average_root_length(details)
# print(rd)