APPLY_PROFILE Applies changes defined in a profile to a data structure. CHGTABS = APPLY_PROFILE( PROFILE, CHGTABSI ) XGD = APPLY_PROFILE( PROFILE, XGDI, DIM ) SD = APPLY_PROFILE( PROFILE, SDI, DIM ) CTSETS = APPLY_PROFILE( PROFILE, CTSETS, DIM ) (not yet implemented) Applies a single profile of the given type to the given ARGIN. There are 4 different types of profiles, and each one affects differently the input to produce the output. Profile input must contain the following fields: Inputs: PROFILE: a single-dimensional Profile struct with the following fields: .type (string) .table (string or scalar) .rows (vector) .col (scalar) .chgtype (scalar) .values (array) with at most 3 dimensions assumed to be [ (1 or nt) by (1 or nj_max) or (1 or length(rows)) ] See IDX_PROFILE for details on the Profile struct. CHGTABI: cell array of change tables to be modified XGDI: xGenData struct to be modified STORAGEI: StorageData struct to be modified CTSETSI: array with ContingencyData (not yet implemented) DIM : (scalar) indicates the total number of elements in the table or field being modified. Elements here refers to the 3rd dimension, not time nor scenarios, but rather elements such as generators, number of different contingencies in master chgtab matrix (different labels), and storage units. DIM required to be able to expand, to a full DIM dimension, the data to be modified when it is summarized by a singleton dimension representing all the elements in that particular data set. It is ignored for type 'mpcData', mandatory for all other types. Outputs: CHGTABS : cell array of modified change tables (nr x 7) XGD: modified xGenData struct STORAGE: modified StorageData struct CTSETS: (not yet implemented) Additional notes: In general, field 'values' does not need to match dimensions of dim = [nt nj_max n], where 'n' represents the subset of elements being affected by the profile, i.e., the elements indicated by 'rows', but it does need to be smaller or equal. Each dimension of 'values' is allowed to be either the indicated above, or a singleton dimension, in which case a singleton meaning that the profile "applies to all" elements in that dimension, with the exception that the third dimension may be a singleton also in the case affecting a single element (as opposed to all elements in the third dimension). type == 'mpcData' Generates/adds contingency-like tables to a cell array can be used to apply a change 'chgtype' to values in column 'col' of elements 'rows' on table 'table'. 'values' is a numeric array with up to 3 dimensions organized necessarily as in [nt nj_max n]. The third dimension indicates the subset of elements to which the profile is to be applied. Output CHGTABS is a (nt by nj) cell array of chgtab matrices (7 cols) with unspecified labels nor probabilities. CHGTABI must always be provided, even if it's a cell array with (nt x nj_max) empty entries. These dimensions are required in order to be able to expand changes correctly across time periods and scenarios. Dimensions of 'values' are expanded if required (i.e., if inconsistent with nt, nj_max, or length of 'rows', resp.). type == 'xGenData' Profile modifies the field of XGD struct indicated by the string 'table'. 'rows' indicates gens to modify, 'col' is ignored, and 'chgtype' the type of change using 'values'. Dimensions of 'values' are expanded if required (ie, if inconsistent with nt, nj_max, or length of 'rows', resp.). type == 'StorageData' Profile modifies the field of STORAGE struct indicated by the string 'table'. 'rows' indicates storage units to modify (using storage-dedicated idx's as opposed to gen idx's), 'col' is ignored, and 'chgtype' the type of change using 'values'. Dimensions of 'values' are expanded if required (ie, if inconsistent with nt, nj_max, or length of 'rows', resp.). type == 'ContingencyData' (not yet implemented) Profile modifies the provided 'indicative' 3-dim array of binary variables: 1st dim spans the labels of contingencies, 2nd dim spans time periods, and 3rd dim spans scenarios. Thus, 'rows' indicates which labeled contingencies are to be modified by the profile, 'col' is ignored, and 'cghtype' the type of change using 'values'. Dimensions of 'values' expanded if required (ie, if inconsistent with nt, nj_max, or length of 'rows', resp.).
0001 function argout = apply_profile(profile, argin, dim) 0002 %APPLY_PROFILE Applies changes defined in a profile to a data structure. 0003 % 0004 % CHGTABS = APPLY_PROFILE( PROFILE, CHGTABSI ) 0005 % XGD = APPLY_PROFILE( PROFILE, XGDI, DIM ) 0006 % SD = APPLY_PROFILE( PROFILE, SDI, DIM ) 0007 % CTSETS = APPLY_PROFILE( PROFILE, CTSETS, DIM ) (not yet implemented) 0008 % 0009 % Applies a single profile of the given type to the given ARGIN. There are 0010 % 4 different types of profiles, and each one affects differently the 0011 % input to produce the output. Profile input must contain the following 0012 % fields: 0013 % 0014 % Inputs: 0015 % PROFILE: a single-dimensional Profile struct with the following fields: 0016 % .type (string) 0017 % .table (string or scalar) 0018 % .rows (vector) 0019 % .col (scalar) 0020 % .chgtype (scalar) 0021 % .values (array) with at most 3 dimensions assumed to be 0022 % [ (1 or nt) by (1 or nj_max) or (1 or length(rows)) ] 0023 % See IDX_PROFILE for details on the Profile struct. 0024 % 0025 % CHGTABI: cell array of change tables to be modified 0026 % XGDI: xGenData struct to be modified 0027 % STORAGEI: StorageData struct to be modified 0028 % CTSETSI: array with ContingencyData (not yet implemented) 0029 % 0030 % DIM : (scalar) indicates the total number of elements in the 0031 % table or field being modified. Elements here refers to the 0032 % 3rd dimension, not time nor scenarios, but rather elements 0033 % such as generators, number of different contingencies in 0034 % master chgtab matrix (different labels), and storage units. 0035 % DIM required to be able to expand, to a full DIM dimension, 0036 % the data to be modified when it is summarized by a 0037 % singleton dimension representing all the elements in that 0038 % particular data set. It is ignored for type 'mpcData', 0039 % mandatory for all other types. 0040 % 0041 % Outputs: 0042 % CHGTABS : cell array of modified change tables (nr x 7) 0043 % XGD: modified xGenData struct 0044 % STORAGE: modified StorageData struct 0045 % CTSETS: (not yet implemented) 0046 % 0047 % Additional notes: 0048 % 0049 % In general, field 'values' does not need to match dimensions of 0050 % dim = [nt nj_max n], where 'n' represents the subset of elements being 0051 % affected by the profile, i.e., the elements indicated by 'rows', but it 0052 % does need to be smaller or equal. Each dimension of 'values' is allowed 0053 % to be either the indicated above, or a singleton dimension, in which 0054 % case a singleton meaning that the profile "applies to all" elements in 0055 % that dimension, with the exception that the third dimension may be a 0056 % singleton also in the case affecting a single element (as opposed to all 0057 % elements in the third dimension). 0058 % 0059 % type == 'mpcData' 0060 % Generates/adds contingency-like tables to a cell array can be 0061 % used to apply a change 'chgtype' to values in column 'col' of 0062 % elements 'rows' on table 'table'. 'values' is a numeric array 0063 % with up to 3 dimensions organized necessarily as in [nt nj_max 0064 % n]. The third dimension indicates the subset of elements to 0065 % which the profile is to be applied. Output CHGTABS is a (nt by 0066 % nj) cell array of chgtab matrices (7 cols) with unspecified 0067 % labels nor probabilities. CHGTABI must always be provided, even 0068 % if it's a cell array with (nt x nj_max) empty entries. These 0069 % dimensions are required in order to be able to expand changes 0070 % correctly across time periods and scenarios. Dimensions of 0071 % 'values' are expanded if required (i.e., if inconsistent with nt, 0072 % nj_max, or length of 'rows', resp.). 0073 % 0074 % type == 'xGenData' 0075 % Profile modifies the field of XGD struct indicated by the 0076 % string 'table'. 'rows' indicates gens to modify, 'col' is 0077 % ignored, and 'chgtype' the type of change using 'values'. 0078 % Dimensions of 'values' are expanded if required (ie, if 0079 % inconsistent with nt, nj_max, or length of 'rows', resp.). 0080 % 0081 % type == 'StorageData' 0082 % Profile modifies the field of STORAGE struct indicated by the 0083 % string 'table'. 'rows' indicates storage units to modify (using 0084 % storage-dedicated idx's as opposed to gen idx's), 'col' is ignored, 0085 % and 'chgtype' the type of change using 'values'. Dimensions of 0086 % 'values' are expanded if required (ie, if inconsistent with nt, 0087 % nj_max, or length of 'rows', resp.). 0088 % 0089 % type == 'ContingencyData' (not yet implemented) 0090 % Profile modifies the provided 'indicative' 3-dim array of 0091 % binary variables: 1st dim spans the labels of contingencies, 0092 % 2nd dim spans time periods, and 3rd dim spans scenarios. Thus, 0093 % 'rows' indicates which labeled contingencies are to be modified 0094 % by the profile, 'col' is ignored, and 'cghtype' the type of 0095 % change using 'values'. Dimensions of 'values' expanded if 0096 % required (ie, if inconsistent with nt, nj_max, or length of 0097 % 'rows', resp.). 0098 0099 % Created by Daniel Munoz-Alvarez (4/18/2013) 0100 0101 % MOST 0102 % Copyright (c) 2013-2016, Power Systems Engineering Research Center (PSERC) 0103 % by Daniel Munoz-Alvarez, PSERC Cornell 0104 % 0105 % This file is part of MOST. 0106 % Covered by the 3-clause BSD License (see LICENSE file for details). 0107 % See https://github.com/MATPOWER/most for more info. 0108 0109 if nargin < 2 0110 error('apply_profile: insufficient arguments') 0111 end 0112 0113 % (A) Preliminary checking 0114 0115 typ = profile.type; 0116 tbl = profile.table; 0117 rows = profile.rows; 0118 col = profile.col; 0119 chgtyp = profile.chgtype; 0120 val = profile.values; 0121 0122 [PR_REP, PR_REL, PR_ADD, PR_TCONT, PR_TYPES, PR_TMPCD,... 0123 PR_TXGD, PR_TCTD, PR_TSTGD, PR_CHGTYPES] = idx_profile; 0124 0125 if length(profile)~=1 0126 error('apply_profile: must input a single profile') 0127 end 0128 if length(rows) > 1 && any(rows == 0) 0129 error('apply_profile: rows field of a profile must not contain zero unless it is the only entry') 0130 end 0131 0132 0133 switch typ 0134 % (B) Type mpcData profile 0135 case 'mpcData' 0136 chgtabs = argin; 0137 0138 nt = size(chgtabs, 1); 0139 nj_max = size(chgtabs, 2); 0140 0141 % (B.1) Check dimensions and fields of PROFILE 0142 if length(profile) > 1 0143 error('apply_profile: multiple profiles should be added separately') 0144 end 0145 0146 % (B) Check consistency of IDX, VALUES and CHGTABI 0147 if size(val,3) ~= length(rows) 0148 error('apply_profile: third dimension of profile.values should match length of profile.rows') 0149 end 0150 0151 if isempty(chgtabs) 0152 error('apply_profile: chgtabs cell array should have dimensions nt by nj_max') 0153 end 0154 0155 0156 % (C) Generate contingency-like rows to add to CHGTABI 0157 0158 % At this point, val can only have dimensions (1 or nt) by 0159 % (1 or nj_max) by (1 or length(rows)), so before transforming into a 0160 % chgtab, val needs to be expanded to full dimensions [nt nj_max length(rows)] 0161 0162 if size(val,1) == 1 && nt > 1 0163 val = repmat(val, [nt 1 1]); 0164 end 0165 if size(val,2) == 1 && nj_max > 1 0166 val = repmat(val, [1 nj_max 1]); 0167 end 0168 if size(val,3) == 1 && length(rows) > 1 0169 val = repmat(val, [1 1 length(rows)]); 0170 end 0171 0172 if any(tbl == PR_TMPCD) 0173 for t = 1:nt 0174 for j = 1:nj_max 0175 new_rows = []; 0176 for i = 1:length(rows) 0177 new_rows = [ new_rows ; 0 0 tbl rows(i) col chgtyp val(t,j,i) ]; 0178 end 0179 chgtabs{t,j} = [ chgtabs{t,j} ; new_rows ]; 0180 end 0181 end 0182 else 0183 error('apply_profile: indicated profile.table not supported for profile changes') 0184 end 0185 0186 argout = chgtabs; 0187 0188 case 'xGenData' 0189 % (C) Type xGenData profile 0190 xgd = argin; 0191 ng = dim; 0192 0193 nt_adhoc = max( size(val,1), size(xgd.(tbl),2) ); % nt_adhoc equals 1 or nt 0194 nj_adhoc = max( size(val,2), size(xgd.(tbl),3) ); % nj_adhoc equals 1 or nj_max 0195 0196 % (C.1) Check fields of PROFILE 0197 if ~ischar(tbl) 0198 error('apply_profile: table field of xGenData profile must be a string') 0199 end 0200 if ~any(strcmp(tbl, PR_TXGD)) 0201 error('apply_profile: field %s of xgd struct cannot be modified through a profile',tbl) 0202 end 0203 0204 % (C.2) Check consistency of ROWS, VALUES and affected field of XGD 0205 0206 if ~(size(xgd.(tbl),1) == 1 || size(xgd.(tbl),1) == ng) 0207 error('apply_profile: rows of xgd.%s must equal 1 or ng',tbl) 0208 end 0209 if ~(size(xgd.(tbl),2) == 1 || size(xgd.(tbl),2) == nt_adhoc) 0210 error('apply_profile: time dimension mismatch between xgd.%s and profile.values',tbl) 0211 end 0212 if ~(size(xgd.(tbl),3) == 1 || size(xgd.(tbl),3) == nj_adhoc) 0213 error('apply_profile: scenario dimension mismatch between xgd.%s and profile.values',tbl) 0214 end 0215 0216 0217 if ~(size(val,1) == 1 || size(val,1) == nt_adhoc) 0218 error('apply_profile: time dimension mismatch between xgd.%s and profile.values',tbl) 0219 end 0220 if ~(size(val,2) == 1 || size(val,2) == nj_adhoc) 0221 error('apply_profile: scenario dimension mismatch between xgd.%s and profile.values',tbl) 0222 end 0223 if length(rows) == 1 0224 if size(val,3) ~= 1 0225 error('apply_profile: 3rd dimension of values field must equal 1 when rows is scalar') 0226 end 0227 else 0228 if ~(size(val,3) == length(rows) || size(val,3) == 1) 0229 error('apply_profile: 3er dimension of values field must equal 1 or length of rows field when rows is not scalar') 0230 end 0231 end 0232 0233 0234 % (C.3) Verify validity of changes and expand field in question to full dimensions if required 0235 % Important: Notice the permutation of values dimensions from 0236 % [1 2 3] to [3 1 2]. 0237 0238 val = permute(val,[3 1 2]); 0239 0240 % From here and on, val dimensions are 0241 % (1 or legnth(rows)) by (1 or nt) by (1 or nj) 0242 % Also, xgd.(tbl) dimensions are 0243 % (1 or ng) by (1 or nt) by (1 or nj) 0244 0245 0246 % Expand cols (time) of xgd.(tbl) 0247 % if val has a time dimension and xgd.(tbl) does not (only necessary if nt_adhoc > 1) 0248 if size(val,2) > size(xgd.(tbl),2) 0249 xgd.(tbl) = repmat( xgd.(tbl), [1 size(val,2) 1]); 0250 0251 % Expands cols (time) of val to match xgd.(tbl) time dimension 0252 elseif size(xgd.(tbl),2) > size(val,2) 0253 val = repmat( val, [ 1 nt_adhoc 1]); 0254 end 0255 0256 % Expand 3rd dim (scenarios) of xgd.(tbl) 0257 % if val has a scenario dimension and xgd.(tbl) does not (only necessary if nj_adhoc > 1) 0258 if size(val,3) > size(xgd.(tbl),3) 0259 xgd.(tbl) = repmat( xgd.(tbl), [ 1 1 size(val,3)] ) ; 0260 0261 % Expands 3rd dim (scenarios) of val to match xgd.(tbl) scenarios dimension 0262 elseif size(xgd.(tbl),3) > size(val,3) 0263 val = repmat(val, [ 1 1 size(xgd.(tbl),3)]); 0264 end 0265 0266 % Expand rows (gens) of xgd.(tbl) 0267 % if profile modifies subset of gens (i.e. if rows~=0) 0268 if size(xgd.(tbl),1) == 1 && any(rows ~= 0) 0269 xgd.(tbl) = repmat( xgd.(tbl), [ ng 1 1]); 0270 end 0271 0272 % Expand rows of val to match gens to modify 0273 if size(val,1) == 1 && size(xgd.(tbl), 1) == ng && length(rows) > 1 0274 val = repmat(val, [length(rows) 1 1]); 0275 elseif size(val,1) == 1 && size(xgd.(tbl), 1) == ng && length(rows) == 1 && rows == 0 0276 val = repmat(val, [ng 1 1]); 0277 end 0278 0279 % Error if chgtype is CT_REL or CT_ADD and field involved is empty 0280 if (chgtyp == PR_REL || chgtyp == PR_ADD) && isempty(xgd.(tbl)) 0281 error('apply_profile: PR_REL or PR_ADD modification cannot be done to xgd.%s if it is empty',tbl) 0282 end 0283 0284 % (C.4) Apply change 0285 if length(rows) == 1 && rows == 0 %% modify all rows 0286 if chgtyp == PR_REP %% replace 0287 xgd.(tbl) = val; 0288 elseif chgtyp == PR_REL %% scale 0289 xgd.(tbl) = val .* xgd.(tbl); 0290 elseif chgtyp == PR_ADD %% shift 0291 xgd.(tbl) = val + xgd.(tbl); 0292 else 0293 error('apply_profile: modification type %d for xgd table not supported', chgtyp); 0294 end 0295 else %% modify single row 0296 if chgtyp == PR_REP %% replace 0297 xgd.(tbl)(rows,:,:) = val; 0298 elseif chgtyp == PR_REL %% scale 0299 xgd.(tbl)(rows,:,:) = val .* xgd.(tbl)(rows,:,:); 0300 elseif chgtyp == PR_ADD %% shift 0301 xgd.(tbl)(rows,:,:) = val + xgd.(tbl)(rows,:,:); 0302 else 0303 error('apply_profile: modification type %d for xgd table not supported', chgtyp); 0304 end 0305 end 0306 0307 0308 argout = xgd; 0309 0310 case 'ContingencyData' 0311 % (D) Type ContingencyData profile (not yet implemented) 0312 ct_subset = argin; 0313 error('apply_profile: type ContingencyData is not yet supported') 0314 argout = ct_subset; 0315 0316 case 'StorageData' 0317 % (E) Type StorageData profile 0318 storage = argin; 0319 ns = dim; % total number of storage units in the system 0320 nt_adhoc = max( size(val,1), size(storage.(tbl),2) ); % nt_adhoc equals 1 or nt 0321 0322 % (E.1) Check fields of PROFILE 0323 if ~ischar(tbl) 0324 error('apply_profile: table field of storage profile must be a string') 0325 end 0326 if ~any(strcmp(tbl, PR_TSTGD)) 0327 error('apply_profile: field %s of storage struct cannot be modified through a profile',tbl) 0328 end 0329 0330 % (E.2) Check consistency of ROWS, VALUES and affected field of STORAGE 0331 0332 if ~(size(storage.(tbl),1) == 1 || size(storage.(tbl),1) == ns) 0333 error('apply_profile: first dimension of field %s of storage struct must equal 1 or ns',tbl) 0334 end 0335 if ~(size(storage.(tbl),2) == 1 || size(storage.(tbl),2) == nt_adhoc) 0336 error('apply_profile: time dimension mismatch between storage.%s and profile.values',tbl) 0337 end 0338 if size(storage.(tbl),3) ~= 1 0339 error('apply_profile: no scenario dimension (3rd) allowed for storage.%s field',tbl) 0340 end 0341 0342 0343 if ~(size(val,1) == 1 || size(val,1) == nt_adhoc) 0344 error('apply_profile: time dimension mismatch between storage.%s and profile.values',tbl) 0345 end 0346 if size(val,2) ~= 1 0347 error('apply_profile: 2nd dimension of values field must equal 1 since no scenario dependent changes allowed ') 0348 end 0349 if length(rows) == 1 0350 if size(val,3) ~= 1 0351 error('apply_profile: 3rd dimension of values field must equal 1 when rows is scalar') 0352 end 0353 else 0354 if ~(size(val,3) == length(rows) || size(val,3) == 1) 0355 error('apply_profile: 3er dimension of values field must equal 1 or length of rows field when rows is a vector') 0356 end 0357 end 0358 0359 0360 % (E.3) Verify validity of changes and expand field in question to full dimensions if required 0361 % Important: Notice the permutation of values dimensions from 0362 % [1 2 3] to [3 1 2]. No scenario dimension allowed. 0363 0364 val = permute(val,[3 1 2]); % Squeeze not use to avoid problems when nt=1 0365 val = val(:,:,1); % From here and on, val dimensions are (1 or legnth(rows) by 1 or nt) 0366 0367 0368 % Expand cols (time) of field involved 0369 if size(val,2) > size(storage.(tbl),2) 0370 storage.(tbl) = storage.(tbl) * ones(1, size(val,2)); 0371 end 0372 0373 % Expand rows (ess units) if change modifies submatrix of the parameter that is being modified (not all rows) 0374 if size(storage.(tbl), 1) == 1 && any(rows ~= 0) 0375 storage.(tbl) = ones(ns, 1) * storage.(tbl); 0376 end 0377 0378 % Expand rows of val to match ess units to change 0379 if size(val,1) == 1 && size(storage.(tbl), 1) == ns && length(rows) > 1 0380 val = ones(length(rows), 1) * val; 0381 end 0382 if size(val,1) == 1 && size(storage.(tbl), 1) == ns && length(rows) == 1 && rows == 0 0383 val = ones(ns, 1) * val; 0384 end 0385 0386 % Expands cols of val to match field's time dimension 0387 if size(val, 2) == 1 && size(storage.(tbl), 2) == nt_adhoc 0388 val = val * ones(1, nt_adhoc); 0389 end 0390 0391 % Error if chgtype is CT_REL or CT_ADD and field involved is empty 0392 if (chgtyp == PR_REL || chgtyp == PR_ADD) && isempty(storage.(tbl)) 0393 error('apply_profile: PR_REL or PR_ADD modification cannot be done to storage.%s if it is empty',tbl) 0394 end 0395 0396 % (E.4) Apply change 0397 if length(rows) == 1 && rows == 0 %% modify all rows 0398 if chgtyp == PR_REP %% replace 0399 storage.(tbl) = val; 0400 elseif chgtyp == PR_REL %% scale 0401 storage.(tbl) = val .* storage.(tbl); 0402 elseif chgtyp == PR_ADD %% shift 0403 storage.(tbl) = val + storage.(tbl); 0404 else 0405 error('apply_profile: modification type %d for storage table not supported', chgtyp); 0406 end 0407 else %% modify single row 0408 if chgtyp == PR_REP %% replace 0409 storage.(tbl)(rows,:) = val; 0410 elseif chgtyp == PR_REL %% scale 0411 storage.(tbl)(rows,:) = val .* storage.(tbl)(rows,:); 0412 elseif chgtyp == PR_ADD %% shift 0413 storage.(tbl)(rows,:) = val + storage.(tbl)(rows,:); 0414 else 0415 error('apply_profile: modification type %d for storage table not supported', chgtyp); 0416 end 0417 end 0418 argout = storage; 0419 end