0001 function md = loadmd(mpci, transmati, xgdi, storagei, contabi, profilesi, trajdatai)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060 if nargin < 7
0061 trajdatai = [];
0062 if nargin < 6
0063 profilesi = [];
0064 if nargin < 5
0065 contabi = [];
0066 if nargin < 4
0067 storagei = [];
0068 if nargin < 3
0069 xgdi = [];
0070 if nargin < 2
0071 transmati = [];
0072 if nargin < 1
0073 error('loadmd: MPC is a mandatory argument');
0074 end
0075 end
0076 end
0077 end
0078 end
0079 end
0080 end
0081
0082 define_constants;
0083 [CT_LABEL, CT_PROB, CT_TABLE, CT_TBUS, CT_TGEN, CT_TBRCH, ...
0084 CT_TAREABUS, CT_TAREAGEN, CT_TAREABRCH, CT_ROW, CT_COL, CT_CHGTYPE, ...
0085 CT_REP, CT_REL, CT_ADD, CT_NEWVAL, CT_TLOAD, CT_TAREALOAD, ...
0086 CT_LOAD_ALL_PQ, CT_LOAD_FIX_PQ, CT_LOAD_DIS_PQ, CT_LOAD_ALL_P, ...
0087 CT_LOAD_FIX_P, CT_LOAD_DIS_P, CT_TGENCOST, CT_TAREAGENCOST, ...
0088 CT_MODCOST_F, CT_MODCOST_X] = idx_ct;
0089 [PR_REP, PR_REL, PR_ADD, PR_TCONT, PR_TYPES, PR_TMPCD,...
0090 PR_TXGD, PR_TCTD, PR_TSTGD, PR_CHGTYPES] = idx_profile;
0091
0092
0093
0094
0095 mpc = loadcase(mpci);
0096
0097
0098
0099
0100
0101 if isempty(transmati)
0102 transmat = {1};
0103 elseif isscalar(transmati) && isnumeric(transmati)
0104 transmat = transmati;
0105 else
0106 type = {'cell'};
0107 transmat = loadgenericdata(transmati, type);
0108 if isempty(transmat)
0109 error('loadmd: must provide a non-empty TRANSMAT cell array')
0110 end
0111 end
0112
0113
0114 type = {'struct'};
0115 fields = {...
0116 'CommitSched', ...
0117 'InitialPg', ...
0118 'RampWearCostCoeff', ...
0119 'PositiveActiveReservePrice', ...
0120 'PositiveActiveReserveQuantity', ...
0121 'NegativeActiveReservePrice', ...
0122 'NegativeActiveReserveQuantity', ...
0123 'PositiveActiveDeltaPrice', ...
0124 'NegativeActiveDeltaPrice', ...
0125 'PositiveLoadFollowReservePrice', ...
0126 'PositiveLoadFollowReserveQuantity', ...
0127 'NegativeLoadFollowReservePrice', ...
0128 'NegativeLoadFollowReserveQuantity', ...
0129 };
0130 xgd = loadgenericdata(xgdi, type, fields);
0131
0132
0133
0134 type = {'struct'};
0135 fields = {...
0136 'UnitIdx';...
0137
0138
0139
0140 'InitialStorage';...
0141
0142
0143
0144 'TerminalStoragePrice';...
0145
0146
0147
0148
0149
0150
0151 'MinStorageLevel';...
0152 'MaxStorageLevel';...
0153
0154
0155
0156
0157 };
0158 storage = loadgenericdata(storagei, type, fields);
0159
0160
0161
0162 type = {'array'};
0163 contab = loadgenericdata(contabi, type);
0164
0165
0166
0167 type = {'struct'};
0168 fields = {'type','table','rows','col','chgtype','values'};
0169
0170
0171
0172
0173
0174 try
0175 profiles = loadgenericdata(profilesi, type, fields);
0176 catch exception
0177 if strcmp(exception.identifier,'loadgenericdata:missingfield')
0178 fields = {'wind', 'load'};
0179 centroids = loadgenericdata(profilesi, type, fields);
0180 if size(centroids.load,3) > 1
0181 table = PR_TAREALOAD;
0182 rows = (1:size(centroids.load,3))';
0183 else
0184 table = PR_TLOAD;
0185 rows = 0;
0186 end
0187 profiles = [ centroids2profile(centroids.wind, PR_TGEN, mpc.iwind, PMAX, PR_REL) ;...
0188 centroids2profile(centroids.load, table, rows, CT_LOAD_ALL_P, PR_REL) ;
0189 ];
0190 else
0191 rethrow(exception);
0192 end
0193 end
0194
0195
0196
0197 type = {'struct'};
0198 fields = {'type','table','rows','col','chgtype','values'};
0199
0200
0201
0202 try
0203 trajdata = loadgenericdata(trajdatai, type, fields);
0204 catch exception
0205 if strcmp(exception.identifier,'loadgenericdata:missingfield')
0206 fields = {'wind', 'load'};
0207 trajdatacentroids = loadgenericdata(trajdatai, type, fields);
0208 if size(trajdatacentroids.load,3) > 1
0209 table = PR_TAREALOAD;
0210 rows = (1:size(trajdatacentroids.load,3))';
0211 else
0212 table = PR_TLOAD;
0213 rows = 0;
0214 end
0215 trajdata = [ centroids2profile(trajdatacentroids.wind, PR_TGEN, mpc.iwind, PMAX, PR_REL) ;...
0216 centroids2profile(trajdatacentroids.load, table, rows, CT_LOAD_ALL_P, PR_REL) ;
0217 ];
0218 else
0219 rethrow(exception);
0220 end
0221 end
0222 if ~isempty(trajdata)
0223 second = true;
0224 else
0225 second = false;
0226 end
0227
0228
0229
0230
0231
0232 md = md_init;
0233
0234
0235
0236 if iscell(transmat)
0237 nt = length(transmat);
0238 else
0239 nt = transmat;
0240 transmat = ones(1, nt);
0241 transmat = mat2cell(transmat, 1, transmat);
0242 end
0243
0244 nj = zeros(nt,1);
0245 for t = 1:nt
0246 nj(t) = size(transmat{t},1);
0247 end
0248 nj_max = max(nj);
0249
0250 nb = size(mpc.bus,1);
0251 ng = size(mpc.gen,1);
0252 if isfield(mpc, 'iwind')
0253 nw = size(mpc.iwind,1);
0254 else
0255 nw = 0;
0256 end
0257 if isfield(mpc, 'iess')
0258 ns = size(mpc.iess,1);
0259 else
0260 ns = 0;
0261 end
0262 nprof = size(profiles,1);
0263
0264 if second
0265 nprof2 = size(trajdata,1);
0266 ntraj = size(trajdata(1).values,2);
0267 end
0268
0269
0270
0271
0272 md.idx.nt = nt;
0273
0274
0275
0276 if any(nj < 1)
0277 error('loadmd: number of scenarios nj must be at least 1');
0278 end
0279
0280 if nt < 1
0281 error('loadmd: number of time periods nt must be at least 1');
0282 end
0283
0284
0285
0286
0287
0288
0289
0290 if any(mpc.bus(:, BUS_I) ~= (1:nb)')
0291 error('loadmd: buses must be numbered consecutively in MPC.bus matrix; use ext2int() to convert to internal ordering')
0292 end
0293
0294
0295
0296
0297
0298 if isempty(xgd)
0299 xgd = loadxgendata([], mpc);
0300 end
0301
0302
0303 if ns == 0
0304 storage = [];
0305 else
0306 if isempty(storage)
0307 error('loadmd: storage struct cannot be empty when MPC contains storage units');
0308 end
0309
0310 if ~isfield(storage,'OutEff')
0311 storage.OutEff = [];
0312 end
0313 if ~isfield(storage,'InEff')
0314 storage.InEff = [];
0315 end
0316 if ~isfield(storage,'LossFactor')
0317 storage.LossFactor = [];
0318 end
0319 if ~isfield(storage,'rho')
0320 storage.rho = [];
0321 end
0322 end
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339 if length(transmat) < nt
0340 error('loadmd: nt (= %d) has been modified and no longer matches transmat time dimension (%d)', nt, length(transmat));
0341 else
0342 if size(transmat{1}, 1) ~= nj(1)
0343 error('loadmd: # of scenarios in t=1, nj(1) = %d, does not match # of rows in transmat{1} (%d)', nj(1), size(transmat{1}, 1));
0344 end
0345 if nt > 1
0346 for t = 2:nt
0347 if any(size(transmat{t}) ~= [nj(t) nj(t-1)])
0348 error('loadmd: dimensions of transmat{%d} (%d x %d) inconsistent with nj(%d) x nj(%d) (%d x %d)', ...
0349 t, size(transmat{t}, 1), size(transmat{t}, 2), t, t-1, nj(t), nj(t-1));
0350 end
0351 end
0352 end
0353 end
0354
0355
0356 if any( [size(xgd.CommitSched, 1) ...
0357 size(xgd.InitialPg, 1) ...
0358 size(xgd.RampWearCostCoeff, 1) ...
0359 size(xgd.PositiveActiveReserveQuantity, 1) ...
0360 size(xgd.NegativeActiveReservePrice, 1) ...
0361 size(xgd.NegativeActiveReserveQuantity, 1) ...
0362 size(xgd.PositiveActiveDeltaPrice, 1) ...
0363 size(xgd.NegativeActiveDeltaPrice, 1) ...
0364 size(xgd.PositiveLoadFollowReservePrice, 1) ...
0365 size(xgd.PositiveLoadFollowReserveQuantity, 1) ...
0366 size(xgd.NegativeLoadFollowReservePrice, 1) ...
0367 size(xgd.NegativeLoadFollowReserveQuantity, 1) ...
0368 ] ~= ng )
0369 error('loadmd: 1st dimension inconsistency in field of xGenData')
0370 end
0371
0372
0373 if ~isempty(storage)
0374 if length(storage.UnitIdx) ~= length(mpc.iess)
0375 error('loadmd: dimensions of storage.UnitIdx (%d) and mpc.iess (%d) must match', length(storage.UnitIdx), length(mpc.iess));
0376 end
0377 end
0378
0379
0380 size_contab = size(contab);
0381 if ~isempty(contab) && (length(size_contab) ~= 2 || size_contab(2) ~= 7)
0382 error('loadmd: contab must be matrix with 7 columns');
0383 end
0384
0385
0386 for p = 1:nprof
0387 if ~isnumeric(profiles(p).values)
0388 error('loadmd: profiles(%d).values is required to be a numeric array', p);
0389 end
0390 if length(size(profiles(p).values)) > 3
0391 error('loadmd: profiles(%d).values must have no more than 3 dimensions', p);
0392 end
0393 if ~( size(profiles(p).values, 1) == 1 ||...
0394 size(profiles(p).values, 1) >= nt )
0395 error('loadmd: time dimension of profiles(%d).values (%d) must be 1 or >= nt = %d', p, size(profiles(p).values, 1), nt);
0396 end
0397 if ~( size(profiles(p).values, 2) == 1 ||...
0398 size(profiles(p).values, 2) == nj_max )
0399 error('loadmd: scenarios dimension of profiles(%d).values (%d) must be 1 or nj_max = %d', p, size(profiles(p).values, 2), nj_max);
0400 end
0401 if ~( size(profiles(p).values, 3) == 1 ||...
0402 size(profiles(p).values, 3) == length(profiles(p).rows) )
0403 error('loadmd: 3rd dimension of profiles(%d).values (%d) must be 1 or %d (length of profiles(%d).rows)', p, size(profiles(p).values, 3), length(profiles(p).rows), p);
0404 end
0405 if ~any(strcmp(profiles(p).type, PR_TYPES))
0406 error('loadmd: profiles(%d).type not supported', p);
0407 end
0408 if ~(isscalar(profiles(p).table) || ischar(profiles(p).table))
0409 error('loadmd: profiles(%d).table must be either scalar or string', p);
0410 end
0411 if ~isvector(profiles(p).rows)
0412 error('loadmd: profiles(%d).rows must be a vector', p);
0413 end
0414 if ~isscalar(profiles(p).col)
0415 error('loadmd: profiles(%d).col must be scalar', p);
0416 end
0417 if ~any(profiles(p).chgtype == PR_CHGTYPES)
0418 error('loadmd: profiles(%d).chgtype not supported', p);
0419 end
0420 end
0421
0422
0423
0424
0425 if second
0426 for p = 1:nprof2
0427 if ~isnumeric(trajdata(p).values)
0428 error('loadmd: trajdata(%d).values is required to be a numeric array', p);
0429 end
0430 if length(size(trajdata(p).values)) > 3
0431 error('loadmd: trajdata(%d).values must have no more than 3 dimensions', p);
0432 end
0433 if ~( size(trajdata(p).values, 1) == 1 ||...
0434 size(trajdata(p).values, 1) >= nt )
0435 error('loadmd: time dimension of trajdata(%d).values (%d) must be 1 or >= nt = %d', p, size(trajdata(p).values, 1), nt);
0436 end
0437 if ~( size(trajdata(p).values, 2) == 1 ||...
0438 size(trajdata(p).values, 2) == ntraj )
0439 error('loadmd: scenarios dimension of trajdata(%d).values (%d) must be 1 or ntraj = %d', p, size(trajdata(p).values, 2), ntraj);
0440 end
0441 if ~( size(trajdata(p).values, 3) == 1 ||...
0442 size(trajdata(p).values, 3) == length(trajdata(p).rows) )
0443 error('loadmd: 3rd dimension of trajdata(%d).values (%d) must be 1 or %d (length of trajdata(%d).rows)', p, size(trajdata(p).values, 3), length(trajdata(p).rows), p);
0444 end
0445 if ~any(strcmp(trajdata(p).type, PR_TYPES))
0446 error('loadmd: trajdata(%d).type not supported', p);
0447 end
0448 if ~(isscalar(trajdata(p).table) || ischar(trajdata(p).table))
0449 error('loadmd: trajdata(%d).table must be either scalar or string', p);
0450 end
0451 if ~isvector(trajdata(p).rows)
0452 error('loadmd: trajdata(%d).rows must be a vector', p);
0453 end
0454 if ~isscalar(trajdata(p).col)
0455 error('loadmd: trajdata(%d).col must be scalar', p);
0456 end
0457 if ~any(trajdata(p).chgtype == PR_CHGTYPES)
0458 error('loadmd: trajdata(%d).chgtype not supported', p);
0459 end
0460 end
0461 end
0462
0463
0464
0465
0466
0467
0468 transmat = transmat(1:nt);
0469
0470
0471
0472
0473 for p = 1:nprof
0474 profiles(p).values = profiles(p).values(1:nt,:,:);
0475 end
0476
0477
0478 if second
0479 for p = 1:nprof2
0480 trajdata(p).values = trajdata(p).values(1:nt,1:ntraj,:);
0481 end
0482 end
0483
0484
0485
0486
0487
0488
0489
0490
0491 for t = 1:nt
0492 md.tstep(t).TransMat = transmat{t};
0493 end
0494
0495
0496 md.mpc = mpc;
0497
0498
0499
0500
0501 optab = cell(nt,nj_max);
0502 for p = 1:nprof
0503 if strcmp(profiles(p).type, 'mpcData')
0504
0505
0506
0507
0508 optab = apply_profile(profiles(p), optab);
0509 end
0510 end
0511
0512
0513 for t = 1:nt
0514 for j = 1:nj(t)
0515 md.tstep(t).OpCondSched(j).tab = optab{t,j};
0516 end
0517 end
0518
0519
0520
0521
0522
0523
0524
0525
0526 if ~isempty(storage)
0527 fields = { ...
0528 'UnitIdx', ...
0529 'ExpectedTerminalStorageAim', ...
0530 'ExpectedTerminalStorageMin', ...
0531 'ExpectedTerminalStorageMax', ...
0532 'InitialStorage', ...
0533 'InitialStorageLowerBound', ...
0534 'InitialStorageUpperBound', ...
0535 'InitialStorageCost', ...
0536 'TerminalStoragePrice', ...
0537 'TerminalChargingPrice0', ...
0538 'TerminalDischargingPrice0', ...
0539 'TerminalChargingPriceK', ...
0540 'TerminalDischargingPriceK', ...
0541 'ExpectedStorageState', ...
0542 'ExpectedStorageDispatch', ...
0543 'MinStorageLevel', ...
0544 'MaxStorageLevel', ...
0545 'OutEff', ...
0546 'InEff', ...
0547 'LossFactor', ...
0548 'rho', ...
0549 };
0550 for f = 1:length(fields)
0551 ff = fields{f};
0552 if isfield(storage, ff)
0553 md.Storage.(ff) = storage.(ff);
0554 end
0555 end
0556 end
0557
0558
0559 if ns > 0
0560 for p = 1:nprof
0561 if strcmp(profiles(p).type, 'StorageData')
0562 md.Storage = apply_profile(profiles(p), md.Storage, [nt nj ns]);
0563 end
0564 end
0565 end
0566
0567
0568
0569
0570 for p = 1:nprof
0571 if strcmp(profiles(p).type, 'xGenData')
0572 xgd = apply_profile(profiles(p), xgd, [nt nj_max ng]);
0573 end
0574 end
0575
0576 if isfield(xgd, 'CommitKey') && ~isempty(xgd.CommitKey)
0577 UC = 1;
0578 else
0579 UC = 0;
0580 end
0581
0582
0583
0584 md.InitialPg = xgd.InitialPg;
0585 if isfield(xgd, 'TerminalPg')
0586 md.TerminalPg = xgd.TerminalPg;
0587 end
0588
0589 if UC
0590 md.UC.InitialState = xgd.InitialState;
0591 md.UC.MinUp = xgd.MinUp;
0592 md.UC.MinDown = xgd.MinDown;
0593 end
0594
0595
0596 fields = {'RampWearCostCoeff'};
0597 for f = 1:length(fields)
0598 ff = fields{f};
0599 if size(xgd.(ff), 2) == 1
0600 for t = 1:nt
0601 md.(ff)(:,t) = xgd.(ff);
0602 end
0603 elseif size(xgd.(ff), 2) == nt
0604 md.(ff) = xgd.(ff);
0605 else
0606 error('loadmd: number of columns in XGD.%s must be 1 or %d', ff, nt);
0607 end
0608 end
0609
0610
0611 fields = {'CommitSched'};
0612 if UC
0613 fields = {fields{:}, 'CommitKey'};
0614 end
0615 for f = 1:length(fields)
0616 ff = fields{f};
0617 if size(xgd.(ff), 2) == 1
0618 for t = 1:nt
0619 md.UC.(ff)(:,t) = xgd.(ff);
0620 end
0621 elseif size(xgd.(ff), 2) == nt
0622 md.UC.(ff) = xgd.(ff);
0623 else
0624 error('loadmd: number of columns in XGD.UC.%s must be 1 or %d', ff, nt);
0625 end
0626 end
0627
0628
0629 fields = {
0630 'PositiveActiveReservePrice', 'PositiveActiveReserveQuantity', ...
0631 'NegativeActiveReservePrice', 'NegativeActiveReserveQuantity', ...
0632 'PositiveActiveDeltaPrice', 'NegativeActiveDeltaPrice', ...
0633 'PositiveLoadFollowReservePrice', 'PositiveLoadFollowReserveQuantity', ...
0634 'NegativeLoadFollowReservePrice', 'NegativeLoadFollowReserveQuantity', ...
0635 };
0636 for f = 1:length(fields)
0637 ff = fields{f};
0638 if size(xgd.(ff), 2) == 1
0639 for t = 1:nt
0640 md.offer(t).(ff) = xgd.(ff);
0641 end
0642 elseif size(xgd.(ff), 2) == nt
0643 for t = 1:nt
0644 md.offer(t).(ff) = xgd.(ff)(:, t);
0645 end
0646 else
0647 error('loadmd: number of columns in XGD.%s must be 1 or %d', ff, nt);
0648 end
0649 end
0650
0651
0652 ct_subset = ones(nt, nj_max, size(contab,1));
0653
0654
0655
0656 for p = 1:nprof
0657 if strcmp(profiles(p).type, 'ContingencyData')
0658 ct_subset = apply_profile(profiles(p), ct_subset, [nt nj_max ncont]);
0659 end
0660 end
0661
0662
0663 for t = 1:nt
0664 for j = 1:nj(t)
0665 md.cont(t,j).contab = contab(squeeze(ct_subset(t,j,:)) == 1,:);
0666 end
0667 end
0668
0669
0670
0671
0672
0673
0674
0675 if second
0676
0677 optab2 = cell(nt,ntraj);
0678
0679
0680
0681
0682
0683
0684 for p = 1:nprof2
0685 optab2 = profile2contabs(optab2, trajdata(p));
0686 end
0687
0688
0689 for t = 1:nt
0690 for j = 1:ntraj
0691 md.second.tstep(t).OpCondSched(j).tab = optab2{t,j};
0692 end
0693 end
0694
0695 end