基于月尺度水分平衡模型的葡萄园规划与行间管理决策

适用于葡萄园规划的月尺度水分平衡模型,并将其集成到决策支持系统(DSS)中,以帮助种植者应对气候变化的挑战。
葡萄园水分平衡决策支持系统包含以下核心功能:
1. 用户输入界面
-
葡萄园特征:架式系统、行距、架高、架宽、植株年龄等
-
土壤参数:土壤水文组、田间持水量、萎蔫点、土壤深度等
-
气象数据:12个月的月平均气温和月降雨量
-
管理措施:永久草被(PG)、清耕(CT)、绿肥(GM)
2. 核心计算模型
-
基于Thornthwaite-Mather方法的水分平衡计算
-
土壤水势计算(Saxton方程)
-
水分胁迫风险评估(根据植株年龄和物候阶段)
-
作物系数动态计算
3. 可视化分析
-
水分平衡组分图:展示降雨量、径流量和蒸发散量
-
土壤水分动态图:显示土壤水分储量变化及关键阈值
-
胁迫风险时间序列:直观展示各月风险等级
-
作物系数变化图:显示葡萄和覆盖作物的作物系数变化
4. 决策支持
-
基于年度风险等级的管理建议
-
针对幼株的特别管理建议
-
不同管理措施的优化建议
-
土壤改良和灌溉规划建议
5. 关键指标展示
-
年度降雨总量
-
年蒸发散量
-
水分利用效率
-
年度水分亏缺量
-
年度胁迫风险等级
# vineyard_water_balance_dss.py
import streamlit as st
import pandas as pd
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import math
from datetime import datetime
import warningswarnings.filterwarnings('ignore')# 页面配置
st.set_page_config(page_title="葡萄园水分平衡决策支持系统",page_icon="🍇",layout="wide",initial_sidebar_state="expanded"
)# 自定义CSS样式
st.markdown("""
<style>.main-header {font-size: 2.5rem;color: #2E8B57;text-align: center;margin-bottom: 2rem;}.metric-card {background-color: #f0f8f0;padding: 1rem;border-radius: 10px;border-left: 4px solid #2E8B57;margin: 0.5rem 0;}.risk-negligible { color: #28a745; font-weight: bold; }.risk-moderate { color: #ffc107; font-weight: bold; }.risk-high { color: #fd7e14; font-weight: bold; }.risk-very-high { color: #dc3545; font-weight: bold; }.section-header {background: linear-gradient(90deg, #2E8B57, #3CB371);color: white;padding: 0.5rem 1rem;border-radius: 5px;margin: 1rem 0;}.recommendation-card {background-color: #f8f9fa;border-radius: 10px;padding: 1rem;margin-bottom: 1rem;box-shadow: 0 4px 6px rgba(0,0,0,0.1);}.recommendation-header {font-weight: bold;margin-bottom: 0.5rem;display: flex;align-items: center;}.priority-high { color: #dc3545; }.priority-medium { color: #fd7e14; }.priority-low { color: #28a745; }
</style>
""", unsafe_allow_html=True)class VineyardWaterBalanceModel:"""葡萄园水分平衡模型核心计算类 - 基于Thornthwaite-Mather方法"""def __init__(self):self.months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']self.growth_months = ['4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月']def calculate_thermal_index(self, monthly_temps):"""计算热力指数 - 公式A2"""I = sum([(max(0, temp) / 5) ** 1.514 for temp in monthly_temps])return Idef calculate_alpha(self, I):"""计算alpha系数 - 公式A3"""if I == 0:return 0alpha = 0.49239 + 0.01792 * I - 0.0000771 * I ** 2 + 0.000000675 * I ** 3return alphadef calculate_potential_evapotranspiration(self, temp, I, daylight_hours=12):"""计算潜在蒸发散 - 公式A1"""if I == 0 or temp <= 0:return 0alpha = self.calculate_alpha(I)pe = 16 * (10 * temp / I) ** alpha# 调整实际日照时数pe_adjusted = pe * daylight_hours / 12return max(0, pe_adjusted)def scs_curve_number(self, soil_group, management):"""SCS曲线数计算 - 基于土壤水文组和管理措施"""cn_values = {'A': {'PG': 65, 'CT': 78, 'GM': 70},'B': {'PG': 75, 'CT': 85, 'GM': 79},'C': {'PG': 82, 'CT': 90, 'GM': 84},'D': {'PG': 86, 'CT': 92, 'GM': 88}}return cn_values.get(soil_group, {}).get(management, 80)def calculate_runoff(self, rainfall, soil_group, management):"""SCS径流计算 - 改进的径流估算方法"""cn = self.scs_curve_number(soil_group, management)S = (1000 / cn) - 10 # 潜在最大滞留量if rainfall <= 0.2 * S:return 0runoff = (rainfall - 0.2 * S) ** 2 / (rainfall + 0.8 * S)return runoffdef calculate_net_rainfall(self, rainfall, runoff):"""计算净降雨量"""return max(0, rainfall - runoff)def calculate_exposed_leaf_area(self, vineyard_params):"""计算暴露叶面积 - 基于几何方法"""H = vineyard_params['trellis_height']D = vineyard_params['trellis_width']E = vineyard_params['row_spacing']c = vineyard_params['canopy_density'] / 100if vineyard_params['trellis_system'] == 'vertical':# 垂直篱架系统ela = 10000 * (2 * H * D * c) / Eelif vineyard_params['trellis_system'] == 'lyra':# Lyra系统ela = 10000 * (2 * H * D * c) / Eelse:# 默认垂直系统ela = 10000 * (2 * H * D * c) / Ereturn eladef calculate_lai_max(self, vineyard_params):"""计算最大叶面积指数"""ela = self.calculate_exposed_leaf_area(vineyard_params)lai_max = ela / 10000 # 转换为m²/m²return min(lai_max, 5.0) # 限制最大LAI为5.0def calculate_kc_vine(self, lai_max, month, plant_age='mature'):"""计算葡萄作物系数 - 基于物候阶段和LAI"""# 基于物候阶段的kc曲线phenology_kc = {'4月': 0.3, '5月': 0.5, '6月': 0.7, '7月': 0.8,'8月': 0.9, '9月': 0.8, '10月': 0.6, '11月': 0.4,'1月': 0.1, '2月': 0.1, '3月': 0.2, '12月': 0.1}base_kc = phenology_kc.get(month, 0.1)# 基于LAI调整 - Beer定律kc_max = 1.0 - math.exp(-0.6 * lai_max)kc = min(base_kc * kc_max, 0.95)# 幼株调整if plant_age == 'young':kc = kc * 0.8 # 幼株蒸散较低return kcdef calculate_kcc_cover(self, management, month, coverage_pct=75, cover_width=1.5, row_width=2.0):"""计算覆盖作物系数 - 公式6的实现"""if management == 'CT':return 0# 覆盖度计算p = coverage_pct / 100R = cover_widthE = row_widthkcc_max = p * (R / E)# 绿肥作物的季节性调整if management == 'GM':if month in ['10月', '11月', '12月', '1月', '2月', '3月']:return kcc_max * 0.8 # 生长季elif month in ['6月', '7月', '8月']:return 0 # 翻压后else:return kcc_max * 0.5else: # PG - 永久草被return kcc_maxdef calculate_soil_water_potential(self, soil_moisture, fc, wp, sk):"""计算土壤水势 - Saxton方程实现"""if soil_moisture <= wp:return -1.5 # 低于萎蔫点# 有效土壤水分含量theta = soil_moisture / (1 - sk / 100)if theta <= 0:return -1.5# Saxton方程简化实现A = 0.5 # 经验系数B = 2.0 # 经验系数psi = -A * ((theta - wp) / (fc - wp)) ** (-B)return max(-1.5, min(-0.01, psi))def assess_stress_risk(self, swp, month, plant_age):"""评估水分胁迫风险 - 基于表2-4的逻辑"""if month not in self.growth_months:return 'N'# 胁迫风险阈值定义if plant_age == 'young':# 幼株胁迫阈值 - 表2aif swp >= -0.2:return 'N'elif swp >= -0.5:return 'M'elif swp >= -0.8:return 'H'else:return 'VH'else:# 成熟株胁迫阈值 - 基于物候阶段(表2b)phenology_thresholds = {'4月': (-0.2, -0.4, -0.6), # (N阈值, M阈值, H阈值)'5月': (-0.3, -0.5, -0.7),'6月': (-0.4, -0.6, -0.8),'7月': (-0.5, -0.7, -0.9),'8月': (-0.6, -0.8, -1.0),'9月': (-0.5, -0.7, -0.9),'10月': (-0.4, -0.6, -0.8),'11月': (-0.3, -0.5, -0.7)}n_thresh, m_thresh, h_thresh = phenology_thresholds.get(month, (-0.3, -0.5, -0.7))if swp >= n_thresh:return 'N'elif swp >= m_thresh:return 'M'elif swp >= h_thresh:return 'H'else:return 'VH'def calculate_annual_risk_score(self, monthly_risks):"""计算年度风险得分 - 基于表4的逻辑"""risk_scores = {'N': 0, 'M': 1, 'H': 2, 'VH': 3}growth_risks = [risk for month, risk in monthly_risks.items() if month in self.growth_months]if not growth_risks:return 0, 'N'total_score = sum(risk_scores[risk] for risk in growth_risks)# 年度风险分类if total_score <= 3:return total_score, 'N'elif total_score <= 9:return total_score, 'M'elif total_score <= 18:return total_score, 'H'else:return total_score, 'VH'def run_water_balance(self, input_data):"""运行完整的水分平衡计算 - 核心算法"""results = {'monthly_data': [],'annual_metrics': {},'risk_assessment': {}}# 提取输入数据monthly_temps = input_data['monthly_temperatures']monthly_rain = input_data['monthly_rainfall']soil_params = input_data['soil_parameters']vineyard_params = input_data['vineyard_characteristics']management = input_data['management_practice']# 计算热力指数I = self.calculate_thermal_index(monthly_temps)# 确定根系深度rooting_depth = 0.35 if vineyard_params['plant_age'] == 'young' else 0.75if rooting_depth > soil_params['soil_depth']:rooting_depth = soil_params['soil_depth']# 计算可用水容量awc = (soil_params['fc'] - soil_params['wp']) * rooting_depth * 1000 # 转换为mmsoil_moisture = awc # 初始为田间持水量monthly_risks = {}for i, month in enumerate(self.months):# 基本气象数据temp = monthly_temps[i]rain = monthly_rain[i]# 计算径流和净降雨runoff = self.calculate_runoff(rain, soil_params['hydro_group'], management)net_rain = self.calculate_net_rainfall(rain, runoff)# 计算潜在蒸发散pe = self.calculate_potential_evapotranspiration(temp, I)# 计算最大LAIlai_max = self.calculate_lai_max(vineyard_params)# 计算作物系数kc_vine = self.calculate_kc_vine(lai_max,month,vineyard_params['plant_age'])kc_cover = self.calculate_kcc_cover(management,month,vineyard_params['cover_coverage'],vineyard_params['cover_width'],vineyard_params['row_spacing'])# 计算实际蒸发散etc = pe * (kc_vine + kc_cover)# 土壤水分平衡计算water_deficit = net_rain - etcif water_deficit >= 0:# 水分盈余soil_moisture = min(awc, soil_moisture + water_deficit)deep_percolation = max(0, soil_moisture + water_deficit - awc)if deep_percolation > 0:soil_moisture = awcelse:# 水分亏缺soil_moisture = max(0, soil_moisture + water_deficit)deep_percolation = 0# 计算土壤水势和胁迫风险swp = self.calculate_soil_water_potential(soil_moisture,soil_params['fc'] * rooting_depth * 1000,soil_params['wp'] * rooting_depth * 1000,soil_params['skeleton_content'])risk = self.assess_stress_risk(swp, month, vineyard_params['plant_age'])monthly_risks[month] = risk# 存储月度结果monthly_result = {'month': month,'temperature': temp,'rainfall': rain,'runoff': runoff,'net_rainfall': net_rain,'potential_et': pe,'actual_et': etc,'soil_moisture': soil_moisture,'soil_moisture_percent': (soil_moisture / awc) * 100 if awc > 0 else 0,'water_deficit': water_deficit,'deep_percolation': deep_percolation,'soil_water_potential': swp,'stress_risk': risk,'kc_vine': kc_vine,'kc_cover': kc_cover}results['monthly_data'].append(monthly_result)# 计算年度指标annual_rain = sum(monthly_rain)annual_et = sum([data['actual_et'] for data in results['monthly_data']])annual_runoff = sum([data['runoff'] for data in results['monthly_data']])# 年度胁迫风险评估annual_score, annual_risk = self.calculate_annual_risk_score(monthly_risks)results['annual_metrics'] = {'total_rainfall': annual_rain,'total_evapotranspiration': annual_et,'total_runoff': annual_runoff,'water_use_efficiency': annual_et / annual_rain if annual_rain > 0 else 0,'annual_water_deficit': sum([min(0, data['water_deficit']) for data in results['monthly_data']])}results['risk_assessment'] = {'monthly_risks': monthly_risks,'annual_score': annual_score,'annual_risk': annual_risk,'rooting_depth': rooting_depth,'awc': awc}return resultsdef create_visualizations(results, input_data):"""创建交互式可视化图表"""monthly_df = pd.DataFrame(results['monthly_data'])# 1. 水分平衡组分图fig1 = make_subplots(rows=2, cols=1,subplot_titles=('水分平衡组分 (mm)', '土壤水分动态 (mm)'),vertical_spacing=0.15)# 水分平衡组分fig1.add_trace(go.Bar(name='降雨量', x=monthly_df['month'], y=monthly_df['rainfall'],marker_color='#1f77b4', opacity=0.8),row=1, col=1)fig1.add_trace(go.Bar(name='径流量', x=monthly_df['month'], y=monthly_df['runoff'],marker_color='#ff7f0e', opacity=0.8),row=1, col=1)fig1.add_trace(go.Scatter(name='实际蒸发散', x=monthly_df['month'], y=monthly_df['actual_et'],line=dict(color='#d62728', width=3), mode='lines+markers'),row=1, col=1)# 土壤水分动态fig1.add_trace(go.Scatter(name='土壤水分储量', x=monthly_df['month'], y=monthly_df['soil_moisture'],line=dict(color='#8c564b', width=3), mode='lines+markers'),row=2, col=1)# 添加田间持水量和萎蔫点参考线awc = results['risk_assessment']['awc']rooting_depth = results['risk_assessment']['rooting_depth']fc_line = input_data['soil_parameters']['fc'] * rooting_depth * 1000wp_line = input_data['soil_parameters']['wp'] * rooting_depth * 1000fig1.add_hline(y=fc_line, line_dash="dash", line_color="green",annotation_text="田间持水量", row=2, col=1)fig1.add_hline(y=wp_line, line_dash="dash", line_color="red",annotation_text="萎蔫点", row=2, col=1)fig1.update_layout(height=700,showlegend=True,title_text="葡萄园月尺度水分平衡分析",legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1))# 2. 胁迫风险时间序列图risk_colors = {'N': '#28a745', 'M': '#ffc107', 'H': '#fd7e14', 'VH': '#dc3545'}risk_values = {'N': 0, 'M': 1, 'H': 2, 'VH': 3}monthly_risks_num = [risk_values[risk] for risk in monthly_df['stress_risk']]fig2 = go.Figure()# 添加风险区域背景for i, month in enumerate(monthly_df['month']):risk = monthly_df.loc[i, 'stress_risk']fig2.add_vrect(x0=i - 0.5, x1=i + 0.5,fillcolor=risk_colors[risk], opacity=0.3,line_width=0, annotation_text=risk)fig2.add_trace(go.Scatter(x=monthly_df['month'], y=monthly_risks_num,mode='lines+markers+text',line=dict(color='black', width=3),marker=dict(size=10, color='white', line=dict(width=2, color='black')),text=monthly_df['stress_risk'],textposition="top center",name='胁迫风险等级'))fig2.update_layout(title="月度水分胁迫风险评估",xaxis_title="月份",yaxis_title="风险等级",yaxis=dict(tickvals=[0, 1, 2, 3],ticktext=['无风险(N)', '中等(M)', '高(H)', '极高(VH)'],range=[-0.5, 3.5]),height=400,showlegend=False)# 3. 作物系数变化图fig3 = go.Figure()fig3.add_trace(go.Scatter(x=monthly_df['month'], y=monthly_df['kc_vine'],mode='lines+markers', name='葡萄作物系数',line=dict(color='#2ca02c', width=3)))if input_data['management_practice'] != 'CT':fig3.add_trace(go.Scatter(x=monthly_df['month'], y=monthly_df['kc_cover'],mode='lines+markers', name='覆盖作物系数',line=dict(color='#ff7f0e', width=3)))fig3.update_layout(title="作物系数月变化",xaxis_title="月份",yaxis_title="作物系数",height=400)return fig1, fig2, fig3def generate_recommendations(results, input_data):"""基于模型结果生成决策建议"""recommendations = []annual_risk = results['risk_assessment']['annual_risk']plant_age = input_data['vineyard_characteristics']['plant_age']management = input_data['management_practice']annual_deficit = results['annual_metrics']['annual_water_deficit']# 基于年度风险的通用建议risk_based_recs = {'VH': {'priority': '高','suggestions': ['必须安装灌溉系统,建议采用滴灌或微喷灌','在开花期和果实膨大期确保充足水分供应','考虑使用保水剂和覆盖材料减少蒸发损失','调整产量目标,减少植株负荷']},'H': {'priority': '高','suggestions': ['强烈建议安装灌溉设施','优化灌溉制度,采用亏缺灌溉策略','加强土壤保湿措施','考虑选择更抗旱的品种和砧木']},'M': {'priority': '中','suggestions': ['建议准备应急灌溉设备','优化行间管理减少水分竞争','在关键物候期监测土壤水分','考虑调整种植密度']},'N': {'priority': '低','suggestions': ['当前水分条件良好,可维持现有管理','建议定期监测以防气候异常','可尝试节水管理措施提高水分利用效率']}}if annual_risk in risk_based_recs:rec_info = risk_based_recs[annual_risk]recommendations.append({'category': '💧 水分管理策略','priority': rec_info['priority'],'suggestions': rec_info['suggestions']})# 基于植株年龄的建议if plant_age == 'young':recommendations.append({'category': '🌱 幼株特别管理','priority': '高','suggestions': ['幼株根系浅,对水分胁迫敏感,需确保生长季水分充足','选择抗旱砧木如1103P、140Ru、110R等','减少行间竞争,前3年可考虑清耕或局部覆盖','建立滴灌系统支持幼株健康生长']})# 基于管理措施的建议management_recs = {'PG': {'suggestions': ['永久草被在干旱期会增加水分竞争,注意控制草高','可考虑在干旱严重时临时控制草被生长','选择浅根性草种如白三叶草减少水分竞争']},'CT': {'suggestions': ['清耕减少水分竞争但增加水土流失风险','建议结合覆盖作物或秸秆覆盖改善土壤结构','注意雨季的水土保持措施']},'GM': {'suggestions': ['绿肥作物在翻压前注意水分管理','适时翻压避免与葡萄强烈竞争水分','选择豆科绿肥提高土壤肥力']}}if management in management_recs:recommendations.append({'category': '🌾 行间管理优化','priority': '中','suggestions': management_recs[management]['suggestions']})# 基于土壤特性的建议fc = input_data['soil_parameters']['fc']wp = input_data['soil_parameters']['wp']awc = fc - wpif awc < 0.1:recommendations.append({'category': '🏞️ 土壤改良建议','priority': '中','suggestions': ['土壤有效水容量较低,建议增施有机质改善保水能力','考虑深松耕作打破犁底层,增加根系生长空间','使用土壤改良剂提高保水性能']})# 基于水分亏缺量的灌溉建议if annual_deficit < -100:recommendations.append({'category': '⚙️ 灌溉规划','priority': '高','suggestions': [f'年度水分亏缺量达{abs(annual_deficit):.1f}mm,需制定灌溉计划','建议在关键物候期(开花期、果实膨大期)优先灌溉','采用土壤水分传感器监测实时水分状况']})elif annual_deficit < -50:recommendations.append({'category': '⚙️ 灌溉规划','priority': '中','suggestions': [f'年度水分亏缺量达{abs(annual_deficit):.1f}mm,建议准备应急灌溉','在干旱月份监测土壤水分状况','考虑采用局部灌溉减少水分损失']})return recommendationsdef display_recommendations(recommendations):"""展示决策建议"""st.subheader("🍇 水分管理决策建议")if not recommendations:st.info("当前条件下无需特殊管理措施,建议定期监测水分状况。")returnfor rec in recommendations:with st.container():st.markdown(f"<div class='recommendation-card'>", unsafe_allow_html=True)# 分类标题st.markdown(f"<div class='recommendation-header'>{rec['category']}</div>", unsafe_allow_html=True)# 优先级priority_class = ""if rec['priority'] == '高':priority_class = "priority-high"elif rec['priority'] == '中':priority_class = "priority-medium"else:priority_class = "priority-low"st.markdown(f"<div><b>优先级:</b> <span class='{priority_class}'>{rec['priority']}</span></div>",unsafe_allow_html=True)# 具体建议st.markdown("<b>具体建议:</b>", unsafe_allow_html=True)for suggestion in rec['suggestions']:st.markdown(f"- {suggestion}")st.markdown("</div>", unsafe_allow_html=True)def get_user_input():"""获取用户输入参数"""input_data = {}st.sidebar.header("🍇 葡萄园基本信息")# 管理措施management = st.sidebar.selectbox("行间管理措施",options=['PG (永久草被)', 'CT (清耕)', 'GM (绿肥)'],index=0)input_data['management_practice'] = management[:2]# 葡萄园特征st.sidebar.subheader("葡萄园特征")vineyard_params = {}vineyard_params['trellis_system'] = st.sidebar.selectbox("架式系统",options=['vertical (垂直篱架)', 'lyra (Lyra系统)', 'other (其他)'],index=0).split(' ')[0]vineyard_params['row_spacing'] = st.sidebar.slider("行距 (米)", min_value=1.5, max_value=4.0, value=2.5, step=0.1)vineyard_params['trellis_height'] = st.sidebar.slider("架高 (米)", min_value=1.0, max_value=2.5, value=1.8, step=0.1)vineyard_params['trellis_width'] = st.sidebar.slider("架宽 (米)", min_value=0.5, max_value=2.0, value=1.2, step=0.1)vineyard_params['plant_age'] = st.sidebar.selectbox("植株年龄",options=['young (幼株, <3年)', 'mature (成熟株, >3年)'],index=1).split(' ')[0]vineyard_params['canopy_density'] = st.sidebar.slider("冠层密度 (%)", min_value=50, max_value=100, value=85, step=1)vineyard_params['cover_coverage'] = st.sidebar.slider("覆盖作物覆盖度 (%)", min_value=0, max_value=100, value=75, step=1)vineyard_params['cover_width'] = st.sidebar.slider("覆盖作物宽度 (米)", min_value=0.5, max_value=2.0, value=1.5, step=0.1)input_data['vineyard_characteristics'] = vineyard_params# 土壤参数st.sidebar.subheader("土壤参数")soil_params = {}soil_params['hydro_group'] = st.sidebar.selectbox("土壤水文组",options=['A (砂质土)', 'B (壤砂土)', 'C (粘壤土)', 'D (粘土)'],index=1).split(' ')[0]soil_params['fc'] = st.sidebar.slider("田间持水量 (m³/m³)", min_value=0.1, max_value=0.5, value=0.35, step=0.01)soil_params['wp'] = st.sidebar.slider("萎蔫点 (m³/m³)", min_value=0.01, max_value=0.2, value=0.12, step=0.01)soil_params['soil_depth'] = st.sidebar.slider("土壤深度 (米)", min_value=0.3, max_value=2.0, value=1.2, step=0.1)soil_params['skeleton_content'] = st.sidebar.slider("石砾含量 (%)", min_value=0, max_value=50, value=10, step=1)input_data['soil_parameters'] = soil_params# 气象数据st.header("🌦️ 气象数据输入")st.info("请输入当地月平均气温(℃)和月降雨量(mm)")col1, col2 = st.columns(2)monthly_temps = []monthly_rain = []months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']with col1:st.subheader("月平均气温 (℃)")for i, month in enumerate(months[:6]):temp = st.slider(f"{month}", min_value=-10.0, max_value=40.0, value=15.0 if i < 2 else 20.0, step=0.5,key=f"temp_{i}")monthly_temps.append(temp)for i, month in enumerate(months[6:]):temp = st.slider(f"{month}", min_value=-10.0, max_value=40.0, value=25.0 if i < 3 else 15.0, step=0.5,key=f"temp_{i + 6}")monthly_temps.append(temp)with col2:st.subheader("月降雨量 (mm)")for i, month in enumerate(months[:6]):rain = st.slider(f"{month}", min_value=0, max_value=300, value=30 if i < 3 else 80, step=5,key=f"rain_{i}")monthly_rain.append(rain)for i, month in enumerate(months[6:]):rain = st.slider(f"{month}", min_value=0, max_value=300, value=100 if i < 2 else 40, step=5,key=f"rain_{i + 6}")monthly_rain.append(rain)input_data['monthly_temperatures'] = monthly_tempsinput_data['monthly_rainfall'] = monthly_rainreturn input_datadef display_key_metrics(results):"""展示关键指标卡片"""annual_metrics = results['annual_metrics']risk_assessment = results['risk_assessment']col1, col2, col3, col4, col5 = st.columns(5)with col1:st.markdown(f"""<div class="metric-card"><div>年降雨总量</div><div style="font-size: 1.8rem; font-weight: bold;">{annual_metrics['total_rainfall']:.1f} mm</div></div>""", unsafe_allow_html=True)with col2:st.markdown(f"""<div class="metric-card"><div>年蒸发散量</div><div style="font-size: 1.8rem; font-weight: bold;">{annual_metrics['total_evapotranspiration']:.1f} mm</div></div>""", unsafe_allow_html=True)with col3:wue = annual_metrics['water_use_efficiency'] * 100st.markdown(f"""<div class="metric-card"><div>水分利用效率</div><div style="font-size: 1.8rem; font-weight: bold;">{wue:.1f} %</div></div>""", unsafe_allow_html=True)with col4:deficit = annual_metrics['annual_water_deficit']st.markdown(f"""<div class="metric-card"><div>年度水分亏缺</div><div style="font-size: 1.8rem; font-weight: bold;">{deficit:.1f} mm</div></div>""", unsafe_allow_html=True)with col5:risk_level = risk_assessment['annual_risk']risk_class = ""if risk_level == 'N':risk_class = "risk-negligible"risk_text = "无风险"elif risk_level == 'M':risk_class = "risk-moderate"risk_text = "中等风险"elif risk_level == 'H':risk_class = "risk-high"risk_text = "高风险"else:risk_class = "risk-very-high"risk_text = "极高风险"st.markdown(f"""<div class="metric-card"><div>年度胁迫风险</div><div style="font-size: 1.8rem; font-weight: bold;" class="{risk_class}">{risk_text}</div></div>""", unsafe_allow_html=True)def main():"""主应用函数"""st.title("🍇 葡萄园水分平衡决策支持系统")st.markdown("""<div class="main-header">基于Thornthwaite-Mather方法的葡萄园水分平衡模型</div>""", unsafe_allow_html=True)# 获取用户输入input_data = get_user_input()# 添加运行按钮if st.button("运行水分平衡模型", use_container_width=True):with st.spinner("计算中,请稍候..."):# 初始化模型model = VineyardWaterBalanceModel()# 运行模型results = model.run_water_balance(input_data)# 显示关键指标st.markdown("<div class='section-header'>关键指标</div>", unsafe_allow_html=True)display_key_metrics(results)# 显示可视化结果st.markdown("<div class='section-header'>可视化分析</div>", unsafe_allow_html=True)fig1, fig2, fig3 = create_visualizations(results, input_data)st.plotly_chart(fig1, use_container_width=True)col1, col2 = st.columns(2)with col1:st.plotly_chart(fig2, use_container_width=True)with col2:st.plotly_chart(fig3, use_container_width=True)# 显示决策建议recommendations = generate_recommendations(results, input_data)display_recommendations(recommendations)# 显示详细数据表st.markdown("<div class='section-header'>详细数据</div>", unsafe_allow_html=True)monthly_df = pd.DataFrame(results['monthly_data'])st.dataframe(monthly_df.round(2), use_container_width=True)if __name__ == "__main__":main()
