function canlab_glm_group_levels(varargin)
% Performs group level robust GLM analysis with robfit
%   1. sets up analysis
%   2. runs robfit
%   3. (optionally) make inverse p maps (for FSL viewing)
%   4. (optionally) estimate significant cluster sizes
%   5. publishes analysis with robfit_results_batch
%
% :Usage:
% ::
%
%     canlab_glm_group_levels([options])
%
% :Optional Inputs:
%
%   **'s', subjects:**
%        cell array of filenames of subject-level analysis directories IN
%        modeldir
%        (note: modeldir won't be prepended to absolute paths)
%
%   **'m', modeldir:**
%        filename of directory containing subject level analyses
%
%   **'o', grpmodeldir:**
%        output directory name
%
%   **'c', cov:**
%        a matrix describing group level model
%        (do not include intercept, it is automatically included as first regressor)
%
%        see help robfit
%
%        note: requires specifying an output directory name
%
%        note: ordering of inputs (rows) must match subjects ordering
%
%   **'n', covname:**
%        a cell array of names for the covariates in cov
%
%   **'f', covfile:**
%        a csv file will specify the group level model:
%        first column, header 'subject', contains names of subject
%        directories (to be found in modeldir)
%        subsequent columns have covariates, headers are names of covariates
%        name of covfile will be name of group analysis directory (placed in
%        grpmodeldir)
%
%   **'mask', maskimage:**
%        filename of mask image
%
%   **DSGN:**
%        will use the following fields of the DSGN structure:
%        modeldir    = DSGN.modeldir
%
%        subjects    = DSGN.subjects
%
%        maskimage   = DSGN.mask
%
% :Note:
%   A covfile will cause other specifications of subject, cov, and
%   covnames to be ignored.
%
%   If parameters are defined more than once (e.g., modeldir or subjects),
%   only the last entered option will count.
%
% :Defaults:
%
%   **subjects:**
%        all SPM.mat-containing directories in modeldir
%
%   **modeldir:**
%        pwd
%
%   **grpmodeldir:**
%        modeldir/one_sample_t_test
%
%   **cov:**
%        {} (run 1 sample t-test, see help robfit)
%
%   **covname:**
%        'groupmean'
%
%   **mask:**
%        'brainmask.nii'
%
% :Options:
%
%   **'README':**
%        prints canlab_glm_README, an overview of canlab_glm_{subject,group}_levels
%
%   **'overwrite':**
%        overwrite existing output directories
%
%   **'noresults':**
%        don't run/publish robfit_results_batch
%
%   **'onlyresults':**
%        just run/publish robfit_results_batch, don't run robfit (assumes existing analyses)
%
%   **'whichcons', [which cons]
%       vector of contrasts to analyze (DEFAULT: aall subject level contrasts)
%       see [which cons] in help robfit
%
%   **'invp' [, target_space_image]:**
%       generate inverse p maps and resample to the voxel and image dimensions
%       of target_space_image
%       (viewable on dream with ~ruzicl/scripts/invpview)
%
%   **'nolinks':**
%        do not make directory of named links to robust directories (using contrast names)
%
%   **'dream':**
%        if you're running on the dream cluster, this option will cause
%       all analyses (e.g., lower level contrasts) to be run in parallel
%       (submitted with matlab DCS and the Sun Grid Engine)
%       Note: currently only works with MATLAB R2009a
%
%   **'email', address:**
%       send notification email to address when done running
%
% ..
%     ----------------------------------------------------------------------
%     Copyright (C) 2013  Luka Ruzic
%
%     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/>.
%     ----------------------------------------------------------------------
%
%     Programmers' notes
%     NOT READY YET:
%     'grf'
%       estimate significant cluster sizes for each contrast using GRF theory
%       will run at a=.05, voxelwise thresholds of .05, .01, .005, .001
%       see help estimate_cluster_extent
% ..

STARTTIME = datestr(now,31); % SET UP

STARTINGDIR = pwd;

% path
addpath(genpath('/usr/local/spm/spm8/matlabbatch'));
addpath(genpath('/usr/local/spm/spm8/apriori'));
addpath(genpath('/usr/local/spm/spm8/canonical'));

% set defaults
OPTS.parallel_dream = '';
OPTS.overwrite = false;
OPTS.run_results = true;
OPTS.run_robfit = true;
OPTS.run_printconnames = true;
OPTS.run_invp = false;
OPTS.run_grf = false;
OPTS.run_links = true;
OPTS.nocatch = false;

pthresh = [.05 .01 .005 .001]; % for significant cluster extent estimation

EXPT.cov = [];
EXPT.mask = which('brainmask.nii');

% set up statuses
robfitstatus = 0;
invpstatus = 0;
grfstatus = 0;
linkdirstatus = 0;
reviewstatus = 0;

diarydirname = 'canlab_glm_logs';
diaryfilename = ['group_levels_' regexprep(regexprep(STARTTIME,' ','_'), ':','') '.log'];

%% parse arguments
i=1;
while i<=numel(varargin)
    if isstruct(varargin{i})
        DSGN = varargin{i};
        if isfield(DSGN,'modeldir')
            modeldir = DSGN.modeldir;
        end
        if isfield(DSGN,'subjects')
            for s = 1:numel(DSGN.subjects)
                [dummy subname{s}] = fileparts(DSGN.subjects{s}); %#ok
                sublevs{s} = subname{s}; %#ok
            end
        end
        if isfield(DSGN,'mask')
            EXPT.mask = DSGN.mask;
        end
    elseif ischar(varargin{i})
        switch varargin{i}
            case {'README'}
                if ispc()
                    system(sprintf('type %s',which('canlab_glm_README.txt')));
                else
                    system(sprintf('cat %s',which('canlab_glm_README.txt')));
                end
                return;
            case {'dream'}
                version = ver('matlab');
                switch version.Release
                    case '(R2009a)'
                        OPTS.parallel_dream = '2009a';
                    case '(R2011a)'
                        OPTS.parallel_dream = '2011a';
                    otherwise
                        error('Current version of matlab (%s)',version.Release)
                end
            case {'f'}
                i=i+1;
                covfile = varargin{i};
            case {'c'}
                i=i+1;
                EXPT.cov = varargin{i};
            case {'n'}
                i=i+1;
                EXPT.covnames = ['intercept' varargin{i}];
            case {'s'}
                i=i+1;
                sublevs = varargin{i};
            case {'d' 'm'}
                i=i+1;
                modeldir = varargin{i};
            case {'mask'}
                i=i+1;
                EXPT.mask = varargin{i};
            case {'overwrite'}
                OPTS.overwrite = true;
            case {'noresults'}
                OPTS.run_results = false;
            case {'onlyresults'}
                OPTS.run_robfit = false;
            case {'whichcons'}
                i=i+1;
                includedcons = varargin{i};
            case {'invp'}
                OPTS.run_invp = true;
            case {'grf'}
                OPTS.run_grf = true;
            case {'nolinks'}
                OPTS.run_links = false;
            case {'nocatch'}
                OPTS.nocatch = true;
            case {'o'}
                i=i+1;
                grpmodeldir = varargin{i};
            case {'email'}
                i=i+1;
                address = varargin{i};
            otherwise
                error(['Unrecognized argument: ' varargin{i}])
        end
    else
        disp(varargin{i})
        error('Above argument is unrecognized.')
    end
    i=i+1;
end

% MODELDIR
if ~exist('modeldir','var')
    modeldir = pwd;
end
if ~exist(modeldir,'dir')
    error(['No such directory: ' modeldir])
else
    % make absolute (unsure if necessary)

    % This is a bug on discovery
%     modeldir = filenames(modeldir,'absolute','char');
end

% SUBLEVS
if exist('sublevs','var')
    for s = 1:numel(sublevs)
        if ~strcmp(sublevs{s}(1),'/')
            sublevs{s} = fullfile(modeldir,sublevs{s}); %#ok
        end
    end
end

% GRPMODELDIR
if ~exist('grpmodeldir','var')
    if exist('modeldir','var')
        grpmodeldir = fullfile(modeldir,'one_sample_t_test');
    else
        grpmodeldir = fullfile(pwd,'one_sample_t_test');
    end
end
% make grpmodeldir
if ~exist(grpmodeldir,'dir')
    mkdir(grpmodeldir)
end
% make absolute
grpmodeldir = filenames(grpmodeldir,'absolute','char');

% COV
if exist('covfile','var')
    if ~exist(covfile,'file')
        error(['No such file: ' covfile])
    else
        [d f e] = fileparts(covfile); %#ok

        % grpmodeldir
        grpmodeldir = fullfile(fileparts(grpmodeldir),f);

        % sublevs
        tempsubsfile = fullfile(d,[f '_tempsubs.txt']);
        system(['cut -d, -f1 < ' covfile ' | tail -n +2 > ' tempsubsfile]);
        sublevs = importdata(tempsubsfile); delete(tempsubsfile);
        if isnumeric(sublevs), sublevs = textscan(num2str(sublevs'), '%s'); sublevs=sublevs{1}; end
        for i=1:numel(sublevs)
            sublevs{i} = fullfile(modeldir,sublevs{i});
        end

        % cov, covnames
        tempcovsfile = fullfile(d,[f '_tempcovs.txt']);
        system(['cut -s -d, -f2- < ' covfile ' > ' tempcovsfile]);
        s = importdata(tempcovsfile); delete(tempcovsfile);
        if isfield(s,'data')
            EXPT.cov = s.data;
            EXPT.covnames = ['intercept' s.colheaders];
        else
            EXPT.covnames = {'groupmean'};
        end
    end
else
    if isempty(EXPT.cov)
        EXPT.covnames = {'groupmean'};
    else
        if ~exist('grpmodeldir','var')
            error('cov has been specified: must specify grpmodeldir.')
        end
        if isfield(EXPT,'covnames')
            if numel(EXPT.cov) ~= numel(EXPT.covnames)
                error('Number of covariate names (%d) does not match number of covariates (%d).',numel(EXPT.covnames),numel(EXPT.cov))
            end
        else
            EXPT.covnames{1} = 'intercept';
            for i=2:numel(EXPT.cov)
                EXPT.covnames{i} = sprintf('grpcov%d',i-1);
            end
        end
    end
end

% set up diary - to be on except when calling other functions that do their own logging
diarydir = fullfile(grpmodeldir,diarydirname);
if ~exist(diarydir,'dir'), mkdir(diarydir); end
% diarydir = filenames(diarydir,'absolute','char');
diarydir = filenames(diarydir, 'char');
diaryname = fullfile(diarydir,diaryfilename);
fulldiaryname = regexprep(diaryname,'\.log$','_full.log');
fprintf('Writing to logfile: %s\n',diaryname)
diary(diaryname), fprintf('> STARTED: %s\n',STARTTIME), diary off

% make working directory
wd = regexprep(diaryname,'\.log$','');
mkdir(wd)

%% SET UP AND RUN ROBFIT
diary(diaryname), announce_string('ROBUST REGRESSION'), diary off
if ~OPTS.run_robfit
    diary(diaryname), fprintf('> SKIPPED: turned off in options\n'); diary off
else
    % subject level analyses + 1 SPM.mat (assumed representative)
    if ~exist('sublevs','var')
        diary(diaryname), fprintf('> No subject levels specified: looking for all subject level analyses in:\n\t%s\n',modeldir); diary off
%         spmfiles = filenames(fullfile(modeldir,'*/SPM.mat'),'absolute');
        spmfiles = filenames(fullfile(modeldir,'*/SPM.mat'));
        if isempty(spmfiles)
            diary(diaryname), fprintf('> ERROR: No subject level analyses found.\n'), diary off
            cd(STARTINGDIR)
            return
        end
        for i=1:numel(spmfiles), [sublevs{i}] = fileparts(spmfiles{i}); end %#ok
        sublevs = unique(sublevs);
        spmfile = spmfiles{1};
    else
        spmfile = fullfile(sublevs{1},'SPM.mat');
    end

    diary(diaryname)
    fprintf('> Subject level analyses:\n')
    for i=1:numel(sublevs)
        fprintf('>  %-8d%s\n',i,sublevs{i})
    end
    diary off

    if exist(spmfile,'file')
        load(spmfile)
    else
        diary(diaryname), fprintf('> ERROR: No such file: %s\n',spmfile); diary off
        cd(STARTINGDIR)
        return
    end

    % connames, connums, P
    diary(diaryname), fprintf('> Loading contrast names from:\n> \t%s\n',spmfile); diary off
    tcons = strmatch('T', char(SPM.xCon.STAT));
    EXPT.SNPM.connames = strvcat(SPM.xCon(tcons).name); %#ok

    ncons = size(EXPT.SNPM.connames,1);
    EXPT.SNPM.connums = 1:ncons;
    EXPT.SNPM.P = {};
    for c = 1:ncons
        confiles = {};
        for s = 1:numel(sublevs)
            confilename = fullfile(sublevs{s}, sprintf('con_%04d.nii', tcons(c)));
%             confile = filenames(confilename, 'char', 'absolute');
            confile=confilename;
            if exist(confile,'file')
                confiles{s} = confile; %#ok
            else
                diary(diaryname), fprintf('> ERROR: No such contrast file: %s\n',confilename); diary off
                cd(STARTINGDIR)
                return
            end
        end
        EXPT.SNPM.P{c} = strvcat(confiles); %#ok
    end

    %% RUN ROBFIT
    diary(diaryname), fprintf('> Group level analysis directory:\n> \t%s\n',grpmodeldir); diary off
    cd(grpmodeldir);

    save EXPT EXPT

    % which contrasts should be run
    if ~exist('includedcons','var')
        includedcons = [];
        for c = 1:numel(EXPT.SNPM.connums)
            if OPTS.overwrite || numel(filenames(fullfile(pwd,sprintf('robust%04d', c),'rob_p_*img'))) < size(EXPT.cov,2)+1
                includedcons = [includedcons, c]; %#ok
            end
        end
    end

    if isempty(includedcons)
        diary(diaryname), fprintf('> No robust regressions to run.\n'); diary off
    else
        diary(diaryname)
        fprintf('> Subject level contrasts:\n');
        for i=1:size(EXPT.SNPM.connames,1)
            fprintf('> ');
            if ~sum(find(includedcons == i)), fprintf('*EXCLUDED*  '); end
            fprintf(' %-4d%s\n',i,EXPT.SNPM.connames(i,:));
        end
        fprintf('> Group level predictors:\n');
        for i=1:numel(EXPT.covnames)
            fprintf('>  %-4d%s\n',i,EXPT.covnames{i});
        end
        diary off

        njobs = numel(includedcons) * (1+numel(EXPT.covnames));
        if ~isempty(OPTS.parallel_dream) && njobs>1
            % define scheduler
            sched = findResource('scheduler', 'type', 'generic');
            set(sched,'ClusterSize', 1);
            set(sched,'DataLocation',wd);
            switch OPTS.parallel_dream
                case '2009a'
                    set(sched,'ClusterMatlabRoot','/usr/local/matlab/R2009a');
                    set(sched,'ParallelSubmitFcn',@sgeParallelSubmitFcn);
                    set(sched,'SubmitFcn',@sgeSubmitFcn);
                    set(sched,'DestroyJobFcn', @sgeDestroyJobFcn);
                    set(sched,'DestroyTaskFcn',@sgeDestroyTaskFcn);
                case '2011a'
                    set(sched,'ClusterMatlabRoot','/usr/local/matlab/R2011a');
                    set(sched,'ParallelSubmitFcn',@parallelSubmitFcn);
                    set(sched,'SubmitFcn',@distributedSubmitFcn);
                    set(sched,'DestroyJobFcn', @destroyJobFcn);
                    set(sched,'DestroyTaskFcn',@destroyTaskFcn);
            end
            set(sched,'ClusterOsType','unix');
            set(sched,'HasSharedFileSystem', true);
            nargsout = 1;

            % submit jobs
            diary(diaryname), fprintf('> %s\tSubmitting jobs to cluster\n',datestr(now,31)); date; diary off
            for c = 1:numel(includedcons)
                %                 save(fullfile(wd,sprintf('env_%04d',c)),'EXPT','includedcons','OPTS','grpmodeldir','pthresh');
                save(fullfile(wd,sprintf('env_%04d',c)),'EXPT','includedcons','OPTS','grpmodeldir','STARTINGDIR');
                j = sched.createJob();
                set(j,'PathDependencies',cellstr(path));
                createTask(j, str2func('canlab_glm_group_levels_run1input'), nargsout, {wd c});
                alltasks = get(j, 'Tasks');
                set(alltasks, 'CaptureCommandWindowOutput', true);
                diary(diaryname), fprintf('> Submitting analysis for contrast number %d\n',includedcons(c)); diary off
                submit(j);
            end

            % wait
            diary(diaryname), fprintf('> WAITING for jobs to stop running (they may run for a while)\n'); diary off
            t1 = clock;
            notdone = true;
            fprintf('Elapsed minutes:         ')
            while notdone
                notdone = false;
                for i=1:8, fprintf('\b'); end; fprintf('%8.1f',etime(clock,t1)/60);
                pause(10)
%                 jobstatefiles = filenames(sprintf('%s/Job*.state.mat',wd),'absolute');
                jobstatefiles = filenames(sprintf('%s/Job*.state.mat',wd));
                for s = 1:numel(jobstatefiles)
                    jobstate = textread(jobstatefiles{s},'%s');
                    if strcmp(jobstate,'running') || strcmp(jobstate,'queued'), notdone = true; break; end
                end
            end
            diary(diaryname), fprintf('> \n> %s\tJobs done running\n',datestr(now,31)); diary off

            % handle output arguments/streams
            diary(diaryname), fprintf('> GATHERING job outputs\n'); diary off
%             jobdirs = filenames(sprintf('%s/Job*[0-9]',wd),'absolute');
            jobdirs = filenames(sprintf('%s/Job*[0-9]',wd));
            for i = 1:numel(jobdirs)
                % load state and output
                jobin = load(sprintf('%s/Task1.in.mat',jobdirs{i}));
                jobout = load(sprintf('%s/Task1.out.mat',jobdirs{i}));

                % parse output arguments
                robfitstatuses(jobin.argsin{2}) = jobout.argsout{1}; %#ok
%                 grfstatuses(jobin.argsin{2}) = jobout.argsout{2}; %#ok

                % output stream
                diary(fullfile(wd,sprintf('cmdwnd_%04d.txt',jobin.argsin{2}))), regexprep(jobout.commandwindowoutput,'\b[^\n]*\n',' LINES WITH BACKSPACES OMITTED\n'), diary off
            end
            % merge statuses
            if any(robfitstatuses==-1), robfitstatus = -1; else robfitstatus = 1; end
%             if any(grfstatuses==-1), grfstatus = -1; else grfstatus = 1; end

            % output stream
            if ispc()
                [ignore ignore] = system(sprintf('type %s/cmdwnd_*txt > %s',wd,fulldiaryname));
            else
                [ignore ignore] = system(sprintf('cat %s/cmdwnd_*txt > %s',wd,fulldiaryname));
            end

%             system(sprintf('cat %s/cmdwnd_*txt > %s',wd,fulldiaryname)); %#ok

            % merge diaries
            [ignore ignore] = system(sprintf('grep ''^> '' %s >> %s',fulldiaryname,diaryname)); %#ok
        else
            cmd = 'EXPT = robfit(EXPT, includedcons, 0, EXPT.mask);';
            diary(diaryname), disp(cmd); diary off
            try
                eval(cmd)
                robfitstatus = 1;
            catch exc
                if OPTS.nocatch, cd(STARTINGDIR); rethrow(exc);
                else diary(diaryname), fprintf('> %s\n',getReport(exc,'extended')), diary off; end
                robfitstatus = -1;
            end
        end
    end

    %% post processes
    % write contrast names to textfiles
    if OPTS.run_printconnames
        subconnamefile = fullfile(grpmodeldir,'subconnames.txt');
        grpconnamefile = fullfile(grpmodeldir,'grpconnames.txt');
        diary(diaryname), announce_string('WRITING CONTRAST NAMES FILES'), diary off
        diary(diaryname), fprintf('> %s\n> %s\n',subconnamefile,grpconnamefile), diary off

        fid = fopen(subconnamefile,'w');
        for i = 1:size(EXPT.SNPM.connames,1)
            fprintf(fid,'> %d %s\n',i,deblank(EXPT.SNPM.connames(i,:)));
        end
        fclose(fid);

        fid = fopen(grpconnamefile,'w');
        for i = 1:numel(EXPT.covnames)
            fprintf(fid,'> %d %s\n',i,EXPT.covnames{i});
        end
        fclose(fid);
    end

    % estimate significant cluster sizes
    %     if ~OPTS.parallel_dream && OPTS.run_grf
    if OPTS.run_grf
        diary(diaryname), announce_string('SIGNIFICANT CLUSTER SIZE ESTIMATION using GRF'), diary off
        graymattermask = which('scalped_avg152T1_graymatter_smoothed.img'); %#ok used in eval
        try
%             robdirs = filenames(fullfile(grpmodeldir,'robust[0-9][0-9][0-9][0-9]'),'absolute');
            robdirs = filenames(fullfile(grpmodeldir,'robust[0-9][0-9][0-9][0-9]'));

            for i = 1:numel(robdirs)
                load(fullfile(robdirs{i},'SETUP.mat'));

                cmd = 'sigclext = estimate_cluster_extent(.05, pthresh, SETUP.files, ''mask'', graymattermask);';
                diary(diaryname), fprintf('> %s\n',cmd), diary off
                eval(cmd);
                close all

                fout = fullfile(robdirs{i},'significant_cluster_extents_grf.txt');
                dlmwrite(fout,[pthresh' sigclext(:,1)],'precision','%g','delimiter',' '); %#ok
            end

            grfstatus = 1;
        catch exc
            if OPTS.nocatch, cd(STARTINGDIR); rethrow(exc)
            else diary(diaryname), fprintf('> %s\n',getReport(exc,'extended')), diary off; end
            grfstatus = -1;
        end
    end

    % make invp maps
    if OPTS.run_invp
        cmd = sprintf('robust_results_make_invp_maps(''d'',''%s'');',grpmodeldir);
        diary(diaryname), announce_string('MAKING INVERSE P MAPS'), diary off
        try
            eval(cmd);
            invpstatus = 1;
        catch exc
            if OPTS.nocatch, cd(STARTINGDIR); rethrow(exc);
            else diary(diaryname), fprintf('> %s\n',getReport(exc,'extended')), diary off; end
            invpstatus = -1;
        end
    end

    % make named links to robust directories
    if OPTS.run_links
        diary(diaryname), announce_string('MAKING NAMED LINKS TO ROBUST DIRECTORIES'), diary off
        try
            % get grpmodeldir without /../
            if ismac
                [dummy absgrpmodeldir] = system(sprintf('cd %s; pwd -P',grpmodeldir)); %#ok ~ doesn't work in older matlabs
            else
                [dummy absgrpmodeldir] = system(sprintf('readlink -f %s',grpmodeldir)); %#ok ~ doesn't work in older matlabs
            end
            absgrpmodeldir = deblank(absgrpmodeldir);
            % make output directory
            linkdir = fullfile(absgrpmodeldir,'named_robust_directories');
            mkdir(linkdir);
            % make links
            for i = 1:size(EXPT.SNPM.connames,1)
                % get absolute path of robust directory (with no /../)
                robdir = fullfile(absgrpmodeldir, sprintf('robust%04d',i));

                % clean up contrast name for filesystem
                linkname = deblank(EXPT.SNPM.connames(i,:));
                linkname = regexprep(linkname,'[()]','');
                linkname = regexprep(linkname,'[^0-9A-Za-z-_]','_');
                linkname = fullfile(linkdir,linkname);

                % make link
                diary(diaryname)
                fprintf('> %20s: %s\n','robust directory',robdir)
                fprintf('> %20s: %s\n','named link',linkname)
                eval(sprintf('!ln -s %s %s',robdir,linkname))
                diary off
            end

            linkdirstatus = 1;
        catch exc
            if OPTS.nocatch, cd(STARTINGDIR); rethrow(exc);
            else diary(diaryname), fprintf('> %s\n',getReport(exc,'extended')), diary off; end
            linkdirstatus = -1;
        end
    end

end

%% PUBLISH RESULTS
diary(diaryname), announce_string('PUBLISH RESULTS'), diary off
if ~OPTS.run_results
    diary(diaryname), fprintf('> SKIPPED: turned off in options.\n'); diary off
elseif robfitstatus == -1
    diary(diaryname), fprintf('> SKIPPED: robfit failed.\n'); diary off
else
    try
        canlab_glm_publish('g', grpmodeldir);
        reviewstatus = 1;
    catch exc
        if OPTS.nocatch, cd(STARTINGDIR); rethrow(exc);
        else diary(diaryname), fprintf('> %s\n',getReport(exc,'extended')), diary off; end
        reviewstatus = -1;
    end
end

%% failure report
diary(diaryname)
announce_string('FAILURE REPORT')
fail = 0;
if robfitstatus == -1
    fprintf('> \n> WARNING: robfit failed.\n')
    fail=fail+1;
end
if invpstatus == -1
    fprintf('> \n> WARNING: inverse p map making failed.\n')
    fail=fail+1;
end
if grfstatus == -1
    fprintf('> \n> WARNING: cluster size estimation failed.\n')
    fail=fail+1;
end
if linkdirstatus == -1
    fprintf('> \n> WARNING: named linking to robust directories failed.\n')
    fail=fail+1;
end
if reviewstatus == -1
    fprintf('> \n> WARNING: review publishing failed.\n')
    fail=fail+1;
end

if fail==0, fprintf('> \n> RAN WITH NO PROBLEMS (or at least so it seems).\n'); end
diary off

%% email notification
if exist('address','var')
    diary(diaryname)
    try
        [ignore output] = system(sprintf('printf "canlab_glm_group_levels has finished running.\nDirectory: %s\n\nLog file: %s\nFailed parts: %d\n" | mail -v -s "canlab_glm_group_levels done" %s',grpmodeldir,diaryname,fail,address)); %#ok
    catch %#ok
        fprintf('The email notification job failed.\n');
    end
    diary off
end

%% clean up
diary(diaryname), fprintf('> \n> \n> FINISHED: %s\n',datestr(now,31)), diary off

cd(STARTINGDIR)

end

% -------------------------------------------------------------------------
%  SUBFUNCTIONS  ----------------------------------------------------------
% -------------------------------------------------------------------------

function announce_string(string)

s = sprintf('--  %s  --',string);
l = regexprep(s,'.','-');
fprintf('> \n> \n> \n> %s\n> %s\n> %s\n> \n',l,s,l);

end

%% From Kathy Pearson:
% replace each first instance of SPM-like output backspace with newline;
% ignore additional backspaces found in sequence
%
% function [wrapstr] = nobackspace(str)
%
% wrapstr = str;
% i = strfind(wrapstr, 8);
% if ~isempty(i)
%     k = 0;
%     n = length(str);
%     first8 = 1;
%     for j = 1:n
%         if str(j) == 8
%             if first8
%                 k = k + 1;
%                 wrapstr(k) = 10;
%                 first8 = 0;
%             end
%         else
%             k = k + 1;
%             wrapstr(k) = str(j);
%             first8 = 1;
%         end
%     end
%     wrapstr = wrapstr(1:k);
% end
%
% end


function aboxes_out = merge_detected_bboxes(aboxes)
%
% This file is part of the code that implements the following ICCV2015 accepted paper:
% title: "Object detection via a multi-region & semantic segmentation-aware CNN model"
% authors: Spyros Gidaris, Nikos Komodakis
% institution: Universite Paris Est, Ecole des Ponts ParisTech
% Technical report: http://arxiv.org/abs/1505.01749
% code: https://github.com/gidariss/mrcnn-object-detection
%
% AUTORIGHTS
% --------------------------------------------------------
% Copyright (c) 2015 Spyros Gidaris
%
% "Object detection via a multi-region & semantic segmentation-aware CNN model"
% Technical report: http://arxiv.org/abs/1505.01749
% Licensed under The MIT License [see LICENSE for details]
% ---------------------------------------------------------

num_methods  = length(aboxes);
num_classes  = length(aboxes{1});
num_imgs     = length(aboxes{1}{1});

aboxes_out   = cell(num_classes, 1);

for j = 1:num_classes, aboxes_out{j} = cell(num_imgs,1); end

for i = 1:num_imgs
    for j = 1:num_classes
        aboxes_this_img_this_cls = cell(num_methods, 1);
        for d = 1:num_methods
            aboxes_this_img_this_cls{d} = aboxes{d}{j}{i};
        end
        aboxes_out{j}{i} = cell2mat(aboxes_this_img_this_cls);
    end
end

aboxes_out = {aboxes_out};

end


function t_most_mpopf(quiet)
%T_MOST_MPOPF  Tests of deterministic multiperiod DC OPF problems
%
%   Cases taken from most_ex5_mpopf.m.

%   MOST
%   Copyright (c) 2015-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
    quiet = 0;      %% verbose by default
end

ntests = 42;
t_begin(ntests, quiet);

if quiet
    verbose = 0;
else
    verbose = 0;
end
% verbose = 2;

if have_feature('octave')
    if have_feature('octave', 'vnum') >= 4
        file_in_path_warn_id = 'Octave:data-file-in-path';
    else
        file_in_path_warn_id = 'Octave:load-file-in-path';
    end
    s1 = warning('query', file_in_path_warn_id);
    warning('off', file_in_path_warn_id);
    near_sing_matrix_warn_id = 'Octave:nearly-singular-matrix';
else
    near_sing_matrix_warn_id = 'MATLAB:nearlySingularMatrix';
end
s = warning('query', near_sing_matrix_warn_id);
warning('off', near_sing_matrix_warn_id);

casefile = 'ex_case3b';
solnfile =  't_most_mpopf_soln';
soln = load(solnfile);
mpopt = mpoption('verbose', verbose);
mpopt = mpoption(mpopt, 'out.gen', 1);
mpopt = mpoption(mpopt, 'model', 'DC');
mpopt = mpoption(mpopt, 'most.solver', 'MIPS');
mpopt = mpoption(mpopt, 'most.dc_model', 1);
% mpopt = mpoption(mpopt, 'opf.violation', 1e-6, 'mips.gradtol', 1e-8, ...
%         'mips.comptol', 1e-8, 'mips.costtol', 1e-8);
if have_feature('octave') && have_feature('octave', 'vnum') > 7
    mpopt = mpoption(mpopt, 'mips.linsolver', 'LU');
end
if ~verbose
    mpopt = mpoption(mpopt, 'out.all', 0);
end
% mpopt = mpoption(mpopt, 'out.all', -1);

%% load base case file
mpc = loadcase(casefile);

nb = size(mpc.bus, 1);
nl = size(mpc.branch, 1);
ng = size(mpc.gen, 1);

xgd = loadxgendata('ex_xgd_ramp', mpc);
[iwind, mpc, xgd] = addwind('ex_wind', mpc, xgd);
profiles = getprofiles('ex_wind_profile_d', iwind);
profiles = getprofiles('ex_load_profile', profiles);
nt = size(profiles(1).values, 1);       % number of periods

mpc_full = mpc;
xgd_full = xgd;

%%-----  Multiperiod DC OPF (w/ramp)  -----
t = 'Multiperiod DC OPF w/ramp : ';
mdi = loadmd(mpc, nt, xgd, [], [], profiles);
mdo = most(mdi, mpopt);
% EPg1 = mdo.results.ExpectedDispatch;    % active generation
% Elam1 = mdo.results.GenPrices;          % nodal energy price
t_is(mdo.results.success, 1, 12, [t 'success']);
ms = most_summary(mdo);
ex = soln.wramp;
t_is(ms.f, ex.f, 1.8, [t 'f']);
t_is(ms.Pg, ex.Pg, 3.5, [t 'Pg']);
t_is(ms.Rup, ex.Rup, 2.5, [t 'Rup']);
t_is(ms.Rdn, ex.Rdn, 2.5, [t 'Rdn']);
t_is(ms.Pf, ex.Pf, 4, [t 'Pf']);
t_is(ms.u, ex.u, 8, [t 'u']);
t_is(ms.lamP, ex.lamP, 5, [t 'lamP']);
t_is(ms.muF, ex.muF, 5, [t 'muF']);
ex = soln.rramp;
t_is(mdo.results.GenPrices, ex.GenPrices, 3, [t 'GenPrices']);
t_is(mdo.results.GenTLMP, ex.GenTLMP, 2, [t 'TLMP']);
% rramp = mdo.results;
% wramp = most_summary(mdo);
% keyboard;

%%-----  Multiperiod DC OPF (w/ramp+wear/tear)  -----
t = 'Multiperiod DC OPF w/ramp+wear/tear : ';
xgd.RampWearCostCoeff(1:3) = 1;
mdi = loadmd(mpc, nt, xgd, [], [], profiles);
mdo = most(mdi, mpopt);
% EPg1 = mdo.results.ExpectedDispatch;    % active generation
% Elam1 = mdo.results.GenPrices;          % nodal energy price
t_is(mdo.results.success, 1, 12, [t 'success']);
ms = most_summary(mdo);
ex = soln.wwear;
t_is(ms.f, ex.f, 0.5, [t 'f']);
t_is(ms.Pg, ex.Pg, 2.8, [t 'Pg']);
t_is(ms.Rup, ex.Rup, 2.5, [t 'Rup']);
t_is(ms.Rdn, ex.Rdn, 2.5, [t 'Rdn']);
t_is(ms.Pf, ex.Pf, 3, [t 'Pf']);
t_is(ms.u, ex.u, 8, [t 'u']);
t_is(ms.lamP, ex.lamP, 2.5, [t 'lamP']);
t_is(ms.muF, ex.muF, 2, [t 'muF']);
ex = soln.rwear;
t_is(mdo.results.GenPrices, ex.GenPrices, 2.8, [t 'GenPrices']);
t_is(mdo.results.GenTLMP, ex.GenTLMP, 1, [t 'TLMP']);
% rwear = mdo.results;
% wwear = most_summary(mdo);
% keyboard;

t = 'build model without solving : ';
mpopt = mpoption(mpopt, 'most.build_model', 1, ...
                        'most.solve_model', 0, ...
                        'most.resolve_new_cost', 0);
mdo = most(mdi, mpopt);
t_ok(isfield(mdo, 'om'), [t '''om'' field']);
t_ok(isfield(mdo, 'QP'), [t '''QP'' field']);
t_ok(~isfield(mdo.QP, 'x'), [t 'no ''QP.x'' field']);
t_ok(~isfield(mdo.QP, 'f'), [t 'no ''QP.f'' field']);
t_ok(~isfield(mdo.QP, 'exitflag'), [t 'no ''QP.exitflag'' field']);
t_ok(~isfield(mdo.QP, 'output'), [t 'no ''QP.output'' field']);
t_ok(isfield(mdo.results, 'SetupTime'), [t '''results.SetupTime'' field']);
t_ok(~isfield(mdo.results, 'success'), [t 'no ''results.success'' field']);

t = 'solve previously built model : ';
mpopt = mpoption(mpopt, 'most.build_model', 0, ...
                        'most.solve_model', 1, ...
                        'most.resolve_new_cost', 1);
mdi1 = mdo;
mdo = most(mdi1, mpopt);
t_is(mdo.results.success, 1, 12, [t 'success']);
ms = most_summary(mdo);
ex = soln.wwear;
t_is(ms.f, ex.f, 0.5, [t 'f']);
t_is(ms.Pg, ex.Pg, 2.8, [t 'Pg']);
t_is(ms.Rup, ex.Rup, 2.5, [t 'Rup']);
t_is(ms.Rdn, ex.Rdn, 2.5, [t 'Rdn']);
t_is(ms.Pf, ex.Pf, 3, [t 'Pf']);
t_is(ms.u, ex.u, 8, [t 'u']);
t_is(ms.lamP, ex.lamP, 2.5, [t 'lamP']);
t_is(ms.muF, ex.muF, 2, [t 'muF']);
ex = soln.rwear;
t_is(mdo.results.GenPrices, ex.GenPrices, 2.8, [t 'GenPrices']);
t_is(mdo.results.GenTLMP, ex.GenTLMP, 1, [t 'TLMP']);
% wwear = most_summary(mdo);
% keyboard;

t = 'output model is copy of input model';
mdo.om.add_var('test', 10);
t_is(mdo.om.var.N, mdi1.om.var.N+10, 12, t);

if have_feature('octave')
    warning(s1.state, file_in_path_warn_id);
end
warning(s.state, near_sing_matrix_warn_id);

t_end;

% save t_most_mpopf_soln wramp wwear rramp rwear


% READEGI - read EGI Simple Binary datafile (versions 2,3,4,5,6,7).
%	      Return header info, EEG data, and any event data.
% Usage:
%   >> [head, TrialData, EventData, CatIndex] = readegi(filename, dataChunks, forceversion)
%
% Required Input:
%   filename = EGI data filename
%
% Optional Input:
%   dataChunks = vector containing desired frame numbers(for unsegmented
%                datafiles) or segments (for segmented files). If this
%                input is empty or is not provided then all data will be
%                returned.
%   forceversion = integer from 2 to 7 which overrides the EGI version read from the
%                file header.  This has been occasionally necessary in cases where
%                the file format was incorrectly indicated in the header.
% Outputs:
%   head = struct containing header info (see READEGIHDR )
%   TrialData = EEG channel data
%   EventData = event codes
%   CatIndex  = segment category indices
%
% Author: Cooper Roddey, SCCN, 13 Nov 2002
%
% Note: code derived from C source code written by
%       Tom Renner at EGI, Inc.
%
% See also: READEGIHDR

% Copyright (C) 2002 , Salk Institute, arno@salk.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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  [head, TrialData, EventData, SegmentCatIndex] = readegi(filename, dataChunks,forceversion)

if nargin <1 || nargin > 3,
    help readegi;
    return;
end

if nargout < 2 || nargout > 4,
	error('2 to 4 output args required');
end

if ~exist('dataChunks','var')
     dataChunks = [];
end

if ~isvector(dataChunks)
     error('dataChunks must either be empty or a vector');
end

[fid,message] = fopen(filename,'rb','b');
if (fid < 0),
   error(message);
end

% get our header structure
fprintf('Importing binary EGI data file ...\n');
if exist('forceversion')
   head = readegihdr(fid,forceversion);
else
   head = readegihdr(fid);
end

% do we have segmented data?
segmented = 0;
switch(head.version),
    case {2,4,6}
       segmented = 0;
    case {3,5,7}
       segmented = 1;
end

% each type of event has a dedicated "channel"
FrameVals = head.nchan + head.eventtypes;

if (segmented)

    desiredSegments = dataChunks;
    if isempty(desiredSegments),
       desiredSegments = [1:head.segments];
    end

    nsegs = length(desiredSegments);

    TrialData = zeros(FrameVals,head.segsamps*nsegs);
    readexpected = FrameVals*head.segsamps*nsegs;

else

    desiredFrames = dataChunks;
    if isempty(desiredFrames),
       desiredFrames = [1:head.samples];
    end

    nframes = length(desiredFrames);

    TrialData = zeros(FrameVals,nframes);
    readexpected = FrameVals*nframes;

end

% get datatype from version number
switch(head.version)
   case {2,3}
      datatype = 'integer*2';
   case {4,5}
      datatype = 'float32';
   case {6,7}
      datatype = 'float64';
   otherwise,
      error('Unknown data format');
end

% read in epoch data
readtotal = 0;
j=0;
SegmentCatIndex = [];
if (segmented),

    for i=1:head.segments,
	segcatind = fread(fid,1,'integer*2');
	segtime = fread(fid,1,'integer*4');

	[tdata, count] = ...
	   fread(fid,[FrameVals,head.segsamps],datatype);

       % check if this segment is one of our desired ones
        if ismember(i,desiredSegments)

           j=j+1;
           SegmentCatIndex(j) = segcatind;
           SegmentStartTime(j) = segtime;

           TrialData(:,[1+(j-1)*head.segsamps:j*head.segsamps]) = tdata;

           readtotal = readtotal + count;
        end

	if (j >= nsegs), break; end

    end

else
    % read unsegmented data

    % if dataChunks is empty, read all frames
    if isempty(dataChunks)

        [TrialData, readtotal] = fread(fid, [FrameVals,head.samples],datatype);

    else   % grab only the desiredFrames
           % This could take a while...

        for i=1:head.samples,

          [tdata, count] = fread(fid, [FrameVals,1],datatype);

          % check if this segment is a keeper
          if ismember(i,desiredFrames),
              j=j+1;
              TrialData(:,j) = tdata;
              readtotal = readtotal + count;
          end

          if (j >= nframes), break; end

        end
    end
end

fclose(fid);

if ~isequal(readtotal, readexpected)
     error('Number of values read not equal to the number expected.');
end

EventData = [];
if (head.eventtypes > 0),
	EventData = TrialData(head.nchan+1:end,:);
	TrialData = TrialData(1:head.nchan,:);
end

% convert from A/D units to microvolts
if ( head.bits ~= 0 && head.range ~= 0 )
       TrialData = (head.range/(2^head.bits))*TrialData;
end

% convert event codes to char
% ---------------------------
head.eventcode = char(head.eventcode);

%--------------------------- ISVECTOR ---------------
function retval = isvector(V)

   s = size(V);
   retval = ( length(s) < 3 ) & ( min(s) <= 1 );

%------------------------------------------------------


%APPLYCHANNELGAINS  Implements an efficient fixed-point approximation for applying channel gains, which is the last step of multiple white balance algorithms
%
%     dst = cv.applyChannelGains(src, gains)
%
% ## Input
% * __src__ Input 3-channel image in the BGR color space (either `uint8` or
%   `uint16`).
% * __gains__ gains for the [B,G,R] channels.
%
% ## Output
% * __dst__ Output image of the same size and type as `src`.
%
% See also: cv.GrayworldWB, cv.LearningBasedWB, imapplymatrix
%


function checkCoordsNodes(flat)
%
%AUTHOR:  Wandell & Huk
%DATE:    12.01.00
%PURPOSE:
%   We verify that the gray matter nodes in the segmentation
% is consistent with the coords and nodes in the mrLoadRet
% directories.
%
% The nodes in Gray/coords are leftNodes and rightNodes.  These
% are supposed to be a subset of the nodes in the segmentation
% at leftPath and rightPath.  So, we load the two sets and we
% make sure that every one of the leftNodes is inside the set of
% nodes read from the segmentation.  Then we do it again for the
% right.
%
% bw, 01/12/01  Updated Flat coords reading so that it checks
%   the proper Flat sub-directory.
% djh, 2/5/2001
%    Use fullfile instead of hardcoded 'load Gray/coords'
%    Added check to compare mrLoadRet's gray nodes with the full set of gray nodes

mrGlobals

% open hiddenGray to get the relevant info
gray = getSelectedGray;
if isempty(gray)
    gray = initHiddenGray;
end
if isempty(flat)
    flat = initHiddenFlat;
end

% yank out relevant rows and reorder them as necessary
grayNodes = gray.nodes(1:3,:);
if ~isempty(gray.allLeftNodes)
    grayAllLeftNodes = gray.allLeftNodes(1:3,:);
else
    grayAllLeftNodes = [];
end
if ~isempty(gray.allRightNodes)
    grayAllRightNodes = gray.allRightNodes(1:3,:);
else
    grayAllRightNodes = [];
end
if ~isempty(flat.grayCoords{1})
    flatLeftGrayCoords = flat.grayCoords{1}([2 1 3],:);
else
    flatLeftGrayCoords = [];
end
if ~isempty(flat.grayCoords{2})
    flatRightGrayCoords = flat.grayCoords{2}([2 1 3],:);
else
    flatRightGrayCoords = [];
end

% check that gray.nodes are a subset of the full set of gray nodes
if isempty(gray.nodes)
    disp('Empty gray.nodes.');
else
    [cLeft,iaLeft,ibLeft] = intersectCols(grayNodes,grayAllLeftNodes);
    [cRight,iaRight,ibRight] = intersectCols(grayNodes,grayAllRightNodes);
    numDifference = size(grayNodes,2) - (size(cLeft,2)+size(cRight,2));
    if numDifference~=0
        disp('Gray.nodes are NOT all contained in the segmentation.');
        disp(['Number missing:  ',num2str(numDifference)]);
        mismatch(gray,flat);
    else
        disp('Gray.nodes are all contained in the segmentation.');
    end
end

% check that flat.grayCoords are contained in the gray.nodes
if isempty(flat.grayCoords)
    disp('Empty flat.grayCoords.');
else
    [cLeft,iaLeft,ibLeft] = intersectCols(flatLeftGrayCoords,grayNodes);
    [cRight,iaRight,ibRight] = intersectCols(flatRightGrayCoords,grayNodes);
    numDifference = (size(flatLeftGrayCoords,2) - size(cLeft,2)) + ...
                    (size(flatRightGrayCoords,2) - size(cRight,2));
    if numDifference~=0
        disp('Flat.grayCoords are NOT all contained in the gray.nodes');
        disp(['Number missing: ',num2str(numDifference)]);
        mismatch(gray,flat);
    else
        disp('Flat.grayCoords are all contained in the gray.nodes');
    end
end

% check that flat nodes are contained in segmentation
if isempty(flat.grayCoords)
    disp('Empty flat.grayCoords.');
else
    [cLeft,iaLeft,ibLeft] = intersectCols(flatLeftGrayCoords,grayAllLeftNodes);
    [cRight,iaRight,ibRight] = intersectCols(flatRightGrayCoords,grayAllRightNodes);
    numDifference = (size(flatLeftGrayCoords,2) - size(cLeft,2)) + ...
                    (size(flatRightGrayCoords,2) - size(cRight,2));
    if numDifference~=0
        disp('flat.grayCoords are NOT all contained in the segmentation.');
        disp(['Number missing:  ',num2str(numDifference)]);
        mismatch(gray,flat);
    else
        disp('flat.grayCoords are all contained in the segmentation.');
    end
end

msgbox([viewDir(flat),' and ',viewDir(gray),' are OK.'],'Verify Gray-Flat match');

return;

function mismatch(gray,flat)
myErrorDlg(['Mismatch detected between ',viewDir(flat),' and ',viewDir(gray),...
        '. Run Install Segmentation and/or Install Unfold from Xform menu.']);
return;


classdef PTKGetContextForLobe < PTKPlugin
    % PTKGetContextForLobe. Plugin for finding the region of interest for a lobe.
    %
    %     This is a plugin for the Pulmonary Toolkit. Plugins can be run using
    %     the gui, or through the interfaces provided by the Pulmonary Toolkit.
    %     See PTKPlugin.m for more information on how to run plugins.
    %
    %     Plugins should not be run directly from your code.
    %
    %     PTKGetContextForLobe runs the plugin PTKLeftAndRightLungs to segment
    %     the left and right lungs, then calls the library function
    %     PTKGetLobeROI to extract the region of interest for the required lobe.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2012.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    properties
        ButtonText = 'Lobe<BR>ROI'
        ToolTip = 'Fetches the ROI for a lobe context'
        Category = 'Context'

        AllowResultsToBeCached = true
        AlwaysRunPlugin = false
        Context = PTKContextSet.Lobe
        PluginType = 'ReplaceImage'
        HidePluginInDisplay = true
        FlattenPreviewImage = false
        PTKVersion = '2'
        ButtonWidth = 6
        ButtonHeight = 2
        GeneratePreview = true

        MemoryCachePolicy = 'Permanent'
        DiskCachePolicy = 'Permanent'
    end

    methods (Static)
        function results = RunPlugin(dataset, context, reporting)
            lobe_mask = dataset.GetResult('PTKLobes', PTKContext.LungROI);
            results = PTKGetLobeROI(lobe_mask, context, reporting);
        end
    end
end


function [VertexLabelIds, LabelMap, AtlasName] = in_label_bs(FileName)
% IN_LABEL_SVREG: Import an atlas from an SVReg-labelled surface
%
% USAGE: in_label_bs(FileName, Verbosity=1) : Load labeled vertices from given file
%
% INPUT
%       - FileName : full path of SVReg surface file to read
%
% OUTPUT
%       - LabelIds :  vector of vertex label ids
%       - LabelMap : java.util.HashMap of label names and colors for corresponding vertex index.
%           - LabelMap.get(id): cell containing label name and color of id i

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Andrew Krause, 2013

% ===== Read XML Label Description File =====
fPath = bst_fileparts(FileName);

st=strfind(FileName,'.svreg.');
ed=strfind(FileName,'.dfs');
AtlasName = FileName(st+7:ed-1);

XmlFile = file_find(fPath, ['brainsuite_labeldescription*',AtlasName,'.xml']);
if isempty(XmlFile)
    fprintf(1, 'BST> For Atlas %s could not find XML label description file brainsuite_labeldescription.xml\n', AtlasName);
    fprintf(1, 'BST> Only label Ids will be used for this atlas without label names\n');
    LabelMap = [];
else
    LabelMap = generate_label_map(XmlFile);
end

% ===== Get Vertex Labels from DFS FILE =====
VertexLabelIds = get_vertex_label_ids(FileName);

end

%% ======================================================================================
%  ===== HELPER FUNCTIONS ===============================================================
%  ======================================================================================
%% Generate mapping between label id and label name and color
function labelMap = generate_label_map(xmlFileName)
    import javax.xml.xpath.*

    try
        docNode = xmlread(xmlFileName);
    catch
        error('Could not open XML Label Description: %s', xmlFileName);
    end

    factory = XPathFactory.newInstance;
    xPath = factory.newXPath;

    idsExpression    = xPath.compile('//label/@id');
    tagsExpression   = xPath.compile('//label/@fullname');
    colorsExpression = xPath.compile('//label/@color');
    idsList    = idsExpression.evaluate(docNode, XPathConstants.NODESET);
    tagsList   = tagsExpression.evaluate(docNode, XPathConstants.NODESET);
    colorsList = colorsExpression.evaluate(docNode, XPathConstants.NODESET);

    numLabels = idsList.getLength;
    labelMap = java.util.HashMap;
    for i = 1:numLabels
        idNode = idsList.item(i-1);
        tagNode = tagsList.item(i-1);
        colorNode = colorsList.item(i-1);

        % Convert color from hexadecimal to RGB [0, 1]
        colorHex = char(colorNode.getNodeValue);
        while length(colorHex) < 8, colorHex = [colorHex '0']; end
        color = [hex2dec(colorHex(3:4)) hex2dec(colorHex(5:6)) hex2dec(colorHex(7:8))] ./ 255;

        % Add ids, names, and colors to hashmap
        id = char(idNode.getNodeValue);
        labelName = char(tagNode.getNodeValue);
        if strncmp(labelName, 'L.', 2) || strncmp(labelName, 'R.', 2)
            labelName = labelName(4:end);
        end
        labelMap.put(id, {labelName, color});
    end
end

%% Return the label ids of each vertex
function Labels = get_vertex_label_ids(s)
    fid=fopen(s,'r');
    if (fid<0)
        error('Unable to read surface: %s',s);
    end

    %% ===== Read number of vertices in surface and labels =====
    fseek(fid, 28, -1); % Skip to nVertices
    nVertices = fread(fid,1,'int32');
    fseek(fid, 20, 0); % Skip to labelOffset
    LabelOffset = fread(fid,1,'int32');

    if (LabelOffset > 0)
        fseek(fid, LabelOffset, -1);
        Labels = fread(fid, nVertices,'uint16');
    else
        error('Surface does not have label attributes');
    end
    fclose(fid);
end


function DI = detectChange(obj, t1, t2)
DI = abs(double(t1) - double(t2));
end


function X = full(X)
%FULL Convert to a (dense) tensor.
%
%   FULL(X) returns X, i.e., does nothing.
%
%   See also SPTENSOR/FULL, KTENSOR/FULL, TTENSOR/FULL.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2012) Sandia Corporation. Under the terms of Contract
% DE-AC04-94AL85000, there is a non-exclusive license for use of this
% work by or on behalf of the U.S. Government. Export of this data may
% require a license from the United States Government.
% The full license terms can be found in the file LICENSE.txt

return;


function [res, bytesReq] = hlp_haveSufficientMemory(numelts,datatype)
% Check if we have sufficient memory to allocate an array.
%
% Inputs:
%   numelts: The number of elements in the array.
%       If the array is sparse, then numelts is the number of non-zero elements
%   datatype: The class of the array.
%       This can be any of the following: logical,int*,uint*,single,double,char
%
% Output:
%   res: true if we have sufficient memory, else false
%   bytesReq: the number of bytesRequired to allocate the array
%
% Author: Tim Mullen, SCCN/INC/UCSD, Jan, 2014

switch datatype
    case {'logical','int8','uint8'} , N=1;
    case {'char','int16','uint16'}  , N=2;
    case {'double','int64','uint64'}, N=8;
    case {'single','int32','uint32'}, N=4;
    otherwise
        error('unsupported datatype %s',datatype);
end

bytesReq = numelts*N;
res = (bytesReq <= hlp_getAvailableMemory('Bytes'));


%kvlocmin 'Regional Min'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros vlocmin.pane file
%
% Parameters:
% InputFile: i 'Input Image ', required: 'Input image'
% InputFile: str 'Struct Element', required: 'Structuring Element'
% OutputFile: o 'Output Image', required: 'resulting output image'
%
% Example: o = kvlocmin({i, str}, {'i','';'str','';'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% vlocmin - Regional Min
%
%  DESCRIPTION
% .I vlocmin
% will find the local minimum of an image.
%
%
%
%
%  EXAMPLES
% vlocmin -i feath.xv -str b.str -o outimage.xv
%
% Will find the local minimum of the input image "feath.xv". The connectivity is defined by the structuring element b. The transformed image is written to "outimage.xv".
%
%  "SEE ALSO"
% vcast1(1)
%
%  RESTRICTIONS
% .I vlocmin
% can be defined for all data types supported by Khoros (except bit), but at the moment it has been implemented just for the unsigned char type.
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993-1997 Junior Barrera, Roberto Lotufo.  All rights reserved.
%

function varargout = kvlocmin(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,..] = kvlocmin(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i', '__input';'str', '__input';'o', '__output'};
maxval={0,0,0};
minval={0,0,0};
istoggle=[0,0,0];
was_set=istoggle * 0;
paramtype={'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 'vlocmin"  '],Inputs,narglist);


classdef PTKSegmentalBronchi < PTKPlugin
    % PTKSegmentalBronchi. Plugin to find the segmental bronchi in each lobe
    %
    %     This is a plugin for the Pulmonary Toolkit. Plugins can be run using
    %     the gui, or through the interfaces provided by the Pulmonary Toolkit.
    %     See PTKPlugin.m for more information on how to run plugins.
    %
    %     Plugins should not be run directly from your code.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2013.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    properties
        ButtonText = 'Segmental<br>bronchi'
        ToolTip = 'Finds the segmental bronchi in each lobe'
        Category = 'Airways'

        AllowResultsToBeCached = true
        AlwaysRunPlugin = false
        PluginType = 'DoNothing'
        HidePluginInDisplay = true
        FlattenPreviewImage = true
        PTKVersion = '1'
        ButtonWidth = 6
        ButtonHeight = 2
        GeneratePreview = false
        Visibility = 'Developer'
end

    methods (Static)
        function results = RunPlugin(dataset, reporting)
            lobes = dataset.GetResult('PTKLobes');
            centreline_tree = dataset.GetResult('PTKAirwayCentreline');
            results_image = dataset.GetTemplateImage(PTKContext.LungROI);
            centreline_tree.AirwayCentrelineTree.GenerateBranchParameters;
            new_centreline_tree = PTKGetSegmentalBronchiCentrelinesForEachLobe(centreline_tree.AirwayCentrelineTree, lobes, results_image, reporting);

            results = [];
            results.StartBranches = new_centreline_tree;
        end
    end
end


function vol = ft_headmodel_infinite(varargin)

% FT_HEADMODEL_INFINITE returns an infinitely large homogenous
% volume conduction model. For EEG the volume conductor can be used
% to compute the leadfield of electric current dipoles, for MEG it
% can be used for computing the leadfield of magnmetic dipoles.
%
% Use as
%   vol = ft_headmodel_infinite;
%
% See also FT_PREPARE_VOL_SENS, FT_COMPUTE_LEADFIELD

% this is an easy one
vol = [];
vol.type = 'infinite';


function img_data=read_img_rgb(img_file, data_type)

assert(strcmp(data_type, 'uint8'));

try

	[img_data, map] = imread(img_file);

catch err_info

	disp(err_info);
	disp(img_file);
	error('image read error');

end

if size(img_data, 4)>1

	error('cannot read images with multi-frames');

    % only load the first frame
    img_data=img_data(:,:,:, 1);
end

if ~isempty(map)
	img_data = ind2rgb(img_data,map);
end

if size(img_data, 3)==1

    [img_data map]=gray2ind(img_data);
    img_data=ind2rgb(img_data, map);

end

if strcmp(data_type, 'uint8')
    img_data=im2uint8(img_data);
end
if strcmp(data_type, 'double')
    img_data=im2double(img_data);
end
if strcmp(data_type, 'single')
    img_data=im2single(img_data);
end

try
    assert(size(img_data, 3)==3);
catch error_msg
    disp(error_msg);
    dbstack;
    keyboard;
end

end


function Prod_cell = mult_vec(F_cell, G_cell)

chkarg(istypesizeof(F_cell, 'complexcell', [1 0]) || istypesizeof(F_cell, 'complexcell', [0 1]), ...
	'"F_cell" should be row or column cell array whose each element is array with complex elements.');
chkarg(istypesizeof(G_cell, 'complexcell', [1 0]) || istypesizeof(G_cell, 'complexcell', [0 1]), ...
	'"F_cell" should be row or column cell array whose each element is array with complex elements.', Axis.count);
chkarg(length(F_cell)==length(G_cell), '"F_cell" and "G_cell" should be the same length.');

n = length(F_cell);

Prod_cell = cell(size(F_cell));
for w = 1:n
	chkarg(all(size(F_cell{w})==size(G_cell{w})), '%d-component of "F_cell" and "G_cell" should have the same size.');
	Prod_cell{w} = F_cell{w} .* G_cell{w};
end


function MimSaveListOfPointsAndValues(file_path, file_name, xc, yc, zc, value_list, coordinate_system, template_image)
    % MimSaveListOfPointsAndValues. Exports a list of coordinates and values
    %
    %     Syntax
    %     ------
    %
    %         MimSaveListOfPointsAndValues(file_path, file_name, xc, yc, zc, value_list, template_image, reporting)
    %
    %             file_path       is the path where the output file is to be
    %                             stored
    %             file_name       is the file name
    %             xc, yc, zx      are the coordinates in PTK cordinates
    %             coordinate_system  a MimCoordinateSystem enumeration
    %                             specifying the coordinate system to use
    %             template_image  A PTKImage providing voxel size and image size
    %                             parameters
    %             reporting       an object implementing CoreReportingInterface
    %                             for reporting progress and warnings
    %
    %
    %     Licence
    %     -------
    %     Part of the TD MIM Toolkit. https://github.com/tomdoel
    %     Author: Tom Doel, 2013.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    if nargin < 7
        reporting.Error('MimSaveListOfPointsAndValues:BadArguments', 'No coordinate_system parameter specified');
    end

    if ~isa(coordinate_system, 'MimCoordinateSystem')
        reporting.Error('MimSaveListOfPointsAndValues:BadArguments', 'coordinate_system parameter is not of type MimCoordinateSystem');
    end

    CoreDiskUtilities.CreateDirectoryIfNecessary(file_path);
    results_file_name = fullfile(file_path, file_name);
    file_handle = fopen(results_file_name, 'w');

    number_points = length(xc);

    for index = 1 : number_points
        dicom_coords = MimImageCoordinateUtilities.ConvertFromPTKCoordinates([xc(index), yc(index), zc(index)], coordinate_system, template_image);
        coord_x = dicom_coords(1);
        coord_y = dicom_coords(2);
        coord_z = dicom_coords(3);

        density = value_list(index);
        if any(density(:) == 0)
            disp('Warning: zero density');
        end

        output_string = sprintf('%6.6g,%6.6g,%6.6g,%6.6g\r\n', coord_x, coord_y, coord_z, density);
        fprintf(file_handle, regexprep(output_string, ' ', ''));
    end

    fclose(file_handle);
end


classdef WOF_WeightIndividual < handle
% WOF_WeightIndividual - The class of an individual used in WOF to store
% weight variables.

% -----------------------------------------------------------------------
%  Copyright (C) 2020 Heiner Zille
%
%  This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0
%  International License. (CC BY-NC-SA 4.0). To view a copy of this license,
%  visit http://creativecommons.org/licenses/by-nc-sa/4.0/ or see the
%  pdf-file "License-CC-BY-NC-SA-4.0.pdf" that came with this code.
%
%  You are free to:
%  * Share ? copy and redistribute the material in any medium or format
%  * Adapt ? remix, transform, and build upon the material
%  Under the following terms:
%  * Attribution ? You must give appropriate credit, provide a link to the
%     license, and indicate if changes were made. You may do so in any reasonable
%     manner, but not in any way that suggests the licensor endorses you or your use.
%  * NonCommercial ? You may not use the material for commercial purposes.
%  * ShareAlike ? If you remix, transform, or build upon the material, you must
%    distribute your contributions under the same license as the original.
%  * No additional restrictions ? You may not apply legal terms or technological
%    measures that legally restrict others from doing anything the license permits.
%
%  Author of this Code:
%   Heiner Zille <heiner.zille@ovgu.de> or <heiner.zille@gmail.com>
%
%  This code is based on the following publications:
%
%  1) Heiner Zille
%     "Large-scale Multi-objective Optimisation: New Approaches and a Classification of the State-of-the-Art"
%     PhD Thesis, Otto von Guericke University Magdeburg, 2019
%     http://dx.doi.org/10.25673/32063
%
%  2) Heiner Zille and Sanaz Mostaghim
%     "Comparison Study of Large-scale Optimisation Techniques on the LSMOP Benchmark Functions"
%     IEEE Symposium Series on Computational Intelligence (SSCI), IEEE, Honolulu, Hawaii, November 2017
%     https://ieeexplore.ieee.org/document/8280974
%
%  3) Heiner Zille, Hisao Ishibuchi, Sanaz Mostaghim and Yusuke Nojima
%     "A Framework for Large-scale Multi-objective Optimization based on Problem Transformation"
%     IEEE Transactions on Evolutionary Computation, Vol. 22, Issue 2, pp. 260-275, April 2018.
%     http://ieeexplore.ieee.org/document/7929324
%
%  4) Heiner Zille, Hisao Ishibuchi, Sanaz Mostaghim and Yusuke Nojima
%     "Weighted Optimization Framework for Large-scale Mullti-objective Optimization"
%     Genetic and Evolutionary Computation Conference (GECCO), ACM, Denver, USA, July 2016
%     http://dl.acm.org/citation.cfm?id=2908979
%
%  This file is intended to work with the PlatEMO framework version 2.5.
%  Date of publication of this code: 06.04.2020
%  Last Update of this code: 06.04.2020
%  A newer version of this algorithm may be available. Please contact the author
%  or see http://www.ci.ovgu.de/Research/Codes.html.
%
% The files may have been modified in Feb 2021 by the authors of the Platemo framework to work with the Platemo 3.0 release.
% -----------------------------------------------------------------------
% This file is derived from its original version containied in the PlatEMO
% framework.
% -----------------------------------------------------------------------

    properties(SetAccess = private)
        dec;        % Decision variables of the individual
        obj;        % Objective values of the individual
        con;        % Constraint values of the individual
        add;        % Additional properties of the individual
        ind;        % the actual individual to extract later
    end
    methods
        %% Constructor
        function obj = WOF_WeightIndividual(variables, GlobalDummy, addValues)

            if nargin > 0
                xPrimeVars = GlobalDummy.xPrime.dec;
                xPrimeSize = size(xPrimeVars,2);

                obj = WOF_WeightIndividual;

                % Set the infeasible decision variables to boundary values
                variables  = max(min(variables,GlobalDummy.upper),GlobalDummy.lower);

                x = WOF_transformationFunctionMatrixForm(xPrimeVars,variables(GlobalDummy.G),GlobalDummy.xPrimeupper,GlobalDummy.xPrimelower, GlobalDummy.psi);

                Problem = WOF_WeightIndividual.Current();
                obj.dec = variables;
                obj.ind = Problem.Evaluation(x);
                obj.obj = obj.ind.obj;
                obj.con = obj.ind.con;

                if nargin > 2
                    CallStack = dbstack();
                    Field     = CallStack(2).name;
                    obj.add.(Field) = addValues;
                end
            end

        end
        %% Get the matrix of decision variables of the population
        function value = decs(obj)
        %decs - Get the matrix of decision variables of the population
        %
        %   A = obj.decs returns the matrix of decision variables of the
        %   population obj, where obj is an array of INDIVIDUAL objects.

            value = cat(1,obj.dec);
        end
        %% Get the matrix of objective values of the population
        function value = objs(obj)
        %objs - Get the matrix of objective values of the population
        %
        %   A = obj.objs returns the matrix of objective values of the
        %   population obj, where obj is an array of INDIVIDUAL objects.

            value = cat(1,obj.obj);
        end
        %% Get the matrix of constraint values of the population
        function value = cons(obj)
        %cons - Get the matrix of constraint values of the population
        %
        %   A = obj.cons returns the matrix of constraint values of the
        %   population obj, where obj is an array of INDIVIDUAL objects.

            value = cat(1,obj.con);
        end
        %% Get the matrix of additional property of the population
        function value = adds(obj,addValue)
        %adds - Get the matrix of additional property values of the population
        %
        %   A = obj.adds(AddProper) returns the matrix of the values of the
        %   additional property of the INDIVIDUAL objects obj. The name of
        %   the additional property is same to the function name of the
        %   caller, that is, the values of one additional property of the
        %   individuals can only be obtained by the function which created
        %   them. If any individual in obj does not contain the specified
        %   additional property, assign it a default value specified in
        %   AddProper.

            CallStack = dbstack();
            Field     = CallStack(2).name;
            value     = zeros(length(obj),size(addValue,2));
            for i = 1 : length(obj)
                if ~isfield(obj(i).add,Field)
                    obj(i).add.(Field) = addValue(i,:);
                end
                value(i,:) = obj(i).add.(Field);
            end
        end
    end
    methods(Static, Sealed)
        function obj = Current(obj)
        %Current - Get or set the current PROBLEM object.

            persistent Problem;
            if nargin > 0
                Problem = obj;
            end
            if nargout > 0
                obj = Problem;
            end
        end
    end
end


function experiments = stack_vottir2015()

set_global_variable('bundle', 'http://www.cvl.isy.liu.se/research/datasets/ltir/version1.0/ltir_v1_0_8bit.zip');
set_global_variable('legacy_rasterization', true);
set_global_variable('bounded_overlap', false);

baseline.name = 'baseline';
baseline.converter = [];
baseline.type = 'supervised';
baseline.tags = {'camera_motion', 'illum_change', 'occlusion', 'size','motion', 'empty'};

baseline.parameters.repetitions = 15;
baseline.parameters.burnin = 10;
baseline.parameters.skip_initialize = 5;
baseline.parameters.failure_overlap = 0;

experiments = {baseline};

end


addpath('functions/ht_pnp_function');
addpath('functions/at_netvlad_function');
addpath('functions/utils');
addpath('functions/wustl_function');
addpath('functions/relja_matlab');
addpath('functions/relja_matlab/matconvnet/');
addpath('functions/netvlad/');

addpath('functions/yael_matlab_linux64_v438');
addpath('functions/Inpaint_nans/Inpaint_nans');
run('functions/vlfeat/toolbox/vl_setup.m');
run('functions/matconvnet/matlab/vl_setupnn.m');


function options = drawFluxVariability(map,model,minFlux,maxFlux,options,varargin)
%drawFluxVariablity Overlay flux variability data on a metabolic map
%
% options = drawFluxVariability(map,model,minFlux,maxflux,options,varargin)
%
%INPUTS
% map           COBRA map structure
% model         COBRA model structure
% minFlux       Vector containing minimum flux values for each reaction
% maxFlux       Vector containing maximum flux values for each reaction
%
%OPTIONAL INPUTS
% options       options structure
% varargin      parameter, parameter value inputs for optional parameters
%
%OUTPUT
% options       options structure used to generate map
%
%Richard Que (03/2010)

if nargin<5, options = []; end
if ~isfield(options,'fluxVarColor'), options.fluxVarColor = []; end
if mod(length(varargin),2)==0
    for i=1:2:length(varargin)-1
        options = setMapOptions(options,map,model,varargin{i},varargin{i+1});
%         switch lower(varargin{i})
%             case 'bidircolor', options.fluxVarColor.biDirColor = varargin{i+1};
%             case 'unidirirrcolor', options.fluxVarColor.uniDirIrrColor = varargin{i+1};
%             case 'unidirfwdcolor', options.fluxVarColor.uniDirFwdColor = varargin{i+1};
%             case 'unidirrevcolor', options.fluxVarColor.uniDirRevColor = varargin{i+1};
%             case 'filename', options.fileName = varargin{i+1};
%             case 'rxndirflag', options.rxnDirFlag = varargin{i+1};
%             case 'rxndirmultiplier', options.rxnDirMultiplier = varargin{i+1};
%             otherwise
%                 options.(varargin{i}) = varargin{i+1};
%                 fprintf('Unrecognized parameter %s\n',varargin{i});
%         end
    end
else
    error('Invalid number of parameters/values');
end
color = zeros(length(model.rxns),3);
%set defaults
if ~isfield(options.fluxVarColor,'biDirColor')
    options.fluxVarColor.biDirColor = [0 255 0];
end
if ~isfield(options.fluxVarColor,'uniDirIrrColor')
    options.fluxVarColor.uniDirIrrColor = [0 0 255];
end
if ~isfield(options.fluxVarColor,'uniDirFwdColor')
    options.fluxVarColor.uniDirFwdColor = [255 0 255];
end
if ~isfield(options.fluxVarColor,'uniDirRevColor')
    options.fluxVarColor.uniDirRevColor = [0 255 255];
end
if isfield(options,'rxnDirMultiplier')
    options.rxnDirFlag = true;
end
if ~isfield(options,'rxnDirFlag')
    rxnDirFlag = false;
else
    rxnDirFlag = options.rxnDirFlag;
end

%assign colors
for i=1:length(model.rxns)
    if minFlux(i)*maxFlux(i)>=0
        %unidirectional
        if model.lb(i) < 0
            %reversible
            if minFlux(i)<0 || maxFlux(i)<0
                %reverse direction: Cyan 0 255 255
                color(i,:) = options.fluxVarColor.uniDirRevColor;
            else
                %forward direction: Magenta 255 0 255
                color(i,:) = options.fluxVarColor.uniDirFwdColor;
            end
        else
            %irreversible: Blue 0 0 255
            color(i,:) = options.fluxVarColor.uniDirIrrColor;
        end
    else
        %bidirectional: Green 0 255 0
        color(i,:) = options.fluxVarColor.biDirColor;
    end
end

if rxnDirFlag
    options.rxnDir = zeros(length(map.rxnIndex),1);
    options.rxnDir(ismember(map.connectionAbb,model.rxns((maxFlux>0) & (minFlux>=0)))) = 1;
    options.rxnDir(ismember(map.connectionAbb,model.rxns((maxFlux<=0) & (minFlux<0)))) = -1;
end

options = setMapOptions(options,map,model,'edgeColor',color);
drawCbMap(map,options);


function F = eq(X,Y)
% Internal class for constraint lists

superiorto('sdpvar');
superiorto('double');

if isa(X,'sdpvar')
    if is(X,'binary')
        F=iff(X,Y);
        return;
    end
end
if isa(Y,'sdpvar')
    if is(Y,'binary')
        F=iff(Y,X);
        return;
    end
end

error('Equalities can not be used in double-sided constraints')


function dij = matRad_calcPhotonDoseMC(ct,stf,pln,cst,nCasePerBixel,visBool)
% matRad ompMC monte carlo photon dose calculation wrapper
%
% call
%   dij = matRad_calcPhotonDoseMc(ct,stf,pln,cst,visBool)
%
% input
%   ct:                         matRad ct struct
%   stf:                        matRad steering information struct
%   pln:                        matRad plan meta information struct
%   cst:                        matRad cst struct
%   visBool:                    binary switch to enable visualization
% output
%   dij:                        matRad dij struct
%
% References
%   -
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Copyright 2018 the matRad development team.
%
% This file is part of the matRad project. It is subject to the license
% terms in the LICENSE file found in the top-level directory of this
% distribution and at https://github.com/e0404/matRad/LICENSES.txt. No part
% of the matRad project, including this file, may be copied, modified,
% propagated, or distributed except according to the terms contained in the
% LICENSE file.
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

matRad_cfg =  MatRad_Config.instance();

tic

% disable visualiazation by default
if nargin < 6
    visBool = false;
end

if nargin < 5
    nCasePerBixel = matRad_cfg.propMC.ompMC_defaultHistories;
    matRad_cfg.dispInfo('Using default number of Histories per Bixel: %d\n',nCasePerBixel);
end

fileFolder = fileparts(mfilename('fullpath'));

if ~matRad_checkMexFileExists('omc_matrad') %exist('matRad_ompInterface','file') ~= 3
    matRad_cfg.dispWarning('Compiled mex interface not found. Trying to compile the ompMC interface on the fly!');
    try
        matRad_compileOmpMCInterface();
    catch MException
        matRad_cfg.dispError('Could not find/generate mex interface for MC dose calculation.\nCause of error:\n%s\n Please compile it yourself (preferably with OpenMP support).',MException.message);
    end
end

matRad_calcDoseInit;

% gaussian filter to model penumbra from (measured) machine output / see diploma thesis siggel 4.1.2
if isfield(machine.data,'penumbraFWHMatIso')
    penumbraFWHM = machine.data.penumbraFWHMatIso;
else
    penumbraFWHM = 5;
    matRad_cfg.dispWarning('photon machine file does not contain measured penumbra width in machine.data.penumbraFWHMatIso. Assuming 5 mm.');
end

sourceFWHM = penumbraFWHM * machine.meta.SCD/(machine.meta.SAD - machine.meta.SCD);
sigmaGauss = sourceFWHM / sqrt(8*log(2)); % [mm]

% set up arrays for book keeping
dij.bixelNum = NaN*ones(dij.totalNumOfBixels,1);
dij.rayNum   = NaN*ones(dij.totalNumOfBixels,1);
dij.beamNum  = NaN*ones(dij.totalNumOfBixels,1);

dij.numHistoriesPerBeamlet = nCasePerBixel;

omcFolder = [matRad_cfg.matRadRoot filesep 'ompMC'];
%omcFolder = [matRad_cfg.matRadRoot filesep 'submodules' filesep 'ompMC'];

%% Setup OmpMC options / parameters

%display options
ompMCoptions.verbose = matRad_cfg.logLevel - 1;

% start MC control
ompMCoptions.nHistories = nCasePerBixel;
ompMCoptions.nSplit = 20;
ompMCoptions.nBatches = 10;
ompMCoptions.randomSeeds = [97 33];

%start source definition
ompMCoptions.spectrumFile       = [omcFolder filesep 'spectra' filesep 'mohan6.spectrum'];
ompMCoptions.monoEnergy         = 0.1;
ompMCoptions.charge             = 0;
ompMCoptions.sourceGeometry     = 'gaussian';
ompMCoptions.sourceGaussianWidth = 0.1*sigmaGauss;

% start MC transport
ompMCoptions.dataFolder   = [omcFolder filesep 'data' filesep];
ompMCoptions.pegsFile     = [omcFolder filesep 'pegs4' filesep '700icru.pegs4dat'];
ompMCoptions.pgs4formFile = [omcFolder filesep 'pegs4' filesep 'pgs4form.dat'];

ompMCoptions.global_ecut = 0.7;
ompMCoptions.global_pcut = 0.010;

% Relative Threshold for dose
ompMCoptions.relDoseThreshold = 1 - matRad_cfg.propDoseCalc.defaultLateralCutOff;

% Output folders
ompMCoptions.outputFolder = [omcFolder filesep 'output' filesep];

% Create Material Density Cube
material = cell(4,5);
material{1,1} = 'AIR700ICRU';
material{1,2} = -1024;
material{1,3} = -974;
material{1,4} = 0.001;
material{1,5} = 0.044;
material{2,1} = 'LUNG700ICRU';
material{2,2} = -974;
material{2,3} = -724;
material{2,4} = 0.044;
material{2,5} = 0.302;
material{3,1} = 'ICRUTISSUE700ICRU';
material{3,2} = -724;
material{3,3} = 101;
material{3,4} = 0.302;
material{3,5} = 1.101;
material{4,1} = 'ICRPBONE700ICRU';
material{4,2} = 101;
material{4,3} = 1976;
material{4,4} = 1.101;
material{4,5} = 2.088;

% conversion from HU to densities & materials
for s = 1:dij.numOfScenarios

    HUcube{s} =  matRad_interp3(dij.ctGrid.x,dij.ctGrid.y',dij.ctGrid.z,ct.cubeHU{s}, ...
                            dij.doseGrid.x,dij.doseGrid.y',dij.doseGrid.z,'nearest');

    % projecting out of bounds HU values where necessary
    if max(HUcube{s}(:)) > material{end,3}
        matRad_cfg.dispWarning('Projecting out of range HU values');
        HUcube{s}(HUcube{s}(:) > material{end,3}) = material{end,3};
    end
    if min(HUcube{s}(:)) < material{1,2}
        matRad_cfg.dispWarning('Projecting out of range HU values');
        HUcube{s}(HUcube{s}(:) < material{1,2}) = material{1,2};
    end

    % find material index
    cubeMatIx{s} = NaN*ones(dij.doseGrid.dimensions,'int32');
    for i = size(material,1):-1:1
        cubeMatIx{s}(HUcube{s} <= material{i,3}) = i;
    end

    % create an artificial HU lookup table
    hlut = [];
    for i = 1:size(material,1)
        hlut = [hlut;material{i,2} material{i,4};material{i,3}-1e-10 material{i,5}]; % add eps for interpolation
    end

    cubeRho{s} = interp1(hlut(:,1),hlut(:,2),HUcube{s});

end

ompMCgeo.material = material;

scale = 10; % to convert to cm

ompMCgeo.xBounds = (dij.doseGrid.resolution.y * (0.5 + [0:dij.doseGrid.dimensions(1)])) ./ scale;
ompMCgeo.yBounds = (dij.doseGrid.resolution.x * (0.5 + [0:dij.doseGrid.dimensions(2)])) ./ scale;
ompMCgeo.zBounds = (dij.doseGrid.resolution.z * (0.5 + [0:dij.doseGrid.dimensions(3)])) ./ scale;

%% debug visualization
if visBool

    figure
    hold on

    axis equal

    % ct box
    ctCorner1 = [ompMCgeo.xBounds(1) ompMCgeo.yBounds(1) ompMCgeo.zBounds(1)];
    ctCorner2 = [ompMCgeo.xBounds(end) ompMCgeo.yBounds(end) ompMCgeo.zBounds(end)];
    plot3([ctCorner1(1) ctCorner2(1)],[ctCorner1(2) ctCorner1(2)],[ctCorner1(3) ctCorner1(3)],'k' )
    plot3([ctCorner1(1) ctCorner2(1)],[ctCorner2(2) ctCorner2(2)],[ctCorner1(3) ctCorner1(3)],'k' )
    plot3([ctCorner1(1) ctCorner1(1)],[ctCorner1(2) ctCorner2(2)],[ctCorner1(3) ctCorner1(3)],'k' )
    plot3([ctCorner2(1) ctCorner2(1)],[ctCorner1(2) ctCorner2(2)],[ctCorner1(3) ctCorner1(3)],'k' )
    plot3([ctCorner1(1) ctCorner2(1)],[ctCorner1(2) ctCorner1(2)],[ctCorner2(3) ctCorner2(3)],'k' )
    plot3([ctCorner1(1) ctCorner2(1)],[ctCorner2(2) ctCorner2(2)],[ctCorner2(3) ctCorner2(3)],'k' )
    plot3([ctCorner1(1) ctCorner1(1)],[ctCorner1(2) ctCorner2(2)],[ctCorner2(3) ctCorner2(3)],'k' )
    plot3([ctCorner2(1) ctCorner2(1)],[ctCorner1(2) ctCorner2(2)],[ctCorner2(3) ctCorner2(3)],'k' )
    plot3([ctCorner1(1) ctCorner1(1)],[ctCorner1(2) ctCorner1(2)],[ctCorner1(3) ctCorner2(3)],'k' )
    plot3([ctCorner2(1) ctCorner2(1)],[ctCorner1(2) ctCorner1(2)],[ctCorner1(3) ctCorner2(3)],'k' )
    plot3([ctCorner1(1) ctCorner1(1)],[ctCorner2(2) ctCorner2(2)],[ctCorner1(3) ctCorner2(3)],'k' )
    plot3([ctCorner2(1) ctCorner2(1)],[ctCorner2(2) ctCorner2(2)],[ctCorner1(3) ctCorner2(3)],'k' )

    xlabel('x [cm]')
    ylabel('y [cm]')
    zlabel('z [cm]')

    rotate3d on

end

%% Create beamlet source
useCornersSCD = true; %false -> use ISO corners

numOfBixels = [stf(:).numOfRays];
beamSource = zeros(dij.numOfBeams, 3);

bixelCorner = zeros(dij.totalNumOfBixels,3);
bixelSide1 = zeros(dij.totalNumOfBixels,3);
bixelSide2 = zeros(dij.totalNumOfBixels,3);

counter = 0;

for i = 1:dij.numOfBeams % loop over all beams

    % define beam source in physical coordinate system in cm
    beamSource(i,:) = (stf(i).sourcePoint + stf(i).isoCenter)/10;

    for j = 1:stf(i).numOfRays % loop over all rays / for photons we only have one bixel per ray!

        counter = counter + 1;

        dij.beamNum(counter)  = i;
        dij.rayNum(counter)   = j;
        dij.bixelNum(counter) = j;

        if useCornersSCD
            beamletCorners = stf(i).ray(j).rayCorners_SCD;
        else
            beamletCorners = stf(i).ray(j).beamletCornersAtIso;
        end

        % get bixel corner and delimiting vectors.
        % a) change coordinate system (Isocenter cs-> physical cs) and units mm -> cm
        currCorner = (beamletCorners(1,:) + stf(i).isoCenter) ./ scale;
        bixelCorner(counter,:) = currCorner;
        bixelSide1(counter,:) = (beamletCorners(2,:) + stf(i).isoCenter) ./ scale - currCorner;
        bixelSide2(counter,:) = (beamletCorners(4,:) + stf(i).isoCenter) ./ scale - currCorner;

        if visBool
            for k = 1:4
                currCornerVis = (beamletCorners(k,:) + stf(i).isoCenter)/10;
                % rays connecting source and ray corner
                plot3([beamSource(i,1) currCornerVis(1)],[beamSource(i,2) currCornerVis(2)],[beamSource(i,3) currCornerVis(3)],'b')
                % connection between corners
                lRayCorner = (beamletCorners(mod(k,4) + 1,:) + stf(i).isoCenter)/10;
                plot3([lRayCorner(1) currCornerVis(1)],[lRayCorner(2) currCornerVis(2)],[lRayCorner(3) currCornerVis(3)],'r')
            end
        end

    end

end

ompMCsource.nBeams = dij.numOfBeams;
ompMCsource.iBeam = dij.beamNum(:);

% Switch x and y directions to match ompMC cs.
ompMCsource.xSource = beamSource(:,2);
ompMCsource.ySource = beamSource(:,1);
ompMCsource.zSource = beamSource(:,3);

ompMCsource.nBixels = sum(numOfBixels(:));
ompMCsource.xCorner = bixelCorner(:,2);
ompMCsource.yCorner = bixelCorner(:,1);
ompMCsource.zCorner = bixelCorner(:,3);

ompMCsource.xSide1 = bixelSide1(:,2);
ompMCsource.ySide1 = bixelSide1(:,1);
ompMCsource.zSide1 = bixelSide1(:,3);

ompMCsource.xSide2 = bixelSide2(:,2);
ompMCsource.ySide2 = bixelSide2(:,1);
ompMCsource.zSide2 = bixelSide2(:,3);

if visBool
    plot3(ompMCsource.ySource,ompMCsource.xSource,ompMCsource.zSource,'rx')
end

%% Call the OmpMC interface

%ompMC for matRad returns dose/history * nHistories.
% This factor calibrates to 1 Gy in a %(5x5)cm^2 open field (1 bixel) at
% 5cm depth for SSD = 900 which corresponds to the calibration for the
% analytical base data.
absCalibrationFactor = 3.49056 * 1e12; %Approximate!

%Now we have to calibrate to the the beamlet width.
absCalibrationFactor = absCalibrationFactor * (pln.propStf.bixelWidth/50)^2;

matRad_cfg.dispInfo('matRad: OmpMC photon dose calculation... \n');

outputVariance = matRad_cfg.propMC.ompMC_defaultOutputVariance;

if isfield(pln,'propMC') && isfield(pln.propMC,'outputVariance')
    outputVariance = pln.propMC.outputVariance;
end

%run over all scenarios
for s = 1:dij.numOfScenarios
    ompMCgeo.isoCenter = [stf(:).isoCenter];

    %Run the Monte Carlo simulation and catch  possible mex-interface
    %issues
    try
        %If we ask for variance, a field in the dij will be filled
        if outputVariance
            [dij.physicalDose{s},dij.physicalDose_MCvar{s}] = omc_matrad(cubeRho{s},cubeMatIx{s},ompMCgeo,ompMCsource,ompMCoptions);
        else
            [dij.physicalDose{s}] = omc_matrad(cubeRho{s},cubeMatIx{s},ompMCgeo,ompMCsource,ompMCoptions);
        end
    catch ME
        errorString = [ME.message '\nThis error was thrown by the MEX-interface of ompMC.\nMex interfaces can raise compatability issues which may be resolved by compiling them by hand directly on your particular system.'];
        matRad_cfg.dispError(errorString);
    end

    %Calibrate the dose with above factor
    dij.physicalDose{s} = dij.physicalDose{s} * absCalibrationFactor;
    if isfield(dij,'physicalDose_MCvar')
        dij.physicalDose_MCvar{s} = dij.physicalDose_MCvar{s} * absCalibrationFactor^2;
    end
end

matRad_cfg.dispInfo('matRad: MC photon dose calculation done!\n');
matRad_cfg.dispInfo(evalc('toc'));

try
    % wait 0.1s for closing all waitbars
    allWaitBarFigures = findall(0,'type','figure','tag','TMWWaitbar');
    delete(allWaitBarFigures);
    pause(0.1);
catch
end

end


function test_bug2069

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_appendfreq ft_freqstatistics ft_timelockstatistics

%% simulate some data

tl = cell(1,20);
tl_shuff = cell(1,20);
freq = cell(1,20);
freq_shuff = cell(1,20);

for k = 1:20
  % tl will hold timelocked structures with no channel order shuffling
  tl{k} = [];
  tl{k}.label = {'MLC11','MLC12','MLC13','MLC14','MLC15','MLC16','MLC17','MLC21','MLC22','MLC23','MLC24','MLC25','MLC31','MLC32','MLC41','MLC42','MLC51','MLC52','MLC53','MLC54','MLC55','MLC61','MLC62','MLC63','MLF11','MLF12','MLF13','MLF14','MLF21','MLF22','MLF23','MLF24','MLF25','MLF31','MLF32','MLF33','MLF34','MLF35','MLF41','MLF42','MLF43','MLF44','MLF45','MLF46','MLF51','MLF52','MLF53','MLF54','MLF55','MLF56','MLF61','MLF62','MLF63','MLF64','MLF65','MLF66','MLF67','MLO13','MLO14','MLO23','MLO24','MLO31','MLO32','MLO33','MLO34','MLO41','MLO42','MLO43','MLO44','MLO51','MLO52','MLO53','MLP11','MLP12','MLP21','MLP22','MLP23','MLP31','MLP32','MLP33','MLP34','MLP35','MLP41','MLP42','MLP43','MLP44','MLP45','MLP51','MLP52','MLP53','MLP54','MLP55','MLP56','MLP57','MLT11','MLT12','MLT13','MLT14','MLT15','MLT16','MLT21','MLT22','MLT23','MLT24','MLT25','MLT26','MLT27','MLT31','MLT32','MLT33','MLT34','MLT35','MLT36','MLT37','MLT41','MLT42','MLT43','MLT44','MLT45','MLT46','MLT47','MLT51','MLT52','MLT53','MLT54','MLT55','MLT56','MLT57','MRC11','MRC12','MRC13','MRC14','MRC15','MRC16','MRC17','MRC21','MRC22','MRC23','MRC24','MRC25','MRC31','MRC32','MRC41','MRC42','MRC51','MRC52','MRC53','MRC54','MRC55','MRC61','MRC62','MRC63','MRF11','MRF12','MRF13','MRF14','MRF21','MRF22','MRF23','MRF24','MRF25','MRF31','MRF32','MRF33','MRF34','MRF35','MRF41','MRF42','MRF43','MRF44','MRF45','MRF46','MRF51','MRF52','MRF53','MRF54','MRF55','MRF56','MRF61','MRF62','MRF63','MRF64','MRF65','MRF67','MRO11','MRO12','MRO13','MRO14','MRO21','MRO22','MRO23','MRO24','MRO31','MRO32','MRO33','MRO34','MRO41','MRO42','MRO43','MRO44','MRO51','MRO53','MRP11','MRP12','MRP21','MRP22','MRP23','MRP31','MRP32','MRP33','MRP34','MRP35','MRP41','MRP42','MRP43','MRP44','MRP45','MRP51','MRP52','MRP53','MRP54','MRP55','MRP56','MRP57','MRT11','MRT12','MRT13','MRT14','MRT15','MRT16','MRT21','MRT22','MRT23','MRT24','MRT25','MRT26','MRT27','MRT31','MRT32','MRT33','MRT34','MRT35','MRT36','MRT37','MRT41','MRT42','MRT43','MRT44','MRT45','MRT46','MRT47','MRT51','MRT52','MRT53','MRT54','MRT55','MRT56','MRT57','MZC01','MZC02','MZC03','MZC04','MZF01','MZF02','MZF03','MZO01','MZO03','MZP01','MLO11','MLO12','MLO21','MLO22','MZO02'};

  tl{k}.avg = randn(273,100);
  tl{k}.time = 0.01:0.01:1;
  tl{k}.dimord = 'chan_time';

  % shuffle the channel orders for tl_shuff
  perm = randperm(numel(tl{k}.label));
  tl_shuff{k} = tl{k};
  tl_shuff{k}.label = tl{k}.label(perm);
  tl_shuff{k}.avg = tl{k}.avg(perm,:);

  % take the same data as tl for a freq structure with singleton freq
  freq{k} = [];
  freq{k}.label = tl{k}.label;
  freq{k}.freq = 10;
  freq{k}.time = tl{k}.time;
  freq{k}.powspctrm = reshape(tl{k}.avg, [273 1 100]);
  freq{k}.dimord = 'chan_freq_time';

  % and also make a freq_shuff using the same shuffling as for tl_shuff
  freq_shuff{k} = freq{k};
  freq_shuff{k}.label = freq{k}.label(perm);
  freq_shuff{k}.powspctrm = freq{k}.powspctrm(perm,:,:);
end

% note: to visually verify that the shuffling was done correctly simply do
% cfg = [];
% cfg.layout = 'CTF275.lay';
% figure; ft_topoplotER(cfg, tl{1});
% figure; ft_topoplotER(cfg, tl_shuff{1});

%% stats cfg: common stuff for both methods
cfg = [];
cfg.method = 'montecarlo';
cfg.statistic = 'ft_statfun_depsamplesT';
cfg.correctm = 'cluster';
cfg.clusteralpha = 0.05;
cfg.clusterstatistic = 'maxsum';
cfg.minnbchan = 2;

c2 = [];
c2.method = 'template';
c2.template = 'CTF275_neighb.mat';
cfg.neighbours = ft_prepare_neighbours(c2);

cfg.tail = 0;
cfg.clustertail = 0;
cfg.alpha = 0.025;
cfg.numrandomization = 10;
cfg.clusterthreshold = 'nonparametric_common';

cfg.design = [
  ones(1,10) ones(1,10)*2;
  1:10 1:10
];
cfg.ivar  = 1;
cfg.uvar = 2;

%% do the stats

% timelockstatistics
stat_tl = ft_timelockstatistics(cfg, tl{:});
stat_tl_shuff = ft_timelockstatistics(cfg, tl_shuff{:});

% freqstatistics
cfg.avgoverfreq = 'yes';
cfg.frequency = [7 14];
stat_freq = ft_freqstatistics(cfg, freq{:});
stat_freq_shuff = ft_freqstatistics(cfg, freq_shuff{:});

%% diagnostics

% make channel order across structures consistent again
% note that we only fix the .stat field as that is the only one we test
% later on
[sel1,sel2] = match_str(stat_tl.label, stat_tl_shuff.label);
stat_tl_shuff.label = stat_tl_shuff.label(sel2);
stat_tl_shuff.stat = stat_tl_shuff.stat(sel2,:);
stat_tl_shuff.prob = stat_tl_shuff.prob(sel2,:);

[sel1,sel2] = match_str(stat_tl.label, stat_freq.label);
stat_freq.label = stat_freq.label(sel2);
stat_freq.stat = stat_freq.stat(sel2,:,:);
stat_freq.prob = stat_freq.prob(sel2,:,:);

[sel1,sel2] = match_str(stat_tl.label, stat_freq_shuff.label);
stat_freq_shuff.label = stat_freq_shuff.label(sel2);
stat_freq_shuff.stat = stat_freq_shuff.stat(sel2,:,:);
stat_freq_shuff.prob = stat_freq_shuff.prob(sel2,:,:);

fprintf('\ndiagnostic results:\n');
errflag = 0;

if all(stat_tl.stat(:) == stat_tl_shuff.stat(:))
  fprintf('for timelockstatistics, shuffling does not matter\n');
else
  fprintf('ERROR in timelockstatistics when channels are shuffled!\n');
  errflag = 1;
end

if all(stat_freq.stat(:) == stat_freq_shuff.stat(:))
  fprintf('for freqstatistics, shuffling does not matter\n');
else
  fprintf('ERROR in freqstatistics when channels are shuffled!\n');
  errflag = 1;
end

if all(stat_freq.stat(:) == stat_tl.stat(:))
  fprintf('with normal channel order, freqstats equal tlstats\n');
else
  fprintf('with normal channel order, freqstats DOES NOT equal tlstats\n');
  errflag = 1;
end

if all(stat_freq_shuff.stat(:) == stat_tl_shuff.stat(:))
  fprintf('with identically shuffled channel order, freqstats equal tlstats\n');
else
  fprintf('with identically shuffled channel order, freqstats DOES NOT equal tlstats\n');
  errflag = 1;
end

if errflag
  fprintf('\n');
  error('something bad happened, see above for details');
end


function perm = ordmmdmex(adjncy) %#ok
% perm = ordmmdmex(adjncy)
%
%   Computes multiple-minimum-degree permutation, for sparse
%   Cholesky. Adjncy is  a sparse symmetric matrix; its diagonal
%   is irrelevant.
%
%   Invokes SPARSPAK-A Release III.
%
% **********  INTERNAL FUNCTION OF CHOLTOOL  **********

%   This file is part of CholTool 1.00
%   Copyright (C) 1998 Jos F. Sturm
%   CRL, McMaster University, Canada.
%   Supported by the Netherlands Organization for Scientific Research (NWO).
%
%   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., 675 Mass Ave, Cambridge, MA 02139, USA.

%Indicate to the user Matlab cannot find the SeDuMi binaries
sedumi_binary_error();


%% PYTHONPLOT
function pythonplot(obj)
    obj.plot('metric', {'counts';'cum_mag'});
end