Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

cimhub_raw

cimhub_raw

RAW v34 ↔ CIM converter for the cimhub ecosystem.

Supports reading, writing, and bidirectional conversion between RAW v34 files and CIM (IEC 61970) network models using cimgraph.


Installation

uv sync
# or
pip install -e .

Set the CIM profile before importing (required by cimgraph):

import os
os.environ.setdefault("CIMG_CIM_PROFILE", "cim17v40")

Usage

1. Read a RAW file (no CIM conversion)

The source is bound at construction and read_all() returns a cimhub_core.GraphModel — the same graph[RecordClass][identifier] container used across the cimhub ecosystem. Records are the LinkML-generated dataclasses in raw34_schema.

from cimhub_raw.importer.raw34_reader import Raw34Reader
import cimhub_raw.schema.raw_v34.raw34_schema as raw

raw_network = Raw34Reader("network.raw").read_all()

# Counts and iteration go through the GraphModel API:
print(f"Buses: {raw_network.count(raw.BusRecord)}")
print(f"Loads: {raw_network.count(raw.LoadRecord)}")
print(f"Generators: {raw_network.count(raw.GeneratorRecord)}")

for bus in raw_network.list_by_class(raw.BusRecord):
    print(f"  Bus {bus.bus_number}: {bus.name}, {bus.base_voltage} kV")

Note: the reader used to return a RawModel container with .bus_records / .load_records list attributes. That container is gone — use count() / list_by_class() / find_by_attribute() instead.

1a. Basic editing style

Records live at raw_network.graph[RecordClass][identifier]. The identifier is the composite key the reader assigns per record type (see the table below), so you can look a record up directly and mutate its fields in place:

import cimhub_raw.schema.raw_v34.raw34_schema as raw

# Direct access by composite identifier — generator id "3" on bus 10111:
gen = raw_network.graph[raw.GeneratorRecord]['10111_3']
gen.p_output = 250.0          # set active power (MW)
gen.q_output = 40.0           # set reactive power (MVAr)

# Or find a record without knowing its exact key:
(bus,) = raw_network.find_by_attribute(raw.BusRecord, 'bus_number', 10111)
bus.base_voltage = 138.0

# find_by_attribute returns a LIST (exact string match), so index or unpack it:
loads = raw_network.find_by_attribute(raw.LoadRecord, 'bus_number', 10111)
for load in loads:
    load.status = 0           # take every load on the bus out of service

Composite identifier keys (what to put in graph[Cls][...]):

Record Identifier key
BusRecord bus_number
LoadRecord bus_number_loadid
FixedShuntRecord bus_number_shuntid
GeneratorRecord bus_number_genid
BranchRecord / SwitchRecord from_to_ckt
TransformerRecord i_j_k_ckt
SwitchedShuntRecord bus_number
VscDcRecord name_ibus

If you don't know the exact key, find_by_attribute(cls, attr, value) is the safe path — it matches on the string form of any field.

2. Write a RAW file

The writer's standard input is a GraphModel — pass the one you read/edited straight to write():

from cimhub_raw.exporter.raw34_writer import Raw34Writer

writer = Raw34Writer()
writer.write(raw_network, "output.raw")

To render a single record without writing a file, use writer.serialize(obj).

3. RAW → RAW round-trip (read + write, no CIM)

from cimhub_raw.importer.raw34_reader import Raw34Reader
from cimhub_raw.exporter.raw34_writer import Raw34Writer

raw_network = Raw34Reader("network.raw").read_all()
Raw34Writer().write(raw_network, "output.raw")

4. RAW → CIM

Convert a RAW file to a CIM NodeBreakerModel (cimgraph):

import os
os.environ.setdefault("CIMG_CIM_PROFILE", "cim17v40")

from cimhub_raw.importer.raw34_to_cim import raw34_to_cim
import cimhub_raw.schema.data_profile as cim

network = raw34_to_cim("network.raw")

buses = network.list_by_class(cim.TopologicalNode)
loads = network.list_by_class(cim.EnergyConsumer)
gens  = network.list_by_class(cim.SynchronousMachine)

print(f"Buses: {len(buses)}, Loads: {len(loads)}, Generators: {len(gens)}")

Pass include_extensions=True to attach raw_extension objects (e.g. RawBusRecord) alongside each CIM object — useful for lossless round-trips:

network = raw34_to_cim("network.raw", include_extensions=True)

5. CIM → RAW

Export a CIM BusBranchModel back to a RAW file:

from cimhub_raw.exporter.cim_to_raw import cim_to_raw

cim_to_raw(network, "output.raw")

Or build the intermediate GraphModel first (e.g. to inspect before writing):

from cimhub_raw.exporter.cim_to_raw import Raw34Exporter
from cimhub_raw.exporter.raw34_writer import Raw34Writer

raw_model = Raw34Exporter().to_model(network, system_base_mva=100.0)
writer = Raw34Writer()
writer.write(raw_model, "output.raw")

6. Full RAW → CIM → RAW round-trip

import os
os.environ.setdefault("CIMG_CIM_PROFILE", "cim17v40")

from cimhub_raw.importer.raw34_to_cim import raw34_to_cim
from cimhub_raw.exporter.cim_to_raw import cim_to_raw

network = raw34_to_cim("network.raw", include_extensions=True)
cim_to_raw(network, "output.raw")

7. Serialize CIM to XML / JSON-LD

Once you have a CIM network model, serialize it to CIM XML or JSON-LD:

from cimgraph.utils import write_xml, write_json_ld

write_xml(network, "network.xml")
write_json_ld(network, "network.jsonld")

Equipment Coverage

Fully converted (RAW ↔ CIM)

RAW Record CIM Class(es)
BusRecord TopologicalNode, ConnectivityNode
LoadRecord EnergyConsumer
GeneratorRecord SynchronousMachine
FixedShuntRecord LinearShuntCompensator (single-section)
SwitchedShuntRecord LinearShuntCompensator (multi-section)
BranchRecord ACLineSegment, SeriesCompensator, Breaker
TransformerRecord PowerTransformer (2-winding)
TwoTerminalDCRecord DCLineSegment + CsConverter x2
VscDcRecord DCLineSegment + VsConverter x2
FactsDeviceRecord StaticVarCompensator, VsConverter
InductionMachineRecord AsynchronousMachine
AreaInterchangeRecord ControlArea / SubControlArea
ZoneRecord SubGeographicalRegion
OwnerRecord AssetOwner
MultiSectionLineRecord Line (container grouping)
SwitchRecord Switch / Breaker

Passthrough only (read + write, no CIM conversion)

These record types are parsed and written verbatim but have no CIM mapping:

RAW Record Reason
InterareaTransferRecord No standard CIM equivalent
ImpedanceCorrectionRecord No CIM class in the CIM 17 profile
MultiTerminalDCRecord Sub-records (converters, bus links) not fully parsed
GneDeviceRecord Generic extensible model; depends on model field

Running Tests

# From the repo root
uv run pytest cimhub_raw/tests/

# Key test files
uv run pytest cimhub_raw/tests/test_raw34_roundtrip.py       # RAW → RAW (no CIM)
uv run pytest cimhub_raw/tests/test_ieee14_roundtrip.py      # Full RAW → CIM → RAW
uv run pytest cimhub_raw/tests/test_production_roundtrip.py  # 169-bus production model

TODO

CIM mappings needed for passthrough record types

These record types are currently read and written verbatim (no CIM conversion). Implementing them requires either finding an appropriate CIM class or extending the data profile.

1. InterareaTransferRecord

  • Represents scheduled power transfers between control areas.
  • No direct CIM equivalent in CIM 17. Closest candidates: TieFlow or a custom extension.
  • Work needed: define CIM mapping, implement importer + exporter, add tests.

2. ImpedanceCorrectionRecord

  • Tap-dependent impedance correction tables for transformers.
  • No CIM class in the CIM 17 profile. Closest: TransformerMeshImpedance or a raw_extension.
  • Work needed: define CIM mapping or raw_extension class, implement importer + exporter, add tests.

3. MultiTerminalDCRecord

  • Represents multi-terminal HVDC lines (3+ converter stations).
  • CIM has DCNode, DCTopologicalNode, DCConverterUnit — mapping is feasible but complex.
  • Current reader only parses the header line; converter/bus/link sub-records are skipped.
  • Work needed: extend reader to parse all sub-record types, define CIM mapping, implement importer + exporter.

4. GneDeviceRecord

  • Generic network element: a catch-all for vendor-specific dynamic models.
  • No universal CIM mapping — depends on the model field value.
  • Work needed: case-by-case assessment per model type; may require raw_extension approach.

Other known gaps

  • 3-winding transformers: TransformerRecord currently handles 2-winding only. 3-winding transformers are represented as a star (3 × 2-winding) in raw; CIM uses PowerTransformerEnd with 3 ends. Needs dedicated handling.
  • Multi-terminal DC importer registration: MultiTerminalDCRecord is not in IMPORT_ORDER in raw34_to_cim.py.

Legacy PSS/E RAW extension layer (cimgraph_raw_extension). Provides raw-extension dataclasses that can be attached alongside CIM objects during a PSS/E import to preserve fields that have no direct CIM mapping.

Usage

from cimgraph_raw_extension.converters.rawToCim import raw_to_cim
from cimgraph_raw_extension.converters.cimToRaw import cim_to_raw

# Import RAW → CIM with extensions attached
network = raw_to_cim("network.raw")

# Export CIM → RAW
cim_to_raw(network, "output.raw")

Structure

src/cimgraph_raw_extension/
    data_profile/raw_extension.py   # Extension dataclasses (RawBusRecord, etc.)
    models/rawModel.py              # RawModel container (legacy)
    converters/rawToCim.py          # RAW → CIM conversion
    converters/cimToRaw.py          # CIM → RAW conversion

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cimhub_raw-2.0.0a3.tar.gz (213.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cimhub_raw-2.0.0a3-py3-none-any.whl (192.5 kB view details)

Uploaded Python 3

File details

Details for the file cimhub_raw-2.0.0a3.tar.gz.

File metadata

  • Download URL: cimhub_raw-2.0.0a3.tar.gz
  • Upload date:
  • Size: 213.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for cimhub_raw-2.0.0a3.tar.gz
Algorithm Hash digest
SHA256 8433bbeeee4d4eb09cfea67d8229ca905d25e2fe849d20f199d57200dbedffe1
MD5 2fcbb4eb22a1da84e0483133dd52d664
BLAKE2b-256 94306799abdce099ff23fd968dd94537fb287875eb82130dadb9d8dfc79f6a64

See more details on using hashes here.

Provenance

The following attestation bundles were made for cimhub_raw-2.0.0a3.tar.gz:

Publisher: publish-cimhub-raw.yml on PNNL-CIM-Tools/CIMHub

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cimhub_raw-2.0.0a3-py3-none-any.whl.

File metadata

  • Download URL: cimhub_raw-2.0.0a3-py3-none-any.whl
  • Upload date:
  • Size: 192.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for cimhub_raw-2.0.0a3-py3-none-any.whl
Algorithm Hash digest
SHA256 55708dd2041a6a2a90b856431b700d050e830f5227921b08ae35ed5051e99661
MD5 2fb0c121d1aee3f625554471485d86aa
BLAKE2b-256 59bb6f1ce909bc13679e9c1796bef5d14bccf3a1768043bc08e0f00f39d4f53c

See more details on using hashes here.

Provenance

The following attestation bundles were made for cimhub_raw-2.0.0a3-py3-none-any.whl:

Publisher: publish-cimhub-raw.yml on PNNL-CIM-Tools/CIMHub

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page