Skip to content
Back to skills

Docs

ASecurity

> **Stage ID**: s3_weather_preparation > **Pipeline order**: 3 of 9 > **Depends on**: s1_watershed_delineation (for station locations)

  • 200 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 11, 2026
toolspythonbash

Works with

  • cli

Security analysis

A100/100

Pro scans all 15 files and shows the line behind each finding

Scanned September 11, 2026

npx -y skills add lzwei196/KISS---Knowledge-Infrastructure-for-Scientific-Simulation --skill docs --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Docs?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Docs
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/lzwei196-docs-3067805b/badge)](https://www.skillsdirectory.com/skills/lzwei196-docs-3067805b)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# Weather Data Preparation — Skill Document

> **Stage ID**: s3_weather_preparation
> **Pipeline order**: 3 of 9
> **Depends on**: s1_watershed_delineation (for station locations)

## Purpose

SWAT+ requires daily meteorological forcing as the primary driver of hydrological processes. Weather data must be provided in a specific multi-file format: five variable types, each with individual station files and a .cli index file, plus a weather-sta.cli mapping and a weather generator (wgn.wgn). Incorrect weather preparation is the most common source of silent errors in SWAT+ simulations, because the model will run with wrong data without any error message.

## Prerequisites

Before starting this stage, verify:

- [ ] Subbasin centroids computed from S1 (for nearest-station assignment)
- [ ] Source forcing data covers the simulation period plus warmup years
- [ ] Source data contains all 5 variables: precipitation, temperature (max+min), solar radiation, relative humidity, wind speed
- [ ] For CMFD: data directory at `data/forcing/Data_forcing_03hr_010deg/`
- [ ] For MSWX: data directory at `KISSPATH_FORCING/`
- [ ] Python environment with xarray, netCDF4, pandas

## Inputs

| Input | Type | Source | Description |
|-------|------|--------|-------------|
| Forcing data | directory | CMFD / MSWX / CSV / NASA POWER | Raw meteorological data |
| Station coordinates | config | Grid cell centers or real station locations | Lat/lon pairs for weather stations |
| Start/end dates | string | User | Simulation period (YYYY-MM-DD) |
| Subbasin centroids | config | From S1 | For nearest-station assignment in weather-sta.cli |

## Procedure

### Step 1: Determine station locations

Define weather station locations. Options:
- **Gridded data** (CMFD, MSWX): Use grid cell centers within/near the basin as station locations
- **Real stations**: Use actual meteorological station coordinates
- **Single station**: One station for the entire basin (acceptable for small basins <500 km2)

**Expected result**: List of station coordinates with unique names.

### Step 2: Extract and convert weather data

```bash
python tools/s3/prepare_weather_files.py
```

For each station, extract daily values from the source and write SWAT+ format files.

**SWAT+ weather file format** (all 5 types follow this pattern):

```
Station precipitation data          <-- Line 1: title (free text)
nbyr       tstep      lat         lon         elev       <-- Line 2: column headers
10         0          32.500      116.800     45.0       <-- Line 3: metadata
2000       1          0.00                               <-- Line 4+: year jday value(s)
2000       2          5.20
```

Variable-specific formats:
- **.pcp**: year, jday, precip (mm)
- **.tmp**: year, jday, tmp_max (C), tmp_min (C)
- **.slr**: year, jday, solar radiation (MJ/m2)
- **.hmd**: year, jday, relative humidity (fraction 0-1)
- **.wnd**: year, jday, wind speed (m/s)

**Critical unit conversions from CMFD/MSWX**:
| Variable | Source Unit (CMFD) | SWAT+ Unit | Conversion |
|----------|-------------------|------------|------------|
| Temperature | K | C | subtract 273.15 |
| Precipitation | mm/3hr | mm/day | sum 8 timesteps |
| Solar radiation | W/m2 | MJ/m2/day | multiply by 0.0864 (avg W/m2 -> MJ/m2/day) |
| Relative humidity | specific humidity (kg/kg) | fraction (0-1) | compute from q, T, P |
| Wind speed | m/s | m/s | no conversion needed |

**If this fails**: See diagnostic triplet dt_002 (format error) or dt_012 (unit error).

### Step 3: Generate .cli index files

For each variable, create a .cli file listing all station file names:

```
Precipitation station files
filename
p000001.pcp
p000002.pcp
```

**Expected result**: pcp.cli, tmp.cli, slr.cli, hmd.cli, wnd.cli in TxtInOut.

### Step 4: Generate weather-sta.cli

```bash
python tools/s3/generate_weather_stations.py
```

Map station combinations to spatial objects. Each record in weather-sta.cli has these columns,
**in this exact order** (verified against the shipped rev59 developer example
`run_lrew/swatplus_rev59_demo/weather-sta.cli`):

```
name    wgn         pcp         tmp         slr         hmd         wnd         wnd_dir  atmo_dep
sta01   wgn_sta01   sta01.pcp   sta01.tmp   sta01.slr   sta01.hmd   sta01.wnd   null     null
```

Two traps (`dt_040`):
- The `wgn` column comes **second**, not last. Writing `pcp` first makes SWAT+ read the pcp
  station name as the wgn name.
- The pcp..wnd columns hold the **file name including its extension** (`sta01.pcp`), not a bare
  stem.

Station names are matched **by name** against the `wst` column of `hru.con` / `rout_unit.con`.
`generate_hru_from_global.py` writes `staNN` there, so `prepare_weather_files.py` must be given
those names (its 7th argument) — otherwise it emits `p000001.pcp` and nothing binds.

**Expected result**: weather-sta.cli with one record per unique station combination.

### Step 5: Generate the weather generator (`weather-wgn.cli`)

SWAT+ Rev 59 reads **`weather-wgn.cli`** — the name listed in `file.cio`. A SWAT2012-style
`wgn.wgn` is NOT read. Layout, per station: a header line (`name lat lon elev rain_yrs`), then a
14-column header, then 12 monthly rows of:

```
tmp_max_ave tmp_min_ave tmp_max_sd tmp_min_sd pcp_ave pcp_sd pcp_skew
wet_dry wet_wet pcp_days pcp_hhr slr_ave dew_ave wnd_ave
```

`generate_weather_stations.py` computes all 14 from each station's own `.pcp/.tmp/.slr/.hmd/.wnd`
(wet/dry Markov probabilities from the daily sequence; dew point by inverse Magnus from RH and
mean T). `pcp_hhr` (max 30-min rainfall) is not resolvable from a daily series and is estimated as
0.3 × the largest daily total; supply a sub-hourly series if sediment yield (MUSLE peak rate) is
the calibration target.

**Expected result**: weather-wgn.cli with 12 monthly rows per station. SWAT+ reads it at startup
even when the observed record is complete.

### Step 6: Validate weather data

```bash
python tools/s3/validate_weather_data.py
```

**Expected result**: All files pass QC checks (no Tmax < Tmin, no negative precip, no values outside physical ranges).

**If this fails**: See diagnostic triplet dt_003 (Tmax < Tmin).

## Expected Outputs

| Output | Path | Verification |
|--------|------|--------------|
| *.pcp files | `TxtInOut/*.pcp` | 3-line header + daily rows; precip >= 0; no NaN |
| *.tmp files | `TxtInOut/*.tmp` | 3-line header + daily rows; Tmax >= Tmin |
| *.slr files | `TxtInOut/*.slr` | 3-line header + daily rows; 0 <= solar <= 40 MJ/m2 |
| *.hmd files | `TxtInOut/*.hmd` | 3-line header + daily rows; 0 <= RH <= 1 |
| *.wnd files | `TxtInOut/*.wnd` | 3-line header + daily rows; wind >= 0 |
| pcp.cli | `TxtInOut/pcp.cli` | Lists all .pcp files |
| weather-sta.cli | `TxtInOut/weather-sta.cli` | Maps stations to spatial objects |
| wgn.wgn | `TxtInOut/wgn.wgn` | 12 monthly rows per station |

## Validation Checks

1. **Header line count**: Each weather file must have exactly 3 header lines, then data.
   - Command: `head -5 TxtInOut/p000001.pcp` — line 4 should be first data row
   - If wrong: See diagnostic triplet dt_002

2. **Temperature consistency**: Tmax >= Tmin for every row in every .tmp file.
   - If violated: See diagnostic triplet dt_003

3. **Precipitation non-negative**: All precip values >= 0.
   - Negative precipitation causes mass balance errors

4. **Solar radiation range**: 0 to ~40 MJ/m2/day (varies by latitude and season).
   - If values >50: Wrong units (likely W/m2 instead of MJ/m2). See dt_012.

5. **Date continuity**: No gaps in daily sequence (year, jday).

6. **Station count consistency**: Number of files listed in pcp.cli = number of .pcp files in TxtInOut.

## Common Pitfalls

> **PITFALL**: Solar radiation in W/m2 instead of MJ/m2/day
> CMFD provides instantaneous W/m2. SWAT+ expects daily total MJ/m2/day. Forgetting the conversion (multiply by 0.0864 for daily average) gives radiation ~12x too high. The model still runs but ET is massively overestimated.
> **Do this instead**: Convert W/m2 to MJ/m2/day: daily_MJ = daily_mean_W * 86400 / 1e6.
> See diagnostic triplet dt_012.

> **PITFALL**: Relative humidity as percentage instead of fraction
> SWAT+ expects RH as a fraction (0-1). Providing percentage values (0-100) makes RH = 60.0, which SWAT+ may interpret as 6000%. Silent error.
> **Do this instead**: Divide percentage values by 100.

> **PITFALL**: Missing wgn.wgn weather generator file
> Even with complete observed weather data, SWAT+ reads wgn.wgn at initialization. If missing, the simulation crashes immediately.
> **Do this instead**: Always generate wgn.wgn, even if weather data has no gaps.

> **PITFALL**: Wrong number of header lines in weather files
> SWAT+ expects exactly 3 header lines. Extra blank lines or missing headers cause data parsing to shift by N rows, reading header text as numbers.
> See diagnostic triplet dt_002.

---

*This skill document is part of the SWAT+ knowledge infrastructure.*
*Stage 3 of 9 | Tools used: prepare_weather_files, generate_weather_stations, validate_weather_data | Related triplets: dt_002, dt_003, dt_012*

Files in this skill

  • REFERENCES.md1.6 KB
  • format_spec.yaml72.1 KB
  • model_couplings.yaml11.8 KB
  • papers.json7 KB
  • s1_watershed_delineation_skill.md6.7 KB
  • s2_hru_definition_skill.md5.5 KB
  • s3_weather_preparation_skill.md8.9 KB
  • s4_soil_database_skill.md5.8 KB
  • s5_landuse_management_skill.md6 KB
  • s6_calibration_parameters_skill.md6.5 KB
  • s7_simulation_config_skill.md8.5 KB
  • s8_model_execution_skill.md5.1 KB
  • s9_output_parsing_skill.md7 KB
  • validation_convention.yaml21.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…