Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bugs in JSON serialization #291

Merged
merged 3 commits into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ og:description: See what's new in the latest release of Roseau Load Flow !

## Unreleased

- {gh-pr}`291` Fixed several bugs in JSON serialization and deserialization.
- {gh-pr}`289` Improve the `TransformerParameters` class and the transformers catalogue

- Add 15kV transformers to the catalogue (SE and FT)
Expand Down
61 changes: 45 additions & 16 deletions roseau/load_flow/io/dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,18 @@ 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:
if version <= 0:
data = v0_to_v1_converter(data)
include_results = False # V0 network dictionaries didn't have results
if version == 1:
if version <= 1:
data = v1_to_v2_converter(data)
if version == 2:
if version <= 2:
data = v2_to_v3_converter(data)
else:
# If we arrive here, we dealt with all legacy versions, it must be the current one
Expand Down Expand Up @@ -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)
Expand All @@ -195,12 +206,22 @@ def network_from_dict( # noqa: C901
id = transformer_data["id"]
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, 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)
Expand Down Expand Up @@ -302,13 +323,13 @@ def network_to_dict(en: "ElectricalNetwork", *, include_results: bool) -> JsonDi
line_params: list[JsonDict] = []
for lp in lines_params_dict.values():
line_params.append(lp.to_dict(include_results=include_results))
line_params.sort(key=lambda x: x["id"]) # Always keep the same order
line_params.sort(key=lambda x: (type(x["id"]).__name__, str(x["id"]))) # Always keep the same order

# Transformer parameters
transformer_params: list[JsonDict] = []
for tp in transformers_params_dict.values():
transformer_params.append(tp.to_dict(include_results=include_results))
transformer_params.sort(key=lambda x: x["id"]) # Always keep the same order
transformer_params.sort(key=lambda x: (type(x["id"]).__name__, str(x["id"]))) # Always keep the same order

res = {
"version": NETWORK_JSON_VERSION,
Expand Down Expand Up @@ -629,7 +650,7 @@ def v1_to_v2_converter(data: JsonDict) -> JsonDict:
return results


def v2_to_v3_converter(data: JsonDict) -> JsonDict:
def v2_to_v3_converter(data: JsonDict) -> JsonDict: # noqa: C901
"""Convert a v2 network dict to a v3 network dict.

Args:
Expand Down Expand Up @@ -663,9 +684,17 @@ def v2_to_v3_converter(data: JsonDict) -> JsonDict:
transformers_params = []
transformers_params_max_loading = {}
for transformer_param_data in old_transformers_params:
transformer_param_data["vg"] = transformer_param_data.pop("type")
vg = transformer_param_data.pop("type")
if vg == "single":
vg = "Ii0"
elif vg == "center":
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
Expand All @@ -676,14 +705,14 @@ def v2_to_v3_converter(data: JsonDict) -> JsonDict:
lines_params = []
for line_param_data in old_lines_params:
size = len(line_param_data["z_line"][0])
if (maximal_current := line_param_data.pop("maximal_current", None)) is not None:
if (maximal_current := line_param_data.pop("max_current", None)) is not None:
line_param_data["ampacities"] = [maximal_current] * size
if (section := line_param_data.pop("section", None)) is not None:
line_param_data["sections"] = [section] * size
if (conductor_type := line_param_data.pop("conductor_types", None)) is not None:
if (conductor_type := line_param_data.pop("conductor_type", None)) is not None:
line_param_data["materials"] = [conductor_type] * size
if (
(insulator_type := line_param_data.pop("insulator_types", None)) is not None
(insulator_type := line_param_data.pop("insulator_type", None)) is not None
) and insulator_type.lower() != "unknown":
line_param_data["insulators"] = [insulator_type] * size
lines_params.append(line_param_data)
Expand All @@ -699,7 +728,7 @@ def v2_to_v3_converter(data: JsonDict) -> JsonDict:
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 = {
Expand Down
13 changes: 13 additions & 0 deletions roseau/load_flow/io/tests/data/README.md
Original file line number Diff line number Diff line change
@@ -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.
Loading
Loading