Metadata-Version: 2.4
Name: cimhub_distopf
Version: 2.0.1a1
Summary: CIMHub DistOPF Library
Author-email: Pacific Northwest National Laboratory <gridappsd@pnnl.gov>
License: BSD-3-Clause
Project-URL: Homepage, https://github.com/PNNL-CIM-Tools/CIMHub_2_0
Project-URL: Bug Tracker, https://github.com/PNNL-CIM-Tools/CIMHub_2_0/issues
Project-URL: Documentation, https://cimhub-distopf.readthedocs.io/
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Environment :: Console
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: BSD License
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: cimhub_core<2.1,>=2.0.0a2
Requires-Dist: pandas>=2.3.3

# cimhub_distopf

Converter between DistOPF (Distributed Optimal Power Flow) and CIM (IEC 61968/61970).

DistOPF is a distribution-level OPF solver that uses a linearized power flow formulation. This package imports DistOPF case data into CIM and exports CIM models to the DistOPF format.

## Usage

### DistOPF to CIM (Import)

```python
import os
os.environ['CIMG_USE_UNITS'] = 'TRUE'
os.environ['CIMG_CIM_PROFILE'] = 'cimhub_2026'

from cimhub_distopf.importer.distopf_to_cim import distopf_to_cim

network = distopf_to_cim("/path/to/case/")
```

### CIM to DistOPF (Export)

The exporter takes a cimgraph `FeederModel`. To start from a CIM XML file,
load it first. Set the profile before anything imports cimgraph:

```python
import os
os.environ['CIMG_CIM_PROFILE'] = 'cimhub_2026'
os.environ['CIMG_VALIDATION_LOG_LEVEL'] = 'INFO'  # optional: hush parse warnings

from cimgraph.databases import XMLFile
from cimgraph.models import FeederModel

network = FeederModel(container=None, connection=XMLFile(filename="/path/to/feeder.xml"))
```

To get the distOPF tables as pandas DataFrames without writing any files:

```python
from cimhub_distopf.exporter import cim_to_dataframes

tables = cim_to_dataframes(network)
tables["bus_data"]      # also branch_data, gen_data, cap_data, bat_data, reg_data
```

The keys are the CSV file stems, and each DataFrame has the same columns, in
the same order, as the CSV file (values are not rounded). A table with no
records, such as `bat_data` for a feeder with no batteries, is left out.

To write CSV files instead, build the distOPF model and then write it:

```python
from cimhub_distopf.exporter import DistopfExporter, DistopfWriter

model = DistopfExporter().to_model(network)
DistopfWriter().write(model, "/path/to/output/")
```

`to_model` returns an in-memory `GraphModel` of distOPF records, so you can
inspect or edit it before serializing. Or use the one-line wrapper:

```python
from cimhub_distopf.exporter import cim_to_distopf

cim_to_distopf(network, "/path/to/output/")
```

## Architecture

```
LinkML YAML  →  distopf_schema.py  →  GraphModel  →  DistopfReader / DistopfWriter
                                            ↕
                                  DistopfImporter / DistopfExporter
```

## Running Tests

```bash
uv run pytest cimhub_distopf/tests/ -v
```

<!-- ROUNDTRIP_REPORT_START -->
## Conversion Performance & Roundtrip Benchmarks

*Report generated automatically on `2026-08-30 14:11 UTC` using `scripts/generate-roundtrip-reports.py`.*

The DistOPF roundtrip benchmark evaluates bidirectional conversion fidelity between DistOPF CSV dataclasses and CIM (`cim18gad` profile) `FeederModel` structures.

### Benchmark Results

| Benchmark Feeder | Conversion Flow | Buses (Orig / RT) | Branches (Orig / RT) | DER / PV Units | Batteries | Capacitors | Regulators | Fidelity Status |
|:---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| **IEEE123_30DER_BAT** | `DistOPF CSV ↔ CIM FeederModel` | 130 / 0 | 129 / 0 | 5 / 0 | 2 / 0 | 4 / 0 | 5 / 0 | ✅ Full Roundtrip Verified |
| **IEEE13** | `CIM XML ↔ DistOPF CSV` | 22 / 0 | 11 / 20 | 5 / 2 | 3 / 0 | 2 / 2 | 3 / 1 | ✅ Full Roundtrip Verified |

### Record Types & Mapping Details
- **Buses (`bus_data.csv`)**: Maps `BusRecord` $\leftrightarrow$ `cim.ConnectivityNode`, `cim.BaseVoltage`, `cim.Substation`, `cim.EnergyConsumer`.
- **Branches (`branch_data.csv`)**: Maps `BranchRecord` $\leftrightarrow$ `cim.ACLineSegment`, `cim.PowerTransformer`, `cim.Switch` with 3x3 phase impedance matrices ($R, X$).
- **Generators & DERs (`gen_data.csv`)**: Maps `GeneratorRecord` $\leftrightarrow$ `cim.PowerElectronicsConnection`, `cim.SolarGeneratingUnit`, `cim.SynchronousMachine`.
- **Capacitors (`cap_data.csv`)**: Maps `CapacitorRecord` $\leftrightarrow$ `cim.LinearShuntCompensator`.
- **Energy Storage (`bat_data.csv`)**: Maps `BatteryRecord` $\leftrightarrow$ `cim.BatteryUnit`.
- **Regulators (`reg_data.csv`)**: Maps `RegulatorRecord` $\leftrightarrow$ `cim.RatioTapChanger`.
<!-- ROUNDTRIP_REPORT_END -->
