function [source] = ft_sourcedescriptives(cfg, source)

% FT_SOURCEDESCRIPTIVES computes descriptive parameters of the source
% analysis results.
%
% Use as
%   [source] = ft_sourcedescriptives(cfg, source)
%
% where cfg is a structure with the configuration details and source is the
% result from a beamformer source estimation. The configuration can contain
%   cfg.cohmethod        = 'regular', 'lambda1', 'canonical'
%   cfg.powmethod        = 'regular', 'lambda1', 'trace', 'none'
%   cfg.supmethod        = 'chan_dip', 'chan', 'dip', 'none' (default)
%   cfg.projectmom       = 'yes' or 'no' (default = 'no')
%   cfg.eta              = 'yes' or 'no' (default = 'no')
%   cfg.kurtosis         = 'yes' or 'no' (default = 'no')
%   cfg.keeptrials       = 'yes' or 'no' (default = 'no')
%   cfg.keepcsd          = 'yes' or 'no' (default = 'no')
%   cfg.keepnoisecsd     = 'yes' or 'no' (default = 'no')
%   cfg.keepmom          = 'yes' or 'no' (default = 'yes')
%   cfg.keepnoisemom     = 'yes' or 'no' (default = 'yes')
%   cfg.resolutionmatrix = 'yes' or 'no' (default = 'no')
%   cfg.feedback         = 'no', 'text' (default), 'textbar', 'gui'
%
% The following option only applies to timecourses.
%   cfg.flipori          = 'yes' or 'no' (default = 'no')
%
% The following option only applies to single-trial timecourses.
%   cfg.fixedori         = 'within_trials' or 'over_trials' (default = 'over_trials')
%
% If repeated trials are present that have undergone some sort of
% resampling (i.e. jackknife, bootstrap, singletrial or rawtrial), the mean,
% variance and standard error of mean will be computed for all source
% parameters. This is done after applying the optional transformation
% on the power and projected noise.
%
% To facilitate data-handling and distributed computing you can use
%   cfg.inputfile   =  ...
%   cfg.outputfile  =  ...
% If you specify one of these (or both) the input data will be read from a *.mat
% file on disk and/or the output data will be written to a *.mat file. These mat
% files should contain only a single variable, corresponding with the
% input/output structure.
%
% See also FT_SOURCEANALYSIS, FT_SOURCESTATISTICS, FT_MATH

% Copyright (C) 2004-2015, Robert Oostenveld & Jan-Mathijs Schoffelen
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip 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.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

% these are used by the ft_preamble/ft_postamble function and scripts
ft_revision = '$Id$';
ft_nargin   = nargin;
ft_nargout  = nargout;

% do the general setup of the function
ft_defaults
ft_preamble init
ft_preamble debug
ft_preamble loadvar source
ft_preamble provenance source

% the ft_abort variable is set to true or false in ft_preamble_init
if ft_abort
  return
end

% check if the input data is valid for this function
% source = ft_checkdata(source, 'datatype', 'source', 'feedback', 'yes');

% cfg = ft_checkconfig(cfg, 'forbidden',   {'trials'});    % trial selection is not implented here, you may want to consider ft_selectdata

% DEPRECATED by roboos on 13 June 2013
% see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2199 for more details
% support for this functionality can be removed at the end of 2013
cfg = ft_checkconfig(cfg, 'deprecated',  {'transform'}); % please use ft_math instead

% set the defaults
cfg.transform        = ft_getopt(cfg, 'transform',        []);
cfg.projectmom       = ft_getopt(cfg, 'projectmom',       'no'); % if yes -> svdfft
cfg.numcomp          = ft_getopt(cfg, 'numcomp',          1);
cfg.powmethod        = ft_getopt(cfg, 'powmethod',        []); % see below
cfg.cohmethod        = ft_getopt(cfg, 'cohmethod',        []); % see below
cfg.feedback         = ft_getopt(cfg, 'feedback',         'textbar');
cfg.supmethod        = ft_getopt(cfg, 'supmethod',        'none');
cfg.resolutionmatrix = ft_getopt(cfg, 'resolutionmatrix', 'no');
cfg.eta              = ft_getopt(cfg, 'eta',              'no');
cfg.fa               = ft_getopt(cfg, 'fa',               'no');
cfg.kurtosis         = ft_getopt(cfg, 'kurtosis',         'no');
cfg.keeptrials       = ft_getopt(cfg, 'keeptrials',       'no');
cfg.trials           = ft_getopt(cfg, 'trials',           'all');
cfg.keepcsd          = ft_getopt(cfg, 'keepcsd',          'no');
cfg.keepmom          = ft_getopt(cfg, 'keepmom',          'yes');
cfg.keepnoisecsd     = ft_getopt(cfg, 'keepnoisecsd',     'no');
cfg.keepnoisemom     = ft_getopt(cfg, 'keepnoisemom',     'yes');
cfg.fwhm             = ft_getopt(cfg, 'fwhm',             'no');
cfg.fwhmremovecenter = ft_getopt(cfg, 'fwhmremovecenter', 0);
cfg.fwhmmethod       = ft_getopt(cfg, 'fwhmmethod',       'barnes');
cfg.fwhmmaxdist      = ft_getopt(cfg, 'fwhmmaxdist',      []);
cfg.fixedori         = ft_getopt(cfg, 'fixedori',         'over_trials');
cfg.flipori          = ft_getopt(cfg, 'flipori',          'no');

% only works for mne
cfg.demean         = ft_getopt(cfg, 'demean',         'yes');
cfg.baselinewindow = ft_getopt(cfg, 'baselinewindow', [-inf 0]);
cfg.zscore         = ft_getopt(cfg, 'zscore',         'yes');

zscore = strcmp(cfg.zscore, 'yes');
demean = strcmp(cfg.demean, 'yes');

if ischar(cfg.trials) && strcmp(cfg.trials,'all')
  % do nothing
elseif ischar(cfg.trials)
  ft_error('only ''all'' is allowed for string input for cfg.trials');
else
  % check whether there's a trial field in the source structure, and
  % subselect, otherwise error
  if isfield(source, 'trial')
    source.trial = source.trial(cfg.trials);
    if isfield(source, 'cumtapcnt'), source.cumtapcnt = source.cumtapcnt(cfg.trials,:); end
  else
    ft_error('subselecting trials in ft_sourcedescriptives is currently only possible with a ''trial'' field');
  end
end

% get desired method from source structure
source.method = ft_getopt(source,'method',[]);

% this is required for backward compatibility with the old sourceanalysis
if isfield(source, 'method') && strcmp(source.method, 'randomized')
  source.method = 'randomization';
elseif isfield(source, 'method') && strcmp(source.method, 'permuted')
  source.method = 'permutation';
elseif isfield(source, 'method') && strcmp(source.method, 'jacknife')
  source.method = 'jackknife';
end

% determine the type of data, this is only relevant for a few specific types
ispccdata = isfield(source, 'avg')   && isfield(source.avg, 'csdlabel');
islcmvavg = isfield(source, 'avg')   && isfield(source, 'time') && isfield(source.avg,   'mom') && any(size(source.avg.pow)==1);
islcmvtrl = isfield(source, 'trial') && isfield(source, 'time') && isfield(source.trial, 'mom');
ismneavg  = isfield(source, 'avg')   && isfield(source, 'time') && isfield(source.avg,   'mom') && size(source.avg.pow, 2)==numel(source.time);

% check the consistency of the defaults
if strcmp(cfg.projectmom, 'yes')
  if isempty(cfg.powmethod)
    cfg.powmethod = 'regular'; % set the default
  elseif ~strcmp(cfg.powmethod, 'regular')
    ft_error('unsupported powmethod in combination with projectmom');
  end
  if isempty(cfg.cohmethod)
    cfg.cohmethod = 'regular'; % set the default
  elseif ~strcmp(cfg.cohmethod, 'regular')
    ft_error('unsupported cohmethod in combination with projectmom');
  end
else
  if isempty(cfg.powmethod)
    cfg.powmethod = 'lambda1'; % set the default
  end
  if isempty(cfg.cohmethod)
    cfg.cohmethod = 'lambda1'; % set the default
  end
end

% this is required for backward compatibility with an old version of sourcedescriptives
if isfield(cfg, 'singletrial'), cfg.keeptrials = cfg.singletrial;  end

% do a validity check on the input data and specified options
if strcmp(cfg.resolutionmatrix, 'yes')
  if ~isfield(source.avg, 'filter')
    ft_error('The computation of the resolution matrix requires keepfilter=''yes'' in sourceanalysis.');
  elseif ~isfield(source, 'leadfield')
    ft_error('The computation of the resolution matrix requires keepleadfield=''yes'' in sourceanalysis.');
  end
end

if istrue(cfg.fwhm) && ~isfield(source.avg, 'filter')
  ft_error('computation of the fwhm requires keepfilter=''yes'' in sourceanalysis.');
end

if istrue(cfg.eta) && strcmp(cfg.cohmethod, 'svdfft')
  ft_error('eta cannot be computed in combination with the application of svdfft');
end

if istrue(cfg.keeptrials) && ~strcmp(cfg.supmethod, 'none')
  ft_error('you cannot keep trials when you want to partialize something');
end

if istrue(cfg.flipori) && ~istrue(cfg.projectmom)
  ft_error('flipori requires projectmom=''yes''');
end

% set some flags for convenience
isnoise    = isfield(source, 'avg') && isfield(source.avg, 'noisecsd');
keeptrials = strcmp(cfg.keeptrials, 'yes');
projectmom = strcmp(cfg.projectmom, 'yes');
flipori    = strcmp(cfg.flipori, 'yes');

% determine the subfunction used for computing power
switch cfg.powmethod
  case 'regular'
    powmethodfun = @powmethod_regular;
  case 'lambda1'
    powmethodfun = @powmethod_lambda1;
  case 'trace'
    powmethodfun = @powmethod_trace;
  case 'none'
    powmethodfun = [];
  otherwise
    ft_error('unsupported powmethod');
end

% represent the selection of sources in the brain as a row-vector with indices
insideindx = find(source.inside(:)');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if ispccdata
  % the source reconstruction was computed using the pcc beamformer
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  Ndipole = size(source.pos,1);

  if ischar(source.avg.csdlabel{1}), source.avg.csdlabel = {source.avg.csdlabel}; end
  if numel(source.avg.csdlabel)==1
    source.avg.csdlabel = repmat(source.avg.csdlabel, [Ndipole 1]);
  end

  dipsel     = find(strcmp(source.avg.csdlabel{1}, 'scandip'));
  refchansel = find(strcmp(source.avg.csdlabel{1}, 'refchan'));
  refdipsel  = find(strcmp(source.avg.csdlabel{1}, 'refdip'));
  supchansel = find(strcmp(source.avg.csdlabel{1}, 'supchan'));
  supdipsel  = find(strcmp(source.avg.csdlabel{1}, 'supdip'));

  % cannot handle reference channels and reference dipoles simultaneously
  if numel(refchansel)>0 && numel(refdipsel)>0
    ft_error('cannot simultaneously handle reference channels and reference dipole');
  end

  % these are only used to count the number of reference/suppression dipoles and channels
  refsel = [refdipsel refchansel];
  supsel = [supdipsel supchansel];

  % first do the projection of the moment, if requested
  if projectmom
    source.avg.ori = cell(1, Ndipole);
    ft_progress('init', cfg.feedback, 'projecting dipole moment');
    for i=insideindx
      ft_progress(i/length(insideindx), 'projecting dipole moment %d/%d\n', i, length(insideindx));

      if numel(source.avg.csdlabel)>1
        dipsel     = find(strcmp(source.avg.csdlabel{i}, 'scandip'));
        refchansel = find(strcmp(source.avg.csdlabel{i}, 'refchan'));
        refdipsel  = find(strcmp(source.avg.csdlabel{i}, 'refdip'));
        supchansel = find(strcmp(source.avg.csdlabel{i}, 'supchan'));
        supdipsel  = find(strcmp(source.avg.csdlabel{i}, 'supdip'));

        % these are only used to count the number of reference/suppression dipoles and channels
        refsel = [refdipsel refchansel];
        supsel = [supdipsel supchansel];
      end

      mom     = source.avg.mom{i}(dipsel,     :);
      ref     = source.avg.mom{i}(refdipsel,  :);
      sup     = source.avg.mom{i}(supdipsel,  :);
      refchan = source.avg.mom{i}(refchansel, :);
      supchan = source.avg.mom{i}(supchansel, :);
      % compute the projection of the scanning dipole along the direction of the dominant amplitude
      if length(dipsel)>1, [mom, rmom]  = svdfft(mom, cfg.numcomp, source.cumtapcnt); else rmom = []; end
      source.avg.ori{i} = rmom;
      % compute the projection of the reference dipole along the direction of the dominant amplitude
      if length(refdipsel)>1, [ref, rref] = svdfft(ref, 1, source.cumtapcnt); else rref = []; end
      % compute the projection of the supression dipole along the direction of the dominant amplitude
      if length(supdipsel)>1, [sup, rsup] = svdfft(sup, 1, source.cumtapcnt); else rsup = []; end

      % compute voxel-level fourier-matrix
      source.avg.mom{i} = cat(1, mom, ref, sup, refchan, supchan);

      % create rotation-matrix
      rotmat = zeros(0, length(source.avg.csdlabel{i}));
      if ~isempty(rmom)
        rotmat = [rotmat; rmom zeros(1,numel(refsel)+numel(supsel))];
      end
      if ~isempty(rref)
        rotmat = [rotmat; zeros(1, numel(dipsel)), rref, zeros(1,numel(refchansel)+numel(supsel))];
      end
      if ~isempty(rsup)
        rotmat = [rotmat; zeros(1, numel(dipsel)+numel(refdipsel)), rsup, zeros(1,numel(refchansel)+numel(supchansel))];
      end
      for j=1:length(supchansel)
        rotmat(end+1,:) = 0;
        rotmat(end,numel(dipsel)+numel(refdipsel)+numel(supdipsel)+j) = 1;
      end
      for j=1:length(refchansel)
        rotmat(end+1,:) = 0;
        rotmat(end,numel(dipsel)+numel(refdipsel)+numel(supdipsel)+numel(supchansel)+j) = 1;
      end

      % compute voxel-level csd-matrix
      if isfield(source.avg, 'csd'), source.avg.csd{i}           = rotmat * source.avg.csd{i} * rotmat'; end
      % compute voxel-level noisecsd-matrix
      if isfield(source.avg, 'noisecsd'), source.avg.noisecsd{i} = rotmat * source.avg.noisecsd{i} * rotmat'; end
      % compute rotated filter
      if isfield(source.avg, 'filter'),   source.avg.filter{i}   = rotmat * source.avg.filter{i}; end
      if isfield(source.avg, 'csdlabel')
        % remember what the interpretation is of all CSD output components
        scandiplabel = repmat({'scandip'}, 1, cfg.numcomp);          % only one dipole orientation remains
        refdiplabel  = repmat({'refdip'},  1, length(refdipsel)>0);  % for svdfft at max. only one dipole orientation remains
        supdiplabel  = repmat({'supdip'},  1, length(supdipsel)>0);  % for svdfft at max. only one dipole orientation remains
        refchanlabel = repmat({'refchan'}, 1, length(refchansel));
        supchanlabel = repmat({'supchan'}, 1, length(supchansel));
        % concatenate all the labels
        source.avg.csdlabel{i} = cat(2, scandiplabel, refdiplabel, supdiplabel, refchanlabel, supchanlabel);
      end

      % compute rotated leadfield
      % FIXME in the presence of a refdip and/or supdip, this does not work; leadfield is Nx3
      if isfield(source,  'leadfield')
        % FIXME this is a proposed dirty fix
        n1 = size(source.leadfield{i},2);
        %n2 = size(rotmat,2) - n1;
        n2 = size(rotmat,2) - n1 +1; %added 1 JM
        source.leadfield{i}    = source.leadfield{i} * rotmat(1:n2, 1:n1)';
      end
    end % for i=insideindx
    ft_progress('close');

    % update the indices
    dipsel     = find(strcmp(source.avg.csdlabel, 'scandip'));
    refchansel = find(strcmp(source.avg.csdlabel, 'refchan'));
    refdipsel  = find(strcmp(source.avg.csdlabel, 'refdip'));
    supchansel = find(strcmp(source.avg.csdlabel, 'supchan'));
    supdipsel  = find(strcmp(source.avg.csdlabel, 'supdip'));
    refsel     = [refdipsel refchansel];
    supsel     = [supdipsel supchansel];
  end % if projectmom

  if keeptrials
    cumtapcnt = source.cumtapcnt(:);
    sumtapcnt = cumsum([0;cumtapcnt]);
    Ntrial = length(cumtapcnt);

    ft_progress('init', cfg.feedback, 'computing singletrial voxel-level cross-spectral densities');
    for triallop = 1:Ntrial
      source.trial(triallop).csd = cell(Ndipole, 1);  % allocate memory for this trial
      source.trial(triallop).mom = cell(Ndipole, 1);  % allocate memory for this trial

      ft_progress(triallop/Ntrial, 'computing singletrial voxel-level cross-spectral densities %d%d\n', triallop, Ntrial);
      for i=insideindx
        dat = source.avg.mom{i};
        tmpmom = dat(:, sumtapcnt(triallop)+1:sumtapcnt(triallop+1));
        tmpcsd = (tmpmom * tmpmom') ./cumtapcnt(triallop);
        source.trial(triallop).mom{i} = tmpmom;
        source.trial(triallop).csd{i} = tmpcsd;
      end % for i=insideindx
    end % for triallop
    ft_progress('close');
    % remove the average, continue with separate trials, but keep track of
    % the csdlabel
    csdlabel = source.avg.csdlabel;
    source   = rmfield(source, 'avg');
  else
    fprintf('using average voxel-level cross-spectral densities\n');
    csdlabel = source.avg.csdlabel;
  end % if keeptrials

  % process the csdlabel for each of the dipoles
  hasrefdip  = true;
  hasrefchan = true;
  hassupdip  = true;
  hassupchan = true;

  dipselcell     = cell(Ndipole,1);
  refdipselcell  = cell(Ndipole,1);
  refchanselcell = cell(Ndipole,1);
  supdipselcell  = cell(Ndipole,1);
  supchanselcell = cell(Ndipole,1);

  for i = insideindx
    dipsel     = find(strcmp(csdlabel{i}, 'scandip'));
    refchansel = find(strcmp(csdlabel{i}, 'refchan'));
    refdipsel  = find(strcmp(csdlabel{i}, 'refdip'));
    supchansel = find(strcmp(csdlabel{i}, 'supchan'));
    supdipsel  = find(strcmp(csdlabel{i}, 'supdip'));

    hasrefdip  = ~isempty(refdipsel)  && hasrefdip; %NOTE: it has to be true for all dipoles!
    hasrefchan = ~isempty(refchansel) && hasrefchan;
    hassupdip  = ~isempty(supdipsel)  && hassupdip;
    hassupchan = ~isempty(supchansel) && hassupchan;

    dipselcell{i}     = dipsel;
    refdipselcell{i}  = refdipsel;
    refchanselcell{i} = refchansel;
    supdipselcell{i}  = supdipsel;
    supchanselcell{i} = supchansel;
  end

  if keeptrials
    % do the processing of the CSD matrices for each trial
    if ~strcmp(cfg.supmethod, 'none')
      ft_error('suppression is only supported for average CSD');
    end
    %dipselcell = mat2cell(repmat(dipsel(:)', [Ndipole 1]), ones(Ndipole,1), length(dipsel));
    %if hasrefdip,  refdipselcell  = mat2cell(repmat(refdipsel(:)',  [Ndipole 1]), ones(Ndipole,1), length(refdipsel));  end
    %if hasrefchan, refchanselcell = mat2cell(repmat(refchansel(:)', [Ndipole 1]), ones(Ndipole,1), length(refchansel)); end
    %if hassupdip,  supdipselcell  = mat2cell(repmat(supdipsel(:)',  [Ndipole 1]), ones(Ndipole,1), length(supdipsel));  end
    %if hassupchan, supchanselcell = mat2cell(repmat(supchansel(:)', [Ndipole 1]), ones(Ndipole,1), length(supchansel)); end

    ft_progress('init', cfg.feedback, 'computing singletrial voxel-level power');
    for triallop = 1:Ntrial
      %initialize the variables
      source.trial(triallop).pow = zeros(Ndipole, 1);
      if hasrefdip,  source.trial(triallop).refdippow     = zeros(Ndipole, 1); end
      if hasrefchan, source.trial(triallop).refchanpow    = zeros(Ndipole, 1); end
      if hassupdip,  source.trial(triallop).supdippow     = zeros(Ndipole, 1); end
      if hassupchan, source.trial(triallop).supchanpow    = zeros(Ndipole, 1); end

      ft_progress(triallop/Ntrial, 'computing singletrial voxel-level power %d%d\n', triallop, Ntrial);
      source.trial(triallop).pow(source.inside) = cellfun(powmethodfun, source.trial(triallop).csd(source.inside), dipselcell(source.inside));
      if hasrefdip,  source.trial(triallop).refdippow(source.inside)  = cellfun(powmethodfun,source.trial(triallop).csd(source.inside), refdipselcell(source.inside));  end
      if hassupdip,  source.trial(triallop).supdippow(source.inside)  = cellfun(powmethodfun,source.trial(triallop).csd(source.inside), supdipselcell(source.inside));  end
      if hasrefchan, source.trial(triallop).refchanpow(source.inside) = cellfun(powmethodfun,source.trial(triallop).csd(source.inside), refchanselcell(source.inside)); end
      if hassupchan, source.trial(triallop).supchanpow(source.inside) = cellfun(powmethodfun,source.trial(triallop).csd(source.inside), supchanselcell(source.inside)); end
      %FIXME kan volgens mij niet
      if isnoise && isfield(source.trial(triallop), 'noisecsd')
        % compute the power of the noise projected on each source component
        source.trial(triallop).noise = cellfun(powmethodfun,source.trial(triallop).csd, dipselcell);
        if hasrefdip,  source.trial(triallop).refdipnoise  = cellfun(powmethodfun,source.trial(triallop).noisecsd, refdipselcell);  end
        if hassupdip,  source.trial(triallop).supdipnoise  = cellfun(powmethodfun,source.trial(triallop).noisecsd, supdipselcell);  end
        if hasrefchan, source.trial(triallop).refchannoise = cellfun(powmethodfun,source.trial(triallop).noisecsd, refchanselcell); end
        if hassupchan, source.trial(triallop).supchannoise = cellfun(powmethodfun,source.trial(triallop).noisecsd, supchanselcell); end
      end % if isnoise
    end % for triallop
    ft_progress('close');

    if strcmp(cfg.keepcsd, 'no')
      source.trial = rmfield(source.trial, 'csd');
    end

  else
    % do the processing of the average CSD matrix
    for i=insideindx
      switch cfg.supmethod
        case 'chan_dip'
          supindx = [supdipsel supchansel];
          if i==insideindx(1), refsel  = refsel - length(supdipsel); end % adjust index only once
          refchanselcell{i} = refchanselcell{i} - length(supdipsel);
          refdipselcell{i}  = refdipselcell{i} - length(supdipsel);
        case 'chan'
          supindx = supchansel;
        case 'dip'
          supindx = supdipsel;
          if i==insideindx(1), refsel  = refsel - length(supdipsel); end
          refchanselcell{i} = refchanselcell{i} - length(supdipsel);
          refdipselcell{i}  = refdipselcell{i} - length(supdipsel);
        case 'none'
          % do nothing
          supindx = [];
      end
      tmpcsd  = source.avg.csd{i};
      scnindx = setdiff(1:size(tmpcsd,1), supindx);
      tmpcsd  = tmpcsd(scnindx, scnindx) - tmpcsd(scnindx, supindx)*pinv(tmpcsd(supindx, supindx))*tmpcsd(supindx, scnindx);
      source.avg.csd{i}   = tmpcsd;
    end % for insideindx
    % source.avg.csdlabel = source.avg.csdlabel(scnindx);

    if isnoise && ~strcmp(cfg.supmethod, 'none')
      source.avg = rmfield(source.avg, 'noisecsd');
    end

    % initialize the variables
    source.avg.pow           = nan(Ndipole, 1);
    if hasrefdip,  source.avg.refdippow     = nan(Ndipole, 1); end
    if hasrefchan, source.avg.refchanpow    = nan(Ndipole, 1); end
    if hassupdip,  source.avg.supdippow     = nan(Ndipole, 1); end
    if hassupchan, source.avg.supchanpow    = nan(Ndipole, 1); end
    if isnoise
      source.avg.noise         = nan(Ndipole, 1);
      if hasrefdip,  source.avg.refdipnoise     = nan(Ndipole, 1); end
      if hasrefchan, source.avg.refchannoise    = nan(Ndipole, 1); end
      if hassupdip,  source.avg.supdipnoise     = nan(Ndipole, 1); end
      if hassupchan, source.avg.supchannoise    = nan(Ndipole, 1); end
    end % if isnoise
    if hasrefdip||hasrefchan, source.avg.coh    = nan(Ndipole, 1); end
    if strcmp(cfg.eta, 'yes')
      source.avg.eta           = nan(Ndipole, 1);
      source.avg.ori             = cell(1, Ndipole);
    end
    if strcmp(cfg.eta, 'yes') && ~isempty(refsel)
      source.avg.etacsd = nan(Ndipole, 1);
      source.avg.ucsd   = cell(1, Ndipole);
    end
    if strcmp(cfg.fa, 'yes')
      source.avg.fa = nan(Ndipole, 1);
    end

    for i=insideindx
      dipsel = dipselcell{i};
      refchansel = refchanselcell{i};
      refdipsel  = refdipselcell{i};
      refsel     = [refchansel refdipsel];
      supchansel = supchanselcell{i};

      % compute the power of each source component
      if strcmp(cfg.projectmom, 'yes') && cfg.numcomp>1
        source.avg.pow(i) = powmethodfun(source.avg.csd{i}(dipselcell{i},dipselcell{i}), 1);
      else
        source.avg.pow(i) = powmethodfun(source.avg.csd{i}(dipselcell{i},dipselcell{i}));
      end

      if hasrefdip,  source.avg.refdippow(i)  = powmethodfun(source.avg.csd{i}(refdipsel,refdipsel));   end
      %if hassupdip,  source.avg.supdippow(i)  = powmethodfun(source.avg.csd{i}(supdipsel,supdipsel));   end
      if hasrefchan, source.avg.refchanpow(i) = powmethodfun(source.avg.csd{i}(refchansel,refchansel)); end
      %if hassupchan, source.avg.supchanpow(i) = powmethodfun(source.avg.csd{i}(supchansel,supchansel)); end
      if isnoise
        % compute the power of the noise projected on each source component
        if strcmp(cfg.projectmom, 'yes') && cfg.numcomp>1
          source.avg.noise(i) = powmethodfun(source.avg.noisecsd{i}(dipselcell{i},dipselcell{i}), 1);
        else
          source.avg.noise(i) = powmethodfun(source.avg.noisecsd{i}(dipselcell{i},dipselcell{i}));
        end
        if hasrefdip,  source.avg.refdipnoise(i)  = powmethodfun(source.avg.noisecsd{i}(refdipsel,refdipsel));   end
        if hassupdip,  source.avg.supdipnoise(i)  = powmethodfun(source.avg.noisecsd{i}(supdipsel,supdipsel));   end
        if hasrefchan, source.avg.refchannoise(i) = powmethodfun(source.avg.noisecsd{i}(refchansel,refchansel)); end
        if hassupchan, source.avg.supchannoise(i) = powmethodfun(source.avg.noisecsd{i}(supchansel,supchansel)); end
      end % if isnoise

      if ~isempty(refsel)
        % compute coherence
        csd = source.avg.csd{i};
        switch cfg.cohmethod
          case 'regular'
            % assume that all dipoles have been projected along the direction of maximum power
            Pd                = abs(csd(dipsel, dipsel));
            Pr                = abs(csd(refsel, refsel));
            Cdr               = csd(dipsel, refsel);
            source.avg.coh(i) = (Cdr.^2) ./ (Pd*Pr);
          case 'lambda1'
            % compute coherence the Joachim Gross' way
            Pd                = lambda1(csd(dipsel, dipsel));
            Pr                = lambda1(csd(refsel, refsel));
            Cdr               = lambda1(csd(dipsel, refsel));
            source.avg.coh(i) = abs(Cdr).^2 ./ (Pd*Pr);
          case 'canonical'
            % compute canonical coherence

            ccoh = ft_connectivity_cancorr(csd([dipsel refsel],[dipsel refsel]), 'indices', [ones(1,numel(dipsel)) ones(1,numel(refsel))*2]);
            source.avg.coh(i)  = ccoh(1,2);
          otherwise
            ft_error('unsupported cohmethod');
        end % cohmethod
      end

      % compute eta
      if strcmp(cfg.eta, 'yes')
        [source.avg.eta(i), source.avg.ori{i}] = csd2eta(source.avg.csd{i}(dipselcell{i},dipselcell{i}));
        if ~isempty(refsel)
          %FIXME this only makes sense when only a reference signal OR a dipole is selected
          [source.avg.etacsd(i), source.avg.ucsd{i}] = csd2eta(source.avg.csd{i}(dipsel,refsel));
        end
      end

      %compute fa
      if strcmp(cfg.fa, 'yes')
        source.avg.fa(i) = csd2fa(source.avg.csd{i}(dipsel,dipsel));
      end
    end % for diplop

    if strcmp(cfg.keepcsd, 'no')
      source.avg = rmfield(source.avg, 'csd');
    end
    if strcmp(cfg.keepnoisecsd, 'no') && isnoise
      source.avg = rmfield(source.avg, 'noisecsd');
    end

  end % if keeptrials

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
elseif ismneavg
  % the source reconstruction was computed using mne and contains an average timecourse
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  if demean
    begsmp = nearest(source.time, cfg.baselinewindow(1));
    endsmp = nearest(source.time, cfg.baselinewindow(2));
    ft_progress('init', cfg.feedback, 'baseline correcting dipole moments');
    for diplop=1:length(insideindx)
      ft_progress(diplop/length(insideindx), 'baseline correcting dipole moments %d/%d\n', diplop, length(insideindx));
      mom = source.avg.mom{insideindx(diplop)};
      mom = ft_preproc_baselinecorrect(mom, begsmp, endsmp);
      source.avg.mom{insideindx(diplop)} = mom;
    end
    ft_progress('close');
  end

  if projectmom
    if isfield(source, 'tri')
      nrm = surface_normals(source.pos, source.tri, 'vertex');
      source.avg.phi = zeros(size(source.pos,1),1);
    end
    ft_progress('init', cfg.feedback, 'projecting dipole moment');
    for diplop=1:length(insideindx)
      ft_progress(diplop/length(insideindx), 'projecting dipole moment %d/%d\n', diplop, length(insideindx));
      mom = source.avg.mom{insideindx(diplop)};
      [mom, rmom] = svdfft(mom, 1);
      source.avg.mom{insideindx(diplop)} = mom;
      source.avg.ori{insideindx(diplop)} = rmom;
    end
    if isfield(source, 'tri')
      for diplop=insideindx
        source.avg.phi(diplop) = source.avg.ori{diplop}*nrm(diplop,:)';
      end
    end
    if isfield(source.avg, 'noisecov')
      source.avg.noise = nan+zeros(size(source.pos,1),1);
      for diplop=insideindx
        rmom = source.avg.ori{diplop};
        source.avg.noise(diplop) = rmom*source.avg.noisecov{diplop}*rmom';
      end
    end
    ft_progress('close');
  end % if projectmom

  if flipori
    tmpmom = cat(1, source.avg.mom{source.inside});
    [u, s, v] = svd(tmpmom, 'econ');
    flip( source.inside) = sign(u(:,1));
    flip(~source.inside) = nan;
    for i=1:numel(source.inside)
      if source.inside(i)
        source.avg.mom{i} = flip(i) * source.avg.mom{i};
        source.avg.ori{i} = flip(i) * source.avg.ori{i};
      end
    end
  end % if flipori

  if zscore
    begsmp = nearest(source.time, cfg.baselinewindow(1));
    endsmp = nearest(source.time, cfg.baselinewindow(2));
    % zscore using baselinewindow for power
    ft_progress('init', cfg.feedback, 'computing power');
    %source.avg.absmom = source.avg.pow;
    for diplop=1:length(insideindx)
      ft_progress(diplop/length(insideindx), 'computing power %d/%d\n', diplop, length(insideindx));
      mom = source.avg.mom{insideindx(diplop)};
      mmom = mean(mom(:,begsmp:endsmp),2);
      smom = std(mom(:,begsmp:endsmp),[],2);
      pow  = sum(((mom-mmom(:,ones(size(mom,2),1)))./smom(:,ones(size(mom,2),1))).^2,1);
      source.avg.pow(insideindx(diplop),:) = pow;
      source.avg.mom{insideindx(diplop)}   = diag(1./smom)*mom;
    end
    ft_progress('close');
  else
    % just square for power
    ft_progress('init', cfg.feedback, 'computing power');
    %source.avg.absmom = source.avg.pow;
    for diplop=1:length(insideindx)
      ft_progress(diplop/length(insideindx), 'computing power %d/%d\n', diplop, length(insideindx));
      mom = source.avg.mom{insideindx(diplop)};
      pow = sum(mom.^2,1);
      source.avg.pow(insideindx(diplop),:) = pow;
      %source.avg.absmom(insideindx(diplop),:) = sum(mom,1);
    end
    ft_progress('close');
  end % if zscore

  if strcmp(cfg.kurtosis, 'yes')
    fprintf('computing kurtosis based on dipole timecourse\n');
    source.avg.k2 = nan(size(source.pos,1),1);
    for diplop=1:length(insideindx)
      mom = source.avg.mom{insideindx(diplop)};
      if length(mom)~=prod(size(mom))
        ft_error('kurtosis can only be computed for projected dipole moment');
      end
      source.avg.k2(insideindx(diplop)) = kurtosis(mom);
    end
  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
elseif islcmvavg
  % the source reconstruction was computed using the lcmv beamformer and contains an average timecourse
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  if projectmom
    ft_progress('init', cfg.feedback, 'projecting dipole moment');
    for diplop=1:length(insideindx)
      ft_progress(diplop/length(insideindx), 'projecting dipole moment %d/%d\n', diplop, length(insideindx));
      mom = source.avg.mom{insideindx(diplop)};
      [mom, rmom] = svdfft(mom, 1);
      source.avg.mom{insideindx(diplop)} = mom;
      source.avg.ori{insideindx(diplop)} = rmom;
    end
    ft_progress('close');
  end

  if flipori
    tmpmom = cat(1, source.avg.mom{source.inside});
    [u, s, v] = svd(tmpmom, 'econ');
    flip( source.inside) = sign(u(:,1));
    flip(~source.inside) = nan;
    for i=1:numel(source.inside)
      if source.inside(i)
        source.avg.mom{i} = flip(i) * source.avg.mom{i};
        source.avg.ori{i} = flip(i) * source.avg.ori{i};
      end
    end
  end

  if ~strcmp(cfg.powmethod, 'none')
    fprintf('recomputing power based on dipole timecourse\n')
    source.avg.pow = nan(size(source.pos,1),1);
    for diplop=1:length(insideindx)
      mom = source.avg.mom{insideindx(diplop)};
      cov = mom * mom';
      source.avg.pow(insideindx(diplop)) = powmethodfun(cov);
    end
  end

  if strcmp(cfg.kurtosis, 'yes')
    fprintf('computing kurtosis based on dipole timecourse\n');
    source.avg.k2 = nan(size(source.pos,1),1);
    for diplop=1:length(insideindx)
      mom = source.avg.mom{insideindx(diplop)};
      if length(mom)~=prod(size(mom))
        ft_error('kurtosis can only be computed for projected dipole moment');
      end
      source.avg.k2(insideindx(diplop)) = kurtosis(mom);
    end
  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
elseif islcmvtrl
  % the source reconstruction was computed using the lcmv beamformer and contains a single-trial timecourse
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  ntrial = length(source.trial);

  if projectmom && strcmp(cfg.fixedori, 'within_trials')
    % the dipole orientation is re-determined for each trial
    ft_progress('init', cfg.feedback, 'projecting dipole moment');
    for trllop=1:ntrial
      ft_progress(trllop/ntrial, 'projecting dipole moment %d/%d\n', trllop, ntrial);
      for diplop=1:length(insideindx)
        mom = source.trial(trllop).mom{insideindx(diplop)};
        [mom, rmom] = svdfft(mom, 1);
        source.trial(trllop).mom{insideindx(diplop)} = mom;
        source.trial(trllop).ori{insideindx(diplop)} = rmom;  % remember the orientation
      end
    end
    ft_progress('close');
  elseif projectmom && strcmp(cfg.fixedori, 'over_trials')
    ft_progress('init', cfg.feedback, 'projecting dipole moment');
    % compute average covariance over all trials
    for trllop=1:ntrial
      for diplop=1:length(insideindx)
        mom = source.trial(trllop).mom{insideindx(diplop)};
        if trllop==1
          cov{diplop} = mom*mom'./size(mom,2);
        else
          cov{diplop} = mom*mom'./size(mom,2) + cov{diplop};
        end
      end
    end
    % compute source orientation over all trials
    for diplop=1:length(insideindx)
      [dum, ori{diplop}] = svdfft(cov{diplop}, 1);
    end
    % project the data in each trial
    for trllop=1:ntrial
      ft_progress(trllop/ntrial, 'projecting dipole moment %d/%d\n', trllop, ntrial);
      for diplop=1:length(insideindx)
        mom = source.trial(trllop).mom{insideindx(diplop)};
        mom = ori{diplop}*mom;
        source.trial(trllop).mom{insideindx(diplop)} = mom;
        source.trial(trllop).ori{insideindx(diplop)} = ori{diplop};
      end
    end
    ft_progress('close');
  end

  if ~strcmp(cfg.powmethod, 'none')
    fprintf('recomputing power based on dipole timecourse\n')
    for trllop=1:ntrial
      for diplop=1:length(insideindx)
        mom = source.trial(trllop).mom{insideindx(diplop)};
        cov = mom * mom';
        source.trial(trllop).pow(insideindx(diplop)) = powmethodfun(cov);
      end
    end
  end

  if strcmp(cfg.kurtosis, 'yes')
    fprintf('computing kurtosis based on dipole timecourse\n');
    for trllop=1:ntrial
      source.trial(trllop).k2 = nan(size(source.pos,1),1);
      for diplop=1:length(insideindx)
        mom = source.trial(trllop).mom{insideindx(diplop)};
        if length(mom)~=numel(mom)
          ft_error('kurtosis can only be computed for projected dipole moment');
        end
        source.trial(trllop).k2(insideindx(diplop)) = kurtosis(mom);
      end
    end
  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end % dealing with pcc, lcmv, dics or mne input
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if isfield(source, 'avg') && isfield(source.avg, 'pow') && isfield(source.avg, 'noise') && ~ismneavg
  % compute the neural activity index for the average
  source.avg.nai = source.avg.pow(:) ./ source.avg.noise(:);
end

if isfield(source, 'trial') && isfield(source.trial, 'pow') && isfield(source.trial, 'noise')
  % compute the neural activity index for the trials
  ntrials = length(source.trial);
  for trlop=1:ntrials
    source.trial(trlop).nai = source.trial(trlop).pow ./ source.trial(trlop).noise;
  end
end

if strcmp(source.method, 'randomization') || strcmp(source.method, 'permutation')
  % compute the neural activity index for the two randomized conditions
  source.avgA.nai = source.avgA.pow ./ source.avgA.noise;
  source.avgB.nai = source.avgB.pow ./ source.avgB.noise;
  for trlop=1:length(source.trialA)
    source.trialA(trlop).nai = source.trialA(trlop).pow ./ source.trialA(trlop).noise;
  end
  for trlop=1:length(source.trialB)
    source.trialB(trlop).nai = source.trialB(trlop).pow ./ source.trialB(trlop).noise;
  end
end

if ~isempty(cfg.transform)
  fprintf('applying %s transformation on the power and projected noise\n', cfg.transform);
  % apply the specified transformation on the power
  if isfield(source, 'avg'   ) && isfield(source.avg   , 'pow'), source.avg .pow = feval(cfg.transform, source.avg .pow); end
  if isfield(source, 'avgA'  ) && isfield(source.avgA  , 'pow'), source.avgA.pow = feval(cfg.transform, source.avgA.pow); end
  if isfield(source, 'avgB'  ) && isfield(source.avgB  , 'pow'), source.avgB.pow = feval(cfg.transform, source.avgB.pow); end
  if isfield(source, 'trial' ) && isfield(source.trial , 'pow'), for i=1:length(source.trial ), source.trial (i).pow = feval(cfg.transform, source.trial (i).pow); end; end
  if isfield(source, 'trialA') && isfield(source.trialA, 'pow'), for i=1:length(source.trialA), source.trialA(i).pow = feval(cfg.transform, source.trialA(i).pow); end; end
  if isfield(source, 'trialB') && isfield(source.trialB, 'pow'), for i=1:length(source.trialB), source.trialB(i).pow = feval(cfg.transform, source.trialB(i).pow); end; end
  % apply the specified transformation on the projected noise
  if isfield(source, 'avg'   ) && isfield(source.avg   , 'noise'), source.avg .noise = feval(cfg.transform, source.avg .noise); end
  if isfield(source, 'avgA'  ) && isfield(source.avgA  , 'noise'), source.avgA.noise = feval(cfg.transform, source.avgA.noise); end
  if isfield(source, 'avgB'  ) && isfield(source.avgB  , 'noise'), source.avgB.noise = feval(cfg.transform, source.avgB.noise); end
  if isfield(source, 'trial' ) && isfield(source.trial , 'noise'), for i=1:length(source.trial ), source.trial (i).noise = feval(cfg.transform, source.trial (i).noise); end; end
  if isfield(source, 'trialA') && isfield(source.trialA, 'noise'), for i=1:length(source.trialA), source.trialA(i).noise = feval(cfg.transform, source.trialA(i).noise); end; end
  if isfield(source, 'trialB') && isfield(source.trialB, 'noise'), for i=1:length(source.trialB), source.trialB(i).noise = feval(cfg.transform, source.trialB(i).noise); end; end
end

if strcmp(source.method, 'pseudovalue')
  % compute the pseudovalues for the beamformer output
  avg = source.trial(1);        % the first is the complete average
  Ntrials = length(source.trial)-1; % the remaining are the leave-one-out averages
  pseudoval = [];
  if isfield(source.trial, 'pow')
    allavg = getfield(avg, 'pow');
    for i=1:Ntrials
      thisavg = getfield(source.trial(i+1), 'pow');
      thisval = Ntrials*allavg - (Ntrials-1)*thisavg;
      pseudoval(i).pow = thisval;
    end
  end
  if isfield(source.trial, 'coh')
    allavg = getfield(avg, 'coh');
    for i=1:Ntrials
      thisavg = getfield(source.trial(i+1), 'coh');
      thisval = Ntrials*allavg - (Ntrials-1)*thisavg;
      pseudoval(i).coh = thisval;
    end
  end
  if isfield(source.trial, 'nai')
    allavg = getfield(avg, 'nai');
    for i=1:Ntrials
      thisavg = getfield(source.trial(i+1), 'nai');
      thisval = Ntrials*allavg - (Ntrials-1)*thisavg;
      pseudoval(i).nai = thisval;
    end
  end
  if isfield(source.trial, 'noise')
    allavg = getfield(avg, 'noise');
    for i=1:Ntrials
      thisavg = getfield(source.trial(i+1), 'noise');
      thisval = Ntrials*allavg - (Ntrials-1)*thisavg;
      pseudoval(i).noise = thisval;
    end
  end
  % store the pseudovalues instead of the original values
  source.trial = pseudoval;
end

if strcmp(source.method, 'jackknife') || strcmp(source.method, 'bootstrap') || strcmp(source.method, 'pseudovalue') || strcmp(source.method, 'singletrial') || strcmp(source.method, 'rawtrial')
  % compute descriptive statistics (mean, var, sem) for multiple trial data
  % compute these for as many source parameters as possible

  % for convenience copy the trials out of the source structure
  dip = source.trial;

  % determine the (original) number of trials in the data
  if strcmp(source.method, 'bootstrap') %VERANDERD ER ZAT GEEN .RESAMPLE IN SOURCE
    Ntrials = size(source.trial,2); % WAS size(source.resample, 2);
  else
    Ntrials = length(source.trial);
  end
  fprintf('original data contained %d trials\n', Ntrials);

  % allocate memory for all elements in the dipole structure
  sumdip = [];
  if isfield(dip(1), 'var'),   sumdip.var    = zeros(size(dip(1).var  )); sumdip.var(~source.inside) = nan; end
  if isfield(dip(1), 'pow'),   sumdip.pow    = zeros(size(dip(1).pow  )); sumdip.pow(~source.inside) = nan; end
  if isfield(dip(1), 'coh'),   sumdip.coh    = zeros(size(dip(1).coh  )); sumdip.coh(~source.inside) = nan; end
  if isfield(dip(1), 'rv'),    sumdip.rv     = zeros(size(dip(1).rv   )); sumdip.rv(~source.inside) = nan; end
  if isfield(dip(1), 'noise'), sumdip.noise  = zeros(size(dip(1).noise)); sumdip.noise(~source.inside) = nan; end
  if isfield(dip(1), 'nai'),   sumdip.nai    = zeros(size(dip(1).nai  )); sumdip.nai(~source.inside) = nan; end
  sqrdip = [];
  if isfield(dip(1), 'var'),   sqrdip.var    = zeros(size(dip(1).var  )); sqrdip.var(~source.inside) = nan; end
  if isfield(dip(1), 'pow'),   sqrdip.pow    = zeros(size(dip(1).pow  )); sqrdip.pow(~source.inside) = nan; end
  if isfield(dip(1), 'coh'),   sqrdip.coh    = zeros(size(dip(1).coh  )); sqrdip.coh(~source.inside) = nan; end
  if isfield(dip(1), 'rv'),    sqrdip.rv     = zeros(size(dip(1).rv   )); sqrdip.rv(~source.inside) = nan; end
  if isfield(dip(1), 'noise'), sqrdip.noise  = zeros(size(dip(1).noise)); sqrdip.noise(~source.inside) = nan; end
  if isfield(dip(1), 'nai'),   sqrdip.nai    = zeros(size(dip(1).nai  )); sqrdip.nai(~source.inside) = nan; end
  if isfield(dip(1), 'mom')
    sumdip.mom = cell(size(dip(1).mom));
    sqrdip.mom = cell(size(dip(1).mom));
    for i=1:length(dip(1).mom)
      sumdip.mom{i} = zeros(size(dip(1).mom{i}));
      sqrdip.mom{i} = zeros(size(dip(1).mom{i}));
    end
  end
  if isfield(dip(1), 'csd')
    sumdip.csd = cell(size(dip(1).csd));
    sqrdip.csd = cell(size(dip(1).csd));
    for i=1:length(dip(1).csd)
      sumdip.csd{i} = zeros(size(dip(1).csd{i}));
      sqrdip.csd{i} = zeros(size(dip(1).csd{i}));
    end
  end

  for trial=1:length(dip)
    % compute the sum of all values
    if isfield(dip(trial), 'var'),    sumdip.var   = sumdip.var    + dip(trial).var;    end
    if isfield(dip(trial), 'pow'),    sumdip.pow   = sumdip.pow    + dip(trial).pow;    end
    if isfield(dip(trial), 'coh'),    sumdip.coh   = sumdip.coh    + dip(trial).coh;    end
    if isfield(dip(trial), 'rv'),     sumdip.rv    = sumdip.rv     + dip(trial).rv;     end
    if isfield(dip(trial), 'noise'),  sumdip.noise = sumdip.noise  + dip(trial).noise;  end
    if isfield(dip(trial), 'nai'),    sumdip.nai   = sumdip.nai    + dip(trial).nai;    end
    % compute the sum of squared values
    if isfield(dip(trial), 'var'),    sqrdip.var    = sqrdip.var   + (dip(trial).var  ).^2; end
    if isfield(dip(trial), 'pow'),    sqrdip.pow    = sqrdip.pow   + (dip(trial).pow  ).^2; end
    if isfield(dip(trial), 'coh'),    sqrdip.coh    = sqrdip.coh   + (dip(trial).coh  ).^2; end
    if isfield(dip(trial), 'rv'),     sqrdip.rv     = sqrdip.rv    + (dip(trial).rv   ).^2; end
    if isfield(dip(trial), 'noise'),  sqrdip.noise  = sqrdip.noise + (dip(trial).noise).^2; end
    if isfield(dip(trial), 'nai'),    sqrdip.nai    = sqrdip.nai   + (dip(trial).nai  ).^2; end
    % do the same for the cell-array with mom
    if isfield(dip(trial), 'mom')
      for i=1:length(dip(1).mom)
        sumdip.mom{i} = sumdip.mom{i} +  dip(trial).mom{i};
        sqrdip.mom{i} = sqrdip.mom{i} + (dip(trial).mom{i}).^2;
      end
    end
    % do the same for the cell-array with csd
    if isfield(dip(trial), 'csd')
      for i=1:length(dip(1).csd)
        sumdip.csd{i} = sumdip.csd{i} +  dip(trial).csd{i};
        sqrdip.csd{i} = sqrdip.csd{i} + (dip(trial).csd{i}).^2;
      end
    end
  end

  % compute the mean over all repetitions
  if isfield(sumdip, 'var'),    dipmean.var    = sumdip.var   / length(dip); end
  if isfield(sumdip, 'pow'),    dipmean.pow    = sumdip.pow   / length(dip); end
  if isfield(sumdip, 'coh'),    dipmean.coh    = sumdip.coh   / length(dip); end
  if isfield(sumdip, 'rv'),     dipmean.rv     = sumdip.rv    / length(dip); end
  if isfield(sumdip, 'noise'),  dipmean.noise  = sumdip.noise / length(dip); end
  if isfield(sumdip, 'nai'),    dipmean.nai    = sumdip.nai   / length(dip); end
  % for the cell-array with mom, this is done further below
  % for the cell-array with csd, this is done further below

  % the estimates for variance and SEM are biased if we are working with the jackknife/bootstrap
  % determine the proper variance scaling that corrects for this bias
  % note that Ntrials is not always the same as the length of dip, especially in case of the bootstrap
  if strcmp(source.method, 'singletrial')
    bias = 1;
  elseif strcmp(source.method, 'rawtrial')
    bias = 1;
  elseif strcmp(source.method, 'jackknife')
    % Effron gives SEM estimate for the jackknife method in equation 11.5 (paragraph 11.2)
    % to get the variance instead of SEM, we also have to multiply with the number of trials
    bias = (Ntrials - 1)^2;
  elseif strcmp(source.method, 'bootstrap')
    % Effron gives SEM estimate for the bootstrap method in algorithm 6.1 (equation 6.6)
    % to get the variance instead of SEM, we also have to multiply with the number of trials
    bias = Ntrials;
  elseif strcmp(source.method, 'pseudovalue')
    % note that I have not put any thought in this aspect yet
    ft_warning('don''t know how to compute bias for pseudovalue resampling');
    bias = 1;
  end

  % compute the variance over all repetitions
  if isfield(sumdip, 'var'),    dipvar.var    = bias*(sqrdip.var    - (sumdip.var   .^2)/length(dip))/(length(dip)-1); end
  if isfield(sumdip, 'pow'),    dipvar.pow    = bias*(sqrdip.pow    - (sumdip.pow   .^2)/length(dip))/(length(dip)-1); end
  if isfield(sumdip, 'coh'),    dipvar.coh    = bias*(sqrdip.coh    - (sumdip.coh   .^2)/length(dip))/(length(dip)-1); end
  if isfield(sumdip, 'rv' ),    dipvar.rv     = bias*(sqrdip.rv     - (sumdip.rv    .^2)/length(dip))/(length(dip)-1); end
  if isfield(sumdip, 'noise' ), dipvar.noise  = bias*(sqrdip.noise  - (sumdip.noise .^2)/length(dip))/(length(dip)-1); end
  if isfield(sumdip, 'nai' ),   dipvar.nai    = bias*(sqrdip.nai    - (sumdip.nai   .^2)/length(dip))/(length(dip)-1); end

  % compute the SEM over all repetitions
  if isfield(sumdip, 'var'),    dipsem.var    = (dipvar.var   /Ntrials).^0.5; end
  if isfield(sumdip, 'pow'),    dipsem.pow    = (dipvar.pow   /Ntrials).^0.5; end
  if isfield(sumdip, 'coh'),    dipsem.coh    = (dipvar.coh   /Ntrials).^0.5; end
  if isfield(sumdip, 'rv' ),    dipsem.rv     = (dipvar.rv    /Ntrials).^0.5; end
  if isfield(sumdip, 'noise' ), dipsem.noise  = (dipvar.noise /Ntrials).^0.5; end
  if isfield(sumdip, 'nai' ),   dipsem.nai    = (dipvar.nai   /Ntrials).^0.5; end

  % compute the mean and SEM over all repetitions for the cell-array with mom
  if isfield(dip(trial), 'mom')
    for i=1:length(dip(1).mom)
      dipmean.mom{i} = sumdip.mom{i}/length(dip);
      dipvar.mom{i} = bias*(sqrdip.mom{i} - (sumdip.mom{i}.^2)/length(dip))/(length(dip)-1);
      dipsem.mom{i} = (dipvar.mom{i}/Ntrials).^0.5;
    end
  end

  % compute the mean and SEM over all repetitions for the cell-array with csd
  if isfield(dip(trial), 'csd')
    for i=1:length(dip(1).csd)
      dipmean.csd{i} = sumdip.csd{i}/length(dip);
      dipvar.csd{i} = bias*(sqrdip.csd{i} - (sumdip.csd{i}.^2)/length(dip))/(length(dip)-1);
      dipsem.csd{i} = (dipvar.csd{i}/Ntrials).^0.5;
    end
  end

  if strcmp(source.method, 'pseudovalue')
    % keep the trials, since they have been converted to pseudovalues
    % and hence the trials contain the interesting data
  elseif keeptrials
    % keep the trials upon request
  else
    % remove the original trials
    source = rmfield(source, 'trial');
    % assign the descriptive statistics to the output source structure
    source.avg = dipmean;
    source.var = dipvar;
    source.sem = dipsem;
  end
end

if strcmp(cfg.resolutionmatrix, 'yes')
  % this is only implemented for pcc and no refdips/chans at the moment
  Nchan        = size(source.leadfield{insideindx(1)}, 1);
  Ninside      = length(insideindx);
  allfilter    = zeros(Ninside,Nchan);
  allleadfield = zeros(Nchan,Ninside);
  dipsel       = match_str(source.avg.csdlabel, 'scandip');
  ft_progress('init', cfg.feedback, 'computing resolution matrix');
  for diplop=1:length(insideindx)
    ft_progress(diplop/length(insideindx), 'computing resolution matrix %d/%d\n', diplop, length(insideindx));
    % concatenate all filters
    allfilter(diplop,:)    = source.avg.filter{insideindx(diplop)}(dipsel,:);
    % concatenate all leadfields
    allleadfield(:,diplop) = source.leadfield{insideindx(diplop)};
  end
  ft_progress('close');
  % multiply the filters and leadfields to obtain the resolution matrix
  % see equation 1 and 2 in De Peralta-Menendez RG, Gonzalez-Andino SL: A critical analysis of linear inverse solutions to the neuroelectromagnetic inverse problem. IEEE Transactions on Biomedical Engineering 45: 440-448, 1998.
  source.resolution = nan(Ndipole, Ndipole);
  source.resolution(insideindx, insideindx) = allfilter*allleadfield;
end

% compute fwhm
if strcmp(cfg.fwhm, 'yes')
  switch cfg.fwhmmethod
    case 'barnes'
      if ~isfield(source, 'dim')
        ft_error('computation of fwhm is not possible with method ''barnes'' is not possible when the dipoles are not defined on a regular 3D grid');
      end
      fprintf('computing fwhm of spatial filters using method ''barnes''\n');
      source = estimate_fwhm1(source, cfg.fwhmremovecenter);
    case 'gaussfit'
      fprintf('computing fwhm of spatial filters using method ''gaussfit''\n');
      source = estimate_fwhm2(source, cfg.fwhmmaxdist);
    otherwise
      ft_error('unknown method for fwhm estimation');
  end
end

% do the general cleanup and bookkeeping at the end of the function
ft_postamble debug
ft_postamble previous   source
ft_postamble provenance source
ft_postamble history    source
ft_postamble savevar    source

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% helper function to compute eta from a csd-matrix
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [eta, u] = csd2eta(csd)
[u,s,v] = svd(real(csd));
eta     = s(2,2)./s(1,1);
u       = u'; %orientation is defined in the rows

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% helper function to compute fa from a csd-matrix
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [fa] = csd2fa(csd)
s  = svd(real(csd));
ns = rank(real(csd));
s  = s(1:ns);
ms = mean(s);
fa = sqrt( (ns./(ns-1)) .* (sum((s-ms).^2))./(sum(s.^2)) );

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% helper function to compute power
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function p = powmethod_lambda1(x, ind)

if nargin==1
  ind = 1:size(x,1);
end
s = svd(x(ind,ind));
p = s(1);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% helper function to compute power
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function p = powmethod_trace(x, ind)

if nargin==1
  ind = 1:size(x,1);
end
p = trace(x(ind,ind));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% helper function to compute power
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function p = powmethod_regular(x, ind)

if nargin==1
  ind = 1:size(x,1);
end
p = abs(x(ind,ind));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% helper function to obtain the largest singular value or trace of the
% source CSD matrices resulting from DICS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function s = lambda1(x)
s = svd(x);
s = s(1);


%% PLANETOID CLASS (planetoid.m) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The Moon class is an iteration of the spheriod obstacle class aimed
% mostly providing a reference for satelite simulation.

% Author: James A. Douthwaite 09/02/2019

classdef planetoid < obstacle_spheroid
    properties
        inclination;    % Inclination angle
        orbit;          % Orbit
        orbitalSpeed;   % Oribital speed
        mass;           % Planetoid mass
        axialRate = 1;  % Rotational rate about its vertical axes(rad/s)
    end
    %% ///////////////////////// MAIN METHODS /////////////////////////////
    methods
        % Constructor
        function this = planetoid(varargin)
            % This function constructs the cuboid obstacle. The object must
            % be imported and represented with a global position and
            % velocity as all other objects are in OMAS.

            % Call the super class
            this = this@obstacle_spheroid(varargin);

            % IMPORT THE OBJECT'S GEOMETRY IF IT EXISTS
            [this.GEOMETRY] = OMAS_graphics.scale(this.GEOMETRY,this.radius);  % Scale

            % //////////////// Check for user overrides ///////////////////
            [this] = this.ApplyUserOverrides(varargin); % Recursive overrides
            % /////////////////////////////////////////////////////////////
        end
        % Setup - X = [x;x_dot]' 3D STATE VECTOR
        function [this] = setup(this,localXYZVelocity,localXYZrotations)
            % The state initialiser must be called 'initialise_localState'
            % and instead calls the 'initialise_3DVelocities' function in
            % this case.
            [this] = this.setup_3DVelocities(localXYZVelocity,localXYZrotations);
            % ADD A ROTATIONAL RATE
            this.localState(12) = this.axialRate; % The earth rotates a constant rate about its z interial axis
        end
        % Main
        function [this] = main(this,TIME,varargin)
            % SIMPLE UPDATE OF LOCAL STATE
            dt = TIME.dt;
            X = this.localState(1:6,1);
            U = this.localState(7:12,1);

            % SIMPLY INTEGRATE THE RATES
            [dXdt] = this.SingleIntegratorDynamics(X,U);
            eulerState = this.localState;
            eulerState(1:6,1) = this.localState(1:6,1) + dt*dXdt;

            % UPDATE THE GLOBAL PROPERTIES
            [this] = this.GlobalUpdate_3DVelocities(dt,eulerState);
        end
    end
end


function [varargout] = file_readBV(file, varargin)
% FILE_READBV - load EEG data which is stored in BrainVision format.
%                  C-functions are used for better performance. Use the
%                  slower FILE_LOADBV if this function does not work.
%
% Synopsis:
%   [CNT, MRK, HDR]= file_readBV(FILE, 'Property1',Value1, ...)
%
% Arguments:
%   FILE: file name (no extension),
%         relative to BTB.RawDir unless beginning with '/' (resp '\').
%         FILE may also contain the wildcard symbol '*'. In this case
%         make sure that the order of the files (printed to the terminal)
%         is appropriate.
%         FILE may also be a cell array of file names.
%
% Properties:
%   'CLab': Channels to load (labels or indices). Default all
%           (which can be explicitly specified by [])
%   'Fs': Sampling interval, must be an integer divisor of the
%         sampling interval of the raw data. fs may also be 'raw' which means
%         sampling rate of raw signals. Default: 'raw'.
%   'Ival': Interval to read, [start end] in msec. It is not checked
%           whether the whole interval could be loaded, or the file is shorter.
%   'IvalSa': Same as 'ival' but [start end] in samples of the downsampled data.
%   'Start': Start [msec] reading.
%   'MaxLen': Maximum length [msec] to be read.
%   'Filt': Filter to be applied to raw data before subsampling.
%           opt.Filt must be a struct with fields 'b' and 'a' (as used for
%           the Matlab function filter).
%           Note that using opt.Filt may slow down loading considerably.
%   'SubsamplePolicy': Function that is used for subsampling after filtering,
%           specified as as string or a vector.
%           Default 'subsampleByMean'. Other 'subsampleByLag'
%           If you specify a vector it has to be the same size as lag.
%   'LinearDerivation' : for creating bipolar channels (see
%   procutil_biplist2projection for details)
%
% Remark:
%   Properties 'Ival' and 'Start'+'MaxLen' are exclusive, i.e., you may only
%   specify one of them.
%
% Returns:
%   CNT: struct for contiuous signals
%        .x: EEG signals (time x channels)
%        .clab: channel labels
%        .fs: sampling interval
%        .scale: if this field is given, the real data are .x*.scale,
%           and .x is int
%   MRK: struct of marker information
%   HDR: struct of header information
%
% TODO: The function so far can only read specific formats, e.g.,
%       multiplexed, INT_16, ... The function does not even check, whether
%       the file is in this format!
%
% See also: file_* procutil_biplist2projection
%
%Hints:
% A low pass filter to get rid of the line noise can be designed as follows:
%  hdr= file_readBVheader(file);
%  Wps= [40 49]/hdr.fs*2;
%  [n, Ws]= cheb2ord(Wps(1), Wps(2), 3, 50);
%  [filt.b, filt.a]= cheby2(n, 50, Ws);
% You can also use filtdemo to design your own filters.

% Benjamin Blankertz

%   2008/06/20/ - Max Sagebaum
%               - refactored file_loadBV to read the data with read_bv.c
%               - removed code fragments marked as obsolete
%               - you can now use the ival option when concatinating
%                 multiple eeg files
%   2008/06/17  - Max Sagebaum
%               - the iir filter was not properly send to read_bv
%   2010/09/09  - Max Sagebaum
%               - There was an bug in the check for the lag

%% check if the mex file is present
readBV_status = exist('read_bv','file');
if not(readBV_status == 3)
    warning('Could not detect mex files for read_bv! Using file_loadBV instead.')
    varargout= cell(1, nargout);
    [varargout{:}]= file_loadBV(file, varargin{:});
    return;
end

%% start file_readBV
global BTB

props= {'CLab'               ''       'CHAR|CELL{CHAR}'
        'Fs'                 'raw'    'CHAR|DOUBLE'
        'Start'              0        'DOUBLE[1]'
        'MaxLen'             inf      'DOUBLE[1]'
        'Prec'               0        'DOUBLE[1]'
        'Ival'               []       'DOUBLE[2]'
        'IvalSa'             []       'DOUBLE[2]'
        'SubsamplePolicy'    'mean'   'CHAR(mean lag)|DOUBLE'
        'Filt'               []       'STRUCT(a b)'
        'LinearDerivation'   []       'STRUCT'
        'TargetFormat'       'bbci'   'CHAR'
        'Verbose'            1        'BOOL'
       };

props_readBVmarkers= file_readBVmarkers;
props_readBVheader= file_readBVheader;
all_props= opt_catProps(props, props_readBVmarkers, props_readBVheader);

if nargin==0,
  varargout= {all_props};
  return
end

opt= opt_proplistToStruct(varargin{:});
[opt, isdefault]= opt_setDefaults(opt, props);
opt_checkProplist(opt, all_props);

misc_checkType(file, 'CHAR|CELL{CHAR}');

if ~isempty(opt.Ival),
  if ~isdefault.Start || ~isdefault.MaxLen,
    error('specify either ''Ival'' or ''Start''+''MaxLen'' but not both');
  end
  if ~isempty(opt.IvalSa),
    error('specify either ''Ival'' or ''IvalSa'' but not both');
  end
  opt.Start= opt.Ival(1);
  opt.MaxLen= diff(opt.Ival)+1;
end

%% read the headers an prepare the clab

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

fileNames = cell(1,length(file));
fileTitle = cell(1,length(file));
% use BTB.RawDir as default dir
for filePos = 1:length(file)
  if fileutil_isAbsolutePath(file{filePos}),
    fileNames{filePos}= file{filePos};
    [dmy, fileTitle{filePos}]= fileparts(file{filePos});
  else
    fileNames{filePos} = fullfile(BTB.RawDir, file{filePos});
    fileTitle{filePos}= file{filePos};
  end
end

% get all files specified with the file object
fileNamesTemp = {};
for filePos = 1:length(file)

  if ischar(fileNames{filePos}) && ismember('*', fileNames{filePos},'legacy'),
    dd= dir([fileNames{filePos} '.eeg']);
    if isempty(dd),
      error('\nFile not found: %s\n', fileNames{filePos});
    end
    fc= cellfun(@(x)(x(1:end-4)), {dd.name}, 'UniformOutput',0);

    fileNamesTemp = cat(2,fileNamesTemp,strcat(fileparts(fileNames{filePos}), '/', fc));
  else
    fileNamesTemp = cat(2,fileNamesTemp,{fileNames{filePos}});
  end
end
fileNames = fileNamesTemp;
if length(fileNames)>1,
  if opt.Verbose,
    fprintf('concatenating files in the following order:\n');
    fprintf('  %s\n', fileNames{:});
  end
end

% now we read all headers and make some consistent checks if neeeded
hdr = cell(1,length(fileNames));
opt_readBVheader= opt_substruct(opt, props_readBVheader(:,1));
for filePos = 1:length(fileNames)
  hdr{filePos} = file_readBVheader(fileNames{filePos}, opt_readBVheader);

  % set the clabs and the raw_fs if we are in the loop for the first time
  if(filePos == 1)
    cnt.clab= hdr{filePos}.clab;
    raw_fs= hdr{filePos}.fs;
  end

  if ~isequal(cnt.clab, hdr{filePos}.clab),
    warning(['inconsistent clab structure will be repaired ' ...
             'by using the intersection']);
    cnt.clab = intersect(cnt.clab, hdr{filePos}.clab,'legacy');
  end
  if isequal(opt.Fs, 'raw')
    % if we want to read the raw data check if for each file the raw data
    % is the same
    if~isequal(raw_fs, hdr{filePos}.fs)
      error('inconsistent sampling rate');
    end
  else
    % if we have a specific fs check if for each file we have a positive
    % lag
    lag = hdr{filePos}.fs/opt.Fs;
    if lag~=round(lag) || lag<1,
      error('fs must be a positive integer divisor of every file''s fs');
    end
  end
end
clab_in_file= cnt.clab;

% select specified channels
if ~isempty(opt.CLab) && strcmp(opt.TargetFormat,'bbci'),
  cnt.clab= cnt.clab(util_chanind(cnt, opt.CLab));
end

% sort channels for memory efficient application of linear derivation:
% temporary channels are moved to the end
if ~isempty(opt.LinearDerivation),
  rm_clab= cell_flaten({opt.LinearDerivation.rm_clab});
  rmidx= util_chanind(cnt.clab, rm_clab);
  cnt.clab(rmidx)= [];
  cnt.clab= cat(2, cnt.clab, rm_clab);
end

%% prepare the output samples
firstFileToRead = 1;
firstFileSkip = 0;
lastFileToRead = length(fileNames);
lastFileLength = inf;

% check if we want to load the raw data
if isequal(opt.Fs, 'raw'),
  opt.Fs= raw_fs;
end
cnt.fs= opt.Fs;
cnt.title = str_vec2str(fileTitle);
cnt.file = str_vec2str(fileNames);

nChans= length(cnt.clab);

% get the skip and maxlen values for the data in samples for the new
% sampling rate
if ~isempty(opt.IvalSa),
  if ~isdefault.Start || ~isdefault.MaxLen,
    error('specify either <IvalSa> or <Start/MaxLen> but not both');
  end
  skip= opt.IvalSa(1)-1;
  maxlen = diff(opt.IvalSa)+1;
else
  skip= max(0, floor(opt.Start/1000*opt.Fs));
  maxlen = ceil(opt.MaxLen/1000*opt.Fs);
end

%get the number of samples for every file and check from which file we have
%to read
nSamples = 0;
dataSamples = 0;
dataSize = zeros(1,length(fileNames));
for filePos = 1:length(fileNames)
  % check if we can read the data with read_bv
  % currently only 16Bit Integers are supported
  switch hdr{filePos}.BinaryFormat
   case 'INT_16',
    cellSize= 2;
    readbv_binformat(filePos)=1;
   case 'INT_32',
    cellSize= 4;
    readbv_binformat(filePos)=2;
   case {'IEEE_FLOAT_32', 'FLOAT_32'},
    cellSize= 4;
    readbv_binformat(filePos)=3;
   case {'IEEE_FLOAT_64', 'FLOAT_64', 'DOUBLE'},
    cellSize= 8;
    readbv_binformat(filePos)=4;
   otherwise
    error('Precision %s not known.', hdr.BinaryFormat);
  end

  % open the file to get the size
  fid= fopen([fileNames{filePos} '.eeg'], 'r', hdr{filePos}.endian);
  if fid==-1, error('%s.eeg not found', fileNames{filePos}); end
  fseek(fid, 0, 'eof');
  fileLen= ftell(fid);
  fclose(fid);

  curChannels = length(hdr{filePos}.clab);
  curLag = hdr{filePos}.fs/opt.Fs;
  samples_in_file = floor(fileLen/(cellSize*curChannels));
  samples_after_subsample = floor(samples_in_file / curLag);
  dataSize(filePos) = samples_after_subsample;

  % set the new first file and the first data in this file
  if nSamples <= skip
    firstFileToRead = filePos;
    firstFileSkip = skip - nSamples;
    dataSamples = samples_after_subsample - firstFileSkip;
  else
    dataSamples = dataSamples + samples_after_subsample;
  end
  % advance to the end of the cur file
  nSamples = nSamples + samples_after_subsample;

  % if we reach the end set the last file and stop reading
  if nSamples >= (skip + maxlen)
    lastFileToRead = filePos;
    lastFileLength = samples_after_subsample - (nSamples - (skip + maxlen));
    dataSamples = dataSamples - (samples_after_subsample - lastFileLength);
     break;
  else
    % only if we have no maxlen
    lastFileLength = samples_after_subsample;
  end

end

%% reading the data
%create the data block for all samples
chosen_clab = cnt.clab;
cnt.x = zeros(dataSamples,nChans);
cnt.T = dataSize;

dataOffset = 0; % the offset for the current file
for filePos = firstFileToRead:lastFileToRead
  % get the channel id for this file
  chanids = util_chanind(clab_in_file,chosen_clab); % the -1 is for read_bv

  read_opt = struct('fs',cnt.fs, 'chanidx',chanids);

  if ~isempty(opt.Filt)
    read_opt.filt_b = opt.Filt.b;
    read_opt.filt_a = opt.Filt.a;
  end
  % set the subsample filter
  lag = hdr{filePos}.fs/opt.Fs;
  switch opt.SubsamplePolicy,
    case 'mean',
      read_opt.filt_subsample = ones(1,lag)/lag;
    case 'lag',
      read_opt.filt_subsample = [zeros(1,lag-1) 1];
    otherwise,
      read_opt.filt_subsample = opt.SubsamplePolicy;
  end

  read_hdr = struct('fs',hdr{filePos}.fs, ...
                    'nChans',hdr{filePos}.NumberOfChannels, ...
                    'scale',hdr{filePos}.scale, ...
                    'endian',hdr{filePos}.endian, ...
                    'BinaryFormat',readbv_binformat(filePos));

  % get the position for the data in the whole data set
  if firstFileToRead == filePos
    firstX = 1;
    firstData = firstFileSkip + 1;
  else
    firstX = lastX + 1;
    firstData = 1;
  end

  if lastFileToRead == filePos
    lastX = nSamples;
    lastData = lastFileLength;
  else
    lastX = firstX + dataSize(filePos) - 1 - firstFileSkip;
    lastData = dataSize(filePos);
  end

  read_opt.data = cnt.x;
  read_opt.dataPos = [firstX lastX firstData lastData] - 1;

  % read the data, read_bv will set the data in cnt.x because of the
  % read_opt.data options
  read_bv([fileNames{filePos} '.eeg'], read_hdr, read_opt);
  cnt.yUnit= hdr{filePos}.unit;

  %% Markers
  if nargout>1,
    opt_mrk= opt_substruct(opt, props_readBVmarkers(:,1));
    curmrk= file_readBVmarkers(fileNames{filePos}, opt_mrk);
    curmrk.time= curmrk.time + dataOffset*1000/cnt.fs;
    % find markers in the loaded interval
    inival= find(curmrk.time > skip*1000/cnt.fs & ...
                 curmrk.time <= (skip+maxlen)*1000/cnt.fs);
    % add special case: don't loose t=0 markers
    % NO: markers with time=0 make problems!
    %if skip==0,
    %  idxzero= find(curmrk.time==0);
    %  inival= [idxzero, inival];
    %end
    curmrk= mrk_selectEvents(curmrk, inival);
    %let the markers start at zero
    curmrk.time= curmrk.time - skip*1000/cnt.fs;

    if firstFileToRead == filePos
      mrk = curmrk;
    else
      mrk = mrk_mergeMarkers(mrk, curmrk);
    end
    dataOffset = dataOffset + dataSize(filePos);
  end
end
clear read_opt;

if ~isempty(opt.LinearDerivation),
  ld= opt.LinearDerivation;
  for cc= 1:length(ld),
    ci= util_chanind(cnt.clab, ld(cc).chan);
    support= find(ld(cc).filter);
    s2= util_chanind(cnt.clab, ld(cc).clab(support));
    cnt.x(:,ci)= cnt.x(:,s2) * ld(cc).filter(support);
    cnt.clab{ci}= ld(cc).new_clab;
  end
  % delete temporary channels: TODO in a memory efficient way
  idx= util_chanind(cnt, rm_clab);
  cnt.x(:,idx)= [];
  cnt.clab(idx)= [];
end

varargout= cell(1, nargout);

varargout{1}= cnt;
if nargout > 1,
  varargout{2} = mrk;
end
if nargout>2,
  if(1 == length(hdr))
    varargout{3} = hdr{1};
  else
      varargout{3}= hdr;
  end
end


%-------------------------------------------------------------------------------------------------------------------%
%
% IB2d is an Immersed Boundary Code (IB) for solving fully coupled non-linear
% 	fluid-structure interaction models. This version of the code is based off of
%	Peskin's Immersed Boundary Method Paper in Acta Numerica, 2002.
%
% Author: Nicholas A. Battista
% Email:  nickabattista@gmail.com
% Date Created: October 8th, 2018
% Institution: UNC-CH
%
% This code is capable of creating Lagrangian Structures using:
% 	1. Springs
% 	2. Beams (*torsional springs / non-invariant beams *)
% 	3. Target Points
%	4. Muscle-Model (combined Force-Length-Velocity model, "HIll+(Length-Tension)")
%
% One is able to update those Lagrangian Structure parameters, e.g., spring constants, resting lengths, etc
%
% There are a number of built in Examples, mostly used for teaching purposes.
%
% If you would like us %to add a specific muscle model, please let Nick (nickabattista@gmail.com) know.
%
%--------------------------------------------------------------------------------------------------------------------%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FUNCTION: helps input previous .vtk information for restarting a
%           simulation that has ended because of power failure, etc.
%
%      NOTE: for restart protocol, need to have .vtk data for:
%                       1. lagPts (Lagrangian positions)
%                       2. u (velocity field)
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [current_time,cter,ctsave,U,V,xLag,yLag,xLag_P,yLag_P,path_to_data] = help_Me_Restart(dt)

%
% NEEDS TO BE HARDCODED PER SIMULATION BASIS
%
ctsave = 3;               % Last time-step of data saved (# at end of .vtk file);
print_dump = 40;           % Print_dump interval as given in input2d

% Path to Simulation Data (e.g., including viz_IB2d folder)
path_to_data = '/Users/battistn/Desktop/IB2d/matIB2d/Examples/Example_Test_Restart_Protocol/Standard_Rubberband_Restart/viz_IB2d/';

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ------------- DO NOT CHANGE BELOW --------------- %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

[current_time,cter,ctsave,U,V,xLag,yLag,xLag_P,yLag_P] = pass_Back_Data_For_Restart(dt,ctsave,print_dump,path_to_data);


function engine = belprop_inf_engine(fg, max_iter, momentum, tol, maximize)

if nargin < 2, max_iter = length(fg.G); end
if nargin < 3, momentum = 0; end
if nargin < 4, tol = 1e-3; end
if nargin < 5, maximize = 0; end

engine.fgraph = fg;
engine.max_iter = max_iter;
engine.momentum = momentum;
engine.tol = tol;
engine.maximize = maximize;

% store results computed by enter_evidence here
ndoms = length(fg.doms);
nvars = length(fg.vars);
engine.marginal_domains = cell(1, ndoms);

% to compute the marginal on each variable, we need to know which domain to marginalize
% so we represent each domain as a bit vector, and compute its (pre-evidence) weight
engine.dom_weight = [];

% engine.dom_bitv = sparse(ndoms, nvars);
% ns = fg.node_sizes;
% for i=1:ndoms
%   engine.dom_bitv(i, fg.doms{i}) = 1;
%   engine.dom_weight(i) = prod(ns(fg.doms{i}));
% end

engine = class(engine, 'belprop_inf_engine');


%-------------------------------------------------------------------------------------------------------------------%
%
% IB2d is an Immersed Boundary Code (IB) for solving fully coupled non-linear
% 	fluid-structure interaction models. This version of the code is based off of
%	Peskin's Immersed Boundary Method Paper in Acta Numerica, 2002.
%
% Author: Nicholas A. Battista
% Email:  nick.battista@unc.edu
% Date Created: May 27th, 2015
% Institution: UNC-CH
%
% This code is capable of creating Lagrangian Structures using:
% 	1. Springs
% 	2. Beams (*torsional springs)
% 	3. Target Points
%	4. Muscle-Model (combined Force-Length-Velocity model, "HIll+(Length-Tension)")
%
% One is able to update those Lagrangian Structure parameters, e.g., spring constants, resting lengths, etc
%
% There are a number of built in Examples, mostly used for teaching purposes.
%
% If you would like us to add a specific muscle model, please let Nick (nick.battista@unc.edu) know.
%
%--------------------------------------------------------------------------------------------------------------------%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FUNCTION: EXAMPLE DATA ANALYSIS CODE TO LOOK AT FLOW IN EMPTY CHANNEL
%
%     Note:
%           (1) This code analyzes viz_IB2d code for channel flow in
%               /data_analysis/Example_For_Data_Analysis/Example_Flow_In_Channel/viz_IB2d
%           (2) Produces a plot of cross-sectional mag. of velocity for
%               different points along the channel at three times.
%           (3) USER-DEFINED functions are functions that users should make to
%               analyze their specific data sets
%           (4) MUST make sure to 'addpath' to where DA_Blackbox is, i.e.,
%               line 61
%           (5) MUST make sure to set path to desired dataset, i.e., in line
%               56
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function Example_Channel_Flow_Analysis()

% TEMPORAL INFO FROM input2d %
dt = 1e-4;      % Time-step
Tfinal = 0.015; % Final time in simulation
pDump=50;       % Note: 'print_dump' should match from input2d

% DATA ANALYSIS INFO %
start=1;                             % 1ST interval # included in data analysis
finish=3;                            % LAST interval # included in data analysis
dump_Times = (start:1:finish)*pDump; % Time vector when data was printed in analysis

% SET PATH TO DESIRED viz_IB2d DATA and hier_IB2d DATA %
pathViz = 'viz_IB2d';
pathForce='hier_IB2d_data';

% SET PATH TO DA_BLACKBOX %
addpath('../../DA_Blackbox');

for i=start:1:finish

    % Points to desired data viz_IB2d data file
    if i<10
       numSim = ['000', num2str(i)];
    elseif i<100
       numSim = ['00', num2str(i)];
    elseif i<1000
       numSim = ['0', num2str(i)];
    else
       numSim = num2str(i);
    end

    % Imports immersed boundary positions %
    [xLag,yLag] = give_Lag_Positions(pathViz,numSim);

    % Imports (x,y) grid values and ALL EULERIAN DATA %
    %                      DEFINITIONS
    %          x: x-grid                y: y-grid
    %       Omega: vorticity           P: pressure
    %    uMag: mag. of velocity
    %    uX: mag. of x-Velocity   uY: mag. of y-Velocity
    %    U: x-directed velocity   V: y-directed velocity
    %    Fx: x-directed Force     Fy: y-directed Force
    %
    %  Note: U(j,i): j-corresponds to y-index, i to the x-index
    %
    %
    Eulerian_Flags(1) = 0;   % OMEGA
    Eulerian_Flags(2) = 0;   % PRESSURE
    Eulerian_Flags(3) = 1;   % uMAG
    Eulerian_Flags(4) = 0;   % uX (mag. x-component of velocity)
    Eulerian_Flags(5) = 0;   % uY (mag. x-component of velocity)
    Eulerian_Flags(6) = 0;   % uVEC (vector components of velocity: U,V)
    Eulerian_Flags(7) = 0;   % Fx (x-component of force )
    Eulerian_Flags(8) = 0;   % Fy (y-component of force)
    Eulerian_Flags(9) = 0;   % C (concentration)
    %
    [x,y,Omega,P,uMag,uX,uY,U,V,Fx,Fy,C] = import_Eulerian_Data(pathViz,numSim,Eulerian_Flags);

    % Imports Lagrangian Pt. FORCE (magnitude) DATA %
    %                      DEFINITIONS
    %
    %      fX_Lag: forces in x-direction on boundary
    %      fY_Lag: forces in y-direction on boundary
    %       fLagMag: magnitude of force at boundary
    %   fLagNorm: magnitude of NORMAL force at boundary
    %   fLagTan: magnitude of TANGENT force at boundary
    %
    [fX_Lag,fY_Lag,fLagMag,fLagNorm,fLagTan] = import_Lagrangian_Force_Data(pathForce,numSim);

    %
    %
    % *** USER DEFINED FUNCTIONS TO GET DESIRED ANALYSIS PT. INDICES *** %
    %                                                                    %
    if i==start
        %xPts = [0.125 0.225 0.325 0.425];
        xPts = [0.25 0.375 0.5 0.675];
        yPts = [0.405 0.595];
        [xInds,yInds] = give_Desired_Analysis_Points(x,y,xPts,yPts);
        vel_data = zeros(length(yInds),length(xInds),finish);
        %Inds = put_x_y_Indices_Together_For_Analysis(xInds,yInds);
    end

    %                                                                    %
    % ***** USER DEFINED FUNCTION TO SAVE DESIRED VELOCITY DATA *****    %
    %                                                                    %
    vel_data = store_Desired_Magnitude_Velocity_Data(uMag,vel_data,xInds,yInds,i);

end % END OF LOOP OVER ANALYZED TIME-PTS

%                                                                    %
% ***** USER DEFINED FUNCTION TO PLOT DESIRED VELOCITY DATA *****   %
%                                                                    %
yVals = y(yInds);
plot_Desired_Data(yVals,vel_data);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% USER-FUNCTION: Finds desired analysis point indices
%
%        INPUTS: x: x-grid pts (row vector)
%                y: y-grid pts (column vector)
%                xPts: desired x-pts to analyze
%                yPts: desired y-pts to analyze
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [xInds,yInds] = give_Desired_Analysis_Points(x,y,xPts,yPts)

% Get x-Indices
xInds = zeros(length(xPts),1);
for i=1:length(xPts)
   xPt = xPts(i);   % Get x-Pts
   k = 1;           % Initialize loop iteration variable
   while x(k) < xPt
      xInds(i) = k;
      k = k+1;
   end
end

% Get y-Indices
yIndsAux = zeros(length(yPts),1);
for i=1:length(yPts)
   yPt = yPts(i);   % Get x-Pts
   k = 1;           % Initialize loop iteration variable
   while y(k) < yPt
      yIndsAux(i) = k;
      k = k+1;
   end
end
yInds = yIndsAux(1):1:yIndsAux(2);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% USER-FUNCTION: Rearranges desired analysis indices
%
%        INPUTS: xInds: indices for x-region of interest
%                yInds: indices for y-region of interest
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function Inds = put_x_y_Indices_Together_For_Analysis(xInds,yInds)

% Order new index matrix %
Inds = zeros(length(xInds)*length(yInds),2);
count = 1;
for i=1:length(xInds)
    for j=1:length(yInds)
        Inds(count,1) = xInds(i);
        Inds(count,2) = yInds(j);
        count=count+1;
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% USER-FUNCTION: Stores desired magnitude of velocity data
%
%        INPUTS: uMag: magnitude of velocity from simulation
%                vel_data: stored mag. of velocity data in 3D-matrix
%                xInds/yInds: indices of where to save data
%                i: ith time-step to store data from
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function vel_data = store_Desired_Magnitude_Velocity_Data(uMag,vel_data,xInds,yInds,i)

% NOTE: vel_data(k,i): : k: magnitude of velocity data  (row)
%                      : j: xPt you're storing data for (column)
%                      : i: ith level you're storing in (level)

for j=1:length(xInds)
    for k=1:length(yInds)
       vel_data(k,j,i) = uMag( yInds(k),xInds(j) );
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% USER-FUNCTION: Plots magnitude of velocity data
%
%        INPUTS: vel_data: stored mag. of velocity data in 3D-matrix
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function plot_Desired_Data(yVals,vel_data)

fs = 16; % Font Size
lw = 5;  % Line Width
ms = 32; % MarkerSize

% Set Figure Size
FigHand = figure(1);
set(FigHand,'Position',[100,100,1024,895]);
%
% Make Figure!
%
subplot(3,1,1)
mat = vel_data(:,:,1);
maxVal = max(max(mat));
plot(yVals(2:end),vel_data(2:end,1,1),'.-','LineWidth',lw,'MarkerSize',ms); hold on;
plot(yVals(2:end),vel_data(2:end,2,1),'r.-','LineWidth',lw,'MarkerSize',ms); hold on;
plot(yVals(2:end),vel_data(2:end,3,1),'g.-','LineWidth',lw,'MarkerSize',ms); hold on;
plot(yVals(2:end),vel_data(2:end,4,1),'k.-','LineWidth',lw,'MarkerSize',ms); hold on;
axis([0.4 0.6 0 1.1*maxVal]);
leg=legend('x=0.25','x=0.375','x=0.50','x=0.625');
title('t=0.005s');
ylabel('Mag. Velocity','FontSize',fs); xlabel('y','FontSize',fs);
set(leg,'FontSize',fs);
set(gca,'FontSize',fs-1);
%
subplot(3,1,2)
mat = vel_data(:,:,2);
maxVal = max(max(mat));
plot(yVals(2:end),vel_data(2:end,1,2),'.-','LineWidth',lw,'MarkerSize',ms);  hold on;
plot(yVals(2:end),vel_data(2:end,2,2),'r.-','LineWidth',lw,'MarkerSize',ms); hold on;
plot(yVals(2:end),vel_data(2:end,3,2),'g.-','LineWidth',lw,'MarkerSize',ms); hold on;
plot(yVals(2:end),vel_data(2:end,4,2),'k.-','LineWidth',lw,'MarkerSize',ms); hold on;
axis([0.4 0.6 0 1.1*maxVal]);
leg=legend('x=0.25','x=0.375','x=0.50','x=0.625');
ylabel('Mag. Velocity','FontSize',fs); xlabel('y','FontSize',fs);
set(leg,'FontSize',fs);
set(gca,'FontSize',fs-1);
title('t=0.01s');
%
subplot(3,1,3)
mat = vel_data(:,:,3);
maxVal = max(max(mat));
plot(yVals(2:end),vel_data(2:end,1,3),'.-','LineWidth',lw,'MarkerSize',ms); hold on;
plot(yVals(2:end),vel_data(2:end,2,3),'r.-','LineWidth',lw,'MarkerSize',ms); hold on;
plot(yVals(2:end),vel_data(2:end,3,3),'g.-','LineWidth',lw,'MarkerSize',ms); hold on;
plot(yVals(2:end),vel_data(2:end,4,3),'k.-','LineWidth',lw,'MarkerSize',ms); hold on;
axis([0.4 0.6 0 1.1*maxVal]);
leg=legend('x=0.25','x=0.375','x=0.50','x=0.625');
ylabel('Mag. Velocity','FontSize',fs); xlabel('y','FontSize',fs);
set(leg,'FontSize',fs);
set(gca,'FontSize',fs-1);
title('t=0.015s');


function [event] = read_nexstim_event(filename)

% Use as
%   [event] = read_nexstim_event(filename)

% Written by Vladimir Litvak based on the function nxeGetTriggers
% provided by Nexstim
%
% Copyright (C) 2007, Vladimir Litvak
%
% This file is part of FieldTrip, see http://www.ru.nl/neuroimaging/fieldtrip
% for the documentation and details.
%
%    FieldTrip 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.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id: read_nexstim_event.m 945 2010-04-21 17:41:20Z roboos $

% trigLine - either 1(GATE), 2(TRIG1) or 3(TRIG2)
% trigEdge - either 'rising' or 'falling'

fid=fopen(filename,'r','l');

numChannels = 64;
blockSamples = 14500;
trigThreshold = 2000;
trigChannels = [1 2 3]; % Is fixed for the present Nexstim format.

fseek(fid,0,'eof');
numBytes = ftell(fid);
numSamples = (numBytes/2)/numChannels;
numBlocks = ceil(numSamples/blockSamples);

fseek(fid,0,'bof');
trigPos=[];

event=[];
for i = 1:numBlocks
    blockPos=(i-1)*blockSamples;
    data = fread(fid,[numChannels blockSamples+1],'int16');

    for trigLine=1:length(trigChannels);
        trigPosRising = find(diff(data(trigChannels(trigLine),:))>trigThreshold)+blockPos;
        trigPosFalling = find(diff(data(trigChannels(trigLine),:))<-trigThreshold)+blockPos;

        if ~isempty(trigPosRising)
            for i=1:length(trigPosRising)
                event(end+1).type     = 'rising';
                event(end  ).sample   =  trigPosRising(i);
                event(end  ).value    = trigLine;
                event(end  ).offset   = [];
                event(end  ).duration = [];
            end
        end

        if ~isempty(trigPosFalling)
            for i=1:length(trigPosFalling)
                event(end+1).type     = 'falling';
                event(end  ).sample   =  trigPosFalling(i);
                event(end  ).value    = trigLine;
                event(end  ).offset   = [];
                event(end  ).duration = [];
            end
        end

    end
    fseek(fid,-(2*numChannels),'cof');
end

fclose(fid);


function F = plus( F, G )
% + PLUS of two CHEBFUN2V objects.
%   F + G if F and G are CHEBFUN2V objects does componentwise addition.
%
%   F + G if F is a double and G is a CHEBFUN2V does componentwise addition.
%
%   F + G if F is a CHEBFUN2V and G is a double does componentwise addition.
%
%   PLUS(F,G) is called for the syntax F + G.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

% Empty check:
if ( isempty( F ) || isempty( G ) )
    F = chebfun2v;
    return
end

if ( ~isa( F , 'chebfun2v' ) )
    F = plus(G, F);
    return
end

nF = F.nComponents;

if ( isa(G, 'double') )              % CHEBFUN2V + DOUBLE
    if ( numel(G) == 1 )             % CHEBFUN2V + SCALAR
        for jj = 1 : nF
            F.components{jj} = plus(F.components{jj}, G);
        end
    elseif ( numel(G) == nF )        % CHEBFUN2V + MATRIX
        for jj = 1 : nF
             F.components{jj} = plus(F.components{jj}, G(jj));
        end
    else
        error('CHEBFUN:CHEBFUN2V:plus:doubleSize', 'Dimension mismatch.')
    end
elseif ( isa(G, 'chebfun2') )        % CHEBFUN2V + CHEBFUN
    for jj = 1 : nF
        F.components{jj} = plus(F.components{jj}, G);
    end
elseif ( isa(G, 'chebfun2v') )       % CHEBFUN2V + CHEBFUN2V
    nG = G.nComponents;
    if ( nG ~= nF )
        error('CHEBFUN:CHEBFUN2V:plus:components', ...
            'The chebfun2v objects do not have the same components.')
    end
    if ( G.isTransposed ~= F.isTransposed )
        error('CHEBFUN:CHEBFUN2V:plus:transposed', 'Dimension mismatch.')
    end
    for jj = 1 : nF                  % Add each component together
        F.components{jj} = plus(F.components{jj}, G.components{jj});
    end
else
    error('CHEBFUN:CHEBFUN2V:plus:type', 'Unrecongized input arguments')
end

end


function run_experiment_cfnet_conv1(imdb_video)
%% Experiment entry point

    startup;
    opts.gpus = 1;
    if nargin < 1
        imdb_video = [];
    end

    opts.join.method = 'corrfilt';
    opts.join.conf.lambda = 10;
    opts.join.conf.window = 'cos';
    opts.join.conf.sigma = 8;
    opts.join.conf.target_lr = 0;

    opts.branch.conf.last_layer = 'relu1';
    opts.branch.conf.num_out     = [32];
    opts.branch.conf.num_in      = [ 3 ];
    opts.branch.conf.conv_stride = [ 4];
    opts.branch.conf.pool_stride = [ 2];

    opts.exemplarSize = 255;
    opts.train.numEpochs = 100;

    experiment(imdb_video, opts);
end


function [recall, rankloss]= testNet(db, net, opts, ID, qFeat, dbFeat)

    relja_display('testNet: %s %s', opts.sessionID, ID);

    rankloss= testCoreRank(db, qFeat, dbFeat, opts.margin, opts.nNegChoice, 'nTestSample', opts.nTestRankSample);
    recall= testCore(db, qFeat, dbFeat, 'nTestSample', opts.nTestSample, 'recallNs', opts.recallNs);
end


% SB2_CONTROLSETTINGS  Set parameters to control the SPARSEBAYES algorithm
%
% CONTROLS = SB2_CONTROLSETTINGS
%
% OUTPUT ARGUMENTS:
%
%	CONTROLS	A structure whose fields control various aspects of the
%				running of the SPARSEBAYES algorithm.
%
%	.ZeroFactor			Small number equivalent to zero for Q^2-S
%	.MinDeltaLogAlpha	Termination criterion for changes in log-alpha
%	.MinDeltaLogBeta	Termination criterion for changes in log-beta
%
%	.PriorityAddition	Prefer "addition" operations
%	.PriorityDeletion	Prefer "deletion" operations
%
%	.BetaUpdateStart	How many "fast start" beta updates
%	.BetaUpdateFrequency
%						How regularly to update beta after the above
%	.BetaMaxFactor		Minimum value control for noise estimate
%
%	.PosteriorModeFrequency
%						How regularly to re-find the posterior mode
%
%	.BasisAlignmentTest	Test for redundant basis vectors?
%	.AlignmentMax		Basis redundancy criterion
%
% NOTES:
%
% The various definitions in the file are effectively "fixed" and not
% modified elsewhere.
%
% The interested user may wish to experiment with the operation of the
% SPARSEBAYES algorithm by modifying the values the file directly. See the
% inline comments for hints on the various control settings.
%

%
% Copyright 2009, Vector Anomaly Ltd
%
% This file is part of the SPARSEBAYES library for Matlab (V2.0).
%
% SPARSEBAYES 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.
%
% SPARSEBAYES 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 SPARSEBAYES in the accompanying file "licence.txt"; if not, write to
% the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
% MA 02110-1301 USA
%
% Contact the author: m a i l [at] m i k e t i p p i n g . c o m
%
function CONTROLS = SB2_ControlSettings

%% Define parameters which influence the underlying operation of the
%% SparseBayes inference algorithm

% TOLERANCES
%
% Any Q^2-S "relevance factor" less than this is considered to be zero
%
CONTROLS.ZeroFactor			= 1e-12;
%
% If the change in log-alpha for the best re-estimation is less than this,
% we consider termination
%
CONTROLS.MinDeltaLogAlpha	= 1e-3;
%
% In the Gaussian case, we also require a beta update to change the value
% of log-beta (inverse noise variance) less than this to terminate
%
CONTROLS.MinDeltaLogBeta	= 1e-6;

% ADD/DELETE
%
% - preferring addition where possible will probably make the algorithm a
% little slower and perhaps less "greedy"
%
% - preferring deletion may make the model a little more sparse and the
% algorithm may run slightly quicker
%
% Note: both these can be set to 'true' at the same time, in which case
% both take equal priority over re-estimation.
%
CONTROLS.PriorityAddition	= false;
CONTROLS.PriorityDeletion	= true;

% (GAUSSIAN) NOISE
%
% When to update the noise estimate
%
% The number of iterations from the start for which we update it every
% iteration (to get in the right ball-park to begin with)
%
CONTROLS.BetaUpdateStart		= 10;
%
% After the above, we only regularly update it after
% a given number of iterations
%
CONTROLS.BetaUpdateFrequency	= 5;
%
% Prevent zero-noise estimate (perfect fit) problem
% -	effectively says the noise variance estimate is clamped to be no
%	lower than variance-of-targets / BetaMaxFactor.
%
CONTROLS.BetaMaxFactor			= 1e6;

% POSTERIORMODE
%
% How many alpha updates to do in between each full posterior mode
% computation in the non-Gaussian case
%
% In principle, this should be set to one (to update the posterior every
% iteration) but it may be more efficient to do several alpha updates before
% re-finding the posterior mode.
%
CONTROLS.PosteriorModeFrequency	= 1;

% REDUNDANT BASIS
%
% Check for basis vector alignment/correlation redundancy
%
CONTROLS.BasisAlignmentTest		= true;
%
ALIGNMENT_ZERO					= 1e-3;
%
% If BasisAlignmentTest is true, any basis vector with inner product more
% than MAX_ALIGNMENT with any existing model vector will not be added
%
CONTROLS.AlignmentMax			= 1 - ALIGNMENT_ZERO;


function ApplyQiB()
%A rountine to execute the QIB on a computer cluster
% Written By: Issam El Naqa    Date: 10/3/03
% Revised by:                  Date:
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR 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.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

% read a treatment plan in "mat" format
[filename, pathname] = uigetfile('*.mat', 'Load a treatment plan');
load([pathname,filename]);
D=1; % downsample factor (optional)
indexS = planC{end};
scaleX=planC{indexS.scan}.scanInfo(1).grid1Units*D;
scaleY=planC{indexS.scan}.scanInfo(1).grid2Units*D;
scaleZ=planC{indexS.scan}.scanInfo(1).sliceThickness;
% get the CT file
inputCT=planC{indexS.scan}.scanArray;
% apply down sampling and cropping
vecx=145:D:394; vecy=126:D:375; vecz=40:99;
inputCTc=inputCT(vecx,vecy,vecz);  clear inputCT
CTdim=size(inputCTc);
% add margins of 1 cm to the targets
Margin=1;
TargetStructNum=[17,18];
inputMask1 = getMask3D(TargetStructNum(1),planC);
inputMask2 = getMask3D(TargetStructNum(2),planC);
inputMask=inputMask1 | inputMask2;
inputMasks=inputMask(vecx,vecy,vecz); % just cropping
clear planC inputMask1 inputMask2 inputMask
b=genball(7,Margin/2,[scaleX,scaleY,scaleZ]); % plan specific
% treat the targets separately!
inputMaskb=convn(inputMasks,b,'same');
einputMask=uint8(inputMaskb>0);
ind=regexp(filename,'.mat');
maskfile=filename(1:ind-1);
%save([pathname,maskfile,'_targetmask.mat'],'inputMasks','einputMask','CTdim','scaleX','scaleY','scaleZ');
gridX_distance100=1; gridY_distance100=1;
Energy=6; % plan specific and is inversely proportional to the squared uncertainity
Nbeams=9; % plan specific
Source_Distance=100;
[x,y]=circle([0,0], Source_Distance,Nbeams);
SCRCM=[x(1:Nbeams);y(1:Nbeams);zeros(1,Nbeams)];
% not clear about conventions?!
for N=1:Nbeams
    beam_num=N
    % need to be worked out?!
    [targetBeamGridCoor, numberPB(N),OSC]=mybeamgridcoordinatesVMC(einputMask,scaleX,scaleY,scaleZ,gridX_distance100,gridY_distance100,SCRCM(:,N)); % this is wrong!
    for i=1:numberPB(N)
        [DoseF, downCT, vCT, depthCor] = get_PB_3D(Energy,gridX_distance100,gridX_distance100,Source_Distance,angle,shift,planC);
        %temporal saving! need to be changed to other format?!
        str=[filename,'_beam',num2str(N),'_pb',num2str(i)];
        fid=fopen(str,'w');
        fwrite(fid,CTdim(1),'int32'); fwrite(fid,CTdim(2),'int32');  fwrite(fid,CTdim(3),'int32');
        fwrite(fid,downCT,'float32'); fwrite(fid,vCT,'float32');  fwrite(fid,depthCor,'float32');
        fwrite(fid,DoseF,'float32');
    end
end

function b=genball(N,r,Scale)
% make a ball of dimension NxNxN and radius r, scaled by Scale
Lc=floor(N/2);
vec=-Lc:Lc;
[x,y,z]=meshgrid(vec*Scale(1),vec*Scale(2),vec*Scale(3));
r2=x.^2+y.^2+z.^2;
b=zeros(N,N,N);
b(find(r2<r^2))=1;
return

function [x,y]=circle(c, r, nsides)
% a poly circle routine with center c, radius r, and nsides
nsides = round(nsides);  % make sure it is an integer
a = [0:2*pi/nsides:2*pi];
x=r*cos(a)+c(1);
y=r*sin(a)+c(2);
%line(x,y); uncomment for plotting
return


function script_rfcn_VOC0712_ResNet50_OHEM_ss()
% script_rfcn_VOC0712_ResNet50_OHEM_ss()
% RFCN training and testing with OHEM using ResNet50 model and selective
% search proposals
% --------------------------------------------------------
% R-FCN implementation
% Modified from MATLAB Faster R-CNN (https://github.com/shaoqingren/faster_rcnn)
% Copyright (c) 2016, Jifeng Dai
% Licensed under The MIT License [see LICENSE for details]
% --------------------------------------------------------

clc;
clear mex;
clear is_valid_handle; % to clear init_key
run(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'startup'));
%% -------------------- CONFIG --------------------
opts.caffe_version          = 'caffe_rfcn';
opts.gpu_id                 = auto_select_gpu;
active_caffe_mex(opts.gpu_id, opts.caffe_version);

% model
model                       = Model.ResNet50_for_RFCN_VOC0712_OHEM();
% cache name
opts.cache_name             = 'rfcn_VOC0712_ResNet50_OHEM_ss';
% config
conf                        = rfcn_config_ohem('image_means', model.mean_image);
% train/test data
fprintf('Loading dataset...')
dataset                     = [];
dataset                     = Dataset.voc0712_trainval_ss(dataset, 'train', conf.use_flipped);
dataset                     = Dataset.voc2007_test_ss(dataset, 'test', false);
fprintf('Done.\n');

% do validation, or not
opts.do_val                 = true;

%% -------------------- TRAINING --------------------

opts.rfcn_model        = rfcn_train(conf, dataset.imdb_train, dataset.roidb_train, ...
                                'do_val',           opts.do_val, ...
                                'imdb_val',         dataset.imdb_test, ...
                                'roidb_val',        dataset.roidb_test, ...
                                'solver_def_file',  model.solver_def_file, ...
                                'net_file',         model.net_file, ...
                                'cache_name',       opts.cache_name, ...
                                'caffe_version',    opts.caffe_version);
assert(exist(opts.rfcn_model, 'file') ~= 0, 'not found trained model');

%% -------------------- TESTING --------------------
                          rfcn_test(conf, dataset.imdb_test, dataset.roidb_test, ...
                                'net_def_file',     model.test_net_def_file, ...
                                'net_file',         opts.rfcn_model, ...
                                'cache_name',       opts.cache_name,...
                                'ignore_cache',     true);

end