def _calculate(self): logger.info("Calculating PTDF Matrix") self._calculate_ptdf() self._calculate_phi_adjust() self._calculate_phi_loss_constant() self._calculate_phase_shift() self._calculate_losses_phase_shift()
def add_violations(gt_viol_lazy, lt_viol_lazy, PFV, mb, md, solver, ptdf_options, PTDF, time=None): model = mb.model() baseMVA = md.data['system']['baseMVA'] persistent_solver = isinstance(solver, PersistentSolver) ## static information between runs rel_ptdf_tol = ptdf_options['rel_ptdf_tol'] abs_ptdf_tol = ptdf_options['abs_ptdf_tol'] ## helper for generating pf def _iter_over_viol_set(viol_set): for i in viol_set: bn = PTDF.branches_keys[i] if mb.pf[bn].expr is None: expr = libbranch.get_power_flow_expr_ptdf_approx( mb, bn, PTDF, abs_ptdf_tol=abs_ptdf_tol, rel_ptdf_tol=rel_ptdf_tol) mb.pf[bn] = expr yield i, bn constr = mb.ineq_pf_branch_thermal_lb lt_viol_in_mb = mb._lt_idx_monitored for i, bn in _iter_over_viol_set(lt_viol_lazy): thermal_limit = PTDF.branch_limits_array[i] logger.info( _generate_flow_monitor_message('LB', bn, PFV[i], -thermal_limit, baseMVA, time)) constr[bn] = (-thermal_limit, mb.pf[bn], None) lt_viol_in_mb.append(i) if persistent_solver: solver.add_constraint(constr[bn]) constr = mb.ineq_pf_branch_thermal_ub gt_viol_in_mb = mb._gt_idx_monitored for i, bn in _iter_over_viol_set(gt_viol_lazy): thermal_limit = PTDF.branch_limits_array[i] logger.info( _generate_flow_monitor_message('UB', bn, PFV[i], thermal_limit, baseMVA, time)) constr[bn] = (None, mb.pf[bn], thermal_limit) gt_viol_in_mb.append(i) if persistent_solver: solver.add_constraint(constr[bn])
def _calculate_total_and_monitored_violations( self, viol_array, viol_lazy_idx, monitored_indices, flow_variable, flow_array, index_names, limits, name, outer_name, other_flows): ## viol_idx_idx will be indexed by viol_lazy_idx viol_idx_idx = np.nonzero(viol_array > 0)[0] viol_idx = frozenset(viol_lazy_idx[viol_idx_idx]) self.total_violations += len(viol_idx) viol_in_mb = viol_idx.intersection(monitored_indices) self.monitored_violations += len(viol_in_mb) for i in viol_in_mb: element_name = index_names[i] thermal_limit = limits[i] flow = flow_array[i] if outer_name: element_name = (outer_name, element_name) thermal_limit += other_flows[i] flow += other_flows[i] logger.info(self.prepend_str + _generate_flow_viol_warning( flow_variable, name, element_name, flow, thermal_limit, self.baseMVA, self.time)) ## useful debugging code if logger.level <= logging.DEBUG: for i in monitored_indices: element_name = index_names[i] thermal_limit = limits[i] flow = flow_array[i] if outer_name: element_name = (outer_name, element_name) thermal_limit += other_flows[i] flow += other_flows[i] print( f'contingency: {element_name[0]}, branch: {element_name[1]}' ) print(f'delta: {flow_array[i]}') print(f'base : {other_flows[i]}') print(f'flow : {flow_array[i]+other_flows[i]}') print(f'model: {pyo.value(flow_variable[element_name])}') if not math.isclose(pyo.value(flow_variable[element_name]), flow_array[i] + other_flows[i]): print( f'contingency: {element_name[0]}, branch_idx: {i}') diff = pyo.value(flow_variable[element_name]) - ( flow_array[i] + other_flows[i]) print(f'ABSOLUTE DIFFERENCE: { abs(diff) }') flow_variable[element_name].pprint() raise Exception() print('') else: print(f'{name}: {element_name}') print(f'flow : {flow_array[i]}') print(f'model: {pyo.value(flow_variable[element_name])}') print('')
def _calculate_ptdf_factorization(self): logger.info("Calculating PTDF Matrix Factorization") MLU, B_dA, ref_bus_mask, contingency_compensators, B_dA_I, I = \ tx_calc.calculate_ptdf_factorization(self._branches, self._buses,self.branches_keys, self.buses_keys, self._reference_bus, self._base_point, contingencies=self.contingencies, mapping_bus_to_idx=self._busname_to_index_map, mapping_branch_to_idx=self._branchname_to_index_map, interfaces = self.interfaces, index_set_interface = self.interface_keys,) self.MLU = MLU self.B_dA = B_dA self.ref_bus_mask = ref_bus_mask self.contingency_compensators = contingency_compensators self.B_dA_I = B_dA_I self._calculate_phase_shift_flow_adjuster() self._calculate_phi_adjust(ref_bus_mask) self.phase_shift_flow_adjuster_array_interface = I @ self.phase_shift_flow_adjuster_array
def _lazy_ptdf_dcopf_model_solve_loop(m, md, solver, solver_tee=True, symbolic_solver_labels=False, iteration_limit=100000): ''' The lazy PTDF DCOPF solver loop. This function iteratively adds violated transmission constraints until either the result is transmission feasible or we're tracking every violated constraint in the model Parameters ---------- m : pyomo.environ.ConcreteModel An egret DCOPF model with no transmission constraints md : egret.data.ModelData An egret ModelData object solver : pyomo.opt.solver A pyomo solver object solver_tee : bool (optional) For displaying the solver log (default is True) symbolic_solver_labels : bool (optional) Use symbolic solver labels when writing to the solver (default is False) iteration_limit : int (optional) Number of iterations before a hard termination (default is 100000) Returns ------- egret.common.lazy_ptdf_utils.LazyPTDFTerminationCondition : the termination status pyomo.opt.results.SolverResults : The results object from the pyomo solver int : The number of iterations before termination ''' from pyomo.solvers.plugins.solvers.persistent_solver import PersistentSolver PTDF = m._PTDF ptdf_options = m._ptdf_options persistent_solver = isinstance(solver, PersistentSolver) for i in range(iteration_limit): PFV, PFV_I, viol_num, mon_viol_num, viol_lazy, int_viol_lazy \ = lpu.check_violations(m, md, PTDF, ptdf_options['max_violations_per_iteration']) iter_status_str = "iteration {0}, found {1} violation(s)".format( i, viol_num) if mon_viol_num: iter_status_str += ", {} of which are already monitored".format( mon_viol_num) logger.info(iter_status_str) if viol_num <= 0: ## in this case, there are no violations! ## load the duals now too, if we're using a persistent solver if persistent_solver: solver.load_duals() return lpu.LazyPTDFTerminationCondition.NORMAL elif viol_num == mon_viol_num: logger.warning( 'WARNING: Terminating with monitored violations! Result is not transmission feasible.' ) if persistent_solver: solver.load_duals() return lpu.LazyPTDFTerminationCondition.FLOW_VIOLATION lpu.add_violations(viol_lazy, int_viol_lazy, PFV, PFV_I, m, md, solver, ptdf_options, PTDF) total_flow_constr_added = len(viol_lazy) + len(int_viol_lazy) logger.info("iteration {0}, added {1} flow constraint(s)".format( i, total_flow_constr_added)) if persistent_solver: solver.solve(m, tee=solver_tee, load_solutions=False, save_results=False) solver.load_vars() else: solver.solve(m, tee=solver_tee, symbolic_solver_labels=symbolic_solver_labels) else: # we hit the iteration limit logger.warning( 'WARNING: Exiting on maximum iterations for lazy PTDF model. Result is not transmission feasible.' ) if persistent_solver: solver.load_duals() return lpu.LazyPTDFTerminationCondition.ITERATION_LIMIT