NewtonRaphsonSolver.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. package holeg.power_flow;
  2. import Jama.LUDecomposition;
  3. import Jama.Matrix;
  4. import java.io.PrintStream;
  5. import java.util.Arrays;
  6. public class NewtonRaphsonSolver implements Solver {
  7. @Override
  8. public SolverResult solve(PowerFlowProblem problem, SolverSettings settings) {
  9. if (problem == null)
  10. throw new IllegalArgumentException("problem is null");
  11. if (settings == null)
  12. throw new IllegalArgumentException("settings is null");
  13. try {
  14. long timeStart = System.nanoTime();
  15. // Check data first
  16. if (!problem.checkForValidData())
  17. return SolverResult.error(SolverError.InvalidData);
  18. // Create performance monitor
  19. SolverPerformance performance = new SolverPerformance();
  20. // Build admittance matrix
  21. AdmittanceMatrix admittanceMatrix = AdmittanceMatrix.build(problem.buses, problem.lines);
  22. Matrix G_bus = admittanceMatrix.getG();
  23. Matrix B_bus = admittanceMatrix.getB();
  24. // Copy data over to do math with it
  25. int busCount = problem.buses.length;
  26. double[] V = new double[busCount];
  27. double[] delta = new double[busCount];
  28. double[] Pset = new double[busCount];
  29. double[] Qset = new double[busCount];
  30. for (int i = 0; i < busCount; i++) {
  31. V[i] = problem.buses[i].voltage;
  32. delta[i] = problem.buses[i].delta;
  33. Pset[i] = problem.buses[i].Pg - problem.buses[i].Pl; // generation - load
  34. Qset[i] = problem.buses[i].Qg - problem.buses[i].Ql;
  35. }
  36. // Find PQ/PV nodes
  37. int[] pq = Util.indicesOf(problem.buses, BusType.PQ);
  38. int[] pv = Util.indicesOf(problem.buses, BusType.PV);
  39. // Main solver iteration
  40. double tolerance = Double.MAX_VALUE;
  41. // Jacobian caching
  42. Matrix inverseJ = Matrix.identity(1, 1);
  43. double factor = 1;
  44. int jacobianRecalculation = 0;
  45. for (int iter = 1; iter <= settings.maxIterations; iter++) {
  46. // Calculate current P/Q values
  47. double[] P = new double[busCount];
  48. double[] Q = new double[busCount];
  49. for (int i = 0; i < busCount; i++) {
  50. for (int j = 0; j < busCount; j++) {
  51. P[i] += V[i] * V[j] * (G_bus.get(i, j) * Math.cos(delta[i] - delta[j]) + B_bus.get(i, j) * Math.sin(delta[i] - delta[j]));
  52. Q[i] += V[i] * V[j] * (G_bus.get(i, j) * Math.sin(delta[i] - delta[j]) - B_bus.get(i, j) * Math.cos(delta[i] - delta[j]));
  53. }
  54. }
  55. // Reactive power limit
  56. if (iter > 2 && iter < 20) {
  57. for (int i = 0; i < pv.length; i++) {
  58. Bus bus = problem.buses[i];
  59. double q = Q[i] + bus.Ql;
  60. if (q < bus.Qmin)
  61. V[i] += 0.01;
  62. else if (q > bus.Qmax)
  63. V[i] -= 0.01;
  64. }
  65. }
  66. // Calculate error given by delta between set values and current values
  67. double[] dP = Util.subtract(Pset, P);
  68. double[] dQ = Util.subtract(Qset, Q);
  69. // Create error vector
  70. double[] error = new double[busCount - 1 + pq.length];
  71. for (int i = 0; i < busCount - 1; i++)
  72. error[i] = dP[i + 1];
  73. for (int i = 0; i < pq.length; i++)
  74. error[i + busCount - 1] = dQ[pq[i]];
  75. // Update performance
  76. performance.iterations = iter;
  77. performance.error = tolerance;
  78. // Calculate mismatch between values excepted and current values
  79. tolerance = Arrays.stream(error).map(Math::abs).max().orElse(0);
  80. if (tolerance < settings.minError)
  81. break;
  82. if (jacobianRecalculation <= 0) {
  83. // Jacobian matrix J1
  84. Matrix J1 = new Matrix(busCount - 1, busCount - 1);
  85. for (int i = 0; i < busCount - 1; i++) {
  86. int m = i + 1;
  87. for (int k = 0; k < busCount - 1; k++) {
  88. int n = k + 1;
  89. if (n == m) {
  90. for (int l = 0; l < busCount - 1; l++)
  91. J1.set(i, k, J1.get(i, k) + V[m] * V[l] * (-G_bus.get(m, l) * Math.sin(delta[m] - delta[l]) + B_bus.get(m, l) * Math.cos(delta[m] - delta[l])));
  92. J1.set(i, k, J1.get(i, k) - Math.pow(V[m], 2) * B_bus.get(m, m));
  93. } else
  94. J1.set(i, k, V[m] * V[n] * (G_bus.get(m, n) * Math.sin(delta[m] - delta[n]) - B_bus.get(m, n) * Math.cos(delta[m] - delta[n])));
  95. }
  96. }
  97. // Jacobian matrix J2
  98. Matrix J2 = new Matrix(busCount - 1, pq.length);
  99. for (int i = 0; i < busCount - 1; i++) {
  100. int m = i + 1;
  101. for (int k = 0; k < pq.length; k++) {
  102. int n = pq[k];
  103. if (n == m) {
  104. for (int l = 0; l < busCount; l++)
  105. J2.set(i, k, J2.get(i, k) + V[l] * (G_bus.get(m, l) * Math.cos(delta[m] - delta[l]) + B_bus.get(m, l) * Math.sin(delta[m] - delta[l])));
  106. J2.set(i, k, J2.get(i, k) + V[m] * G_bus.get(m, m));
  107. } else
  108. J2.set(i, k, V[m] * (G_bus.get(m, n) * Math.cos(delta[m] - delta[n]) + B_bus.get(m, n) * Math.sin(delta[m] - delta[n])));
  109. }
  110. }
  111. // Jacobian matrix J3
  112. Matrix J3 = new Matrix(pq.length, busCount - 1);
  113. for (int i = 0; i < pq.length; i++) {
  114. int m = pq[i];
  115. for (int k = 0; k < busCount - 1; k++) {
  116. int n = k + 1;
  117. if (n == m) {
  118. for (int l = 0; l < busCount; l++)
  119. J3.set(i, k, J3.get(i, k) + V[m] * V[l] * (G_bus.get(m, l) * Math.cos(delta[m] - delta[l]) + B_bus.get(m, l) * Math.sin(delta[m] - delta[l])));
  120. J3.set(i, k, J3.get(i, k) - Math.pow(V[m], 2) * G_bus.get(m, m));
  121. } else
  122. J3.set(i, k, V[m] * V[n] * (-G_bus.get(m, n) * Math.cos(delta[m] - delta[n]) - B_bus.get(m, n) * Math.sin(delta[m] - delta[n])));
  123. }
  124. }
  125. // Jacobian matrix J4
  126. Matrix J4 = new Matrix(pq.length, pq.length);
  127. for (int i = 0; i < pq.length; i++) {
  128. int m = pq[i];
  129. for (int k = 0; k < pq.length; k++) {
  130. int n = pq[k];
  131. if (n == m) {
  132. for (int l = 0; l < busCount; l++)
  133. J4.set(i, k, J4.get(i, k) + V[l] * (G_bus.get(m, l) * Math.sin(delta[m] - delta[l]) - B_bus.get(m, l) * Math.cos(delta[m] - delta[l])));
  134. J4.set(i, k, J4.get(i, k) - V[m] * B_bus.get(m, m));
  135. } else
  136. J4.set(i, k, V[m] * (G_bus.get(m, n) * Math.sin(delta[m] - delta[n]) - B_bus.get(m, n) * Math.cos(delta[m] - delta[n])));
  137. }
  138. }
  139. // Construct matrix like this:
  140. // J1 | J2
  141. // -------
  142. // J3 | J4
  143. Matrix J12 = Util.concatColumns(J1, J2);
  144. Matrix J34 = Util.concatColumns(J3, J4);
  145. Matrix J = Util.concatRows(J12, J34);
  146. // Inverse of matrix
  147. try {
  148. LUDecomposition lu = new LUDecomposition(J);
  149. inverseJ = lu.solve(Matrix.identity(J.getRowDimension(), J.getColumnDimension()));
  150. }
  151. catch (Exception e) {
  152. for (int row = 0; row < J.getRowDimension(); row++) {
  153. for (int col = 0; col < J.getColumnDimension(); col++)
  154. System.out.printf("%f ", J.get(col, row));
  155. System.out.println(";");
  156. }
  157. throw e;
  158. }
  159. // Try to find good factor to slow down convergence
  160. factor = 0.1;
  161. try {
  162. double[] eigenvalues = inverseJ.eig().getRealEigenvalues();
  163. double maxEigenvalue = Arrays.stream(eigenvalues).map(Math::abs).max().orElse(0);
  164. // Will only convergence when eigenvalues of matrix are < 1
  165. if (maxEigenvalue > 1)
  166. factor = 1 / maxEigenvalue;
  167. } catch (Exception unused) {
  168. // ignored
  169. }
  170. jacobianRecalculation = settings.jacobianRecalculationInterval;
  171. }
  172. else
  173. jacobianRecalculation--;
  174. // Newton step
  175. Matrix x = inverseJ.times(Util.fromArray(error));
  176. // Update current state (delta, voltage)
  177. for (int i = 0; i < busCount - 1; i++)
  178. delta[i + 1] += x.get(i, 0) * factor;
  179. for (int i = 0; i < pq.length; i++)
  180. V[pq[i]] += x.get(i + busCount - 1, 0) * factor;
  181. }
  182. // Tolerance is to high
  183. if (tolerance >= settings.maxError)
  184. return SolverResult.error(SolverError.ConvergenceError);
  185. // Complex voltages
  186. ComplexNumber[] voltages = new ComplexNumber[V.length];
  187. for (int i = 0; i < V.length; i++)
  188. voltages[i] = ComplexNumber.fromPolar(V[i], delta[i]);
  189. // Calculate flows
  190. FlowData flowData = FlowCalculation.calculate(admittanceMatrix, problem.buses, problem.lines, voltages);
  191. // Save finished time
  192. performance.timeInMilliseconds = (System.nanoTime() - timeStart) / 1e6;
  193. // Return success
  194. return SolverResult.success(performance, voltages, flowData);
  195. }
  196. catch(Exception e) {
  197. e.printStackTrace();
  198. }
  199. return SolverResult.error(SolverError.Internal);
  200. }
  201. }