bihgrid 0.1.0__py3-none-any.whl
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.
- bihgrid/__init__.py +18 -0
- bihgrid/dataset.py +229 -0
- bihgrid-0.1.0.dist-info/METADATA +139 -0
- bihgrid-0.1.0.dist-info/RECORD +6 -0
- bihgrid-0.1.0.dist-info/WHEEL +4 -0
- bihgrid-0.1.0.dist-info/licenses/LICENSE +21 -0
bihgrid/__init__.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""bihgrid — the Bosnia and Herzegovina transmission grid as a PyG dataset.
|
|
2
|
+
|
|
3
|
+
Real ≥220 kV grid topology (PyPSA-Eur / OSM) joined with ENTSO-E hourly
|
|
4
|
+
zone-level time series (2015→present), packaged as a
|
|
5
|
+
`torch_geometric.data.InMemoryDataset`.
|
|
6
|
+
|
|
7
|
+
from bihgrid import BiHGrid
|
|
8
|
+
ds = BiHGrid(root="data/bihgrid")
|
|
9
|
+
data = ds[0] # static graph + time-series tensors
|
|
10
|
+
ds.node_generation() # [T, N] heuristic per-bus generation
|
|
11
|
+
|
|
12
|
+
See https://github.com/FarukDziho/bih-power-data for sources, licenses and
|
|
13
|
+
the design decisions behind every heuristic (dataset/DESIGN.md).
|
|
14
|
+
"""
|
|
15
|
+
from .dataset import BiHGrid
|
|
16
|
+
|
|
17
|
+
__version__ = "0.1.0"
|
|
18
|
+
__all__ = ["BiHGrid", "__version__"]
|
bihgrid/dataset.py
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"""BiHGrid: torch_geometric InMemoryDataset for the BiH transmission grid."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pandas as pd
|
|
9
|
+
import torch
|
|
10
|
+
from torch_geometric.data import Data, InMemoryDataset
|
|
11
|
+
|
|
12
|
+
REPO = "FarukDziho/bih-power-data"
|
|
13
|
+
RAW_FILES = [
|
|
14
|
+
"nodes.csv",
|
|
15
|
+
"edges.csv",
|
|
16
|
+
"gen_bus_weights.csv",
|
|
17
|
+
"zone_series.parquet",
|
|
18
|
+
"dataset_summary.json",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
# static node features, in x column order
|
|
22
|
+
NODE_FEATURES = [
|
|
23
|
+
"voltage_kv",
|
|
24
|
+
"lon",
|
|
25
|
+
"lat",
|
|
26
|
+
"is_ba", # 1 = BA bus, 0 = border bus
|
|
27
|
+
"plant_coal_mw",
|
|
28
|
+
"plant_hydro_reservoir_mw",
|
|
29
|
+
"plant_hydro_pumped_storage_mw",
|
|
30
|
+
"plant_hydro_ror_mw",
|
|
31
|
+
"plant_wind_mw",
|
|
32
|
+
]
|
|
33
|
+
# edge features, in edge_attr column order
|
|
34
|
+
EDGE_FEATURES = ["r", "x", "b", "s_nom", "length_km", "circuits",
|
|
35
|
+
"is_transformer", "cross_border"]
|
|
36
|
+
|
|
37
|
+
_PLANT_COLS = {
|
|
38
|
+
"plant_coal_mw": ["plant_fossil_brown_coal_lignite_mw", "plant_fossil_hard_coal_mw"],
|
|
39
|
+
"plant_hydro_reservoir_mw": ["plant_hydro_water_reservoir_mw"],
|
|
40
|
+
"plant_hydro_pumped_storage_mw": ["plant_hydro_pumped_storage_mw"],
|
|
41
|
+
"plant_hydro_ror_mw": ["plant_hydro_run-of-river_and_poundage_mw",
|
|
42
|
+
"plant_hydro_run_of_river_and_poundage_mw"],
|
|
43
|
+
"plant_wind_mw": ["plant_wind_onshore_mw"],
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class BiHGrid(InMemoryDataset):
|
|
48
|
+
"""The Bosnia and Herzegovina ≥220 kV transmission grid.
|
|
49
|
+
|
|
50
|
+
One static graph (51 buses, 67 per-circuit edges incl. transformers)
|
|
51
|
+
plus hourly ENTSO-E zone-level series (UTC) and a curated
|
|
52
|
+
generation→bus weight matrix.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
root: cache directory.
|
|
56
|
+
revision: git revision of ``FarukDziho/bih-power-data`` to download
|
|
57
|
+
the dataset files from. A tag like ``"v0.1.0"`` first tries the
|
|
58
|
+
GitHub-release asset zip, then falls back to raw files at that
|
|
59
|
+
revision; ``"main"`` (default) uses the latest raw files.
|
|
60
|
+
transform, pre_transform: standard PyG hooks.
|
|
61
|
+
|
|
62
|
+
Node/edge feature orders are ``bihgrid.dataset.NODE_FEATURES`` and
|
|
63
|
+
``bihgrid.dataset.EDGE_FEATURES``. The heuristics and their limits are
|
|
64
|
+
documented in the repo's ``dataset/DESIGN.md`` — read it before using
|
|
65
|
+
node-level generation as ground truth (it is capacity-weighted
|
|
66
|
+
zone data, not per-plant metering).
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def __init__(self, root: str | Path, revision: str = "main",
|
|
70
|
+
transform=None, pre_transform=None, force_reload: bool = False):
|
|
71
|
+
self.revision = revision
|
|
72
|
+
super().__init__(str(root), transform, pre_transform,
|
|
73
|
+
force_reload=force_reload)
|
|
74
|
+
self.load(self.processed_paths[0])
|
|
75
|
+
with open(Path(self.processed_dir) / "meta.json") as f:
|
|
76
|
+
self._meta = json.load(f)
|
|
77
|
+
|
|
78
|
+
# ------------------------------------------------------------------ names
|
|
79
|
+
@property
|
|
80
|
+
def raw_file_names(self):
|
|
81
|
+
return RAW_FILES
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def processed_file_names(self):
|
|
85
|
+
return ["data.pt", "meta.json"]
|
|
86
|
+
|
|
87
|
+
# ------------------------------------------------------------------ download
|
|
88
|
+
def download(self):
|
|
89
|
+
import io
|
|
90
|
+
import zipfile
|
|
91
|
+
import requests
|
|
92
|
+
|
|
93
|
+
raw_dir = Path(self.raw_dir)
|
|
94
|
+
if self.revision.startswith("v"):
|
|
95
|
+
url = (f"https://github.com/{REPO}/releases/download/"
|
|
96
|
+
f"{self.revision}/bihgrid-dataset.zip")
|
|
97
|
+
r = requests.get(url, timeout=300)
|
|
98
|
+
if r.ok:
|
|
99
|
+
with zipfile.ZipFile(io.BytesIO(r.content)) as z:
|
|
100
|
+
for name in RAW_FILES:
|
|
101
|
+
member = next((m for m in z.namelist()
|
|
102
|
+
if m.endswith("dataset/" + name)), None)
|
|
103
|
+
if member is None:
|
|
104
|
+
break
|
|
105
|
+
(raw_dir / name).write_bytes(z.read(member))
|
|
106
|
+
else:
|
|
107
|
+
return
|
|
108
|
+
base = (f"https://raw.githubusercontent.com/{REPO}/"
|
|
109
|
+
f"{self.revision}/dataset/")
|
|
110
|
+
for name in RAW_FILES:
|
|
111
|
+
r = requests.get(base + name, timeout=300)
|
|
112
|
+
r.raise_for_status()
|
|
113
|
+
(raw_dir / name).write_bytes(r.content)
|
|
114
|
+
|
|
115
|
+
# ------------------------------------------------------------------ process
|
|
116
|
+
def process(self):
|
|
117
|
+
raw = Path(self.raw_dir)
|
|
118
|
+
nodes = pd.read_csv(raw / "nodes.csv", dtype={"bus_id": str})
|
|
119
|
+
edges = pd.read_csv(raw / "edges.csv", dtype={"bus0": str, "bus1": str})
|
|
120
|
+
weights = pd.read_csv(raw / "gen_bus_weights.csv", dtype={"bus_id": str})
|
|
121
|
+
zone = pd.read_parquet(raw / "zone_series.parquet")
|
|
122
|
+
summary = json.loads((raw / "dataset_summary.json").read_text())
|
|
123
|
+
|
|
124
|
+
bus_ids = nodes["bus_id"].tolist()
|
|
125
|
+
idx = {b: i for i, b in enumerate(bus_ids)}
|
|
126
|
+
|
|
127
|
+
# ---- static node features
|
|
128
|
+
feats = pd.DataFrame(index=nodes.index)
|
|
129
|
+
feats["voltage_kv"] = nodes["voltage"].astype(float)
|
|
130
|
+
feats["lon"] = nodes["x"].astype(float)
|
|
131
|
+
feats["lat"] = nodes["y"].astype(float)
|
|
132
|
+
feats["is_ba"] = (nodes["role"] == "ba").astype(float)
|
|
133
|
+
for out_col, candidates in _PLANT_COLS.items():
|
|
134
|
+
cols = [c for c in candidates if c in nodes.columns]
|
|
135
|
+
feats[out_col] = nodes[cols].sum(axis=1) if cols else 0.0
|
|
136
|
+
x = torch.tensor(feats[NODE_FEATURES].to_numpy(), dtype=torch.float)
|
|
137
|
+
pos = torch.tensor(nodes[["x", "y"]].to_numpy(), dtype=torch.float)
|
|
138
|
+
|
|
139
|
+
# ---- edges (undirected -> both directions; parallel circuits kept)
|
|
140
|
+
e = edges.copy()
|
|
141
|
+
e["is_transformer"] = (e["kind"] == "transformer").astype(float)
|
|
142
|
+
e["cross_border"] = e["cross_border"].astype(bool).astype(float)
|
|
143
|
+
for c in ["r", "x", "b", "s_nom", "length_km", "circuits"]:
|
|
144
|
+
e[c] = pd.to_numeric(e.get(c), errors="coerce").fillna(0.0)
|
|
145
|
+
src = e["bus0"].map(idx).to_numpy()
|
|
146
|
+
dst = e["bus1"].map(idx).to_numpy()
|
|
147
|
+
attr = e[EDGE_FEATURES].to_numpy(dtype=np.float32)
|
|
148
|
+
edge_index = torch.tensor(np.concatenate([np.stack([src, dst]),
|
|
149
|
+
np.stack([dst, src])], axis=1),
|
|
150
|
+
dtype=torch.long)
|
|
151
|
+
edge_attr = torch.tensor(np.concatenate([attr, attr]), dtype=torch.float)
|
|
152
|
+
|
|
153
|
+
# ---- generation weight matrix [N, n_types]
|
|
154
|
+
types = sorted(weights["entsoe_type"].unique())
|
|
155
|
+
W = np.zeros((len(bus_ids), len(types)), dtype=np.float32)
|
|
156
|
+
for _, r in weights.iterrows():
|
|
157
|
+
W[idx[r["bus_id"]], types.index(r["entsoe_type"])] = r["weight"]
|
|
158
|
+
|
|
159
|
+
# ---- zone-level hourly series [T, F] (NaN kept as NaN)
|
|
160
|
+
zone = zone.sort_index()
|
|
161
|
+
zone_t = torch.tensor(zone.to_numpy(dtype=np.float32))
|
|
162
|
+
time_unix = torch.tensor(
|
|
163
|
+
zone.index.view("int64") // 10**9, dtype=torch.long)
|
|
164
|
+
|
|
165
|
+
data = Data(x=x, edge_index=edge_index, edge_attr=edge_attr, pos=pos,
|
|
166
|
+
gen_weights=torch.tensor(W),
|
|
167
|
+
zone_series=zone_t, time_unix=time_unix)
|
|
168
|
+
data.num_nodes = len(bus_ids)
|
|
169
|
+
if self.pre_transform is not None:
|
|
170
|
+
data = self.pre_transform(data)
|
|
171
|
+
self.save([data], self.processed_paths[0])
|
|
172
|
+
|
|
173
|
+
meta = {
|
|
174
|
+
"bus_ids": bus_ids,
|
|
175
|
+
"nearest_place": nodes.get("nearest_place",
|
|
176
|
+
pd.Series([None] * len(nodes))).tolist(),
|
|
177
|
+
"node_features": NODE_FEATURES,
|
|
178
|
+
"edge_features": EDGE_FEATURES,
|
|
179
|
+
"gen_weight_types": types,
|
|
180
|
+
"zone_columns": zone.columns.tolist(),
|
|
181
|
+
"revision": self.revision,
|
|
182
|
+
"summary": summary,
|
|
183
|
+
}
|
|
184
|
+
(Path(self.processed_dir) / "meta.json").write_text(json.dumps(meta))
|
|
185
|
+
|
|
186
|
+
# ------------------------------------------------------------------ helpers
|
|
187
|
+
@property
|
|
188
|
+
def meta(self) -> dict:
|
|
189
|
+
return self._meta
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def bus_ids(self) -> list[str]:
|
|
193
|
+
return self._meta["bus_ids"]
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def zone_columns(self) -> list[str]:
|
|
197
|
+
return self._meta["zone_columns"]
|
|
198
|
+
|
|
199
|
+
def zone_dataframe(self) -> pd.DataFrame:
|
|
200
|
+
"""Zone-level hourly series as a pandas DataFrame (UTC index)."""
|
|
201
|
+
d = self[0]
|
|
202
|
+
index = pd.to_datetime(d.time_unix.numpy(), unit="s", utc=True)
|
|
203
|
+
return pd.DataFrame(d.zone_series.numpy(), index=index,
|
|
204
|
+
columns=self.zone_columns)
|
|
205
|
+
|
|
206
|
+
def node_generation(self, gen_type: str = "Fossil coal (combined)"
|
|
207
|
+
) -> torch.Tensor:
|
|
208
|
+
"""Heuristic per-bus generation series ``[T, N]`` for one type.
|
|
209
|
+
|
|
210
|
+
This is zone generation spread over buses by installed-capacity
|
|
211
|
+
share of *mapped* plants — a documented heuristic, not metering.
|
|
212
|
+
For ``"Fossil coal (combined)"`` the two ENTSO-E fossil columns are
|
|
213
|
+
summed first (their classification drifts across years).
|
|
214
|
+
"""
|
|
215
|
+
d = self[0]
|
|
216
|
+
types = self._meta["gen_weight_types"]
|
|
217
|
+
if gen_type not in types:
|
|
218
|
+
raise ValueError(f"unknown type {gen_type!r}; choose from {types}")
|
|
219
|
+
w = d.gen_weights[:, types.index(gen_type)] # [N]
|
|
220
|
+
cols = self.zone_columns
|
|
221
|
+
if gen_type == "Fossil coal (combined)":
|
|
222
|
+
sel = [cols.index("gen_fossil_brown_coal_lignite_mw"),
|
|
223
|
+
cols.index("gen_fossil_hard_coal_mw")]
|
|
224
|
+
zone = d.zone_series[:, sel].nansum(dim=1) # [T]
|
|
225
|
+
else:
|
|
226
|
+
name = ("gen_" + gen_type.lower().replace(" ", "_")
|
|
227
|
+
.replace("/", "_").replace("-", "_") + "_mw")
|
|
228
|
+
zone = d.zone_series[:, cols.index(name)]
|
|
229
|
+
return zone.unsqueeze(1) * w.unsqueeze(0)
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bihgrid
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The Bosnia and Herzegovina power grid as a PyTorch Geometric dataset: real >=220kV topology + ENTSO-E hourly time series (2015-present)
|
|
5
|
+
Project-URL: Homepage, https://github.com/FarukDziho/bih-power-data
|
|
6
|
+
Project-URL: Repository, https://github.com/FarukDziho/bih-power-data
|
|
7
|
+
Project-URL: Documentation, https://github.com/FarukDziho/bih-power-data#readme
|
|
8
|
+
Author-email: Faruk Dziho <faruk.dziho@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: Bosnia and Herzegovina,ENTSO-E,dataset,energy,graph-neural-networks,power-grid,pytorch-geometric
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Requires-Dist: numpy
|
|
19
|
+
Requires-Dist: pandas
|
|
20
|
+
Requires-Dist: pyarrow
|
|
21
|
+
Requires-Dist: requests
|
|
22
|
+
Requires-Dist: torch-geometric>=2.4
|
|
23
|
+
Requires-Dist: torch>=2.0
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# bih-power-data
|
|
27
|
+
|
|
28
|
+
Continuously refreshed dataset and monthly report for the **Bosnia and Herzegovina power system**
|
|
29
|
+
(BA control area, operated by [NOSBiH](https://www.nosbih.ba/en/)), collected from the
|
|
30
|
+
[ENTSO-E Transparency Platform](https://transparency.entsoe.eu/).
|
|
31
|
+
|
|
32
|
+
**Live report:** `report/index.html` (enable GitHub Pages on this repo to serve it).
|
|
33
|
+
|
|
34
|
+
## What's collected
|
|
35
|
+
|
|
36
|
+
| dataset | description |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `load_actual` | actual total load, hourly |
|
|
39
|
+
| `load_forecast` | day-ahead load forecast |
|
|
40
|
+
| `generation_per_type` | actual generation per production type (lignite, hydro ×3, wind, solar…) |
|
|
41
|
+
| `generation_forecast` | day-ahead generation forecast |
|
|
42
|
+
| `installed_capacity` | installed capacity per type (annual) |
|
|
43
|
+
| `flow_BA_XX` / `flow_XX_BA` | cross-border physical flows with HR / RS / ME, both directions |
|
|
44
|
+
| `sched_BA_XX` / `sched_XX_BA` | scheduled commercial exchanges with HR / RS / ME |
|
|
45
|
+
| `day_ahead_prices`, `hydro_reservoir_storage` | attempted; BA may not report these (status noted in `data/state.json`) |
|
|
46
|
+
|
|
47
|
+
Everything is stored as parquet in `data/`, full history from 2015 where available.
|
|
48
|
+
`data/state.json` tracks coverage and per-dataset status.
|
|
49
|
+
|
|
50
|
+
## Setup
|
|
51
|
+
|
|
52
|
+
1. Register (free) at [transparency.entsoe.eu](https://transparency.entsoe.eu/) and generate an
|
|
53
|
+
API security token in your account settings.
|
|
54
|
+
2. First full collection (locally):
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install -r requirements.txt
|
|
58
|
+
ENTSOE_TOKEN=your-token python src/collect.py # full history on first run (takes a while)
|
|
59
|
+
python src/build_report.py # writes report/index.html
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
3. Push to GitHub, then add the token so the weekly refresh works:
|
|
63
|
+
**Settings → Secrets and variables → Actions → New repository secret** → name `ENTSOE_TOKEN`.
|
|
64
|
+
|
|
65
|
+
The included workflow (`.github/workflows/refresh.yml`) then re-collects incrementally every
|
|
66
|
+
Monday 03:17 UTC and commits any new data plus a rebuilt report. You can also trigger it manually
|
|
67
|
+
from the Actions tab (**Run workflow**).
|
|
68
|
+
|
|
69
|
+
## Pipeline test without a token
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
python src/collect.py --demo && python src/build_report.py
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
generates synthetic data so the whole pipeline and report can be exercised end-to-end.
|
|
76
|
+
|
|
77
|
+
## Graph-ready dataset
|
|
78
|
+
|
|
79
|
+
`src/join_graph.py` joins the ENTSO-E time series onto the ≥220 kV topology
|
|
80
|
+
(`topology/out/`) and writes a graph-ready dataset into `dataset/`: hourly
|
|
81
|
+
zone-level series (UTC), 51 buses with `nearest_place` labels and per-type
|
|
82
|
+
plant capacities (from the curated `topology/plants.csv`), 67 per-circuit
|
|
83
|
+
edges with electrical parameters, generation→bus weight vectors, and a
|
|
84
|
+
MultiGraph GraphML. All design decisions (zone-level vs node-level signals,
|
|
85
|
+
plant mapping coverage, cleaning rules) are documented in
|
|
86
|
+
[`dataset/DESIGN.md`](dataset/DESIGN.md). Runs offline from the repo checkout:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
python src/join_graph.py
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## `bihgrid` — PyTorch Geometric package
|
|
93
|
+
|
|
94
|
+
The dataset ships as a PyG `InMemoryDataset` (auto-downloads from the GitHub
|
|
95
|
+
release or raw files, caches locally):
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install bihgrid
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from bihgrid import BiHGrid
|
|
103
|
+
|
|
104
|
+
ds = BiHGrid(root="data/bihgrid") # revision="v0.1.0" pins a release
|
|
105
|
+
data = ds[0]
|
|
106
|
+
data.x # [51, 9] voltage, coords, role, per-type plant MW
|
|
107
|
+
data.edge_index # [2, 134] 67 undirected per-circuit edges, both directions
|
|
108
|
+
data.edge_attr # [134, 8] r, x, b, s_nom, length_km, circuits, flags
|
|
109
|
+
data.zone_series # [T, 18] hourly zone signals, UTC (NaN = gap/cleaned)
|
|
110
|
+
ds.zone_dataframe() # same as pandas DataFrame
|
|
111
|
+
ds.node_generation("Fossil coal (combined)") # [T, 51] heuristic — see DESIGN.md
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Feature orders: `bihgrid.dataset.NODE_FEATURES` / `EDGE_FEATURES`. Read
|
|
115
|
+
[`dataset/DESIGN.md`](dataset/DESIGN.md) and [`DATASET_CARD.md`](DATASET_CARD.md)
|
|
116
|
+
before treating node-level signals as measurements — they are documented
|
|
117
|
+
heuristics over zone-level data. Tests: `python -m pytest tests/`.
|
|
118
|
+
|
|
119
|
+
## Releasing
|
|
120
|
+
|
|
121
|
+
`git tag vX.Y.Z && git push origin vX.Y.Z` → tests, GitHub release with
|
|
122
|
+
dataset zip, PyPI publish, Zenodo DOI. One-time account setup in
|
|
123
|
+
[`PUBLISHING.md`](PUBLISHING.md).
|
|
124
|
+
|
|
125
|
+
## Roadmap
|
|
126
|
+
|
|
127
|
+
- [x] Combine with grid topology (PyPSA-Eur / OpenStreetMap extract for BiH) into a
|
|
128
|
+
graph-ready dataset — candidate for publication. → `dataset/`, `src/join_graph.py`
|
|
129
|
+
- [x] PyG package `bihgrid` (InMemoryDataset, auto-download, PyPI). → `bihgrid/`
|
|
130
|
+
- [x] Zenodo deposit with versioned DOI + dataset card. → `.zenodo.json`,
|
|
131
|
+
`DATASET_CARD.md`, automated via `release.yml` (one-time setup in `PUBLISHING.md`)
|
|
132
|
+
- [ ] Data paper (Scientific Data / NeurIPS D&B).
|
|
133
|
+
- [ ] Companion collectors for EIA + ERCOT following the same layout.
|
|
134
|
+
|
|
135
|
+
## License / attribution
|
|
136
|
+
|
|
137
|
+
Data © ENTSO-E Transparency Platform, reported by NOSBiH; reuse subject to ENTSO-E's
|
|
138
|
+
[terms](https://transparency.entsoe.eu/content/static_content/Static%20content/terms%20and%20conditions/terms%20and%20conditions.html).
|
|
139
|
+
Collection and report code: MIT.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
bihgrid/__init__.py,sha256=ghc5IUy0dY8sNaOdWqlkAX3rQ_MnfyoEMtLaeItBSvE,680
|
|
2
|
+
bihgrid/dataset.py,sha256=nXpSQVl7aBd6ghLMXGTZfSquqEuEaGTg-9fpgJbxBzc,9598
|
|
3
|
+
bihgrid-0.1.0.dist-info/METADATA,sha256=iTN1oMSJyvpMXepU2JI11cdK_FGYGXMyST6HKa8Lz8Y,6039
|
|
4
|
+
bihgrid-0.1.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
5
|
+
bihgrid-0.1.0.dist-info/licenses/LICENSE,sha256=6ZM94bBr-3GCGqd8TveAgtqCiukteHFTWAb_0f0SjBQ,1068
|
|
6
|
+
bihgrid-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Faruk Dziho
|
|
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.
|