/** * Returns two matrices containing partial derivatives of the complex bus power injections w.r.t * voltage magnitude and voltage angle respectively (for all buses). If YBUS is a sparse matrix, * the return values will be also. The following explains the expressions used to form the * matrices: * * <p>S = diag(V) * conj(Ibus) = diag(conj(Ibus)) * V * * <p>Partials of V & Ibus w.r.t. voltage magnitudes dV/dVm = diag(V./abs(V)) dI/dVm = Ybus * * dV/dVm = Ybus * diag(V./abs(V)) * * <p>Partials of V & Ibus w.r.t. voltage angles dV/dVa = j * diag(V) dI/dVa = Ybus * dV/dVa = * Ybus * j * diag(V) * * <p>Partials of S w.r.t. voltage magnitudes dS/dVm = diag(V) * conj(dI/dVm) + diag(conj(Ibus)) * * dV/dVm = diag(V) * conj(Ybus * diag(V./abs(V))) + conj(diag(Ibus)) * diag(V./abs(V)) * * <p>Partials of S w.r.t. voltage angles dS/dVa = diag(V) * conj(dI/dVa) + diag(conj(Ibus)) * * dV/dVa = diag(V) * conj(Ybus * j * diag(V)) + conj(diag(Ibus)) * j * diag(V) = -j * diag(V) * * conj(Ybus * diag(V)) + conj(diag(Ibus)) * j * diag(V) = j * diag(V) * conj(diag(Ibus) - Ybus * * diag(V)) * * @param Ybus * @param V * @return */ @SuppressWarnings("static-access") public static DComplexMatrix2D[] jp_dSbus_dV(DComplexMatrix2D Ybus, DComplexMatrix1D V) { int n; int[] ib; DComplexMatrix1D Ibus, absV, Vnorm; DComplexMatrix2D[] dSbus_dV; SparseRCDComplexMatrix2D diagV, diagIbus, diagVnorm, rhs, dS_dVa, conjInorm, dS_dVm, addend; n = (int) V.size(); ib = Djp_util.irange(n); Ibus = Ybus.zMult(V, null); diagV = new SparseRCDComplexMatrix2D(n, n, ib, ib, V.toArray(), false, false); diagIbus = new SparseRCDComplexMatrix2D(n, n, ib, ib, Ibus.toArray(), false, false); absV = V.copy().assign(cfunc.abs); Vnorm = V.copy().assign(absV, cfunc.div); diagVnorm = new SparseRCDComplexMatrix2D(n, n, ib, ib, Vnorm.toArray(), false, false); rhs = (SparseRCDComplexMatrix2D) Ybus.zMult(diagV, null); rhs.assign(diagIbus, cfunc.swapArgs(cfunc.minus)).assign(cfunc.conj); dS_dVa = (SparseRCDComplexMatrix2D) diagV.zMult(rhs, null); dS_dVa.assign(cfunc.mult(new double[] {0, 1})); conjInorm = (SparseRCDComplexMatrix2D) Ybus.zMult(diagVnorm, null); conjInorm.assign(cfunc.conj); dS_dVm = (SparseRCDComplexMatrix2D) diagV.zMult(conjInorm, null); diagIbus.assign(cfunc.conj); addend = (SparseRCDComplexMatrix2D) diagVnorm.zMult(diagIbus, null); dS_dVm.assign(addend, cfunc.plus); dSbus_dV = new DComplexMatrix2D[] {dS_dVm, dS_dVa}; return dSbus_dV; }
/** * Solves for bus voltages given the full system admittance matrix (for all buses), the complex * bus power injection vector (for all buses), the initial vector of complex bus voltages, and * column vectors with the lists of bus indices for the swing bus, PV buses, and PQ buses, * respectively. The bus voltage vector contains the set point for generator (including ref bus) * buses, and the reference angle of the swing bus, as well as an initial guess for remaining * magnitudes and angles. JPOPT is a JPOWER options vector which can be used to set the * termination tolerance, maximum number of iterations, and output options (see JPOPTION for * details). Uses default options if this parameter is not given. Returns the final complex * voltages, a flag which indicates whether it converged or not, and the number of iterations * performed. * * @param Ybus * @param Sbus * @param V0 * @param ref * @param pv * @param pq * @param jpopt * @return */ @SuppressWarnings("static-access") public static Object[] jp_newtonpf( DComplexMatrix2D Ybus, DComplexMatrix1D Sbus, DComplexMatrix1D V0, int ref, int[] pv, int[] pq, Map<String, Double> jpopt) { int i, max_it, verbose, npv, npq, j1, j2, j3, j4, j5, j6; int[] pvpq; double tol, normF; boolean converged; DoubleMatrix1D F, dx; DoubleMatrix2D J11, J12, J21, J22, J1, J2, J; DComplexMatrix1D mis, V, Va, Vm, dxz; DComplexMatrix2D dSbus_dVm, dSbus_dVa; DComplexMatrix2D[] dSbus_dV; SparseRCDoubleMatrix2D JJ; /* options */ tol = jpopt.get("PF_TOL"); max_it = jpopt.get("PF_MAX_IT").intValue(); verbose = jpopt.get("VERBOSE").intValue(); /* initialize */ pvpq = Djp_util.icat(pv, pq); converged = false; i = 0; V = V0; Va = V.copy().assign(cfunc.arg); Vm = V.copy().assign(cfunc.abs); /* set up indexing for updating V */ npv = pv.length; npq = pq.length; j1 = 0; j2 = npv; // j1:j2 - V angle of pv buses j3 = j2; j4 = j2 + npq; // j3:j4 - V angle of pq buses j5 = j4; j6 = j4 + npq; // j5:j6 - V mag of pq buses /* evaluate F(x0) */ mis = Ybus.zMult(V, null).assign(cfunc.conj); mis.assign(V, cfunc.mult).assign(Sbus, cfunc.minus); F = DoubleFactory1D.sparse.make( new DoubleMatrix1D[] { mis.viewSelection(pvpq).getRealPart(), mis.viewSelection(pq).getImaginaryPart() }); /* check tolerance */ normF = DenseDoubleAlgebra.DEFAULT.norm(F, Norm.Infinity); if (verbose > 0) System.out.print("(Newton)\n"); if (verbose > 1) { System.out.printf("\n it max P & Q mismatch (p.u.)"); System.out.printf("\n---- ---------------------------"); System.out.printf("\n%3d %10.3e", i, normF); } if (normF < tol) { converged = true; if (verbose > 1) System.out.printf("\nConverged!\n"); } /* do Newton iterations */ while ((!converged) & (i < max_it)) { /* update iteration counter */ i += 1; /* evaluate Jacobian */ dSbus_dV = Djp_dSbus_dV.jp_dSbus_dV(Ybus, V); dSbus_dVm = dSbus_dV[0]; dSbus_dVa = dSbus_dV[1]; J11 = dSbus_dVa.getRealPart().viewSelection(pvpq, pvpq).copy(); J12 = dSbus_dVm.getRealPart().viewSelection(pvpq, pq).copy(); J21 = dSbus_dVa.getImaginaryPart().viewSelection(pq, pvpq).copy(); J22 = dSbus_dVm.getImaginaryPart().viewSelection(pq, pq).copy(); J1 = DoubleFactory2D.sparse.appendColumns(J11, J12); J2 = DoubleFactory2D.sparse.appendColumns(J21, J22); J = DoubleFactory2D.sparse.appendRows(J1, J2); JJ = new SparseRCDoubleMatrix2D(J.rows(), J.columns()); JJ.assign(J); dx = SparseDoubleAlgebra.DEFAULT.solve(JJ, F).assign(dfunc.neg); dxz = Djp_util.complex(dx, null); /* update voltage */ if (npv > 0) Va.viewSelection(pv).assign(dxz.viewSelection(Djp_util.irange(j1, j2)), cfunc.plus); if (npq > 0) { Va.viewSelection(pq).assign(dxz.viewSelection(Djp_util.irange(j3, j4)), cfunc.plus); Vm.viewSelection(pq).assign(dxz.viewSelection(Djp_util.irange(j5, j6)), cfunc.plus); } V = Djp_util.polar(Vm.getRealPart(), Va.getRealPart()); /* update Vm and Va again in case we wrapped around with a negative Vm */ Va = V.copy().assign(cfunc.arg); Vm = V.copy().assign(cfunc.abs); /* evalute F(x) */ mis = Ybus.zMult(V, null).assign(cfunc.conj); mis.assign(V, cfunc.mult).assign(Sbus, cfunc.minus); F = DoubleFactory1D.sparse.make( new DoubleMatrix1D[] { mis.viewSelection(pvpq).getRealPart(), mis.viewSelection(pq).getImaginaryPart() }); /* check for convergence */ normF = DenseDoubleAlgebra.DEFAULT.norm(F, Norm.Infinity); if (verbose > 1) System.out.printf("\n%3d %10.3e", i, normF); if (normF < tol) { converged = true; if (verbose > 0) System.out.printf("\nNewton's method power flow converged in %d iterations.\n", i); } } if (verbose > 0) if (!converged) System.out.printf("\nNewton''s method power did not converge in %d iterations.\n", i); return new Object[] {V, converged, i}; }