CGMES Export

writeCGMESFiles exports a Sparlectra Net as a CGMES 2.4.15 (RDF/XML) delivery — EQ, TP, SSH, and SV:

  • EQ + TP: buses (TopologicalNode with BaseVoltage/VoltageLevel containers), AC lines (ACLineSegment), two- and three-winding transformers (PowerTransformer with two or three PowerTransformerEnds), loads (EnergyConsumer), machines (SynchronousMachine with GeneratingUnit and, for voltage-regulating units, a RegulatingControl), external network injections, asynchronous machines, static VAr compensators, shunts (LinearShuntCompensator), and bus links (closed Breakers) — each with its terminals and topology associations. Optional zero-sequence line attributes and harvested machine/injection short-circuit attributes go into the EquipmentShortCircuit part of EQ.
  • SSH: the operating point — load and machine p/q, the slack unit's referencePriority, voltage-regulation targets, tap steps, and shunt sections.
  • SV: the network's current voltage state (SvVoltage per bus, SvPowerFlow per terminal). After a solve this is the solution, so a re-import can start from it (cgmes_import.start_values: sv) and validates cleanly against it; right after an import it is the start state.

A re-import of the exported files rebuilds the same electrical model: the power flow of an exported and re-imported network matches the original to solver precision, including transformers with a phase shift.

Every file starts with a tool-provenance line — Generated by Sparlectra.jl v<version> on <date> — and carries the same information as md:Model.description in the profile header. The date is the created timestamp (by default the export time).

It works for any Net — imported from CGMES, MATPOWER, or DTF, or built programmatically — because the export reads directly from the network model.

using Sparlectra

net = Net(name = "demo", baseMVA = 100.0)
addBus!(net = net, busName = "B1", vn_kV = 110.0, vm_pu = 1.0, va_deg = 0.0)
addBus!(net = net, busName = "B2", vn_kV = 110.0, vm_pu = 1.0, va_deg = 0.0)
addACLine!(net = net, fromBus = "B1", toBus = "B2", length = 25.0, r = 0.2, x = 0.39)

files = writeCGMESFiles(net; path = "out")
# -> ["out/demo_EQ.xml", "out/demo_TP.xml", "out/demo_SSH.xml", "out/demo_SV.xml"]

Two-winding transformers export with the full impedance on end 2 (the branch model's to-side voltage base) and the effective turns ratio encoded in the end ratedU values, so the importer's ratio reconstruction reproduces exactly the solved ratio. A phase shift is written as a single-step linear phase tap changer whose increment is the shift angle — the exact solved state, not the original tap table. A winding that carries ratio-tap machinery (PowerTransformerTaps) exports it as a RatioTapChanger with its range, neutral data, and current step; the end ratedU absorbs the residual so the solved ratio survives in every case. Three-winding transformers imported from CGMES are reassembled from their star equivalent into one PowerTransformer with three ends — with the original mRIDs — whenever the reconstruction is exact; a star group the importer could not reproduce exactly stays in the two-winding star representation with a notice.

Optional keyword arguments:

  • sc_line_data::Dict{Int,CGMESLineShortCircuit} — zero-sequence / short-circuit data per line index (order of net.linesAC), written into the EQ profile. Only supplied values are written; nothing is invented from positive-sequence data. For a net imported from CGMES, cgmesLineShortCircuitData(result) builds this dictionary from the zero-sequence line attributes harvested during the import, matched through the same structural keys the export uses.
  • sc_source::CGMESShortCircuitData — the short-circuit harvest of a CGMES import (result.shortcircuit). Machine, injection, and motor short-circuit attributes (x''d, feeder current limits, locked-rotor data) are written back onto the units by mRID, so a short-circuit evaluation of the re-imported delivery reproduces the original results.
  • zip::Bool — additionally pack the profiles into <name>_CGMES.zip, a single delivery file that the importer and the Web UI upload read directly; its path is appended to the returned list.
  • created::DateTime — the md:Model.scenarioTime / md:Model.created header stamp (default: current time). Pass a fixed value to make the output byte-reproducible, e.g. for regression comparisons.
  • notices::Vector{String} — collects one line per model element the export could not carry exactly (e.g. a star group whose three-winding reconstruction is not exact). Without a sink the same lines are emitted as warnings. An empty notice list means the export is model-complete.

A runnable example lives in examples/experimental/cgmes_export_demo.jl.

Identity and mRIDs on export

Every CGMES object carries a globally unique identifier (mRID). The export resolves these ids through structural keys stored in net.cgmes_ids — a key describes what an object is in the network, not what it is called:

KeyObject
TN|<busname>TopologicalNode of a bus
BV|<vn_kV> / VL|<vn_kV>BaseVoltage / VoltageLevel per nominal voltage
ACL|<busA>|<busB>|<k>ACLineSegment; the bus pair is sorted lexicographically, <k> numbers parallel lines on the same pair in first-seen order
LNC|<busA>|<busB>|<k>cim:Line container of that segment
PT|<busA>|<busB>|<k>PowerTransformer (same pair and <k> rules, counted over transformer branches)
PT3|<busA>|<busB>|<busC>|<k>three-winding PowerTransformer over its sorted side buses
…|E1 / …|E2 / …|E3PowerTransformerEnd by end number
…|PTCthe phase-shift-carrying linear phase tap changer
…|RTCthe exported ratio tap changer of a tap-carrying winding
SVC|<bus>|<k>StaticVarCompensator (also with …|RC)
LNK|<busA>|<busB>|<k>bus link (Breaker)
EC|<bus>|<k>EnergyConsumer; <k> numbers the bus's units of one class in first-seen order
SM|<bus>|<k>SynchronousMachine, with …|GU (GeneratingUnit) and …|RC (RegulatingControl) children
ENI|<bus>|<k>ExternalNetworkInjection (also with …|RC)
ASM|<bus>|<k>AsynchronousMachine
SH|<bus>|<k>LinearShuntCompensator
…|T1 / …|T2Terminals by equipment sequence number (T1 = from side)
MODEL|EQ / MODEL|TP / MODEL|SSH / MODEL|SVmd:FullModel header ids

Two sources feed this table:

  • Imported networks keep their original ids. The CGMES importer records the source mRIDs under the same structural keys, so a CGMES → Sparlectra → CGMES roundtrip writes each bus, line, and terminal with the mRID it arrived with. Downstream tools that track objects by mRID keep working across the roundtrip.
  • Everything else is minted deterministically. For keys without a recorded id (programmatic nets, MATPOWER/DTF imports, objects the source did not carry), the export mints a uuid5 from the key string and records it on the net. The same network structure therefore always produces the same ids — exports are diff-stable across runs and across machines.

Because identity is structural, renaming a component never changes its mRID. Only structural changes do: renaming a bus changes the identity of its TopologicalNode and of the line keys built from it, so buses that must stay identifiable across exports should keep their names.

If two different keys resolve to the same mRID (possible only through a corrupted or hand-edited net.cgmes_ids), the export aborts with an error naming both keys before any file is written — an RDF file with duplicate rdf:ID values is never produced.

Export from the Web UI

The run form offers an Export case as CGMES delivery checkbox. When checked, the run writes one artifact — the combined <case>_CGMES.zip containing the EQ, TP, SSH, and SV profiles — right after the network is built; the export works for runs that do not converge too (the SV then carries the start state). The zip appears in the run's artifact list for download and re-imports directly, also via the Web UI upload. The result page shows a CGMES export row naming the delivery and, as a warning badge, the export notices (an export without a badge is model-complete).

The checkbox works for every case format. For CGMES cases the zero-sequence line attributes harvested from the delivery ride along automatically; MATPOWER and DTF cases export without them. Programmatic service callers get the same behavior with export_cgmes: true in the start_powerflow_run request.

Scope

Not produced: tap and machine controller wiring (the exported tap changers carry range and position, not the controller logic), per-step tabular tap tables (the solved ratio/shift is exact, the table itself is not reconstructed), and the DC modeling of a source delivery. See CGMES Import for the import side.