🎉 init(init):初始化仓库
This commit is contained in:
0
irrgiation/__init__.py
Normal file
0
irrgiation/__init__.py
Normal file
BIN
irrgiation/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
irrgiation/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
irrgiation/__pycache__/crop_growth_stages.cpython-310.pyc
Normal file
BIN
irrgiation/__pycache__/crop_growth_stages.cpython-310.pyc
Normal file
Binary file not shown.
BIN
irrgiation/__pycache__/dailyEvaporation.cpython-310.pyc
Normal file
BIN
irrgiation/__pycache__/dailyEvaporation.cpython-310.pyc
Normal file
Binary file not shown.
BIN
irrgiation/__pycache__/db_connect.cpython-310.pyc
Normal file
BIN
irrgiation/__pycache__/db_connect.cpython-310.pyc
Normal file
Binary file not shown.
BIN
irrgiation/__pycache__/irrigateDecisionDemo.cpython-310.pyc
Normal file
BIN
irrgiation/__pycache__/irrigateDecisionDemo.cpython-310.pyc
Normal file
Binary file not shown.
BIN
irrgiation/__pycache__/mathuntils.cpython-310.pyc
Normal file
BIN
irrgiation/__pycache__/mathuntils.cpython-310.pyc
Normal file
Binary file not shown.
BIN
irrgiation/__pycache__/soil_Ke.cpython-310.pyc
Normal file
BIN
irrgiation/__pycache__/soil_Ke.cpython-310.pyc
Normal file
Binary file not shown.
BIN
irrgiation/__pycache__/weatherAndSoilDataRequest.cpython-310.pyc
Normal file
BIN
irrgiation/__pycache__/weatherAndSoilDataRequest.cpython-310.pyc
Normal file
Binary file not shown.
68
irrgiation/crop_growth_stages.py
Normal file
68
irrgiation/crop_growth_stages.py
Normal file
@@ -0,0 +1,68 @@
|
||||
crop_growth_stages={
|
||||
'甘草': {
|
||||
'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%概率在20cm,40%概率在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%概率在30cm,50%概率在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
|
||||
}
|
||||
}
|
||||
}
|
||||
365
irrgiation/dailyEvaporation.py
Normal file
365
irrgiation/dailyEvaporation.py
Normal file
@@ -0,0 +1,365 @@
|
||||
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%概率在20cm,40%概率在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%概率在30cm,50%概率在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%概率在20cm,40%概率在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%概率在30cm,50%概率在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)
|
||||
199
irrgiation/db_connect.py
Normal file
199
irrgiation/db_connect.py
Normal file
@@ -0,0 +1,199 @@
|
||||
import configparser
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Optional, Union, List
|
||||
|
||||
import pandas as pd
|
||||
import psycopg2
|
||||
from dotenv import load_dotenv
|
||||
from psycopg2 import sql
|
||||
from psycopg2.extras import execute_batch
|
||||
from sqlalchemy import create_engine, text
|
||||
|
||||
|
||||
def get_config():
|
||||
config = configparser.ConfigParser()
|
||||
try:
|
||||
project_nifi = Path(__file__).parent.parent / 'config.nifi'
|
||||
config.read(project_nifi)
|
||||
# 确保所有必要键都存在
|
||||
required_keys = ['host', 'port', 'database', 'user', 'password','schema']
|
||||
for key in required_keys:
|
||||
if key not in config['postgresql']:
|
||||
raise ValueError(f"Missing required config key: {key}")
|
||||
|
||||
return {
|
||||
"host": config['postgresql']['host'],
|
||||
"port": config['postgresql']['port'],
|
||||
"database": config['postgresql']['database'],
|
||||
"user": config['postgresql']['user'],
|
||||
"password": config['postgresql']['password'],
|
||||
"schema": config['postgresql']['schema'],
|
||||
"tablename": config['postgresql']['tablename']
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"配置读取错误: {e}")
|
||||
# 返回默认配置或退出
|
||||
return None
|
||||
def connect():
|
||||
"""建立数据库连接"""
|
||||
try:
|
||||
config_params=get_config()
|
||||
conn = psycopg2.connect(host=config_params['host'],port=config_params['port'],dbname=config_params['database'],
|
||||
user=config_params['user'],password=config_params['password']
|
||||
)
|
||||
cursor = conn.cursor()
|
||||
except Exception as e:
|
||||
print(f"❌ 连接失败: {e}")
|
||||
raise
|
||||
|
||||
# 根据条件查询
|
||||
def query_postgresql_to_dataframe(
|
||||
condition: Optional[dict] = None,
|
||||
condition_operator: str = "AND",
|
||||
columns: Union[str, List[str]] = "*",):
|
||||
|
||||
# 连接数据库
|
||||
config_params = get_config()
|
||||
conn = psycopg2.connect(host=config_params['host'], port=config_params['port'], dbname=config_params['database'],
|
||||
user=config_params['user'], password=config_params['password']
|
||||
)
|
||||
try:
|
||||
# 构建列选择部分
|
||||
if isinstance(columns, list):
|
||||
columns_sql = sql.SQL(", ").join(sql.Identifier(col) for col in columns)
|
||||
else:
|
||||
columns_sql = sql.SQL(columns)
|
||||
|
||||
# 构建基础查询
|
||||
query = sql.SQL("SELECT {} FROM {}").format(
|
||||
columns_sql,
|
||||
sql.Identifier(config_params['tablename'])
|
||||
)
|
||||
|
||||
# 构建条件部分(参数化)
|
||||
params = {}
|
||||
if condition:
|
||||
conditions = []
|
||||
for i, (key, value) in enumerate(condition.items()):
|
||||
param_name = f"param_{i}"
|
||||
conditions.append(sql.SQL("{} = %({})s").format(
|
||||
sql.Identifier(key),
|
||||
sql.SQL(param_name)
|
||||
))
|
||||
params[param_name] = value
|
||||
|
||||
where_clause = sql.SQL(" WHERE {}").format(
|
||||
sql.SQL(f" {condition_operator} ").join(conditions)
|
||||
)
|
||||
query = query + where_clause
|
||||
print(query)
|
||||
# 执行查询
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute(query, params)
|
||||
if cursor.description:
|
||||
columns = [desc[0] for desc in cursor.description]
|
||||
data = cursor.fetchall()
|
||||
return pd.DataFrame(data, columns=columns)
|
||||
return pd.DataFrame()
|
||||
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
# 插入库表
|
||||
def dataframe_to_postgresql_batch(df,batch_size=1000):
|
||||
"""
|
||||
使用execute_batch批量插入DataFrame数据
|
||||
|
||||
参数:
|
||||
df: 要插入的DataFrame
|
||||
table_name: 目标表名
|
||||
config_params: 数据库连接配置
|
||||
batch_size: 每批插入的行数
|
||||
"""
|
||||
if df.empty:
|
||||
print("DataFrame为空,无需插入")
|
||||
return
|
||||
|
||||
# 获取列名
|
||||
columns = df.columns.tolist()
|
||||
data = [tuple(x) for x in df.to_numpy()]
|
||||
|
||||
try:
|
||||
config_params = get_config()
|
||||
conn = psycopg2.connect(host=config_params['host'], port=config_params['port'],
|
||||
dbname=config_params['database'],
|
||||
user=config_params['user'], password=config_params['password']
|
||||
)
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 构建INSERT语句
|
||||
insert_query = sql.SQL("INSERT INTO {} ({}) VALUES ({})").format(
|
||||
sql.Identifier(config_params['tablename']),
|
||||
sql.SQL(', ').join(map(sql.Identifier, columns)),
|
||||
sql.SQL(', ').join([sql.Placeholder()] * len(columns))
|
||||
)
|
||||
|
||||
# 批量执行
|
||||
execute_batch(cursor, insert_query, data, batch_size)
|
||||
|
||||
conn.commit()
|
||||
|
||||
except Exception as e:
|
||||
conn.rollback()
|
||||
print(f"批量插入时出错: {e}")
|
||||
finally:
|
||||
if conn is not None:
|
||||
conn.close()
|
||||
# 根据条件更新某个字段
|
||||
def update_irrigation_data(date_value, id_value, field_to_update, new_value):
|
||||
"""
|
||||
更新表中单条记录的单个字段
|
||||
|
||||
参数:
|
||||
db_url: 数据库连接字符串
|
||||
table_name: 表名
|
||||
date_field: 日期字段名
|
||||
id_field: ID/地块字段名
|
||||
date_value: 日期值
|
||||
id_value: ID/地块值
|
||||
field_to_update: 要更新的字段名
|
||||
new_value: 新值
|
||||
"""
|
||||
try:
|
||||
# 数据库配置
|
||||
db_config = {
|
||||
"db_url": "postgresql://postgres:postgres@localhost:5432/datastore",
|
||||
"table_name": "irrigation_data",
|
||||
"date_field": "Date",
|
||||
"id_field": "dkbm"
|
||||
}
|
||||
engine = create_engine(db_config["db_url"])
|
||||
table_name=db_config["table_name"]
|
||||
date_field=db_config["date_field"]
|
||||
id_field=db_config["id_field"]
|
||||
with engine.begin() as conn: # 自动提交事务
|
||||
# 使用参数化查询防止SQL注入
|
||||
update_sql = text(f"""
|
||||
UPDATE {table_name}
|
||||
SET "{field_to_update}" = :new_value
|
||||
WHERE "{date_field}" = :date_value AND "{id_field}" = :id_value""")
|
||||
conn.execute(update_sql, {
|
||||
'new_value': new_value,
|
||||
'date_value': date_value,
|
||||
'id_value': id_value
|
||||
})
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"更新失败: {str(e)}")
|
||||
return False
|
||||
finally:
|
||||
engine.dispose() # 确保连接关闭
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
config = configparser.ConfigParser()
|
||||
project_nifi = Path(__file__).parent.parent / 'config.nifi'
|
||||
config.read(project_nifi)
|
||||
620
irrgiation/irrigateDecisionDemo.py
Normal file
620
irrgiation/irrigateDecisionDemo.py
Normal file
@@ -0,0 +1,620 @@
|
||||
import statistics
|
||||
import uuid
|
||||
|
||||
from collections import defaultdict
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from irrgiation.db_connect import query_postgresql_to_dataframe, dataframe_to_postgresql_batch,update_irrigation_data
|
||||
|
||||
from irrgiation.weatherAndSoilDataRequest import getWeatherAndSoilData, loginAuth, dateToTimestamp, get_soil_data_dk1, \
|
||||
getFutureWeather, weather_params, get_soil_data_dk2
|
||||
from irrgiation.dailyEvaporation import get_daily_kc, cal_et0_List, calculate_etc_List, export_etc_et0_date, \
|
||||
cal_soil_fc_wp, estimate_mad_from_et, cal_stagebyDate, calculate_average_root_length,calculate_etc_List_new
|
||||
from irrgiation.mathuntils import day_of_year
|
||||
from irrgiation.soil_Ke import calculate_ke,calculate_D_ei
|
||||
from irrgiation.crop_growth_stages import crop_growth_stages
|
||||
|
||||
#解析数据接口,计算均值、最大、最小值
|
||||
def analy_soil_data(data):
|
||||
soil_result = {}
|
||||
for key in data:
|
||||
daily_data = defaultdict(lambda: defaultdict(list))
|
||||
for metric, entries in data[key].items():
|
||||
for entry in entries:
|
||||
dt = datetime.strptime(entry["datetime"], "%Y-%m-%d %H:%M:%S")
|
||||
date_key = dt.date() # 按日期分组
|
||||
value = float(entry["value"])
|
||||
daily_data[date_key][metric].append(value)
|
||||
result = {}
|
||||
for date, metrics in daily_data.items():
|
||||
date_stats = {}
|
||||
for metric, values in metrics.items():
|
||||
date_stats[metric] = {
|
||||
"max": max(values),
|
||||
"min": min(values),
|
||||
"mean": statistics.mean(values),
|
||||
'count': len(values),
|
||||
'sum': sum(values)
|
||||
}
|
||||
result[str(date)] = date_stats # 将日期转为字符串作为键
|
||||
soil_result[key] = result
|
||||
return soil_result
|
||||
|
||||
|
||||
#获取地块6个传感器的土壤湿度均值
|
||||
def analy_soil_data_mean(soil_data):
|
||||
result = defaultdict(lambda: {
|
||||
"SOIL_MOISTURE_SURFACE": [],
|
||||
"SOIL_MOISTURE_MIDDLE": [],
|
||||
"SOIL_MOISTURE_BOTTOM": []
|
||||
|
||||
})
|
||||
# 填充数据
|
||||
for sensor, dates in soil_data.items():
|
||||
for date, layers in dates.items():
|
||||
result[date]["SOIL_MOISTURE_SURFACE"].append(layers["SOIL_MOISTURE_SURFACE"]["mean"])
|
||||
result[date]["SOIL_MOISTURE_MIDDLE"].append(layers["SOIL_MOISTURE_MIDDLE"]["mean"])
|
||||
result[date]["SOIL_MOISTURE_BOTTOM"].append(layers["SOIL_MOISTURE_BOTTOM"]["mean"])
|
||||
# 转换为普通字典
|
||||
final_result = dict(result)
|
||||
result_soil = {}
|
||||
for date, layers in final_result.items():
|
||||
result_soil[date] = {
|
||||
"SOIL_MOISTURE_SURFACE_MEAN": sum(layers["SOIL_MOISTURE_SURFACE"]) / len(layers["SOIL_MOISTURE_SURFACE"]),
|
||||
"SOIL_MOISTURE_MIDDLE_MEAN": sum(layers["SOIL_MOISTURE_MIDDLE"]) / len(layers["SOIL_MOISTURE_MIDDLE"]),
|
||||
"SOIL_MOISTURE_BOTTOM_MEAN": sum(layers["SOIL_MOISTURE_BOTTOM"]) / len(layers["SOIL_MOISTURE_BOTTOM"])
|
||||
}
|
||||
|
||||
return final_result, result_soil
|
||||
|
||||
|
||||
def analy_soil_dataNight_mean(soil_data):
|
||||
daily_means = defaultdict(lambda: defaultdict(list))
|
||||
# 计算平均值
|
||||
for sensor, measurements in soil_data.items():
|
||||
for measure_type, dates in measurements.items():
|
||||
for date, value in dates.items():
|
||||
daily_means[date][measure_type].append(float(value))
|
||||
|
||||
# 计算并格式化结果
|
||||
result = {}
|
||||
for date, measures in daily_means.items():
|
||||
result[date] = {
|
||||
f"{measure_type}_MEAN": round(sum(values) / len(values), 2)
|
||||
for measure_type, values in measures.items()
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
|
||||
#获取地块6个传感器中土壤湿度最大值
|
||||
def analy_soil_data_max(soil_data):
|
||||
result = defaultdict(lambda: {
|
||||
"SOIL_MOISTURE_SURFACE": [],
|
||||
"SOIL_MOISTURE_MIDDLE": [],
|
||||
"SOIL_MOISTURE_BOTTOM": []
|
||||
|
||||
})
|
||||
# 填充数据
|
||||
for sensor, dates in soil_data.items():
|
||||
for date, layers in dates.items():
|
||||
result[date]["SOIL_MOISTURE_SURFACE"].append(layers["SOIL_MOISTURE_SURFACE"]["mean"])
|
||||
result[date]["SOIL_MOISTURE_MIDDLE"].append(layers["SOIL_MOISTURE_MIDDLE"]["mean"])
|
||||
result[date]["SOIL_MOISTURE_BOTTOM"].append(layers["SOIL_MOISTURE_BOTTOM"]["mean"])
|
||||
# 转换为普通字典
|
||||
final_result = dict(result)
|
||||
result_soil = {}
|
||||
for date, layers in final_result.items():
|
||||
result_soil[date] = {
|
||||
"SOIL_MOISTURE_SURFACE_MEAN": max(layers["SOIL_MOISTURE_SURFACE"]),
|
||||
"SOIL_MOISTURE_MIDDLE_MEAN": max(layers["SOIL_MOISTURE_MIDDLE"]),
|
||||
"SOIL_MOISTURE_BOTTOM_MEAN": max(layers["SOIL_MOISTURE_BOTTOM"])
|
||||
}
|
||||
|
||||
return final_result, result_soil
|
||||
|
||||
|
||||
def get_soil_data_night_eyveryDay(data):
|
||||
daily_data = {}
|
||||
for sersor in data:
|
||||
data_depth = {}
|
||||
for key in data[sersor]:
|
||||
target_time = (21, 59, 59)
|
||||
result = {} # 时、分、秒元组
|
||||
daily_records = {} # 临时存储每天的所有记录,用于找不到22点数据时获取最新记录
|
||||
for record in data[sersor][key]:
|
||||
try:
|
||||
dt = datetime.strptime(record["datetime"], "%Y-%m-%d %H:%M:%S")
|
||||
date_str = record["datetime"].split(" ")[0] # 提取日期部分
|
||||
# 严格匹配 02:00:00
|
||||
# 提取时间部分(时、分、秒)
|
||||
current_time = (dt.hour, dt.minute, dt.second)
|
||||
# 存储每天的所有记录(按时间排序)
|
||||
if date_str not in daily_records:
|
||||
daily_records[date_str] = []
|
||||
daily_records[date_str].append((dt, record['value']))
|
||||
# 比较时间部分
|
||||
if current_time >= target_time:
|
||||
if date_str not in result:
|
||||
result[date_str] = record['value']
|
||||
except:
|
||||
continue
|
||||
# 对于没有22点数据的日期,取当天最新的一条数据
|
||||
for date_str in daily_records:
|
||||
if date_str not in result and daily_records[date_str]:
|
||||
daily_records[date_str].sort(key=lambda x: x[0]) # 按datetime排序
|
||||
result[date_str] = daily_records[date_str][-1][1] # 取最后一个值
|
||||
data_depth[key] = result
|
||||
daily_data[sersor] = data_depth
|
||||
return daily_data
|
||||
|
||||
|
||||
def analyze_weather_data1(data):
|
||||
# 1. 按日期分组数据
|
||||
daily_data = defaultdict(lambda: defaultdict(list))
|
||||
for metric, entries in data.items():
|
||||
for entry in entries:
|
||||
dt = datetime.strptime(entry["datetime"], "%Y-%m-%d %H:%M:%S")
|
||||
date_key = dt.date() # 按日期分组
|
||||
if metric == "AIR_LUX":
|
||||
value = float(entry["value_solar"])
|
||||
else:
|
||||
value = float(entry["value"])
|
||||
daily_data[date_key][metric].append(value)
|
||||
# 2. 计算每日统计值
|
||||
result = {}
|
||||
for date, metrics in daily_data.items():
|
||||
date_stats = {}
|
||||
for metric, values in metrics.items():
|
||||
date_stats[metric] = {
|
||||
"max": max(values),
|
||||
"min": min(values),
|
||||
"mean": statistics.mean(values),
|
||||
'count': len(values),
|
||||
'sum': sum(values)
|
||||
}
|
||||
result[str(date)] = date_stats # 将日期转为字符串作为键
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# 获取彭曼公式的入参
|
||||
def get_params(start_date, monitor_date, data):
|
||||
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]
|
||||
date_params = {}
|
||||
for date in date_strings:
|
||||
result_params = get_weather_params(data, date)
|
||||
date_params[date] = result_params
|
||||
return date_params
|
||||
|
||||
|
||||
def get_weather_params(data, date):
|
||||
result = {}
|
||||
elevation = 865 # 海拔(m)
|
||||
lat = 41.34252110189814 # 纬度(度)
|
||||
#计算当前日期位于当年的多少天
|
||||
doy = day_of_year(date)
|
||||
|
||||
for item in data['AIR_LUX']:
|
||||
item['value_solar'] = float(item['value']) * 0.0081 * 3600
|
||||
data_tj = analyze_weather_data1(data)
|
||||
data_tj_date = data_tj[date];
|
||||
tmax = data_tj_date['AIR_TEMPERATURE']['max']
|
||||
tmin = data_tj_date['AIR_TEMPERATURE']['min']
|
||||
tmean = data_tj_date['AIR_TEMPERATURE']['mean']
|
||||
rh_mean = data_tj_date['AIR_HUMIDITY']['mean']
|
||||
wind_speed = data_tj_date['WIND_SPEED']['mean']
|
||||
solar = data_tj_date['AIR_LUX']['sum'] / 1000000
|
||||
result['tmax'] = round(tmax, 3)
|
||||
result['tmin'] = round(tmin, 3)
|
||||
result['tmean'] = round(tmean, 3)
|
||||
result['rh_mean'] = round(rh_mean, 3)
|
||||
result['wind_speed'] = round(wind_speed, 3)*0.94
|
||||
result['solar_rad'] = round(solar, 3)
|
||||
result['elevation'] = elevation
|
||||
result['lat'] = round(lat, 3)
|
||||
result['doy'] = doy
|
||||
return result
|
||||
|
||||
|
||||
# 判断是否需要灌溉
|
||||
def isNeedirrigate(df, qx_coff, soil_coff,Di_1,zwlx_growth_stages):
|
||||
df['RD'] = 0.0
|
||||
df['Di'] = 0.0
|
||||
df['Di-1'] = Di_1
|
||||
df['mad'] = 0.0
|
||||
df['irrigation_depth'] = 0.0
|
||||
df['irrigation_acre'] = 0.0
|
||||
df['isNeedirrigate'] = False
|
||||
df['Reset_Flag'] = False
|
||||
# df['irrigate_sd_predict'] = 0.0
|
||||
df['f_t'] = 0.0
|
||||
df['f_js'] = 0.0
|
||||
df['f_soil'] = 0.0
|
||||
for i in range(len(df)):
|
||||
# 设置Di-1(前一天累计值)
|
||||
if i > 0:
|
||||
df.at[i, 'Di-1'] = df.at[i - 1, 'Di']
|
||||
# 计算当前累计值(Di-1 + 当天ETc)
|
||||
raw, rd, mad, k_rain = cal_raw(df.at[i, 'ETc'], df.at[i, 'Date'],zwlx_growth_stages)
|
||||
if df.at[i, 'rain_effective']<5:
|
||||
df.at[i, 'rain_effective'] = 0
|
||||
else:
|
||||
df.at[i, 'rain_effective'] = df.at[i, 'rain_effective'] * k_rain
|
||||
current_cum = df.at[i, 'Di-1'] + df.at[i, 'ETc']- df.at[i, 'rain_effective']
|
||||
df['RD'] = rd
|
||||
df.at[i,'mad'] = mad
|
||||
df.at[i, 'raw'] = round(raw, 3)
|
||||
f_t = qx_coff[df.at[i, 'Date']]['qw']
|
||||
f_js = qx_coff[df.at[i, 'Date']]['js']
|
||||
f_soil = soil_coff[df.at[i, 'Date']]
|
||||
raw_adj = cal_raw_adjust(raw, f_t, f_js, f_soil)
|
||||
df.at[i, 'f_t'] = f_t
|
||||
df.at[i, 'f_js'] = f_js
|
||||
df.at[i, 'f_soil'] = f_soil
|
||||
df.at[i, 'raw_adjust'] = round(raw_adj, 3)
|
||||
# 判断是否需要重置
|
||||
if current_cum > raw_adj:
|
||||
df.at[i, 'Reset_Flag'] = True
|
||||
df.at[i, 'irrigation_depth'] = round(current_cum, 3)
|
||||
df.at[i, 'isNeedirrigate'] = True
|
||||
df.at[i, 'Di'] = 0 # 保留当天ETc值
|
||||
df.at[i, 'irrigation_acre'] = round((current_cum*667/1000),3)
|
||||
else:
|
||||
df.at[i, 'Di'] = round(current_cum, 3) # 正常累加
|
||||
return df
|
||||
|
||||
|
||||
def cal_raw(etc, monitor_date,zwlx_growth_stages):
|
||||
theta_fc, theta_wp = cal_soil_fc_wp()
|
||||
stage, details,hight,k_rain= cal_stagebyDate(monitor_date,zwlx_growth_stages)
|
||||
rd = calculate_average_root_length(details)
|
||||
mad = estimate_mad_from_et(etc)
|
||||
raw = mad * (theta_fc - theta_wp) * rd * 10
|
||||
return raw, rd,mad,k_rain
|
||||
|
||||
|
||||
def cal_raw_adjust(raw, f_t, f_rain, f_soil):
|
||||
raw_adjust = raw * f_soil * f_t * f_rain
|
||||
return raw_adjust
|
||||
|
||||
|
||||
def cal_qxcoefficient_adjust(start_date, monitor_date, qx_data):
|
||||
|
||||
qx_coefficient = {}
|
||||
current_date = start_date
|
||||
qxData_filter = {}
|
||||
for key in qx_data:
|
||||
if key == "AIR_TEMPERATURE" or key == "RAIN_FALL_REALTIME":
|
||||
qxData_filter[key] = qx_data[key]
|
||||
qxData_filter_tj = analyze_weather_data1(qxData_filter)
|
||||
now_date = datetime.now().date()
|
||||
while current_date < monitor_date:
|
||||
qx_futureData = []
|
||||
result = {}
|
||||
if (current_date + timedelta(days=3)).date() < now_date:
|
||||
start = datetime.strptime((current_date + timedelta(days=1)).strftime("%Y-%m-%d"), "%Y-%m-%d")
|
||||
end = datetime.strptime((current_date + timedelta(days=3)).strftime("%Y-%m-%d"), "%Y-%m-%d")
|
||||
# 筛选日期范围内的数据
|
||||
filter = {
|
||||
date: values
|
||||
for date, values in qxData_filter_tj.items()
|
||||
if start <= datetime.strptime(date, "%Y-%m-%d") <= end
|
||||
}
|
||||
qx_futureData = transform_data(filter)
|
||||
else:
|
||||
try:
|
||||
# print(f"进入else分支: {current_date}")
|
||||
qx_futureData = getFutureWeather(current_date)
|
||||
except Exception as e:
|
||||
# print(f"else分支异常: {e}")
|
||||
raise # 保留异常以便调试
|
||||
qw_mean = (qx_futureData['qw_day1']['mean'] + qx_futureData['qw_day2']['mean'] + qx_futureData['qw_day3']['mean']) / 3
|
||||
js_sum = qx_futureData['js_day1']['max'] + qx_futureData['js_day2']['max'] + qx_futureData['js_day3']['max']
|
||||
qw_coff = 1.0
|
||||
js_coff = 1.0
|
||||
if qw_mean < 10:
|
||||
qw_coff = 1.1
|
||||
elif 10 < qw_mean <= 25:
|
||||
qw_coff = 1
|
||||
elif 25 < qw_mean <= 30:
|
||||
qw_coff = 0.85
|
||||
else:
|
||||
qw_coff = 0.75
|
||||
if js_sum <= 5:
|
||||
js_coff = 1.0 # 少雨
|
||||
elif 5 < js_sum <= 10:
|
||||
js_coff = 1.2 # 中雨
|
||||
elif 10 < js_sum <= 20:
|
||||
js_coff = 1.4 # 大雨
|
||||
else:
|
||||
js_coff = 1.6 # 暴雨
|
||||
result['qw'] = qw_coff
|
||||
result['js'] = js_coff
|
||||
qx_coefficient[current_date.strftime("%Y-%m-%d")] = result
|
||||
current_date = current_date + timedelta(days=1)
|
||||
return qx_coefficient
|
||||
|
||||
|
||||
def transform_data(original_data):
|
||||
transformed = {}
|
||||
# 处理温度数据 (qw_day)
|
||||
for i, (date, metrics) in enumerate(original_data.items(), 1):
|
||||
temp_data = metrics["AIR_TEMPERATURE"]
|
||||
transformed[f"qw_day{i}"] = {
|
||||
"max": round(temp_data["max"], 2),
|
||||
"min": round(temp_data["min"], 2),
|
||||
"mean": round(temp_data["mean"], 2),
|
||||
"sum": round(temp_data["sum"], 2)
|
||||
}
|
||||
|
||||
# 处理降雨数据 (js_day)
|
||||
for i, (date, metrics) in enumerate(original_data.items(), 1):
|
||||
rain_data = metrics["RAIN_FALL_REALTIME"]
|
||||
transformed[f"js_day{i}"] = {
|
||||
"max": round(rain_data["max"], 2),
|
||||
"min": round(rain_data["min"], 2),
|
||||
"mean": round(rain_data["mean"], 2),
|
||||
"sum": round(rain_data["sum"], 2)
|
||||
}
|
||||
|
||||
return transformed
|
||||
|
||||
|
||||
def cal_soil_coff(soil_data):
|
||||
soil_data_coff = {}
|
||||
for sensor in soil_data:
|
||||
for date in soil_data[sensor]:
|
||||
soil_cof = 1.0
|
||||
sd_surf = float(soil_data['SOIL_MOISTURE_SURFACE'][date])
|
||||
sd_mid = float(soil_data['SOIL_MOISTURE_MIDDLE'][date])
|
||||
if sd_surf < 10:
|
||||
soil_cof = 0.5
|
||||
if 10 <sd_surf < 15:
|
||||
soil_cof = 0.75
|
||||
elif 15<sd_surf < 20:
|
||||
soil_cof = 1.0
|
||||
else:
|
||||
soil_cof = 1.2
|
||||
soil_data_coff[date] = soil_cof
|
||||
return soil_data_coff
|
||||
|
||||
|
||||
#将两块地的传感器数据分隔开
|
||||
def get_soil_data_bydk(soil_data):
|
||||
target_key = 7
|
||||
dk1_soildata = {}
|
||||
dk2_soildata = {}
|
||||
|
||||
for key, value in soil_data.items():
|
||||
parts = key.split("号传感器")
|
||||
if int(parts[0]) < target_key:
|
||||
dk1_soildata[key] = value
|
||||
else:
|
||||
dk2_soildata[key] = value
|
||||
return dk1_soildata, dk2_soildata
|
||||
# 整生育期监测
|
||||
def cal_dk_isNeegirrigate(zwlx_name,dk_name,start_date, monitor_date,Di_1):
|
||||
auth_token = loginAuth()
|
||||
date_start = start_date.strftime("%Y-%m-%d") + " 00:00:00.123"
|
||||
date_end_qx=monitor_date
|
||||
if (monitor_date + timedelta(days=3)).date()<= datetime.now().date():
|
||||
date_end_qx=(monitor_date + timedelta(days=3)).strftime("%Y-%m-%d") + " 23:59:59.123"
|
||||
else:
|
||||
date_end_qx=datetime.now().date().strftime("%Y-%m-%d") + " 23:59:59.123"
|
||||
date_end = monitor_date.strftime("%Y-%m-%d") + " 23:59:59.123"
|
||||
startTs = dateToTimestamp(date_start)
|
||||
endTs = dateToTimestamp(date_end)
|
||||
zwlx_growth_stages = crop_growth_stages[zwlx_name]
|
||||
kc_daily = get_daily_kc(zwlx_growth_stages)
|
||||
# #获取气象数据
|
||||
qxdata = getWeatherAndSoilData(auth_token, weather_params['device_id'], startTs, dateToTimestamp(date_end_qx), weather_params['agg'],
|
||||
weather_params['interval'], weather_params['limit'], weather_params['orderBy'],
|
||||
weather_params['keys'])
|
||||
# # #彭曼公式气象入参
|
||||
qx_params = get_params(start_date, monitor_date, qxdata)
|
||||
# #获取土壤传感器数据
|
||||
data = get_soil_data_dk1(auth_token, startTs, endTs)
|
||||
soil_data = get_soil_data_night_eyveryDay(data)
|
||||
dk1_soildata, dk2_soildata = get_soil_data_bydk(soil_data)
|
||||
# 膜边探头优先原则,1号和7号传感器分别为1号地和5号地的膜边探头
|
||||
dk1_soil_mean = dk1_soildata['1号传感器']
|
||||
dk2_soil_mean = dk2_soildata['7号传感器']
|
||||
# #计算参考蒸散量
|
||||
et0_list = cal_et0_List(start_date, monitor_date, qx_params)
|
||||
#计算土壤蒸发系数
|
||||
ke_data = cal_ke_daily_list(start_date, monitor_date, et0_list, kc_daily, qxdata)
|
||||
ke_daily = []
|
||||
rain_daily=[]
|
||||
irrigate_daily=[]
|
||||
for date in sorted(ke_data.keys()):
|
||||
ke_value = round(ke_data[date]['ke'],3)
|
||||
rain_value= round(ke_data[date]['rain'],3)
|
||||
irrigate_value = ke_data[date]['irrigation']
|
||||
ke_daily.append(ke_value)
|
||||
rain_daily.append(rain_value)
|
||||
irrigate_daily.append(irrigate_value)
|
||||
|
||||
# #获取作物蒸散量
|
||||
etc_list, date_strings, kc_list = calculate_etc_List_new(et0_list, start_date, monitor_date, kc_daily,ke_daily)
|
||||
# # 获取未来3天气象数据
|
||||
qx_coff = cal_qxcoefficient_adjust(start_date, monitor_date, qxdata)
|
||||
if "1" in dk_name:
|
||||
df = export_etc_et0_date(et0_list, etc_list, date_strings, kc_list,ke_daily, dk1_soil_mean,rain_daily,irrigate_daily,dk_name)
|
||||
# 基于每天实测土壤相对湿度计算土壤系数
|
||||
soil_coff = cal_soil_coff(dk1_soil_mean)
|
||||
elif "5" in dk_name:
|
||||
df = export_etc_et0_date(et0_list, etc_list, date_strings, kc_list,ke_daily, dk2_soil_mean,rain_daily,irrigate_daily,dk_name)
|
||||
# 基于每天实测土壤相对湿度计算土壤系数
|
||||
soil_coff = cal_soil_coff(dk2_soil_mean)
|
||||
else:
|
||||
return "该地块数据不存在"
|
||||
# 判断是否需要灌溉
|
||||
dataframe = isNeedirrigate(df, qx_coff, soil_coff,Di_1,zwlx_growth_stages)
|
||||
random_uuid = uuid.uuid4()
|
||||
uuid_str = str(random_uuid)
|
||||
# df.to_csv(
|
||||
# 'D:/悦柠/遥感/甘草/ceshi/' + dk_name + "_" + start_date.strftime("%Y-%m-%d") + "-" + monitor_date.strftime(
|
||||
# "%Y-%m-%d")+"_"+uuid_str + ".csv", index=False) # CSV 文件
|
||||
return dataframe
|
||||
def cal_dk_isNeegirrigate_Day(zwlx_name,dk_name,soil_key,start_date, monitor_date,Di_1,weather_key):
|
||||
auth_token = loginAuth()
|
||||
date_start = start_date.strftime("%Y-%m-%d") + " 00:00:00.123"
|
||||
date_end_qx=monitor_date
|
||||
if (monitor_date + timedelta(days=3)).date()<= datetime.now().date():
|
||||
date_end_qx=(monitor_date + timedelta(days=3)).strftime("%Y-%m-%d") + " 23:59:59.123"
|
||||
else:
|
||||
date_end_qx=datetime.now().date().strftime("%Y-%m-%d") + " 23:59:59.123"
|
||||
date_end = monitor_date.strftime("%Y-%m-%d") + " 23:59:59.123"
|
||||
startTs = dateToTimestamp(date_start)
|
||||
endTs = dateToTimestamp(date_end)
|
||||
zwlx_growth_stages=crop_growth_stages[zwlx_name]
|
||||
kc_daily = get_daily_kc(zwlx_growth_stages)
|
||||
# #获取气象数据
|
||||
qxdata = getWeatherAndSoilData(auth_token, weather_key, startTs, dateToTimestamp(date_end_qx), weather_params['agg'],
|
||||
weather_params['interval'], weather_params['limit'], weather_params['orderBy'],
|
||||
weather_params['keys'])
|
||||
# 获取土壤传感器数据
|
||||
data = get_soil_data_dk2(auth_token, soil_key, startTs, endTs)
|
||||
soil_data = get_soil_data_night_eyveryDay(data)
|
||||
# dk1_soildata, dk2_soildata = get_soil_data_bydk(soil_data)
|
||||
# 膜边探头优先原则,1号和7号传感器分别为1号地和5号地的膜边探头
|
||||
dk_soil_mean = soil_data[soil_key]
|
||||
if len(qxdata) !=0 and len(dk_soil_mean) !=0:
|
||||
# # #彭曼公式气象入参
|
||||
qx_params = get_params(start_date, monitor_date, qxdata)
|
||||
# #计算参考蒸散量
|
||||
et0_list = cal_et0_List(start_date, monitor_date, qx_params)
|
||||
# 计算土壤蒸发系数
|
||||
ke_data = cal_ke_daily_list(start_date, monitor_date, et0_list, kc_daily, qxdata, zwlx_growth_stages)
|
||||
ke_daily = []
|
||||
rain_daily = []
|
||||
irrigate_daily = []
|
||||
for date in sorted(ke_data.keys()):
|
||||
ke_value = round(ke_data[date]['ke'], 3)
|
||||
rain_value = round(ke_data[date]['rain'], 3)
|
||||
irrigate_value = ke_data[date]['irrigation']
|
||||
ke_daily.append(ke_value)
|
||||
rain_daily.append(rain_value)
|
||||
irrigate_daily.append(irrigate_value)
|
||||
# #获取作物蒸散量
|
||||
etc_list, date_strings, kc_list = calculate_etc_List_new(et0_list, start_date, monitor_date, kc_daily,
|
||||
ke_daily)
|
||||
# # 获取未来3天气象数据
|
||||
qx_coff = cal_qxcoefficient_adjust(start_date, monitor_date, qxdata)
|
||||
|
||||
df = export_etc_et0_date(et0_list, etc_list, date_strings, kc_list, ke_daily, dk_soil_mean, rain_daily,
|
||||
irrigate_daily, dk_name)
|
||||
# 基于每天实测土壤相对湿度计算土壤系数
|
||||
soil_coff = cal_soil_coff(dk_soil_mean)
|
||||
# 判断是否需要灌溉
|
||||
dataframe = isNeedirrigate(df, qx_coff, soil_coff, Di_1, zwlx_growth_stages)
|
||||
return dataframe
|
||||
elif len(qxdata) ==0 and len(dk_soil_mean) !=0:
|
||||
raise ValueError("未查询到气象数据")
|
||||
elif len(qxdata) !=0 and len(dk_soil_mean) ==0:
|
||||
raise ValueError("未查询到土壤数据")
|
||||
else:
|
||||
raise ValueError("未查询到气象和土壤数据")
|
||||
|
||||
|
||||
#计算土壤蒸发系数
|
||||
def cal_ke_daily_list(start_date,monitor_date,et0_list,kc_list,qx_data,zwlx_growth_stages):
|
||||
stage, details, hight ,k_rain= cal_stagebyDate(monitor_date,zwlx_growth_stages)
|
||||
REW=9
|
||||
I=0.0
|
||||
theta_fc=0.2884
|
||||
theta_wp=0.1086
|
||||
current_date=start_date
|
||||
qxData_tj = analyze_weather_data1(qx_data)
|
||||
ke_data= {}
|
||||
i=0
|
||||
while current_date< monitor_date:
|
||||
date_key = str(current_date.date())
|
||||
u2=qxData_tj[date_key]['WIND_SPEED']['mean']
|
||||
rain=qxData_tj[date_key]['RAIN_FALL_REALTIME']['max']
|
||||
rh_min=qxData_tj[date_key]['AIR_HUMIDITY']['min']
|
||||
if current_date == start_date:
|
||||
DE_i_1 = 0
|
||||
fw=0.35
|
||||
else:
|
||||
# 从上一天的数据中获取DE_i(如果存在)
|
||||
prev_date = current_date - timedelta(days=1)
|
||||
prev_date_key = str(prev_date.date())
|
||||
if prev_date_key in ke_data:
|
||||
DE_i_1 = ke_data[prev_date_key]['DE_i']
|
||||
else:
|
||||
DE_i_1 = 0 # 处理特殊情况(如start_date等于monitor_date)
|
||||
if I > 0 and rain < 4:
|
||||
fw = 0.35
|
||||
elif I > 0 and rain < 4:
|
||||
fw = 1
|
||||
elif rain > 4 and I == 0:
|
||||
fw = 1
|
||||
else:
|
||||
fw = ke_data[prev_date_key]['fw']
|
||||
et0 = 0.0
|
||||
kc = 0.0
|
||||
if i < len(et0_list):
|
||||
et0 = et0_list[i]
|
||||
kc = kc_list[i]
|
||||
ke,few=calculate_ke(hight, u2, rh_min, kc, DE_i_1, REW, fw, theta_fc,theta_wp)
|
||||
et_soil=ke*et0
|
||||
DE_i = calculate_D_ei(DE_i_1, rain, I,et_soil, fw,few)
|
||||
#创建当天的数据字典
|
||||
daily_data = {
|
||||
'ke': ke,
|
||||
'DE_i': DE_i,
|
||||
'et0': et0,
|
||||
'et_soil': et_soil,
|
||||
'fw':fw,
|
||||
"rain":rain,
|
||||
"irrigation":I
|
||||
}
|
||||
ke_data[date_key]=daily_data
|
||||
current_date = current_date + timedelta(days=1)
|
||||
i=i+1
|
||||
return ke_data
|
||||
# 单天监测
|
||||
def cal_irrigationByDay(zwlx_name,dkname,start_date,end_date,soil_key,weather_key,irrigation_really):
|
||||
yesterday_date=(start_date - timedelta(days=1)).strftime("%Y-%m-%d")
|
||||
condition = {"Date": yesterday_date,"dkbm":dkname}
|
||||
df=query_postgresql_to_dataframe(condition)
|
||||
Di_1 = 0
|
||||
if irrigation_really>0:
|
||||
Di_1 = 0
|
||||
update_irrigation_data(yesterday_date,dkname,"irrigation_really",irrigation_really)
|
||||
else:
|
||||
# 将Date列转换为日期时间类型
|
||||
df['Date'] = pd.to_datetime(df['Date'])
|
||||
if len(df[df.Date == (start_date - timedelta(days=1))])!=0:
|
||||
isNeedjg=df[df.Date == (start_date- timedelta(days=1))]['isNeedirrigate'].values[0]
|
||||
if isNeedjg:
|
||||
Di_1 = df[df.Date == (start_date - timedelta(days=1))]['Di-1'].values[0]+df[df.Date == (start_date - timedelta(days=1))]['ETc'].values[0]
|
||||
else:
|
||||
Di_1 = df[df.Date == (start_date - timedelta(days=1))]['Di'].values[0]
|
||||
dataframe=cal_dk_isNeegirrigate_Day(zwlx_name,dkname,soil_key,start_date,end_date,Di_1,weather_key)
|
||||
condition_new = {"Date": start_date.strftime("%Y-%m-%d"), "dkbm": dkname}
|
||||
df_query=query_postgresql_to_dataframe(condition_new)
|
||||
if len(df_query)==0:
|
||||
dataframe_to_postgresql_batch(dataframe)
|
||||
else:
|
||||
print("库表中已存在该数据")
|
||||
return dataframe
|
||||
if __name__ == "__main__":
|
||||
#调用气象数据接口--获取具体日期的气象数据(气象)
|
||||
# auth_token = loginAuth()
|
||||
start_date = datetime(2025, 7, 16)
|
||||
monitor_date = datetime(2025, 7, 17)
|
||||
dk_name = "5"
|
||||
zwlx_name="甘草"
|
||||
soil_key = "8637b970-561b-11f0-a556-4f10f26fc07f"
|
||||
weather_key="18d121f0-561b-11f0-a556-4f10f26fc07f"
|
||||
irrigation_really=5
|
||||
cal_irrigationByDay(zwlx_name,dk_name,start_date,monitor_date,soil_key,weather_key,irrigation_really)
|
||||
# cal_dk_isNeegirrigate(dk_name, planting_date, monitor_date,0)
|
||||
371
irrgiation/mathuntils.py
Normal file
371
irrgiation/mathuntils.py
Normal file
@@ -0,0 +1,371 @@
|
||||
#根据日期计算当年天数
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
|
||||
def is_leap_year(year):
|
||||
return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
|
||||
|
||||
def day_of_year(date_str):
|
||||
date_part = date_str.split()[0]
|
||||
year = int(date_str[:4]) # 取前4位 → 2025
|
||||
month = int(date_str[5:7]) # 取第5-6位 → 06 → 6
|
||||
day = int(date_str[8:10]) # 取第8-9位 → 30
|
||||
month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||
if is_leap_year(year):
|
||||
month_days[1] = 29 # 闰年2月29天
|
||||
total = sum(month_days[:month-1]) + day
|
||||
return total
|
||||
#计算每天有效日照时长
|
||||
def count_above_threshold(data, threshold,date):
|
||||
filtered = filter(lambda x: float(x['value_cal']) >= threshold and x['datetime'].split(" ")[0] == date, data)
|
||||
return len(list(filtered))
|
||||
# 示例计算函数:Lux转W/m²
|
||||
def lux_to_wm2(lux_value):
|
||||
"""将Lux值转换为W/m²(使用标准系数0.0081)"""
|
||||
return lux_value * 0.0081
|
||||
def convert_lux_to_Radiant_Flux(data_dict):
|
||||
"""
|
||||
递归地将字典中的所有'timestamp'字段转换为可读的日期时间格式
|
||||
保留原始时间戳的同时添加新的'datetime'字段
|
||||
"""
|
||||
if 'value' in data_dict:
|
||||
radiant_Flux=data_dict["value"]*0.001496
|
||||
data_dict["value_radiant"] =radiant_Flux
|
||||
return data_dict
|
||||
def lux_to_solar_rad(lux,h):
|
||||
|
||||
return lux * 0.001496*h * 3.6 / 1000
|
||||
def plot(soil_data,name):
|
||||
import matplotlib.dates as mdates
|
||||
# 创建画布
|
||||
plt.figure(figsize=(14, 8))
|
||||
|
||||
# 处理并绘制地表湿度数据
|
||||
surface_df = pd.DataFrame(soil_data["SOIL_MOISTURE_SURFACE"])
|
||||
surface_df['datetime'] = pd.to_datetime(surface_df['datetime'])
|
||||
surface_df['value'] = surface_df['value'].astype(float)
|
||||
plt.plot(surface_df['datetime'], surface_df['value'],
|
||||
label='Surface Moisture (0-5cm)', color='#FF6B6B', linewidth=2, marker='o', markersize=5)
|
||||
|
||||
# 处理并绘制中层湿度数据
|
||||
middle_df = pd.DataFrame(soil_data["SOIL_MOISTURE_MIDDLE"])
|
||||
middle_df['datetime'] = pd.to_datetime(middle_df['datetime'])
|
||||
middle_df['value'] = middle_df['value'].astype(float)
|
||||
plt.plot(middle_df['datetime'], middle_df['value'],
|
||||
label='Middle Layer Moisture', color='#4ECDC4', linewidth=2, marker='s', markersize=5)
|
||||
# 处理并绘制中层湿度数据
|
||||
middle_df = pd.DataFrame(soil_data["SOIL_MOISTURE_BOTTOM"])
|
||||
middle_df['datetime'] = pd.to_datetime(middle_df['datetime'])
|
||||
middle_df['value'] = middle_df['value'].astype(float)
|
||||
plt.plot(middle_df['datetime'], middle_df['value'],
|
||||
label='BOTTOM Layer Moisture', color='blue', linewidth=2, marker='s', markersize=5)
|
||||
|
||||
# 设置图表格式
|
||||
plt.title('Soil Moisture Variation (Jun 18 - Jul 3, 2025)', fontsize=16, pad=20)
|
||||
plt.xlabel('Date', fontsize=12)
|
||||
plt.ylabel('Soil Moisture (%)', fontsize=12)
|
||||
plt.grid(True, linestyle='--', alpha=0.7)
|
||||
|
||||
# 设置x轴日期格式
|
||||
ax = plt.gca()
|
||||
ax.xaxis.set_major_locator(mdates.DayLocator(interval=2))
|
||||
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d'))
|
||||
plt.xticks(rotation=45)
|
||||
|
||||
# 添加图例和注释
|
||||
plt.legend(loc='upper right', fontsize=10)
|
||||
plt.tight_layout()
|
||||
# 保存图片到本地
|
||||
output_path = 'D:\悦柠\遥感\甘草\ceshi/'+name+".png"
|
||||
plt.savefig(output_path, dpi=300, bbox_inches='tight')
|
||||
# 显示图表
|
||||
# plt.show()
|
||||
|
||||
|
||||
def rh_to_theta_vg(rh, soil_params, temperature=25):
|
||||
"""使用Van Genuchten模型将相对湿度转换为体积含水量"""
|
||||
# 计算土壤水势(kPa)
|
||||
psi = -145 * np.log(rh / 100)
|
||||
|
||||
# 提取土壤参数
|
||||
theta_s = soil_params["theta_s"] # 饱和含水量
|
||||
theta_r = soil_params["theta_r"] # 残余含水量
|
||||
alpha = soil_params["alpha"] # Van Genuchten参数
|
||||
n = soil_params["n"] # Van Genuchten参数
|
||||
m = 1 - 1 / n
|
||||
|
||||
# 计算体积含水量
|
||||
theta = theta_r + (theta_s - theta_r) / ((1 + (alpha * abs(psi)) ** n) ** m)
|
||||
print(theta)
|
||||
return theta
|
||||
|
||||
|
||||
def calculate_soil_moisture_after_irrigation(
|
||||
initial_moisture: float,
|
||||
field_capacity: float,
|
||||
irrigation_volume: float,
|
||||
soil_volume: float,
|
||||
area: float = None,
|
||||
verbose: bool = False
|
||||
) -> float:
|
||||
"""
|
||||
不考虑降雨量和蒸散量时,计算灌溉后的土壤相对湿度
|
||||
|
||||
参数:
|
||||
initial_moisture: 初始土壤相对湿度 (%)
|
||||
field_capacity: 田间持水量 (%)
|
||||
irrigation_volume: 灌溉量 (m³)
|
||||
soil_volume: 土壤体积 (m³)
|
||||
area: 灌溉面积 (㎡,可选,仅用于打印提示)
|
||||
verbose: 是否打印详细计算过程
|
||||
|
||||
返回:
|
||||
float: 灌溉后土壤相对湿度 (%)
|
||||
"""
|
||||
# 参数验证
|
||||
if not (0 <= initial_moisture <= 100):
|
||||
raise ValueError("初始湿度必须在0-100%之间")
|
||||
if not (0 < field_capacity <= 100):
|
||||
raise ValueError("田间持水量必须在0-100%之间且大于0")
|
||||
if irrigation_volume < 0:
|
||||
raise ValueError("灌溉量不能为负数")
|
||||
if soil_volume <= 0:
|
||||
raise ValueError("土壤体积必须大于0")
|
||||
|
||||
# 计算初始土壤含水量(m³)
|
||||
initial_water = (initial_moisture / 100) * (field_capacity / 100) * soil_volume
|
||||
|
||||
# 灌溉后总含水量(m³)
|
||||
total_water = initial_water + irrigation_volume
|
||||
|
||||
# 计算田间持水总量(m³)
|
||||
max_water = (field_capacity / 100) * soil_volume
|
||||
|
||||
# 计算灌溉后湿度(超过田间持水量时取100%)
|
||||
final_moisture = min((total_water / max_water) * 100, 100.0)
|
||||
|
||||
# if verbose:
|
||||
# area_info = f"(面积: {area}㎡)" if area else ""
|
||||
# print(f"===== 不考虑降雨与蒸散的灌溉计算 {area_info} =====")
|
||||
# print(f"初始湿度: {initial_moisture}%")
|
||||
# print(f"田间持水量: {field_capacity}%")
|
||||
# print(f"土壤体积: {soil_volume}m³")
|
||||
# print(f"灌溉量: {irrigation_volume}m³")
|
||||
# print(f"初始含水量: {initial_water:.2f}m³")
|
||||
# print(f"灌溉后含水量: {total_water:.2f}m³")
|
||||
# print(f"田间最大持水量: {max_water:.2f}m³")
|
||||
# print(f"灌溉后土壤湿度: {final_moisture:.2f}%")
|
||||
|
||||
return final_moisture
|
||||
def calculate_irrigation_volume(
|
||||
initial_moisture: float,
|
||||
target_moisture: float,
|
||||
field_capacity: float,
|
||||
soil_volume: float
|
||||
) -> float:
|
||||
"""
|
||||
计算为达到目标土壤相对湿度所需的灌溉量
|
||||
|
||||
参数:
|
||||
initial_moisture: 初始土壤相对湿度 (%)
|
||||
target_moisture: 目标土壤相对湿度 (%)
|
||||
field_capacity: 田间持水量 (%)
|
||||
soil_volume: 土壤体积 (m³)
|
||||
area: 灌溉面积 (㎡,可选,仅用于打印提示)
|
||||
verbose: 是否打印详细计算过程
|
||||
|
||||
返回:
|
||||
float: 需要的灌溉量 (m³)
|
||||
"""
|
||||
# 参数验证
|
||||
if not (0 <= initial_moisture <= 100):
|
||||
raise ValueError("初始湿度必须在0-100%之间")
|
||||
if not (0 <= target_moisture <= 100):
|
||||
raise ValueError("目标湿度必须在0-100%之间")
|
||||
if not (0 < field_capacity <= 100):
|
||||
raise ValueError("田间持水量必须在0-100%之间且大于0")
|
||||
if soil_volume <= 0:
|
||||
raise ValueError("土壤体积必须大于0")
|
||||
if target_moisture <= initial_moisture:
|
||||
raise ValueError("目标湿度必须大于初始湿度")
|
||||
|
||||
# 计算初始土壤含水量(m³)
|
||||
initial_water = (initial_moisture / 100) * (field_capacity / 100) * soil_volume
|
||||
|
||||
# 计算目标含水量(m³)
|
||||
target_water = (target_moisture / 100) * (field_capacity / 100) * soil_volume
|
||||
|
||||
# 需要的灌溉量
|
||||
irrigation_volume = target_water - initial_water
|
||||
|
||||
return irrigation_volume
|
||||
def irriDepth_irrvolume(area,irrDepth):
|
||||
volume=area*667*(irrDepth/1000)
|
||||
return volume
|
||||
|
||||
|
||||
def calculate_irrigation(dry_soil_weight, current_humidity, target_humidity,
|
||||
irrigation_efficiency=0.8, water_density=1000):
|
||||
"""
|
||||
计算达到目标湿度所需的灌溉量
|
||||
|
||||
Args:
|
||||
dry_soil_weight (float): 土壤干重(kg)
|
||||
current_humidity (float): 当前相对湿度(%)
|
||||
target_humidity (float): 目标相对湿度(%)
|
||||
irrigation_efficiency (float): 灌溉效率(0~1)
|
||||
water_density (float): 水密度(kg/m³)
|
||||
|
||||
Returns:
|
||||
float: 灌溉量(立方米)
|
||||
"""
|
||||
if current_humidity >= target_humidity:
|
||||
return 0.0
|
||||
|
||||
delta_humidity = (target_humidity - current_humidity) / 100
|
||||
water_weight = dry_soil_weight * delta_humidity
|
||||
water_volume = water_weight / water_density
|
||||
return water_volume / irrigation_efficiency
|
||||
def calculate_rh_target(
|
||||
initial_moisture: float,
|
||||
root: float,
|
||||
field_capacity: float,
|
||||
irrigation:float
|
||||
) -> float:
|
||||
initial_moisture=(initial_moisture / 100) * field_capacity
|
||||
iir_volume=irrigation/(10*root)
|
||||
target_moisture = initial_moisture + (iir_volume/field_capacity)
|
||||
return target_moisture
|
||||
|
||||
|
||||
def calculate_rh_target(
|
||||
initial_moisture: float, # 初始土壤相对湿度(%)
|
||||
root: float, # 根系深度(cm)
|
||||
field_capacity: float, # 田间持水量(体积含水量 cm³/cm³)
|
||||
irrigation: float # 灌溉量(mm)
|
||||
) -> float:
|
||||
"""
|
||||
计算灌溉后的目标土壤相对湿度(%)
|
||||
|
||||
参数:
|
||||
initial_moisture: 初始土壤相对湿度(%)
|
||||
root: 根系深度(cm)
|
||||
field_capacity: 田间持水量(体积含水量 cm³/cm³)
|
||||
irrigation: 灌溉量(mm)
|
||||
|
||||
返回:
|
||||
float: 灌溉后的目标土壤相对湿度(%)
|
||||
"""
|
||||
# 参数验证
|
||||
if initial_moisture < 0 or initial_moisture > 100:
|
||||
raise ValueError("初始湿度必须在0-100%之间")
|
||||
if root <= 0:
|
||||
raise ValueError("根系深度必须大于0")
|
||||
if field_capacity <= 0 or field_capacity > 1:
|
||||
raise ValueError("田间持水量必须在0-1 cm³/cm³之间")
|
||||
if irrigation < 0:
|
||||
raise ValueError("灌溉量不能为负值")
|
||||
|
||||
# 将相对湿度转为体积含水量
|
||||
initial_volume_moisture = (initial_moisture / 100) * field_capacity
|
||||
|
||||
# 计算灌溉增加的体积含水量
|
||||
# 将mm转为cm,并除以根系深度得到体积含水量增量
|
||||
moisture_increase = (irrigation / 10) / root
|
||||
|
||||
# 计算灌溉后的体积含水量
|
||||
target_volume_moisture = initial_volume_moisture + moisture_increase
|
||||
# 转换回相对湿度(%)
|
||||
target_rh = (target_volume_moisture / field_capacity) * 100
|
||||
|
||||
# 确保不超过100%
|
||||
target_rh = min(target_rh, 100.0)
|
||||
|
||||
# # 3. 计算目标体积含水量 (不超过田间持水量)
|
||||
# target_volume = min(initial_volume + moisture_increase, field_capacity)
|
||||
#
|
||||
# # 4. 转换回相对湿度 (%)
|
||||
# target_rh = (target_volume / field_capacity) * 100
|
||||
|
||||
return target_rh
|
||||
|
||||
|
||||
def calculate_rh_target_rz(
|
||||
initial_moisture: float, # 初始土壤相对湿度(%)
|
||||
soil_root: float, # 根系深度(cm)
|
||||
area: float, # 灌溉面积(亩)
|
||||
irrigation: float, # 灌溉量(mm)
|
||||
field_capacity: float = 28.84, # 田间持水量(%),默认35%
|
||||
soil_bulk_density: float = 1.5 # 土壤容重(g/cm³),默认1.5
|
||||
) -> float:
|
||||
"""
|
||||
计算灌溉后的目标根区土壤相对湿度
|
||||
|
||||
参数:
|
||||
initial_moisture: 初始土壤相对湿度(%)
|
||||
soil_root: 根系深度(cm)
|
||||
area: 灌溉面积(亩)
|
||||
irrigation: 灌溉量(mm)
|
||||
field_capacity: 田间持水量(%),默认35%
|
||||
soil_bulk_density: 土壤容重(g/cm³),默认1.5
|
||||
|
||||
返回:
|
||||
float: 灌溉后的目标土壤相对湿度(%)
|
||||
"""
|
||||
# 参数验证
|
||||
if initial_moisture < 0 or initial_moisture > 100:
|
||||
raise ValueError("初始湿度必须在0-100%之间")
|
||||
if soil_root <= 0:
|
||||
raise ValueError("根系深度必须大于0")
|
||||
if area <= 0:
|
||||
raise ValueError("面积必须大于0")
|
||||
if irrigation < 0:
|
||||
raise ValueError("灌溉量不能为负值")
|
||||
|
||||
# 计算根区体积
|
||||
root_volume = area * 667 * (soil_root / 100) # m³,将cm转为m
|
||||
|
||||
# 计算灌溉水体积
|
||||
water_volume = (irrigation / 1000) * area * 667 # m³,将mm转为m
|
||||
|
||||
# 计算灌溉增加的土壤湿度(%)
|
||||
moisture_increase = (water_volume / (root_volume * soil_bulk_density)) * 100
|
||||
|
||||
# 计算目标湿度
|
||||
target_moisture = initial_moisture + moisture_increase
|
||||
|
||||
# 确保不超过田间持水量
|
||||
target_moisture = min(target_moisture, field_capacity)
|
||||
|
||||
return target_moisture
|
||||
if __name__ == '__main__':
|
||||
# volume=irriDepth_irrvolume(10.95,11.123)
|
||||
# soil_volume_dk1 = 10.95 * 667 * 0.15
|
||||
# soil_volume_dk2 = 8.92 * 667 * 0.15
|
||||
# result1 = calculate_soil_moisture_after_irrigation(
|
||||
# initial_moisture=15.2,
|
||||
# field_capacity=28.84,
|
||||
# irrigation_volume=168,
|
||||
# soil_volume=soil_volume_dk1,
|
||||
# verbose=True
|
||||
# )
|
||||
# print(f"\n示例1结果: 灌溉后湿度 = {result1:.2f}%\n")
|
||||
# print(soil_volume_dk1)
|
||||
# result2=calculate_irrigation_volume(initial_moisture=15.44,
|
||||
# field_capacity=28.84,
|
||||
# target_moisture=70,
|
||||
# soil_volume=soil_volume_dk1)
|
||||
# print(f"\n达到目标湿度所需灌溉量 = {result2:.2f}\n")
|
||||
# # 调用示例
|
||||
# dry_soil_weight=10.95*667*0.1*1200
|
||||
# volume = calculate_irrigation(
|
||||
# dry_soil_weight=dry_soil_weight,
|
||||
# current_humidity=15.4,
|
||||
# target_humidity=70
|
||||
# )
|
||||
# print(f"灌溉量: {volume:.2f} m³") # 输出: 0.09 m³
|
||||
rh=calculate_rh_target(67.96,6,0.2884,33.14)
|
||||
rh1 = rh*0.7
|
||||
print(rh,rh1)
|
||||
133
irrgiation/soil_Ke.py
Normal file
133
irrgiation/soil_Ke.py
Normal file
@@ -0,0 +1,133 @@
|
||||
# 计算土壤蒸发系数
|
||||
def calculate_ke(h, u2, rh_min, k_cb, DE_i_1,REW,fw,theta_fc,theta_wp):
|
||||
"""
|
||||
计算土壤蒸发系数 ke
|
||||
参数:
|
||||
h: 株高(m)
|
||||
u2: 2米高处风速(m/s)
|
||||
rh_min: 最小相对湿度(%)
|
||||
k_cb: 基础作物系数
|
||||
DE_i_1: 前一天从土壤表层蒸发的累积深度(mm)
|
||||
TEW: 总可蒸发水量(mm)
|
||||
REW: 易蒸发水量(mm)
|
||||
few: 裸露湿润的土壤的比值
|
||||
返回:
|
||||
ke: 土壤蒸发系数
|
||||
"""
|
||||
K_cmin = 0.175
|
||||
Z_e=0.12
|
||||
kc_max = calculate_kc_max(h, u2, rh_min, k_cb)
|
||||
fc = calculate_fc(k_cb, K_cmin, kc_max, h)
|
||||
few = calculate_fev(fc, fw)
|
||||
TEW = calculate_tew(theta_fc, theta_wp, Z_e)
|
||||
kr = calculate_Kr(DE_i_1, TEW, REW)
|
||||
term1 = kr * (kc_max - k_cb)
|
||||
term2 = few * k_cb
|
||||
return min(term1, term2),few
|
||||
|
||||
# 每日土壤蒸发量累积量
|
||||
#土壤蒸发有效部分
|
||||
def calculate_fev(fc, fw):
|
||||
fev = min(1 - fc, fw)
|
||||
return fev
|
||||
#计算作物覆盖率fc
|
||||
def calculate_fc(Kcb, Kcmin, Kcmax, h):
|
||||
#Kcb:作物基础系数,Kcmin:无地表覆盖的干燥土壤最小 值(约为 0.15-0.20),Kcmax:紧随湿润过程的土壤最大 值
|
||||
|
||||
fc = ((Kcb- Kcmin) / (Kcmax - Kcmin)) ** (1 + 0.5 * h)
|
||||
return fc
|
||||
# 计算蒸发减少系数
|
||||
def calculate_Kr(DE_i_1, TEW, REW):
|
||||
if DE_i_1 <= REW:
|
||||
Kr = 1
|
||||
else:
|
||||
print("dd")
|
||||
Kr = (TEW - DE_i_1) / (TEW - REW)
|
||||
return Kr
|
||||
#计算Kcmax
|
||||
def calculate_kc_max(h: float, u2: float, rh_min: float, k_cb: float) -> float:
|
||||
"""
|
||||
计算作物系数上限 kc_max
|
||||
参数:
|
||||
h: 株高(m)
|
||||
u2: 2米高处风速(m/s)
|
||||
rh_min: 最小相对湿度(%)
|
||||
k_cb: 基础作物系数
|
||||
返回:
|
||||
kc_max: 作物系数上限
|
||||
"""
|
||||
term1 = 1.2 + (0.04 * (u2 - 2) - 0.004 * (rh_min - 45)) * (h / 3) ** 0.3
|
||||
term2 = k_cb + 0.5
|
||||
return max(term1, term2)
|
||||
#计算TEW
|
||||
def calculate_tew(theta_fc: float, theta_wp: float, Z_e: float) -> float:
|
||||
"""
|
||||
计算总可蒸发水量 TEW
|
||||
参数:
|
||||
theta_fc: 田间持水量(m³/m³)
|
||||
theta_wp: 萎蔫系数(m³/m³)
|
||||
Z_e: 土壤蒸发层深度(cm)
|
||||
返回:
|
||||
TEW: 总可蒸发水量(mm)
|
||||
"""
|
||||
return 1000 * (theta_fc - theta_wp) * Z_e
|
||||
# 计算深层渗漏损失
|
||||
def calculate_DP_ei(P_i, RO_i, I_i, D_e_prev, f_w):
|
||||
if (P_i - RO_i) + I_i / f_w - D_e_prev >= 0:
|
||||
return (P_i - RO_i) + I_i / f_w - D_e_prev
|
||||
else:
|
||||
return 0
|
||||
|
||||
# 计算每日土壤蒸发量累积量
|
||||
def calculate_D_ei(D_e_prev, P_i, I_i, E_i, f_w, f_ew):
|
||||
RO_i=0
|
||||
T_ew_i=0
|
||||
DP_ei = calculate_DP_ei(P_i, RO_i, I_i, D_e_prev, f_w)
|
||||
D_ei = D_e_prev - (P_i - RO_i) - I_i / f_w + E_i / f_ew + T_ew_i + DP_ei
|
||||
return D_ei
|
||||
# 示例计算
|
||||
if __name__ == "__main__":
|
||||
# # 示例参数
|
||||
# h = 0.07 # 株高(m)
|
||||
# u2 = 3.0 # 2米高处风速(m/s)
|
||||
# rh_min = 20.0 # 最小相对湿度(%)
|
||||
# k_cb = 0.4 # 基础作物系数
|
||||
# K_s = 0.6 # 土壤导水率
|
||||
# K_cmin = 0.175
|
||||
#
|
||||
# fw = 0.35 # 土壤表层被灌溉浸湿的部分
|
||||
# DE_i = 6.24 # 前一天从土壤表层蒸发的累积深度(mm)
|
||||
# DE_i_1 = 2.965 # 前一天从土壤表层蒸发的累积深度(mm)
|
||||
# theta_fc = 0.2884 # 田间持水量(m³/m³)
|
||||
# theta_wp = 0.1086 # 萎蔫系数(m³/m³)
|
||||
# Z_e = 0.1 # 土壤蒸发层深度(m)
|
||||
#
|
||||
# # # # 计算 TEW
|
||||
# # TEW = calculate_tew(theta_fc, theta_wp, Z_e)
|
||||
# REW = 5.178 # 假设REW为TEW的40%
|
||||
# # #
|
||||
# # # # 计算各参数
|
||||
# # kc_max = calculate_kc_max(h, u2, rh_min, k_cb)
|
||||
# # fc = calculate_fc(k_cb, K_cmin, kc_max, h)
|
||||
# # few= calculate_fev(fc, fw)
|
||||
# # kr = calculate_Kr(DE_i_1,DE_i, TEW, REW)
|
||||
# ke=calculate_ke(h, u2, rh_min, k_cb, DE_i_1,DE_i,REW)
|
||||
# # 输出结果
|
||||
#
|
||||
# print(f"土壤蒸发系数 Ke: {ke:.4f}")
|
||||
# 假设初始参数
|
||||
TEW = 1000 # 总可蒸发水量,单位:mm
|
||||
D_e_start = TEW # 模拟开始时的初始D_e
|
||||
D_e_prev = 0 # 模拟第一天的D_e,假设充分灌溉后为0
|
||||
# 假设一些每日数据,实际应用中需替换为真实数据
|
||||
P_i = 10 # 第i天的降雨量,单位:mm
|
||||
RO_i = 0 # 第i天的降雨形成地表径流量,这里假定为0,单位:mm
|
||||
I_i = 19 # 第i天渗入土壤的灌溉量,单位:mm
|
||||
k_e = 0.14 # 土壤蒸发系数
|
||||
ET_o = 8.188 # 参考作物蒸散量,单位:mm
|
||||
E_i = k_e * ET_o # 第i天的蒸发量
|
||||
T_ew_i = 0 # 第i天湿润裸露表层土壤的蒸腾量,这里假定为0,单位:mm
|
||||
f_w = 0.8 # 经灌溉湿润的土壤面积比值
|
||||
f_ew = 0.6 # 裸露湿润土壤面积比值
|
||||
D_ei = calculate_D_ei(D_e_prev, P_i, RO_i, I_i, f_w, f_ew)
|
||||
print(f"第i天末土壤完全湿润后的累积蒸发(消耗)量为: {D_ei} mm")
|
||||
10
irrgiation/utils.py
Normal file
10
irrgiation/utils.py
Normal file
@@ -0,0 +1,10 @@
|
||||
dk_irriationInfo={
|
||||
"1号地":{
|
||||
"dkbm":1,
|
||||
"irriationFile":"D:/悦柠/遥感/甘草/model_result/1号地_灌溉数据.xlsx"
|
||||
},
|
||||
"5号地":{
|
||||
"dkbm":5,
|
||||
"irriationFile":"D:/悦柠/遥感/甘草/model_result/5号地_灌溉数据.xlsx"
|
||||
}
|
||||
}
|
||||
336
irrgiation/weatherAndSoilDataRequest.py
Normal file
336
irrgiation/weatherAndSoilDataRequest.py
Normal file
@@ -0,0 +1,336 @@
|
||||
from datetime import datetime, timezone, timedelta, date
|
||||
|
||||
import pandas as pd
|
||||
import requests
|
||||
import json
|
||||
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
|
||||
#登录接口认证
|
||||
|
||||
def loginAuth():
|
||||
# 接口地址
|
||||
global auth_token
|
||||
url = "https://xj-tb.maimaiag.com/api/auth/login" # 请替换为实际地址
|
||||
|
||||
# 请求头
|
||||
headers = {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
# 请求体数据
|
||||
payload = {
|
||||
"username": "read@xj.com",
|
||||
"password": "maimai"
|
||||
}
|
||||
|
||||
try:
|
||||
# 发送POST请求
|
||||
response = requests.post(
|
||||
url,
|
||||
headers=headers,
|
||||
data=json.dumps(payload) # 或者直接使用 json=payload
|
||||
)
|
||||
|
||||
# 检查响应状态码
|
||||
if response.status_code == 200:
|
||||
print("登录成功!")
|
||||
print("响应数据:", response.json())
|
||||
|
||||
# 通常登录接口会返回token,可以这样获取
|
||||
response_data = response.json()
|
||||
auth_token = response_data.get("token") # 根据实际返回字段调整
|
||||
if auth_token:
|
||||
print("获取到的认证Token:", auth_token)
|
||||
else:
|
||||
print(f"登录失败,状态码: {response.status_code}")
|
||||
print("错误信息:", response.text)
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"请求发生异常: {str(e)}")
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"JSON解析错误: {str(e)}")
|
||||
return auth_token
|
||||
# 调用数据接口--历史数据
|
||||
def getWeatherAndSoilData(auth_token,device_id,startTs,endTs,agg,interval,limit,orderBy,keys):
|
||||
# 配置信息
|
||||
BASE_URL = "https://xj-tb.maimaiag.com/" # 请替换为实际API地址
|
||||
TOKEN = auth_token # 替换为实际的Bearer token
|
||||
DEVICE_ID = device_id # 替换为实际的设备ID
|
||||
# 构造请求URL
|
||||
endpoint = f"/api/plugins/telemetry/DEVICE/{DEVICE_ID}/values/timeseries"
|
||||
url = BASE_URL + endpoint
|
||||
# 请求头
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Authorization": f"Bearer+{TOKEN}"
|
||||
}
|
||||
# 查询参数
|
||||
params = {
|
||||
"keys": keys, # 要查询的参数,多个用逗号分隔
|
||||
"startTs": startTs, # 开始时间戳(毫秒)- 可选
|
||||
"endTs": endTs, # 结束时间戳(毫秒)- 可选
|
||||
"agg": agg, # 聚合函数 - 可选
|
||||
"interval": interval, # 聚合间隔(毫秒)- 可选
|
||||
"limit": limit, # 返回条数 - 可选
|
||||
"orderBy": orderBy # 排序方式 - 可选
|
||||
}
|
||||
try:
|
||||
# 发送GET请求
|
||||
response = requests.get(
|
||||
url,
|
||||
headers=headers,
|
||||
params=params
|
||||
)
|
||||
# 检查响应状态码
|
||||
if response.status_code == 200:
|
||||
# print("请求成功!")
|
||||
data = response.json()
|
||||
# print("响应数据:", json.dumps(data, indent=2))
|
||||
converted_data = {k: convert_timestamp_to_datetime(v) for k, v in data.items()}
|
||||
return converted_data
|
||||
elif response.status_code == 401:
|
||||
print("认证失败,请检查Token是否正确")
|
||||
elif response.status_code == 404:
|
||||
print("设备不存在或路径错误")
|
||||
else:
|
||||
print(f"请求失败,状态码: {response.status_code}")
|
||||
print("错误信息:", response.text)
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"请求发生异常: {str(e)}")
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"JSON解析错误: {str(e)}")
|
||||
print("原始响应:", response.text)
|
||||
def convert_timestamp_to_datetime(data_dict):
|
||||
"""
|
||||
递归地将字典中的所有'timestamp'字段转换为可读的日期时间格式
|
||||
保留原始时间戳的同时添加新的'datetime'字段
|
||||
"""
|
||||
if isinstance(data_dict, dict):
|
||||
if "ts" in data_dict:
|
||||
# 转换毫秒时间戳为datetime对象
|
||||
timestamp_sec = data_dict["ts"] / 1000
|
||||
dt = datetime.fromtimestamp(timestamp_sec)
|
||||
# 添加新字段,保留原始时间戳
|
||||
data_dict["datetime"] = dt.strftime("%Y-%m-%d %H:%M:%S")
|
||||
return data_dict
|
||||
elif isinstance(data_dict, list):
|
||||
return [convert_timestamp_to_datetime(item) for item in data_dict]
|
||||
else:
|
||||
return data_dict
|
||||
|
||||
def dateToTimestamp(date):
|
||||
# dt = datetime.strptime(date, "%Y-%m-%d %H:%M:%S")
|
||||
if isinstance(date, datetime):
|
||||
# 如果已经是datetime对象,直接使用
|
||||
dt = date
|
||||
elif isinstance(date, str):
|
||||
# 如果是字符串,解析为datetime对象
|
||||
dt = datetime.strptime(date, "%Y-%m-%d %H:%M:%S.%f")
|
||||
else:
|
||||
raise TypeError("date参数必须是字符串或datetime对象")
|
||||
timestamp_ms = int(dt.timestamp() * 1000)
|
||||
return timestamp_ms
|
||||
|
||||
#调用接口获取未来气象数据
|
||||
def getFutureWeather(monitor_date):
|
||||
base_url_future="https://api.open-meteo.com/"
|
||||
end_point="v1/forecast"
|
||||
current_date = datetime.now().date()
|
||||
params = {
|
||||
"latitude": "41.34252110189814", # 纬度
|
||||
"longitude": "86.28810755462379", # 经度
|
||||
"hourly": "temperature_2m,precipitation,precipitation_probability"
|
||||
}
|
||||
# if monitor_date.date()<current_date:
|
||||
# # url = base_url_history + end_point
|
||||
# params["start_date"] = (monitor_date + timedelta(days=1)).strftime("%Y-%m-%d")
|
||||
# params["end_date"] = (monitor_date + timedelta(days=3)).strftime("%Y-%m-%d")
|
||||
#
|
||||
# else:
|
||||
url = base_url_future + end_point
|
||||
params["forecast_days"]= 4
|
||||
|
||||
try:
|
||||
# 发送GET请求
|
||||
response = requests.get(
|
||||
url,
|
||||
params=params
|
||||
)
|
||||
# 检查响应状态码
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
result={}
|
||||
if monitor_date.date()<current_date:
|
||||
result["qw_day1"] = get_tjvalue(data['hourly']['temperature_2m'][:24])
|
||||
result["qw_day2"] = get_tjvalue(data['hourly']['temperature_2m'][24:48])
|
||||
result["qw_day3"] = get_tjvalue(data['hourly']['temperature_2m'][48:72])
|
||||
result["js_day1"] = get_tjvalue(data['hourly']['precipitation'][:24])
|
||||
result["js_day2"] = get_tjvalue(data['hourly']['precipitation'][24:48])
|
||||
result["js_day3"] = get_tjvalue(data['hourly']['precipitation'][48:72])
|
||||
else:
|
||||
result["qw_day1"] = get_tjvalue(data['hourly']['temperature_2m'][24:48])
|
||||
result["qw_day2"] = get_tjvalue(data['hourly']['temperature_2m'][48:72])
|
||||
result["qw_day3"] = get_tjvalue(data['hourly']['temperature_2m'][72:96])
|
||||
result["js_day1"] = get_tjvalue(data['hourly']['precipitation'][24:48])
|
||||
result["js_day2"] = get_tjvalue(data['hourly']['precipitation'][48:72])
|
||||
result["js_day3"] = get_tjvalue(data['hourly']['precipitation'][72:96])
|
||||
return result
|
||||
elif response.status_code == 401:
|
||||
print("认证失败,请检查Token是否正确")
|
||||
elif response.status_code == 404:
|
||||
print("设备不存在或路径错误")
|
||||
else:
|
||||
print(f"请求失败,状态码: {response.status_code}")
|
||||
print("错误信息:", response.text)
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"请求发生异常: {str(e)}")
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"JSON解析错误: {str(e)}")
|
||||
print("原始响应:", response.text)
|
||||
def get_tjvalue(data):
|
||||
result={}
|
||||
max_val = max(data)
|
||||
min_val = min(data)
|
||||
mean_val = sum(data) / len(data)
|
||||
sum_val = sum(data)
|
||||
result['max']=max_val
|
||||
result['min']=min_val
|
||||
result['mean']=mean_val
|
||||
result['sum'] = sum_val
|
||||
return result
|
||||
soil_params={
|
||||
"1号传感器":{
|
||||
"device_id":"31fbb2d0-561b-11f0-a556-4f10f26fc07f"
|
||||
},
|
||||
"2号传感器": {
|
||||
"device_id": "3bf4cc90-561b-11f0-a556-4f10f26fc07f"
|
||||
},
|
||||
"3号传感器": {
|
||||
"device_id": "43a57cf0-561b-11f0-a556-4f10f26fc07f"
|
||||
},
|
||||
"4号传感器": {
|
||||
"device_id": "4ff6b780-561b-11f0-a556-4f10f26fc07f"
|
||||
},
|
||||
"5号传感器": {
|
||||
"device_id": "598c5480-561b-11f0-a556-4f10f26fc07f"
|
||||
},
|
||||
"6号传感器": {
|
||||
"device_id": "6ff07260-561b-11f0-a556-4f10f26fc07f"
|
||||
},
|
||||
"7号传感器": {
|
||||
"device_id": "8637b970-561b-11f0-a556-4f10f26fc07f"
|
||||
},
|
||||
"8号传感器": {
|
||||
"device_id": "955de5f0-561b-11f0-a556-4f10f26fc07f"
|
||||
},
|
||||
"9号传感器": {
|
||||
"device_id": "a24e94d0-561b-11f0-a556-4f10f26fc07f"
|
||||
},
|
||||
"10号传感器": {
|
||||
"device_id": "adb7e060-561b-11f0-a556-4f10f26fc07f"
|
||||
},
|
||||
"11号传感器": {
|
||||
"device_id": "b74c6bf0-561b-11f0-a556-4f10f26fc07f"
|
||||
},
|
||||
"12号传感器": {
|
||||
"device_id": "c0f36e10-561b-11f0-a556-4f10f26fc07f"
|
||||
},
|
||||
|
||||
}
|
||||
def get_soil_data_dk1(auth_token,startTs, endTs):
|
||||
keys_soil = "SOIL_MOISTURE_SURFACE,SOIL_MOISTURE_MIDDLE,SOIL_MOISTURE_BOTTOM"
|
||||
limit = ""
|
||||
orderBy = ""
|
||||
result={}
|
||||
for key in soil_params:
|
||||
id=soil_params[key]['device_id']
|
||||
soil_data = getWeatherAndSoilData(auth_token,id, startTs, endTs, "AVG", 3600000, limit, orderBy,
|
||||
keys_soil)
|
||||
result[key]=soil_data
|
||||
return result
|
||||
def get_soil_data_dk2(auth_token,device_id,startTs, endTs):
|
||||
keys_soil = "SOIL_MOISTURE_SURFACE,SOIL_MOISTURE_MIDDLE,SOIL_MOISTURE_BOTTOM"
|
||||
limit = ""
|
||||
orderBy = ""
|
||||
result={}
|
||||
soil_data = getWeatherAndSoilData(auth_token,device_id, startTs, endTs, "AVG", 3600000, limit, orderBy,
|
||||
keys_soil)
|
||||
result[device_id]=soil_data
|
||||
return result
|
||||
weather_params={
|
||||
"device_id" : "18d121f0-561b-11f0-a556-4f10f26fc07f",
|
||||
"agg" :"AVG",
|
||||
"interval" : 3600000, #1小时
|
||||
"limit" :"",
|
||||
"orderBy" : "",
|
||||
"keys":"AIR_TEMPERATURE,WIND_SPEED,AIR_LUX,AIR_HUMIDITY,RAIN_FALL_REALTIME"
|
||||
}
|
||||
def get_plot(data_list):
|
||||
df = pd.DataFrame(data_list)
|
||||
df['value'] = pd.to_numeric(df['value'], errors='coerce').round(3)# 转换湿度值为浮点数
|
||||
df['datetime'] = pd.to_datetime(df['datetime']) # 转换为datetime类型
|
||||
|
||||
# 设置画布大小
|
||||
plt.figure(figsize=(12, 6))
|
||||
|
||||
# 绘制折线图
|
||||
plt.plot(df['datetime'], df['value'],
|
||||
color='teal',
|
||||
linestyle='-',
|
||||
linewidth=2,
|
||||
marker='o',
|
||||
markersize=4,
|
||||
markerfacecolor='orange',
|
||||
markeredgecolor='orange',
|
||||
label='Soil Moisture (%)')
|
||||
|
||||
# 添加22点后的数据高亮(符合你之前获取夜间数据的需求)
|
||||
night_data = df[df['datetime'].dt.hour >= 22]
|
||||
plt.scatter(night_data['datetime'], night_data['value'],
|
||||
color='red',
|
||||
s=30,
|
||||
label='22:00-06:00 Data')
|
||||
|
||||
# 设置标题和坐标轴标签
|
||||
plt.title('Soil Moisture Time Series (2025-06-22 to 2025-06-30)',
|
||||
fontsize=14,
|
||||
pad=15)
|
||||
plt.xlabel('Datetime', fontsize=12, labelpad=10)
|
||||
plt.ylabel('Soil Moisture (%)', fontsize=12, labelpad=10)
|
||||
|
||||
# 设置x轴刻度旋转,避免重叠
|
||||
plt.xticks(rotation=45, ha='right', fontsize=10)
|
||||
|
||||
# 添加网格线
|
||||
plt.grid(axis='y', linestyle='--', alpha=0.7)
|
||||
|
||||
# 添加图例
|
||||
plt.legend(loc='upper right', fontsize=10)
|
||||
|
||||
# 调整布局
|
||||
plt.tight_layout()
|
||||
|
||||
# 显示图表
|
||||
plt.show()
|
||||
if __name__ == "__main__":
|
||||
auth_token = loginAuth()
|
||||
device_id="18d121f0-561b-11f0-a556-4f10f26fc07f"
|
||||
agg="AVG"
|
||||
interval=21600000
|
||||
limit=""
|
||||
orderBy=""
|
||||
keys="RAIN_FALL_REALTIME"
|
||||
date_start = "2025-06-25 00:00:00.123"
|
||||
date_end = "2025-07-01 23:59:59.123"
|
||||
startTs=dateToTimestamp(date_start)
|
||||
endTs=dateToTimestamp(date_end)
|
||||
# data=get_soil_data_dk1(auth_token,startTs,endTs)
|
||||
# print(data)
|
||||
data=getWeatherAndSoilData(auth_token,device_id,startTs,endTs,"AVG",3600000,limit,orderBy,keys)
|
||||
print(data['RAIN_FALL'])
|
||||
# get_plot(data['1号传感器']['SOIL_MOISTURE_SURFACE'])
|
||||
get_plot(data['RAIN_FALL_REALTIME'])
|
||||
Reference in New Issue
Block a user