CPF_DEFAULT_CALLBACK Default callback function for CPF [NX, CX, DONE, ROLLBACK, EVNTS, CB_DATA, RESULTS] = CPF_DEFAULT_CALLBACK(K, NX, CX, PX, DONE, ROLLBACK, EVNTS, ... CB_DATA, CB_ARGS, RESULTS) Default callback function used by RUNCPF that collects the resulst and optionally, plots the nose curve. Inputs and outputs are defined below, with the RESULTS argument being optional, used only for the final call when K is negative. Inputs: K - continuation step iteration count NX - next state (corresponding to proposed next step), struct with the following fields: lam_hat - value of LAMBDA from predictor V_hat - vector of complex bus voltages from predictor lam - value of LAMBDA from corrector V - vector of complex bus voltages from corrector z - normalized tangent predictor default_step - default step size default_parm - default parameterization this_step - step size for this step only this_parm - paramterization for this step only step - current step size parm - current parameterization events - struct array, event log cb - user state, for callbacks (replaces CB_STATE), the user may add fields containing any information the callback function would like to pass from one invokation to the next, taking care not to step on fields being used by other callbacks, such as the 'default' field used by this default callback ef - cell array of event function values CX - current state (corresponding to most recent successful step) (same structure as NX) PX - previous state (corresponding to last successful step prior to CX) DONE - struct, with flag to indicate CPF termination and reason, with fields: flag - termination flag, 1 => terminate, 0 => continue msg - string containing reason for termination ROLLBACK - scalar flag to indicate that the current step should be rolled back and retried with a different step size, etc. EVNTS - struct array listing any events detected for this step, see CPF_DETECT_EVENTS for details CB_DATA - struct containing potentially useful "static" data, with the following fields (all based on internal indexing): mpc_base - MATPOWER case struct of base state mpc_target - MATPOWER case struct of target state Sbusb - handle of function returning nb x 1 vector of complex base case injections in p.u. and derivatives w.r.t. |V| Sbust - handle of function returning nb x 1 vector of complex target case injections in p.u. and derivatives w.r.t. |V| Ybus - bus admittance matrix Yf - branch admittance matrix, "from" end of branches Yt - branch admittance matrix, "to" end of branches pv - vector of indices of PV buses pq - vector of indices of PQ buses ref - vector of indices of REF buses idx_pmax - vector of generator indices for generators fixed at their PMAX limits mpopt - MATPOWER options struct CB_ARGS - arbitrary data structure containing callback arguments RESULTS - initial value of output struct to be assigned to CPF field of results struct returned by RUNCPF Outputs: (all are updated versions of the corresponding input arguments) NX - user state ('cb' field ) should be updated here if ROLLBACK is false CX - may contain updated 'this_step' or 'this_parm' values to be used if ROLLBACK is true DONE - callback may have requested termination and set the msg field ROLLBACK - callback can request a rollback step, even if it was not indicated by an event function EVNTS - msg field for a given event may be updated CB_DATA - this data should only be modified if the underlying problem has been changed (e.g. generator limit reached) and should always be followed by a step of zero length, i.e. set NX.this_step to 0 It is the job of any callback modifying CB_DATA to ensure that all data in CB_DATA is kept consistent. RESULTS - updated version of RESULTS input arg This function is called in three different contexts, distinguished by the value of K, as follows: (1) initial - called with K = 0, without RESULTS input/output args, after base power flow, before 1st CPF step. (2) iterations - called with K > 0, without RESULTS input/output args, at each iteration, after predictor-corrector step (3) final - called with K < 0, with RESULTS input/output args, after exiting predictor-corrector loop, inputs identical to last iteration call, except K which is negated User Defined CPF Callback Functions: The user can define their own callback functions which take the same form and are called in the same contexts as CPF_DEFAULT_CALLBACK. These are specified via the MATPOWER option 'cpf.user_callback'. This option can be a string containing the name of the callback function, or a struct with the following fields, where all but the first are optional: 'fcn' - string with name of callback function 'priority' - numerical value specifying callback priority (default = 20, see CPF_REGISTER_CALLBACK for details) 'args' - arbitrary value (any type) passed to the callback as CB_ARGS each time it is invoked Multiple user callbacks can be registered by assigning a cell array of such strings and/or structs to the 'cpf.user_callback' option. See also RUNCPF, CPF_REGISTER_CALLBACK.
0001 function [nx, cx, done, rollback, evnts, cb_data, results] = ... 0002 cpf_default_callback(k, nx, cx, px, done, rollback, evnts, ... 0003 cb_data, cb_args, results) 0004 %CPF_DEFAULT_CALLBACK Default callback function for CPF 0005 % [NX, CX, DONE, ROLLBACK, EVNTS, CB_DATA, RESULTS] = 0006 % CPF_DEFAULT_CALLBACK(K, NX, CX, PX, DONE, ROLLBACK, EVNTS, ... 0007 % CB_DATA, CB_ARGS, RESULTS) 0008 % 0009 % Default callback function used by RUNCPF that collects the resulst and 0010 % optionally, plots the nose curve. Inputs and outputs are defined below, 0011 % with the RESULTS argument being optional, used only for the final call 0012 % when K is negative. 0013 % 0014 % Inputs: 0015 % K - continuation step iteration count 0016 % NX - next state (corresponding to proposed next step), struct with 0017 % the following fields: 0018 % lam_hat - value of LAMBDA from predictor 0019 % V_hat - vector of complex bus voltages from predictor 0020 % lam - value of LAMBDA from corrector 0021 % V - vector of complex bus voltages from corrector 0022 % z - normalized tangent predictor 0023 % default_step - default step size 0024 % default_parm - default parameterization 0025 % this_step - step size for this step only 0026 % this_parm - paramterization for this step only 0027 % step - current step size 0028 % parm - current parameterization 0029 % events - struct array, event log 0030 % cb - user state, for callbacks (replaces CB_STATE), the user may 0031 % add fields containing any information the callback function 0032 % would like to pass from one invokation to the next, taking 0033 % care not to step on fields being used by other callbacks, 0034 % such as the 'default' field used by this default callback 0035 % ef - cell array of event function values 0036 % CX - current state (corresponding to most recent successful step) 0037 % (same structure as NX) 0038 % PX - previous state (corresponding to last successful step prior to CX) 0039 % DONE - struct, with flag to indicate CPF termination and reason, 0040 % with fields: 0041 % flag - termination flag, 1 => terminate, 0 => continue 0042 % msg - string containing reason for termination 0043 % ROLLBACK - scalar flag to indicate that the current step should be 0044 % rolled back and retried with a different step size, etc. 0045 % EVNTS - struct array listing any events detected for this step, 0046 % see CPF_DETECT_EVENTS for details 0047 % CB_DATA - struct containing potentially useful "static" data, 0048 % with the following fields (all based on internal indexing): 0049 % mpc_base - MATPOWER case struct of base state 0050 % mpc_target - MATPOWER case struct of target state 0051 % Sbusb - handle of function returning nb x 1 vector of complex 0052 % base case injections in p.u. and derivatives w.r.t. |V| 0053 % Sbust - handle of function returning nb x 1 vector of complex 0054 % target case injections in p.u. and derivatives w.r.t. |V| 0055 % Ybus - bus admittance matrix 0056 % Yf - branch admittance matrix, "from" end of branches 0057 % Yt - branch admittance matrix, "to" end of branches 0058 % pv - vector of indices of PV buses 0059 % pq - vector of indices of PQ buses 0060 % ref - vector of indices of REF buses 0061 % idx_pmax - vector of generator indices for generators fixed 0062 % at their PMAX limits 0063 % mpopt - MATPOWER options struct 0064 % CB_ARGS - arbitrary data structure containing callback arguments 0065 % RESULTS - initial value of output struct to be assigned to 0066 % CPF field of results struct returned by RUNCPF 0067 % 0068 % Outputs: 0069 % (all are updated versions of the corresponding input arguments) 0070 % NX - user state ('cb' field ) should be updated here if ROLLBACK 0071 % is false 0072 % CX - may contain updated 'this_step' or 'this_parm' values to be used 0073 % if ROLLBACK is true 0074 % DONE - callback may have requested termination and set the msg field 0075 % ROLLBACK - callback can request a rollback step, even if it was not 0076 % indicated by an event function 0077 % EVNTS - msg field for a given event may be updated 0078 % CB_DATA - this data should only be modified if the underlying problem 0079 % has been changed (e.g. generator limit reached) and should always 0080 % be followed by a step of zero length, i.e. set NX.this_step to 0 0081 % It is the job of any callback modifying CB_DATA to ensure that 0082 % all data in CB_DATA is kept consistent. 0083 % RESULTS - updated version of RESULTS input arg 0084 % 0085 % This function is called in three different contexts, distinguished by 0086 % the value of K, as follows: 0087 % (1) initial - called with K = 0, without RESULTS input/output args, 0088 % after base power flow, before 1st CPF step. 0089 % (2) iterations - called with K > 0, without RESULTS input/output args, 0090 % at each iteration, after predictor-corrector step 0091 % (3) final - called with K < 0, with RESULTS input/output args, after 0092 % exiting predictor-corrector loop, inputs identical to last 0093 % iteration call, except K which is negated 0094 % 0095 % User Defined CPF Callback Functions: 0096 % The user can define their own callback functions which take 0097 % the same form and are called in the same contexts as 0098 % CPF_DEFAULT_CALLBACK. These are specified via the MATPOWER 0099 % option 'cpf.user_callback'. This option can be a string containing 0100 % the name of the callback function, or a struct with the following 0101 % fields, where all but the first are optional: 0102 % 'fcn' - string with name of callback function 0103 % 'priority' - numerical value specifying callback priority 0104 % (default = 20, see CPF_REGISTER_CALLBACK for details) 0105 % 'args' - arbitrary value (any type) passed to the callback 0106 % as CB_ARGS each time it is invoked 0107 % Multiple user callbacks can be registered by assigning a cell array 0108 % of such strings and/or structs to the 'cpf.user_callback' option. 0109 % 0110 % See also RUNCPF, CPF_REGISTER_CALLBACK. 0111 0112 % MATPOWER 0113 % Copyright (c) 2013-2016, Power Systems Engineering Research Center (PSERC) 0114 % by Ray Zimmerman, PSERC Cornell 0115 % 0116 % This file is part of MATPOWER. 0117 % Covered by the 3-clause BSD License (see LICENSE file for details). 0118 % See http://www.pserc.cornell.edu/matpower/ for more info. 0119 0120 %% skip if rollback, except if it is a FINAL call 0121 if rollback && k > 0 0122 return; 0123 end 0124 0125 %% initialize variables 0126 step = nx.step; 0127 V = nx.V; 0128 lam = nx.lam; 0129 V_hat = nx.V_hat; 0130 lam_hat = nx.lam_hat; 0131 0132 %%----- initialize/update state/results ----- 0133 if k == 0 %% INITIAL call 0134 %% initialize state 0135 cxx = struct( 'V_hat', V_hat, ... 0136 'lam_hat', lam_hat, ... 0137 'V', V, ... 0138 'lam', lam, ... 0139 'steps', step, ... 0140 'iterations', 0 ); 0141 nxx = cxx; 0142 cx.cb.default = cxx; %% update current callback state 0143 nx.cb.default = nxx; %% updatenext callback state 0144 else 0145 nxx = nx.cb.default; %% get next callback state 0146 if k > 0 %% ITERATION call 0147 %% update state 0148 nxx.V_hat = [nxx.V_hat V_hat]; 0149 nxx.lam_hat = [nxx.lam_hat lam_hat]; 0150 nxx.V = [nxx.V V]; 0151 nxx.lam = [nxx.lam lam]; 0152 nxx.steps = [nxx.steps step]; 0153 nxx.iterations = k; 0154 nx.cb.default = nxx; %% update next callback state 0155 else %% FINAL call 0156 %% assemble results struct 0157 results.V_hat = nxx.V_hat; 0158 results.lam_hat = nxx.lam_hat; 0159 results.V = nxx.V; 0160 results.lam = nxx.lam; 0161 results.steps = nxx.steps; 0162 results.iterations = -k; 0163 results.max_lam = max(nxx.lam); 0164 end 0165 end 0166 0167 %%----- plot continuation curve ----- 0168 %% initialize plotting options 0169 plot_level = cb_data.mpopt.cpf.plot.level; 0170 plot_bus = cb_data.mpopt.cpf.plot.bus; 0171 plot_bus_default = 0; 0172 if plot_level 0173 if isempty(plot_bus) && ~isfield(nxx, 'plot_bus_default') %% no bus specified 0174 %% pick PQ bus with largest transfer 0175 Sxfr = cb_data.Sbust(abs(V)) - cb_data.Sbusb(abs(V)); 0176 [junk, idx] = max(Sxfr(cb_data.pq)); 0177 if isempty(idx) %% or bus 1 if there are none 0178 idx = 1; 0179 else 0180 idx = cb_data.pq(idx(1)); 0181 end 0182 idx_e = cb_data.mpc_target.order.bus.i2e(idx); 0183 0184 %% save it to keep it from changing in subsequent calls 0185 plot_bus_default = idx_e; 0186 else 0187 if isempty(plot_bus) 0188 idx_e = nxx.plot_bus_default; %% external bus number, saved 0189 else 0190 idx_e = plot_bus; %% external bus number, provided 0191 end 0192 idx = full(cb_data.mpc_target.order.bus.e2i(idx_e)); 0193 if idx == 0 0194 error('cpf_default_callback: %d is not a valid bus number for MPOPT.cpf.plot.bus', idx_e); 0195 end 0196 end 0197 0198 %% set bounds for plot axes 0199 xmin = 0; 0200 xmax = max([max(nxx.lam_hat); max(nxx.lam)]); 0201 ymin = min([min(abs(nxx.V_hat(idx, :))); min(abs(nxx.V(idx, :)))]); 0202 ymax = max([max(abs(nxx.V_hat(idx, :))); max(abs(nxx.V(idx, :)))]); 0203 if xmax < xmin + cb_data.mpopt.cpf.step / 100; 0204 xmax = xmin + cb_data.mpopt.cpf.step / 100; 0205 end 0206 if ymax - ymin < 2e-5; 0207 ymax = ymax + 1e-5; 0208 ymin = ymin - 1e-5; 0209 end 0210 xmax = xmax * 1.05; 0211 ymax = ymax + 0.05 * (ymax-ymin); 0212 ymin = ymin - 0.05 * (ymax-ymin); 0213 0214 %%----- INITIAL call ----- 0215 if k == 0 0216 %% save default plot bus in the state so we don't have to detect it 0217 %% each time, since we don't want it to change in the middle of the run 0218 if plot_bus_default 0219 cx.cb.default.plot_bus_default = plot_bus_default; 0220 end 0221 0222 %% initialize lambda-V nose curve plot 0223 axis([xmin xmax ymin ymax]); 0224 plot(cxx.lam_hat(1), abs(cxx.V_hat(idx,1)), '-', 'Color', [0.25 0.25 1]); 0225 title(sprintf('Voltage at Bus %d', idx_e)); 0226 xlabel('\lambda'); 0227 ylabel('Voltage Magnitude'); 0228 hold on; 0229 %%----- ITERATION call ----- 0230 elseif k > 0 0231 %% plot single step of the lambda-V nose curve 0232 if plot_level > 1 0233 axis([xmin xmax ymin ymax]); 0234 plot([nxx.lam(k); nxx.lam_hat(k+1)], ... 0235 [abs(nxx.V(idx,k)); abs(nxx.V_hat(idx,k+1))], '-', ... 0236 'Color', 0.85*[1 0.75 0.75]); 0237 plot([nxx.lam_hat(k+1); nxx.lam(k+1)], ... 0238 [abs(nxx.V_hat(idx,k+1)); abs(nxx.V(idx,k+1))], '-', ... 0239 'Color', 0.85*[0.75 1 0.75]); 0240 plot(nxx.lam_hat(k+1), abs(nxx.V_hat(idx,k+1)), 'x', ... 0241 'Color', 0.85*[1 0.75 0.75]); 0242 plot(nxx.lam(k+1)', abs(nxx.V(idx,k+1))', '-o', ... 0243 'Color', [0.25 0.25 1]); 0244 drawnow; 0245 if plot_level > 2 0246 pause; 0247 end 0248 end 0249 %%----- FINAL call ----- 0250 else % k < 0 0251 %% finish final lambda-V nose curve plot 0252 axis([xmin xmax ymin ymax]); 0253 plot(nxx.lam', abs(nxx.V(idx,:))', '-', 'Color', [0.25 0.25 1]); 0254 hold off; 0255 end 0256 end