We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
bug in WLSZeroInjectionConstraintsAlgorithm
code in line 135 of the file, https://github.com/e2nIEE/pandapower/blob/develop/pandapower/estimation/algorithm/base.py

bugs when zero_injection_bus is empty.




--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pandapower/estimation/algorithm/base.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 # Copyright (c) 2016-2020 by University of Kassel and Fraunhofer Institute for Energy Economics
4 # and Energy System Technology (IEE), Kassel. All rights reserved.
5 
6 import numpy as np
7 from scipy.sparse import csr_matrix, vstack, hstack
8 from scipy.sparse.linalg import spsolve
9 
10 from pandapower.estimation.algorithm.estimator import BaseEstimatorIRWLS, get_estimator
11 from pandapower.estimation.algorithm.matrix_base import BaseAlgebra, \
12     BaseAlgebraZeroInjConstraints
13 from pandapower.estimation.idx_bus import ZERO_INJ_FLAG, P, P_STD, Q, Q_STD
14 from pandapower.estimation.ppc_conversion import ExtendedPPCI
15 from pandapower.pypower.idx_bus import bus_cols
16 
17 try:
18     import pplog as logging
19 except ImportError:
20     import logging
21 std_logger = logging.getLogger(__name__)
22 
23 __all__ = ["WLSAlgorithm", "WLSZeroInjectionConstraintsAlgorithm", "IRWLSAlgorithm"]
24 
25 
26 class BaseAlgorithm:
27     def __init__(self, tolerance, maximum_iterations, logger=std_logger):
28         self.tolerance = tolerance
29         self.max_iterations = maximum_iterations
30         self.logger = logger
31         self.successful = False
32         self.iterations = None
33 
34         # Parameters for estimate
35         self.eppci = None
36         self.pp_meas_indices = None
37 
38     def check_observability(self, eppci: ExtendedPPCI, z):
39         # Check if observability criterion is fulfilled and the state estimation is possible
40         if len(z) < 2 * eppci["bus"].shape[0] - 1:
41             self.logger.error("System is not observable (cancelling)")
42             self.logger.error("Measurements available: %d. Measurements required: %d" %
43                               (len(z), 2 * eppci["bus"].shape[0] - 1))
44             raise UserWarning("Measurements available: %d. Measurements required: %d" %
45                               (len(z), 2 * eppci["bus"].shape[0] - 1))
46 
47     def check_result(self, current_error, cur_it):
48         # print output for results
49         if current_error <= self.tolerance:
50             self.successful = True
51             self.logger.debug("State Estimation successful ({:d} iterations)".format(cur_it))
52         else:
53             self.successful = False
54             self.logger.debug("State Estimation not successful ({:d}/{:d} iterations)".format(cur_it,
55                                                                                               self.max_iterations))
56 
57     def initialize(self, eppci: ExtendedPPCI):
58         # Check observability
59         self.eppci = eppci
60         self.pp_meas_indices = eppci.pp_meas_indices
61         self.check_observability(eppci, eppci.z)
62 
63     def estimate(self, ppci: ExtendedPPCI, **kwargs):
64         # Must be implemented individually!!
65         pass
66 
67 
68 class WLSAlgorithm(BaseAlgorithm):
69     def __init__(self, tolerance, maximum_iterations, logger=std_logger):
70         super(WLSAlgorithm, self).__init__(tolerance, maximum_iterations, logger)
71 
72         # Parameters for Bad data detection
73         self.R_inv = None
74         self.Gm = None
75         self.r = None
76         self.H = None
77         self.hx = None
78 
79     def estimate(self, eppci, **kwargs):
80         self.initialize(eppci)
81         # matrix calculation object
82         sem = BaseAlgebra(eppci)
83 
84         current_error, cur_it = 100., 0
85         # invert covariance matrix
86         r_inv = csr_matrix(np.diagflat(1 / eppci.r_cov ** 2))
87         E = eppci.E
88         while current_error > self.tolerance and cur_it < self.max_iterations:
89             self.logger.debug("Starting iteration {:d}".format(1 + cur_it))
90             try:
91                 # residual r
92                 r = csr_matrix(sem.create_rx(E)).T
93 
94                 # jacobian matrix H
95                 H = csr_matrix(sem.create_hx_jacobian(E))
96 
97                 # gain matrix G_m
98                 # G_m = H^t * R^-1 * H
99                 G_m = H.T * (r_inv * H)
100 
101                 # state vector difference d_E
102                 # d_E = G_m^-1 * (H' * R^-1 * r)
103                 d_E = spsolve(G_m, H.T * (r_inv * r))
104 
105                 # Update E with d_E
106                 E += d_E.ravel()
107                 eppci.update_E(E)
108 
109                 # prepare next iteration
110                 cur_it += 1
111                 current_error = np.max(np.abs(d_E))
112                 self.logger.debug("Current error: {:.7f}".format(current_error))
113             except np.linalg.linalg.LinAlgError:
114                 self.logger.error("A problem appeared while using the linear algebra methods."
115                                   "Check and change the measurement set.")
116                 return False
117 
118         # check if the estimation is successfull
119         self.check_result(current_error, cur_it)
120         if self.successful:
121             # store variables required for chi^2 and r_N_max test:
122             self.R_inv = r_inv.toarray()
123             self.Gm = G_m.toarray()
124             self.r = r.toarray()
125             self.H = H.toarray()
126             # create h(x) for the current iteration
127             self.hx = sem.create_hx(eppci.E)
128         return eppci
129 
130 
131 class WLSZeroInjectionConstraintsAlgorithm(BaseAlgorithm):
132     def estimate(self, eppci, **kwargs):
133         # state vector built from delta, |V| and zero injections
134         # Find pq bus with zero p,q and shunt admittance
135         zero_injection_bus = np.argwhere(eppci["bus"][:, bus_cols + ZERO_INJ_FLAG] == True).ravel()
136         eppci["bus"][zero_injection_bus, [bus_cols + P, bus_cols + P_STD, bus_cols + Q, bus_cols + Q_STD]] = np.NaN
137         # Withn pq buses with zero injection identify those who have also no p or q measurement
138         p_zero_injections = zero_injection_bus
139         q_zero_injections = zero_injection_bus
140         new_states = np.zeros(len(p_zero_injections) + len(q_zero_injections))
141 
142         num_bus = eppci["bus"].shape[0]
143 
144         # matrix calculation object
145         sem = BaseAlgebraZeroInjConstraints(eppci)
146 
147         current_error, cur_it = 100., 0
148         r_inv = csr_matrix((np.diagflat(1 / eppci.r_cov) ** 2))
149         E = eppci.E
150         # update the E matrix
151         E_ext = np.r_[eppci.E, new_states]
152 
153         while current_error > self.tolerance and cur_it < self.max_iterations:
154             self.logger.debug("Starting iteration {:d}".format(1 + cur_it))
155             try:
156                 c_x = sem.create_cx(E, p_zero_injections, q_zero_injections)
157 
158                 # residual r
159                 r = csr_matrix(sem.create_rx(E)).T
160                 c_rxh = csr_matrix(c_x).T
161 
162                 # jacobian matrix H
163                 H_temp = sem.create_hx_jacobian(E)
164                 C_temp = sem.create_cx_jacobian(E, p_zero_injections, q_zero_injections)
165                 H, C = csr_matrix(H_temp), csr_matrix(C_temp)
166 
167                 # gain matrix G_m
168                 # G_m = H^t * R^-1 * H
169                 G_m = H.T * (r_inv * H)
170 
171                 # building a new gain matrix for new constraints.
172                 A_1 = vstack([G_m, C])
173                 c_ax = hstack([C, np.zeros((C.shape[0], C.shape[0]))])
174                 c_xT = c_ax.T
175                 M_tx = csr_matrix(hstack((A_1, c_xT)))  # again adding to the new gain matrix
176                 rhs = H.T * (r_inv * r)  # original right hand side
177                 C_rhs = vstack((rhs, -c_rxh))  # creating the righ hand side with new constraints
178 
179                 # state vector difference d_E and update E
180                 d_E_ext = spsolve(M_tx, C_rhs)
181                 E_ext += d_E_ext.ravel()
182                 E = E_ext[:E.shape[0]]
183                 eppci.update_E(E)
184 
185                 # prepare next iteration
186                 cur_it += 1
187                 current_error = np.max(np.abs(d_E_ext[:len(eppci.non_slack_buses) + num_bus]))
188                 self.logger.debug("Current error: {:.7f}".format(current_error))
189             except np.linalg.linalg.LinAlgError:
190                 self.logger.error("A problem appeared while using the linear algebra methods."
191                                   "Check and change the measurement set.")
192                 return False
193 
194         # check if the estimation is successfull
195         self.check_result(current_error, cur_it)
196         return eppci
197 
198 
199 class IRWLSAlgorithm(BaseAlgorithm):
200     def estimate(self, eppci, estimator="wls", **kwargs):
201         self.initialize(eppci)
202 
203         # matrix calculation object
204         sem = get_estimator(BaseEstimatorIRWLS, estimator)(eppci, **kwargs)
205 
206         current_error, cur_it = 100., 0
207         E = eppci.E
208         while current_error > self.tolerance and cur_it < self.max_iterations:
209             self.logger.debug("Starting iteration {:d}".format(1 + cur_it))
210             try:
211                 # residual r
212                 r = csr_matrix(sem.create_rx(E)).T
213 
214                 # jacobian matrix H
215                 H = csr_matrix(sem.create_hx_jacobian(E))
216 
217                 # gain matrix G_m
218                 # G_m = H^t * Phi * H
219                 phi = csr_matrix(sem.create_phi(E))
220                 G_m = H.T * (phi * H)
221 
222                 # state vector difference d_E and update E
223                 d_E = spsolve(G_m, H.T * (phi * r))
224                 E += d_E.ravel()
225                 eppci.update_E(E)
226 
227                 # prepare next iteration
228                 cur_it += 1
229                 current_error = np.max(np.abs(d_E))
230                 self.logger.debug("Current error: {:.7f}".format(current_error))
231             except np.linalg.linalg.LinAlgError:
232                 self.logger.error("A problem appeared while using the linear algebra methods."
233                                   "Check and change the measurement set.")
234                 return False
235 
236         # check if the estimation is successfull
237         self.check_result(current_error, cur_it)
238         # update V/delta
239         return eppci
240
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pandapower/estimation/algorithm/base.py b/pandapower/estimation/algorithm/base.py
--- a/pandapower/estimation/algorithm/base.py
+++ b/pandapower/estimation/algorithm/base.py
@@ -132,6 +132,8 @@
     def estimate(self, eppci, **kwargs):
         # state vector built from delta, |V| and zero injections
         # Find pq bus with zero p,q and shunt admittance
+        if not np.any(eppci["bus"][:, bus_cols + ZERO_INJ_FLAG]):
+            raise UserWarning("Network has no bus with zero injections! Please use WLS instead!")
         zero_injection_bus = np.argwhere(eppci["bus"][:, bus_cols + ZERO_INJ_FLAG] == True).ravel()
         eppci["bus"][zero_injection_bus, [bus_cols + P, bus_cols + P_STD, bus_cols + Q, bus_cols + Q_STD]] = np.NaN
         # Withn pq buses with zero injection identify those who have also no p or q measurement

{"golden_diff": "diff --git a/pandapower/estimation/algorithm/base.py b/pandapower/estimation/algorithm/base.py\n--- a/pandapower/estimation/algorithm/base.py\n+++ b/pandapower/estimation/algorithm/base.py\n@@ -132,6 +132,8 @@\n     def estimate(self, eppci, **kwargs):\n         # state vector built from delta, |V| and zero injections\n         # Find pq bus with zero p,q and shunt admittance\n+        if not np.any(eppci[\"bus\"][:, bus_cols + ZERO_INJ_FLAG]):\n+            raise UserWarning(\"Network has no bus with zero injections! Please use WLS instead!\")\n         zero_injection_bus = np.argwhere(eppci[\"bus\"][:, bus_cols + ZERO_INJ_FLAG] == True).ravel()\n         eppci[\"bus\"][zero_injection_bus, [bus_cols + P, bus_cols + P_STD, bus_cols + Q, bus_cols + Q_STD]] = np.NaN\n         # Withn pq buses with zero injection identify those who have also no p or q measurement\n", "issue": "bug in WLSZeroInjectionConstraintsAlgorithm\ncode in line 135 of the file, https://github.com/e2nIEE/pandapower/blob/develop/pandapower/estimation/algorithm/base.py\r\n\r\nbugs when zero_injection_bus is empty.\r\n\r\n\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright (c) 2016-2020 by University of Kassel and Fraunhofer Institute for Energy Economics\n# and Energy System Technology (IEE), Kassel. All rights reserved.\n\nimport numpy as np\nfrom scipy.sparse import csr_matrix, vstack, hstack\nfrom scipy.sparse.linalg import spsolve\n\nfrom pandapower.estimation.algorithm.estimator import BaseEstimatorIRWLS, get_estimator\nfrom pandapower.estimation.algorithm.matrix_base import BaseAlgebra, \\\n    BaseAlgebraZeroInjConstraints\nfrom pandapower.estimation.idx_bus import ZERO_INJ_FLAG, P, P_STD, Q, Q_STD\nfrom pandapower.estimation.ppc_conversion import ExtendedPPCI\nfrom pandapower.pypower.idx_bus import bus_cols\n\ntry:\n    import pplog as logging\nexcept ImportError:\n    import logging\nstd_logger = logging.getLogger(__name__)\n\n__all__ = [\"WLSAlgorithm\", \"WLSZeroInjectionConstraintsAlgorithm\", \"IRWLSAlgorithm\"]\n\n\nclass BaseAlgorithm:\n    def __init__(self, tolerance, maximum_iterations, logger=std_logger):\n        self.tolerance = tolerance\n        self.max_iterations = maximum_iterations\n        self.logger = logger\n        self.successful = False\n        self.iterations = None\n\n        # Parameters for estimate\n        self.eppci = None\n        self.pp_meas_indices = None\n\n    def check_observability(self, eppci: ExtendedPPCI, z):\n        # Check if observability criterion is fulfilled and the state estimation is possible\n        if len(z) < 2 * eppci[\"bus\"].shape[0] - 1:\n            self.logger.error(\"System is not observable (cancelling)\")\n            self.logger.error(\"Measurements available: %d. Measurements required: %d\" %\n                              (len(z), 2 * eppci[\"bus\"].shape[0] - 1))\n            raise UserWarning(\"Measurements available: %d. Measurements required: %d\" %\n                              (len(z), 2 * eppci[\"bus\"].shape[0] - 1))\n\n    def check_result(self, current_error, cur_it):\n        # print output for results\n        if current_error <= self.tolerance:\n            self.successful = True\n            self.logger.debug(\"State Estimation successful ({:d} iterations)\".format(cur_it))\n        else:\n            self.successful = False\n            self.logger.debug(\"State Estimation not successful ({:d}/{:d} iterations)\".format(cur_it,\n                                                                                              self.max_iterations))\n\n    def initialize(self, eppci: ExtendedPPCI):\n        # Check observability\n        self.eppci = eppci\n        self.pp_meas_indices = eppci.pp_meas_indices\n        self.check_observability(eppci, eppci.z)\n\n    def estimate(self, ppci: ExtendedPPCI, **kwargs):\n        # Must be implemented individually!!\n        pass\n\n\nclass WLSAlgorithm(BaseAlgorithm):\n    def __init__(self, tolerance, maximum_iterations, logger=std_logger):\n        super(WLSAlgorithm, self).__init__(tolerance, maximum_iterations, logger)\n\n        # Parameters for Bad data detection\n        self.R_inv = None\n        self.Gm = None\n        self.r = None\n        self.H = None\n        self.hx = None\n\n    def estimate(self, eppci, **kwargs):\n        self.initialize(eppci)\n        # matrix calculation object\n        sem = BaseAlgebra(eppci)\n\n        current_error, cur_it = 100., 0\n        # invert covariance matrix\n        r_inv = csr_matrix(np.diagflat(1 / eppci.r_cov ** 2))\n        E = eppci.E\n        while current_error > self.tolerance and cur_it < self.max_iterations:\n            self.logger.debug(\"Starting iteration {:d}\".format(1 + cur_it))\n            try:\n                # residual r\n                r = csr_matrix(sem.create_rx(E)).T\n\n                # jacobian matrix H\n                H = csr_matrix(sem.create_hx_jacobian(E))\n\n                # gain matrix G_m\n                # G_m = H^t * R^-1 * H\n                G_m = H.T * (r_inv * H)\n\n                # state vector difference d_E\n                # d_E = G_m^-1 * (H' * R^-1 * r)\n                d_E = spsolve(G_m, H.T * (r_inv * r))\n\n                # Update E with d_E\n                E += d_E.ravel()\n                eppci.update_E(E)\n\n                # prepare next iteration\n                cur_it += 1\n                current_error = np.max(np.abs(d_E))\n                self.logger.debug(\"Current error: {:.7f}\".format(current_error))\n            except np.linalg.linalg.LinAlgError:\n                self.logger.error(\"A problem appeared while using the linear algebra methods.\"\n                                  \"Check and change the measurement set.\")\n                return False\n\n        # check if the estimation is successfull\n        self.check_result(current_error, cur_it)\n        if self.successful:\n            # store variables required for chi^2 and r_N_max test:\n            self.R_inv = r_inv.toarray()\n            self.Gm = G_m.toarray()\n            self.r = r.toarray()\n            self.H = H.toarray()\n            # create h(x) for the current iteration\n            self.hx = sem.create_hx(eppci.E)\n        return eppci\n\n\nclass WLSZeroInjectionConstraintsAlgorithm(BaseAlgorithm):\n    def estimate(self, eppci, **kwargs):\n        # state vector built from delta, |V| and zero injections\n        # Find pq bus with zero p,q and shunt admittance\n        zero_injection_bus = np.argwhere(eppci[\"bus\"][:, bus_cols + ZERO_INJ_FLAG] == True).ravel()\n        eppci[\"bus\"][zero_injection_bus, [bus_cols + P, bus_cols + P_STD, bus_cols + Q, bus_cols + Q_STD]] = np.NaN\n        # Withn pq buses with zero injection identify those who have also no p or q measurement\n        p_zero_injections = zero_injection_bus\n        q_zero_injections = zero_injection_bus\n        new_states = np.zeros(len(p_zero_injections) + len(q_zero_injections))\n\n        num_bus = eppci[\"bus\"].shape[0]\n\n        # matrix calculation object\n        sem = BaseAlgebraZeroInjConstraints(eppci)\n\n        current_error, cur_it = 100., 0\n        r_inv = csr_matrix((np.diagflat(1 / eppci.r_cov) ** 2))\n        E = eppci.E\n        # update the E matrix\n        E_ext = np.r_[eppci.E, new_states]\n\n        while current_error > self.tolerance and cur_it < self.max_iterations:\n            self.logger.debug(\"Starting iteration {:d}\".format(1 + cur_it))\n            try:\n                c_x = sem.create_cx(E, p_zero_injections, q_zero_injections)\n\n                # residual r\n                r = csr_matrix(sem.create_rx(E)).T\n                c_rxh = csr_matrix(c_x).T\n\n                # jacobian matrix H\n                H_temp = sem.create_hx_jacobian(E)\n                C_temp = sem.create_cx_jacobian(E, p_zero_injections, q_zero_injections)\n                H, C = csr_matrix(H_temp), csr_matrix(C_temp)\n\n                # gain matrix G_m\n                # G_m = H^t * R^-1 * H\n                G_m = H.T * (r_inv * H)\n\n                # building a new gain matrix for new constraints.\n                A_1 = vstack([G_m, C])\n                c_ax = hstack([C, np.zeros((C.shape[0], C.shape[0]))])\n                c_xT = c_ax.T\n                M_tx = csr_matrix(hstack((A_1, c_xT)))  # again adding to the new gain matrix\n                rhs = H.T * (r_inv * r)  # original right hand side\n                C_rhs = vstack((rhs, -c_rxh))  # creating the righ hand side with new constraints\n\n                # state vector difference d_E and update E\n                d_E_ext = spsolve(M_tx, C_rhs)\n                E_ext += d_E_ext.ravel()\n                E = E_ext[:E.shape[0]]\n                eppci.update_E(E)\n\n                # prepare next iteration\n                cur_it += 1\n                current_error = np.max(np.abs(d_E_ext[:len(eppci.non_slack_buses) + num_bus]))\n                self.logger.debug(\"Current error: {:.7f}\".format(current_error))\n            except np.linalg.linalg.LinAlgError:\n                self.logger.error(\"A problem appeared while using the linear algebra methods.\"\n                                  \"Check and change the measurement set.\")\n                return False\n\n        # check if the estimation is successfull\n        self.check_result(current_error, cur_it)\n        return eppci\n\n\nclass IRWLSAlgorithm(BaseAlgorithm):\n    def estimate(self, eppci, estimator=\"wls\", **kwargs):\n        self.initialize(eppci)\n\n        # matrix calculation object\n        sem = get_estimator(BaseEstimatorIRWLS, estimator)(eppci, **kwargs)\n\n        current_error, cur_it = 100., 0\n        E = eppci.E\n        while current_error > self.tolerance and cur_it < self.max_iterations:\n            self.logger.debug(\"Starting iteration {:d}\".format(1 + cur_it))\n            try:\n                # residual r\n                r = csr_matrix(sem.create_rx(E)).T\n\n                # jacobian matrix H\n                H = csr_matrix(sem.create_hx_jacobian(E))\n\n                # gain matrix G_m\n                # G_m = H^t * Phi * H\n                phi = csr_matrix(sem.create_phi(E))\n                G_m = H.T * (phi * H)\n\n                # state vector difference d_E and update E\n                d_E = spsolve(G_m, H.T * (phi * r))\n                E += d_E.ravel()\n                eppci.update_E(E)\n\n                # prepare next iteration\n                cur_it += 1\n                current_error = np.max(np.abs(d_E))\n                self.logger.debug(\"Current error: {:.7f}\".format(current_error))\n            except np.linalg.linalg.LinAlgError:\n                self.logger.error(\"A problem appeared while using the linear algebra methods.\"\n                                  \"Check and change the measurement set.\")\n                return False\n\n        # check if the estimation is successfull\n        self.check_result(current_error, cur_it)\n        # update V/delta\n        return eppci\n", "path": "pandapower/estimation/algorithm/base.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright (c) 2016-2020 by University of Kassel and Fraunhofer Institute for Energy Economics\n# and Energy System Technology (IEE), Kassel. All rights reserved.\n\nimport numpy as np\nfrom scipy.sparse import csr_matrix, vstack, hstack\nfrom scipy.sparse.linalg import spsolve\n\nfrom pandapower.estimation.algorithm.estimator import BaseEstimatorIRWLS, get_estimator\nfrom pandapower.estimation.algorithm.matrix_base import BaseAlgebra, \\\n    BaseAlgebraZeroInjConstraints\nfrom pandapower.estimation.idx_bus import ZERO_INJ_FLAG, P, P_STD, Q, Q_STD\nfrom pandapower.estimation.ppc_conversion import ExtendedPPCI\nfrom pandapower.pypower.idx_bus import bus_cols\n\ntry:\n    import pplog as logging\nexcept ImportError:\n    import logging\nstd_logger = logging.getLogger(__name__)\n\n__all__ = [\"WLSAlgorithm\", \"WLSZeroInjectionConstraintsAlgorithm\", \"IRWLSAlgorithm\"]\n\n\nclass BaseAlgorithm:\n    def __init__(self, tolerance, maximum_iterations, logger=std_logger):\n        self.tolerance = tolerance\n        self.max_iterations = maximum_iterations\n        self.logger = logger\n        self.successful = False\n        self.iterations = None\n\n        # Parameters for estimate\n        self.eppci = None\n        self.pp_meas_indices = None\n\n    def check_observability(self, eppci: ExtendedPPCI, z):\n        # Check if observability criterion is fulfilled and the state estimation is possible\n        if len(z) < 2 * eppci[\"bus\"].shape[0] - 1:\n            self.logger.error(\"System is not observable (cancelling)\")\n            self.logger.error(\"Measurements available: %d. Measurements required: %d\" %\n                              (len(z), 2 * eppci[\"bus\"].shape[0] - 1))\n            raise UserWarning(\"Measurements available: %d. Measurements required: %d\" %\n                              (len(z), 2 * eppci[\"bus\"].shape[0] - 1))\n\n    def check_result(self, current_error, cur_it):\n        # print output for results\n        if current_error <= self.tolerance:\n            self.successful = True\n            self.logger.debug(\"State Estimation successful ({:d} iterations)\".format(cur_it))\n        else:\n            self.successful = False\n            self.logger.debug(\"State Estimation not successful ({:d}/{:d} iterations)\".format(cur_it,\n                                                                                              self.max_iterations))\n\n    def initialize(self, eppci: ExtendedPPCI):\n        # Check observability\n        self.eppci = eppci\n        self.pp_meas_indices = eppci.pp_meas_indices\n        self.check_observability(eppci, eppci.z)\n\n    def estimate(self, ppci: ExtendedPPCI, **kwargs):\n        # Must be implemented individually!!\n        pass\n\n\nclass WLSAlgorithm(BaseAlgorithm):\n    def __init__(self, tolerance, maximum_iterations, logger=std_logger):\n        super(WLSAlgorithm, self).__init__(tolerance, maximum_iterations, logger)\n\n        # Parameters for Bad data detection\n        self.R_inv = None\n        self.Gm = None\n        self.r = None\n        self.H = None\n        self.hx = None\n\n    def estimate(self, eppci, **kwargs):\n        self.initialize(eppci)\n        # matrix calculation object\n        sem = BaseAlgebra(eppci)\n\n        current_error, cur_it = 100., 0\n        # invert covariance matrix\n        r_inv = csr_matrix(np.diagflat(1 / eppci.r_cov ** 2))\n        E = eppci.E\n        while current_error > self.tolerance and cur_it < self.max_iterations:\n            self.logger.debug(\"Starting iteration {:d}\".format(1 + cur_it))\n            try:\n                # residual r\n                r = csr_matrix(sem.create_rx(E)).T\n\n                # jacobian matrix H\n                H = csr_matrix(sem.create_hx_jacobian(E))\n\n                # gain matrix G_m\n                # G_m = H^t * R^-1 * H\n                G_m = H.T * (r_inv * H)\n\n                # state vector difference d_E\n                # d_E = G_m^-1 * (H' * R^-1 * r)\n                d_E = spsolve(G_m, H.T * (r_inv * r))\n\n                # Update E with d_E\n                E += d_E.ravel()\n                eppci.update_E(E)\n\n                # prepare next iteration\n                cur_it += 1\n                current_error = np.max(np.abs(d_E))\n                self.logger.debug(\"Current error: {:.7f}\".format(current_error))\n            except np.linalg.linalg.LinAlgError:\n                self.logger.error(\"A problem appeared while using the linear algebra methods.\"\n                                  \"Check and change the measurement set.\")\n                return False\n\n        # check if the estimation is successfull\n        self.check_result(current_error, cur_it)\n        if self.successful:\n            # store variables required for chi^2 and r_N_max test:\n            self.R_inv = r_inv.toarray()\n            self.Gm = G_m.toarray()\n            self.r = r.toarray()\n            self.H = H.toarray()\n            # create h(x) for the current iteration\n            self.hx = sem.create_hx(eppci.E)\n        return eppci\n\n\nclass WLSZeroInjectionConstraintsAlgorithm(BaseAlgorithm):\n    def estimate(self, eppci, **kwargs):\n        # state vector built from delta, |V| and zero injections\n        # Find pq bus with zero p,q and shunt admittance\n        if not np.any(eppci[\"bus\"][:, bus_cols + ZERO_INJ_FLAG]):\n            raise UserWarning(\"Network has no bus with zero injections! Please use WLS instead!\")\n        zero_injection_bus = np.argwhere(eppci[\"bus\"][:, bus_cols + ZERO_INJ_FLAG] == True).ravel()\n        eppci[\"bus\"][zero_injection_bus, [bus_cols + P, bus_cols + P_STD, bus_cols + Q, bus_cols + Q_STD]] = np.NaN\n        # Withn pq buses with zero injection identify those who have also no p or q measurement\n        p_zero_injections = zero_injection_bus\n        q_zero_injections = zero_injection_bus\n        new_states = np.zeros(len(p_zero_injections) + len(q_zero_injections))\n\n        num_bus = eppci[\"bus\"].shape[0]\n\n        # matrix calculation object\n        sem = BaseAlgebraZeroInjConstraints(eppci)\n\n        current_error, cur_it = 100., 0\n        r_inv = csr_matrix((np.diagflat(1 / eppci.r_cov) ** 2))\n        E = eppci.E\n        # update the E matrix\n        E_ext = np.r_[eppci.E, new_states]\n\n        while current_error > self.tolerance and cur_it < self.max_iterations:\n            self.logger.debug(\"Starting iteration {:d}\".format(1 + cur_it))\n            try:\n                c_x = sem.create_cx(E, p_zero_injections, q_zero_injections)\n\n                # residual r\n                r = csr_matrix(sem.create_rx(E)).T\n                c_rxh = csr_matrix(c_x).T\n\n                # jacobian matrix H\n                H_temp = sem.create_hx_jacobian(E)\n                C_temp = sem.create_cx_jacobian(E, p_zero_injections, q_zero_injections)\n                H, C = csr_matrix(H_temp), csr_matrix(C_temp)\n\n                # gain matrix G_m\n                # G_m = H^t * R^-1 * H\n                G_m = H.T * (r_inv * H)\n\n                # building a new gain matrix for new constraints.\n                A_1 = vstack([G_m, C])\n                c_ax = hstack([C, np.zeros((C.shape[0], C.shape[0]))])\n                c_xT = c_ax.T\n                M_tx = csr_matrix(hstack((A_1, c_xT)))  # again adding to the new gain matrix\n                rhs = H.T * (r_inv * r)  # original right hand side\n                C_rhs = vstack((rhs, -c_rxh))  # creating the righ hand side with new constraints\n\n                # state vector difference d_E and update E\n                d_E_ext = spsolve(M_tx, C_rhs)\n                E_ext += d_E_ext.ravel()\n                E = E_ext[:E.shape[0]]\n                eppci.update_E(E)\n\n                # prepare next iteration\n                cur_it += 1\n                current_error = np.max(np.abs(d_E_ext[:len(eppci.non_slack_buses) + num_bus]))\n                self.logger.debug(\"Current error: {:.7f}\".format(current_error))\n            except np.linalg.linalg.LinAlgError:\n                self.logger.error(\"A problem appeared while using the linear algebra methods.\"\n                                  \"Check and change the measurement set.\")\n                return False\n\n        # check if the estimation is successfull\n        self.check_result(current_error, cur_it)\n        return eppci\n\n\nclass IRWLSAlgorithm(BaseAlgorithm):\n    def estimate(self, eppci, estimator=\"wls\", **kwargs):\n        self.initialize(eppci)\n\n        # matrix calculation object\n        sem = get_estimator(BaseEstimatorIRWLS, estimator)(eppci, **kwargs)\n\n        current_error, cur_it = 100., 0\n        E = eppci.E\n        while current_error > self.tolerance and cur_it < self.max_iterations:\n            self.logger.debug(\"Starting iteration {:d}\".format(1 + cur_it))\n            try:\n                # residual r\n                r = csr_matrix(sem.create_rx(E)).T\n\n                # jacobian matrix H\n                H = csr_matrix(sem.create_hx_jacobian(E))\n\n                # gain matrix G_m\n                # G_m = H^t * Phi * H\n                phi = csr_matrix(sem.create_phi(E))\n                G_m = H.T * (phi * H)\n\n                # state vector difference d_E and update E\n                d_E = spsolve(G_m, H.T * (phi * r))\n                E += d_E.ravel()\n                eppci.update_E(E)\n\n                # prepare next iteration\n                cur_it += 1\n                current_error = np.max(np.abs(d_E))\n                self.logger.debug(\"Current error: {:.7f}\".format(current_error))\n            except np.linalg.linalg.LinAlgError:\n                self.logger.error(\"A problem appeared while using the linear algebra methods.\"\n                                  \"Check and change the measurement set.\")\n                return False\n\n        # check if the estimation is successfull\n        self.check_result(current_error, cur_it)\n        # update V/delta\n        return eppci\n", "path": "pandapower/estimation/algorithm/base.py"}]}