1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """Evaluates nonlinear constraints and their Jacobian for OPF.
18 """
19
20 from numpy import zeros, ones, conj, exp, r_, Inf, arange
21
22 from scipy.sparse import lil_matrix, vstack, hstack, csr_matrix as sparse
23
24 from idx_gen import GEN_BUS, PG, QG
25 from idx_brch import F_BUS, T_BUS, RATE_A
26
27 from makeSbus import makeSbus
28 from dSbus_dV import dSbus_dV
29 from dIbr_dV import dIbr_dV
30 from dSbr_dV import dSbr_dV
31 from dAbr_dV import dAbr_dV
32
33
34 -def opf_consfcn(x, om, Ybus, Yf, Yt, ppopt, il=None, *args):
35 """Evaluates nonlinear constraints and their Jacobian for OPF.
36
37 Constraint evaluation function for AC optimal power flow, suitable
38 for use with L{pips}. Computes constraint vectors and their gradients.
39
40 @param x: optimization vector
41 @param om: OPF model object
42 @param Ybus: bus admittance matrix
43 @param Yf: admittance matrix for "from" end of constrained branches
44 @param Yt: admittance matrix for "to" end of constrained branches
45 @param ppopt: PYPOWER options vector
46 @param il: (optional) vector of branch indices corresponding to
47 branches with flow limits (all others are assumed to be
48 unconstrained). The default is C{range(nl)} (all branches).
49 C{Yf} and C{Yt} contain only the rows corresponding to C{il}.
50
51 @return: C{h} - vector of inequality constraint values (flow limits)
52 limit^2 - flow^2, where the flow can be apparent power real power or
53 current, depending on value of C{OPF_FLOW_LIM} in C{ppopt} (only for
54 constrained lines). C{g} - vector of equality constraint values (power
55 balances). C{dh} - (optional) inequality constraint gradients, column
56 j is gradient of h(j). C{dg} - (optional) equality constraint gradients.
57
58 @see: L{opf_costfcn}, L{opf_hessfcn}
59
60 @author: Carlos E. Murillo-Sanchez (PSERC Cornell & Universidad
61 Autonoma de Manizales)
62 @author: Ray Zimmerman (PSERC Cornell)
63 @author: Richard Lincoln
64 """
65
66
67
68 ppc = om.get_ppc()
69 baseMVA, bus, gen, branch = \
70 ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"]
71 vv, _, _, _ = om.get_idx()
72
73
74 nb = bus.shape[0]
75 nl = branch.shape[0]
76 ng = gen.shape[0]
77 nxyz = len(x)
78
79
80 if il is None:
81 il = arange(nl)
82 nl2 = len(il)
83
84
85 Pg = x[vv["i1"]["Pg"]:vv["iN"]["Pg"]]
86 Qg = x[vv["i1"]["Qg"]:vv["iN"]["Qg"]]
87
88
89 gen[:, PG] = Pg * baseMVA
90 gen[:, QG] = Qg * baseMVA
91
92
93 Sbus = makeSbus(baseMVA, bus, gen)
94
95
96
97 Va = x[vv["i1"]["Va"]:vv["iN"]["Va"]]
98 Vm = x[vv["i1"]["Vm"]:vv["iN"]["Vm"]]
99 V = Vm * exp(1j * Va)
100
101
102 mis = V * conj(Ybus * V) - Sbus
103
104
105
106 g = r_[ mis.real,
107 mis.imag ]
108
109
110 if nl2 > 0:
111 flow_max = (branch[il, RATE_A] / baseMVA)**2
112 flow_max[flow_max == 0] = Inf
113 if ppopt['OPF_FLOW_LIM'] == 2:
114 If = Yf * V
115 It = Yt * V
116 h = r_[ If * conj(If) - flow_max,
117 It * conj(It) - flow_max ].real
118 else:
119
120
121 Sf = V[ branch[il, F_BUS].astype(int) ] * conj(Yf * V)
122
123 St = V[ branch[il, T_BUS].astype(int) ] * conj(Yt * V)
124 if ppopt['OPF_FLOW_LIM'] == 1:
125 h = r_[ Sf.real**2 - flow_max,
126 St.real**2 - flow_max ]
127 else:
128 h = r_[ Sf * conj(Sf) - flow_max,
129 St * conj(St) - flow_max ].real
130 else:
131 h = zeros((0,1))
132
133
134
135 iVa = arange(vv["i1"]["Va"], vv["iN"]["Va"])
136 iVm = arange(vv["i1"]["Vm"], vv["iN"]["Vm"])
137 iPg = arange(vv["i1"]["Pg"], vv["iN"]["Pg"])
138 iQg = arange(vv["i1"]["Qg"], vv["iN"]["Qg"])
139 iVaVmPgQg = r_[iVa, iVm, iPg, iQg].T
140
141
142 dSbus_dVm, dSbus_dVa = dSbus_dV(Ybus, V)
143
144 neg_Cg = sparse((-ones(ng), (gen[:, GEN_BUS], range(ng))), (nb, ng))
145
146
147 dg = lil_matrix((2 * nb, nxyz))
148 blank = sparse((nb, ng))
149 dg[:, iVaVmPgQg] = vstack([
150
151 hstack([dSbus_dVa.real, dSbus_dVm.real, neg_Cg, blank]),
152
153 hstack([dSbus_dVa.imag, dSbus_dVm.imag, blank, neg_Cg])
154 ], "csr")
155 dg = dg.T
156
157 if nl2 > 0:
158
159 if ppopt['OPF_FLOW_LIM'] == 2:
160 dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft = \
161 dIbr_dV(branch[il, :], Yf, Yt, V)
162 else:
163 dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft = \
164 dSbr_dV(branch[il, :], Yf, Yt, V)
165 if ppopt['OPF_FLOW_LIM'] == 1:
166 dFf_dVa = dFf_dVa.real
167 dFf_dVm = dFf_dVm.real
168 dFt_dVa = dFt_dVa.real
169 dFt_dVm = dFt_dVm.real
170 Ff = Ff.real
171 Ft = Ft.real
172
173
174 df_dVa, df_dVm, dt_dVa, dt_dVm = \
175 dAbr_dV(dFf_dVa, dFf_dVm, dFt_dVa, dFt_dVm, Ff, Ft)
176
177
178
179 dh = lil_matrix((2 * nl2, nxyz))
180 dh[:, r_[iVa, iVm].T] = vstack([
181 hstack([df_dVa, df_dVm]),
182 hstack([dt_dVa, dt_dVm])
183 ], "csr")
184 dh = dh.T
185 else:
186 dh = None
187
188 return h, g, dh, dg
189