def control_step(self, net): """ Implements one step of the Discrete controller, always stepping only one tap position up or down """ if self.nothing_to_do(net): return vm_pu = read_from_net(net, "res_bus", self.controlled_bus, "vm_pu", self._read_write_flag) self.tap_pos = read_from_net(net, self.trafotable, self.controlled_tid, "tap_pos", self._read_write_flag) increment = np.where( self.tap_side_coeff * self.tap_sign == 1, np.where( np.logical_and(vm_pu < self.vm_lower_pu, self.tap_pos > self.tap_min), -1, np.where( np.logical_and(vm_pu > self.vm_upper_pu, self.tap_pos < self.tap_max), 1, 0)), np.where( np.logical_and(vm_pu < self.vm_lower_pu, self.tap_pos < self.tap_max), 1, np.where( np.logical_and(vm_pu > self.vm_upper_pu, self.tap_pos > self.tap_min), -1, 0))) self.tap_pos += increment # WRITE TO NET write_to_net(net, self.trafotable, self.controlled_tid, 'tap_pos', self.tap_pos, self._read_write_flag)
def is_converged(self, net): """ The ContinuousTapControl is converged, when the difference of the voltage between control steps is smaller than the Tolerance (tol). """ if self.nothing_to_do(net): return True vm_pu = read_from_net(net, "res_bus", self.controlled_bus, "vm_pu", self._read_write_flag) self.tap_pos = read_from_net(net, self.trafotable, self.controlled_tid, "tap_pos", self._read_write_flag) difference = 1 - self.vm_set_pu / vm_pu if self.check_tap_bounds: reached_limit = np.where( self.tap_side_coeff * self.tap_sign == 1, (vm_pu < self.vm_set_pu) & (self.tap_pos == self.tap_min) | (vm_pu > self.vm_set_pu) & (self.tap_pos == self.tap_max), (vm_pu < self.vm_set_pu) & (self.tap_pos == self.tap_max) | (vm_pu > self.vm_set_pu) & (self.tap_pos == self.tap_min)) converged = np.logical_or(reached_limit, np.abs(difference) < self.tol) else: converged = np.abs(difference) < self.tol return np.all(converged)
def is_converged(self, net): """ Actual implementation of the convergence criteria: If controller is applied, it can stop """ # read input values input_values = read_from_net(net, self.input_element, self.input_element_index, self.input_variable, self.read_flag) # calculate set values self.values = net.characteristic.object.at[self.characteristic_index]( input_values) # read previous set values output_values = read_from_net(net, self.output_element, self.output_element_index, self.output_variable, self.write_flag) # compare old and new set values diff = self.values - output_values # write new set values write_to_net(net, self.output_element, self.output_element_index, self.output_variable, self.values, self.write_flag) return self.applied and np.all(np.abs(diff) < self.tol)
def _set_valid_tid_controlled_bus(self, net): self.trafobus = read_from_net(net, self.trafotable, self.tid, self.side + '_bus', self._read_write_flag) element_in_service = read_from_net(net, self.trafotable, self.tid, 'in_service', self._read_write_flag) ext_grid_bus = np.isin( self.trafobus, net.ext_grid.loc[net.ext_grid.in_service, 'bus'].values) tid_in_net = np.isin(self.tid, net[self.trafotable].index.values) controlled = np.logical_and( np.logical_and(element_in_service, tid_in_net), np.logical_not(ext_grid_bus)) if self._read_write_flag == 'single_index': self.controlled_tid = self.tid if controlled else None self.controlled_bus = self.trafobus if controlled else None else: self.controlled_tid = self.tid[controlled] self.controlled_bus = self.trafobus[controlled] if np.all(~controlled): logger.warning( "All controlled buses are not valid: controller has no effect")
def is_converged(self, net): """ Checks if the voltage is within the desired voltage band, then returns True """ if self.nothing_to_do(net): return True vm_pu = read_from_net(net, "res_bus", self.controlled_bus, "vm_pu", self._read_write_flag) self.tap_pos = read_from_net(net, self.trafotable, self.controlled_tid, "tap_pos", self._read_write_flag) reached_limit = np.where( self.tap_side_coeff * self.tap_sign == 1, (vm_pu < self.vm_lower_pu) & (self.tap_pos == self.tap_min) | (vm_pu > self.vm_upper_pu) & (self.tap_pos == self.tap_max), (vm_pu < self.vm_lower_pu) & (self.tap_pos == self.tap_max) | (vm_pu > self.vm_upper_pu) & (self.tap_pos == self.tap_min)) converged = np.logical_or( reached_limit, np.logical_and(self.vm_lower_pu < vm_pu, vm_pu < self.vm_upper_pu)) return np.all(converged)
def _set_tap_side_coeff(self, net): tap_side = read_from_net(net, self.trafotable, self.controlled_tid, 'tap_side', self._read_write_flag) if (len(np.setdiff1d(tap_side, ['hv', 'lv'])) > 0 and self.trafotype == "2W") or \ (len(np.setdiff1d(tap_side, ['hv', 'lv', 'mv'])) > 0 and self.trafotype == "3W"): raise ValueError( "Trafo tap side (in net.%s) has to be either hv or lv, " "but received: %s for trafo %s" % (self.trafotable, tap_side, self.controlled_tid)) if self._read_write_flag == "single_index": self.tap_side_coeff = 1 if tap_side == 'hv' else -1 if self.tap_step_percent < 0: self.tap_side_coeff *= -1 else: self.tap_side_coeff = np.where(tap_side == 'hv', 1, -1) self.tap_side_coeff[self.tap_step_percent < 0] *= -1
def _set_t_nom(self, net): vn_hv_kv = read_from_net(net, self.trafotable, self.controlled_tid, 'vn_hv_kv', self._read_write_flag) hv_bus = read_from_net(net, self.trafotable, self.controlled_tid, 'hv_bus', self._read_write_flag) vn_hv_bus_kv = read_from_net(net, "bus", hv_bus, 'vn_kv', self._read_write_flag) if self.trafotype == "3W" and self.side == "mv": vn_mv_kv = read_from_net(net, self.trafotable, self.controlled_tid, 'vn_mv_kv', self._read_write_flag) mv_bus = read_from_net(net, self.trafotable, self.controlled_tid, 'mv_bus', self._read_write_flag) vn_mv_bus_kv = read_from_net(net, "bus", mv_bus, 'vn_kv', self._read_write_flag) self.t_nom = vn_mv_kv / vn_hv_kv * vn_hv_bus_kv / vn_mv_bus_kv else: vn_lv_kv = read_from_net(net, self.trafotable, self.controlled_tid, 'vn_lv_kv', self._read_write_flag) lv_bus = read_from_net(net, self.trafotable, self.controlled_tid, 'lv_bus', self._read_write_flag) vn_lv_bus_kv = read_from_net(net, "bus", lv_bus, 'vn_kv', self._read_write_flag) self.t_nom = vn_lv_kv / vn_hv_kv * vn_hv_bus_kv / vn_lv_bus_kv
def control_step(self, net): """ Implements one step of the ContinuousTapControl """ if self.nothing_to_do(net): return delta_vm_pu = read_from_net(net, "res_bus", self.controlled_bus, 'vm_pu', self._read_write_flag) - self.vm_set_pu tc = delta_vm_pu / self.tap_step_percent * 100 / self.t_nom self.tap_pos = self.tap_pos + tc * self.tap_side_coeff * self.tap_sign if self.check_tap_bounds: self.tap_pos = np.clip(self.tap_pos, self.tap_min, self.tap_max) # WRITE TO NET # necessary in case the dtype of the column is int if net[self.trafotable].tap_pos.dtype != "float": net[self.trafotable].tap_pos = net[self.trafotable].tap_pos.astype( float) write_to_net(net, self.trafotable, self.controlled_tid, "tap_pos", self.tap_pos, self._read_write_flag)
def _set_tap_parameters(self, net): self.tap_min = read_from_net(net, self.trafotable, self.controlled_tid, "tap_min", self._read_write_flag) self.tap_max = read_from_net(net, self.trafotable, self.controlled_tid, "tap_max", self._read_write_flag) self.tap_neutral = read_from_net(net, self.trafotable, self.controlled_tid, "tap_neutral", self._read_write_flag) self.tap_step_percent = read_from_net(net, self.trafotable, self.controlled_tid, "tap_step_percent", self._read_write_flag) self.tap_step_degree = read_from_net(net, self.trafotable, self.controlled_tid, "tap_step_degree", self._read_write_flag) self.tap_pos = read_from_net(net, self.trafotable, self.controlled_tid, "tap_pos", self._read_write_flag) if self._read_write_flag == "single_index": self.tap_sign = 1 if np.isnan(self.tap_step_degree) else np.sign( np.cos(np.deg2rad(self.tap_step_degree))) if (self.tap_sign == 0) | (np.isnan(self.tap_sign)): self.tap_sign = 1 if np.isnan(self.tap_pos): self.tap_pos = self.tap_neutral else: self.tap_sign = np.where( np.isnan(self.tap_step_degree), 1, np.sign(np.cos(np.deg2rad(self.tap_step_degree)))) self.tap_sign = np.where( (self.tap_sign == 0) | (np.isnan(self.tap_sign)), 1, self.tap_sign) self.tap_pos = np.where(np.isnan(self.tap_pos), self.tap_neutral, self.tap_pos) if np.any(np.isnan(self.tap_min)) or np.any(np.isnan( self.tap_max)) or np.any(np.isnan(self.tap_step_percent)): logger.error( "Trafo-Controller has been initialized with NaN values, check " "net.trafo.tap_pos etc. if they are set correctly!")