PySWATPlus is a Python framework for calibrating, validating, and analyzing SWAT+ watershed models. It provides multiple optimization algorithms (DDS, PSO, GLUE), global sensitivity analysis (Sobol, Morris), and an interactive Streamlit dashboard for managing calibration workflows.
Built for hydrologists and water resources engineers who need reproducible, efficient model calibration with statistical rigor.
- Multi-Algorithm Calibration — DDS (Dynamically Dimensioned Search), PSO (Particle Swarm Optimization), GLUE (Generalized Likelihood Uncertainty Estimation)
- Global Sensitivity Analysis — Sobol variance decomposition, Morris elementary effects
- Multi-Objective Optimization — Pareto-optimal parameter sets with NSE, KGE, PBIAS, RMSE
- Parallel Execution — Concurrent SWAT+ simulations with configurable worker pools
- Interactive Dashboard — Streamlit UI for project setup, parameter management, and result visualization
- Validation Framework — Split-sample, k-fold, and multi-site validation with statistical tests
- SWAT+ Native — Direct cal_parms.cal editing, output parsing, and project management
pip install pyswatplusOr from source:
git clone https://github.com/rushmarshall/PySWATPlus.git
cd PySWATPlus
pip install -e ".[dev]"from pyswatplus import Calibrator, SWATProject
project = SWATProject("path/to/swatplus/model")
calibrator = Calibrator(
project=project,
algorithm="dds",
objective="kge",
max_iterations=1000,
n_workers=4,
)
# Define parameter bounds
calibrator.add_parameter("cn2", -0.3, 0.3, method="relative")
calibrator.add_parameter("esco", 0.0, 1.0, method="replace")
calibrator.add_parameter("alpha_bf", 0.0, 1.0, method="replace")
# Run calibration
results = calibrator.run(
observed="observed_flow.csv",
warmup_years=2,
calibration_period=("2010-01-01", "2015-12-31"),
)
print(f"Best KGE: {results.best_objective:.4f}")
results.plot_hydrograph("calibration_hydrograph.png")
results.save("calibration_results.json")streamlit run src/pyswatplus/ui/app.py| Algorithm | Type | Best For | Parameters |
|---|---|---|---|
| DDS | Single-objective | Fast convergence, high-dimensional | r_val, max_iter |
| PSO | Single/Multi-objective | Global search, avoiding local optima | n_particles, w, c1, c2 |
| GLUE | Uncertainty | Behavioral parameter identification | n_simulations, threshold |
from pyswatplus.sensitivity import SobolAnalysis
sobol = SobolAnalysis(project=project, n_samples=1024)
sobol.add_parameter("cn2", -0.3, 0.3)
sobol.add_parameter("esco", 0.0, 1.0)
sobol.add_parameter("alpha_bf", 0.0, 1.0)
results = sobol.analyze(output_variable="streamflow")
results.plot_indices("sobol_indices.png")| Metric | Range | Optimal | Description |
|---|---|---|---|
| NSE | (-inf, 1] | 1.0 | Nash-Sutcliffe Efficiency |
| KGE | (-inf, 1] | 1.0 | Kling-Gupta Efficiency |
| PBIAS | (-inf, inf) | 0.0 | Percent Bias |
| RMSE | [0, inf) | 0.0 | Root Mean Square Error |
| R2 | [0, 1] | 1.0 | Coefficient of Determination |
| LogNSE | (-inf, 1] | 1.0 | Log-transformed NSE (low flows) |
pyswatplus/
├── calibration/ # Calibration engine
│ ├── algorithms/ DDS, PSO, GLUE implementations
│ ├── objective.py Objective function library
│ └── sampler.py Parameter sampling strategies
├── sensitivity/ # Sensitivity analysis
│ ├── sobol.py Sobol variance decomposition
│ └── morris.py Morris elementary effects
├── core/ # SWAT+ integration
│ ├── project.py Project management
│ ├── runner.py Parallel SWAT+ execution
│ ├── parser.py Output file parsing
│ └── parameters.py cal_parms.cal management
├── validation/ # Model validation
│ ├── splitter.py Train/test splitting strategies
│ └── metrics.py Statistical validation tests
└── ui/ # Streamlit dashboard
├── app.py Main application
└── components.py Reusable UI components
Contributions welcome. Please open an issue to discuss proposed changes before submitting a pull request.
git clone https://github.com/rushmarshall/PySWATPlus.git
cd PySWATPlus
pip install -e ".[dev]"
pytest tests/ -v
Developed at Hydrosense Lab, University of Virginia
Part of the Global Hydrology and Water Resources research group