-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathCase3.py
More file actions
154 lines (145 loc) · 5.94 KB
/
Copy pathCase3.py
File metadata and controls
154 lines (145 loc) · 5.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
from pylon import Case
from networkx import DiGraph, shortest_path_length,shortest_path, draw
from pylab import plot,show
from numpy import zeros, imag
from collections import defaultdict
rootNode="root node"
forkNode="fork node"
endNode="end node"
normalNode="normal node"
class Case3(Case):
"""
This class defines a radial network which will be studied further. It uses directed graph implemented in networkx.
"""
def __init__(self,name=None, base_mva=1.0, base_kv=20.0, buses=None, branches=None, generators=None):
#Case.__init__(self,buses=buses,branches=branches)
self.buses=buses
self.base_mva=base_mva
self.base_kv=base_kv
self.base_z=base_kv**2/base_mva
self.branches=branches
self.generators=generators
self.G=DiGraph()
self._buildGraph()
self.rootbus=[b for b in self.buses if self.G.pred[b] == {}]
self.forkbuses=[b for b in self.buses if self.G.degree()[b]>2]
self.normalbuses=[b for b in self.buses if self.G.degree()[b]==2]
self.endbuses=[b for b in self.buses if self.G.succ[b] == {}]
self.updateTypeG()
self.bus_level=shortest_path_length(self.G,source=self.rootbus[0])
self.updateBusConnBranch()
self.buses_loadJ=self.updateBusLoadCurrent()
self.identifyPVbuses()
self.calculateZpos()
for b in self.buses:
b.base_mva=base_mva
#draw(self.G)
#pl.show()
def _buildGraph(self):
""" add buses as nodes and branches as edges.
"""
self.G.add_nodes_from([bus for bus in self.buses])
self.G.add_edges_from([(b.from_bus,b.to_bus) for b in self.branches])
def plotGraph(self):
draw(self.G)
show()
return
def plotVP(self):
""" Plot voltage profile of distribution system"""
V=[abs(b.E) for b in self.buses]
name=[b.name for b in self.buses]
plot(V)
show()
return
def updateBusConnBranch(self):
"""
Updating to which branch a bus is connected.
"""
for a in self.branches:
a.from_bus.connected_to_branch.append(a)
a.to_bus.connected_from_branch.append(a)
# as edges are added, there should be a procedure to update bus.connected_to and bus.connected_from
def updateTypeG(self):
for b in self.buses:
if self.rootbus.__contains__(b):
b.typeG=rootNode
if self.forkbuses.__contains__(b):
b.typeG=forkNode
if self.endbuses.__contains__(b):
b.typeG=endNode
def updateBusLoadCurrent(self):
return [b.calc_loadI() for b in self.buses]
def getRoot(self):
"""
Get the root node of a network which is the substation node.
"""
rootNode=[n for n in self.G.node if self.G.pred[n]=={}]
return rootNode[0]
def updateBaseKV(self,aNode):
"""
update base_kv of aNode children. This is done after a voltage regulator changes its tap.
"""
for b in aNode.connected_to_branch:
b.updateToBusBaseKV()
if b.to_bus.connected_to_branch!=[]:
self.updateBaseKV(b.to_bus)
def identifyPVbuses(self):
"""
identify pv buses in the network. Important when creating the positive sequence matrix needed to update injected current
"""
self.pvbuses=[g.bus for g in self.generators if g.type=='PV'] # a list of buses connected to generators controlled as PV bus.
for b in self.pvbuses:
b.type='PV' # update the bus.type according to its generator control mode.
def calculateZpos(self):
"""
calculate positive impedance matrix for updating injected current at PV bus in BFS with DGs
"""
self.identifyPVbuses()
pathToRoot={}
lines={}
Z1diag={}
pvbusindex={}
d=defaultdict(dict)
npvb=len(self.pvbuses) # number of pv buses
Z1=zeros([npvb,npvb],dtype='complex')
for pvb in self.pvbuses:
pathToRoot[pvb]=shortest_path(self.G,self.rootbus[0],pvb)
lines[pvb]=[b.connected_from_branch[0] for b in pathToRoot[pvb] if b.connected_from_branch!=[]]
self.pathToRoot=pathToRoot# a list of buses that incident with the path from a pv bus to root bus.
self.lines=lines # a list of lines that forms the path from a pvbus to the root bus.
Z_1=zeros([npvb,npvb]) # prepare an all zero matrix with size npvb x npvb
# This function requires a positif sequence of all lines in self.lines. The positive sequence impedance is available at line.Z012[0]
# the situation is more intricate if there is a transformer within the path between the PV bus to root bus. If on of the transformer winding
# is connected in delta, the path for positive sequence is disconnected. The implementation for this kind of situation is postponed.
# the current implementation assumes that there is NO TRANSFORMER exist in the path. 27th May 2011.
for pvb in self.pvbuses:
Z1sum=complex(0,0)
for l in self.lines[pvb]:
Z1sum=Z1sum+l.Z012[1][1]
Z1diag[pvb]=Z1sum
self.Z1diag=Z1diag # this is the diagonal element of positive impedance matrix, the output of this function.
ind=0
for pvb in self.pvbuses:
pvbusindex[pvb]=ind
ind=ind+1
self.pvbusindex=pvbusindex
for pvb in self.pvbuses:
for pv in self.pvbuses:
d[pvb][pv]=set(self.lines[pvb]).intersection(set(self.lines[pv]))
Z1sum=0
for l in d[pvb][pv]:
Z1sum=Z1sum+l.Z012[1][1]
Z1[pvbusindex[pvb],pvbusindex[pv]]=Z1sum
self.d=d# this is a two dimensional dictionary. Its diagonal element contains list of lines on the path between a pv bus and root bus.
# Its of diagonal contains the common lines between path to root of two pv buses. If we sum the positive sequence impedance
# of each element, we have already the element of postive sequence impedance matrix we wish to calculate in this function.
self.Z1=Z1
self.X1=imag(Z1)
def P_to_S(P,pf):
theta=arccos(pf)
Samp=P/pf
S=Samp*cos(theta)+1j*Samp*sin(theta)
return S
def polarToRect(magnitude,degree):
result=magnitude*(cos(degree)+1j*sin(degree))
return result