Skip to main content

Machine learning for power flow

Project description

MLPF is a python library for (optimal) power flow calculations with machine learning.

It offers a few main features such as:

:chart_with_downwards_trend: Efficient loss functions compatible with both PyTorch and scikit-learn .

💱 Conversion functions to go from PPCs to NumPy arrays or Torch tensors.


As well as some optional high level utilities:

ðŸ—‚ï¸ Data classes that make it easy to go from PPCs to custom (or PyTorch Geometric ) data objects with all the info needed for (O)PF extracted.

📊 Metrics specific to (O)PF for logging and evaluation.

🔎 Visualization and description tools to take a quick look at your data.

Contributions welcome!

Installation

pip install mlpf

The previous command will install all the dependencies for working with numpy and scikit-learn. It will not, however, install all the dependencies needed for working with torch. To use the torch functionalities, please install PyTorch, PyTorch Geometric with its dependencies(torch-scatter etc.) and optionally TorchMetrics.

Installation directly from the master branch:

pip install git+https://github.com/viktor-ktorvi/mlpf.git

Basic usage

:cd: :file_folder: Load your data in the PYPOWER case format.

:open_file_folder: :arrow_heading_up: Extract powers, voltages, limits and cost coefficients from the PPCs into either NumPy arrays or torch tensors.

ðŸ‹ðŸ»â€â™€ï¸ :chart_with_downwards_trend: Plug the data into your machine learning models.

:chart_with_upwards_trend: :bar_chart: Use the loss functions to evaluate your results or to train your models(the torch versions of the loss functions are differentiable!).

In depth examples

Power flow Optimal power flow
Data extraction and loss
Supervised learning
Unsupervised learning

Quick start

Power flow

ppc
import copy

import pandapower as pp
import pandapower.networks as pn

from pypower.ppoption import ppoption
from pypower.runpf import runpf

net = pn.case118()

ppc = pp.converter.to_ppc(net, init="flat")

ppopt = ppoption(OUT_ALL=0, VERBOSE=0)
ppc, converged = runpf(copy.deepcopy(ppc), ppopt=ppopt)
NumPy/scikit-learn
import numpy as np

from mlpf.data.conversion.numpy.power_flow import (
    extract_line_arrays,
    extract_power_arrays,
    extract_voltage_arrays
)

from mlpf.loss.numpy.power_flow import (
    active_power_errors,
    reactive_power_errors
)

# extract quantities
active_powers, reactive_powers = extract_power_arrays(ppc)
voltage_magnitudes, voltage_angles = extract_voltage_arrays(ppc)
edge_index, conductances, susceptances = extract_line_arrays(ppc)

active_errors = active_power_errors(edge_index, active_powers, voltage_magnitudes, voltage_angles, conductances, susceptances)
reactive_errors = reactive_power_errors(edge_index, reactive_powers, voltage_magnitudes, voltage_angles, conductances, susceptances)

print(f"Total P loss = {np.sum(active_errors):.3e} p.u.")
print(f"Total Q loss = {np.sum(reactive_errors):.3e} p.u.")
Torch
import torch

from mlpf.data.conversion.torch.power_flow import (
    extract_line_tensors,
    extract_power_tensors,
    extract_voltage_tensors
)
from mlpf.loss.torch.power_flow import (
    active_power_errors,
    reactive_power_errors
)

# extract quantities
# note: going from float64 to float32(the standard in torch) will increase the PF loss significantly
active_powers, reactive_powers = extract_power_tensors(ppc, dtype=torch.float64)
voltage_magnitudes, voltage_angles = extract_voltage_tensors(ppc, dtype=torch.float64)
edge_index, conductances, susceptances = extract_line_tensors(ppc, dtype=torch.float64)

active_errors = active_power_errors(edge_index, active_powers, voltage_magnitudes, voltage_angles, conductances, susceptances)
reactive_errors = reactive_power_errors(edge_index, reactive_powers, voltage_magnitudes, voltage_angles, conductances, susceptances)

print(f"Total P loss = {torch.sum(active_errors):.3e} p.u.")
print(f"Total Q loss = {torch.sum(reactive_errors):.3e} p.u.")

Optimal power flow

ppc
import copy

import pandapower as pp
import pandapower.networks as pn

from pypower.ppoption import ppoption
from pypower.runopf import runopf

net = pn.case118()
ppc = pp.converter.to_ppc(net, init="flat")

ppopt = ppoption(OUT_ALL=0, VERBOSE=0)
ppc = runopf(copy.deepcopy(ppc), ppopt=ppopt)
NumPy/scikit-learn
import numpy as np

from mlpf.data.conversion.numpy.optimal_power_flow import (
    extract_active_power_limits_arrays,
    extract_cost_coefficients_array,
    extract_demand_arrays,
    extract_reactive_power_limits_arrays,
    extract_voltage_limits_arrays,
)

from mlpf.data.conversion.numpy.power_flow import (
    extract_power_arrays,
    extract_voltage_arrays
)

from mlpf.loss.numpy.bound_errors import (
    lower_bound_errors,
    upper_bound_errors
)

from mlpf.loss.numpy.costs import polynomial_costs

# extract quantities
active_powers, reactive_powers = extract_power_arrays(ppc)
voltage_magnitudes, voltage_angles = extract_voltage_arrays(ppc)

voltages_min, voltages_max = extract_voltage_limits_arrays(ppc)
active_powers_min, active_powers_max = extract_active_power_limits_arrays(ppc)
reactive_powers_min, reactive_powers_max = extract_reactive_power_limits_arrays(ppc)

active_power_demands, _ = extract_demand_arrays(ppc)
active_powers_generation = (active_powers + active_power_demands) * ppc["baseMVA"]

cost_coefficients = extract_cost_coefficients_array(ppc)

# calculate errors
voltage_upper_errors = upper_bound_errors(voltage_magnitudes, voltages_max)
voltage_lower_errors = lower_bound_errors(voltage_magnitudes, voltages_min)

active_upper_errors = upper_bound_errors(active_powers, active_powers_max)
active_lower_errors = lower_bound_errors(active_powers, active_powers_min)

reactive_upper_errors = upper_bound_errors(reactive_powers, reactive_powers_max)
reactive_lower_errors = lower_bound_errors(reactive_powers, reactive_powers_min)

cost_errors = np.sum(polynomial_costs(active_powers_generation, cost_coefficients)) - ppc["f"]

print(f"Total V max violation = {np.sum(voltage_upper_errors):.3e} p.u.")
print(f"Total V min violation = {np.sum(voltage_lower_errors):.3e} p.u.")

print(f"Total P max violation = {np.sum(active_upper_errors):.3e} p.u.")
print(f"Total P min violation = {np.sum(active_lower_errors):.3e} p.u.")

print(f"Total Q max violation = {np.sum(reactive_upper_errors):.3e} p.u.")
print(f"Total Q min violation = {np.sum(reactive_lower_errors):.3e} p.u.")

print(f"Total costs = {cost_errors:.3e} $/h")
Torch
import torch

from mlpf.data.conversion.torch.optimal_power_flow import (
    extract_active_power_limits_tensors,
    extract_cost_coefficients_tensor,
    extract_demand_tensors,
    extract_reactive_power_limits_tensors,
    extract_voltage_limits_tensors,
)

from mlpf.data.conversion.torch.power_flow import (
    extract_power_tensors,
    extract_voltage_tensors
)

from mlpf.loss.torch.bound_errors import (
    lower_bound_errors,
    upper_bound_errors
)

from mlpf.loss.torch.costs import polynomial_costs

# extract quantities
active_powers, reactive_powers = extract_power_tensors(ppc, dtype=torch.float64)
voltage_magnitudes, voltage_angles = extract_voltage_tensors(ppc, dtype=torch.float64)

voltages_min, voltages_max = extract_voltage_limits_tensors(ppc, dtype=torch.float64)
active_powers_min, active_powers_max = extract_active_power_limits_tensors(ppc, dtype=torch.float64)
reactive_powers_min, reactive_powers_max = extract_reactive_power_limits_tensors(ppc, dtype=torch.float64)

active_power_demands, _ = extract_demand_tensors(ppc, dtype=torch.float64)
active_powers_generation = (active_powers + active_power_demands) * ppc["baseMVA"]

cost_coefficients = extract_cost_coefficients_tensor(ppc, dtype=torch.float64)

# calculate errors
voltage_upper_errors = upper_bound_errors(voltage_magnitudes, voltages_max)
voltage_lower_errors = lower_bound_errors(voltage_magnitudes, voltages_min)

active_upper_errors = upper_bound_errors(active_powers, active_powers_max)
active_lower_errors = lower_bound_errors(active_powers, active_powers_min)

reactive_upper_errors = upper_bound_errors(reactive_powers, reactive_powers_max)
reactive_lower_errors = lower_bound_errors(reactive_powers, reactive_powers_min)

cost_errors = torch.sum(polynomial_costs(active_powers_generation, cost_coefficients)) - ppc["f"]

print(f"Total V max violation = {torch.sum(voltage_upper_errors):.3e} p.u.")
print(f"Total V min violation = {torch.sum(voltage_lower_errors):.3e} p.u.")

print(f"Total P max violation = {torch.sum(active_upper_errors):.3e} p.u.")
print(f"Total P min violation = {torch.sum(active_lower_errors):.3e} p.u.")

print(f"Total Q max violation = {torch.sum(reactive_upper_errors):.3e} p.u.")
print(f"Total Q min violation = {torch.sum(reactive_lower_errors):.3e} p.u.")

print(f"Total costs = {cost_errors:.3e} $/h")

Development

git clone https://github.com/viktor-ktorvi/mlpf.git
cd mlpf

conda env create -f environment.yml
conda activate mlpfenv

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mlpf-0.0.9.tar.gz (45.2 kB view details)

Uploaded Source

Built Distribution

mlpf-0.0.9-py3-none-any.whl (54.1 kB view details)

Uploaded Python 3

File details

Details for the file mlpf-0.0.9.tar.gz.

File metadata

  • Download URL: mlpf-0.0.9.tar.gz
  • Upload date:
  • Size: 45.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.16

File hashes

Hashes for mlpf-0.0.9.tar.gz
Algorithm Hash digest
SHA256 6704a5c9b1735a60d2598f4d1f82d602d190abb9245e5a061b6a182c0d7a2a85
MD5 55ad2ee90c0431c8fba09a55632a95e0
BLAKE2b-256 2c9466b2b1b1fc236a826e040a9795b3cfbc236f0a3f8f736f83af9199e1f669

See more details on using hashes here.

File details

Details for the file mlpf-0.0.9-py3-none-any.whl.

File metadata

  • Download URL: mlpf-0.0.9-py3-none-any.whl
  • Upload date:
  • Size: 54.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.16

File hashes

Hashes for mlpf-0.0.9-py3-none-any.whl
Algorithm Hash digest
SHA256 b48876a3d2402b7a657b7b9311c8a4637e59e3de158d3bafa1fafbdf9a1693f0
MD5 0e8d960a205d6b2203554bc550bb9ba2
BLAKE2b-256 f261143345c5f47fae762f2a8f0fe214917b1a5dd70959272146e06cfb833089

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page