构建暴雨灾害链和地震灾害链DBN模型

This commit is contained in:
wzy-warehouse
2026-06-05 16:10:46 +08:00
parent c9cd96cca2
commit 844fa7d719
15 changed files with 3055 additions and 0 deletions
View File
+194
View File
@@ -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]
+266
View File
@@ -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.0minor):频繁但无显著地质灾害
# - M4.0-4.9light):偶发,轻微地质灾害
# - M5.0-5.9moderate):可能触发近场滑坡
# - M6.0-6.9strong):显著地质灾害
# - M7.0-7.9major):区域性地质灾害
# - M≥8.0great):灾难性(如1556年华县地震)
# [minor, light, moderate, strong, major, great]
probabilities: [0.40, 0.25, 0.18, 0.10, 0.05, 0.02]
epicenter_distance:
type: prior
# 西安地区可能的震中距分布:
# - <30kmvery_near):本地断裂发震
# - 30-100km(near):渭河断裂、秦岭北缘断裂
# - 100-300kmmoderate):汾渭地震带
# - >300kmfar):远场地震
# [very_near, near, moderate, far]
probabilities: [0.10, 0.25, 0.35, 0.30]
seismic_intensity:
type: prior
# 西安地区地震烈度分布:
# - I-V(minor):无显著地质灾害
# - VI-VIIlight):轻微地质灾害
# - VIII-IXmoderate):显著地质灾害
# - X-XIIsevere):严重地质灾害
# > XIIextreme):灾难性(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
+168
View File
@@ -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]
+362
View File
@@ -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
+168
View File
@@ -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]
+31
View File
@@ -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))
+3
View File
@@ -0,0 +1,3 @@
"""
DBN 模型模块
"""
+8
View File
@@ -0,0 +1,8 @@
"""
地震灾害链DBN模型模块
"""
from .earthquake_dbn import EarthquakeDBN, earthquake_dbn
__all__ = [
'EarthquakeDBN', 'earthquake_dbn',
]
+395
View File
@@ -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()
+11
View File
@@ -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',
]
+394
View File
@@ -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()
+515
View File
@@ -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()
+471
View File
@@ -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()
+69
View File
@@ -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()