Skip to content
Back to skills

Docs

ASecurity

> **Stage ID**: s3_apply_deltas > **Pipeline order**: 3 of 4 > **Depends on**: s2_compute_deltas (delta file), VIC baseline forcing (forcing_1d output)

  • 231 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 11, 2026
testingpythonbash

Works with

  • cli

Security analysis

A100/100

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

Scanned November 9, 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-33fcd36b/badge)](https://www.skillsdirectory.com/skills/lzwei196-docs-33fcd36b)

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
# Apply Deltas to VIC Forcing — Skill Document

> **Stage ID**: s3_apply_deltas
> **Pipeline order**: 3 of 4
> **Depends on**: s2_compute_deltas (delta file), VIC baseline forcing (forcing_1d output)

## Purpose

Generate future VIC forcing files by applying CMIP6 monthly climate change deltas to the existing CMFD/MSWX baseline forcing. This preserves the sub-daily variability and all 7 meteorological variables from the baseline while incorporating projected changes in temperature and precipitation.

## Prerequisites

Before starting this stage, verify:

- [ ] Delta file exists: `deltas/{MODEL}_{ssp}_deltas_{basin}_{period}.nc`
- [ ] Baseline forcing_1d files exist: `outputs/{basin}/vic_temp/forcing/forcing_1d/temp_*.nc`, `prec_*.nc`, etc.
- [ ] VIC grid file exists
- [ ] Python environment activated

## Inputs

| Input | Type | Source | Description |
|-------|------|--------|-------------|
| BASELINE_FORCING_DIR | directory | VIC workflow | `outputs/{basin}/vic_temp/forcing/forcing_1d/` |
| DELTA_FILE | file | Stage 2 | Monthly delta NetCDF file |
| GRID_NC | file | VIC grid | Basin grid file |
| TARGET_YEARS | year range | User choice | Years to generate forcing for |

## Procedure

### Step 1: Choose target period

The target period should match the FUTURE_PERIOD used in delta computation. For a 30-year window:

```
FUTURE_PERIOD = 2041-2070
```

The tool recycles baseline years to fill the target period. Leap and non-leap baseline years are cycled separately, in order: a leap target year takes the next leap baseline year (real Feb 29), a normal target year the next normal baseline year; within each leap-status group every baseline year is used before any is reused. Example: baseline 1990-2000 (leap: 1992, 1996, 2000; normal: the other 8) onto 2041-2044 gives 1990, 1991, 1993, 1992 (2044 is leap). So the baseline year order is not kept exactly. Only monthly forcing_1d files are accepted (annual files stop the tool). If the target period has a leap year but the baseline has none, the tool stops with an error (it does not invent Feb 29).

Baseline forcing_1d NetCDF units (CMFD / MSWX convention, required by both S3 tools): temp K, prec kg m-2 s-1, pres Pa, srad W m-2, lrad W m-2, shum kg kg-1 (specific humidity), wind m s-1, 3-hourly. Do not pre-convert to degC / mm / kPa; that happens in Step 3 (VIC ASCII output). All 7 variables and all three deltas (delta_pr, delta_tasmax, delta_tasmin) are required: a precipitation-only GCM or a missing baseline variable/month stops the tool with exit code 2.

### Step 2: Run delta application

```bash
python skills/climate-projection/tools/s3_apply_deltas/apply_deltas_forcing.py \
  outputs/{basin}/vic_temp/forcing/forcing_1d \
  outputs/{basin}/climate_projection/deltas/{MODEL}_{ssp}_deltas_{basin}_2041-2070.nc \
  outputs/{basin}/vic_temp/grid/basin_grid.nc \
  outputs/{basin}/climate_projection/forcing_{MODEL}_{ssp} \
  {basin} {MODEL} {ssp} \
  2041 2070
```

**Expected result**: 7 variables × 30 years = 210 NetCDF files in `forcing_{MODEL}_{ssp}/`

**Runtime**: 5-15 minutes (reads and rewrites all forcing files).

### Step 3: Convert projected forcing NC → VIC ASCII

Use the dedicated conversion tool (NOT `process_forcing.py`, which requires error-prone config editing):

```bash
python skills/climate-projection/tools/s3_apply_deltas/convert_projected_forcing.py \
  outputs/{basin}/climate_projection/forcing_{MODEL}_{ssp} \
  outputs/{basin}/climate_projection/forcing_final_{MODEL}_{ssp} \
  outputs/{basin}/vic_temp/soil/SOIL_PARAM_COMPLETE.txt \
  "{forcing_prefix}" "{basin_tag}" \
  2041 2070
```

Where:
- `{forcing_prefix}` matches the baseline prefix (e.g., `nuxia_0.25deg_`). Check with: `ls outputs/{basin}/vic_temp/forcing/forcing_final/ | head -1`
- `{basin_tag}` is the suffix used in NC filenames (usually the basin name from config_paths.py)

**Expected result**: One ASCII file per grid cell in `forcing_final_{MODEL}_{ssp}/`, each with 87,664 lines (30 years × 365.25 days × 8 timesteps/day). 7 columns: air_temp, prec, pressure, swdown, lwdown, vp, wind.

**Runtime**: ~2-5 minutes per SSP scenario.

### Step 4: Verify projected forcing

```bash
# Check file count matches grid cells
ls outputs/{basin}/climate_projection/forcing_final_{MODEL}_{ssp}/ | wc -l

# Check line count (should be ~87,664 for 30 years of 3-hourly data)
wc -l outputs/{basin}/climate_projection/forcing_final_{MODEL}_{ssp}/* | tail -1

# Spot-check temperature (should be in Celsius, not Kelvin)
head -3 outputs/{basin}/climate_projection/forcing_final_{MODEL}_{ssp}/*_30.0000_*
```

## Expected Outputs

| Output | Path | Verification |
|--------|------|--------------|
| Projected forcing NC | `forcing_{MODEL}_{ssp}/temp_*_{year}.nc` | One per variable per year |
| Projected forcing ASCII | `forcing_final_{MODEL}_{ssp}/` | One per grid cell, matching VIC format |

## Validation Checks

1. **Temperature increase**: Mean annual temperature in projected forcing > baseline
2. **Variable completeness**: All 7 variables present (not just temp and prec)
3. **No NaN values**: Projected forcing should have no gaps
4. **Non-negative precipitation**: All precip values >= 0 after multiplicative scaling

## Common Pitfalls

> **PITFALL**: Using `process_forcing.py` instead of `convert_projected_forcing.py`
> The old approach required editing hardcoded paths in `process_forcing.py` (INPUT_DATA_DIR, START_DATE, etc.) — error-prone and not reusable.
> **Do this instead**: Use `convert_projected_forcing.py` which takes all parameters as CLI arguments.
> See diagnostic triplet dt_cc_006.

> **PITFALL**: Time coordinate mismatch
> When cycling baseline years into future years, leap years must line up. apply_deltas_forcing.py now cycles leap and non-leap baseline years separately, so each target year gets a baseline year with the same leap status (Feb 29 is only dropped if the baseline has no non-leap year at all), and convert_projected_forcing.py stops if time steps are duplicated, missing or irregular.
> **Do this instead**: Use a baseline of at least 4 consecutive years (it then always contains both leap and non-leap years).

> **PITFALL**: Missing variables or NaN in projected forcing
> convert_projected_forcing.py needs all 7 variables with the NetCDF units above. It no longer fills missing variables or NaN with defaults: it stops with exit 1 (missing variable / wrong unit) or exit 2 (NaN cells, time gaps), and lists the failed cells.

---

*This skill document is part of the climate-projection knowledge infrastructure.*
*Stage 3 of 4 | Tools used: apply_deltas_forcing | Related triplets: dt_cc_006, dt_cc_007*

Files in this skill

  • REFERENCES.md2 KB
  • format_spec.yaml10.6 KB
  • papers.json6.8 KB
  • s1_extract_cmip_skill.md5.3 KB
  • s2_compute_deltas_skill.md4.4 KB
  • s3_apply_deltas_skill.md5 KB
  • s4_ensemble_analysis_skill.md5.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.

View all in testing →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.