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.