# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# SPDX-License-Identifier: MPL-2.0
from typing import List
import bz2
import xml.etree.ElementTree as ET
from VeraGridEngine.IO.iidm.devices.rtesubstation import IidmSubstation
from VeraGridEngine.IO.iidm.devices.voltage_level import IidmVoltageLevel
from VeraGridEngine.IO.iidm.devices.iidm_area import IidmArea
from VeraGridEngine.IO.iidm.devices.iidm_bus import IidmBus
from VeraGridEngine.IO.iidm.devices.iidm_generator import IidmGenerator
from VeraGridEngine.IO.iidm.devices.iidm_load import IidmLoad
from VeraGridEngine.IO.iidm.devices.iidm_line import IidmLine
from VeraGridEngine.IO.iidm.devices.two_winding_transformer import TwoWindingsTransformer
from VeraGridEngine.IO.iidm.devices.iidm_dangling_line import IidmDanglingLine
from VeraGridEngine.IO.iidm.devices.shunt import Shunt
from VeraGridEngine.IO.iidm.devices.switch import Switch
from VeraGridEngine.IO.iidm.devices.iidm_busbar_section import IidmBusbarSection
from VeraGridEngine.IO.iidm.devices.static_var_compensator import StaticVarCompensator
from VeraGridEngine.IO.iidm.devices.iidm_circuit import IidmCircuit
"""
# See:
https://powsybl.readthedocs.io/projects/pypowsybl/en/latest/reference/network.html
https://powsybl.readthedocs.io/projects/powsybl-core/en/stable/grid_model/network_subnetwork.html
"""
[docs]
def strip_ns(tag: str) -> str:
"""
:param tag:
:return:
"""
return tag.split("}")[-1] if "}" in tag else tag
[docs]
def parse_xiidm_file(file_path: str) -> IidmCircuit:
"""
Parse Xiidm to IidmCircuit
:param file_path: xiidm file path
:return: IidmCircuit
"""
# Read as a text file (assuming UTF-8 encoding)
if file_path.endswith(".bz2"):
with bz2.open(file_path, mode='rt', encoding='utf-8') as file:
tree = ET.parse(file)
else:
tree = ET.parse(file_path)
root = tree.getroot()
circuit = IidmCircuit()
for elem in root.iter():
tag = strip_ns(elem.tag)
if tag == "substation":
circuit.substations.append(IidmSubstation(
id=elem.attrib.get("id", ""),
country=elem.attrib.get("country", ""),
tso=elem.attrib.get("tso", ""),
geographicalTags=elem.attrib.get("geographicalTags", "")
))
elif tag == "voltageLevel":
circuit.voltage_levels.append(IidmVoltageLevel(
_id=elem.attrib.get("id", ""),
name=elem.attrib.get("name", ""),
nominalV=float(elem.attrib.get("nominalV", 0)),
topologyKind=elem.attrib.get("topologyKind", "")
))
elif tag == "area":
circuit.areas.append(IidmArea(
_id=elem.attrib.get("id", ""),
name=elem.attrib.get("Name", ""),
area_type=elem.attrib.get("AreaType", ""),
interchange_target=float(elem.attrib.get("interchangeTarget", 0)),
))
elif tag == "bus":
circuit.buses.append(IidmBus(
_id=elem.attrib.get("id", ""),
area_number=elem.attrib.get("areaNumber", -1),
status=elem.attrib.get("status", ""),
nodes=[int(e) for e in elem.attrib.get("nodes", "").split(",")],
))
elif tag == "generator":
circuit.generators.append(IidmGenerator(
id=elem.attrib.get("id", ""),
bus=elem.attrib.get("bus", ""),
targetP=float(elem.attrib.get("targetP", 0)),
targetQ=float(elem.attrib.get("targetQ", 0)),
targetV=float(elem.attrib.get("targetV", 0))
))
elif tag == "load":
circuit.loads.append(IidmLoad(
id=elem.attrib.get("id", ""),
bus=elem.attrib.get("bus", ""),
p0=float(elem.attrib.get("p0", 0)),
q0=float(elem.attrib.get("q0", 0))
))
elif tag == "line":
circuit.lines.append(IidmLine(
id=elem.attrib.get("id", ""),
voltageLevelId1=elem.attrib.get("voltageLevelId1", ""),
bus1=elem.attrib.get("bus1", ""),
voltageLevelId2=elem.attrib.get("voltageLevelId2", ""),
bus2=elem.attrib.get("bus2", ""),
r=float(elem.attrib.get("r", 0)),
x=float(elem.attrib.get("x", 0)),
g1=float(elem.attrib.get("g1", 0)),
b1=float(elem.attrib.get("b1", 0)),
g2=float(elem.attrib.get("g2", 0)),
b2=float(elem.attrib.get("b2", 0))
))
elif tag == "twoWindingsTransformer":
circuit.transformers.append(TwoWindingsTransformer(
id=elem.attrib.get("id", ""),
voltageLevelId1=elem.attrib.get("voltageLevelId1", ""),
bus1=elem.attrib.get("bus1", ""),
voltageLevelId2=elem.attrib.get("voltageLevelId2", ""),
bus2=elem.attrib.get("bus2", ""),
r=float(elem.attrib.get("r", 0)),
x=float(elem.attrib.get("x", 0)),
g=float(elem.attrib.get("g", 0)),
b=float(elem.attrib.get("b", 0)),
ratedU1=float(elem.attrib.get("ratedU1", 0)),
ratedU2=float(elem.attrib.get("ratedU2", 0))
))
elif tag == "danglingLine":
circuit.dangling_lines.append(IidmDanglingLine(
_id=elem.attrib.get("id", ""),
bus=elem.attrib.get("bus", ""),
p0=float(elem.attrib.get("p0", 0)),
q0=float(elem.attrib.get("q0", 0)),
u0=float(elem.attrib.get("u0", 0)),
r=float(elem.attrib.get("r", 0)),
x=float(elem.attrib.get("x", 0)),
g=float(elem.attrib.get("g", 0)),
b=float(elem.attrib.get("b", 0))
))
elif tag == "shunt":
circuit.shunts.append(Shunt(
id=elem.attrib.get("id", ""),
bus=elem.attrib.get("bus", ""),
g=float(elem.attrib.get("g", 0)),
b=float(elem.attrib.get("b", 0))
))
elif tag == "switch":
circuit.switches.append(Switch(
id=elem.attrib.get("id", ""),
bus1=elem.attrib.get("bus1", ""),
bus2=elem.attrib.get("bus2", ""),
kind=elem.attrib.get("kind", ""),
open=elem.attrib.get("open", "false").lower() == "true",
retained=elem.attrib.get("retained", "false").lower() == "true"
))
elif tag == "busbarSection":
circuit.busbar_sections.append(IidmBusbarSection(
_id=elem.attrib.get("id", "")
))
elif tag == "staticVarCompensator":
circuit.svcs.append(StaticVarCompensator(
id=elem.attrib.get("id", ""),
bus=elem.attrib.get("bus", ""),
bMin=float(elem.attrib.get("bMin", 0)),
bMax=float(elem.attrib.get("bMax", 0)),
voltageSetPoint=float(elem.attrib.get("voltageSetPoint", 0))
))
return circuit
if __name__ == "__main__":
# fname = "/home/santi/Documentos/Git/GitHub/RTE7000/2021/01/01/recollement-auto-20210101-0000-enrichi.xiidm"
# fname = "/home/santi/Documentos/Git/GitHub/RTE7000/2021/01/01/recollement-auto-20210101-0000-enrichi.xiidm.bz2"
fname = "/Users/santi/Git/eRoots/VeraGrid/src/tests/data/grids/ucte/network.xiidm"
# import pypowsybl as pp
# grid = pp.network.load(fname)
# res = pp.loadflow.run_dc(grid, pp.loadflow.Parameters(distributed_slack=False))
iidm_circuit = parse_xiidm_file(fname)
print()