用Python+GIS手把手实现高斯烟羽模型:从理论公式到污染扩散可视化
2026/5/15 11:39:28 网站建设 项目流程

用Python+GIS手把手实现高斯烟羽模型:从理论公式到污染扩散可视化

环境科学和应急管理领域经常需要快速评估污染事件的影响范围。想象这样一个场景:某化工厂发生气体泄漏,作为环境工程师的你需要在半小时内生成扩散预测图,为疏散决策提供依据。高斯烟羽模型正是解决这类问题的经典工具,但理论公式如何转化为可执行的代码?本文将用Python和GIS技术搭建完整解决方案,从数学公式到交互式地图可视化,一步步拆解实现过程。

1. 环境准备与工具链配置

实现污染扩散模拟需要整合数值计算、空间分析和可视化三个技术栈。我们选择以下工具链:

  • 核心计算库:NumPy处理矩阵运算,SciPy进行特殊函数计算
  • 地理处理:GeoPandas管理空间数据,Rasterio生成浓度栅格
  • 可视化:Folium创建交互地图,Matplotlib辅助调试绘图

安装依赖库的命令如下:

pip install numpy scipy geopandas rasterio folium matplotlib jupyterlab

配置开发环境时需要注意几个关键点:

  • 确保Proj库版本≥7.2(GeoPandas的坐标转换依赖)
  • 对于Windows用户,建议通过conda安装GDAL依赖
  • 测试Folium渲染时可能需要设置自定义Tile服务器地址

提示:所有代码示例均在Jupyter Notebook中测试通过,建议配合使用以便实时查看中间结果

2. 高斯模型核心算法实现

2.1 扩散参数计算

根据《环境影响评价技术导则》,扩散系数σy和σz的计算采用以下分段幂函数形式:

def calculate_sigma(StabilityClass, x): """ 计算水平和垂直扩散系数 参数: StabilityClass: 大气稳定度等级(A-F) x: 下风向距离(m) 返回: (σy, σz) 单位:米 """ # 水平扩散参数系数表 a_y = {'A':0.901074, 'B':0.850934, 'C':0.801235, 'D':0.756410, 'E':0.711364, 'F':0.707810} b_y = {'A':0.425809, 'B':0.398940, 'C':0.396353, 'D':0.322659, 'E':0.180167, 'F':0.104634} # 垂直扩散参数系数表 a_z = {'A':0.425809, 'B':0.398940, 'C':0.396353, 'D':0.322659, 'E':0.180167, 'F':0.104634} b_z = {'A':0.901074, 'B':0.850934, 'C':0.801235, 'D':0.756410, 'E':0.711364, 'F':0.707810} σy = a_y[StabilityClass] * (x ** b_y[StabilityClass]) σz = a_z[StabilityClass] * (x ** b_z[StabilityClass]) return σy, σz

2.2 浓度场计算函数

实现高斯烟羽公式的核心函数如下,注意处理地面反射的镜像源法:

import numpy as np from math import exp, pi, sqrt def gaussian_plume(Q, u, H, StabilityClass, x, y, z=1.8): """ 计算点(x,y,z)处的污染物浓度 参数: Q: 源强(mg/s) u: 风速(m/s) H: 有效源高(m) StabilityClass: 稳定度等级(A-F) x,y,z: 计算点坐标(m) 返回: 浓度值(mg/m³) """ σy, σz = calculate_sigma(StabilityClass, x) # 镜像源法处理地面反射 term1 = exp(-0.5*(y/σy)**2) / (sqrt(2*pi)*σy) term2 = (exp(-0.5*((z-H)/σz)**2) + exp(-0.5*((z+H)/σz)**2)) / (sqrt(2*pi)*σz) C = (Q / u) * term1 * term2 return C

3. 空间离散化与栅格生成

3.1 创建计算网格

将研究区域离散化为规则网格,每个网格点作为浓度计算位置:

import rasterio from rasterio.transform import from_origin def create_simulation_grid(center_lon, center_lat, size_km=10, resolution=100): """ 创建以指定点为中心的模拟网格 参数: center_lon, center_lat: 中心点经纬度 size_km: 模拟区域边长(km) resolution: 网格分辨率(m) 返回: (x_grid, y_grid, transform) 网格坐标和地理变换参数 """ # 转换为UTM坐标确保距离单位为米 utm_crs = calculate_utm_zone(center_lon, center_lat) transformer = pyproj.Transformer.from_crs("EPSG:4326", utm_crs) x_center, y_center = transformer.transform(center_lat, center_lon) # 生成网格 half_size = size_km * 500 # 半径米数 x_coords = np.arange(x_center - half_size, x_center + half_size, resolution) y_coords = np.arange(y_center - half_size, y_center + half_size, resolution) x_grid, y_grid = np.meshgrid(x_coords, y_coords) transform = from_origin(x_coords[0], y_coords[-1], resolution, resolution) return x_grid, y_grid, transform, utm_crs

3.2 批量计算浓度场

向量化计算提升性能,避免Python循环:

def calculate_concentration_field(Q, u, H, StabilityClass, x_grid, y_grid): """ 计算整个网格区域的浓度分布 """ # 计算每个点到源头的距离 distances = np.sqrt(x_grid**2 + y_grid**2) # 向量化计算 σy, σz = np.vectorize(calculate_sigma)(StabilityClass, distances) # 高斯公式向量化实现 term1 = np.exp(-0.5*(y_grid/σy)**2) / (np.sqrt(2*np.pi)*σy) term2 = (np.exp(-0.5*((1.8-H)/σz)**2) + np.exp(-0.5*((1.8+H)/σz)**2)) term2 /= (np.sqrt(2*np.pi)*σz) concentration = (Q / u) * term1 * term2 return concentration

4. 可视化与GIS集成

4.1 生成浓度等值线图

使用Matplotlib创建专业级浓度分布图:

import matplotlib.pyplot as plt from matplotlib.colors import LogNorm def plot_concentration(concentration, levels=[1, 10, 50, 100, 500]): """ 绘制浓度等值线图 """ plt.figure(figsize=(10, 8)) contour = plt.contourf(concentration, levels=levels, norm=LogNorm(), cmap='RdYlGn_r') plt.colorbar(label='浓度 (mg/m³)') plt.title('污染物浓度分布') plt.xlabel('X方向距离 (m)') plt.ylabel('Y方向距离 (m)') plt.grid(True) return contour

4.2 创建交互式Web地图

将结果集成到Leaflet地图实现空间分析:

import folium from folium.plugins import HeatMap def create_interactive_map(concentration, transform, utm_crs): """ 生成带浓度热图的交互式地图 """ # 转换回经纬度 transformer = pyproj.Transformer.from_crs(utm_crs, "EPSG:4326") rows, cols = concentration.shape lons, lats = [], [] for i in range(rows): for j in range(cols): x = transform[2] + j * transform[0] y = transform[5] + i * transform[4] lat, lon = transformer.transform(y, x) lons.append(lon) lats.append(lat) # 创建热图数据 heat_data = [[lat, lon, c] for lat, lon, c in zip(lats, lons, concentration.flatten()) if c > 1] # 创建底图 m = folium.Map(location=[np.mean(lats), np.mean(lons)], zoom_start=12, tiles='Stamen Terrain') # 添加热图 HeatMap(heat_data, radius=15, blur=10, min_opacity=0.5, max_val=concentration.max()).add_to(m) return m

5. 完整工作流集成

将各模块串联成端到端解决方案:

def run_full_simulation(Q, u, H, StabilityClass, center_lon, center_lat): """ 执行完整模拟流程 """ # 1. 创建计算网格 x_grid, y_grid, transform, utm_crs = create_simulation_grid(center_lon, center_lat) # 2. 计算浓度场 concentration = calculate_concentration_field(Q, u, H, StabilityClass, x_grid, y_grid) # 3. 可视化 plot_concentration(concentration) map_obj = create_interactive_map(concentration, transform, utm_crs) # 4. 输出结果 save_results(concentration, transform, utm_crs) return map_obj def save_results(concentration, transform, crs): """ 保存计算结果为GeoTIFF """ profile = { 'driver': 'GTiff', 'height': concentration.shape[0], 'width': concentration.shape[1], 'count': 1, 'dtype': np.float32, 'crs': crs, 'transform': transform } with rasterio.open('concentration.tif', 'w', **profile) as dst: dst.write(concentration.astype(np.float32), 1)

6. 实战案例:化工厂氯气泄漏模拟

假设某化工厂(坐标121.4737°E, 31.2304°N)发生氯气泄漏,参数如下:

参数说明
Q5000 mg/s源强
u3 m/s风速
H45 m有效源高
稳定度C大气条件

执行模拟并分析结果:

# 设置参数 params = { 'Q': 5000, 'u': 3, 'H': 45, 'StabilityClass': 'C', 'center_lon': 121.4737, 'center_lat': 31.2304 } # 运行模拟 result_map = run_full_simulation(**params) result_map.save('pollution_simulation.html')

关键发现:

  • 下风向1公里处出现最大浓度值约320mg/m³
  • 安全阈值50mg/m³的影响范围达3.2公里
  • 东北方向因风速影响呈现明显羽流形态

在项目实际部署时,我们封装了参数输入界面和自动化报告生成功能。一个经验技巧是:对持续排放源,采用时间步进方式模拟浓度累积效应,这需要修改核心算法加入时间维度积分。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询