HydroPilot

SWAT 2012

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 TxtInOut style project
  • parameters are written into classic SWAT text inputs such as .mgt and .gw
  • outputs are extracted from files such as output.rch, output.sub, or output.hru
  • you want a compact config without manually specifying fixed-width positions

Typical configuration pattern ​

The normal entry is version: swat:

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

HydroPilot 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, and GW_DELAY
  • output extraction from output.rch
  • an objective such as NSE

Minimal example shape ​

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

This 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_OUT into 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:

  1. start from a simple example such as test_daily.yaml
  2. replace basic.projectPath and basic.command
  3. validate with hydropilot-validate
  4. smoke test with hydropilot-test
  5. move to SimModel or UQPyLAdapter when repeated evaluations are needed

Typical first commands:

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

What 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:

  1. prepare a version: swat config
  2. run hydropilot-validate
  3. run hydropilot-test
  4. wrap the config with UQPyLAdapter
  5. 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 ​

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

Stabilize HydroPilot first ​

Before optimization, make sure the runtime path works on its own:

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

This step matters because UQPyLAdapter does not fix broken runtime wiring. It only exposes the working HydroPilot config to the optimizer.

Wrap it with UQPyLAdapter ​

python
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 ​

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)

The most important outputs are:

  • bestDecs for the best parameter vector
  • bestObjs for 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:

  1. the same HydroPilot config can support both smoke testing and repeated optimization
  2. HydroPilot and UQPyL have a clean division of responsibilities
  3. 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 maxFEs too 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.