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
RawModelcontainer with.bus_records/.load_recordslist attributes. That container is gone — usecount()/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:
TieFlowor 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:
TransformerMeshImpedanceor 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
modelfield value. - Work needed: case-by-case assessment per model type; may require raw_extension approach.
Other known gaps
- 3-winding transformers:
TransformerRecordcurrently handles 2-winding only. 3-winding transformers are represented as a star (3 × 2-winding) in raw; CIM usesPowerTransformerEndwith 3 ends. Needs dedicated handling. - Multi-terminal DC importer registration:
MultiTerminalDCRecordis not inIMPORT_ORDERinraw34_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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8433bbeeee4d4eb09cfea67d8229ca905d25e2fe849d20f199d57200dbedffe1
|
|
| MD5 |
2fcbb4eb22a1da84e0483133dd52d664
|
|
| BLAKE2b-256 |
94306799abdce099ff23fd968dd94537fb287875eb82130dadb9d8dfc79f6a64
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cimhub_raw-2.0.0a3.tar.gz -
Subject digest:
8433bbeeee4d4eb09cfea67d8229ca905d25e2fe849d20f199d57200dbedffe1 - Sigstore transparency entry: 2523628797
- Sigstore integration time:
-
Permalink:
PNNL-CIM-Tools/CIMHub@1b73b91d85485ed800952094156d04858b0081d3 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/PNNL-CIM-Tools
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-cimhub-raw.yml@1b73b91d85485ed800952094156d04858b0081d3 -
Trigger Event:
workflow_dispatch
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55708dd2041a6a2a90b856431b700d050e830f5227921b08ae35ed5051e99661
|
|
| MD5 |
2fb0c121d1aee3f625554471485d86aa
|
|
| BLAKE2b-256 |
59bb6f1ce909bc13679e9c1796bef5d14bccf3a1768043bc08e0f00f39d4f53c
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cimhub_raw-2.0.0a3-py3-none-any.whl -
Subject digest:
55708dd2041a6a2a90b856431b700d050e830f5227921b08ae35ed5051e99661 - Sigstore transparency entry: 2523628860
- Sigstore integration time:
-
Permalink:
PNNL-CIM-Tools/CIMHub@1b73b91d85485ed800952094156d04858b0081d3 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/PNNL-CIM-Tools
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-cimhub-raw.yml@1b73b91d85485ed800952094156d04858b0081d3 -
Trigger Event:
workflow_dispatch
-
Statement type: