def estimate(self, v_start=None, delta_start=None, calculate_voltage_angles=True): """ The function estimate is the main function of the module. It takes up to three input arguments: v_start, delta_start and calculate_voltage_angles. The first two are the initial state variables for the estimation process. Usually they can be initialized in a "flat-start" condition: All voltages being 1.0 pu and all voltage angles being 0 degrees. In this case, the parameters can be left at their default values (None). If the estimation is applied continuously, using the results from the last estimation as the starting condition for the current estimation can decrease the amount of iterations needed to estimate the current state. The third parameter defines whether all voltage angles are calculated absolutely, including phase shifts from transformers. If only the relative differences between buses are required, this parameter can be set to False. Returned is a boolean value, which is true after a successful estimation and false otherwise. The resulting complex voltage will be written into the pandapower network. The result fields are found res_bus_est of the pandapower network. INPUT: **net** - The net within this line should be created **v_start** (np.array, shape=(1,), optional) - Vector with initial values for all voltage magnitudes in p.u. (sorted by bus index) **delta_start** (np.array, shape=(1,), optional) - Vector with initial values for all voltage angles in degrees (sorted by bus index) OPTIONAL: **calculate_voltage_angles** - (bool) - Take into account absolute voltage angles and phase shifts in transformers Default is True. OUTPUT: **successful** (boolean) - True if the estimation process was successful Optional estimation variables: The bus power injections can be accessed with *se.s_node_powers* and the estimated values corresponding to the (noisy) measurement values with *se.hx*. (*hx* denotes h(x)) EXAMPLE: success = estimate(np.array([1.0, 1.0, 1.0]), np.array([0.0, 0.0, 0.0])) """ if self.net is None: raise UserWarning("Component was not initialized with a network.") # add initial values for V and delta # node voltages # V<delta if v_start is None: v_start = np.ones(self.net.bus.shape[0]) if delta_start is None: delta_start = np.zeros(self.net.bus.shape[0]) # initialize the ppc bus with the initial values given vm_backup, va_backup = self.net.res_bus.vm_pu.copy( ), self.net.res_bus.va_degree.copy() self.net.res_bus.vm_pu = v_start self.net.res_bus.vm_pu[self.net.bus.index[self.net.bus.in_service == False]] = np.nan self.net.res_bus.va_degree = delta_start # select elements in service and convert pandapower ppc to ppc self.net._options = {} _add_ppc_options(self.net, check_connectivity=False, init="results", trafo_model="t", copy_constraints_to_ppc=False, mode="pf", enforce_q_lims=False, calculate_voltage_angles=calculate_voltage_angles, r_switch=0.0, recycle=dict(_is_elements=False, ppc=False, Ybus=False)) self.net["_is_elements"] = _select_is_elements(self.net) ppc, _ = _pd2ppc(self.net) mapping_table = self.net["_pd2ppc_lookups"]["bus"] br_cols = ppc["branch"].shape[1] bs_cols = ppc["bus"].shape[1] self.net.res_bus.vm_pu = vm_backup self.net.res_bus.va_degree = va_backup # add 6 columns to ppc[bus] for Vm, Vm std dev, P, P std dev, Q, Q std dev bus_append = np.full((ppc["bus"].shape[0], 6), np.nan, dtype=ppc["bus"].dtype) v_measurements = self.net.measurement[ (self.net.measurement.type == "v") & (self.net.measurement.element_type == "bus")] if len(v_measurements): bus_positions = mapping_table[v_measurements.bus.values.astype( int)] bus_append[bus_positions, 0] = v_measurements.value.values bus_append[bus_positions, 1] = v_measurements.std_dev.values p_measurements = self.net.measurement[ (self.net.measurement.type == "p") & (self.net.measurement.element_type == "bus")] if len(p_measurements): bus_positions = mapping_table[p_measurements.bus.values.astype( int)] bus_append[bus_positions, 2] = p_measurements.value.values * 1e3 / self.s_ref bus_append[bus_positions, 3] = p_measurements.std_dev.values * 1e3 / self.s_ref q_measurements = self.net.measurement[ (self.net.measurement.type == "q") & (self.net.measurement.element_type == "bus")] if len(q_measurements): bus_positions = mapping_table[q_measurements.bus.values.astype( int)] bus_append[bus_positions, 4] = q_measurements.value.values * 1e3 / self.s_ref bus_append[bus_positions, 5] = q_measurements.std_dev.values * 1e3 / self.s_ref # add virtual measurements for artificial buses, which were created because # of an open line switch. p/q are 0. and std dev is 1. (small value) new_in_line_buses = np.setdiff1d(np.arange(ppc["bus"].shape[0]), mapping_table[mapping_table >= 0]) bus_append[new_in_line_buses, 2] = 0. bus_append[new_in_line_buses, 3] = 1. bus_append[new_in_line_buses, 4] = 0. bus_append[new_in_line_buses, 5] = 1. # add 12 columns to mpc[branch] for Im_from, Im_from std dev, Im_to, Im_to std dev, # P_from, P_from std dev, P_to, P_to std dev, Q_from,Q_from std dev, Q_to, Q_to std dev branch_append = np.full((ppc["branch"].shape[0], 12), np.nan, dtype=ppc["branch"].dtype) i_measurements = self.net.measurement[ (self.net.measurement.type == "i") & (self.net.measurement.element_type == "line")] if len(i_measurements): meas_from = i_measurements[(i_measurements.bus.values.astype( int) == self.net.line.from_bus[i_measurements.element]).values] meas_to = i_measurements[(i_measurements.bus.values.astype( int) == self.net.line.to_bus[i_measurements.element]).values] ix_from = meas_from.element.values.astype(int) ix_to = meas_to.element.values.astype(int) i_a_to_pu_from = (self.net.bus.vn_kv[meas_from.bus] * 1e3 / self.s_ref).values i_a_to_pu_to = (self.net.bus.vn_kv[meas_to.bus] * 1e3 / self.s_ref).values branch_append[ix_from, 0] = meas_from.value.values * i_a_to_pu_from branch_append[ix_from, 1] = meas_from.std_dev.values * i_a_to_pu_from branch_append[ix_to, 2] = meas_to.value.values * i_a_to_pu_to branch_append[ix_to, 3] = meas_to.std_dev.values * i_a_to_pu_to p_measurements = self.net.measurement[ (self.net.measurement.type == "p") & (self.net.measurement.element_type == "line")] if len(p_measurements): meas_from = p_measurements[(p_measurements.bus.values.astype( int) == self.net.line.from_bus[p_measurements.element]).values] meas_to = p_measurements[(p_measurements.bus.values.astype( int) == self.net.line.to_bus[p_measurements.element]).values] ix_from = meas_from.element.values.astype(int) ix_to = meas_to.element.values.astype(int) branch_append[ix_from, 4] = meas_from.value.values * 1e3 / self.s_ref branch_append[ix_from, 5] = meas_from.std_dev.values * 1e3 / self.s_ref branch_append[ix_to, 6] = meas_to.value.values * 1e3 / self.s_ref branch_append[ix_to, 7] = meas_to.std_dev.values * 1e3 / self.s_ref q_measurements = self.net.measurement[ (self.net.measurement.type == "q") & (self.net.measurement.element_type == "line")] if len(q_measurements): meas_from = q_measurements[(q_measurements.bus.values.astype( int) == self.net.line.from_bus[q_measurements.element]).values] meas_to = q_measurements[(q_measurements.bus.values.astype( int) == self.net.line.to_bus[q_measurements.element]).values] ix_from = meas_from.element.values.astype(int) ix_to = meas_to.element.values.astype(int) branch_append[ix_from, 8] = meas_from.value.values * 1e3 / self.s_ref branch_append[ix_from, 9] = meas_from.std_dev.values * 1e3 / self.s_ref branch_append[ix_to, 10] = meas_to.value.values * 1e3 / self.s_ref branch_append[ix_to, 11] = meas_to.std_dev.values * 1e3 / self.s_ref i_tr_measurements = self.net.measurement[ (self.net.measurement.type == "i") & (self.net.measurement.element_type == "transformer")] if len(i_tr_measurements): meas_from = i_tr_measurements[( i_tr_measurements.bus.values.astype(int) == self.net.trafo.hv_bus[i_tr_measurements.element]).values] meas_to = i_tr_measurements[( i_tr_measurements.bus.values.astype(int) == self.net.trafo.lv_bus[i_tr_measurements.element]).values] ix_from = meas_from.element.values.astype(int) ix_to = meas_to.element.values.astype(int) i_a_to_pu_from = (self.net.bus.vn_kv[meas_from.bus] * 1e3 / self.s_ref).values i_a_to_pu_to = (self.net.bus.vn_kv[meas_to.bus] * 1e3 / self.s_ref).values branch_append[ix_from, 0] = meas_from.value.values * i_a_to_pu_from branch_append[ix_from, 1] = meas_from.std_dev.values * i_a_to_pu_from branch_append[ix_to, 2] = meas_to.value.values * i_a_to_pu_to branch_append[ix_to, 3] = meas_to.std_dev.values * i_a_to_pu_to p_tr_measurements = self.net.measurement[ (self.net.measurement.type == "p") & (self.net.measurement.element_type == "transformer")] if len(p_tr_measurements): meas_from = p_tr_measurements[( p_tr_measurements.bus.values.astype(int) == self.net.trafo.hv_bus[p_tr_measurements.element]).values] meas_to = p_tr_measurements[( p_tr_measurements.bus.values.astype(int) == self.net.trafo.lv_bus[p_tr_measurements.element]).values] ix_from = len(self.net.line) + meas_from.element.values.astype(int) ix_to = len(self.net.line) + meas_to.element.values.astype(int) branch_append[ix_from, 4] = meas_from.value.values * 1e3 / self.s_ref branch_append[ix_from, 5] = meas_from.std_dev.values * 1e3 / self.s_ref branch_append[ix_to, 6] = meas_to.value.values * 1e3 / self.s_ref branch_append[ix_to, 7] = meas_to.std_dev.values * 1e3 / self.s_ref q_tr_measurements = self.net.measurement[ (self.net.measurement.type == "q") & (self.net.measurement.element_type == "transformer")] if len(q_tr_measurements): meas_from = q_tr_measurements[( q_tr_measurements.bus.values.astype(int) == self.net.trafo.hv_bus[q_tr_measurements.element]).values] meas_to = q_tr_measurements[( q_tr_measurements.bus.values.astype(int) == self.net.trafo.lv_bus[q_tr_measurements.element]).values] ix_from = len(self.net.line) + meas_from.element.values.astype(int) ix_to = len(self.net.line) + meas_to.element.values.astype(int) branch_append[ix_from, 8] = meas_from.value.values * 1e3 / self.s_ref branch_append[ix_from, 9] = meas_from.std_dev.values * 1e3 / self.s_ref branch_append[ix_to, 10] = meas_to.value.values * 1e3 / self.s_ref branch_append[ix_to, 11] = meas_to.std_dev.values * 1e3 / self.s_ref ppc["bus"] = np.hstack((ppc["bus"], bus_append)) ppc["branch"] = np.hstack((ppc["branch"], branch_append)) with warnings.catch_warnings(): warnings.simplefilter("ignore") ppc_i = ext2int(ppc) p_bus_not_nan = ~np.isnan(ppc_i["bus"][:, bs_cols + 2]) p_line_f_not_nan = ~np.isnan(ppc_i["branch"][:, br_cols + 4]) p_line_t_not_nan = ~np.isnan(ppc_i["branch"][:, br_cols + 6]) q_bus_not_nan = ~np.isnan(ppc_i["bus"][:, bs_cols + 4]) q_line_f_not_nan = ~np.isnan(ppc_i["branch"][:, br_cols + 8]) q_line_t_not_nan = ~np.isnan(ppc_i["branch"][:, br_cols + 10]) v_bus_not_nan = ~np.isnan(ppc_i["bus"][:, bs_cols + 0]) i_line_f_not_nan = ~np.isnan(ppc_i["branch"][:, br_cols + 0]) i_line_t_not_nan = ~np.isnan(ppc_i["branch"][:, br_cols + 2]) # piece together our measurement vector z z = np.concatenate( (ppc_i["bus"][p_bus_not_nan, bs_cols + 2], ppc_i["branch"][p_line_f_not_nan, br_cols + 4], ppc_i["branch"][p_line_t_not_nan, br_cols + 6], ppc_i["bus"][q_bus_not_nan, bs_cols + 4], ppc_i["branch"][q_line_f_not_nan, br_cols + 8], ppc_i["branch"][q_line_t_not_nan, br_cols + 10], ppc_i["bus"][v_bus_not_nan, bs_cols + 0], ppc_i["branch"][i_line_f_not_nan, br_cols + 0], ppc_i["branch"][i_line_t_not_nan, br_cols + 2])).real.astype(np.float64) # number of nodes n_active = len(np.where(ppc_i["bus"][:, 1] != 4)[0]) slack_buses = np.where(ppc_i["bus"][:, 1] == 3)[0] # Check if observability criterion is fulfilled and the state estimation is possible if len(z) < 2 * n_active - 1: self.logger.error("System is not observable (cancelling)") self.logger.error( "Measurements available: %d. Measurements required: %d" % (len(z), 2 * n_active - 1)) return False # Set the starting values for all active buses v_m = ppc_i["bus"][:, 7] delta = ppc_i["bus"][:, 8] * np.pi / 180 # convert to rad delta_masked = np.ma.array(delta, mask=False) delta_masked.mask[slack_buses] = True non_slack_buses = np.arange(len(delta))[~delta_masked.mask] # Matrix calculation object sem = wls_matrix_ops(ppc_i, slack_buses, non_slack_buses, self.s_ref, bs_cols, br_cols) # state vector E = np.concatenate((delta_masked.compressed(), v_m)) # Covariance matrix R r_cov = np.concatenate( (ppc_i["bus"][p_bus_not_nan, bs_cols + 3], ppc_i["branch"][p_line_f_not_nan, br_cols + 5], ppc_i["branch"][p_line_t_not_nan, br_cols + 7], ppc_i["bus"][q_bus_not_nan, bs_cols + 5], ppc_i["branch"][q_line_f_not_nan, br_cols + 9], ppc_i["branch"][q_line_t_not_nan, br_cols + 11], ppc_i["bus"][v_bus_not_nan, bs_cols + 1], ppc_i["branch"][i_line_f_not_nan, br_cols + 1], ppc_i["branch"][i_line_t_not_nan, br_cols + 3])).real.astype(np.float64) r_inv = csr_matrix(np.linalg.inv(np.diagflat(r_cov)**2)) current_error = 100 current_iterations = 0 while current_error > self.tolerance and current_iterations < self.max_iterations: self.logger.debug(" Starting iteration %d" % (1 + current_iterations)) try: # create h(x) for the current iteration h_x = sem.create_hx(v_m, delta) # Residual r r = csr_matrix(z - h_x).T # Jacobian matrix H H = csr_matrix(sem.create_jacobian(v_m, delta)) # if not np.linalg.cond(H) < 1 / sys.float_info.epsilon: # self.logger.error("Error in matrix H") # Gain matrix G_m # G_m = H^t * R^-1 * H G_m = H.T * (r_inv * H) # State Vector difference d_E # d_E = G_m^-1 * (H' * R^-1 * r) d_E = spsolve(G_m, H.T * (r_inv * r)) E += d_E # Update V/delta delta[non_slack_buses] = E[:len(non_slack_buses)] v_m = np.squeeze(E[len(non_slack_buses):]) current_iterations += 1 current_error = np.max(np.abs(d_E)) self.logger.debug("Current error: %.4f" % current_error) except np.linalg.linalg.LinAlgError: self.logger.error( "A problem appeared while using the linear algebra methods." "Check and change the measurement set.") return False # Print output for results if current_error <= self.tolerance: successful = True self.logger.info( "WLS State Estimation successful (%d iterations)" % current_iterations) else: successful = False self.logger.info( "WLS State Estimation not successful (%d/%d iterations" % (current_iterations, self.max_iterations)) # write voltage into ppc ppc_i["bus"][:, 7] = v_m ppc_i["bus"][:, 8] = delta * 180 / np.pi # convert to degree # calculate bus powers v_cpx = v_m * np.exp(1j * delta) bus_powers_conj = np.zeros(len(v_cpx), dtype=np.complex128) for i in range(len(v_cpx)): bus_powers_conj[i] = np.dot(sem.Y_bus[i, :], v_cpx) * np.conjugate( v_cpx[i]) ppc_i["bus"][:, 2] = bus_powers_conj.real # saved in per unit ppc_i["bus"][:, 3] = -bus_powers_conj.imag # saved in per unit # convert to pandapower indices with warnings.catch_warnings(): warnings.simplefilter("ignore") ppc = int2ext(ppc_i) _set_buses_out_of_service(ppc) # Store results, overwrite old results self.net.res_bus_est = pd.DataFrame( columns=["vm_pu", "va_degree", "p_kw", "q_kvar"], index=self.net.bus.index) self.net.res_line_est = pd.DataFrame(columns=[ "p_from_kw", "q_from_kvar", "p_to_kw", "q_to_kvar", "pl_kw", "ql_kvar", "i_from_ka", "i_to_ka", "i_ka", "loading_percent" ], index=self.net.line.index) bus_idx = mapping_table[self.net["bus"].index.values] self.net["res_bus_est"]["vm_pu"] = ppc["bus"][bus_idx][:, 7] self.net["res_bus_est"]["va_degree"] = ppc["bus"][bus_idx][:, 8] self.net.res_bus_est.p_kw = -get_values( ppc["bus"][:, 2], self.net.bus.index, mapping_table) * self.s_ref / 1e3 self.net.res_bus_est.q_kvar = -get_values( ppc["bus"][:, 3], self.net.bus.index, mapping_table) * self.s_ref / 1e3 self.net.res_line_est = calculate_line_results(self.net, use_res_bus_est=True) # Store some variables required for Chi^2 and r_N_max test: self.R_inv = r_inv.toarray() self.Gm = G_m.toarray() self.r = r.toarray() self.H = H.toarray() self.Ht = self.H.T self.hx = h_x self.V = v_m self.delta = delta return successful
def estimate(self, v_start=None, delta_start=None, calculate_voltage_angles=True): """ The function estimate is the main function of the module. It takes up to three input arguments: v_start, delta_start and calculate_voltage_angles. The first two are the initial state variables for the estimation process. Usually they can be initialized in a "flat-start" condition: All voltages being 1.0 pu and all voltage angles being 0 degrees. In this case, the parameters can be left at their default values (None). If the estimation is applied continuously, using the results from the last estimation as the starting condition for the current estimation can decrease the amount of iterations needed to estimate the current state. The third parameter defines whether all voltage angles are calculated absolutely, including phase shifts from transformers. If only the relative differences between buses are required, this parameter can be set to False. Returned is a boolean value, which is true after a successful estimation and false otherwise. The resulting complex voltage will be written into the pandapower network. The result fields are found res_bus_est of the pandapower network. INPUT: **net** - The net within this line should be created **v_start** (np.array, shape=(1,), optional) - Vector with initial values for all voltage magnitudes in p.u. (sorted by bus index) **delta_start** (np.array, shape=(1,), optional) - Vector with initial values for all voltage angles in degrees (sorted by bus index) OPTIONAL: **calculate_voltage_angles** - (bool) - Take into account absolute voltage angles and phase shifts in transformers Default is True. OUTPUT: **successful** (boolean) - True if the estimation process was successful Optional estimation variables: The bus power injections can be accessed with *se.s_node_powers* and the estimated values corresponding to the (noisy) measurement values with *se.hx*. (*hx* denotes h(x)) EXAMPLE: success = estimate(np.array([1.0, 1.0, 1.0]), np.array([0.0, 0.0, 0.0])) """ if self.net is None: raise UserWarning("Component was not initialized with a network.") t0 = time() # add initial values for V and delta # node voltages # V<delta if v_start is None: v_start = np.ones(self.net.bus.shape[0]) if delta_start is None: delta_start = np.zeros(self.net.bus.shape[0]) # initialize result tables if not existent _copy_power_flow_results(self.net) # initialize ppc ppc, ppci = _init_ppc(self.net, v_start, delta_start, calculate_voltage_angles) # add measurements to ppci structure ppci = _add_measurements_to_ppc(self.net, ppci, self.s_ref) # calculate relevant vectors from ppci measurements z, self.pp_meas_indices, r_cov = _build_measurement_vectors(ppci) # number of nodes n_active = len(np.where(ppci["bus"][:, 1] != 4)[0]) slack_buses = np.where(ppci["bus"][:, 1] == 3)[0] # Check if observability criterion is fulfilled and the state estimation is possible if len(z) < 2 * n_active - 1: self.logger.error("System is not observable (cancelling)") self.logger.error( "Measurements available: %d. Measurements required: %d" % (len(z), 2 * n_active - 1)) return False # set the starting values for all active buses v_m = ppci["bus"][:, 7] delta = ppci["bus"][:, 8] * np.pi / 180 # convert to rad delta_masked = np.ma.array(delta, mask=False) delta_masked.mask[slack_buses] = True non_slack_buses = np.arange(len(delta))[~delta_masked.mask] # matrix calculation object sem = wls_matrix_ops(ppci, slack_buses, non_slack_buses, self.s_ref) # state vector E = np.concatenate((delta_masked.compressed(), v_m)) # invert covariance matrix r_inv = csr_matrix(np.linalg.inv(np.diagflat(r_cov)**2)) current_error = 100. cur_it = 0 G_m, r, H, h_x = None, None, None, None while current_error > self.tolerance and cur_it < self.max_iterations: self.logger.debug(" Starting iteration %d" % (1 + cur_it)) try: # create h(x) for the current iteration h_x = sem.create_hx(v_m, delta) # residual r r = csr_matrix(z - h_x).T # jacobian matrix H H = csr_matrix(sem.create_jacobian(v_m, delta)) # gain matrix G_m # G_m = H^t * R^-1 * H G_m = H.T * (r_inv * H) # state vector difference d_E # d_E = G_m^-1 * (H' * R^-1 * r) d_E = spsolve(G_m, H.T * (r_inv * r)) E += d_E # update V/delta delta[non_slack_buses] = E[:len(non_slack_buses)] v_m = np.squeeze(E[len(non_slack_buses):]) # prepare next iteration cur_it += 1 current_error = np.max(np.abs(d_E)) self.logger.debug("Current error: %.7f" % current_error) except np.linalg.linalg.LinAlgError: self.logger.error( "A problem appeared while using the linear algebra methods." "Check and change the measurement set.") return False # print output for results if current_error <= self.tolerance: successful = True self.logger.debug( "WLS State Estimation successful (%d iterations)" % cur_it) else: successful = False self.logger.debug( "WLS State Estimation not successful (%d/%d iterations)" % (cur_it, self.max_iterations)) # store results for all elements # calculate bus power injections v_cpx = v_m * np.exp(1j * delta) bus_powers_conj = np.zeros(len(v_cpx), dtype=np.complex128) for i in range(len(v_cpx)): bus_powers_conj[i] = np.dot(sem.Y_bus[i, :], v_cpx) * np.conjugate( v_cpx[i]) ppci["bus"][:, 2] = bus_powers_conj.real # saved in per unit ppci["bus"][:, 3] = -bus_powers_conj.imag # saved in per unit ppci["bus"][:, 7] = v_m ppci["bus"][:, 8] = delta * 180 / np.pi # convert to degree # calculate line results (in ppc_i) s_ref, bus, gen, branch = _get_pf_variables_from_ppci(ppci)[0:4] out = np.flatnonzero(branch[:, BR_STATUS] == 0) # out-of-service branches br = np.flatnonzero(branch[:, BR_STATUS]).astype( int) # in-service branches # complex power at "from" bus Sf = v_cpx[np.real(branch[br, F_BUS]).astype(int)] * np.conj( sem.Yf[br, :] * v_cpx) * s_ref # complex power injected at "to" bus St = v_cpx[np.real(branch[br, T_BUS]).astype(int)] * np.conj( sem.Yt[br, :] * v_cpx) * s_ref branch[np.ix_(br, [PF, QF, PT, QT])] = np.c_[Sf.real, Sf.imag, St.real, St.imag] branch[np.ix_(out, [PF, QF, PT, QT])] = np.zeros((len(out), 4)) et = time() - t0 ppci = _store_results_from_pf_in_ppci(ppci, bus, gen, branch, successful, cur_it, et) # convert to pandapower indices ppc = _copy_results_ppci_to_ppc(ppci, ppc, mode="se") # extract results from ppc _add_pf_options(self.net, tolerance_kva=1e-5, trafo_loading="current", numba=True, ac=True, algorithm='nr', max_iteration="auto") # writes res_bus.vm_pu / va_degree and res_line _extract_results_se(self.net, ppc) # restore backup of previous results _rename_results(self.net) # additionally, write bus power injection results (these are not written in _extract_results) mapping_table = self.net["_pd2ppc_lookups"]["bus"] self.net.res_bus_est.p_kw = -get_values( ppc["bus"][:, 2], self.net.bus.index.values, mapping_table) * self.s_ref / 1e3 self.net.res_bus_est.q_kvar = -get_values( ppc["bus"][:, 3], self.net.bus.index.values, mapping_table) * self.s_ref / 1e3 # store variables required for chi^2 and r_N_max test: self.R_inv = r_inv.toarray() self.Gm = G_m.toarray() self.r = r.toarray() self.H = H.toarray() self.Ht = self.H.T self.hx = h_x self.V = v_m self.delta = delta # delete results which are not correctly calculated for k in list(self.net.keys()): if k.startswith("res_") and k.endswith("_est") and \ k not in ("res_bus_est", "res_line_est", "res_trafo_est", "res_trafo3w_est"): del self.net[k] return successful