SWAT 2012
This page presents the typical SWAT 2012 model path in HydroPilot: how a classic TxtInOut project is organized into a runtime that can be validated, evaluated repeatedly, and connected to UQPyL.
Why this case matters
It shows the minimum useful workflow:
- define a SWAT template config
- validate it
- smoke test it
- run one or more evaluations
When to use this case
Choose this path when:
- the target project is a SWAT 2012
TxtInOutstyle project - parameters are written into classic SWAT text inputs such as
.mgtand.gw - outputs are extracted from files such as
output.rch,output.sub, oroutput.hru - you want a compact config without manually specifying fixed-width positions
Typical configuration pattern
The normal entry is version: swat:
version: swat
basic:
projectPath: ./TxtInOut
workPath: ./work
command: swat.exeHydroPilot then expands this compact SWAT-aware config into a general runtime config before execution.
Typical ingredients
version: swat- design parameters such as
CN2,ALPHA_BF, andGW_DELAY - output extraction from
output.rch - an objective such as NSE
Minimal example shape
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: vThis is not a full runnable config, but it reflects the usual skeleton of the SWAT 2012 path.
What HydroPilot handles for you
For SWAT 2012, the template layer can take care of several low-level details:
- resolving parameter write positions from the SWAT parameter database
- applying HRU filters based on subbasin, land use, soil, and slope
- converting variable names such as
FLOW_OUTinto output column spans - calculating row ranges from simulation period, timestep, and object IDs
This is the main reason to prefer version: swat over writing a fully expanded version: general config by hand.
Practical workflow
For most projects, a sensible path is:
- start from a simple example such as
test_daily.yaml - replace
basic.projectPathandbasic.command - validate with
hydropilot-validate - smoke test with
hydropilot-test - move to
SimModelorUQPyLAdapterwhen repeated evaluations are needed
Typical first commands:
hydropilot-validate examples/test_daily.yaml
hydropilot-test examples/test_daily.yamlWhat this case supports well
- compact SWAT-aware config authoring
- HRU-level parameter targeting
- output extraction from standard SWAT result files
- straightforward progression from single-run testing to algorithm-driven search
Boundary
This case is specific to SWAT 2012 style projects. If the target project is SWAT+, move to the SWAT+ Example. If the project is CSV-oriented, move to the XAJ Example.
Connection to UQPyL
This case becomes especially useful when SWAT 2012 evaluations need to be driven by optimization or calibration algorithms. HydroPilot handles file-oriented model execution, while UQPyL can handle the search layer through UQPyLAdapter.
Full closed-loop case: single-objective calibration with UQPyL
The most natural next step is to hand the same HydroPilot config to UQPyL and run a real optimization loop.
A minimal closed-loop path usually looks like this:
- prepare a
version: swatconfig - run
hydropilot-validate - run
hydropilot-test - wrap the config with
UQPyLAdapter - run a single-objective optimizer
A very common setup is:
- parameters:
CN2,ALPHA_BF,GW_DELAY - output: outlet flow
- objective: maximize
NSE - optimizer:
GA
A HydroPilot config that can be passed into UQPyL
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: maxStabilize HydroPilot first
Before optimization, make sure the runtime path works on its own:
hydropilot-validate my_swat_uqpyl.yaml
hydropilot-test my_swat_uqpyl.yamlThis step matters because UQPyLAdapter does not fix broken runtime wiring. It only exposes the working HydroPilot config to the optimizer.
Wrap it with UQPyLAdapter
from hydropilot.integrations import UQPyLAdapter
with UQPyLAdapter("my_swat_uqpyl.yaml") as problem:
print(problem.nInput)
print(problem.lb)
print(problem.ub)At this point, UQPyL can treat the HydroPilot config as a standard optimization problem.
Run a single-objective optimizer
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)The most important outputs are:
bestDecsfor the best parameter vectorbestObjsfor the corresponding best objective value
That creates a real end-to-end workflow:
- HydroPilot owns project execution, parameter writes, output extraction, and metric evaluation
- UQPyL owns the search process
What this full case demonstrates
It shows three things especially well:
- the same HydroPilot config can support both smoke testing and repeated optimization
- HydroPilot and UQPyL have a clean division of responsibilities
- the safest engineering order is always runtime first, optimization second
Common pitfalls in this full case
- trying optimization before the HydroPilot config is stable
- using parameter bounds that are too wide too early
- misaligned observation and simulation periods
- setting
maxFEstoo high during the first validation run
A practical rule is: start with a small budget, prove the loop works, then scale it up.
Suggested path
Start from the daily example first, then move to monthly or multi-objective setups if needed.
