1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """Builds the DC PTDF matrix for a given choice of slack.
18 """
19
20 from sys import stderr
21
22 from numpy import zeros, arange, isscalar, dot, ix_, flatnonzero as find
23
24 from numpy.linalg import solve
25
26 from idx_bus import BUS_TYPE, REF, BUS_I
27 from makeBdc import makeBdc
28
29
30 -def makePTDF(baseMVA, bus, branch, slack=None):
31 """Builds the DC PTDF matrix for a given choice of slack.
32
33 Returns the DC PTDF matrix for a given choice of slack. The matrix is
34 C{nbr x nb}, where C{nbr} is the number of branches and C{nb} is the
35 number of buses. The C{slack} can be a scalar (single slack bus) or an
36 C{nb x 1} column vector of weights specifying the proportion of the
37 slack taken up at each bus. If the C{slack} is not specified the
38 reference bus is used by default.
39
40 For convenience, C{slack} can also be an C{nb x nb} matrix, where each
41 column specifies how the slack should be handled for injections
42 at that bus.
43
44 @see: L{makeLODF}
45
46 @author: Ray Zimmerman (PSERC Cornell)
47 @author: Richard Lincoln
48 """
49
50 if slack is None:
51 slack = find(bus[:, BUS_TYPE] == REF)
52 slack = slack[0]
53
54
55 if isscalar(slack):
56 slack_bus = slack
57 else:
58 slack_bus = 0
59
60 nb = bus.shape[0]
61 nbr = branch.shape[0]
62 noref = arange(1, nb)
63 noslack = find(arange(nb) != slack_bus)
64
65
66 if any(bus[:, BUS_I] != arange(nb)):
67 stderr.write('makePTDF: buses must be numbered consecutively')
68
69
70 Bbus, Bf, _, _ = makeBdc(baseMVA, bus, branch)
71 Bbus, Bf = Bbus.todense(), Bf.todense()
72 H = zeros((nbr, nb))
73 H[:, noslack] = solve( Bbus[ix_(noslack, noref)].T, Bf[:, noref].T ).T
74
75
76
77 if not isscalar(slack):
78 if len(slack.shape) == 1:
79 slack = slack / sum(slack)
80
81
82
83
84 v = dot(H, slack)
85 for k in range(nb):
86 H[:, k] = H[:, k] - v
87 else:
88 H = dot(H, slack)
89
90 return H
91