Metadata-Version: 2.5
Name: popo-flow
Version: 0.1.0
Summary: Low-voltage network simulation and state estimation for DER studies.
Project-URL: Homepage, https://github.com/sambaiga/popo
Project-URL: Repository, https://github.com/sambaiga/popo
Project-URL: Documentation, https://sambaiga.github.io/popo-docs
Project-URL: Bug Tracker, https://github.com/sambaiga/popo/issues
Project-URL: Changelog, https://github.com/sambaiga/popo/blob/main/CHANGELOG.md
Author-email: sambaiga <sambaiga@gmail.com>
License: Apache-2.0
License-File: LICENSE
Keywords: der,distribution-networks,low-voltage,opendss,power-systems,state-estimation
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: numpy>=2.4.4
Requires-Dist: pandas>=2.3.3
Requires-Dist: pyarrow>=23.0.0
Requires-Dist: pydantic>=2.13.0
Requires-Dist: rich>=15.0.0
Provides-Extra: all
Requires-Dist: great-tables>=0.21.0; extra == 'all'
Requires-Dist: lets-plot>=4.10.1; extra == 'all'
Requires-Dist: matplotlib>=3.10.0; extra == 'all'
Requires-Dist: opendssdirect-py>=0.9.4; extra == 'all'
Requires-Dist: pandapower>=3.5.4; extra == 'all'
Requires-Dist: scienceplots>=2.1.1; extra == 'all'
Requires-Dist: seaborn>=0.13.2; extra == 'all'
Provides-Extra: estimation
Requires-Dist: pandapower>=3.5.4; extra == 'estimation'
Provides-Extra: notebooks
Requires-Dist: great-tables>=0.21.0; extra == 'notebooks'
Requires-Dist: matplotlib>=3.10.0; extra == 'notebooks'
Provides-Extra: opendss
Requires-Dist: opendssdirect-py>=0.9.4; extra == 'opendss'
Provides-Extra: plot
Requires-Dist: great-tables>=0.21.0; extra == 'plot'
Requires-Dist: lets-plot>=4.10.1; extra == 'plot'
Requires-Dist: matplotlib>=3.10.0; extra == 'plot'
Requires-Dist: scienceplots>=2.1.1; extra == 'plot'
Requires-Dist: seaborn>=0.13.2; extra == 'plot'
Description-Content-Type: text/markdown

<p align="center">
  <img src="https://sambaiga.github.io/popo-docs/_static/img/logo.svg" alt="popo" width="320">
</p>

<p align="center">
  <a href="https://sambaiga.github.io/popo-docs"><b>Documentation</b></a> ·
  <a href="https://sambaiga.github.io/popo-docs/getting-started/quickstart.html">Quickstart</a> ·
  <a href="https://sambaiga.github.io/popo-docs/gallery.html">Tutorials</a> ·
  <a href="https://pypi.org/project/popo-flow/">PyPI</a>
</p>

# popo

<img src="https://sambaiga.github.io/popo-docs/_static/img/overview.svg" alt="popo simulates a feeder forward under rooftop solar and EV uptake, and estimates its state from the few measurements that exist" width="100%">

Low-voltage network simulation and state estimation for distributed energy resource studies.

**popo** is Swahili for bat. It is a companion to [twiga](https://sambaiga.github.io/twiga-docs),
Swahili for giraffe: twiga sees far, which is forecasting ahead in time; popo sees
in the dark, which is inferring the state of a network that is not measured.

Low-voltage distribution is largely unobservable. There are measurements at the
secondary substation and very little downstream, yet the decisions that matter,
how much solar or how many electric vehicles a feeder can take, depend on what
is happening at every customer terminal. This library is about reconstructing
that from what little is metered, and about simulating what a network would do
under a given level of DER uptake.

## Install

The solvers are optional, because reading a network definition or checking a
voltage limit against a standard needs neither:

```bash
uv add popo-flow                  # core: networks, standards, results
uv add popo-flow[opendss]         # + time-series power flow
uv add popo-flow[estimation]      # + weighted-least-squares state estimation
uv add popo-flow[all]
```

The distribution is named `popo-flow` because `popo` was already taken on PyPI;
the package itself is still imported as `import popo`.

## What is in it

| module | purpose |
|---|---|
| `popo.network` | load an OpenDSS circuit, inspect topology and elements |
| `popo.powerflow` | time-series solution, monitors, substation results |
| `popo.estimation` | WLS state estimation from a sparse measurement set |
| `popo.standards` | EN 50160 and ANSI C84.1 limits, violation reporting |
| `popo.scenarios` | DER penetration scenarios, EV and PV allocation |
| `popo.profiles` | household, PV and EV profile synthesis, and the SMART-DS pool |

## Learn it

Three tutorial notebooks under [`notebooks/`](notebooks/), each running end to end against
vendored data:

- [`01-opendss-lv-modeling.ipynb`](notebooks/01-opendss-lv-modeling.ipynb): build an LV circuit
  from scratch (transformer, linecodes, lines, loads), read it back with `popo.network.Circuit`
  and `popo.powerflow.results`, check compliance and list violations with
  `popo.standards.VoltageLimits`, and three worked network-expansion exercises.
- [`02-timeseries-der-modeling.ipynb`](notebooks/02-timeseries-der-modeling.ipynb): a real
  188-customer UK feeder with real household, PV and EV profiles, a time-series solve with
  `popo.powerflow.solve_time_series`, a hosting-capacity sweep with `run_uk_sweep`, every
  customer's voltage traced alongside the substation's, Volt-VAr, Volt-Watt and storage compared,
  and diversified against uncoordinated EV charging.
- [`03-lv-state-estimation.ipynb`](notebooks/03-lv-state-estimation.ipynb): the same feeder
  converted to pandapower and checked against OpenDSS, then estimated from the substation, smart
  meters and line sensors with `popo.estimation`, including how many meters are enough and why a
  coherent substation forecast estimates better than three separate ones.

`uv sync --all-extras` installs everything the notebooks use.

## Development

```bash
uv sync --all-extras          # environment with both solvers
make test                     # suite with the coverage gate, solvers deselected
make test-solver              # only the tests that need OpenDSS or pandapower
make lint                     # ruff check
make fmt                      # ruff format
make typecheck                # ty
make docs                     # serve the docs locally
```

Commits follow [conventional commits](https://www.conventionalcommits.org),
checked by commitizen through a pre-commit hook. Install the hooks once with
`uv run pre-commit install --install-hooks -t pre-commit -t commit-msg`.

## Status

Alpha, version 0.1.0. Nothing is published yet.

`popo` is cited in the thesis as `\texttt{Popo} \cite{faustine2026popo}` (Chapter 2, "The Three
Simulated Datasets"). What it can reproduce today, of the three:

- **DSS-US**: SMART-DS `AUS_P1U`, 596 pole transformers, around 6 customers each through a
  0.12 kV split-phase secondary, measured (not fixed-power-factor) P/Q, ANSI C84.1, mean customer
  power factor 0.911±0.041. Reproducible today: `popo.powerflow.sweep.run_us_sweep`, regression
  tested against a real recorded run in `tests/integration/test_us_sweep_regression.py`.
- **DSS-UK**: UK Generic Distribution System models, two substations selected by voltage
  sensitivity ("Feeder A", stiff, `21_1_1135`, 157 customers, 315 kVA; "Feeder B", weak,
  `17_1_1149`, 188 customers, 500 kVA), Low Carbon London demand ADMD-scaled to 0.8 kW/customer,
  PVWatts-driven PV, recorded EV charging sessions at constant 7.4 kW, and three modifications
  that decouple P from Q: independent customer power-factor profiles (0.88 to 0.995 lagging), a
  Q(U) droop on PV inverters (±0.33 pu per EN 50549-1/IEEE 1547), and an 11 kV source voltage
  that follows a demand-dependent profile within ±2% with a 0.5% tap-changer deadband.
  Reproducible today: `popo.powerflow.sweep.run_uk_sweep`, regression tested against a freshly
  generated real run in `tests/integration/test_uk_sweep_regression.py`.
- **DSS-EU**: a four-feeder Hybrid European MV-LV network (Deakin2021/Koirala2020 topology),
  AusNet demand/PV, Fachrizal2021 EV profiles, fixed power factor throughout with unity-PF PV
  inverters, EN 50160. Not reproducible: the generating script was never located in
  `ml-energy-disaggregation`, across two separate audits. See `docs/simulations.md` for the full
  account and `docs/EXTRACTION_PLAN.md` for the extraction history.

The core mechanics are extracted from `ml-energy-disaggregation`'s two legacy power-flow runners
and generalized across them: DER attachment and Volt-VAr control (`popo.scenarios`), the
time-series solve loop with convergence reported rather than printed (`popo.powerflow`),
transformer parsing and utilisation-based selection (`popo.network`), state estimation
(`popo.estimation`), and named voltage/inverter standards replacing the runners' divergent bare
constants (`popo.standards`). See `docs/simulations.md` for copy-pasteable end-to-end commands for
DSS-US and DSS-UK, and `docs/EXTRACTION_PLAN.md` for the extraction this package is built from.
Expect the API to change.

## Licence

Apache-2.0.
