# PA3 Technical Report: Bias Correction and Stacking Ensemble for Monthly S2S/Seasonal Forecast Fields

## 1. Mục tiêu

PA3 được thiết kế để thử nghiệm và đánh giá hệ thống bias correction (BC) cho hai biến mục tiêu:

- `pr_o`: lượng mưa tháng quan trắc, đơn vị `mm/month`.
- `t2_o`: nhiệt độ trung bình 2 m tháng quan trắc, đơn vị `°C`.

Các trường dự báo đầu vào gồm hai nguồn mô hình khu vực:

- `RegCM`
- `clWRF`

với các hạn dự báo:

- `lead1` đến `lead6`.

Mục tiêu kỹ thuật của PA3 là:

1. Giữ các mô hình BC riêng cho từng nguồn mô hình (`RegCM`, `clWRF`) làm cơ sở so sánh.
2. Sử dụng Ridge Regression làm benchmark chính vì các thử nghiệm PA2 cho thấy Ridge ổn định nhất.
3. Tiếp tục thử nghiệm các cấu hình XGBoost và ANN/MLP.
4. Thêm stacking ensemble với ba nhóm:
   - `within_RegCM`: stacking chỉ từ các BC models của RegCM.
   - `within_clWRF`: stacking chỉ từ các BC models của clWRF.
   - `multi_source`: stacking kết hợp cả RegCM và clWRF.
5. Dùng year-blocked K-fold cross-validation trong giai đoạn training để tạo out-of-fold predictions cho stacking, tránh rò rỉ thông tin từ test period.
6. Tạo báo cáo HTML tự động, trong đó có bảng hyperparameter, bảng ranking, so sánh stacking với individual models, và các bảng/hình đánh giá.

## 2. Quy ước dữ liệu

Các file đầu vào có dạng:

```text
lead{lead}_{source_model}_01_BL_Test_VN.nc
```

Ví dụ:

```text
lead6_RegCM_01_BL_Test_VN.nc
lead6_clWRF_01_BL_Test_VN.nc
```

Các chiều dữ liệu:

```text
mon = 480
lat = 68
lon = 40
```

Quy ước thời gian:

```text
mon = 1   -> 1982-01
mon = 2   -> 1982-02
...
mon = 480 -> 2021-12
```

`lead1..lead6` là hạn dự báo theo tháng. Trục `mon` là tháng mục tiêu/dự báo, không phải tháng khởi tạo.

Ví dụ:

```text
init = 1982-01, lead1 -> lưu tại mon=2, tức 1982-02
init = 1982-01, lead6 -> lưu tại mon=7, tức 1982-07
```

File mask:

```text
Mask_VN_0.25_Corrected.nc
```

có biến:

```text
reg(lat, lon)
```

với quy ước:

```text
reg = 1..7 -> R1..R7
reg = -99  -> ngoài vùng khí hậu / missing
```

## 3. Biến mục tiêu và predictors

### 3.1. Biến quan trắc

```text
pr_o : observed monthly precipitation, mm/month
t2_o : observed monthly 2-m temperature, °C
```

### 3.2. Biến mô hình

Các biến mô hình gồm:

```text
pr, t2, tx, tm,
h500, h850, olr, q2, rh2, slp,
u200, u850, w700
```

Trong đó `w700` được hiểu là vertical velocity at 700 mb level.

## 4. Công thức bias correction

PA3 sử dụng phương pháp **monthly anomaly-to-anomaly mapping**.

Với mỗi biến mô hình `x` và tháng lịch `m`, climatology được tính từ training period:

```text
clim_x(m, lat, lon) = mean[x(year, m, lat, lon)] over training years
```

Với target quan trắc `y_o`:

```text
clim_y_o(m, lat, lon) = mean[y_o(year, m, lat, lon)] over training years
```

Anomaly mô hình:

```text
x'(t, lat, lon) = x(t, lat, lon) - clim_x(month(t), lat, lon)
```

Anomaly quan trắc:

```text
y_o'(t, lat, lon) = y_o(t, lat, lon) - clim_y_o(month(t), lat, lon)
```

Mô hình ML học ánh xạ:

```text
X_model_anomaly -> y_observed_anomaly
```

Sau khi dự báo anomaly, hoàn nguyên về giá trị gốc:

```text
y_BC(t, lat, lon) = y_predicted_anomaly(t, lat, lon) + clim_y_o(month(t), lat, lon)
```

Với lượng mưa:

```text
pr_BC = max(pr_BC, 0)
```

## 5. Training/test split

PA3 giữ test period độc lập:

```text
Training period: 1982-2013
Test period    : 2014-2021
```

Tất cả metrics cuối cùng được tính trên test period `2014-2021`.

Climatology được tính **chỉ từ training period**. Không dùng dữ liệu test để tính climatology, scaler, model hay meta-model.

## 6. Individual BC models

Các mô hình cá thể được chạy riêng cho từng:

```text
source_model × lead × target × spatial_mode × predictor_set × method
```

Trong đó:

```text
source_model = RegCM, clWRF
lead = 1..6
target = pr_o, t2_o
spatial_mode = regional, national
predictor_set = P2, P4
```

Các method gồm:

```text
raw
ridge
xgb_d2
xgb_d3
xgb_d4
xgb_slow
xgb_regularized
mlp_small
mlp_medium
mlp_deep
ann_tanh
ann_lbfgs
```

`raw` là dự báo thô, không hiệu chỉnh.

## 7. Predictor sets

### 7.1. P2

P2 sử dụng biến mô hình trực tiếp tương ứng với target, cộng với thông tin không gian nếu bật trong cấu hình.

Với `pr_o`:

```text
pr anomaly + lat + lon + reg (nếu national)
```

Với `t2_o`:

```text
t2 anomaly + lat + lon + reg (nếu national)
```

### 7.2. P4

P4 là predictor set vật lý chọn lọc.

Với `pr_o`:

```text
pr, olr, q2, rh2, slp, u850, w700, h500, h850
```

Với `t2_o`:

```text
t2, tx, tm, h500, h850, slp, q2, rh2, olr
```

Tất cả biến mô hình trong P2/P4 đều được đưa vào ML dưới dạng anomaly theo monthly training climatology.

## 8. Stacking ensemble approach

### 8.1. Ý tưởng

Stacking ensemble có hai tầng:

1. Base models: các mô hình BC cá thể như Ridge, XGBoost, MLP/ANN.
2. Meta-model: học cách kết hợp các prediction từ base models để dự báo observed anomaly.

Công thức tổng quát:

```text
pred_base_1, pred_base_2, ..., pred_base_K -> observed anomaly
```

Trong PA3, base predictions được tạo ở dạng anomaly. Sau khi meta-model dự báo anomaly cuối cùng, kết quả được cộng lại observed training climatology để về original unit.

### 8.2. Ba stacking scopes

PA3 tạo ba loại stacking:

```text
within_RegCM
within_clWRF
multi_source
```

`within_RegCM` sử dụng base predictions chỉ từ RegCM.

`within_clWRF` sử dụng base predictions chỉ từ clWRF.

`multi_source` sử dụng base predictions từ cả RegCM và clWRF. Đây là multi-model stacking ensemble cuối cùng.

### 8.3. Base models cho stacking

Mặc định:

```text
ridge
xgb_d2
xgb_regularized
mlp_small
ann_tanh
```

và predictor sets:

```text
P2, P4
```

Với `multi_source`, số base members mặc định là:

```text
2 source_models × 2 predictor_sets × 5 base_methods = 20 base predictions
```

### 8.4. Meta-models

PA3 thử các meta-models:

```text
stack_mean
stack_ridge
stack_elasticnet
stack_nnls
```

Ý nghĩa:

- `stack_mean`: trung bình đơn giản các base predictions.
- `stack_ridge`: Ridge Regression ở tầng meta.
- `stack_elasticnet`: ElasticNet ở tầng meta.
- `stack_nnls`: linear regression với hệ số không âm.

### 8.5. Tránh leakage bằng year-blocked K-fold

Vì chuỗi thời gian ngắn, PA3 không tách riêng một meta-training period cố định. Thay vào đó, trong training period `1982-2013`, PA3 dùng year-blocked K-fold.

Mặc định:

```text
K = 8
```

Quy trình:

1. Chia 32 năm training thành 8 folds theo năm, mỗi fold khoảng 4 năm.
2. Với mỗi fold:
   - train base models trên 7 folds còn lại;
   - predict fold bị bỏ ra;
   - lưu out-of-fold predictions.
3. Ghép out-of-fold predictions cho toàn bộ `1982-2013`.
4. Train meta-model trên out-of-fold predictions và observed anomaly.
5. Refit base models trên toàn bộ `1982-2013`.
6. Predict `2014-2021` bằng base models đã refit.
7. Dùng meta-model để tạo stacked prediction trên `2014-2021`.
8. Đánh giá stacking trên test period `2014-2021`.

Cách này đảm bảo meta-model không học từ predictions được tạo bởi base models đã thấy chính samples đó.

## 9. Metrics

### 9.1. Lượng mưa `pr_o`

Metrics chính:

```text
RMAE_percent (%)
CORR
```

Metrics phụ:

```text
MAE
RMSE
BIAS
```

RMAE được định nghĩa dạng tổng:

```text
RMAE = sum(|prediction - observation|) / sum(observation) × 100%
```

### 9.2. Nhiệt độ `t2_o`

Metrics chính:

```text
MAE (°C)
RMSE (°C)
CORR
```

Không dùng RMAE cho `t2_o` trong report PA3.

## 10. Output files

Sau khi chạy xong, các output chính gồm:

```text
outputs/metrics/summary_all.csv
outputs/metrics/summary_weighted_domain.csv
outputs/metrics/best_vs_raw.csv
outputs/metrics/best_per_source_lead.csv
outputs/metrics/best_by_method.csv
outputs/metrics/method_ranking.csv
outputs/metrics/stacking_vs_individual.csv
outputs/metrics/method_hyperparameters.csv
outputs/metrics/stack_weights_all.csv
outputs/report/index.html
```

Các file NetCDF dự báo hiệu chỉnh:

```text
outputs/corrected/pred_*.nc
```

Trong PA3 hiện tại, `pred_*.nc` lưu test period `2014-2021` để phục vụ đánh giá. Phiên bản sản phẩm nghiệp vụ sau này có thể mở rộng để xuất toàn chuỗi `1982-2021` hoặc real-time forecast.

## 11. Cấu trúc chương trình

```text
bc_ml_project_pa3_stacking_report/
├── config/
│   └── experiment.yaml
├── scripts/
│   ├── 00_make_tasks.py
│   ├── 00_make_stack_tasks.py
│   ├── 01_run_task.py
│   ├── 02_collect_summary.py
│   ├── 03_analyze_results.py
│   ├── 04_run_stack_task.py
│   ├── run_all_local.py
│   ├── run_slurm_array.sbatch
│   ├── setup_env_login.sh
│   └── check_env.py
├── src/
│   ├── data_utils.py
│   ├── features.py
│   ├── metrics.py
│   ├── models.py
│   ├── stacking_eval.py
│   ├── train_eval.py
│   └── plotting.py
├── TECHNICAL_REPORT_PA3.md
├── README.md
└── requirements.txt
```

## 12. Cách chạy trên HPC

### 12.1. Cài môi trường Python một lần

```bash
bash scripts/setup_env_login.sh
venv_bcml/bin/python scripts/check_env.py
```

Nếu môi trường đã có từ lần trước và kiểm tra OK, không cần cài lại.

### 12.2. Chạy bằng SLURM

Sửa số node trong:

```bash
scripts/run_slurm_array.sbatch
```

Ví dụ 1 node:

```bash
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=20
```

Ví dụ 2 node:

```bash
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=20
```

Submit:

```bash
sbatch scripts/run_slurm_array.sbatch
```

Script sẽ tự chạy:

1. individual BC tasks;
2. stacking tasks;
3. collect summaries;
4. generate HTML report.

## 13. Diễn giải kết quả cần xem trong report

Trong `outputs/report/index.html`, cần xem các phần sau:

1. `Model hyperparameters`: liệt kê hyperparameters của từng method.
2. `Best correction vs RAW`: kiểm tra mức cải thiện so với dự báo thô.
3. `Method ranking`: xem Ridge, XGB, MLP/ANN và stacking xếp hạng thế nào.
4. `Stacking vs individual models`: kiểm tra stacking có vượt best individual model hay không.
5. `Stacking weights`: xem meta-model dùng RegCM/clWRF và các base models với trọng số thế nào.
6. `Top configurations`: xem cấu hình tốt nhất cho từng target/metric.

## 14. Lưu ý cho real-time application

Để áp dụng real-time, cần lưu và dùng lại:

1. training-period model climatology cho tất cả predictors;
2. training-period observed climatology cho targets;
3. scaler của Ridge/MLP/ANN nếu có;
4. trained base models;
5. trained meta-model nếu dùng stacking;
6. danh sách base features và thứ tự base models trong stacking.

Real-time workflow sẽ là:

```text
raw real-time forecast
-> subtract model training climatology
-> predict observed anomaly with base models
-> combine base predictions with meta-model if stacking
-> add observed training climatology
-> clip precipitation to >= 0
-> write BC forecast NetCDF
```

Phiên bản PA3 tập trung vào training/evaluation. Phiên bản sau có thể tách riêng `train_eval` và `realtime_apply`.
