import json
import math
import pathlib
import sys
import pypowsybl as pp
import pypowsybl.loadflow as lf
ROOT = pathlib.Path(__file__).resolve().parents[2]
FIXTURES = ROOT / "tests" / "data" / "ucte"
OPENRAO = ROOT / "tests" / "data" / "benchmark-grids" / "powsybl-open-rao"
def listed(extension):
found = []
for line in (ROOT / "tests" / "data" / "openrao-fixtures.txt").read_text().splitlines():
if not line.strip() or line.startswith("#"):
continue
name, relative = line.split()[:2]
if name.endswith("." + extension):
found.append((name, OPENRAO / relative))
return sorted(found)
def gridoxide_slack(path):
best = None
block = None
for raw in path.read_bytes().split(b"\n"):
line = raw.rstrip(b"\r").decode("latin-1")
if line.startswith("##"):
tag = line[2:].strip()
block = "N" if (tag == "N" or tag.startswith("Z")) else tag[:1]
continue
if block != "N" or len(line) < 25:
continue
code = line[:8]
regulating = line[24] in "23"
try:
generation = -float(line[49:56].strip() or 0.0)
except ValueError:
generation = 0.0
if generation <= 0.0:
continue
key = (regulating, generation, [-ord(c) for c in code])
if best is None or key > best[0]:
best = (key, code)
return best[1].strip() if best else None
def clean(x):
if x is None or (isinstance(x, float) and not math.isfinite(x)):
return None
return float(x)
def reference(path):
network = pp.network.load(str(path))
slack = gridoxide_slack(path)
parameters = lf.Parameters(
distributed_slack=False,
use_reactive_limits=False,
transformer_voltage_control_on=False,
phase_shifter_regulation_on=False,
voltage_init_mode=pp.loadflow.VoltageInitMode.UNIFORM_VALUES,
provider_parameters={
"slackBusSelectionMode": "NAME",
"slackBusesIds": slack or "",
"voltageRemoteControl": "false",
},
)
status = str(lf.run_ac(network, parameters=parameters)[0].status)
levels = network.get_voltage_levels()
buses = {}
for bus_id, row in network.get_bus_breaker_view_buses().iterrows():
nominal = levels.loc[row["voltage_level_id"], "nominal_v"]
buses[bus_id.strip()] = {
"v_pu": clean(row["v_mag"] / nominal),
"angle_deg": clean(row["v_angle"]),
}
branches = {}
for frame, kind in (
(network.get_lines(), "line"),
(network.get_2_windings_transformers(), "xfmr"),
):
for element_id, row in frame.iterrows():
branches[element_id] = {
"kind": kind,
"p1": clean(row["p1"]),
"q1": clean(row["q1"]),
"p2": clean(row["p2"]),
"q2": clean(row["q2"]),
}
return {"slack": slack, "status": status, "buses": buses, "branches": branches}
def main():
cases = listed("uct")
if not cases:
sys.exit("no .uct fixtures listed in tests/data/openrao-fixtures.txt")
for name, case in cases:
try:
document = reference(case)
except Exception as error: print(f" skip {name}: {error}")
continue
out = FIXTURES / pathlib.Path(name).with_suffix(".pypowsybl.json")
out.write_text(json.dumps(document, indent=1) + "\n")
print(
f" {name}: {document['status']}, slack {document['slack']}, "
f"{len(document['buses'])} buses, {len(document['branches'])} branches"
)
if __name__ == "__main__":
main()