POSTPROC_MAXLOADLIM Performs some post processing on the results returned by the ACOPF run in MATPOWER. RESULTS = POSTPROC_MAXLOADLIM(RESULTS,DIR_MLL) transforms the dispatchable loads back to normal loads and parse the results in the struct RESULTS to provide contextual information on the maximum loadability point found in the direction of load increase defined by DIR_MLL. It returns the updated struct RESULTS.
0001 function results = postproc_maxloadlim(results,dir_mll) 0002 % POSTPROC_MAXLOADLIM Performs some post processing on the results returned 0003 % by the ACOPF run in MATPOWER. 0004 % RESULTS = POSTPROC_MAXLOADLIM(RESULTS,DIR_MLL) transforms the dispatchable 0005 % loads back to normal loads and parse the results in the struct RESULTS 0006 % to provide contextual information on the maximum loadability point 0007 % found in the direction of load increase defined by DIR_MLL. It returns 0008 % the updated struct RESULTS. 0009 0010 % MATPOWER 0011 % Copyright (c) 2015-2016, Power Systems Engineering Research Center (PSERC) 0012 % by Camille Hamon 0013 % 0014 % This file is part of MATPOWER/mx-maxloadlim. 0015 % Covered by the 3-clause BSD License (see LICENSE file for details). 0016 % See https://github.com/MATPOWER/mx-maxloadlim/ for more info. 0017 0018 define_constants; 0019 0020 % Transforming the dispatchable gen back to loads 0021 idx_gen_load_disp = isload(results.gen); 0022 idx_bus_load_disp = results.gen(idx_gen_load_disp,GEN_BUS); 0023 results.bus(idx_bus_load_disp ,[PD QD]) = -results.gen(idx_gen_load_disp,[PG QG]); 0024 results.gen(idx_gen_load_disp,:) = []; 0025 results.gencost(idx_gen_load_disp,:) = []; 0026 % Removing the shadow prices corresponding to dispatchable loads 0027 results.var.mu.u.Pg(idx_gen_load_disp) = []; 0028 results.var.mu.l.Pg(idx_gen_load_disp) = []; 0029 results.var.mu.u.Qg(idx_gen_load_disp) = []; 0030 results.var.mu.l.Qg(idx_gen_load_disp) = []; 0031 % If all gens at bus have non zero reactive power shadow prices, this bus 0032 % is PQ 0033 for bb = 1:size(results.bus,1) 0034 gen_list_at_bb = results.gen(:,GEN_BUS) == bb; 0035 if all(results.var.mu.u.Qg(gen_list_at_bb)>0) 0036 results.bus(bb,BUS_TYPE) = PQ; 0037 end 0038 end 0039 0040 % Create a new field for the stability margin in load increase 0041 results.stab_marg = results.var.val.alpha; 0042 % Create a new field for the stability margin in gen change 0043 if isfield(results.var.val,'beta') 0044 results.gen_stab_marg = results.var.val.beta; 0045 end 0046 0047 % Remove the cost for the printpf function to consider the results as load 0048 % flow results. 0049 results.f = []; 0050 % Direction defined over all buses (not only over nonzero loads) 0051 results.dir_mll = dir_mll; 0052 0053 % Determining the type of bifurcation (SNB or SLL) 0054 % SLL is characterized by having both reactive power limit and voltage 0055 % limit binding at one generator 0056 shadow_price_Qg = results.var.mu.u.Qg; 0057 shadow_price_Vm = results.var.mu.u.Vm; 0058 % Map the shadow price of bus voltage magnitude to generators 0059 shadow_price_Vg = shadow_price_Vm(results.gen(:,GEN_BUS)); 0060 idx_bus_sll = shadow_price_Qg & shadow_price_Vg; 0061 if sum(idx_bus_sll) > 0 0062 results.bif.short_name = 'LIB'; 0063 results.bif.full_name = 'limit-induced bifurcation'; 0064 results.bif.gen_sll = find(idx_bus_sll); 0065 else 0066 results.bif.short_name = 'SNB'; 0067 results.bif.full_name = 'saddle-node bifurcation'; 0068 end 0069 % Building the sets of gens that reached their Q lims and of gens that did 0070 % not 0071 gen_a = shadow_price_Vm(results.gen(:,GEN_BUS))~= 0; 0072 gen_b = shadow_price_Qg ~= 0; 0073 results.bif.gen_a = gen_a; 0074 results.bif.gen_b = gen_b;