HydroPilot

SWAT 2012

SWAT 2012

这一页展示的是 SWAT 2012 在 HydroPilot 里的典型模型路径,也就是怎样把一个经典 TxtInOut 工程整理成可校验、可重复评估、可接入 UQPyL 的运行链路。

为什么这个案例重要

它覆盖了一条最小但足够实用的流程:

  • 定义 SWAT 模板配置
  • 校验配置
  • 做一次冒烟测试
  • 执行一次或多次评估

什么情况下适合用这一类配置

如果你的项目符合下面这些条件,可以优先考虑这一类配置:

  • 目标工程是 SWAT 2012 的 TxtInOut 风格目录
  • 参数需要写入 .mgt.gw 等经典 SWAT 文本输入文件
  • 输出主要来自 output.rchoutput.suboutput.hru
  • 你希望配置保持紧凑,而不是手写所有定宽字段位置

典型配置形态

这条路径通常从 version: swat 开始:

yaml
version: swat
basic:
  projectPath: ./TxtInOut
  workPath: ./work
  command: swat.exe

随后 HydroPilot 会先把这份紧凑的 SWAT 模板配置展开成通用运行时配置,再进入执行阶段。

典型组成

  • version: swat
  • CN2ALPHA_BFGW_DELAY 这类设计参数
  • output.rch 中提取输出
  • 以 NSE 之类的指标作为目标

如果把它放到一个真实率定任务里,最常见的结构通常包括:

  • basic:指定 TxtInOut 工程目录、工作目录和 swat.exe
  • parameters.design:定义优化器看到的参数和取值范围
  • series:描述从 output.rchoutput.suboutput.hru 中提取哪些结果
  • functions / derived / objectives:把模拟结果和观测值连成可计算的目标函数

也就是说,这一类案例的核心不是“怎么把 SWAT 跑起来”,而是“怎样把 SWAT 工程组织成一条可重复评估的率定链路”。

最小示例形态

yaml
version: swat
basic:
  projectPath: ./TxtInOut
  workPath: ./work
  command: swat.exe

parameters:
  design:
    - name: CN2
      bounds: [35, 98]
    - name: ALPHA_BF
      bounds: [0, 1]
  physical:
    - name: CN2
      mode: v
    - name: ALPHA_BF
      mode: v

这还不是完整可运行配置,但已经能代表 SWAT 2012 场景下最常见的配置骨架。

如果你继续往下补,一般还需要再加:

  • series:指定读哪个输出文件、哪个子流域、哪段时段
  • obs:指定观测文件
  • functions / objectives:定义 NSE、RMSE 或其他评价指标

HydroPilot 帮你处理了什么

在 SWAT 2012 场景下,模板层会替你处理很多底层细节:

  • 从 SWAT 参数数据库解析参数写入位置
  • 按子流域、土地利用、土壤和坡度做 HRU 过滤
  • FLOW_OUT 这类变量名解析为具体输出列
  • 根据模拟时段、时间步长和对象 ID 自动计算读取行范围

这也是为什么通常优先用 version: swat,而不是直接手写完整的 version: general

换句话说,version: swat 的主要价值就在于:你可以先按 SWAT 用户熟悉的参数名和变量名来写配置,而不必一上来就关心每个字段最终落在哪个文件、哪一列、哪一行。

实际使用流程

对大多数项目来说,比较稳妥的做法是:

  1. test_daily.yaml 这类简单示例开始
  2. 替换 basic.projectPathbasic.command
  3. hydropilot-validate 做校验
  4. hydropilot-test 做冒烟测试
  5. 如果需要重复评估,再转向 SimModelUQPyLAdapter

最常见的第一步命令是:

bash
hydropilot-validate examples/test_daily.yaml
hydropilot-test examples/test_daily.yaml

如果你准备进一步把它用到真实项目里,比较推荐的推进顺序是:

  1. 先跑通最简单的日尺度单目标版本
  2. 再确认观测序列和模拟序列是否对齐
  3. 再逐步增加参数数量
  4. 之后再考虑加入 HRU 过滤、多目标或派生指标

这样做的原因很实际:SWAT 2012 工程一旦同时叠加参数过滤、多个输出文件和多个目标,排查问题的成本会明显升高。

这一类配置最擅长解决什么

  • 用紧凑配置描述 SWAT 工程
  • 做 HRU 级参数定位
  • 从标准 SWAT 输出文件提取结果
  • 从单次测试平滑过渡到算法驱动搜索

进一步扩展时常见的方向

在 SWAT 2012 这一类案例上,最常见的扩展方向有三类:

从日尺度扩展到月尺度

这是最自然的一步。你通常只需要:

  • 把工程的 IPRINT 切到月尺度
  • 准备对应的月尺度观测文件
  • 调整 period 和观测行数

相比日尺度,月尺度更适合长期率定、水质场景和运行速度敏感的场景。

从单目标扩展到多目标

当你同时关心流量、总氮、泥沙或其他指标时,可以把多个 derived 结果接成多个 objectives。这时更适合引入 UQPyL 的多目标优化器。

从全局参数扩展到带过滤的参数

如果一个参数只希望作用于特定土地利用、土壤或子流域,就可以在 physical 里加入 filter。这会显著增强配置表达力,但也更容易把问题复杂化,因此建议在基础版本跑通之后再做。

常见注意点

这一类案例里最容易出问题的地方通常是:

  • projectPath 指错,导致 file.ciofig.fig 找不到
  • 观测文件行数和 period 对不上
  • sim.id 超出子流域或河段范围
  • 还没确认工程本身能正常运行,就先开始堆优化逻辑
  • 一开始就引入过多参数和过滤条件,导致不好排查

比较稳妥的原则是:先保证“能跑”,再保证“跑对”,最后再追求“跑得复杂”。

适用边界

这一页只面向 SWAT 2012 风格工程。如果目标工程是 SWAT+,应转到 SWAT+ 示例。如果工程主要采用 CSV 组织形式,则应转到 XAJ 示例

和 UQPyL 的连接点

当 SWAT 2012 的评估需要被优化或率定算法驱动时,这一页就会很有参考价值。HydroPilot 负责面向文件的模型执行层,UQPyL 则可以通过 UQPyLAdapter 接管搜索层。

完整闭环案例:用 UQPyL 做单目标率定

如果你想把这一页里的模型接入继续推进成一条真正可运行的优化链路,最自然的做法就是把同一份 HydroPilot 配置交给 UQPyL。

一个最小可用的闭环通常包含这几步:

  1. 准备 version: swat 配置
  2. 先跑 hydropilot-validate
  3. 再跑 hydropilot-test
  4. UQPyLAdapter 包装成 Problem
  5. 用 UQPyL 的单目标优化器执行率定

最常见的场景设定是:

  • 参数:CN2ALPHA_BFGW_DELAY
  • 输出:出口流量
  • 目标:最大化 NSE
  • 优化器:GA

一份可接入 UQPyL 的基础配置

yaml
version: swat

basic:
  projectPath: ./TxtInOut
  workPath: ./work
  command: swat.exe

parameters:
  design:
    - name: CN2
      bounds: [35, 98]
    - name: ALPHA_BF
      bounds: [0, 1]
    - name: GW_DELAY
      bounds: [0, 500]

series:
  - id: flow
    sim:
      file: output.rch
      id: 33
      variable: FLOW_OUT
      period: [2010, 2015]
    obs:
      file: obs_flow.txt
      rowRanges:
        - [1, 2191]
      colNum: 1

functions:
  - name: NSE
    kind: builtin

derived:
  - id: nse_flow
    call:
      func: NSE
      args: [flow.sim, flow.obs]

objectives:
  - id: obj_nse
    ref: nse_flow
    sense: max

这份配置本质上就是把 SWAT 2012 工程、观测值和目标函数整理成一个可重复评估的问题。

先打通 HydroPilot 这一层

在接优化算法之前,先确认运行链路没有问题:

bash
hydropilot-validate my_swat_uqpyl.yaml
hydropilot-test my_swat_uqpyl.yaml

这一步不能省。因为 UQPyLAdapter 只负责把问题包装给优化器,并不会替你修复工程路径、参数写入或输出提取的问题。

UQPyLAdapter 包装成优化问题

python
from hydropilot.integrations import UQPyLAdapter

with UQPyLAdapter("my_swat_uqpyl.yaml") as problem:
    print(problem.nInput)
    print(problem.lb)
    print(problem.ub)

这一步会自动把:

  • 设计参数数量
  • 参数边界
  • 目标数量
  • 约束数量

映射成 UQPyL 认识的 Problem

运行一个单目标优化器

python
from UQPyL.optimization.soea import GA
from hydropilot.integrations import UQPyLAdapter

with UQPyLAdapter("my_swat_uqpyl.yaml") as problem:
    algorithm = GA(
        nPop=20,
        maxFEs=100,
        verboseFlag=False,
        logFlag=False,
        saveFlag=False,
    )
    result = algorithm.run(problem, seed=42)

    print(result.bestDecs)
    print(result.bestObjs)

这里最值得关注的是两类结果:

  • bestDecs:最优参数组合
  • bestObjs:对应的最优目标值

这就构成了一条完整闭环:

  • HydroPilot 负责 SWAT 工程运行、参数写入、输出提取和目标计算
  • UQPyL 负责搜索最优参数

这个完整案例最适合展示什么

它最适合拿来说明三件事:

  1. 同一份 HydroPilot 配置既能单次测试,也能重复优化
  2. HydroPilot 和 UQPyL 的职责边界非常清楚
  3. 最稳妥的做法永远是先把运行链路打通,再去放大优化规模

做这个案例时最常见的问题

  • HydroPilot 配置本身还没跑通,就直接上优化
  • 参数边界过宽,导致大量无效评估
  • 观测文件和模拟时段没有严格对齐
  • maxFEs 一开始设得过大,导致调试成本太高

所以更推荐的方式是:先用小规模评估次数把链路打通,再逐步增加复杂度。

建议路径

建议先从日尺度示例开始,跑通之后再根据需要扩展到月尺度或多目标配置。