--- name: service-area-analysis description: 基于实时水力模拟数据的水源追溯供水服务范围分区。通过管段流量确定水流方向,从水库BFS追溯服务节点,环网/零流量节点用无向拓扑补充分配,输出分区可视化。 --- # 供水服务范围分区工作流 ## 概述 本工作流基于指定时刻的水力模拟结果,通过**流向追溯法**将全部管网节点分配到各水库的服务范围。核心思路:利用管段流量符号判定水流方向,构建有向图从水库逐级追溯,对环网和零流量节点用无向拓扑修正。 适用场景:供水服务范围评估、DMA分区规划、多水源供水格局分析、管网调度策略评估。 ## 分区方法 ### 第一步:水流方向判定 对于每条管段,根据实时流量 `flow` 判定水流方向: | flow 值 | 水流方向 | 说明 | |---------|----------|------| | `flow > 1e-6` | node1 → node2 | 正向流量 | | `flow < -1e-6` | node2 → node1 | 反向流量 | | `|flow| ≤ 1e-6` | 无方向 | 零流量,不参与有向追溯 | ### 第二步:多源有向BFS 1. 以每个水库为根节点,沿水流方向执行 BFS 2. 遍历到的节点归属该水库的服务范围 3. **先到先得**:一个节点首次被访问到的水库即为归属 4. 预期覆盖 **85–90%** 节点 ### 第三步:无向拓扑修正 有向BFS不可达节点(通常 10–15%)通过无向图邻近性补充分配: | 不可达原因 | 说明 | |------------|------| | 环状管网 | 水流回路中下游节点反向连回上游,有向遍历被阻断 | | 零流量管段 | `flow≈0` 的管段无方向,其下游节点断开 | | 多水源交汇 | 交汇区流向往复,非树状拓扑 | ### 输出统计 每个分区输出: - `node_count`:分区内节点总数 - `total_demand`:总需水量(负数=净供水区) - `avg_pressure`/`min_pressure`/`max_pressure`:压力统计 ## 数据依赖 | 步骤 | 命令 | 数据量 | 超时 | 关键字段 | |------|------|--------|------|----------| | ① 管道拓扑 | `network get-all-pipes-properties` | ~11.7MB / 91K条 | 120s | id, node1, node2 | | ② 水库属性 | `network get-all-reservoirs-properties` | ~小 | 120s | id, links | | ③ 管段流量 | `data timeseries realtime links --start-time T --end-time T+15min` | ~39MB / 182K条 | 300s | id, flow, time | | ④ 节点数据 | `data timeseries realtime nodes --start-time T --end-time T+15min` | ~28MB / 176K条 | 300s | id, pressure, actual_demand, time | > **时间窗口**:模拟步长 15 分钟,查询 T~T+15min 覆盖 1–2 个时间步。脚本按 `--target-time` 精确筛选。 > **文件输入**:四份调用都使用 `store_result=true`,包括结果较小的水库属性。脚本读取每次返回的 `data_file.file_path`;文件都属于当前对话,禁止使用 `/tmp` 或全局 `tool-output/`。 ## 执行步骤 ### 第 1 步:并行拉取数据 4 个 `tjwater_cli` 调用(互不依赖),可一次发起: ```bash # ① 管道静态拓扑 tjwater_cli(command="network get-all-pipes-properties", timeout=120, store_result=true) # ② 水库属性 tjwater_cli(command="network get-all-reservoirs-properties", timeout=120, store_result=true) # ③ 目标时刻管段流量 tjwater_cli(command="data timeseries realtime links --start-time 2026-04-01T08:00:00+08:00 --end-time 2026-04-01T08:15:00+08:00", timeout=300, store_result=true) # ④ 目标时刻节点数据 tjwater_cli(command="data timeseries realtime nodes --start-time 2026-04-01T08:00:00+08:00 --end-time 2026-04-01T08:15:00+08:00", timeout=300, store_result=true) ``` ### 第 2 步:运行分区脚本 ```bash python3 /scripts/service_area_partition.py \ --pipe-props \ --reservoirs \ --links \ --nodes \ --target-time '2026-04-01T08:00:00+08:00' \ --output ./service_area_partition_wrapper.json ``` **脚本参数**: | 参数 | 说明 | 必填 | |------|------|------| | `--pipe-props` | 管道属性 JSON 文件路径 | 是 | | `--reservoirs` | 水库属性 JSON 文件路径 | 是 | | `--links` | 实时管段数据 JSON 文件路径 | 是 | | `--nodes` | 实时节点数据 JSON 文件路径 | 是 | | `--target-time` | 目标时刻 ISO8601 | 是 | | `--output` | 分区结果输出路径 | 是 | **输出**: - **stderr**:处理日志 + 各分区统计表格 - **stdout**:紧凑 JSON 摘要(total_nodes, reservoirs, areas) - **文件**:符合 `store_render_ref` 要求的 `{metadata, location, data}` 包装 JSON,其中 `data` 包含 `node_area_map`、`area_ids`、`area_colors` 和分析元数据 ### 第 3 步:前端可视化 ```bash # 持久化分区结果 store_render_ref(file_path=) # 渲染节点分区 render_junctions(render_ref="res-xxxxxxxx-xxxx-xx") # 定位水库 locate_features(ids=[...], feature_type="reservoir") # 展示统计图表 show_chart(title="各水源分区节点数/压力对比", chart_type="bar", ...) ``` ## 参考数据规模 基于 91,000 管段 / 88,000 节点规模的管网模型: | 指标 | 实测值 | |------|--------| | 管道拓扑数据量 | 91,052 条 | | 水库数量 | 13 个 | | 总节点数 | 87,907 | | 有向BFS分配节点 | ~76,900 (87.5%) | | 无向修正节点 | ~11,000 (12.5%) | | 分区覆盖率 | 100% | | 脚本处理时间 | ~15-30 秒 | | 峰值内存 | ~400-500MB | ## 已知限制 - **水库顺序敏感**:多源 BFS 中先遍历到的水库优先分配,不同水库启动顺序可能影响边界区域分配结果 - **单时刻快照**:分区仅反映目标时刻的水力工况,不同时段的泵站启停、阀门切换可能导致分区边界变化 - **零流量阈值**:`1e-6` 阈值过滤极低流量管段,若管网有长期小流量管段可能漏判方向 ## Learned Patterns - [6614a914a8f7dcc2fc34c1ba] 实时数据时间匹配必须用 norm_time 归一化为 UTC 再比较(数据 time 为 UTC 格式如 2026-06-03T00:00:00+00:00,target-time 传 +08:00 会因字符串不等而筛出 0 条);links/nodes 记录主键字段为 link_id/node_id(不是 id)。执行分区前先确认目标时刻存在实时数据,可用 `data timeseries realtime simulation-by-id-time` 探测;数据可能只覆盖某几天(本模型覆盖 2026-06-03 附近,2026-04 与 2026-08 均无数据)。