AI-powered 4x super-resolution downscaling of ERA5 temperature reanalysis
data over India. Increases spatial resolution from 0.25° (28 km/px) to
0.0625° (7 km/px) using a Swin2SR ensemble with physics-aware improvements.
1. Ensemble — Two Swin2SR variants averaged pixel-by-pixel.
The realworld model handles texture; the classical model handles
clean bicubic degradation (closer to ERA5). Their average cancels
each model's noise while preserving genuine fine-scale structure.
Result: sharpness gain doubled from +10.8% to +21.3%.
2. Physics anomaly pre-processing — Subtract the ERA5 temporal
mean field before inference, add it back after. The model sees
temperature anomalies (~±2K) rather than absolute values (~250-310K).
This frees the model's attention capacity from reproducing the
large-scale India temperature gradient and focuses it on fine structure.
3. Elevation lapse rate correction — Apply a 6.5K/1000m lapse
rate correction post-inference using a DEM proxy derived from the
ERA5 mean field Laplacian. Fixes the known cold bias at Himalayan
and Western Ghats mountain edges. Correction range: -1.09K to +1.67K.
4. Land-sea mask — AI enhancement applied only to land pixels.
Ocean pixels (Bay of Bengal, Arabian Sea, Indian Ocean) are passed
through directly from ERA5. Swin2SR has no ocean knowledge and would
hallucinate fine-scale SST structure that doesn't exist physically.
Land: 7651/15609 pixels (49%) in the India bounding box.
Performance
Metric
Value
Live inference (first call)
~12,000ms (ensemble × 2 models)
Cached inference
~28ms
Sharpness gain vs bilinear
+21.3%
PSD gain @ 27km wavelength
+4.58 dB
RAM at runtime
~13-14GB (79-85% of 16.5GB)
CPU threads
12 logical (Ryzen 5 5600H)
Data
Source: ERA5 Reanalysis 2020, 2m Temperature (t2m)
Region: India (6°N–38°N, 68°E–98°E)
Period: 2020-01-01 to 2020-12-31, hourly (8784 timesteps)
File: data/raw/era5_real_2020-01-01_2020-12-31.nc
Note: this NetCDF file isn't bundled in this repo. To run ATMOS, bring your own — see below.
Bringing Your Own Data
This repo ships code only, not the data file. To test it, you need a NetCDF
file matching what the pipeline expects:
Path: save it as data/raw/era5_real_2020-01-01_2020-12-31.nc — that
exact filename is currently hardcoded in dashboard_backend/main.py
Using a different region or variable will also need matching changes in
config/default.yaml (region bounds) and dashboard_frontend/index.html
(the BOUNDS/CENTER constants), since the land-sea mask and elevation
correction are both built against this specific India grid.
Usage
.\run.bat
Opens http://127.0.0.1:8080 automatically.
To pre-compute all 8784 frames (optional, makes every frame instant):
Click the Build Cache button in the dashboard bottom bar.
Estimated time: ~2 hrs (2 workers) or ~1 hr (4 workers).
RAM during build: ~85%. CPU: ~90%.
Project Structure
project/
├── dashboard_backend/main.py FastAPI backend, all 4 improvements
├── dashboard_frontend/index.html ATMOS dashboard (Leaflet, Canvas)
├── src/models/downscaler.py Swin2SR ensemble + physics + elevation
├── src/models/land_mask.py Land-sea mask builder
├── src/data/netcdf_loader.py ERA5 NetCDF loader
├── src/data/preprocessor.py Z-score normalisation
├── checkpoints/swin2sr/ HuggingFace cached model weights (downloaded on first run, not bundled)
├── data/raw/ ERA5 NetCDF file
├── serve.py Local (Windows) entry point
└── run.bat Windows launcher