Spaces:
Sleeping
Sleeping
File size: 6,704 Bytes
479b6b0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | # EcoGrid-OpenEnv β Technical Specification
## 1. Overview
EcoGrid-OpenEnv is a production-grade Reinforcement Learning environment for the
OpenEnv framework that simulates sustainable energy grid management. An agent
controls energy distribution across renewable sources (solar + wind), fossil fuels,
and battery storage to meet variable demand while minimising cost and carbon emissions.
**Author:** Team DD
**Hackathon:** Scaler School of Technology Γ Meta PyTorch Finale
**Theme:** #3 β World Modeling (Professional Tasks) + Mercor Sub-theme
---
## 2. File Tree
```
eco-grid-openenv/
βββ env/
β βββ __init__.py # Package init, re-exports EcoGridEnv
β βββ environment.py # Core EcoGridEnv class (reset/step/state)
β βββ dynamics.py # Deterministic physics helpers (solar/wind/demand/battery)
β βββ reward.py # Multi-objective reward function
β βββ tasks.py # 3 task graders (easy/medium/hard)
βββ models/
β βββ __init__.py # Package init, re-exports all schemas
β βββ schemas.py # Pydantic v2 typed models
βββ tests/
β βββ test_environment.py # Environment unit tests
β βββ test_reward.py # Reward function tests
β βββ test_graders.py # Grader determinism tests
βββ docs/
β βββ SPEC.md # This file
βββ logs/ # Runtime logs (gitignored)
βββ lora_adapter/ # Trained LoRA weights (gitignored)
βββ openenv.yaml # OpenEnv specification file
βββ baseline.py # Heuristic + LLM inference script
βββ train_unsloth.py # Unsloth GRPO training script
βββ app.py # Streamlit dashboard for HF Spaces
βββ Dockerfile # Multi-stage production Dockerfile
βββ docker-compose.yml # Local dev compose config
βββ requirements.txt # Pinned Python dependencies
βββ README.md # Full hackathon README
βββ BLOG.md # HuggingFace blog post (β€400 words)
βββ .gitignore # Ignore logs/, lora_adapter/, __pycache__
```
---
## 3. State Space
| Field | Type | Range | Unit | Description |
|-------|------|-------|------|-------------|
| demand | float | [0, 200] | MWh | Energy demand this timestep |
| solar_capacity | float | [0, 1] | ratio | Available solar generation capacity |
| wind_capacity | float | [0, 1] | ratio | Available wind generation capacity |
| battery_level | float | [0, 1] | ratio | Battery state of charge |
| grid_stability | float | [0, 1] | ratio | Grid frequency stability indicator |
| carbon_budget_remaining | float | [0, 1000] | kgCOβ | Remaining carbon emission budget |
| price_signal | float | [0, 300] | $/MWh | Current spot electricity price |
| time_step | int | [0, 96] | step | Current simulation timestep |
---
## 4. Action Space
| Field | Type | Range | Constraint | Description |
|-------|------|-------|-----------|-------------|
| renewable_ratio | float | [0, 1] | sum β€ 1.0 | Fraction of demand met by renewables |
| fossil_ratio | float | [0, 1] | sum β€ 1.0 | Fraction of demand met by fossil fuels |
| battery_action | float | [-1, 1] | β | Charge (+1) or discharge (-1) battery |
**Constraint:** `renewable_ratio + fossil_ratio β€ 1.0`
The remaining fraction `1 - renewable_ratio - fossil_ratio` is unmet demand (blackout risk).
---
## 5. Reward Function
### Terms (summing to [0, 1])
| Term | Weight | Formula |
|------|--------|---------|
| cost_savings | 0.30 | `1 - normalised(fossil_cost + grid_cost)` |
| carbon_score | 0.30 | `1 - normalised(carbon_emission)` |
| stability_score | 0.25 | `1 - blackout_risk` |
| renewable_bonus | 0.15 | `renewable_ratio Γ (1 - blackout_risk)` |
### Penalties (subtracted before clip)
| Penalty | Trigger | Value |
|---------|---------|-------|
| blackout_penalty | demand unmet > 20% | -0.5 |
| carbon_overrun | carbon_budget < 0 (hard only) | -0.8 |
**Final:** `clip(weighted_sum - penalties, 0, 1)`
---
## 6. Task Specifications
### Easy: BasicGridBalance
- **Episode length:** 48 steps
- **Conditions:** Predictable solar (low noise), stable demand, no battery
- **Objective:** Minimise cost
- **Grader criteria:** avg_cost_reduction > 30%, no blackouts, avg_renewable_ratio > 0.5
- **Score:** total_reward / max_possible_reward
### Medium: RenewableVariability
- **Episode length:** 96 steps
- **Conditions:** Noisy solar+wind, demand spikes, small battery (capacity=0.3)
- **Objective:** Avoid blackouts while maintaining renewable usage
- **Grader criteria:** blackout_episodes < 3, avg_renewable_ratio > 0.6
- **Score:** 0.4Γ(renewable) + 0.4Γ(stability) + 0.2Γ(cost)
### Hard: CarbonConstrained
- **Episode length:** 96 steps
- **Conditions:** Strict carbon cap (500 kgCOβ), high volatility (2Γ noise), limited storage
- **Objective:** Never exceed carbon cap, maintain stability > 0.7
- **Grader criteria:** carbon_budget β₯ 0 at all steps, grid_stability > 0.7
- **Score:** 0 if any carbon overrun; else 0.5Γ(carbon) + 0.3Γ(cost) + 0.2Γ(stability)
---
## 7. Physics Model
All functions are **deterministic** given a seed (use `np.random.default_rng(seed)`).
### Solar Output
```
solar = 0.5 + 0.5 Γ sin(2Ο Γ time_step / 24) + noise Γ N(0, noise_level)
clamped to [0, 1]
```
### Wind Output
```
wind = random_walk(previous_wind, step_size=0.05) + noise Γ N(0, noise_level)
clamped to [0, 1]
```
### Demand Curve
```
base = 80 MWh
morning_peak = 30 Γ exp(-((t - 8)Β² / 8))
evening_peak = 40 Γ exp(-((t - 18)Β² / 8))
spike = random_spike_probability Γ spike_magnitude
demand = base + morning_peak + evening_peak + spike
```
### Battery
```
new_level = clamp(level + action Γ charge_rate, 0, 1)
```
### Carbon Emission
```
emission = fossil_ratio Γ demand Γ emission_factor (kg COβ/MWh)
```
---
## 8. Mercor Sub-theme
The reward function is designed so that **more tokens of agent reasoning correspond
to better reward scaling**. Specifically:
- Actions that consider multiple objectives (cost + carbon + stability) score higher
- Chain-of-thought prompts in baseline.py encourage structured reasoning
- GRPO training rewards longer, more considered outputs with higher task scores
---
## 9. Performance Targets
| Metric | Target |
|--------|--------|
| Episodes/second (numpy sim) | > 10,000 |
| Random baseline score (easy) | 0.15β0.25 |
| Heuristic baseline score (easy) | 0.68β0.74 |
| Trained agent score (easy) | 0.75β0.85 |
| Seed determinism | 100% reproducible |
|