function Write_PhaseMap(FileWritingSetup)
% write_PhaseMap(FileWritingSetup)
%
% FUNCTION:
%
%   This function takes the symbolically derived impact map equations and
%   writes them to a function file.
%
%
% ARGUMENTS: FileWritingSetup.
%
%   SolnOne = A struct with a field containing an expression for the rates
%             immediately after a sticking collision with foot one
%
%   SolnTwo = A struct with a field containing an expression for the rates
%             immediately after a sticking collision with foot two
%
%   States = [2N x 2] cell array where the first column is the name of
%       the states, and the second column is comments about that states.
%       The index of a state in this array will match the index in the
%       dynamics function to be written. It is assumed that the second
%       block of N states are the time derivatives of the first block of N
%       states. Furthermore, it is assumed that the first N states are
%       positions and are not affected by impact.
%
%   Parameters = [K x 2] cell array with all of the input parameters. The
%       first column is for names, the second for comments
%
%   Directory = the name of the directory to write the files in.
%
%
% RETURNS:
%   This function will write a file for the dynamics equations in each
%   field of Dyn.
%
%
% NOTE:
%
%   1)  It is assumed that the symbols in all of the inputs are self
%       consistent; that is - if Contacts{1,1} = H1, then there must be a field
%       in Dyn.(FileNames{i,1}) called H1.
%
%
% Written by Matthew Kelly
% December 6, 2013
% Cornell University
%
% See also DERIVE_EOM

States = FileWritingSetup.States;
SolnOne = FileWritingSetup.SolnOne;
SolnTwo = FileWritingSetup.SolnTwo;
Directory = FileWritingSetup.Directory;

CurrDir = cd;
if ~exist(Directory,'dir')
    mkdir(Directory);
end
cd(Directory);

fid = fopen('phaseMap.m','w');

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%
%                           Function Header                               %
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%

fprintf(fid,['function StateAfter = phaseMap(StateBefore,PhaseBefore,PhaseAfter)\n']);
fprintf(fid,'%% function StateAfter = phaseMap(StateBefore,PhaseBefore,PhaseAfter)\n');
fprintf(fid,'%%\n');
fprintf(fid,'%% Computer Generated File -- DO NOT EDIT\n');
fprintf(fid,'%%\n');
fprintf(fid,'%% This function was created by the function Write_PhaseMap()\n');
fprintf(fid,['%% ' datestr(now) '\n']);
fprintf(fid,'%%\n');
fprintf(fid,'%% Dymanics Model: retractable double pendulum biped\n');
fprintf(fid,'%% Phases: Flight (F) == Both feet in the air\n');
fprintf(fid,'%%         Double Stance (D) == Both feet on the ground\n');
fprintf(fid,'%%         Single Stance One (S1) == Foot One -> ground, Foot Two -> air\n');
fprintf(fid,'%%         Single Stance Two (S2) == Foot One -> air, Foot Two -> ground\n');
fprintf(fid,'%%\n');
fprintf(fid,'%% FUNCTION:\n');
fprintf(fid,'%%   This function will compute the impact map that occurs during\n');
fprintf(fid,'%%   transitions between any two phases of motion. Detailed assumptions can\n');
fprintf(fid,'%%   be found in Derive_EoM.m\n');
fprintf(fid,'%%\n');
fprintf(fid,'%% ARGUMENTS:\n');
fprintf(fid,'%%   StateBefore = [Nx1] state vector\n');
fprintf(fid,'%%   PhaseBefore = element of set {''F'',''D'',''S1'',''S2''} = phase before impact\n');
fprintf(fid,'%%   PhaseAfter = element of set {''F'',''D'',''S1'',''S2''} = phase after impact\n');
fprintf(fid,'%%\n');
fprintf(fid,'%% RETURNS:\n');
fprintf(fid,'%%   StateAfter = [Nx1] state vector\n');
fprintf(fid,'%%\n');
fprintf(fid,'%% Matthew Kelly\n');
fprintf(fid,'%% Cornell University\n');
fprintf(fid,'%%\n');
fprintf(fid,'%%\n');

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%
%                            Select Impact Map                            %
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%

fprintf(fid,'switch PhaseBefore    \n');
fprintf(fid,'    case ''F''    \n');
fprintf(fid,'        switch PhaseAfter    \n');
fprintf(fid,'            case ''F''    \n');
fprintf(fid,'                StateAfter = StateBefore;    \n');
fprintf(fid,'            case ''D'' %%Assume that collision happens on Foot One then Two    \n');
fprintf(fid,'                StateInt = MapOne(StateBefore);    \n');
fprintf(fid,'                StateAfter = MapTwo(StateInt);    \n');
fprintf(fid,'            case ''S1''    \n');
fprintf(fid,'                StateAfter = MapOne(StateBefore);    \n');
fprintf(fid,'            case ''S2''    \n');
fprintf(fid,'                StateAfter = MapTwo(StateBefore);    \n');
fprintf(fid,'            otherwise    \n');
fprintf(fid,'                error(''Invalid phase after collision. Must be element of set: {''''F'''',''''D'''',''''S1'''',''''S2''''}'');    \n');
fprintf(fid,'        end    \n');
fprintf(fid,'    case ''D''    \n');
fprintf(fid,'         StateAfter = StateBefore;    \n');
fprintf(fid,'    case ''S1''    \n');
fprintf(fid,'        switch PhaseAfter    \n');
fprintf(fid,'            case {''F'',''S1''}    \n');
fprintf(fid,'                StateAfter = StateBefore;    \n');
fprintf(fid,'            case {''D'',''S2''}    \n');
fprintf(fid,'                StateAfter = MapTwo(StateBefore);    \n');
fprintf(fid,'            otherwise    \n');
fprintf(fid,'                error(''Invalid phase after collision. Must be element of set: {''''F'''',''''D'''',''''S1'''',''''S2''''}'');    \n');
fprintf(fid,'        end    \n');
fprintf(fid,'    case ''S2''    \n');
fprintf(fid,'        switch PhaseAfter    \n');
fprintf(fid,'            case {''F'',''S2''}    \n');
fprintf(fid,'                StateAfter = StateBefore;    \n');
fprintf(fid,'            case {''D'',''S1''}    \n');
fprintf(fid,'                StateAfter = MapOne(StateBefore);    \n');
fprintf(fid,'            otherwise    \n');
fprintf(fid,'                error(''Invalid phase after collision. Must be element of set: {''''F'''',''''D'''',''''S1'''',''''S2''''}'');    \n');
fprintf(fid,'        end    \n');
fprintf(fid,'    otherwise    \n');
fprintf(fid,'                error(''Invalid phase before collision. Must be element of set: {''''F'''',''''D'''',''''S1'''',''''S2''''}'');    \n');
fprintf(fid,'end    \n');
fprintf(fid,'\n');
fprintf(fid,'end\n');
fprintf(fid,'\n\n');
fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
fprintf(fid,'%%%%%%%%  ~~~~~~~~~~~~~~~~~~~ Sub Functions  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%%%%%%%%\n');
fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
fprintf(fid,'\n\n');

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%
%                        Write MapOne subfunction                         %
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%

    fprintf(fid,'function StateAfter = MapOne(StateBefore)    \n\n');

    for idxState=1:size(States,1)
        fprintf(fid,[States{idxState,1} ' = StateBefore(' num2str(idxState) '); %% ' ...
            States{idxState,2} '\n']);
    end %idxState
    fprintf(fid,'\n');

    Ndof = size(States,1)/2;
    N = num2str(Ndof);
    fprintf(fid,'StateAfter = zeros(size(StateBefore));\n');
    fprintf(fid,['StateAfter(1:' N ',:) = '...
        'StateBefore(1:' N ',:); %% Configuration not changed by collision\n']);
    for idx=1:Ndof
        writeIndex = idx + Ndof;
        writeName = [States{writeIndex,1} '_plus'];
        vectorizedExpression = char(SolnOne.(writeName));
        fprintf(fid,['StateAfter(' num2str(writeIndex) ') = ' ...
            vectorizedExpression ';\n']);
    end %idxAcc
    fprintf(fid,'\n');

    fprintf(fid,'end\n\n\n');

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%
%                        Write MapTwo subfunction                         %
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%

    fprintf(fid,'function StateAfter = MapTwo(StateBefore)    \n\n');

    for idxState=1:size(States,1)
        fprintf(fid,[States{idxState,1} ' = StateBefore(' num2str(idxState) '); %% ' ...
            States{idxState,2} '\n']);
    end %idxState
    fprintf(fid,'\n');

    Ndof = size(States,1)/2;
    N = num2str(Ndof);
    fprintf(fid,'StateAfter = zeros(size(StateBefore));\n');
    fprintf(fid,['StateAfter(1:' N ',:) = '...
        'StateBefore(1:' N ',:); %% Configuration not changed by collision\n']);
    for idx=1:Ndof
        writeIndex = idx + Ndof;
        writeName = [States{writeIndex,1} '_plus'];
        vectorizedExpression = char(SolnTwo.(writeName));
        fprintf(fid,['StateAfter(' num2str(writeIndex) ') = ' ...
            vectorizedExpression ';\n']);
    end %idxAcc
    fprintf(fid,'\n');

    fprintf(fid,'end\n');

fclose(fid);

cd(CurrDir);

end


function [pc, x3, y3, z3] = getPointCloud(imName)
	paths = getPaths();
	dt = load(fullfile(paths.pcDir, strcat(imName, '.mat')));
	x3 = dt.x3;
	y3 = dt.y3;
	z3 = dt.z3;
	pc(:,:,1) = x3;
	pc(:,:,2) = y3;
	pc(:,:,3) = z3;
end


function obj = t_mp_table(quiet)
%T_MP_TABLE  Tests for MP_TABLE (and TABLE).

%   MATPOWER
%   Copyright (c) 2021, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://matpower.org for more info.

if nargin < 1
    quiet = 0;
end

% define_constants;
if quiet
    verbose = 0;
else
    verbose = 1;
end

nt = 166;
skip_tests_for_tablicious = 1;
table_classes = {@mp_table};
class_names = {'mp_table'};
if have_feature('table')
    table_classes = {@table, table_classes{:}};
    class_names = {'table', class_names{:}};
end
nc = length(table_classes);

t_begin(nc*nt, quiet);

%% set up example data
var1 = [1:6]';
var2 = var1 + var1/10;
var3 = {'one'; 'two'; 'three'; 'four'; 'five'; 'six'};
var4 = 1./var1;
var5 = [3;-5;0;1;-2;4] <= 0;
var6 = [10 15; 20 25; 30 35; 40 45; 50 55; 60 65];
var_names = {'igr', 'flt', 'str', 'dbl', 'boo', 'mat'};
var_values = {var1, var2, var3, var4, var5, var6};
row_names = {'row1'; 'second row'; 'row 3'; 'fourth row'; '5'; '6th row'};
dim_names = {'records', 'fields'};

%% run tests
for k = 1:nc
    table_class = table_classes{k};
    cls = upper(class_names{k});

    t = sprintf('%s : constructor - no args : ', cls);
    T = table_class();
    skip_oct_tab = isa(T, 'table') && have_feature('octave') && ...
            skip_tests_for_tablicious;
    skip_ml_tab = isa(T, 'table') && have_feature('matlab') && ...
            have_feature('matlab', 'vnum') < 9.010;
    t_ok(isa(T, class_names{k}), [t 'class']);
    t_ok(isempty(T), [t 'isempty']);

    t = sprintf('%s : constructor - ind vars : ', cls);
    T = table_class(var1, var2, var3, var4, var5(:), var6);
    t_ok(isa(T, class_names{k}), [t 'class']);
    t_ok(~isempty(T), [t 'not isempty']);
    t_is(size(T), [6 6], 12, [t 'sz = size(T)']);
    t_is(size(T, 1), 6, 12, [t 'sz = size(T, 1)']);
    t_is(size(T, 2), 6, 12, [t 'sz = size(T, 2)']);
    [nr, nz] = size(T);
    t_is([nr, nz], [6 6], 12, [t '[nr, nz] = size(T)']);
    t_ok(isequal(T.Properties.VariableNames, ...
        {'var1', 'var2', 'var3', 'var4', 'Var5', 'var6'}), [t 'VariableNames'] );
    t_ok(isempty(T.Properties.RowNames), [t 'RowNames'] );
    t_ok(isequal(T.Properties.DimensionNames, {'Row', 'Variables'}), ...
        [t 'DimensionNames'] );
% show_me(T)

    %% subsref () (w/o RowNames)
    t = sprintf('%s : subsref () w/o RowNames : ', cls);
    t_is(size(T([2;4],[1;3;4])), [2 3], 12, [t 'T(ii,jj) : size(T(ii,jj))']);
% show_me(T([2;4],[1;3;4]));
    t_is(size(T(:,1:2:5)), [6 3], 12, [t 'T(:,j1:jN) : size']);
% show_me(T(:,1:2:5));
    t_is(size(T(1:2:5,:)), [3 6], 12, [t 'T(i1:iN,:) : size']);
% show_me(T(1:2:5,:));
    t_is(size(T(5,4)), [1 1], 12, [t 'T(i,j) : size']);
    t_is(size(T(4,6)), [1 1], 12, [t 'T(i,j) : size']);
% show_me(T(5,4));

    t = sprintf('%s : constructor - ind vars, w/names : ', cls);
    if skip_oct_tab || skip_ml_tab
        T = table_class(var1, var2, var3, var4, var5, var6, ...
            'VariableNames', var_names, 'RowNames', row_names);
    else
        T = table_class(var1, var2, var3, var4, var5, var6, ...
            'VariableNames', var_names, 'RowNames', row_names, ...
            'DimensionNames', dim_names);
    end
    t_ok(isa(T, class_names{k}), [t 'class'])
    t_ok(~isempty(T), [t 'not isempty']);
    t_is(size(T), [6 6], 12, [t 'sz = size(T)']);
    t_is(size(T, 1), 6, 12, [t 'sz = size(T, 1)']);
    t_is(size(T, 2), 6, 12, [t 'sz = size(T, 2)']);
    [nr, nz] = size(T);
    t_is([nr, nz], [6 6], 12, [t '[nr, nz] = size(T)']);
    t_ok(isequal(T.Properties.VariableNames, var_names), [t 'VariableNames'] );
    t_ok(isequal(T.Properties.RowNames, row_names), [t 'RowNames'] );
    if skip_oct_tab || skip_ml_tab
        t_skip(1, [t 'DimensionNames not yet supported'] );
    else
        t_ok(isequal(T.Properties.DimensionNames, dim_names), [t 'DimensionNames'] );
    end

    %% . indexing
    %% get full variables
    t = sprintf('%s : subsref . : ', cls);
    t_is(T.igr, var1, 12, [t 'T.igr']);
    t_is(T.flt, var2, 12, [t 'T.flt']);
    t_ok(isequal(T.str, var3), [t 'T.str']);
    t_is(T.dbl, var4, 12, [t 'T.dbl']);
    t_is(T.boo, var5, 12, [t 'T.boo']);
    t_is(T.mat, var6, 12, [t 'T.mat']);

    %% get indexed variables
    t_is(T.igr(2), var1(2), 12, [t 'T.igr(i)']);
    t_is(T.flt(4:6), var2(4:6), 12, [t 'T.flt(i1:iN)']);
    t_ok(isequal(T.str{3}, var3{3}), [t 'T.str{i}']);
    t_ok(isequal(T.str(6:-1:4), var3(6:-1:4)), [t 'T.str(iN:-1:i1)']);
    t_is(T.dbl([5;3]), var4([5;3]), 12, [t 'T.dbl(ii)']);
    t_is(T.boo(var5 == 1), var5(var5 == 1), 12, [t 'T.boo(<logical>)']);
    t_is(T.mat([6;2;4], :), var6([6;2;4], :), 12, [t 'T.mat(ii, :)']);
    t_is(T.mat([6;2;4], 2), var6([6;2;4], 2), 12, [t 'T.mat(ii, j)']);
    t_is(T.mat([6;2;4], [2;1]), var6([6;2;4], [2;1]), 12, [t 'T.mat(ii, jj)']);
    t_is(T.mat(5, :), var6(5, :), 12, [t 'T.mat(i, :)']);
    t_is(T.mat(5, 2), var6(5, 2), 12, [t 'T.mat(i, j)']);
    t_is(T.mat(8:10), var6(8:10), 12, [t 'T.mat(jj)']);

    %% set full variables
    t = sprintf('%s : subsasgn . : ', cls);
    T.igr = var1(end:-1:1);
    T.flt = var2(end:-1:1);
    T.str = var3(end:-1:1);
    T.dbl = var4(end:-1:1);
    T.boo = var5(end:-1:1);
    T.mat = var6(end:-1:1, end:-1:1);
    t_is(T.igr, var1(end:-1:1), 12, [t 'T.igr']);
    t_is(T.flt, var2(end:-1:1), 12, [t 'T.flt']);
    t_ok(isequal(T.str, var3(end:-1:1)), [t 'T.str']);
    t_is(T.dbl, var4(end:-1:1), 12, [t 'T.dbl']);
    t_is(T.boo, var5(end:-1:1), 12, [t 'T.boo']);
    t_is(T.mat, var6(end:-1:1, end:-1:1), 12, [t 'T.mat']);

    %% set indexed variables
    T.igr(2) = 55;
    T.flt(4:6) = [0.4 0.5 0.6];
    T.str{3} = 'tres';
    T.str(6:-1:4) = {'seis'; 'cinco'; 'cuatro'};
    T.dbl([5;3]) = [pi; exp(1)];
    T.boo(var5 == 1) = false;
    T.mat([5;3],:) = [5 0.5; 3 0.3];

    v1 = var1(end:-1:1); v1(2) = 55;
    v2 = var2(end:-1:1); v2(4:6) = [0.4 0.5 0.6];
    v3 = var3(end:-1:1);
    v3(6:-1:3) = {'seis'; 'cinco'; 'cuatro'; 'tres'};
    v4 = var4(end:-1:1); v4([5;3]) = [pi; exp(1)];
    v5 = var5(end:-1:1); v5(var5 == 1) = false;
    v6 = var6(end:-1:1, end:-1:1); v6([5;3],:) = [5 0.5; 3 0.3];
    t_is(T.igr, v1, 12, [t 'T.igr(i)']);
    t_is(T.flt, v2, 12, [t 'T.flt(i1:iN)']);
    t_ok(isequal(T.str, v3), [t 'T.str{i}']);
    t_is(T.dbl, v4, 12, [t 'T.dbl(ii)']);
    t_is(T.boo, v5, 12, [t 'T.boo(<logical>)']);
    t_is(T.mat, v6, 12, [t 'T.mat(ii, :)']);
% show_me(T);

    %% {} indexing
    t = sprintf('%s : subsref {} : ', cls);
    if skip_oct_tab
        t_skip(6, [t 'T{:, j} syntax not yet supported'])
    else
        t_ok(isequal(T{:, 1}, v1), [t 'T{:, 1} == v1']);
        t_ok(isequal(T{:, 2}, v2), [t 'T{:, 2} == v2']);
        t_ok(isequal(T{:, 3}, v3), [t 'T{:, 3} == v3']);
        t_ok(isequal(T{:, 4}, v4), [t 'T{:, 4} == v4']);
        t_ok(isequal(T{:, 5}, v5), [t 'T{:, 5} == v5']);
        t_ok(isequal(T{:, 6}, v6), [t 'T{:, 6} == v6']);
    end

    t_ok(isequal(T{2, 1}, v1(2)), [t 'T{i, j} == v<j>(i)']);
    if skip_oct_tab
        t_skip(1, [t 'T{i, j} syntax not yet supported for matrices'])
    else
        t_ok(isequal(T{4, 6}, v6(4, :)), [t 'T{i, j} == v<j>(i)']);
    end

    %% remove skip_oct_tab when
    %% https://github.com/apjanke/octave-tablicious/pull/89 is merged
    if skip_oct_tab
        t_skip(1, [t 'T{end, end} syntax not yet supported'])
    else
        t_ok(isequal(T{end, end}, v6(end,:)), [t 'T{end, end} == v<end>(end,:)']);
    end
    if skip_oct_tab
        t_skip(8, [t 'T{ii, j} syntax not yet supported'])
    else
        t_ok(isequal(T{1:3, 2}, v2(1:3)), [t 'T{i1:iN, j} == v<j>(i1:iN)']);
        t_ok(isequal(T{1:3, 6}, v6(1:3, :)), [t 'T{i1:iN, j} == v<j>(i1:iN, :)']);
        t_ok(isequal(T{[6;3], 5}, v5([6;3])), [t 'T{ii, j} == v<j>(ii)']);
        t_ok(isequal(T{[6;3], 6}, v6([6;3], :)), [t 'T{ii, j} == v<j>(ii, :)']);
        t_ok(isequal(T{6:-1:3, [2;4;5]}, [v2(6:-1:3) v4(6:-1:3) v5(6:-1:3)]), [t 'T{iN:-1:i1, jj}']);
        t_ok(isequal(T{6:-1:3, [2;4;6]}, [v2(6:-1:3) v4(6:-1:3) v6(6:-1:3, :)]), [t 'T{iN:-1:i1, jj}']);
        t_ok(isequal(T{:, [4;1]}, [v4 v1]), [t 'T{:, jj} == [v<j1> v<j2> ...]']);
        t_ok(isequal(T{:, [4;6;1]}, [v4 v6 v1]), [t 'T{:, jj} == [v<j1> v<j2> ...]']);
    end

    t = sprintf('%s : subsasgn {} : ', cls);
    T{:, 1} = var1;
    t_is(T.igr, var1, 12, [t 'T{:, 1} = var1']);
    T{:, 2} = var2;
    t_is(T.flt, var2, 12, [t 'T{:, 2} = var2']);
    T{:, 3} = var3;
    t_ok(isequal(T.str, var3), [t 'T{:, 3} = var3']);
    T{:, 4} = var4;
    t_is(T.dbl, var4, 12, [t 'T{:, 4} = var4']);
    T{:, 5} = var5;
    t_is(T.boo, var5, 12, [t 'T{:, 5} = var5']);
    if skip_oct_tab
        t_skip(1, 'T{:, j} = M syntax not yet supported for matrices');
    else
        T{:, 6} = var6;
        t_is(T.mat, var6, 12, [t 'T{:, 6} = var6']);
    end

    T{2, 1} = v1(2);
    t_ok(isequal(T{2, 1}, v1(2)), [t 'T{i, j} = v<j>(i)']);
    if skip_oct_tab
        t_skip(1, 'T{i, j} = M syntax not yet supported for matrices');
    else
        T{4, 6} = v6(4, :);
        t_ok(isequal(T{4, 6}, v6(4, :)), [t 'T{i, j} = v<j>(i, :)']);
    end
    T{1:3, 2} = v2(1:3);
    t_ok(isequal(T.flt(1:3), v2(1:3)), [t 'T{i1:iN, j} = v<j>(i1:iN)']);
    if skip_oct_tab
        t_skip(2, 'T{i1:iN, j} = M syntax not yet supported for matrices');
    else
        T{1:3, 6} = v6(1:3, :);
        t_ok(isequal(T.mat(1:3, :), v6(1:3, :)), [t 'T{i1:iN, j} = v<j>(i1:iN, :)']);
        T{1:3, 6} = v6(1:3, [2; 1]);
        t_ok(isequal(T.mat(1:3, :), v6(1:3, [2; 1])), [t 'T{i1:iN, j} = v<j>(i1:iN, jj)']);
    end
    T{[6;3], 5} = v5([6;3]);
    t_ok(isequal(T.boo([6;3]), v5([6;3])), [t 'T{ii, j} = v<j>(ii)']);
    if skip_oct_tab
        t_skip(2, 'T{ii, j} = M syntax not yet supported for matrices');
    else
        T{[6;3], 6} = v6([6;3], :);
        t_ok(isequal(T.mat([6;3], :), v6([6;3], :)), [t 'T{ii, j} = v<j>(ii, :)']);
        T{[6;3], 6} = v6([6;3], [2;1]);
        t_ok(isequal(T.mat([6;3], :), v6([6;3], [2;1])), [t 'T{ii, j} = v<j>(ii, jj)']);
    end
    if skip_oct_tab
        t_skip(2, [t 'T{ii, jj} syntax not yet supported'])
    else
        T{6:-1:3, [2;4;6;5]} = [v2(6:-1:3) v4(6:-1:3) v6(6:-1:3, :) v5(6:-1:3)];
        t_ok(isequal(T{6:-1:3, [2;4;6;5]}, [v2(6:-1:3) v4(6:-1:3) v6(6:-1:3, :) v5(6:-1:3)]), [t 'T{iN:-1:i1, jj}']);
        T{:, [6;4;1]} = [v6 v4 v1];
        t_ok(isequal(T{:, [6;4;1]}, [v6 v4 v1]), [t 'T{:, jj} = [v<j1> v<j2> ...]']);
    end
    T{:, 1} = v1;
    T{:, 2} = v2;
    T{:, 3} = v3;
    T{:, 4} = v4;
    T{:, 5} = v5;
    if ~skip_oct_tab
        T{:, 6} = v6;
    end

    %% () indexing
    t = sprintf('%s : subsref () : T(ii,jj) : ', cls);
    ii = [2;4]; jj = [1;3;4;6];
    T2 = T(ii,jj);
% show_me(T2);
    t_is(size(T2), [2 4], 12, [t 'size']);
    t_ok(isequal(T2.Properties.VariableNames, var_names(jj)), [t 'VariableNames']);
    t_ok(isequal(table_values(T2), {v1(ii), v3(ii), v4(ii), v6(ii, :)}), [t 'VariableValues']);
    t_ok(isequal(T2.Properties.RowNames, row_names(ii)), [t 'RowNames']);
    if skip_oct_tab || skip_ml_tab
        t_skip(1, [t 'DimensionNames not yet supported'])
    else
        t_ok(isequal(T2.Properties.DimensionNames, dim_names), [t 'DimensionNames']);
    end

    t = sprintf('%s : subsref () : T(:,j1:s:jN) : ', cls);
    jj = [2:2:6];
    T2 = T(:,2:2:6);
% show_me(T2);
    t_is(size(T2), [6 3], 12, [t 'size']);
    t_ok(isequal(T2.Properties.VariableNames, var_names(jj)), [t 'VariableNames']);
    t_ok(isequal(table_values(T2), {v2, v4, v6}), [t 'VariableValues']);
    t_ok(isequal(T2.Properties.RowNames, row_names), [t 'RowNames']);
    if skip_oct_tab || skip_ml_tab
        t_skip(1, [t 'DimensionNames not yet supported'])
    else
        t_ok(isequal(T2.Properties.DimensionNames, dim_names), [t 'DimensionNames']);
    end

    t = sprintf('%s : subsref () : T(i1:s:iN,:)) : ', cls);
    ii = [1:2:5];
    T2 = T(1:2:5,:);
% show_me(T2);
    t_is(size(T2), [3 6], 12, [t 'size']);
    t_ok(isequal(T2.Properties.VariableNames, var_names), [t 'VariableNames']);
    t_ok(isequal(table_values(T2), {v1(ii), v2(ii), v3(ii), v4(ii), v5(ii), v6(ii, :)}), [t 'VariableValues']);
    t_ok(isequal(T2.Properties.RowNames, row_names(ii)), [t 'RowNames']);
    if skip_oct_tab || skip_ml_tab
        t_skip(1, [t 'DimensionNames not yet supported'])
    else
        t_ok(isequal(T2.Properties.DimensionNames, dim_names), [t 'DimensionNames']);
    end

    t = sprintf('%s : subsref () : T(i,j) : ', cls);
    T2 = T(5,4);
% show_me(T2);
    t_is(size(T2), [1 1], 12, [t 'size']);
    t_ok(isequal(T2.Properties.VariableNames, var_names(4)), [t 'VariableNames']);
    t_ok(isequal(table_values(T2), {v4(5)}), [t 'VariableValues']);
    t_ok(isequal(T2.Properties.RowNames, row_names(5)), [t 'RowNames']);
    if skip_oct_tab || skip_ml_tab
        t_skip(1, [t 'DimensionNames not yet supported'])
    else
        t_ok(isequal(T2.Properties.DimensionNames, dim_names), [t 'DimensionNames']);
    end
    T2 = T(3,6);
% show_me(T2);
    t_is(size(T2), [1 1], 12, [t 'size']);
    t_ok(isequal(T2.Properties.VariableNames, var_names(6)), [t 'VariableNames']);
    t_ok(isequal(table_values(T2), {v6(3, :)}), [t 'VariableValues']);
    t_ok(isequal(T2.Properties.RowNames, row_names(3)), [t 'RowNames']);
    if skip_oct_tab || skip_ml_tab
        t_skip(1, [t 'DimensionNames not yet supported'])
    else
        t_ok(isequal(T2.Properties.DimensionNames, dim_names), [t 'DimensionNames']);
    end

    %% remove skip_oct_tab
    %% when https://github.com/apjanke/octave-tablicious/pull/89 is merged
    if skip_oct_tab
        t_skip(5, sprintf('%s : T(end, end) not yet supported.', cls));
    else
        t = sprintf('%s : subsref () : T(end, end) : ', cls);
        T2 = T(end, end);
    % show_me(T2);
        t_is(size(T2), [1 1], 12, [t 'size']);
        t_ok(isequal(T2.Properties.VariableNames, var_names(6)), [t 'VariableNames']);
        t_ok(isequal(table_values(T2), {v6(end, :)}), [t 'VariableValues']);
        t_ok(isequal(T2.Properties.RowNames, row_names(end)), [t 'RowNames']);
        if skip_oct_tab || skip_ml_tab
            t_skip(1, [t 'DimensionNames not yet supported'])
        else
            t_ok(isequal(T2.Properties.DimensionNames, dim_names), [t 'DimensionNames']);
        end
    end

    if skip_oct_tab
        t_skip(20, sprintf('%s : subsasgn () not yet supported.', cls));
    else
        t = sprintf('%s : subsasgn () : T(ii,jj) : ', cls);
        ii0 = [2;4]; jj = [1;3;4;6];
        T3 = T(ii0,jj);
        ii = [4;2];
        T(ii,jj) = T3;
        T2 = T(ii,jj);
        t_ok(isequal(T2.Properties.VariableNames, var_names(jj)), [t 'VariableNames']);
        t_ok(isequal(table_values(T2), {v1(ii0), v3(ii0), v4(ii0), v6(ii0, :)}), [t 'VariableValues']);
        t_ok(isequal(T2.Properties.RowNames, row_names(ii)), [t 'RowNames']);
        if skip_oct_tab || skip_ml_tab
            t_skip(1, [t 'DimensionNames not yet supported'])
        else
            t_ok(isequal(T2.Properties.DimensionNames, dim_names), [t 'DimensionNames']);
        end
        T(ii0, jj) = T2;        %% restore

        t = sprintf('%s : subsasgn () : T(:,j1:s:jN) : ', cls);
        jj = [2:2:6];
        T3 = T(end:-1:1,2:2:6);
        T(:,2:2:6) = T3;
        T2 = T(:,2:2:6);
        t_ok(isequal(T2.Properties.VariableNames, var_names(jj)), [t 'VariableNames']);
        t_ok(isequal(table_values(T2), {v2(end:-1:1), v4(end:-1:1), v6(end:-1:1, :)}), [t 'VariableValues']);
        t_ok(isequal(T2.Properties.RowNames, row_names), [t 'RowNames']);
        if skip_oct_tab || skip_ml_tab
            t_skip(1, [t 'DimensionNames not yet supported'])
        else
            t_ok(isequal(T2.Properties.DimensionNames, dim_names), [t 'DimensionNames']);
        end
        T(end:-1:1,2:2:6) = T3;     %% restore

        t = sprintf('%s : subsasgn () : T(i1:s:iN,:)) : ', cls);
        ii0 = [1:2:5];
        T3 = T(1:2:5,:);
        ii = [5:-2:1];
        T(5:-2:1, :) = T3;
        T2 = T(5:-2:1, :);
        t_ok(isequal(T2.Properties.VariableNames, var_names), [t 'VariableNames']);
        t_ok(isequal(table_values(T2), {v1(ii0), v2(ii0), v3(ii0), v4(ii0), v5(ii0), v6(ii0, :)}), [t 'VariableValues']);
        t_ok(isequal(T2.Properties.RowNames, row_names(ii)), [t 'RowNames']);
        if skip_oct_tab || skip_ml_tab
            t_skip(1, [t 'DimensionNames not yet supported'])
        else
            t_ok(isequal(T2.Properties.DimensionNames, dim_names), [t 'DimensionNames']);
        end
        T(1:2:5, :) = T3;   %% restore

        t = sprintf('%s : subsref () : T(i,j) : ', cls);
        T3 = T(5,4);
        T3{1,1} = exp(1);
        T(5,4) = T3;
        T2 = T(5,4);
        t_ok(isequal(T2.Properties.VariableNames, var_names(4)), [t 'VariableNames']);
        t_ok(isequal(table_values(T2), {exp(1)}), [t 'VariableValues']);
        t_ok(isequal(T2.Properties.RowNames, row_names(5)), [t 'RowNames']);
        if skip_oct_tab || skip_ml_tab
            t_skip(1, [t 'DimensionNames not yet supported'])
        else
            t_ok(isequal(T2.Properties.DimensionNames, dim_names), [t 'DimensionNames']);
        end
        T{5,4} = pi;

        T3 = T(3,6);
        T3{1,1} = [111 222];
        T(3,6) = T3;
        T2 = T(3,6);
        t_ok(isequal(T2.Properties.VariableNames, var_names(6)), [t 'VariableNames']);
        t_ok(isequal(table_values(T2), {[111 222]}), [t 'VariableValues']);
        t_ok(isequal(T2.Properties.RowNames, row_names(3)), [t 'RowNames']);
        if skip_oct_tab || skip_ml_tab
            t_skip(1, [t 'DimensionNames not yet supported'])
        else
            t_ok(isequal(T2.Properties.DimensionNames, dim_names), [t 'DimensionNames']);
        end
        T{3,6} = [3 0.3];
    end

    %% vertical concatenation
    t = sprintf('%s : vertical concatenation : ', cls);
    T1 = T(1:3, :);
    T2 = T(4:6, :);
    T3 = T([4:6 1:3], :);
    T4 = [T2; T1];
    t_ok(isequal(T4, T3), [t '[T1;T2]']);
    T5 = table_class([7;8],[7.7;8.8],{'seven';'eight'},1./[7;8],[-1;2]<=0, [70 75; 80 85], ...
        'VariableNames', var_names);
    if skip_oct_tab
        t_skip(1, [t 'RowNames auto-generation not yet supported']);
    else
        T6 = [T5; T2; T1];
        t_ok(isequal(T6, [T5;T3]), [t '[T1;T2;T3]']);
    end

    %% horizontal concatenation
    t = sprintf('%s : horizontal concatenation : ', cls);
    T1 = T(:, 1:3);
    T2 = T(:, 4:6);
    T3 = T(:, [4:6 1:3]);
    T4 = [T2 T1];
    t_ok(isequal(T4, T3), [t '[T1 T2]']);
    T5 = table_class(var3, var2);
    T6 = [T2 T1 T5];
    t_ok(isequal(T6, [T4 T5]), [t '[T1 T2 T3]']);

    %% deleting variables
    t = sprintf('%s : delete variables : ', cls);
    if skip_oct_tab
        t_skip(1, [t 'not yet supported']);
    else
        T7 = T;
        T7(:, [5 6 4]) = [];
        t_ok(isequal(T7, T1), [t 'T(:, j) = []']);
    end

    %% adding variables
    t = sprintf('%s : add variables : ', cls);
    T7 = T1;
    T7.dbl = T2.dbl;
    T7.boo = T2.boo;
    T7.mat = T2.mat;
    t_ok(isequal(T7, T), [t 'T.new_var = val']);

    %% more {} indexing
    t = sprintf('%s : more subsref {} : ', cls);
    T2 = T(:, [1;2;4;6;5]);
    T3 = T6(:, 6:7);
    ii = [5;3;1];
    jj = [6:7];
    if skip_oct_tab
        t_skip(6, [t 'T{ii, :} syntax not yet supported'])
    else
        ex = horzcat(v3, var3);
        t_is(T2{ii, :}, [v1(ii) v2(ii) v4(ii) v6(ii, :) v5(ii)], 12, [t 'T{ii,:} (double)']);
        t_is(T2{:, :}, [v1 v2 v4 v6 v5], 12, [t 'T{:,:} (double)']);
        t_ok(isequal(T6{ii, 6:7}, ex(ii, :)), [t 'T{ii,j1:j2} (cell)']);
        t_ok(isequal(T6{:, 6:7}, ex), [t 'T{:,j1:j2} (cell)']);
        t_ok(isequal(T3{ii, :}, ex(ii, :)), [t 'T{ii,:} (cell)']);
        t_ok(isequal(T3{:, :}, ex), [t 'T{:,:} (cell)']);
    end

    t = sprintf('%s : more subsasgn {} : ', cls);
    if skip_oct_tab
        t_skip(6, [t 'T{ii, :} syntax not yet supported'])
    else
        T2{ii, :} = [var1(ii) var2(ii) var4(ii) var6(ii, :) var5(ii)];
        t_is(T2{ii, :}, [var1(ii) var2(ii) var4(ii) var6(ii, :) var5(ii)], 12, [t 'T{ii,:} (double)']);
        T2{:, :} = [v1 v2 v4 v6 v5];
        t_is(T2{:, :}, [v1 v2 v4 v6 v5], 12, [t 'T{:,:} (cell)']);
        v1 = horzcat(var3, v3);
        v2 = horzcat(v3, var3);
        T6{ii, 6:7} = v1(ii, :);
        t_ok(isequal(T6{ii, 6:7}, v1(ii, :)), [t 'T{ii,j1:j2} (cell)']);
        T6{:, 6:7} = v2;
        t_ok(isequal(T6{:, 6:7}, v2), [t 'T{:,j1:j2} (cell)']);
        T3{ii, :} = v1(ii, :);
        t_ok(isequal(T3{ii, :}, v1(ii, :)), [t 'T{ii,:} (cell)']);
        T3{:, :} = v2;
        t_ok(isequal(T3{:, :}, v2), [t 'T{:,:} (cell)']);
    end

    %% value class, not handle class
    t = sprintf('%s : value class, not handle', cls);
    T2 = T;
    T.igr(2) = 2;
    t_is(T.igr(2), 2, 12, t);
    t_is(T2.igr(2), 55, 12, t);

    %% nested tables
    t = sprintf('%s : nested tables : ', cls);
    T1 = table_class([1;2;3],[4;5;6]);
    T2 = table_class({'one';'two';'three'},{'four';'five';'six'});
    T3 = table_class([10;20;30],{'uno';'dos';'tres'}, T1, T2);
    t_ok(isequal(T3.T1, T1), [t 'T.T1 == T1']);
    t_ok(isequal(T3.T2, T2), [t 'T.T2 == T2']);
    t_ok(isequal(T3.T1([1;3], :), T1([1;3], :)), [t 'T.T1(ii, :) == T1(ii, :)']);
    t_ok(isequal(T3.T2([1;3], :), T2([1;3], :)), [t 'T.T2(ii, :) == T2(ii, :)']);
    t_ok(isequal(T3.T1.Var1, T1.Var1), [t 'T.T1.Var1 == T1.Var1']);
    t_ok(isequal(T3.T2.Var2([1;3], :), T2.Var2([1;3], :)), [t 'T.T2.Var2(ii) == T.T2.Var2(ii)']);
    %% check for Octave trouble in subsref
    T4 = T3(:, :);
    T5 = T3([1;2;3], :);
    t_ok(isequal(T3, T4), [t 'T == T(:, :))']);
    t_ok(isequal(T3, T5), [t 'T == T(ii, :))']);
end

if nargout
    obj = T;
end

t_end;

function Tv = table_values(T)
if isa(T, 'table') && have_feature('matlab')
    Tv = cellfun(@(c)T{:, c}, num2cell(1:size(T, 2)), 'UniformOutput', false);
else
    Tv = T.Properties.VariableValues;
end

function show_me(T)
if isa(T, 'table') && have_feature('octave')
    prettyprint(T)
else
    T
end


% File:   itload.m
% Brief:  Load an IT++ itfile content to Matlab/Octave workspace
% Author: Tony Ottosson and Adam Piatyszek
%
% Usage: itload("fname.it")
%
% This functions loads all variables from an IT++ file format to the
% Matlab/Octave workspace.
%
% -------------------------------------------------------------------------
%
% Copyright (C) 1995-2010  (see AUTHORS file for a list of contributors)
%
% This file is part of IT++ - a C++ library of mathematical, signal
% processing, speech processing, and communications classes and functions.
%
% IT++ is free software: you can redistribute it and/or modify it under the
% terms of the GNU General Public License as published by the Free Software
% Foundation, either version 3 of the License, or (at your option) any
% later version.
%
% IT++ is distributed in the hope that it will be useful, but WITHOUT ANY
% WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
% FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
% details.
%
% You should have received a copy of the GNU General Public License along
% with IT++.  If not, see <http://www.gnu.org/licenses/>.
%
% -------------------------------------------------------------------------

function itload(fname)

[fid, err_msg] = fopen(fname, 'rb', 'ieee-le');
if (fid == -1)
  fname = [fname '.it'];
  [fid, err_msg2] = fopen(fname, 'rb', 'ieee-le');
  if (fid == -1)
    error(err_msg);
  end
end

% Check file size
fseek(fid, 0, 'eof');
file_size = ftell(fid);
fseek(fid, 0, 'bof');

% Read "IT++" magic string
[d, n] = fread(fid, 5, 'char');
if (n ~= 5 | d(1:4) ~= [73 84 43 43]')
  error('Not an IT++ file!');
end

% Check the IT++ file version
if (d(5) ~= 3)
  error('Only IT++ file version 3 is supported by this function!');
end

while (1)
  p = ftell(fid); % Save current file position
  [d1, n] = fread(fid, 3, 'uint64'); % Read header, data, and total block sizes
  name = fgetstr(fid); % Read current variable name
  type = fgetstr(fid); % Read current variable type
  fseek(fid, p+d1(1), 'bof'); % Skip header bytes

  if (length(type) == 0) % A deleted entry -> skip it

  % --- bin ---
  elseif (strcmp(type, 'bin'))
    [d, n] = fread(fid, 1, 'char');
    assignin('caller', name, d);
  % --- int8 (char) ---
  elseif (strcmp(type, 'int8'))
    [d, n] = fread(fid, 1, 'int8');
    assignin('caller', name, d);
  % --- int16 (short) ---
  elseif (strcmp(type, 'int16'))
    [d, n] = fread(fid, 1, 'int16');
    assignin('caller', name, d);
  % --- int32 (int) ---
  elseif (strcmp(type, 'int32'))
    [d, n] = fread(fid, 1, 'int32');
    assignin('caller', name, d);
  % --- float32 (float) ---
  elseif (strcmp(type, 'float32'))
    [d, n] = fread(fid, 1, 'float32');
    assignin('caller', name, d);
  % --- float64 (double) ---
  elseif (strcmp(type, 'float64'))
    [d, n] = fread(fid, 1, 'float64');
    assignin('caller', name, d);
  % --- cfloat32 (complex<float>) ---
  elseif (strcmp(type, 'cfloat32'))
    [d, n] = fread(fid, 2, 'float32');
    d = complex(d(1), d(2));
    assignin('caller', name, d);
  % --- cfloat64 (complex<double>) ---
  elseif (strcmp(type, 'cfloat64'))
    [d, n] = fread(fid, 2, 'float64');
    d = complex(d(1), d(2));
    assignin('caller', name, d);

  % --- bvec ---
  elseif (strcmp(type, 'bvec'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size, 'char');
    assignin('caller', name, d);
  % --- svec ---
  elseif (strcmp(type, 'svec'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size, 'int16');
    assignin('caller', name, d);
  % --- ivec ---
  elseif (strcmp(type, 'ivec'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size, 'int32');
    assignin('caller', name, d);
  % --- fvec ---
  elseif (strcmp(type, 'fvec'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size, 'float32');
    assignin('caller', name, d);
  % --- dvec ---
  elseif (strcmp(type, 'dvec'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size, 'float64');
    assignin('caller', name, d);
  % --- fcvec ---
  elseif (strcmp(type, 'fcvec'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size*2, 'float32');
    d = complex(d(1:2:end), d(2:2:end));
    assignin('caller', name, d);
  % --- dcvec ---
  elseif (strcmp(type, 'dcvec'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size*2, 'float64');
    d = complex(d(1:2:end), d(2:2:end));
    assignin('caller', name, d);
  % --- string ---
  elseif (strcmp(type, 'string'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size, 'char');
    d = char(d);
    assignin('caller', name, d);

  % --- bmat ---
  elseif (strcmp(type, 'bmat'))
    [size, n] = fread(fid, 2, 'uint64');
    [d, n] = fread(fid, size', 'char');
    assignin('caller', name, d);
  % --- smat ---
  elseif (strcmp(type, 'smat'))
    [size, n] = fread(fid, 2, 'uint64');
    [d, n] = fread(fid, size', 'int16');
    assignin('caller', name, d);
  % --- imat ---
  elseif (strcmp(type, 'imat'))
    [size, n] = fread(fid, 2, 'uint64');
    [d, n] = fread(fid, size', 'int32');
    assignin('caller', name, d);
  % --- fmat ---
  elseif (strcmp(type, 'fmat'))
    [size, n] = fread(fid, 2, 'uint64');
    [d, n] = fread(fid, size', 'float32');
    assignin('caller', name, d);
  % --- dmat ---
  elseif (strcmp(type, 'dmat'))
    [size, n] = fread(fid, 2, 'uint64');
    [d, n] = fread(fid, size', 'float64');
    assignin('caller', name, d);
  % --- fcmat ---
  elseif (strcmp(type, 'fcmat'))
    [size, n] = fread(fid, 2, 'uint64');
    [d, n] = fread(fid, size(1)*size(2)*2, 'float32');
    d = reshape(complex(d(1:2:end), d(2:2:end)), size(1), size(2));
    assignin('caller', name, d);
  % --- dcmat ---
  elseif (strcmp(type, 'dcmat'))
    [size, n] = fread(fid, 2, 'uint64');
    [d, n] = fread(fid, size(1)*size(2)*2, 'float64');
    d = reshape(complex(d(1:2:end), d(2:2:end)), size(1), size(2));
    assignin('caller', name, d);

  % --- bArray ---
  elseif (strcmp(type, 'bArray'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size, 'char');
    assignin('caller', name, d);
  % --- sArray ---
  elseif (strcmp(type, 'sArray'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size, 'int16');
    assignin('caller', name, d);
  % --- iArray ---
  elseif (strcmp(type, 'iArray'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size, 'int32');
    assignin('caller', name, d);
  % --- fArray ---
  elseif (strcmp(type, 'fArray'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size, 'float32');
    assignin('caller', name, d);
  % --- dArray ---
  elseif (strcmp(type, 'dArray'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size, 'float64');
    assignin('caller', name, d);
  % --- fcArray ---
  elseif (strcmp(type, 'fcArray'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size*2, 'float32');
    d = complex(d(1:2:end), d(2:2:end));
    assignin('caller', name, d);
  % --- dcArray ---
  elseif (strcmp(type, 'dcArray'))
    [size, n] = fread(fid, 1, 'uint64');
    [d, n] = fread(fid, size*2, 'float64');
    d = complex(d(1:2:end), d(2:2:end));
    assignin('caller', name, d);

  % --- bvecArray ---
  elseif (strcmp(type, 'bvecArray'))
    [size, n] = fread(fid, 1, 'uint64');
    clear d2;
    for i=1:size;
      [size2, n] = fread(fid, 1, 'uint64');
      [d, n] = fread(fid, size2, 'char');
      d2{i} = d;
    end
    assignin('caller', name, d2);
  % --- svecArray ---
  elseif (strcmp(type, 'svecArray'))
    [size, n] = fread(fid, 1, 'uint64');
    clear d2;
    for i=1:size;
      [size2, n] = fread(fid, 1, 'uint64');
      [d, n] = fread(fid, size2, 'int16');
      d2{i} = d;
    end
    assignin('caller', name, d2);
  % --- ivecArray ---
  elseif (strcmp(type, 'ivecArray'))
    [size, n] = fread(fid, 1, 'uint64');
    clear d2;
    for i=1:size;
      [size2, n] = fread(fid, 1, 'uint64');
      [d, n] = fread(fid, size2, 'int32');
      d2{i} = d;
    end
    assignin('caller', name, d2);
  % --- vecArray ---
  elseif (strcmp(type, 'vecArray'))
    [size, n] = fread(fid, 1, 'uint64');
    clear d2;
    for i=1:size;
      [size2, n] = fread(fid, 1, 'uint64');
      [d, n] = fread(fid, size2, 'float64');
      d2{i} = d;
    end
    assignin('caller', name, d2);
  % --- cvecArray ---
  elseif (strcmp(type, 'cvecArray'))
    [size, n] = fread(fid, 1, 'uint64');
    clear d2;
    for i=1:size;
      [size2, n] = fread(fid, 1, 'uint64');
      [d, n] = fread(fid, size2*2, 'float64');
      d2{i} = complex(d(1:2:end), d(2:2:end));
    end
    assignin('caller', name, d2);
  % --- stringArray ---
  elseif (strcmp(type, 'stringArray'))
    [size, n] = fread(fid, 1, 'uint64');
    clear d2;
    for i=1:size;
      [size2, n] = fread(fid, 1, 'uint64');
      [d, n] = fread(fid, size2, 'char');
      d2{i} = char(d);
    end
    assignin('caller', name, d2);

  % --- bmatArray ---
  elseif (strcmp(type, 'bmatArray'))
    [size, n] = fread(fid, 1, 'uint64');
    clear d2;
    for i=1:size;
      [size2, n] = fread(fid, 2, 'uint64');
      [d, n] = fread(fid, size2', 'char');
      d2{i} = d;
    end
    assignin('caller', name, d2);
  % --- smatArray ---
  elseif (strcmp(type, 'smatArray'))
    [size, n] = fread(fid, 1, 'uint64');
    clear d2;
    for i=1:size;
      [size2, n] = fread(fid, 2, 'uint64');
      [d, n] = fread(fid, size2', 'int16');
      d2{i} = d;
    end
    assignin('caller', name, d2);
  % --- imatArray ---
  elseif (strcmp(type, 'imatArray'))
    [size, n] = fread(fid, 1, 'uint64');
    clear d2;
    for i=1:size;
      [size2, n] = fread(fid, 2, 'uint64');
      [d, n] = fread(fid, size2', 'int32');
      d2{i} = d;
    end
    assignin('caller', name, d2);
  % --- matArray ---
  elseif (strcmp(type, 'matArray'))
    [size, n] = fread(fid, 1, 'uint64');
    clear d2;
    for i=1:size;
      [size2, n] = fread(fid, 2, 'uint64');
      [d, n] = fread(fid, size2', 'float64');
      d2{i} = d;
    end
    assignin('caller', name, d2);
  % --- cmatArray ---
  elseif (strcmp(type, 'cmatArray'))
    [size, n] = fread(fid, 1, 'uint64');
    clear d2;
    for i=1:size;
      [size2, n] = fread(fid, 2, 'uint64');
      [d, n] = fread(fid, size2(1)*size2(2)*2, 'float64');
      d2{i} = reshape(complex(d(1:2:end), d(2:2:end)), size2(1), size2(2));
    end
    assignin('caller', name, d2);

  % --- else ---
  else
    warning(['Not supported type: ' type]);
  end

  if (p + d1(3) >= file_size)
    break;
  else
    fseek(fid, p+d1(3), 'bof');
  end

end

fclose(fid);

function str = fgetstr(fid)
str = '';
while (1)
  [d, n] = fread(fid, 1, 'char');
  if (d == 0)
    break;
  end
  str = [str char(d)];
end


function disp( x, prefix )
if nargin < 2,
    prefix = '';
end
disp( [ prefix, 'cvx tuple object: ' ] );
prefix = [ prefix, '   ' ];
do_disp( x.value_, {}, prefix, prefix, '' );

function do_disp( x, f, fprefix, prefix, suffix )
switch class( x ),
    case 'struct',
        do_disp( struct2cell(x), fieldnames(x), fprefix, prefix, suffix );
    case 'cell',
        fprefix = [ fprefix, '{ ' ];
        prefix  = [ prefix, '  ' ];
        nsuffix = '';
        kend = numel( x );
        for k = 1 : kend,
            if k == kend, nsuffix = [ ' }', suffix ]; end
            if ~isempty( f ),
                fprefix = sprintf( '%s%s: ', fprefix, f{k} );
            end
            do_disp( x{k}, {}, fprefix, prefix, nsuffix );
            fprefix = prefix;
        end
    case 'cvx',
        dual = getdual( x );
        if ~isempty( dual ),
            suffix = sprintf( ' (dual: %s)%s', dual, suffix );
        end
        disp( [ fprefix, cvx_class( x, true, true ), ' ', type( x ), suffix ] );
    case 'double',
        fprintf( 1, '%s%g%s\n', fprefix, x, suffix );
end

% Copyright 2010 Michael C. Grant and Stephen P. Boyd.
% See the file COPYING.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function dump_error(list, errimg, errdet, misimg, misdet, gt, root)
% dump_error(list, error_img, err_detail, miss_image, miss_detail, 'error_dump/')
    if nargin < 7
        dump = false;
    else
        dump = true;
    end
    all_neg = errimg; %union(errimg, misimg);
    for i = 1 : length(all_neg)
        id = all_neg(i);
        fprintf('%d...\n', id);
        img = imread(list{id});
        gtt = gt{i};
        gtt = [gtt(:,[1 2]) gtt(:,3)-gtt(:,1) gtt(:,4)-gtt(:,2)];
        img = insertShape(img, 'rectangle', gtt, 'Color', 'yellow', 'LineWidth', 2);
        if(any(errimg==id))
            err = errdet{id};
            err = [err(:,[1 2]) err(:,3)-err(:,1) err(:,4)-err(:,2)];
            img = insertShape(img, 'rectangle', err, 'Color', 'yellow', 'LineWidth', 2);
        end
        if(any(misimg==id))
            err = misdet{id};
            err = [err(:,[1 2]) err(:,3)-err(:,1) err(:,4)-err(:,2)];
            img = insertShape(img, 'rectangle', err, 'Color', 'red', 'LineWidth', 2);
        end
        hold off;
        imshow(img);
        if dump
            imwrite(img, fullfile(root, [num2str(id) '.jpg']));
        end
        waitforbuttonpress;
    end

end


function opt = mpoption_info_most(selector)
%MPOPTION_INFO_MOST  Returns MATPOWER option info for MOST.
%
%   DEFAULT_OPTS = MPOPTION_INFO_MOST('D')
%   VALID_OPTS   = MPOPTION_INFO_MOST('V')
%   EXCEPTIONS   = MPOPTION_INFO_MOST('E')
%
%   Returns a structure for MOST options for MATPOWER containing ...
%   (1) default options,
%   (2) valid options, or
%   (3) NESTED_STRUCT_COPY exceptions for setting options
%   ... depending on the value of the input argument.
%
%   This function is used by MPOPTION to set default options, check validity
%   of option names or modify option setting/copying behavior for this
%   subset of optional MATPOWER options.
%
%   See also MPOPTION.

%   MOST
%   Copyright (c) 2014-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MOST.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://github.com/MATPOWER/most for more info.

if nargin < 1
    selector = 'D';
end
if have_feature('most')
    switch upper(selector)
        case {'D', 'V'}     %% default and valid options
            opt = struct(...
                'most',   struct(...
                    'build_model',                  1, ...          %% was md.CreateQP
                    'solve_model',                  1, ...          %% was md.Solve
                    'resolve_new_cost',             0, ...          %% was md.ReSolveNewCoordCost
                    'dc_model',                     1, ...          %% was md.DCMODEL = []
                    'fixed_res',                    -1, ...         %% was md.IncludeFixedReserves = []
                    'q_coordination',               0, ...          %% was md.QCoordination
                    'security_constraints',         -1, ...         %% was md.SecurityConstrained = []
                    'storage',                      struct(...
                        'terminal_target',              -1, ...     %% was md.Storage.ForceExpectedTerminalStorage
                        'cyclic',                       0), ...     %% was md.Storage.ForceCyclicStorage
                    'uc',                           struct(...
                        'run',                          -1, ...     %% was missing
                        'cyclic',                       0), ...     %% was md.UC.CyclicCommitment
                    'alpha',                        0, ...          %% was md.alpha
                    'solver',                       'DEFAULT', ...  %% was md.QP.opt.alg
                    'skip_prices',                  0, ...          %% was md.QP.opt.skip_prices
                    'price_stage_warn_tol',         1e-7 ...
                ) ...
            );
        case 'E'            %% exceptions used by nested_struct_copy() for applying
            opt = struct([]);   %% no exceptions
        otherwise
            error('mpoption_info_most: ''%s'' is not a valid input argument', selector);
    end
else
    opt = struct([]);       %% MOST is not available
end


function img = ldrimread(filename, bDouble)
%
%       img = ldrimread(filename, bDouble)
%
%
%        Input:
%           -filename: the name of the file to open
%
%        Output:
%           -img: the opened image
%
%     Copyright (C) 2011-15  Francesco Banterle
%
%     This program is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
%     This program is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%     GNU General Public License for more details.
%
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see <http://www.gnu.org/licenses/>.
%

if(~exist('filename', 'var'))
    error('A filename with extension needs to be passed as input!');
end

if(~exist('bDouble', 'var'))
    bDouble = 1;
end

img = [];

try
    image_info = imfinfo(filename);

    if((image_info.BitDepth == 24) || (image_info.BitDepth == 8))
        if(bDouble)
            img = double(imread(filename)) / 255.0;
        else
            img = single(imread(filename)) / 255.0;
        end
    end

    if(image_info.BitDepth == 48)
        if(bDouble)
            img = double(imread(filename)) / 65535.0;
        else
            img = single(imread(filename)) / 65535.0;
        end
    end

catch err
    disp(['Error in reading ', filename]);
end

end


function STMuNet_test(varargin)

if ~isempty(gcp('nocreate'))
    delete(gcp)
end

opts.train.gpus = [ 1 ] ;

opts = cnn_setup_environment(opts);
opts.nSplit =  1 ;

% opts.dataSet = 'hmdb51';
opts.dataSet = 'ucf101';

model = ['ST-MulNet-img50-flow50-final-split=' num2str(opts.nSplit)];
model = ['ST-MulNet-img50-flow152-split=' num2str(opts.nSplit)];

opts.train.memoryMapFile = fullfile(tempdir, 'ramdisk', ['matconvnet' num2str(opts.nSplit ) '.bin']) ;
opts.dataDir = fullfile(opts.dataPath, opts.dataSet) ;
opts.splitDir = 'ucf101_splits'; nClasses = 101;
opts.imdbPath = fullfile(opts.dataDir, [opts.dataSet '_split' num2str(opts.nSplit) 'imdb.mat']);
opts.model = fullfile(opts.modelPath, [opts.dataSet model '.mat']) ;
opts.expDir = fullfile(opts.dataDir, [opts.dataSet '-' model]) ;
[opts, varargin] = vl_argparse(opts, varargin) ;

opts.train.saveAllPredScores = 1;
opts.train.denseEval = 1;
opts.train.plotDiagnostics = 0 ;
opts.train.continue = 1 ;
opts.train.prefetch = 1 ;
opts.train.expDir = opts.expDir ;
opts.train.numAugments = 1;
opts.train.frameSample = 'random';

opts = vl_argparse(opts, varargin) ;

% -------------------------------------------------------------------------
%                                                   Database initialization
% -------------------------------------------------------------------------
if exist(opts.imdbPath)
  imdb = load(opts.imdbPath) ;
  imdb.flowDir = opts.flowDir;
else
  imdb = cnn_setup_data(opts) ;
  save(opts.imdbPath, '-struct', 'imdb', '-v6') ;
end

% -------------------------------------------------------------------------
%                                                    Network initialization
% -------------------------------------------------------------------------
if ~exist(opts.model,'file')
  [~, baseModel] = fileparts(opts.model);
  fprintf('Downloading base model file: %s ...\n', baseModel);
  mkdir(fileparts(opts.model)) ;
  urlwrite(...
  ['http://ftp.tugraz.at/pub/feichtenhofer/st-mul/final/' baseModel '.mat'], ...
    opts.model) ;
end
net = load(opts.model) ;

if isfield(net, 'net'), net=net.net;end
net = dagnn.DagNN.loadobj(net);

opts.train.augmentation = 'f25noCtr';
opts.train.frameSample = 'temporalStrideRandom';
opts.train.nFramesPerVid = 1;
opts.train.temporalStride = 1:15;
opts.train.valmode = 'temporalStrideRandom';
opts.train.numValFrames = 25 ;
opts.train.saveAllPredScores = 1 ;
opts.train.denseEval = 1;
opts.train.temporalFullConvTest = 1;

opts.train.train = NaN;

net.rebuild() ;

net.conserveMemory = 1 ;
fn = getBatchWrapper_rgbflow(net.meta.normalization, opts.numFetchThreads, opts.train) ;
[info] = cnn_train_dag(net, imdb, fn, opts.train) ;


classdef TestImwrite
    %TestImwrite

    properties (Constant)
        im = cv.imread(fullfile(mexopencv.root(),'test','fruits.jpg'), 'ReduceScale',2);
    end

    methods (Static)
        function test_write
            frmts = TestImwrite.getFormats();
            for i=1:numel(frmts)
                filename = [tempname() frmts(i).ext];
                cObj = onCleanup(@() TestImwrite.deleteFile(filename));
                try
                    if strcmp(frmts(i).ext, '.exr')
                        img = single(TestImwrite.im) / 255;
                    else
                        img = TestImwrite.im;
                    end
                    if any(strcmp(frmts(i).ext, {'.pbm', '.pgm'}))
                        img = cv.cvtColor(img, 'RGB2GRAY');
                    end
                    cv.imwrite(filename, img, frmts(i).opts{:});
                    assert(exist(filename,'file')==2, ...
                        'Failed to write %s', frmts(i).name);
                catch ME
                    %TODO: some codecs are not available on all platforms
                    %error('mexopencv:testskip', 'codecs %s (%s)', ...
                    %    frmts(i).name, frmts(i).ext);
                    continue;
                end
            end
        end

        function test_write_multi
            if true
                fname = which('mri.mat');
                if isempty(fname)
                    error('mexopencv:testskip', 'missing data');
                end
                mri = load(fname);
                imgs = cell(size(mri.D,4), 1);
                for i=1:size(mri.D,4)
                    imgs{i} = ind2gray(mri.D(:,:,1,i), mri.map);
                end
            else
                fnames = dir(fullfile(toolboxdir('images'), 'imdata', 'AT3_*.tif'));
                if isempty(fnames)
                    error('mexopencv:testskip', 'missing data');
                end
                imgs = cell(numel(fnames), 1);
                for i=1:numel(fnames)
                    imgs{i} = imread(fullfile(fnames(i).folder, fnames(i).name));
                end
            end

            filename = [tempname() '.tiff'];
            cObj = onCleanup(@() TestImwrite.deleteFile(filename));

            cv.imwrite(filename, imgs);
            assert(exist(filename,'file')==2, 'Failed to write TIFF');
        end

        function test_verify_lossless_png
            filename = [tempname() '.png'];
            cObj = onCleanup(@() TestImwrite.deleteFile(filename));

            % write image to PNG file (lossless)
            cv.imwrite(filename, TestImwrite.im);
            assert(exist(filename,'file')==2, 'Failed to write PNG');

            % read back image from disk
            img = imread(filename);

            % compare
            assert(isequal(img, TestImwrite.im), 'Images are not equal');
        end

        function test_flip_channels
            filename1 = [tempname() '.png'];
            filename2 = [tempname() '.png'];
            cObj1 = onCleanup(@() TestImwrite.deleteFile(filename1));
            cObj2 = onCleanup(@() TestImwrite.deleteFile(filename2));

            cv.imwrite(filename1, TestImwrite.im, 'FlipChannels',false);
            cv.imwrite(filename2, TestImwrite.im, 'FlipChannels',true);
            im1 = imread(filename1);
            im2 = imread(filename2);
            assert(isequal(im1, flipdim(im2,3)), 'FlipChannels option failed');
        end

        function test_error_argnum
            try
                cv.imwrite();
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end

        function test_error_unrecognized_extension
            %TODO: crashes Octave
            if true
                error('mexopencv:testskip', 'todo');
            end

            try
                cv.imwrite('image.foobar', TestImwrite.im);
                throw('UnitTest:Fail');
            catch e
                %TODO: C++ exception thrown by OpenCV
                %assert(strcmp(e.identifier,'MATLAB:unexpectedCPPexception'));
            end
        end
    end

    %% helper functions
    methods (Static)
        function deleteFile(fname)
            if exist(fname, 'file') == 2
                delete(fname);
            end
        end

        function frmts = getFormats()
            frmts = repmat(struct('name','', 'ext','', 'opts',{{}}), 11, 1);
            frmts(1).name = 'JPEG';
            frmts(1).ext = '.jpg';
            frmts(1).opts = {'JpegQuality',90, 'JpegProgressive',false, ...
                'JpegOptimize',false, 'JpegResetInterval',0, ...
                'JpegLumaQuality',0, 'JpegChromaQuality',0};
            frmts(2).name = 'PNG';
            frmts(2).ext = '.png';
            frmts(2).opts = {'PngCompression',9, 'PngStrategy','RLE'};
            frmts(3).name = 'PPM';
            frmts(3).ext = '.ppm';
            frmts(3).opts = {'PxmBinary',false};
            frmts(4).name = 'TIFF';
            frmts(4).ext = '.tif';
            frmts(5).name = 'BMP';
            frmts(5).ext = '.bmp';
            frmts(6).name = 'WebP';
            frmts(6).ext = '.webp';
            frmts(7).name = 'Sun Raster';
            frmts(7).ext = '.ras';
            frmts(8).name = 'JPEG-2000';
            frmts(8).ext = '.jp2';
            frmts(9).name = 'OpenEXR';
            frmts(9).ext = '.exr';
            frmts(9).opts = {'ExrType','Float'};
            frmts(10).name = 'Radiance HDR';
            frmts(10).ext = '.hdr';
            frmts(11).name = 'PAM';
            frmts(11).ext = '.pam';
            frmts(11).opts = {'PamTupleType','RGB'};
        end
    end

end


function readAllDICOM(pathRead,pathSave,nBatch,nameSaveOption)
% -------------------------------------------------------------------------
% function readAllDICOM(pathRead,pathSave,batchFlag,nameSaveOption)
% -------------------------------------------------------------------------
% DESCRIPTION:
% This function reads the DICOM content of all the sub-folder tree of a
% starting directory defined by 'pathRead'. It then organizes the data
% (files throughout the starting directory are associated by
% 'SeriesInstanceUID') in a cell of structures called 'sData' (stands for
% STAMP data), and it finally computes the region of interest (ROI) defined
% by an associated RTstruct, and save as well all the  REG, RTdose and
% RTplan structures(if present in the sub-folder tree of the starting
% directory).
% All sData structures hereby created are saved in 'pathSave' with a name
% varying with the variable 'nameSaveOption'.
%
% DIFFERENTIATION/ASSOCIATION OF DICOM FILES: 1)imaging, 2)RTstruct, 3)REG, 4)RTdose, 5)RTplan.
% 1) Imaging volumes are differentiated by the 'SeriesInstanceUID' field
% 2) Association between a RTstruct and an imaging volume is performed with:
%    - 'ReferencedFrameOfReferenceSequence.Item_1.FrameOfReferenceUID' field, or
%    - 'FrameOfReferenceUID' field.
% 3) Association between a REG and an imaging volume is performed with:
%    - 'RegistrationSequence.Item_2.FrameOfReferenceUID' field, or
%    - 'FrameOfReferenceUID' field.
% 4) Association between a RTdose and an imaging volume is performed with:
%    - 'FrameOfReferenceUID' field.
% 5) Association between a RTplan and an imaging volume is performed with:
%    - 'FrameOfReferenceUID' field.
%
% If multiple imaging volumes have the same 'FrameOfReferenceUID' field,
% they will all be assigned a RTstruct, REG, RTdose and RTplan possessing
% that same field.
%
% IMPORTANT: This function has only been tested on Ubuntu 14.04. May work
%            using MAC, will fail using Windows.
% -------------------------------------------------------------------------
% INPUTS:
% 1. pathRead: String specifying the full path to the starting directory
%              where the DICOM path to read are located.
%              --> Ex: '/home/myStudy/DICOM'
% 2. pathSave: String specifying the full path to the directory where to
%              save all the sData structures created by the current function.
%              --> Ex: '/home/myStudy/DATA'
% 3. nBatch: Numerical value specifying the number of batch to use in the
%            parallel computations (use 0 for serial).
%            --> Ex: 8
% 4. nameSaveOption: (optional). If this argument is not present (default)
%                    all sData structures will be saved with a filename
%                    defined by the 'Modality' field present in the
%                    DICOM header of their corresponding imaging volume. If
%                    multiple volumes of the same modality are present for
%                    the same 'PatientID', the different volumes will be
%                    numerated (e.g. CT1, CT2, CT3, etc.). If this argument
%                    is present and set to 'folder', all sData structures
%                    will be saved with a filename defined by the name of
%                    the folder in which all DICOM files of a given imaging
%                    volume are located (useful to keep track of meaningful
%                    names). The 'folder' option assumes that all imaging
%                    DICOM files of a given imaging volume are present in
%                    the same directory. Note: the 'folder' argument may
%                    lead to overwritting of data if not organized properly.
%                    Finally, if this argument is present and set to
%                    'modality',  all sData structures will be saved with a
%                    filename defined by the 'Modality' field in the DICOM
%                    header, but without enumerating multiple volumes of
%                    the same modality and same 'PatientID' (this may lead
%                    to overwritting, but is faster if the user is sure
%                    that only one scan of each modality for each patient
%                    is present in 'pathRead'.
%                    --> Options: - No argument
%                                 - 'folder'
%                                 - 'modality'
% -------------------------------------------------------------------------
% OUTPUTS: Multiple sData files
% - sData: Cell of structures organizing the content of the volume data,
%          DICOM headers, DICOM RTstruct* (used to compute the ROI) and
%          DICOM REGstruct* (used to register a given volume to another),
%          DICOM RTdose* and DICOM RTplan*.
%          * If present in the sub-folder tree
%    --> sData{1}: Explanation of cell content
%    --> sData{2}: Imaging data and ROI defintion
%    --> sData{3}: DICOM headers of imaging data
%    --> sData{4}: DICOM RTstruct (if applicable)
%    --> sData{5}: DICOM REGstruct (if applicable)
%    --> sData{6}: DICOM RTdose (if applicable)
%    --> sData{7}: DICOM RTplan (if applicable)
% -------------------------------------------------------------------------
% AUTHOR(S):
% - Martin Vallieres <mart.vallieres@gmail.com>
% -------------------------------------------------------------------------
% HISTORY:
% - Creation: February 2016
%--------------------------------------------------------------------------
% STATEMENT:
% This file is part of <https://github.com/mvallieres/radiomics/>,
% a package providing MATLAB programming tools for radiomics analysis.
% --> Copyright (C) 2015  Martin Vallieres
%
%    This package is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    This package is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with this package.  If not, see <http://www.gnu.org/licenses/>.
% -------------------------------------------------------------------------

startpath = pwd;
warning off

% INITIALIZATION
cd(pathRead)
stackPathRS = {}; stackFrameRS = {}; % Full path and FrameOfReferenceUID of the RTstruct files.
stackPathREG = {}; stackFrameREG = {}; % Full path and FrameOfReferenceUID of the REG files.
stackPathRD = {}; stackFrameRD = {}; % Full path and FrameOfReferenceUID of the RTdosefiles.
stackPathRP = {}; stackFrameRP = {}; % Full path and FrameOfReferenceUID of the RTplan files.
cellSeriesID = {}; % Cell of 'SeriesInstanceUID' of different imaging volumes (string).
cellFrameID = {}; % Cell of 'FrameOfReferenceUID' of different imaging volumes (string). Cell index is associated to the index of cellSeriesID.
cellPathImages = {}; % Cell of paths to the different imaging volumes. Cell index is associated to the index of cellSeriesID. Each cell in turn contains all the different path to the dicom images of a given volume.
cellPathRS = {}; % Cell of paths to the different RTstruct file (struct). Cell index is associated to the index of cellSeriesID.
cellPathREG = {}; % Cell of paths to the different REG file (struct). Cell index is associated to the index of cellSeriesID.
cellPathRD = {}; % Cell of paths to the different RTdose file (struct). Cell index is associated to the index of cellSeriesID.
cellPathRP = {}; % Cell of paths to the different RTplan file (struct). Cell index is associated to the index of cellSeriesID.
nameSave = {}; % Cell of filenames for all created sData structures (string). Cell index is associated to the index of cellSeriesID.
fidErr = fopen('readAllDICOM_err','w');
fidRead = fopen('readAllDICOM_log','w');

% SCANNING ALL FOLDERS IN INITIAL DIRECTORY
stackFolder = {pathRead}; % Stack of folder paths to scan
ind = strfind(stackFolder{1},'/'); nameDir = stackFolder{1}((ind(end)+1):end);
indUnder = strfind(nameDir,'_');
if ~isempty(indUnder)
    for under = numel(indUnder)
        nameDir = [nameDir(1:indUnder(under)-1),'\',nameDir(indUnder(under):end)];
    end
end
while ~isempty(stackFolder)
    cd(stackFolder{1})
    fprintf(fidRead,['\nScanning files in directory: ',stackFolder{1},' ... ']);
    list = dir; nElem = numel(list);
    for i = 1:nElem
        if ~strcmp(list(i).name,'.') && ~strcmp(list(i).name,'..') && isempty(strfind(list(i).name,'DS_Store')) % Good enough for linux, maybe add other conditions for MAC and Windows
            if list(i).isdir
                cd(list(i).name), stackFolder = [stackFolder;pwd]; cd ..
            elseif isdicom(list(i).name)
                try
                    info = dicominfo(list(i).name);
                    if strcmp(info.Modality,'MR') || strcmp(info.Modality,'PT') || strcmp(info.Modality,'CT')
                        [indSeriesID] = findUIDcellIndex(info.SeriesInstanceUID,cellSeriesID);
                        if indSeriesID > numel(cellSeriesID) % New volume
                            cellSeriesID = [cellSeriesID cell(1)]; cellSeriesID{indSeriesID} = info.SeriesInstanceUID;
                            cellFrameID = [cellFrameID cell(1)]; cellFrameID{indSeriesID} = info.FrameOfReferenceUID;
                            cellPathImages = [cellPathImages cell(1)]; cellPathImages{indSeriesID} = {};
                            cellPathRS = [cellPathRS cell(1)]; cellPathRS{indSeriesID} = {};
                            cellPathREG = [cellPathREG cell(1)]; cellPathREG{indSeriesID} = {};
                            cellPathRD = [cellPathRD cell(1)]; cellPathRD{indSeriesID} = {};
                            cellPathRP = [cellPathRP cell(1)]; cellPathRP{indSeriesID} = {};
                            nameSave = [nameSave cell(1)];
                            if nargin > 3 && strcmp(nameSaveOption,'folder')
                                path = pwd;
                                ind = strfind(path,'/'); % NOT GOOD FOR WINDOWS
                                nameSave{indSeriesID} = path((ind(end)+1):end);
                            elseif nargin > 3 && strcmp(nameSaveOption,'modality')
                                nameSave{indSeriesID} = info.Modality;
                            else
                                try
                                    nameSave{indSeriesID} = info.SeriesDescription;
                                catch
                                    nameSave{indSeriesID} = info.SeriesInstanceUID;
                                end
                            end
                        end
                        cellPathImages{indSeriesID} = [cellPathImages{indSeriesID};fullfile(pwd,list(i).name)];
                    elseif strcmp(info.Modality,'RTSTRUCT')
                        stackPathRS = [stackPathRS;fullfile(pwd,list(i).name)];
                        try
                            frameUID = info.ReferencedFrameOfReferenceSequence.Item_1.FrameOfReferenceUID;
                        catch
                            frameUID = info.FrameOfReferenceUID;
                        end
                        stackFrameRS = [stackFrameRS;frameUID];
                    elseif strcmp(info.Modality,'REG')
                        stackPathREG = [stackPathREG;fullfile(pwd,list(i).name)];
                        try
                            frameUID = info.RegistrationSequence.Item_2.FrameOfReferenceUID;
                        catch
                            frameUID = info.FrameOfReferenceUID;
                        end
                        stackFrameREG = [stackFrameREG;frameUID];
                    elseif strcmp(info.Modality,'RTDOSE')
                        stackPathRD = [stackPathRD;fullfile(pwd,list(i).name)];
                        frameUID = info.FrameOfReferenceUID;
                        stackFrameRD = [stackFrameRD;frameUID];
                    elseif strcmp(info.Modality,'RTPLAN')
                        stackPathRP = [stackPathRP;fullfile(pwd,list(i).name)];
                        frameUID = info.FrameOfReferenceUID;
                        stackFrameRP = [stackFrameRP;frameUID];
                    end
                catch
                    fprintf(fidErr,'Error while reading: %s\n',fullfile(pwd,list(i).name));
                end
            end
        end
    end
    stackFolder(1) = [];
    fprintf(fidRead,'DONE!');
end
fclose(fidErr);
fprintf(fidRead,'\n');

% ASSOCIATING ALL RTSTRUCT TO IMAGING VOLUMES
nRS = numel(stackPathRS);
if nRS
    fprintf(fidRead,'\nASSOCIATING ALL RTSTRUCT TO IMAGING VOLUMES ... ');
    for i = 1:nRS
        [indSeriesID] = findUIDcellIndex(stackFrameRS{i},cellFrameID);
        for n = 1:numel(indSeriesID)
            cellPathRS{indSeriesID(n)} = [cellPathRS{indSeriesID(n)};stackPathRS{i}];
        end
    end
    fprintf(fidRead,'DONE!');
end

% ASSOCIATING ALL REG TO IMAGING VOLUMES
nREG = numel(stackPathREG);
if nREG
    fprintf(fidRead,'\nASSOCIATING ALL REG TO IMAGING VOLUMES ... ');
    for i = 1:nREG
        [indSeriesID] = findUIDcellIndex(stackFrameREG{i},cellFrameID);
        for n = 1:numel(indSeriesID)
            cellPathREG{indSeriesID(n)} = [cellPathREG{indSeriesID(n)};stackPathREG{i}];
        end
    end
    fprintf(fidRead,'DONE!');
end

% ASSOCIATING ALL RTdose TO IMAGING VOLUMES
nRD = numel(stackPathRD);
if nRD
    fprintf(fidRead,'\nASSOCIATING ALL RTdose TO IMAGING VOLUMES ... ');
    for i = 1:nRD
        [indSeriesID] = findUIDcellIndex(stackFrameRD{i},cellFrameID);
        for n = 1:numel(indSeriesID)
            cellPathRD{indSeriesID(n)} = [cellPathRD{indSeriesID(n)};stackPathRD{i}];
        end
    end
    fprintf(fidRead,'DONE!');
end

% ASSOCIATING ALL RTplan TO IMAGING VOLUMES
nRP = numel(stackPathRP);
if nRP
    fprintf(fidRead,'\nASSOCIATING ALL RTplan TO IMAGING VOLUMES ... ');
    for i = 1:nRP
        [indSeriesID] = findUIDcellIndex(stackFrameRP{i},cellFrameID);
        for n = 1:numel(indSeriesID)
            cellPathRP{indSeriesID(n)} = [cellPathRP{indSeriesID(n)};stackPathRP{i}];
        end
    end
    fprintf(fidRead,'DONE!');
end

% READING ALL IMAGES TO CREATE ALL sData STRUCTURES
nScans = numel(cellPathImages);
if nBatch
    if nScans < nBatch
        nBatch = nScans;
    end
    fprintf(fidRead,['\n\nREADING AND PROCESSING ALL DICOM DATA USING ',num2str(nBatch),' PARALLEL BATCH ... ']);
    cd(pathRead), mkdir('BATCH_LOG'), cd('BATCH_LOG'), pathBatch = pwd;
    [scans] = batchPatients(nScans,nBatch); % Scans for each batch
    save('workspace','scans','pathSave','cellPathImages','cellPathRS','cellPathREG','cellPathRD','cellPathRP','nameSave'), pause(2)
    for i = 1:nBatch
        nScan = numel(scans{i});
        nameScript = ['batch',num2str(i),'_script.m'];
        fid = fopen(nameScript,'w');
        fprintf(fid,'dummy = 0;\n');
        fprintf(fid,'load(''workspace'')\n');
        for j = 1:nScan
            fprintf(fid,['sDataCreation_FromDICOMpaths(pathSave,cellPathImages{scans{',num2str(i),'}(',num2str(j),')},cellPathRS{scans{',num2str(i),'}(',num2str(j),')},cellPathREG{scans{',num2str(i),'}(',num2str(j),')},cellPathRD{scans{',num2str(i),'}(',num2str(j),')},cellPathRP{scans{',num2str(i),'}(',num2str(j),')},nameSave{scans{',num2str(i),'}(',num2str(j),')})\n']);
        end
        fprintf(fid,['system(''touch batch',num2str(i),'_end'');\n']);
        fprintf(fid,'clear all');
        fclose(fid);
        system(['matlab -nojvm -nodisplay -nodesktop -nosplash < ',nameScript,' >& ',nameScript(1:end-1),'log &']);
    end
    waitBatch(pathBatch,30,nBatch)
    cd ..
    %system('rm -r BATCH_LOG');
else
    fprintf(fidRead,'\n\nREADING AND PROCESSING ALL DICOM DATA ... ');
    for i = 1:nScans
        sDataCreation_FromDICOMpaths(pathSave,cellPathImages{i},cellPathRS{i},cellPathREG{i},cellPathRD{i},cellPathRP{i},nameSave{i});
    end
end
fprintf(fidRead,'DONE!\n');

% POST-PROCESSING OF SAVED FILES IF 4th ARGUMENT IS SET TO 'modality'
if nargin < 4
    fprintf(fidRead,'\nCORRECTING NAME OF SAVED FILES ... ');
    type = {'.CTscan','.PTscan','.MRscan'}; nType = numel(type);
    cd(pathSave)
    list = dir; nElem = numel(list);
    cellNames = {};
    for i = 1:nElem
        if ~list(i).isdir
            cellNames = [cellNames,list(i).name];
        end
    end
    nNames = numel(cellNames);
    temp = '';
    for i = 1:nNames
        try
            load(cellNames{i})
            idString = sData{3}(1).PatientID;
            if strcmp(idString,temp)
                ok = 0;
            else
                ok = 1;
            end
        catch
            ok = 0;
        end
        if ok
            cellTemp = strfind(cellNames,idString);
            for c = 1:numel(cellTemp)
                if isempty(cellTemp{c})
                    cellTemp{c} = [0];
                end
            end
            idIndex = find(cell2mat(cellTemp));
            nIndex = numel(idIndex); nameComp = cell(1,nIndex);
            for j = 1:nIndex
                nameComp{j} = cellNames{idIndex(j)};
            end
            for j = 1:nType
                cellTemp = strfind(nameComp,type{j});
                for c = 1:numel(cellTemp)
                    if isempty(cellTemp{c})
                        cellTemp{c} = [0];
                    end
                end
                scanIndex = find(cell2mat(cellTemp));
                nScanIndex = numel(scanIndex);
                if nScanIndex > 0
                    for k = 1:nScanIndex
                        ind1 = numel(idString) + 1; % Getting the '_' position after the PatientID
                        ind2 = numel(nameComp{scanIndex(k)}) - 10; % Getting the '.' position
                        name = nameComp{scanIndex(k)};
                        indWrong = strfind(name,'\');
                        if ~isempty(indWrong)
                            nInd = length(indWrong);
                            for n = 1:nInd
                                name = [name(1:indWrong(n)+n-2),'\',name(indWrong(n)+n-1:end)];
                            end
                        end
                        indWrong = strfind(name,'(');
                        if ~isempty(indWrong)
                            nInd = length(indWrong);
                            for n = 1:nInd
                                name = [name(1:indWrong(n)+n-2),'\',name(indWrong(n)+n-1:end)];
                            end
                        end
                        indWrong = strfind(name,')');
                        if ~isempty(indWrong)
                            nInd = length(indWrong);
                            for n = 1:nInd
                                name = [name(1:indWrong(n)+n-2),'\',name(indWrong(n)+n-1:end)];
                            end
                        end
                        indWrong = strfind(name,'&');
                        if ~isempty(indWrong)
                            nInd = length(indWrong);
                            for n = 1:nInd
                                name = [name(1:indWrong(n)+n-2),'\',name(indWrong(n)+n-1:end)];
                            end
                        end
                        indWrong = strfind(name,' ');
                        if ~isempty(indWrong)
                            nInd = length(indWrong);
                            for n = 1:nInd
                                name = [name(1:indWrong(n)+n-2),'\',name(indWrong(n)+n-1:end)];
                            end
                        end
                        if nScanIndex == 1
                            system(['mv ',name,' ',nameComp{scanIndex(k)}(1:ind1(1)),type{j}(2:3),nameComp{scanIndex(k)}(ind2(1):end)]);
                        else
                            system(['mv ',name,' ',nameComp{scanIndex(k)}(1:ind1(1)),type{j}(2:3),num2str(k),nameComp{scanIndex(k)}(ind2(1):end)]);
                        end
                    end
                end
            end
            temp = idString;
        end
    end
    fprintf(fidRead,'DONE!\n');
end
fclose(fidRead);

cd(startpath)
end


function h = imdisp(im, opt)

% imdisp -- Display an image
%
% Usage:
%       h = imdisp(im, opt)
%
% Input:
%       im          Image to display
%       opt         Display options
%
% Output:
%       h           Handle to image object
%
%
% Author: Brendt Wohlberg <brendt@lanl.gov>  Modified: 2014-05-29
%
% This file is part of the SPORCO library. Details of the copyright
% and user license can be found in the 'License' file distributed with
% the library.

if nargin < 2,
  opt = [];
end

% Check for box plot region options
brgn = [];
if isfield(opt,'bregion'),
  brgn = opt.bregion;
end

% Check for zoom region options
zrgn = [];
if isfield(opt,'zregion'),
  zrgn = opt.zregion;
elseif isfield(opt,'zgap') && isfield(opt,'bregion'),
  zrgn = opt.bregion + opt.zgap*[-1 -1 1 1];
end
if ~isempty(zrgn),
  im = im(zrgn(1):zrgn(3),zrgn(2):zrgn(4),:);
  if ~isempty(brgn),
    brgn = brgn - [zrgn(1:2) zrgn(1:2)];
  end
end

% Handle image offset and scaling
if 0,
if isfloat(im) && min(im(:)) < 0,
  im = im - min(im(:));
end
if isfloat(im) && max(im(:)) > 1,
    im = im / max(im(:));
end
else
  if isfloat(im),
    im = im - min(im(:));
    im = im / max(im(:));
  end
end

% Different behaviour for greyscale and RGB images
if size(im,3) == 1,
  hh = imagesc(im);
  colormap(gray);
else
  hh = image(im);
end
axis image; axis off;

% Plot box region if option supplied
if ~isempty(brgn),
  bx = brgn([2 2 4 4 2]) + [-0.5 -0.5 0.5  0.5 -0.5] + 1;
  by = brgn([1 3 3 1 1]) + [-0.5  0.5 0.5 -0.5 -0.5] + 1;
  bl = 'r-';
  if isfield(opt,'bline'),
    bl = opt.bline;
  end
  hold on;
  plot(bx, by, bl);
  hold off;
end

% Check for title option
if isfield(opt, 'title'),
  title(opt.title);
end

if nargout > 0
    h = hh;
end

return


function [CellResp,data,dimCR] = LoadFileFromParts(data_dir,filename,namestring)
disp('loading file from parts...');
% tic
fishdir = fullfile(data_dir,filename);
load(fishdir,'data');
load(fishdir,'dimCR');
CellResp = zeros(dimCR);
num = 0;
nParts = round(dimCR(1)*dimCR(2)/(10^8));
disp(['in ' num2str(nParts) ' parts']);
for i = 1:nParts,
    disp(num2str(i));
    load(fishdir,[namestring,'_' num2str(i)]);
    eval(['len = size(',namestring,'_' num2str(i) ',1);']);
    eval(['CellResp(num+1:num+len,:) = ',namestring,'_' num2str(i) ';']);
    num = num+len;
end
% toc

end


function y = cvx_value( x )
global cvx___
y = cellfun( @cvx_value, x, 'UniformOutput', false );

% Copyright 2005-2016 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function a = hlp_wrapresults(f,varargin)
% Wraps all outputs produced by function f for the given arguments into a cell array.
% Results = hlp_wrapresults(Function, Arguments...)
%
% In:
%   Function     : some function handle to execute
%
%   Arguments... : list of arguments to pass to the function
%
% Out:
%   Results : cell array of all function results
%
%
% Notes:
%   It is not (currently) possible to efficiently determine the number of out-args for a
%   varargout function; in this case, at most 10 outputs are supported.
%
% Examples:
%   % wrap both outputs of a particualr sort() call into a cell array
%   results = hlp_wrapresults(@sort,[1 4 2 1 3 6 0])
%
% See also:
%   hlp_getresult
%
%					         	 Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                2010-03-28

% Copyright (C) Christian Kothe, SCCN, 2010, christian@sccn.ucsd.edu
%
% This program is free software; you can redistribute it and/or modify it under the terms of the GNU
% General Public License as published by the Free Software Foundation; either version 2 of the
% License, or (at your option) any later version.
%
% This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
% even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
% General Public License for more details.
%
% You should have received a copy of the GNU General Public License along with this program; if not,
% write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
% USA
dp;

% find out how many arguments f can maximally produce
len = nargout(f);
% for varargout functions, we assume at most 10
if len < 0
    len = 10; end
% ... then invoke the function
while len >= 1
    try
        % get the appropriate number of results from f()
        [a{1:len}] = f(varargin{:});
        return;
    catch e
        % got an exception, check if it is outarg-related
        if ~any(strcmp(e.identifier,{'MATLAB:TooManyOutputs','MATLAB:maxlhs','MATLAB:unassignedOutputs'}))
            % it isn't: propagate the error
            settings = dbstatus;
            if any(strcmp({settings.cond},'error'))
                % if in dbstop if error mode, we're re-running the line to get the debugger to stop at the right place
                fprintf('hlp_wrapresults: caught error while in "dbstop if error" mode; re-running offending code to get break point...\n');
                fprintf('  error traceback was: %s\n',hlp_handleerror(e));
                [a{1:len}] = f(varargin{:});
            else
                rethrow(e);
            end
        end
        % but if it was, we need to retry with fewer out-arguments
        len = len-1;
    end
end

% len = 0: f produces no outputs
f(varargin{:});
a = {};


function model = setFoodConstraints(model, foodMenu, compensateDiet)
% This function sets diet/food constraints for uptake reactions of
% a whole-body metabolic model.
%
% function model = setFoodConstraints(model, Diet, factor)
%
% INPUT
%   model         model structure
%   foodMenu      {column vector of food items, column vector of serving mass (g))
%Optional Input:
%   compensateDiet   boolean 0 and 1; 1 indicates to compensate for gaps in nutrition components in the EUAverageDiet. default is 1

% OUTPUT
%   model         updated model
%
% AUTHORS
%   Bronson R. Weston 2021-2022

%Add any food reactions if necessary
foodMenu=makeDietFormatConsistant(model,foodMenu);
[model,~] = addFoodRxns2HM(model,foodMenu(:,1));

%Clear any current dietary/food reaction fluxes
fdRxns=find(contains(model.rxns,'Food_EX_'));
metRxns=find(contains(model.rxns,'Diet_EX_'));
model.lb(fdRxns)=0;
model.ub(fdRxns)=0;
model.lb(metRxns)=0;
model.ub(metRxns)=0;

%Add diet components
for i=1:length(foodMenu(:,1))
    %     foodMenu{i,1}
    %     find(ismember(model.rxns,foodMenu{i,1}))
    if ischar(foodMenu{i,2})
        val= -1*str2num(foodMenu{i,2});
    else
        val= -1*foodMenu{i,2};
    end
    model.ub(find(ismember(model.rxns,foodMenu{i,1}))) = val;
    model.lb(find(ismember(model.rxns,foodMenu{i,1}))) = val;
    if isempty(find(ismember(model.rxns,foodMenu{i,1})))
        error(['"' foodMenu{i,1} '" is not a valid food item/ metabolite'])
    end
end

if ~exist('compensateDiet','var')
    compensateDiet=1;
end

% load 'fdTable.mat'
% load 'fdCategoriesTable.mat'
metFlux = getMetaboliteFlux(foodMenu);

if compensateDiet~=1
    model.SetupInfo.DietComposition = metFlux;
    return
end

% If compensating diet, make changes in accordance with setDietConstraints
% and EUAverageDietNew

EUAverageDietNew
Diet = getMetaboliteFlux(Diet);

for i=1:length(Diet(:,1))
    [missingEUmets,ind]=setdiff(Diet(:,1),metFlux(:,1));
    metFlux=[metFlux; Diet(ind,:)];
end

microbiotaEnabling =1; % consider essential microbial metabolites to be added to diet

% load essential metabolite list for AGORA models
AGORAEssentialMetabolites;
AGORAessential = regexprep(AGORAessential,'EX_','Diet_EX_');
AGORAessential = regexprep(AGORAessential,'\[u\]','\[d\]');

% ensure uptake of metabolites required for microbiota (may not all be
% needed)
if microbiotaEnabling == 1
    MissingUptakes = setdiff(AGORAessential,metFlux(:,1));
    % open uptake for those reactions
    % set constraints to a default
    model.lb(ismember(model.rxns,MissingUptakes))=-0.1;
end

% these compounds are in the diet and needed for the proper function of the
% model but are not reported in our diet database
if 1
    PotentialMissingDietCompounds={'Diet_EX_asn_L[d]'; 'Diet_EX_gln_L[d]';'Diet_EX_chol[d]';'Diet_EX_crn[d]';'Diet_EX_elaid[d]';...
        'Diet_EX_hdcea[d]';'Diet_EX_dlnlcg[d]';'Diet_EX_adrn[d]';'Diet_EX_hco3[d]';...
        'Diet_EX_sprm[d]'; 'Diet_EX_carn[d]';'Diet_EX_7thf[d]';...
        'Diet_EX_Lcystin[d]';%??
        'Diet_EX_hista[d]';'Diet_EX_orn[d]';...
        'Diet_EX_ptrc[d]';'Diet_EX_creat[d]';
        'Diet_EX_cytd[d]'; 'Diet_EX_so4[d]'
        };
    MissingDietCompounds=setdiff(PotentialMissingDietCompounds,metFlux(:,1));
    model.lb(ismember(model.rxns,MissingDietCompounds))=-50;
end

% micronutrient - defined to have mole/day/person rate below 1e-6 mol/day/person
% lower bounds will be relaxed by factor 10
micronutrients ={%'Diet_EX_adpcbl[d]'
    % I changed the exchange ID since it was generated based on the
    % metabolite (ID adocbl). AH 16/12/01
    'Diet_EX_adocbl[d]'
    'Diet_EX_vitd2[d]'
    'Diet_EX_vitd3[d]'
    'Diet_EX_psyl[d]'
    'Diet_EX_gum[d]'
    'Diet_EX_bglc[d]'
    'Diet_EX_phyQ[d]'
    'Diet_EX_fol[d]'
    'Diet_EX_5mthf[d]'
    'Diet_EX_q10[d]'
    'Diet_EX_retinol_9_cis[d]'
    'Diet_EX_pydxn[d]'
    'Diet_EX_pydam[d]'
    'Diet_EX_pydx[d]'
    'Diet_EX_pheme[d]'
    'Diet_EX_ribflv[d]'
    'Diet_EX_thm[d]'
    % added 24.08.2016
    'Diet_EX_avite1[d]'
    'Diet_EX_pnto_R[d]'
    };
%no uptake enforced but max uptake rate
ions={    'Diet_EX_na1[d]'	%'0.056546816'
    'Diet_EX_cl[d]'	%'0.056412715'
    'Diet_EX_k[d]'	%'0.12020983'
    'Diet_EX_pi[d]'	%'0.007143207'
    'Diet_EX_zn2[d]'
    'Diet_EX_cu2[d]'
    };
so4={
    %02.06.2017
    'Diet_EX_so4[d]' % see text above about addition of met for brain demand
    };

for i = 1:  size(metFlux(:,1),1)
    R = metFlux{i,1};
    index=find(ismember(model.rxns,R));
    % exception for micronutrients to avoid numberical issues
    if ~isempty(find(ismember(micronutrients,R)))&& metFlux{i,2}<=10
        model.lb(index) = -10;
        model.ub(index) = -10;
%     elseif ~isempty(find(ismember(micronutrients,R))) &&  metFlux{i,2}<0.1
%         model.lb(index) = -1*metFlux{i,2}*99 +model.lb(index);
%         model.ub(index) = model.lb(index);
    elseif ~isempty(find(ismember(ions,R)))
        model.lb(index) = -1* metFlux{i,2}*99+model.lb(index);
        model.ub(index) = model.lb(index);
    elseif ~isempty(find(ismember(so4,R)))
        model.lb(index) = -1000;
        model.ub(index) = -1000;
    elseif ~isempty(find(ismember(missingEUmets,R)))
        model.lb(index) = -1* metFlux{i,2}+model.lb(index);
        model.ub(index) = model.lb(index);
    end
end

model.SetupInfo.DietComposition = metFlux;