| from __future__ import annotations |
|
|
| from dataclasses import dataclass |
|
|
| from smartgrid_mas.models import DispatchAction, MarketObservation |
|
|
|
|
| @dataclass |
| class ReliabilityDispatchControlAgent: |
| """Reduced-order dispatcher that turns market state into corrective dispatch.""" |
|
|
| personality: str = "balanced" |
|
|
| def act(self, obs: MarketObservation, cleared_mwh: float) -> DispatchAction: |
| forecast_gap = max(0.0, obs.forecast_demand_mwh - obs.forecast_renewable_mwh) |
| actual_gap = max(0.0, obs.demand_mwh - obs.renewable_availability_mwh) |
| scarcity = max(0.0, obs.scarcity_index) |
| reserve_pressure = min(1.0, max(0.0, scarcity - 0.15)) |
|
|
| if self.personality == "risk_averse": |
| reserve_scale = 0.62 |
| peaker_scale = 1.08 |
| storage_scale = 0.82 |
| redispatch_scale = 0.38 |
| elif self.personality == "opportunistic": |
| reserve_scale = 0.34 |
| peaker_scale = 0.72 |
| storage_scale = 0.52 |
| redispatch_scale = 0.22 |
| else: |
| reserve_scale = 0.48 |
| peaker_scale = 0.92 |
| storage_scale = 0.68 |
| redispatch_scale = 0.30 |
|
|
| reserve_activation_mwh = max(0.0, forecast_gap * reserve_scale * (0.75 + 0.25 * reserve_pressure)) |
| peaker_adjustment_mwh = max(0.0, actual_gap * peaker_scale * (0.85 + 0.15 * reserve_pressure)) |
|
|
| storage_dispatch_mwh = 0.0 |
| if scarcity > 0.25: |
| storage_dispatch_mwh = min(obs.ev_storage_mwh, actual_gap * storage_scale) |
| elif obs.renewable_availability_mwh > obs.demand_mwh * 0.95: |
| storage_dispatch_mwh = -min( |
| max(0.0, obs.ev_storage_capacity_mwh - obs.ev_storage_mwh), |
| (obs.renewable_availability_mwh - obs.demand_mwh) * 0.25, |
| ) |
|
|
| corrective_redispatch_mwh = max(0.0, (cleared_mwh - obs.demand_mwh + actual_gap) * redispatch_scale) |
| if scarcity > 0.40: |
| corrective_redispatch_mwh += actual_gap * 0.20 |
| elif scarcity < 0.12: |
| corrective_redispatch_mwh -= min(corrective_redispatch_mwh, obs.demand_mwh * 0.03) |
|
|
| return DispatchAction( |
| reserve_activation_mwh=round(reserve_activation_mwh, 3), |
| peaker_adjustment_mwh=round(peaker_adjustment_mwh, 3), |
| storage_dispatch_mwh=round(storage_dispatch_mwh, 3), |
| corrective_redispatch_mwh=round(corrective_redispatch_mwh, 3), |
| ) |
|
|