You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Loading the ReliCapGrid CGMES v3.0 multi-TSO dataset (https://github.com/entsoe/relicapgrid) via pypowsybl 1.15.0 fails with multiple distinct errors depending on the loading approach. ReliCapGrid is the ENTSO-E open-source synthetic CGMES v3.0 test dataset recently integrated into powsybl-core Java tests via PR #3592.
Attempt 1 — Full CGM (all 8 TSOs in one zip):
Fails with duplicate triplestore key error because all 5 boundary files share the same md:Model.modelingAuthoritySet URI http://ninerealms.nr/boundary:
Duplicate key http://ninerealms.nr/boundary (attempted merging values [Boundary_Border-Svedala-Belgovia.xml] and [Boundary_Border-Galia-Britheim.xml])
Attempt 2 — Full CGM with patched boundary URIs (unique URI per boundary file):
Fails with VoltageLevel not created during node/breaker → IIDM conversion, even though the VoltageLevel is correctly defined in the included EQ file:
BusbarSection 4b62e70e-41fd-3615-d8b0-36d0adf2e35b voltage level b7630cf0-3bd1-4813-8be3-404a1c4cfc7a has not been created in IIDM
Attempt 3 — Individual IGMs (each TSO loaded separately):
6 out of 8 IGMs load and converge. Two fail:
Espheim: Same VoltageLevel not created error as Attempt 2
Nordheim: Loads without exception but produces 0 buses and 1 substation — network is empty and unusable
Describe the expected behavior
All 8 ReliCapGrid IGMs should load successfully and produce non-empty networks with correct bus counts, consistent with the Java tests in powsybl-core PR #3592. The full 8-TSO CGM should be mergeable into a single network for AC load flow and sensitivity analysis via pypowsybl.
Collect all grid + common + boundary files (excluding Portheim)
files = []
for tso in TSOs:
d = ROOT / tso / 'Grid' / 'cimxml'
if d.exists():
files.extend(list(d.glob('.xml')))
files.extend(list((ROOT / 'commonData' / 'Grid' / 'cimxml').glob('.xml')))
for f in (ROOT / 'boundaryData' / 'Grid' / 'cimxml').glob('*.xml'):
if 'Portheim' not in f.name:
files.append(f)
Pack into a zip and load
with tempfile.TemporaryDirectory() as tmp:
zippath = os.path.join(tmp, 'cgm.zip')
with zipfile.ZipFile(zippath, 'w') as zf:
for f in files:
zf.write(f, Path(f).name)
with tempfile.TemporaryDirectory() as tmp:
zippath = os.path.join(tmp, 'cgm_patched.zip')
with zipfile.ZipFile(zippath, 'w') as zf:
for f in files:
if f.parent == boundary_dir:
patched = Path(tmp) / f'patched_{f.name}'
patch_boundary_uri(f, patched)
zf.write(patched, f.name)
else:
zf.write(f, Path(f).name)
# Step 5a: Try loading with patched boundary URIs -> triggers Bug 2
net = pp.network.load(zippath, parameters={
'iidm.import.cgmes.cgm-with-subnetworks': 'false',
})
Observe Bug 2: VoltageLevel b7630cf0 not created in IIDM for Espheim
To reproduce Bug 3 (Nordheim empty network), load Nordheim IGM individually:
python# Apply data fix from relicapgrid issue Add features #3 — remove duplicate ConnectivityNode
from Boundary_Border-Galia-Nordheim.xml, then load Nordheim alone
def patch_nordheim_boundary(src: Path, dst: Path):
content = src.read_text(encoding='utf-8')
content = content.replace(
'http://ninerealms.nr/boundary',
f'http://ninerealms.nr/boundary/{src.stem}'
)
tree = ET.parse(io.StringIO(content))
root = tree.getroot()
to_remove = [
elem for elem in root
if any(
dup_id.replace('-','') in v.replace('-','').strip('#').replace('urn:uuid:','')
for v in elem.attrib.values()
for dup_id in DUPLICATE_IDS
)
]
for elem in to_remove:
root.remove(elem)
tree.write(dst, encoding='UTF-8', xml_declaration=True)
with tempfile.TemporaryDirectory() as tmp:
patched_b = Path(tmp) / boundary_src.name
patch_nordheim_boundary(boundary_src, patched_b)
zippath = os.path.join(tmp, 'Nordheim.zip')
with zipfile.ZipFile(zippath, 'w') as zf:
for f in nordheim_files + common_files:
zf.write(f, Path(f).name)
zf.write(patched_b, boundary_src.name)
net = pp.network.load(zippath, parameters={
'iidm.import.cgmes.source-for-iidm-id': 'mRID',
'iidm.import.cgmes.cgm-with-subnetworks': 'false',
})
print('Buses:', len(net.get_buses())) # prints 0
print('Substations:', len(net.get_substations())) # prints 1
Observe Bug 3: Nordheim loads without error but produces 0 buses and 1 substation.
The network is empty and cannot be used for load flow or sensitivity analysis.
Duplicate key http://ninerealms.nr/boundary (attempted merging values
[Boundary_Border-Svedala-Belgovia.xml] and [Boundary_Border-Galia-Britheim.xml])
Attempt 2 — Full CGM, boundary URIs patched to be unique
BusbarSection 4b62e70e-41fd-3615-d8b0-36d0adf2e35b voltage level
b7630cf0-3bd1-4813-8be3-404a1c4cfc7a has not been created in IIDM
Attempt 3 — Individual IGMs, result per TSO
OK Belgovia buses=15 LF=CONVERGED
OK Britheim buses=6 LF=CONVERGED
FAIL Espheim BusbarSection 4b62e70e... voltage level b7630cf0... has not been created in IIDM
OK Galia buses=11 LF=CONVERGED
FAIL Nordheim buses=0 substations=1 (loads without error but empty network)
OK Svedala buses=112 LF=CONVERGED
OK DC-Espheim-Svedala buses=6 LF=NO_CALCULATION
OK DC-Nordheim-Galia buses=7 LF=CONVERGED
Extra Information
Three distinct bugs identified:
Bug 1 — Duplicate modelingAuthoritySet URI (Attempt 1)
All 5 ReliCapGrid boundary files share md:Model.modelingAuthoritySet = http://ninerealms.nr/boundary. The pypowsybl triplestore rejects duplicate keys when multiple boundary files are loaded together. Workaround: patch each boundary file to use a unique URI (e.g. http://ninerealms.nr/boundary/Boundary_Border-Svedala-Belgovia). This resolves Bug 1 but exposes Bug 2.
Bug 2 — VoltageLevel not created in IIDM for Espheim (Attempt 2 and 3)
VoltageLevel b7630cf0-3bd1-4813-8be3-404a1c4cfc7a is correctly defined in 20220615T2230Z__Espheim_EQ_1.xml with rdf:ID:
xml<cim:VoltageLevel rdf:ID="_b7630cf0-3bd1-4813-8be3-404a1c4cfc7a">
cim:IdentifiedObject.mRIDb7630cf0-3bd1-4813-8be3-404a1c4cfc7a</cim:IdentifiedObject.mRID>
...
</cim:VoltageLevel>
It does not appear in any boundary file — it is purely internal to Espheim. pypowsybl fails to create it during CGMES v3.0 node/breaker → IIDM conversion. This bug persists with both cgm-with-subnetworks=true and cgm-with-subnetworks=false. No workaround found.
Bug 3 — Nordheim IGM loads with 0 buses (Attempt 3)
After applying the data fix from relicapgrid issue #3 (removing duplicate ConnectivityNode 892ef502 and its hierarchy from Boundary_Border-Galia-Nordheim.xml), Nordheim loads without exception but produces an empty network (0 buses, 0 lines, 1 substation). The substation shell is created but no topology is built. No workaround found.
Additional notes:
VeraGrid (GridCal/eRoots) successfully loads all 8 ReliCapGrid TSOs and runs AC load flow, confirming the dataset itself is valid CGMES v3.0
The duplicate boundary URI issue (Bug 1) may affect other multi-TSO CGMES v3.0 datasets where multiple boundary files share a modelingAuthoritySet
Cross-reference: relicapgrid issue #3 documents the Nordheim duplicate ConnectivityNode data issue
Cross-reference: powsybl-core PR #3592 — Java tests load ReliCapGrid successfully, but the Python API (pypowsybl) does not yet expose equivalent functionality for this dataset
Minimal reproduction code:
pythonimport pypowsybl as pp
import zipfile, tempfile, os
from pathlib import Path
files = []
for tso in TSOs:
d = ROOT / tso / 'Grid' / 'cimxml'
if d.exists():
files.extend(list(d.glob('.xml')))
files.extend(list((ROOT / 'commonData' / 'Grid' / 'cimxml').glob('.xml')))
for f in (ROOT / 'boundaryData' / 'Grid' / 'cimxml').glob('*.xml'):
if 'Portheim' not in f.name:
files.append(f)
with tempfile.TemporaryDirectory() as tmp:
zippath = os.path.join(tmp, 'cgm.zip')
with zipfile.ZipFile(zippath, 'w') as zf:
for f in files:
zf.write(f, Path(f).name)
net = pp.network.load(zippath) # Fails with Bug 1
Describe the current behavior
Loading the ReliCapGrid CGMES v3.0 multi-TSO dataset (https://github.com/entsoe/relicapgrid) via pypowsybl 1.15.0 fails with multiple distinct errors depending on the loading approach. ReliCapGrid is the ENTSO-E open-source synthetic CGMES v3.0 test dataset recently integrated into powsybl-core Java tests via PR #3592.
Attempt 1 — Full CGM (all 8 TSOs in one zip):
Fails with duplicate triplestore key error because all 5 boundary files share the same md:Model.modelingAuthoritySet URI http://ninerealms.nr/boundary:
Duplicate key http://ninerealms.nr/boundary (attempted merging values [Boundary_Border-Svedala-Belgovia.xml] and [Boundary_Border-Galia-Britheim.xml])
Attempt 2 — Full CGM with patched boundary URIs (unique URI per boundary file):
Fails with VoltageLevel not created during node/breaker → IIDM conversion, even though the VoltageLevel is correctly defined in the included EQ file:
BusbarSection 4b62e70e-41fd-3615-d8b0-36d0adf2e35b voltage level b7630cf0-3bd1-4813-8be3-404a1c4cfc7a has not been created in IIDM
Attempt 3 — Individual IGMs (each TSO loaded separately):
6 out of 8 IGMs load and converge. Two fail:
Espheim: Same VoltageLevel not created error as Attempt 2
Nordheim: Loads without exception but produces 0 buses and 1 substation — network is empty and unusable
Describe the expected behavior
All 8 ReliCapGrid IGMs should load successfully and produce non-empty networks with correct bus counts, consistent with the Java tests in powsybl-core PR #3592. The full 8-TSO CGM should be mergeable into a single network for AC load flow and sensitivity analysis via pypowsybl.
Describe the steps
Describe the steps to reproduce
Clone the ReliCapGrid dataset:
git clone https://github.com/entsoe/relicapgrid data/relicapgrid
Install pypowsybl:
pip install pypowsybl==1.15.0
Run the following Python script:
pythonimport pypowsybl as pp
import zipfile, tempfile, os
from pathlib import Path
ROOT = Path('data/relicapgrid/Instance')
TSOs = ['Belgovia','Britheim','DC-Espheim-Svedala','DC-Nordheim-Galia',
'Espheim','Galia','Nordheim','Svedala']
Collect all grid + common + boundary files (excluding Portheim)
files = []
for tso in TSOs:
d = ROOT / tso / 'Grid' / 'cimxml'
if d.exists():
files.extend(list(d.glob('.xml')))
files.extend(list((ROOT / 'commonData' / 'Grid' / 'cimxml').glob('.xml')))
for f in (ROOT / 'boundaryData' / 'Grid' / 'cimxml').glob('*.xml'):
if 'Portheim' not in f.name:
files.append(f)
Pack into a zip and load
with tempfile.TemporaryDirectory() as tmp:
zippath = os.path.join(tmp, 'cgm.zip')
with zipfile.ZipFile(zippath, 'w') as zf:
for f in files:
zf.write(f, Path(f).name)
Observe Bug 1: Duplicate key error for http://ninerealms.nr/boundary
Apply workaround for Bug 1 — patch boundary URIs to be unique:
pythonimport io
import xml.etree.ElementTree as ET
def patch_boundary_uri(src: Path, dst: Path):
content = src.read_text(encoding='utf-8')
content = content.replace(
'http://ninerealms.nr/boundary',
f'http://ninerealms.nr/boundary/{src.stem}'
)
dst.write_text(content, encoding='utf-8')
boundary_dir = ROOT / 'boundaryData' / 'Grid' / 'cimxml'
with tempfile.TemporaryDirectory() as tmp:
zippath = os.path.join(tmp, 'cgm_patched.zip')
with zipfile.ZipFile(zippath, 'w') as zf:
for f in files:
if f.parent == boundary_dir:
patched = Path(tmp) / f'patched_{f.name}'
patch_boundary_uri(f, patched)
zf.write(patched, f.name)
else:
zf.write(f, Path(f).name)
Observe Bug 2: VoltageLevel b7630cf0 not created in IIDM for Espheim
To reproduce Bug 3 (Nordheim empty network), load Nordheim IGM individually:
python# Apply data fix from relicapgrid issue Add features #3 — remove duplicate ConnectivityNode
from Boundary_Border-Galia-Nordheim.xml, then load Nordheim alone
DUPLICATE_IDS = {
'892ef502-162b-469f-b93f-266aae828227',
'e61f8ecf-8129-4702-a3a2-826bdf5ad13d',
'c39c3eb8-9cce-4778-9069-6952a117ba2b',
'77467625-a8fe-8792-7cf2-06c5dfd5fba9',
'9356077b-f716-0d6c-0cac-32c074bd8fa3',
}
def patch_nordheim_boundary(src: Path, dst: Path):
content = src.read_text(encoding='utf-8')
content = content.replace(
'http://ninerealms.nr/boundary',
f'http://ninerealms.nr/boundary/{src.stem}'
)
tree = ET.parse(io.StringIO(content))
root = tree.getroot()
to_remove = [
elem for elem in root
if any(
dup_id.replace('-','') in v.replace('-','').strip('#').replace('urn:uuid:','')
for v in elem.attrib.values()
for dup_id in DUPLICATE_IDS
)
]
for elem in to_remove:
root.remove(elem)
tree.write(dst, encoding='UTF-8', xml_declaration=True)
nordheim_files = list((ROOT / 'Nordheim' / 'Grid' / 'cimxml').glob('.xml'))
common_files = list((ROOT / 'commonData' / 'Grid' / 'cimxml').glob('.xml'))
boundary_src = ROOT / 'boundaryData' / 'Grid' / 'cimxml' / 'Boundary_Border-Galia-Nordheim.xml'
with tempfile.TemporaryDirectory() as tmp:
patched_b = Path(tmp) / boundary_src.name
patch_nordheim_boundary(boundary_src, patched_b)
The network is empty and cannot be used for load flow or sensitivity analysis.
Environment
pypowsybl version: 1.15.0
Python version: 3.11
OS: Linux Ubuntu 24 (GitHub Codespaces)
Dataset: ReliCapGrid v1.0 — https://github.com/entsoe/relicapgrid
Dataset format: CGMES v3.0, node/breaker topology
Reference Java test: powsybl-core PR #3592
Relevant Log Output
Attempt 1 — Full CGM, all boundary files included
Duplicate key http://ninerealms.nr/boundary (attempted merging values
[Boundary_Border-Svedala-Belgovia.xml] and [Boundary_Border-Galia-Britheim.xml])
Attempt 2 — Full CGM, boundary URIs patched to be unique
BusbarSection 4b62e70e-41fd-3615-d8b0-36d0adf2e35b voltage level
b7630cf0-3bd1-4813-8be3-404a1c4cfc7a has not been created in IIDM
Attempt 3 — Individual IGMs, result per TSO
OK Belgovia buses=15 LF=CONVERGED
OK Britheim buses=6 LF=CONVERGED
FAIL Espheim BusbarSection 4b62e70e... voltage level b7630cf0... has not been created in IIDM
OK Galia buses=11 LF=CONVERGED
FAIL Nordheim buses=0 substations=1 (loads without error but empty network)
OK Svedala buses=112 LF=CONVERGED
OK DC-Espheim-Svedala buses=6 LF=NO_CALCULATION
OK DC-Nordheim-Galia buses=7 LF=CONVERGED
Extra Information
Three distinct bugs identified:
Bug 1 — Duplicate modelingAuthoritySet URI (Attempt 1)
All 5 ReliCapGrid boundary files share md:Model.modelingAuthoritySet = http://ninerealms.nr/boundary. The pypowsybl triplestore rejects duplicate keys when multiple boundary files are loaded together. Workaround: patch each boundary file to use a unique URI (e.g. http://ninerealms.nr/boundary/Boundary_Border-Svedala-Belgovia). This resolves Bug 1 but exposes Bug 2.
Bug 2 — VoltageLevel not created in IIDM for Espheim (Attempt 2 and 3)
VoltageLevel b7630cf0-3bd1-4813-8be3-404a1c4cfc7a is correctly defined in 20220615T2230Z__Espheim_EQ_1.xml with rdf:ID:
xml<cim:VoltageLevel rdf:ID="_b7630cf0-3bd1-4813-8be3-404a1c4cfc7a">
cim:IdentifiedObject.mRIDb7630cf0-3bd1-4813-8be3-404a1c4cfc7a</cim:IdentifiedObject.mRID>
...
</cim:VoltageLevel>
It does not appear in any boundary file — it is purely internal to Espheim. pypowsybl fails to create it during CGMES v3.0 node/breaker → IIDM conversion. This bug persists with both cgm-with-subnetworks=true and cgm-with-subnetworks=false. No workaround found.
Bug 3 — Nordheim IGM loads with 0 buses (Attempt 3)
After applying the data fix from relicapgrid issue #3 (removing duplicate ConnectivityNode 892ef502 and its hierarchy from Boundary_Border-Galia-Nordheim.xml), Nordheim loads without exception but produces an empty network (0 buses, 0 lines, 1 substation). The substation shell is created but no topology is built. No workaround found.
Additional notes:
VeraGrid (GridCal/eRoots) successfully loads all 8 ReliCapGrid TSOs and runs AC load flow, confirming the dataset itself is valid CGMES v3.0
The duplicate boundary URI issue (Bug 1) may affect other multi-TSO CGMES v3.0 datasets where multiple boundary files share a modelingAuthoritySet
Cross-reference: relicapgrid issue #3 documents the Nordheim duplicate ConnectivityNode data issue
Cross-reference: powsybl-core PR #3592 — Java tests load ReliCapGrid successfully, but the Python API (pypowsybl) does not yet expose equivalent functionality for this dataset
Minimal reproduction code:
pythonimport pypowsybl as pp
import zipfile, tempfile, os
from pathlib import Path
ROOT = Path('data/relicapgrid/Instance') # git clone https://github.com/entsoe/relicapgrid
TSOs = ['Belgovia','Britheim','DC-Espheim-Svedala','DC-Nordheim-Galia',
'Espheim','Galia','Nordheim','Svedala']
files = []
for tso in TSOs:
d = ROOT / tso / 'Grid' / 'cimxml'
if d.exists():
files.extend(list(d.glob('.xml')))
files.extend(list((ROOT / 'commonData' / 'Grid' / 'cimxml').glob('.xml')))
for f in (ROOT / 'boundaryData' / 'Grid' / 'cimxml').glob('*.xml'):
if 'Portheim' not in f.name:
files.append(f)
with tempfile.TemporaryDirectory() as tmp:
zippath = os.path.join(tmp, 'cgm.zip')
with zipfile.ZipFile(zippath, 'w') as zf:
for f in files:
zf.write(f, Path(f).name)
net = pp.network.load(zippath) # Fails with Bug 1