watt-the-hack 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. watt_the_hack-0.2.0/LICENSE +21 -0
  2. watt_the_hack-0.2.0/PKG-INFO +145 -0
  3. watt_the_hack-0.2.0/README.md +125 -0
  4. watt_the_hack-0.2.0/pyproject.toml +42 -0
  5. watt_the_hack-0.2.0/setup.cfg +4 -0
  6. watt_the_hack-0.2.0/tests/test_engine.py +1591 -0
  7. watt_the_hack-0.2.0/tests/test_forecast.py +251 -0
  8. watt_the_hack-0.2.0/tests/test_metrics.py +190 -0
  9. watt_the_hack-0.2.0/tests/test_metrics_contract.py +175 -0
  10. watt_the_hack-0.2.0/tests/test_runner.py +67 -0
  11. watt_the_hack-0.2.0/watt_the_hack/__init__.py +1 -0
  12. watt_the_hack-0.2.0/watt_the_hack/api/__init__.py +1 -0
  13. watt_the_hack-0.2.0/watt_the_hack/api/sandbox.py +147 -0
  14. watt_the_hack-0.2.0/watt_the_hack/api/server.py +482 -0
  15. watt_the_hack-0.2.0/watt_the_hack/constants.py +11 -0
  16. watt_the_hack-0.2.0/watt_the_hack/controllers/__init__.py +11 -0
  17. watt_the_hack-0.2.0/watt_the_hack/controllers/parametric.py +40 -0
  18. watt_the_hack-0.2.0/watt_the_hack/controllers/rule_based.py +82 -0
  19. watt_the_hack-0.2.0/watt_the_hack/data_loaders/__init__.py +0 -0
  20. watt_the_hack-0.2.0/watt_the_hack/data_loaders/aemo.py +44 -0
  21. watt_the_hack-0.2.0/watt_the_hack/data_loaders/scenarios.py +472 -0
  22. watt_the_hack-0.2.0/watt_the_hack/engine/__init__.py +8 -0
  23. watt_the_hack-0.2.0/watt_the_hack/engine/base_engine.py +18 -0
  24. watt_the_hack-0.2.0/watt_the_hack/engine/engine.py +1584 -0
  25. watt_the_hack-0.2.0/watt_the_hack/engine/legacy engines/simple_engine.py +117 -0
  26. watt_the_hack-0.2.0/watt_the_hack/metrics/__init__.py +3 -0
  27. watt_the_hack-0.2.0/watt_the_hack/metrics/metrics.py +122 -0
  28. watt_the_hack-0.2.0/watt_the_hack/playtest.py +1099 -0
  29. watt_the_hack-0.2.0/watt_the_hack/scenarios/synthetic/agentic_demo.json +381 -0
  30. watt_the_hack-0.2.0/watt_the_hack/scenarios/synthetic/duck_curve.json +1023 -0
  31. watt_the_hack-0.2.0/watt_the_hack/simulation/__init__.py +1 -0
  32. watt_the_hack-0.2.0/watt_the_hack/simulation/boot.py +96 -0
  33. watt_the_hack-0.2.0/watt_the_hack/simulation/runner.py +265 -0
  34. watt_the_hack-0.2.0/watt_the_hack/simulation/strategy.py +190 -0
  35. watt_the_hack-0.2.0/watt_the_hack.egg-info/PKG-INFO +145 -0
  36. watt_the_hack-0.2.0/watt_the_hack.egg-info/SOURCES.txt +37 -0
  37. watt_the_hack-0.2.0/watt_the_hack.egg-info/dependency_links.txt +1 -0
  38. watt_the_hack-0.2.0/watt_the_hack.egg-info/requires.txt +14 -0
  39. watt_the_hack-0.2.0/watt_the_hack.egg-info/top_level.txt +1 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DeepNeuron / Watt The Hack contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.4
2
+ Name: watt-the-hack
3
+ Version: 0.2.0
4
+ Summary: Watt The Hack 24-hour energy grid simulation hackathon engine
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: pydantic>=2.0
9
+ Provides-Extra: api
10
+ Requires-Dist: fastapi; extra == "api"
11
+ Requires-Dist: uvicorn; extra == "api"
12
+ Requires-Dist: python-dotenv; extra == "api"
13
+ Provides-Extra: playtest
14
+ Requires-Dist: matplotlib>=3.5; extra == "playtest"
15
+ Requires-Dist: openai>=1.0; extra == "playtest"
16
+ Provides-Extra: test
17
+ Requires-Dist: pytest; extra == "test"
18
+ Requires-Dist: pytest-cov; extra == "test"
19
+ Dynamic: license-file
20
+
21
+ # Watt The Hack Engine
22
+
23
+ The simulation engine for the **Watt The Hack** energy grid hackathon (DeepNeuron).
24
+
25
+ This is the public engine package — controllers, scenarios authoring, and the judging server live in private repos. Participants use this package to develop and test their controllers locally before submitting to the hackathon evaluation server.
26
+
27
+ ## How it works
28
+
29
+ You write a **controller**. The engine runs a grid as a simulation in 15-minute steps (`duck_curve` = 96 steps over 24 h). At each step it hands your controller a snapshot of the grid and asks for an action:
30
+
31
+ ```
32
+ every 15 minutes:
33
+
34
+ state ──► your controller ──► action ──► engine simulates ──► cost
35
+ (demand, solar, step(state) (battery, physics + market
36
+ price, soc, …) diesel, …)
37
+
38
+ score = sum of cost over all 96 steps (lower wins)
39
+ ```
40
+
41
+ You see only the **current** step (plus a forecast in later scenarios) and return how much to charge/discharge the battery, run diesel, or curtail solar. The engine simulates that 15 minutes — clipping to physical limits, then applying the market — and charges you a cost. Your score is the total over every step.
42
+
43
+ **One worked step — the duck curve at noon.** Solar is 80 MW, demand 30 MW: a 50 MW surplus. Do nothing and that surplus floods the grid past its 50 MW export cap → an **overvoltage penalty**. Instead, charge the battery (`battery_flow_mw = -20`): you bank cheap midday energy and release it into the 6 pm peak, when grid power is dear. *Store the midday glut, spend it at the evening peak* — that trade-off is the duck curve, and it's exactly what the starter below does. Every run also prints how your cost compares to a do-nothing and a best-known baseline, so you always know whether a change helped.
44
+
45
+ ## Quick start
46
+
47
+ Three steps: install, write `strategy.py`, run `python strategy.py`.
48
+
49
+ > **⚠️ Make a virtual environment first.** Installing into your system Python (or conda base) can clash with other tools; a venv isolates it and you can delete it with `rm -rf .venv` if anything goes wrong. **Colab users:** skip the venv — run the `pip install` line in a cell, or just [open the starter notebook](https://colab.research.google.com/github/AaronEliasZachariah/Watt-The-Hack-Engine-Public/blob/main/notebooks/training_starter.ipynb).
50
+
51
+ **1. Create a venv and install the engine.** The `[playtest]` extra adds plots and the agentic-track OpenAI client.
52
+
53
+ macOS / Linux:
54
+ ```bash
55
+ python3 -m venv .venv
56
+ source .venv/bin/activate
57
+ python3 -m pip install "watt_the_hack[playtest] @ git+https://github.com/AaronEliasZachariah/Watt-The-Hack-Engine-Public.git@main"
58
+ ```
59
+
60
+ Windows (PowerShell):
61
+ ```powershell
62
+ python -m venv .venv
63
+ .venv\Scripts\Activate.ps1
64
+ python -m pip install "watt_the_hack[playtest] @ git+https://github.com/AaronEliasZachariah/Watt-The-Hack-Engine-Public.git@main"
65
+ ```
66
+
67
+ Your prompt should now start with `(.venv)`. (`python -m pip` — not bare `pip` — guarantees you install into the active venv on every OS.)
68
+
69
+ **2. Create `strategy.py`.** Your controller *and* its local test live in one file:
70
+
71
+ ```python
72
+ # strategy.py — edit the controller, then run: python strategy.py
73
+ def controller(state):
74
+ # Duck curve 101: bank the midday solar surplus, spend it at the evening peak.
75
+ demand, solar, soc = state["demand"], state["solar"], state["soc"]
76
+ surplus = solar - demand # +ve = excess solar right now
77
+ flow = 0.0
78
+ if surplus > 5 and soc < 0.9: # midday: store the excess
79
+ flow = -min(20.0, surplus) # negative = charge
80
+ elif surplus < 0 and soc > 0.2: # evening: cover the shortfall
81
+ flow = min(20.0, -surplus) # positive = discharge
82
+ net = demand - solar - flow # what's left for the grid
83
+ curtail = max(0.0, -net - 50.0) # dump unstorable export
84
+ return {"battery_flow_mw": flow, "curtail_solar": curtail}
85
+
86
+
87
+ # --- Local playtest. Runs on `python strategy.py`; the judge ignores this block. ---
88
+ if __name__ == "__main__":
89
+ from watt_the_hack.playtest import run_playtest
90
+ result = run_playtest(__file__, "duck_curve", plots=True, open_report=True)
91
+ print(f"\nRaw cost (lower wins): ${result['metrics']['final_score']:,.2f}")
92
+ ```
93
+
94
+ **3. Run it:**
95
+
96
+ ```bash
97
+ python strategy.py
98
+ ```
99
+
100
+ It prints your cost breakdown and opens an HTML report (plots, worst timesteps, diagnostics). In an IDE (VS Code, PyCharm) this is just the ▶ Run button — no command line at all. Edit the controller, re-run, repeat.
101
+
102
+ `result["metrics"]["final_score"]` is your **raw cost in dollars — lower wins.** The 0–150 leaderboard points are computed server-side on the hidden judging variants; locally you minimise the raw cost.
103
+
104
+ ### Scenarios you can run offline
105
+
106
+ The wheel bundles two: `duck_curve` (rule-based track) and `agentic_demo` (LLM / `plan`-`replan` track). List them any time:
107
+
108
+ ```bash
109
+ python -m watt_the_hack.playtest --list-scenarios
110
+ ```
111
+ ```text
112
+ duck_curve synthetic The Duck Curve
113
+ agentic_demo synthetic Agentic Demo — Your First LLM Controller
114
+ ```
115
+
116
+ Switch scenario by changing the id in `run_playtest(__file__, "duck_curve", ...)`. The scored judging variants stay on the server — a green local run translates directly to a submission.
117
+
118
+ ### Updating as new scenarios drop
119
+
120
+ Scenarios are released incrementally. Update inside the same venv:
121
+
122
+ ```bash
123
+ python -m pip install --upgrade --force-reinstall "watt_the_hack[playtest] @ git+https://github.com/AaronEliasZachariah/Watt-The-Hack-Engine-Public.git@main"
124
+ ```
125
+
126
+ ### Power user: the CLI
127
+
128
+ `run_playtest` is the easy path. The CLI runs the same harness without editing the file, and adds a **sweep** — compare several controllers on one scenario, ranked side by side:
129
+
130
+ ```bash
131
+ python -m watt_the_hack.playtest strategy.py --scenario duck_curve --open-report
132
+ python -m watt_the_hack.playtest a.py b.py c.py --scenario duck_curve
133
+ ```
134
+
135
+ ## What's in here
136
+
137
+ - `watt_the_hack/engine/` — physics + market step
138
+ - `watt_the_hack/metrics/` — scoring metrics
139
+ - `watt_the_hack/simulation/` — runner glue
140
+ - `watt_the_hack/controllers/` — reference controllers (rule-based, parametric)
141
+ - `watt_the_hack/data_loaders/` — scenario loading utilities
142
+
143
+ ## License
144
+
145
+ MIT
@@ -0,0 +1,125 @@
1
+ # Watt The Hack Engine
2
+
3
+ The simulation engine for the **Watt The Hack** energy grid hackathon (DeepNeuron).
4
+
5
+ This is the public engine package — controllers, scenarios authoring, and the judging server live in private repos. Participants use this package to develop and test their controllers locally before submitting to the hackathon evaluation server.
6
+
7
+ ## How it works
8
+
9
+ You write a **controller**. The engine runs a grid as a simulation in 15-minute steps (`duck_curve` = 96 steps over 24 h). At each step it hands your controller a snapshot of the grid and asks for an action:
10
+
11
+ ```
12
+ every 15 minutes:
13
+
14
+ state ──► your controller ──► action ──► engine simulates ──► cost
15
+ (demand, solar, step(state) (battery, physics + market
16
+ price, soc, …) diesel, …)
17
+
18
+ score = sum of cost over all 96 steps (lower wins)
19
+ ```
20
+
21
+ You see only the **current** step (plus a forecast in later scenarios) and return how much to charge/discharge the battery, run diesel, or curtail solar. The engine simulates that 15 minutes — clipping to physical limits, then applying the market — and charges you a cost. Your score is the total over every step.
22
+
23
+ **One worked step — the duck curve at noon.** Solar is 80 MW, demand 30 MW: a 50 MW surplus. Do nothing and that surplus floods the grid past its 50 MW export cap → an **overvoltage penalty**. Instead, charge the battery (`battery_flow_mw = -20`): you bank cheap midday energy and release it into the 6 pm peak, when grid power is dear. *Store the midday glut, spend it at the evening peak* — that trade-off is the duck curve, and it's exactly what the starter below does. Every run also prints how your cost compares to a do-nothing and a best-known baseline, so you always know whether a change helped.
24
+
25
+ ## Quick start
26
+
27
+ Three steps: install, write `strategy.py`, run `python strategy.py`.
28
+
29
+ > **⚠️ Make a virtual environment first.** Installing into your system Python (or conda base) can clash with other tools; a venv isolates it and you can delete it with `rm -rf .venv` if anything goes wrong. **Colab users:** skip the venv — run the `pip install` line in a cell, or just [open the starter notebook](https://colab.research.google.com/github/AaronEliasZachariah/Watt-The-Hack-Engine-Public/blob/main/notebooks/training_starter.ipynb).
30
+
31
+ **1. Create a venv and install the engine.** The `[playtest]` extra adds plots and the agentic-track OpenAI client.
32
+
33
+ macOS / Linux:
34
+ ```bash
35
+ python3 -m venv .venv
36
+ source .venv/bin/activate
37
+ python3 -m pip install "watt_the_hack[playtest] @ git+https://github.com/AaronEliasZachariah/Watt-The-Hack-Engine-Public.git@main"
38
+ ```
39
+
40
+ Windows (PowerShell):
41
+ ```powershell
42
+ python -m venv .venv
43
+ .venv\Scripts\Activate.ps1
44
+ python -m pip install "watt_the_hack[playtest] @ git+https://github.com/AaronEliasZachariah/Watt-The-Hack-Engine-Public.git@main"
45
+ ```
46
+
47
+ Your prompt should now start with `(.venv)`. (`python -m pip` — not bare `pip` — guarantees you install into the active venv on every OS.)
48
+
49
+ **2. Create `strategy.py`.** Your controller *and* its local test live in one file:
50
+
51
+ ```python
52
+ # strategy.py — edit the controller, then run: python strategy.py
53
+ def controller(state):
54
+ # Duck curve 101: bank the midday solar surplus, spend it at the evening peak.
55
+ demand, solar, soc = state["demand"], state["solar"], state["soc"]
56
+ surplus = solar - demand # +ve = excess solar right now
57
+ flow = 0.0
58
+ if surplus > 5 and soc < 0.9: # midday: store the excess
59
+ flow = -min(20.0, surplus) # negative = charge
60
+ elif surplus < 0 and soc > 0.2: # evening: cover the shortfall
61
+ flow = min(20.0, -surplus) # positive = discharge
62
+ net = demand - solar - flow # what's left for the grid
63
+ curtail = max(0.0, -net - 50.0) # dump unstorable export
64
+ return {"battery_flow_mw": flow, "curtail_solar": curtail}
65
+
66
+
67
+ # --- Local playtest. Runs on `python strategy.py`; the judge ignores this block. ---
68
+ if __name__ == "__main__":
69
+ from watt_the_hack.playtest import run_playtest
70
+ result = run_playtest(__file__, "duck_curve", plots=True, open_report=True)
71
+ print(f"\nRaw cost (lower wins): ${result['metrics']['final_score']:,.2f}")
72
+ ```
73
+
74
+ **3. Run it:**
75
+
76
+ ```bash
77
+ python strategy.py
78
+ ```
79
+
80
+ It prints your cost breakdown and opens an HTML report (plots, worst timesteps, diagnostics). In an IDE (VS Code, PyCharm) this is just the ▶ Run button — no command line at all. Edit the controller, re-run, repeat.
81
+
82
+ `result["metrics"]["final_score"]` is your **raw cost in dollars — lower wins.** The 0–150 leaderboard points are computed server-side on the hidden judging variants; locally you minimise the raw cost.
83
+
84
+ ### Scenarios you can run offline
85
+
86
+ The wheel bundles two: `duck_curve` (rule-based track) and `agentic_demo` (LLM / `plan`-`replan` track). List them any time:
87
+
88
+ ```bash
89
+ python -m watt_the_hack.playtest --list-scenarios
90
+ ```
91
+ ```text
92
+ duck_curve synthetic The Duck Curve
93
+ agentic_demo synthetic Agentic Demo — Your First LLM Controller
94
+ ```
95
+
96
+ Switch scenario by changing the id in `run_playtest(__file__, "duck_curve", ...)`. The scored judging variants stay on the server — a green local run translates directly to a submission.
97
+
98
+ ### Updating as new scenarios drop
99
+
100
+ Scenarios are released incrementally. Update inside the same venv:
101
+
102
+ ```bash
103
+ python -m pip install --upgrade --force-reinstall "watt_the_hack[playtest] @ git+https://github.com/AaronEliasZachariah/Watt-The-Hack-Engine-Public.git@main"
104
+ ```
105
+
106
+ ### Power user: the CLI
107
+
108
+ `run_playtest` is the easy path. The CLI runs the same harness without editing the file, and adds a **sweep** — compare several controllers on one scenario, ranked side by side:
109
+
110
+ ```bash
111
+ python -m watt_the_hack.playtest strategy.py --scenario duck_curve --open-report
112
+ python -m watt_the_hack.playtest a.py b.py c.py --scenario duck_curve
113
+ ```
114
+
115
+ ## What's in here
116
+
117
+ - `watt_the_hack/engine/` — physics + market step
118
+ - `watt_the_hack/metrics/` — scoring metrics
119
+ - `watt_the_hack/simulation/` — runner glue
120
+ - `watt_the_hack/controllers/` — reference controllers (rule-based, parametric)
121
+ - `watt_the_hack/data_loaders/` — scenario loading utilities
122
+
123
+ ## License
124
+
125
+ MIT
@@ -0,0 +1,42 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "watt-the-hack"
7
+ version = "0.2.0"
8
+ description = "Watt The Hack 24-hour energy grid simulation hackathon engine"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "pydantic>=2.0",
13
+ ]
14
+
15
+ [project.optional-dependencies]
16
+ api = [
17
+ "fastapi",
18
+ "uvicorn",
19
+ "python-dotenv",
20
+ ]
21
+ playtest = [
22
+ "matplotlib>=3.5",
23
+ "openai>=1.0",
24
+ ]
25
+ test = [
26
+ "pytest",
27
+ "pytest-cov",
28
+ ]
29
+
30
+ [tool.setuptools.packages.find]
31
+ include = ["watt_the_hack*"]
32
+
33
+ # Ship scenario JSONs that live in-package. The public mirror keeps released
34
+ # scenarios under watt_the_hack/scenarios/ for pip distribution. In this source
35
+ # repo scenarios live top-level, so this glob matches nothing here — harmless.
36
+ [tool.setuptools.package-data]
37
+ watt_the_hack = ["scenarios/*/*.json"]
38
+
39
+ [tool.pytest.ini_options]
40
+ # Only collect the real test suite. Keeps bare `pytest` from scanning stray
41
+ # scratch dirs (e.g. codex-pytest-tmp) that can trip collection on Windows.
42
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+