构建暴雨灾害链和地震灾害链DBN模型
This commit is contained in:
@@ -0,0 +1,194 @@
|
|||||||
|
# 离散化规则配置
|
||||||
|
# 定义所有连续因子的分箱规则
|
||||||
|
# 包含暴雨灾害链和地震灾害链的全部因子
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 暴雨触发层离散化规则
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
rain_intensity:
|
||||||
|
description: "降雨强度等级"
|
||||||
|
unit: "mm/h"
|
||||||
|
bins: [0, 0.2, 5, 15, 30, 70, 140, 99999]
|
||||||
|
labels: [no_rain, light, moderate, heavy, storm, downpour, extreme]
|
||||||
|
|
||||||
|
duration:
|
||||||
|
description: "持续时间"
|
||||||
|
unit: "h"
|
||||||
|
bins: [1, 3, 12, 99999]
|
||||||
|
labels: [short, medium, long]
|
||||||
|
|
||||||
|
accum_rain:
|
||||||
|
description: "累计降雨量"
|
||||||
|
unit: "mm"
|
||||||
|
bins: [0, 10, 25, 50, 100, 99999]
|
||||||
|
labels: [trace, light, moderate, heavy, extreme]
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 地震触发层离散化规则
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
magnitude:
|
||||||
|
description: "地震震级"
|
||||||
|
unit: "Richter"
|
||||||
|
# 基于Keefer (1984) 地震触发地质灾害的震级阈值
|
||||||
|
# M<4.0: 无显著地质灾害; M4.0-4.9: 轻微; M5.0-5.9: 中等
|
||||||
|
# M6.0-6.9: 显著; M7.0-7.9: 严重; M≥8.0: 灾难性
|
||||||
|
bins: [0, 4.0, 5.0, 6.0, 7.0, 8.0, 10.0]
|
||||||
|
labels: [minor, light, moderate, strong, major, great]
|
||||||
|
|
||||||
|
epicenter_distance:
|
||||||
|
description: "震中距"
|
||||||
|
unit: "km"
|
||||||
|
# 地震地质灾害影响范围(Keefer 1984):
|
||||||
|
# M5.0: ~10km; M6.0: ~30km; M7.0: ~100km; M8.0: ~300km
|
||||||
|
# 分级取各震级影响范围的中位值
|
||||||
|
bins: [0, 30, 100, 300, 99999]
|
||||||
|
labels: [very_near, near, moderate, far]
|
||||||
|
|
||||||
|
seismic_intensity:
|
||||||
|
description: "地震烈度"
|
||||||
|
unit: "中国烈度表"
|
||||||
|
# GB 18306-2015 中国地震动参数区划图
|
||||||
|
# I-V: 无显著地质灾害; VI-VII: 轻微; VIII-IX: 显著; X-XII: 严重; >XII: 灾难性
|
||||||
|
# 输入为数值烈度(1-12),映射到离散等级
|
||||||
|
bins: [0, 5, 7, 9, 12, 99]
|
||||||
|
labels: [minor, light, moderate, severe, extreme]
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 环境层离散化规则(暴雨/地震共享)
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
elevation:
|
||||||
|
description: "高程"
|
||||||
|
unit: "m"
|
||||||
|
bins: [0, 400, 500, 700, 1000, 1500, 99999]
|
||||||
|
labels: [basin, plain_urban, transition, low_mountain, mid_mountain, high_mountain]
|
||||||
|
|
||||||
|
slope:
|
||||||
|
description: "坡度"
|
||||||
|
unit: "度"
|
||||||
|
bins: [0, 5, 15, 25, 35, 45, 90]
|
||||||
|
labels: [flat, gentle, moderate, steep, very_steep, extreme_steep]
|
||||||
|
|
||||||
|
aspect:
|
||||||
|
description: "坡向"
|
||||||
|
unit: "度"
|
||||||
|
bins: [0, 45, 135, 225, 315, 360]
|
||||||
|
labels: [north, east, south, west, north_loop]
|
||||||
|
|
||||||
|
soil_type:
|
||||||
|
description: "土壤分类(中国土壤分类系统)"
|
||||||
|
unit: "分类代码"
|
||||||
|
# 数据库实际编码(xian_soil 表 value 字段,来源:pg_description)
|
||||||
|
mapping:
|
||||||
|
0: ultisol # 老成土
|
||||||
|
6: entisol # 初育土
|
||||||
|
11: fluvo_aquic # 潮土
|
||||||
|
18: yellow_brown # 黄棕壤
|
||||||
|
default: entisol
|
||||||
|
|
||||||
|
lithology:
|
||||||
|
description: "岩性(中国地质分类)"
|
||||||
|
unit: "分类代码"
|
||||||
|
# 数据库实际编码(xian_lithology 表 value 字段,来源:pg_description)
|
||||||
|
# 工程地质分组:按 SiO₂ 含量 + 成因合并同类岩性
|
||||||
|
mapping:
|
||||||
|
1: acid_rock # 酸性侵入岩(花岗岩等,SiO₂>66%,100条)
|
||||||
|
3: basic_rock # 基性侵入岩(辉长岩等,SiO₂ 45-52%,5条)
|
||||||
|
4: basic_rock # 基性火山岩(玄武岩等,合并入基性岩,17条)
|
||||||
|
5: carbonate # 碳酸盐岩(石灰岩、白云岩,142条)
|
||||||
|
10: metamorphic # 变质岩(片麻岩、大理岩,156条)
|
||||||
|
11: mixed_clastic # 混合碎屑沉积岩(砂岩+泥岩互层,35条)
|
||||||
|
13: terrigenous # 陆源碎屑岩(砂岩、粉砂岩,180条)
|
||||||
|
14: unconsolidated # 松散堆积物(黄土、冲洪积,566条)
|
||||||
|
default: unconsolidated
|
||||||
|
|
||||||
|
landuse:
|
||||||
|
description: "土地利用类型"
|
||||||
|
unit: "分类代码"
|
||||||
|
# 数据库实际编码(GLC FCS30 分类体系)
|
||||||
|
mapping:
|
||||||
|
10: forest # 林地(377条)
|
||||||
|
30: farmland # 农田(190条)
|
||||||
|
40: urban # 城市(105条)
|
||||||
|
50: water # 水域(505条)
|
||||||
|
60: barren # 裸地(23条)
|
||||||
|
80: farmland # 耕地(1条,合并入农田)
|
||||||
|
default: farmland
|
||||||
|
|
||||||
|
terrain:
|
||||||
|
description: "地形分类(中国地形分类体系)"
|
||||||
|
unit: "分类代码"
|
||||||
|
# 数据库实际编码(xian_landform 表 value 字段,来源:pg_description)
|
||||||
|
# 工程地质分组:按坡度 + 地貌特征合并
|
||||||
|
mapping:
|
||||||
|
1: mountain # 断裂山麓地带(秦岭北麓,276条)
|
||||||
|
2: plain # 平坦平原(渭河平原,218条)
|
||||||
|
3: deep_valley # 高山深峡谷(秦岭腹地,11条)
|
||||||
|
4: hill # 丘陵(黄土塬,250条)
|
||||||
|
5: gentle_hill # 低缓丘陵(塬边过渡带,86条)
|
||||||
|
6: low_mountain # 低山(骊山等,261条)
|
||||||
|
7: flat_plain # 平缓平原(冲积平原,99条)
|
||||||
|
default: hill
|
||||||
|
|
||||||
|
impervious:
|
||||||
|
description: "不透水面"
|
||||||
|
unit: "比例"
|
||||||
|
bins: [0, 0.3, 0.6, 1.0]
|
||||||
|
labels: [low, medium, high]
|
||||||
|
|
||||||
|
ndvi:
|
||||||
|
description: "植被指数"
|
||||||
|
unit: "NDVI值"
|
||||||
|
bins: [-1, 0, 0.1, 0.3, 0.5, 0.8, 1.0]
|
||||||
|
labels: [water, bare, sparse, moderate, dense, very_dense]
|
||||||
|
|
||||||
|
sand_content:
|
||||||
|
description: "土壤含沙量"
|
||||||
|
unit: "百分比"
|
||||||
|
bins: [0, 20, 40, 100]
|
||||||
|
labels: [low, medium, high]
|
||||||
|
|
||||||
|
ph:
|
||||||
|
description: "土壤PH值"
|
||||||
|
unit: "PH值"
|
||||||
|
bins: [0, 6.5, 7.5, 14]
|
||||||
|
labels: [acidic, neutral, alkaline]
|
||||||
|
|
||||||
|
soil_moisture:
|
||||||
|
description: "土壤湿度"
|
||||||
|
unit: "百分比"
|
||||||
|
bins: [0, 20, 40, 80, 100]
|
||||||
|
labels: [dry, moist, wet, saturated]
|
||||||
|
|
||||||
|
organic_carbon:
|
||||||
|
description: "有机碳"
|
||||||
|
unit: "百分比"
|
||||||
|
bins: [0, 1, 2, 100]
|
||||||
|
labels: [low, medium, high]
|
||||||
|
|
||||||
|
dist_to_river:
|
||||||
|
description: "距离河道距离"
|
||||||
|
unit: "米"
|
||||||
|
bins: [0, 50, 200, 500, 99999]
|
||||||
|
labels: [very_close, close, moderate, far]
|
||||||
|
|
||||||
|
dist_to_fault:
|
||||||
|
description: "距离断裂带距离"
|
||||||
|
unit: "米"
|
||||||
|
bins: [0, 500, 1500, 3000, 99999]
|
||||||
|
labels: [very_close, close, moderate, far]
|
||||||
|
|
||||||
|
pipe_density:
|
||||||
|
description: "供水管网密度"
|
||||||
|
unit: "m/m²"
|
||||||
|
# 默认规则
|
||||||
|
default:
|
||||||
|
bins: [0, 0.001, 0.01, 0.05, 99999]
|
||||||
|
labels: [none, low, medium, high]
|
||||||
|
# 区域覆盖规则
|
||||||
|
region_overrides:
|
||||||
|
610100: # 西安市
|
||||||
|
bins: [0, 0.002, 0.015, 0.04, 99999]
|
||||||
|
labels: [none, low, medium, high]
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
# ================================================================
|
||||||
|
# 地震灾害链 条件概率表(CPT)配置
|
||||||
|
# ================================================================
|
||||||
|
# 地震触发地质灾害:滑坡、泥石流、崩塌
|
||||||
|
# 参考:
|
||||||
|
# - Keefer (1984) Landslides caused by earthquakes
|
||||||
|
# - Rodriguez et al. (1999) Earthquake-induced landslides
|
||||||
|
# - 1556年华县M8.0地震诱发滑坡史料
|
||||||
|
# - GB 18306-2015 中国地震动参数区划图
|
||||||
|
|
||||||
|
# 推理配置
|
||||||
|
match_strategy: first
|
||||||
|
default_strategy: use_default
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 触发层(地震参数先验概率)
|
||||||
|
# ============================================
|
||||||
|
# 主要发震构造:秦岭北缘断裂(M7.0+)、渭河断裂(M6.5+)
|
||||||
|
# 历史最大地震:1556年华县M8.0(距西安约80km)
|
||||||
|
|
||||||
|
magnitude:
|
||||||
|
type: prior
|
||||||
|
# 西安地区地震危险性分析:
|
||||||
|
# - M<4.0(minor):频繁但无显著地质灾害
|
||||||
|
# - M4.0-4.9(light):偶发,轻微地质灾害
|
||||||
|
# - M5.0-5.9(moderate):可能触发近场滑坡
|
||||||
|
# - M6.0-6.9(strong):显著地质灾害
|
||||||
|
# - M7.0-7.9(major):区域性地质灾害
|
||||||
|
# - M≥8.0(great):灾难性(如1556年华县地震)
|
||||||
|
# [minor, light, moderate, strong, major, great]
|
||||||
|
probabilities: [0.40, 0.25, 0.18, 0.10, 0.05, 0.02]
|
||||||
|
|
||||||
|
epicenter_distance:
|
||||||
|
type: prior
|
||||||
|
# 西安地区可能的震中距分布:
|
||||||
|
# - <30km(very_near):本地断裂发震
|
||||||
|
# - 30-100km(near):渭河断裂、秦岭北缘断裂
|
||||||
|
# - 100-300km(moderate):汾渭地震带
|
||||||
|
# - >300km(far):远场地震
|
||||||
|
# [very_near, near, moderate, far]
|
||||||
|
probabilities: [0.10, 0.25, 0.35, 0.30]
|
||||||
|
|
||||||
|
seismic_intensity:
|
||||||
|
type: prior
|
||||||
|
# 西安地区地震烈度分布:
|
||||||
|
# - I-V(minor):无显著地质灾害
|
||||||
|
# - VI-VII(light):轻微地质灾害
|
||||||
|
# - VIII-IX(moderate):显著地质灾害
|
||||||
|
# - X-XII(severe):严重地质灾害
|
||||||
|
# > XII(extreme):灾难性(1556年华县地震西安烈度约IX-X)
|
||||||
|
# [minor, light, moderate, severe, extreme]
|
||||||
|
probabilities: [0.35, 0.30, 0.20, 0.10, 0.05]
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 灾害层(条件概率)
|
||||||
|
# 规则匹配策略:首条匹配,从上到下扫描,命中即返回
|
||||||
|
# 高风险规则在前,低风险兜底规则在后
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# 滑坡(Landslide)- 地震触发
|
||||||
|
# 西安特征:
|
||||||
|
# - 黄土滑坡:黄土台塬塬边(白鹿塬、神禾塬、少陵塬),地震时黄土震陷
|
||||||
|
# - 岩质滑坡:秦岭北坡变质岩/花岗岩区,节理面在地震荷载下失稳
|
||||||
|
# - 工程滑坡:城区开挖坡脚,地震加剧变形
|
||||||
|
# - 断裂带控制:秦岭北缘断裂沿线近场效应显著
|
||||||
|
# - 1556年华县地震:触发了渭河平原大规模黄土滑坡
|
||||||
|
# ----------------------------------------
|
||||||
|
landslide:
|
||||||
|
type: conditional
|
||||||
|
parents: [magnitude, epicenter_distance, slope, lithology, soil_moisture, dist_to_fault, ndvi, soil_type, landuse, terrain]
|
||||||
|
default_probability: 0.02
|
||||||
|
rules:
|
||||||
|
# === 极高风险(≥0.70)===
|
||||||
|
# 大地震+近场+陡坡:最大规模地震滑坡
|
||||||
|
# 参考:M7.0+近场(<30km)陡坡区滑坡概率>80%(Keefer 1984)
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [very_near], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.85
|
||||||
|
# 大地震+近场+饱和土体:黄土震陷+液化
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [very_near], soil_moisture: [wet, saturated]}
|
||||||
|
probability: 0.82
|
||||||
|
# 强震+近场+陡坡+断裂带附近:近场效应+岩体破碎
|
||||||
|
- condition: {magnitude: [strong, major, great], epicenter_distance: [very_near], slope: [steep, very_steep, extreme_steep], dist_to_fault: [very_close, close]}
|
||||||
|
probability: 0.80
|
||||||
|
# 大地震+近场+松散堆积物:黄土滑坡(1556年华县地震典型场景)
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [very_near, near], lithology: [unconsolidated, mixed_clastic]}
|
||||||
|
probability: 0.78
|
||||||
|
|
||||||
|
# === 高风险(0.50-0.65)===
|
||||||
|
# 强震+近场+陡坡
|
||||||
|
- condition: {magnitude: [strong, major], epicenter_distance: [very_near, near], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.65
|
||||||
|
# 大地震+中距+陡坡+断裂带
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [near, moderate], slope: [steep, very_steep, extreme_steep], dist_to_fault: [very_close, close]}
|
||||||
|
probability: 0.62
|
||||||
|
# 强震+中陡坡+松散堆积物:黄土塬边滑坡
|
||||||
|
- condition: {magnitude: [strong, major], epicenter_distance: [very_near, near], slope: [moderate, steep, very_steep, extreme_steep], lithology: [unconsolidated]}
|
||||||
|
probability: 0.60
|
||||||
|
# 强震+陡坡+饱和土体
|
||||||
|
- condition: {magnitude: [strong, major], slope: [steep, very_steep, extreme_steep], soil_moisture: [wet, saturated]}
|
||||||
|
probability: 0.58
|
||||||
|
# 大地震+近场+丘陵地形:黄土塬边
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [very_near, near], terrain: [hill, gentle_hill]}
|
||||||
|
probability: 0.55
|
||||||
|
# 强震+近场+初育土(黄土)
|
||||||
|
- condition: {magnitude: [strong, major], epicenter_distance: [very_near, near], soil_type: [entisol]}
|
||||||
|
probability: 0.52
|
||||||
|
|
||||||
|
# === 中风险(0.20-0.40)===
|
||||||
|
# 中强震+近场+陡坡
|
||||||
|
- condition: {magnitude: [moderate, strong], epicenter_distance: [very_near, near], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.40
|
||||||
|
# 强震+中距+陡坡
|
||||||
|
- condition: {magnitude: [strong, major], epicenter_distance: [near, moderate], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.35
|
||||||
|
# 强震+中坡+松散堆积物
|
||||||
|
- condition: {magnitude: [strong, major], slope: [moderate, steep], lithology: [unconsolidated]}
|
||||||
|
probability: 0.30
|
||||||
|
# 大地震+远距(仍有影响,1556年华县地震影响范围>300km)
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [moderate, far], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.28
|
||||||
|
# 断裂带+陡坡(即使中小地震也有蠕变风险)
|
||||||
|
- condition: {dist_to_fault: [very_close], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.25
|
||||||
|
# 中强震+中坡
|
||||||
|
- condition: {magnitude: [moderate, strong], slope: [moderate, steep]}
|
||||||
|
probability: 0.22
|
||||||
|
|
||||||
|
# === 低风险兜底(≤0.05)===
|
||||||
|
- condition: {magnitude: [minor]}
|
||||||
|
probability: 0.02
|
||||||
|
- condition: {epicenter_distance: [far]}
|
||||||
|
probability: 0.02
|
||||||
|
- condition: {slope: [flat, gentle]}
|
||||||
|
probability: 0.01
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# 泥石流(Debris Flow)- 地震触发
|
||||||
|
# 西安特征:
|
||||||
|
# - 秦岭北麓沟道:地震松动物源→后续降雨触发泥石流
|
||||||
|
# - 地震直接触发:强震+陡坡+松散物源可直接启动泥石流
|
||||||
|
# - 震后效应:地震后数年内泥石流频率显著增加(物源松动)
|
||||||
|
# - 典型场景:M6.0+秦岭北坡沟道区
|
||||||
|
# ----------------------------------------
|
||||||
|
debris_flow:
|
||||||
|
type: conditional
|
||||||
|
parents: [magnitude, epicenter_distance, slope, elevation, lithology, sand_content, soil_moisture, dist_to_fault, ndvi]
|
||||||
|
default_probability: 0.01
|
||||||
|
rules:
|
||||||
|
# === 极高风险(≥0.70)===
|
||||||
|
# 大地震+近场+陡坡+高含沙量:物源充足+强震动
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [very_near], slope: [steep, very_steep, extreme_steep], sand_content: [medium, high]}
|
||||||
|
probability: 0.80
|
||||||
|
# 大地震+近场+中高山区+松散堆积物:秦岭北麓沟道
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [very_near, near], elevation: [mid_mountain, high_mountain], lithology: [unconsolidated, mixed_clastic]}
|
||||||
|
probability: 0.78
|
||||||
|
# 强震+近场+陡坡+断裂带:破碎岩体提供物源
|
||||||
|
- condition: {magnitude: [strong, major, great], epicenter_distance: [very_near], slope: [steep, very_steep, extreme_steep], dist_to_fault: [very_close, close]}
|
||||||
|
probability: 0.75
|
||||||
|
# 大地震+饱和+陡坡:液化+滑坡→泥石流
|
||||||
|
- condition: {magnitude: [major, great], soil_moisture: [wet, saturated], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.72
|
||||||
|
|
||||||
|
# === 高风险(0.50-0.65)===
|
||||||
|
# 强震+近场+陡坡
|
||||||
|
- condition: {magnitude: [strong, major], epicenter_distance: [very_near, near], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.62
|
||||||
|
# 强震+中高山区+松散堆积物
|
||||||
|
- condition: {magnitude: [strong, major], elevation: [mid_mountain, high_mountain], lithology: [unconsolidated, mixed_clastic]}
|
||||||
|
probability: 0.58
|
||||||
|
# 大地震+中距+陡坡+高含沙量
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [near, moderate], slope: [steep, very_steep, extreme_steep], sand_content: [medium, high]}
|
||||||
|
probability: 0.55
|
||||||
|
# 强震+陡坡+松散堆积物
|
||||||
|
- condition: {magnitude: [strong, major], slope: [steep, very_steep, extreme_steep], lithology: [unconsolidated, mixed_clastic]}
|
||||||
|
probability: 0.52
|
||||||
|
|
||||||
|
# === 中风险(0.20-0.40)===
|
||||||
|
# 中强震+近场+陡坡
|
||||||
|
- condition: {magnitude: [moderate, strong], epicenter_distance: [very_near, near], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.38
|
||||||
|
# 强震+中高山区(物源区本身不稳定)
|
||||||
|
- condition: {magnitude: [strong, major], elevation: [mid_mountain, high_mountain], slope: [moderate, steep]}
|
||||||
|
probability: 0.30
|
||||||
|
# 大地震+远距+陡坡
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [moderate, far], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.28
|
||||||
|
# 断裂带+陡坡+松散堆积物(无强震也有蠕变崩塌→物源积累)
|
||||||
|
- condition: {dist_to_fault: [very_close], slope: [steep, very_steep, extreme_steep], lithology: [unconsolidated]}
|
||||||
|
probability: 0.22
|
||||||
|
|
||||||
|
# === 低风险兜底(≤0.05)===
|
||||||
|
- condition: {magnitude: [minor]}
|
||||||
|
probability: 0.01
|
||||||
|
- condition: {slope: [flat, gentle]}
|
||||||
|
probability: 0.01
|
||||||
|
- condition: {elevation: [basin, plain_urban]}
|
||||||
|
probability: 0.01
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# 崩塌(Collapse)- 地震触发
|
||||||
|
# 西安特征:
|
||||||
|
# - 黄土崩塌:渭河、灞河、浐河侧蚀黄土塬边+地震触发
|
||||||
|
# - 岩质崩塌:秦岭北坡陡崖(>45°),花岗岩/变质岩节理面失稳
|
||||||
|
# - 崩塌是地震触发最敏感的地质灾害类型
|
||||||
|
# - 1556年华县地震:秦岭北坡大规模崩塌
|
||||||
|
# - 断裂带控制:秦岭北缘断裂沿线崩塌密度最高
|
||||||
|
# ----------------------------------------
|
||||||
|
collapse:
|
||||||
|
type: conditional
|
||||||
|
parents: [magnitude, epicenter_distance, slope, lithology, dist_to_fault, dist_to_river, soil_moisture]
|
||||||
|
default_probability: 0.02
|
||||||
|
rules:
|
||||||
|
# === 极高风险(≥0.70)===
|
||||||
|
# 大地震+近场+极陡坡+硬岩(花岗岩/变质岩):节理面失稳
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [very_near], slope: [very_steep, extreme_steep], lithology: [acid_rock, metamorphic, basic_rock]}
|
||||||
|
probability: 0.88
|
||||||
|
# 大地震+近场+陡坡+断裂带:岩体极度破碎
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [very_near], slope: [steep, very_steep, extreme_steep], dist_to_fault: [very_close, close]}
|
||||||
|
probability: 0.85
|
||||||
|
# 大地震+近场+松散堆积物+陡坡:黄土塬边崩塌
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [very_near], slope: [steep, very_steep, extreme_steep], lithology: [unconsolidated, terrigenous, mixed_clastic]}
|
||||||
|
probability: 0.80
|
||||||
|
# 强震+近场+极陡坡
|
||||||
|
- condition: {magnitude: [strong, major], epicenter_distance: [very_near], slope: [very_steep, extreme_steep]}
|
||||||
|
probability: 0.75
|
||||||
|
|
||||||
|
# === 高风险(0.50-0.65)===
|
||||||
|
# 强震+近场+陡坡+断裂带
|
||||||
|
- condition: {magnitude: [strong, major], epicenter_distance: [very_near, near], slope: [steep, very_steep, extreme_steep], dist_to_fault: [very_close, close]}
|
||||||
|
probability: 0.68
|
||||||
|
# 大地震+中距+陡坡+硬岩
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [near, moderate], slope: [steep, very_steep, extreme_steep], lithology: [acid_rock, metamorphic]}
|
||||||
|
probability: 0.62
|
||||||
|
# 强震+近场+陡坡+松散堆积物:黄土崩塌
|
||||||
|
- condition: {magnitude: [strong, major], epicenter_distance: [very_near, near], slope: [steep, very_steep, extreme_steep], lithology: [unconsolidated]}
|
||||||
|
probability: 0.60
|
||||||
|
# 近河道+陡坡+松散堆积物+地震:河流侧蚀+地震触发
|
||||||
|
- condition: {dist_to_river: [very_close, close], slope: [steep, very_steep, extreme_steep], lithology: [unconsolidated], magnitude: [strong, major, great]}
|
||||||
|
probability: 0.58
|
||||||
|
# 强震+中陡坡+断裂带
|
||||||
|
- condition: {magnitude: [strong, major], slope: [moderate, steep, very_steep, extreme_steep], dist_to_fault: [very_close, close]}
|
||||||
|
probability: 0.55
|
||||||
|
|
||||||
|
# === 中风险(0.20-0.40)===
|
||||||
|
# 中强震+近场+陡坡
|
||||||
|
- condition: {magnitude: [moderate, strong], epicenter_distance: [very_near, near], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.40
|
||||||
|
# 强震+中距+陡坡
|
||||||
|
- condition: {magnitude: [strong, major], epicenter_distance: [near, moderate], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.35
|
||||||
|
# 近河道+中坡+松散堆积物(无强震也有侧蚀崩塌)
|
||||||
|
- condition: {dist_to_river: [very_close, close], lithology: [unconsolidated], slope: [moderate, steep]}
|
||||||
|
probability: 0.30
|
||||||
|
# 断裂带+陡坡(无强震也有蠕变崩塌)
|
||||||
|
- condition: {dist_to_fault: [very_close], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.28
|
||||||
|
# 大地震+远距+陡坡
|
||||||
|
- condition: {magnitude: [major, great], epicenter_distance: [moderate, far], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.25
|
||||||
|
|
||||||
|
# === 低风险兜底(≤0.05)===
|
||||||
|
- condition: {magnitude: [minor]}
|
||||||
|
probability: 0.01
|
||||||
|
- condition: {slope: [flat, gentle]}
|
||||||
|
probability: 0.01
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
# 地震灾害链 DBN 图结构配置
|
||||||
|
# 定义节点、各层节点列表、父子关系
|
||||||
|
# 地震触发:滑坡、泥石流、崩塌
|
||||||
|
|
||||||
|
# 推理配置
|
||||||
|
inference_config:
|
||||||
|
match_strategy: first # first=首条匹配(规则优先级从上到下),max=取最大概率
|
||||||
|
default_strategy: use_default # 无规则匹配时使用 default_probability
|
||||||
|
max_cpt_parents: 20 # CPT 最大父节点数
|
||||||
|
|
||||||
|
layers:
|
||||||
|
# 触发层(3个节点)
|
||||||
|
trigger:
|
||||||
|
- magnitude # 震级(Richter scale)
|
||||||
|
- epicenter_distance # 震中距(km)
|
||||||
|
- seismic_intensity # 地震烈度(中国烈度表 I-XII)
|
||||||
|
|
||||||
|
# 环境层(14个节点)
|
||||||
|
# 去掉暴雨模型中的 impervious(不透水面)和 pipe_density(管网密度)
|
||||||
|
# 这两个因子主要影响城市内涝,与地震地质灾害关系不大
|
||||||
|
environment:
|
||||||
|
- elevation # 高程
|
||||||
|
- slope # 坡度
|
||||||
|
- aspect # 坡向
|
||||||
|
- soil_type # 土壤分类
|
||||||
|
- lithology # 岩性
|
||||||
|
- landuse # 土地利用类型
|
||||||
|
- terrain # 地形分类
|
||||||
|
- ndvi # 植被指数
|
||||||
|
- sand_content # 土壤含沙量
|
||||||
|
- ph # 土壤PH值
|
||||||
|
- soil_moisture # 土壤湿度
|
||||||
|
- organic_carbon # 有机碳
|
||||||
|
- dist_to_river # 距离河道距离
|
||||||
|
- dist_to_fault # 距离断裂带距离
|
||||||
|
|
||||||
|
# 灾害层(3个节点)
|
||||||
|
# 地震触发的地质灾害:滑坡、泥石流、崩塌
|
||||||
|
# 不含山洪(flash_flood)和内涝(waterlogging),这两个主要由暴雨触发
|
||||||
|
hazard:
|
||||||
|
- landslide # 滑坡
|
||||||
|
- debris_flow # 泥石流
|
||||||
|
- collapse # 崩塌
|
||||||
|
|
||||||
|
edges:
|
||||||
|
# ============================================
|
||||||
|
# 触发层 → 灾害层
|
||||||
|
# 地震参数直接影响所有地质灾害类型
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# 震级 → 灾害
|
||||||
|
- [magnitude, landslide]
|
||||||
|
- [magnitude, debris_flow]
|
||||||
|
- [magnitude, collapse]
|
||||||
|
|
||||||
|
# 震中距 → 灾害
|
||||||
|
- [epicenter_distance, landslide]
|
||||||
|
- [epicenter_distance, debris_flow]
|
||||||
|
- [epicenter_distance, collapse]
|
||||||
|
|
||||||
|
# 地震烈度 → 灾害
|
||||||
|
- [seismic_intensity, landslide]
|
||||||
|
- [seismic_intensity, debris_flow]
|
||||||
|
- [seismic_intensity, collapse]
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 环境层 → 灾害层
|
||||||
|
# 场地条件影响地震波放大效应和地质灾害易发性
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# 高程影响泥石流
|
||||||
|
# - 泥石流:高程反映沟道纵坡和物源区高差(秦岭北麓800-1500m高发)
|
||||||
|
- [elevation, debris_flow]
|
||||||
|
|
||||||
|
# 坡度影响滑坡、泥石流、崩塌(最核心的场地因子)
|
||||||
|
# - 滑坡:Newmark位移与坡度直接相关
|
||||||
|
# - 泥石流:沟道纵坡决定物源运移能力
|
||||||
|
# - 崩塌:陡坡+地震是崩塌的典型触发条件
|
||||||
|
- [slope, landslide]
|
||||||
|
- [slope, debris_flow]
|
||||||
|
- [slope, collapse]
|
||||||
|
|
||||||
|
# 坡向影响滑坡
|
||||||
|
# - 阳坡冻融风化强烈,岩体更破碎,地震时更易失稳
|
||||||
|
- [aspect, landslide]
|
||||||
|
|
||||||
|
# 土壤类型影响滑坡、泥石流
|
||||||
|
# - 初育土(黄土)地震液化和震陷风险高
|
||||||
|
- [soil_type, landslide]
|
||||||
|
- [soil_type, debris_flow]
|
||||||
|
|
||||||
|
# 岩性影响滑坡、泥石流、崩塌(关键地质因子)
|
||||||
|
# - 松散堆积物(黄土):地震时易发生震陷和液化
|
||||||
|
# - 变质岩/花岗岩:节理发育时崩塌风险高
|
||||||
|
# - 碎屑岩:软硬互层界面是滑动面
|
||||||
|
- [lithology, landslide]
|
||||||
|
- [lithology, debris_flow]
|
||||||
|
- [lithology, collapse]
|
||||||
|
|
||||||
|
# 土地利用类型影响滑坡
|
||||||
|
# - 城市:工程开挖坡脚/弃土加载降低边坡稳定性
|
||||||
|
# - 农田:梯田改造改变坡体应力状态
|
||||||
|
- [landuse, landslide]
|
||||||
|
|
||||||
|
# 地形分类影响滑坡、泥石流
|
||||||
|
# - 山地/深谷:地震波放大效应显著
|
||||||
|
# - 丘陵:黄土塬边地震滑坡
|
||||||
|
- [terrain, landslide]
|
||||||
|
- [terrain, debris_flow]
|
||||||
|
|
||||||
|
# 植被指数影响滑坡、泥石流
|
||||||
|
# - 根系加固作用:植被好→滑坡风险降低
|
||||||
|
# - 但地震烈度高时植被保护作用有限
|
||||||
|
- [ndvi, landslide]
|
||||||
|
- [ndvi, debris_flow]
|
||||||
|
|
||||||
|
# 土壤含沙量影响泥石流
|
||||||
|
# - 高含沙量→松散物源丰富→地震触发泥石流
|
||||||
|
- [sand_content, debris_flow]
|
||||||
|
|
||||||
|
# 土壤湿度影响滑坡、泥石流
|
||||||
|
# - 饱和土体在地震荷载下更易发生液化和失稳
|
||||||
|
# - 孔隙水压力升高降低有效应力
|
||||||
|
- [soil_moisture, landslide]
|
||||||
|
- [soil_moisture, debris_flow]
|
||||||
|
|
||||||
|
# 距离河道距离影响泥石流、崩塌
|
||||||
|
# - 泥石流:沟道物源供给
|
||||||
|
# - 崩塌:河流侧蚀黄土塬边 + 地震触发
|
||||||
|
- [dist_to_river, debris_flow]
|
||||||
|
- [dist_to_river, collapse]
|
||||||
|
|
||||||
|
# 距离断裂带距离影响滑坡、崩塌、泥石流
|
||||||
|
# - 发震断裂附近地震动强度大(近场效应)
|
||||||
|
# - 断裂带岩体破碎,地震时更易失稳
|
||||||
|
# - 西安:秦岭北缘断裂、渭河断裂为主要发震构造
|
||||||
|
- [dist_to_fault, landslide]
|
||||||
|
- [dist_to_fault, collapse]
|
||||||
|
- [dist_to_fault, debris_flow]
|
||||||
|
|
||||||
|
# 节点状态定义
|
||||||
|
# 与 discretization.yaml 保持一致
|
||||||
|
node_states:
|
||||||
|
# 触发层(地震参数)
|
||||||
|
magnitude: [minor, light, moderate, strong, major, great]
|
||||||
|
epicenter_distance: [very_near, near, moderate, far]
|
||||||
|
seismic_intensity: [minor, light, moderate, severe, extreme]
|
||||||
|
|
||||||
|
# 环境层(与暴雨模型共享,状态名一致)
|
||||||
|
elevation: [basin, plain_urban, transition, low_mountain, mid_mountain, high_mountain]
|
||||||
|
slope: [flat, gentle, moderate, steep, very_steep, extreme_steep]
|
||||||
|
aspect: [north, east, south, west, north_loop]
|
||||||
|
soil_type: [ultisol, entisol, fluvo_aquic, yellow_brown]
|
||||||
|
lithology: [acid_rock, basic_rock, carbonate, metamorphic, mixed_clastic, terrigenous, unconsolidated]
|
||||||
|
landuse: [forest, farmland, urban, water, barren]
|
||||||
|
terrain: [mountain, plain, deep_valley, hill, gentle_hill, low_mountain, flat_plain]
|
||||||
|
ndvi: [water, bare, sparse, moderate, dense, very_dense]
|
||||||
|
sand_content: [low, medium, high]
|
||||||
|
ph: [acidic, neutral, alkaline]
|
||||||
|
soil_moisture: [dry, moist, wet, saturated]
|
||||||
|
organic_carbon: [low, medium, high]
|
||||||
|
dist_to_river: [very_close, close, moderate, far]
|
||||||
|
dist_to_fault: [very_close, close, moderate, far]
|
||||||
|
|
||||||
|
# 灾害层
|
||||||
|
landslide: [none, low, medium, high, very_high]
|
||||||
|
debris_flow: [none, low, medium, high, very_high]
|
||||||
|
collapse: [none, low, medium, high, very_high]
|
||||||
@@ -0,0 +1,362 @@
|
|||||||
|
# ================================================================
|
||||||
|
# 条件概率表(CPT)配置
|
||||||
|
# ================================================================
|
||||||
|
|
||||||
|
# 推理配置
|
||||||
|
match_strategy: first # 首条匹配(规则优先级从上到下,max为最大匹配)
|
||||||
|
default_strategy: use_default # 无匹配时使用 default_probability
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 触发层
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
rain_intensity:
|
||||||
|
type: prior
|
||||||
|
# 西安气象站统计:无雨~小雨占60%,中雨~大雨25%,暴雨+15%
|
||||||
|
# [无雨, 小雨, 中雨, 大雨, 暴雨, 大暴雨, 特大暴雨]
|
||||||
|
probabilities: [0.35, 0.25, 0.15, 0.10, 0.08, 0.05, 0.02]
|
||||||
|
|
||||||
|
duration:
|
||||||
|
type: prior
|
||||||
|
# 西安暴雨特征:短历时(<3h)占多数,长历时(>12h)与华西秋雨相关
|
||||||
|
# [短, 中, 长]
|
||||||
|
probabilities: [0.50, 0.30, 0.20]
|
||||||
|
|
||||||
|
accum_rain:
|
||||||
|
type: prior
|
||||||
|
# 西安年均降水550-700mm,汛期集中60-70%
|
||||||
|
# [微量, 小雨, 中雨, 大雨, 极端]
|
||||||
|
probabilities: [0.30, 0.25, 0.20, 0.15, 0.10]
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# 灾害层(条件概率)
|
||||||
|
# 规则匹配策略:首条匹配,从上到下扫描,命中即返回
|
||||||
|
# 高风险规则在前,低风险兜底规则在后
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# 滑坡(Landslide)
|
||||||
|
# 西安特征:
|
||||||
|
# - 黄土滑坡:黄土台塬塬边(白鹿塬、神禾塬、少陵塬),坡度15-35°
|
||||||
|
# - 岩质滑坡:秦岭北坡变质岩/花岗岩区,坡度>25°
|
||||||
|
# - 工程滑坡:城区开挖坡脚(地铁/道路建设)、弃土加载
|
||||||
|
# - 触发因素:前期降雨饱和+短历时高强度暴雨
|
||||||
|
# - 断裂带控制:秦岭北缘断裂沿线滑坡密度最高
|
||||||
|
# ----------------------------------------
|
||||||
|
landslide:
|
||||||
|
type: conditional
|
||||||
|
parents: [rain_intensity, duration, slope, soil_type, lithology, ndvi, soil_moisture, aspect, dist_to_river, dist_to_fault, landuse]
|
||||||
|
default_probability: 0.02
|
||||||
|
rules:
|
||||||
|
# === 极高风险(≥0.70)===
|
||||||
|
# 暴雨+陡坡+前期饱和:秦岭北坡典型触发条件
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], slope: [steep, very_steep, extreme_steep], soil_moisture: [wet, saturated]}
|
||||||
|
probability: 0.75
|
||||||
|
# 暴雨+陡坡+断裂带附近:秦岭北缘断裂沿线,岩体破碎
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], slope: [steep, very_steep, extreme_steep], dist_to_fault: [very_close, close]}
|
||||||
|
probability: 0.72
|
||||||
|
# 长历时暴雨+陡坡+饱和:持续降雨导致深层渗流
|
||||||
|
- condition: {duration: [long], rain_intensity: [heavy, storm, downpour, extreme], slope: [steep, very_steep, extreme_steep], soil_moisture: [wet, saturated]}
|
||||||
|
probability: 0.70
|
||||||
|
|
||||||
|
# === 高风险(0.50-0.65)===
|
||||||
|
# 暴雨+中陡坡:黄土塬边典型触发条件
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], slope: [moderate, steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.60
|
||||||
|
# 大雨+陡坡+松散堆积物:黄土滑坡物质条件充分
|
||||||
|
- condition: {rain_intensity: [heavy, storm, downpour], slope: [steep, very_steep, extreme_steep], lithology: [unconsolidated]}
|
||||||
|
probability: 0.58
|
||||||
|
# 暴雨+中陡坡+断裂带附近
|
||||||
|
- condition: {rain_intensity: [heavy, storm, downpour], slope: [moderate, steep, very_steep, extreme_steep], dist_to_fault: [very_close, close]}
|
||||||
|
probability: 0.55
|
||||||
|
# 城区开挖坡脚/弃土加载+暴雨:工程滑坡
|
||||||
|
- condition: {landuse: [urban], slope: [moderate, steep, very_steep, extreme_steep], rain_intensity: [heavy, storm, downpour, extreme]}
|
||||||
|
probability: 0.52
|
||||||
|
# 大雨+陡坡+初育土(黄土):黄土塬边滑坡
|
||||||
|
- condition: {rain_intensity: [heavy, storm, downpour], slope: [steep, very_steep, extreme_steep], soil_type: [entisol]}
|
||||||
|
probability: 0.50
|
||||||
|
|
||||||
|
# === 中风险(0.20-0.40)===
|
||||||
|
# 大雨+中坡+饱和
|
||||||
|
- condition: {rain_intensity: [heavy], slope: [moderate, steep], soil_moisture: [wet, saturated]}
|
||||||
|
probability: 0.40
|
||||||
|
# 中雨+陡坡
|
||||||
|
- condition: {rain_intensity: [moderate, heavy], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.35
|
||||||
|
# 暴雨+缓坡+松散堆积物:塬面黄土
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], slope: [gentle, moderate], lithology: [unconsolidated]}
|
||||||
|
probability: 0.30
|
||||||
|
# 断裂带+陡坡(无强降雨也有基岩蠕变风险)
|
||||||
|
- condition: {dist_to_fault: [very_close], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.25
|
||||||
|
# 城区+中坡:工程扰动
|
||||||
|
- condition: {landuse: [urban], slope: [moderate, steep]}
|
||||||
|
probability: 0.20
|
||||||
|
|
||||||
|
# === 低风险兜底(≤0.05)===
|
||||||
|
- condition: {rain_intensity: [no_rain, light]}
|
||||||
|
probability: 0.02
|
||||||
|
- condition: {slope: [flat, gentle]}
|
||||||
|
probability: 0.02
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# 泥石流(Debris Flow)
|
||||||
|
# 西安特征:
|
||||||
|
# - 集中在秦岭北麓沟道(周至、户县、长安、蓝田)
|
||||||
|
# - 物源:秦岭北缘断裂破碎带+坡面松散堆积物+崩塌堆积体
|
||||||
|
# - 沟道纵坡大(>15°),高差500-2000m,势能充足
|
||||||
|
# - 触发:短历时高强度暴雨(3h降雨>50mm)
|
||||||
|
# - 高发区海拔800-1500m(中山带,物源最丰富)
|
||||||
|
# ----------------------------------------
|
||||||
|
debris_flow:
|
||||||
|
type: conditional
|
||||||
|
parents: [rain_intensity, duration, slope, soil_type, lithology, sand_content, ndvi, soil_moisture, dist_to_river, dist_to_fault, elevation]
|
||||||
|
default_probability: 0.02
|
||||||
|
rules:
|
||||||
|
# === 极高风险(≥0.70)===
|
||||||
|
# 暴雨+陡坡+高含沙量:典型泥石流触发条件
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], slope: [steep, very_steep, extreme_steep], sand_content: [medium, high]}
|
||||||
|
probability: 0.80
|
||||||
|
# 暴雨+陡坡+断裂带附近:破碎岩体提供丰富物源
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], slope: [steep, very_steep, extreme_steep], dist_to_fault: [very_close, close]}
|
||||||
|
probability: 0.75
|
||||||
|
# 暴雨+中高山区+松散堆积物:秦岭北麓沟道泥石流
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], elevation: [mid_mountain, high_mountain], lithology: [unconsolidated, mixed_clastic]}
|
||||||
|
probability: 0.75
|
||||||
|
# 长历时暴雨+陡坡+饱和:深层渗透触发
|
||||||
|
- condition: {duration: [long], rain_intensity: [heavy, storm, downpour, extreme], slope: [steep, very_steep, extreme_steep], soil_moisture: [wet, saturated]}
|
||||||
|
probability: 0.72
|
||||||
|
|
||||||
|
# === 高风险(0.50-0.65)===
|
||||||
|
# 暴雨+中陡坡:沟道汇流
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], slope: [moderate, steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.60
|
||||||
|
# 大雨+陡坡+高含沙量
|
||||||
|
- condition: {rain_intensity: [heavy, storm, downpour], slope: [steep, very_steep, extreme_steep], sand_content: [medium, high]}
|
||||||
|
probability: 0.55
|
||||||
|
# 中高山区+中等降雨:物源区本身不稳定
|
||||||
|
- condition: {elevation: [mid_mountain, high_mountain], slope: [moderate, steep, very_steep, extreme_steep], rain_intensity: [heavy, storm, downpour, extreme]}
|
||||||
|
probability: 0.55
|
||||||
|
# 松散堆积物+陡坡+大雨:黄土泥石流
|
||||||
|
- condition: {lithology: [unconsolidated, mixed_clastic], slope: [steep, very_steep, extreme_steep], rain_intensity: [heavy, storm, downpour, extreme]}
|
||||||
|
probability: 0.52
|
||||||
|
|
||||||
|
# === 中风险(0.20-0.40)===
|
||||||
|
# 大雨+中坡
|
||||||
|
- condition: {rain_intensity: [moderate, heavy], slope: [moderate, steep]}
|
||||||
|
probability: 0.30
|
||||||
|
# 中高山区+中等降雨:物源区稳定性差
|
||||||
|
- condition: {elevation: [mid_mountain, high_mountain], slope: [moderate, steep], rain_intensity: [moderate, heavy]}
|
||||||
|
probability: 0.28
|
||||||
|
# 暴雨+缓坡+松散堆积物
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], slope: [gentle, moderate], lithology: [unconsolidated]}
|
||||||
|
probability: 0.25
|
||||||
|
# 断裂带+陡坡(无强降雨,崩塌堆积物也可启动)
|
||||||
|
- condition: {dist_to_fault: [very_close], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.22
|
||||||
|
|
||||||
|
# === 低风险兜底(≤0.05)===
|
||||||
|
- condition: {rain_intensity: [no_rain, light]}
|
||||||
|
probability: 0.01
|
||||||
|
- condition: {slope: [flat, gentle]}
|
||||||
|
probability: 0.02
|
||||||
|
- condition: {elevation: [basin, plain_urban]}
|
||||||
|
probability: 0.02
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# 山洪(Flash Flood)
|
||||||
|
# 西安特征:
|
||||||
|
# - 秦岭北坡溪流:短沟、陡坡、汇流快,暴雨后1-2h即达峰值
|
||||||
|
# - 城区河流(灞河、浐河、沣河、涝河):暴雨叠加城市径流
|
||||||
|
# - 渭河平原低洼区:排水不畅+河道顶托
|
||||||
|
# - 关键控制因子:降雨强度、前期土壤湿度、地形坡度
|
||||||
|
# - 典型事件:2016年7月长安区秦岭北坡山洪,2021年8月蓝田山洪
|
||||||
|
# ----------------------------------------
|
||||||
|
flash_flood:
|
||||||
|
type: conditional
|
||||||
|
parents: [rain_intensity, duration, accum_rain, elevation, terrain, dist_to_river, soil_moisture]
|
||||||
|
default_probability: 0.04
|
||||||
|
rules:
|
||||||
|
# === 极高风险(≥0.80)===
|
||||||
|
# 暴雨+饱和土壤+近河道:入渗率接近零,全部转为地表径流
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], soil_moisture: [saturated], dist_to_river: [very_close, close]}
|
||||||
|
probability: 0.90
|
||||||
|
# 暴雨+饱和+山地地形:秦岭北坡典型山洪条件
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], soil_moisture: [wet, saturated], terrain: [mountain, deep_valley, low_mountain]}
|
||||||
|
probability: 0.85
|
||||||
|
# 大暴雨+近河道+低洼区:渭河平原洪水
|
||||||
|
- condition: {rain_intensity: [downpour, extreme], dist_to_river: [very_close, close], elevation: [basin, plain_urban]}
|
||||||
|
probability: 0.82
|
||||||
|
|
||||||
|
# === 高风险(0.55-0.75)===
|
||||||
|
# 暴雨+近河道
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], dist_to_river: [very_close, close]}
|
||||||
|
probability: 0.70
|
||||||
|
# 暴雨+山地地形(远离河道但汇流快)
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], terrain: [mountain, deep_valley, low_mountain]}
|
||||||
|
probability: 0.65
|
||||||
|
# 大雨+饱和土壤+近河道
|
||||||
|
- condition: {rain_intensity: [heavy, storm, downpour], soil_moisture: [wet, saturated], dist_to_river: [very_close, close]}
|
||||||
|
probability: 0.60
|
||||||
|
# 长历时暴雨+山地:持续汇流
|
||||||
|
- condition: {duration: [long], rain_intensity: [heavy, storm, downpour, extreme], terrain: [mountain, deep_valley, low_mountain]}
|
||||||
|
probability: 0.58
|
||||||
|
# 极端累计降雨+山地地形
|
||||||
|
- condition: {accum_rain: [extreme], terrain: [mountain, deep_valley, low_mountain]}
|
||||||
|
probability: 0.55
|
||||||
|
|
||||||
|
# === 中风险(0.25-0.45)===
|
||||||
|
# 大雨+近河道
|
||||||
|
- condition: {rain_intensity: [heavy], dist_to_river: [very_close, close]}
|
||||||
|
probability: 0.45
|
||||||
|
# 暴雨+湿土(非饱和)
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], soil_moisture: [wet]}
|
||||||
|
probability: 0.40
|
||||||
|
# 大雨+山地地形
|
||||||
|
- condition: {rain_intensity: [heavy], terrain: [mountain, deep_valley, low_mountain]}
|
||||||
|
probability: 0.35
|
||||||
|
# 中雨+饱和+近河道
|
||||||
|
- condition: {rain_intensity: [moderate, heavy], soil_moisture: [saturated], dist_to_river: [very_close, close]}
|
||||||
|
probability: 0.40
|
||||||
|
# 极端累计+低洼区
|
||||||
|
- condition: {accum_rain: [extreme], elevation: [basin, plain_urban]}
|
||||||
|
probability: 0.35
|
||||||
|
# 暴雨+缓坡+近河道(平原河道溢出)
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], dist_to_river: [very_close], terrain: [plain, flat_plain]}
|
||||||
|
probability: 0.30
|
||||||
|
|
||||||
|
# === 低风险兜底(≤0.05)===
|
||||||
|
- condition: {rain_intensity: [no_rain, light]}
|
||||||
|
probability: 0.01
|
||||||
|
- condition: {dist_to_river: [far]}
|
||||||
|
probability: 0.03
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# 内涝(Waterlogging)
|
||||||
|
# 西安特征:
|
||||||
|
# - 主城区(碑林、莲湖、新城):不透水面率>60%,老城区管网密度不足
|
||||||
|
# - 高新区/经开区:新建区管网较好,但不透水面率高
|
||||||
|
# - 渭河平原低洼区:排水出口受河道水位顶托
|
||||||
|
# - 典型事件:2016年7月城区内涝(1h降雨46mm),2018年7月暴雨内涝
|
||||||
|
# - 关键控制因子:降雨强度+不透水面+管网密度+地形低洼
|
||||||
|
# ----------------------------------------
|
||||||
|
waterlogging:
|
||||||
|
type: conditional
|
||||||
|
parents: [rain_intensity, duration, accum_rain, elevation, landuse, impervious, soil_moisture, dist_to_river, pipe_density]
|
||||||
|
default_probability: 0.06
|
||||||
|
rules:
|
||||||
|
# === 极高风险(≥0.80)===
|
||||||
|
# 暴雨+高不透水面+管网不足:老城区典型内涝条件
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], impervious: [high], pipe_density: [none, low]}
|
||||||
|
probability: 0.90
|
||||||
|
# 极端累计降雨+长历时+高不透水面:持续强降雨
|
||||||
|
- condition: {accum_rain: [heavy, extreme], duration: [long], impervious: [medium, high]}
|
||||||
|
probability: 0.82
|
||||||
|
# 极端累计+低洼区+管网不足:积水无处排出
|
||||||
|
- condition: {accum_rain: [heavy, extreme], elevation: [basin, plain_urban], pipe_density: [none, low]}
|
||||||
|
probability: 0.80
|
||||||
|
|
||||||
|
# === 高风险(0.55-0.75)===
|
||||||
|
# 暴雨+高不透水面
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], impervious: [high]}
|
||||||
|
probability: 0.72
|
||||||
|
# 大雨+长历时+高不透水面
|
||||||
|
- condition: {rain_intensity: [heavy], duration: [long], impervious: [high]}
|
||||||
|
probability: 0.65
|
||||||
|
# 暴雨+城市用地+管网不足
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], landuse: [urban], pipe_density: [none, low]}
|
||||||
|
probability: 0.68
|
||||||
|
# 大雨+中高不透水面
|
||||||
|
- condition: {rain_intensity: [heavy, storm, downpour], impervious: [medium, high]}
|
||||||
|
probability: 0.60
|
||||||
|
# 极端累计+低洼区(不透水面不高也会积水)
|
||||||
|
- condition: {accum_rain: [extreme], elevation: [basin, plain_urban]}
|
||||||
|
probability: 0.58
|
||||||
|
# 饱和土壤+暴雨+低洼区:入渗饱和后地表积水
|
||||||
|
- condition: {soil_moisture: [saturated], rain_intensity: [heavy, storm, downpour, extreme], elevation: [basin, plain_urban]}
|
||||||
|
probability: 0.55
|
||||||
|
|
||||||
|
# === 中风险(0.25-0.45)===
|
||||||
|
# 大雨+中高不透水面
|
||||||
|
- condition: {rain_intensity: [moderate, heavy], impervious: [medium, high]}
|
||||||
|
probability: 0.40
|
||||||
|
# 中等累计+管网不足
|
||||||
|
- condition: {accum_rain: [moderate, heavy], pipe_density: [none, low], impervious: [medium]}
|
||||||
|
probability: 0.38
|
||||||
|
# 暴雨+低不透水面(非城区但排水不畅)
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], impervious: [low]}
|
||||||
|
probability: 0.30
|
||||||
|
# 近河道+暴雨:排水出口受河道水位顶托
|
||||||
|
- condition: {dist_to_river: [very_close, close], rain_intensity: [heavy, storm, downpour, extreme], elevation: [basin, plain_urban]}
|
||||||
|
probability: 0.35
|
||||||
|
# 农田积水:低洼农田排水不畅
|
||||||
|
- condition: {landuse: [farmland], rain_intensity: [heavy, storm, downpour, extreme], elevation: [basin, plain_urban]}
|
||||||
|
probability: 0.30
|
||||||
|
|
||||||
|
# === 低风险兜底(≤0.05)===
|
||||||
|
# 老城区管网堵塞可在无雨时积水
|
||||||
|
- condition: {rain_intensity: [no_rain], pipe_density: [none, low], landuse: [urban]}
|
||||||
|
probability: 0.05
|
||||||
|
- condition: {rain_intensity: [no_rain, light]}
|
||||||
|
probability: 0.02
|
||||||
|
- condition: {impervious: [low], pipe_density: [medium, high]}
|
||||||
|
probability: 0.03
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# 崩塌(Collapse)
|
||||||
|
# 西安特征:
|
||||||
|
# - 黄土崩塌:渭河、灞河、浐河、沣河侧蚀黄土塬边,形成陡坎
|
||||||
|
# - 岩质崩塌:秦岭北坡陡崖(>45°),节理发育的花岗岩/变质岩
|
||||||
|
# - 工程崩塌:道路切坡、采石场边坡
|
||||||
|
# - 触发因素:降雨入渗软化+冻融风化+河流侧蚀
|
||||||
|
# - 断裂带控制:秦岭北缘断裂沿线岩体破碎,崩塌密度高
|
||||||
|
# ----------------------------------------
|
||||||
|
collapse:
|
||||||
|
type: conditional
|
||||||
|
parents: [rain_intensity, duration, slope, lithology, soil_moisture, dist_to_fault, dist_to_river]
|
||||||
|
default_probability: 0.02
|
||||||
|
rules:
|
||||||
|
# === 极高风险(≥0.70)===
|
||||||
|
# 暴雨+陡坡+松散岩性(黄土/碎屑岩):黄土塬边崩塌
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], slope: [steep, very_steep, extreme_steep], lithology: [terrigenous, unconsolidated, mixed_clastic]}
|
||||||
|
probability: 0.72
|
||||||
|
# 近河道+松散堆积物+陡坡:河流侧蚀致崩塌(渭河/灞河/浐河)
|
||||||
|
- condition: {dist_to_river: [very_close, close], lithology: [unconsolidated], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.70
|
||||||
|
|
||||||
|
# === 高风险(0.50-0.65)===
|
||||||
|
# 暴雨+陡坡+断裂带附近:岩体破碎
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], slope: [moderate, steep, very_steep, extreme_steep], dist_to_fault: [very_close, close]}
|
||||||
|
probability: 0.65
|
||||||
|
# 暴雨+中陡坡+饱和:岩土体强度降低
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], slope: [moderate, steep, very_steep, extreme_steep], soil_moisture: [wet, saturated]}
|
||||||
|
probability: 0.60
|
||||||
|
# 近河道+暴雨+中陡坡:岸坡浸泡+洪水冲刷
|
||||||
|
- condition: {dist_to_river: [very_close, close], rain_intensity: [storm, downpour, extreme], slope: [moderate, steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.58
|
||||||
|
# 暴雨+中陡坡
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], slope: [moderate, steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.50
|
||||||
|
# 长历时+大雨+陡坡+松散岩性:持续入渗软化
|
||||||
|
- condition: {duration: [long], rain_intensity: [heavy, storm, downpour, extreme], slope: [steep, very_steep, extreme_steep], lithology: [terrigenous, unconsolidated, mixed_clastic]}
|
||||||
|
probability: 0.55
|
||||||
|
|
||||||
|
# === 中风险(0.20-0.40)===
|
||||||
|
# 近河道+缓坡+松散堆积物:侧蚀累积效应
|
||||||
|
- condition: {dist_to_river: [very_close, close], lithology: [unconsolidated], slope: [moderate]}
|
||||||
|
probability: 0.35
|
||||||
|
# 大雨+中坡
|
||||||
|
- condition: {rain_intensity: [heavy], slope: [moderate, steep]}
|
||||||
|
probability: 0.30
|
||||||
|
# 断裂带+陡坡(无强降雨也有蠕变崩塌风险)
|
||||||
|
- condition: {dist_to_fault: [very_close], slope: [steep, very_steep, extreme_steep]}
|
||||||
|
probability: 0.25
|
||||||
|
# 暴雨+缓坡+松散岩性
|
||||||
|
- condition: {rain_intensity: [storm, downpour, extreme], slope: [gentle, moderate], lithology: [unconsolidated]}
|
||||||
|
probability: 0.22
|
||||||
|
|
||||||
|
# === 低风险兜底(≤0.05)===
|
||||||
|
- condition: {rain_intensity: [no_rain, light]}
|
||||||
|
probability: 0.01
|
||||||
|
- condition: {slope: [flat, gentle]}
|
||||||
|
probability: 0.01
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
# DBN 图结构配置
|
||||||
|
# 定义节点、各层节点列表、父子关系
|
||||||
|
|
||||||
|
# 推理配置
|
||||||
|
inference_config:
|
||||||
|
match_strategy: first # first=首条匹配(规则优先级从上到下),max=取最大概率
|
||||||
|
default_strategy: use_default # 无规则匹配时使用 default_probability
|
||||||
|
max_cpt_parents: 20 # CPT 最大父节点数(超过则采用规则加权融合)
|
||||||
|
|
||||||
|
layers:
|
||||||
|
# 触发层(3个节点)
|
||||||
|
trigger:
|
||||||
|
- rain_intensity # 降雨强度
|
||||||
|
- duration # 持续时间
|
||||||
|
- accum_rain # 累计降雨量
|
||||||
|
|
||||||
|
# 环境层(16个节点)
|
||||||
|
environment:
|
||||||
|
- elevation # 高程
|
||||||
|
- slope # 坡度
|
||||||
|
- aspect # 坡向
|
||||||
|
- soil_type # 土壤分类
|
||||||
|
- lithology # 岩性
|
||||||
|
- landuse # 土地利用类型
|
||||||
|
- terrain # 地形分类
|
||||||
|
- impervious # 不透水面
|
||||||
|
- ndvi # 植被指数
|
||||||
|
- sand_content # 土壤含沙量
|
||||||
|
- ph # 土壤PH值(辅助因子,不入CPT)
|
||||||
|
- soil_moisture # 土壤湿度
|
||||||
|
- organic_carbon # 有机碳(辅助因子,不入CPT)
|
||||||
|
- dist_to_river # 距离河道距离
|
||||||
|
- dist_to_fault # 距离断裂带距离
|
||||||
|
- pipe_density # 供水管网密度
|
||||||
|
|
||||||
|
# 灾害层(5个节点)
|
||||||
|
hazard:
|
||||||
|
- landslide # 滑坡
|
||||||
|
- debris_flow # 泥石流
|
||||||
|
- flash_flood # 山洪
|
||||||
|
- waterlogging # 内涝
|
||||||
|
- collapse # 崩塌
|
||||||
|
|
||||||
|
edges:
|
||||||
|
# 触发层 → 灾害层
|
||||||
|
# 降雨强度
|
||||||
|
- [rain_intensity, landslide]
|
||||||
|
- [rain_intensity, debris_flow]
|
||||||
|
- [rain_intensity, flash_flood]
|
||||||
|
- [rain_intensity, waterlogging]
|
||||||
|
- [rain_intensity, collapse]
|
||||||
|
|
||||||
|
# 持续时间
|
||||||
|
- [duration, landslide]
|
||||||
|
- [duration, debris_flow]
|
||||||
|
- [ duration, flash_flood ]
|
||||||
|
- [duration, waterlogging]
|
||||||
|
- [duration, collapse]
|
||||||
|
|
||||||
|
# 累计降雨量
|
||||||
|
- [accum_rain, landslide]
|
||||||
|
- [accum_rain, debris_flow]
|
||||||
|
- [accum_rain, flash_flood]
|
||||||
|
- [accum_rain, waterlogging]
|
||||||
|
- [accum_rain, collapse]
|
||||||
|
|
||||||
|
# 环境层 → 灾害层
|
||||||
|
# 高程影响山洪、内涝、泥石流
|
||||||
|
# - 山洪:高程影响汇流面积和河道坡降
|
||||||
|
# - 内涝:低洼处积水
|
||||||
|
# - 泥石流:高程反映沟道纵坡和物源区高差(秦岭北麓1000m+高发)
|
||||||
|
- [elevation, flash_flood]
|
||||||
|
- [elevation, waterlogging]
|
||||||
|
- [elevation, debris_flow]
|
||||||
|
|
||||||
|
# 坡度影响滑坡、泥石流、崩塌
|
||||||
|
- [slope, landslide]
|
||||||
|
- [slope, debris_flow]
|
||||||
|
- [slope, collapse]
|
||||||
|
|
||||||
|
# 坡向影响滑坡(阳坡冻融风化强烈)
|
||||||
|
- [aspect, landslide]
|
||||||
|
|
||||||
|
# 土壤类型影响滑坡、泥石流
|
||||||
|
- [soil_type, landslide]
|
||||||
|
- [soil_type, debris_flow]
|
||||||
|
|
||||||
|
# 岩性影响滑坡、泥石流、崩塌
|
||||||
|
- [lithology, landslide]
|
||||||
|
- [lithology, debris_flow]
|
||||||
|
- [lithology, collapse]
|
||||||
|
|
||||||
|
# 土地利用类型影响内涝、滑坡
|
||||||
|
# - 内涝:城市地表不透水
|
||||||
|
# - 滑坡:开挖坡脚/弃土加载/梯田改造
|
||||||
|
- [landuse, waterlogging]
|
||||||
|
- [landuse, landslide]
|
||||||
|
|
||||||
|
# 地形分类影响山洪、内涝
|
||||||
|
- [terrain, flash_flood]
|
||||||
|
- [terrain, waterlogging]
|
||||||
|
|
||||||
|
# 不透水面影响内涝
|
||||||
|
- [impervious, waterlogging]
|
||||||
|
|
||||||
|
# 植被指数影响滑坡、泥石流
|
||||||
|
- [ndvi, landslide]
|
||||||
|
- [ndvi, debris_flow]
|
||||||
|
|
||||||
|
# 土壤含沙量影响泥石流
|
||||||
|
- [sand_content, debris_flow]
|
||||||
|
|
||||||
|
# 土壤湿度影响滑坡、泥石流、内涝、山洪
|
||||||
|
# - 山洪:前期土壤湿度决定入渗率,饱和土壤几乎全部转为地表径流
|
||||||
|
- [soil_moisture, landslide]
|
||||||
|
- [soil_moisture, debris_flow]
|
||||||
|
- [soil_moisture, waterlogging]
|
||||||
|
- [soil_moisture, flash_flood]
|
||||||
|
|
||||||
|
# 距离河道距离影响山洪、泥石流、内涝、崩塌
|
||||||
|
# - 山洪:河道溢出 → [dist_to_river, flash_flood]
|
||||||
|
# - 泥石流:沟道物源供给 → [dist_to_river, debris_flow]
|
||||||
|
# - 内涝:排水出口受阻 → [dist_to_river, waterlogging]
|
||||||
|
# - 崩塌:河流侧蚀黄土塬边(渭河/灞河/浐河/沣河)→ [dist_to_river, collapse]
|
||||||
|
- [dist_to_river, flash_flood]
|
||||||
|
- [dist_to_river, debris_flow]
|
||||||
|
- [dist_to_river, waterlogging]
|
||||||
|
- [dist_to_river, collapse]
|
||||||
|
|
||||||
|
# 距离断裂带距离影响滑坡、崩塌、泥石流
|
||||||
|
- [dist_to_fault, landslide]
|
||||||
|
- [dist_to_fault, collapse]
|
||||||
|
- [dist_to_fault, debris_flow]
|
||||||
|
|
||||||
|
# 供水管网密度影响内涝
|
||||||
|
- [pipe_density, waterlogging]
|
||||||
|
|
||||||
|
# 节点状态定义(与 discretization.yaml 保持一致)
|
||||||
|
node_states:
|
||||||
|
# 触发层
|
||||||
|
rain_intensity: [no_rain, light, moderate, heavy, storm, downpour, extreme]
|
||||||
|
duration: [short, medium, long]
|
||||||
|
accum_rain: [trace, light, moderate, heavy, extreme]
|
||||||
|
|
||||||
|
# 环境层(离散字段状态名与数据库编码一一对应,连续字段用工程分级)
|
||||||
|
elevation: [basin, plain_urban, transition, low_mountain, mid_mountain, high_mountain]
|
||||||
|
slope: [flat, gentle, moderate, steep, very_steep, extreme_steep]
|
||||||
|
aspect: [north, east, south, west, north_loop]
|
||||||
|
soil_type: [ultisol, entisol, fluvo_aquic, yellow_brown]
|
||||||
|
lithology: [acid_rock, basic_rock, carbonate, metamorphic, mixed_clastic, terrigenous, unconsolidated]
|
||||||
|
landuse: [forest, farmland, urban, water, barren]
|
||||||
|
terrain: [mountain, plain, deep_valley, hill, gentle_hill, low_mountain, flat_plain]
|
||||||
|
impervious: [low, medium, high]
|
||||||
|
ndvi: [water, bare, sparse, moderate, dense, very_dense]
|
||||||
|
sand_content: [low, medium, high]
|
||||||
|
ph: [acidic, neutral, alkaline]
|
||||||
|
soil_moisture: [dry, moist, wet, saturated]
|
||||||
|
organic_carbon: [low, medium, high]
|
||||||
|
dist_to_river: [very_close, close, moderate, far]
|
||||||
|
dist_to_fault: [very_close, close, moderate, far]
|
||||||
|
pipe_density: [none, low, medium, high]
|
||||||
|
|
||||||
|
# 灾害层
|
||||||
|
landslide: [none, low, medium, high, very_high]
|
||||||
|
debris_flow: [none, low, medium, high, very_high]
|
||||||
|
flash_flood: [none, low, medium, high, very_high]
|
||||||
|
waterlogging: [none, low, medium, high, very_high]
|
||||||
|
collapse: [none, low, medium, high, very_high]
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
"""
|
||||||
|
项目配置模块
|
||||||
|
提供统一的项目路径和配置管理
|
||||||
|
"""
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# 项目根目录(app/config/ 的上两级)
|
||||||
|
PROJECT_ROOT = Path(__file__).parent.parent.parent
|
||||||
|
|
||||||
|
# 日志目录
|
||||||
|
LOG_DIR = PROJECT_ROOT / "logs"
|
||||||
|
|
||||||
|
# 配置文件目录
|
||||||
|
CONFIG_DIR = PROJECT_ROOT / "app" / "config"
|
||||||
|
|
||||||
|
# DBN 配置目录
|
||||||
|
DBN_CONFIG_DIR = CONFIG_DIR / "dbn"
|
||||||
|
|
||||||
|
|
||||||
|
def get_logger(name: str = "algorithm"):
|
||||||
|
"""
|
||||||
|
获取日志记录器的便捷函数
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: 日志名称
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
logging.Logger 实例
|
||||||
|
"""
|
||||||
|
from app.utils.logger import get_logger as _get_logger
|
||||||
|
return _get_logger(name, str(LOG_DIR))
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
DBN 模型模块
|
||||||
|
"""
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
"""
|
||||||
|
地震灾害链DBN模型模块
|
||||||
|
"""
|
||||||
|
from .earthquake_dbn import EarthquakeDBN, earthquake_dbn
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'EarthquakeDBN', 'earthquake_dbn',
|
||||||
|
]
|
||||||
@@ -0,0 +1,395 @@
|
|||||||
|
"""
|
||||||
|
地震灾害链DBN模型
|
||||||
|
实现贝叶斯网络推理,预测地震触发的3类地质灾害概率:
|
||||||
|
滑坡(landslide)、泥石流(debris_flow)、崩塌(collapse)
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import math
|
||||||
|
import yaml
|
||||||
|
from typing import Optional, List, Dict, Any
|
||||||
|
|
||||||
|
from app.utils.discretizer import discretizer
|
||||||
|
from app.repositories.dbn_repository import DbnRepository
|
||||||
|
from app.config.paths import DBN_CONFIG_DIR, get_logger
|
||||||
|
|
||||||
|
logger = get_logger("earthquake_dbn")
|
||||||
|
|
||||||
|
|
||||||
|
class EarthquakeDBN:
|
||||||
|
"""地震灾害链DBN模型"""
|
||||||
|
|
||||||
|
# 灾害概率→离散等级的阈值映射
|
||||||
|
HAZARD_LEVEL_THRESHOLDS = [
|
||||||
|
(0.6, 'very_high'),
|
||||||
|
(0.4, 'high'),
|
||||||
|
(0.2, 'medium'),
|
||||||
|
(0.05, 'low'),
|
||||||
|
(0.0, 'none'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def _probability_to_level(self, prob: float) -> str:
|
||||||
|
"""将连续概率映射到离散等级"""
|
||||||
|
for threshold, level in self.HAZARD_LEVEL_THRESHOLDS:
|
||||||
|
if prob >= threshold:
|
||||||
|
return level
|
||||||
|
return 'none'
|
||||||
|
|
||||||
|
def __init__(self, config_dir: Optional[str] = None):
|
||||||
|
"""
|
||||||
|
初始化地震DBN模型
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_dir: 配置文件目录,默认为 app/config/dbn
|
||||||
|
"""
|
||||||
|
if config_dir is None:
|
||||||
|
config_dir = str(DBN_CONFIG_DIR)
|
||||||
|
|
||||||
|
self.config_dir = config_dir
|
||||||
|
self.graph_config = self._load_graph_config()
|
||||||
|
self.cpt_config = self._load_cpt_config()
|
||||||
|
|
||||||
|
self._build_network()
|
||||||
|
|
||||||
|
def _load_graph_config(self) -> Dict[str, Any]:
|
||||||
|
"""加载地震图结构配置"""
|
||||||
|
config_path = os.path.join(self.config_dir, 'earthquake_dbn_graph.yaml')
|
||||||
|
|
||||||
|
if not os.path.exists(config_path):
|
||||||
|
logger.error(f"地震图结构配置文件不存在: {config_path}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
|
return yaml.safe_load(f)
|
||||||
|
|
||||||
|
def _load_cpt_config(self) -> Dict[str, Any]:
|
||||||
|
"""加载地震CPT配置"""
|
||||||
|
config_path = os.path.join(self.config_dir, 'earthquake_cpt_params.yaml')
|
||||||
|
|
||||||
|
if not os.path.exists(config_path):
|
||||||
|
logger.error(f"地震CPT配置文件不存在: {config_path}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
|
return yaml.safe_load(f)
|
||||||
|
|
||||||
|
def _build_network(self):
|
||||||
|
"""构建贝叶斯网络结构"""
|
||||||
|
self.trigger_nodes = self.graph_config.get('layers', {}).get('trigger', [])
|
||||||
|
self.environment_nodes = self.graph_config.get('layers', {}).get('environment', [])
|
||||||
|
self.hazard_nodes = self.graph_config.get('layers', {}).get('hazard', [])
|
||||||
|
|
||||||
|
self.all_nodes = self.trigger_nodes + self.environment_nodes + self.hazard_nodes
|
||||||
|
self.edges = self.graph_config.get('edges', [])
|
||||||
|
self.node_states = self.graph_config.get('node_states', {})
|
||||||
|
|
||||||
|
self.children = {node: [] for node in self.all_nodes}
|
||||||
|
self.parents = {node: [] for node in self.all_nodes}
|
||||||
|
|
||||||
|
for parent, child in self.edges:
|
||||||
|
if parent in self.all_nodes and child in self.all_nodes:
|
||||||
|
self.children[parent].append(child)
|
||||||
|
self.parents[child].append(parent)
|
||||||
|
|
||||||
|
self._build_cpt_tables()
|
||||||
|
|
||||||
|
def _build_cpt_tables(self):
|
||||||
|
"""构建条件概率表"""
|
||||||
|
self.cpt_tables = {}
|
||||||
|
|
||||||
|
for node in self.all_nodes:
|
||||||
|
if node in self.cpt_config:
|
||||||
|
self.cpt_tables[node] = self.cpt_config[node]
|
||||||
|
else:
|
||||||
|
states = self.node_states.get(node, ['no', 'yes'])
|
||||||
|
if len(states) == 2:
|
||||||
|
self.cpt_tables[node] = {
|
||||||
|
'type': 'prior',
|
||||||
|
'probabilities': [0.5, 0.5]
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
prob = 1.0 / len(states)
|
||||||
|
self.cpt_tables[node] = {
|
||||||
|
'type': 'prior',
|
||||||
|
'probabilities': [prob] * len(states)
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def estimate_seismic_intensity(magnitude: float, epicenter_distance_km: float) -> float:
|
||||||
|
"""
|
||||||
|
根据震级和震中距估算地震烈度
|
||||||
|
使用中国地震烈度衰减关系
|
||||||
|
|
||||||
|
I = 0.923 + 1.621*M - 3.494*ln(R+10)
|
||||||
|
|
||||||
|
参考:GB 18306-2015 中国地震动参数区划图
|
||||||
|
|
||||||
|
Args:
|
||||||
|
magnitude: 震级(Richter)
|
||||||
|
epicenter_distance_km: 震中距(km)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
估算的地震烈度(中国烈度表数值)
|
||||||
|
"""
|
||||||
|
if epicenter_distance_km < 0:
|
||||||
|
epicenter_distance_km = 0
|
||||||
|
|
||||||
|
intensity = 0.923 + 1.621 * magnitude - 3.494 * math.log(epicenter_distance_km + 10)
|
||||||
|
|
||||||
|
# 限制在合理范围内
|
||||||
|
return max(1.0, min(12.0, intensity))
|
||||||
|
|
||||||
|
def _get_node_probability(self, node: str, evidence: Dict[str, str]) -> List[float]:
|
||||||
|
"""获取节点的概率分布"""
|
||||||
|
cpt = self.cpt_tables.get(node)
|
||||||
|
if not cpt:
|
||||||
|
states = self.node_states.get(node, ['no', 'yes'])
|
||||||
|
return [1.0 / len(states)] * len(states)
|
||||||
|
|
||||||
|
if cpt.get('type') == 'prior':
|
||||||
|
return cpt.get('probabilities', [0.5, 0.5])
|
||||||
|
|
||||||
|
if cpt.get('type') == 'conditional':
|
||||||
|
return self._evaluate_conditional_probability(node, cpt, evidence)
|
||||||
|
|
||||||
|
return [0.5, 0.5]
|
||||||
|
|
||||||
|
def _evaluate_conditional_probability(self, node: str, cpt: Dict[str, Any],
|
||||||
|
evidence: Dict[str, str]) -> List[float]:
|
||||||
|
"""评估条件概率"""
|
||||||
|
states = self.node_states.get(node, ['no', 'yes'])
|
||||||
|
default_prob = cpt.get('default_probability', 0.02)
|
||||||
|
|
||||||
|
rules = cpt.get('rules', [])
|
||||||
|
for rule in rules:
|
||||||
|
condition = rule.get('condition', {})
|
||||||
|
probability = rule.get('probability', default_prob)
|
||||||
|
|
||||||
|
if self._check_condition(condition, evidence):
|
||||||
|
return [1.0 - probability, probability]
|
||||||
|
|
||||||
|
return [1.0 - default_prob, default_prob]
|
||||||
|
|
||||||
|
def _check_condition(self, condition: Dict[str, Any], evidence: Dict[str, str]) -> bool:
|
||||||
|
"""检查条件是否满足"""
|
||||||
|
for node, required_states in condition.items():
|
||||||
|
if node not in evidence:
|
||||||
|
return False
|
||||||
|
|
||||||
|
evidence_state = evidence[node]
|
||||||
|
|
||||||
|
if isinstance(required_states, list):
|
||||||
|
if evidence_state not in required_states:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if evidence_state != required_states:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def predict_single_point(self, point: Dict[str, Any],
|
||||||
|
magnitude: float,
|
||||||
|
epicenter_distance: Optional[float] = None,
|
||||||
|
seismic_intensity: Optional[float] = None,
|
||||||
|
epicenter_lon: Optional[float] = None,
|
||||||
|
epicenter_lat: Optional[float] = None) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
对单个点进行地震灾害预测
|
||||||
|
|
||||||
|
Args:
|
||||||
|
point: 点信息(包含 static_factors 字段,来自 xian_risk_factors 表)
|
||||||
|
magnitude: 地震震级(Richter)
|
||||||
|
epicenter_distance: 震中距(km),若未提供则通过震中坐标计算
|
||||||
|
seismic_intensity: 地震烈度(中国烈度表),若未提供则自动估算
|
||||||
|
epicenter_lon: 震中经度(可选,用于计算震中距)
|
||||||
|
epicenter_lat: 震中纬度(可选,用于计算震中距)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
预测结果
|
||||||
|
"""
|
||||||
|
point_id = point.get('id')
|
||||||
|
lon = point.get('lon')
|
||||||
|
lat = point.get('lat')
|
||||||
|
source_type = point.get('source_type')
|
||||||
|
|
||||||
|
logger.info(f"地震预测点 ID={point_id}, source_type={source_type}")
|
||||||
|
|
||||||
|
# 计算震中距(如果未直接提供)
|
||||||
|
if epicenter_distance is None:
|
||||||
|
if epicenter_lon is not None and epicenter_lat is not None:
|
||||||
|
epicenter_distance = self._haversine_distance(
|
||||||
|
lon, lat, epicenter_lon, epicenter_lat
|
||||||
|
)
|
||||||
|
logger.info(f"计算震中距: {epicenter_distance:.1f} km")
|
||||||
|
else:
|
||||||
|
logger.warning("未提供震中距或震中坐标,使用默认值 100km")
|
||||||
|
epicenter_distance = 100.0
|
||||||
|
|
||||||
|
# 估算地震烈度(如果未直接提供)
|
||||||
|
if seismic_intensity is None:
|
||||||
|
seismic_intensity = self.estimate_seismic_intensity(magnitude, epicenter_distance)
|
||||||
|
logger.info(f"估算地震烈度: {seismic_intensity:.1f}")
|
||||||
|
|
||||||
|
# 获取静态因子数据
|
||||||
|
raw_factors = point.get('static_factors', {})
|
||||||
|
static_factors = {
|
||||||
|
'elevation': raw_factors.get('dem_value'),
|
||||||
|
'slope': raw_factors.get('slope_value'),
|
||||||
|
'aspect': raw_factors.get('aspect_value'),
|
||||||
|
'soil_type': raw_factors.get('soil_type'),
|
||||||
|
'lithology': raw_factors.get('lithology'),
|
||||||
|
'landuse': raw_factors.get('landuse'),
|
||||||
|
'terrain': raw_factors.get('landform'),
|
||||||
|
'ndvi': raw_factors.get('vegetation_index'),
|
||||||
|
'sand_content': raw_factors.get('soil_sand'),
|
||||||
|
'ph': raw_factors.get('soil_ph'),
|
||||||
|
'soil_moisture': raw_factors.get('soil_moisture'),
|
||||||
|
'organic_carbon': raw_factors.get('organic_carbon'),
|
||||||
|
'dist_to_river': raw_factors.get('river_distance'),
|
||||||
|
'dist_to_fault': raw_factors.get('fault_distance'),
|
||||||
|
}
|
||||||
|
|
||||||
|
# 合并地震触发因子和静态因子
|
||||||
|
all_factors = {
|
||||||
|
'magnitude': magnitude,
|
||||||
|
'epicenter_distance': epicenter_distance,
|
||||||
|
'seismic_intensity': seismic_intensity,
|
||||||
|
**static_factors
|
||||||
|
}
|
||||||
|
|
||||||
|
# 离散化
|
||||||
|
evidence = discretizer.discretize_all_factors(all_factors)
|
||||||
|
|
||||||
|
# 运行推理
|
||||||
|
hazard_results = self._run_inference(evidence)
|
||||||
|
|
||||||
|
# 构造输出
|
||||||
|
result = {
|
||||||
|
'point_id': point_id,
|
||||||
|
'source_type': source_type,
|
||||||
|
'lon': lon,
|
||||||
|
'lat': lat,
|
||||||
|
'earthquake_params': {
|
||||||
|
'magnitude': magnitude,
|
||||||
|
'epicenter_distance': round(epicenter_distance, 1),
|
||||||
|
'seismic_intensity': round(seismic_intensity, 1),
|
||||||
|
},
|
||||||
|
'disaster_probabilities': {
|
||||||
|
h: r['probability'] for h, r in hazard_results.items()
|
||||||
|
},
|
||||||
|
'disaster_levels': {
|
||||||
|
h: r['level'] for h, r in hazard_results.items()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _haversine_distance(self, lon1: float, lat1: float,
|
||||||
|
lon2: float, lat2: float) -> float:
|
||||||
|
"""
|
||||||
|
使用Haversine公式计算两点间距离
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lon1, lat1: 点1的经纬度
|
||||||
|
lon2, lat2: 点2的经纬度
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
距离(km)
|
||||||
|
"""
|
||||||
|
R = 6371.0 # 地球半径(km)
|
||||||
|
|
||||||
|
lat1_rad = math.radians(lat1)
|
||||||
|
lat2_rad = math.radians(lat2)
|
||||||
|
dlat = math.radians(lat2 - lat1)
|
||||||
|
dlon = math.radians(lon2 - lon1)
|
||||||
|
|
||||||
|
a = math.sin(dlat / 2) ** 2 + \
|
||||||
|
math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(dlon / 2) ** 2
|
||||||
|
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
|
||||||
|
|
||||||
|
return R * c
|
||||||
|
|
||||||
|
def _run_inference(self, evidence: Dict[str, str]) -> Dict[str, Any]:
|
||||||
|
"""运行贝叶斯推理"""
|
||||||
|
hazard_probabilities = {}
|
||||||
|
|
||||||
|
for hazard_node in self.hazard_nodes:
|
||||||
|
prob_dist = self._get_node_probability(hazard_node, evidence)
|
||||||
|
|
||||||
|
if len(prob_dist) >= 2:
|
||||||
|
prob = prob_dist[1]
|
||||||
|
else:
|
||||||
|
prob = 0.0
|
||||||
|
|
||||||
|
hazard_probabilities[hazard_node] = {
|
||||||
|
'probability': round(prob, 4),
|
||||||
|
'level': self._probability_to_level(prob)
|
||||||
|
}
|
||||||
|
|
||||||
|
return hazard_probabilities
|
||||||
|
|
||||||
|
def predict(self, region_code: Optional[str] = None,
|
||||||
|
magnitude: float = 6.0,
|
||||||
|
epicenter_distance: Optional[float] = None,
|
||||||
|
seismic_intensity: Optional[float] = None,
|
||||||
|
epicenter_lon: Optional[float] = None,
|
||||||
|
epicenter_lat: Optional[float] = None) -> List[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
对所有点进行地震灾害预测
|
||||||
|
|
||||||
|
Args:
|
||||||
|
region_code: 行政区划代码(可选)
|
||||||
|
magnitude: 地震震级(默认6.0)
|
||||||
|
epicenter_distance: 震中距(km,可选)
|
||||||
|
seismic_intensity: 地震烈度(可选)
|
||||||
|
epicenter_lon: 震中经度(可选)
|
||||||
|
epicenter_lat: 震中纬度(可选)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
预测结果列表
|
||||||
|
"""
|
||||||
|
points = DbnRepository.get_all_points(region_code)
|
||||||
|
|
||||||
|
if not points:
|
||||||
|
logger.warning(f"没有找到点数据,region_code={region_code}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
logger.info(f"地震灾害预测:共 {len(points)} 个点,震级 M{magnitude}")
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for point in points:
|
||||||
|
try:
|
||||||
|
result = self.predict_single_point(
|
||||||
|
point,
|
||||||
|
magnitude=magnitude,
|
||||||
|
epicenter_distance=epicenter_distance,
|
||||||
|
seismic_intensity=seismic_intensity,
|
||||||
|
epicenter_lon=epicenter_lon,
|
||||||
|
epicenter_lat=epicenter_lat
|
||||||
|
)
|
||||||
|
results.append(result)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"预测点 {point.get('id')} 失败: {e}")
|
||||||
|
results.append({
|
||||||
|
'point_id': point.get('id'),
|
||||||
|
'source_type': point.get('source_type'),
|
||||||
|
'lon': point.get('lon'),
|
||||||
|
'lat': point.get('lat'),
|
||||||
|
'error': str(e)
|
||||||
|
})
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def get_model_info(self) -> Dict[str, Any]:
|
||||||
|
"""获取模型信息"""
|
||||||
|
return {
|
||||||
|
'model_type': 'earthquake',
|
||||||
|
'trigger_nodes': self.trigger_nodes,
|
||||||
|
'environment_nodes': self.environment_nodes,
|
||||||
|
'hazard_nodes': self.hazard_nodes,
|
||||||
|
'edges': self.edges,
|
||||||
|
'node_states': self.node_states
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# 创建全局实例
|
||||||
|
earthquake_dbn = EarthquakeDBN()
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
"""
|
||||||
|
暴雨灾害链DBN模型模块
|
||||||
|
数据库查询统一由 app.repositories.dbn_repository 提供
|
||||||
|
离散化工具由 app.utils.discretizer 提供
|
||||||
|
空间计算由 app.utils.spatial_utils 提供
|
||||||
|
"""
|
||||||
|
from .rainfall_dbn import RainfallDBN, rainfall_dbn
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'RainfallDBN', 'rainfall_dbn',
|
||||||
|
]
|
||||||
@@ -0,0 +1,394 @@
|
|||||||
|
"""
|
||||||
|
暴雨灾害链DBN模型
|
||||||
|
实现贝叶斯网络推理,预测5类灾害概率
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
from typing import Optional, List, Dict, Any
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from app.utils.discretizer import discretizer
|
||||||
|
from app.repositories.dbn_repository import DbnRepository
|
||||||
|
from app.config.paths import DBN_CONFIG_DIR, get_logger
|
||||||
|
|
||||||
|
logger = get_logger("dbn")
|
||||||
|
|
||||||
|
|
||||||
|
class RainfallDBN:
|
||||||
|
"""暴雨灾害链DBN模型"""
|
||||||
|
|
||||||
|
# 灾害概率→离散等级的阈值映射
|
||||||
|
HAZARD_LEVEL_THRESHOLDS = [
|
||||||
|
(0.6, 'very_high'),
|
||||||
|
(0.4, 'high'),
|
||||||
|
(0.2, 'medium'),
|
||||||
|
(0.05, 'low'),
|
||||||
|
(0.0, 'none'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def _probability_to_level(self, prob: float) -> str:
|
||||||
|
"""将连续概率映射到离散等级"""
|
||||||
|
for threshold, level in self.HAZARD_LEVEL_THRESHOLDS:
|
||||||
|
if prob >= threshold:
|
||||||
|
return level
|
||||||
|
return 'none'
|
||||||
|
|
||||||
|
def __init__(self, config_dir: Optional[str] = None):
|
||||||
|
"""
|
||||||
|
初始化DBN模型
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_dir: 配置文件目录
|
||||||
|
"""
|
||||||
|
if config_dir is None:
|
||||||
|
config_dir = str(DBN_CONFIG_DIR)
|
||||||
|
|
||||||
|
self.config_dir = config_dir
|
||||||
|
self.graph_config = self._load_graph_config()
|
||||||
|
self.cpt_config = self._load_cpt_config()
|
||||||
|
|
||||||
|
# 构建贝叶斯网络结构
|
||||||
|
self._build_network()
|
||||||
|
|
||||||
|
def _load_graph_config(self) -> Dict[str, Any]:
|
||||||
|
"""加载图结构配置"""
|
||||||
|
config_path = os.path.join(self.config_dir, 'rainfall_dbn_graph.yaml')
|
||||||
|
|
||||||
|
if not os.path.exists(config_path):
|
||||||
|
logger.error(f"图结构配置文件不存在: {config_path}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
def _load_cpt_config(self) -> Dict[str, Any]:
|
||||||
|
"""加载CPT配置"""
|
||||||
|
config_path = os.path.join(self.config_dir, 'rainfall_cpt_params.yaml')
|
||||||
|
|
||||||
|
if not os.path.exists(config_path):
|
||||||
|
logger.error(f"CPT配置文件不存在: {config_path}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
def _build_network(self):
|
||||||
|
"""构建贝叶斯网络结构"""
|
||||||
|
# 获取节点列表
|
||||||
|
self.trigger_nodes = self.graph_config.get('layers', {}).get('trigger', [])
|
||||||
|
self.environment_nodes = self.graph_config.get('layers', {}).get('environment', [])
|
||||||
|
self.hazard_nodes = self.graph_config.get('layers', {}).get('hazard', [])
|
||||||
|
|
||||||
|
# 获取所有节点
|
||||||
|
self.all_nodes = self.trigger_nodes + self.environment_nodes + self.hazard_nodes
|
||||||
|
|
||||||
|
# 获取边关系
|
||||||
|
self.edges = self.graph_config.get('edges', [])
|
||||||
|
|
||||||
|
# 获取节点状态
|
||||||
|
self.node_states = self.graph_config.get('node_states', {})
|
||||||
|
|
||||||
|
# 构建父子关系
|
||||||
|
self.children = {node: [] for node in self.all_nodes}
|
||||||
|
self.parents = {node: [] for node in self.all_nodes}
|
||||||
|
|
||||||
|
for parent, child in self.edges:
|
||||||
|
if parent in self.all_nodes and child in self.all_nodes:
|
||||||
|
self.children[parent].append(child)
|
||||||
|
self.parents[child].append(parent)
|
||||||
|
|
||||||
|
# 构建CPT表
|
||||||
|
self._build_cpt_tables()
|
||||||
|
|
||||||
|
def _build_cpt_tables(self):
|
||||||
|
"""构建条件概率表"""
|
||||||
|
self.cpt_tables = {}
|
||||||
|
|
||||||
|
for node in self.all_nodes:
|
||||||
|
if node in self.cpt_config:
|
||||||
|
self.cpt_tables[node] = self.cpt_config[node]
|
||||||
|
else:
|
||||||
|
# 如果没有配置,使用均匀分布
|
||||||
|
states = self.node_states.get(node, ['no', 'yes'])
|
||||||
|
if len(states) == 2:
|
||||||
|
# 二值节点
|
||||||
|
self.cpt_tables[node] = {
|
||||||
|
'type': 'prior',
|
||||||
|
'probabilities': [0.5, 0.5]
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
# 多值节点
|
||||||
|
prob = 1.0 / len(states)
|
||||||
|
self.cpt_tables[node] = {
|
||||||
|
'type': 'prior',
|
||||||
|
'probabilities': [prob] * len(states)
|
||||||
|
}
|
||||||
|
|
||||||
|
def _get_node_probability(self, node: str, evidence: Dict[str, str]) -> List[float]:
|
||||||
|
"""
|
||||||
|
获取节点的概率分布
|
||||||
|
|
||||||
|
Args:
|
||||||
|
node: 节点名称
|
||||||
|
evidence: 证据字典
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
概率分布列表
|
||||||
|
"""
|
||||||
|
cpt = self.cpt_tables.get(node)
|
||||||
|
if not cpt:
|
||||||
|
states = self.node_states.get(node, ['no', 'yes'])
|
||||||
|
return [1.0 / len(states)] * len(states)
|
||||||
|
|
||||||
|
# 如果是先验概率
|
||||||
|
if cpt.get('type') == 'prior':
|
||||||
|
return cpt.get('probabilities', [0.5, 0.5])
|
||||||
|
|
||||||
|
# 如果是条件概率
|
||||||
|
if cpt.get('type') == 'conditional':
|
||||||
|
return self._evaluate_conditional_probability(node, cpt, evidence)
|
||||||
|
|
||||||
|
return [0.5, 0.5]
|
||||||
|
|
||||||
|
def _evaluate_conditional_probability(self, node: str, cpt: Dict[str, Any],
|
||||||
|
evidence: Dict[str, str]) -> List[float]:
|
||||||
|
"""
|
||||||
|
评估条件概率
|
||||||
|
|
||||||
|
Args:
|
||||||
|
node: 节点名称
|
||||||
|
cpt: CPT配置
|
||||||
|
evidence: 证据字典
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
概率分布列表
|
||||||
|
"""
|
||||||
|
states = self.node_states.get(node, ['no', 'yes'])
|
||||||
|
default_prob = cpt.get('default_probability', 0.05)
|
||||||
|
|
||||||
|
# 检查规则
|
||||||
|
rules = cpt.get('rules', [])
|
||||||
|
for rule in rules:
|
||||||
|
condition = rule.get('condition', {})
|
||||||
|
probability = rule.get('probability', default_prob)
|
||||||
|
|
||||||
|
# 检查是否满足条件
|
||||||
|
if self._check_condition(condition, evidence):
|
||||||
|
# 返回 [P(no), P(yes)]
|
||||||
|
return [1.0 - probability, probability]
|
||||||
|
|
||||||
|
# 如果没有匹配的规则,返回默认概率
|
||||||
|
return [1.0 - default_prob, default_prob]
|
||||||
|
|
||||||
|
def _check_condition(self, condition: Dict[str, Any], evidence: Dict[str, str]) -> bool:
|
||||||
|
"""
|
||||||
|
检查条件是否满足
|
||||||
|
|
||||||
|
Args:
|
||||||
|
condition: 条件字典
|
||||||
|
evidence: 证据字典
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
是否满足
|
||||||
|
"""
|
||||||
|
for node, required_states in condition.items():
|
||||||
|
if node not in evidence:
|
||||||
|
return False
|
||||||
|
|
||||||
|
evidence_state = evidence[node]
|
||||||
|
|
||||||
|
# 如果required_states是列表,检查是否在列表中
|
||||||
|
if isinstance(required_states, list):
|
||||||
|
if evidence_state not in required_states:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
# 如果是单个值,检查是否相等
|
||||||
|
if evidence_state != required_states:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def predict_single_point(self, point: Dict[str, Any],
|
||||||
|
rainfall: Optional[float] = None,
|
||||||
|
duration: Optional[float] = None,
|
||||||
|
query_time: Optional[datetime] = None) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
对单个点进行预测
|
||||||
|
|
||||||
|
Args:
|
||||||
|
point: 点信息(包含 static_factors 字段)
|
||||||
|
rainfall: 累计降雨量(可选)
|
||||||
|
duration: 持续时间(可选)
|
||||||
|
query_time: 查询时间(可选)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
预测结果
|
||||||
|
"""
|
||||||
|
point_id = point.get('id')
|
||||||
|
lon = point.get('lon')
|
||||||
|
lat = point.get('lat')
|
||||||
|
source_type = point.get('source_type')
|
||||||
|
|
||||||
|
logger.info(f"预测点 ID={point_id}, source_type={source_type}")
|
||||||
|
|
||||||
|
# 获取降雨数据
|
||||||
|
if rainfall is not None and duration is not None:
|
||||||
|
rain_intensity = rainfall / duration if duration > 0 else 0.0
|
||||||
|
rainfall_data = {
|
||||||
|
'accum_rain': rainfall,
|
||||||
|
'duration_hours': duration,
|
||||||
|
'rain_intensity': rain_intensity
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
rainfall_data = DbnRepository.get_rainfall_data_with_duration(lon, lat, query_time)
|
||||||
|
|
||||||
|
# 获取静态因子数据(从 point 的 static_factors 字段)
|
||||||
|
raw_factors = point.get('static_factors', {})
|
||||||
|
static_factors = {
|
||||||
|
'elevation': raw_factors.get('dem_value'),
|
||||||
|
'slope': raw_factors.get('slope_value'),
|
||||||
|
'aspect': raw_factors.get('aspect_value'),
|
||||||
|
'soil_type': raw_factors.get('soil_type'),
|
||||||
|
'lithology': raw_factors.get('lithology'),
|
||||||
|
'landuse': raw_factors.get('landuse'),
|
||||||
|
'terrain': raw_factors.get('landform'),
|
||||||
|
'impervious': raw_factors.get('impervious_surface'),
|
||||||
|
'ndvi': raw_factors.get('vegetation_index'),
|
||||||
|
'sand_content': raw_factors.get('soil_sand'),
|
||||||
|
'ph': raw_factors.get('soil_ph'),
|
||||||
|
'soil_moisture': raw_factors.get('soil_moisture'),
|
||||||
|
'organic_carbon': raw_factors.get('organic_carbon'),
|
||||||
|
'dist_to_river': raw_factors.get('river_distance'),
|
||||||
|
'dist_to_fault': raw_factors.get('fault_distance'),
|
||||||
|
'pipe_density': raw_factors.get('pipe_density')
|
||||||
|
}
|
||||||
|
|
||||||
|
# 合并所有因子
|
||||||
|
all_factors = {
|
||||||
|
'rain_intensity': rainfall_data.get('rain_intensity', 0.0),
|
||||||
|
'duration': rainfall_data.get('duration_hours', 0),
|
||||||
|
'accum_rain': rainfall_data.get('accum_rain', 0.0),
|
||||||
|
**static_factors
|
||||||
|
}
|
||||||
|
|
||||||
|
# 离散化
|
||||||
|
evidence = discretizer.discretize_all_factors(all_factors)
|
||||||
|
|
||||||
|
# 运行推理
|
||||||
|
hazard_results = self._run_inference(evidence)
|
||||||
|
|
||||||
|
# 构造输出
|
||||||
|
result = {
|
||||||
|
'point_id': point_id,
|
||||||
|
'source_type': source_type,
|
||||||
|
'lon': lon,
|
||||||
|
'lat': lat,
|
||||||
|
'disaster_probabilities': {
|
||||||
|
h: r['probability'] for h, r in hazard_results.items()
|
||||||
|
},
|
||||||
|
'disaster_levels': {
|
||||||
|
h: r['level'] for h, r in hazard_results.items()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _run_inference(self, evidence: Dict[str, str]) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
运行贝叶斯推理
|
||||||
|
|
||||||
|
Args:
|
||||||
|
evidence: 证据字典
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
灾害概率字典,每个值包含 probability 和 level
|
||||||
|
"""
|
||||||
|
hazard_probabilities = {}
|
||||||
|
|
||||||
|
for hazard_node in self.hazard_nodes:
|
||||||
|
# 获取灾害节点的概率
|
||||||
|
prob_dist = self._get_node_probability(hazard_node, evidence)
|
||||||
|
|
||||||
|
# 取发生概率(第二个状态)
|
||||||
|
if len(prob_dist) >= 2:
|
||||||
|
prob = prob_dist[1]
|
||||||
|
else:
|
||||||
|
prob = 0.0
|
||||||
|
|
||||||
|
hazard_probabilities[hazard_node] = {
|
||||||
|
'probability': round(prob, 4),
|
||||||
|
'level': self._probability_to_level(prob)
|
||||||
|
}
|
||||||
|
|
||||||
|
return hazard_probabilities
|
||||||
|
|
||||||
|
def predict(self, region_code: Optional[str] = None,
|
||||||
|
rainfall: Optional[float] = None,
|
||||||
|
duration: Optional[float] = None,
|
||||||
|
timestamp: Optional[datetime] = None) -> List[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
预测灾害概率
|
||||||
|
|
||||||
|
Args:
|
||||||
|
region_code: 行政区划代码(可选)
|
||||||
|
rainfall: 累计降雨量(可选,全局值)
|
||||||
|
duration: 持续时间(可选,全局值)
|
||||||
|
timestamp: 时间(可选)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
预测结果列表
|
||||||
|
"""
|
||||||
|
# 1. 获取点列表
|
||||||
|
points = DbnRepository.get_all_points(region_code)
|
||||||
|
|
||||||
|
if not points:
|
||||||
|
logger.warning(f"没有找到点数据,region_code={region_code}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
logger.info(f"共找到 {len(points)} 个点")
|
||||||
|
|
||||||
|
# 2. 对每个点进行预测
|
||||||
|
results = []
|
||||||
|
for point in points:
|
||||||
|
try:
|
||||||
|
result = self.predict_single_point(
|
||||||
|
point,
|
||||||
|
rainfall=rainfall,
|
||||||
|
duration=duration,
|
||||||
|
query_time=timestamp
|
||||||
|
)
|
||||||
|
results.append(result)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"预测点 {point.get('id')} 失败: {e}")
|
||||||
|
results.append({
|
||||||
|
'point_id': point.get('id'),
|
||||||
|
'source_type': point.get('source_type'),
|
||||||
|
'lon': point.get('lon'),
|
||||||
|
'lat': point.get('lat'),
|
||||||
|
'error': str(e)
|
||||||
|
})
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def get_model_info(self) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
获取模型信息
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
模型信息字典
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
'trigger_nodes': self.trigger_nodes,
|
||||||
|
'environment_nodes': self.environment_nodes,
|
||||||
|
'hazard_nodes': self.hazard_nodes,
|
||||||
|
'edges': self.edges,
|
||||||
|
'node_states': self.node_states
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# 创建全局实例
|
||||||
|
rainfall_dbn = RainfallDBN()
|
||||||
@@ -0,0 +1,515 @@
|
|||||||
|
"""
|
||||||
|
数据库查询模块
|
||||||
|
负责从 xian_risk_factors、xian_meteorology 等表获取数据
|
||||||
|
"""
|
||||||
|
import math
|
||||||
|
from typing import Optional, List, Dict, Any
|
||||||
|
from datetime import datetime
|
||||||
|
from app.utils.db_helper import db_helper
|
||||||
|
from app.config.paths import get_logger
|
||||||
|
|
||||||
|
logger = get_logger("dbn")
|
||||||
|
|
||||||
|
|
||||||
|
class DbnRepository:
|
||||||
|
"""数据库查询类 - 所有DBN相关查询统一管理"""
|
||||||
|
|
||||||
|
# ==================== 风险因子查询 ====================
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_all_points(region_code: Optional[str] = None) -> List[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取所有隐患点和风险点(从 xian_risk_factors 表)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
region_code: 行政区划代码(区县名称),可选
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
点列表,每个元素包含:id, source_id, source_type, lon, lat, static_factors
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
source_id,
|
||||||
|
source_type,
|
||||||
|
lon,
|
||||||
|
lat,
|
||||||
|
static_factors
|
||||||
|
FROM xian_risk_factors
|
||||||
|
WHERE is_delete = 0
|
||||||
|
"""
|
||||||
|
params = (region_code,) if region_code else None
|
||||||
|
|
||||||
|
if region_code:
|
||||||
|
sql += " AND county = %s"
|
||||||
|
|
||||||
|
results = db_helper.execute_query(sql, params)
|
||||||
|
|
||||||
|
points = []
|
||||||
|
for row in results:
|
||||||
|
points.append({
|
||||||
|
'id': row['id'],
|
||||||
|
'source_id': row['source_id'],
|
||||||
|
'source_type': row['source_type'],
|
||||||
|
'lon': float(row['lon']) if row['lon'] else None,
|
||||||
|
'lat': float(row['lat']) if row['lat'] else None,
|
||||||
|
'static_factors': row.get('static_factors') or {}
|
||||||
|
})
|
||||||
|
|
||||||
|
return points
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_point_by_id(point_id: int) -> Optional[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
根据ID获取单个点信息
|
||||||
|
|
||||||
|
Args:
|
||||||
|
point_id: xian_risk_factors 表的 ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
点信息
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
rf.id,
|
||||||
|
rf.source_id,
|
||||||
|
rf.source_type,
|
||||||
|
rf.lon,
|
||||||
|
rf.lat,
|
||||||
|
rf.static_factors
|
||||||
|
FROM xian_risk_factors rf
|
||||||
|
WHERE rf.id = %s AND rf.is_delete = 0
|
||||||
|
"""
|
||||||
|
result = db_helper.execute_query_one(sql, (point_id,))
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return {
|
||||||
|
'id': result['id'],
|
||||||
|
'source_id': result['source_id'],
|
||||||
|
'source_type': result['source_type'],
|
||||||
|
'lon': float(result['lon']) if result['lon'] else None,
|
||||||
|
'lat': float(result['lat']) if result['lat'] else None,
|
||||||
|
'static_factors': result.get('static_factors') or {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_static_factors(point_id: int) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
获取点的静态因子数据
|
||||||
|
|
||||||
|
Args:
|
||||||
|
point_id: xian_risk_factors 表的 ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
静态因子数据
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT static_factors
|
||||||
|
FROM xian_risk_factors
|
||||||
|
WHERE id = %s AND is_delete = 0
|
||||||
|
"""
|
||||||
|
result = db_helper.execute_query_one(sql, (point_id,))
|
||||||
|
|
||||||
|
if result and result.get('static_factors'):
|
||||||
|
return result['static_factors']
|
||||||
|
return {}
|
||||||
|
|
||||||
|
# ==================== 降雨数据查询 ====================
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_nearest_station_rainfall(lon: float, lat: float,
|
||||||
|
query_time: Optional[datetime] = None) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
获取最近雨量站的降雨数据
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lon: 经度
|
||||||
|
lat: 纬度
|
||||||
|
query_time: 查询时间,若未提供则取当前时间
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
降雨数据
|
||||||
|
"""
|
||||||
|
if query_time is None:
|
||||||
|
query_time = datetime.now()
|
||||||
|
|
||||||
|
# noinspection SqlNoDataSourceInspection
|
||||||
|
sql = """
|
||||||
|
WITH station_data AS (
|
||||||
|
SELECT
|
||||||
|
lon,
|
||||||
|
lat,
|
||||||
|
SUM(CAST(rainfall_1h AS DOUBLE PRECISION)) as total_rainfall,
|
||||||
|
COUNT(*) as record_count
|
||||||
|
FROM xian_meteorology
|
||||||
|
WHERE datetime BETWEEN
|
||||||
|
CAST(EXTRACT(EPOCH FROM (%s::timestamp - INTERVAL '24 hours')) AS BIGINT)
|
||||||
|
AND CAST(EXTRACT(EPOCH FROM %s::timestamp) AS BIGINT)
|
||||||
|
AND rainfall_1h IS NOT NULL
|
||||||
|
AND CAST(rainfall_1h AS DOUBLE PRECISION) > 0
|
||||||
|
GROUP BY lon, lat
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
lon,
|
||||||
|
lat,
|
||||||
|
total_rainfall,
|
||||||
|
record_count,
|
||||||
|
ST_DistanceSphere(
|
||||||
|
ST_SetSRID(ST_MakePoint(lon, lat), 4326),
|
||||||
|
ST_SetSRID(ST_MakePoint(%s, %s), 4326)
|
||||||
|
) as distance
|
||||||
|
FROM station_data
|
||||||
|
ORDER BY distance
|
||||||
|
LIMIT 1
|
||||||
|
"""
|
||||||
|
result = db_helper.execute_query_one(sql, (query_time, query_time, lon, lat))
|
||||||
|
|
||||||
|
if result:
|
||||||
|
return {
|
||||||
|
'rainfall': float(result['total_rainfall']) if result['total_rainfall'] else 0.0,
|
||||||
|
'record_count': int(result['record_count']) if result['record_count'] else 0,
|
||||||
|
'distance': float(result['distance']) if result['distance'] else 0.0,
|
||||||
|
'station_lon': float(result['lon']) if result['lon'] else None,
|
||||||
|
'station_lat': float(result['lat']) if result['lat'] else None
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return {
|
||||||
|
'rainfall': 0.0,
|
||||||
|
'record_count': 0,
|
||||||
|
'distance': 0.0,
|
||||||
|
'station_lon': None,
|
||||||
|
'station_lat': None
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_rainfall_data_with_duration(lon: float, lat: float,
|
||||||
|
query_time: Optional[datetime] = None) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
获取降雨数据,包括累计降雨量和持续时间
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lon: 经度
|
||||||
|
lat: 纬度
|
||||||
|
query_time: 查询时间,若未提供则取当前时间
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
降雨数据:{accum_rain, duration_hours, rain_intensity}
|
||||||
|
"""
|
||||||
|
if query_time is None:
|
||||||
|
query_time = datetime.now()
|
||||||
|
|
||||||
|
# 查找最近的雨量站
|
||||||
|
# noinspection SqlNoDataSourceInspection
|
||||||
|
sql = """
|
||||||
|
SELECT lon, lat, dist
|
||||||
|
FROM (
|
||||||
|
SELECT DISTINCT lon, lat,
|
||||||
|
ST_DistanceSphere(
|
||||||
|
ST_SetSRID(ST_MakePoint(lon, lat), 4326),
|
||||||
|
ST_SetSRID(ST_MakePoint(%s, %s), 4326)
|
||||||
|
) as dist
|
||||||
|
FROM xian_meteorology
|
||||||
|
) t
|
||||||
|
WHERE dist < 50000
|
||||||
|
ORDER BY dist
|
||||||
|
LIMIT 1
|
||||||
|
"""
|
||||||
|
station = db_helper.execute_query_one(sql, (lon, lat))
|
||||||
|
|
||||||
|
if not station:
|
||||||
|
return {'accum_rain': 0.0, 'duration_hours': 0, 'rain_intensity': 0.0}
|
||||||
|
|
||||||
|
station_lon = station['lon']
|
||||||
|
station_lat = station['lat']
|
||||||
|
|
||||||
|
# 查询该站点的降雨时序数据
|
||||||
|
# noinspection SqlNoDataSourceInspection
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
datetime,
|
||||||
|
CAST(rainfall_1h AS DOUBLE PRECISION) as rainfall
|
||||||
|
FROM xian_meteorology
|
||||||
|
WHERE lon = %s AND lat = %s
|
||||||
|
AND datetime BETWEEN
|
||||||
|
CAST(EXTRACT(EPOCH FROM (%s::timestamp - INTERVAL '72 hours')) AS BIGINT)
|
||||||
|
AND CAST(EXTRACT(EPOCH FROM %s::timestamp) AS BIGINT)
|
||||||
|
ORDER BY datetime DESC
|
||||||
|
"""
|
||||||
|
results = db_helper.execute_query(sql, (station_lon, station_lat, query_time, query_time))
|
||||||
|
|
||||||
|
if not results:
|
||||||
|
return {'accum_rain': 0.0, 'duration_hours': 0, 'rain_intensity': 0.0}
|
||||||
|
|
||||||
|
# 计算累计降雨量和持续时间
|
||||||
|
accum_rain = 0.0
|
||||||
|
duration_hours = 0
|
||||||
|
consecutive_no_rain = 0
|
||||||
|
|
||||||
|
for row in results:
|
||||||
|
rainfall = float(row['rainfall']) if row['rainfall'] else 0.0
|
||||||
|
if rainfall > 0:
|
||||||
|
accum_rain += rainfall
|
||||||
|
duration_hours += 1
|
||||||
|
consecutive_no_rain = 0
|
||||||
|
else:
|
||||||
|
consecutive_no_rain += 1
|
||||||
|
if consecutive_no_rain >= 3:
|
||||||
|
break
|
||||||
|
if accum_rain > 0:
|
||||||
|
duration_hours += 1
|
||||||
|
|
||||||
|
rain_intensity = accum_rain / duration_hours if duration_hours > 0 else 0.0
|
||||||
|
|
||||||
|
return {
|
||||||
|
'accum_rain': accum_rain,
|
||||||
|
'duration_hours': duration_hours,
|
||||||
|
'rain_intensity': rain_intensity
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==================== 空间查询 ====================
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_nearest_station(lon: float, lat: float,
|
||||||
|
station_type: str = 'meteorology') -> Optional[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
获取最近的气象站点
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lon: 经度
|
||||||
|
lat: 纬度
|
||||||
|
station_type: 站点类型
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
最近站点信息
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT DISTINCT ON (lon, lat)
|
||||||
|
lon,
|
||||||
|
lat,
|
||||||
|
ST_DistanceSphere(
|
||||||
|
ST_SetSRID(ST_MakePoint(lon, lat), 4326),
|
||||||
|
ST_SetSRID(ST_MakePoint(%s, %s), 4326)
|
||||||
|
) as distance
|
||||||
|
FROM xian_meteorology
|
||||||
|
WHERE is_delete = 0
|
||||||
|
ORDER BY lon, lat, distance
|
||||||
|
LIMIT 1
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = db_helper.execute_query_one(sql, (lon, lat))
|
||||||
|
|
||||||
|
if result:
|
||||||
|
return {
|
||||||
|
'lon': float(result['lon']),
|
||||||
|
'lat': float(result['lat']),
|
||||||
|
'distance': float(result['distance'])
|
||||||
|
}
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_distance_to_river(lon: float, lat: float) -> float:
|
||||||
|
"""
|
||||||
|
计算点到最近河流的距离
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lon: 经度
|
||||||
|
lat: 纬度
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
距离(米)
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
MIN(ST_DistanceSphere(
|
||||||
|
ST_SetSRID(ST_MakePoint(%s, %s), 4326),
|
||||||
|
geom
|
||||||
|
)) as min_distance
|
||||||
|
FROM xian_rivers
|
||||||
|
WHERE is_delete = 0
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = db_helper.execute_query_one(sql, (lon, lat))
|
||||||
|
|
||||||
|
if result and result['min_distance']:
|
||||||
|
return float(result['min_distance'])
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_distance_to_fault(lon: float, lat: float) -> float:
|
||||||
|
"""
|
||||||
|
计算点到最近断裂带的距离
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lon: 经度
|
||||||
|
lat: 纬度
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
距离(米)
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
MIN(ST_DistanceSphere(
|
||||||
|
ST_SetSRID(ST_MakePoint(%s, %s), 4326),
|
||||||
|
geom
|
||||||
|
)) as min_distance
|
||||||
|
FROM xian_fault_lines
|
||||||
|
WHERE is_delete = 0
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = db_helper.execute_query_one(sql, (lon, lat))
|
||||||
|
|
||||||
|
if result and result['min_distance']:
|
||||||
|
return float(result['min_distance'])
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_pipe_density(lon: float, lat: float, buffer_radius: float = 500.0) -> float:
|
||||||
|
"""
|
||||||
|
计算点周围缓冲区内的管网密度
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lon: 经度
|
||||||
|
lat: 纬度
|
||||||
|
buffer_radius: 缓冲区半径(米)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
管网密度(m/m²)
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
COALESCE(SUM(ST_Length(wp.geom::geography)), 0) as total_length
|
||||||
|
FROM xian_water_pipe wp
|
||||||
|
WHERE wp.is_delete = 0
|
||||||
|
AND ST_DWithin(
|
||||||
|
ST_SetSRID(ST_MakePoint(%s, %s), 4326)::geography,
|
||||||
|
wp.geom::geography,
|
||||||
|
%s
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = db_helper.execute_query_one(sql, (lon, lat, buffer_radius))
|
||||||
|
|
||||||
|
if result and result['total_length']:
|
||||||
|
total_length = float(result['total_length'])
|
||||||
|
buffer_area = math.pi * buffer_radius ** 2
|
||||||
|
density = total_length / buffer_area
|
||||||
|
return density
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_river_density(lon: float, lat: float, buffer_radius: float = 1000.0) -> float:
|
||||||
|
"""
|
||||||
|
计算点周围缓冲区内的河流密度
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lon: 经度
|
||||||
|
lat: 纬度
|
||||||
|
buffer_radius: 缓冲区半径(米)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
河流密度(m/m²)
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
COALESCE(SUM(ST_Length(r.geom::geography)), 0) as total_length
|
||||||
|
FROM xian_rivers r
|
||||||
|
WHERE r.is_delete = 0
|
||||||
|
AND ST_DWithin(
|
||||||
|
ST_SetSRID(ST_MakePoint(%s, %s), 4326)::geography,
|
||||||
|
r.geom::geography,
|
||||||
|
%s
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = db_helper.execute_query_one(sql, (lon, lat, buffer_radius))
|
||||||
|
|
||||||
|
if result and result['total_length']:
|
||||||
|
total_length = float(result['total_length'])
|
||||||
|
buffer_area = math.pi * buffer_radius ** 2
|
||||||
|
density = total_length / buffer_area
|
||||||
|
return density
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_point_elevation(lon: float, lat: float) -> Optional[float]:
|
||||||
|
"""
|
||||||
|
获取点的高程值
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lon: 经度
|
||||||
|
lat: 纬度
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
高程值(米)
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
ST_Value(rast, ST_SetSRID(ST_MakePoint(%s, %s), 4326)) as elevation
|
||||||
|
FROM xian_dem
|
||||||
|
WHERE ST_Intersects(rast, ST_SetSRID(ST_MakePoint(%s, %s), 4326))
|
||||||
|
LIMIT 1
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = db_helper.execute_query_one(sql, (lon, lat, lon, lat))
|
||||||
|
|
||||||
|
if result and result['elevation']:
|
||||||
|
return float(result['elevation'])
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_point_slope(lon: float, lat: float) -> Optional[float]:
|
||||||
|
"""
|
||||||
|
获取点的坡度值
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lon: 经度
|
||||||
|
lat: 纬度
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
坡度值(度)
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
ST_Value(rast, ST_SetSRID(ST_MakePoint(%s, %s), 4326)) as slope
|
||||||
|
FROM xian_slope
|
||||||
|
WHERE ST_Intersects(rast, ST_SetSRID(ST_MakePoint(%s, %s), 4326))
|
||||||
|
LIMIT 1
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = db_helper.execute_query_one(sql, (lon, lat, lon, lat))
|
||||||
|
|
||||||
|
if result and result['slope']:
|
||||||
|
return float(result['slope'])
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_point_aspect(lon: float, lat: float) -> Optional[float]:
|
||||||
|
"""
|
||||||
|
获取点的坡向值
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lon: 经度
|
||||||
|
lat: 纬度
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
坡向值(度)
|
||||||
|
"""
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
ST_Value(rast, ST_SetSRID(ST_MakePoint(%s, %s), 4326)) as aspect
|
||||||
|
FROM xian_aspect
|
||||||
|
WHERE ST_Intersects(rast, ST_SetSRID(ST_MakePoint(%s, %s), 4326))
|
||||||
|
LIMIT 1
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = db_helper.execute_query_one(sql, (lon, lat, lon, lat))
|
||||||
|
|
||||||
|
if result and result['aspect']:
|
||||||
|
return float(result['aspect'])
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# 创建全局实例
|
||||||
|
dbn_repository = DbnRepository()
|
||||||
@@ -0,0 +1,471 @@
|
|||||||
|
"""
|
||||||
|
离散化模块
|
||||||
|
负责将连续值转换为离散状态
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
from typing import Optional, List, Dict, Any, Tuple
|
||||||
|
from app.config.paths import DBN_CONFIG_DIR, get_logger
|
||||||
|
|
||||||
|
logger = get_logger("dbn")
|
||||||
|
|
||||||
|
|
||||||
|
class Discretizer:
|
||||||
|
"""离散化工具类"""
|
||||||
|
|
||||||
|
def __init__(self, config_dir: Optional[str] = None):
|
||||||
|
"""
|
||||||
|
初始化离散化器
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_dir: 配置文件目录,默认为 app/config/dbn
|
||||||
|
"""
|
||||||
|
if config_dir is None:
|
||||||
|
config_dir = str(DBN_CONFIG_DIR)
|
||||||
|
|
||||||
|
self.config_dir = config_dir
|
||||||
|
self.config = self._load_config()
|
||||||
|
|
||||||
|
def _load_config(self) -> Dict[str, Any]:
|
||||||
|
"""加载离散化配置"""
|
||||||
|
config_path = os.path.join(self.config_dir, 'discretization.yaml')
|
||||||
|
|
||||||
|
if not os.path.exists(config_path):
|
||||||
|
logger.warning(f"离散化配置文件不存在: {config_path}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
def discretize(self, factor_name: str, value: float,
|
||||||
|
region_code: Optional[str] = None) -> str:
|
||||||
|
"""
|
||||||
|
将连续值离散化
|
||||||
|
|
||||||
|
Args:
|
||||||
|
factor_name: 因子名称
|
||||||
|
value: 连续值
|
||||||
|
region_code: 行政区划代码,用于区域覆盖
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
if factor_name not in self.config:
|
||||||
|
logger.warning(f"因子 {factor_name} 没有离散化配置")
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
factor_config = self.config[factor_name]
|
||||||
|
|
||||||
|
# 检查是否是分类变量(有mapping字段)
|
||||||
|
if 'mapping' in factor_config:
|
||||||
|
return self._discretize_categorical(factor_config, value)
|
||||||
|
|
||||||
|
# 检查是否有区域覆盖
|
||||||
|
if region_code and 'region_overrides' in factor_config:
|
||||||
|
if region_code in factor_config['region_overrides']:
|
||||||
|
override_config = factor_config['region_overrides'][region_code]
|
||||||
|
return self._discretize_continuous(override_config, value)
|
||||||
|
|
||||||
|
# 使用默认配置
|
||||||
|
if 'default' in factor_config:
|
||||||
|
return self._discretize_continuous(factor_config['default'], value)
|
||||||
|
elif 'bins' in factor_config:
|
||||||
|
return self._discretize_continuous(factor_config, value)
|
||||||
|
|
||||||
|
logger.warning(f"因子 {factor_name} 的配置格式不正确")
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
def _discretize_categorical(self, config: Dict[str, Any], value: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化分类变量
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config: 配置
|
||||||
|
value: 值
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
mapping = config.get('mapping', {})
|
||||||
|
default = config.get('default', 'unknown')
|
||||||
|
|
||||||
|
# 将值转换为整数
|
||||||
|
int_value = int(value)
|
||||||
|
|
||||||
|
return mapping.get(int_value, default)
|
||||||
|
|
||||||
|
def _discretize_continuous(self, config: Dict[str, Any], value: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化连续变量
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config: 配置
|
||||||
|
value: 值
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
bins = config.get('bins', [])
|
||||||
|
labels = config.get('labels', [])
|
||||||
|
|
||||||
|
if not bins or not labels:
|
||||||
|
logger.warning("离散化配置缺少bins或labels")
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
# 确保bins和labels长度匹配
|
||||||
|
if len(bins) != len(labels) + 1:
|
||||||
|
logger.warning(f"bins长度({len(bins)})应该比labels长度({len(labels)})多1")
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
# 进行分箱
|
||||||
|
for i in range(len(bins) - 1):
|
||||||
|
if bins[i] <= value < bins[i + 1]:
|
||||||
|
return labels[i]
|
||||||
|
|
||||||
|
# 如果值超出范围,返回最后一个标签
|
||||||
|
if value >= bins[-1]:
|
||||||
|
return labels[-1]
|
||||||
|
|
||||||
|
return labels[0]
|
||||||
|
|
||||||
|
def discretize_rain_intensity(self, rainfall_mm_h: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化降雨强度
|
||||||
|
|
||||||
|
Args:
|
||||||
|
rainfall_mm_h: 降雨强度(mm/h)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('rain_intensity', rainfall_mm_h)
|
||||||
|
|
||||||
|
def discretize_duration(self, duration_hours: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化持续时间
|
||||||
|
|
||||||
|
Args:
|
||||||
|
duration_hours: 持续时间(小时)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('duration', duration_hours)
|
||||||
|
|
||||||
|
def discretize_accum_rain(self, accum_rain_mm: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化累计降雨量
|
||||||
|
|
||||||
|
Args:
|
||||||
|
accum_rain_mm: 累计降雨量(mm)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('accum_rain', accum_rain_mm)
|
||||||
|
|
||||||
|
# ---- 地震触发层离散化 ----
|
||||||
|
|
||||||
|
def discretize_magnitude(self, magnitude: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化地震震级
|
||||||
|
|
||||||
|
Args:
|
||||||
|
magnitude: 震级(Richter)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('magnitude', magnitude)
|
||||||
|
|
||||||
|
def discretize_epicenter_distance(self, distance_km: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化震中距
|
||||||
|
|
||||||
|
Args:
|
||||||
|
distance_km: 震中距(km)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('epicenter_distance', distance_km)
|
||||||
|
|
||||||
|
def discretize_seismic_intensity(self, intensity: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化地震烈度
|
||||||
|
|
||||||
|
Args:
|
||||||
|
intensity: 地震烈度(中国烈度表数值)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('seismic_intensity', intensity)
|
||||||
|
|
||||||
|
def discretize_elevation(self, elevation_m: float,
|
||||||
|
region_code: Optional[str] = None) -> str:
|
||||||
|
"""
|
||||||
|
离散化高程
|
||||||
|
|
||||||
|
Args:
|
||||||
|
elevation_m: 高程(米)
|
||||||
|
region_code: 行政区划代码
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('elevation', elevation_m, region_code)
|
||||||
|
|
||||||
|
def discretize_slope(self, slope_deg: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化坡度
|
||||||
|
|
||||||
|
Args:
|
||||||
|
slope_deg: 坡度(度)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('slope', slope_deg)
|
||||||
|
|
||||||
|
def discretize_aspect(self, aspect_deg: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化坡向
|
||||||
|
|
||||||
|
Args:
|
||||||
|
aspect_deg: 坡向(度)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('aspect', aspect_deg)
|
||||||
|
|
||||||
|
def discretize_soil_type(self, soil_type_code: int) -> str:
|
||||||
|
"""
|
||||||
|
离散化土壤类型
|
||||||
|
|
||||||
|
Args:
|
||||||
|
soil_type_code: 土壤类型代码
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('soil_type', soil_type_code)
|
||||||
|
|
||||||
|
def discretize_lithology(self, lithology_code: int) -> str:
|
||||||
|
"""
|
||||||
|
离散化岩性
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lithology_code: 岩性代码
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('lithology', lithology_code)
|
||||||
|
|
||||||
|
def discretize_landuse(self, landuse_code: int) -> str:
|
||||||
|
"""
|
||||||
|
离散化土地利用类型
|
||||||
|
|
||||||
|
Args:
|
||||||
|
landuse_code: 土地利用类型代码
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('landuse', landuse_code)
|
||||||
|
|
||||||
|
def discretize_terrain(self, terrain_code: int) -> str:
|
||||||
|
"""
|
||||||
|
离散化地形分类
|
||||||
|
|
||||||
|
Args:
|
||||||
|
terrain_code: 地形分类代码
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('terrain', terrain_code)
|
||||||
|
|
||||||
|
def discretize_impervious(self, impervious_ratio: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化不透水面
|
||||||
|
|
||||||
|
Args:
|
||||||
|
impervious_ratio: 不透水面比例
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('impervious', impervious_ratio)
|
||||||
|
|
||||||
|
def discretize_ndvi(self, ndvi_value: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化植被指数
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ndvi_value: NDVI值
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('ndvi', ndvi_value)
|
||||||
|
|
||||||
|
def discretize_sand_content(self, sand_percent: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化土壤含沙量
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sand_percent: 含沙量百分比
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('sand_content', sand_percent)
|
||||||
|
|
||||||
|
def discretize_ph(self, ph_value: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化土壤PH值
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ph_value: PH值
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('ph', ph_value)
|
||||||
|
|
||||||
|
def discretize_soil_moisture(self, moisture_percent: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化土壤湿度
|
||||||
|
|
||||||
|
Args:
|
||||||
|
moisture_percent: 湿度百分比
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('soil_moisture', moisture_percent)
|
||||||
|
|
||||||
|
def discretize_organic_carbon(self, carbon_percent: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化有机碳
|
||||||
|
|
||||||
|
Args:
|
||||||
|
carbon_percent: 有机碳百分比
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('organic_carbon', carbon_percent)
|
||||||
|
|
||||||
|
def discretize_dist_to_river(self, distance_m: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化距离河道距离
|
||||||
|
|
||||||
|
Args:
|
||||||
|
distance_m: 距离(米)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('dist_to_river', distance_m)
|
||||||
|
|
||||||
|
def discretize_dist_to_fault(self, distance_m: float) -> str:
|
||||||
|
"""
|
||||||
|
离散化距离断裂带距离
|
||||||
|
|
||||||
|
Args:
|
||||||
|
distance_m: 距离(米)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('dist_to_fault', distance_m)
|
||||||
|
|
||||||
|
def discretize_pipe_density(self, density: float,
|
||||||
|
region_code: Optional[str] = None) -> str:
|
||||||
|
"""
|
||||||
|
离散化供水管网密度
|
||||||
|
|
||||||
|
Args:
|
||||||
|
density: 管网密度(m/m²)
|
||||||
|
region_code: 行政区划代码
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散状态标签
|
||||||
|
"""
|
||||||
|
return self.discretize('pipe_density', density, region_code)
|
||||||
|
|
||||||
|
def discretize_all_factors(self, factors: Dict[str, Any],
|
||||||
|
region_code: Optional[str] = None) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
离散化所有因子
|
||||||
|
|
||||||
|
Args:
|
||||||
|
factors: 因子字典,key为因子名称,value为连续值
|
||||||
|
region_code: 行政区划代码
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
离散化后的因子字典
|
||||||
|
"""
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
# 暴雨触发层
|
||||||
|
if 'rain_intensity' in factors:
|
||||||
|
result['rain_intensity'] = self.discretize_rain_intensity(factors['rain_intensity'])
|
||||||
|
if 'duration' in factors:
|
||||||
|
result['duration'] = self.discretize_duration(factors['duration'])
|
||||||
|
if 'accum_rain' in factors:
|
||||||
|
result['accum_rain'] = self.discretize_accum_rain(factors['accum_rain'])
|
||||||
|
|
||||||
|
# 地震触发层
|
||||||
|
if 'magnitude' in factors:
|
||||||
|
result['magnitude'] = self.discretize_magnitude(factors['magnitude'])
|
||||||
|
if 'epicenter_distance' in factors:
|
||||||
|
result['epicenter_distance'] = self.discretize_epicenter_distance(factors['epicenter_distance'])
|
||||||
|
if 'seismic_intensity' in factors:
|
||||||
|
result['seismic_intensity'] = self.discretize_seismic_intensity(factors['seismic_intensity'])
|
||||||
|
|
||||||
|
# 环境层
|
||||||
|
if 'elevation' in factors:
|
||||||
|
result['elevation'] = self.discretize_elevation(factors['elevation'], region_code)
|
||||||
|
if 'slope' in factors:
|
||||||
|
result['slope'] = self.discretize_slope(factors['slope'])
|
||||||
|
if 'aspect' in factors:
|
||||||
|
result['aspect'] = self.discretize_aspect(factors['aspect'])
|
||||||
|
if 'soil_type' in factors:
|
||||||
|
result['soil_type'] = self.discretize_soil_type(factors['soil_type'])
|
||||||
|
if 'lithology' in factors:
|
||||||
|
result['lithology'] = self.discretize_lithology(factors['lithology'])
|
||||||
|
if 'landuse' in factors:
|
||||||
|
result['landuse'] = self.discretize_landuse(factors['landuse'])
|
||||||
|
if 'terrain' in factors:
|
||||||
|
result['terrain'] = self.discretize_terrain(factors['terrain'])
|
||||||
|
if 'impervious' in factors:
|
||||||
|
result['impervious'] = self.discretize_impervious(factors['impervious'])
|
||||||
|
if 'ndvi' in factors:
|
||||||
|
result['ndvi'] = self.discretize_ndvi(factors['ndvi'])
|
||||||
|
if 'sand_content' in factors:
|
||||||
|
result['sand_content'] = self.discretize_sand_content(factors['sand_content'])
|
||||||
|
if 'ph' in factors:
|
||||||
|
result['ph'] = self.discretize_ph(factors['ph'])
|
||||||
|
if 'soil_moisture' in factors:
|
||||||
|
result['soil_moisture'] = self.discretize_soil_moisture(factors['soil_moisture'])
|
||||||
|
if 'organic_carbon' in factors:
|
||||||
|
result['organic_carbon'] = self.discretize_organic_carbon(factors['organic_carbon'])
|
||||||
|
if 'dist_to_river' in factors:
|
||||||
|
result['dist_to_river'] = self.discretize_dist_to_river(factors['dist_to_river'])
|
||||||
|
if 'dist_to_fault' in factors:
|
||||||
|
result['dist_to_fault'] = self.discretize_dist_to_fault(factors['dist_to_fault'])
|
||||||
|
if 'pipe_density' in factors:
|
||||||
|
result['pipe_density'] = self.discretize_pipe_density(factors['pipe_density'], region_code)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
# 创建全局实例
|
||||||
|
discretizer = Discretizer()
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
"""
|
||||||
|
空间计算工具模块
|
||||||
|
提供纯数学计算功能(不涉及数据库查询)
|
||||||
|
"""
|
||||||
|
import math
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
|
||||||
|
class SpatialUtils:
|
||||||
|
"""空间计算工具类 - 纯数学计算"""
|
||||||
|
|
||||||
|
EARTH_RADIUS = 6371000 # 地球半径(米)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def haversine_distance(lon1: float, lat1: float, lon2: float, lat2: float) -> float:
|
||||||
|
"""
|
||||||
|
使用Haversine公式计算两点间的球面距离
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lon1: 点1经度
|
||||||
|
lat1: 点1纬度
|
||||||
|
lon2: 点2经度
|
||||||
|
lat2: 点2纬度
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
距离(米)
|
||||||
|
"""
|
||||||
|
lon1, lat1, lon2, lat2 = map(math.radians, [lon1, lat1, lon2, lat2])
|
||||||
|
|
||||||
|
dlon = lon2 - lon1
|
||||||
|
dlat = lat2 - lat1
|
||||||
|
a = math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2
|
||||||
|
c = 2 * math.asin(math.sqrt(a))
|
||||||
|
distance = SpatialUtils.EARTH_RADIUS * c
|
||||||
|
|
||||||
|
return distance
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def calculate_buffer_area(radius: float) -> float:
|
||||||
|
"""
|
||||||
|
计算缓冲区面积
|
||||||
|
|
||||||
|
Args:
|
||||||
|
radius: 半径(米)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
面积(平方米)
|
||||||
|
"""
|
||||||
|
return math.pi * radius ** 2
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def calculate_density(total_length: float, area: float) -> float:
|
||||||
|
"""
|
||||||
|
计算密度(长度/面积)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
total_length: 总长度(米)
|
||||||
|
area: 面积(平方米)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
密度(m/m²)
|
||||||
|
"""
|
||||||
|
if area <= 0:
|
||||||
|
return 0.0
|
||||||
|
return total_length / area
|
||||||
|
|
||||||
|
|
||||||
|
# 创建全局实例
|
||||||
|
spatial_utils = SpatialUtils()
|
||||||
Reference in New Issue
Block a user