load-flow-engine 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- load_flow_engine/__init__.py +42 -0
- load_flow_engine/constants.py +12 -0
- load_flow_engine/enums.py +24 -0
- load_flow_engine/example.py +114 -0
- load_flow_engine/helpers.py +84 -0
- load_flow_engine/models.py +219 -0
- load_flow_engine/network.py +256 -0
- load_flow_engine/solver.py +546 -0
- load_flow_engine/tools/cim_adapter.py +720 -0
- load_flow_engine/tools/cyme_adapter.py +545 -0
- load_flow_engine/tools/diagnostics/__init__.py +194 -0
- load_flow_engine/tools/diagnostics/_common.py +163 -0
- load_flow_engine/tools/diagnostics/_diag_controls.py +105 -0
- load_flow_engine/tools/diagnostics/_diag_duplicates.py +136 -0
- load_flow_engine/tools/diagnostics/_diag_grounding.py +58 -0
- load_flow_engine/tools/diagnostics/_diag_impedance.py +94 -0
- load_flow_engine/tools/diagnostics/_diag_load_model.py +144 -0
- load_flow_engine/tools/diagnostics/_diag_open_conductor.py +132 -0
- load_flow_engine/tools/diagnostics/_diag_phase.py +150 -0
- load_flow_engine/tools/diagnostics/_diag_topology.py +181 -0
- load_flow_engine/tools/diagnostics/_diag_transformer.py +104 -0
- load_flow_engine/tools/diagnostics/_diag_voltage_base.py +151 -0
- load_flow_engine/tools/load_allocation.py +87 -0
- load_flow_engine/tools/multiconductor_adapter.py +577 -0
- load_flow_engine/tools/opendss_adapter.py +322 -0
- load_flow_engine/tools/output.py +89 -0
- load_flow_engine/tools/sqlite_adapter.py +367 -0
- load_flow_engine-0.1.0.dist-info/METADATA +12 -0
- load_flow_engine-0.1.0.dist-info/RECORD +32 -0
- load_flow_engine-0.1.0.dist-info/WHEEL +5 -0
- load_flow_engine-0.1.0.dist-info/entry_points.txt +2 -0
- load_flow_engine-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""
|
|
2
|
+
load_flow_engine — Three-phase unbalanced load flow solver package.
|
|
3
|
+
|
|
4
|
+
Re-exports all public symbols for convenience::
|
|
5
|
+
|
|
6
|
+
from load_flow_engine import Network, ThreePhaseLoadFlowSolver, Bus, Branch, ...
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .enums import PhaseType, BusType
|
|
10
|
+
from .constants import _a, _A, _Ai
|
|
11
|
+
from .models import (
|
|
12
|
+
StudyCase,
|
|
13
|
+
Bus,
|
|
14
|
+
Branch,
|
|
15
|
+
Transformer,
|
|
16
|
+
Load,
|
|
17
|
+
Generator,
|
|
18
|
+
Shunt,
|
|
19
|
+
BranchResult,
|
|
20
|
+
)
|
|
21
|
+
from .helpers import _active_phases, _seq_to_z_abc, _matrix_invert_3x3
|
|
22
|
+
from .network import Network
|
|
23
|
+
from .solver import ThreePhaseLoadFlowSolver
|
|
24
|
+
from .example import build_example_network, run_example
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
# Enums
|
|
28
|
+
"PhaseType", "BusType",
|
|
29
|
+
# Constants
|
|
30
|
+
"_a", "_A", "_Ai",
|
|
31
|
+
# Models
|
|
32
|
+
"StudyCase", "Bus", "Branch", "Transformer", "Load",
|
|
33
|
+
"Generator", "Shunt", "BranchResult",
|
|
34
|
+
# Helpers
|
|
35
|
+
"_active_phases", "_seq_to_z_abc", "_matrix_invert_3x3",
|
|
36
|
+
# Network
|
|
37
|
+
"Network",
|
|
38
|
+
# Solver
|
|
39
|
+
"ThreePhaseLoadFlowSolver",
|
|
40
|
+
# Example
|
|
41
|
+
"build_example_network", "run_example",
|
|
42
|
+
]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Symmetrical-component (Fortescue) transformation matrices.
|
|
3
|
+
Mirrors ETAP's use of A-matrix for zero/pos/neg sequence decomposition.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
_a = np.exp(1j * 2.0 * np.pi / 3.0) # 1∠120°
|
|
9
|
+
_A = np.array([[1, 1, 1 ], # Fortescue A
|
|
10
|
+
[1, _a**2, _a ],
|
|
11
|
+
[1, _a, _a**2 ]], dtype=complex)
|
|
12
|
+
_Ai = np.linalg.inv(_A) # A⁻¹
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Phase and bus type enumerations matching ETAP definitions."""
|
|
2
|
+
|
|
3
|
+
from enum import IntEnum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PhaseType(IntEnum):
|
|
7
|
+
"""
|
|
8
|
+
Matches ETAPPhaseType enum in NetworkReductionEC.h.
|
|
9
|
+
Defines which phases a bus or branch participates in.
|
|
10
|
+
"""
|
|
11
|
+
ABC = 0 # three-phase
|
|
12
|
+
A = 5 # single-phase A
|
|
13
|
+
B = 6 # single-phase B
|
|
14
|
+
C = 7 # single-phase C
|
|
15
|
+
AB = 8 # two-phase A-B
|
|
16
|
+
BC = 9 # two-phase B-C
|
|
17
|
+
CA = 10 # two-phase C-A
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BusType(IntEnum):
|
|
21
|
+
"""Standard power-flow bus types."""
|
|
22
|
+
SLACK = 0 # swing bus — |V| and ∠V fixed per phase
|
|
23
|
+
PV = 1 # voltage-controlled — P and |V| fixed, Q within limits
|
|
24
|
+
PQ = 2 # load bus — P and Q fixed per phase
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Four-bus radial distribution feeder example.
|
|
3
|
+
|
|
4
|
+
Topology (12.47 kV primary, 4.16 kV secondary after transformer):
|
|
5
|
+
|
|
6
|
+
BUS1 (slack) ──── XFM1 ──── BUS2 ──── BR1 ──── BUS3 ──── BR2 ──── BUS4
|
|
7
|
+
12.47 kV 4.16 kV 4.16 kV 4.16 kV
|
|
8
|
+
swing bus 3φ balanced load 3φ+1φ unbalanced load 1φ-A load only
|
|
9
|
+
|
|
10
|
+
BUS2: 3-phase balanced load 150 kW + j50 kVAr on each phase
|
|
11
|
+
BUS3: unbalanced load 300 kW/ph-A, 100 kW/ph-B, 200 kW/ph-C + reactive
|
|
12
|
+
BUS4: single-phase A load 400 kW + j200 kVAr on phase A only
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
from .enums import PhaseType, BusType
|
|
18
|
+
from .constants import _Ai
|
|
19
|
+
from .models import Bus, Branch, Transformer, Load, StudyCase
|
|
20
|
+
from .network import Network
|
|
21
|
+
from .solver import ThreePhaseLoadFlowSolver
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def build_example_network() -> Network:
|
|
25
|
+
sc = StudyCase(max_iterations=50, solution_precision=1e-4, base_mva=10.0)
|
|
26
|
+
net = Network(sc)
|
|
27
|
+
|
|
28
|
+
# ---- Buses ----
|
|
29
|
+
net.add_bus(Bus("BUS1", BusType.SLACK, PhaseType.ABC, base_kv=12.47))
|
|
30
|
+
net.add_bus(Bus("BUS2", BusType.PQ, PhaseType.ABC, base_kv=4.16))
|
|
31
|
+
net.add_bus(Bus("BUS3", BusType.PQ, PhaseType.ABC, base_kv=4.16))
|
|
32
|
+
net.add_bus(Bus("BUS4", BusType.PQ, PhaseType.ABC, base_kv=4.16))
|
|
33
|
+
|
|
34
|
+
# ---- Transformer BUS1 → BUS2 ----
|
|
35
|
+
# 3 MVA, 12.47/4.16 kV, wye-grounded / wye-grounded
|
|
36
|
+
# Z1 = 1%, Z0 = 1% on transformer base
|
|
37
|
+
net.add_transformer(Transformer(
|
|
38
|
+
id="XFM1", from_bus="BUS1", to_bus="BUS2",
|
|
39
|
+
r1=0.005, x1=0.06, r0=0.005, x0=0.06,
|
|
40
|
+
mva_rating=3.0,
|
|
41
|
+
conn_primary='wye_grounded', conn_secondary='wye_grounded',
|
|
42
|
+
))
|
|
43
|
+
|
|
44
|
+
# ---- Branch BUS2 → BUS3 (3-phase overhead line, 1 km) ----
|
|
45
|
+
# Z1 = 0.306 + j0.627 Ω/km, Z0 = 0.745 + j1.2 Ω/km
|
|
46
|
+
# Base Z = (4.16²/10) = 1.731 Ω → divide to get pu
|
|
47
|
+
Zbase = 4.16**2 / 10.0 # 1.731 Ω
|
|
48
|
+
net.add_branch(Branch(
|
|
49
|
+
id="BR1", from_bus="BUS2", to_bus="BUS3",
|
|
50
|
+
phase_type=PhaseType.ABC,
|
|
51
|
+
r1=0.306/Zbase, x1=0.627/Zbase,
|
|
52
|
+
r0=0.745/Zbase, x0=1.200/Zbase,
|
|
53
|
+
b1=0.0,
|
|
54
|
+
ampacity=np.full(3, 300.0), # 300 A rated
|
|
55
|
+
))
|
|
56
|
+
|
|
57
|
+
# ---- Branch BUS3 → BUS4 (single-phase A, 0.5 km) ----
|
|
58
|
+
net.add_branch(Branch(
|
|
59
|
+
id="BR2", from_bus="BUS3", to_bus="BUS4",
|
|
60
|
+
phase_type=PhaseType.A,
|
|
61
|
+
r1=(0.306*0.5)/Zbase, x1=(0.627*0.5)/Zbase,
|
|
62
|
+
r0=(0.745*0.5)/Zbase, x0=(1.200*0.5)/Zbase,
|
|
63
|
+
ampacity=np.array([200.0, 0.0, 0.0]),
|
|
64
|
+
))
|
|
65
|
+
|
|
66
|
+
# ---- Loads ----
|
|
67
|
+
# BUS2: balanced 3-phase load 150 kW + j50 kVAr / phase
|
|
68
|
+
net.add_load(Load("LD2", "BUS2", PhaseType.ABC,
|
|
69
|
+
mw = np.array([0.15, 0.15, 0.15]),
|
|
70
|
+
mvar = np.array([0.05, 0.05, 0.05])))
|
|
71
|
+
|
|
72
|
+
# BUS3: unbalanced 3-phase load
|
|
73
|
+
net.add_load(Load("LD3", "BUS3", PhaseType.ABC,
|
|
74
|
+
mw = np.array([0.30, 0.10, 0.20]),
|
|
75
|
+
mvar = np.array([0.15, 0.05, 0.10])))
|
|
76
|
+
|
|
77
|
+
# BUS4: single-phase A load 400 kW + j200 kVAr
|
|
78
|
+
net.add_load(Load("LD4", "BUS4", PhaseType.A,
|
|
79
|
+
mw = np.array([0.40, 0.0, 0.0]),
|
|
80
|
+
mvar = np.array([0.20, 0.0, 0.0])))
|
|
81
|
+
|
|
82
|
+
return net
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def run_example() -> None:
|
|
86
|
+
print("\n" + "=" * 72)
|
|
87
|
+
print(" ETAP-Style Three-Phase Unbalanced Load Flow — 4-Bus Feeder")
|
|
88
|
+
print("=" * 72)
|
|
89
|
+
|
|
90
|
+
net = build_example_network()
|
|
91
|
+
solver = ThreePhaseLoadFlowSolver(net)
|
|
92
|
+
|
|
93
|
+
converged = solver.solve()
|
|
94
|
+
|
|
95
|
+
if not converged:
|
|
96
|
+
print("WARNING: solver did not converge!")
|
|
97
|
+
|
|
98
|
+
solver.print_bus_results()
|
|
99
|
+
|
|
100
|
+
br_results = solver.compute_branch_results()
|
|
101
|
+
solver.print_branch_results(br_results)
|
|
102
|
+
|
|
103
|
+
# ---- Voltage unbalance at BUS3 ----
|
|
104
|
+
b3 = net.buses["BUS3"]
|
|
105
|
+
V_abc = np.array([
|
|
106
|
+
b3.v_mag[p] * np.exp(1j * np.deg2rad(b3.v_ang[p]))
|
|
107
|
+
for p in range(3)
|
|
108
|
+
])
|
|
109
|
+
V_012 = _Ai @ V_abc
|
|
110
|
+
vuf_neg = abs(V_012[2]) / abs(V_012[1]) * 100.0
|
|
111
|
+
vuf_zero = abs(V_012[0]) / abs(V_012[1]) * 100.0
|
|
112
|
+
print(f" BUS3 Voltage Unbalance Factor (NEMA neg-seq) : {vuf_neg:.3f} %")
|
|
113
|
+
print(f" BUS3 Voltage Unbalance Factor (zero-seq) : {vuf_zero:.3f} %")
|
|
114
|
+
print()
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Helper functions for impedance transforms and phase mapping."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from .enums import PhaseType
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _active_phases(phase_type: PhaseType) -> List[int]:
|
|
11
|
+
"""
|
|
12
|
+
Return the sorted list of active phase indices (0=A, 1=B, 2=C)
|
|
13
|
+
for a given PhaseType, matching ETAPPhaseType handling in
|
|
14
|
+
NetworkReductionEC.cpp.
|
|
15
|
+
"""
|
|
16
|
+
mapping = {
|
|
17
|
+
PhaseType.ABC: [0, 1, 2],
|
|
18
|
+
PhaseType.A: [0],
|
|
19
|
+
PhaseType.B: [1],
|
|
20
|
+
PhaseType.C: [2],
|
|
21
|
+
PhaseType.AB: [0, 1],
|
|
22
|
+
PhaseType.BC: [1, 2],
|
|
23
|
+
PhaseType.CA: [0, 2],
|
|
24
|
+
}
|
|
25
|
+
return sorted(mapping.get(phase_type, [0, 1, 2]))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _seq_to_z_abc(z1: complex, z0: complex) -> np.ndarray:
|
|
29
|
+
"""
|
|
30
|
+
Convert positive- and zero-sequence impedances to the 3×3 phase-domain
|
|
31
|
+
impedance matrix for a fully transposed line.
|
|
32
|
+
|
|
33
|
+
Mirrors NetworkReductionEC's use of the symmetrical-component transform:
|
|
34
|
+
Z_abc = A · diag(Z0, Z1, Z1) · A⁻¹
|
|
35
|
+
|
|
36
|
+
For a transposed line this reduces to the Toeplitz form:
|
|
37
|
+
Zs = (Z0 + 2·Z1) / 3 (self impedance)
|
|
38
|
+
Zm = (Z0 − Z1) / 3 (mutual impedance)
|
|
39
|
+
|
|
40
|
+
Z_abc = [[Zs, Zm, Zm],
|
|
41
|
+
[Zm, Zs, Zm],
|
|
42
|
+
[Zm, Zm, Zs]]
|
|
43
|
+
"""
|
|
44
|
+
Zs = (z0 + 2.0 * z1) / 3.0
|
|
45
|
+
Zm = (z0 - z1) / 3.0
|
|
46
|
+
return np.array([[Zs, Zm, Zm],
|
|
47
|
+
[Zm, Zs, Zm],
|
|
48
|
+
[Zm, Zm, Zs]], dtype=complex)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _matrix_invert_3x3(Z: np.ndarray) -> Optional[np.ndarray]:
|
|
52
|
+
"""
|
|
53
|
+
Invert a 3×3 complex matrix using Gauss-Jordan elimination.
|
|
54
|
+
Mirrors MatrixInvert(DComplexEC mtxZ[3][3]) in NetworkReductionEC.cpp,
|
|
55
|
+
including the same singular-matrix guard (returns None on failure).
|
|
56
|
+
"""
|
|
57
|
+
SMALL = 1e-12
|
|
58
|
+
A = Z.astype(complex).copy()
|
|
59
|
+
I = np.eye(3, dtype=complex)
|
|
60
|
+
|
|
61
|
+
for i in range(3):
|
|
62
|
+
# Partial pivoting (mirrors ETAP's row-sum fallback)
|
|
63
|
+
if abs(A[i, i]) < SMALL:
|
|
64
|
+
swapped = False
|
|
65
|
+
for k in range(i + 1, 3):
|
|
66
|
+
if abs(A[k, i]) >= SMALL:
|
|
67
|
+
A[[i, k]] = A[[k, i]]
|
|
68
|
+
I[[i, k]] = I[[k, i]]
|
|
69
|
+
swapped = True
|
|
70
|
+
break
|
|
71
|
+
if not swapped:
|
|
72
|
+
return None # singular
|
|
73
|
+
|
|
74
|
+
pivot = A[i, i]
|
|
75
|
+
A[i] /= pivot
|
|
76
|
+
I[i] /= pivot
|
|
77
|
+
|
|
78
|
+
for k in range(3):
|
|
79
|
+
if k != i and abs(A[k, i]) >= SMALL:
|
|
80
|
+
factor = A[k, i]
|
|
81
|
+
A[k] -= factor * A[i]
|
|
82
|
+
I[k] -= factor * I[i]
|
|
83
|
+
|
|
84
|
+
return I
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"""Data classes mirroring ETAP DB accessor structures."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import List
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from .enums import PhaseType, BusType
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class StudyCase:
|
|
13
|
+
"""
|
|
14
|
+
Mirrors LF3PH_STUDY_CASE_DATA from dataTyp6.h.
|
|
15
|
+
Controls solver parameters.
|
|
16
|
+
"""
|
|
17
|
+
max_iterations: int = 100 # maximumIteration
|
|
18
|
+
solution_precision: float = 1e-4 # solutionPrecision (MVA mismatch)
|
|
19
|
+
base_mva: float = 100.0 # system MVA base
|
|
20
|
+
flat_start: bool = True # use 1.0 pu / nominal angles
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class Bus:
|
|
25
|
+
"""
|
|
26
|
+
Mirrors IBusLF3PHAccessor from IBusLF3PH.h.
|
|
27
|
+
|
|
28
|
+
All voltage magnitudes are in per-unit; angles in degrees.
|
|
29
|
+
Powers are in MW and MVAr (converted to pu internally during solve).
|
|
30
|
+
Array index 0=A, 1=B, 2=C throughout.
|
|
31
|
+
"""
|
|
32
|
+
id: str
|
|
33
|
+
bus_type: BusType = BusType.PQ
|
|
34
|
+
phase_type: PhaseType = PhaseType.ABC
|
|
35
|
+
base_kv: float = 12.47 # m_BasekV
|
|
36
|
+
name: str = '' # MC source name for cross-referencing
|
|
37
|
+
|
|
38
|
+
# Solved voltages — m_VMagA/B/C, m_VAngA/B/C
|
|
39
|
+
v_mag: np.ndarray = field(
|
|
40
|
+
default_factory=lambda: np.ones(3))
|
|
41
|
+
v_ang: np.ndarray = field(
|
|
42
|
+
default_factory=lambda: np.array([0.0, -120.0, 120.0]))
|
|
43
|
+
|
|
44
|
+
# Initial voltage guess — m_IniVMagA/B/C, m_IniAngA/B/C
|
|
45
|
+
ini_v_mag: np.ndarray = field(
|
|
46
|
+
default_factory=lambda: np.ones(3))
|
|
47
|
+
ini_v_ang: np.ndarray = field(
|
|
48
|
+
default_factory=lambda: np.array([0.0, -120.0, 120.0]))
|
|
49
|
+
|
|
50
|
+
# Scheduled generation per phase (MW, MVAr) — m_GenMWA/B/C, m_GenMvarA/B/C
|
|
51
|
+
gen_mw: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
52
|
+
gen_mvar: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
53
|
+
|
|
54
|
+
# Scheduled load per phase (MW, MVAr) — m_LoadMWA/B/C, m_LoadMvarA/B/C
|
|
55
|
+
load_mw: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
56
|
+
load_mvar: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
57
|
+
|
|
58
|
+
# Reactive limits (PV buses) — m_MvarMax, m_MvarMin
|
|
59
|
+
mvar_max: float = 9999.0
|
|
60
|
+
mvar_min: float = -9999.0
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class Branch:
|
|
65
|
+
"""
|
|
66
|
+
Mirrors IConnectLF3PHAccessor from IConnectLF3PH.h.
|
|
67
|
+
|
|
68
|
+
Stores positive- and zero-sequence impedances in per-unit.
|
|
69
|
+
The 3×3 phase-domain matrix Z_abc is computed at build time via the
|
|
70
|
+
symmetrical-component transform (same as NetworkReductionEC).
|
|
71
|
+
"""
|
|
72
|
+
id: str
|
|
73
|
+
from_bus: str
|
|
74
|
+
to_bus: str
|
|
75
|
+
phase_type: PhaseType = PhaseType.ABC
|
|
76
|
+
name: str = ''
|
|
77
|
+
|
|
78
|
+
# Positive-sequence series impedance (pu) — m_R, m_X
|
|
79
|
+
r1: float = 0.0
|
|
80
|
+
x1: float = 0.0
|
|
81
|
+
|
|
82
|
+
# Zero-sequence series impedance (pu) — m_R0, m_X0
|
|
83
|
+
r0: float = 0.0
|
|
84
|
+
x0: float = 0.0
|
|
85
|
+
|
|
86
|
+
# Shunt charging susceptance (pu, positive-sequence total line charging)
|
|
87
|
+
b1: float = 0.0
|
|
88
|
+
|
|
89
|
+
# Ampacity per phase (amps) for loading-% calc — m_AmpacityA/B/C
|
|
90
|
+
ampacity: np.ndarray = field(default_factory=lambda: np.full(3, 9999.0))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@dataclass
|
|
94
|
+
class Transformer:
|
|
95
|
+
"""
|
|
96
|
+
Two-winding transformer.
|
|
97
|
+
Mirrors LF3PH_Xfmr2Data from dataTyp6.h.
|
|
98
|
+
|
|
99
|
+
Impedances are in pu on the transformer's own MVA base; they are
|
|
100
|
+
converted to the system base during Network.build().
|
|
101
|
+
"""
|
|
102
|
+
id: str
|
|
103
|
+
from_bus: str # primary (HV) bus
|
|
104
|
+
to_bus: str # secondary (LV) bus
|
|
105
|
+
phase_type: PhaseType = PhaseType.ABC
|
|
106
|
+
name: str = ''
|
|
107
|
+
|
|
108
|
+
# Leakage impedance (pu on xfmr base) — positive-sequence
|
|
109
|
+
r1: float = 0.0
|
|
110
|
+
x1: float = 0.01
|
|
111
|
+
|
|
112
|
+
# Zero-sequence leakage impedance
|
|
113
|
+
r0: float = 0.0
|
|
114
|
+
x0: float = 0.01
|
|
115
|
+
|
|
116
|
+
# Transformer MVA rating (used for base conversion)
|
|
117
|
+
mva_rating: float = 1.0
|
|
118
|
+
|
|
119
|
+
# Off-nominal tap (pu of nominal ratio) — m_TapPctPrim / m_TapPctSec
|
|
120
|
+
tap_primary: float = 1.0
|
|
121
|
+
tap_secondary: float = 1.0
|
|
122
|
+
|
|
123
|
+
# Winding connections (affects zero-sequence path)
|
|
124
|
+
# Supported: 'wye_grounded', 'wye', 'delta'
|
|
125
|
+
conn_primary: str = 'wye_grounded'
|
|
126
|
+
conn_secondary: str = 'wye_grounded'
|
|
127
|
+
|
|
128
|
+
# HV phases this transformer is connected to (0=A, 1=B, 2=C)
|
|
129
|
+
hv_phases: List[int] = field(default_factory=lambda: [0, 1, 2])
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@dataclass
|
|
133
|
+
class Load:
|
|
134
|
+
"""
|
|
135
|
+
Static load element — mirrors LF3PH_StaticLoadData from dataTyp6.h.
|
|
136
|
+
Per-phase MW and MVAr. add_load() aggregates these onto the bus.
|
|
137
|
+
"""
|
|
138
|
+
id: str
|
|
139
|
+
bus_id: str
|
|
140
|
+
phase_type: PhaseType = PhaseType.ABC
|
|
141
|
+
name: str = ''
|
|
142
|
+
mw: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
143
|
+
mvar: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@dataclass
|
|
147
|
+
class Generator:
|
|
148
|
+
"""
|
|
149
|
+
Synchronous generator — mirrors LF3PH_SynGenData from dataTyp6.h.
|
|
150
|
+
"""
|
|
151
|
+
id: str
|
|
152
|
+
bus_id: str
|
|
153
|
+
bus_type: BusType = BusType.PV
|
|
154
|
+
name: str = ''
|
|
155
|
+
|
|
156
|
+
mw: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
157
|
+
v_set_pu: float = 1.0
|
|
158
|
+
mvar_max: float = 9999.0
|
|
159
|
+
mvar_min: float = -9999.0
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@dataclass
|
|
163
|
+
class Shunt:
|
|
164
|
+
"""
|
|
165
|
+
Shunt element — per-phase MW and MVAr (capacitor/reactor banks).
|
|
166
|
+
"""
|
|
167
|
+
id: str
|
|
168
|
+
bus_id: str
|
|
169
|
+
phase_type: PhaseType = PhaseType.ABC
|
|
170
|
+
name: str = ''
|
|
171
|
+
p_mw: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
172
|
+
q_mvar: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
173
|
+
vn_kv: float = 12.47
|
|
174
|
+
closed: bool = True
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@dataclass
|
|
178
|
+
class Switch:
|
|
179
|
+
"""
|
|
180
|
+
Switch element — connects two buses with optional resistance.
|
|
181
|
+
"""
|
|
182
|
+
id: str
|
|
183
|
+
bus: int = 0
|
|
184
|
+
element: int = 0
|
|
185
|
+
et: str = 'b' # 'b' = bus-bus, 'l' = line
|
|
186
|
+
sw_type: str = 'LBS'
|
|
187
|
+
closed: bool = True
|
|
188
|
+
phase: int = 0
|
|
189
|
+
r_ohm: float = 0.0
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
@dataclass
|
|
193
|
+
class BranchResult:
|
|
194
|
+
"""
|
|
195
|
+
Post-solve per-branch results.
|
|
196
|
+
Field names mirror LFSumBranchLF3PHAccessor from LFSumBranchLF3PH.h.
|
|
197
|
+
"""
|
|
198
|
+
id: str
|
|
199
|
+
from_bus: str
|
|
200
|
+
to_bus: str
|
|
201
|
+
|
|
202
|
+
# Per-phase current — m_LoadingAmpMagA/B/C, m_LoadingAmpAngA/B/C
|
|
203
|
+
i_mag_abc: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
204
|
+
i_ang_abc: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
205
|
+
|
|
206
|
+
# Per-phase apparent power (MVA) from/to — m_LoadingInMVAA/B/C, m_LoadingOutMVAA/B/C
|
|
207
|
+
mva_from: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
208
|
+
mva_to: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
209
|
+
|
|
210
|
+
# Per-phase loading percent — m_Loading_A/B/C
|
|
211
|
+
loading_pct: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
212
|
+
|
|
213
|
+
# Sequence currents — m_LoadingAmpMag0/1/2, m_LoadingAmpAng0/1/2
|
|
214
|
+
i_mag_012: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
215
|
+
i_ang_012: np.ndarray = field(default_factory=lambda: np.zeros(3))
|
|
216
|
+
|
|
217
|
+
# Unbalance factors — m_CUF2 (negative-seq), m_CUF0 (zero-seq)
|
|
218
|
+
cuf2: float = 0.0
|
|
219
|
+
cuf0: float = 0.0
|