构建暴雨灾害链和地震灾害链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