当前位置: 首页 > article >正文

洪水模拟示例代码

my_shallow_water_project/
├── python-backend/
│   ├── requirements.txt
│   ├── shallow_water_sim.py
│   └── app.py
├── vue-frontend/
│   ├── package.json
│   ├── vite.config.js
│   ├── src/
│   │   ├── main.js
│   │   ├── App.vue
│   │   ├── views/
│   │   │   └── HomeView.vue
│   │   └── assets/
│   │       └── style.css
│   └── public/

python-backend/requirements.txt

Flask==2.3.2
numpy==1.24.3
matplotlib==3.7.1
shapely==2.0.1

python-backend/shallow_water_sim.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import numpy as np
import os, json
import matplotlib.pyplot as plt
from shapely.geometry import Polygon, mapping
# from numba import njit

NX, NY = 100, 100
DX, DY = 30.0, 30.0
DT = 1.0
G = 9.81
DRY_TOL = 1e-3
CFL = 0.5
SIM_TIME = 100
DEM_FILE = "data/dem.npy"
OUTPUT_DIR = "output"
MANNING_N = 0.03
INITIAL_WATER_LEVEL = 15.0

def load_dem(fp):
    dem = np.load(fp)
    return dem

def initialize_water(dem):
    return np.maximum(INITIAL_WATER_LEVEL - dem, 0.0)

def compute_time_step(u, v, h):
    ws = np.sqrt(G * h) + np.sqrt(u**2 + v**2)
    m = np.nanmax(ws)
    if m < 1e-6:
        return DT
    return min(CFL * min(DX, DY) / m, DT)

def boundary_condition(u, v, h, dem):
    u[0,:] = u[1,:]
    u[-1,:] = u[-2,:]
    u[:,0] = u[:,1]
    u[:,-1] = u[:,-2]

    v[0,:] = v[1,:]
    v[-1,:] = v[-2,:]
    v[:,0] = v[:,1]
    v[:,-1] = v[:,-2]

    h[0,:] = h[1,:]
    h[-1,:] = h[-2,:]
    h[:,0] = h[:,1]
    h[:,-1] = h[:,-2]

def manning_friction(u, v, h, n=MANNING_N):
    mask = (h > DRY_TOL)
    sp2 = u**2 + v**2
    fc = G * n**2 / np.power(h, 4.0/3.0, where=mask)
    fc[~mask] = 0.0
    return fc, sp2

# @njit
def shallow_water_step(u, v, h, dem, dt):
    fc, sp2 = manning_friction(u, v, h)
    qx = u * h
    qy = v * h

    h2 = np.copy(h)
    u2 = np.copy(u)
    v2 = np.copy(v)

    dqx_dx = (np.roll(qx, -1, axis=1) - qx) / DX
    dqy_dy = (np.roll(qy, -1, axis=0) - qy) / DY

    h2 -= dt * (dqx_dx + dqy_dy)

    mask = (h2 > DRY_TOL)
    sp = np.sqrt(sp2)
    fx = fc * u * sp
    fy = fc * v * sp

    u2[mask] = u[mask] - dt * fx[mask]
    v2[mask] = v[mask] - dt * fy[mask]

    h2[h2 < DRY_TOL] = 0.0
    u2[~mask] = 0.0
    v2[~mask] = 0.0

    return u2, v2, h2

def create_inundation_polygon(h, stepi):
    fig, ax = plt.subplots()
    X = np.arange(0, NX*DX, DX)
    Y = np.arange(0, NY*DY, DY)
    cc = ax.contourf(X, Y, h[::-1,:], [DRY_TOL, 1e9], cmap='Blues')
    polys = []

    for c in cc.collections:
        for p in c.get_paths():
            v = p.vertices
            poly = Polygon(v)
            polys.append(poly)

    from shapely.ops import unary_union
    if len(polys) == 0:
        plt.close(fig)
        return

    pu = unary_union(polys) if len(polys) > 1 else polys[0]
    geo = mapping(pu)
    fn = os.path.join(OUTPUT_DIR, f"inundation_{stepi:04d}.geojson")
    with open(fn, 'w') as f:
        json.dump({
            "type": "Feature",
            "geometry": geo,
            "properties": {"step": stepi}
        }, f)

    plt.close(fig)

def run_simulation():
    dem = load_dem(DEM_FILE)
    h = initialize_water(dem)
    u = np.zeros_like(h)
    v = np.zeros_like(h)

    if not os.path.exists(OUTPUT_DIR):
        os.makedirs(OUTPUT_DIR)

    t = 0.0
    cnt = 0
    while t < SIM_TIME:
        boundary_condition(u, v, h, dem)
        dt_ = compute_time_step(u, v, h)
        dt_ = min(dt_, SIM_TIME - t)
        u, v, h = shallow_water_step(u, v, h, dem, dt_)

        fn = f"step_{cnt:04d}.npz"
        np.savez(os.path.join(OUTPUT_DIR, fn), u=u, v=v, h=h, time=t+dt_)

        if cnt % 5 == 0:
            create_inundation_polygon(h, cnt)

        t += dt_
        cnt += 1

def main():
    run_simulation()

if __name__ == "__main__":
    main()

python-backend/app.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from flask import Flask, jsonify, request
import os, glob, json, threading
from shallow_water_sim import run_simulation

app = Flask(__name__)

@app.post("/api/start_sim")
def start_sim():
    def do_sim():
        run_simulation()
    t = threading.Thread(target=do_sim)
    t.start()
    return jsonify({"message": "模拟已启动"})

@app.get("/api/inundation_list")
def inundation_list():
    files = glob.glob("output/inundation_*.geojson")
    file_names = [os.path.basename(f) for f in files]
    return jsonify({"files": file_names})

@app.get("/api/inundation_geojson")
def inundation_geojson():
    fname = request.args.get('file')
    if not fname:
        return jsonify({"error": "file param missing"}), 400
    path = os.path.join("output", fname)
    if not os.path.exists(path):
        return jsonify({"error": "file not found"}), 404
    with open(path, 'r') as f:
        data = json.load(f)
    return jsonify(data)

if __name__=="__main__":
    app.run(debug=True)

vue-frontend/package.json

{
  "name": "vue3-shallow-water",
  "version": "1.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "serve": "vite preview"
  },
  "dependencies": {
    "vue": "^3.3.4",
    "axios": "^1.4.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^4.1.0",
    "vite": "^4.3.2"
  }
}

vue-frontend/vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  server: {
    // 若后端在 localhost:5000,可配置代理
    proxy: {
      '/api': {
        target: 'http://127.0.0.1:5000',
        changeOrigin: true
      }
    }
  }
})

vue-frontend/src/main.js

import { createApp } from 'vue'
import App from './App.vue'
import './assets/style.css'

const app = createApp(App)
app.mount('#app')

vue-frontend/src/App.vue

<template>
  <div id="app">
    <HomeView />
  </div>
</template>

<script>
import HomeView from './views/HomeView.vue'
export default {
  name: 'App',
  components: { HomeView }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  margin: 0 auto;
}
</style>

vue-frontend/src/views/HomeView.vue

<template>
  <div class="home">
    <h1>Vue 3 - Shallow Water Simulation</h1>

    <button @click="startSimulation">启动模拟</button>
    <p v-if="statusMessage">后端状态: {{ statusMessage }}</p>

    <button @click="fetchInundationList">刷新淹没文件列表</button>
    <h2>已生成的淹没文件:</h2>
    <ul>
      <li v-for="(file, idx) in inundationFiles" :key="idx">
        <button @click="fetchGeoJSON(file)">{{ file }}</button>
      </li>
    </ul>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: 'HomeView',
  data() {
    return {
      statusMessage: '',
      inundationFiles: []
    }
  },
  methods: {
    async startSimulation() {
      try {
        const res = await axios.post('/api/start_sim')
        this.statusMessage = res.data.message || '已请求启动模拟'
      } catch (err) {
        console.error(err)
        this.statusMessage = '启动失败'
      }
    },
    async fetchInundationList() {
      try {
        const res = await axios.get('/api/inundation_list')
        this.inundationFiles = res.data.files || []
      } catch (err) {
        console.error(err)
      }
    },
    async fetchGeoJSON(fname) {
      try {
        const res = await axios.get('/api/inundation_geojson', {
          params: { file: fname }
        })
        console.log('GeoJSON内容:', res.data)
        // 在这里可以将拿到的GeoJSON渲染到Cesium或Leaflet地图上
      } catch (err) {
        console.error(err)
      }
    }
  },
  mounted() {
    this.fetchInundationList()
  }
}
</script>

<style scoped>
.home {
  padding: 1rem;
}
</style>

vue-frontend/src/assets/style.css

body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
}

http://www.kler.cn/a/458629.html

相关文章:

  • 25考研总结
  • 笔记:使用python对飞书用户活跃度统计的一个尝试
  • 【分布式数据库与数据存储方案】详解
  • ES elasticsearch-8.17.0-windows-x86_64使用
  • NVR管理平台EasyNVR设备通过ONVIF接入出现404访问错误是什么原因?
  • 【Java 新特性】常用函数式接口
  • openEuler安装OpenGauss5.0
  • HTML-CSS(day01)
  • 佛塔宝珠c++
  • 解锁自动化新高度,zTasker v2.0全方位提升效率
  • NoETL 自动化指标平台如何保障数据质量和口径一致性?
  • 车载软件架构 --- Autosar OS
  • IOS 关于ARKi使用
  • 通过Cephadm工具搭建Ceph分布式存储以及通过文件系统形式进行挂载的步骤
  • Day58 图论part08
  • HarmonyOS NEXT应用开发实战:免费练手的网络API接口分享
  • 手机租赁平台开发全攻略打造高效便捷的租赁服务系统
  • 【Java 数据结构】面试题 02.02. 返回倒数第 k 个节点
  • 计算机网络 (7)物理层下面的传输媒体
  • 宝塔-firefox(Docker应用)-构建自己的Web浏览器
  • PyQt实战——使用python提取JSON数据(十)
  • 树形查询转成TreeNode[],添加新节点
  • MongoDB 管理工具
  • C# 使用Newtonsoft.Json
  • 数据库的创建使用与查找
  • 【集合】——LinkedList