% STD_ERSPPLOT - plot STUDY cluster ERSPs. Displays either mean cluster ERSPs,
%                  or else all cluster component ERSPs plus the mean cluster
%                  ERSP in one figure per condition. The ERSPs can be plotted
%                  only if component ERSPs were computed and saved in the
%                  EEG datasets in the STUDY. These may either be computed
%                  during pre-clustering using the gui-based function
%                  POP_PRECLUST, or via the equivalent commandline functions
%                  EEG_CREATEDATA and EEG_PRECLUST. Called by POP_CLUSTEDIT.
% Usage:
%   >> [STUDY] = std_erspplot(STUDY, ALLEEG, key1, val1, key2, val2);
%   >> [STUDY erspdata ersptimes erspfreqs pgroup pcond pinter] = ...
%                std_erspplot(STUDY, ALLEEG ...);
%
% Inputs:
%   STUDY    - STUDY set comprising some or all of the EEG datasets in ALLEEG.
%   ALLEEG   - global vector of EEG structures for the datasets included
%              in the STUDY. ALLEEG for a STUDY set is typically created
%              using LOAD_ALLEEG.
%   either 'channels' or 'cluster' inputs are also mandatory.
%
% Optional inputs for channel plotting:
%   'channels' - [numeric vector]  specific channel group to plot. By
%                default, the grand mean channel ERSP is plotted (using the
%                same format as for the cluster component means described above)
%   'subject'  - [numeric vector]  In 'changrp' mode (above), index of
%                the subject(s) to plot. Else by default, plot all components
%                in the cluster.
%   'plotsubjects' - ['on'|'off'] When 'on', plot ERSP of all subjects.
%   'noplot'   - ['on'|'off'] When 'on', only return output values. Default
%                is 'off'.
%
% Optional inputs:
%   'clusters' - [numeric vector|'all'] indices of clusters to plot.
%                If no component indices ('comps' below) are given, the average
%                ERSPs of the requested clusters are plotted in the same figure,
%                with ERSPs for different conditions (and groups if any) plotted
%                in different colors. In 'comps' (below) mode, ERSP for each
%                specified cluster are plotted in separate figures (one per
%                condition), each overplotting cluster component ERSP plus the
%                average cluster ERSP in bold. Note this parameter has no effect
%                if the 'comps' option (below) is used. {default: 'all'}
%   'comps'    - [numeric vector|'all'] indices of the cluster components to plot.
%                Note that 'comps', 'all' is equivalent to 'plotsubjects', 'on'.
%
% Other optional inputs:
%   'plotmode'  - ['normal'|'condensed'|'none'] 'normal'  -> plot in a new figure;
%                 'condensed' -> plot all curves in the current figure in a
%                 condensed fashion. 'none' toggles off plotting {default: 'normal'}
%   'key','val' - All optional inputs to POP_SPECPARAMS are also accepted here
%                 to plot subset of time, statistics etc. The values used by default
%                 are the ones set using POP_SPECPARAMS and stored in the
%                 STUDY structure.
% Output:
%   STUDY      - the input STUDY set structure with the plotted cluster
%                mean ERSPs stored to allow quick replotting
%   erspdata   - [cell] ERSP data for each condition, group and subjects.
%                size of cell array is [nconds x ngroups]. Size of each element
%                is [freqs x times x subjects] for data channels or
%                [freqs x times x components] for component clusters. This
%                array may be gicen as input  directly to the STATCOND f
%                unction or STD_STATS function to compute statistics.
%   ersptimes  - [array] ERSP time point latencies.
%   erspfreqs  - [array] ERSP point frequency values.
%   pgroup     - [array or cell] p-values group statistics. Output of the
%                STATCOND function.
%   pcond      - [array or cell] condition statistics. Output of the STATCOND
%                function.
%   pinter     - [array or cell] groups x conditions statistics. Output of
%                STATCOND function.
%
% Example:
%        >> [STUDY] = std_erspplot(STUDY,ALLEEG, 'clusters', 'all', ...
%                                       'mode', 'together');
%           % Plot the mean ERSPs of all clusters in STUDY together
%           % on the same figure.
%
% Known limitations: when plotting multiple clusters, the output
%                    contains the last plotted cluster.
%
% See also: POP_CLUSTEDIT, POP_PRECLUST, EEG_CREATEDATA, EEG_PRECLUST, POP_CLUSTEDIT
%
% Authors: Arnaud Delorme, CERCO, August, 2006

% Copyright (C) Arnaud Delorme, 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 [STUDY, allersp, alltimes, allfreqs, pgroup, pcond, pinter, events] = std_erspplot(STUDY, ALLEEG, varargin)

if nargin < 2
    help std_erspstatplot;
    return;
end

% find datatype and default options
% ---------------------------------
dtype = 'ersp';
for ind = 1:2:length(varargin)
    if strcmpi(varargin{ind}, 'datatype')
        dtype = varargin{ind+1};
    end
end
if strcmpi(dtype, 'erpim')
     STUDY  = pop_erpimparams(STUDY, varargin{:});
     params = STUDY.etc.erpimparams;
else STUDY  = pop_erspparams( STUDY, varargin{:});
     params = STUDY.etc.erspparams;
end

% get parameters
% --------------
statstruct.etc = STUDY.etc;
statstruct = pop_statparams(statstruct, varargin{:});

% potentially missing fields
% --------------------------
fields     = { 'freqrange'     [];
               'topofreq'      [];
               'topotrial'     [];
               'trialrange'    []
               'concatenate'   'off';
               'colorlimits'   [];
               'ersplim'       [];
               'itclim'        [];
               'maskdata'      'off';
               'subbaseline'   'off' };
for ind=1:size(fields,1)
    if ~isfield(params, fields{ind,1}),
        params = setfield(params, fields{ind,1}, fields{ind,2});
    end
end

% decode input parameters
% -----------------------
options = mystruct(varargin);
options = myrmfield( options, myfieldnames(params));
options = myrmfield( options, myfieldnames(statstruct.etc.statistics));
options = myrmfield( options, { 'threshold' 'statistics' } ); % for backward compatibility
[ opt, moreparams ] = finputcheck( options, { ...
                               'design'      'integer' [] STUDY.currentdesign;
                               'caxis'       'real'    [] [];
                               'statmode'    'string'  [] ''; % deprecated
                               'channels'    'cell'    []              {};
                               'clusters'    'integer' []              [];
                               'datatype'    'string'  { 'itc','ersp','pac' 'erpim' } 'ersp';
                               'plottf'      'real'    []              [];
                               'mode'        'string'  []              ''; % for backward compatibility (now used for statistics)
                               'comps'       {'integer','string'}  []              []; % for backward compatibility
                               'plotsubjects' 'string' { 'on','off' }  'off';
                               'noplot'      'string'  { 'on','off' }  'off';
                               'plotmode'    'string'  { 'normal','condensed','none' }  'normal';
                               'subject'     'string'  []              '' }, ...
                                  'std_erspstatplot', 'ignore');
if ischar(opt), error(opt); end
if strcmpi(opt.noplot, 'on'), opt.plotmode = 'none'; end
if isempty(opt.caxis)
    if strcmpi(opt.datatype, 'ersp')
         opt.caxis = params.ersplim;
    elseif strcmpi(opt.datatype, 'itc') && ~isempty(params.itclim)
        opt.caxis = [-params.itclim(end) params.itclim(end)];
    end
end

allconditions  = {};
allgroups      = {};
condname       = '';
groupname      = '';
if length(STUDY.design(opt.design).variable) > 0, allconditions = STUDY.design(opt.design).variable(1).value; condname  = STUDY.design(opt.design).variable(1).label; end
if length(STUDY.design(opt.design).variable) > 1, allgroups     = STUDY.design(opt.design).variable(2).value; groupname = STUDY.design(opt.design).variable(2).label; end

% for backward compatibility
% --------------------------
if strcmpi(opt.datatype, 'erpim')
    params.topofreq = params.topotrial;
    opt.caxis       = params.colorlimits;
    valunit = 'trials';
else
    valunit = 'Hz';
end
if isempty(opt.plottf) && ~isempty(params.topofreq) && ~isempty(params.topotime) && ~isnan(params.topofreq(1)) && ~isnan(params.topotime(1))
     params.plottf = [ params.topofreq(1) params.topofreq(end) params.topotime(1) params.topotime(end) ];
else params.plottf = opt.plottf;
end
%if strcmpi(opt.mode, 'comps'), opt.plotsubjects = 'on'; end %deprecated
stats = statstruct.etc.statistics;
stats.fieldtrip.channelneighbor = struct([]); % assumes one channel or 1 component
if isempty(STUDY.design(opt.design).variable)
    stats.paired = { };
else
    stats.paired = { STUDY.design(opt.design).variable(:).pairing };
end
if strcmpi(stats.singletrials, 'off') && ((~isempty(opt.subject) || ~isempty(opt.comps)))
    if strcmpi(stats.condstats, 'on') || strcmpi(stats.groupstats, 'on')
        stats.groupstats = 'off';
        stats.condstats  = 'off';
        disp('No statistics for single subject/component');
    end
end

if length(opt.comps) == 1
    stats.condstats = 'off'; stats.groupstats = 'off';
    disp('Statistics cannot be computed for single component');
end

alpha    = fastif(strcmpi(stats.mode, 'eeglab'), stats.eeglab.alpha, stats.fieldtrip.alpha);
mcorrect = fastif(strcmpi(stats.mode, 'eeglab'), stats.eeglab.mcorrect, stats.fieldtrip.mcorrect);
method   = fastif(strcmpi(stats.mode, 'eeglab'), stats.eeglab.method, ['Fieldtrip ' stats.fieldtrip.method ]);
plottfopt = { ...
   'ersplim',     opt.caxis, ...
   'threshold',   alpha, ...
   'effect',      stats.effect, ...
   'maskdata',    params.maskdata ...
   'averagemode'  params.averagemode };
if ~isempty(params.plottf) && length(opt.channels) < 5  && isempty(opt.clusters)
    warndlg2(strvcat('ERSP/ITC parameters indicate that you wish to plot scalp maps', 'Select at least 5 channels to plot topography'));
    allersp = {}; alltimes = []; allfreqs = []; pgroup = []; pcond = []; pinter = []; events  = [];
    return;
end

% plot single scalp map
% ---------------------
if ~isempty(opt.channels)
    if isempty(params.plottf) && length(opt.channels) > 1 && strcmpi(stats.singletrials, 'on')
        error('Cannot plot several channels on the same figure when using single trial statistics');
    end

    [STUDY, allersp, alltimes, allfreqs, events, paramsersp] = std_readdata(STUDY, ALLEEG, 'channels', opt.channels, 'timerange', params.timerange, ...
        'freqrange', params.freqrange, 'subject', opt.subject, 'singletrials', stats.singletrials, 'design', opt.design, 'datatype', opt.datatype, 'subbaseline', params.subbaseline);
    % 'concatenate', params.concatenate NOT TAKEN INTO ACCOUNT
    unitPower = newtimefpowerunit(paramsersp);

    if strcmpi(opt.datatype, 'ersp') && strcmpi(params.subbaseline, 'off')
        if  strcmpi(stats.singletrials, 'off')
            % rational for baseline
            % - no baseline calculation or log transformation at reading time (except single trial baseline if any)
            % - if not single trial and no common baseline, remove baseline and transform data here in each condition (before stats)
            % - otherwise, do so after baseline removal
            paramsersp.singletrials = stats.singletrials;
            paramsersp.commonbase   = params.subbaseline;
            [allersp,basesamples,basevals] = newtimefbaseln(allersp, alltimes, paramsersp);
        else
            opt.subbaseline = 'on';
            disp('Warning: when using single-trial statistics, a common baseline is forced across all conditions');
        end
    end

    %[STUDY allersp alltimes allfreqs tmp events unitPower] = std_readerp(STUDY, ALLEEG, 'channels', opt.channels, 'infotype', opt.datatype, 'subject', opt.subject, ...
    %    'singletrials', stats.singletrials, 'subbaseline', params.subbaseline, 'timerange', params.timerange, 'freqrange', params.freqrange, 'design', opt.design, 'concatenate', params.concatenate);
    %tic
    %[STUDY allersp alltimes allfreqs tmp events unitPower] = std_readersp(STUDY, ALLEEG, 'channels', opt.channels, 'infotype', opt.datatype, 'subject', opt.subject, ...
    %   'singletrials', stats.singletrials, 'subbaseline', params.subbaseline, 'timerange', params.timerange, 'freqrange', params.freqrange, 'design', opt.design, 'concatenate', params.concatenate);
    %toc

    % average single trials
    % ---------------------
    if strcmpi(opt.datatype, 'ersp')
        if  strcmpi(params.subbaseline, 'on')
            disp('Computing common baseline has changed since EEGLAB 14: averaging baselines is now');
            disp('performed before log-transformation of the baseline - in a similar way that baseline');
            disp('is averaged across trials (log transformation is only performed at the end for display)');
            % see above for rational for baseline
            paramsersp.singletrials = stats.singletrials;
            paramsersp.commonbase   = params.subbaseline;
            allersp = newtimefbaseln(allersp, alltimes, paramsersp);
        else
            paramsersp.singletrials = stats.singletrials;
            allersp = cellfun(@(x)newtimefbaseln(x, alltimes, paramsersp), allersp, 'uniformoutput', false);
        end
        % transform to log (except single trials where the transformation
        % is after taking the average - which is after doing stats
        if strcmpi(stats.singletrials, 'off')
            if ~isfield(paramsersp, 'scale') || strcmpi(paramsersp.scale, 'log')
                allersp = cellfun(@(x)10*log10(x), allersp, 'uniformoutput', false);
            end
        end
    end

    % select specific time and freq
    % -----------------------------
    if ~isempty(params.plottf)
        if length(params.plottf) < 3
            params.plottf(3:4) = params.plottf(2);
            params.plottf(2)   = params.plottf(1);
        end
        [~, fi1] = min(abs(allfreqs-params.plottf(1)));
        [~, fi2] = min(abs(allfreqs-params.plottf(2)));
        [~, ti1] = min(abs(alltimes-params.plottf(3)));
        [~, ti2] = min(abs(alltimes-params.plottf(4)));
        for index = 1:length(allersp(:))
            allersp{index} = mean(mean(allersp{index}(fi1:fi2,ti1:ti2,:,:),1),2);
            allersp{index} = reshape(allersp{index}, [1 size(allersp{index},3) size(allersp{index},4) ]);
        end

        % prepare channel neighbor matrix for Fieldtrip
        statstruct = std_prepare_neighbors(statstruct, ALLEEG, 'channels', opt.channels);
        stats.fieldtrip.channelneighbor = statstruct.etc.statistics.fieldtrip.channelneighbor;

        params.plottf = { params.plottf(1:2) params.plottf(3:4) };
        [pcond, pgroup, pinter] = std_stat(allersp, stats);
        if (~isempty(pcond) && length(pcond{1}) == 1) || (~isempty(pgroup) && length(pgroup{1}) == 1), pcond = {}; pgroup = {}; pinter = {}; end % single subject STUDY
    else
        [pcond, pgroup, pinter] = std_stat(allersp, stats);
        if (~isempty(pcond ) && (size( pcond{1},1) == 1 || size( pcond{1},2) == 1)) || ...
           (~isempty(pgroup) && (size(pgroup{1},1) == 1 || size(pgroup{1},2) == 1))
            pcond = {}; pgroup = {}; pinter = {};
            disp('No statistics possible for single subject STUDY');
        end % single subject STUDY
    end

    if strcmpi(stats.singletrials, 'on')
        % For ITC this is optional but it does not change anything
        if strcmpi(opt.datatype, 'ersp')
            if ndims(allersp{1}) == 4, for ind = 1:length(allersp(:)), allersp{ind} = mean(allersp{ind},4); end; end
            if ndims(allersp{1}) == 3, for ind = 1:length(allersp(:)), allersp{ind} = mean(allersp{ind},3); end; end
            if strcmpi(opt.datatype, 'ersp') && (~isfield(paramsersp, 'scale') || strcmpi(paramsersp.scale, 'log'))
                allersp = cellfun(@(x)10*log10(x), allersp, 'uniformoutput', false);
            end
        elseif strcmpi(opt.datatype, 'itc')
            if ~isfield(params, 'itctype'), params.itctype = 'phasecoher'; end
            for iDat = 1:length(allersp(:))
                allersp{iDat} = newtimefitc(allersp{iDat}, params.itctype);
                allersp{iDat} = abs(allersp{iDat});
            end
        end
    end

    % Average channels
    if ~strcmpi(params.averagechan, 'off') && length(opt.channels) > 1
        for index = 1:length(allersp(:))
            if strcmpi(params.averagemode, 'ave')
                allersp{index} = squeeze(mean(allersp{index},3));
            else
                disp('Computing RMS while preserving sign');
                tfsign  = sign(squeeze(mean(allersp{index},3)));
                allersp{index} = squeeze(sqrt(mean(allersp{index}.^2,3))).*tfsign;
            end
        end
    end

    % plot specific channel(s)
    % ------------------------
    if ~strcmpi(opt.plotmode, 'none')
        locsOri = eeg_mergelocs(ALLEEG.chanlocs);
        locs = locsOri(std_chaninds(STUDY, opt.channels));

        % in case channels are being averaged
        if ~strcmpi(params.averagechan, 'off') && length(opt.channels) > 1
            if length(opt.channels) ~= length(locsOri)
                chanlabels = { locs.labels };
                chanlabels(2,:) = {','};
                chanlabels(2,end) = {''};
                locs(1).labels = [ chanlabels{:} ];
            else
                locs(1).labels = 'All channels';
            end
            locs(2:end) = [];
        end

        if ~isempty(params.plottf) % incomtible with averagechan above
            alltitles = std_figtitle('threshold', alpha, 'mcorrect', mcorrect, 'condstat', stats.condstats, 'cond2stat', stats.groupstats, ...
                                     'statistics', method, 'condnames', allconditions, 'cond2names', allgroups, 'chanlabels', { locs.labels }, ...
                                     'subject', opt.subject, 'valsunit', { valunit 'ms' }, 'vals', params.plottf, 'datatype', upper(opt.datatype), ...
                                     'effect', stats.effect, 'factor1', condname, 'factor2', groupname);
            std_chantopo(allersp, 'groupstats', pgroup, 'condstats', pcond, 'interstats', pinter, 'caxis', opt.caxis, ...
                                          'chanlocs', locs, 'threshold', alpha, 'titles', alltitles);
        else
            if length(locs) > 1, opt.plottopo = 'on'; else opt.plottopo = 'off'; end
            if length(locs) == 1 && size(allersp{1},3) > 1
                % channels should be in 3rd dim; reshape data to put subjects in the 4th dim if number of channels is 1
                for index = 1:length(allersp(:))
                    allersp{index} = reshape(allersp{index}, size(allersp{index},1), size(allersp{index},2), 1, size(allersp{index},3));
                end
            end

%             nc = ceil(sqrt(length(opt.channels)));
%             nr = ceil(length(opt.channels)/nc);
%             for index = 1:length(locs)
%                 if length(opt.channels) > 1, try, subplot(nr,nc,index, 'align'); catch, subplot(nr,nc,index); end; end
%                 tmpersp = cell(size(allersp));
%                 for ind = 1:length(allersp(:))
%                     if ~isempty(allersp{ind})
%                         tmpersp{ind} = squeeze(allersp{ind}(:,:,index,:));
%                         tmpersp{ind} = permute(tmpersp{ind}, [2 1 3]); % somehow time/freq are swapped in ntimes = nfreqs
%                     end
%                 end
%                 for ind = 1:length(allersp(:))
%                     if ~isempty(allersp{ind})
%                         allersp{ind} = permute(allersp{ind}, [2 1 3 4]); % somehow time/freq are swapped for tftopo
%                     end
%                 end
                alltitles = std_figtitle('threshold', alpha, 'mcorrect', mcorrect, 'condstat', stats.condstats, 'cond2stat', stats.groupstats, ...
                    'statistics', method, 'condnames', allconditions, 'cond2names', allgroups, ...
                    'subject', opt.subject, 'datatype', upper(opt.datatype), 'plotmode', opt.plotmode, ...
                    'effect', stats.effect, 'factor1', condname, 'factor2', groupname);
                std_plottf(alltimes, allfreqs, allersp, 'datatype', opt.datatype, 'titles', alltitles, ...
                    'groupstats', pgroup, 'condstats', pcond, 'interstats', pinter, 'plottopo', opt.plottopo, 'plotmode', ...
                    opt.plotmode, 'unitcolor', unitPower, 'chanlocs', locs, 'events', events, plottfopt{:});
%             end
        end
    end
else
    if length(opt.clusters) > 1 && strcmpi(stats.singletrials, 'on')
        error('Cannot plot several components on the same figure when using single trial statistics');
    end

    if length(opt.clusters) > 1 && ~strcmpi(opt.plotmode, 'none'), figure; opt.plotmode = 'condensed'; end
    nc = ceil(sqrt(length(opt.clusters)));
    nr = ceil(length(opt.clusters)/nc);
    comp_names = {};

    if length(opt.clusters) > 1 && ( strcmpi(stats.condstats, 'on') || strcmpi(stats.groupstats, 'on'))
        stats.condstats = 'off'; stats.groupstats = 'off';
    end

    for index = 1:length(opt.clusters)

        [STUDY, allersp, alltimes, allfreqs, events, paramsersp] = std_readdata(STUDY, ALLEEG, 'clusters', opt.clusters(index), 'datatype', opt.datatype, ...
            'component', opt.comps, 'singletrials', stats.singletrials, 'subbaseline', params.subbaseline, 'timerange', params.timerange, 'freqrange', params.freqrange, 'design', opt.design, 'concatenate', params.concatenate);
        if length(opt.clusters) > 1, try, subplot(nr,nc,index, 'align'); catch, subplot(nr,nc,index); end; end
        unitPower = newtimefpowerunit(paramsersp);

        % plot specific component
        % -----------------------
        if ~isempty(opt.comps)
            comp_names = { STUDY.cluster(opt.clusters(index)).comps(opt.comps) };
            opt.subject = STUDY.datasetinfo(STUDY.cluster(opt.clusters(index)).sets(1,opt.comps)).subject;
        end

        % average single trials
        % ---------------------
        if strcmpi(opt.datatype, 'ersp')
            if  strcmpi(params.subbaseline, 'on')
                disp('Computing common baseline has changed since EEGLAB 14: averaging baselines is now');
                disp('performed before log-transformation of the baseline - in a similar way that baseline');
                disp('is averaged across trials (log transformation is only performed at the end for display)');
                % see above for rational for baseline
                paramsersp.singletrials = stats.singletrials;
                paramsersp.commonbase   = params.subbaseline;
                allersp = newtimefbaseln(allersp, alltimes, paramsersp);
            else
                paramsersp.singletrials = stats.singletrials;
                allersp = cellfun(@(x)newtimefbaseln(x, alltimes, paramsersp), allersp, 'uniformoutput', false);
            end
            % transform to log (except single trials)
            if strcmpi(stats.singletrials, 'off')
                if ~isfield(paramsersp, 'scale') || strcmpi(paramsersp.scale, 'log')
                    allersp = cellfun(@(x)10*log10(x), allersp, 'uniformoutput', false);
                end
            end
        end

        % statistics
        % ----------
        [pcond pgroup pinter] = std_stat(allersp, stats);
        if (~isempty(pcond ) && (size( pcond{1},1) == 1 || size( pcond{1},2) == 1)) || ...
           (~isempty(pgroup) && (size(pgroup{1},1) == 1 || size(pgroup{1},2) == 1)),
            pcond = {}; pgroup = {}; pinter = {};
            disp('No statistics possible for single subject STUDY');
        end % single subject STUDY

        if strcmpi(stats.singletrials, 'on')
            if strcmpi(opt.datatype, 'ersp')
                if ndims(allersp{1}) == 4, for ind = 1:length(allersp(:)), allersp{ind} = mean(allersp{ind},4); end; end
                if ndims(allersp{1}) == 3, for ind = 1:length(allersp(:)), allersp{ind} = mean(allersp{ind},3); end; end
                if ~isfield(paramsersp, 'scale') || strcmpi(paramsersp.scale, 'log')
                    allersp = cellfun(@(x)10*log10(x), allersp, 'uniformoutput', false);
                end
            elseif strcmpi(opt.datatype, 'itc')
                if ~isfield(params, 'itctype'), params.itctype = 'phasecoher'; end
                for iDat = 1:length(allersp(:))
                    allersp{iDat} = newtimefitc(allersp{iDat}, params.itctype);
                    allersp{iDat} = abs(allersp{iDat});
                end
            end
        end

        % plot specific component
        % -----------------------
        if index == length(opt.clusters), opt.legend = 'on'; end
        if ~strcmpi(opt.plotmode, 'none')
            alltitles = std_figtitle('threshold', alpha, 'mcorrect', mcorrect, 'condstat', stats.condstats, 'cond2stat', stats.groupstats, ...
                                     'statistics', method, 'condnames', allconditions, 'cond2names', allgroups, 'clustname', STUDY.cluster(opt.clusters(index)).name, 'compnames', comp_names, ...
                                     'subject', opt.subject, 'datatype', upper(opt.datatype), 'plotmode', opt.plotmode, ...
                                     'effect', stats.effect, 'factor1', condname, 'factor2', groupname);

            std_plottf(alltimes, allfreqs, allersp, 'datatype', opt.datatype, ...
                                           'groupstats', pgroup, 'condstats', pcond, 'interstats', pinter, 'plotmode', ...
                                           opt.plotmode, 'titles', alltitles, ...
                                          'events', events, 'unitcolor', unitPower, 'chanlocs', ALLEEG(1).chanlocs, plottfopt{:});
        end
    end
end

% remove fields and ignore fields who are absent
% ----------------------------------------------
function s = myrmfield(s, f);

for index = 1:length(f)
    if isfield(s, f{index})
        s = rmfield(s, f{index});
    end
end

% convert to structure (but take into account cells)
% --------------------------------------------------
function s = mystruct(v);

for index=1:length(v)
    if iscell(v{index})
        v{index} = { v{index} };
    end
end
try
    s = struct(v{:});
catch, error('Parameter error'); end

% convert to structure (but take into account cells)
% --------------------------------------------------
function s = myfieldnames(v);

s = fieldnames(v);
if isfield(v, 'eeglab')
    s2 = fieldnames(v.eeglab);
    s = { s{:} s2{:} };
end
if isfield(v, 'fieldtrip')
    s3 = fieldnames(v.fieldtrip);
    for index=1:length(s3)
        s3{index} = [ 'fieldtrip' s3{index} ];
    end
    s = { s{:} s3{:} };
end


function handle = plot_sequence_strip(sequence, trajectories, varargin)
% plot_sequence_strip Generate an preview of a sequence as a strip of frames
%
% The function generates dedicated tracker legend plot. Tracker labels and
% their symbols are ordered in a grid.
%
% Input:
% - trackers (cell): A cell array of tracker structures.
% - varargin[Handle] (handle): Plot on existing figure handle.
% - varargin[Visible] (boolean): Is the figure visible on the display.
% - varargin[Window] (double): Figure width hint.
% - varargin[Samples] (double): Figure height hint.
% - varargin[Scale] (integer): Number of rows in a grid.
% - varargin[Columns] (integer): Number of columns in a grid.
%
% Output:
% - handle (handle): A figure handle.
%

handle = -1;
visible = false;
trajectories_markers = {};
window = 120;
samples = 12;
scale = 1;
frame_numbers = false;

groundtruth_color = [1, 1, 1];
trajectories_colors = mat2cell(repmat([1, 0, 0], length(trajectories), 1), ...
    ones(length(trajectories), 1));

for i = 1:2:length(varargin)
    switch lower(varargin{i})
        case 'handle'
            handle = varargin{i+1};
        case 'visible'
            visible = varargin{i+1};
        case 'window'
            window = varargin{i+1};
        case 'samples'
            samples = varargin{i+1};
        case 'scale'
            scale = varargin{i+1};
        case 'framenumbers'
            frame_numbers = varargin{i+1};
        case 'groundtruthcolor'
            groundtruth_color = varargin{i+1};
        case 'trajectorycolor'
            trajectories_colors = varargin{i+1};
        case 'trajectorymarkers'
            trajectories_markers = varargin{i+1};
        otherwise
            error(['Unknown switch ', varargin{i},'!']) ;
    end
end

if numel(samples) > 1
    indices = samples(samples > 0 & samples <= sequence.length);
else
    indices = round(linspace(1, sequence.length, samples));
end;

if ishandle(handle)
    set(0, 'CurrentFigure', handle);
else
    if visible
        handle = figure();
    else
        handle = figure('Visible', 'off');
    end;
end;
handles = tight_subplots(1, length(indices), 0, 0, 0);

for i = 1:length(indices)

	if isinf(window)

		offset = [0, 0];

		patch = imread(sequence_get_image(sequence, indices(i)));

	else

	    patch = zeros(window, window, 3);

		region = region_convert(sequence_get_region(sequence, indices(i)), 'rectangle');

		offset = region(1:2) + (region(3:4) - window) / 2;

		source = imread(sequence_get_image(sequence, indices(i)));

		patch = patch_operation(patch, source, -offset([2, 1]), '=');

	end;

    axes(handles(i)); %#ok<LAXES>

    if ~visible
        set(handle, 'Visible', 'off');
    end;

    axis tight;

    imshow(uint8(patch));

    hold on;

    for t = 1:length(trajectories)

        region = trajectories{t}{indices(i)};

        if numel(region) < 2;
            continue;
        end;

        region = region_offset(region, -offset);

        region_draw(region, trajectories_colors{t}, 2);

        if ~isempty(trajectories_markers)
            bounds = region_convert(region, 'rectangle');
            center = bounds(1:2) + bounds(3:4) / 2;

            plot(center(1), center(2), trajectories_markers{t}, 'MarkerSize', 7, 'LineWidth', 1.5, 'Color', trajectories_colors{t});

        end;

    end;

    if ~isempty(groundtruth_color)

        region = sequence_get_region(sequence, indices(i));

        region = region_offset(region, -offset);

        region_draw(region, groundtruth_color, 2);

    end;

    if frame_numbers
        text(10, 10, sprintf('%d', indices(i)), 'Color', 'w', 'BackgroundColor', [0, 0, 0]);

    end;

    hold off;
end

width = numel(indices);
height = 1;

set(handle, 'PaperUnits', 'inches', 'PaperSize', [width, height] * scale, 'PaperPosition', [0, 0, width, height] * scale);


function [n,filters] = plx_chan_filters(filename)
% plx_chan_filters(filename): read channel filter settings for each spike channel from a .plx or .pl2 file
%
% [n,filters] = plx_chan_filters(filename)
%
% INPUT:
%   filename - if empty string, will use File Open dialog
%
% OUTPUT:
%   filter - array of filter values (0 or 1)
%   n - number of channels

if nargin ~= 1
    error 'expected 1 input argument';
end

[ filename, isPl2 ] = internalPL2ResolveFilenamePlx( filename );
if isPl2 == 1
    pl2 = PL2GetFileIndex(filename);
    n = numel(pl2.SpikeChannels);
    if n > 0
        filters = zeros(n,1);
    end
    return
end

[n,filters] = mexPlex(10, filename);

end


classdef StateSpaceModelX < BaseX & dynamicprops
% StateSpaceModelX Abstract class
%
% Summary of StateSpaceModelX:
%  This is the base class for all TrackingX state-space models.
%  State-space model is effectivevely a container that brings together and
%  provides a common interface to all underlying models
%
% StateSpaceModelX Properties:
%   - Transition     Object handle to a TransitionModelX subclass
%   - Measurement    Object handle to an MeasurementModelX subclass
%   - Control        Object handle to a ControlModelX subclass
%   - Clutter        Object handle to a ClutterModelX subclass
%   - Detection      Object handle to an DetectionModelX subclass
%   - Birth          Object handle to a BirthModelX subclass
%
% StateSpaceModelX Methods:
%    StateSpaceModelX    - Constructor method
%
% See also TransitionModelX, MeasurementModelX and ControlModel template classes
%
% January 2018 Lyudmil Vladimirov, University of Liverpool.

    properties
        Transition
        Measurement
        Control
        Clutter
        Birth
        Detection
    end

    methods
        function this = StateSpaceModelX(varargin)
        % STATESPACEMODEL Constructor method
        %
        % Parameters
        % ==========
        % Transition: TransitionModelX subclass object handle
        %   A transition model
        % Measurement: MeasurementModelX subclass object handle
        %   A measurement model
        % Control: ControlModelX subclass object handle, optional
        %
        % Usage
        % =====
        % * StateSpaceModelX(ssm,Transition,Measurement) configures and returns the object
        %   ssm given the preconfigured transition and measurement models.
        % * StateSpaceModelX(config); where "config" is a structure MUST contain
        %   the required fields "config.Transition" and "config.Measurement" as objects
        %   handles, while it can optionally contain "config.Control"
        % * StateSpaceModelX(___,Name,Value) instantiates an object
        %   handle, configured with options specified by one or more Name,Value
        %   pair arguments.
        %
        %  See also TransitionModelX, MeasurementModelX and ControlModel.

            if(nargin==0)
                return;
            end

            % First check to see if a structure was received
            if(nargin==1)
                if(isstruct(varargin{1}))
                    if (isfield(varargin{1},'Transition'))
                        this.Transition = varargin{1}.Transition;
                    end
                    if (isfield(varargin{1},'Measurement'))
                        this.Measurement = varargin{1}.Measurement;
                    end
                    if (isfield(varargin{1},'Control'))
                        this.Control = varargin{1}.Control;
                    end
                    if (isfield(varargin{1},'Clutter'))
                        this.Clutter = varargin{1}.Clutter;
                    end
                    if (isfield(varargin{1},'Birth'))
                        this.Birth = varargin{1}.Birth;
                    end
                    if (isfield(varargin{1},'Detection'))
                        this.Detection = varargin{1}.Detection;
                    end
                end
                return;
            end

            % Otherwise, fall back to input parser
            parser = inputParser;
            parser.KeepUnmatched = true;
            parser.addOptional('Transition',[]);%, @(x) isa(x,'TransitionModelX'));
            parser.addOptional('Measurement',[]); %, @(x) isa(x,'MeasurementModelX'));
            parser.addParameter('Control',[]);
            parser.addParameter('Clutter',[]);
            parser.addParameter('Birth',[]);
            parser.addParameter('Detection',[]);
            parser.parse(varargin{:});

            this.Transition = parser.Results.Transition;
            this.Measurement = parser.Results.Measurement;
            this.Clutter = parser.Results.Clutter;
            this.Birth = parser.Results.Birth;
            this.Detection = parser.Results.Detection;
        end
    end
end


function transition_net_multi(varargin)

opts.expDir = fullfile('../data','DCFNet-net-7') ;
opts = vl_argparse(opts, varargin);

modelPath = dir(fullfile(opts.expDir, 'net-epoch-*.mat'));
modelPath = sort({modelPath.name});

[~,out_name,~] = fileparts(opts.expDir);

for i = 1:numel(modelPath)
    load(fullfile(opts.expDir, modelPath{i}));
    net = dagnn.DagNN.loadobj(net) ;
    net = deployDCFNet(net);
    if ~exist('../model_multi', 'dir')
        mkdir('../model_multi');
    end
    save(fullfile('../model_multi', [out_name num2str(i, 'epoch_%d.mat')]), 'net') ;
end
end


function varargout=mvtest(varargin)
%EIG (overloaded)

switch class(varargin{1})

    case 'double'
        varargout{1} = sum(varargin{1}.^2,2);

    case 'sdpvar' % Overloaded operator for SDPVAR objects. Pass on args and save them.

        x = varargin{1};
        y = yalmip('definemulti',mfilename,x,[size(x,1) 1]);
        varargout{1} = y;

    case 'char'

        X = varargin{3};

        operator = struct('convexity','convex','monotonicity','none','definiteness','none','model','callback');

        varargout{1} = [];
        varargout{2} = operator;
        varargout{3} = X;

    otherwise
        error('Strange type on first argument in SDPVAR/SORT');
end


function conf = voc_config_inriaperson()
% Configuration used for training the INRIA person model
%
% To use this execute:
%  >> global VOC_CONFIG_OVERRIDE;
%  >> VOC_CONFIG_OVERRIDE = @voc_config_inriaperson;

% SEE: INRIA/README for more details

% AUTORIGHTS
% -------------------------------------------------------
% Copyright (C) 2011-2012 Ross Girshick
%
% This file is part of the voc-releaseX code
% (http://people.cs.uchicago.edu/~rbg/latent/)
% and is available under the terms of an MIT-like license
% provided in COPYING. Please retain this notice and
% COPYING if you use this file (or a portion of it) in
% your project.
% -------------------------------------------------------

conf.training.C = 0.006;


function checkroot(a,b)
% CHECKROOT checks that the root members of a&b are the same

if isempty(a.root)|isempty(b.root), return, end
if (length(a.root)~=length(b.root))|any(a.root~=b.root)
   error('adiff objects must come from the same root')
end


%GEOM_CLEAN Cleanup geometry objects.
%
%   [ SOUT ] = GEOM_CLEAN( SIN, BREP2BIN ) Cleans geometry (objects)
%   in SIN by removing polygon data only used for visualization (for
%   BIN, BREP, STEP, and IGES geometry object types). If the BREP2BIN
%   flag is set (default true) ascii brep data is converted to binary
%   format.

% Copyright 2013-2022 Precise Simulation, Ltd.


% std_readdata() - LEGACY FUNCTION, SHOULD NOT BE USED ANYMORE. INSTEAD
%                  USE std_readerp, std_readspec, ...
%                  load one or more requested measures
%                  ['erp'|'spec'|'ersp'|'itc'|'dipole'|'map']
%                  for all components of a specified cluster.
%                  Called by cluster plotting functions
%                  std_envtopo(), std_erpplot(), std_erspplot(), ...
% Usage:
%         >> [STUDY, clustinfo, finalinds] = std_readdata(STUDY, ALLEEG);
%                                              % return all measures
%         >> [STUDY, clustinfo, finalinds] = std_readdata(STUDY, ALLEEG, ...
%                                              cluster, infotype,varargin);
% Inputs:
%       STUDY - studyset structure containing some or all files in ALLEEG
%      ALLEEG - vector of loaded EEG datasets
%
% Optional inputs:
%  'infotype'  - ['erp'|'spec'|'ersp'|'itc'|'dipole'|'map'|'data'|'event']
%                type of stored data or cluster information to read. May
%                also be a cell array of these types, for example: { 'erp'
%                'map' 'dipole' }. {default: 'erp'}
%  'channels'  - [cell] list of channels to import {default: all}
%  'clusters'  - [integer] list of clusters to import {[]|default: all but
%                the parent cluster (1) and any 'NotClust' clusters}
%  'freqrange' - [min max] frequency range {default: whole measure range}
%  'timerange' - [min max] time range {default: whole measure epoch}
%  'statmode'  - ['individual'|'trials'] statistical mode for ERSP (also
%                specify what type of data to import -- mean (of individual
%                subjects), or trials. This functionality is still unstable
%                for 'trials' { default: 'individual'}
%  'rmsubjmean' - ['on'|'off'] remove mean subject spectrum from every component
%                 or channel spectrum, making them easier to compare
%                 { default: 'off' }
%  'subbaseline' - ['on'|'off'] remove all condition and spectrum baselines
%                  for ERSP data { default: 'on' }
%
% Optional inputs for events:
%  'type','timewin','fieldname' - optional parameters for the function
%                  eeg_geteventepoch may also be used to select specific
%                  events.
%
% Optional inputs for raw data:
%  'rmclust'  - [integer] list of artifact cluster indices to subtract
%               when reading raw data.
%
% Output:
%    STUDY     - (possibly) updated STUDY structure
%    clustinfo - structure of specified cluster information.
%                This is the same as STUDY.cluster(cluster_number)
%    Fields:
%     clustinfo.erpdata    % (ncomps, ntimes) array of component ERPs
%     clustinfo.erptimes   % vector of ERP epoch latencies (ms)
%
%     clustinfo.specdata   % (ncomps, nfreqs) array of component spectra
%     clustinfo.specfreqs  % vector of spectral frequencies (Hz)
%
%     clustinfo.erspdata   % (ncomps,ntimes,nfreqs) array of component ERSPs
%      clustinfo.ersptimes % vector of ERSP latencies (ms)
%      clustinfo.erspfreqs % vector of ERSP frequencie (Hz)
%
%     clustinfo.itcdata    % (ncomps,ntimes,nfreqs) array of component ITCs
%      clustinfo.itctimes  % vector of ITC latencies (ms)
%      clustinfo.itc_freqs % vector of ITC frequencies (Hz)
%
%     clustinfo.topo       % (ncomps,65,65) array of component scalp map grids
%       clustinfo.topox    % abscissa values for columns of the scalp maps
%       clustinfo.topoy    % ordinate values for rows of the scalp maps
%
%     clustinfo.data           % raw data arrays
%       clustinfo.datatimes    % time point for raw data
%       clustinfo.datasortvals % sorting values (one per trial)
%       clustinfo.datacontinds % dataset indices (contacted for all trials)
%
%     clustinfo.dipole     % array of component dipole information structs
%                          % with the same format as EEG.dipfit.model
%
%   finalinds - either the cluster(s) or channel(s) indices selected.
%
% Example:
%         % To obtain the ERPs for all Cluster-3 components from a STUDY
%         %
%         [STUDY clustinfo] = std_readdata(STUDY, ALLEEG, 'clusters',3, 'infotype','erp');
%         figure; plot(clustinfo.erptimes, mean(clustinfo.erpdata,2));
%
% Author: Arnaud Delorme, CERCO, 2006-

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

function [STUDY, clustinfo, finalinds] = std_readdata(STUDY, ALLEEG, varargin);

if nargin < 2
    help std_readdata;
    return;
end
if nargin < 3
    channel = {};
end

[opt moreopts] = finputcheck( varargin, { ...
    'type'       { 'string' 'cell' } { [] [] } '';
    'timewin'    'real'    []        [-Inf Inf];
    'fieldname'  'string'  []        'latency';
    'condition'  'cell'    []       {};
    'channels'   'cell'    []       {};
    'clusters'   'integer' []       [];
    'rmclust'    'integer' []       [];
    'freqrange'  'real'    []       [];
    'timerange'  'real'    []       [];
    'statmode'   'string'  { 'subjects' 'individual' 'common' 'trials' }       'individual';
    'rmicacomps'   'string'  { 'on' 'off' }       'off';
    'subbaseline'  'string'  { 'on' 'off' }       'off';
    'rmsubjmean'   'string'  { 'on' 'off' }       'off';
    'singletrials' 'string'  { 'on' 'off' }       'on';
    'infotype'   'string'  { 'erp' 'spec' 'ersp' 'itc' 'map' 'topo' 'dipole' 'scalp' 'data' 'event' '' } '' }, ...
    'std_readdata', 'ignore');
if isstr(opt), error(opt); end;
if isempty(opt.infotype), disp('No measure selected, returning ERPs'); opt.infotype = 'erp'; end;

if strcmpi(opt.infotype, 'erp'),
    STUDY = pop_erpparams(STUDY, 'default');
    if isempty(opt.timerange), opt.timerange = STUDY.etc.erpparams.timerange; end;
elseif strcmpi(opt.infotype, 'spec'),
    STUDY = pop_specparams(STUDY, 'default');
    if isempty(opt.freqrange), opt.freqrange = STUDY.etc.specparams.freqrange; end;
elseif strcmpi(opt.infotype, 'ersp') | strcmpi(opt.infotype, 'itc')
    STUDY = pop_erspparams(STUDY, 'default');
    if isempty(opt.freqrange), opt.freqrange   = STUDY.etc.erspparams.freqrange; end;
    if isempty(opt.timerange), opt.timerange   = STUDY.etc.erspparams.timerange; end;
    if strcmpi(opt.statmode, 'individual') |  strcmpi(opt.statmode, 'subjects'), opt.statmode    = STUDY.etc.erspparams.statmode;end;
    if strcmpi(opt.subbaseline, 'on'),      opt.subbaseline = STUDY.etc.erspparams.subbaseline; end;
end;

nc = max(length(STUDY.condition),1);
ng = max(length(STUDY.group),1);
zero = single(0);
tmpver = version;
if tmpver(1) == '6' | tmpver(1) == '5'
    zero = double(zero);
end;

% find channel indices
% --------------------
if ~isempty(opt.channels)
    finalinds = std_chaninds(STUDY, opt.channels);
else
    finalinds = opt.clusters;
end;

% read topography with another function
% -------------------------------------
if strcmpi(opt.infotype, 'map') | strcmpi(opt.infotype, 'scalp') | strcmpi(opt.infotype, 'topo')
    [STUDY tmpclust] = std_readtopoclust(STUDY, ALLEEG, opt.clusters);
    clustinfo = [];
    for index = 1:length(tmpclust)
        if index == 1, clustinfo        = tmpclust{index};
        else           clustinfo(index) = tmpclust{index};
        end;
    end;
    return;
end;

% read indices for removing component clusters from data
% ------------------------------------------------------
% NOT USED ANY MORE
if ~isempty(opt.rmclust)
    for ind = 1:length(opt.rmclust)
        [tmp setindsrm{ind} allindsrm{ind}] = std_setinds2cell(STUDY, opt.rmclust(ind));
    end;
end;

for ind = 1:length(finalinds)

    % find indices
    % ------------
    if ~isempty(opt.channels)
        tmpstruct = STUDY.changrp(finalinds(ind));
        alldatasets = 1:length(STUDY.datasetinfo);
        %allchanorcomp = -tmpstruct.chaninds;
        allinds       = tmpstruct.allinds;
        for i=1:length(allinds(:)), allinds{i} = -allinds{i}; end; % invert sign for reading
        setinds       = tmpstruct.setinds;
    else
        % Use the 3 lines below and comment the last one when ready
        % to switch and remove all .comps and .inds
        %tmpstruct = STUDY.cluster(finalinds(ind));
        %allinds = tmpstruct.allinds;
        %setinds = tmpstruct.setinds;
        [ tmpstruct setinds allinds ] = std_setcomps2cell(STUDY, finalinds(ind));
        %[ STUDY.cluster(finalinds(ind)) ] = std_setcomps2cell(STUDY, finalinds(ind));
        %STUDY.cluster(finalinds(ind))     = std_cell2setcomps( STUDY, ALLEEG, finalinds(ind));
        %[ STUDY.cluster(finalinds(ind)) setinds allinds ] = std_setcomps2cell(STUDY, finalinds(ind));
    end;

    dataread = 0;
    switch opt.infotype
        case 'event',
            % check if data is already here
            % -----------------------------
            if isfield(tmpstruct, 'datasortvals')
                if ~isempty(tmpstruct.datasortvals)
                    dataread = 1;
                end;
            end;

            if ~dataread
                % reserve arrays
                % --------------
                datasortvals   = cell( max(length(STUDY.condition),1), max(length(STUDY.group),1) );
                datacontinds    = cell( max(length(STUDY.condition),1), max(length(STUDY.group),1) );
                for c = 1:nc
                    for g = 1:ng
                        datasortvals{c, g} = repmat(zero, [1, sum([ ALLEEG(setinds{c,g}).trials ] )]);
                        datacontinds{c, g} = repmat(zero, [1, sum([ ALLEEG(setinds{c,g}).trials ] )]);
                    end;
                end;

                % read the data and select channels
                % ---------------------------------
                if ~isempty(opt.type)
                    fprintf('Reading events:');
                    for c = 1:nc
                        for g = 1:ng
                            counttrial = 1;
                            for indtmp = 1:length(allinds{c,g})
                                tmpdata  = eeg_getepochevent(ALLEEG(setinds{c,g}(indtmp)), ...
                                    'type', opt.type, 'timewin', opt.timewin, 'fieldname', opt.fieldname);
                                datasortvals{c, g}(:,counttrial:counttrial+ALLEEG(setinds{c,g}(indtmp)).trials-1) = squeeze(tmpdata);
                                datacontinds{c, g}(:,counttrial:counttrial+ALLEEG(setinds{c,g}(indtmp)).trials-1) = setinds{c,g}(indtmp);
                                counttrial = counttrial+ALLEEG(setinds{c,g}(indtmp)).trials;
                                fprintf('.');
                            end;
                        end;
                    end;
                end;
                fprintf('\n');
                tmpstruct.datasortvals = datasortvals;
                tmpstruct.datacontinds = datacontinds;
            end;

        case 'data',
            % check if data is already here
            % -----------------------------
            if isfield(tmpstruct, 'data')
                if ~isempty(tmpstruct.data)
                    dataread = 1;
                end;
            end;

            if ~dataread
                % reserve arrays
                % --------------
                alldata   = cell( max(length(STUDY.condition),1), max(length(STUDY.group),1) );
                for c = 1:nc
                    for g = 1:ng
                        alldata{c, g} = repmat(zero, [ALLEEG(1).pnts, sum([ ALLEEG(setinds{c,g}).trials ] )]);
                    end;
                end;

                % read the data and select channels
                % ---------------------------------
                fprintf('Reading data/activity:');
                for c = 1:nc
                    for g = 1:ng
                        counttrial = 1;
                        for indtmp = 1:length(allinds{c,g})
                            settmpind = STUDY.datasetinfo(setinds{c,g}(indtmp)).index; % current dataset

                            if isempty(opt.channels)
                                tmpdata = eeg_getdatact(ALLEEG(settmpind), 'component', allinds{c,g}(indtmp), 'verbose', 'off');
                            elseif isempty(opt.rmclust) & strcmpi(opt.rmicacomps, 'off')
                                tmpdata = eeg_getdatact(ALLEEG(settmpind),  'channel', -allinds{c,g}(indtmp), 'verbose', 'off');
                            elseif strcmpi(opt.rmicacomps, 'on')
                                rmcomps = find(ALLEEG(settmpind).reject.gcompreject);
                                tmpdata = eeg_getdatact(ALLEEG(settmpind),  'channel', -allinds{c,g}(indtmp), 'rmcomps', rmcomps, 'verbose', 'off');
                            else
                                rmcomps = getclustcomps(STUDY, opt.rmclust, settmpind);
                                tmpdata = eeg_getdatact(ALLEEG(settmpind),  'channel', -allinds{c,g}(indtmp), 'rmcomps', rmcomps, 'verbose', 'off');
                            end;

                            alldata{c, g}(:,counttrial:counttrial+ALLEEG(setinds{c,g}(indtmp)).trials-1) = squeeze(tmpdata);
                            counttrial = counttrial+ALLEEG(setinds{c,g}(indtmp)).trials;
                            fprintf('.');
                        end;
                    end;
                end;
                fprintf('\n');
                tmpstruct.datatimes = ALLEEG(1).times;
                tmpstruct.data      = alldata;
            end;

        case 'erp',
            disp('std_readdata is a legacy function, it should not be used to read ERP data, use std_readerp instead');

            % check if data is already here
            % -----------------------------
            if isfield(tmpstruct, 'erpdata')
                if isequal( STUDY.etc.erpparams.timerange, opt.timerange) & ~isempty(tmpstruct.erpdata)
                    dataread = 1;
                end;
            end;

            if ~dataread
                % reserve arrays
                % --------------
                allerp   = cell( max(length(STUDY.condition),1), max(length(STUDY.group),1) );
                tmpind = 1; while(isempty(setinds{tmpind})), tmpind = tmpind+1; end;
                [ tmp alltimes ] = std_readerp( ALLEEG, setinds{tmpind}(1), allinds{tmpind}(1), opt.timerange);
                for c = 1:nc
                    for g = 1:ng
                        allerp{c, g} = repmat(zero, [length(alltimes), length(allinds{c,g})]);
                    end;
                end;

                % read the data and select channels
                % ---------------------------------
                fprintf('Reading ERP data:');
                for c = 1:nc
                    for g = 1:ng
                        for indtmp = 1:length(allinds{c,g})
                            [ tmperp alltimes ] = std_readerp( ALLEEG, setinds{c,g}(indtmp), allinds{c,g}(indtmp), opt.timerange);
                            allerp{c, g}(:,indtmp) = tmperp(:);
                            fprintf('.');
                        end;
                    end;
                end;
                fprintf('\n');
                tmpstruct.erptimes = alltimes;
                tmpstruct.erpdata  = allerp;
            end;

        case 'spec',
            disp('std_readdata is a legacy function, it should not be used to read SPECTRUM data, use std_readspec instead');
            % check if data is already here
            % -----------------------------
            if isfield(tmpstruct, 'specdata')
                if isequal( STUDY.etc.specparams.freqrange, opt.freqrange) & ~isempty(tmpstruct.specdata)
                    dataread = 1;
                end;
            end;

            if ~dataread
                % reserve arrays
                % --------------
                allspec  = cell( max(length(STUDY.condition),1), max(length(STUDY.group),1) );
                filetype = 'spec';
                tmpind = 1; while(isempty(setinds{tmpind})), tmpind = tmpind+1; end;
                try,
                    [ tmp allfreqs ] = std_readspec( ALLEEG, setinds{tmpind}(1), allinds{tmpind}(1), opt.freqrange);
                catch
                    filetype = 'ersp';
                    disp('Cannot find spectral file, trying ERSP baseline file instead');
                    [ tmpersp allfreqs alltimes tmpparams tmpspec] = std_readersp( ALLEEG, setinds{tmpind}(1), allinds{tmpind}(1), [], opt.freqrange);
                end;
                for c = 1:nc
                    for g = 1:ng
                        allspec{c, g} = repmat(zero, [length(allfreqs), length(allinds{c,g}) ]);
                    end;
                end;

                % read the data and select channels
                % ---------------------------------
                if strcmpi(filetype, 'spec')
                    fprintf('Reading Spectrum data...');
                    for c = 1:nc
                        for g = 1:ng
                            allspec{c, g} = std_readspec( ALLEEG, setinds{c,g}(:), allinds{c,g}(:), opt.freqrange)';
                        end;
                    end;
                else % std_readersp cannot be converted to read multiple datasets since it subtracts data between conditions
                    fprintf('Reading Spectrum data:');
                    for c = 1:nc
                        for g = 1:ng
                            for indtmp = 1:length(allinds{c,g})
                                [ tmpersp allfreqs alltimes tmpparams tmpspec] = std_readersp( ALLEEG, setinds{c,g}(indtmp), allinds{c,g}(indtmp), [], opt.freqrange);
                                allspec{c, g}(:,indtmp) = 10*log(tmpspec(:));
                                fprintf('.');
                            end;
                        end;
                    end;
                end;
                fprintf('\n');

                % remove mean of each subject across groups and conditions
                if strcmpi(opt.rmsubjmean, 'on') & ~isempty(opt.channels)
                    disp('Removing mean spectrum accross subjects');
                    for indtmp = 1:length(allinds{c,g}) % scan subjects
                       meanspec =zeros(size( allspec{1, 1}(:,indtmp) ));
                       for c = 1:nc
                            for g = 1:ng
                                meanspec = meanspec + allspec{c, g}(:,indtmp)/(nc*ng);
                            end;
                       end;
                       for c = 1:nc
                            for g = 1:ng
                                allspec{c, g}(:,indtmp) = allspec{c, g}(:,indtmp) - meanspec; % subtractive model
                                % allspec{c, g}(:,indtmp) = allspec{c, g}(:,indtmp)./meanspec; % divisive model
                            end;
                       end;
                    end;
                end;

                tmpstruct.specfreqs = allfreqs;
                tmpstruct.specdata  = allspec;
            end;

        case { 'ersp' 'itc' 'pac' },
            disp('std_readdata is a legacy function, it should not be used to read ERSP/ITC data, use std_readersp instead');
            % check if data is already here
            % -----------------------------
            if strcmpi(opt.infotype, 'ersp')
                if isfield(tmpstruct, 'erspdata')
                    if isequal( STUDY.etc.erspparams.timerange, opt.timerange) & ...
                            isequal( STUDY.etc.erspparams.freqrange, opt.freqrange) & ~isempty(tmpstruct.erspdata)
                        dataread = 1;
                    end;
                end;
            elseif strcmpi(opt.infotype, 'itc')
                if isfield(tmpstruct, 'itcdata')
                    if isequal( STUDY.etc.erspparams.timerange, opt.timerange) & ...
                            isequal( STUDY.etc.erspparams.freqrange, opt.freqrange) & ~isempty(tmpstruct.itcdata)
                        dataread = 1;
                    end;
                end;
            else
                if isfield(tmpstruct, 'pacdata')
                    dataread = 1;
                end;
            end;

            if ~dataread
                % find total nb of trials
                % -----------------------
                if strcmpi(opt.statmode, 'trials')
                    tottrials = cell( length(STUDY.condition), length(STUDY.group) );
                    for index = 1:length( STUDY.datasetinfo )
                        condind = strmatch( STUDY.datasetinfo(index).condition, STUDY.condition );
                        grpind  = strmatch( STUDY.datasetinfo(index).group    , STUDY.group     );
                        if isempty(tottrials{condind, grpind}), tottrials{condind, grpind} = ALLEEG(index).trials;
                        else       tottrials{condind, grpind} = tottrials{condind, grpind} + ALLEEG(index).trials;
                        end;
                    end;
                end;

                % reserve arrays
                % --------------
                ersp     = cell( max(length(STUDY.condition),1), max(length(STUDY.group),1) );
                erspbase = cell( max(length(STUDY.condition),1), max(length(STUDY.group),1) );
                erspinds = cell( max(length(STUDY.condition),1), max(length(STUDY.group),1) );
                tmpind = 1; while(isempty(setinds{tmpind})), tmpind = tmpind+1; end;
                [ tmp allfreqs alltimes ] = std_readersp( ALLEEG, setinds{tmpind}(1), Inf*allinds{tmpind}(1), opt.timerange, opt.freqrange);
                for c = 1:nc
                    for g = 1:ng
                        ersp{c, g}     = repmat(zero, [length(alltimes), length(allfreqs), length(allinds{c,g}) ]);
                        erspbase{c, g} = repmat(zero, [               1, length(allfreqs), length(allinds{c,g}) ]);
                        if strcmpi(opt.statmode, 'trials')
                            ersp{ c, g} = repmat(zero, [length(alltimes), length(allfreqs), tottrials{c, g} ]);
                            count{c, g} = 1;
                        end;
                    end;
                end;

                % read the data and select channels
                % ---------------------------------
                fprintf('Reading all %s data:', upper(opt.infotype));
                for c = 1:nc
                    for g = 1:ng
                        for indtmp = 1:length(allinds{c,g})
                            try     % this 'try' is a poor solution the problem of attempting
                                % to read specific channel/component data that doesn't exist
                                % called below by: allinds{c,g}(indtmp)
                                if strcmpi(opt.statmode, 'trials')
                                    [ tmpersp allfreqs alltimes tmpparams] = std_readtimef( ALLEEG, setinds{c,g}(indtmp), allinds{c,g}(indtmp), ...
                                        opt.timerange, opt.freqrange);
                                    indices = [count{c, g}:count{c, g}+size(tmpersp,3)-1];
                                    ersp{    c, g}(:,:,indices) = permute(tmpersp, [2 1 3]);
                                    erspinds{c, g}(1:2,indtmp) = [ count{c, g} count{c, g}+size(tmpersp,3)-1 ];
                                    count{c, g} = count{c, g}+size(tmpersp,3);
                                    if size(tmpersp,3) ~= ALLEEG(STUDY.datasetinfo(index).index).trials
                                        error( sprintf('Wrong number of trials in datafile for dataset %d\n', STUDY.datasetinfo(index).index));
                                    end;
                                elseif strcmpi(opt.infotype, 'itc')
                                    [ tmpersp allfreqs alltimes tmpparams] = std_readitc( ALLEEG, setinds{c,g}(indtmp), allinds{c,g}(indtmp), ...
                                        opt.timerange, opt.freqrange);
                                    ersp{c, g}(:,:,indtmp)     = abs(permute(tmpersp    , [2 1]));
                                elseif strcmpi(opt.infotype, 'pac')
                                    [ tmpersp allfreqs alltimes tmpparams] = std_readpac( ALLEEG, setinds{c,g}(indtmp), allinds{c,g}(indtmp), ...
                                        opt.timerange, opt.freqrange);
                                    ersp{c, g}(:,:,indtmp)     = abs(permute(tmpersp    , [2 1]));
                                else
                                    [ tmpersp allfreqs alltimes tmpparams tmperspbase] = std_readersp( ALLEEG, setinds{c,g}(indtmp), allinds{c,g}(indtmp), ...
                                        opt.timerange, opt.freqrange);
                                    ersp{c, g}(    :,:,indtmp) = permute(tmpersp    , [2 1]);
                                    erspbase{c, g}(:,:,indtmp) = 10*log(permute(tmperspbase, [2 1]));
                                end
                            catch
                            end
                            fprintf('.');
                        end;
                    end;
                end;
                fprintf('\n');

                % compute ERSP or ITC if trial mode
                % (since only the timef have been loaded)
                % ---------------------------------------
                if strcmpi(opt.statmode, 'trials')
                    for c = 1:nc
                        for g = 1:ng
                            if strcmpi(opt.infotype, 'itc')
                                ersp{c,g} = ersp{c,g}./abs(ersp{c,g});
                            else
                                ersp{c,g} = 20*log10(abs(ersp{c,g}));
                                % remove baseline (each trial baseline is removed => could
                                % also be the average across all data trials)
                                [tmp indl] = min( abs(alltimes-0) );
                                erspbase{c,g} = mean(ersp{c,g}(1:indl,:,:,:));
                                ersp{c,g} = ersp{c,g} - repmat(erspbase{c,g}, [size(ersp{c,g},1) 1 1 1]);
                            end;
                        end;
                    end;
                end;

                % compute average baseline across groups and conditions
                % -----------------------------------------------------
                if strcmpi(opt.subbaseline, 'on') & strcmpi(opt.infotype, 'ersp')
                    disp('Recomputing baseline...');
                    for g = 1:ng        % ng = number of groups
                        for c = 1:nc    % nc = number of components
                            if strcmpi(opt.statmode, 'trials')
                                if c == 1, meanpowbase = abs(mean(erspbase{c,g}/nc,3));
                                else       meanpowbase = meanpowbase + abs(mean(erspbase{c,g}/nc,3));
                                end;
                            else
                                if c == 1, meanpowbase = abs(erspbase{c,g}/nc);
                                else       meanpowbase = meanpowbase + abs(erspbase{c,g}/nc);
                                end;
                            end;
                        end;

                        % subtract average baseline
                        % -------------------------
                        for c = 1:nc
                            if strcmpi(opt.statmode, 'trials'), tmpmeanpowbase = repmat(meanpowbase, [length(alltimes) 1 tottrials{c,g}]);
                            else                                tmpmeanpowbase = repmat(meanpowbase, [length(alltimes) 1 1]);
                            end;
                            ersp{c,g} = ersp{c,g} - repmat(abs(erspbase{c,g}), [length(alltimes) 1 1 1]) + tmpmeanpowbase;
                        end;
                        clear meanpowbase;
                    end;
                end;

                if strcmpi(opt.statmode, 'common')
                    % collapse the two last dimensions before computing significance
                    % i.e. 18 subject with 4 channels -> same as 4*18 subjects
                    % --------------------------------------------------------------
                    disp('Using all channels for statistics...');
                    for c = 1:nc
                        for g = 1:ng
                            ersp{c,g} = reshape( ersp{c,g}, size(ersp{c,g},1), size(ersp{c,g},2), size(ersp{c,g},3)*size(ersp{c,g},4));
                        end;
                    end;
                end;

                % copy data to structure
                % ----------------------
                if strcmpi(opt.infotype, 'ersp')
                    tmpstruct.erspfreqs = allfreqs;
                    tmpstruct.ersptimes = alltimes;
                    tmpstruct.erspdata  = ersp;
                    tmpstruct.erspbase  = erspbase;
                    if strcmpi(opt.statmode, 'trials')
                        tmpstruct.erspsubjinds  = erspinds;
                    end;
                elseif strcmpi(opt.infotype, 'itc')
                    tmpstruct.itcfreqs = allfreqs;
                    tmpstruct.itctimes = alltimes;
                    tmpstruct.itcdata  = ersp;
                    if strcmpi(opt.statmode, 'trials')
                        tmpstruct.itcsubjinds  = erspinds;
                    end;
                else
                    tmpstruct.pacfreqs = allfreqs;
                    tmpstruct.pactimes = alltimes;
                    tmpstruct.pacdata  = ersp;
                end;
            end;
        case 'dipole',
            fprintf('Reading dipole data...\n');
%           old format EEGLAB 8.3
%             alldips = {};
%             for c = 1:nc
%                 for g = 1:ng
%                     for indtmp = 1:size(tmpstruct.sets,2)
%                         alldips{c, g}(indtmp).posxyz = ALLEEG(tmpstruct.sets(1,indtmp)).dipfit.model(tmpstruct.comps(1,indtmp)).posxyz;
%                         alldips{c, g}(indtmp).momxyz = ALLEEG(tmpstruct.sets(1,indtmp)).dipfit.model(tmpstruct.comps(1,indtmp)).momxyz;
%                         alldips{c, g}(indtmp).rv     = ALLEEG(tmpstruct.sets(1,indtmp)).dipfit.model(tmpstruct.comps(1,indtmp)).rv;
%                     end;
%                 end;
%             end;
%            tmpstruct.dipoles = alldips;
            alldips = [];
            for indtmp = 1:size(tmpstruct.sets,2)
                alldips(indtmp).posxyz = ALLEEG(tmpstruct.sets(1,indtmp)).dipfit.model(tmpstruct.comps(1,indtmp)).posxyz;
                alldips(indtmp).momxyz = ALLEEG(tmpstruct.sets(1,indtmp)).dipfit.model(tmpstruct.comps(1,indtmp)).momxyz;
                alldips(indtmp).rv     = ALLEEG(tmpstruct.sets(1,indtmp)).dipfit.model(tmpstruct.comps(1,indtmp)).rv;
            end;
            tmpstruct.alldipoles = alldips;

        case { 'map' 'scalp' 'topo' }
            % this is currenlty being done by the function std_readtopoclust
            % at the beginning of this function
        otherwise, error('Unrecognized ''infotype'' entry');
    end; % end switch

    % copy results to structure
    % -------------------------
    fieldnames = { 'erpdata' 'erptimes' 'specdata' 'specfreqs' 'erspdata' 'erspbase' 'erspfreqs' 'ersptimes' ...
        'itcfreqs' 'itctimes' 'itcdata' 'erspsubjinds' 'itcsubjinds' 'allinds' 'setinds' 'dipoles' 'alldipoles' ...
        'data' 'datatimes' 'datasortvals' 'datacontinds' };
    for f = 1:length(fieldnames)
        if isfield(tmpstruct, fieldnames{f}),
            tmpdata = getfield(tmpstruct, fieldnames{f});
            if ~isempty(opt.channels)
                STUDY.changrp = setfield(STUDY.changrp, { finalinds(ind) }, fieldnames{f}, tmpdata);
            else STUDY.cluster = setfield(STUDY.cluster, { finalinds(ind) }, fieldnames{f}, tmpdata);
            end;
        end;
    end;
end;

% return structure
% ----------------
if ~isempty(opt.channels)
    clustinfo = STUDY.changrp(finalinds);
else clustinfo = STUDY.cluster(finalinds);
end;

% find components in cluster for specific dataset
% -----------------------------------------------
function rmcomps = getclustcomps(STUDY, rmclust, settmpind);

rmcomps   = [ ];
for rmi = 1:length(rmclust)
    findind   = find(settmpind == STUDY.cluster(rmclust(rmi)).setinds{c,g});
    rmcomps   = [ rmcomps STUDY.cluster(rmclust(rmi)).allinds{c,g}(findind) ];
end;


classdef LaunchVehicleViewProfileVectorData < matlab.mixin.SetGet
    %LaunchVehicleViewProfileVectorData Summary of this class goes here
    %   Detailed explanation goes here

    properties
        %these are for vehicle trajectory data and not the point itself!
        timesArr(1,:) cell = {};
        xInterps(1,:) cell = {};
        yInterps(1,:) cell = {};
        zInterps(1,:) cell = {};
        vxInterps(1,:) cell = {};
        vyInterps(1,:) cell = {};
        vzInterps(1,:) cell = {};

        markerPlot = matlab.graphics.GraphicsPlaceholder.empty(1,0)
        vector AbstractGeometricVector
        viewFrame AbstractReferenceFrame
    end

    methods
        function obj = LaunchVehicleViewProfileVectorData(vector, viewFrame)
            obj.vector = vector;
            obj.viewFrame = viewFrame;
        end

        function addData(obj, times, rVects, vVects)
            obj.timesArr{end+1} = times;

            if(length(times) >= 3)
                method = 'pchip';
            else
                method = 'linear';
            end

            obj.xInterps{end+1} = griddedInterpolant(times, rVects(:,1), method, 'linear');
            obj.yInterps{end+1} = griddedInterpolant(times, rVects(:,2), method, 'linear');
            obj.zInterps{end+1} = griddedInterpolant(times, rVects(:,3), method, 'linear');
            obj.vxInterps{end+1} = griddedInterpolant(times, vVects(:,1), method, 'linear');
            obj.vyInterps{end+1} = griddedInterpolant(times, vVects(:,2), method, 'linear');
            obj.vzInterps{end+1} = griddedInterpolant(times, vVects(:,3), method, 'linear');
        end

        function plotVectorAtTime(obj, time, hAx)
            [origin, vect] = obj.getVectorAtTime(time);

            if(isempty(obj.markerPlot))
                hold(hAx,'on');
                for(i=1:size(vect,2))
                    obj.markerPlot(i) = quiver3(hAx, origin(1,i),origin(2,i),origin(3,i), vect(1,i),vect(2,i),vect(3,i), 'AutoScale','off', 'Color',obj.vector.lineColor.color, 'LineStyle',obj.vector.lineSpec.linespec);
                end
                hold(hAx,'off');
            else
                for(i=1:size(vect,2))
                    obj.markerPlot(i).XData = origin(1,i);
                    obj.markerPlot(i).YData = origin(2,i);
                    obj.markerPlot(i).ZData = origin(3,i);

                    obj.markerPlot(i).UData = vect(1,i);
                    obj.markerPlot(i).VData = vect(2,i);
                    obj.markerPlot(i).WData = vect(3,i);
                end
            end
        end
    end

    methods(Access=private)
        function [origin, vect] = getVectorAtTime(obj, time)
            origin = [];
            vect = [];
            for(i=1:length(obj.timesArr))
                times = obj.timesArr{i};

                if(time >= min(floor(times)) && time <= max(ceil(times)))
                    xInterp = obj.xInterps{i};
                    x = xInterp(time);

                    yInterp = obj.yInterps{i};
                    y = yInterp(time);

                    zInterp = obj.zInterps{i};
                    z = zInterp(time);

                    vxInterp = obj.vxInterps{i};
                    vx = vxInterp(time);

                    vyInterp = obj.vyInterps{i};
                    vy = vyInterp(time);

                    vzInterp = obj.vzInterps{i};
                    vz = vzInterp(time);

                    vehElemSet = CartesianElementSet(time, [x;y;z], [vx;vy;vz], obj.viewFrame);
                    vect(:,end+1) = obj.vector.getVectorAtTime(time, vehElemSet, obj.viewFrame); %#ok<AGROW>

                    origin(:,end+1) = obj.vector.getOriginPointInViewFrame(time, vehElemSet, obj.viewFrame); %#ok<AGROW>
                end
            end
        end
    end
end


function title = p08_title ( )

%*****************************************************************************80
%
%% P08_TITLE returns the title of problem P08.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string TITLE, the title of the problem.
%
  title = 'Problem 8, Enright and Pryce #B3';

  return
end


function [status,exitflag] = scipRetCode(code)
%Returns Status associated with SCIP Return Code

%Note v3.2.0 some numbers changed! Below as per scip.m
%   Return Status:
%       0 - Unknown
%       1 - User Interrupted
%       2 - Node Limit Reached
%       3 - Total Node Limit Reached
%       4 - Stall Node Limit Reached
%       5 - Time Limit Reached
%       6 - Memory Limit Reached
%       7 - Gap Limit Reached
%       8 - Solution Limit Reached
%       9 - Solution Improvement Limit Reached
%      10 - Restart Limit Reached
%      11 - Problem Solved to Optimality
%      12 - Problem is Infeasible
%      13 - Problem is Unbounded
%      14 - Problem is Either Infeasible or Unbounded

switch(code)
    case 1, status = 'User Exited'; exitflag = -5;
    case 2, status = 'Node Limit Reached'; exitflag = 0;
    case 3, status = 'Total Node Limit Reached'; exitflag = 0;
    case 4, status = 'Stall Node Limit Reached'; exitflag = 0;
    case 5, status = 'Time Limit Reached'; exitflag = 0;
    case 6, status = 'Memory Limit Reached'; exitflag = -4;
    case 7, status = 'Gap Limit Reached'; exitflag = 0;
    case 8, status = 'Solution Limit Reached'; exitflag = 0;
    case 9, status = 'Solution Improvement Limit Reached'; exitflag = 0;
    case 10, status = 'Restart Limit Reached'; exitflag = 0;
    case 11, status = 'Globally Optimal'; exitflag = 1;
    case 12, status = 'Infeasible'; exitflag = -1;
    case 13, status = 'Unbounded'; exitflag = -2;
    case 14, status = 'Unbounded or Infeasible'; exitflag = -2;
    otherwise, status = 'Unknown'; exitflag = -4;
end


function [inputImages,inputTraces,infoStruct, algorithmStr] = loadNeurodataWithoutBorders(inputFilePath,varargin)
	% Load NWB file containing cell-extraction data.
	% Biafra Ahanonu
	% started: 2020.04.04 [15:02:22]
	% inputs
		% inputFilePath - Str: path to NWB file. If a cell, will only load the first string.
	% outputs
		% inputImages - 3D or 4D matrix containing cells and their spatial information, format: [x y nCells].
		% inputSignals - 2D matrix containing activity traces in [nCells nFrames] format.
		% infoStruct - contains information about the file, e.g. the 'description' property that can contain information about the algorithm.
		% algorithmStr - String of the algorithm name.

	% changelog
		% 2021.02.05 [19:02:44] - Parse the algorithm associated with the NWB signal extraction data.
		% 2021.08.08 [19:30:20] - Updated to handle CIAtah v4.0 switch to all functions inside ciapkg package.
	% TODO
		%

	import ciapkg.api.* % import CIAtah functions in ciapkg package API.

	%========================
	% DESCRIPTION
	% cellmax, pcaica, cnmf, cnmfe, extract, roi
	options.algorithm = '';
	% String: main name for image mask group
	options.groupImages = '/processing/ophys/ImageSegmentation/PlaneSegmentation';
	options.planeNo = 1;
	% Dataset name for image masks
	options.imagesName = 'image_mask';
	% String: main name for fluorescence series
	options.groupSignalSeries = '/processing/ophys/Fluorescence/RoiResponseSeries';
	% Cell array of strings: alternative names for fluorescence series
	options.groupSignalSeriesAlt = {'/processing/ophys/Fluorescence/Series','/processing/ophys/Fluorescence/RoiResponseSeries'};
	options.signalsName = 'data';
	% Int: user specified series number if needed
	options.signalSeriesNo = [];
	% 1 = load images, 0 = do not load images (e.g. when user only wants the traces)
	options.loadImages = 1;
	% get options
	options = getOptions(options,varargin);
	% display(options)
	% unpack options into current workspace
	% fn=fieldnames(options);
	% for i=1:length(fn)
	% 	eval([fn{i} '=options.' fn{i} ';']);
	% end
	%========================

	try
		% Check that NWB code is downloaded and setup.
		ciapkg.api.setupNwb('checkDependencies',1);

		inputImages = [];
		inputTraces = [];
		infoStruct = struct;
		algorithmStr = '';

		if iscell(inputFilePath)
			inputFilePath = inputFilePath{1};
		end
		% Return if not a string, return as not appropriate input
		if ~ischar(inputFilePath)
			return;
		end
		try
			imagesGroupName = [options.groupImages num2str(options.planeNo) '/' options.imagesName];
			imagesGroupNameAttr = [options.groupImages num2str(options.planeNo)];
			% Check exist else use different default
			h5info(inputFilePath,imagesGroupName);
		catch
			imagesGroupName = [options.groupImages '/' options.imagesName];
			imagesGroupNameAttr = [options.groupImages];
		end

		if options.loadImages==1
			fprintf('Loading: %s file -> %s.\n',inputFilePath,imagesGroupName);
			inputImages = h5read(inputFilePath,imagesGroupName);
		else
			inputImages = [];
		end

		roitestNames = {options.groupSignalSeries,options.groupSignalSeriesAlt{:}};
		tracesGroupNameFinal = '';
		nNums = 2;
		numList = [1:nNums NaN];
		if ~isempty(options.signalSeriesNo)
			numList = [options.signalSeriesNo numList];
		end
		% Iterate until find the correct name for activity series
		for nameNo = 1:length(roitestNames)
			for seriesNo = numList
				try
					if isnan(seriesNo)==1
						tracesGroupName = [roitestNames{nameNo} '/' options.signalsName];
					else
						tracesGroupName = [roitestNames{nameNo} num2str(seriesNo) '/' options.signalsName];
					end
					% Check exist else use different default
					h5info(inputFilePath,tracesGroupName);
					tracesGroupNameFinal = tracesGroupName;
				catch
				end
			end
		end
		fprintf('Loading: %s file -> %s.\n',inputFilePath,tracesGroupNameFinal);
		inputTraces = h5read(inputFilePath,tracesGroupNameFinal);

		disp(['inputImages: ' num2str(size(inputImages))]);
		disp(['inputTraces: ' num2str(size(inputTraces))]);

		% Get description if later need cell-extraction information
		tmp = h5readatt(inputFilePath,imagesGroupNameAttr,'description');
		infoStruct.description = tmp;

		% Check if extraction method in infoStruct then add
		try
			if isfield(infoStruct,'description')
				tmpStr = regexp(infoStruct.description,'Extraction method: \w+','match');
				try
					tmpStr = strsplit(tmpStr{1}{1},': ');
				catch
					tmpStr = strsplit(tmpStr{1},': ');
				end
				algorithmStr = tmpStr{2};
			end
		catch err
			disp(repmat('@',1,7))
			disp(getReport(err,'extended','hyperlinks','on'));
			disp(repmat('@',1,7))
		end
	catch err
		disp(repmat('@',1,7))
		disp(getReport(err,'extended','hyperlinks','on'));
		disp(repmat('@',1,7))
	end
end


function this = add_dims(this, iDim, varargin)
% Adds additional dimensions to existing dimInfo
%
%   Y = MrDimInfo()
%   Y.add_dims(iDims, varargin)
%
% This is a method of class MrDimInfo.
%
% IN
%   iDim        (vector of) dimension indices to be added (e.g. 3 for 3rd
%               dimension)
%                   or
%               (cell of) strings of dimension names
%   varargin    PropertyName/Value pairs to set parameters of the new
%               dimension
%
% OUT
%
% EXAMPLE
%   add_dims('coil', 'units', 'nil', 'samplingPoints', {1:8})
%
%   See also MrDimInfo set_dims

% Author:   Saskia Bollmann & Lars Kasper
% Created:  2016-06-18
% Copyright (C) 2016 Institute for Biomedical Engineering
%                    University of Zurich and ETH Zurich
%
% This file is part of the TAPAS UniQC Toolbox, which is released
% under the terms of the GNU General Public License (GPL), version 3.
% You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version).
% For further details, see the file COPYING or
%  <http://www.gnu.org/licenses/>.

% nothing to do here...
if isempty(iDim)
    return
end

%% To update a dimension (set_dims), it has to have a label first
% This can be given explicitly or using the default dimLabels of MrDimInfo

% later permutation at specified index, setup here
doPermute = isnumeric(iDim);
if doPermute
    iDimNumeric = iDim;
end

% direct adding of a labeled dimension, e.g., add_dims('coil', ...)
isStringiDimInput = ischar(iDim) || (iscell(iDim) && ischar(iDim{1}));
if isStringiDimInput
    additionalDimLabels = cellstr(iDim);
else
    % add_dims via their index, e.g. add_dims([4:6}, propName/Value...)
    if ~iscell(iDim)
        iDim = num2cell(iDim);
    end

    if isempty(iDim{1})
        % empty set of dimLabels to add, therefore return
        return
    else

        additionalDimLabels = cellfun(@(x) this.get_default_dim_labels(x), iDim, ...
            'UniformOutput', false);
    end
end

% empty defaults here will be overwritten by set_dims
nDimsOld = this.nDims;
nDimsAdditional = numel(additionalDimLabels);
this.dimLabels = [this.dimLabels additionalDimLabels];
this.samplingPoints(nDimsOld+(1:nDimsAdditional)) = {[]};
this.resolutions(nDimsOld+(1:nDimsAdditional)) = 1;
this.samplingWidths(nDimsOld+(1:nDimsAdditional)) = NaN;
this.units(nDimsOld+(1:nDimsAdditional)) = {''};
% set_dims also needed to add samplingPoints (e.g. via Nsamples/resolution)
if nargin > 2
    this.set_dims(additionalDimLabels, varargin{:});
end

% permute here to corresponding index
if doPermute
    iDim = iDimNumeric;
    nDimsNew = nDimsOld + nDimsAdditional;

    % current order of dimensions after appending the dimensions at the end
    dimOrderNew = [setdiff(1:nDimsNew, iDim), iDim];

    % desired permutation to have right dimensions at their place
    invDimOrderNew(dimOrderNew) = 1:length(dimOrderNew); % inverse permutation
    this.permute(invDimOrderNew);
end


function [success] = writeMatfileToHDF5(inputMatfilePath,varName,outputFilename,varargin)
	% [success] = writeMatfileToHDF5(inputMatfilePath,varName,outputFilename,varargin)
	%
	% Writes a MAT-file dataset to HDF5 by reading the matrix in parts to avoid large overhead.
	%
	% Biafra Ahanonu
	% started: 2022.03.13 [23:49:18]
	%
	% inputs
	% 	inputMatfilePath - path to matfile object containing data.
	% 	varName - Str: name of variable in MAT-file to save. Should be matrix of [x y frames].
	% 	inputFilename - Str: path where HDF5 file should be saved.
	%
	% outputs
	% 	success - Binary: 1 = data saved correctly, 0 = data not saved correctly.

	% changelog
		%
	% TODO
		%

	% ========================
	% Str: name of HDF5 dataset to save data into.
	options.datasetname = '/1';
	% HDF5: append (don't blank HDF5 file) or new (blank HDF5 file)
	options.writeMode = 'new';
	% Int: Number of frames to use for chunking the data to save in parts.
	options.chunkSize = 200;
	% Int: Defines gzip compression level (0-9). 0 = no compression, 9 = most compression.
	options.deflateLevel = 9;
	% Int: chunk size in [x y z] of the dataset, leave empty for auto chunking
	options.dataDimsChunkCopy = [];
	% Struct: structure of information to add. Will create a HDF5 file
	options.addInfo = [];
	% Str: e.g. '/movie/processingSettings'
	options.addInfoName = '';
	% get options
	options = ciapkg.io.getOptions(options,varargin);
	% display(options)
	% unpack options into current workspace
	% fn=fieldnames(options);
	% for i=1:length(fn)
	% 	eval([fn{i} '=options.' fn{i} ';']);
	% end
	% ========================

	try
		success = 0;

		% Create matfile object.
		inputObj = matfile(inputMatfilePath);

		% Get size of the input data, call this way instead of size(inputObj.varName) to avoid loading entire dataset into memory.
		dataDims = size(inputObj,varName);

		if length(dataDims)~=3
			disp('Data is not a 3D matrix of size [:, :, >1], returning...')
			return;
		end

		% Get coordinates to use.
		nFrames = dataDims(3);
		subsetSize = options.chunkSize;
		movieLength = nFrames;
		numSubsets = ceil(movieLength/subsetSize)+1;
		subsetList = round(linspace(1,movieLength,numSubsets));
		nSubsets = (length(subsetList)-1);

		% Write data out in chunks.
		for thisSet = 1:nSubsets
			% subsetStartTime = tic;

			subsetStartIdx = subsetList(thisSet);
			subsetEndIdx = subsetList(thisSet+1);
			disp(repmat('$',1,7))
			if thisSet==nSubsets
				movieSubset = subsetStartIdx:subsetEndIdx;
			else
				movieSubset = subsetStartIdx:(subsetEndIdx-1);
			end
			disp([num2str(movieSubset(1)) '-' num2str(movieSubset(end)) ' ' num2str(thisSet) '/' num2str(nSubsets)])

			% Slice into the desired variable using dynamic field references to avoid loading entire dataset into memory.
			inputDataSlice = inputObj.(varName)(:,:,movieSubset);

			if thisSet==1
				ciapkg.hdf5.createHdf5File(outputFilename, options.datasetname, inputDataSlice,'deflateLevel',options.deflateLevel,'dataDimsChunkCopy',options.dataDimsChunkCopy);
			else
				ciapkg.hdf5.appendDataToHdf5(outputFilename, options.datasetname, inputDataSlice);
			end

			% toc(subsetStartTime)
		end

		% add information about data to HDF5 file
		if strcmp(options.writeMode,'new')
			hdf5write(outputFilename,'/movie/info/dimensions',dataDims,'WriteMode','append');
			currentDateTimeStr = datestr(now,'yyyymmdd_HHMM','local');
			hdf5write(outputFilename,'/movie/info/date',currentDateTimeStr,'WriteMode','append');
			hdf5write(outputFilename,'/movie/info/savePath',outputFilename,'WriteMode','append');
			hdf5write(outputFilename,'/movie/info/Deflate',options.deflateLevel,'WriteMode','append');
		end
		if ~isempty(options.addInfo)
			if ~iscell(options.addInfo)
				options.addInfo = {options.addInfo};
				options.addInfoName = {options.addInfoName};
			end
			addInfoLen = length(options.addInfo);
			for addInfoStructNo = 1:addInfoLen
				thisAddInfo = options.addInfo{addInfoStructNo};
				infoList = fieldnames(thisAddInfo);
				nInfo = length(infoList);
				for fieldNameNo = 1:nInfo
					thisField = infoList{fieldNameNo};
					hdf5write(outputFilename,[options.addInfoName{addInfoStructNo} '/' thisField],thisAddInfo.(thisField),'WriteMode','append');
					% h5write(fileSavePath,[options.addInfoName{addInfoStructNo} '/' thisField],thisAddInfo.(thisField),'WriteMode','append');
				end
			end
		end

		success = 1;
	catch err
		success = 0;
		disp(repmat('@',1,7))
		disp(getReport(err,'extended','hyperlinks','on'));
		disp(repmat('@',1,7))
	end

	% function [outputs] = nestedfxn_exampleFxn(arg)
	% 	% Always start nested functions with "nestedfxn_" prefix.
	% 	% outputs = ;
	% end
end


function s=cosmo_structjoin(varargin)
% joins values in structs or key-value pairs
%
% s=cosmo_structjoin(arg1, arg2, ...)
%
% Inputs:
%   arg{X}      Any of the following:
%               - if a cell, then it should contain structs or key-value
%                 pairs
%               - if a struct, then value=arg{X}.(key) for each key in
%                 fieldnames(arg{X}) is stored as s.(key)=value.
%                 In this case, it is required that the struct is of size
%                 1x1.
%               - if a string, then it is stored as s.(arg{X})=arg{X+1}
%
% Returns:
%   s           Struct with fieldnames and their associated values
%               as key-value pairs. Values in the input are stored from
%               left-to-right.
%
% Example:
%     x=cosmo_structjoin('a',{1;2},'b',{3,4});
%     cosmo_disp(x);
%     %|| .a
%     %||   { [ 1 ]
%     %||     [ 2 ] }
%     %|| .b
%     %||   { [ 3 ]  [ 4 ] }
%     y=cosmo_structjoin(x,'a',66,'x',x,{'c','hello'});
%     cosmo_disp(y);
%     %|| .a
%     %||   [ 66 ]
%     %|| .b
%     %||   { [ 3 ]  [ 4 ] }
%     %|| .x
%     %||   .a
%     %||     { [ 1 ]
%     %||       [ 2 ] }
%     %||   .b
%     %||     { [ 3 ]  [ 4 ] }
%     %|| .c
%     %||   'hello'
%
%     % simulate a function definition function out=f(varargin)
%     % to illustrate overriding default values
%     varargin={'radius',2,'nsamples',12};
%     defaults=struct();
%     defaults.radius=10;
%     defaults.nfeatures=2;
%     params=cosmo_structjoin(defaults,varargin);
%     cosmo_disp(params);
%     %|| .radius
%     %||   [ 2 ]
%     %|| .nfeatures
%     %||   [ 2 ]
%     %|| .nsamples
%     %||   [ 12 ]
%
%     % illustrate overriding values in 'sub-structs' (structs as values in
%     % other structs)
%     v=struct();
%     v.a.foo={1,2};
%     v.b=3;
%     w=struct();
%     w.a.bar=[2,3];
%     w.c=4;
%     j=cosmo_structjoin(v,w);
%     cosmo_disp(j)
%     %|| .a
%     %||   .foo
%     %||     { [ 1 ]  [ 2 ] }
%     %||   .bar
%     %||     [ 2         3 ]
%     %|| .b
%     %||   [ 3 ]
%     %|| .c
%     %||   [ 4 ]
%
%
% Notes:
%  - this function can be used to parse input arguments (including
%    varargin in a "'key1',value1,'key2',value2,..." fashion)
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #

    % use a wrapper so that recursive calls can be forwarded to the wrapper
    % without using mfilename
    s=structjoin_wrapper(varargin{:});

function s=structjoin_wrapper(varargin)

    s=struct(); % output
    n=numel(varargin);

    k=0;
    while k<n
        % go over all input arguments
        k=k+1;
        v=varargin{k}; %k-th argument

        if iscell(v)
            if isempty(v)
                continue;
            end

            % use recursion
            v=structjoin_wrapper(v{:});
        end

        if isstruct(v)
            if numel(v)~=1
                error(['only singleton structs (of size 1x1) '...
                            'are supported']);
            end

            % overwrite any values in s
            fns=fieldnames(v);

            for j=1:numel(fns);
                fn=fns{j};
                v_fn=v.(fn);

                if isstruct(v_fn) && isfield(s,fn) && isstruct(s.(fn))
                    s.(fn)=structjoin_wrapper(s.(fn),v_fn);
                else
                    s.(fn)=v_fn;
                end
            end
        elseif ischar(v)
            % <key>, <value> pair
            if k+1>n
                % cannot be last argument
                error('Missing argument after key ''%s''', v);
            end

            % move forward to next argument and get value
            k=k+1;
            vv=varargin{k};

            if isstruct(vv) && isfield(s,v) && isstruct(s.(v))
                s.(v)=structjoin_wrapper(s.(v),vv);
            else
                s.(v)=vv;
            end
        else
            error(['Illegal input at position %d: expected cell, struct, ',...
                        'or string'], k);
        end
    end


function xyz_io_test ( )

%*****************************************************************************80
%
%% XYZ_IO_TEST tests the XYZ_IO library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    07 January 2009
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'XYZ_IO_TEST\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the XYZ_IO library.\n' );

  xyz_io_test01 ( );
  xyz_io_test02 ( );
  xyz_io_test03 ( );
  xyz_io_test04 ( );
  xyz_io_test05 ( );
  xyz_io_test06 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'XYZ_IO_TEST\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


 function y = mtimes_block(ob, x, istart, nblock)
%function y = mtimes_block(ob, x, istart, nblock)
% y = G(i'th block) * x	or y = G'(i'th block) * x
% in either case the projection data will be "small"
% istart is 1,...,nblock

% support 'exists' option for seeing if this routine is available
if nargin == 2 && ischar(x) && streq(x, 'exists')
	y = ~isempty(ob.handle_mtimes_block);
	return
end

if nargin ~= 4, ir_usage, end

if isempty(ob.handle_mtimes_block)
	error 'bug: no mtimes_block() method for this object'
end

if ob.is_transpose
	y = Fatrix_mtimes_block_back(ob, x, istart, nblock);
else
	y = Fatrix_mtimes_block_forw(ob, x, istart, nblock);
end

% caution: cascade_* may not work except for scalars here

function y = Fatrix_mtimes_block_forw(ob, x, istart, nblock);

x = do_cascade(ob.cascade_before, x, false, istart, nblock, true);
y = ob.handle_mtimes_block(ob.arg, ob.is_transpose, x, istart, nblock);
y = do_cascade(ob.cascade_after, y, false, istart, nblock, false);

function x = Fatrix_mtimes_block_back(ob, y, istart, nblock);

y = do_cascade(ob.cascade_after, y, true, istart, nblock, false);
x = ob.handle_mtimes_block(ob.arg, ob.is_transpose, y, istart, nblock);
x = do_cascade(ob.cascade_before, x, true, istart, nblock, true);