| """ | |
| SIH26077 — Centralized Configuration | |
| ===================================== | |
| Single source of truth for all paths, hyperparameters, thresholds, | |
| and normalization statistics used across the entire pipeline. | |
| """ | |
| import os | |
| import torch | |
| # ============================================================ | |
| # Paths | |
| # ============================================================ | |
| PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) | |
| # Dataset | |
| DATASET_ROOT = os.path.join(PROJECT_ROOT, "dataset_root") | |
| INDEX_PATH = os.path.join(DATASET_ROOT, "window_index.json") | |
| DEM_PATH = os.path.join(DATASET_ROOT, "dem", "cartodem.tif") | |
| # Output | |
| CHECKPOINT_DIR = os.path.join(PROJECT_ROOT, "checkpoints") | |
| OUTPUT_DIR = os.path.join(PROJECT_ROOT, "output") | |
| CHECKPOINT_PATH = os.path.join(CHECKPOINT_DIR, "best_model.pth") | |
| os.makedirs(CHECKPOINT_DIR, exist_ok=True) | |
| os.makedirs(OUTPUT_DIR, exist_ok=True) | |
| # ============================================================ | |
| # Device | |
| # ============================================================ | |
| DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu') | |
| # Enable TF32 Tensor Cores — CRITICAL for RTX 50-series/40-series Blackwell/Ada | |
| # Without this, matmul runs in full FP32, wasting ~3x compute on the Tensor Cores. | |
| if torch.cuda.is_available(): | |
| torch.set_float32_matmul_precision('high') | |
| torch.backends.cuda.matmul.allow_tf32 = True | |
| torch.backends.cudnn.allow_tf32 = True | |
| torch.backends.cudnn.benchmark = True # cuDNN auto-tunes conv kernels per input size | |
| # ============================================================ | |
| # Data | |
| # ============================================================ | |
| GRID_SIZE = (256, 256) # Unified spatial grid (H, W) | |
| LEAD_TIMES = ['2', '3', '4', '5', '6'] | |
| DEFAULT_LEAD_TIME = '3' # 3-hour prediction window | |
| # IMDAA variables per timestep (5 variables × 6 pressure levels = 30 channels) | |
| # Variables: HGT, RH, TMP, UGRD, VGRD | |
| # Levels: 1000, 300, 500, 700, 850, 925 hPa | |
| IMDAA_CHANNELS = 30 | |
| IMDAA_TIMESTEPS = 6 | |
| # INSAT channels: WV (L1B), CTT (L2B_CTP), HEM (L2B_HEM) | |
| INSAT_CHANNELS = 3 | |
| INSAT_TIMESTEPS = 6 | |
| # Terrain: Elevation + Slope | |
| TERRAIN_CHANNELS = 2 | |
| # Target: Cloudburst, Thunderstorm, Flash Flood | |
| NUM_TARGETS = 3 | |
| TARGET_NAMES = ['Cloudburst', 'Thunderstorm', 'Flash Flood'] | |
| # ============================================================ | |
| # Normalization Statistics (channel-wise mean/std) | |
| # ============================================================ | |
| # Channel ordering (after timestamp-based grouping in data_loader): | |
| # ch[00-05] HGT at 1000, 300, 500, 700, 850, 925 hPa (geopotential height, m) | |
| # ch[06-11] RH at 1000, 300, 500, 700, 850, 925 hPa (relative humidity, %) | |
| # ch[12-17] TMP at 1000, 300, 500, 700, 850, 925 hPa (temperature, K) | |
| # ch[18-23] UGRD at 1000, 300, 500, 700, 850, 925 hPa (u-wind, m/s) | |
| # ch[24-29] VGRD at 1000, 300, 500, 700, 850, 925 hPa (v-wind, m/s) | |
| # | |
| # Values computed empirically from windows 0, 22, 44 using correct | |
| # timestamp-grouped IMDAA files. Pressure levels sort alphabetically: | |
| # 1000 < 300 < 500 < 700 < 850 < 925 mb (by leading digit). | |
| IMDAA_MEAN = torch.tensor([ | |
| # HGT (geopotential height, m): 1000, 300, 500, 700, 850, 925 hPa | |
| 68.10, 9454.68, 5721.24, 3065.77, 1457.89, 739.89, | |
| # RH (relative humidity, %): 1000, 300, 500, 700, 850, 925 hPa | |
| 64.14, 35.49, 44.89, 55.46, 60.53, 64.67, | |
| # TMP (temperature, K): 1000, 300, 500, 700, 850, 925 hPa | |
| 294.63, 237.24, 261.38, 276.90, 286.31, 290.23, | |
| # UGRD (u-wind, m/s): 1000, 300, 500, 700, 850, 925 hPa | |
| -0.13, -1.27, 0.28, 1.02, 0.68, 0.35, | |
| # VGRD (v-wind, m/s): 1000, 300, 500, 700, 850, 925 hPa | |
| 1.87, -0.49, -0.70, -0.16, 0.85, 1.86, | |
| ]).view(30, 1, 1, 1) | |
| IMDAA_STD = torch.tensor([ | |
| # HGT | |
| 54.39, 1525.39, 922.82, 495.01, 238.00, 127.57, | |
| # RH | |
| 25.87, 25.38, 29.89, 25.18, 26.01, 28.10, | |
| # TMP | |
| 47.76, 38.35, 42.21, 44.76, 46.38, 47.07, | |
| # UGRD | |
| 4.83, 11.51, 5.78, 4.97, 6.44, 6.32, | |
| # VGRD | |
| 3.87, 7.33, 4.51, 3.99, 4.38, 4.73, | |
| ]).view(30, 1, 1, 1) | |
| # INSAT channels: WV (raw counts ~700-1000), CTT (~180-320 K), HEM (0-257 mm/30min), CTT_RATE (K/step) | |
| # CTT_RATE: frame-to-frame CTT difference. Mean≈0 (as many warming as cooling steps), | |
| # Std≈5K/step during active monsoon convection. | |
| INSAT_MEAN = torch.tensor([900.0, 265.0, 2.5, 0.0]).view(4, 1, 1, 1) | |
| INSAT_STD = torch.tensor([ 80.0, 30.0, 5.0, 5.0]).view(4, 1, 1, 1) | |
| # Terrain: Elevation (~0-7000 m), Slope (~0-60 deg) | |
| TERRAIN_MEAN = torch.tensor([2500.0, 10.0]).view(2, 1, 1) | |
| TERRAIN_STD = torch.tensor([2000.0, 12.0]).view(2, 1, 1) | |
| # ============================================================ | |
| # Training Hyperparameters (Optimized for RTX 5080 Laptop, 4-5 hr run) | |
| # ============================================================ | |
| BATCH_SIZE = 4 | |
| EPOCHS = 400 | |
| LEARNING_RATE = 1e-4 # Higher than before — needed to break CB/FF out of zero | |
| WEIGHT_DECAY = 1e-3 | |
| NUM_WORKERS = 0 | |
| TRAIN_SPLIT = 0.8 | |
| GRAD_ACCUM_STEPS = 8 | |
| EARLY_STOP_PATIENCE = 50 # More patience — Focal Loss trains slower initially | |
| # Class imbalance weights for BCE loss | |
| # Updated after switching CB labels to HEM (2816x2805 resolution): | |
| # CB: HEM gives ~200 positive pixels/window (vs 25 from GPI) → imbalance ~300:1 → pos_weight=50 | |
| # TS: ~430 positive pixels (~0.66%) → pos_weight=3 | |
| # FF: regenerated slope-mask labels, ~47 positive pixels → pos_weight=80 | |
| POS_WEIGHTS = torch.tensor([50.0, 3.0, 80.0]) | |
| # ============================================================ | |
| # Alert Thresholds | |
| # ============================================================ | |
| ALERT_THRESHOLDS = { | |
| 'WATCH': 0.3, # Probability > 30% | |
| 'WARNING': 0.5, # Probability > 50% | |
| 'EMERGENCY': 0.7, # Probability > 70% | |
| } | |
| # From label_config.json — thresholds used for generating weak labels | |
| LABEL_THRESHOLDS = { | |
| 'QPE_CLOUDBURST_THRESH_MM': 50.0, | |
| 'CTT_THUNDERSTORM_THRESH_K': 208.15, | |
| 'CAPE_THUNDERSTORM_THRESH': 1500.0, | |
| } | |
| # ============================================================ | |
| # Dashboard / Map | |
| # ============================================================ | |
| MAP_BOUNDS = [[29.0, 76.0], [33.0, 81.0]] # Himachal/Uttarakhand | |
| MAP_CENTER = [31.0, 78.5] | |