架构
这一页从当前实现视角介绍 HydroPilot 的架构。
两条主链路
HydroPilot 有两条彼此关联但职责不同的链路:
- 配置链路:YAML 配置 -> 校验与模板展开 ->
RunConfig - 运行链路:
SimModel->Session->Workspace->Executor-> 执行服务 -> 结果汇报
配置链路负责把用户输入转换成可执行的运行配置。运行链路负责利用这份配置完成模型执行、结果提取、指标评估和归档保存。
配置链路
从整体上看,配置准备过程大致是这样:
text
YAML
-> prepare_config()
-> 可选的模板展开
-> 通用配置校验
-> RunConfig.from_raw()
-> load_config()这里有几个关键点:
version: general表示 YAML 已经直接描述了运行时配置。version: swat、version: swatplus、version: xaj这类模板模式,会先展开为通用运行配置再执行。- 校验是在展开后的配置上完成的,所以模型模板层面的错误可以尽早暴露。
- 运行时加载成功后,HydroPilot 可以把解析后的
_general.yaml输出到源配置旁边,便于检查。
这条链路同时服务命令行校验和 Python 运行时。区别只在于:命令行会把失败转换成用户可读的诊断信息,而 Python 接口会直接抛异常。
主要模块
面向运行时的核心模块可以概括为:
api:公开入口,例如SimModelcli:命令行接口config:配置加载、路径解析和 schema 转换evaluation:目标、约束、诊断项和派生值计算io:运行器、reader 和 writermodels:模板注册和模型专属逻辑params:参数空间和参数写入reporting:归档输出和运行产物runtime:session 与 workspace 生命周期series:模拟值和观测值的提取规划validation:面向用户的配置诊断
运行链路
运行时路径从 SimModel 开始,然后委托给一组编排组件:
text
SimModel
-> Session
-> Workspace
-> Executor
-> ExecutionServices
-> ParamSpace
-> ParamWritePlan
-> ParamApplier
-> SeriesPlan
-> ObsStore
-> SubprocessRunner
-> SeriesExtractor
-> Evaluator
-> RunReporter各层职责比较清晰:
SimModel:面向 Python 用户的公开入口Session:负责一次运行时实例的生命周期和清理Workspace:负责创建隔离工作目录并管理可复用的模型副本Executor:负责顺序或并行执行评估任务ExecutionServices:从RunConfig组装实际运行所需的依赖RunReporter:负责归档结果、摘要和运行产物
Workspace 与执行过程
HydroPilot 会在 basic.workPath 下创建隔离的工作目录。对于每次评估,它大致会按下面的顺序工作:
- 创建或获取一个准备好的工程副本
- 将设计变量转换成物理参数
- 把参数写入模型输入文件
- 执行配置中的模型命令
- 提取模拟输出和观测切片
- 计算目标、约束和诊断项
- 归档结果并释放实例
默认情况下,instance_* 这类临时目录会在 session 关闭时清理掉。如果打开 basic.keepInstances: true,这些目录会被保留下来,方便调试。
为什么模板很重要
模板是 HydroPilot 架构里的关键优势之一。它让用户可以直接使用 SWAT 参数、XAJ CSV 映射这类模型层概念,而不必手写所有底层 reader 和 writer。
从工程上看,这意味着:
- 模型专属知识被收敛在模板层
- 运行时始终执行统一的通用配置
- 命令行、Python 接口和 UQPyL 集成都共用同一套执行基础
这套拆分的意义
正是这种拆分,使 HydroPilot 能作为稳定的工程执行层:
- 配置保持声明式
- 模型专属细节收敛在模板与 I/O 处理层
- 运行编排可以同时服务命令行、Python 接口和 UQPyL 集成
