Transmission networks
A transmission case parses into a BalancedNetwork: a Julia object with raw MATPOWER units (MW/MVAr, degrees), 1-based bus ids, and a live handle into the Rust core that the to_* transforms run off.
Formats
Each format reads and writes, so any pair converts. A same-format round trip is byte exact; a cross-format conversion reports fields the target cannot represent as warnings.
| Format | Tokens | Extension |
|---|---|---|
| MATPOWER | "matpower", "m" | .m |
| PSS/E revisions 33, 34, and 35 | "psse", "raw" | .raw |
| PowerWorld | "powerworld", "aux" | .aux |
| PSLF EPC | "pslf", "epc" | .epc |
| PowerModels.jl network data JSON | "powermodels-json", "powermodels", "pm" | .json |
| egret ModelData JSON | "egret-json", "egret" | .json |
| pandapower JSON | "pandapower-json", "pandapower" | .json |
| Surge JSON | "surge-json", "surge" | .json |
| PyPSA static network CSV | "pypsa-csv" | directory |
| GridFM Parquet dataset | — (see read_gridfm) | directory |
The format is inferred from the extension unless from is given. egret and PowerModels both use .json, so those two need the hint:
net = parse_file("case14.m")
egret = parse_file("grid.json"; from="egret")Parsing
parse_file reads a path or an IO; parse_str reads in-memory text (a String argument to parse_file is always a path); from_json rebuilds from the internal balanced JSON snapshot to_json writes.
net = parse_file("case14.m")
net = parse_file(IOBuffer(text), "matpower")
net = parse_str(text, "matpower")
net = from_json(to_json(net))Whatever the reader could not represent or had to assume is retained on the handle; read it with PowerIO.warnings.
Inspecting a case
The element tables mirror the Rust BalancedNetwork: raw source units, 1-based bus ids, out-of-service elements retained. Consumers normalize as they see fit. Cheap metadata properties read a Rust summary and do not materialize net.data; element table properties materialize the cached JSON payload. REPL display uses the same summary path: compact display stays on one line, and the multiline text/plain form prints counts, base values, topology, warnings, and whether net.data has been materialized.
net.name
net.source_format
net.base_mva
net.buses # same as PowerIO.buses(net)
PowerIO.buses(net) # id, kind, vm, va (deg), base_kv, vmax, vmin, ...
PowerIO.generators(net) # bus, pg, qg, limits, cost, caps, in_service
PowerIO.branches(net) # from, to, r, x, b, rates, tap, shift (deg), ...
PowerIO.loads(net) # bus, p (MW), q (MVAr), in_service
PowerIO.shunts(net)
PowerIO.storage(net)
PowerIO.hvdc(net)
PowerIO.n_buses(net), PowerIO.n_branches(net), PowerIO.n_gens(net)
PowerIO.base_mva(net)
PowerIO.source_format(net) # "Matpower", "Psse", ...
PowerIO.reference_bus_id(net) # the slack bus id, or nothing
PowerIO.n_components(net) # connected components of the in-service topology
PowerIO.is_radial(net)
PowerIO.to_graph(net) # all buses, in-service branch edgesNormalizing
to_normalized derives a computation-ready copy: powers per unit, angles in radians, tap 0 → 1, out-of-service and isolated elements dropped, source bus ids preserved, bus types inferred.
norm = to_normalized(net)
PowerIO.source_format(norm) # "Normalized"
norm = to_normalized(net; clamp_angle_bounds=true, angle_bound_pad=pi / 3)The angle clamp option repairs PowerModels style branch angle bounds during normalization. The default to_normalized(net) preserves the source bounds.
Serializing
to_matpower(net) # ::String, byte exact when the input was MATPOWER
to_format(net, "powermodels-json") # (text, warnings)
to_json(net) # internal balanced JSON payload
convert_file("case14.m", "psse") # parse + write in one shot -> (text, warnings)
convert_str(text, "psse"; from="matpower")
write_pypsa_csv_folder(net, "out/") # the one directory writerDense numeric arrays
to_dense pulls the numeric tables as dense typed arrays straight from the C ABI extractors, skipping JSON entirely — the fast path for matrix assembly:
d = to_dense(net) # or to_dense("case14.m")
d.n, d.m, d.ng # bus / branch / generator counts
d.bus_ids # 1-based ids; row k of every per-bus table is bus_ids[k]
d.branch.from, d.branch.x
d.gen.bus, d.gen.pg
d.demand.pd, d.shunt.bs
d.reference_bus, d.n_components, d.is_radialArrow export
to_arrow brings one table across the Arrow C Data Interface (needs the library built with --features arrow; arrow_available reports it). Raw selectors are :bus, :branch, :gen, :load, :shunt, and :switch. Specialized normalized tables are available for consumers that need the Rust row index space directly.
t = to_arrow(net, :branch) # NamedTuple of owned Julia Vectors
z = to_arrow(net, :branch; copy=false) # zero copy ArrowTable; close when doneThe default returns owned columns (Tables.jl compatible, flows into Arrow.write, DataFrame, etc.) with no lifetime caveat. copy=false returns a zero copy ArrowTable whose columns reference the producer's memory. Extracted columns root the buffers themselves; reads after close(z) throw a Julia error.
See Matrices for the Rust computed sparse matrix API.