Skip to content

shankarkarki/Distrubution-Factors-Implementation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 

Repository files navigation

⚡ Power System Sensitivity Factors — PTDF, LODF & GSF

A production-grade Python toolkit for computing and analyzing network sensitivity factors in electricity markets and transmission planning.
Built by a power systems & market engineer with hands-on experience across ERCOT, MISO, PJM, SPP, and the Australian NEM.


🧭 Overview

Network sensitivity factors are at the heart of transmission planning, security-constrained economic dispatch (SCED), and locational marginal pricing (LMP). Every time a market operator clears energy — whether it's AEMO's NEM dispatch engine or PJM's real-time market — these linear approximations of power flow govern how generation shift propagates through the network.

This project computes, validates, and visualizes three foundational sensitivity matrices:

Factor Full Name Core Question It Answers
PTDF Power Transfer Distribution Factor "If I shift 1 MW from bus A to bus B, what fraction flows on line k?"
LODF Line Outage Distribution Factor "If line k trips, what fraction of its pre-outage flow diverts onto line m?"
GSF / ISF Generation Shift Factor / Injection Shift Factor "If generator at bus i increases output by 1 MW (slack absorbs), what is the change in flow on line k?"

Together, these factors power:

  • Contingency Analysis (N-1, N-2) — rapid screening without full AC power flow
  • Congestion Rent & FTR/CRR Valuation — financial transmission rights settlement
  • Interface Limit Monitoring — enforcing flowgate constraints in real-time dispatch
  • Integrated System Planning — REZ capacity expansion & transmission augmentation studies (e.g., AEMO ISP)
  • Production Cost Modeling — PLEXOS and PROMOD constraint formulations

📐 Mathematical Foundations

Network Representation

A power network is represented by its bus admittance matrix $Y_{bus}$ (or its DC approximation). Under the DC power flow linearization (lossless, flat voltage profile, small angle differences):

$$P_{flow} = B_{f} \cdot \theta$$

$$B_{bus} \cdot \theta = P_{inject}$$

Where:

  • $B_{bus} \in \mathbb{R}^{n \times n}$ — susceptance matrix (nodal)
  • $B_f \in \mathbb{R}^{l \times n}$ — branch susceptance matrix
  • $\theta \in \mathbb{R}^{n}$ — voltage angle vector
  • $P_{inject} \in \mathbb{R}^{n}$ — net bus injections (generation − load)

1️⃣ Power Transfer Distribution Factor (PTDF)

The PTDF matrix $H$ is defined as:

$$H = B_f \cdot B_{bus,red}^{-1}$$

Where $B_{bus,red}$ is the reduced susceptance matrix (reference bus row/column removed). Each element:

$$\text{PTDF}_{k, i \to j} = H_{k,i} - H_{k,j}$$

represents the fraction of a 1 MW transaction from bus $i$ to bus $j$ that flows on branch $k$.

Key properties:

  • $\sum_k \text{PTDF}_{k, i \to j} \neq 1$ (flows split across parallel paths)
  • PTDF is topology-dependent — it changes with network switching
  • Used in zonal PTDFs for market clearing (e.g., AEMO's regional reference nodes)

2️⃣ Line Outage Distribution Factor (LODF)

When line $k$ is outaged, the flow redistribution onto line $m$ is:

$$\text{LODF}_{m,k} = \frac{\Delta F_m}{F_k^0}$$

Computed analytically from the PTDF matrix:

$$\text{LODF}_{m,k} = \frac{\text{PTDF}_{m, i(k) \to j(k)}}{1 - \text{PTDF}_{k, i(k) \to j(k)}}$$

Where $i(k)$ and $j(k)$ are the from-bus and to-bus of the outaged line $k$.

Key properties:

  • $\text{LODF}_{k,k} = -1$ (outaged line carries zero flow post-outage)
  • Enables N-1 contingency screening in $O(l^2)$ vs. full power flow per contingency
  • Foundation of post-contingency flow calculation: $F_m^{post} = F_m^{pre} + \text{LODF}_{m,k} \cdot F_k^{pre}$

3️⃣ Generation Shift Factor (GSF) / Injection Shift Factor (ISF)

The GSF for generator at bus $i$ on branch $k$:

$$\text{GSF}_{k,i} = H_{k,i}$$

This is simply the $i$-th column of the PTDF matrix (relative to the slack bus). It answers: "If bus $i$ increases injection by 1 MW with the slack bus absorbing, how does flow on branch $k$ change?"

Relationship between factors:

$$\text{PTDF}_{k, i \to j} = \text{GSF}_{k,i} - \text{GSF}_{k,j}$$

Applications:

  • SCED constraint formulation — each generator's impact on monitored flowgates
  • Congestion component of LMP$\lambda_k^{congestion} = \sum_m \mu_m \cdot \text{GSF}_{m,k}$ where $\mu_m$ is the shadow price on constraint $m$
  • Redispatch analysis — identifying which generators relieve congestion most efficiently

🗂️ Repository Structure

power-sensitivity-factors/
│
├── data/
│   ├── raw/                    # Raw network data (MATPOWER, PSS/E, CSV)
│   ├── processed/              # Cleaned bus/branch/gen tables
│   └── test_cases/             # IEEE 14-bus, 30-bus, 118-bus test cases
│
├── src/
│   ├── network/
│   │   ├── __init__.py
│   │   ├── admittance.py       # Y_bus, B_bus construction
│   │   ├── dc_powerflow.py     # DC power flow solver
│   │   └── topology.py         # Network graph utilities
│   │
│   ├── sensitivity/
│   │   ├── __init__.py
│   │   ├── ptdf.py             # PTDF computation engine
│   │   ├── lodf.py             # LODF computation (full & sparse)
│   │   ├── gsf.py              # GSF / ISF computation
│   │   └── contingency.py      # N-1 / N-2 screening using LODF
│   │
│   ├── market/
│   │   ├── lmp_decomposition.py   # Energy + congestion + loss components
│   │   ├── ftr_valuation.py       # Financial transmission rights
│   │   └── flowgate_monitor.py    # Real-time interface monitoring
│   │
│   └── visualization/
│       ├── network_plot.py     # Networkx / plotly network diagrams
│       ├── heatmaps.py         # PTDF/LODF matrix heatmaps
│       └── congestion_map.py   # Geospatial congestion overlays
│
├── notebooks/
│   ├── 01_theory_and_derivation.ipynb     # Mathematical walkthrough
│   ├── 02_ieee14_ptdf_demo.ipynb          # PTDF on IEEE 14-bus
│   ├── 03_n1_contingency_screening.ipynb  # LODF-based contingency analysis
│   ├── 04_lmp_decomposition.ipynb         # Congestion pricing example
│   └── 05_nem_interface_monitoring.ipynb  # Australian NEM flowgate case study
│
├── tests/
│   ├── test_ptdf.py
│   ├── test_lodf.py
│   ├── test_gsf.py
│   └── validate_against_powerworld.py    # Cross-validation with commercial tools
│
├── docs/
│   ├── theory.md               # Extended mathematical documentation
│   ├── market_applications.md  # How factors are used in market operations
│   └── aemo_case_study.md      # NEM-specific application notes
│
├── requirements.txt
├── environment.yml
└── README.md

🚀 Quick Start

Installation

git clone https://github.com/shankar/<repo-name>.git
cd power-sensitivity-factors

# Using pip
pip install -r requirements.txt

# Or using conda (recommended for power systems stack)
conda env create -f environment.yml
conda activate power-sensitivity

Dependencies

numpy>=1.24
scipy>=1.10          # sparse matrix operations (critical for large networks)
pandas>=2.0
networkx>=3.0        # network topology
pandapower>=2.13     # power system modeling & validation
matplotlib>=3.7
plotly>=5.15         # interactive network visualization
pypower              # MATPOWER-compatible DC/AC power flow

Compute PTDF — Minimal Example

import numpy as np
from src.network.admittance import build_Bbus
from src.sensitivity.ptdf import compute_ptdf

# Load IEEE 14-bus test case
from pypower.case14 import case14
ppc = case14()

# Build susceptance matrices
Bf, Bbus = build_Bbus(ppc)

# Compute full PTDF matrix [branches x buses]
ptdf = compute_ptdf(Bf, Bbus, ref_bus=0)

print(f"PTDF shape: {ptdf.shape}")  # (20, 14) for IEEE 14-bus
print(f"PTDF[line_1, bus_2→bus_5]: {ptdf[0, 1] - ptdf[0, 4]:.4f}")

Compute LODF from PTDF

from src.sensitivity.lodf import compute_lodf

# LODF matrix [branches x branches]
lodf = compute_lodf(ptdf, ppc['branch'])

# Post-contingency flow on line m when line k trips
line_k = 5   # outaged line index
pre_flow = np.array([...])   # pre-contingency flows in MW

post_flow = pre_flow + lodf[:, line_k] * pre_flow[line_k]
print(f"Post-contingency flow on line 3: {post_flow[2]:.2f} MW")

N-1 Contingency Screening

from src.sensitivity.contingency import n1_screening

results = n1_screening(
    base_flows=pre_flow,
    lodf=lodf,
    ratings=ppc['branch'][:, 5],   # thermal ratings in MVA
    threshold=0.95                  # flag at 95% of rating
)

violations = results[results['overload_pct'] > 100]
print(violations[['outaged_line', 'overloaded_line', 'overload_pct']])

📊 Key Results & Validation

IEEE 14-Bus PTDF Heatmap

The PTDF matrix visually reveals electrical coupling between transactions and branches. High-magnitude cells indicate strong sensitivity — a 1 MW shift on that bus pair significantly loads that branch.

📓 See notebooks/02_ieee14_ptdf_demo.ipynb for full visualization

N-1 Contingency Screening Performance

Network Size Full AC Power Flow (per contingency) LODF Screening
14-bus (20 lines) ~400 power flows 1 matrix multiply
118-bus (186 lines) ~34,716 power flows 1 matrix multiply
2000-bus (3,000 lines) ~9M power flows Sparse matrix ops

LODF-based screening provides exact N-1 results under DC assumptions at a fraction of the computational cost — which is precisely why real-time market engines (ERCOT SCED, AEMO's dispatch engine) rely on them.

Validation

All sensitivity matrices are cross-validated against:

  • PYPOWER — open-source MATPOWER port
  • pandapower — for DC power flow cross-checks
  • Analytical hand-calculations — on 3-bus and 5-bus toy networks

🌏 Market Applications & Case Studies

Australian NEM — Interface Flow Monitoring

AEMO monitors interconnector flows (e.g., Heywood, QNI, Basslink) using sensitivity-based constraint formulations. The Market Constraint Equations in NEMDE (NEM Dispatch Engine) are linear constraint rows of the form:

Σ (GSF_k,i × P_i) ≤ RHS_k    for each monitored element k

This project includes a case study replicating NEM-style interface constraint formulation using publicly available AEMO network data.

📓 See notebooks/05_nem_interface_monitoring.ipynb

LMP Congestion Component Decomposition

The congestion component of an LMP at bus $i$:

$$\lambda_i^{congestion} = -\sum_{k \in \text{binding}} \mu_k \cdot \text{GSF}_{k,i}$$

Where $\mu_k$ is the shadow price (dual variable) on binding constraint $k$. This project demonstrates LMP decomposition on a 5-bus illustrative network.

FTR / CRR Valuation

Financial Transmission Rights settle on the difference in LMPs weighted by the FTR MW quantity. Under the PTDF framework:

$$\text{FTR Revenue} = \text{FTR}_{MW} \times (\lambda_{sink} - \lambda_{source})$$

The project includes utilities for simulating FTR auction value under different congestion scenarios.


🔬 Implementation Notes

Numerical Stability

  • The $B_{bus}$ matrix inversion uses sparse LU factorization (scipy.sparse.linalg.splu) for large networks — critical for real-world systems with thousands of buses
  • Reference bus removal must be handled consistently — an off-by-one error here produces silently wrong PTDF values
  • For near-radial networks, some LODF denominators approach zero (radial line has PTDF ≈ 1) — these are handled with a configurable threshold

Sparse vs Dense

For networks > 500 buses, dense matrix operations become prohibitive. The lodf.py module offers both:

  • compute_lodf_dense() — for small networks and testing
  • compute_lodf_sparse() — scipy sparse, suitable for real ISO-scale networks

Sign Convention

This implementation follows the from-bus injection positive convention consistent with MATPOWER and pandapower. Some commercial tools (PowerWorld, PSS/E) may use different sign conventions — always verify before cross-validation.


🗺️ Roadmap

  • AC sensitivity factors (Q-V sensitivity, voltage sensitivity matrix)
  • Multi-period PTDF for time-varying topology (switching, maintenance outages)
  • LODF extension to N-2 contingencies (cascading failure screening)
  • Integration with NEMOSIS / AEMO data API for real NEM network data
  • PLEXOS-compatible constraint export (LP file format)
  • Interactive Plotly dashboard for congestion visualization

👤 About the Author

Shankar — Simulation Engineer | Power Markets & Transmission Planning

📚 References & Further Reading

  1. Stott, B., Jardim, J., Alsaç, O. (2009). DC Power Flow Revisited. IEEE Transactions on Power Systems.
  2. Wood, A.J., Wollenberg, B.F., Sheblé, G.B.Power Generation, Operation and Control (3rd Ed.)
  3. Ott, A. (2010). Experience with PJM Market Operation, System Design, and Implementation — IEEE Trans. Power Systems
  4. AEMOIntegrated System Plan 2024, Constraint Formulation Guidelines
  5. Kirschen, D., Strbac, G.Fundamentals of Power System Economics
  6. Christie, R.D., Wollenberg, B.F., Wangensteen, I. (2000). Transmission Management in the Deregulated Environment

📄 License

MIT License — see LICENSE for details.


About

The repo formulates the flow matrix , PTDF and LODF .

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages