% std_plottf() - plot ERSP/ITC images a component
%              or channel cluster in a STUDY. Also allows plotting scalp
%              maps.
% Usage:
%          >> std_plottf( times, freqs, data, 'key', 'val', ...)
% Inputs:
%  times - [vector] latencies in ms of the data points.
%  freqs - [vector] frequencies in Hz of the data points.
%  data  -  [cell array] mean data for each subject group and/or data
%           condition. For example, to plot mean ERPs from a STUDY
%           for epochs of 800 frames in two conditions from three groups
%           of 12 subjects:
%
%           >> data = { [800x12] [800x12] [800x12];... % 3 groups, cond 1
%                       [800x12] [800x12] [800x12] };  % 3 groups, cond 2
%           >> std_plottf(erp_ms,data);
%
%           By default, parametric statistics are computed across subjects
%           in the three groups. (group,condition) ERP averages are plotted.
%           See below and >> help statcond
%           for more information about the statistical computations.
%
% Optional display parameters:
%  'datatype'    - ['ersp'|'itc'] data type {default: 'ersp'}
%  'titles'      - [cell array of string] titles for each of the subplots.
%                  { default: none}
%
% Statistics options:
%  'groupstats'  - ['on'|'off'] Compute (or not) statistics across groups.
%                  {default: 'off'}
%  'condstats'   - ['on'|'off'] Compute (or not) statistics across groups.
%                  {default: 'off'}

%  'threshold'   - [NaN|real<<1] Significance threshold. NaN -> plot the
%                  p-values themselves on a different figure. When possible,
%                  significance regions are indicated below the data.
%                  {default: NaN}
%  'maskdata'    - ['on'|'off'] when threshold is non-NaN and not both
%                  condition and group statistics are computed, the user
%                  has the option to mask the data for significance.
%                  {defualt: 'off'}
%
% Other plotting options:
%  'plotmode'    - ['normal'|'condensed'] statistics plotting mode:
%                  'condensed' -> plot statistics under the curves
%                  (when possible); 'normal' -> plot them in separate
%                  axes {default: 'normal'}
%  'freqscale'   - ['log'|'linear'|'auto'] frequency plotting scale.
%                  {default: 'auto'}
%  'ylim'        - [min max] ordinate limits for ERP and spectrum plots
%                  {default: all available data}
%
% ITC/ERSP image plotting options:
%  'tftopoopt'   - [cell array] tftopo() plotting options (ERSP and ITC)
%  'caxis'       - [min max] color axis (ERSP, ITC, scalp maps)
%
% Scalp map plotting options:
%  'chanlocs'    - [struct] channel location structure
%
% Author: Arnaud Delorme, CERCO, CNRS, 2006-
%
% See also: pop_erspparams(), pop_erpparams(), pop_specparams(), statcond()

% Copyright (C) 2006 Arnaud Delorme
%
% 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 [pgroup, pcond, pinter] = std_plottf(timevals, freqs, data, varargin)

pgroup = [];
pcond  = [];
pinter = [];
if nargin < 2
    help std_plottf;
    return;
end;

opt = finputcheck( varargin, { 'titles'         'cell'   []              cell(20,20);
                               'caxis'          'real'   []              [];
                               'ersplim'        'real'   []              []; % same as above
                               'itclim'         'real'   []              []; % same as above
                               'ylim'           'real'   []              [];
                               'tftopoopt'      'cell'   []              {};
                               'threshold'      'real'   []              NaN;
                               'unitx'          'string' []              'ms'; % just for titles
                               'chanlocs'       'struct' []              struct('labels', {});
                               'freqscale'      'string' { 'log' 'linear' 'auto' }  'auto';
                               'groupstats'     'cell'   []              {};
                               'condstats'      'cell'   []              {};
                               'interstats'     'cell'   []              {};
                               'maskdata'       'string' { 'on' 'off' }   'off';
                               'datatype'       'string' { 'ersp' 'itc' }    'ersp';
                               'plotmode'       'string' { 'normal' 'condensed' }  'normal' }, 'std_plottf');
if isstr(opt), error(opt); end;
if all(all(cellfun('size', data, 3)==1))               opt.singlesubject = 'on'; end;

% remove empty entries
datapresent = ~cellfun(@isempty, data);
for c = size(data,1):-1:1, if sum(datapresent(c,:)) == 0, data(c,:) = []; opt.titles(c,:) = []; if ~isempty(opt.groupstats), opt.groupstats(c) = []; end; end; end;
for g = size(data,2):-1:1, if sum(datapresent(:,g)) == 0, data(:,g) = []; opt.titles(:,g) = []; if ~isempty(opt.condstats ), opt.condstats( g) = []; end; end; end;

if ~isempty(opt.groupstats) & ~isempty(opt.condstats) & strcmpi(opt.maskdata, 'on')
    disp('Cannot use ''maskdata'' option with both condition stat. and group stat. on');
    disp('Disabling statistics');
    opt.groupstats = {}; opt.condstats = {}; opt.maskdata = 'off';
end;
if ~isempty(opt.ersplim), opt.caxis = opt.ersplim; end;
if ~isempty(opt.itclim), opt.caxis = opt.itclim; end;
onecol  = { 'b' 'b' 'b' 'b' 'b' 'b' 'b' 'b' 'b' 'b' };
manycol = { 'b' 'r' 'g' 'k' 'c' 'y' };

nc = size(data,1);
ng = size(data,2);
if nc >= ng, opt.transpose = 'on';
else         opt.transpose = 'off';
end;

% test log frequencies
% --------------------
if length(freqs) > 2 & strcmpi(opt.freqscale, 'auto')
    midfreq = (freqs(3)+freqs(1))/2;
    if midfreq*.9999 < freqs(2) & midfreq*1.0001 > freqs(2), opt.freqscale = 'linear';
    else                                                     opt.freqscale = 'log';
    end;
end;

% condensed plot
% --------------
if strcmpi(opt.plotmode, 'condensed')
    meanplot = zeros(size(data{1},1), size(data{1},2));
    count = 0;
    for c = 1:nc
        for g = 1:ng
            if ~isempty(data{c,g})
                meanplot = meanplot + mean(data{c,g},3);
                count = count+1;
            end;
        end;
    end;
    meanplot = meanplot/count;
    options = { 'chanlocs', opt.chanlocs, 'electrodes', 'off', 'cbar', 'on', ...
            'cmode', 'separate', opt.tftopoopt{:} };

    if strcmpi(opt.freqscale, 'log'), options = { options{:} 'logfreq', 'native' }; end;
    tftopo( meanplot', timevals, freqs, 'title', opt.titles{1}, options{:});
    currentHangle = gca;
    if ~isempty( opt.caxis )
        caxis( currentHangle, opt.caxis )
    end
    colorbarHandle = cbar;
    title(colorbarHandle,'dB');
    axes(currentHangle);
    return;
end;

% plotting paramters
% ------------------
if ng > 1 && ~isempty(opt.groupstats), addc = 1; else addc = 0; end;
if nc > 1 && ~isempty(opt.condstats  ), addr = 1; else addr = 0; end;

% compute significance mask
% --------------------------
if ~isempty(opt.interstats), pinter = opt.interstats{3}; end;

if ~isnan(opt.threshold) && ( ~isempty(opt.groupstats) || ~isempty(opt.condstats) )
    pcondplot  = opt.condstats;
    pgroupplot = opt.groupstats;
    pinterplot = pinter;
    maxplot = 1;
else
    warning off;
    for ind = 1:length(opt.condstats),  pcondplot{ind}  = -log10(opt.condstats{ind}); end;
    for ind = 1:length(opt.groupstats), pgroupplot{ind} = -log10(opt.groupstats{ind}); end;
    if ~isempty(pinter), pinterplot = -log10(pinter); end;
    maxplot = 3;
    warning on;
end;

% -------------------------------
% masking for significance of not
% -------------------------------
statmask = 0;
if strcmpi(opt.maskdata, 'on') && ~isnan(opt.threshold) && ...
        (~isempty(opt.condstats) || ~isempty(opt.condstats))
    addc = 0; addr = 0; statmask = 1;
end;

% -------------------------
% plot time/frequency image
% -------------------------
options = { 'chanlocs', opt.chanlocs, 'electrodes', 'off', 'cbar', 'off', ...
            'cmode', 'separate', opt.tftopoopt{:} };
if strcmpi(opt.freqscale, 'log'), options = { options{:} 'logfreq', 'native' }; end;

% adjust figure size
% ------------------
fig = figure('color', 'w');
pos = get(fig, 'position');
set(fig, 'position', [ pos(1)+15 pos(2)+15 pos(3)/2.5*(nc+addr), pos(4)/2*(ng+addc) ]);
pos = get(fig, 'position');
if strcmpi(opt.transpose, 'off'), set(gcf, 'position', [ pos(1) pos(2) pos(4) pos(3)]);
else                              set(gcf, 'position', pos);
end;

tmpc = [inf -inf];
for c = 1:nc
    for g = 1:ng
        hdl(c,g) = mysubplot(nc+addr, ng+addc, g + (c-1)*(ng+addc), opt.transpose);
        if ~isempty(data{c,g})
            tmpplot = mean(data{c,g},3);
            if ~isreal(tmpplot(1)), tmpplot = abs(tmpplot); end;
            if statmask,
                if ~isempty(opt.condstats), tmpplot(find(pcondplot{g}(:) == 0)) = 0;
                else                        tmpplot(find(pgroupplot{c}(:) == 0)) = 0;
                end;
            end;

            tftopo( tmpplot', timevals, freqs, 'title', opt.titles{c,g}, options{:});

            if isempty(opt.caxis) && ~isempty(tmpc)
                warning off;
                tmpc = [ min(min(tmpplot(:)), tmpc(1)) max(max(tmpplot(:)), tmpc(2)) ];
                warning on;
            else
                if ~isempty(opt.caxis)
                    caxis(opt.caxis);
                end;
            end;

            if c > 1
                ylabel('');
            end;
        end;

        % statistics accross groups
        % -------------------------
        if g == ng && ng > 1 && ~isempty(opt.groupstats) && ~isinf(pgroupplot{c}(1)) && ~statmask
            hdl(c,g+1) = mysubplot(nc+addr, ng+addc, g + 1 + (c-1)*(ng+addc), opt.transpose);
            tftopo( pgroupplot{c}', timevals, freqs, 'title', opt.titles{c,g+1}, options{:});
            caxis([-maxplot maxplot]);
        end;
    end;
end;

for g = 1:ng
    % statistics accross conditions
    % -----------------------------
    if ~isempty(opt.condstats) && ~isinf(pcondplot{g}(1)) && ~statmask && nc > 1
        hdl(nc+1,g) = mysubplot(nc+addr, ng+addc, g + c*(ng+addc), opt.transpose);
        tftopo( pcondplot{g}', timevals, freqs, 'title', opt.titles{nc+1,g}, options{:});
        caxis([-maxplot maxplot]);
    end;
end;

% color scale
% -----------
if isempty(opt.caxis)
    tmpc = [-max(abs(tmpc)) max(abs(tmpc))];
    for c = 1:nc
        for g = 1:ng
            axes(hdl(c,g));
            if ~isempty(tmpc)
                caxis(tmpc);
            end;
        end;
    end;
end;

% statistics accross group and conditions
% ---------------------------------------
if ~isempty(opt.groupstats) && ~isempty(opt.condstats) && ng > 1 && nc > 1
    hdl(nc+1,ng+1) = mysubplot(nc+addr, ng+addc, g + 1 + c*(ng+addr), opt.transpose);
    tftopo( pinterplot',  timevals, freqs, 'title', opt.titles{nc+1,ng+1}, options{:});
    caxis([-maxplot maxplot]);
    ylabel('');
end;

% color bars
% ----------
axes(hdl(nc,ng));
cbar_standard(opt.datatype, ng);
if isnan(opt.threshold) && (nc ~= size(hdl,1) || ng ~= size(hdl,2))
    ind = find(hdl(end:-1:1));
    axes(hdl(end-ind(1)+1));
    cbar_signif(ng, maxplot);
end;

% mysubplot (allow to transpose if necessary)
% -------------------------------------------
function hdl = mysubplot(nr,nc,ind,transp);

    r = ceil(ind/nc);
    c = ind -(r-1)*nc;
    if strcmpi(transp, 'on'), hdl = subplot(nc,nr,(c-1)*nr+r);
    else                      hdl = subplot(nr,nc,(r-1)*nc+c);
    end;

% colorbar for ERSP and scalp plot
% --------------------------------
function cbar_standard(datatype, ng);
    pos = get(gca, 'position');
    tmpc = caxis;
    fact = fastif(ng == 1, 40, 20);
    tmp = axes('position', [ pos(1)+pos(3)+max(pos(3)/fact,0.006) pos(2) max(pos(3)/fact,0.01) pos(4) ]);
    set(gca, 'unit', 'normalized');
    if strcmpi(datatype, 'itc')
         cbar(tmp, 0, tmpc, 10); ylim([0.5 1]);
         title('ITC');
    else cbar(tmp, 0, tmpc, 5);title('dB');
    end;

% colorbar for significance
% -------------------------
function cbar_signif(ng, maxplot);
    pos = get(gca, 'position');
    tmpc = caxis;
    fact = fastif(ng == 1, 40, 20);
    tmp = axes('position', [ pos(1)+pos(3)+max(pos(3)/fact,0.006) pos(2) max(pos(3)/fact,0.01) pos(4) ]);
    map = colormap;
    n = size(map,1);
    cols = [ceil(n/2):n]';
    image([0 1],linspace(0,maxplot,length(cols)),[cols cols]);
    %cbar(tmp, 0, tmpc, 5);
    tick = linspace(0, maxplot, maxplot+1);
    set(gca, 'ytickmode', 'manual', 'YAxisLocation', 'right', 'xtick', [], ...
        'ytick', tick, 'yticklabel', round(10.^-tick*1000)/1000);
    xlabel('');

% rapid filtering for ERP
% -----------------------
function tmpdata2 = myfilt(tmpdata, lowpass, highpass, factor, filtertype)

    tmpdata2 = reshape(tmpdata, size(tmpdata,1), size(tmpdata,2)*size(tmpdata,3)*size(tmpdata,4));
    tmpdata2 = eegfiltfft(tmpdata2',lowpass, highpass, factor, filtertype)';
    tmpdata2 = reshape(tmpdata2, size(tmpdata,1), size(tmpdata,2), size(tmpdata,3), size(tmpdata,4));


% [succeeded,outmatname,trx] = cadabra2ctrax(featname,roiname,moviename,[outmatname],[doflipup],[dofliplr],[rot])
% inputs cadabra mat file output names, loads in the trajectories, and
% converts to ctrax trx format. these trx will be saved to the file
% outmatname (user will be prompted for this name if none given).
% inputs:
% featname: [optional] "feat" output by cadabra. if not input, user will be
% prompted for file.
% roiname: [optional] "roi" output by cadabra. if not input, user will be
% prompted for file.
% moviename: name of movie tracked
% outmatname: [optional] mat file to save trx trajectories to. user will be
% prompted for file name if none given
% doflipud: [optional] whether to flip the trajectories vertically across
% the middle of the video. Default: false.
% dofliplr: [optional] whether to flip the trajectories horizontally across
% the center of the video. Default: false.
% rot: [optional] degrees to rotate the trajectories by around the center
% of the video. Default: 0.

function [succeeded,outmatname,trx] = cadabra2ctrax(featname,roiname,moviename,outmatname,doflipud,dofliplr,rot,movieinfo)

% initialize outputs
succeeded = false;
if ~exist('outmatname','var'),
  outmatname = '';
end
trx = [];

if ~exist('featname','var') || isempty(featname),
  helpmsg = 'Choose CADABRA feat mat file';
  [featname,featpath] = uigetfilehelp('*.mat','Choose feat file','','helpmsg',helpmsg);
  if ~ischar(featname),
    return;
  end
  featname = fullfile(featpath,featname);
end

if ~exist('roiname','var') || isempty(roiname),
  helpmsg = sprintf('Choose CADABRA roi mat file corresponding to feat file %s',featname);
  roiname = strrep(featname,'feat','roi');
  [roiname,roipath] = uigetfilehelp('*.mat','Choose feat file',roiname,'helpmsg',helpmsg);
  if ~ischar(roiname),
    return;
  end
  roiname = fullfile(roipath,roiname);
end

if ~exist('moviename','var') || isempty(moviename),
  helpmsg = sprintf('Choose movie file corresponding to feat file %s',featname);
  moviename = strrep(featname,'_feat.mat','.avi');
  [moviename,moviepath] = uigetfilehelp('*.avi','Choose movie file',moviename,'helpmsg',helpmsg);
  if ~ischar(moviename),
    return;
  end
  moviename = fullfile(moviepath,moviename);
end

if ~exist('doflipud','var'),
  doflipud = false;
end

if ~exist('dofliplr','var'),
  dofliplr = false;
end

if ~exist('rot','var'),
  rot = 0;
end

if rot ~= 0,
  phi = rot*pi/180;
  R = [cos(rot),sin(rot);-sin(rot),cos(rot)];
end

% load in data
feat = load(featname);
roi = load(roiname);

if ~exist('movieinfo','var') || isempty(movieinfo),

  % read fps, frame size, moviename is either the name of the movie or an mmreader object
  if ~ischar(moviename),
    readerobj = moviename;
    moviename = fullfile(get(readerobj,'Path'),get(readerobj,'Name'));
  else
    readerobj = mmreader(moviename);
  end
  fps = get(readerobj,'FrameRate')+0;
  movieheight = get(readerobj,'Height')+0;
  moviewidth = get(readerobj,'Width')+0;
else
  fps = movieinfo.fps;
  movieheight = movieinfo.height;
  moviewidth = movieinfo.width;
end
movieheight_mm = movieheight * roi.scale.y;
moviewidth_mm = moviewidth * roi.scale.x;

% scale, pxpermm
pxpermm = 1/mean([roi.scale.x,roi.scale.y]);

% allocate
c = cell(1,2);
trx = struct('x',c,'y',c,'theta',c,'a',c,'b',c,...
  'id',c,'moviename',c,'firstframe',c,'arena',c,...
  'nframes',c,'endframe',c,'pxpermm',c,'fps',c,'x_mm',c,...
  'y_mm',c,'a_mm',c,'b_mm',c,'dt',c);
obj = [feat.fly_feat.obj1,feat.fly_feat.obj2];
firstframeoff = feat.fly_feat.frame(1) - 1;
arena = struct('x',nan,'y',nan,'r',nan);
for fly = 1:2,

  % frames for which fly is tracked

  % (x,y) = (0,0) for untracked frames
  badframes = obj(fly).pos_x == 0 & obj(fly).pos_y == 0;
  lastframe = find(~badframes,1,'last');
  firstframe = find(~badframes,1);
  if isempty(lastframe),
    firstframe = 1;
    lastframe = 0;
  end
  nframes = lastframe - firstframe + 1;

  % allocate
  trx(fly).x = nan(1,nframes);
  trx(fly).y = nan(1,nframes);
  trx(fly).theta = nan(1,nframes);
  trx(fly).a = nan(1,nframes);
  trx(fly).b = nan(1,nframes);
  trx(fly).xwingl = nan(1,nframes);
  trx(fly).ywingl = nan(1,nframes);
  trx(fly).xwingr = nan(1,nframes);
  trx(fly).ywingr = nan(1,nframes);
  trx(fly).x_mm = nan(1,nframes);
  trx(fly).y_mm = nan(1,nframes);
  trx(fly).a_mm = nan(1,nframes);
  trx(fly).b_mm = nan(1,nframes);
  trx(fly).dt = nan(1,nframes-1);

  % store parameters
  trx(fly).moviename = moviename;
  trx(fly).firstframe = firstframe + firstframeoff;
  trx(fly).endframe = lastframe + firstframeoff;
  trx(fly).nframes = nframes;
  trx(fly).pxpermm = pxpermm;
  trx(fly).fps = fps;
  trx(fly).id = fly;
  trx(fly).arena = arena;
  %trx(fly).f2i = @(f) f - trx(fly).firstframe + 1;

  % store data
  idx = feat.fly_feat.frame(firstframe:lastframe)-trx(fly).firstframe + 1;
  % we use the quarter major, minor axis length
  trx(fly).a_mm(idx) = obj(fly).FLength/4;
  % maybe area is major/2 * minor/2 * pi, store quarter minor axis length
  trx(fly).b_mm(idx) = (obj(fly).FArea./(obj(fly).FLength/2)/pi)/2;
  % convert degrees to radians
  trx(fly).theta(idx) = obj(fly).headdir*pi/180;

  % convert mm to px, incorporate offset
  trx(fly).x(idx) = obj(fly).pos_x*pxpermm + roi.ROI.cols(1) - 1;
  trx(fly).y(idx) = obj(fly).pos_y*pxpermm + roi.ROI.rows(1) - 1 - 1;
  trx(fly).x_mm = trx(fly).x / pxpermm;
  trx(fly).y_mm = trx(fly).y / pxpermm;
  trx(fly).a = trx(fly).a_mm*pxpermm;
  trx(fly).b = trx(fly).b_mm*pxpermm;

  phil = obj(fly).phil*pi/180;
  wingll = obj(fly).wingll*pxpermm;
  xwl = trx(fly).x(idx) + wingll.*cos(-phil-trx(fly).theta(idx)-pi);
  ywl = trx(fly).y(idx) + wingll.*sin(-phil-trx(fly).theta(idx));
  phir = obj(fly).phir*pi/180;
  winglr = obj(fly).winglr*pxpermm;
  xwr = trx(fly).x(idx) + winglr.*cos(phir-trx(fly).theta(idx)-pi);
  ywr = trx(fly).y(idx) + winglr.*sin(phir-trx(fly).theta(idx));
  trx(fly).xwingl(idx) = xwl;
  trx(fly).ywingl(idx) = ywl;
  trx(fly).xwingr(idx) = xwr;
  trx(fly).ywingr(idx) = ywr;
  trx(fly).xwingl_mm = trx(fly).xwingl / pxpermm;
  trx(fly).ywingl_mm = trx(fly).ywingl / pxpermm;
  trx(fly).xwingr_mm = trx(fly).xwingr / pxpermm;
  trx(fly).ywingr_mm = trx(fly).ywingr / pxpermm;

  trx(fly).dt(idx(1:end-1)) = diff(feat.fly_feat.time(firstframe:lastframe));

  % flipud if necessary
  if doflipud,
    trx(fly).y_mm = movieheight_mm - trx(fly).y_mm;
    trx(fly).y = movieheight - trx(fly).y;
    trx(fly).theta = -trx(fly).theta;
  end

  % fliplr if necessary
  if dofliplr,
    trx(fly).x_mm = moviewidth_mm - trx(fly).x_mm;
    trx(fly).x = moviewidth - trx(fly).x;
    trx(fly).theta = modrange(pi-trx(fly).theta,-pi,pi);
  end

  % rotate if necessary
  if rot ~= 0,
    trx(fly).x_mm = (trx(fly).x_mm - moviewidth_mm/2)*R + moviewidth_mm/2;
    trx(fly).y_mm = (trx(fly).y_mm - movieheight_mm/2)*R + movieheight_mm/2;
    trx(fly).x = (trx(fly).x - moviewidth/2)*R + moviewidth/2;
    trx(fly).y = (trx(fly).y - movieheight/2)*R + movieheight/2;
    trx(fly).theta = modrange(trx(fly).theta + phi,-pi,pi);
  end

end

if ~exist('outmatname','var') || isempty(outmatname),
  [pathstr,name] = fileparts(featname);
  outname = strrep(name,'_feat','');
  outmatname = fullfile(pathstr,[outname,'_trx.mat']);
  helpmsg = {};
  helpmsg{1} = 'Choose mat file to save Ctrax version of trajectories loaded from:';
  helpmsg{2} = sprintf('CADABRA feat file: %s',featname);
  helpmsg{3} = sprintf('CADABRA roi file: %s',roiname);
  [outmatname,outmatpath] = uiputfilehelp('*.mat',sprintf('Save ctrax version of %s',name),outmatname,'helpmsg',helpmsg);
  if ~ischar(outmatname),
    outmatname = '';
    return;
  end
  outmatname = fullfile(outmatpath,outmatname);
  fprintf('Saving to %s...\n',outmatname);
end

save(outmatname,'trx');
succeeded = true;


function plotPredictionResults_LGG(pathResults,nameOutcome,fSetNames,metric,maxOrder,pathFig)
% -------------------------------------------------------------------------
% function plotPredictionResults_LGG(pathResults,nameOutcome,fSetNames,metrics,maxOrder)
% -------------------------------------------------------------------------
% DESCRIPTION:
% This function plots prediction performance estimation results for all the
% different feature set types entered as inputs in the LGG study.
% -------------------------------------------------------------------------
% INPUTS:
% 1. pathResults: Full path to the 'RESULTS' folder where prediction results
%                 are saved.
%                 --> Ex: '/myProject/WORKSPACE/LOGISTIC_REGRESSION/RESULTS'
% 2. nameOutcome: String specifying the name of the outcome being displayed
%                 --> Ex: 'progression'
% 3. fSetNames: Cell of strings specifying the name of the type of feature
%               set analyzed.
%               --> Ex: {'T1W_T2W','T1W_T2F','T1CE_T2W','T1CE_T2F'}
% 4. metric: String specifying the metric to display.
%            --> 'AUC632'
% 5. maxOrder: Integer specifying the maximal multivariable model order.
%              --> Ex: 10
% 6. pathFig: (optional).  Full path to where figure is saved without
%             displaying it. Put '' for displaying the figure and not
%             saving it to 'pathFig' (default).
%             --> Ex: ''
% -------------------------------------------------------------------------
% AUTHOR(S): Martin Vallieres <mart.vallieres@gmail.com>
% -------------------------------------------------------------------------
% HISTORY:
% - Creation: January 2017
%--------------------------------------------------------------------------
% STATEMENT:
% This file is part of <https://github.com/mvallieres/radiomics/>,
% a package providing MATLAB programming tools for radiomics analysis.
% --> Copyright (C) 2015-2017  Martin Vallieres
%
%    This package is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    This package is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with this package.  If not, see <http://www.gnu.org/licenses/>.
% -------------------------------------------------------------------------

if nargin < 6
    pathFig = '';
end

startpath = pwd;
cd(pathResults)

signs = {'-r',':b','--g','-.y'};
nFSET = numel(fSetNames);

maxOrderChosen = maxOrder;

if isempty(pathFig)
    figure
else
    h = figure('visible','off');
end
for i = 1:nFSET
    fSET = fSetNames{i};
    results = load(['RESULTS_',fSET,'_',nameOutcome]); results = struct2cell(results); results = results{1};
    nOrders = numel(fieldnames(results));
    if nOrders < maxOrderChosen
        maxOrder = nOrders;
    else
        maxOrder = maxOrderChosen;
    end
    val = zeros(maxOrder,1);
    val_SE = zeros(maxOrder,1);
    for j = 1:maxOrder
        orderName = ['Order',num2str(j)];
        val(j,1) = results.(orderName).(metric);
        val_SE(j,1) = results.(orderName).(['SE_',metric]);
    end
    errorbar(1:maxOrder,val(:,1),val_SE(:,1),signs{i},'LineWidth',3,'MarkerFaceColor',signs{i}(end),'MarkerSize',6)
    hold on
end
set(gca,'FontSize',20)
xlabel('Model Order','FontSize',24)
ylabel('Prediction performance','FontSize',24)
ind = strfind(metric,'632');
if ~isempty(ind)
    metric = [metric,'+'];
end
metric = [metric(1:ind-1),'_{',metric(ind:end),'}'];
ind = strfind(nameOutcome,'Death');
if ~isempty(ind)
    nameOutcome(ind:ind+4) = [];
    nameOutcome = ['Survival',nameOutcome];
end
titleName = [nameOutcome,' -- ',metric];
title(titleName,'FontSize',30,'FontWeight','bold')
legend(fSetNames,'Location','SouthEast')
axis([0 maxOrderChosen+1 0.5 1])
set(gca,'XTick',[1 2 3 4 5 6 7 8 9 10])

if ~isempty(pathFig)
    cd(pathFig)
    saveas(h,titleName,'fig')
end

cd(startpath)
end


function [ResultsMaleFemale] = compareMaleFemale(male,female)
% This function compares basic features of the male and female whole-body
% metabolic models
%
% [ResultsMaleFemale] = compareMaleFemale(male,female)
%
% INPUT
% male                  model structure (male whole-body metabolic model)
% female                model structure (female whole-body metabolic model)
%
% OUTPUT
% ResultsMaleFemale     structure containing the basic differences and
%                       commenalities between male and female model
%
% Ines Thiele 2017

% reactions unique to male
ResultsMaleFemale.MaleOnly = setdiff(male.rxns,female.rxns);
ResultsMaleFemale.FemaleOnly = setdiff(female.rxns,male.rxns);
ResultsMaleFemale.BothGender = intersect(female.rxns,male.rxns);

[maleOrgans]=unique(strtok(male.rxns,'_'));
[femaleOrgans]=unique(strtok(female.rxns,'_'));

for i = 1 : length(maleOrgans)
    ResultsMaleFemale.OrgansNumRxnMale(i,1) = length(strmatch(maleOrgans(i),male.rxns));
    ResultsMaleFemale.OrgansNumRxnMale(i,2) = length(strmatch(maleOrgans(i),ResultsMaleFemale.MaleOnly));
    % fraction
    ResultsMaleFemale.OrgansNumRxnMale(i,3) = ResultsMaleFemale.OrgansNumRxnMale(i,2)/ResultsMaleFemale.OrgansNumRxnMale(i,1);
end

for i = 1 : length(femaleOrgans)
    ResultsMaleFemale.OrgansNumRxnFemale(i,1) = length(strmatch(femaleOrgans(i),female.rxns));
    ResultsMaleFemale.OrgansNumRxnFemale(i,2) = length(strmatch(femaleOrgans(i),ResultsMaleFemale.FemaleOnly));
    % fraction
    ResultsMaleFemale.OrgansNumRxnFemale(i,3) = ResultsMaleFemale.OrgansNumRxnFemale(i,2)/ResultsMaleFemale.OrgansNumRxnFemale(i,1);
end

ResultsMaleFemale.maleOrgans = maleOrgans;
ResultsMaleFemale.femaleOrgans = femaleOrgans;

%get subsystems for gall rxns
FemaleSS = female.subSystems(find(ismember(female.rxns,ResultsMaleFemale.FemaleOnly(strmatch('Gall_',ResultsMaleFemale.FemaleOnly)))));
ResultsMaleFemale.FemaleGallSSEnrich = unique(FemaleSS);
for i = 1 : length(ResultsMaleFemale.FemaleGallSSEnrich)
    ResultsMaleFemale.FemaleGallSSEnrich{i,2} = num2str(length(strmatch(ResultsMaleFemale.FemaleGallSSEnrich{i},FemaleSS,'exact')));
end
MaleSS = male.subSystems(find(ismember(male.rxns,ResultsMaleFemale.MaleOnly(strmatch('Gall_',ResultsMaleFemale.MaleOnly)))));
ResultsMaleFemale.MaleGallSSEnrich = unique(MaleSS);
for i = 1 : length(ResultsMaleFemale.MaleGallSSEnrich)
    ResultsMaleFemale.MaleGallSSEnrich{i,2} = num2str(length(strmatch(ResultsMaleFemale.MaleGallSSEnrich{i},MaleSS,'exact')));
end

% unique biofluid exchange reactions

ResultsMaleFemale.MaleOnlyBiofluid = ResultsMaleFemale.MaleOnly(find(~cellfun(@isempty,strfind(ResultsMaleFemale.MaleOnly,'_EX_'))));
ResultsMaleFemale.FemaleOnlyBiofluid = ResultsMaleFemale.FemaleOnly(find(~cellfun(@isempty,strfind(ResultsMaleFemale.FemaleOnly,'_EX_'))));


function mrInit_updateSessiontSeries()
%
% USAGE: Takes a session that has already been initialized with an older
% version of mrInit and update it to the newest version. This version
% is of 2013-05-05 and it no longer uses tSeries data in the form of
% matrices, instead saving tSeries data to a nifti and using that.
%
% INPUT: N/A, no input is used. As long as the user is in the directory of
% the session to be migrated, this should work correctly.
%
% OUTPUT: N/A, no output is given. The error handling has been upgraded to
% use built in matlab try-catch blocks.
%
% This migration tool takes a series of folders of tSeries*.mat files and
% makes some assumptions about their orientation. Specifically, it is assumed
% that these are already in the normal display format.
% All of the tSeries data is loaded and the migration tool creates
% a nifti structure around this data, saves it to the filesystem and writes
% the information about its location in the session and datatype global
% variables, before saving these to mrSESSION.mat as well.

try
    loadSession;
    mrGlobals;

    %Before we reset mrSESSION, let's save a backup
    copyfile('mrSESSION.mat','mrSESSION_tSeriesMigrationBackup.mat');

    %Now that we have the number of scans, we know how many tSeries nifti
    %files we will need to create

    % Use local paths, not absolute paths
    % inplaneBasePath = fullfile(pwd,'Inplane');
    inplaneBasePath = 'Inplane';

    for dtNum = 1:numel(dataTYPES)
        fprintf('Starting dataTYPE number %d\n', dtNum);
        tSeriesOutPath = fullfile(inplaneBasePath, dtGet(dataTYPES(dtNum),'Name'));
        tSeriesInBasePath = fullfile(tSeriesOutPath,'TSeries');

        if exist(fullfile(tSeriesInBasePath,'Scan1','tSeries1.mat'),'file')
            %Checks to see if there is any inplane tSeries data in this
            %dataTYPE if there is, then does all of the processing

            numScans = dtGet(dataTYPES(dtNum),'N Scans');

            keepFrames = zeros(numScans,2);

            for scan = 1:numScans
                fprintf('Starting scan number %d\n', scan);
                % For each scan, go through each scan directory, read in all of the
                % matrix files and then build the data for a nifti from them.
                numSlices = dtGet(dataTYPES(dtNum),'N Slices', scan);
                tSeriesInFolder = fullfile(tSeriesInBasePath,['Scan' num2str(scan)]);
                dimSize = [dtGet(dataTYPES(dtNum),'N Frames', scan) dtGet(dataTYPES(dtNum),'Func Size', scan) dtGet(dataTYPES(dtNum),'N Slices', scan)];
                tSeries = zeros(dimSize);
                for slice = 1:numSlices
                    tSeriesInFile = fullfile(HOMEDIR, tSeriesInFolder,['tSeries' num2str(slice) '.mat']);
                    tSeriesIn = load(tSeriesInFile);
                    tSeriesIn = reshape(tSeriesIn.tSeries, dimSize(1:3));
                    tSeries(:,:,:,slice) = tSeriesIn;
                end %for

                % The following transform will preserve the orientation of the data
                % across the migration, such that inplane to vAnatomy xforms do not
                % need to change, nor do parameter maps, ROIs, etc. The permute([2 1])
                % followed by flipdim(2) effectively converts from x/y coordinates to
                % row/column coordinates. The reason we do this is that the old
                % vistasoft (prior to the move to NIFTIs) did this transform when
                % showing the slices as images, whereas the current code simply pulls
                % the data array from a nifti (after applying a standard xform to the
                % nifti), and uses an image tool such as imagesc slice by slice without
                % re-orienting the array. Since we no longer do this xform each time we
                % show the data, we must do it here as part of the migration if want
                % the migrated data to appear the same way as the pre-migrated data.
                % See also mrInit_updateInplaneSession.m.
                tSeries = permute(tSeries,[3 2 4 1]); %Standard format: freq phase slice time
                tSeries = flip(tSeries, 2);
                %Note: this needed to be changed to reflect the fact that
                %MATLAB stores values row, column, etc. and not column,
                %row,

                %Create the freq, phase and slice dimensions, assuming that we are in
                %standard format
                freqPhaseSliceDims = [1 2 3];

                %Create the slice information
                % We are assuming that the voxels are the same size in all
                % of the dataTYPES
                funcVoxel = sessionGet(mrSESSION,'Functional Voxel Size',scan);

                xform = [[diag(1./funcVoxel); 0 0 0], size(tSeries)'/2];

                funcVoxel(4) = dtGet(dataTYPES(dtNum),'Frame Period',scan);

                sliceInfo = [3 0 dtGet(dataTYPES(dtNum),'N Slices',scan)-1 funcVoxel(4)];

                %Build the nifti from the components above
                nii = niftiCreate('data',tSeries,'qto_xyz',xform,'freq_dim',freqPhaseSliceDims,'slice_code',sliceInfo);

                %However, this does not create the proper pix dims, so let's fix that
                nii = niftiSet(nii,'Pix dim',funcVoxel);

                keepFrames(scan, 1) = 0;
                keepFrames(scan, 2) = -1;

                mrSESSION = sessionSet(mrSESSION,'Keep Frames',keepFrames, scan);

                tSeriesOut = fullfile(tSeriesInBasePath,['tSeriesScan' num2str(scan) '.nii.gz']);

                nii = niftiSet(nii,'File Path',tSeriesOut);

                dataTYPES(dtNum) = dtSet(dataTYPES(dtNum),'Inplane Path',tSeriesOut,scan);
                dataTYPES(dtNum) = dtSet(dataTYPES(dtNum),'Keep Frames', keepFrames, scan);

                niftiWrite(nii,tSeriesOut);

                mrSESSION = sessionSet(mrSESSION,'Version','2.1');

                %Update the session variables
                save('mrSESSION.mat', 'mrSESSION','-append');
                save('mrSESSION.mat', 'dataTYPES','-append');

                % we already wrote the nifti 4 lines above. this is
                % redundant.
                %   writeFileNifti(nii);

                fprintf('Finished scan number %d\n', scan)
            end %for

        end %if
        fprintf('Finished dataTYPE number %d\n', dtNum)
    end %for

catch err
    warning(['There was an error when attempting to update your session.',...
        'No changes have been made to your system. Please run the update code again.']);
    rethrow(err);
end %try

return


%yuv2yuv can change the resolution and format of YUV-Files.
%	yuv2yuv('Filename_old',width_old,height_old,format_old,'Filename_new',w
%	idth_new,height_new,format_new) read one YUV-File with the
%	specified resolution and format and write it to a second YUV-File with
%	the specified resolution and format.
%
%	Filename_old --> Name of original File (e.g. 'Test_old.yuv')
%   width_old    --> width of original frame  (e.g. 352)
%   height_old   --> height of original frame (e.g. 280)
%   format_old   --> subsampling rate of original YUV-File('400','411','420','422' or '444')
%	Filename_new --> Name of new File (e.g. 'Test_new.yuv')
%   width_new    --> width of new frame  (e.g. 704)
%   height_new   --> height of new frame (e.g. 560)
%   format_new   --> subsampling rate of new YUV-File('400','411','420','422' or '444')
%example: yuv2yuv('Test_old.yuv',352,288,'420','Test_new.yuv',704,560,'400')

function yuv2yuv(File_old,width_old,height_old,format_old,File_new,width_new,height_new,format_new)

    %set factor for UV-sampling
    [fwidth_old,fheight_old] = getformatfactor(format_old);
    [fwidth_new,fheight_new] = getformatfactor(format_new);
    %get Filesize and Framenumber of original File
    filep = dir(File_old);
    fileBytes = filep.bytes; %Filesize
    clear filep
    framenumber = fileBytes/(width_old*height_old*(1+2*fheight_old*fwidth_old)); %Framenumber
    if mod(framenumber,1) ~= 0
        display('Error: wrong resolution, format or filesize');
    else
        fclose(fopen(File_new,'w')); %Init File
        h = waitbar(0,'Please wait ... ');
        %read YUV-Frames
        for cntf = 1:1:framenumber
            waitbar(cntf/framenumber,h);
            YUV     = loadFileYUV(width_old,height_old,cntf,File_old,fheight_old,fwidth_old);
            YUV_new = imresize(YUV,[height_new width_new],'bicubic');
            save_yuv(YUV_new,File_new,width_new,height_new,fheight_new,fwidth_new);
        end
        close(h);
    end

%get factor for YUV-subsampling
function [fwidth,fheight] = getformatfactor(format)
    fwidth = 0.5;
    fheight= 0.5;
    if strcmp(format,'400')
        fwidth = 0;
        fheight= 0;
    elseif strcmp(format,'411')
        fwidth = 0.25;
        fheight= 1;
    elseif strcmp(format,'420')
        fwidth = 0.5;
        fheight= 0.5;
    elseif strcmp(format,'422')
        fwidth = 0.5;
        fheight= 1;
    elseif strcmp(format,'444')
        fwidth = 1;
        fheight= 1;
    else
        display('Error: wrong format');
    end

% read YUV-data from file
function YUV = loadFileYUV(width,heigth,Frame,fileName,Teil_h,Teil_b)
    % get size of U and V
    fileId = fopen(fileName,'r');
    width_h = width*Teil_b;
    heigth_h = heigth*Teil_h;
    % compute factor for framesize
    factor = 1+(Teil_h*Teil_b)*2;
    % compute framesize
    framesize = width*heigth;

    fseek(fileId,(Frame-1)*factor*framesize, 'bof');
    % create Y-Matrix
    YMatrix = fread(fileId, width * heigth, 'uchar');
    YMatrix = int16(reshape(YMatrix,width,heigth)');
    % create U- and V- Matrix
    if Teil_h == 0
        UMatrix = 0;
        VMatrix = 0;
    else
        UMatrix = fread(fileId,width_h * heigth_h, 'uchar');
        UMatrix = int16(UMatrix);
        UMatrix = reshape(UMatrix,width_h, heigth_h).';

        VMatrix = fread(fileId,width_h * heigth_h, 'uchar');
        VMatrix = int16(VMatrix);
        VMatrix = reshape(VMatrix,width_h, heigth_h).';
    end
    % compose the YUV-matrix:
    YUV(1:heigth,1:width,1) = YMatrix;

    if Teil_h == 0
        YUV(:,:,2) = 127;
        YUV(:,:,3) = 127;
    end
    % consideration of the subsampling of U and V
    if Teil_b == 1
        UMatrix1(:,:) = UMatrix(:,:);
        VMatrix1(:,:) = VMatrix(:,:);

    elseif Teil_b == 0.5
        UMatrix1(1:heigth_h,1:width) = int16(0);
        UMatrix1(1:heigth_h,1:2:end) = UMatrix(:,1:1:end);
        UMatrix1(1:heigth_h,2:2:end) = UMatrix(:,1:1:end);

        VMatrix1(1:heigth_h,1:width) = int16(0);
        VMatrix1(1:heigth_h,1:2:end) = VMatrix(:,1:1:end);
        VMatrix1(1:heigth_h,2:2:end) = VMatrix(:,1:1:end);

    elseif Teil_b == 0.25
        UMatrix1(1:heigth_h,1:width) = int16(0);
        UMatrix1(1:heigth_h,1:4:end) = UMatrix(:,1:1:end);
        UMatrix1(1:heigth_h,2:4:end) = UMatrix(:,1:1:end);
        UMatrix1(1:heigth_h,3:4:end) = UMatrix(:,1:1:end);
        UMatrix1(1:heigth_h,4:4:end) = UMatrix(:,1:1:end);

        VMatrix1(1:heigth_h,1:width) = int16(0);
        VMatrix1(1:heigth_h,1:4:end) = VMatrix(:,1:1:end);
        VMatrix1(1:heigth_h,2:4:end) = VMatrix(:,1:1:end);
        VMatrix1(1:heigth_h,3:4:end) = VMatrix(:,1:1:end);
        VMatrix1(1:heigth_h,4:4:end) = VMatrix(:,1:1:end);
    end

    if Teil_h == 1
        YUV(:,:,2) = UMatrix1(:,:);
        YUV(:,:,3) = VMatrix1(:,:);

    elseif Teil_h == 0.5
        YUV(1:heigth,1:width,2) = int16(0);
        YUV(1:2:end,:,2) = UMatrix1(:,:);
        YUV(2:2:end,:,2) = UMatrix1(:,:);

        YUV(1:heigth,1:width,3) = int16(0);
        YUV(1:2:end,:,3) = VMatrix1(:,:);
        YUV(2:2:end,:,3) = VMatrix1(:,:);

    elseif Teil_h == 0.25
        YUV(1:heigth,1:width,2) = int16(0);
        YUV(1:4:end,:,2) = UMatrix1(:,:);
        YUV(2:4:end,:,2) = UMatrix1(:,:);
        YUV(3:4:end,:,2) = UMatrix1(:,:);
        YUV(4:4:end,:,2) = UMatrix1(:,:);

        YUV(1:heigth,1:width) = int16(0);
        YUV(1:4:end,:,3) = VMatrix1(:,:);
        YUV(2:4:end,:,3) = VMatrix1(:,:);
        YUV(3:4:end,:,3) = VMatrix1(:,:);
        YUV(4:4:end,:,3) = VMatrix1(:,:);
    end
    YUV = uint8(YUV);
    fclose(fileId);

%Save YUV-Data to File
function save_yuv(data,video_file,BreiteV,HoeheV,HoehenteilerV,BreitenteilerV)

    %get Resolution od Data
    datasize = size(data);
    datasizelength = length(datasize);

    %open File
    fid = fopen(video_file,'a');

    %subsampling of U and V
    if datasizelength == 2 | HoehenteilerV == 0
        %4:0:0
        y(1:HoeheV,1:BreiteV) = data(:,:,1);
    elseif datasizelength == 3
        y(1:HoeheV,1:BreiteV) = double(data(:,:,1));
        u(1:HoeheV,1:BreiteV) = double(data(:,:,2));
        v(1:HoeheV,1:BreiteV) = double(data(:,:,3));
        if BreitenteilerV == 1
            %4:1:1
            u2 = u;
            v2 = v;
        elseif HoehenteilerV == 0.5
            %4:2:0
            u2(1:HoeheV/2,1:BreiteV/2) = u(1:2:end,1:2:end)+u(2:2:end,1:2:end)+u(1:2:end,2:2:end)+u(2:2:end,2:2:end);
            u2                         = u2/4;
            v2(1:HoeheV/2,1:BreiteV/2) = v(1:2:end,1:2:end)+v(2:2:end,1:2:end)+v(1:2:end,2:2:end)+v(2:2:end,2:2:end);
            v2                         = v2/4;
        elseif BreitenteilerV == 0.25
            %4:1:1
            u2(1:HoeheV,1:BreiteV/4) = u(:,1:4:end)+u(:,2:4:end)+u(:,3:4:end)+u(:,4:4:end);
            u2                       = u2/4;
            v2(1:HoeheV,1:BreiteV/4) = v(:,1:4:end)+v(:,2:4:end)+v(:,3:4:end)+v(:,4:4:end);
            v2                       = v2/4;
        elseif BreitenteilerV == 0.5 & HoehenteilerV == 1
            %4:2:2
            u2(1:HoeheV,1:BreiteV/2) = u(:,1:2:end)+u(:,2:2:end);
            u2                       = u2/2;
            v2(1:HoeheV,1:BreiteV/2) = v(:,1:2:end)+v(:,2:2:end);
            v2                       = v2/2;
        end
    end

    fwrite(fid,uint8(y'),'uchar'); %writes Y-Data

    if HoehenteilerV ~= 0
        %writes U- and V-Data if no 4:0:0 format
        fwrite(fid,uint8(u2'),'uchar');
        fwrite(fid,uint8(v2'),'uchar');
    end

    fclose(fid);


function [charData] = srcCharLayerForward(W_rnn, W_emb, input, mask, charMap, vocabSize, params, isTest)
% Running char layer forward to compute word representations
% Input:
%   W_rnn: recurrent connections of multiple layers, e.g., W_rnn{ll}.
%   input: indices for the current batch
%   isTest: 1 -- don't store intermediate results in each state
%   isDecoder: 0 -- encoder, 1 -- decoder
% Output:
%   charData
%
% Thang Luong @ 2015, <lmthang@stanford.edu>

  charData.params = params;
  charData.params.numLayers = params.charNumLayers;

  % find rare words
  charData.rareFlags = input > params.srcCharShortList;
  charData.rareWords = unique(input(charData.rareFlags));

  % sample from frequent words
  if isTest == 0 && params.charSrcSample > 0
    % select by types: not masked and not unk
    freqWords = unique(input(~charData.rareFlags & mask & (input ~= params.srcUnk)));
    numSelect = floor(length(freqWords)*params.charSrcSample);
    perm = randperm(length(freqWords));
    selectFreqWords = freqWords(perm(1:numSelect));

    % assert
    if params.assert
      assert(isempty(intersect(charData.rareWords, selectFreqWords)) == 1);
      assert(ismember(params.srcSos, selectFreqWords) == 0);
    end

    % update rare words and flags
    charData.rareWords = union(charData.rareWords, selectFreqWords);
    charData.rareFlags = ismember(input, charData.rareWords);

    if params.assert
      assert(isempty(find(charData.rareWords == params.srcUnk, 1)));
    end
  end

  charData.numRareWords = length(charData.rareWords);
  charSeqs = charMap(charData.rareWords);
  seqLens = cellfun(@(x) length(x), charSeqs);

  if charData.numRareWords > 0
    charData.params.curBatchSize = charData.numRareWords;
    [charData.batch, charData.mask, charData.maxLen, charData.numSeqs] = leftPad(charMap(charData.rareWords), seqLens, params.srcCharSos, params.srcCharEos);

    charData.rnnFlags = struct('decode', 0, 'test', isTest, 'attn', 0, 'feedInput', 0, 'charSrcRep', 0, 'charTgtGen', 0);
    zeroState = createZeroState(charData.params);
    [charData.states, ~, ~] = rnnLayerForward(W_rnn, W_emb, zeroState, charData.batch, charData.mask, charData.params, charData.rnnFlags, [], [], []);
    charData.rareWordReps = charData.states{end}{end}.h_t;
    charData.rareWordMap = zeros(vocabSize, 1);
    charData.rareWordMap(charData.rareWords) = 1:charData.numRareWords;
  end
end


% POP_SELECT - given an input EEG dataset structure, output a new EEG data structure
%                retaining and/or excluding specified time/latency, data point, channel,
%                and/or epoch range(s).
% Usage:
%   >> OUTEEG = pop_select(INEEG, 'key1', value1, 'key2', value2 ...);
%
% Graphic interface:
%   "Time range" - [edit box] RETAIN only the indicated epoch latency or continuous data
%                  time range: [low high] in ms, inclusive. For continuous data, several
%                  time ranges may be specified, separated by semicolons.
%                  Example: "5 10; 12 EEG.xmax" will retain the indicated
%                  stretches of continuous data, and remove data portions outside
%                  the indicated ranges, e.g. from 0 s to 5 s and from 10 s to 12 s.
%                  Command line equivalent: 'time' (or 'notime' - see below)
%   "Time range" - [checkbox] EXCLUDE the indicated latency range(s) from the data.
%                  For epoched data, it is not possible to remove a range of latencies
%                  from the middle of the epoch, so either the low and/or the high values
%                  in the specified latency range (see above) must be at an epoch boundary
%                  (EEG.xmin, EEGxmax).  Command line equivalent: [if checked] 'notime'
%   "Point range" - [edit box] RETAIN the indicated data point range(s).
%                  Same options as for the "Time range" features (above).
%                  Command line equivalent: 'point' (or 'nopoint' - see below).
%   "Point range" - [checkbox] EXCLUDE the indicated point range(s).
%                  Command line equivalent: [if checked] 'nopoint'
%   "Epoch range" - [edit box] RETAIN the indicated data epoch indices in the dataset.
%                  This checkbox is only visible for epoched datasets.
%                  Command line equivalent: 'trial' (or 'notrial' - see below)
%   "Epoch range" - [checkbox] EXCLUDE the specified data epochs.
%                   Command line equivalent: [if checked] 'notrial'
%   "Channel range" - [edit box] RETAIN the indicated vector of data channels
%                  Command line equivalent: 'channel' (or 'nochannel' - see below)
%   "Channel range" - [checkbox] EXCLUDE the indicated channels.
%                  Command line equivalent: [if checked] 'nochannel'
%   "..." - [button] select channels by name.
%   "Scroll dataset" - [button] call the EEGPLOT function to scroll the
%                  channel activities in a new window for visual inspection.
%                  Commandline equivalent: EEGPLOT - see its help for details.
% Inputs:
%   INEEG         - input EEG dataset structure
%
% Optional inputs
%   'time'        - [min max] in seconds. Epoch latency or continuous data time range
%                   to retain in the new dataset, (Note: not ms, as in the GUI text entry
%                   above). For continuous data (only), several time ranges can be specified,
%                   separated by semicolons. Example: "5 10; 12 EEG.xmax" will retain
%                   the indicated times ranges, removing data  outside the indicated ranges
%                   e.g. here from 0 to 5 s and from 10 s to 12 s. (See also, 'notime')
%   'rmtime'      - [min max] in seconds. Epoch latency or continuous dataset time range
%                   to exclude from the new dataset. For continuous data, may be
%                   [min1 max1; min2 max2; ...] to exclude several time ranges. For epoched
%                   data, the latency range must include an epoch boundary, as latency
%                   ranges in the middle of epochs cannot be removed from epoched data.
%   'point'       - [min max] epoch or continuous data point range to retain in the new
%                   dataset. For continuous datasets, this may be [min1 max1; min2 max2; ...]
%                   to retain several point ranges. (Notes: If both 'point'/'nopoint' and
%                   'time' | 'notime' are specified, the 'point' limit values take precedence.
%                   The 'point' argument was originally a point vector, now deprecated).
%   'rmpoint'     - [min max] epoch or continuous data point range to exclude in the new dataset.
%                   For epoched data, the point range must include either the first (0)
%                   or the last point (EEG.pnts), as a central point range cannot be removed.
%   'trial'       - [integer array] array of trial indices to retain in the new dataset
%   'rmtrial'     - [integer array] array of trial indices to exclude from the new dataset
%   'sorttrial'   - ['on'|'off'] sort trial indices before extracting them (default: 'on').
%   'checkchans'  - ['on'|'off'] check that channels are present before
%                   rejecting them (default: 'on')
%   'channel'     - vector of channel indices to retain in the new
%                   dataset. Can also be a cell array of channel names.
%   'rmchannel'   - vector of channel indices to exclude from the new
%                   dataset. Can also be a cell array of channel names.
%   'chantype'    - [string|cell] list of channel types to keep
%   'rmchantype'  - [string|cell] list of channel types to remove
%
% Outputs:
%   OUTEEG        - new EEG dataset structure
%
% Note: This function performs a conjunction (AND) of all its optional inputs.
%       Using negative counterparts of all options, any logical combination is
%       possible. Legacy input 'notrial', 'notime', 'nochannel', 'nopoint'
%       are still supported.
%
% Author: Arnaud Delorme, CNL/Salk Institute, 2001; SCCN/INC/UCSD, 2002-
%
% see also: EEGLAB

% Copyright (C) 2001 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

% 01-25-02 reformated help & license -ad
% 01-26-02 changed the format for events and trial conditions -ad
% 02-04-02 changed display format and allow for negation of inputs -ad
% 02-17-02 removed the event removal -ad
% 03-17-02 added channel info subsets selection -ad
% 03-21-02 added event latency recalculation -ad

function [EEG, com] = pop_select( EEG, varargin)

com = '';
if nargin < 1
    help pop_select;
    return;
end
if isempty(EEG(1).data)
    disp('Pop_select error: cannot process empty dataset'); return;
end

if nargin < 2
   geometry = { [1 1 1] [1 1 0.25 0.23 0.51] [1 1 0.25 0.23 0.51] [1 1 0.25 0.23 0.51] [1 1 0.25 0.23 0.51] ...
           [1 1 0.25 0.23 0.51] [1] [1 1 1]};
   enabletype = ~isempty(EEG(1).chanlocs) && isfield(EEG(1).chanlocs, 'type') && ~isempty(EEG(1).chanlocs(1).type);
   uilist = { ...
         { 'Style', 'text', 'string', 'Select data in:', 'fontweight', 'bold'  }, ...
         { 'Style', 'text', 'string', 'Input desired range', 'fontweight', 'bold'  }, ...
         { 'Style', 'text', 'string', 'on->remove these', 'fontweight', 'bold'  }, ...
         { 'Style', 'text', 'string', 'Time range [min max] (s)', 'fontangle', fastif(length(EEG)>1, 'italic', 'normal') }, ...
         { 'Style', 'edit', 'string', '', 'enable', 'on' }, ...
         { }, { 'Style', 'checkbox', 'string', '    ', 'enable', 'on' },{ }, ...
         ...
         { 'Style', 'text', 'string', 'Point range (ex: [1 10])', 'fontangle', fastif(length(EEG)>1, 'italic', 'normal') }, ...
         { 'Style', 'edit', 'string', '', 'enable', 'on' }, ...
         { }, { 'Style', 'checkbox', 'string', '    ', 'enable', 'on' },{ }, ...
         ...
         { 'Style', 'text', 'string', 'Epoch range (ex: 3:2:10)', 'fontangle', fastif(length(EEG)>1, 'italic', 'normal') }, ...
         { 'Style', 'edit', 'string', '', 'enable', 'on' }, ...
         { }, { 'Style', 'checkbox', 'string', '    ', 'enable', 'on' },{ }, ...
         ...
         { 'Style', 'text', 'string', 'Channel(s)' }, ...
         { 'Style', 'edit', 'string', '', 'tag', 'chans' }, ...
         { }, { 'Style', 'checkbox', 'string', '    ' }, ...
         { 'style' 'pushbutton' 'string'  '...', 'enable' fastif(isempty(EEG(1).chanlocs), 'off', 'on') ...
           'callback' 'pop_chansel(get(gcbf, ''userdata''), ''field'', ''labels'',   ''handle'', findobj(''parent'', gcbf, ''tag'', ''chans''));' }, ...
           ...
         { 'Style', 'text', 'string', 'Channel type(s)' }, ...
         { 'Style', 'edit', 'string', '', 'tag', 'chantype' }, ...
         { }, { 'Style', 'checkbox', 'string', '    ' }, ...
         { 'style' 'pushbutton' 'string'  '...', 'enable' fastif(enabletype, 'on', 'off') ...
           'callback'  'pop_chansel(get(gcbf, ''userdata''), ''field'', ''type'',   ''handle'', findobj(''parent'', gcbf, ''tag'', ''chantype''));' }, ...
         ...
           { }, { }, { 'Style', 'pushbutton', 'string', 'Scroll dataset', 'enable', fastif(length(EEG)>1, 'off', 'on'), 'callback', ...
                          'eegplot(EEG.data, ''srate'', EEG.srate, ''winlength'', 5, ''limits'', [EEG.xmin EEG.xmax]*1000, ''position'', [100 300 800 500], ''xgrid'', ''off'', ''eloc_file'', EEG.chanlocs);' } {}};
%           'callback' 'tmplabels = get(gcbf, ''userdata''); [~, tmpvalchan] = pop_chansel(tmplabels, ''withindex'', ''on''); set(findobj(gcbf, ''tag'', ''chans''), ''string'',tmpvalchan); clear tmplabels tmpvalchan' }, ...
   chanlocs = eeg_mergelocs(EEG.chanlocs);
   results = inputgui( 'geometry', geometry, 'uilist', uilist, 'helpcom', 'pophelp(''pop_select'');', 'title', 'Select data -- pop_select()', 'userdata', chanlocs );
   if isempty(results), return; end

   % decode inputs
   % -------------
   args = {};
   if ~isempty( results{1} )
       if ~results{2}, args = { args{:}, 'time', eval( [ '[' results{1} ']' ] ) };
       else            args = { args{:}, 'rmtime', eval( [ '[' results{1} ']' ] ) }; end
   end

   if ~isempty( results{3} )
       if ~results{4}, args = { args{:}, 'point', eval( [ '[' results{3} ']' ] ) };
       else            args = { args{:}, 'rmpoint', eval( [ '[' results{3} ']' ] ) }; end
   end

   if ~isempty( results{5} )
       if ~results{6}, args = { args{:}, 'trial', eval( [ '[' results{5} ']' ] ) };
       else            args = { args{:}, 'rmtrial', eval( [ '[' results{5} ']' ] ) }; end
   end

   if ~isempty( results{7} )
       [ chaninds, chanlist ] = eeg_decodechan(chanlocs, results{7});
       if isempty(chanlist)
           if length(EEG) > 1 && length(unique([EEG.nbchan])) > 1
               error([ 'Cannot use channel indices when processing multiple datasets' 10 ...
                   'with some channels already removed' ])
           end
           chanlist = chaninds;
       end
       if ~results{8}, args = { args{:}, 'channel'  , chanlist };
       else            args = { args{:}, 'rmchannel', chanlist }; end
   end

   if ~isempty( results{9} )
       [ ~, chantypes ] = eeg_decodechan(chanlocs, results{9}, 'type');
       if ~results{10}, args = { args{:}, 'chantype'  , unique(chantypes) };
       else             args = { args{:}, 'rmchantype', unique(chantypes) }; end
   end

else
    args = varargin;
end

% process multiple datasets
% -------------------------
if length(EEG) > 1
    if nargin < 2
        [ EEG, com ] = eeg_eval( 'pop_select', EEG, 'warning', 'on', 'params', args);
    else
        [ EEG, com ] = eeg_eval( 'pop_select', EEG, 'warning', 'off', 'params',args);
    end
    return;
end

%----------------------------AMICA---------------------------------
if isfield(EEG.etc,'amica') && isfield(EEG.etc.amica,'prob_added')
    for index = 1:2:length(args)
       if strcmpi(args{index}, 'channel')
           args{index+1} = [ args{index+1} EEG.nbchan-(0:2*EEG.etc.amica.num_models-1)];
       end
    end
end
%--------------------------------------------------------------------

g = finputcheck(args, { 'time'    'real'      []         []; ...
                        'notime'  'real'      []         []; ...
                        'rmtime'  'real'      []         []; ...
                        'trial'   'integer'   []         [1:EEG.trials]; ...
                        'notrial' 'integer'   []         []; ...
                        'rmtrial' 'integer'   []         []; ...
                        'point'   'integer'   []         []; ...
                        'nopoint' 'integer'   []         []; ...
                        'rmpoint' 'integer'   []         []; ...
                        'channel'   { 'integer','cell' }  []   [];
                        'nochannel' { 'integer','cell' }   []  [];
                        'rmchannel' { 'integer','cell' }   []  [];
                        'chantype'    { 'string','cell' }    []  {};
                        'rmchantype'  { 'string','cell' }    []  {};
                        'trialcond'   'integer'   []         []; ...
                        'notrialcond' 'integer'   []         []; ...
                        'sort'        'integer'   []         []; ...
                        'sorttrial'   'string'    { 'on','off' } 'on' }, 'pop_select');
if ischar(g), error(g); end
if ~isempty(g.sort)
    if g.sort, g.sorttrial = 'on';
    else       g.sorttrial = 'off';
    end
end
if strcmpi(g.sorttrial, 'on')
    g.trial = sort(setdiff( g.trial, g.notrial ));
    if isempty(g.trial), error('Error: dataset %s is empty',EEG.filename); end
else
    g.trial(ismember(g.trial,g.notrial)) = [];
    % still warn about & remove duplicate trials (may be removed in the future)
    [p,q] = unique_bc(g.trial);
    if length(p) ~= length(g.trial)
        disp('Warning: trial selection contained duplicated elements, which were removed.');
    end
    g.trial = g.trial(sort(q));
end

% rename parameters
% -----------------
if ~isempty(g.rmtime)    g.notime    = g.rmtime; end
if ~isempty(g.rmpoint)   g.nopoint   = g.rmpoint; end
if ~isempty(g.rmtrial)   g.notrial   = g.rmtrial; end
if ~isempty(g.rmchannel) g.nochannel = g.rmchannel; end

% decode channels
% ---------------
if ~isempty(g.channel) || ~isempty(g.nochannel)
    % find channels by name
    if ~isempty(g.channel)
        if ~isempty(g.chantype) || ~isempty(g.rmchantype)
            error('You can select channels by name or by type but not both');
        end
        inds = eeg_decodechan(EEG, g.channel, 'labels', true);
        chanFlag = zeros(1, EEG.nbchan);
        chanFlag(inds) = 1;
    else
        chanFlag = ones(1, EEG.nbchan);
    end
    if ~isempty(g.nochannel)
        if ~isempty(g.chantype) || ~isempty(g.rmchantype)
            error('You can select channels by name or by type but not both');
        end
        inds = eeg_decodechan(EEG, g.nochannel, 'labels', true);
        chanFlag(inds) = 0;
    end
else
    % find channels by type
    if ~isempty(g.chantype)
        inds = eeg_decodechan(EEG, g.chantype, 'type', true);
        chanFlag = zeros(1, EEG.nbchan);
        chanFlag(inds) = 1;
    else
        chanFlag = ones(1, EEG.nbchan);
    end
    if ~isempty(g.rmchantype)
        inds = eeg_decodechan(EEG, g.rmchantype, 'type', true);
        chanFlag(inds) = 0;
    end
end
g.channel = find(chanFlag);

% time selection
% --------------
if ~isempty(g.time) && (g.time(1) < EEG.xmin*1000) && (g.time(2) > EEG.xmax*1000)
   error('Wrong time range');
end
if min(g.trial) < 1 || max( g.trial ) > EEG.trials
   error('Wrong trial range');
end
if size(g.point,2) > 2
    g.point = [g.point(1) g.point(end)];
    disp('Warning: vector format for point range is deprecated');
end
if size(g.nopoint,2) > 2
    g.nopoint = [g.nopoint(1) g.nopoint(end)];
    disp('Warning: vector format for point range is deprecated');
end
if ~isempty( g.point )
    g.time = zeros(size(g.point));
    for index = 1:length(g.point(:))
        g.time(index) = eeg_point2lat(g.point(index), 1, EEG.srate, [EEG.xmin EEG.xmax]);
    end
    g.notime = [];
end
if ~isempty( g.nopoint )
    g.notime = zeros(size(g.nopoint));
    for index = 1:length(g.nopoint(:))
        g.notime(index) = eeg_point2lat(g.nopoint(index), 1, EEG.srate, [EEG.xmin EEG.xmax]);
    end
    g.time = [];
end
if ~isempty( g.notime )
    if size(g.notime,2) ~= 2
        error('Time/point range must contain 2 columns exactly');
    end
    if g.notime(2) == EEG.xmax
        g.time = [EEG.xmin g.notime(1)];
    else
        if g.notime(1) == EEG.xmin
            g.time = [g.notime(2) EEG.xmax];
        elseif EEG.trials > 1
            error('Wrong notime range. Remember that it is not possible to remove a slice of time for data epochs.');
        end
    end
    if g.notime(end) > EEG.xmax, g.notime(end) = EEG.xmax; end
    if g.notime(1)   < EEG.xmin, g.notime(1)   = EEG.xmin; end
    if floor(max(g.notime(:))) > EEG.xmax
        error('Time/point range exceed upper data limits');
    end
    if min(g.notime(:)) < EEG.xmin
        error('Time/point range exceed lower data limits');
    end
end
if ~isempty(g.time)
    if size(g.time,2) ~= 2
        error('Time/point range must contain 2 columns exactly');
    end
    for index = 1:length(g.time)
        if g.time(index) > EEG.xmax
            g.time(index) = EEG.xmax;
            disp('Upper time limits exceed data, corrected');
        elseif g.time(index) < EEG.xmin
            g.time(index) = EEG.xmin;
            disp('Lower time limits exceed data, corrected');
        end
    end
end

% select trial values
%--------------------
if ~isempty(g.trialcond)
   try
        tt = struct( g.trialcond{:} ); catch
        error('Trial conditions format error');
   end
   ttfields = fieldnames (tt);
   for index = 1:length(ttfields)
        if ~isfield( EEG.epoch, ttfields{index} )
            error([ ttfields{index} 'is not a field of EEG.epoch' ]);
        end
        tmpepoch = EEG.epoch;
	    eval( [ 'Itriallow  = find( [ tmpepoch(:).' ttfields{index} ' ] >= tt.' ttfields{index} '(1) );' ] );
	    eval( [ 'Itrialhigh = find( [ tmpepoch(:).' ttfields{index} ' ] <= tt.' ttfields{index} '(end) );' ] );
	    Itrialtmp = intersect_bc(Itriallow, Itrialhigh);
	    g.trial = intersect_bc( g.trial(:)', Itrialtmp(:)');
   end
end

if isempty(g.trial)
   error('Empty dataset, no trial');
end
if length(g.trial) ~= EEG.trials
	fprintf('Removing %d trial(s)...\n', EEG.trials - length(g.trial));
end
if length(g.channel) ~= EEG.nbchan
	fprintf('Removing %d channel(s)...\n', EEG.nbchan - length(g.channel));
end

try
    % For AMICA probabilities...
    %-----------------------------------------------------
    if isfield(EEG.etc, 'amica') && ~isempty(EEG.etc.amica) && isfield(EEG.etc.amica, 'v_smooth') && ~isempty(EEG.etc.amica.v_smooth) && ~isfield(EEG.etc.amica,'prob_added')
        if isfield(EEG.etc.amica, 'num_models') && ~isempty(EEG.etc.amica.num_models)
            if size(EEG.data,2) == size(EEG.etc.amica.v_smooth,2) && size(EEG.data,3) == size(EEG.etc.amica.v_smooth,3) && size(EEG.etc.amica.v_smooth,1) == EEG.etc.amica.num_models

                EEG = eeg_formatamica(EEG);

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

                [EEG, com] = pop_select(EEG,args{:});

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

                EEG = eeg_reformatamica(EEG);
                EEG = eeg_checkamica(EEG);
                return;
            else
                disp('AMICA probabilities not compatible with size of data, probabilities cannot be rejected')

                disp('Resuming rejection...')
            end
        end

    end
    % ------------------------------------------------------
catch
    warnmsg = strcat('your dataset contains amica information, but the amica plugin is not installed.  Continuing and ignoring amica information.');
    warning(warnmsg)
end

% recompute latency and epoch number for events
% ---------------------------------------------
if length(g.trial) ~= EEG.trials && ~isempty(EEG.event)
    if ~isfield(EEG.event, 'epoch')
        disp('Pop_epoch warning: bad event format with epoch dataset, removing events');
        EEG.event = [];
    else
        if isfield(EEG.event, 'epoch')
            keepevent = [];
            for indexevent = 1:length(EEG.event)
                newindex = find( EEG.event(indexevent).epoch == g.trial );% For AMICA probabilities...
                %-----------------------------------------------------
                try
                    if isfield(EEG.etc, 'amica') && ~isempty(EEG.etc.amica) && isfield(EEG.etc.amica, 'v_smooth') && ~isempty(EEG.etc.amica.v_smooth) && ~isfield(EEG.etc.amica,'prob_added')
                        if isfield(EEG.etc.amica, 'num_models') && ~isempty(EEG.etc.amica.num_models)
                            if size(EEG.data,2) == size(EEG.etc.amica.v_smooth,2) && size(EEG.data,3) == size(EEG.etc.amica.v_smooth,3) && size(EEG.etc.amica.v_smooth,1) == EEG.etc.amica.num_models

                                EEG = eeg_formatamica(EEG);

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

                                [EEG, com] = pop_select(EEG,args{:});

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

                                EEG = eeg_reformatamica(EEG);
                                EEG = eeg_checkamica(EEG);
                                return;
                            else
                                disp('AMICA probabilities not compatible with size of data, probabilities cannot be rejected')

                                disp('Resuming rejection...')
                            end
                        end

                    end
                catch
                    warnmsg = strcat('your dataset contains amica information, but the amica plugin is not installed.  Continuing and ignoring amica information.');
                    warning(warnmsg)
                end;
                % ------------------------------------------------------

                if ~isempty(newindex)
                    keepevent = [keepevent indexevent];
                    if isfield(EEG.event, 'latency')
                        EEG.event(indexevent).latency = EEG.event(indexevent).latency - (EEG.event(indexevent).epoch-1)*EEG.pnts + (newindex-1)*EEG.pnts;
                    end
                    EEG.event(indexevent).epoch = newindex;
                end
            end
            diffevent = setdiff_bc([1:length(EEG.event)], keepevent);
            if ~isempty(diffevent)
                disp(['Pop_select: removing ' int2str(length(diffevent)) ' unreferenced events']);
                EEG.event(diffevent) = [];
            end
        end
    end
end

% performing removal
% ------------------
if ~isempty(g.time) || ~isempty(g.notime)
    if EEG.trials > 1
        % select new time window
        % ----------------------
        try,   tmpevent = EEG.event;
               tmpeventlatency = [ tmpevent.latency ];
        catch, tmpeventlatency = [];
        end
        alllatencies = 1-(EEG.xmin*EEG.srate); % time 0 point
        alllatencies = linspace( alllatencies, EEG.pnts*(EEG.trials-1)+alllatencies, EEG.trials);
        [EEG.data, tmptime, indices, epochevent]= epoch(EEG.data, alllatencies, ...
                                                     [g.time(1) g.time(2)]*EEG.srate, 'allevents', tmpeventlatency);
        tmptime = tmptime/EEG.srate;
        if g.time(1) ~= tmptime(1) && g.time(2)-1/EEG.srate ~= tmptime(2)
            fprintf('pop_select(): time limits have been adjusted to [%3.3f %3.3f] to fit data points limits\n', tmptime(1), tmptime(2)+1/EEG.srate);
        end
        EEG.xmin = tmptime(1);
        EEG.xmax = tmptime(2);
        EEG.pnts = size(EEG.data,2);
        alllatencies = alllatencies(indices);

        % modify the event structure accordingly (latencies and add epoch field)
        % ----------------------------------------------------------------------
        allevents = [];
        newevent = [];
        count = 1;
        if ~isempty(epochevent)
            newevent = EEG.event(1);
            for index=1:EEG.trials
                for indexevent = epochevent{index}
                    newevent(count)         = EEG.event(indexevent);
                    newevent(count).epoch   = index;
                    newevent(count).latency = newevent(count).latency - alllatencies(index) - tmptime(1)*EEG.srate + 1 + EEG.pnts*(index-1);
                    count = count + 1;
                end
            end
        end
        EEG.event = newevent;

        % erase event-related fields from the epochs
        % ------------------------------------------
        if ~isempty(EEG.epoch)
            fn = fieldnames(EEG.epoch);
            EEG.epoch = rmfield(EEG.epoch,{fn{strmatch('event',fn)}});
        end
    else
        if isempty(g.notime)
            if length(g.time) == 2 && EEG.xmin < 0
                disp('Warning: negative minimum time; unchanged to ensure correct latency of initial boundary event');
            end
            g.notime = g.time';
            g.notime = g.notime(:);
            if g.notime(1) ~= 0, g.notime = [EEG.xmin g.notime(:)'];
            else                 g.notime = [g.notime(2:end)'];
            end
            if g.time(end) == EEG.xmax, g.notime(end) = [];
            else                        g.notime(end+1) = EEG.xmax;
            end

            for index = 1:length(g.notime)
                if g.notime(index) ~= 0  && g.notime(index) ~= EEG.xmax
                    if mod(index,2), g.notime(index) = g.notime(index) + 1/EEG.srate;
                    else             g.notime(index) = g.notime(index) - 1/EEG.srate;
                    end
                end
            end
            g.notime = reshape(g.notime, 2, length(g.notime)/2)';
        end

        nbtimes = length(g.notime(:));
        [points,flag] = eeg_lat2point(g.notime(:)', ones(1,nbtimes), EEG.srate, [EEG.xmin EEG.xmax]);
        points = reshape(points, size(g.notime));

        % fixing if last region is the same
        if flag
            if ~isempty(find((points(end,1)-points(end,2))== 0)), points(end,:) = []; end
        end

        EEG = eeg_eegrej(EEG, points);
    end
end

% performing removal
% ------------------
if ~isequal(g.channel,1:size(EEG.data,1)) || ~isequal(g.trial,1:size(EEG.data,3))
    eeglab_options;
    if option_memmapdata
        % this code below is preferred for memory mapped files
        diff1 = setdiff_bc([1:size(EEG.data,1)], g.channel);
        diff2 = setdiff_bc([1:size(EEG.data,3)], g.trial);
        if ~isempty(diff1)
            EEG.data(diff1, :, :) = [];
        end
        if ~isempty(diff2)
            EEG.data(:, :, diff2) = [];
        end
    else
        EEG.data  = EEG.data(g.channel, :, g.trial);
    end
end
if ~isempty(EEG.icaact), EEG.icaact = EEG.icaact(:,:,g.trial); end
if ~isempty(EEG.chanlocs)
    if ~isfield(EEG.chaninfo, 'removedchans')
        EEG.chaninfo.removedchans = [];
    end
    try
        diff1 = setdiff_bc([1:EEG.nbchan], g.channel);
        fields = fieldnames(EEG.chanlocs);
        for iChan = diff1(:)'
            EEG.chaninfo.removedchans(end+1).(fields{1}) = EEG.chanlocs(iChan).(fields{1});
            for iField = 1:length(fields)
                EEG.chaninfo.removedchans(end).(fields{iField}) = EEG.chanlocs(iChan).(fields{iField});
            end
        end
    catch
        disp('There was an issue storing removed channels in pop_select');
    end
    EEG.chanlocs = EEG.chanlocs(g.channel);
end
EEG.trials    = length(g.trial);
EEG.pnts      = size(EEG.data,2);
EEG.nbchan    = length(g.channel);
if ~isempty(EEG.epoch)
   EEG.epoch = EEG.epoch( g.trial );
end
if ~isempty(EEG.specdata)
	if length(g.point) == EEG.pnts
   		EEG.specdata = EEG.specdata(g.channel, :, g.trial);
   	else
   		EEG.specdata = [];
   		fprintf('Warning: spectral data were removed because of the change in the number of points\n');
    end
end

% ica specific
% ------------
if ~isempty(EEG.icachansind)

    rmchans = setdiff_bc( EEG.icachansind, g.channel ); % channels to remove

    % channel sub-indices
    % -------------------
    icachans = 1:length(EEG.icachansind);
    for index = length(rmchans):-1:1
        chanind           = find(EEG.icachansind == rmchans(index));
        icachans(chanind) = [];
    end

    % new channels indices
    % --------------------
    count   = 1;
    newinds = [];
    for index = 1:length(g.channel)
        if any(EEG.icachansind == g.channel(index))
            newinds(count) = index;
            count          = count+1;
        end
    end
    EEG.icachansind = newinds;

else
    icachans = 1:size(EEG.icasphere,2);
end

if ~isempty(EEG.icawinv)
    flag_rmchan = (length(icachans) ~= size(EEG.icawinv,1));
    if  isempty(EEG.icaweights) || flag_rmchan
        EEG.icawinv    = EEG.icawinv(icachans,:);
        EEG.icaweights = pinv(EEG.icawinv);
        EEG.icasphere  = eye(size(EEG.icaweights,2));
    end
end
if ~isempty(EEG.specicaact)
    if length(g.point) == EEG.pnts
        EEG.specicaact = EEG.specicaact(icachans, :, g.trial);
    else
        EEG.specicaact = [];
        fprintf('Warning: spectral ICA data were removed because of the change in the number of points\n');
    end
end

% check if only one epoch
% -----------------------
if EEG.trials == 1
    if isfield(EEG.event, 'epoch')
        EEG.event = rmfield(EEG.event, 'epoch');
    end
    EEG.epoch = [];
end
if isfield(EEG.reject, 'gcompreject') && isequal(g.channel,1:size(EEG.data,1))
    tmpgcompreject = EEG.reject.gcompreject;
    EEG.reject = [];
    EEG.reject.gcompreject = tmpgcompreject;
else
    EEG.reject = [];
end
EEG.stats  = [];
EEG.reject.rejmanual = [];
% for stats, can adapt remove the selected trials and electrodes
% in the future to gain time -----------------------------------
EEG.stats.jp = [];
EEG = eeg_checkset(EEG, 'eventconsistency');

% generate command
% ----------------
if nargout > 1
    com = sprintf('EEG = pop_select( EEG, %s);', vararg2str(args));
end

return;

% ********* OLD, do not remove any event any more
% ********* in the future maybe do a pack event to remove events not in the time range of any epoch

if ~isempty(EEG.event)
    % go to array format if necessary
    if isstruct(EEG.event), format = 'struct';
    else                     format = 'array';
    end
    switch format, case 'struct', EEG = eventsformat(EEG, 'array'); end

    % keep only events related to the selected trials
    Indexes = [];
    Ievent  = [];
    for index = 1:length( g.trial )
        currentevents = find( EEG.event(:,2) == g.trial(index));
        Indexes = [ Indexes ones(1, length(currentevents))*index ];
        Ievent  = union_bc( Ievent, currentevents );
    end
    EEG.event = EEG.event( Ievent,: );
    EEG.event(:,2) = Indexes(:);

    switch format, case 'struct', EEG = eventsformat(EEG, 'struct'); end
end


%kPlot3D '3D Plot Object Menuform'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros Plot3D.pane file
%
% Parameters:
% MultiChoice: plot3DXOrientation 'X Orientation', default: 1: 'x orientation'
%    Choices are:
%   1: 'Width'
%   2: 'Height'
%   3: 'Depth'
%   4: 'Time'
%   5: 'Elements'
% MultiChoice: plot3DYOrientation 'Y Orientation', default: 2: 'y orientation'
%    Choices are:
%   1: 'Width'
%   2: 'Height'
%   3: 'Depth'
%   4: 'Time'
%   5: 'Elements'
% Integer: plot3DWidthOffset 'Width Offset', default: 0: 'width offset'
% Integer: plot3DHeightOffset 'Height Offset', default: 0: 'height offset'
% Integer: plot3DDepthOffset 'Depth Offset', default: 0: 'depth offset'
% Integer: plot3DTimeOffset 'Time Offset', default: 0: 'time offset'
% Integer: plot3DElementsOffset 'Elements Offset', default: 0: 'elements offset'
%
% Example: kPlot3D( {'plot3DXOrientation',1;'plot3DYOrientation',2;'plot3DWidthOffset',0;'plot3DHeightOffset',0;'plot3DDepthOffset',0;'plot3DTimeOffset',0;'plot3DElementsOffset',0})
%
% Khoros helpfile follows below:
%
% The 3D plot object supports the display of a 3D plot.
% .begin tagged
% .item "Plot Type"
% This list selection lets you set the plot type that is used by the
% 3D plot object.  Choices include: "Line Plot," "Wireframe," "Mesh,"
% "Horizon," "Scatter," "Impulse," "Contour 3D," "Contour 2D,"  or
% "Constant Shade.
% .item "Line Type"
% There are seven line types available: "Solid," "Dotted," "Dot Dash,"
% "Short Dash," "Long Dash," "Odd Dash," and "Grid Dotted."  The line type
% is not used with scatter plots or shaded plots.
% .item "Marker Type"
% This attribute only applies to plots that use a marker, ie, scatter plots.
% There is a wide variety of marker types that may be used with scatter plots.
% .item "Surface Shade Type"
% This attribute only applies to the constant shade plot type.
% It specifies what part of the data is to dictate the shading.
% "Imagery" specifies that shading is to be done on imagery (or color)
% ie, using the "d" value of each data point as defined by its C
% oord structure.  "Elevation" specifies that shading is to be done on
% elevation, ie, using the "z" value of each data point as defined
% by its Coord structure.  When "Normals" is used, the normal to each
% data point is computed, and shading is done using the normals.
% .item "Color Origination"
% When this attribute is set to "Use Foreground Color," the plot is colored in
% the foreground color.   When set to "Use Data Values," the plot is colored
% according to the plot data (see manual for more details).
% .item "Foreground Color"
% This stringlist selection lets you set the foreground color of the 3D
% plot, using the color name.  It is only used when "Color Origination"
% is set to "Use Foreground Color."
% .item "Fill Color"
% This stringlist selection lets you set the color that is used with
% filled plots.  The only filled plots are the mesh and the horizon plots.
% .item "X and Y Orientation"
% These toggles only take effect when the plot data input is provided via a
% data object (as opposed to an array of Coords).  Furthermore, they only apply
% when the plot data is stored in the value segment of the data object (as
% opposed to the location segment of the data object).  They dictate how the
% 3D plot data is to be extracted from the value segment of the data object.
% The 3D plot data is always extracted as a surface, but that surface may be
% defined over any two of the dimensions supported by the value segment. For
% example, the default surface orientation is (width x height), but you might
% specify it to be (height x depth),  (width x time), or any other combination
% of the 5 supported dimensions.
% .item "Width, Height, Depth, Time, And Elements Offsets"
% These integer selections may be set in conjunction with the "X and Y
% Orientation" toggles.  When neither the X or Y orientation" set to "Width,"
% the "Width Offset" may be used to specify the width offset at which the
% surface of plot data is to be extracted.  Similarly, "Height Offset,"
% "Depth Offset," "Time Offset" and "Elements Offset" may be used to specify
% offsets into height, depth, time, and elements whenever that dimension is
% "not" being plotted.  Note that an offset may only be used when that
% dimension of the value data is greater than 1.
% .item "Rotation About X"
% This parameter allows you to rotate the camera (the eye) about the X axis.
% Values are given in degrees, from 0 to 360.
% .item "Rotation About Y"
% This parameter allows you to rotate the camera (the eye) about the Y axis.
% Values are given in degrees, from 0 to 360.
% .item "Rotation About Z"
% This parameter allows you to rotate the camera (the eye) about the Z axis.
% Values are given in degrees, from 0 to 360.
% .item "Eye Distance"
% This parameter specifies the distance between the plot and the eye.
% The default value of 0 is right up against the bounding box of the
% plot.
% .end tagged

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

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


% ----------------------------------------------------------------------------
% function hfssCylinder(fid, Name, Axis, Center, Radius, Height, Units)
%
% Description :
% -------------
% Creates the VB script necessary to model a cylinder in HFSS.
%
% Parameters :
% ------------
% fid     - file identifier of the HFSS script file.
% Name    - name of the cylinder (in HFSS).
% Center  - center of the cylinder (specify as [x, y, z]). This is also the
%           starting point of the cylinder.
% Axis    - axis of the cylinder (specify as 'X', 'Y', or 'Z').
% Radius  - radius of the cylinder (scalar).
% Height  - height of the cylidner (from the point specified by Center).
% Units   - specify as 'in', 'mm', 'meter' or anything else defined in HFSS.
%
% Note :
% ------
%
% Example :
% ---------
% fid = fopen('myantenna.vbs', 'wt');
% ...
% hfssCylinder(fid, 'Cyl1', 'Z', [0, 0, 0], 0.1, 10, 'in');
% ----------------------------------------------------------------------------

% ----------------------------------------------------------------------------
% This file is part of HFSS-MATLAB-API.
%
% HFSS-MATLAB-API 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.
%
% HFSS-MATLAB-API 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
% Foobar; if not, write to the Free Software Foundation, Inc., 59 Temple
% Place, Suite 330, Boston, MA  02111-1307  USA
%
% Copyright 2004, Vijay Ramasami (rvc@ku.edu)
% ----------------------------------------------------------------------------
function hfssCylinder(fid, Name, Axis, Center, Radius, Height, Units)

% Cylinder Parameters.
fprintf(fid, '\n');
fprintf(fid, 'oEditor.CreateCylinder _\n');
fprintf(fid, 'Array("NAME:CylinderParameters", _\n');
fprintf(fid, '"XCenter:=", "%f%s", _\n', Center(1), Units);
fprintf(fid, '"YCenter:=", "%f%s", _\n', Center(2), Units);
fprintf(fid, '"ZCenter:=", "%f%s", _\n', Center(3), Units);
fprintf(fid, '"Radius:=", "%f%s", _\n', Radius, Units);
fprintf(fid, '"Height:=", "%f%s", _\n', Height, Units);
fprintf(fid, '"WhichAxis:=", "%s"), _\n', upper(Axis));

% Cylinder Properties.
fprintf(fid, 'Array("NAME:Attributes", _\n');
fprintf(fid, '"Name:=", "%s", _\n', Name);
fprintf(fid, '"Flags:=", "", _\n');
fprintf(fid, '"Color:=", "(132 132 193)", _\n');
fprintf(fid, '"Transparency:=", 0, _\n');
fprintf(fid, '"PartCoordinateSystem:=", "Global", _\n');
fprintf(fid, '"MaterialName:=", "vacuum", _\n');
fprintf(fid, '"SolveInside:=", true)\n');
fprintf(fid, '\n');


function test_bug1607

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_channelrepair ft_topoplotER

% During preprocessing I lost some channels which I got back through
% ft_channelrepair after which the channel order changed per subject.
% I realigned the channel order and the associated data structure of each subject
% to one reference order after which the topoplots look completely different.
% They look even worse than before realignment. Anybody got a clue where the
% confusion arises?
% Attached a script and two data files, one with reference data and one with the
% to be aligned data.

% solution
% was not a bug, instead jonas was indexing the wrong way around:
%
%     nERPdata_nD_left{isubject}.avg(:,:) = ERPdata_nD_left{isubject}.avg(loc,:);     % realign data to ref channel order
% instead of
%     nERPdata_nD_left{isubject}.avg(loc,:) = ERPdata_nD_left{isubject}.avg(:,:);     % realign data to ref channel order

ERPdata_nD_left = [];
reference_labels = [];

%load(dccnpath('/home/common/matlab/fieldtrip/data/test/bug1607/06_control_ICA_clean.mat'));
load(dccnpath('/home/common/matlab/fieldtrip/data/test/bug1607/ERPdata.mat'));
load(dccnpath('/home/common/matlab/fieldtrip/data/test/bug1607/reference.mat'));

% reference_labels = ICA_clean.label;

nERPdata_nD_left = ERPdata_nD_left;
% nERPdata_D_left = ERPdata_D_left;
% nERPdata_nD_right = ERPdata_nD_right;
% nERPdata_D_right = ERPdata_D_right;

for isubject = 1:1%length(ERPdata_nD_left)
%     disp(num2str(isubject))
    [a loc] = ismember(ERPdata_nD_left{isubject}.label, reference_labels);  % compare the channel labeling of each subject with a reference
%     for isens = 1 : 64
%         if loc(isens) ~= isens
%             disp(['changing subj ' num2str(isubject) ' sensnr ' num2str(isens)]);
%             break;
%         end
%     end
%     disp(num2str(any(find((ERPdata_nD_left{isubject}.avg == ERPdata_nD_left{isubject}.avg(loc,:))==0))));
    nERPdata_nD_left{isubject}.label = reference_labels;    % relabel the channels according to the reference
%     nERPdata_nD_left{isubject}.avg(:,:) = ERPdata_nD_left{isubject}.avg(loc,:);     % realign data to ref channel order
    nERPdata_nD_left{isubject}.avg(loc,:) = ERPdata_nD_left{isubject}.avg(:,:);     % realign data to ref channel order
    nERPdata_nD_left{isubject}.dof(:,:) = ERPdata_nD_left{isubject}.dof(loc,:);     % realign data to ref channel order

end
% after realigning the data the plots look completely different, compare
% old and new data

cfg = [];
cfg.layout      = 'biosemi64.lay';
cfg.xlim        = [.04 .06];
cfg.channel     = 'all';
cfg.interactive = 'no';
cfg.highlight   = 'yes';
cfg.highlightchannel = reference_labels(end-6:end);

figure; ft_topoplotER(cfg,ERPdata_nD_left{1});      % plot original data
figure; ft_topoplotER(cfg,nERPdata_nD_left{1});     % plot corrected data


any(cellfun(@exist,{'mdwt', 'midwt', 'mirdwt', 'mrdwt'})==3)


% [HEIGHT] = lpyrHt(INDICES)
%
% Compute height of Laplacian pyramid with given its INDICES matrix.
% See buildLpyr.m

% Eero Simoncelli, 6/96.

function [ht] =  lpyrHt(pind)

% Don't count lowpass residual band
ht = size(pind,1)-1;


function [tt]=tt_elem_reverse(tt)
% Elementwise reverse of a tensor train vector
% NOT tested on a multidimensional case
%
% use tt_qutrtoepl(core(tt_shf(d)'*tt_elem_reverse(tt))) - to build
% upper-toeplitz matrix in "normal", blin, indexing, i.e. second element
% goes to S^{+1}, usw.

d = tt.d;
tt = core2cell(tt);

for i=1:d
    n = size(tt{i}, 2);
    tt{i} = tt{i}(:,(n:-1:1),:);
end;

tt = cell2core(tt_tensor, tt);

end


% SPM5 UPDATE 14/11/06
% UPDATE 27/01/05
% Sets the default values for the FieldMap toolbox
%
% FORMAT pm_defaults_Sonata
%_______________________________________________________________________
%
% This file is intended for use with the Siemens fieldmap sequence
% on the Sonata scanner at the FIL with the being phased out sequence
% ralf_epi_tbr and nw_mepi_silent_v1a.
%_______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Chloe Hutton and Jesper Andersson
% $Id: pm_defaults_Sonata.m 5015 2012-10-24 13:40:07Z guillaume $

global pm_def

% Defaults for creating field map. (See pm_make_fieldmap.m and
%                                   FieldMap.man for more info.)
%=======================================================================
pm_def.INPUT_DATA_FORMAT = 'PM';      % 'RI' = load two real and
                                      % imaginary image pairs
                                      % 'PM' = load one or two
                                      % phase and magnitude image
                                      % pairs.
pm_def.SHORT_ECHO_TIME = 10.0;        % Short echo time in ms for Sonata
pm_def.LONG_ECHO_TIME = 14.76;        % Long echo time in ms for Sonata
pm_def.MASKBRAIN = 1;                 % Do brain masking (1 or 0,
                      % 0 for EPI fieldmaps)

% Defaults for unwrapping options. (See pm_make_fieldmap.m and
%                                   FieldMap.man for more info.)
%=======================================================================
pm_def.UNWRAPPING_METHOD = 'Mark3D';  % Unwrapping options are:
                                      % 'Huttonish', 'Mark3D' or 'Mark2D'
pm_def.FWHM = 10;                     % FWHM of Gaussian filter used to
                                      % implement weighted smoothing of
                                      % unwrapped maps.
pm_def.PAD = 0;                       % Size of padding kernel if required.
pm_def.WS = 1;                        % Weighted or normal smoothing.

% Flags for brain extraction
%=======================================================================
pm_def.MFLAGS.TEMPLATE = fullfile(spm('Dir'),'toolbox','FieldMap','T1.nii');
pm_def.MFLAGS.FWHM = 5; % In mm
pm_def.MFLAGS.NERODE = 2;% In voxels
pm_def.MFLAGS.NDILATE = 4; % In voxels
pm_def.MFLAGS.THRESH = 0.5;
pm_def.MFLAGS.REG = 0.02; % A larger value helps segmentation to converge
pm_def.MFLAGS.GRAPHICS = 0; % A larger value helps segmentation to converge

% Defaults for converting field map to voxel displacement map.
%=======================================================================
pm_def.EPI_BASED_FIELDMAPS = 0;         % EPI=1, other=0.
pm_def.K_SPACE_TRAVERSAL_BLIP_DIR = -1; % +ve k-space = 1, -ve = -1.
pm_def.TOTAL_EPI_READOUT_TIME = 32;     % Sonata EPI RO time (500E-6*64)

% Defaults for Unwarping.
%=======================================================================
pm_def.DO_JACOBIAN_MODULATION = 0;    % Do jacobian modulation to adjust
                                      % for compression or stretching
                                      % No = 0, Yes = 1