Metadata-Version: 2.4
Name: ndse-tools
Version: 1.0.0
Summary: NDSE Tools for Electrical Power System
Author-email: "Márcio A. Tamashiro" <marcio.tamashiro@gmail.com>
Project-URL: Homepage, https://github.com/tamashiroBR/ndse-python
Project-URL: Bug Tracker, https://github.com/tamashiroBR/ndse-python/issues
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Topic :: Scientific/Engineering :: Physics
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# NDSE Tools for Electrical Power System

[![PyPI version](https://badge.fury.io/py/ndse.svg)](https://badge.fury.io/py/ndse)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![Python](https://img.shields.io/badge/python-3.8%2B-blue)](https://www.python.org/)

**NDSE Tools** is a Python library for electrical power system simulation, providing tools for steady-state Load Flow analysis and time-domain Transient Stability Analysis.

Originally developed in PHP as part of a doctoral thesis at the Federal University of Uberlândia (UFU) to investigate web-based interaction strategies for electrical engineering simulation, this package is a pure Python port of the original codebase — with no external numerical dependencies.

---

## Features

| Module | Description |
|---|---|
| `ndse.tools.LoadFlow` | Newton-Raphson AC power flow solver with reactive power limit control |
| `ndse.tools.TransientAnalysis` | Implicit trapezoidal / Newton-Raphson time-domain stability simulation |
| `ndse.math.Complex` | Complex number arithmetic (rectangular and polar forms) |
| `ndse.math.Angle` | Angle conversion utilities (degrees ↔ radians) |
| `ndse.math.Matrix` | Dense matrix operations (add, multiply, transpose, sub-matrix) |
| `ndse.math.Sparse` | Sparse matrix in CSC format for Y-bus construction |
| `ndse.math.lu_decomp` / `lu_solver` | LU decomposition and forward/back substitution solver |

---

## Installation

```bash
pip install ndse
```

---

## Usage Examples

### Load Flow — IEEE 9-Bus System

```python
import json
from ndse.tools import LoadFlow

# Load IEEE 9-bus system data
with open("examples/loadflow_9bus.json", "r") as f:
    data = json.load(f)

# Build Y-bus and run Newton-Raphson solver
lf = LoadFlow(data)
lf.make_ybus()
result = lf.run()

print(f"Converged in {result['iteration']} iteration(s)")
print(f"Total losses: {result['loss'][0]:.4f} MW")

# Bus results: [bus_id, V (pu), angle (deg), Pg (MW), Qg (MVAr), Pd (MW), ...]
for row in result["bus"]:
    print(f"Bus {int(row[0])}: V={row[1]:.4f} pu, δ={row[2]:.4f}°")
```

**Expected output (IEEE 9-bus, Anderson & Fouad):**

```
Converged in 3 iteration(s)
Total losses: 4.6410 MW
Bus 1: V=1.0400 pu, δ=0.0000°
Bus 2: V=1.0250 pu, δ=9.2800°
Bus 3: V=1.0250 pu, δ=4.6648°
Bus 4: V=1.0258 pu, δ=-2.2168°
Bus 5: V=1.0127 pu, δ=-3.6874°
Bus 6: V=1.0324 pu, δ=1.9667°
Bus 7: V=1.0159 pu, δ=0.7275°
Bus 8: V=1.0258 pu, δ=3.7197°
Bus 9: V=0.9956 pu, δ=-3.9888°
```

---

### Transient Stability Analysis — IEEE 9-Bus System

```python
import json
from ndse.tools import TransientAnalysis

# Load IEEE 9-bus system with dynamic models and a 3-phase fault event
with open("examples/stability_9bus.json", "r") as f:
    data = json.load(f)

ta = TransientAnalysis(data)
result = ta.run()

print(f"Simulation completed. Time steps: {len(result['time'])}")
print(f"Final rotor angle of generator 1: {result['delta'][0][-1]:.4f} rad")
```

---

### Math Utilities

#### Angle Conversions

```python
from ndse.math.angle import Angle

a = Angle(30, "deg")
print(a.rad())   # 0.5235987755982988

b = Angle(3.14159, "rad")
print(b.deg())   # 179.9998...
```

#### Complex Number Arithmetic

```python
from ndse.math.complex import Complex
from ndse.math.angle   import Angle

# Rectangular form
Z = Complex(0.01, 0.05)          # impedance Z = 0.01 + j0.05 pu
Y = Z.inv()                       # admittance Y = 1/Z
print(f"Y = {Y.re:.4f} + j{Y.img:.4f}")   # Y = 3.8462 + j-19.2308

# Polar form: V = 1.04 ∠ 9.28°
V = Complex(1.04, Angle(9.28, "deg"))
print(f"|V| = {V.abs():.4f} pu")          # |V| = 1.0400 pu
print(f"∠V  = {V.ang() * 57.296:.2f}°")  # ∠V  = 9.28°

# Apparent power: S = V · I*
I = Complex(1.2, Angle(-15.0, "deg"))
S = V.multiply(I.conj())
print(f"S = {S.re:.4f} + j{S.img:.4f} pu")  # S = 1.1376 + j0.5132 pu

# Arithmetic
a = Complex(3, 4)
b = Complex(1, -2)
print(a.add(b))       # 4 + j2
print(a.multiply(b))  # 11 + j-2
print(a.abs())        # 5.0
print(a.conj())       # 3 + j-4
```

#### Dense Matrix Operations

```python
from ndse.math.matrix import Matrix

A = Matrix([[1, 2], [3, 4]])
B = Matrix([[5, 6], [7, 8]])

C = A.multiply(B)
print(C.get(0, 0))   # 19
print(C.get(1, 1))   # 50

T = A.transpose()
print(T.get(0, 1))   # 3

Z = Matrix.zeros(3, 3)
print(Z.get(1, 1))   # 0.0
```

#### Sparse Matrix — Y-bus Construction

```python
from ndse.math.sparse  import Sparse
from ndse.math.complex import Complex

# 2-bus system: Z_12 = j0.1 pu → Y_12 = -j10 pu
Ybus = Sparse(2, 2)
Ybus.set(Complex(0, -10.0), 0, 0)   # Y[1,1]
Ybus.set(Complex(0,  10.0), 0, 1)   # Y[1,2]
Ybus.set(Complex(0,  10.0), 1, 0)   # Y[2,1]
Ybus.set(Complex(0, -10.0), 1, 1)   # Y[2,2]
Ybus.compress()

y11 = Ybus.get(0, 0)
print(f"Y[1,1] = {y11.re} + j{y11.img}")  # Y[1,1] = 0.0 + j-10.0
```

#### LU Decomposition Solver

```python
from ndse.math.sparse  import Sparse
from ndse.math.linalg  import lu_decomp, lu_solver

# Solve J·Δx = r (Newton-Raphson Jacobian system)
J = Sparse(3, 3)
J.set(16.4,  0, 0); J.set(-8.2,  0, 1)
J.set(-8.2,  1, 0); J.set(24.6,  1, 1); J.set(-8.2,  1, 2)
J.set(-8.2,  2, 1); J.set(16.4,  2, 2)
J.compress()

r  = [1.63, 0.0, 0.85]   # power mismatches (pu)
LU = lu_decomp(J)
dx = lu_solver(LU, r)     # angle corrections (rad)

print(f"Δθ = {[round(x, 6) for x in dx]} rad")
# Δθ = [0.137195, 0.075610, 0.089634] rad
```

---

## Input Data Format

### `optLF` — Load Flow Options

```json
[sbase, max_iter, tol, qlim]
```

| Field | Description | Example |
|---|---|---|
| `sbase` | System base power (MVA) | `100` |
| `max_iter` | Maximum Newton-Raphson iterations | `10` |
| `tol` | Convergence tolerance (pu) | `0.001` |
| `qlim` | Reactive power limit enforcement (`0`=off, `1`=on) | `0` |

### `bus` — Bus Data (12 columns per row)

```
[id, type, Pg, Qg, Pd, Qd, Gs, Bs, Vm, Va, Qmax, Qmin]
```

| Column | Description | Unit |
|---|---|---|
| `id` | Bus number | — |
| `type` | Bus type: `1`=PQ, `2`=PV, `3`=slack | — |
| `Pg` | Active power generation | MW |
| `Qg` | Reactive power generation | MVAr |
| `Pd` | Active power demand | MW |
| `Qd` | Reactive power demand | MVAr |
| `Gs` | Shunt conductance | pu |
| `Bs` | Shunt susceptance | pu |
| `Vm` | Voltage magnitude (initial) | pu |
| `Va` | Voltage angle (initial) | deg |
| `Qmax` | Maximum reactive power | MVAr |
| `Qmin` | Minimum reactive power | MVAr |

### `branch` — Branch Data (8 columns per row)

```
[from, to, r, x, b, tap, shift, status]
```

| Column | Description | Unit |
|---|---|---|
| `from` | From bus number | — |
| `to` | To bus number | — |
| `r` | Series resistance | pu |
| `x` | Series reactance | pu |
| `b` | Total line charging susceptance | pu |
| `tap` | Transformer tap ratio (`0`=transmission line) | pu |
| `shift` | Phase shift angle | deg |
| `status` | Branch status (`1`=in service, `0`=out) | — |

---

## Example Files

The `examples/` directory contains ready-to-use data files and scripts:

| File | Description |
|---|---|
| `loadflow_9bus.json` | IEEE 9-bus system data (Anderson & Fouad) |
| `loadflow_57bus.json` | IEEE 57-bus system data |
| `loadflow_118bus.json` | IEEE 118-bus system data |
| `stability_9bus.json` | IEEE 9-bus system with dynamic models and fault event |
| `example_loadflow_9bus.py` | Load Flow example with tabular output |
| `example_math.py` | Math utilities demonstration |

---

## License

This project is licensed under the **GNU General Public License v2.0 or later** (GPL-2.0-or-later).
