| """ |
| Karnataka Grid Scenarios |
| ======================== |
| Generates difficulty variants of the Karnataka 15-bus grid. |
| Same topology (KPTCL transmission map), different operating conditions. |
| |
| Scenarios vary: |
| - Renewable penetration (solar/wind max_p) |
| - Load magnitude (base_p multiplier) |
| - Line capacity (tighter or relaxed limits) |
| - Battery capacity |
| """ |
|
|
| import copy |
| from typing import Dict |
|
|
| from src.tasks import generate_karnataka_task |
|
|
| __all__ = ['generate_karnataka_scenario', 'KARNATAKA_SCENARIOS'] |
|
|
|
|
| |
| _DIFFICULTY_PROFILES = { |
| "easy": { |
| "description": "Low renewables, light load, relaxed lines", |
| "renewable_multiplier": 0.3, |
| "load_multiplier": 0.6, |
| "line_capacity_multiplier": 1.5, |
| "battery_capacity_multiplier": 1.5, |
| "max_steps": 50, |
| }, |
| "medium": { |
| "description": "Moderate renewables, normal load, standard lines", |
| "renewable_multiplier": 0.7, |
| "load_multiplier": 1.0, |
| "line_capacity_multiplier": 1.0, |
| "battery_capacity_multiplier": 1.0, |
| "max_steps": 50, |
| }, |
| "hard": { |
| "description": "High renewables, peak demand, tight lines", |
| "renewable_multiplier": 1.3, |
| "load_multiplier": 1.4, |
| "line_capacity_multiplier": 0.75, |
| "battery_capacity_multiplier": 0.7, |
| "max_steps": 50, |
| }, |
| } |
|
|
|
|
| def generate_karnataka_scenario(difficulty: str, seed: int = 808) -> Dict: |
| """Generate a Karnataka grid scenario at a given difficulty level. |
| |
| The base topology (15 buses, 18 lines, 4 zones) is identical across |
| all difficulties. Only the operating conditions change: |
| - Renewable generation capacity (solar/wind max_p) |
| - Load demand (base_p on load buses) |
| - Transmission line capacity |
| - Battery storage capacity |
| |
| This enables curriculum learning on a consistent grid structure. |
| """ |
| if difficulty not in _DIFFICULTY_PROFILES: |
| raise ValueError( |
| f"Unknown difficulty '{difficulty}'. " |
| f"Available: {list(_DIFFICULTY_PROFILES.keys())}" |
| ) |
|
|
| profile = _DIFFICULTY_PROFILES[difficulty] |
| base = generate_karnataka_task(seed=seed) |
|
|
| |
| for bus in base["buses"]: |
| bus_type = bus["type"] |
|
|
| if bus_type in ("solar", "wind"): |
| bus["max_p"] = round(bus["max_p"] * profile["renewable_multiplier"], 1) |
|
|
| elif bus_type == "load": |
| bus["base_p"] = round(bus["base_p"] * profile["load_multiplier"], 1) |
|
|
| elif bus_type == "battery": |
| bus["max_p"] = round(bus["max_p"] * profile["battery_capacity_multiplier"], 1) |
| bus["capacity"] = round(bus["capacity"] * profile["battery_capacity_multiplier"], 1) |
| bus["init_soc"] = round(bus["capacity"] * 0.5, 1) |
|
|
| elif bus_type == "slack": |
| |
| total_load = sum( |
| b["base_p"] * (profile["load_multiplier"] if b["type"] == "load" else 1.0) |
| for b in base["buses"] if b["type"] == "load" |
| ) |
| bus["max_p"] = max(200, round(total_load * 0.8, 1)) |
| bus["min_p"] = -bus["max_p"] |
|
|
| |
| for line in base["lines"]: |
| line["capacity"] = round(line["capacity"] * profile["line_capacity_multiplier"], 1) |
|
|
| |
| base["id"] = f"karnataka_{difficulty}" |
| base["difficulty"] = f"karnataka_{difficulty}" |
| base["max_steps"] = profile["max_steps"] |
| base["scenario_description"] = profile["description"] |
|
|
| return base |
|
|
|
|
| |
| KARNATAKA_SCENARIOS = { |
| f"karnataka_{diff}": generate_karnataka_scenario(diff) |
| for diff in _DIFFICULTY_PROFILES |
| } |
|
|