Metadata-Version: 2.4
Name: powerio
Version: 0.11.9
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: License :: OSI Approved :: Apache Software License
Classifier: License :: OSI Approved :: MIT License
Classifier: Topic :: Scientific/Engineering
Classifier: Operating System :: OS Independent
Requires-Dist: numpy>=1.21 ; extra == 'all'
Requires-Dist: scipy>=1.7 ; extra == 'all'
Requires-Dist: networkx>=2.6 ; extra == 'all'
Requires-Dist: polars>=1 ; extra == 'all'
Requires-Dist: pandapower==3.2.2 ; extra == 'bench'
Requires-Dist: matpowercaseframes<3 ; extra == 'bench'
Requires-Dist: gridx-egret>=0.6 ; extra == 'bench'
Requires-Dist: pypsa>=1.0 ; extra == 'bench'
Requires-Dist: opendssdirect-py>=0.9,<0.10 ; extra == 'bench'
Requires-Dist: jsonschema>=4.18 ; extra == 'bench'
Requires-Dist: networkx>=2.6 ; extra == 'graph'
Requires-Dist: polars>=1 ; extra == 'gridfm'
Requires-Dist: numpy>=1.21 ; extra == 'matrix'
Requires-Dist: scipy>=1.7 ; extra == 'matrix'
Requires-Dist: mcp>=2,<3 ; extra == 'mcp'
Requires-Dist: numpy>=1.21 ; extra == 'mcp'
Requires-Dist: scipy>=1.7 ; extra == 'mcp'
Requires-Dist: pandas>=2 ; extra == 'pandas'
Requires-Dist: pyarrow>=23.0.1 ; extra == 'pandas'
Provides-Extra: all
Provides-Extra: bench
Provides-Extra: graph
Provides-Extra: gridfm
Provides-Extra: matrix
Provides-Extra: mcp
Provides-Extra: pandas
License-File: LICENSE-APACHE
License-File: LICENSE-MIT
Summary: Case parsing, conversion, matrices, and language bindings for power system data
Keywords: power systems,matpower,psse,powermodels,sparse,ptdf,dc-opf
License: MIT OR Apache-2.0
Requires-Python: >=3.11
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Documentation, https://eigenergy.github.io/powerio/
Project-URL: Issues, https://github.com/eigenergy/powerio/issues
Project-URL: Repository, https://github.com/eigenergy/powerio

# PowerIO

[![Rust](https://github.com/eigenergy/powerio/actions/workflows/rust.yml/badge.svg?branch=main)](https://github.com/eigenergy/powerio/actions/workflows/rust.yml)
[![Python](https://github.com/eigenergy/powerio/actions/workflows/python.yml/badge.svg?branch=main)](https://github.com/eigenergy/powerio/actions/workflows/python.yml)
[![Julia binding](https://github.com/eigenergy/powerio/actions/workflows/julia-binding.yml/badge.svg?branch=main)](https://github.com/eigenergy/powerio/actions/workflows/julia-binding.yml)
[![crates.io](https://img.shields.io/crates/v/powerio)](https://crates.io/crates/powerio)
[![docs.rs](https://docs.rs/powerio/badge.svg)](https://docs.rs/powerio)
[![PyPI](https://img.shields.io/pypi/v/powerio)](https://pypi.org/project/powerio/)
[![MSRV 1.88](https://img.shields.io/badge/MSRV-1.88-blue.svg)](https://github.com/eigenergy/powerio/blob/main/Cargo.toml)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](https://github.com/eigenergy/powerio/blob/main/LICENSE-MIT)

<p align="center">
  <img
    src="https://raw.githubusercontent.com/eigenergy/powerio/60e0126c/docs/src/assets/powerio-hero.png"
    alt="PowerIO format and matrix flow"
    width="720"
  >
</p>

PowerIO reads power system data into typed values, writes those values back
out in the formats other tools read, and builds the sparse matrices and graph
data that solvers consume. The core is Rust, and the Python package, the
Julia package [PowerIO.jl](https://github.com/eigenergy/PowerIO.jl), and the
C ABI expose the same operations under the same names.

A parse returns a `PioModule`, which is one typed value together with its
sources, diagnostics, source map, and history. Depending on what the source
declares, the value is a network, an operating point, a calculation instance,
a solution, a time series, a scenario set, a geographic layer, or a PSS/E
contingency analysis file.

[Convert files in the browser](https://powerio.dev/convert/), including mixed
transmission and distribution batches. Files stay on the computer.

## Install

```sh
cargo add powerio                 # parsing, emission, PowerIO IR
cargo add powerio -F matrix       # and sparse matrices, sensitivities, graph data
pip install powerio               # pip install 'powerio[all]' adds SciPy, NetworkX, Polars
julia -e 'using Pkg; Pkg.add("PowerIO")'
cargo install powerio-cli         # the powerio command
```

## Parse and emit

The examples use [case9.m](https://github.com/eigenergy/powerio/blob/main/tests/data/case9.m), the nine-bus MATPOWER case
included in this repository. Save it in your working directory first, or
replace `"case9.m"` with the path to your own case.

Rust:

```rust,ignore
use powerio::{PioValue, emit, parse};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let module = parse("case9.m")?;
    let PioValue::BalancedNetwork(network) = module.value() else {
        panic!("expected a balanced network");
    };
    assert_eq!(network.buses().len(), 9);
    emit(&module, "matpower", "copy.m")?;   // the source bytes, unchanged
    let result = emit(&module, "psse", "case9.raw")?;
    for finding in result.diagnostics() {
        eprintln!("{}", finding.code());    // what PSS/E cannot carry
    }
    Ok(())
}
```

Python:

```python
import powerio

module = powerio.parse("case9.m")
network = module.value
assert isinstance(network, powerio.BalancedNetwork)
module.diagnostics                          # the reader's findings
powerio.emit(module, "matpower", "copy.m")  # the source bytes, unchanged
result = powerio.emit(module, "psse")       # text in memory plus findings
```

Julia:

```julia
using PowerIO

module_ = parse("case9.m")            # PioModule{BalancedNetwork}
net = module_.value
length(net.buses)                     # 9
module_.diagnostics
emit(module_, "matpower", "copy.m")
```

Command line:

```sh
powerio convert case9.m --to psse -o case9.raw
powerio serialize case9.m -o case9.pio.json
powerio verify case9.m --kind bdoubleprime
powerio sensitivities case9.m -o out
```

If you write an unchanged module back to its own format, you get the source
back byte for byte. If you write it to another format, PowerIO keeps what
that format can represent and reports each loss as a diagnostic with a stable
code, so you can see what the conversion dropped. `serialize` and
`deserialize` write and read PowerIO IR, the JSON document that stores a
complete module for another PowerIO consumer to read back. It preserves the
typed data and its history; retained source bytes stay in the running process.
After deserialization, `emit` writes fresh output from the stored value.

## Formats

| Format | Token | Read | Write |
|---|---|---|---|
| MATPOWER `.m` | `matpower` | yes | yes |
| PSS/E RAW | `psse`, `psse34`, `psse35` | revisions 32 to 35 | 33, 34, 35 |
| PSS/E RAWX | `psse-rawx` | revision 35 | 35 |
| PSS/E contingency, subsystem, and monitored element files `.con`, `.sub`, `.mon` | `psse-con`, `psse-sub`, `psse-mon` | yes | yes |
| PowSybl XIIDM | `xiidm` | 1.0 to 1.17 | 1.17 |
| PowSybl JIIDM | `jiidm` | 1.0 to 1.17 | 1.17 |
| CIM CGMES profile set | `cgmes` | 2.4.15, 3.0 | 3.0 |
| ENTSO-E UCTE-DEF `.uct` | `ucte` | 2003.09.01, 2007.05.01 | 2007.05.01 |
| PowerWorld `.aux` | `powerworld` | yes | yes |
| PowerWorld `.pwb` | `pwb` | yes | no |
| PowerWorld `.pwd` display | `powerworld-pwd` | yes | no |
| GE PSLF `.epc` | `pslf` | yes | yes |
| IEEE Common Data Format | `ieee-cdf` | yes | no |
| PowerModels JSON | `powermodels-json` | yes | yes |
| Egret JSON | `egret-json` | yes | yes |
| pandapower JSON | `pandapower-json` | yes | yes |
| PyPSA CSV directory | `pypsa-csv` | yes | yes |
| Surge JSON | `surge-json` | yes | yes |
| MG-RAVENS JSON, balanced and multiconductor profiles | `ravens-json` | yes | yes |
| GridFM Parquet directory, `gridfm` feature | `gridfm` | yes | yes |
| DOE GO Challenge 3 JSON | `goc3-json` | problem, or problem with solution | a complete solution |
| DeepMind OPFData JSON | `opfdata-json` | yes | no |
| OpenDSS `.dss` | `dss` | yes | yes |
| PowerModelsDistribution ENGINEERING JSON | `pmd-json` | yes | yes |
| PowerModelsDistribution MATHEMATICAL JSON | `pmd-math-json` | yes | yes |
| BMOPF JSON | `bmopf-json`, `bmopf-json@0.1.0`, `bmopf-json@0.2.0` | 0.1.0, 0.2.0 | 0.1.0, 0.2.0 (default) |
| Distribution CIM, CIM100 RDF/XML | `cim-dist` | cim17v40, one document or a directory | cim17v40, one document |
| PSS SINCAL project, `sincal` feature | `sincal-balanced`, `sincal-multiconductor` | yes, with an explicit profile | an unchanged source byte for byte; an experimental fresh writer in Rust |
| Geographic layer `.geo.json` | `geo-json` | yes | yes |

The balanced transmission formats parse to `BalancedNetwork`, and OpenDSS,
PMD, BMOPF, and distribution CIM parse to `MulticonductorNetwork`. SINCAL
holds both kinds of network in one project, so a parse names its profile:
`sincal-balanced` gives a `BalancedNetwork` and `sincal-multiconductor` a
`MulticonductorNetwork`. A GO Challenge 3 problem
parses to `AcScucInstance`, a problem with its solution to `AcScucSolution`,
an OPFData file to `AcOpfSolution`, a GridFM dataset to
`ScenarioSet<BalancedNetwork>`, a PyPSA directory with several snapshots to a
`TimeSeries<BalancedNetwork>`, or to `TimeSeries<OperatingPoint<BalancedNetwork>>`
when only the electrical state varies, a PowerWorld `.pwd` display and a
`.geo.json` file to `GeoLayer`, and the PSS/E `.con`, `.sub`, and `.mon` files to
`ContingencySet`, `SubsystemSet`, and `MonitoredSet`. PowerIO IR is not in the
table: it moves only through `serialize` and `deserialize`, and `parse`
refuses it.

The `gridfm` and `sincal` cargo features gate their formats. The facade
leaves `gridfm` off and turns `sincal` on by default; the CLI and the Python
wheel include both. The
[format guide](https://eigenergy.github.io/powerio/guide/format-fidelity.html)
says what each reader keeps, what each writer reports, and how each is
checked against its reference implementation.

## Packages

Start with `powerio` in an application. The component crates let libraries
depend on just the layer they use.

| Crate | Provides |
|---|---|
| `powerio` | `PioValue`, `parse`, `emit`, `serialize`, `deserialize` |
| `powerio-core` | `Source`, `PioModule`, diagnostics, collections, destinations |
| `powerio-tx` | `BalancedNetwork` and balanced format readers and writers |
| `powerio-dist` | `MulticonductorNetwork` and OpenDSS, PMD, BMOPF, CIM converters |
| `powerio-prob` | Operating points, updates, calculation instances and solutions |
| `powerio-matrix` | Sparse matrices, sensitivities, DC OPF bundles and graph data |
| `powerio-cli` | The `powerio` command and its terminal interface |
| `powerio-py` | The native extension used by the Python package |
| `powerio-capi` | C ABI 7, used by Julia and other FFI bindings |

`powerio-tx` and `powerio-dist` share `powerio-core` and nothing else, so a
distribution consumer pulls in no transmission code. `powerio-prob` is matrix
free. The `powerio` facade re-exports the component crates, with
`powerio-matrix` behind its `matrix` feature. Native SINCAL support is the
`sincal` feature, on by default; it brings in SQLite, so a
`wasm32-unknown-unknown` build with it needs a C compiler with a WebAssembly
backend, and `default-features = false` leaves it out.

## Documentation

- [Guide](https://eigenergy.github.io/powerio/guide/)
- [Core concepts](https://eigenergy.github.io/powerio/guide/concepts.html)
- [Formats and fidelity](https://eigenergy.github.io/powerio/guide/format-fidelity.html)
- [Matrices and graphs](https://eigenergy.github.io/powerio/guide/matrices.html)
- [Rust, Python, Julia, and C](https://eigenergy.github.io/powerio/guide/languages.html)
- [Migrating from 0.10](https://eigenergy.github.io/powerio/guide/migration-0.11.html)
- [Rust API reference](https://eigenergy.github.io/powerio/powerio/)
- [PowerIO.jl](https://eigenergy.github.io/PowerIO.jl)
- [Contributing](https://github.com/eigenergy/powerio/blob/main/CONTRIBUTING.md)

## License

Apache License 2.0 or MIT License, at your option.

