From 0567c1aa52c2947b9e23a376ac36dae0e1055bbc Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sun, 1 Dec 2024 11:50:55 +0100 Subject: [PATCH] Fix convert_v2_to_v3 and test all versions --- roseau/load_flow/io/dict.py | 35 +- roseau/load_flow/io/tests/data/README.md | 13 + .../load_flow/io/tests/data/generators/v0.py | 466 ++++++ .../load_flow/io/tests/data/generators/v1.py | 121 ++ .../load_flow/io/tests/data/generators/v2.py | 137 ++ .../io/tests/data/network_json_v0.json | 452 ++++++ .../io/tests/data/network_json_v0.py | 436 ++++++ .../io/tests/data/network_json_v1.json | 627 ++++++++ .../io/tests/data/network_json_v2.json | 341 +++- roseau/load_flow/io/tests/test_dict.py | 1376 ++--------------- 10 files changed, 2727 insertions(+), 1277 deletions(-) create mode 100644 roseau/load_flow/io/tests/data/README.md create mode 100644 roseau/load_flow/io/tests/data/generators/v0.py create mode 100644 roseau/load_flow/io/tests/data/generators/v1.py create mode 100644 roseau/load_flow/io/tests/data/generators/v2.py create mode 100644 roseau/load_flow/io/tests/data/network_json_v0.json create mode 100644 roseau/load_flow/io/tests/data/network_json_v0.py create mode 100644 roseau/load_flow/io/tests/data/network_json_v1.json diff --git a/roseau/load_flow/io/dict.py b/roseau/load_flow/io/dict.py index 2bed75f1..ff221dcb 100644 --- a/roseau/load_flow/io/dict.py +++ b/roseau/load_flow/io/dict.py @@ -95,9 +95,11 @@ def network_from_dict( # noqa: C901 version = data.get("version", 0) if version <= 2: - logger.warning( + warnings.warn( f"Got an outdated network file (version {version}), trying to update to the current format " - f"(version {NETWORK_JSON_VERSION}). Please save the network again." + f"(version {NETWORK_JSON_VERSION}). Please save the network again.", + category=UserWarning, + stacklevel=find_stack_level(), ) if version <= 0: data = v0_to_v1_converter(data) @@ -177,11 +179,20 @@ def network_from_dict( # noqa: C901 bus2 = buses[line_data["bus2"]] geometry = Line._parse_geometry(line_data.get("geometry")) length = line_data["length"] + max_loading = line_data["max_loading"] lp = lines_params[line_data["params_id"]] gid = line_data.get("ground") ground = grounds[gid] if gid is not None else None line = Line( - id=id, bus1=bus1, bus2=bus2, parameters=lp, phases=phases, length=length, ground=ground, geometry=geometry + id=id, + bus1=bus1, + bus2=bus2, + parameters=lp, + phases=phases, + length=length, + ground=ground, + geometry=geometry, + max_loading=max_loading, ) if include_results: line = _assign_branch_currents(branch=line, branch_data=line_data) @@ -196,12 +207,21 @@ def network_from_dict( # noqa: C901 phases1 = transformer_data["phases1"] phases2 = transformer_data["phases2"] tap = transformer_data["tap"] + max_loading = transformer_data["max_loading"] bus1 = buses[transformer_data["bus1"]] bus2 = buses[transformer_data["bus2"]] geometry = Transformer._parse_geometry(transformer_data.get("geometry")) tp = transformers_params[transformer_data["params_id"]] transformer = Transformer( - id=id, bus1=bus1, bus2=bus2, parameters=tp, phases1=phases1, phases2=phases2, tap=tap, geometry=geometry + id=id, + bus1=bus1, + bus2=bus2, + parameters=tp, + phases1=phases1, + phases2=phases2, + tap=tap, + geometry=geometry, + max_loading=max_loading, ) if include_results: transformer = _assign_branch_currents(branch=transformer, branch_data=transformer_data) @@ -671,7 +691,10 @@ def v2_to_v3_converter(data: JsonDict) -> JsonDict: # noqa: C901 vg = "Iii0" transformer_param_data["vg"] = vg if (max_power := transformer_param_data.pop("max_power", None)) is not None: - transformers_params_max_loading[transformer_param_data["id"]] = max_power / transformer_param_data["sn"] + loading = max_power / transformer_param_data["sn"] + else: + loading = 1 + transformers_params_max_loading[transformer_param_data["id"]] = loading transformers_params.append(transformer_param_data) # Rename `maximal_current` in `ampacities` and uses array @@ -705,7 +728,7 @@ def v2_to_v3_converter(data: JsonDict) -> JsonDict: # noqa: C901 old_transformers = data.get("transformers", []) transformers = [] for transformer_data in old_transformers: - transformer_data["max_loading"] = transformers_params_max_loading.get(transformer_data["params_id"], 1) + transformer_data["max_loading"] = transformers_params_max_loading[transformer_data["params_id"]] transformers.append(transformer_data) results = { diff --git a/roseau/load_flow/io/tests/data/README.md b/roseau/load_flow/io/tests/data/README.md new file mode 100644 index 00000000..02c5d9d7 --- /dev/null +++ b/roseau/load_flow/io/tests/data/README.md @@ -0,0 +1,13 @@ +# Versioned network JSON files for testing + +## JSON files + +**DO NOT MODIFY** the JSON files in this directory if the tests fail. Adapt the converter functions +in the `roseau.load_flow.io.dict` module instead. + +## Generator scripts + +Scripts in the _generators_ directory are used to generate the versioned network JSON files. They +are executed using old versions of rlf. + +**DO NOT UPGRADE** these scripts when modifying rlf. diff --git a/roseau/load_flow/io/tests/data/generators/v0.py b/roseau/load_flow/io/tests/data/generators/v0.py new file mode 100644 index 00000000..0db717e2 --- /dev/null +++ b/roseau/load_flow/io/tests/data/generators/v0.py @@ -0,0 +1,466 @@ +"""This script generates a version 0 JSON file. + +Run with roseau-load-flow==0.2.1, NOT WITH THE CURRENT VERSION:: + + uv run --no-project --script roseau/load_flow/io/tests/data/generators/v0.py +""" + +# Script metadata generated by `uv` +# /// script +# requires-python = ">=3.10,<3.12" +# dependencies = [ +# "roseau-load-flow==0.2.1", +# ] +# /// +from pathlib import Path + +from shapely.geometry import Point + +import roseau.load_flow as rlf + +try: + # Version 0 does not have NETWORK_JSON_VERSION + from roseau.load_flow.io.dict import NETWORK_JSON_VERSION +except ImportError: + NETWORK_JSON_VERSION = 0 +else: + raise ValueError( + f"This script is meant to generate version 0 JSON files, current version: {NETWORK_JSON_VERSION}" + f"\nExecute with `uv run --no-project --script roseau/load_flow/io/tests/data/generators/v0.py`" + ) + +OUTPUT = Path(__file__).parent.parent / f"network_json_v{NETWORK_JSON_VERSION}.json" + +# Buses +buses = { + 1: rlf.VoltageSource( + id=1, + n=4, + ground=None, + source_voltages=[ + 11547.005383792515 + 0.0j, + -5773.502691896258 + -10000.000000179687j, + -5773.502691896258 + 10000.000000179687j, + ], + geometry=Point(0.0, 0.0), + ), + 2: rlf.Bus(id=2, n=3, geometry=Point(0.0, 1.0)), + 3: rlf.Bus(id=3, n=4, geometry=Point(0.0, 1.0)), + 4: rlf.Bus(id=4, n=4, geometry=Point(0.0, 1.0)), + 5: rlf.Bus(id=5, n=4, geometry=Point(0.0, 1.0)), + 6: rlf.Bus(id=6, n=3, geometry=Point(0.0, 1.0)), + 7: rlf.Bus(id=7, n=4, geometry=Point(0.0, 1.0)), + 8: rlf.Bus(id=8, n=3, geometry=Point(0.0, 1.0)), + 9: rlf.Bus(id=9, n=4, geometry=Point(0.0, 1.0)), + 10: rlf.Bus(id=10, n=4, geometry=Point(0.0, 1.0)), + 11: rlf.Bus(id=11, n=4, geometry=Point(0.0, 1.0)), + 12: rlf.Bus(id=12, n=3, geometry=Point(0.0, 1.0)), + 13: rlf.Bus(id=13, n=4, geometry=Point(0.0, 1.0)), +} + +# Grounds and potential references +ground = rlf.Ground() +for bus_id in (1, 3, 4, 5, 7, 9, 10, 11, 13): + ground.connect(buses[bus_id]) +potential_refs = [ + rlf.PotentialRef(element=ground), + rlf.PotentialRef(element=buses[2]), + rlf.PotentialRef(element=buses[6]), + rlf.PotentialRef(element=buses[8]), + rlf.PotentialRef(element=buses[12]), +] + +# Loads +loads = [ + rlf.PowerLoad( + id=1, + bus=buses[2], + n=4, + s=[ + 41916.482229647016 + 20958.241114823508j, + 41916.482230776804 + 20958.2411153884j, + 41916.4822307768 + 20958.241115388402j, + ], + ), + rlf.PowerLoad( + id=2, + bus=buses[3], + n=4, + s=[ + 40459.7989783205 + 20229.89948916025j, + 40459.79897941102 + 20229.89948970551j, + 40459.79897941102 + 20229.89948970551j, + ], + ), + rlf.PowerLoad( + id=3, + bus=buses[4], + n=4, + s=[ + 37922.04164877094 + 18961.020824385465j, + 37922.04164985974 + 18961.020824929874j, + 37922.04164980375 + 18961.02082490188j, + ], + ), + rlf.PowerLoad( + id=4, + bus=buses[5], + n=4, + s=[ + 40459.798978684 + 20229.899489342002j, + 40459.79897977451 + 20229.89948988726j, + 40459.798978684004 + 20229.899489342002j, + ], + ), + rlf.PowerLoad( + id=5, + bus=buses[6], + n=4, + s=[ + 41916.48223002361 + 20958.24111501181j, + 41916.4822311534 + 20958.241115576697j, + 41916.48223002363 + 20958.241115011813j, + ], + ), + rlf.PowerLoad( + id=6, + bus=buses[7], + n=4, + s=[ + 40932.79932474136 + 20466.399662370677j, + 40932.79932583017 + 20466.39966291509j, + 40932.79932479737 + 20466.39966239868j, + ], + ), + rlf.PowerLoad( + id=7, + bus=buses[8], + n=4, + s=[ + 41916.482229647016 + 20958.241114823508j, + 41916.482230776804 + 20958.241115388402j, + 41916.4822307768 + 20958.241115388402j, + ], + ), + rlf.PowerLoad( + id=8, + bus=buses[9], + n=4, + s=[ + 40459.79897832049 + 20229.899489160252j, + 40459.79897941102 + 20229.89948970551j, + 40459.79897941101 + 20229.899489705513j, + ], + ), + rlf.PowerLoad( + id=9, + bus=buses[10], + n=4, + s=[ + 37922.04164877094 + 18961.020824385465j, + 37922.04164985973 + 18961.020824929878j, + 37922.04164980376 + 18961.02082490188j, + ], + ), + rlf.PowerLoad( + id=10, + bus=buses[11], + n=4, + s=[ + 40459.798978684 + 20229.899489342002j, + 40459.79897977452 + 20229.899489887266j, + 40459.798978684004 + 20229.899489342002j, + ], + ), + rlf.PowerLoad( + id=11, + bus=buses[12], + n=4, + s=[ + 41916.48223002361 + 20958.24111501181j, + 41916.4822311534 + 20958.241115576693j, + 41916.48223002362 + 20958.241115011817j, + ], + ), + rlf.PowerLoad( + id=12, + bus=buses[13], + n=4, + s=[ + 40932.79932474137 + 20466.399662370684j, + 40932.79932583017 + 20466.399662915086j, + 40932.799324797365 + 20466.399662398682j, + ], + ), +] + +# Transformers +tc = { + "160kVA_Dd0": rlf.TransformerCharacteristics( + type_name="160kVA_Dd0", + windings="dd0", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Dd6": rlf.TransformerCharacteristics( + type_name="160kVA_Dd6", + windings="dd6", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Dyn11": rlf.TransformerCharacteristics( + type_name="160kVA_Dyn11", + windings="dyn11", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Dyn5": rlf.TransformerCharacteristics( + type_name="160kVA_Dyn5", + windings="dyn5", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Dzn0": rlf.TransformerCharacteristics( + type_name="160kVA_Dzn0", + windings="dzn0", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Dzn6": rlf.TransformerCharacteristics( + type_name="160kVA_Dzn6", + windings="dzn6", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Yd11": rlf.TransformerCharacteristics( + type_name="160kVA_Yd11", + windings="yd11", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Yd5": rlf.TransformerCharacteristics( + type_name="160kVA_Yd5", + windings="yd5", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Yyn0": rlf.TransformerCharacteristics( + type_name="160kVA_Yyn0", + windings="yyn0", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Yyn6": rlf.TransformerCharacteristics( + type_name="160kVA_Yyn6", + windings="yyn6", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Yzn11": rlf.TransformerCharacteristics( + type_name="160kVA_Yzn11", + windings="yzn11", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Yzn5": rlf.TransformerCharacteristics( + type_name="160kVA_Yzn5", + windings="yzn5", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), +} +p = Point(0.0, 0.5) +transformers = [ + rlf.DeltaDeltaTransformer( + id="tr1", + bus1=buses[1], + bus2=buses[2], + phases1="abc", + phases2="abc", + transformer_characteristics=tc["160kVA_Dd0"], + tap=1, + geometry=p, + ), + rlf.WyeWyeTransformer( + id="tr2", + bus1=buses[1], + bus2=buses[3], + phases1="abcn", + phases2="abcn", + transformer_characteristics=tc["160kVA_Yyn0"], + tap=1, + geometry=p, + ), + rlf.DeltaZigzagTransformer( + id="tr3", + bus1=buses[1], + bus2=buses[4], + phases1="abc", + phases2="abcn", + transformer_characteristics=tc["160kVA_Dzn0"], + tap=1, + geometry=p, + ), + rlf.DeltaWyeTransformer( + id="tr4", + bus1=buses[1], + bus2=buses[5], + phases1="abc", + phases2="abcn", + transformer_characteristics=tc["160kVA_Dyn11"], + tap=1, + geometry=p, + ), + rlf.WyeDeltaTransformer( + id="tr5", + bus1=buses[1], + bus2=buses[6], + phases1="abcn", + phases2="abc", + transformer_characteristics=tc["160kVA_Yd11"], + tap=1, + geometry=p, + ), + rlf.WyeZigzagTransformer( + id="tr6", + bus1=buses[1], + bus2=buses[7], + phases1="abcn", + phases2="abcn", + transformer_characteristics=tc["160kVA_Yzn11"], + tap=1, + geometry=p, + ), + rlf.DeltaDeltaTransformer( + id="tr7", + bus1=buses[1], + bus2=buses[8], + phases1="abc", + phases2="abc", + transformer_characteristics=tc["160kVA_Dd6"], + tap=1, + geometry=p, + ), + rlf.WyeWyeTransformer( + id="tr8", + bus1=buses[1], + bus2=buses[9], + phases1="abcn", + phases2="abcn", + transformer_characteristics=tc["160kVA_Yyn6"], + tap=1, + geometry=p, + ), + rlf.DeltaZigzagTransformer( + id="tr9", + bus1=buses[1], + bus2=buses[10], + phases1="abc", + phases2="abcn", + transformer_characteristics=tc["160kVA_Dzn6"], + tap=1, + geometry=p, + ), + rlf.DeltaWyeTransformer( + id="tr10", + bus1=buses[1], + bus2=buses[11], + phases1="abc", + phases2="abcn", + transformer_characteristics=tc["160kVA_Dyn5"], + tap=1, + geometry=p, + ), + rlf.WyeDeltaTransformer( + id="tr11", + bus1=buses[1], + bus2=buses[12], + phases1="abcn", + phases2="abc", + transformer_characteristics=tc["160kVA_Yd5"], + tap=1, + geometry=p, + ), + rlf.WyeZigzagTransformer( + id="tr12", + bus1=buses[1], + bus2=buses[13], + phases1="abcn", + phases2="abcn", + transformer_characteristics=tc["160kVA_Yzn5"], + tap=1, + geometry=p, + ), +] + +en = rlf.ElectricalNetwork( + buses=buses, + branches=transformers, + loads=loads, + special_elements=[ground, *potential_refs], +) + +# The first file we had stored the geometry as a WKT string +Point.__geo_interface__ = Point.wkt + +en.to_json(OUTPUT) diff --git a/roseau/load_flow/io/tests/data/generators/v1.py b/roseau/load_flow/io/tests/data/generators/v1.py new file mode 100644 index 00000000..640b8575 --- /dev/null +++ b/roseau/load_flow/io/tests/data/generators/v1.py @@ -0,0 +1,121 @@ +"""This script generates a version 1 JSON file. + +Run with roseau-load-flow==0.9.1, NOT WITH THE CURRENT VERSION:: + + uv run --no-project --script roseau/load_flow/io/tests/data/generators/v1.py +""" + +# Script metadata generated by `uv` +# /// script +# requires-python = ">=3.10,<3.12" +# dependencies = [ +# "roseau-load-flow==0.9.1", +# ] +# /// +import cmath +from pathlib import Path + +import numpy as np +from shapely import LineString, Point + +import roseau.load_flow as rlf +from roseau.load_flow.io.dict import NETWORK_JSON_VERSION + +if NETWORK_JSON_VERSION != 1: + raise ValueError( + f"This script is meant to generate version 1 JSON files, current version: {NETWORK_JSON_VERSION}" + f"\nExecute with `uv run --no-project --script roseau/load_flow/io/tests/data/generators/v1.py`" + ) + +OUTPUT = Path(__file__).parent.parent / f"network_json_v{NETWORK_JSON_VERSION}.json" + +bus1 = rlf.Bus(id=1, phases="abc", geometry=Point(0.0, 0.0), min_voltage=19e3, max_voltage=21e3) +bus2 = rlf.Bus(id=2, phases="abc", geometry=Point(0.0, 1.0), min_voltage=19e3, max_voltage=21e3) +bus3 = rlf.Bus(id=3, phases="abcn", geometry=Point(0.0, 1.0), min_voltage=207, max_voltage=253) +bus4 = rlf.Bus(id=4, phases="abcn", geometry=Point(0.0, 2.0), min_voltage=207, max_voltage=253) +bus5 = rlf.Bus(id=5, phases="abcn", geometry=Point(0.0, 2.0), min_voltage=207, max_voltage=253) +bus6 = rlf.Bus(id=6, phases="bc", geometry=Point(0.0, 3.0), min_voltage=207, max_voltage=253) +bus7 = rlf.Bus(id=7, phases="abn", geometry=Point(0.0, 3.0), min_voltage=207, max_voltage=253) + +ground = rlf.Ground(id="gnd") +ground.connect(bus3, phase="n") +ground.connect(bus5, phase="n") +potential_ref = rlf.PotentialRef(id="pref", element=ground) + +vs = rlf.VoltageSource(id=1, bus=bus1, voltages=20e3 * np.exp([0, -2j * np.pi / 3, 2j * np.pi / 3]), phases="abc") +fp = rlf.FlexibleParameter( + control_p=rlf.Control.p_max_u_consumption(u_min=18e3, u_down=19e3), + control_q=rlf.Control.constant(), + projection=rlf.Projection(type="euclidean"), + s_max=45e3, +) +power = cmath.rect(40e3, np.acos(0.95)) +rlf.PowerLoad(id=1, bus=bus2, phases="abc", powers=[power, power, power], flexible_params=[fp, fp, fp]) +rlf.PowerLoad( + id=2, + bus=bus2, + phases="abc", + powers=[ + 40459.7989783205 + 20229.89948916025j, + 40459.79897941102 + 20229.89948970551j, + 40459.79897941102 + 20229.89948970551j, + ], +) + + +lp_mv = rlf.LineParameters( + id=1, + z_line=0.35 * np.eye(3, dtype=complex), + y_shunt=1e-6j * np.eye(3, dtype=complex), + line_type=rlf.LineType.UNDERGROUND, + conductor_type=rlf.ConductorType.AL, + insulator_type=rlf.InsulatorType.PVC, + section=rlf.Q_(240, "mm^2"), + max_current=250, +) +lp_lv = rlf.LineParameters( + id=2, + z_line=0.35 * np.eye(4, dtype=complex), + line_type=rlf.LineType.OVERHEAD, + conductor_type=rlf.ConductorType.CU, + insulator_type=None, + section=rlf.Q_(150, "mm^2"), + max_current=160, +) +rlf.Line( + id=1, bus1=bus1, bus2=bus2, parameters=lp_mv, length=10.0, geometry=LineString([(0, 0), (1, 0)]), ground=ground +) +rlf.Line(id=2, bus1=bus3, bus2=bus4, parameters=lp_lv, length=1.0, geometry=LineString([(0, 1), (0, 2)])) + +tp = rlf.TransformerParameters.from_catalogue("SE_Minera_AA0Ak_160kVA") +tp.max_power = 200e3 +rlf.Transformer(id=3, bus1=bus2, bus2=bus3, parameters=tp, geometry=Point(0.0, 1.0), tap=1.025) +tp_single = rlf.TransformerParameters( + id="2", type="single", uhv=400, ulv=400, sn=10e3, z2=0.05, ym=0.01 + 0.02j, max_power=10e3 +) +rlf.Transformer(id=4, bus1=bus4, bus2=bus5, parameters=tp_single, geometry=Point(0.0, 2.0), phases1="bc", phases2="bc") +tp_center = rlf.TransformerParameters( + id="3", type="center", uhv=400, ulv=400, sn=10e3, z2=0.05, ym=0.01 + 0.02j, max_power=10e3 +) +rlf.Transformer(id=5, bus1=bus4, bus2=bus5, parameters=tp_center, geometry=Point(0.0, 2.0), phases1="ab", phases2="abn") + +lp_lv_2_cond = rlf.LineParameters(id=3, z_line=0.35 * np.eye(2, dtype=complex)) +lp_lv_3_cond = rlf.LineParameters(id=4, z_line=0.35 * np.eye(3, dtype=complex)) +rlf.Line( + id=6, bus1=bus5, bus2=bus6, phases="bc", parameters=lp_lv_2_cond, length=1.0, geometry=LineString([(0, 2), (0, 3)]) +) +rlf.Line( + id=7, bus1=bus5, bus2=bus7, phases="abn", parameters=lp_lv_3_cond, length=1.0, geometry=LineString([(0, 2), (0, 3)]) +) +rlf.PowerLoad(id=3, bus=bus6, phases="bc", powers=[1000 + 200j]) +rlf.CurrentLoad(id=4, bus=bus7, phases="abn", currents=[2 + 1j, 0.5 + 0.1j]) +rlf.ImpedanceLoad(id=5, bus=bus7, phases="abn", impedances=[100 + 200j, 300 + 4000j]) + +en = rlf.ElectricalNetwork.from_element(bus1) +en.solve_load_flow() + +# Bug in PowerLoad.res_flexible_powers with include_results=True +assert en.loads[1].flexible_params is not None +en.loads[1]._res_flexible_powers = en.loads[1].res_powers.m + +en.to_json(OUTPUT, include_results=True) diff --git a/roseau/load_flow/io/tests/data/generators/v2.py b/roseau/load_flow/io/tests/data/generators/v2.py new file mode 100644 index 00000000..8f74ba28 --- /dev/null +++ b/roseau/load_flow/io/tests/data/generators/v2.py @@ -0,0 +1,137 @@ +"""This script generates a version 2 JSON file. + +Run with roseau-load-flow==0.10.0, NOT WITH THE CURRENT VERSION:: + + uv run --no-project --script roseau/load_flow/io/tests/data/generators/v2.py +""" + +# Script metadata generated by `uv` +# /// script +# requires-python = ">=3.10,<3.13" +# dependencies = [ +# "roseau-load-flow==0.10.0", +# ] +# /// +import cmath +from pathlib import Path + +import numpy as np +from shapely import LineString, Point + +import roseau.load_flow as rlf +from roseau.load_flow.io.dict import NETWORK_JSON_VERSION + +if NETWORK_JSON_VERSION != 2: + raise ValueError( + f"This script is meant to generate version 2 JSON files, current version: {NETWORK_JSON_VERSION}" + f"\nExecute with `uv run --no-project --script roseau/load_flow/io/tests/data/generators/v2.py`" + ) + +OUTPUT = Path(__file__).parent.parent / f"network_json_v{NETWORK_JSON_VERSION}.json" + +bus1 = rlf.Bus(id=1, phases="abc", geometry=Point(0.0, 0.0), min_voltage=19e3, max_voltage=21e3) +bus2 = rlf.Bus(id=2, phases="abc", geometry=Point(0.0, 1.0), min_voltage=19e3, max_voltage=21e3) +bus3 = rlf.Bus(id=3, phases="abcn", geometry=Point(0.0, 1.0), min_voltage=207, max_voltage=253) +bus4 = rlf.Bus(id=4, phases="abcn", geometry=Point(0.0, 2.0), min_voltage=207, max_voltage=253) +bus5 = rlf.Bus(id=5, phases="abcn", geometry=Point(0.0, 2.0), min_voltage=207, max_voltage=253) +bus6 = rlf.Bus(id=6, phases="bc", geometry=Point(0.0, 3.0), min_voltage=207, max_voltage=253) +bus7 = rlf.Bus(id=7, phases="abn", geometry=Point(0.0, 3.0), min_voltage=207, max_voltage=253) + +ground = rlf.Ground(id="gnd") +ground.connect(bus3, phase="n") +ground.connect(bus5, phase="n") +potential_ref = rlf.PotentialRef(id="pref", element=ground) + +vs = rlf.VoltageSource(id=1, bus=bus1, voltages=20e3 * np.exp([0, -2j * np.pi / 3, 2j * np.pi / 3]), phases="abc") +fp = rlf.FlexibleParameter( + control_p=rlf.Control.p_max_u_consumption(u_min=18e3, u_down=19e3), + control_q=rlf.Control.constant(), + projection=rlf.Projection(type="euclidean"), + s_max=45e3, +) +power = cmath.rect(40e3, np.acos(0.95)) +rlf.PowerLoad(id=1, bus=bus2, phases="abc", powers=[power, power, power], flexible_params=[fp, fp, fp]) +rlf.PowerLoad( + id=2, + bus=bus2, + phases="abc", + powers=[ + 40459.7989783205 + 20229.89948916025j, + 40459.79897941102 + 20229.89948970551j, + 40459.79897941102 + 20229.89948970551j, + ], +) + + +lp_mv = rlf.LineParameters( + id=1, + z_line=0.35 * np.eye(3, dtype=complex), + y_shunt=1e-6j * np.eye(3, dtype=complex), + line_type=rlf.LineType.UNDERGROUND, + conductor_type=rlf.ConductorType.AL, + insulator_type=rlf.InsulatorType.PVC, + section=rlf.Q_(240, "mm^2"), + max_current=250, +) +lp_lv = rlf.LineParameters( + id=2, + z_line=0.35 * np.eye(4, dtype=complex), + line_type=rlf.LineType.OVERHEAD, + conductor_type=rlf.ConductorType.CU, + insulator_type=None, + section=rlf.Q_(150, "mm^2"), + max_current=160, +) +rlf.Line( + id=1, bus1=bus1, bus2=bus2, parameters=lp_mv, length=10.0, geometry=LineString([(0, 0), (1, 0)]), ground=ground +) +rlf.Line(id=2, bus1=bus3, bus2=bus4, parameters=lp_lv, length=1.0, geometry=LineString([(0, 1), (0, 2)])) + +tp = rlf.TransformerParameters.from_catalogue("SE_Minera_AA0Ak_160kVA") +tp.max_power = 200e3 +rlf.Transformer(id=1, bus1=bus2, bus2=bus3, parameters=tp, geometry=Point(0.0, 1.0), tap=1.025) +tp_single = rlf.TransformerParameters( + id="2", + type="single", + uhv=400, + ulv=400, + sn=10e3, + z2=0.05, + ym=0.01 + 0.02j, + max_power=10e3, + manufacturer="roseau tech", + range="testing", + efficiency="good", +) +rlf.Transformer(id=2, bus1=bus4, bus2=bus5, parameters=tp_single, geometry=Point(0.0, 2.0), phases1="bc", phases2="bc") +tp_center = rlf.TransformerParameters( + id="3", + type="center", + uhv=400, + ulv=400, + sn=10e3, + z2=0.05, + ym=0.01 + 0.02j, + max_power=10e3, + manufacturer="roseau tech", + range="testing", + efficiency="good++", +) +rlf.Transformer(id=3, bus1=bus4, bus2=bus5, parameters=tp_center, geometry=Point(0.0, 2.0), phases1="ab", phases2="abn") + +lp_lv_2_cond = rlf.LineParameters(id=3, z_line=0.35 * np.eye(2, dtype=complex)) +lp_lv_3_cond = rlf.LineParameters(id=4, z_line=0.35 * np.eye(3, dtype=complex)) +rlf.Line( + id=3, bus1=bus5, bus2=bus6, phases="bc", parameters=lp_lv_2_cond, length=1.0, geometry=LineString([(0, 2), (0, 3)]) +) +rlf.Line( + id=4, bus1=bus5, bus2=bus7, phases="abn", parameters=lp_lv_3_cond, length=1.0, geometry=LineString([(0, 2), (0, 3)]) +) +rlf.PowerLoad(id=3, bus=bus6, phases="bc", powers=[1000 + 200j]) +rlf.CurrentLoad(id=4, bus=bus7, phases="abn", currents=[2 + 1j, 0.5 + 0.1j]) +rlf.ImpedanceLoad(id=5, bus=bus7, phases="abn", impedances=[100 + 200j, 300 + 4000j]) + +en = rlf.ElectricalNetwork.from_element(bus1) +en.solve_load_flow() + +en.to_json(OUTPUT, include_results=True) diff --git a/roseau/load_flow/io/tests/data/network_json_v0.json b/roseau/load_flow/io/tests/data/network_json_v0.json new file mode 100644 index 00000000..f5c42d58 --- /dev/null +++ b/roseau/load_flow/io/tests/data/network_json_v0.json @@ -0,0 +1,452 @@ +{ + "buses": [ + { + "id": 1, + "type": "slack", + "loads": [], + "voltages": { + "va": [11547.005383792515, 0.0], + "vb": [-5773.502691896258, -10000.000000179687], + "vc": [-5773.502691896258, 10000.000000179687] + }, + "geometry": "POINT (0 0)" + }, + { + "id": 2, + "type": "bus", + "loads": [ + { + "id": 1, + "function": "ys", + "powers": { + "sa": [41916.482229647016, 20958.241114823508], + "sb": [41916.482230776804, 20958.2411153884], + "sc": [41916.4822307768, 20958.241115388402] + } + } + ], + "geometry": "POINT (0 1)" + }, + { + "id": 3, + "type": "bus_neutral", + "loads": [ + { + "id": 2, + "function": "ys_neutral", + "powers": { + "sa": [40459.7989783205, 20229.89948916025], + "sb": [40459.79897941102, 20229.89948970551], + "sc": [40459.79897941102, 20229.89948970551] + } + } + ], + "geometry": "POINT (0 1)" + }, + { + "id": 4, + "type": "bus_neutral", + "loads": [ + { + "id": 3, + "function": "ys_neutral", + "powers": { + "sa": [37922.04164877094, 18961.020824385465], + "sb": [37922.04164985974, 18961.020824929874], + "sc": [37922.04164980375, 18961.02082490188] + } + } + ], + "geometry": "POINT (0 1)" + }, + { + "id": 5, + "type": "bus_neutral", + "loads": [ + { + "id": 4, + "function": "ys_neutral", + "powers": { + "sa": [40459.798978684, 20229.899489342002], + "sb": [40459.79897977451, 20229.89948988726], + "sc": [40459.798978684004, 20229.899489342002] + } + } + ], + "geometry": "POINT (0 1)" + }, + { + "id": 6, + "type": "bus", + "loads": [ + { + "id": 5, + "function": "ys", + "powers": { + "sa": [41916.48223002361, 20958.24111501181], + "sb": [41916.4822311534, 20958.241115576697], + "sc": [41916.48223002363, 20958.241115011813] + } + } + ], + "geometry": "POINT (0 1)" + }, + { + "id": 7, + "type": "bus_neutral", + "loads": [ + { + "id": 6, + "function": "ys_neutral", + "powers": { + "sa": [40932.79932474136, 20466.399662370677], + "sb": [40932.79932583017, 20466.39966291509], + "sc": [40932.79932479737, 20466.39966239868] + } + } + ], + "geometry": "POINT (0 1)" + }, + { + "id": 8, + "type": "bus", + "loads": [ + { + "id": 7, + "function": "ys", + "powers": { + "sa": [41916.482229647016, 20958.241114823508], + "sb": [41916.482230776804, 20958.241115388402], + "sc": [41916.4822307768, 20958.241115388402] + } + } + ], + "geometry": "POINT (0 1)" + }, + { + "id": 9, + "type": "bus_neutral", + "loads": [ + { + "id": 8, + "function": "ys_neutral", + "powers": { + "sa": [40459.79897832049, 20229.899489160252], + "sb": [40459.79897941102, 20229.89948970551], + "sc": [40459.79897941101, 20229.899489705513] + } + } + ], + "geometry": "POINT (0 1)" + }, + { + "id": 10, + "type": "bus_neutral", + "loads": [ + { + "id": 9, + "function": "ys_neutral", + "powers": { + "sa": [37922.04164877094, 18961.020824385465], + "sb": [37922.04164985973, 18961.020824929878], + "sc": [37922.04164980376, 18961.02082490188] + } + } + ], + "geometry": "POINT (0 1)" + }, + { + "id": 11, + "type": "bus_neutral", + "loads": [ + { + "id": 10, + "function": "ys_neutral", + "powers": { + "sa": [40459.798978684, 20229.899489342002], + "sb": [40459.79897977452, 20229.899489887266], + "sc": [40459.798978684004, 20229.899489342002] + } + } + ], + "geometry": "POINT (0 1)" + }, + { + "id": 12, + "type": "bus", + "loads": [ + { + "id": 11, + "function": "ys", + "powers": { + "sa": [41916.48223002361, 20958.24111501181], + "sb": [41916.4822311534, 20958.241115576693], + "sc": [41916.48223002362, 20958.241115011817] + } + } + ], + "geometry": "POINT (0 1)" + }, + { + "id": 13, + "type": "bus_neutral", + "loads": [ + { + "id": 12, + "function": "ys_neutral", + "powers": { + "sa": [40932.79932474137, 20466.399662370684], + "sb": [40932.79932583017, 20466.399662915086], + "sc": [40932.799324797365, 20466.399662398682] + } + } + ], + "geometry": "POINT (0 1)" + } + ], + "branches": [ + { + "id": "tr1", + "bus1": 1, + "bus2": 2, + "geometry": "POINT (0 0.5)", + "type_name": "160kVA_Dd0", + "tap": 1, + "type": "transformer" + }, + { + "id": "tr2", + "bus1": 1, + "bus2": 3, + "geometry": "POINT (0 0.5)", + "type_name": "160kVA_Yyn0", + "tap": 1, + "type": "transformer" + }, + { + "id": "tr3", + "bus1": 1, + "bus2": 4, + "geometry": "POINT (0 0.5)", + "type_name": "160kVA_Dzn0", + "tap": 1, + "type": "transformer" + }, + { + "id": "tr4", + "bus1": 1, + "bus2": 5, + "geometry": "POINT (0 0.5)", + "type_name": "160kVA_Dyn11", + "tap": 1, + "type": "transformer" + }, + { + "id": "tr5", + "bus1": 1, + "bus2": 6, + "geometry": "POINT (0 0.5)", + "type_name": "160kVA_Yd11", + "tap": 1, + "type": "transformer" + }, + { + "id": "tr6", + "bus1": 1, + "bus2": 7, + "geometry": "POINT (0 0.5)", + "type_name": "160kVA_Yzn11", + "tap": 1, + "type": "transformer" + }, + { + "id": "tr7", + "bus1": 1, + "bus2": 8, + "geometry": "POINT (0 0.5)", + "type_name": "160kVA_Dd6", + "tap": 1, + "type": "transformer" + }, + { + "id": "tr8", + "bus1": 1, + "bus2": 9, + "geometry": "POINT (0 0.5)", + "type_name": "160kVA_Yyn6", + "tap": 1, + "type": "transformer" + }, + { + "id": "tr9", + "bus1": 1, + "bus2": 10, + "geometry": "POINT (0 0.5)", + "type_name": "160kVA_Dzn6", + "tap": 1, + "type": "transformer" + }, + { + "id": "tr10", + "bus1": 1, + "bus2": 11, + "geometry": "POINT (0 0.5)", + "type_name": "160kVA_Dyn5", + "tap": 1, + "type": "transformer" + }, + { + "id": "tr11", + "bus1": 1, + "bus2": 12, + "geometry": "POINT (0 0.5)", + "type_name": "160kVA_Yd5", + "tap": 1, + "type": "transformer" + }, + { + "id": "tr12", + "bus1": 1, + "bus2": 13, + "geometry": "POINT (0 0.5)", + "type_name": "160kVA_Yzn5", + "tap": 1, + "type": "transformer" + } + ], + "line_types": [], + "transformer_types": [ + { + "name": "160kVA_Dd0", + "sn": 160000.0, + "uhv": 20000.0, + "ulv": 400.0, + "i0": 0.023, + "p0": 460.0, + "psc": 2350.0, + "vsc": 0.04, + "type": "dd0" + }, + { + "name": "160kVA_Dd6", + "sn": 160000.0, + "uhv": 20000.0, + "ulv": 400.0, + "i0": 0.023, + "p0": 460.0, + "psc": 2350.0, + "vsc": 0.04, + "type": "dd6" + }, + { + "name": "160kVA_Dyn11", + "sn": 160000.0, + "uhv": 20000.0, + "ulv": 400.0, + "i0": 0.023, + "p0": 460.0, + "psc": 2350.0, + "vsc": 0.04, + "type": "dyn11" + }, + { + "name": "160kVA_Dyn5", + "sn": 160000.0, + "uhv": 20000.0, + "ulv": 400.0, + "i0": 0.023, + "p0": 460.0, + "psc": 2350.0, + "vsc": 0.04, + "type": "dyn5" + }, + { + "name": "160kVA_Dzn0", + "sn": 160000.0, + "uhv": 20000.0, + "ulv": 400.0, + "i0": 0.023, + "p0": 460.0, + "psc": 2350.0, + "vsc": 0.04, + "type": "dzn0" + }, + { + "name": "160kVA_Dzn6", + "sn": 160000.0, + "uhv": 20000.0, + "ulv": 400.0, + "i0": 0.023, + "p0": 460.0, + "psc": 2350.0, + "vsc": 0.04, + "type": "dzn6" + }, + { + "name": "160kVA_Yd11", + "sn": 160000.0, + "uhv": 20000.0, + "ulv": 400.0, + "i0": 0.023, + "p0": 460.0, + "psc": 2350.0, + "vsc": 0.04, + "type": "yd11" + }, + { + "name": "160kVA_Yd5", + "sn": 160000.0, + "uhv": 20000.0, + "ulv": 400.0, + "i0": 0.023, + "p0": 460.0, + "psc": 2350.0, + "vsc": 0.04, + "type": "yd5" + }, + { + "name": "160kVA_Yyn0", + "sn": 160000.0, + "uhv": 20000.0, + "ulv": 400.0, + "i0": 0.023, + "p0": 460.0, + "psc": 2350.0, + "vsc": 0.04, + "type": "yyn0" + }, + { + "name": "160kVA_Yyn6", + "sn": 160000.0, + "uhv": 20000.0, + "ulv": 400.0, + "i0": 0.023, + "p0": 460.0, + "psc": 2350.0, + "vsc": 0.04, + "type": "yyn6" + }, + { + "name": "160kVA_Yzn11", + "sn": 160000.0, + "uhv": 20000.0, + "ulv": 400.0, + "i0": 0.023, + "p0": 460.0, + "psc": 2350.0, + "vsc": 0.04, + "type": "yzn11" + }, + { + "name": "160kVA_Yzn5", + "sn": 160000.0, + "uhv": 20000.0, + "ulv": 400.0, + "i0": 0.023, + "p0": 460.0, + "psc": 2350.0, + "vsc": 0.04, + "type": "yzn5" + } + ] +} diff --git a/roseau/load_flow/io/tests/data/network_json_v0.py b/roseau/load_flow/io/tests/data/network_json_v0.py new file mode 100644 index 00000000..19fc1c6e --- /dev/null +++ b/roseau/load_flow/io/tests/data/network_json_v0.py @@ -0,0 +1,436 @@ +from shapely import Point + +import roseau.load_flow as rlf + +# Buses +buses = { + 1: rlf.Bus(id=1, phases="abcn", geometry=Point(0.0, 0.0)), + 2: rlf.Bus(id=2, phases="abc", geometry=Point(0.0, 1.0)), + 3: rlf.Bus(id=3, phases="abcn", geometry=Point(0.0, 1.0)), + 4: rlf.Bus(id=4, phases="abcn", geometry=Point(0.0, 1.0)), + 5: rlf.Bus(id=5, phases="abcn", geometry=Point(0.0, 1.0)), + 6: rlf.Bus(id=6, phases="abc", geometry=Point(0.0, 1.0)), + 7: rlf.Bus(id=7, phases="abcn", geometry=Point(0.0, 1.0)), + 8: rlf.Bus(id=8, phases="abc", geometry=Point(0.0, 1.0)), + 9: rlf.Bus(id=9, phases="abcn", geometry=Point(0.0, 1.0)), + 10: rlf.Bus(id=10, phases="abcn", geometry=Point(0.0, 1.0)), + 11: rlf.Bus(id=11, phases="abcn", geometry=Point(0.0, 1.0)), + 12: rlf.Bus(id=12, phases="abc", geometry=Point(0.0, 1.0)), + 13: rlf.Bus(id=13, phases="abcn", geometry=Point(0.0, 1.0)), +} + +# Grounds and potential references +ground = rlf.Ground("ground") +for bus_id in (1, 3, 4, 5, 7, 9, 10, 11, 13): + ground.connect(buses[bus_id]) +potential_refs = [ + rlf.PotentialRef(id="pref", element=ground), + rlf.PotentialRef(id="tr12", element=buses[2]), + rlf.PotentialRef(id="tr56", element=buses[6]), + rlf.PotentialRef(id="tr78", element=buses[8]), + rlf.PotentialRef(id="tr1112", element=buses[12]), +] + +# Sources and loads +vs = rlf.VoltageSource( + id=1, + bus=buses[1], + voltages=[ + 11547.005383792515 + 0.0j, + -5773.502691896258 + -10000.000000179687j, + -5773.502691896258 + 10000.000000179687j, + ], + phases="abcn", +) +loads = [ + rlf.PowerLoad( + id=1, + bus=buses[2], + phases="abcn", + powers=[ + 41916.482229647016 + 20958.241114823508j, + 41916.482230776804 + 20958.2411153884j, + 41916.4822307768 + 20958.241115388402j, + ], + ), + rlf.PowerLoad( + id=2, + bus=buses[3], + phases="abcn", + powers=[ + 40459.7989783205 + 20229.89948916025j, + 40459.79897941102 + 20229.89948970551j, + 40459.79897941102 + 20229.89948970551j, + ], + ), + rlf.PowerLoad( + id=3, + bus=buses[4], + phases="abcn", + powers=[ + 37922.04164877094 + 18961.020824385465j, + 37922.04164985974 + 18961.020824929874j, + 37922.04164980375 + 18961.02082490188j, + ], + ), + rlf.PowerLoad( + id=4, + bus=buses[5], + phases="abcn", + powers=[ + 40459.798978684 + 20229.899489342002j, + 40459.79897977451 + 20229.89948988726j, + 40459.798978684004 + 20229.899489342002j, + ], + ), + rlf.PowerLoad( + id=5, + bus=buses[6], + phases="abcn", + powers=[ + 41916.48223002361 + 20958.24111501181j, + 41916.4822311534 + 20958.241115576697j, + 41916.48223002363 + 20958.241115011813j, + ], + ), + rlf.PowerLoad( + id=6, + bus=buses[7], + phases="abcn", + powers=[ + 40932.79932474136 + 20466.399662370677j, + 40932.79932583017 + 20466.39966291509j, + 40932.79932479737 + 20466.39966239868j, + ], + ), + rlf.PowerLoad( + id=7, + bus=buses[8], + phases="abcn", + powers=[ + 41916.482229647016 + 20958.241114823508j, + 41916.482230776804 + 20958.241115388402j, + 41916.4822307768 + 20958.241115388402j, + ], + ), + rlf.PowerLoad( + id=8, + bus=buses[9], + phases="abcn", + powers=[ + 40459.79897832049 + 20229.899489160252j, + 40459.79897941102 + 20229.89948970551j, + 40459.79897941101 + 20229.899489705513j, + ], + ), + rlf.PowerLoad( + id=9, + bus=buses[10], + phases="abcn", + powers=[ + 37922.04164877094 + 18961.020824385465j, + 37922.04164985973 + 18961.020824929878j, + 37922.04164980376 + 18961.02082490188j, + ], + ), + rlf.PowerLoad( + id=10, + bus=buses[11], + phases="abcn", + powers=[ + 40459.798978684 + 20229.899489342002j, + 40459.79897977452 + 20229.899489887266j, + 40459.798978684004 + 20229.899489342002j, + ], + ), + rlf.PowerLoad( + id=11, + bus=buses[12], + phases="abcn", + powers=[ + 41916.48223002361 + 20958.24111501181j, + 41916.4822311534 + 20958.241115576693j, + 41916.48223002362 + 20958.241115011817j, + ], + ), + rlf.PowerLoad( + id=12, + bus=buses[13], + phases="abcn", + powers=[ + 40932.79932474137 + 20466.399662370684j, + 40932.79932583017 + 20466.399662915086j, + 40932.799324797365 + 20466.399662398682j, + ], + ), +] + +# Transformers +tp = { + "160kVA_Dd0": rlf.TransformerParameters.from_open_and_short_circuit_tests( + id="160kVA_Dd0", + vg="dd0", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Dd6": rlf.TransformerParameters.from_open_and_short_circuit_tests( + id="160kVA_Dd6", + vg="dd6", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Dyn11": rlf.TransformerParameters.from_open_and_short_circuit_tests( + id="160kVA_Dyn11", + vg="dyn11", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Dyn5": rlf.TransformerParameters.from_open_and_short_circuit_tests( + id="160kVA_Dyn5", + vg="dyn5", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Dzn0": rlf.TransformerParameters.from_open_and_short_circuit_tests( + id="160kVA_Dzn0", + vg="dzn0", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Dzn6": rlf.TransformerParameters.from_open_and_short_circuit_tests( + id="160kVA_Dzn6", + vg="dzn6", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Yd11": rlf.TransformerParameters.from_open_and_short_circuit_tests( + id="160kVA_Yd11", + vg="yd11", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Yd5": rlf.TransformerParameters.from_open_and_short_circuit_tests( + id="160kVA_Yd5", + vg="yd5", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Yyn0": rlf.TransformerParameters.from_open_and_short_circuit_tests( + id="160kVA_Yyn0", + vg="yyn0", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Yyn6": rlf.TransformerParameters.from_open_and_short_circuit_tests( + id="160kVA_Yyn6", + vg="yyn6", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Yzn11": rlf.TransformerParameters.from_open_and_short_circuit_tests( + id="160kVA_Yzn11", + vg="yzn11", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), + "160kVA_Yzn5": rlf.TransformerParameters.from_open_and_short_circuit_tests( + id="160kVA_Yzn5", + vg="yzn5", + sn=160000.0, + uhv=20000.0, + ulv=400.0, + i0=0.023, + p0=460.0, + psc=2350.0, + vsc=0.04, + ), +} +p = Point(0.0, 0.5) +transformers = [ + rlf.Transformer( + id="tr1", + bus1=buses[1], + bus2=buses[2], + phases1="abc", + phases2="abc", + parameters=tp["160kVA_Dd0"], + tap=1, + geometry=p, + ), + rlf.Transformer( + id="tr2", + bus1=buses[1], + bus2=buses[3], + phases1="abcn", + phases2="abcn", + parameters=tp["160kVA_Yyn0"], + tap=1, + geometry=p, + ), + rlf.Transformer( + id="tr3", + bus1=buses[1], + bus2=buses[4], + phases1="abc", + phases2="abcn", + parameters=tp["160kVA_Dzn0"], + tap=1, + geometry=p, + ), + rlf.Transformer( + id="tr4", + bus1=buses[1], + bus2=buses[5], + phases1="abc", + phases2="abcn", + parameters=tp["160kVA_Dyn11"], + tap=1, + geometry=p, + ), + rlf.Transformer( + id="tr5", + bus1=buses[1], + bus2=buses[6], + phases1="abcn", + phases2="abc", + parameters=tp["160kVA_Yd11"], + tap=1, + geometry=p, + ), + rlf.Transformer( + id="tr6", + bus1=buses[1], + bus2=buses[7], + phases1="abcn", + phases2="abcn", + parameters=tp["160kVA_Yzn11"], + tap=1, + geometry=p, + ), + rlf.Transformer( + id="tr7", + bus1=buses[1], + bus2=buses[8], + phases1="abc", + phases2="abc", + parameters=tp["160kVA_Dd6"], + tap=1, + geometry=p, + ), + rlf.Transformer( + id="tr8", + bus1=buses[1], + bus2=buses[9], + phases1="abcn", + phases2="abcn", + parameters=tp["160kVA_Yyn6"], + tap=1, + geometry=p, + ), + rlf.Transformer( + id="tr9", + bus1=buses[1], + bus2=buses[10], + phases1="abc", + phases2="abcn", + parameters=tp["160kVA_Dzn6"], + tap=1, + geometry=p, + ), + rlf.Transformer( + id="tr10", + bus1=buses[1], + bus2=buses[11], + phases1="abc", + phases2="abcn", + parameters=tp["160kVA_Dyn5"], + tap=1, + geometry=p, + ), + rlf.Transformer( + id="tr11", + bus1=buses[1], + bus2=buses[12], + phases1="abcn", + phases2="abc", + parameters=tp["160kVA_Yd5"], + tap=1, + geometry=p, + ), + rlf.Transformer( + id="tr12", + bus1=buses[1], + bus2=buses[13], + phases1="abcn", + phases2="abcn", + parameters=tp["160kVA_Yzn5"], + tap=1, + geometry=p, + ), +] + +en = rlf.ElectricalNetwork( + buses=buses, + lines=[], + transformers=transformers, + switches=[], + loads=loads, + sources=[vs], + grounds=[ground], + potential_refs=potential_refs, +) diff --git a/roseau/load_flow/io/tests/data/network_json_v1.json b/roseau/load_flow/io/tests/data/network_json_v1.json new file mode 100644 index 00000000..224d351b --- /dev/null +++ b/roseau/load_flow/io/tests/data/network_json_v1.json @@ -0,0 +1,627 @@ +{ + "version": 1, + "grounds": [ + { + "id": "gnd", + "buses": [ + { + "id": 3, + "phase": "n" + }, + { + "id": 5, + "phase": "n" + } + ], + "results": { + "potential": [0.0, 0.0] + } + } + ], + "potential_refs": [ + { + "id": "pref", + "ground": "gnd", + "results": { + "current": [-8.881784197001252e-16, 6.556977183436175e-13] + } + } + ], + "buses": [ + { + "id": 1, + "phases": "abc", + "geometry": { + "type": "Point", + "coordinates": [0.0, 0.0] + }, + "min_voltage": 19000.0, + "max_voltage": 21000.0, + "results": { + "potentials": [ + [10000.000000002889, -5773.502691896624], + [-9999.999999997111, -5773.502691896624], + [2.8848055359251603e-9, 11547.00538379215] + ] + } + }, + { + "id": 5, + "phases": "abcn", + "geometry": { + "type": "Point", + "coordinates": [0.0, 2.0] + }, + "min_voltage": 207, + "max_voltage": 253, + "results": { + "potentials": [ + [178.53990652297716, 98.01308155630096], + [-178.62029648184554, -98.02888948768953], + [-173.10176674777532, 303.37964761055053], + [0.0, 0.0] + ] + } + }, + { + "id": 7, + "phases": "abn", + "geometry": { + "type": "Point", + "coordinates": [0.0, 3.0] + }, + "min_voltage": 207, + "max_voltage": 253, + "results": { + "potentials": [ + [177.57971987964694, 97.84178319043295], + [-178.78556926267257, -98.07890216126165], + [1.125459424157262, 0.22131103944013428] + ] + } + }, + { + "id": 6, + "phases": "bc", + "geometry": { + "type": "Point", + "coordinates": [0.0, 3.0] + }, + "min_voltage": 207, + "max_voltage": 253, + "results": { + "potentials": [ + [-178.43390394553083, -97.15554902195422], + [-173.28815928409006, 302.50630714481525] + ] + } + }, + { + "id": 4, + "phases": "abcn", + "geometry": { + "type": "Point", + "coordinates": [0.0, 2.0] + }, + "min_voltage": 207, + "max_voltage": 253, + "results": { + "potentials": [ + [236.29626929786735, -3.144010468821578], + [-120.9207132685627, -199.19464477654748], + [-115.37555602930465, 202.33865524536907], + [0.0, 0.0] + ] + } + }, + { + "id": 3, + "phases": "abcn", + "geometry": { + "type": "Point", + "coordinates": [0.0, 1.0] + }, + "min_voltage": 207, + "max_voltage": 253, + "results": { + "potentials": [ + [236.5716312279474, 0.10332847536841476], + [-118.59114268514145, -204.7595068372243], + [-117.98048854280593, 204.6561783618559], + [0.0, 0.0] + ] + } + }, + { + "id": 2, + "phases": "abc", + "geometry": { + "type": "Point", + "coordinates": [0.0, 1.0] + }, + "min_voltage": 19000.0, + "max_voltage": 21000.0, + "results": { + "potentials": [ + [9985.05926003559, -5751.173645614685], + [-9973.510516153096, -5771.035488411508], + [-11.548743873832889, 11522.209134025094] + ] + } + } + ], + "branches": [ + { + "id": 1, + "type": "line", + "phases1": "abc", + "phases2": "abc", + "bus1": 1, + "bus2": 2, + "geometry": { + "type": "LineString", + "coordinates": [ + [0.0, 0.0], + [1.0, 0.0] + ] + }, + "results": { + "currents1": [ + [4.2976503612585475, -6.329727509125632], + [-7.539556441973673, -0.7549152814617628], + [3.2419060807146662, 7.084642790587623] + ], + "currents2": [ + [-4.240026979571212, 6.429652805425803], + [7.597279132874974, 0.6550477288810725], + [-3.3572521533037523, -7.084700534307103] + ] + }, + "length": 10.0, + "params_id": 1, + "ground": "gnd" + }, + { + "id": 7, + "type": "line", + "phases1": "abn", + "phases2": "abn", + "bus1": 5, + "bus2": 7, + "geometry": { + "type": "LineString", + "coordinates": [ + [0.0, 2.0], + [0.0, 3.0] + ] + }, + "results": { + "currents1": [ + [2.743390409514908, 0.4894239024800332], + [0.47220794522006926, 0.1428933530632191], + [-3.215598354735034, -0.6323172555432408] + ], + "currents2": [ + [-2.743390409514908, -0.4894239024800332], + [-0.47220794522006926, -0.1428933530632191], + [3.215598354735034, 0.6323172555432408] + ] + }, + "length": 1.0, + "params_id": 4 + }, + { + "id": 6, + "type": "line", + "phases1": "bc", + "phases2": "bc", + "bus1": 5, + "bus2": 6, + "geometry": { + "type": "LineString", + "coordinates": [ + [0.0, 2.0], + [0.0, 3.0] + ] + }, + "results": { + "currents1": [ + [-0.5325501037563234, -2.495258473529459], + [0.5325501037564047, 2.4952584735293777] + ], + "currents2": [ + [0.5325501037563234, 2.495258473529459], + [-0.5325501037564047, -2.4952584735293777] + ] + }, + "length": 1.0, + "params_id": 3 + }, + { + "id": 5, + "type": "transformer", + "phases1": "ab", + "phases2": "abn", + "bus1": 4, + "bus2": 5, + "geometry": { + "type": "Point", + "coordinates": [0.0, 2.0] + }, + "results": { + "currents1": [ + [0.7867483716572168, 9.278111269114268], + [-0.7867483716572168, -9.278111269114268] + ], + "currents2": [ + [-2.7433904095149506, -0.48942390248002704], + [-0.4722079452200835, -0.1428933530632136], + [3.2155983547350337, 0.6323172555432406] + ] + }, + "tap": 1.0, + "params_id": "3" + }, + { + "id": 2, + "type": "line", + "phases1": "abcn", + "phases2": "abcn", + "bus1": 3, + "bus2": 4, + "geometry": { + "type": "LineString", + "coordinates": [ + [0.0, 1.0], + [0.0, 2.0] + ] + }, + "results": { + "currents1": [ + [0.7867483716572516, 9.278111269114266], + [6.655915952632126, -15.899605887648088], + [-7.442664324289378, 6.621494618533786], + [0.0, 0.0] + ], + "currents2": [ + [-0.7867483716572516, -9.278111269114266], + [-6.655915952632126, 15.899605887648088], + [7.442664324289378, -6.621494618533786], + [-0.0, -0.0] + ] + }, + "length": 1.0, + "params_id": 2 + }, + { + "id": 4, + "type": "transformer", + "phases1": "bc", + "phases2": "bc", + "bus1": 4, + "bus2": 5, + "geometry": { + "type": "Point", + "coordinates": [0.0, 2.0] + }, + "results": { + "currents1": [ + [7.442664324289386, -6.621494618534029], + [-7.442664324289386, 6.621494618534029] + ], + "currents2": [ + [0.532550103756364, 2.4952584735297023], + [-0.532550103756364, -2.4952584735297023] + ] + }, + "tap": 1.0, + "params_id": "2" + }, + { + "id": 3, + "type": "transformer", + "phases1": "abc", + "phases2": "abcn", + "bus1": 2, + "bus2": 3, + "geometry": { + "type": "Point", + "coordinates": [0.0, 1.0] + }, + "results": { + "currents1": [ + [-0.2429410786685595, -0.5703595420346648], + [-0.2814982836285917, 0.29766984455899637], + [0.5244393622971513, 0.2726896974756685] + ], + "currents2": [ + [-0.7867483716570987, -9.278111269114644], + [-6.655915952633352, 15.899605887647411], + [7.4426643242904404, -6.621494618533509], + [1.0658141036401503e-14, 7.425171588693047e-13] + ] + }, + "tap": 1.025, + "params_id": "SE_Minera_AA0Ak_160kVA" + } + ], + "loads": [ + { + "id": 4, + "bus": 7, + "phases": "abn", + "currents": [ + [2.0, 1.0], + [0.5, 0.1] + ], + "results": { + "currents": [ + [2.0, 1.0], + [0.5, 0.1], + [-2.5, -1.1] + ] + } + }, + { + "id": 5, + "bus": 7, + "phases": "abn", + "impedances": [ + [100.0, 200.0], + [300.0, 4000.0] + ], + "results": { + "currents": [ + [0.7433904095149506, -0.5105760975199731], + [-0.027792054779916475, 0.04289335306321372], + [-0.7155983547350342, 0.4676827444567594] + ] + } + }, + { + "id": 3, + "bus": 6, + "phases": "bc", + "powers": [[1000.0, 200.0]], + "results": { + "currents": [ + [-0.5325501037563766, -2.4952584735294656], + [0.5325501037563766, 2.4952584735294656] + ] + } + }, + { + "id": 1, + "bus": 2, + "phases": "abc", + "powers": [ + [38000.0, 12489.9959967968], + [38000.0, 12489.9959967968], + [38000.0, 12489.9959967968] + ], + "results": { + "currents": [ + [2.316630772078475, -2.585342850824369], + [-3.3972879757172825, -0.713589666297376], + [1.0806572036388076, 3.2989325171217447] + ], + "powers": [ + [38000.45121136502, 12491.455729992955], + [38001.03864058266, 12488.87543118307], + [37998.51014805233, 12489.656829214382] + ] + }, + "flexible_params": [ + { + "control_p": { + "type": "p_max_u_consumption", + "u_min": 18000.0, + "u_down": 19000.0, + "alpha": 1000.0, + "epsilon": 1e-8 + }, + "control_q": { + "type": "constant" + }, + "projection": { + "type": "euclidean", + "alpha": 1000.0, + "epsilon": 1e-8 + }, + "s_max": 45000.0 + }, + { + "control_p": { + "type": "p_max_u_consumption", + "u_min": 18000.0, + "u_down": 19000.0, + "alpha": 1000.0, + "epsilon": 1e-8 + }, + "control_q": { + "type": "constant" + }, + "projection": { + "type": "euclidean", + "alpha": 1000.0, + "epsilon": 1e-8 + }, + "s_max": 45000.0 + }, + { + "control_p": { + "type": "p_max_u_consumption", + "u_min": 18000.0, + "u_down": 19000.0, + "alpha": 1000.0, + "epsilon": 1e-8 + }, + "control_q": { + "type": "constant" + }, + "projection": { + "type": "euclidean", + "alpha": 1000.0, + "epsilon": 1e-8 + }, + "s_max": 45000.0 + } + ] + }, + { + "id": 2, + "bus": 2, + "phases": "abc", + "powers": [ + [40459.7989783205, 20229.89948916025], + [40459.79897941102, 20229.89948970551], + [40459.79897941102, 20229.89948970551] + ], + "results": { + "currents": [ + [2.166337286161528, -3.273950412566573], + [-3.9184928735292957, -0.23912790714230758], + [1.7521555873677672, 3.513078319708881] + ] + } + } + ], + "sources": [ + { + "id": 1, + "bus": 1, + "phases": "abc", + "voltages": [ + [20000.0, 0.0], + [-9999.999999999996, -17320.508075688773], + [-9999.999999999996, 17320.508075688773] + ], + "results": { + "currents": [ + [-4.297650361259068, 6.3297275091254726], + [7.539556441973733, 0.754915281461497], + [-3.241906080714666, -7.08464279058697] + ] + } + } + ], + "lines_params": [ + { + "id": 1, + "z_line": [ + [ + [0.35, 0.0, 0.0], + [0.0, 0.35, 0.0], + [0.0, 0.0, 0.35] + ], + [ + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0] + ] + ], + "y_shunt": [ + [ + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0] + ], + [ + [1e-6, 0.0, 0.0], + [0.0, 1e-6, 0.0], + [0.0, 0.0, 1e-6] + ] + ], + "max_current": 250, + "line_type": "UNDERGROUND", + "conductor_type": "AL", + "insulator_type": "PVC", + "section": 240.0 + }, + { + "id": 2, + "z_line": [ + [ + [0.35, 0.0, 0.0, 0.0], + [0.0, 0.35, 0.0, 0.0], + [0.0, 0.0, 0.35, 0.0], + [0.0, 0.0, 0.0, 0.35] + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0] + ] + ], + "max_current": 160, + "line_type": "OVERHEAD", + "conductor_type": "CU", + "section": 150.0 + }, + { + "id": 3, + "z_line": [ + [ + [0.35, 0.0], + [0.0, 0.35] + ], + [ + [0.0, 0.0], + [0.0, 0.0] + ] + ] + }, + { + "id": 4, + "z_line": [ + [ + [0.35, 0.0, 0.0], + [0.0, 0.35, 0.0], + [0.0, 0.0, 0.35] + ], + [ + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0] + ] + ] + } + ], + "transformers_params": [ + { + "id": "2", + "sn": 10000.0, + "uhv": 400, + "ulv": 400, + "type": "single", + "z2": [0.05, 0.0], + "ym": [0.01, 0.02], + "max_power": 10000.0 + }, + { + "id": "3", + "sn": 10000.0, + "uhv": 400, + "ulv": 400, + "type": "center", + "z2": [0.05, 0.0], + "ym": [0.01, 0.02], + "max_power": 10000.0 + }, + { + "id": "SE_Minera_AA0Ak_160kVA", + "sn": 160000, + "uhv": 20000, + "ulv": 400, + "type": "Dyn11", + "z2": [0.010937500000000001, 0.038475590882402315], + "ym": [1.5749999999999997e-7, -1.9999379834134858e-5], + "i0": 0.15, + "p0": 189, + "psc": 1750, + "vsc": 0.04, + "max_power": 200000.0 + } + ] +} diff --git a/roseau/load_flow/io/tests/data/network_json_v2.json b/roseau/load_flow/io/tests/data/network_json_v2.json index edd8828f..dae4f28a 100644 --- a/roseau/load_flow/io/tests/data/network_json_v2.json +++ b/roseau/load_flow/io/tests/data/network_json_v2.json @@ -13,13 +13,19 @@ "id": 5, "phase": "n" } - ] + ], + "results": { + "potential": [0.0, 0.0] + } } ], "potential_refs": [ { "id": "pref", - "ground": "gnd" + "ground": "gnd", + "results": { + "current": [-8.881784197001252e-16, 6.556977183436175e-13] + } } ], "buses": [ @@ -31,7 +37,14 @@ "coordinates": [0.0, 0.0] }, "min_voltage": 19000.0, - "max_voltage": 21000.0 + "max_voltage": 21000.0, + "results": { + "potentials": [ + [10000.000000002889, -5773.502691896624], + [-9999.999999997111, -5773.502691896624], + [2.8848055359251603e-9, 11547.00538379215] + ] + } }, { "id": 5, @@ -41,7 +54,48 @@ "coordinates": [0.0, 2.0] }, "min_voltage": 207, - "max_voltage": 253 + "max_voltage": 253, + "results": { + "potentials": [ + [178.53990652297716, 98.01308155630096], + [-178.62029648184554, -98.02888948768953], + [-173.10176674777532, 303.37964761055053], + [0.0, 0.0] + ] + } + }, + { + "id": 7, + "phases": "abn", + "geometry": { + "type": "Point", + "coordinates": [0.0, 3.0] + }, + "min_voltage": 207, + "max_voltage": 253, + "results": { + "potentials": [ + [177.57971987964694, 97.84178319043295], + [-178.78556926267257, -98.07890216126165], + [1.125459424157262, 0.22131103944013428] + ] + } + }, + { + "id": 6, + "phases": "bc", + "geometry": { + "type": "Point", + "coordinates": [0.0, 3.0] + }, + "min_voltage": 207, + "max_voltage": 253, + "results": { + "potentials": [ + [-178.43390394553083, -97.15554902195422], + [-173.28815928409006, 302.50630714481525] + ] + } }, { "id": 4, @@ -51,7 +105,15 @@ "coordinates": [0.0, 2.0] }, "min_voltage": 207, - "max_voltage": 253 + "max_voltage": 253, + "results": { + "potentials": [ + [236.29626929786735, -3.144010468821578], + [-120.9207132685627, -199.19464477654748], + [-115.37555602930465, 202.33865524536907], + [0.0, 0.0] + ] + } }, { "id": 3, @@ -61,7 +123,15 @@ "coordinates": [0.0, 1.0] }, "min_voltage": 207, - "max_voltage": 253 + "max_voltage": 253, + "results": { + "potentials": [ + [236.5716312279474, 0.10332847536841476], + [-118.59114268514145, -204.7595068372243], + [-117.98048854280593, 204.6561783618559], + [0.0, 0.0] + ] + } }, { "id": 2, @@ -71,7 +141,14 @@ "coordinates": [0.0, 1.0] }, "min_voltage": 19000.0, - "max_voltage": 21000.0 + "max_voltage": 21000.0, + "results": { + "potentials": [ + [9985.05926003559, -5751.173645614685], + [-9973.510516153096, -5771.035488411508], + [-11.548743873832889, 11522.209134025094] + ] + } } ], "lines": [ @@ -89,6 +166,70 @@ [0.0, 0.0], [1.0, 0.0] ] + }, + "results": { + "currents1": [ + [4.2976503612585475, -6.329727509125632], + [-7.539556441973673, -0.7549152814617628], + [3.2419060807146662, 7.084642790587623] + ], + "currents2": [ + [-4.240026979571212, 6.429652805425803], + [7.597279132874974, 0.6550477288810725], + [-3.3572521533037523, -7.084700534307103] + ] + } + }, + { + "id": 4, + "phases": "abn", + "bus1": 5, + "bus2": 7, + "length": 1.0, + "params_id": 4, + "geometry": { + "type": "LineString", + "coordinates": [ + [0.0, 2.0], + [0.0, 3.0] + ] + }, + "results": { + "currents1": [ + [2.743390409514908, 0.4894239024800332], + [0.47220794522006926, 0.1428933530632191], + [-3.215598354735034, -0.6323172555432408] + ], + "currents2": [ + [-2.743390409514908, -0.4894239024800332], + [-0.47220794522006926, -0.1428933530632191], + [3.215598354735034, 0.6323172555432408] + ] + } + }, + { + "id": 3, + "phases": "bc", + "bus1": 5, + "bus2": 6, + "length": 1.0, + "params_id": 3, + "geometry": { + "type": "LineString", + "coordinates": [ + [0.0, 2.0], + [0.0, 3.0] + ] + }, + "results": { + "currents1": [ + [-0.5325501037563234, -2.495258473529459], + [0.5325501037564047, 2.4952584735293777] + ], + "currents2": [ + [0.5325501037563234, 2.495258473529459], + [-0.5325501037564047, -2.4952584735293777] + ] } }, { @@ -104,6 +245,20 @@ [0.0, 1.0], [0.0, 2.0] ] + }, + "results": { + "currents1": [ + [0.7867483716572516, 9.278111269114266], + [6.655915952632126, -15.899605887648088], + [-7.442664324289378, 6.621494618533786], + [0.0, 0.0] + ], + "currents2": [ + [-0.7867483716572516, -9.278111269114266], + [-6.655915952632126, 15.899605887648088], + [7.442664324289378, -6.621494618533786], + [-0.0, -0.0] + ] } } ], @@ -118,6 +273,17 @@ "type": "Point", "coordinates": [0.0, 2.0] }, + "results": { + "currents1": [ + [0.7867483716572168, 9.278111269114268], + [-0.7867483716572168, -9.278111269114268] + ], + "currents2": [ + [-2.7433904095149506, -0.48942390248002704], + [-0.4722079452200835, -0.1428933530632136], + [3.2155983547350337, 0.6323172555432406] + ] + }, "tap": 1.0, "params_id": "3" }, @@ -131,6 +297,16 @@ "type": "Point", "coordinates": [0.0, 2.0] }, + "results": { + "currents1": [ + [7.442664324289386, -6.621494618534029], + [-7.442664324289386, 6.621494618534029] + ], + "currents2": [ + [0.532550103756364, 2.4952584735297023], + [-0.532550103756364, -2.4952584735297023] + ] + }, "tap": 1.0, "params_id": "2" }, @@ -144,12 +320,89 @@ "type": "Point", "coordinates": [0.0, 1.0] }, + "results": { + "currents1": [ + [-0.2429410786685595, -0.5703595420346648], + [-0.2814982836285917, 0.29766984455899637], + [0.5244393622971513, 0.2726896974756685] + ], + "currents2": [ + [-0.7867483716570987, -9.278111269114644], + [-6.655915952633352, 15.899605887647411], + [7.4426643242904404, -6.621494618533509], + [1.0658141036401503e-14, 7.425171588693047e-13] + ] + }, "tap": 1.025, "params_id": "SE_Minera_AA0Ak_160kVA" } ], "switches": [], "loads": [ + { + "id": 4, + "bus": 7, + "phases": "abn", + "type": "current", + "currents": [ + [2.0, 1.0], + [0.5, 0.1] + ], + "connect_neutral": null, + "results": { + "currents": [ + [2.0, 1.0], + [0.5, 0.1], + [-2.5, -1.1] + ], + "potentials": [ + [177.57971987964694, 97.84178319043295], + [-178.78556926267257, -98.07890216126165], + [1.125459424157262, 0.22131103944013428] + ] + } + }, + { + "id": 5, + "bus": 7, + "phases": "abn", + "type": "impedance", + "impedances": [ + [100.0, 200.0], + [300.0, 4000.0] + ], + "connect_neutral": null, + "results": { + "currents": [ + [0.7433904095149506, -0.5105760975199731], + [-0.027792054779916475, 0.04289335306321372], + [-0.7155983547350342, 0.4676827444567594] + ], + "potentials": [ + [177.57971987964694, 97.84178319043295], + [-178.78556926267257, -98.07890216126165], + [1.125459424157262, 0.22131103944013428] + ] + } + }, + { + "id": 3, + "bus": 6, + "phases": "bc", + "type": "power", + "powers": [[1000.0, 200.0]], + "connect_neutral": null, + "results": { + "currents": [ + [-0.5325501037563766, -2.4952584735294656], + [0.5325501037563766, 2.4952584735294656] + ], + "potentials": [ + [-178.43390394553083, -97.15554902195422], + [-173.28815928409006, 302.50630714481525] + ] + } + }, { "id": 1, "bus": 2, @@ -161,6 +414,23 @@ [38000.0, 12489.9959967968] ], "connect_neutral": null, + "results": { + "currents": [ + [2.316630772078475, -2.585342850824369], + [-3.3972879757172825, -0.713589666297376], + [1.0806572036388076, 3.2989325171217447] + ], + "potentials": [ + [9985.05926003559, -5751.173645614685], + [-9973.510516153096, -5771.035488411508], + [-11.548743873832889, 11522.209134025094] + ], + "flexible_powers": [ + [38000.00000000001, 12489.9959967968], + [37999.99999999999, 12489.9959967968], + [38000.00000000001, 12489.9959967968] + ] + }, "flexible_params": [ { "control_p": { @@ -228,7 +498,19 @@ [40459.79897941102, 20229.89948970551], [40459.79897941102, 20229.89948970551] ], - "connect_neutral": null + "connect_neutral": null, + "results": { + "currents": [ + [2.166337286161528, -3.273950412566573], + [-3.9184928735292957, -0.23912790714230758], + [1.7521555873677672, 3.513078319708881] + ], + "potentials": [ + [9985.05926003559, -5751.173645614685], + [-9973.510516153096, -5771.035488411508], + [-11.548743873832889, 11522.209134025094] + ] + } } ], "sources": [ @@ -241,7 +523,19 @@ [-9999.999999999996, -17320.508075688773], [-9999.999999999996, 17320.508075688773] ], - "connect_neutral": null + "connect_neutral": null, + "results": { + "currents": [ + [-4.297650361259068, 6.3297275091254726], + [7.539556441973733, 0.754915281461497], + [-3.241906080714666, -7.08464279058697] + ], + "potentials": [ + [10000.000000002889, -5773.502691896624], + [-9999.999999997111, -5773.502691896624], + [2.8848055359251603e-9, 11547.00538379215] + ] + } } ], "lines_params": [ @@ -297,6 +591,34 @@ "line_type": "OVERHEAD", "conductor_type": "CU", "section": 150.0 + }, + { + "id": 3, + "z_line": [ + [ + [0.35, 0.0], + [0.0, 0.35] + ], + [ + [0.0, 0.0], + [0.0, 0.0] + ] + ] + }, + { + "id": 4, + "z_line": [ + [ + [0.35, 0.0, 0.0], + [0.0, 0.35, 0.0], + [0.0, 0.0, 0.35] + ], + [ + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0] + ] + ] } ], "transformers_params": [ @@ -338,6 +660,7 @@ "p0": 189, "psc": 1750, "vsc": 0.04, + "max_power": 200000.0, "manufacturer": "SE", "range": "Minera", "efficiency": "AA0Ak" diff --git a/roseau/load_flow/io/tests/test_dict.py b/roseau/load_flow/io/tests/test_dict.py index 665354b4..8ccf8125 100644 --- a/roseau/load_flow/io/tests/test_dict.py +++ b/roseau/load_flow/io/tests/test_dict.py @@ -1,29 +1,47 @@ import copy +import hashlib import importlib.resources as resources import json +import warnings import numpy as np import pytest from shapely import LineString, Point from roseau.load_flow.exceptions import RoseauLoadFlowException, RoseauLoadFlowExceptionCode -from roseau.load_flow.io.dict import v0_to_v1_converter, v1_to_v2_converter, v2_to_v3_converter +from roseau.load_flow.io.dict import NETWORK_JSON_VERSION, v0_to_v1_converter, v1_to_v2_converter, v2_to_v3_converter from roseau.load_flow.models import ( Bus, Ground, Line, LineParameters, PotentialRef, - PowerLoad, Transformer, TransformerParameters, VoltageSource, ) from roseau.load_flow.network import ElectricalNetwork from roseau.load_flow.testing import assert_json_close -from roseau.load_flow.typing import JsonDict from roseau.load_flow.utils import Insulator, LineType, Material +# Store the expected hashes of the files that should not be modified +EXPECTED_HASHES = { + "network_json_v0.json": "ad984cbcd26b36602a2789e2f0badcb5", + "network_json_v1.json": "fc930431b69165f68961b0f0dc2635b5", + "network_json_v2.json": "d85a2658708576c083ceab666a83150b", +} + + +def read_json_file(filename: str) -> str: + return (resources.files("roseau.load_flow.io") / "tests" / "data" / filename).read_text() + + +def ignore_unmatched_warnings(warn_check, /) -> None: + """Ignore unmatched warnings in the pytest.warns context manager.""" + for w in warn_check: + if not warn_check.matches(w): + warn_check.list.remove(w) + def test_to_dict(): ground = Ground("ground") @@ -175,1279 +193,113 @@ def test_to_dict(): assert "geometry" in res["transformers"][1] -def test_v0_to_v3_converter(): - # Do not change `dict_v0` or the network manually, add/update the converters until the test passes - - dict_v0 = { - "buses": [ - { - "id": 1, - "type": "slack", - "loads": [], - "voltages": { - "va": [11547.005383792515, 0.0], - "vb": [-5773.502691896258, -10000.000000179687], - "vc": [-5773.502691896258, 10000.000000179687], - }, - "geometry": "POINT (0 0)", - }, - { - "id": 2, - "type": "bus", - "loads": [ - { - "id": 1, - "function": "ys", - "powers": { - "sa": [41916.482229647016, 20958.241114823508], - "sb": [41916.482230776804, 20958.2411153884], - "sc": [41916.4822307768, 20958.241115388402], - }, - } - ], - "geometry": "POINT (0 1)", - }, - { - "id": 3, - "type": "bus_neutral", - "loads": [ - { - "id": 2, - "function": "ys_neutral", - "powers": { - "sa": [40459.7989783205, 20229.89948916025], - "sb": [40459.79897941102, 20229.89948970551], - "sc": [40459.79897941102, 20229.89948970551], - }, - } - ], - "geometry": "POINT (0 1)", - }, - { - "id": 4, - "type": "bus_neutral", - "loads": [ - { - "id": 3, - "function": "ys_neutral", - "powers": { - "sa": [37922.04164877094, 18961.020824385465], - "sb": [37922.04164985974, 18961.020824929874], - "sc": [37922.04164980375, 18961.02082490188], - }, - } - ], - "geometry": "POINT (0 1)", - }, - { - "id": 5, - "type": "bus_neutral", - "loads": [ - { - "id": 4, - "function": "ys_neutral", - "powers": { - "sa": [40459.798978684, 20229.899489342002], - "sb": [40459.79897977451, 20229.89948988726], - "sc": [40459.798978684004, 20229.899489342002], - }, - } - ], - "geometry": "POINT (0 1)", - }, - { - "id": 6, - "type": "bus", - "loads": [ - { - "id": 5, - "function": "ys", - "powers": { - "sa": [41916.48223002361, 20958.24111501181], - "sb": [41916.4822311534, 20958.241115576697], - "sc": [41916.48223002363, 20958.241115011813], - }, - } - ], - "geometry": "POINT (0 1)", - }, - { - "id": 7, - "type": "bus_neutral", - "loads": [ - { - "id": 6, - "function": "ys_neutral", - "powers": { - "sa": [40932.79932474136, 20466.399662370677], - "sb": [40932.79932583017, 20466.39966291509], - "sc": [40932.79932479737, 20466.39966239868], - }, - } - ], - "geometry": "POINT (0 1)", - }, - { - "id": 8, - "type": "bus", - "loads": [ - { - "id": 7, - "function": "ys", - "powers": { - "sa": [41916.482229647016, 20958.241114823508], - "sb": [41916.482230776804, 20958.241115388402], - "sc": [41916.4822307768, 20958.241115388402], - }, - } - ], - "geometry": "POINT (0 1)", - }, - { - "id": 9, - "type": "bus_neutral", - "loads": [ - { - "id": 8, - "function": "ys_neutral", - "powers": { - "sa": [40459.79897832049, 20229.899489160252], - "sb": [40459.79897941102, 20229.89948970551], - "sc": [40459.79897941101, 20229.899489705513], - }, - } - ], - "geometry": "POINT (0 1)", - }, - { - "id": 10, - "type": "bus_neutral", - "loads": [ - { - "id": 9, - "function": "ys_neutral", - "powers": { - "sa": [37922.04164877094, 18961.020824385465], - "sb": [37922.04164985973, 18961.020824929878], - "sc": [37922.04164980376, 18961.02082490188], - }, - } - ], - "geometry": "POINT (0 1)", - }, - { - "id": 11, - "type": "bus_neutral", - "loads": [ - { - "id": 10, - "function": "ys_neutral", - "powers": { - "sa": [40459.798978684, 20229.899489342002], - "sb": [40459.79897977452, 20229.899489887266], - "sc": [40459.798978684004, 20229.899489342002], - }, - } - ], - "geometry": "POINT (0 1)", - }, - { - "id": 12, - "type": "bus", - "loads": [ - { - "id": 11, - "function": "ys", - "powers": { - "sa": [41916.48223002361, 20958.24111501181], - "sb": [41916.4822311534, 20958.241115576693], - "sc": [41916.48223002362, 20958.241115011817], - }, - } - ], - "geometry": "POINT (0 1)", - }, - { - "id": 13, - "type": "bus_neutral", - "loads": [ - { - "id": 12, - "function": "ys_neutral", - "powers": { - "sa": [40932.79932474137, 20466.399662370684], - "sb": [40932.79932583017, 20466.399662915086], - "sc": [40932.799324797365, 20466.399662398682], - }, - } - ], - "geometry": "POINT (0 1)", - }, - ], - "branches": [ - { - "id": "tr1", - "bus1": 1, - "bus2": 2, - "geometry": "POINT (0 0.5)", - "type_name": "160kVA_Dd0", - "tap": 1.0, - "type": "transformer", - }, - { - "id": "tr2", - "bus1": 1, - "bus2": 3, - "geometry": "POINT (0 0.5)", - "type_name": "160kVA_Yyn0", - "tap": 1.0, - "type": "transformer", - }, - { - "id": "tr3", - "bus1": 1, - "bus2": 4, - "geometry": "POINT (0 0.5)", - "type_name": "160kVA_Dzn0", - "tap": 1.0, - "type": "transformer", - }, - { - "id": "tr4", - "bus1": 1, - "bus2": 5, - "geometry": "POINT (0 0.5)", - "type_name": "160kVA_Dyn11", - "tap": 1.0, - "type": "transformer", - }, - { - "id": "tr5", - "bus1": 1, - "bus2": 6, - "geometry": "POINT (0 0.5)", - "type_name": "160kVA_Yd11", - "tap": 1.0, - "type": "transformer", - }, - { - "id": "tr6", - "bus1": 1, - "bus2": 7, - "geometry": "POINT (0 0.5)", - "type_name": "160kVA_Yzn11", - "tap": 1.0, - "type": "transformer", - }, - { - "id": "tr7", - "bus1": 1, - "bus2": 8, - "geometry": "POINT (0 0.5)", - "type_name": "160kVA_Dd6", - "tap": 1.0, - "type": "transformer", - }, - { - "id": "tr8", - "bus1": 1, - "bus2": 9, - "geometry": "POINT (0 0.5)", - "type_name": "160kVA_Yyn6", - "tap": 1.0, - "type": "transformer", - }, - { - "id": "tr9", - "bus1": 1, - "bus2": 10, - "geometry": "POINT (0 0.5)", - "type_name": "160kVA_Dzn6", - "tap": 1.0, - "type": "transformer", - }, - { - "id": "tr10", - "bus1": 1, - "bus2": 11, - "geometry": "POINT (0 0.5)", - "type_name": "160kVA_Dyn5", - "tap": 1.0, - "type": "transformer", - }, - { - "id": "tr11", - "bus1": 1, - "bus2": 12, - "geometry": "POINT (0 0.5)", - "type_name": "160kVA_Yd5", - "tap": 1.0, - "type": "transformer", - }, - { - "id": "tr12", - "bus1": 1, - "bus2": 13, - "geometry": "POINT (0 0.5)", - "type_name": "160kVA_Yzn5", - "tap": 1.0, - "type": "transformer", - }, - ], - "line_types": [], - "transformer_types": [ - { - "name": "160kVA_Dd0", - "sn": 160000.0, - "uhv": 20000.0, - "ulv": 400.0, - "i0": 0.023, - "p0": 460.0, - "psc": 2350.0, - "vsc": 0.04, - "type": "dd0", - }, - { - "name": "160kVA_Dd6", - "sn": 160000.0, - "uhv": 20000.0, - "ulv": 400.0, - "i0": 0.023, - "p0": 460.0, - "psc": 2350.0, - "vsc": 0.04, - "type": "dd6", - }, - { - "name": "160kVA_Dyn11", - "sn": 160000.0, - "uhv": 20000.0, - "ulv": 400.0, - "i0": 0.023, - "p0": 460.0, - "psc": 2350.0, - "vsc": 0.04, - "type": "dyn11", - }, - { - "name": "160kVA_Dyn5", - "sn": 160000.0, - "uhv": 20000.0, - "ulv": 400.0, - "i0": 0.023, - "p0": 460.0, - "psc": 2350.0, - "vsc": 0.04, - "type": "dyn5", - }, - { - "name": "160kVA_Dzn0", - "sn": 160000.0, - "uhv": 20000.0, - "ulv": 400.0, - "i0": 0.023, - "p0": 460.0, - "psc": 2350.0, - "vsc": 0.04, - "type": "dzn0", - }, - { - "name": "160kVA_Dzn6", - "sn": 160000.0, - "uhv": 20000.0, - "ulv": 400.0, - "i0": 0.023, - "p0": 460.0, - "psc": 2350.0, - "vsc": 0.04, - "type": "dzn6", - }, - { - "name": "160kVA_Yd11", - "sn": 160000.0, - "uhv": 20000.0, - "ulv": 400.0, - "i0": 0.023, - "p0": 460.0, - "psc": 2350.0, - "vsc": 0.04, - "type": "yd11", - }, - { - "name": "160kVA_Yd5", - "sn": 160000.0, - "uhv": 20000.0, - "ulv": 400.0, - "i0": 0.023, - "p0": 460.0, - "psc": 2350.0, - "vsc": 0.04, - "type": "yd5", - }, - { - "name": "160kVA_Yyn0", - "sn": 160000.0, - "uhv": 20000.0, - "ulv": 400.0, - "i0": 0.023, - "p0": 460.0, - "psc": 2350.0, - "vsc": 0.04, - "type": "yyn0", - }, - { - "name": "160kVA_Yyn6", - "sn": 160000.0, - "uhv": 20000.0, - "ulv": 400.0, - "i0": 0.023, - "p0": 460.0, - "psc": 2350.0, - "vsc": 0.04, - "type": "yyn6", - }, - { - "name": "160kVA_Yzn11", - "sn": 160000.0, - "uhv": 20000.0, - "ulv": 400.0, - "i0": 0.023, - "p0": 460.0, - "psc": 2350.0, - "vsc": 0.04, - "type": "yzn11", - }, - { - "name": "160kVA_Yzn5", - "sn": 160000.0, - "uhv": 20000.0, - "ulv": 400.0, - "i0": 0.023, - "p0": 460.0, - "psc": 2350.0, - "vsc": 0.04, - "type": "yzn5", - }, - ], - } - - # Buses - buses = { - 1: Bus(id=1, phases="abcn", geometry=Point(0.0, 0.0)), - 2: Bus(id=2, phases="abc", geometry=Point(0.0, 1.0)), - 3: Bus(id=3, phases="abcn", geometry=Point(0.0, 1.0)), - 4: Bus(id=4, phases="abcn", geometry=Point(0.0, 1.0)), - 5: Bus(id=5, phases="abcn", geometry=Point(0.0, 1.0)), - 6: Bus(id=6, phases="abc", geometry=Point(0.0, 1.0)), - 7: Bus(id=7, phases="abcn", geometry=Point(0.0, 1.0)), - 8: Bus(id=8, phases="abc", geometry=Point(0.0, 1.0)), - 9: Bus(id=9, phases="abcn", geometry=Point(0.0, 1.0)), - 10: Bus(id=10, phases="abcn", geometry=Point(0.0, 1.0)), - 11: Bus(id=11, phases="abcn", geometry=Point(0.0, 1.0)), - 12: Bus(id=12, phases="abc", geometry=Point(0.0, 1.0)), - 13: Bus(id=13, phases="abcn", geometry=Point(0.0, 1.0)), - } - - # Grounds and potential references - ground = Ground("ground") - for bus_id in (1, 3, 4, 5, 7, 9, 10, 11, 13): - ground.connect(buses[bus_id]) - potential_refs = [ - PotentialRef(id="pref", element=ground), - PotentialRef(id="tr12", element=buses[2]), - PotentialRef(id="tr56", element=buses[6]), - PotentialRef(id="tr78", element=buses[8]), - PotentialRef(id="tr1112", element=buses[12]), - ] +def test_all_converters(): + from roseau.load_flow.io.tests.data.network_json_v0 import en - # Sources and loads - vs = VoltageSource( - id=1, - bus=buses[1], - voltages=[ - 11547.005383792515 + 0.0j, - -5773.502691896258 + -10000.000000179687j, - -5773.502691896258 + 10000.000000179687j, - ], - phases="abcn", - ) - loads = [ - PowerLoad( - id=1, - bus=buses[2], - phases="abcn", - powers=[ - 41916.482229647016 + 20958.241114823508j, - 41916.482230776804 + 20958.2411153884j, - 41916.4822307768 + 20958.241115388402j, - ], - ), - PowerLoad( - id=2, - bus=buses[3], - phases="abcn", - powers=[ - 40459.7989783205 + 20229.89948916025j, - 40459.79897941102 + 20229.89948970551j, - 40459.79897941102 + 20229.89948970551j, - ], - ), - PowerLoad( - id=3, - bus=buses[4], - phases="abcn", - powers=[ - 37922.04164877094 + 18961.020824385465j, - 37922.04164985974 + 18961.020824929874j, - 37922.04164980375 + 18961.02082490188j, - ], - ), - PowerLoad( - id=4, - bus=buses[5], - phases="abcn", - powers=[ - 40459.798978684 + 20229.899489342002j, - 40459.79897977451 + 20229.89948988726j, - 40459.798978684004 + 20229.899489342002j, - ], - ), - PowerLoad( - id=5, - bus=buses[6], - phases="abcn", - powers=[ - 41916.48223002361 + 20958.24111501181j, - 41916.4822311534 + 20958.241115576697j, - 41916.48223002363 + 20958.241115011813j, - ], - ), - PowerLoad( - id=6, - bus=buses[7], - phases="abcn", - powers=[ - 40932.79932474136 + 20466.399662370677j, - 40932.79932583017 + 20466.39966291509j, - 40932.79932479737 + 20466.39966239868j, - ], - ), - PowerLoad( - id=7, - bus=buses[8], - phases="abcn", - powers=[ - 41916.482229647016 + 20958.241114823508j, - 41916.482230776804 + 20958.241115388402j, - 41916.4822307768 + 20958.241115388402j, - ], - ), - PowerLoad( - id=8, - bus=buses[9], - phases="abcn", - powers=[ - 40459.79897832049 + 20229.899489160252j, - 40459.79897941102 + 20229.89948970551j, - 40459.79897941101 + 20229.899489705513j, - ], - ), - PowerLoad( - id=9, - bus=buses[10], - phases="abcn", - powers=[ - 37922.04164877094 + 18961.020824385465j, - 37922.04164985973 + 18961.020824929878j, - 37922.04164980376 + 18961.02082490188j, - ], - ), - PowerLoad( - id=10, - bus=buses[11], - phases="abcn", - powers=[ - 40459.798978684 + 20229.899489342002j, - 40459.79897977452 + 20229.899489887266j, - 40459.798978684004 + 20229.899489342002j, - ], - ), - PowerLoad( - id=11, - bus=buses[12], - phases="abcn", - powers=[ - 41916.48223002361 + 20958.24111501181j, - 41916.4822311534 + 20958.241115576693j, - 41916.48223002362 + 20958.241115011817j, - ], - ), - PowerLoad( - id=12, - bus=buses[13], - phases="abcn", - powers=[ - 40932.79932474137 + 20466.399662370684j, - 40932.79932583017 + 20466.399662915086j, - 40932.799324797365 + 20466.399662398682j, - ], - ), - ] + dict_v0 = json.loads(read_json_file("network_json_v0.json")) + net_dict = en.to_dict(include_results=False) + expected_dict = copy.deepcopy(dict_v0) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + expected_dict = v0_to_v1_converter(expected_dict) + expected_dict = v1_to_v2_converter(expected_dict) + expected_dict = v2_to_v3_converter(expected_dict) + assert_json_close(net_dict, expected_dict) - # Transformers - tp = { - "160kVA_Dd0": TransformerParameters.from_open_and_short_circuit_tests( - id="160kVA_Dd0", - vg="dd0", - sn=160000.0, - uhv=20000.0, - ulv=400.0, - i0=0.023, - p0=460.0, - psc=2350.0, - vsc=0.04, - ), - "160kVA_Dd6": TransformerParameters.from_open_and_short_circuit_tests( - id="160kVA_Dd6", - vg="dd6", - sn=160000.0, - uhv=20000.0, - ulv=400.0, - i0=0.023, - p0=460.0, - psc=2350.0, - vsc=0.04, - ), - "160kVA_Dyn11": TransformerParameters.from_open_and_short_circuit_tests( - id="160kVA_Dyn11", - vg="dyn11", - sn=160000.0, - uhv=20000.0, - ulv=400.0, - i0=0.023, - p0=460.0, - psc=2350.0, - vsc=0.04, - ), - "160kVA_Dyn5": TransformerParameters.from_open_and_short_circuit_tests( - id="160kVA_Dyn5", - vg="dyn5", - sn=160000.0, - uhv=20000.0, - ulv=400.0, - i0=0.023, - p0=460.0, - psc=2350.0, - vsc=0.04, - ), - "160kVA_Dzn0": TransformerParameters.from_open_and_short_circuit_tests( - id="160kVA_Dzn0", - vg="dzn0", - sn=160000.0, - uhv=20000.0, - ulv=400.0, - i0=0.023, - p0=460.0, - psc=2350.0, - vsc=0.04, - ), - "160kVA_Dzn6": TransformerParameters.from_open_and_short_circuit_tests( - id="160kVA_Dzn6", - vg="dzn6", - sn=160000.0, - uhv=20000.0, - ulv=400.0, - i0=0.023, - p0=460.0, - psc=2350.0, - vsc=0.04, - ), - "160kVA_Yd11": TransformerParameters.from_open_and_short_circuit_tests( - id="160kVA_Yd11", - vg="yd11", - sn=160000.0, - uhv=20000.0, - ulv=400.0, - i0=0.023, - p0=460.0, - psc=2350.0, - vsc=0.04, - ), - "160kVA_Yd5": TransformerParameters.from_open_and_short_circuit_tests( - id="160kVA_Yd5", - vg="yd5", - sn=160000.0, - uhv=20000.0, - ulv=400.0, - i0=0.023, - p0=460.0, - psc=2350.0, - vsc=0.04, - ), - "160kVA_Yyn0": TransformerParameters.from_open_and_short_circuit_tests( - id="160kVA_Yyn0", - vg="yyn0", - sn=160000.0, - uhv=20000.0, - ulv=400.0, - i0=0.023, - p0=460.0, - psc=2350.0, - vsc=0.04, - ), - "160kVA_Yyn6": TransformerParameters.from_open_and_short_circuit_tests( - id="160kVA_Yyn6", - vg="yyn6", - sn=160000.0, - uhv=20000.0, - ulv=400.0, - i0=0.023, - p0=460.0, - psc=2350.0, - vsc=0.04, - ), - "160kVA_Yzn11": TransformerParameters.from_open_and_short_circuit_tests( - id="160kVA_Yzn11", - vg="yzn11", - sn=160000.0, - uhv=20000.0, - ulv=400.0, - i0=0.023, - p0=460.0, - psc=2350.0, - vsc=0.04, - ), - "160kVA_Yzn5": TransformerParameters.from_open_and_short_circuit_tests( - id="160kVA_Yzn5", - vg="yzn5", - sn=160000.0, - uhv=20000.0, - ulv=400.0, - i0=0.023, - p0=460.0, - psc=2350.0, - vsc=0.04, - ), - } - p = Point(0.0, 0.5) - transformers = [ - Transformer( - id="tr1", - bus1=buses[1], - bus2=buses[2], - phases1="abc", - phases2="abc", - parameters=tp["160kVA_Dd0"], - tap=1, - geometry=p, - ), - Transformer( - id="tr2", - bus1=buses[1], - bus2=buses[3], - phases1="abcn", - phases2="abcn", - parameters=tp["160kVA_Yyn0"], - tap=1, - geometry=p, - ), - Transformer( - id="tr3", - bus1=buses[1], - bus2=buses[4], - phases1="abc", - phases2="abcn", - parameters=tp["160kVA_Dzn0"], - tap=1, - geometry=p, - ), - Transformer( - id="tr4", - bus1=buses[1], - bus2=buses[5], - phases1="abc", - phases2="abcn", - parameters=tp["160kVA_Dyn11"], - tap=1, - geometry=p, - ), - Transformer( - id="tr5", - bus1=buses[1], - bus2=buses[6], - phases1="abcn", - phases2="abc", - parameters=tp["160kVA_Yd11"], - tap=1, - geometry=p, - ), - Transformer( - id="tr6", - bus1=buses[1], - bus2=buses[7], - phases1="abcn", - phases2="abcn", - parameters=tp["160kVA_Yzn11"], - tap=1, - geometry=p, - ), - Transformer( - id="tr7", - bus1=buses[1], - bus2=buses[8], - phases1="abc", - phases2="abc", - parameters=tp["160kVA_Dd6"], - tap=1, - geometry=p, - ), - Transformer( - id="tr8", - bus1=buses[1], - bus2=buses[9], - phases1="abcn", - phases2="abcn", - parameters=tp["160kVA_Yyn6"], - tap=1, - geometry=p, - ), - Transformer( - id="tr9", - bus1=buses[1], - bus2=buses[10], - phases1="abc", - phases2="abcn", - parameters=tp["160kVA_Dzn6"], - tap=1, - geometry=p, - ), - Transformer( - id="tr10", - bus1=buses[1], - bus2=buses[11], - phases1="abc", - phases2="abcn", - parameters=tp["160kVA_Dyn5"], - tap=1, - geometry=p, - ), - Transformer( - id="tr11", - bus1=buses[1], - bus2=buses[12], - phases1="abcn", - phases2="abc", - parameters=tp["160kVA_Yd5"], - tap=1, - geometry=p, - ), - Transformer( - id="tr12", - bus1=buses[1], - bus2=buses[13], - phases1="abcn", - phases2="abcn", - parameters=tp["160kVA_Yzn5"], - tap=1, - geometry=p, - ), - ] - net = ElectricalNetwork( - buses=buses, - lines=[], - transformers=transformers, - switches=[], - loads=loads, - sources=[vs], - grounds=[ground], - potential_refs=potential_refs, - ) +def test_from_dict_v0(): + dict_v0 = json.loads(read_json_file("network_json_v0.json")) - net_dict = net.to_dict(include_results=False) - expected_dict = dict_v0 - expected_dict = v0_to_v1_converter(expected_dict) - expected_dict = v1_to_v2_converter(expected_dict) - expected_dict = v2_to_v3_converter(expected_dict) - # Uncomment the following lines as needed when new versions are added - # expected_dict = v2_to_v3_converter(expected_dict) - # expected_dict = v3_to_v4_converter(expected_dict) + with pytest.warns(UserWarning, match=r"Got an outdated network file \(version 0\)") as warn_check: + en = ElectricalNetwork.from_dict(data=dict_v0, include_results=False) + ignore_unmatched_warnings(warn_check) + net_dict = en.to_dict(include_results=False) + expected_dict = copy.deepcopy(dict_v0) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + expected_dict = v0_to_v1_converter(expected_dict) + expected_dict = v1_to_v2_converter(expected_dict) + expected_dict = v2_to_v3_converter(expected_dict) assert_json_close(net_dict, expected_dict) -def test_v1_to_v2_converter(): - # Do not change `dict_v1` or the network manually, add/update the converters until the test passes - - dict_v1 = { - "version": 1, - "grounds": [], - "potential_refs": [ - { - "id": "pref", - "bus": 1, - "phases": None, - "results": {"current": [-7.771563289958464e-16, -2.220444725761333e-16]}, - } - ], - "buses": [ - { - "id": 1, - "phases": "abc", - "geometry": {"type": "Point", "coordinates": (0.0, 0.0)}, - "results": { - "potentials": [ - [5773.502691896258, -3333.3333333932287], - [-5773.502691896258, -3333.3333333932287], - [9.888685758712307e-24, 6666.666666786457], - ] - }, - }, - { - "id": 2, - "phases": "abc", - "geometry": {"type": "Point", "coordinates": (0.0, 1.0)}, - "results": { - "potentials": [ - [5772.521060368325, -3330.7830499173137], - [-5770.803265855299, -3333.7583572908047], - [-1.7177945130259364, 6664.5414072081185], - ] - }, - }, - ], - "branches": [ - { - "id": 1, - "type": "line", - "phases1": "abc", - "phases2": "abc", - "bus1": 1, - "bus2": 2, - "geometry": {"type": "LineString", "coordinates": ((0.0, 0.0), (1.0, 0.0))}, - "results": { - "currents1": [ - [2.804661508377779, -7.286524216899904], - [-7.712645831309471, 1.214353993074318], - [4.907984322931247, 6.072170223825586], - ], - "currents2": [ - [-2.804661508377779, 7.286524216899904], - [7.712645831309471, -1.214353993074318], - [-4.907984322931247, -6.072170223825586], - ], - }, - "length": 1.0, - "params_id": "lp", - } - ], - "loads": [ - { - "id": 1, - "bus": 2, - "phases": "abc", - "powers": [ - [38000.0, 12489.9959967968], - [38000.0, 12489.9959967968], - [38000.0, 12489.9959967968], - ], - "results": { - "currents": [ - [-0.9366300237736715, -1.623256890969888], - [-0.9374666925612338, 1.6227738400201663], - [1.8740967163349054, 0.00048305094972167506], - ], - "powers": [ - [-0.0, 12489.9959967968], - [-0.0, 12489.9959967968], - [-0.0, 12489.9959967968], - ], - }, - "flexible_params": [ - { - "control_p": { - "type": "p_max_u_consumption", - "u_min": 18000, - "u_down": 19000, - "alpha": 1000.0, - "epsilon": 1e-08, - }, - "control_q": {"type": "constant"}, - "projection": {"type": "euclidean", "alpha": 1000.0, "epsilon": 1e-08}, - "s_max": 45000.0, - }, - { - "control_p": { - "type": "p_max_u_consumption", - "u_min": 18000, - "u_down": 19000, - "alpha": 1000.0, - "epsilon": 1e-08, - }, - "control_q": {"type": "constant"}, - "projection": {"type": "euclidean", "alpha": 1000.0, "epsilon": 1e-08}, - "s_max": 45000.0, - }, - { - "control_p": { - "type": "p_max_u_consumption", - "u_min": 18000, - "u_down": 19000, - "alpha": 1000.0, - "epsilon": 1e-08, - }, - "control_q": {"type": "constant"}, - "projection": {"type": "euclidean", "alpha": 1000.0, "epsilon": 1e-08}, - "s_max": 45000.0, - }, - ], - }, - { - "id": 2, - "bus": 2, - "phases": "abc", - "powers": [ - [40459.7989783205, 20229.89948916025], - [40459.79897941102, 20229.89948970551], - [40459.79897941102, 20229.89948970551], - ], - "results": { - "currents": [ - [3.7412915321516125, -5.663267325930873], - [-6.775179138747953, -0.40841984694689626], - [3.0338876065963407, 6.07168717287777], - ] - }, - }, - ], - "sources": [ - { - "id": 1, - "bus": 1, - "phases": "abc", - "voltages": [ - [11547.005383792515, 0.0], - [-5773.502691896258, -10000.000000179687], - [-5773.502691896258, 10000.000000179687], - ], - "results": { - "currents": [ - [-2.80466150837794, 7.286524216900761], - [7.712645831309187, -1.2143539930732696], - [-4.907984322931247, -6.0721702238274915], - ] - }, - } - ], - "lines_params": [ - { - "id": "lp", - "z_line": [ - [[0.35, 0.0, 0.0], [0.0, 0.35, 0.0], [0.0, 0.0, 0.35]], - [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], - ], - } - ], - "transformers_params": [], - } +def test_from_dict_v1(): + dict_v1 = json.loads(read_json_file("network_json_v1.json")) - # # Buses - # buses = { - # 1: Bus(id=1, phases="abc", geometry=Point(0.0, 0.0)), - # 2: Bus(id=2, phases="abc", geometry=Point(0.0, 1.0)), - # } - # - # # Potential reference - # potential_ref = PotentialRef(id="pref", element=buses[1]) - # - # # Sources and loads - # vs = VoltageSource( - # id=1, - # bus=buses[1], - # voltages=[ - # 11547.005383792515 + 0.0j, - # -5773.502691896258 + -10000.000000179687j, - # -5773.502691896258 + 10000.000000179687j, - # ], - # phases="abc", - # ) - # fp = FlexibleParameter( - # control_p=Control.p_max_u_consumption(u_min=18_000, u_down=19_000), - # control_q=Control.constant(), - # projection=Projection(type="euclidean"), - # s_max=45e3, - # ) - # power = cmath.rect(40e3, math.acos(0.95)) - # loads = [ - # PowerLoad(id=1, bus=buses[2], phases="abc", powers=[power, power, power], flexible_params=[fp, fp, fp]), - # PowerLoad( - # id=2, - # bus=buses[2], - # phases="abc", - # powers=[ - # 40459.7989783205 + 20229.89948916025j, - # 40459.79897941102 + 20229.89948970551j, - # 40459.79897941102 + 20229.89948970551j, - # ], - # ), - # ] - # - # line_parameters = LineParameters(id="lp", z_line=0.35 * np.eye(3, dtype=complex)) - # lines = { - # 1: Line( - # id=1, - # bus1=buses[1], - # bus2=buses[2], - # parameters=line_parameters, - # length=1.0, - # geometry=LineString([(0, 0), (1, 0)]), - # ) - # } - # - # net = ElectricalNetwork( - # buses=buses, - # lines=lines, - # transformers=[], - # switches=[], - # loads=loads, - # sources=[vs], - # grounds=[], - # potential_refs=[potential_ref], - # ) - - # Include results=True - net = ElectricalNetwork.from_dict(data=copy.deepcopy(dict_v1), include_results=True) - net_dict = net.to_dict(include_results=True) + with pytest.warns(UserWarning, match=r"Got an outdated network file \(version 1\)") as warn_check: + en = ElectricalNetwork.from_dict(data=dict_v1, include_results=True) + ignore_unmatched_warnings(warn_check) + net_dict = en.to_dict(include_results=True) expected_dict = copy.deepcopy(dict_v1) - expected_dict = v1_to_v2_converter(expected_dict) - expected_dict = v2_to_v3_converter(expected_dict) - assert_json_close(net_dict, expected_dict) - - # Include results=False - def _delete(d: JsonDict, k: str) -> JsonDict: - if k in d: - d.pop(k) - return d - - net = ElectricalNetwork.from_dict(data=copy.deepcopy(dict_v1), include_results=False) - net_dict = net.to_dict(include_results=False) - dict_v1_without_results = { - k: [_delete(d=x, k="results") for x in v] if isinstance(v, list) else v - for k, v in copy.deepcopy(dict_v1).items() - } - expected_dict = copy.deepcopy(dict_v1_without_results) - expected_dict = v1_to_v2_converter(expected_dict) - expected_dict = v2_to_v3_converter(expected_dict) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + expected_dict = v1_to_v2_converter(expected_dict) + expected_dict = v2_to_v3_converter(expected_dict) assert_json_close(net_dict, expected_dict) - -def test_v2_to_v3_converter(): - # Do not change `"network_json_v2.json"`, add/update the converter until the test passes - dict_v2 = json.loads( - (resources.files("roseau.load_flow.io") / "tests" / "data" / "network_json_v2.json").read_text() - ) - - # Include results=True - net = ElectricalNetwork.from_dict(data=copy.deepcopy(dict_v2), include_results=True) - net_dict = net.to_dict(include_results=True) - expected_dict = copy.deepcopy(dict_v2) - with pytest.warns( - UserWarning, - match=( - r"Starting with version 0.11.0 of roseau-load-flow \(JSON file v3\), `min_voltage` and " - r"`max_voltage` are replaced with `min_voltage_level`, `max_voltage_level` and " - r"`nominal_voltage`. The found values of `min_voltage` or `max_voltage` are dropped." + # Test with `include_results=False` + def remove_results(obj: object, /) -> None: + """Recursively remove the 'results' key from a JSON structure.""" + if isinstance(obj, dict): + if "results" in obj: + del obj["results"] + for v in obj.values(): + remove_results(v) + elif isinstance(obj, list): + for x in obj: + remove_results(x) + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + net = ElectricalNetwork.from_dict(data=dict_v1, include_results=False) + net_dict = net.to_dict(include_results=False) + expected_dict_no_results = copy.deepcopy(dict_v1) + remove_results(expected_dict_no_results) + expected_dict_no_results = v1_to_v2_converter(expected_dict_no_results) + expected_dict_no_results = v2_to_v3_converter(expected_dict_no_results) + assert_json_close(net_dict, expected_dict_no_results) + + +def test_from_dict_v2(): + dict_v2 = json.loads(read_json_file("network_json_v2.json")) + + with ( + pytest.warns(UserWarning, match=r"Got an outdated network file \(version 2\)"), + pytest.warns( + UserWarning, + match=( + r"Starting with version 0.11.0 of roseau-load-flow \(JSON file v3\), `min_voltage` and " + r"`max_voltage` are replaced with `min_voltage_level`, `max_voltage_level` and " + r"`nominal_voltage`. The found values of `min_voltage` or `max_voltage` are dropped." + ), ), ): + en = ElectricalNetwork.from_dict(data=dict_v2, include_results=True) + net_dict = en.to_dict(include_results=True) + expected_dict = copy.deepcopy(dict_v2) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") expected_dict = v2_to_v3_converter(expected_dict) assert_json_close(net_dict, expected_dict) - -def test_v2_to_v3_converter_max_loading(): - # Dict v2 (test the max_power -> max_loading conversion) - # import roseau.load_flow as rlf - # - # bus1 = rlf.Bus(id=1, phases="abc") - # bus2 = rlf.Bus(id=2, phases="abc") - # data = { - # "id": "Yzn11 - 50kVA", - # "z2": rlf.Q_(8.64 + 9.444j, "centiohm"), # Ohm - # "ym": rlf.Q_(0.3625 - 2.2206j, "uS"), # S - # "ulv": rlf.Q_(400, "V"), # V - # "uhv": rlf.Q_(20, "kV"), # V - # "sn": rlf.Q_(50, "kVA"), # VA - # "vg": "yzn11", - # "max_power": rlf.Q_(60, "kVA"), - # } - # tp = rlf.TransformerParameters(**data) - # t = rlf.Transformer(id="t", bus1=bus1, bus2=bus2, parameters=tp) - # vs = rlf.VoltageSource(id="vs", bus=bus1, voltages=20_000) - # p_ref = rlf.PotentialRef(id="pref", element=bus1) - # p_ref2 = rlf.PotentialRef(id="pref2", element=bus2) - # en = rlf.ElectricalNetwork.from_element(bus1) - # en.to_json("test_max_power.json") - dict_v2 = { - "version": 2, - "is_multiphase": True, - "grounds": [], - "potential_refs": [{"id": "pref", "bus": 1, "phases": None}, {"id": "pref2", "bus": 2, "phases": None}], - "buses": [{"id": 1, "phases": "abc"}, {"id": 2, "phases": "abc"}], - "lines": [], - "transformers": [ - { - "id": "t", - "phases1": "abc", - "phases2": "abc", - "bus1": 1, - "bus2": 2, - "tap": 1.0, - "params_id": "Yzn11 - 50kVA", - } - ], - "switches": [], - "loads": [], - "sources": [ - { - "id": "vs", - "bus": 1, - "phases": "abc", - "voltages": [ - [20000.0, 0.0], - [-10000.000000000007, -17320.50807568877], - [-9999.999999999996, 17320.508075688773], - ], - "connect_neutral": None, - } - ], - "lines_params": [], - "transformers_params": [ - { - "id": "Yzn11 - 50kVA", - "sn": 50000.0, - "uhv": 20000.0, - "ulv": 400.0, - "type": "yzn11", - "z2": [0.0864, 0.09444000000000001], - "ym": [3.6249999999999997e-07, -2.2206e-06], - "max_power": 60000.0, - } - ], - } - dict_v3 = v2_to_v3_converter(copy.deepcopy(dict_v2)) - tp_data = dict_v3["transformers_params"][0] - assert tp_data["sn"] == 50000.0 - assert "max_power" not in tp_data - t_data = dict_v3["transformers"][0] - assert t_data["params_id"] == "Yzn11 - 50kVA" - assert t_data["max_loading"] == 60 / 50 - - # The same without max_power in the original transformer parameter - dict_v2_bis = copy.deepcopy(dict_v2) - dict_v2_bis["transformers_params"][0].pop("max_power") - dict_v3 = v2_to_v3_converter(dict_v2_bis) - tp_data = dict_v3["transformers_params"][0] - assert tp_data["sn"] == 50000.0 - assert "max_power" not in tp_data - t_data = dict_v3["transformers"][0] - assert t_data["params_id"] == "Yzn11 - 50kVA" - assert t_data["max_loading"] == 1 + # Test max loading of transformers + for tr in en.transformers.values(): + tp_data = next(tp_d for tp_d in dict_v2["transformers_params"] if tp_d["id"] == tr.parameters.id) + assert tr.max_loading.m == tp_data["max_power"] / tp_data["sn"] + + +@pytest.mark.parametrize("version", list(range(NETWORK_JSON_VERSION))) +def test_json_files_not_modified(version): + """Test that the JSON files have not been modified when refactoring the code.""" + filename = f"network_json_v{version}.json" + dict_data = read_json_file(filename) + digest = hashlib.md5(dict_data.encode()).hexdigest() + if filename not in EXPECTED_HASHES: + # Add the computed hash to EXPECTED_HASHES (after formatting the file with prettier) + raise AssertionError(f"Hash of '{filename}' is not in EXPECTED_HASHES.\nComputed hash: {digest}") + elif EXPECTED_HASHES[filename] != digest: + raise AssertionError( + f"Hash of '{filename}' has changed. Do not change the content of this file or update the hash " + f"for formatting-only changes.\nExpected hash: {EXPECTED_HASHES[filename]}\nComputed hash: {digest}" + )