Haldwani Solar P-CAST — DualStreamCAST Transformer
Physics-Informed Dual-Stream Cross-Attention Solar Transformer
24-hour ahead Global Horizontal Irradiance (GHI) forecasting for the Haldwani microgrid, Uttarakhand, India. The model fuses observed meteorological telemetry with NWP forecast data through a cross-attention mechanism, and enforces physical consistency by predicting a clearness index bounded by deterministic clear-sky irradiance.
Forecast Results
The plots below show 24-hour ahead GHI predictions against ground-truth telemetry across five consecutive days in August 2026, covering a range of atmospheric conditions — clear sky, partial cloud, and heavy overcast.

MAE range: 7.98 – 28.57 W/m² | RMSE range: 14.33 – 61.40 W/m²
The model captures diurnal shape with high fidelity on clear and partially cloudy days. Error increases on heavily overcast days (2026-08-14), consistent with the inherent unpredictability of convective cloud systems.
Overview
| Property | Value |
|---|---|
| Task | Short-range solar irradiance forecasting |
| Target | Global Horizontal Irradiance — GHI (W/m²) |
| Horizon | 24 hours ahead at 1-hour resolution |
| Location | Haldwani, Uttarakhand · 29.2183° N, 79.5130° E · ~424 m asl |
| Climate | Sub-Himalayan foothill: distinct monsoon, winter fog, clear summer |
| Parameters | ~233K trainable |
| Framework | PyTorch 2.3 |
| Frontend | Streamlit (app.py included in this repository) |
Architecture
DualStreamCAST processes two temporally aligned sequences in parallel encoder streams. A cross-attention bridge lets the future NWP stream query the past observed stream, enabling the model to learn how current atmospheric state modulates the reliability of numerical forecast fields. The output head predicts a clearness index Kc ∈ [0, 1], which is then multiplied by a deterministic clear-sky estimate to produce a physically bounded GHI forecast.
┌──────────────────────────────────┐ ┌──────────────────────────────────┐
│ Past Stream [B, 24, 11] │ │ Future Stream [B, 24, 8] │
│ 24h observed telemetry │ │ 24h NWP forecast fields │
└──────────────┬───────────────────┘ └───────────────┬──────────────────┘
│ Linear(11 → 64) │ Linear(8 → 64)
│ PositionalEncoding │ PositionalEncoding
│ TransformerEncoder ×2 │ TransformerEncoder ×2
│ nhead=4, FFN=256 │ nhead=4, FFN=256
│ p_out [B, 24, 64] │ f_out [B, 24, 64]
└──────────────┐ ┌───────────────────┘
▼ ▼
MultiheadAttention
query = f_out
key = p_out
value = p_out
│
LayerNorm( f_out + attn_out ) → fused [B, 24, 64]
│
Concat( f_out ‖ fused ) → [B, 24, 128]
│
Linear(128 → 64) → ReLU → Dropout(0.1)
Linear(64 → 1) → Sigmoid
│
Kc [B, 24] clearness index ∈ [0, 1]
│
Kc × GHI_clearsky → GHI_pred [B, 24] W/m²
GHI_pred = 0 when GHI_clearsky < 10 W/m² (night guard)
Design Rationale
- Dual-stream encoding — past observations and future forecasts have different statistical distributions and temporal semantics; separate encoders allow each stream to develop specialised representations before fusion.
- Cross-attention bridge — by making NWP features the query and observed history the key/value, the model learns to selectively trust or discount forecast fields based on recent atmospheric state.
- Physics-informed output — predicting Kc rather than raw GHI anchors the model to solar geometry. This prevents physically impossible predictions (GHI > clear-sky maximum) and improves generalisation across seasons.
Hyperparameters
| Parameter | Value |
|---|---|
d_model | 64 |
nhead | 4 |
num_layers | 2 |
dim_feedforward | 256 |
past_dim | 11 |
future_dim | 8 |
| Dropout | 0.1 |
| Sequence length | 24 steps (hourly) |
| Activation (head) | Sigmoid |
Input Features
Past stream — 11 features (24h observed)
| Feature | Description | Unit |
|---|---|---|
| GHI | Global Horizontal Irradiance | W/m² |
| DNI | Direct Normal Irradiance | W/m² |
| DHI | Diffuse Horizontal Irradiance | W/m² |
| temperature_2m | Air temperature at 2 m | °C |
| relative_humidity_2m | Relative humidity at 2 m | % |
| surface_pressure | Surface atmospheric pressure | hPa |
| dew_point_2m | Dew point temperature | °C |
| cloud_cover | Total cloud cover | % |
| cloud_cover_low | Low-level cloud fraction | % |
| cloud_cover_mid | Mid-level cloud fraction | % |
| cloud_cover_high | High-level cloud fraction | % |
Future stream — 8 features (24h NWP forecast)
| Feature | Description | Unit |
|---|---|---|
| temperature_2m | Forecast air temperature | °C |
| relative_humidity_2m | Forecast relative humidity | % |
| surface_pressure | Forecast surface pressure | hPa |
| cloud_cover | Forecast total cloud cover | % |
| cloud_cover_low | Forecast low cloud fraction | % |
| cloud_cover_mid | Forecast mid cloud fraction | % |
| cloud_cover_high | Forecast high cloud fraction | % |
| GHI_clearsky | Deterministic clear-sky GHI | W/m² |
All features are standardised with a fitted sklearn.preprocessing.StandardScaler provided as scaler.pkl.
Repository Contents
| File | Description |
|---|---|
best_cast_model.pt | Trained model weights — PyTorch state_dict (~933 KB) |
scaler.pkl | Fitted StandardScaler for input normalisation |
app.py | Streamlit frontend — interactive 24h forecast dashboard |
plots.png | Evaluation plots across 5 days of August 2026 |
The Streamlit frontend (app.py) is a self-contained interactive dashboard. It fetches live weather data from Open-Meteo (no API key required), runs inference through the CAST model, and renders the forecast alongside an hourly breakdown table with error metrics. To run it locally, see the usage section below.
Usage
Clone the repository and run the Streamlit app. The weights are already in the expected weights/ subfolder — no extra setup required.
# 1. Clone
git clone https://huggingface.co/adityasuyal/haldwani-solar-cast
cd haldwani-solar-cast
# 2. Install dependencies
pip install streamlit torch numpy pandas scikit-learn joblib requests plotly pytz
# 3. Run
streamlit run app.py
The expected directory layout after cloning:
haldwani-solar-cast/
├── app.py
├── weights/
│ ├── best_cast_model.pt
│ └── scaler.pkl
└── plots.png
Data Source
Weather data is fetched at runtime from Open-Meteo — no API key required.
| API | Coverage | Used for |
|---|---|---|
| Forecast | ±16 days from today | Live and near-future inference |
| Archive | 1940 – present (−5 day lag) | Historical date exploration |
Clear-sky GHI is estimated as GHI_clearsky = TOA_irradiance × 0.75, where the 0.75 factor approximates mean atmospheric transmittance for the site's elevation and climatology.
Limitations
- Trained and evaluated exclusively on the Haldwani station. Fine-tuning is recommended before applying to stations with meaningfully different climatology.
- The clear-sky parameterisation (
TOA × 0.75) is a site-level approximation. Replacing it with a physical clear-sky model (e.g., Ineichen, REST2) would improve accuracy, particularly for high-aerosol or high-humidity conditions. - Forecast skill degrades under deep convective activity — inherently unpredictable at sub-mesoscale resolution.
Citation
APA
Suyal, A. (2024). DualStreamCAST: Physics-Informed Dual-Stream Cross-Attention Transformer for Solar Irradiance Forecasting. Hugging Face. Retrieved from https://huggingface.co/adityasuyal/haldwani-solar-cast
BibTeX
@misc{suyal2024castmodel,
author = {Aditya Suyal},
title = {DualStreamCAST: Physics-Informed Dual-Stream Cross-Attention Transformer for Solar Irradiance Forecasting},
year = {2024},
publisher = {Hugging Face},
url = {https://huggingface.co/adityasuyal/haldwani-solar-cast}
}
Developed for the Haldwani Microgrid System · CAST Transformer v2.4
adityasuyal · Uttarakhand, India