function plotStats(obj, epochs, stats, plotAccuracy) %#ok<INUSL>
% plotStats(obj, epochs, stats, plotAccuracy)
%
% Plot the results of different metrics on train and validation set.
%
% Copyright by Holger Caesar, 2016

% Define color map
cmap = parula(3);
cmap(3, :) = [255, 140, 0] / 255;

if true
    figure(1);
    clf;
    if plotAccuracy
        hsp1 = subplot(2, 1, 1);
    end
    hold on;
    leg = {};
    datasetModes = {'train', 'val'};
    for datasetModeIdx = 1 : numel(datasetModes)
        datasetMode = datasetModes{datasetModeIdx};
        field = 'objective';
        fieldValues = [stats.(datasetMode).(field)];
        if datasetModeIdx == 1
            marker = '-';
        else
            marker = '--';
        end

        % For i.e. objective with 1 value
        leg{end + 1} = sprintf('%s (%s)', field, datasetMode); %#ok<AGROW>
        values = fieldValues(1, :)';
        plot(epochs, values, 'Color', cmap(1, :), 'LineStyle', marker);
    end
    hleg1 = legend(leg, 'Location', 'NorthEastOutSide');

    xlabel('epoch');
    ylabel('objective');
    grid on;
end

if plotAccuracy
    hsp2 = subplot(2, 1, 2);
    hold on;

    leg = {};
    datasetModes = {'train', 'val'};
    for datasetModeIdx = 1 : numel(datasetModes)
        datasetMode = datasetModes{datasetModeIdx};
        field = 'accuracy';
        fieldValues = [stats.(datasetMode).(field)];
        if datasetModeIdx == 1
            marker = '-';
        else
            marker = '--';
        end

        leg{end + 1} = sprintf('Pix. Acc. (%s)', datasetMode); %#ok<AGROW>
        values = fieldValues(1, :)';
        plot(epochs, values, 'Color', cmap(1, :), 'LineStyle', marker);

        leg{end + 1} = sprintf('Class. Acc. (%s)', datasetMode); %#ok<AGROW>
        values = fieldValues(2, :)';
        plot(epochs, values, 'Color', cmap(2, :), 'LineStyle', marker);

        leg{end + 1} = sprintf('Mean IU (%s)', datasetMode); %#ok<AGROW>
        values = fieldValues(3, :)';
        plot(epochs, values, 'Color', cmap(3, :), 'LineStyle', marker);
    end

    % Define legend
    hleg2 = legend(leg, 'Location', 'NorthEastOutSide');

    % Align both plots
    if false
        plotPos1 = get(hsp1, 'Position');
        plotPos2 = get(hsp2, 'Position');
        set(hsp2, 'Position', [plotPos1(1), plotPos2(2), plotPos1(3:4)]);
        legPos1 = get(hleg1, 'Position');
        legPos2 = get(hleg2, 'Position');
        set(hleg2, 'Position', [legPos1(1), legPos2(2), legPos1(3:4)]);
    end

    xlabel('epoch');
    ylabel('accuracy');
    grid on;
end


% Copyright (C) 2017-2018 Titus Cieslewski, RPG, University of Zurich,
%   Switzerland
%   You can contact the author at <titus at ifi dot uzh dot ch>
% Copyright (C) 2017-2018 Siddharth Choudhary, College of Computing,
%   Georgia Institute of Technology, Atlanta, GA, USA
% Copyright (C) 2017-2018 Davide Scaramuzza, RPG, University of Zurich,
%   Switzerland
%
% This file is part of dslam_open.
%
% dslam_open 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.
%
% dslam_open 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 dslam_open. If not, see <http://www.gnu.org/licenses/>.

function [decentr_state, opt_handle, dgs_stats, opt_increment] = ...
    manageAsyncGaussSeidel(...
    decentr_state, opt_handle, distributed_mapper_location, ...
    wait_finished, max_iters, renew)

n_robots = numel(decentr_state);
dgs_stats = {};
opt_increment = zeros(n_robots);

% If an optimization has previously been launched...
if (opt_handle.running)
    % If optimization still running, don't do anything.
    for i = 1:numel(opt_handle.futures)
        if (~isempty(opt_handle.futures{i}))
            if (wait_finished)
                wait(opt_handle.futures{i});
            else
                if (~strcmp(opt_handle.futures{i}.State, 'finished'))
                    return;
                end
            end
        end
    end
    % Catch any failures.
    for i = 1:numel(opt_handle.futures)
        if (~isempty(opt_handle.futures{i}))
            if (~isempty(opt_handle.futures{i}.Error))
                opt_handle.futures{i}.Error
                opt_handle.futures{i}.Diary
                opt_handle.futures{i}.Error.stack(1)
                opt_handle.futures{i}.Error.stack(end)
                assert(false);
            end
        end
    end

    % Optimization finished successfully: Get stats, update state.
    update_state = cell(n_robots, 1);
    for i = 1:numel(opt_handle.futures)
        if (~isempty(opt_handle.futures{i}))
            update_state(opt_handle.group_assignment == i) = ...
                opt_handle.futures{i}.OutputArguments{1};
            dgs_stats_i = opt_handle.futures{i}.OutputArguments{2};
            dgs_stats = [dgs_stats; dgs_stats_i];

            % Reconstruct communication between pairs of robots.
            dgs_stats_i.comm_link_count
            opt_handle.between_robot_links{i}
            links = opt_handle.between_robot_links{i};
            links = links + links';
            linksum = sum(links(:));
            assert(dgs_stats_i.comm_link_count == linksum);

            group = find(opt_handle.group_assignment == i);
            group_data_exchange = ...
                links * dgs_stats_i.exchange_gs / linksum;
            opt_increment(group, group) = ...
                opt_increment(group, group) + group_data_exchange;
        end
    end

    decentr_state = consistentlyApplyState(update_state, decentr_state);
    decentr_state = setConvergedWhereApplicable(...
        update_state, decentr_state);

    % Indicate which groups are co-optimized, for accuracy eval:
    opt_handle.optimized_groups = [];
    groups = unique(opt_handle.group_assignment);
    for group_i = 1:numel(groups)
        opt_handle.optimized_groups(group_i).members = find(...
            opt_handle.group_assignment == groups(group_i));
    end
    disp (['Have ' num2str(numel(opt_handle.optimized_groups)) ...
        ' optimization groups.']);
end

if renew
    % Launch new optimization
    %opt_future = parfeval(gcp(), @runSyncGaussSeidel, 1, decentr_state, ...
    %    distributed_mapper_location);

    opt_handle.group_assignment = 1:n_robots;
    for i = 1:n_robots
        opt_handle.group_assignment(i) = ...
            min([decentr_state{i}.grouped_with i]);
    end

    opt_groups = unique(opt_handle.group_assignment);

    opt_handle.futures = {};
    for group_i = opt_groups
        group_mask = (opt_handle.group_assignment == group_i);
        group_size = nnz(group_mask);
        if group_size > 1
            members_converged = cellfun(@(x) x.converged, ...
                decentr_state(group_mask));
            if ~all(members_converged)
                group_reindexing = zeros(n_robots, 1);
                group_reindexing(group_mask) = 1:group_size;
                opt_handle.futures{group_i} = parfeval(gcp(), ...
                    @runSyncGaussSeidel, 2, decentr_state(group_mask), ...
                    distributed_mapper_location, group_i, group_reindexing, ...
                    max_iters);
                opt_handle.between_robot_links{group_i} = ...
                    countBetweenRobotLinks(decentr_state(group_mask), ...
                    group_reindexing);
            end
        end
    end
    opt_handle.running = true;
end

end


function [t1,b0] = dtiMakeAnalyze(b0PathName, t1PathName, t1AnalyzePathName, outPathName)
%
% [t1,b0] = dtiMakeAnalyze(b0PathName, t1PathName, t1AnalyzePathName, outPathName)
%
% Takes a set of images from a DTI sequence and saves them out as
% analyze-format files. It will also save out a transform matrix that will
% coregister the DTI images to another scan series (typically a T1 scan
% from the same session).
% Also, if the t1 analyze file is provided and includes a talairach file,
% the transform matrix will also include the affine component of the
% talairach transform.
%
% HISTORY:
% 2003.08.?? RFD (bob@white.stanford.edu) wrote it.

useManual = false;

if ~exist('b0PathName','var') | isempty(b0PathName)
   [f, p] = uigetfile({'*.001','I-files (*.001)';'*.*','All files'}, 'Select one of the B0 I-files...');
   if(isnumeric(f)) error('Need a B0 file to continue...'); end
   b0PathName = fullfile(p, f);
   disp(b0PathName);
end
b0.fname = b0PathName;

if ~exist('t1PathName','var') | isempty(t1PathName)
   [f, p] = uigetfile({'*.001','I-files (*.001)';'*.*','All files'}, 'Select one of the T1 I-files...');
   if(isnumeric(f)) error('Need a T1 file to continue...'); end
   t1PathName = fullfile(p, f);
   disp(t1PathName);
end
t1.fname = t1PathName;

if ~exist('t1AnalyzePathName','var') | isempty(t1AnalyzePathName)
   [f, p] = uigetfile({'*.hdr','Analyze files (*.hdr)';'*.*','All files'},...
       'Select the T1 Analyze file...');
   if(isnumeric(f)) error('Need a T1 file to continue...'); end
   t1AnalyzePathName = fullfile(p, f);
   disp(t1AnalyzePathName);
end
t1.analyzeFname = t1AnalyzePathName;
[p,f,e] = fileparts(t1AnalyzePathName);
t1.analyzeBaseFname = fullfile(p,f);

% Compute the transform that would happen if we made this into an analyze
% format file using our code, which imposes a particular data orientation
% (axial, neurological convention). Note that the transofrm returned here
% should consits of just flips and mirror-reversals. There will be no
% scales, skews or translations.
[b0.cannonical, b0.baseFname, b0.mmPerVox, b0.imDim, b0.notes] = computeCannonicalXformFromIfile(b0.fname);
[t1.cannonical, t1.baseFname, t1.mmPerVox, t1.imDim, t1.notes] = computeCannonicalXformFromIfile(t1.fname);

if(~exist('outPathName','var') | isempty(outPathName))
    outPathName = fullfile(fileparts(fileparts(b0.baseFname)), 'dti_analyses');
end
if(~exist('outPathName','dir'))
    [p,f,e] = fileparts(outPathName);
    mkdir(p, [f e]);
end

swapXY = [0 1 0 0; 1 0 0 0; 0 0 1 0; 0 0 0 1];

t1.talairach = load([t1.analyzeBaseFname '_talairach']);
% We also want a transform that will go into ac-pc space (ie.
% Talairach, but without any scaling). We can compute that by
% adjusting the scale factors in the talairach transform.
t1.talXform = t1.talairach.vol2Tal.transRot'*swapXY;
p = spm_imatrix(t1.talXform);
% We also have to rescale the translations.
scaleDiff = t1.mmPerVox./p(7:9);
p(1:3) = p(1:3).*scaleDiff;
p(7:9) = t1.mmPerVox;
t1.acpcXform = spm_matrix(p);

% Now compute the transform from the standard scanner coordinate space
% to the image coordinate space (eg. scanner2img*[X Y Z 1]' will convert
% the X Y Z scanner coords to indices into the img.)
b0.scanner2img = XformFromIfile(b0.baseFname,'volume');
t1.scanner2img = XformFromIfile(t1.baseFname,'volume');

% create and save the T1 analyze file .mat transform, computed from the
% talairach file.
t1Tal = t1.talairach.vol2Tal.transRot'*swapXY;
M_acpc = t1.acpcXform;
M_tal = t1.talXform;
M = t1.talXform;
save(t1.analyzeBaseFname, 'M', 'M_tal', 'M_acpc');
% Also, make sure the T1 .hdr origin is set to the AC (Talairach 0,0,0)
t1.origin = inv(t1Tal)*[0,0,0,1]';
t1.origin = t1.origin(1:3)';
[dim vox scale type offset origin descrip] = spm_hread(t1.analyzeBaseFname);
spm_hwrite(t1.analyzeBaseFname, dim, vox, scale, type, offset, t1.origin, descrip);

% We use a pre-multiply convention (newCoords = M*oldCoords), so read
% the matrix transforms from right to left:
% 1. undo the b0 cannonical xform (inv(b0.cannonical))
% 2. b0 image space o scanner space (inv(b0.scanner2img))
% 3. scanner space to t1 image space (t1.scanner2img)
% 4. t1 image space to cannonical x-formed t1 image space(t1.cannonical)
% 5. t1 cannonical image space to t1 standard space (t1Hdr.mat)
%
% Note: the SPM convention seems to be to swap X and Y, so we have to undo
% that swap from the t1 transforms when computing ours. Then, we swap our
% transform before saving it. Why? Because it makes everything work. But, I
% really don't understand it fully. Maybe the swap is happening in myCinterp3
% (called from dtiGetSlice)?
M = t1.cannonical * swapXY * t1.scanner2img * inv(b0.scanner2img) * b0.cannonical;
M_tal = t1Tal * M;
M = M*swapXY;
M_tal = M_tal*swapXY;
b0.M = M;
b0.M_tal = M_tal;
% Set the origin to the AC (Talairach 0,0,0)
b0.origin = inv(b0.M_tal)*[0,0,0,1]';
b0.origin = b0.origin(1:3)';

% Build B0, FA and vector images
[b0.img, fa, add, ci, meanDiff, maxEig, medEig, minEig, maxVec] = ...
    dtiLoadTensorcalc(fullfile(fileparts(b0.baseFname), 'Tensor.float.001'));
b0.img = permute(b0.img, [2,1,3]); % x and y are permuted in the Tensor.float file
[b0.imgCannonical, mmPerVoxNew] = applyCannonicalXform(b0.img, b0.cannonical, b0.mmPerVox);
hdr = saveAnalyze(b0.imgCannonical, fullfile(outPathName,'B0'), mmPerVoxNew, b0.notes, b0.origin);
[img, mmPerVoxNew] = applyCannonicalXform(permute(fa*1000, [2,1,3]), b0.cannonical, b0.mmPerVox);
hdr = saveAnalyze(img, fullfile(outPathName,'FA'), mmPerVoxNew, b0.notes, b0.origin);
% The first two dims will get permuted when we write the data out to
% the analyze file (to put them in standard analyze axial form). But,
% we need to permute them here because tensorcalc permuted them
% relative to the original Ifiles.
maxVec = permute(maxVec,[2 1 3 4]);
% Since we just permuted voxel coordinates, we should also swap X and Y,
% but it turns out that the tensorcalc convention makes X
% anterior-posterior and Y left-right, but we want them to be the other
% way to follow Talairach naming convention. So, we leave them as is.
hdr = saveAnalyze(applyCannonicalXform(maxVec(:,:,:,1), b0.cannonical, b0.mmPerVox), fullfile(outPathName,'vecX'), mmPerVoxNew, b0.notes, b0.origin);
hdr = saveAnalyze(applyCannonicalXform(maxVec(:,:,:,2), b0.cannonical, b0.mmPerVox), fullfile(outPathName,'vecY'), mmPerVoxNew, b0.notes, b0.origin);
hdr = saveAnalyze(applyCannonicalXform(maxVec(:,:,:,3), b0.cannonical, b0.mmPerVox), fullfile(outPathName,'vecZ'), mmPerVoxNew, b0.notes, b0.origin);

% Compute and show test images
% t1Hdr should contain the Talairach xform that we just saved.
[t1Img, t1Mm, t1Hdr] = loadAnalyze(t1.analyzeFname);
%t1.img = makeCubeIfiles(t1.baseFname, t1.imDim(1:2), [1:t1.imDim(3)]);

imDims = [-70,70;-120,80;-60,80]';
slice = [0,0,0];

done = false;
newM = b0.M_tal;
while(~done & useManual)
    M = t1Hdr.mat;
    img = t1Img;
    fig = 90;
    [Xsl,x,y,z] = dtiGetSlice(M, img, 3, slice(3), imDims);
    figure(fig); h(1) = subplot(2,3,1); imagesc(imDims(:,1), imDims(:,2), Xsl); colormap(gray); axis equal tight xy;
    [Ysl,x,y,z] = dtiGetSlice(M, img, 2, slice(2), imDims);
    figure(fig); h(2) = subplot(2,3,2); imagesc(imDims(:,3), imDims(:,1), Ysl); colormap(gray); axis equal tight xy;
    [Zsl,x,y,z] = dtiGetSlice(M, img, 1, slice(1), imDims);
    figure(fig); h(3) = subplot(2,3,3); imagesc(imDims(:,3), imDims(:,2), Zsl); colormap(gray); axis equal tight xy;

    t1Xslice = Xsl; t1Yslice = Ysl; t1Zslice = Zsl;

    slice = [0,0,0];
    M = newM;
    %This XY swap business is why we have to do this permute here.
    img = b0.imgCannonical;
    [Xsl,x,y,z] = dtiGetSlice(M, img, 3, slice(3), imDims);
    figure(fig); h(4) = subplot(2,3,4); imagesc(imDims(:,1), imDims(:,2), Xsl); colormap(gray); axis equal tight xy;
    [Ysl,x,y,z] = dtiGetSlice(M, img, 2, slice(2), imDims);
    figure(fig); h(5) = subplot(2,3,5); imagesc(imDims(:,3), imDims(:,1), Ysl); colormap(gray); axis equal tight xy;
    [Zsl,x,y,z] = dtiGetSlice(M, img, 1, slice(1), imDims);
    figure(fig); h(6) = subplot(2,3,6); imagesc(imDims(:,3), imDims(:,2), Zsl); colormap(gray); axis equal tight xy;

    b0Xslice = Xsl; b0Yslice = Ysl; b0Zslice = Zsl;

    disp('select corresponding points on each B0 and T1 image.');
    donePoints = false;
    ptList = [];
    while(~donePoints)
        for(ii=1:6)
            axes(h(ii));
            title('current');
            p = ginput(1);
            title('');
            if(isempty(p))
                donePoints = true;
                break;
            end
            hold on; plot(p(:,1), p(:,2), 'xy'); hold off;
            pts(ii,:) = p;
        end
        % Only add this set if it is complete
        if(size(pts,1)==6)
            if(isempty(ptList)) ptList = pts;
            else ptList = [ptList; pts]; end
        end
    end

    % Adjust newM given points...
    adjustment = eye(4);

    fig = 92;
    t1mv = max([t1Xslice(:); t1Yslice(:); t1Zslice(:)]);
    b0mv = max([b0Xslice(:); b0Yslice(:); b0Zslice(:)]);
    Xsl(:,:,1) = t1Xslice./t1mv.*.5 + b0Xslice./b0mv.*.5;
    Xsl(:,:,2) = t1Xslice./t1mv.*.5; Xsl(:,:,3) = t1Xslice./t1mv.*.5;
    Ysl(:,:,1) = t1Yslice./t1mv.*.5 + b0Yslice./b0mv.*.5;
    Ysl(:,:,2) = t1Yslice./t1mv.*.5; Ysl(:,:,3) = t1Yslice./t1mv.*.5;
    Zsl(:,:,1) = t1Zslice./t1mv.*.5 + b0Zslice./b0mv.*.5;
    Zsl(:,:,2) = t1Zslice./t1mv.*.5; Zsl(:,:,3) = t1Zslice./t1mv.*.5;
    figure(fig); subplot(2,2,1); imagesc(imDims(:,1), imDims(:,2), Xsl); colormap gray; axis equal tight xy;
    figure(fig); subplot(2,2,2); imagesc(imDims(:,3), imDims(:,1), Ysl); colormap(gray); axis equal tight xy;
    figure(fig); subplot(2,2,3); imagesc(imDims(:,3), imDims(:,2), Zsl); colormap(gray); axis equal tight xy;

    bn = questdlg('Is this good?', ...
                  'Continue manual registration...', ...
                  'Yes','No','Abort','No');
    if(strcmpi(bn, 'Yes')) done = true; end
    if(strcmpi(bn, 'Abort')) done = true; useManual = false; end
end

% Save all the transform files
if(useManual)
    M = adjustment*b0.M;
    M_tal = adjustment*b0.M_tal;
else
    slice = [0,0,0];
    img = t1Img;
    [Xsl,x,y,z] = dtiGetSlice(t1Hdr.mat, img, 3, slice(3), imDims);
    [Ysl,x,y,z] = dtiGetSlice(t1Hdr.mat, img, 2, slice(2), imDims);
    [Zsl,x,y,z] = dtiGetSlice(t1Hdr.mat, img, 1, slice(1), imDims);
    t1Xslice = Xsl; t1Yslice = Ysl; t1Zslice = Zsl;

    img = b0.imgCannonical;
    [Xsl,x,y,z] = dtiGetSlice(b0.M_tal, img, 3, slice(3), imDims);
    [Ysl,x,y,z] = dtiGetSlice(b0.M_tal, img, 2, slice(2), imDims);
    [Zsl,x,y,z] = dtiGetSlice(b0.M_tal, img, 1, slice(1), imDims);
    b0Xslice = Xsl; b0Yslice = Ysl; b0Zslice = Zsl;

    fig = figure;
    t1mv = max([t1Xslice(:); t1Yslice(:); t1Zslice(:)]);
    b0mv = max([b0Xslice(:); b0Yslice(:); b0Zslice(:)]);
    Xsl(:,:,1) = t1Xslice./t1mv.*.5 + b0Xslice./b0mv.*.5;
    Xsl(:,:,2) = t1Xslice./t1mv.*.5; Xsl(:,:,3) = t1Xslice./t1mv.*.5;
    Ysl(:,:,1) = t1Yslice./t1mv.*.5 + b0Yslice./b0mv.*.5;
    Ysl(:,:,2) = t1Yslice./t1mv.*.5; Ysl(:,:,3) = t1Yslice./t1mv.*.5;
    Zsl(:,:,1) = t1Zslice./t1mv.*.5 + b0Zslice./b0mv.*.5;
    Zsl(:,:,2) = t1Zslice./t1mv.*.5; Zsl(:,:,3) = t1Zslice./t1mv.*.5;
    figure(fig); subplot(2,2,1); imagesc(imDims(:,1), imDims(:,2), Xsl); colormap gray; axis equal tight xy;
    figure(fig); subplot(2,2,2); imagesc(imDims(:,3), imDims(:,1), Ysl); colormap(gray); axis equal tight xy;
    figure(fig); subplot(2,2,3); imagesc(imDims(:,3), imDims(:,2), Zsl); colormap(gray); axis equal tight xy;

    M = b0.M;
    M_tal = b0.M_tal;
end
save(fullfile(outPathName,'B0'), 'M', 'M_tal');
save(fullfile(outPathName,'FA'), 'M', 'M_tal');
save(fullfile(outPathName,'vecX'), 'M', 'M_tal');
save(fullfile(outPathName,'vecY'), 'M', 'M_tal');
save(fullfile(outPathName,'vecZ'), 'M', 'M_tal');

% Now build and save the dt6 data
[eigVec, eigVal] = dtiLoadTensor(fullfile(fileparts(b0.baseFname), 'Vectors.float.'));
dt6_tmp = dtiRebuildTensor(eigVec, eigVal);
dt6_tmp = permute(dt6_tmp,[2 1 3 4]);
for(ii=1:6)
    dt6(:,:,:,ii) = applyCannonicalXform(dt6_tmp(:,:,:,ii), b0.cannonical, b0.mmPerVox);
end
clear dt6_tmp;
mmPerVox = mmPerVoxNew;
notes = b0.notes;
xformToAnat = M;
xformToTal = M_tal;
b0 = int16(round(b0.imgCannonical));
anat.img = int16(t1Img);
anat.mmPerVox = t1Mm;
anat.xformToTal = t1Hdr.mat;
save(fullfile(outPathName,'dt6'), 'dt6', 'mmPerVox', 'notes', 'xformToAnat', 'xformToTal', 'b0', 'anat');

return;

[subjects, baseDir] = getSubjects('dc', 'c', 'dtiSubjectsCortexPaper.txt');
%baseDir = pwd;
d = dir(baseDir);
subjects = {};
for(ii=1:length(d))
    if(~strcmp(d(ii).name,'.') & ~strcmp(d(ii).name,'..') ...
        & (strcmp(d(ii).name(3),'0') | strcmp(d(ii).name(4),'0')))
        subjects{end+1} = d(ii).name;
    end
end
for(ii=1:length(subjects))
    sub = subjects{ii};
    base = fullfile(baseDir,sub);
    try
    dtiMakeAnalyze(fullfile(base,'dti','B0.001'),...
        fullfile(base,'t1','spgr1','I.001'), ...
        fullfile(base,'t1',[sub '_t1anat_avg']));
    catch
        disp(['skipped subject ' sub]);
    end
end


function vw = recenter3view(vw,orientation)
% view = recenter3view(view,orientation);
%
% recenters a 3-view window based on the current location of the
% mouse pointer with respect to the anatomy windows. This is set
% as a button-down callback function with respect to each anatomy view:
% so when the user presses at a particular location in a 3-view window,
% it will pick that location and redraw the 3-view centered there. (If the
% pointer happens to be outside the window or there is no 3-view window
% open, this function exits quietly).
%
% orientation is an integer from 1-3 that specifies which view
% the user has clicked on.
%       1 -- view is axial
%       2 -- view is coronal
%       3 -- view is sagittal
%
% See also: volume3view.m
%
% 3/06/03 by ras
% 01/04 ras: (chagrin) turns out the whole 1st half of this code, which was
% a convoluted way of figuring out where the user pressed, is completely
% superfluous if you just use the axes' 'CurrentPoint' property.

% % check if window exists
% winTag = ['3VolumeWindow: ',view.name];
% winExists = findobj('Tag',winTag);
%
% % if window doesn't exist, exit quietly
% if isempty(winExists)
%     return;
% end

pts = get(gca,'CurrentPoint');
locX = round(pts(1,1));
locY = round(pts(1,2));

% figure out R/L, A/P, S/I coordinates, based on view
switch orientation
    case 1, % axial view
        locRL = locX;
        locAP = locY;
        locSI = vw.loc(1);
    case 2, % coronal view
        locRL = locX;
        locAP = vw.loc(2);
        locSI = locY;
    case 3, % sagittal view
        locRL = vw.loc(3);
        locAP = locX;
        locSI = locY;
end

% might have imgs L/R flipped into radiological conventions
if (orientation<3) && isfield(vw.ui,'flipLR') && vw.ui.flipLR==1
    locRL = size(vw.anat,3) - locRL + 1;
end

% make the selected orientation the current one
setCurSliceOri(vw,orientation);

% mark the current location
loc = [locSI locAP locRL];

% if we're zoomed in, update the zoom bounds so that the crosshairs are
% centered:
maxZoom = [1 1 1; viewGet(vw,'Size')]';
if ~isequal(vw.ui.zoom, maxZoom)
	rng = diff(vw.ui.zoom, 1, 2) ./ 2;
	newZoom = [loc(:)-rng loc(:)+rng];

	vw.ui.zoom = newZoom;
end

% refresh volume 3-view
vw = volume3View(vw, loc);

return


% clc; clear all; close all;

%% hydro data
hydro = struct();
hydro = readAQWA(hydro, 'cylinder.AH1', 'cylinder.LIS');
hydro = radiationIRF(hydro,5,[],[],[],[]);
hydro = radiationIRFSS(hydro,[],[]);
hydro = excitationIRF(hydro,5,[],[],[],[]);
writeBEMIOH5(hydro)

%% Plot hydro data
% plotBEMIO(hydro)


function D = spm_eeg_ft_datareg_manual(varargin)
% Data registration user-interface routine
% commands the EEG/MEG data co-registration within original sMRI space
%
% FORMAT D = spm_eeg_inv_datareg_ui(D,[val], modality)
% Input:
% Output:
% D         - same data struct including the new required files and variables
%__________________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Vladimir Litvak
% $Id: spm_eeg_ft_datareg_manual.m 5397 2013-04-11 15:13:47Z vladimir $

% initialise
%--------------------------------------------------------------------------
[Finter, Fgraph] = spm('FnUIsetup','Fieldtrip MEEG/MRI manual coregistration', 0);

[D,val] = spm_eeg_inv_check(varargin{:});

[D, ok] = check(D, 'sensfid');

if ~ok
    if check(D, 'basic')
        error(['The requested file is not ready for source reconstruction.'...
            'Use prep to specify sensors and fiducials.']);
    else
        error('The meeg file is corrupt or incomplete');
    end
end

try
    D.inv{val}.mesh.template;
catch
    error('Please add a head model to the file before coregistering');
end

usepolhemus = spm_input('Use polhemus?', 1, 'yes|no', [1, 0]);

if usepolhemus
    meegfid = ft_read_headshape(spm_select(1, '\.*', 'Select polhemus file'));
    meegfid = ft_convert_units(meegfid, 'mm');
else
    meegfid = D.fiducials;
end

mrifid = D.inv{val}.mesh.fid;

if spm_input('Use individual head surface?', 1, 'yes|no', [1, 0])
    isurf = export(gifti(spm_select(1, 'mesh', 'Select head surface file')), 'ft');
    mrifid.pnt = isurf.pnt;
    mrifid.tri = isurf.tri;
end

meeglbl = meegfid.fid.label;
mrilbl = mrifid.fid.label;

newmrifid = mrifid;
newmrifid.fid.pnt = [];
newmrifid.fid.label = {};

if numel(meeglbl)> 3
    [selection ok]= listdlg('ListString', meeglbl, 'SelectionMode', 'multiple',...
        'InitialValue', spm_match_str(upper(meeglbl), upper(mrilbl)), ...
        'Name', 'Select at least 3 fiducials', 'ListSize', [400 300]);

    if ~ok || length(selection) < 3
        error('At least 3 M/EEG fiducials are required for coregistration');
    end

    meegfid.fid.pnt   = meegfid.fid.pnt(selection, :);
    meegfid.fid.label = meegfid.fid.label(selection);
    meeglbl = meeglbl(selection);
end

if numel(meeglbl)>=3
    for i = 1:length(meeglbl)
        switch spm_input(['How to specify ' meeglbl{i} ' position?'] , 1, 'select|type|click|skip')
            case 'select'
                [selection ok]= listdlg('ListString', mrilbl, 'SelectionMode', 'single',...
                    'InitialValue', strmatch(upper(meeglbl{i}), upper(mrilbl)), ...
                    'Name', ['Select matching MRI fiducial for ' meeglbl{i}], 'ListSize', [400 300]);
                if ~ok
                    continue
                end

                newmrifid.fid.pnt   = [newmrifid.fid.pnt; mrifid.fid.pnt(selection, :)];
            case 'type'
                pnt = spm_input('Input MNI coordinates', '+1', 'r', '', 3);
                newmrifid.fid.pnt   = [newmrifid.fid.pnt; pnt(:)'];
            case 'click'
                while 1
                    figure(Fgraph); clf;
                    mri = spm_vol(D.inv{val}.mesh.sMRI);
                    spm_orthviews('Reset');
                    spm_orthviews('Image', mri);
                    rotate3d off;
                    if spm_input(['Select ' meeglbl{i} ' position and click'] , 1,'OK|Retry', [1,0], 1)
                        newmrifid.fid.pnt   = [newmrifid.fid.pnt; spm_orthviews('Pos')'];
                        spm_orthviews('Reset');
                        break;
                    end
                end
            case 'skip'
                meegfid.fid.pnt(i, :) = [];
                meegfid.fid.label(i)  = [];
                continue;
        end
        newmrifid.fid.label = [newmrifid.fid.label  meeglbl{i}];
    end

    if size(newmrifid.fid.label) < 3
        error('At least 3 M/EEG fiducials are required for coregistration');
    end

    switch spm_input('Choose initial coregistration', 1, 'rigid|align1|align2|spm');
        case 'align1'
            M1 = spm_eeg_inv_headcoordinates(meegfid.fid.pnt(1, :), meegfid.fid.pnt(2, :), meegfid.fid.pnt(3, :));
            M =  spm_eeg_inv_headcoordinates(newmrifid.fid.pnt(1, :), newmrifid.fid.pnt(2, :), newmrifid.fid.pnt(3, :));
            M1 = inv(M) * M1;
        case 'align2'
            M1 = spm_eeg_inv_rigidreg(newmrifid.fid.pnt', meegfid.fid.pnt');
            tempfid = ft_transform_headshape(M1, meegfid);
            tempfid.fid.pnt(:, 2) = tempfid.fid.pnt(:, 2)- tempfid.fid.pnt(1, 2)+ newmrifid.fid.pnt(1, 2);
            tempfid.fid.pnt(:, 3) = tempfid.fid.pnt(:, 3)- mean(tempfid.fid.pnt(2:3, 3))+ mean(newmrifid.fid.pnt(2:3, 3));
            M1 = spm_eeg_inv_rigidreg(tempfid.fid.pnt', meegfid.fid.pnt');
        case 'rigid'
            M1 = spm_eeg_inv_rigidreg(newmrifid.fid.pnt', meegfid.fid.pnt');
        case 'spm'
            S =[];
            S.sourcefid = meegfid;
            S.targetfid = newmrifid;
            S.template  = 0;
            S.useheadshape = ~isempty(S.sourcefid.pnt);
            M1 = spm_eeg_inv_datareg(S);
    end
    meegfid = ft_transform_headshape(M1, meegfid);
end
%%
cfg = [];
cfg.individual.headshape = meegfid;
cfg.template.headshape = newmrifid;
cfg = ft_interactiverealign(cfg);

meegfid = ft_transform_headshape(cfg.m, meegfid);

M1 = cfg.m * M1;

if usepolhemus
    origfid = D.fiducials;
    sel1 = spm_match_str(origfid.fid.label, {'nas', 'lpa', 'rpa'});
    sel2 = spm_match_str(meegfid.fid.label, {'nas', 'lpa', 'rpa'});
    M2 = spm_eeg_inv_headcoordinates(meegfid.fid.pnt(sel2(1), :), meegfid.fid.pnt(sel2(2), :), meegfid.fid.pnt(sel2(3), :));
    M3 = spm_eeg_inv_headcoordinates(origfid.fid.pnt(sel1(1), :), origfid.fid.pnt(sel1(2), :), origfid.fid.pnt(sel1(3), :));
    M1 = inv(M2) * M3;
end

ind = 1;
D.inv{val}.datareg = struct([]);

if ~isempty(D.sensors('EEG'))
    D.inv{val}.datareg(ind).sensors = ft_transform_sens(M1, D.sensors('EEG'));
    D.inv{val}.datareg(ind).fid_eeg = ft_transform_headshape(M1, D.fiducials);
    D.inv{val}.datareg(ind).fid_mri = newmrifid;
    D.inv{val}.datareg(ind).toMNI = D.inv{val}.mesh.Affine;
    D.inv{val}.datareg(ind).fromMNI = inv(D.inv{val}.datareg(ind).toMNI);
    D.inv{val}.datareg(ind).modality = 'EEG';
    ind = ind+1;
end

if ~isempty(D.sensors('MEG'))
    D.inv{val}.datareg(ind).sensors = D.sensors('MEG');
    D.inv{val}.datareg(ind).fid_eeg = ft_transform_headshape(inv(M1), meegfid);
    D.inv{val}.datareg(ind).fid_mri = ft_transform_headshape(inv(M1), newmrifid);
    D.inv{val}.datareg(ind).toMNI = D.inv{val}.mesh.Affine*M1;
    D.inv{val}.datareg(ind).fromMNI = inv(D.inv{val}.datareg(ind).toMNI);
    D.inv{val}.datareg(ind).modality = 'MEG';
end

% check and display registration
%--------------------------------------------------------------------------
spm_eeg_inv_checkdatareg(D);

save(D);


function x = matset_withcrop(x,y,varargin)

nd = length(varargin);
szx = size(x);

if nd == 1 && nnz(szx~=1) <= 1,
  % special case for vectors
  inbounds = varargin{1} >= 1 & varargin{1} <= max(szx);
  x(varargin{1}(inbounds)) = y(inbounds);
else
  idxx = cell(1,nd);
  idxy = cell(1,nd);
  for d = 1:nd,
    inbounds = varargin{d} >= 1 & varargin{d} <= szx(d);
    idxx{d} = varargin{d}(inbounds);
    idxy{d} = inbounds;
  end
  x(idxx{:}) = y(idxy{:});
end


%% import_obj_geom
% Below is a demonstration of the features of the |import_obj_geom| function

%%
clear; close all; clc;

%% Syntax
% |[F,V]=import_obj_geom(fileName);|

%% Description
% This function imports the geometry (faces and nodes0 contained in an OBJ
% file. All texture/material data is ignored.

%% Examples
%

defaultFolder = fileparts(fileparts(mfilename('fullpath')));
loadPath=fullfile(defaultFolder,'data','OBJ');
fileName=fullfile(loadPath,'test.obj');

[F,V]=import_obj_geom(fileName);

%%
% Visualize

cFigure;
gpatch(F,V,'w','k');
axisGeom; camlight headlight;
gdrawnow;

%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% 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/>.


%Copyright 2008-2009  Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
%Copyright 2008-2009  David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
%
%THE BSD LICENSE
%
%Redistribution and use in source and binary forms, with or without
%modification, are permitted provided that the following conditions
%are met:
%
%1. Redistributions of source code must retain the above copyright
%   notice, this list of conditions and the following disclaimer.
%2. Redistributions in binary form must reproduce the above copyright
%   notice, this list of conditions and the following disclaimer in the
%   documentation and/or other materials provided with the distribution.
%
%THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
%IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
%OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
%IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
%INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
%NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
%DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
%THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
%(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
%THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

function [indices, dists] = flann_search(data, testset, n, search_params)
%NN_SEARCH  Fast approximate nearest neighbors search
%
% Performs a fast approximate nearest neighbor search using an
% index constructed using flann_build_index or directly a
% dataset.

% Marius Muja, January 2008

    algos = struct( 'linear', 0, 'kdtree', 1, 'kmeans', 2, 'composite', 3, 'saved', 254, 'autotuned', 255 );
    center_algos = struct('random', 0, 'gonzales', 1, 'kmeanspp', 2 );
    log_levels = struct('none', 0, 'fatal', 1, 'error', 2, 'warning', 3, 'info', 4);
    function value = id2value(map, id)
        fields = fieldnames(map);
        for i = 1:length(fields),
            val = cell2mat(fields(i));
            if map.(val) == id
                value = val;
                break;
            end
        end
    end
    function id = value2id(map,value)
        id = map.(value);
    end

    default_params = struct('algorithm', 'kdtree' ,'checks', 32, 'eps', 0.0, 'sorted', 1, 'max_neighbors', -1, 'cores', 1, 'trees', 4, 'branching', 32, 'iterations', 5, 'centers_init', 'random', 'cb_index', 0.4, 'target_precision', 0.9,'build_weight', 0.01, 'memory_weight', 0, 'sample_fraction', 0.1, 'log_level', 'warning', 'random_seed', 0);

    if ~isstruct(search_params)
        error('The "search_params" argument must be a structure');
    end

    params = default_params;
    fn = fieldnames(search_params);
    for i = [1:length(fn)],
        name = cell2mat(fn(i));
        params.(name) = search_params.(name);
    end
    if ~isnumeric(params.algorithm),
        params.algorithm = value2id(algos,params.algorithm);
    end
    if ~isnumeric(params.centers_init),
        params.centers_init = value2id(center_algos,params.centers_init);
    end
    if ~isnumeric(params.log_level),
        params.log_level = value2id(log_levels,params.log_level);
    end

    if (size(data,1)==1 && size(data,2)==1)
        % we already have an index
        [indices,dists] = nearest_neighbors('index_find_nn', data, testset, n, params);
    else
        % create the index and search
        [indices,dists] = nearest_neighbors('find_nn', data, testset, n, params);
    end
end


function val = viewGetRetinotopy(vw,param,varargin)
% Get data from various view structures
%
% This function is wrapped by viewGet. It should not be called by anything
% else other than viewGet.
%
% This function retrieves information from the view that relates to a
% specific component of the application.
%
% We assume that input comes to us already fixed and does not need to be
% formatted again.

if notDefined('vw'), vw = getCurView; end
if notDefined('param'), error('No parameter defined'); end

mrGlobals;
val = [];

switch param

    case 'framestouse'
        % Return a vector of time frames in the current or specified
        % scan to be used for coranal (block) analyses
        %   frames = viewGet(vw,'frames to use');
        %   scan = 1; frames = viewGet(vw,'frames to use',scan);
        if isempty(varargin) || isempty(varargin{1})
            scan = viewGet(vw, 'CurScan');
        else
            scan = varargin{1};
        end
        dt         = viewGet(vw, 'dtStruct');
        blockParms = dtGet(dt,'bparms',scan);
        if checkfields(blockParms, 'framesToUse')
            val = blockParms.framesToUse;
        else
            val = 1: viewGet(vw,'nFrames',scan);
        end

    case 'rmfile'
        % Return the path to the currently loaded retinotopy model.
        %   rmFile = viewGet(vw, 'retinotopy model file');
        if checkfields(vw, 'rm', 'retinotopyModelFile')
            val = vw.rm.retinotopyModelFile;
        else
            val = [];
        end
    case 'rmmodel'
        % Return the currently loaded retinotopy model struct.
        %   rm = viewGet(vw, 'retinotopy model');
        if checkfields(vw, 'rm', 'retinotopyModels')
            val = vw.rm.retinotopyModels;
        else
            val = [];
        end

    case 'rmcurrent'
        % Return the currently selected retinotopy model struct. Note that
        % there may be multiple models loaded.
        %   rm = viewGet(vw, 'rm current model');
        if checkfields(vw, 'rm', 'retinotopyModels')
            val = vw.rm.retinotopyModels{ viewGet(vw, 'rmModelNum') };
        else
            val = [];
        end
    case 'rmmodelnames'
        % Return the description of currently loaded retinotopy models.
        %   models = viewGet(vw, 'rm model names');
        %   models = viewGet(vw, 'retinotopy model names');
        models = viewGet(vw, 'Retinotopy Model');
        val = cell(1,numel(models));
        for n = 1:numel(models)
            val{n} = rmGet(models{n},'description');
        end
    case 'rmparams'
        % Return the retinotopy model parameters.
        %   params = viewGet(vw, 'Retinotopy Parameters');
        if checkfields(vw,'rm')
            val = vw.rm.retinotopyParams;
        end
    case 'rmstimparams'
        % Return the retinotopy model stimulus parameters. This is a subset
        % of the retinopy model parameters.
        %   stimParams = viewGet(vw, 'RM Stimulus Parameters');
        if checkfields(vw,'rm','retinotopyParams','stim')
            val = vw.rm.retinotopyParams.stim;
        end
    case 'rmmodelnum'
        % Return the retinotopy model number that is currently selected.
        % (There may be more than one model loaded.)
        %   modelNum = viewGet(vw, 'Retinotopy Model Number');
        if checkfields(vw, 'rm', 'modelNum') && ...
                ~isempty(vw.rm.modelNum)
            val = vw.rm.modelNum;
        else
            val = rmSelectModelNum(vw);
        end
    case 'rmhrf'
        % Return the hrf struct for the current retinopy model. This struct
        % contains a descriptor (such as 'two gammas (SPM style)') and the
        % parameters associated with this function.
        %   rmhrf = viewGet(vw, 'Retinotopy model HRF');
        if checkfields(vw,'rm','retinotopyParams','stim')
            val1 = vw.rm.retinotopyParams.stim.hrfType;
            switch(lower(val1))
                case {'one gamma (boynton style)','o','one gamma' 'b' 'boynton'}
                    val2 = vw.rm.retinotopyParams.stim.hrfParams{1};
                case {'two gammas (spm style)' 't' 'two gammas' 'spm'}
                    val2 = vw.rm.retinotopyParams.stim.hrfParams{2};
                case {'impulse' 'no hrf' 'none'}
                    val2 = [];
                otherwise
                    val2 = [];
            end
            val = {val1 val2};
        end

    otherwise
        error('Unknown viewGet parameter');

end

return


function plotyy(obj1, obj2, varargin)
   p = inputParser;
   p.addParameter('snum',max([obj1.dnum(1) obj2.dnum(1)]));
   p.addParameter('enum', min([obj1.dnum(end) obj2.dnum(end)]));
   p.addParameter('fun1','plot');
   p.addParameter('fun2','plot');
   p.parse(varargin{:});
   Args = p.Results;

    [ax, ~, ~] = plotyy(obj1.dnum, obj1.data, obj2.dnum, obj2.data, Args.fun1, Args.fun2);
    datetick('x');
    set(ax(2), 'XTick', [], 'XTickLabel', {});
    set(ax(1), 'XLim', [Args.snum Args.enum]);
end


function preparedata

data = load('F:\Dropbox\Workspace\Projects2\Packages\DNN_Demo_2015_08_08\train_clean_multi_tiny.mat');

for i=1:length(data.noisy_list)
    [~,uttID] = fileparts(data.noisy_list{i});
    utt_list{i} = uttID;
end

for i=1:length(data.mfcc_clean_train)
    mfcc_clean_train{i} = single(data.mfcc_clean_train{i}(:,1:13)');
    mfcc_noisy_train{i} = single(data.mfcc_noisy_train{i}(:,1:13)');
end
for i=1:length(data.mfcc_clean_test)
    mfcc_clean_test{i} = single(data.mfcc_clean_test{i}(:,1:13)');
    mfcc_noisy_test{i} = single(data.mfcc_noisy_test{i}(:,1:13)');
end

[label_train phones] = alignment2phonePosterior(data.alignment_train, [], 3);
[label_test] = alignment2phonePosterior(data.alignment_test, [], 3);

save('mfcc_label.mat', 'utt_list', 'mfcc_clean_train', 'mfcc_noisy_train', 'mfcc_clean_test', 'mfcc_noisy_test', 'label_train', 'label_test', 'phones');

end


function bc = specific_bc(xbd,ybd)
%zero_bc   zero boundary condition
%   bc = specific_bc(xbd,ybd);
%   input
%          xbd          x boundary coordinate vector
%          ybd          y boundary coordinate vector
%   IFISS function: DJS; 28 February 2005.
% Copyright (c) 2005 D.J. Silvester, H.C. Elman, A. Ramage
bc=zeros(size(xbd));
return


%kvclorec 'Sup-Reconstruction'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros vclorec.pane file
%
% Parameters:
% InputFile: i1 'Input Image #1', required: 'first input image'
% InputFile: i2 'Input Image #2', required: 'second input image'
% InputFile: str 'Struct Element', required: 'Structuring Element'
% OutputFile: o 'Output Image ', required: 'resulting output image'
%
% Example: o = kvclorec({i1, i2, str}, {'i1','';'i2','';'str','';'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% vclorec - Sup-Reconstruction
%
%  DESCRIPTION
% .I vclorec
% will do the closing by reconstruction of an input image by a set structuring element and a conditional image.
%
% The two input images must be of the same size and have the same
% number of data bands.  The input
% images may be of the same or different data types.  If the input
% images are of different data types, then all input images will be
% upcast to the highest input image data type.  The output
% image data type will be the same as that of the highest data type
% of the input images.
%
%
%
%  EXAMPLES
% vclorec -i1 ball.xv -i2 feath.xv -str b272.str -o outimage.xv
%
% Will do the closing by reconstruction of the image 1 "ball.xv", using "feath.xv" as the conditional image, by the structuring set b272.str, with the resulting image written to "outimage.xv".
%
%  "SEE ALSO"
% vcast1(1)
%
%  RESTRICTIONS
% .I vclorec
% can be defined for all data types supported by Khoros, but at the moment it has been implemented just for the bit and unsigned char types.
% The structuring elements are subsets of the 3x3 matrix and the origin is always at the center of this matrix.
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993-1997 Junior Barrera, Roberto Lotufo.  All rights reserved.
%

function varargout = kvclorec(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kvclorec(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i1', '__input';'i2', '__input';'str', '__input';'o', '__output'};
maxval={0,0,0,0};
minval={0,0,0,0};
istoggle=[0,0,0,0];
was_set=istoggle * 0;
paramtype={'InputFile','InputFile','InputFile','OutputFile'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=1; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(1,1);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
[varargout{:}]=callKhoros([w 'vclorec"  '],Inputs,narglist);


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   Set:
%   Set the specified variable to one.
%   Example: robot = Set(robot, do1);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Copyright (C) 2012, by Arturo Gil Aparicio
%
% This file is part of ARTE (A Robotics Toolbox for Education).
%
% ARTE is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% ARTE 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with ARTE.  If not, see <http://www.gnu.org/licenses/>.
function Set(variable)

global configuration robot

%robot.variable = 1;

%do1 is assigned to the
if variable=='do1'
    T07=directkinematic(robot, robot.q)*robot.tool.TCP;
    robot.tool.Trel=inv(T07)*robot.piece.T0;
end


function cursor_demo()
% CURSOR_DEMO - Demo of the MYCURSORS function

% Pictures for the toolbar buttons
pics = CreatePics();

% Create the figure and controls
handles.Fig    = figure('Tag','Fig','Name','Cursors Demo','NumberTitle','off','MenuBar','none','Toolbar','none','Position',[200 200 550 550],'Color',[1 1 1]);
handles.Axe    = axes('Parent',handles.Fig,'Tag','Axe','Units','pixels','Position',[50 200 450 325]);
handles.TbCurs = uitoolbar('Parent',handles.Fig,'Tag','TbCurs');

handles.PtAdd1  = uipushtool('Parent',handles.TbCurs,'Tag','PtAdd1','CData',pics.Plus,'ClickedCallback',@PtAdd1_ClickedCallback,'TooltipString','Add cursor');
handles.PtDel1  = uipushtool('Parent',handles.TbCurs,'Tag','PtDel1','CData',pics.Minus,'ClickedCallback',@PtDel1_ClickedCallback,'TooltipString','Remove last cursor');
handles.PtVal1  = uipushtool('Parent',handles.TbCurs,'Tag','PtVal1','CData',pics.Val,'ClickedCallback',@PtVal1_ClickedCallback,'TooltipString','Display cursors positions');

handles.PtAdd2  = uipushtool('Parent',handles.TbCurs,'Tag','PtAdd2','CData',pics.PlusR,'ClickedCallback',@PtAdd2_ClickedCallback,'TooltipString','Add cursor');
handles.PtDel2  = uipushtool('Parent',handles.TbCurs,'Tag','PtDel2','CData',pics.MinusR,'ClickedCallback',@PtDel2_ClickedCallback,'TooltipString','Remove last cursor');
handles.PtVal2  = uipushtool('Parent',handles.TbCurs,'Tag','PtVal2','CData',pics.ValR,'ClickedCallback',@PtVal2_ClickedCallback,'TooltipString','Display cursors positions');

handles.StVal1  = uicontrol('Parent',handles.Fig,'Tag','StVal1','style','text','units','pixels','position',[ 10 10 210 150],'string','','HorizontalAlignment','left','FontName','Courier New','BackgroundColor',[1 1 1],'ForegroundColor','k');
handles.StVal2  = uicontrol('Parent',handles.Fig,'Tag','StVal2','style','text','units','pixels','position',[230 10 210 150],'string','','HorizontalAlignment','left','FontName','Courier New','BackgroundColor',[1 1 1],'ForegroundColor','r');

% Plot data
plot(sin(-20:.01:20),'Parent',handles.Axe);

% Init Cursor structure
mycurs1 = [];
mycurs2 = [];

%*******************************************************************************

% --- FIRST CURSOR SET ----------------------------------------------

  function PtAdd1_ClickedCallback(varargin)
    % Adds a cursor on the graph

    % If no cursor was created, simply initializes one
    if isempty(mycurs1)
      mycurs1 = mycursors(handles.Axe,'k'); % Create the first cursor and store the structure of function handles
    else
      mycurs1.add(); % Add a cursor to the graph
    end

  end

  function PtDel1_ClickedCallback(varargin)
    % Removes the last cursor added

    % Execute code only if at least one cursor has already been added
    if ~isempty(mycurs1)
      mycurs1.off('last');
    end

  end

  function PtVal1_ClickedCallback(varargin)
    % Displays the positions of all cursors

    % Execute code only if at least one cursor has already been added
    if ~isempty(mycurs1)

      % Get cursors positions
      data = mycurs1.val();

      % Create a matrix with cursor indices on the 1st line and cursor positions
      % on the 2nd line
      data = [1:length(data);data(:)'];

      % Display info in the static text below the axe
      set(handles.StVal1,'string',sprintf('  Cursor %u: %10.2f\n',data(:)))

    end

  end

% --- SECOND CURSOR SET ---------------------------------------------

  function PtAdd2_ClickedCallback(varargin)
    % Adds a cursor on the graph

    % If no cursor was created, simply initializes one
    if isempty(mycurs2)
      mycurs2 = mycursors(handles.Axe,'r'); % Create the first cursor and store the structure of function handles
    else
      mycurs2.add(); % Add a cursor to the graph
    end

  end

  function PtDel2_ClickedCallback(varargin)
    % Removes the last cursor added

    % Execute code only if at least one cursor has already been added
    if ~isempty(mycurs2)
      mycurs2.off('last');
    end

  end

  function PtVal2_ClickedCallback(varargin)
    % Displays the positions of all cursors

    % Execute code only if at least one cursor has already been added
    if ~isempty(mycurs2)

      % Get cursors positions
      data = mycurs2.val();

      % Create a matrix with cursor indices on the 1st line and cursor positions
      % on the 2nd line
      data = [1:length(data);data(:)'];

      % Display info in the static text below the axe
      set(handles.StVal2,'string',sprintf('  Cursor %u: %10.2f\n',data(:)))

    end

  end

% --- OTHER NESTED FUNCTIONS ----------------------------------------

  function pics = CreatePics()
    % Generate pictures matrices to use in the toolbar

    % + sign
    pics.Plus  = repmat([ ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN   0   0 NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN   0   0 NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN   0   0 NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN   0   0 NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN   0   0   0   0   0   0   0   0   0   0 NaN NaN NaN ; ...
      NaN NaN NaN   0   0   0   0   0   0   0   0   0   0 NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN   0   0 NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN   0   0 NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN   0   0 NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN   0   0 NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN   ...
      ],[1,1,3]);

    % - sign
    pics.Minus = repmat([ ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN   0   0   0   0   0   0   0   0   0   0 NaN NaN NaN ; ...
      NaN NaN NaN   0   0   0   0   0   0   0   0   0   0 NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN   ...
      ],[1,1,3]);

    % Matrix
    pics.Val = repmat([ ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN   0   0 NaN NaN   0   0   0 NaN NaN   0   0   0 NaN NaN ; ...
      NaN   0 NaN   0 NaN NaN NaN NaN   0 NaN NaN NaN NaN   0 NaN NaN ; ...
      NaN NaN NaN   0 NaN NaN   0   0   0 NaN NaN NaN   0   0 NaN NaN ; ...
      NaN NaN NaN   0 NaN NaN   0 NaN NaN NaN NaN NaN NaN   0 NaN NaN ; ...
      NaN NaN NaN   0 NaN NaN   0   0   0 NaN NaN   0   0   0 NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN   0 NaN NaN NaN NaN   0   0   0 NaN NaN   0   0   0 NaN NaN ; ...
      NaN   0 NaN   0 NaN NaN   0 NaN NaN NaN NaN   0 NaN NaN NaN NaN ; ...
      NaN   0   0   0 NaN NaN   0   0   0 NaN NaN   0   0   0 NaN NaN ; ...
      NaN NaN NaN   0 NaN NaN NaN NaN   0 NaN NaN   0 NaN   0 NaN NaN ; ...
      NaN NaN NaN   0 NaN NaN   0   0   0 NaN NaN   0   0   0 NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ; ...
      NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN   ...
      ],[1,1,3]);

    pS = [16 16 3];
    col = [1 0 0]; % Red

    % + sign in red
    pics.PlusR = pics.Plus;
    pics.PlusR(pics.PlusR==0) = 1;
    pics.PlusR = reshape( repmat(col,pS(1)*pS(2),1) .* reshape(pics.PlusR,pS(1)*pS(2),3) , pS );

    % - sign in red
    pics.MinusR = pics.Minus;
    pics.MinusR(pics.MinusR==0) = 1;
    pics.MinusR = reshape( repmat(col,pS(1)*pS(2),1) .* reshape(pics.MinusR,pS(1)*pS(2),3) , pS );

    % Matrix in red
    pics.ValR = pics.Val;
    pics.ValR(pics.ValR==0) = 1;
    pics.ValR = reshape( repmat(col,pS(1)*pS(2),1) .* reshape(pics.ValR,pS(1)*pS(2),3) , pS );

  end

end


function [data,age,ndiscarded] = onl_lslreceive(inlet,timeout,maxage)
if nargin<2
    timeout = -1;
end
if nargin<3
    maxage = Inf;
end
ndiscarded = 0;

[tmpsample,timestamp] = inlet.pull_sample(timeout,true);

if isempty(timestamp) || timestamp == 0
    data = [];
    age = NaN;
    return;
end

% tic;
% calculate the age of the sample
age = lsl_local_clock(inlet.get_libhandle()) - (timestamp+inlet.time_correction());
% fprintf('age: %0.5g\n',age);
while age > maxage
    % discard samples that have expired
    [tmpsample,timestamp] = inlet.pull_sample(timeout,true);
    age = lsl_local_clock(inlet.get_libhandle()) - (timestamp+inlet.time_correction());
    ndiscarded = ndiscarded + 1;
end
% toc

if isempty(tmpsample)
    data = [];
    age = NaN;
    return;
end

% now we have a sufficiently current sample
% ...decode the data
% tic;
data = hlp_deserialize(tmpsample{1});
% toc


function [merged_timestamps, merged_signals] = ...
    merge_signals(sig, offset)
    % Merge two signals sample-by-sample given the samples and offsets

    num_signals = length(sig);
    timestamps = cell(num_signals, 1);
    for i = 1:length(sig)
        timestamps{i} = offset(i):offset(i)+length(sig{i}) - 1;
    end

    if num_signals == 2
        [merged_timestamps, merged_signals] = ...
            merge_samples(timestamps{1}, sig{1}, ...
                          timestamps{2}, sig{2});
    elseif length(sig) == 4
        [merged_timestamps, merged_signals] = ...
            merge_samples4(timestamps{1}, sig{1}, ...
                           timestamps{2}, sig{2}, ...
                           timestamps{3}, sig{3}, ...
                           timestamps{4}, sig{4});
    end
end


% KDTREE_BUILD_DEMO: illustrate the functionalities of kdtree_delete
clc, clear, close all;

mex kdtree_build.cpp
mex kdtree_delete.cpp
disp('compiled.');

p = rand( 10, 3 );
tree = kdtree_build( p );
disp(sprintf('tree structure pointer: %d',tree ));
disp('deleting tree');

kdtree_delete(tree);

disp('tree deleted correctly');


function test_nint_test ( )

%*****************************************************************************80
%
%% TEST_NINT_TEST tests the TEST_NINT library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 March 2007
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST_NINT_TEST\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the TEST_NINT library.\n' );

  test_nint_test01 ( );
  test_nint_test02 ( );
  test_nint_test03 ( );
  test_nint_test04 ( );
  test_nint_test05 ( );
  test_nint_test06 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST_NINT_TEST\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


function [MVAbase, bus, gen, gencost, branch, f, success, et] = ...
                runuopf(casedata, mpopt, fname, solvedcase)
%RUNUOPF  Runs an optimal power flow with unit-decommitment heuristic.
%   [RESULTS, SUCCESS] = RUNUOPF(CASEDATA, MPOPT, FNAME, SOLVEDCASE)
%
%   Runs an optimal power flow (AC OPF by default) with a heuristic which
%   allows it to shut down "expensive" generators, optionally returning
%   a RESULTS struct and SUCCESS flag.
%
%   Inputs (all are optional):
%       CASEDATA : either a MATPOWER case struct or a string containing
%           the name of the file with the case data (default is 'case9')
%           (see also CASEFORMAT and LOADCASE)
%       MPOPT : MATPOWER options struct to override default options
%           can be used to specify the solution algorithm, output options
%           termination tolerances, and more (see also MPOPTION).
%       FNAME : name of a file to which the pretty-printed output will
%           be appended
%       SOLVEDCASE : name of file to which the solved case will be saved
%           in MATPOWER case format (M-file will be assumed unless the
%           specified name ends with '.mat')
%
%   Outputs (all are optional):
%       RESULTS : results struct, with the following fields:
%           (all fields from the input MATPOWER case, i.e. bus, branch,
%               gen, etc., but with solved voltages, power flows, etc.)
%           order - info used in external <-> internal data conversion
%           et - elapsed time in seconds
%           success - success flag, 1 = succeeded, 0 = failed
%           (additional OPF fields, see OPF for details)
%       SUCCESS : the success flag can additionally be returned as
%           a second output argument
%
%   Calling syntax options:
%       results = runuopf;
%       results = runuopf(casedata);
%       results = runuopf(casedata, mpopt);
%       results = runuopf(casedata, mpopt, fname);
%       results = runuopf(casedata, mpopt, fname, solvedcase);
%       [results, success] = runuopf(...);
%
%       Alternatively, for compatibility with previous versions of MATPOWER,
%       some of the results can be returned as individual output arguments:
%
%       [baseMVA, bus, gen, gencost, branch, f, success, et] = runuopf(...);
%
%   Example:
%       results = runuopf('case30');
%
%   See also RUNOPF, RUNDUOPF.

%   MATPOWER
%   Copyright (c) 1996-2016, 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.

%%-----  initialize  -----
%% default arguments
if nargin < 4
    solvedcase = '';                %% don't save solved case
    if nargin < 3
        fname = '';                 %% don't print results to a file
        if nargin < 2
            mpopt = mpoption;       %% use default options
            if nargin < 1
                casedata = 'case9'; %% default data file is 'case9.m'
            end
        end
    end
end

%%-----  run the unit de-commitment / optimal power flow  -----
[r, success] = uopf(casedata, mpopt);

%%-----  output results  -----
if fname
    [fd, msg] = fopen(fname, 'at');
    if fd == -1
        error(msg);
    else
        if mpopt.out.all == 0
            printpf(r, fd, mpoption(mpopt, 'out.all', -1));
        else
            printpf(r, fd, mpopt);
        end
        fclose(fd);
    end
end
printpf(r, 1, mpopt);

%% save solved case
if solvedcase
    savecase(solvedcase, r);
end

if nargout == 1 || nargout == 2
    MVAbase = r;
    bus = success;
elseif nargout > 2
    [MVAbase, bus, gen, gencost, branch, f, et] = ...
        deal(r.baseMVA, r.bus, r.gen, r.gencost, r.branch, r.f, r.et);
% else  %% don't define MVAbase, so it doesn't print anything
end


function DrawFaceOnImg( img, shape, out_loc, orig_bbox, visibilities)
%DRAWFACEONIMG Summary of this function goes here
%   Detailed explanation goes here
    f = figure('visible','off','Position', [100, 100, 600, 600]);

    if(nargin > 3)
        [height_img, width_img,~] = size(img);
        width = orig_bbox(3) - orig_bbox(1);
        height = orig_bbox(4) - orig_bbox(2);

        img_min_x = max(int32(orig_bbox(1) - width/3),1);
        img_max_x = min(int32(orig_bbox(3) + width/3),width_img);

        img_min_y = max(int32(orig_bbox(2) - height/3),1);
        img_max_y = min(int32(orig_bbox(4) + height/3),height_img);

        shape(:,1) = shape(:,1) - double(img_min_x);
        shape(:,2) = shape(:,2) - double(img_min_y);
        img = img(img_min_y:img_max_y, img_min_x:img_max_x, :);
    end

    % Downsize the image if it is very big
    if(size(img,1) > 500 || size(img,2) > 500)
        scale = min(500 / size(img,1), 500 / size(img,2));
        img = imresize(img, scale);
        shape = scale * shape;
    end
    if(nargin > 4)
        % valid points to draw (not to draw
        % occluded ones)
        v_points = visibilities;
    else
        v_points = true(size(shape,1),1);
    end

    if(max(img(:)) > 1)
        imshow(double(img)/255, 'Border', 'tight');
    else
        imshow(double(img), 'Border', 'tight');
    end
    hold on;

    plot(shape(v_points,1), shape(v_points,2),'.r','MarkerSize',20);
    plot(shape(v_points,1), shape(v_points,2),'.b','MarkerSize',10);
    print(f, '-djpeg', out_loc);
    close(f);
end


%% dicom3Dpar
% Below is a demonstration of the features of the |dicom3Dpar| function

%%
clear; close all; clc;

%% Syntax
% |[varargout]=dicom3Dpar(D);|

%% Description
% This function retrieves the voxel size, position, and orientation
% information from a DICOM file.

%% Examples
%

%%
% Path name for dicom files

defaultFolder = fileparts(fileparts(mfilename('fullpath'))); %Set main folder
pathName=fullfile(defaultFolder,'data','DICOM','0001_human_calf');
fileName=fullfile(pathName,'00001.dcm');

%%
% Get dicom information
dcmInfo=dicominfo(fileName);

%%
% Get 3D/geometry information, e.g. voxel size, position, and orientation
% information.

[v,OR,r,c]=dicom3Dpar(dcmInfo)

%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% 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/>.


function w = load_sac(request)
   %LOAD_SAC loads a waveform from SAC files
   % combineWaves isn't currently used!

   % request.combineWaves is ignored

   if isstruct(request)
      [thisSource, chanInfo, startTimes, endTimes, ~] = unpackDataRequest(request);
      for i=1:numel(chanInfo)
         for j=1:numel(startTimes)
            thisfilename = getfilename(thisSource,chanInfo(i),startTimes(j));
            w(i,j) = loadSacByFilenames(thisfilename);
            w(i,j) = extract(w(i,j), 'time', startTimes(j), endTimes(j)); % added by Glenn 2016/05/25
         end
      end
      w = w(:);

   else
      %request should be a filename
      % modified by Glenn 2016/05/25
      thisFilename = request;
      if exist(thisFilename, 'file')
          w = loadSacByFilenames(thisFilename);
      else
          w = waveform();
          warning(sprintf('File %s does not exist',thisFilename));
      end
   end

end

function w = loadSacByFilenames(filename)
   %LOADSAC  creates a waveform from a SAC file
   % waveform = loadSacByFilenames(waveform, filename);
   % To call, the first argument must be a waveform.  However this waveform
   % will never be accessed-- it will be overwritten by the SAC information.
   % Therefore, you can use "waveform" as your first argument, so that a
   % generic waveform object will be created for you
   %
   % If the filename is a cell of several SAC file names, such as:
   % fn = {'BOB.SHZ.AV','TOM.EHZ.AV','HARRY.EHZ.AV'}
   % then, w = loadSacByFilenames(waveform,fn) will return a matrix of waveforms, the
   % same size and shape  as fn.   fn(N,M) will be the SAC file name for the
   % waveform denoted by w(N,M).  In the example above, loadSacByFilenames will return a
   % 1x3 waveform object, with all three files.
   %
   % Programming suggestion???select files using a dialog box, by using the
   % following code:
   %   % display the dialog box used for selecting files, and
   %   % allow for multiple selections
   %   [f,d] = uigetfile({'*.*','all Files (*.*)'}, 'MultiSelect', 'on');
   %
   %   % f will have one or more file names, so concatenate them
   %   % with the directory
   %   filename = strcat(d,f);
   %
   %   %call loadSacByFilenames to load all these files into waveform objects
   %   w = loadSacByFilenames(waveform, filename);
   %
   % The SAC header is parsed out, with the following equivelent fields used
   % by waveform:
   % _waveform_ 	_sac_
   % STATION		KSTNM
   % CHANNEL		KCMPNM
   % FREQUENCY		1 / DELTA (ODELTA is not used)
   % START			NZYEAR, NZJDAY, NZHOUR, NZMIN, NZSEC, NZMSEC
   % UNITS			IDEP is parsed.  IUNK becomes "Counts"
   % All header fields with values - that is, header fields that do not
   % contain the value  -12345 (either numeric or text) - are put into
   % user-defined fields within the waveform.
   % These fields can then be accessed via get/set.  User-defined fields
   % includes those that are parsed into waveform's predefined  fields as
   % listed above.
   %
   % loadSacByFilenames uses routines originating in code borrowed from
   % Mike Thorn
   %
   % For more information about the SAC header, and the interpretation of the
   % fields, check out Lawrence Livermore's web site.  Search for "seismic
   % sac" and you'll find it.

   if ~iscell(filename)
      filename = {filename};
   end

   sacdata = readsacfile(filename{:});
   w = sac2waveform(sacdata);
   w = removeSacDuplicates(w);
   for n=1:numel(filename)
      w(n) = addhistory(w(n),'Loaded SAC file: %s',filename{n});
   end
end

function w = removeSacDuplicates(w)
   % because all the files are loaded with fields blindly filled in, several
   % of the duplicated (and easily outdated and contradictory) fields are
   % henceforth removed
   % These fields are regenerated when the SAC file is written back to disk.
   noHistory = true;
   w = delfield(w,'B',noHistory); %covered by get(w,'start_epoch');
   w = delfield(w,'E',noHistory); %covered by get(w,'end_epoch');
   w = delfield(w,'DEPMIN',noHistory); %covered by min(w);
   w = delfield(w,'DEPMAX',noHistory);%covered by max(w);
   w = delfield(w,'DEPMEN',noHistory);%covered by mean(w);
   w = delfield(w,'NPTS',noHistory); %covered by get(w,'data_length');
   w = delfield(w,'KSTNM',noHistory); %covered by get(w,'station');
   w = delfield(w,'KCMPNM',noHistory); %covered by get(w,'channel');
   w = delfield(w,'KNETWK',noHistory); %covered by get(w,'network');
   w = delfield(w,'DELTA',noHistory); %covered by get(w,'period');
   w = delfield(w,'NVHDR',noHistory); %covered by get(w,'data_length');
   w = delfield(w,'IDEP',noHistory); %covered by get(w,'units'); %idEP is just a code.

   w = delfield(w,'LEVEN',noHistory); %by nature, data is evenly spaced
   w = delfield(w,'IDEP',noHistory); %covered by get(w,'units'); %idEP is just a code.

   %the following date values are convenient, but also may be outdated easily.
   %w = delfield(w,'NZYEAR',noHistory); %covered by get(w,'start');
   %w = delfield(w,'NZJDAY',noHistory); %covered by get(w,'start');
   %w = delfield(w,'NZHOUR',noHistory); %covered by get(w,'start');
   %w = delfield(w,'NZMIN',noHistory); %covered by get(w,'start');
   %w = delfield(w,'NZSEC',noHistory); %covered by get(w,'start');
   %w = delfield(w,'NZMSEC',noHistory); %covered by get(w,'start');
end


function j_progress(varargin)
% function fn_progress(prompt,max[,size])
% function fn_progress(prompt,max,'%' or 'p')
% function fn_progress(prompt)
% function fn_progress(i)
% function fn_progress('end')
% function fn_progress('cont')
% from Thomas Deneux, modified by Julien Cohen-Adad 2006-11-24
%
% example: j_progress('Pouf pouf. Please wait...');for i=1:50, j_progress(i/50), pause(.01), end;j_progress('elapsed')
%---
% progress indicator

persistent promptsize
persistent curi
persistent after
persistent size
persistent pflag
persistent max

if ischar(varargin{1}) % INITIALIZATION or special
    prompt = varargin{1};

    if ischar(prompt) % special cases
        switch prompt
            case 'end'
                fprintf(repmat('\b',1,promptsize+1+size+length(after)+1))
                return
            case 'cont'
                disp(sprintf(repmat(' ',1,promptsize+1+size+length(after))))
                return
            case 'elapsed'
                disp([sprintf([repmat('\b',1,size+length(after)+1) 'OK (elapsed time ' num2str(toc) ' seconds)'])])

%                 disp([sprintf(['elapsed ' num2str(toc) ' s']) after])

%                 disp(['elapsed ' num2str(toc) ' s'])
                return
            case 'elapsedmin'
                disp(['elapsed ' num2str(toc/60,'%.1f') 's.'])
                return
        end
    end

    % Input
    promptsize = length(prompt);
    i = 0; curi = i;
    if nargin<2
        pflag = true;
        max = 1;
        size = 3;
    else
        max = varargin{2};
        if ischar(max)
            max = str2num(max);
        end
        pflag = false;
        if nargin>2
            size = varargin{3};
            if strcmp(size,'%') || strcmp(size,'p')
                pflag = true;
                size = 3;
            elseif ischar(size)
                size = str2num(size);
            end
        else
            size = floor(log10(max))+1;
        end
    end
    csize = num2str(size);
    if pflag
        after = sprintf('%%');
    else
        after = sprintf(['/%' csize 'i'],max);
    end
    disp([sprintf([prompt ' %' csize 'i'],i) after])
    tic
else % STATE PROGRESS
    i = varargin{1};
    if pflag, i = floor(i/max*100); end
    if (i == curi), return, end
    curi = i;
    csize = num2str(size);
    disp([sprintf([repmat('\b',1,size+length(after)+1) '%' csize 'i'],i) after])
end


% --------------------------------------------------------
% MDP Tracking
% Copyright (c) 2015 CVGL Stanford
% Licensed under The MIT License [see LICENSE for details]
% Written by Yu Xiang
% --------------------------------------------------------
%
% draw dres structure
function show_dres(frame_id, I, tit, dres, state, cmap)

if nargin < 5
    state = 1;
end

if nargin < 6
    cmap = colormap;
end

imshow(I);
title(tit);
hold on;

if isempty(dres) == 1
    index = [];
else
    if isfield(dres, 'state') == 1
        index = find(dres.fr == frame_id & dres.state == state);
    else
        index = find(dres.fr == frame_id);
    end
end

ids = unique(dres.id);
for i = 1:numel(index)
    ind = index(i);

    x = dres.x(ind);
    y = dres.y(ind);
    w = dres.w(ind);
    h = dres.h(ind);
    r = dres.r(ind);

    if isfield(dres, 'id') && dres.id(ind) > 0
        id = dres.id(ind);
        id_index = find(id == ids);
        str = sprintf('%d', id_index);
        index_color = min(1 + floor((id_index-1) * size(cmap,1) / numel(ids)), size(cmap,1));
        c = cmap(index_color,:);
    else
        c = 'g';
        str = sprintf('%.2f', r);
    end
    if isfield(dres, 'occluded') && dres.occluded(ind) > 0
        s = '--';
    else
        s = '-';
    end
    rectangle('Position', [x y w h], 'EdgeColor', c, 'LineWidth', 4, 'LineStyle', s);
    text(x, y-size(I,1)*0.01, str, 'BackgroundColor', [.7 .9 .7], 'FontSize', 14);

    if isfield(dres, 'id') && dres.id(ind) > 0
        % show the previous path
        ind = find(dres.id == id & dres.fr <= frame_id);
        centers = [dres.x(ind)+dres.w(ind)/2, dres.y(ind)+dres.h(ind)];
        patchline(centers(:,1), centers(:,2), 'LineWidth', 4, 'edgecolor', c, 'edgealpha', 0.3);
    end
end
hold off;


%ADDPREPROC Add commands in the PREPROC field of a datafile
%
%   A = ADDPREPROC(A,PREPROC,PARS,OUTSIZE)
%
% INPUT
%   A       - Datafile
%   PREPROC - String with preprocessing command
%   PARS    - Cell array with parameters (default empty)
%   OUTSIZE - Output size of objects
%
% OUTPUT
%   A       - Datafile
%
% DESCRIPTION
% Extends the structure array of preprocessing commands, A.PREPROC( )
% with one element, having two fields:
% A.PREPROC(N).PREPROC = PREPROC
% A.PREPROC(N).PARS = PARS
%
% Preprocessing can only be defined for raw datafiles that do not contain
% datasets. It is an error to define preprocessing for a datafile that
% points to MAT files. In that case datasets are expected and preprocessing
% is superfluous.
%
% The first command in the PREPROC field should always be a file read
% command. The DATAFILE constructor stores by default IMREAD. Use
% SETPREPROC to clear the PREPROC field and replace it by another
% command.
%
% PRTools needs to know the size of the output objects. If not supplied in
% the call, it is found by processing the first object. This may take some
% time.
%
% SEE ALSO (PRTools Guide)
% DATAFILES, SETPREPROC, ADDPOSTPROC, DATASETS


function prepro = spm_cfg_eeg_inv_prepro
% Configuration file for configuring imaging source inversion reconstruction
%__________________________________________________________________________
% Copyright (C) 2015 Wellcome Trust Centre for Neuroimaging

% Vladimir Litvak
% $Id: spm_cfg_eeg_inv_prepro.m 6444 2015-05-21 11:15:48Z guillaume $

D = cfg_files;
D.tag = 'D';
D.name = 'M/EEG datasets';
D.filter = 'mat';
D.num = [1 Inf];
D.help = {'Select the M/EEG mat files.'};

val = cfg_entry;
val.tag = 'val';
val.name = 'Inversion index';
val.strtype = 'n';
val.help = {'Index of the cell in D.inv where the forward model can be found and the results will be stored.'};
val.val = {1};

all = cfg_const;
all.tag = 'all';
all.name = 'All';
all.val  = {1};

condlabel = cfg_entry;
condlabel.tag = 'condlabel';
condlabel.name = 'Condition label';
condlabel.strtype = 's';
condlabel.val = {''};

conditions = cfg_repeat;
conditions.tag = 'conditions';
conditions.name = 'Conditions';
conditions.help = {'Specify the labels of the conditions to be included in the inversion'};
conditions.num  = [1 Inf];
conditions.values  = {condlabel};
conditions.val = {condlabel};

whatconditions = cfg_choice;
whatconditions.tag = 'whatconditions';
whatconditions.name = 'What conditions to include?';
whatconditions.values = {all, conditions};
whatconditions.val = {all};

standard = cfg_const;
standard.tag = 'standard';
standard.name = 'Standard';
standard.help = {'Use default settings for the inversion'};
standard.val  = {1};

invtype = cfg_menu;
invtype.tag = 'invtype';
invtype.name = 'Inversion type';
invtype.help = {'Select the desired inversion type'};
invtype.labels = {'GS', 'ARD', 'MSP (GS+ARD)' 'COH', 'IID', 'EBB'};
invtype.values = {'GS', 'ARD', 'MSP', 'LOR', 'IID', 'EBB'};
invtype.val = {'GS'};

woi = cfg_entry;
woi.tag = 'woi';
woi.name = 'Time window of interest';
woi.strtype = 'r';
woi.num = [1 2];
woi.val = {[-Inf Inf]};
woi.help = {'Time window to include in the inversion (ms)'};

foi = cfg_entry;
foi.tag = 'foi';
foi.name = 'Frequency window of interest';
foi.strtype = 'r';
foi.num = [1 2];
foi.val = {[0 256]};
foi.help = {'Frequency window (the same as high-pass and low-pass in the GUI)'};

hanning = cfg_menu;
hanning.tag = 'hanning';
hanning.name = 'PST Hanning window';
hanning.help = {'Multiply the time series by a Hanning taper to emphasize the central part of the response.'};
hanning.labels = {'yes', 'no'};
hanning.values = {1, 0};
hanning.val = {1};

priorsmask  = cfg_files;
priorsmask.tag = 'priorsmask';
priorsmask.name = 'Priors file';
priorsmask.filter = '(.*\.gii$)|(.*\.mat$)|(.*\.nii(,\d+)?$)|(.*\.img(,\d+)?$)';
priorsmask.num = [0 1];
priorsmask.help = {'Select a mask or a mat file with priors.'};
priorsmask.val = {{''}};

space = cfg_menu;
space.tag = 'space';
space.name = 'Prior image space';
space.help = {'Space of the mask image.'};
space.labels = {'MNI', 'Native'};
space.values = {1, 0};
space.val = {1};

priors = cfg_branch;
priors.tag = 'priors';
priors.name = 'Source priors';
priors.help = {'Restrict solutions to pre-specified VOIs'};
priors.val  = {priorsmask, space};

locs  = cfg_entry;
locs.tag = 'locs';
locs.name = 'Source locations';
locs.strtype = 'r';
locs.num = [Inf 3];
locs.help = {'Input source locations as n x 3 matrix'};
locs.val = {zeros(0, 3)};

radius = cfg_entry;
radius.tag = 'radius';
radius.name = 'Radius of VOI (mm)';
radius.strtype = 'r';
radius.num = [1 1];
radius.val = {32};

restrict = cfg_branch;
restrict.tag = 'restrict';
restrict.name = 'Restrict solutions';
restrict.help = {'Restrict solutions to pre-specified VOIs'};
restrict.val  = {locs, radius};

custom = cfg_branch;
custom.tag = 'custom';
custom.name = 'Custom';
custom.help = {'Define custom settings for the inversion'};
custom.val  = {woi, foi, hanning};

isstandard = cfg_choice;
isstandard.tag = 'isstandard';
isstandard.name = 'Inversion parameters';
isstandard.help = {'Choose whether to use standard or custom inversion parameters.'};
isstandard.values = {standard, custom};
isstandard.val = {standard};

modality = cfg_menu;
modality.tag = 'modality';
modality.name = 'Select modalities';
modality.help = {'Select modalities for the inversion (only relevant for multimodal datasets).'};
modality.labels = {'All', 'EEG', 'MEG', 'MEGPLANAR', 'EEG+MEG', 'MEG+MEGPLANAR', 'EEG+MEGPLANAR'};
modality.values = {
    {'All'}
    {'EEG'}
    {'MEG'}
    {'MEGPLANAR'}
    {'EEG', 'MEG'}
    {'MEG', 'MEGPLANAR'}
    {'EEG', 'MEGPLANAR'}
    }';
modality.val = {{'All'}};

prepro = cfg_exbranch;
prepro.tag = 'prepro';
prepro.name = 'Inversion preprocessing';
prepro.val = {D, val, whatconditions, isstandard, modality};
prepro.help = {'Run imaging source reconstruction'};
prepro.prog = @run_prepro;
prepro.vout = @vout_prepro;
prepro.modality = {'EEG'};

function  out = run_prepro(job)

D = spm_eeg_load(job.D{1});

inverse = [];
if isfield(job.whatconditions, 'condlabel')
    inverse.trials = job.whatconditions.condlabel;
end

if isfield(job.isstandard, 'custom')
    %inverse.type = job.isstandard.custom.invtype;
    inverse.woi  = fix([max(min(job.isstandard.custom.woi), 1000*D.time(1)) min(max(job.isstandard.custom.woi), 1000*D.time(end))]);
    inverse.Han  = job.isstandard.custom.hanning;
    inverse.lpf  =  fix(min(job.isstandard.custom.foi));
    inverse.hpf  =  fix(max(job.isstandard.custom.foi));

end

[mod, list] = modality(D, 1, 1);
if strcmp(job.modality{1}, 'All')
    inverse.modality  = list;
else
    inverse.modality  = intersect(list, job.modality);
end

if numel(inverse.modality) == 1
    inverse.modality = inverse.modality{1};
end

D = {};

for i = 1:numel(job.D)
    D{i} = spm_eeg_load(job.D{i});

    D{i}.val = job.val;

    D{i}.con = 1;

    if ~isfield(D{i}, 'inv')
        error('Forward model is missing for subject %d.', i);
    elseif  numel(D{i}.inv)<D{i}.val || ~isfield(D{i}.inv{D{i}.val}, 'forward')
        if D{i}.val>1 && isfield(D{i}.inv{D{i}.val-1}, 'forward')
            D{i}.inv{D{i}.val} = D{i}.inv{D{i}.val-1};
            warning('Duplicating the last forward model for subject %d.', i);
        else
            error('Forward model is missing for subject %d.', i);
        end
    end

    D{i}.inv{D{i}.val}.inverse = inverse;
end

D = spm_eeg_invert_prepro(D);

if ~iscell(D)
    D = {D};
end

for i = 1:numel(D)
    save(D{i});
end

out.D = job.D;

function dep = vout_prepro(job)
% Output is always in field "D", no matter how job is structured
dep = cfg_dep;
dep.sname = 'M/EEG dataset(s) after imaging source reconstruction';
% reference field "D" from output
dep.src_output = substruct('.','D');
% this can be entered into any evaluated input
dep.tgt_spec   = cfg_findspec({{'filter','mat'}});