function [roiVertInds, roiMapMode] = findROIVertices(roi, nodeInds, v2g)
% Returns a list of indices to each vertex belonging to the current ROI.
% [roiVertInds, roiMapMode] = findROIVertices(~, nodeInds, v2g)

% get ROI map mode
prefs = mrmPreferences;
if isequal(prefs.layerMapMode, 'layer1')
    roiMapMode = 'layer1';
else
    roiMapMode = 'any';
end

switch lower(roiMapMode)
	case 'layer1'
		% The following will give us *a* vertex index for each gray node. However,
		% the same gray node may map to multiple vertices, and we want them
		% all. (Otherwise, the color overlay will have holes.) So, we loop
		% until we've got them all.
		[junk, roiVertInds] = ismember(nodeInds, v2g(1,:));
		roiVertInds = roiVertInds(roiVertInds>0);
		while(any(junk))
			v2g(1,roiVertInds) = 0;
			[junk,tmp] = ismember(nodeInds, v2g(1,:));
			roiVertInds = [roiVertInds; tmp(tmp>0)];
		end

	case 'any'
		% if any of the nodes mapping to a given vertex are in the
		% ROI, include that vertex for drawing the ROI
		I = ismember(v2g, nodeInds);
		roiVertInds = find(sum(I)>0); % find columns w/ at least 1 member

	case 'data'
		% take ROI value from the same nodes as the data mapping,
		% rounding up (e.g., for 'mean' data mapping, will behave
		% like 'any'

	otherwise
		error('Invalid ROI Draw Mode preference.')
end

return


function [W] = readDMAT(filename)
  % READDMAT  read a matrix from a dmat file.  first line is <# columns> <#
  % rows>, then values with columns running faster
  %
  % [W] = readDMAT(filename)
  %
  % Input:
  %   filename  name of .dmat file
  % Output:
  %   W  matrix read from file
  %
  % See also: writeDMAT
  %

  % open file
  fp = fopen(filename,'r');
  % read header
  size_W = fliplr(fscanf(fp,'%d %d',[1 2]));
  % read data
  W = fscanf(fp,'%g',size_W);

  if ~feof(fp)
    [size_B,c_B] = fscanf(fp,'%d %d',[1 2]);
    size_B = fliplr(size_B);
    if c_B==2 && all(size_B>0)
      assert(~any(size_W));
      assert(isempty(W));
      % Finish reading header: read '\n' char
      [lf,nlf] = fread(fp,1,'char*1');
      assert(nlf==1);
      assert(lf==int8(sprintf('\n')));
      % We're reading binary then
      size_W = size_B;
      [W,cW] = fread(fp,prod(size_W),'*double');
      assert(cW == prod(size_W));
      W = reshape(W,size_W);
    end
  end

  % close file
  fclose(fp);

  % size should match header
  if(~all(size_W == size(W)))
    error('Size in header (%d,%d) did not match size of data (%d,%d) in file',size_W,size(W));
  end

end


function [atlas, varargout] = handle_atlas_input(atlas, varargin)

% HANDLE_ATLAS_INPUT handles user input to specify volumetric atlases in some coordinate. It
% does two things: (1) call FT_READ_ATLAS to read the atlas from file, if it is specified as a
% string input, and (2) if the optional second data input argument is provided, and it has a
% coordsys and/or unit field, checks the coordinate systems and units of the atlas and the
% input against each other.
%
% This code was taken from ft_sourceplot to avoid duplication upon adding similar functionality
% to ft_sourceplot_interactive.

if ischar(atlas)
  % initialize the atlas
  [p, f, x] = fileparts(atlas);
  fprintf(['reading ', f, ' atlas coordinates and labels\n']);
  atlas = ft_read_atlas(atlas);
end

if nargin > 1
  data_hasunit = isfield(varargin{1}, 'unit');
  data_hascoordsys = isfield(varargin{1}, 'coordsys');

  % ensure that the atlas is formatted properly
  atlas = ft_checkdata(atlas, 'hasunit', data_hasunit, 'hascoordsys', data_hascoordsys);

  if data_hasunit
    % ensure that the units are consistent, convert if required
    atlas = ft_convert_units(atlas, varargin{1}.unit);

    % all data objects should have the same unit
    for i=2:numel(varargin)
      varargin{i} = ft_convert_units(varargin{i}, varargin{1}.unit);
    end
  end

  if data_hascoordsys
    % ensure that the coordinate systems are consistent, convert if required
    atlas = ft_convert_coordsys(atlas, varargin{1}.coordsys);

    % all data objects should have the same coordsys
    for i=2:numel(varargin)
      varargin{i} = ft_convert_coordsys(varargin{i}, varargin{1}.coordsys);
    end
  end
end

% the unit and coordsys might have changed
varargout = varargin;


% msTrainClassifiersCv

LOAD = 1;

nsegments = [5 7 10 15 20 25 35 50 60 70 80 90 100 Inf]; % number of segments per segmentation
labeltol = 0.9; % required percentage of single-label pixels for segment to be good
nclasses = 23;
ncv = 5;

datadir = '~/data/eccv08/msrc21/';
imdir = '~/data/msrc/MSRC_ObjCategImageDatabase_v2/Images/';
outdir = '~/data/eccv08/msrc21/';

if LOAD
    load(fullfile(datadir, 'msrc_imsegs.mat'));
    load(fullfile(datadir, 'trainLabels.mat'));
    load(fullfile(datadir, 'trainTestFn_tu.mat'));
    load(fullfile(datadir, 'msSegmentFeatures_tu.mat'));
end

disp('Getting cross-validation subsets');
if ~exist('testcv', 'var')
    testcv = cell(ncv, 1);
    traincv = cell(ncv, 1);
    ind = train(randperm(numel(train)));
    fi = floor(numel(train)*(0:ncv-1)/ncv+1);
    li = floor(numel(train)*(1:ncv)/ncv);
    for k = 1:ncv
        testcv{k} = ind(fi(k):li(k));
        traincv{k} = setdiff(train, testcv{k});
    end
    save(fullfile(outdir, 'msCvind_tu.mat'), 'traincv', 'testcv');
end

disp('Training segmentation classifier')
if ~exist('segclassifier', 'var')
    for k = 1:ncv
        disp(num2str(k))
        trainind = traincv{k};
        traindata = segfeatures(trainind, :);
        trainlabels = seggood(trainind, :);
        trainweights = trainw(trainind, :);
        segclassifier(k) = mcmcTrainSegmentationClassifier2(traindata, trainlabels, trainweights);
    end
    save(fullfile(outdir, 'msSegmentationClassifier_cv_tu.mat'), 'segclassifier');
end

disp('Training label classifier')
if ~exist('labelclassifier', 'var')
    for k = 1:ncv
        disp(num2str(k))
        trainind = traincv{k};
        traindata = segfeatures(trainind, :);
        trainlabels = seglabel(trainind, :);
        trainweights = trainw(trainind, :);
        labelclassifier(k) = msTrainLabelClassifier(traindata, trainlabels, trainweights, ...
		classnames, Inf);
        %labelclassifier = mcmcTrainSegmentClassifier2(traindata, trainlabels, trainweights);
    end
    save(fullfile(outdir, 'msLabelClassifier_cv_tu.mat'), 'labelclassifier');
end


function kern = polyardKernExpandParam(kern, params)

% POLYARDKERNEXPANDPARAM Create kernel structure from POLYARD kernel's parameters.
% FORMAT
% DESC returns a automatic relevance determination polynomial kernel structure filled with the
% parameters in the given vector. This is used as a helper function to
% enable parameters to be optimised in, for example, the NETLAB
% optimisation functions.
% ARG kern : the kernel structure in which the parameters are to be
% placed.
% ARG param : vector of parameters which are to be placed in the
% kernel structure.
% RETURN kern : kernel structure with the given parameters in the
% relevant locations.
%
% SEEALSO : polyardKernParamInit, polyardKernExtractParam, kernExpandParam
%
% COPYRIGHT : Neil D. Lawrence, 2005, 2006

% KERN

kern.weightVariance = params(1);
kern.biasVariance = params(2);
kern.variance = params(3);
kern.inputScales = params(4:end);


function test_bug1925

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY surface_nesting ft_headmodel_bemcp

[ftver, ftpath] = ft_version;
cd(fullfile(ftpath, 'forward/private')); % this is where the surface_nesting function is located

[pos, tri] = mesh_sphere(162);

bnd10.id  = 10;
bnd10.pos = pos*10;
bnd10.tri = tri;

bnd20.id  = 20;
bnd20.pos = pos*20;
bnd20.tri = tri;

bnd30.id  = 30;
bnd30.pos = pos*30;
bnd30.tri = tri;

bnd40.id  = 40;
bnd40.pos = pos*40;
bnd40.tri = tri;

bnd50.id  = 50;
bnd50.pos = pos*50;
bnd50.tri = tri;

bnd    = bnd10;
bnd(2) = bnd20;
bnd(3) = bnd30;
bnd(4) = bnd40;
bnd(5) = bnd50;
assert(equalorder(surface_nesting(bnd, 'insidefirst'), 1:5));
assert(equalorder(surface_nesting(bnd, 'outsidefirst'), fliplr(1:5)));

bnd    = bnd10;
bnd(3) = bnd20;
bnd(2) = bnd30;
bnd(5) = bnd40;
bnd(4) = bnd50;
assert(equalorder(surface_nesting(bnd, 'insidefirst'), [1 3 2 5 4]));
assert(equalorder(surface_nesting(bnd, 'outsidefirst'), fliplr([1 3 2 5 4])));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% helper function to deal with row and column comparisons
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function bool = equalorder(a, b)
bool = isequal(a(:), b(:));


function [C,logicConverged]=triSurfPermuteColor(varargin)

%% Parse input

switch nargin
    case 2
        F=varargin{1};
        V=varargin{2};
        nc=4;
        maxIter=1000;
    case 3
        F=varargin{1};
        V=varargin{2};
        nc=varargin{3};
        maxIter=1000;
    case 4
        F=varargin{1};
        V=varargin{2};
        nc=varargin{3};
        maxIter=varargin{4};
    otherwise
        error('Wrong number of input arguments');
end

C=randi(nc,size(F,1),1);

%%

TR = triangulation(F,V);
N = neighbors(TR);

%%
numFaces=size(F,1);

%% Random iterations

q=0;
logicConverged=0;
numPrev=numFaces;
while q<maxIter && logicConverged==0

    q=q+1;

    CN=C(N); %Colors for neighbours

    logicDoubleColor=CN==C(:,ones(size(CN,2),1));
    logicRep=any(logicDoubleColor,2);

    C(logicRep)=randi(nc,nnz(logicRep),1);

    %     set(hp,'CData',C);
    %     drawnow;
    numNow=nnz(logicRep);
    p=abs(numPrev-numNow)./numFaces;

    numPrev=nnz(logicRep);

    logicConverged=nnz(logicRep)==0;

    if q==maxIter
        break
    end
end

logicConverged=nnz(logicRep)==0;

%% Structured iterations

if ~logicConverged
    while logicConverged==0

        CN=C(N); %Colors for neighbours

        logicDoubleColor=CN==C(:,ones(size(CN,2),1));
        logicRep=any(logicDoubleColor,2);

        Ir=find(logicRep,1);

        c=C(Ir);
        cn=CN(Ir,:);

        cFound=0;
        s=1;
        while cFound
            if ~any(cn-s==0);
                C(Ir)=s;
                cFound=1;
            elseif s==nc
                cFound=1;
            end
            s=s+1;
        end
        %         set(hp,'CData',C);
        %         drawnow;

        if nnz(logicRep)==0
            logicConverged=1;
        else
            q=q+1;
        end

    end
end
logicConverged=nnz(logicRep)==0;

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


function [OV,OF] = combine(IV,IF,EV,EF)
  % COMBINE Two meshes where the second mesh was constructed as the surface of
  % the union of the volume of the first mesh and a third mesh. The order of
  % vertices is such that the first chunk of vertices in the second mesh is a
  % subsequence of vertices in the first mesh (the remaining chunks are a
  % subsequence of vertices from the third mesh, then new vertices). The goal
  % is to create a new mesh where the vertices are: all the vertices from the
  % first mesh then other vertices and faces from the second mesh. This means
  % in the resulting mesh the unreferenced vertices correspond to vertices that
  % were in the first mesh but not in the second mesh.
  %
  % Inputs:
  %   IV  vertex list of the first mesh
  %   IF  face list of the first mesh
  %   EV  vertex list of the second mesh
  %   EF  face list of the second mesh
  % Outputs:
  %   OV  vertex list of the output mesh
  %   OF  face list of the output mesh
  %

  % create new list of vertices which is IV followed by vertices in EV not in
  % IV
  OV = [IV; setdiff(EV,IV,'rows')];
  % find location in new list for each vertex in EV
  [TF,LOC] = ismember(EV,OV,'rows');
  assert(min(LOC) > 0);
  OF = LOC(EF);
end


classdef P2P < Algorithm

    methods (Access = public)

        function obj = P2P()
            obj.name = 'P2P';
            obj.inputPort = DataType.kSignal;
            obj.outputPort = DataType.kFeature;
        end

        function result = compute(~,signal)
            result = peak2peak(signal);
        end

        function metrics = computeMetrics(~,input)
            n = size(input,1);
            flops = 3 * n;
            memory = 1;
            outputSize = Constants.kFeatureBytes;
            metrics = Metric(flops,memory,outputSize);
        end
    end
end


%==============================================================================
% This code is part of the Matlab-based toolbox
% FAIR - Flexible Algorithms for Image Registration.
% For details see
% - https://github.com/C4IR and
% - http://www.siam.org/books/fa06/
%==============================================================================
% function [ph,th] = plotLM(LM,varargin);
%
% a convenient tool for plotting landmarks
%
% Input
%   LM            landmark positions
%   varargin    optional parameter, see below
%
% Output:
%  ph           handle to plot
%  th           handle to text
%
% see also E5_Hands_TPS for an example
%==============================================================================

function [ph,th] = plotLM(LM,varargin)

if nargin==0
    help(mfilename)
    runMinimalExample;
    return;
end

% setup default parameter
dim       = size(LM,2);
numbering = 'off';
dx        = 0.1;
fontsize  = 20;
color     = 'y';
for k=1:2:length(varargin), % overwrites default parameter
  eval([varargin{k},'=varargin{',int2str(k+1),'};']);
end;

ph = []; th = []; % create empty handles

% handle options 'numbering', 'fontsize' and 'dx'
J = strcmp(varargin,'numbering') ...
  | strcmp(varargin,'dx') | strcmp(varargin,'fontsize');
if any(J),
  I = find(J);
  K = setdiff(1:length(varargin),[I,I+1]);
  varargin = {varargin{K}};
end;

% use plot in 2D or 3D
varargin = {varargin{:},'color',color};
switch dim,
  case 2, ph = plot(LM(:,1),LM(:,2),'x',varargin{:});
  case 3, ph = plot3(LM(:,1),LM(:,2),LM(:,3),'x',varargin{:});
end;

if strcmp(numbering,'off'), return;  end;

% add labels to the landmarks
dx = [dx,zeros(1,dim-1)];
pos = @(j) LM(j,:) + dx;
for j=1:size(LM,1),
  th(j) = text('position',pos(j),'string',sprintf('%d',j));
end;
set(th,'fontsize',fontsize,'color',color);
%------------------------------------------------------------------------------
function runMinimalExample
help(mfilename);
clear
close all
setup2DhandData
figure;
subplot(1,2,1);
viewImage2D(dataT,omega,m,'colormap','bone(265)');
hold on; ph =plotLM(LM(:,1:2),'color','g'); hold off;
set(ph,'marker','s')
subplot(1,2,2);
viewImage2D(dataR,omega,m,'colormap','bone(265)');
hold on; ph = plotLM(LM(:,3:4),'color','r'); hold off;
set(ph,'marker','o')
%------------------------------------------------------------------------------


function [model,delta] = getPredictors(stimList, HRF, varargin)
% Build predictors and delta functions, given a condition function or delta
% function and either a convolution matrix or vector.
%
% :Usage:
% ::
%
%     [model,delta] = getPredictors(stimList, HRF, varargin)
%
% IMPORTANT: YOU MUST ADD THE INTERCEPT YOURSELF!
%
% :Inputs:
%
%   **stimList:**
%        condition function OR delta function (1/0 indicator)
%
%   **HRF:**
%        1) hemodynamic response function
%        2) Basis set (columns)
%        3) or convolution matrix (columns
%           are HRF), defined as:
%           HRF = tril(toeplitz(hrf));
%
%           multiple column vectors for HRF are treated as basis functions!
%
%   **varargin** for downsampling:
%        'dsrate': takes every nth element of the design matrix
%
%        'dslen': the target number (length) you want to downsample to
%
% :Other Optional Inputs:
%
%   **'force_delta':**
%        getPredictors tries to determine if the input stimList
%        is a condition function with integers or a delta function with
%        indicators, but this can fail in some cases.  Use this to force
%        it to treat as a delta function.
%
%   1. a col. vector of stimulus conditions OR a delta function matrix
%
%   2. an HRF vector sampled at the frequency of the stimulus vector, OR
%        a convolution matrix H (empty for default)
%
%   3. Optional: downsampling factor for final design (i.e., TR)
%
%   4. Optional: parametric modulator keyword and modulator values
%
%      'parametric_singleregressor' : Parametrically modulate onsets by
%               modulator values, using single regressor with modulated amplitude
%               Enter a cell array with modulator values for each event
%               type, with a column vector (empty cell for no modulation)
%
%       'parametric_standard' : Parametrically modulate onsets by
%               modulator values, using two regressors per event type - One
%               to model the average response, and one for the
%               mean-centered modulator values
%
% :Outputs:
%
%   1. a n x 2 matrix of regressors (cols) for each condition
%   2. a n x k delta matrix with onsets
%
% :Example: TR = 2, 16 samples per second in hi-res delta dhr
% ::
%
%    X = getPredictors(dhr, hrf, 'dsrate', res*TR);
%    X = getPredictors(dhr, hrf, 'dslen', len/(res*TR));
%
% stimList can be condition function e.g., [1 3 2 4 3 2 1]' or
% delta matrix (n x k), n samples and k conditions, e.g., [1 0 0 0 1 0 1]'
%
% :Resampling: the default N in matlab resample has built-in antialiasing,
% but may not be good for fmri designs!  The appropriate downsampling
% is expected to be res*TR (res is units of samples/s), but we use 0
% because the model will depend on the analysis method used, and this is
% the most veridical approach.  With N = 0, every ith sample is used, where
% i is the downsampling factor you input.  Popular choices are 16*TR (for
% onsets2delta.m), using the SPM default res of 16.
% Delta is NOT resampled.
%
% :Example: TR = 2, 16 samples per second in hi-res delta dhr
% ::
%
%    [tmp,d] = downsample_delta(dhr,16*2); X=getPredictors(d,hrf);
%
% ..
%    Notes:
%    Tor Wager, last modified 2/22/04 to center predictors
%    modified to optionally take H convolution matrix as input
%    in place of HRF vector.  See convmtx.m (Buracas,mseq toolbox)
%
%    Modified 10/2011 by Tor to add parametric modulators
%
%    3/15/12: Tor updated to consider any stimlist with > 30 conditions to be
%    a delta matrix, so that one can input continuous neural response
%    functions and treat them as delta matrices for direct convolution.
%
%    9/3/12: Wani updated this function for two reasons. 1) to fix an error
%    when one condition has two or more parametric modulators. 2) to fix an
%    error due to RT with decimal points. For 2), make two options for downsampling
%   'dsrate' and 'dslen'.
%
%    1/2020: Tor modified to increase tolerance/flexibilty for fractional
%    TRs, add better error reporting for length mismatch
% ..

model = [];
issquare = all(size(HRF) == size(HRF,1));   % if square mtx, assume convolution mtx

% make sure HRF is column vector, if single vector
if size(HRF,1) == 1, HRF = HRF'; end

% parametric modulators
doing_parametric_standard = any(strcmp(varargin, 'parametric_standard'));
doing_parametric_singleregressor = any(strcmp(varargin, 'parametric_singleregressor'));

if doing_parametric_standard || doing_parametric_singleregressor
    wh = find(strcmp(varargin, 'parametric_standard') | strcmp(varargin, 'parametric_singleregressor'));
    pm_vals = varargin{wh(1) + 1};

    if ~iscell(pm_vals)
        error('pm_vals must be cell array.')
    end
end

use_downsample_rate = any(strcmp(varargin, 'dsrate'));
use_downsample_length = any(strcmp(varargin, 'dslen'));
if use_downsample_rate, wh = find(strcmp(varargin, 'dsrate')); rate_downsample = varargin{wh(1) +1}; end
if use_downsample_length, wh = find(strcmp(varargin, 'dslen')); length_downsample = varargin{wh(1) +1}; end

if isdeltamtx(stimList, varargin{:})  % delta matrix
    % -------------------------------------------------------------------------------------------------
    %    * If delta function
    % -------------------------------------------------------------------------------------------------

    delta = stimList;

    if ~issquare
        for i = 1:size(delta,2)

            for j = 1:size(HRF,2)

                if doing_parametric_standard || doing_parametric_singleregressor
                    if length(pm_vals) < i, error('PM values cell array is too short!'); end

                    model = [model pmconv(double(delta(:,i)), HRF(:,j), pm_vals{i}, doing_parametric_standard, doing_parametric_singleregressor)];
                else
                    model(:,end+1) = conv(double(delta(:,i)), HRF(:,j)); % Changed for Matlab 7.9+ compatibility - Thanks, Liane
                end
            end
        end
    end

else
    % -------------------------------------------------------------------------------------------------
    %    * If condition function
    % -------------------------------------------------------------------------------------------------

    for i = 1:max(stimList(:,1)) % condition function

        %delta(:,i) = (stimList == i);
        delta(:,i) = cast((stimList == i), 'single'); % Changed for Matlab 7.9+ compatibility -- thanks, Liane Montana and Bruce McCandliss

        if doing_parametric_standard || doing_parametric_singleregressor
            if length(pm_vals) < i, error('PM values cell array is too short!'); end

            model = [model pmconv(double(delta(:,i)), HRF(:,j), pm_vals{i}, doing_parametric_standard, doing_parametric_singleregressor)];
        end

        if ~issquare
            for j = 1:size(HRF,2)
                model(:,end+1) = conv(double(delta(:,i)), HRF(:,j)); % Changed for Matlab 7.9+ compatibility - Thanks, Liane
            end
        end

    end
end

% -------------------------------------------------------------------------------------------------
%    * If conv. matrix
% -------------------------------------------------------------------------------------------------

if issquare % convolution matrix
    model = HRF * delta;
end

model = model(1:size(stimList,1),:);      	% eliminate extra values

% downsample, if necessary
if use_downsample_rate || use_downsample_length % Wani modified this
% if ~isempty(varargin)

    % dsrate = varargin{1}; % Wani
    [n, k] = size(model);
    % nt = n ./ dsrate; % Wani
    if use_downsample_rate, nt = n ./ rate_downsample; end % Wani modified this line
    if use_downsample_length, nt = length_downsample; rate_downsample = n/length_downsample; end % Wani added this line
    t = (1:n)';             % minor change to save time, tor: 10/12/10

    if abs(nt-round(nt)) > .1 % Tor increased tolerance to 0.1 units (usually TR/16)
        fprintf('X samples: %3.0f, Xout (image) samples: %3.2f, DSrate: %3.2f\n', n, nt, rate_downsample);
        error('Length of stimList is not evenly divisible by downsampling factor.');
    end

    modeli = zeros(round(nt) , k);

    for i = 1:size(model, 2)

        xi = 1:rate_downsample:n;       % downsample rate

        modeli(:, i) = interp1(t, model(:, i), xi, 'linear', 'extrap'); % tor: 10/12/10 : minor change: add extrap
    end

    model = modeli;
    %model = model(1:varargin{1}:end,:); % equivalent to resample(X,1,varargin{1},0)
end

% do not do this if you want to do nonlinear saturation!
% not necessary, i think.
%model = model - repmat(mean(model),size(model,1),1);    % center predictors

end

function isdelta = isdeltamtx(stimList, varargin)

isdelta = 0;

if ~isempty(varargin) && any(strcmp(varargin, 'force_delta'))
    isdelta = 1;
    return
end

if islogical(stimList) || all( sum(stimList == 0 | stimList == 1) == size(stimList, 1) )  % all zeros or ones
    isdelta = 1;

elseif min(size(stimList)) > 1 % multiple columns
    isdelta = 1;

elseif length(unique(stimList)) > 30 % custom neural response function?

end

end % subfunction

function [model, delta] = pmconv(delta, HRF, pm_vals, doing_parametric_standard, doing_parametric_singleregressor)

if doing_parametric_standard && doing_parametric_singleregressor
    error('Cannot do both standard and single-regressor parametric modulator.')
end

% HRF can be basis set, but SINGLE basis function is entered
% this is for one regressor/event type, with multiple basis images

% must identify FIRST events, i.e., preceded by 0
% for epochs... and must get back epoch duration, too.
%wh = find(delta);
wh = find(delta & [1; diff(delta) > 0 ]);  % tor modified 6/5/16 to generalize to non-integer input vals

% wh_end values, for durs
wh_end = find(~delta & [0; diff(delta) < 0]);
if delta(end), wh_end(end+1) = length(delta); end % fix if last event goes to end

% transpose if horiz
if diff(size(pm_vals)) > 0, pm_vals = pm_vals'; end

if ~isempty(pm_vals) && length(wh) ~= length(pm_vals)
    disp('Number of events in parametric modulator does not match number of events in delta function.')
    fprintf('%3.0f events in delta function, %3.0f events in param. modulator\n', sum(delta), length(pm_vals));

    if length(pm_vals) > length(wh)
        disp('Truncating pm_vals. Could be an onset occurred after the end of the run?');
        pm_vals = pm_vals(1:length(wh));
    end

    disp('Bad input?  Stopping in debugger so you can check. Type dbcont or dbquit to continue.')
    keyboard
end

% get modulated delta function

if ~isempty(pm_vals) && doing_parametric_standard
    % create a second delta function that is modulated
    pm_vals = scale(pm_vals, 1);
    delta = repmat(delta, 1, size(pm_vals,2)+1); % Wani modified this line to fix an error when pm_vals has two or more columns.
    % delta(:, end + 1) = delta;

elseif ~isempty(pm_vals) && doing_parametric_singleregressor
    % do nothing; we will just use pm vals

elseif isempty(pm_vals)
else
    error('This should not happen');
end

% This is where they get added.
% tor adjusted aug 2012 to account for epoch case.
if ~isempty(pm_vals)
    for i = 1:length(wh)
        delta(wh(i):wh_end(i), end) = pm_vals(i);
    end
end

% Convolve all preds for this trial type
lendelta = size(delta, 1);

for i = 1:size(delta, 2)

    %for j = 1:size(HRF, 2)
    tmp = conv(double(delta(:,i)), HRF); % Changed for Matlab 7.9+ compatibility - Thanks, Liane

    X{i} = tmp(1:lendelta);
    %end

end

model = cat(2, X{:});

end


function model = rmSearchFit_twoGaussianDoGBetaFixed(model,data,params,wProcess,t)
% rmSearchFit_twoGaussiansDoG - wrapper for 'fine' two DoG Gaussian fit
%
% model = rmSearchFit_twoGaussiansDoG(model,prediction,data,params);
%
% Second gaussian negative only.
%
% 2008/01 SOD: split of from rmSearchFit.

% now get original sigmas:
gridSigmas_unique = unique(params.analysis.sigmaMajor);
% add upper and lower limit:
expandRange    = params.analysis.fmins.expandRange;
gridSigmas = [0.001.*ones(expandRange,1); ...
    gridSigmas_unique; ...
    params.analysis.maxRF.*ones(expandRange,1)];

% fminsearch options
searchOptions = params.analysis.fmins.options;

vethresh = params.analysis.fmins.vethresh;

% convert to double just in case
params.analysis.X = double(params.analysis.X);
params.analysis.Y = double(params.analysis.Y);
params.analysis.allstimimages = double(params.analysis.allstimimages);

% amount of negative fits
nNegFit  = 0;
trends   = t.trends;
t_id     = t.dcid+1;

% initialize
if ~isfield(model,'rssPos')
    model.rsspos = zeros(size(model.rss));
end

if ~isfield(model,'rssNeg')
    model.rssneg = zeros(size(model.rss));
end

%-----------------------------------
% Go for each voxel
%-----------------------------------
progress = 0;tic;
for ii = 1:numel(wProcess),

    % progress monitor (10 dots)
    if floor(ii./numel(wProcess)*10)>progress,
        % print out estimated time left
        if progress==0,
            esttime = toc.*10;
            if floor(esttime./3600)>0,
                fprintf(1,'[%s]:Estimated processing time: %d voxels: %d hours.\n',...
                    mfilename,numel(wProcess),ceil(esttime./3600));
            else
                fprintf(1,'[%s]:Estimated processing time: %d voxels: %d minutes.\n',...
                    mfilename,numel(wProcess),ceil(esttime./60));
            end;
            fprintf(1,'[%s]:Nonlinear optimization (x,y,sigma):',mfilename);
        end;
        fprintf(1,'.');drawnow;
        progress = progress + 1;
    end;

    % volume index
    vi = wProcess(ii);
    vData = double(data(:,ii));

    % raw rss value (non-squared) - faster than sum(data(:,vi).^2)
    rawrss     = norm(vData);

    % reset tolFun: Precision of evaluation function.
    % We define RMS improvement relative to the initial raw 'no-fit' data
    % RMS. So, 1 means stop if there is less than 1% improvement on the fit:
    searchOptions.TolFun = params.analysis.fmins.options.TolFun.*rawrss;

    % start point from grid fit
    startParams = [model.x0(vi); ...
        model.y0(vi); ...
        model.s(vi);...
        model.s2(vi)];

    % tight search region [lowerbound upperbound]
    if params.analysis.scaleWithSigmas,
        step = params.analysis.relativeGridStep.*startParams(3);
        minstep = params.analysis.maxXY./2./params.analysis.minimumGridSampling;
        step = min(step,minstep);
        maxstep = params.analysis.maxXY./2./params.analysis.maximumGridSampling;
        step = max(step,maxstep);
    else
        step = params.analysis.maxXY./2./params.analysis.maximumGridSampling;
    end;
    boundary.xy    = startParams(1:2)*[1 1] + [-1 1;-1 1].*step.*expandRange;

    % gridSigmas==startParams(3), somehow this fails sometimes so we'll
    % look for the closest one. The min and max make sure the closestvalue
    % stays within the data range.
    [tmp,closestvalue] = sort(abs(gridSigmas-startParams(3)));
    closestvalue    = max(closestvalue(1),expandRange+1);
    closestvalue    = min(closestvalue,numel(gridSigmas)-(expandRange+1));
    boundary.sigma     = gridSigmas(closestvalue+[-1 1].*expandRange)';

    % boundary sigma two depends on boudary of sigma 1
    boundary.sigma2 = [boundary.sigma(1).*params.analysis.minSigmaRatio ...
                       params.analysis.sigmaRatioInfVal];

    % combine all boundaries
    bndParams2      = double([boundary.xy;...
        boundary.sigma;...
        boundary.sigma2]);

    % actual fitting routine
    if searchOptions.MaxIter>0
        outParams = ...
            fmincon(@(x) rmModelSearchFit_twoGaussiansDoGBetaFixed(x,vData,...
            params.analysis.X,...
            params.analysis.Y,...
            params.analysis.allstimimages,trends,params.analysis.betaRatioAlpha),...
            startParams,[],[],[],[],bndParams2(:,1),bndParams2(:,2),...
            @(x) distanceCon(x,startParams,step,params.analysis.minSigmaRatio),searchOptions);
    else
        outParams = startParams;
    end

    % make predictions
    Xv = params.analysis.X - outParams(1);   % positive x0 moves center right
    Yv = params.analysis.Y - outParams(2);   % positive y0 moves center up
    %betaRatio = params.analysis.betaRatioAlpha.*(outParams(3).^2./outParams(4).^2);
    betaRatio = (outParams(3)./outParams(4)).^params.analysis.betaRatioAlpha;
    rf(:,1) = exp( (Yv.*Yv + Xv.*Xv) ./ (-2.*(outParams(3).^2)) );
    rf(:,2) = exp( (Yv.*Yv + Xv.*Xv) ./ (-2.*(outParams(4).^2)) );
    rfNew = rf(:,1) - betaRatio.*rf(:,2);
    X = [params.analysis.allstimimages*rfNew trends];
    b    = pinv(X)*vData;
    % force positive fit (is a constraint in the
    % rmModelSearchFit_twoGaussianDoGBetaFixed, so it should return here to get the right values)
    b(1) = abs(b(1));

    % test 1 gaussian alone (must be done prior to with second gaussian)
    if searchOptions.MaxIter==0
        % without second gaussian
        % make only the positive and the negative rf
        % for the positive rf put all the negative rf-values to zero, for
        % the negative rf put all the positive rf-values to zero.

        rfBeta = rfNew.*b(1);
        posInd = rfBeta > 0;
        negInd = rfBeta < 0;
        rfPos = rfNew;
        rfNeg = rfNew;
        rfPos(negInd) = 0;
        rfNeg(posInd) = 0;
        XPos = [params.analysis.allstimimages*rfPos trends];
        XNeg = [params.analysis.allstimimages*rfNeg trends];
        rssPos = norm(vData-XPos*b).^2;
        rssNeg = norm(vData-XNeg*b).^2;
%         rfPos = max(rfBeta,0);
%         rfNeg = min(rfBeta,0);
%         XPos = [params.analysis.allstimimages*rfPos trends];
%         XNeg = [params.analysis.allstimimages*rfNeg trends];
%         rssPos = norm(vData-XPos).^2;
%         rssNeg = norm(vData-XNeg).^2;

    end

    % with second gaussian
    rss  = norm(vData-X*b).^2;

    % store results only if the first beta is positive, somehow fmincon
    % outputs negative fits. If the fit is negative keep old (grid) fit.
    if b(1)>0,
        model.x0(vi)   = outParams(1);
        model.y0(vi)   = outParams(2);
        model.s(vi)    = outParams(3);
        model.s_major(vi)    = outParams(3);
        model.s_minor(vi)    = outParams(3);
        model.s_theta(vi)    = 0;
        model.s2(vi)   = outParams(4);
        model.rss(vi)  = rss;
        model.b([1 t_id],vi) = b;
        if searchOptions.MaxIter==0
            model.rsspos(vi) = rssPos;
            model.rssneg(vi) = rssNeg;
        end
    else
        % change the percent variance explained to be just under the
        % current vethresh. So it counts as a 'coarse'-fit but can still be
        % included in later 'fine'-fits
        model.rss(vi)  = (1-max((vethresh-0.01),0)).*model.rawrss(vi);
        nNegFit = nNegFit + 1;
        if searchOptions.MaxIter==0
            model.rsspos(vi)  = (1-max((vethresh-0.01),0)).*model.rawrss(vi);
            model.rssneg(vi)  = (1-max((vethresh-0.01),0)).*model.rawrss(vi);
        end
    end;
end;

% end time monitor
et  = toc;
if floor(et/3600)>0,
    fprintf(1,'Done [%d hours].\n',ceil(et/3600));
else
    fprintf(1,'Done [%d minutes].\n',ceil(et/60));
end;
fprintf(1,'[%s]:Removed negative fits: %d (%.1f%%).\n',...
    mfilename,nNegFit,nNegFit./numel(wProcess).*100);

return;

%-----------------------------------
% make sure that the pRF can only be moved "step" away from original
% poisiton "startParams"
% For the two Gaussian model we add the additional constraint that the
% second Gaussian is at least twice as large as the first.
function [C, Ceq]=distanceCon(x,startParams,step,minRatio)
Ceq = [];
dist = x([1 2])-startParams([1 2]);
C(1) = sqrt(dist(1).^2+dist(2).^2) - step;
C(2) = minRatio - 0.001 - x(4)./x(3);
return;
%-----------------------------------


function model = gpdisimCreate(numGenes, numProteins, times, geneVals, ...
			       geneVars, options, annotation)

% GPDISIMCREATE Create a GPDISIM model.
% The GPSIM model is a model for estimating the protein
% concentration in a small gene network where several genes are
% governed by one protein. The model is based on Gaussian processes
% and simple linear differential equations of the form
%
% dx(t)/dt = B + Cf(t) - Dx(t)
%
% where x(t) is a given genes concentration and f(t) is the protein
% concentration.
%
% FORMAT
% DESC creates a model for single input motifs with Gaussian
% processes.
% ARG numGenes : number of genes to be modelled in the system.
% ARG numProteins : number of proteins to be modelled in the
% system.
% ARG times : the time points where the data is to be modelled.
% ARG geneVals : the values of each gene at the different time points.
% ARG geneVars : the varuabces of each gene at the different time points.
% ARG options : options structure, the default options can be
% generated using gpsimOptions.
% ARG annotation : annotation for the data (gene names, etc.) that
% is stored with the model. (Optional)
% RETURN model : model structure containing default
% parameterisation.
%
% SEEALSO : modelCreate, gpsimOptions
%
% COPYRIGHT : Neil D. Lawrence, 2006
%
% COPYRIGHT : Antti Honkela, 2007

% SHEFFIELDML

if any(size(geneVars)~=size(geneVals))
  error('The gene variances have a different size matrix to the gene values.');
end

if(numGenes ~= (size(geneVals, 2) - 1))
  error('The number of genes given does not match the dimension of the gene values given.')
end

if(size(times, 1) ~= size(geneVals, 1))
  error('The number of time points given does not match the number of gene values given')
end

model.type = 'gpdisim';

kernType1{1} = 'multi';
kernType2{1} = 'multi';
kernType1{2} = 'rbf';
for i = 1:numGenes
  kernType1{i+2} = 'disim';
end
tieParam = {'di_decay', 'inverse width', 'di_variance', 'rbf(_| . )variance'};

model.y = geneVals(:);
model.yvar = geneVars(:);

model.includeNoise = options.includeNoise;

if model.includeNoise
  model.yvar = zeros(size(geneVars(:)));
else
  model.yvar = geneVars(:);
end

% Check if we have a noise term.
if model.includeNoise
  % Create a new multi kernel to contain the noise term.
  kernType2{1} = 'multi';

  % Set the new multi kernel to just contain 'white' kernels.
  for i = 1:numGenes+1
    kernType2{i+1} = 'white';
  end
  if isfield(options, 'singleNoise') & options.singleNoise
    tieParam{5} = 'white \d+ variance';
  end

  % Now create model with a 'cmpnd' (compound) kernel build from two
  % multi-kernels. The first multi-kernel is the sim-sim one the next
  % multi-kernel is the white-white one.
  model.kern = kernCreate(times, {'cmpnd', kernType1, kernType2});
  simMultiKernName = 'model.kern.comp{1}';
else
  model.kern = kernCreate(times, kernType1);
  simMultiKernName = 'model.kern';
end
simMultiKern = eval(simMultiKernName);

% This is if we need to place priors on parameters ...
if isfield(options, 'addPriors') && options.addPriors,
  for i = 1:length(simMultiKern.numBlocks)
    % Priors on the sim kernels.
    eval([simMultiKernName '.comp{i}.priors = priorCreate(''gamma'');']);
    eval([simMultiKernName '.comp{i}.priors.a = 1;']);
    eval([simMultiKernName '.comp{i}.priors.b = 1;']);
    %model.kern.comp{i}.priors = priorCreate('gamma');
    %model.kern.comp{i}.priors.a = 1;
    %model.kern.comp{i}.priors.b = 1;
    if i == 1
      % For first kernel place prior on inverse width.
      % model.kern.comp{i}.priors.index = [1 2];
      eval([simMultiKernName '.comp{i}.priors.index = [1 2];']);
    elseif i == 2
      %model.kern.comp{i}.priors.index = [1 3 4 5];
      eval([simMultiKernName '.comp{i}.priors.index = [1 3 4 5];']);
    else
      % For other kernels don't place prior on inverse width --- as
      % they are all tied together and it will be counted multiple
      % times.
      %model.kern.comp{i}.priors.index = [4 5];
      eval([simMultiKernName '.comp{i}.priors.index = [4 5];']);
    end
  end

  % Prior on the b values.
  model.bprior = priorCreate('gamma');
  model.bprior.a = 1;
  model.bprior.b = 1;
end

model.kern = modelTieParam(model.kern, tieParam);
if model.includeNoise,
  for i = 1:numGenes+1,
    model.kern.comp{2}.comp{i}.variance = 1e-2;
  end
end

% The decays and sensitivities are actually stored in the kernel.
% We'll put them here as well for convenience.
model.delta = 10;
model.sigma = 1;
for i = 2:simMultiKern.numBlocks
  eval([simMultiKernName '.comp{i}.di_decay = model.delta;']);
  eval([simMultiKernName '.comp{i}.di_variance = model.sigma^2;']);
  model.D(i-1) = simMultiKern.comp{i}.decay;
  model.S(i-1) = sqrt(simMultiKern.comp{i}.variance);
end

rand('seed',0);
model.numParams = numGenes + model.kern.nParams;
model.numGenes = numGenes;
model.mu = mean(geneVals(:, 2:end));
% model.B = model.D.*model.mu;
model.B = model.D.*geneVals(1, 2:end);
model.m = model.y;
model.t = times;

model.optimiser = options.optimiser;

if isfield(options, 'fix')
  model.fix = options.fix;
end

% The basal transcriptions rates must be postitive.
model.bTransform = optimiDefaultConstraint('positive');

if nargin > 6,
  model.annotation = annotation;
end

model.options = options;

% This forces kernel compute.
params = gpdisimExtractParam(model);
model = gpdisimExpandParam(model, params);


%   CLASS Galileo_SS
% =========================================================================
%
% DESCRIPTION
%   container of Galileo Satellite System parameters
%
% REFERENCES
%   CRS parameters, according to each GNSS system CRS definition
%   (ICD document in brackets):
%
%   *_GAL --> GTRF     (Galileo-ICD 1.1)
%   Standard: https://www.gsc-europa.eu/system/files/galileo_documents/Galileo_OS_SIS_ICD.pdf
%
%   Other useful links
%     - http://www.navipedia.net/index.php/Galileo_Signal_Plan
%     - http://www.navipedia.net/index.php/Reference_Frames_in_GNSS
%    Ellipsoid definition is actually coming from this presentation:
%     - http://gage6.upc.es/eknot/Professional_Training/PDF/Reference_Systems.pdf
%    at the moment of writing the Galileo Geodetic Reference Service Provider (GRSP) website (http://www.ggsp.eu/)
%    is actually offline, and the GTRF16v01 (or any other RF) cannot be found online.
%    Since GTRF seems to be based on ITRF (that does not define a reference ellispoid) http://itrf.ign.fr/faq.php?type=answer
%    The ellipsoid found in the presentation is used as reference
%
%   Useful data for the future (PPP):
%     - https://www.gsc-europa.eu/support-to-developers/galileo-iov-satellite-metadata#3.2

%--------------------------------------------------------------------------
%               ___ ___ ___
%     __ _ ___ / __| _ | __|
%    / _` / _ \ (_ |  _|__ \
%    \__, \___/\___|_| |___/
%    |___/                    v 1.0RC1
%
%--------------------------------------------------------------------------
%  Copyright (C) 2021 Geomatics Research & Development srl (GReD)
%  Written by:        Andrea Gatti, Giulio Tagliaferro ...
%  Contributors:      Andrea Gatti, Giulio Tagliaferro ...
%  A list of all the historical goGPS contributors is in CREDITS.nfo
%--------------------------------------------------------------------------
%
%    This program is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    This program is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with this program.  If not, see <http://www.gnu.org/licenses/>.
%
%--------------------------------------------------------------------------
% 01100111 01101111 01000111 01010000 01010011
%--------------------------------------------------------------------------

classdef Galileo_SS < Satellite_System
    properties (Constant, Access = 'public')
        SYS_EXT_NAME = 'Galileo'; % full name of the constellation
        SYS_NAME     = 'GAL';     % 3 characters name of the constellation, this "short name" is used as fields of the property list (struct) to identify a constellation
        SYS_C        = 'E';       % Satellite system (ss) character id

        % System frequencies as struct [MHz]
        F = struct('E1', 1575.420, ...
                   'E5a', 1176.450, ...
                   'E5b', 1207.140, ...
                   'E5', 1191.795, ...
                   'E6', 1278.750)

        % Array of supported frequencies [MHz]
        F_VEC = struct2array(Galileo_SS.F) * 1e6;

        % Array of the corresponding wavelength - lambda => wavelengths
        L_VEC = 299792458 ./ Galileo_SS.F_VEC;

        N_SAT = 36;       % Maximum number of satellite in the constellation
        PRN = (1 : 36)';  % Satellites id numbers as defined in the constellation

        % CODE2DATA ftp://igs.org/pub/data/format/rinex303.pdf
        CODE_RIN3_ATTRIB  = {'ZXACB F' 'XQI F' 'XQI F', 'XQI F', 'ZXACB F'}; % last letter of the observation code Assumption: Public regualted service (PRS ) better than Pilot (C) better than data (A), pilot channel seems to be the quadra pahse one
        CODE_RIN3_DEFAULT_ATTRIB  = {'C' 'I' 'I' 'I' 'C'}; % last letter of the observation code
        CODE_RIN3_2BAND  = '15786';             % id for the freq as stored in F_VEC
        IONO_FREE_PREF  = ['15'; '18'; '17'; '16'; '56'; '76'; '86'; '57'; '58'; '78'];  % to be evaluated which combination is really better
    end

    properties (Constant, Access = 'private')
        % GPS (WGS84) Ellipsoid semi-major axis [m]
        ELL_A = 6378137;
        % GPS (WGS84) Ellipsoid flattening
        ELL_F = 1/298.257222101;
        % GPS (WGS84) Ellipsoid Eccentricity^2
        ELL_E2 = (1 - (1 - Galileo_SS.ELL_F) ^ 2);
        % GPS (WGS84) Ellipsoid Eccentricity
        ELL_E = sqrt(Galileo_SS.ELL_E2);
    end

    properties (Constant, Access = 'public')
        % Structure of orbital parameters (ellipsoid, GM, OMEGA_EARTH_DOT)
        ORBITAL_P = struct('GM', 3.986004418e14, ...               % Galileo (Galileo-ICD) Gravitational constant * (mass of Earth) [m^3/s^2]
                                    'OMEGAE_DOT', 7.2921151467e-5, ...      % Galileo (Galileo-ICD) Angular velocity of the Earth rotation [rad/s]
                                    'ELL',struct( ...                       % Ellipsoidal parameters Galileo (GTRF)
                                    'A', Galileo_SS.ELL_A, ...          % Ellipsoid semi-major axis [m]
                                    'F', Galileo_SS.ELL_F, ...          % Ellipsoid flattening
                                    'E', Galileo_SS.ELL_E, ...          % Eccentricity
                                    'E2', Galileo_SS.ELL_E2));          % Eccentricity^2
        ORBITAL_INC = 56;    % Orbital inclination
        ORBITAL_RADIUS  = 23222000 + 6378137; % Orbital radius
    end

    methods
        function this = Galileo_SS(offset)
            % Creator
            % SYNTAX: Galileo_SS(<offset>);
            if (nargin == 0)
                offset = 0;
            end
            this@Satellite_System(offset);
        end

        function copy = getCopy(this)
            % Get a copy of this
            copy = Galileo_SS(this.getOffset());
            copy.import(this);
        end

    end
end


function [ss,gg,tt,ff,zo]=ssubmmse(si,fsz,pp)
%SSUBMMSE performs speech enhancement using mmse estimate of spectral amplitude or log amplitude [SS,ZO]=(S,FSZ,P)
%
% Usage: y=ssubmmse(x,fs);   % enhance the speech using default parameters
%
% Inputs:
%   si      input speech signal
%   fsz     sample frequency in Hz
%           Alternatively, the input state from a previous call (see below)
%   pp      algorithm parameters [optional]
%
% Outputs:
%   ss        output enhanced speech
%   gg(t,f,i) selected time-frequency values (see pp.tf below)
%   tt        centre of frames (in seconds)
%   ff        centre of frequency bins (in Hz)
%   zo        output state (or the 2nd argument if gg,tt,ff are omitted)
%
% The algorithm operation is controlled by a small number of parameters:
%
%        pp.of          % overlap factor = (fft length)/(frame increment) [2]
%        pp.ti          % desired frame increment [0.016 seconds]
%        pp.ri          % set to 1 to round ti to the nearest power of 2 samples [0]
%        pp.ta          % time const for smoothing SNR estimate [0.396 seconds]
%        pp.gx          % maximum posterior SNR as a power ratio [1000 = +30dB]
%        pp.gn          % min posterior SNR as a power ratio when estimating prior SNR [1 = 0dB]
%        pp.gz          % min posterior SNR as a power ratio [0.001 = -30dB]
%        pp.xn          % minimum prior SNR [0]
%        pp.xb          % bias compensation factor for prior SNR [1]
%        pp.lg          % MMSE target: 0=amplitude, 1=log amplitude [1]
%        pp.ne          % noise estimation: 0=min statistics, 1=MMSE [0]
%        pp.bt          % threshold for binary gain or -1 for continuous gain [-1]
%        pp.mx          % input mixture gain [0]
%        pp.rf          % round output signal to an exact number of frames [0]
%        pp.tf          % selects time-frequency planes to output in the gg() variable ['g']
%                           'i' = input power spectrum
%                           'I' = input complex spectrum
%                           'n' = noise power spectrum
%                           'z' = "posterior" SNR (i.e. (S+N)/N )
%                           'x' = "prior" SNR (i.e. S/N )
%                           'g' = gain
%                           'o' = output power spectrum
%                           'O' = output complex spectrum
%
% The applied gain is mx+(1-mx)*optgain where optgain is calculated according to [1] or [2].
% If pp.bt>=0 then optgain is first thresholded with pp.bt to produce a binary gain 0 or 1.
%
% The default parameters implement the original algorithm in [1,2].
%
% Several parameters relate to the estimation of xi, the so-called "prior SNR",
%
%             xi=max(a*pp.xb*xu+(1-a)*max(gami-1,pp.gn-1),pp.xn);
%
% This is estimated as a smoothed version of 1 less than gami, the "posterior SNR"
% which is the noisy speech power divided by the noise power. This is
% clipped to a min of (pp.gn-1), smoothed using a factor "a" which corresponds to a
% time-constant of pp.ta and then clipped to a minimum of pp.xn. The
% previous value is taken to be pp.xb*xu where xu is the ratio of the
% estimated speech amplitude squared to the noise power.
%
% In addition it is possible to specify parameters for the noise estimation algorithm
% which implements reference [3] or [7] according to the setting of pp.ne
%
% Minimum statistics noise estimate [3]: pp.ne=0
%        pp.taca      % (11): smoothing time constant for alpha_c [0.0449 seconds]
%        pp.tamax     % (3): max smoothing time constant [0.392 seconds]
%        pp.taminh    % (3): min smoothing time constant (upper limit) [0.0133 seconds]
%        pp.tpfall    % (12): time constant for P to fall [0.064 seconds]
%        pp.tbmax     % (20): max smoothing time constant [0.0717 seconds]
%        pp.qeqmin    % (23): minimum value of Qeq [2]
%        pp.qeqmax    % max value of Qeq per frame [14]
%        pp.av        % (23)+13 lines: fudge factor for bc calculation  [2.12]
%        pp.td        % time to take minimum over [1.536 seconds]
%        pp.nu        % number of subwindows to use [3]
%        pp.qith      % Q-inverse thresholds to select maximum noise slope [0.03 0.05 0.06 Inf ]
%        pp.nsmdb     % corresponding noise slope thresholds in dB/second   [47 31.4 15.7 4.1]
%
% MMSE noise estimate [7]: pp.ne=1
%        pp.tax      % smoothing time constant for noise power estimate [0.0717 seconds](8)
%        pp.tap      % smoothing time constant for smoothed speech prob [0.152 seconds](23)
%        pp.psthr    % threshold for smoothed speech probability [0.99] (24)
%        pp.pnsaf    % noise probability safety value [0.01] (24)
%        pp.pspri    % prior speech probability [0.5] (18)
%        pp.asnr     % active SNR in dB [15] (18)
%        pp.psini    % initial speech probability [0.5] (23)
%        pp.tavini   % assumed speech absent time at start [0.064 seconds]
%
% If convenient, you can call specsub in chunks of arbitrary size. Thus the following are equivalent:
%
%                   (a) y=ssubmmse(s,fs);
%
%                   (b) [y1,z]=ssubmmse(s(1:1000),fs);
%                       [y2,z]=ssubmmse(s(1001:2000),z);
%                       y3=ssubmmse(s(2001:end),z);
%                       y=[y1; y2; y3];
%
% If the number of output arguments is either 2 or 5, the last partial frame of samples will
% be retained for overlap adding with the output from the next call to ssubmmse().
%
% See also specsub() for an alternative gain function
%
% Refs:
%    [1] Ephraim, Y. & Malah, D.
%        Speech enhancement using a minimum-mean square error short-time spectral amplitude estimator
%        IEEE Trans Acoustics Speech and Signal Processing, 32(6):1109-1121, Dec 1984
%    [2] Ephraim, Y. & Malah, D.
%        Speech enhancement using a minimum mean-square error log-spectral amplitude estimator
%        IEEE Trans Acoustics Speech and Signal Processing, 33(2):443-445, Apr 1985
%    [3] Rainer Martin.
%        Noise power spectral density estimation based on optimal smoothing and minimum statistics.
%        IEEE Trans. Speech and Audio Processing, 9(5):504-512, July 2001.
%    [4] O. Cappe.
%        Elimination of the musical noise phenomenon with the ephraim and malah noise suppressor.
%        IEEE Trans Speech Audio Processing, 2 (2): 345349, Apr. 1994. doi: 10.1109/89.279283.
%    [5] J. Erkelens, J. Jensen, and R. Heusdens.
%        A data-driven approach to optimizing spectral speech enhancement methods for various error criteria.
%        Speech Communication, 49: 530541, 2007. doi: 10.1016/j.specom.2006.06.012.
%    [6] R. Martin.
%        Statistical methods for the enhancement of noisy speech.
%        In J. Benesty, S. Makino, and J. Chen, editors,
%        Speech Enhancement, chapter 3, pages 4364. Springer-Verlag, 2005.
%    [7] Gerkmann, T. & Hendriks, R. C.
%        Unbiased MMSE-Based Noise Power Estimation With Low Complexity and Low Tracking Delay
%        IEEE Trans Audio, Speech, Language Processing, 2012, 20, 1383-1393

% Bugs/suggestions:
%   (1) sort out behaviour when si() is a matrix rather than a vector
%
%      Copyright (C) Mike Brookes 2004-2011
%      Version: $Id: ssubmmse.m 2460 2012-10-29 22:20:45Z dmb $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   This program is free software; you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation; either version 2 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if numel(si)>length(si)
    error('Input speech signal must be a vector not a matrix');
end
if isstruct(fsz)
    fs=fsz.fs;
    qq=fsz.qq;
    qp=fsz.qp;
    ze=fsz.ze;
    s=zeros(length(fsz.si)+length(si(:)),1); % allocate space for speech
    s(1:length(fsz.si))=fsz.si;
    s(length(fsz.si)+1:end)=si(:);
else
    fs=fsz;     % sample frequency
    s=si(:);
    % default algorithm constants

    qq.of=2;        % overlap factor = (fft length)/(frame increment)
    qq.ti=16e-3;    % desired frame increment (16 ms)
    qq.ri=0;        % round ni to the nearest power of 2
    qq.ta=0.396;    % Time const for smoothing SNR estimate = -tinc/log(0.98) from [1]
    qq.gx=1000;     % maximum posterior SNR = 30dB
    qq.gn=1;        % min posterior SNR as a power ratio when estimating prior SNR [1]
    qq.gz=0.001;    % min posterior SNR as a power ratio [0.001 = -30dB]
    qq.xn=0;        % minimum prior SNR = -Inf dB
    qq.xb=1;        % bias compensation factor for prior SNR [1]
    qq.lg=1;        % use log-domain estimator by default
    qq.ne=0;        % noise estimation: 0=min statistics, 1=MMSE [0]
    qq.bt=-1;       % suppress binary masking
    qq.mx=0;        % no input mixing
    qq.tf='g';      % output the gain time-frequency plane by default
    qq.rf=0;
    if nargin>=3 && ~isempty(pp)
        qp=pp;      % save for estnoisem call
        qqn=fieldnames(qq);
        for i=1:length(qqn)
            if isfield(pp,qqn{i})
                qq.(qqn{i})=pp.(qqn{i});
            end
        end
    else
        qp=struct;  % make an empty structure
    end
end
% derived algorithm constants
if qq.ri
    ni=pow2(nextpow2(ti*fs*sqrt(0.5)));
else
    ni=round(qq.ti*fs);    % frame increment in samples
end
tinc=ni/fs;         % true frame increment time
a=exp(-tinc/qq.ta); % SNR smoothing coefficient
gx=qq.gx;           % max posterior SNR as a power ratio
gz=qq.gz;           % min posterior SNR as a power ratio
kk=sqrt(2*pi);      % sqrt(8)*Gamma(1.5) - required constant
xn=qq.xn;           % floor for prior SNR, xi
ne=qq.ne;           % noise estimation: 0=min statistics, 1=MMSE [0]
gn1=max(qq.gn-1,0); % floor for posterior SNR when estimating prior SNR
xb=qq.xb;
tf=qq.tf;
rf=qq.rf || nargout==2 || nargout==5;            % round down to an exact number of frames

% calculate power spectrum in frames

no=round(qq.of);                  	% integer overlap factor
nf=ni*no;                           % fft length
w=sqrt(hamming(nf+1))'; w(end)=[];  % for now always use sqrt hamming window
w=w/sqrt(sum(w(1:ni:nf).^2));       % normalize to give overall gain of 1
if rf>0
    rfm='';                         % truncated input to an exact number of frames
else
    rfm='r';
end
[y,tt]=enframe(s,w,ni,rfm);
tt=tt/fs;                           % frame times
yf=rfft(y,nf,2);
yp=yf.*conj(yf);                    % power spectrum of input speech
[nr,nf2]=size(yp);                  % number of frames
ff=(0:nf2-1)*fs/nf;
if isstruct(fsz)
    if ne>0
        [dp,ze]=estnoiseg(yp,ze);       % estimate the noise using MMSE
    else
        [dp,ze]=estnoisem(yp,ze);       % estimate the noise using minimum statistics
    end
    ssv=fsz.ssv;
    xu=fsz.xu;                      % saved unsmoothed SNR
else
    if ne>0
        [dp,ze]=estnoiseg(yp,tinc,qp);	% estimate the noise using MMSE
    else
        [dp,ze]=estnoisem(yp,tinc,qp);	% estimate the noise using minimum statistics
    end
    ssv=zeros(ni*(no-1),1);        	% dummy saved overlap
    xu=1;                           % dummy unsmoothed SNR from previous frame
end
if ~nr                             	% no data frames
    ss=[];
    gg=[];
else
    gam=max(min(yp./dp,gx),gz);     % gamma = posterior SNR
    g=zeros(nr,nf2);                % create space for gain matrix
    x=zeros(nr,nf2);                % create space for prior SNR
    if qq.lg                        % use log domain estimator
        for i=1:nr
            gami=gam(i,:);
            xi=max(a*xb*xu+(1-a)*max(gami-1,gn1),xn);  % prior SNR
            xir=xi./(1+xi);
            gi=xir.*exp(0.5*expint(xir.*gami));
            g(i,:)=gi;             	% save gain for later
            x(i,:)=xi;              % save prior SNR
            xu=gami.*gi.^2;         % unsmoothed prior SNR
        end
    else
        for i=1:nr
            gami=gam(i,:);
            xi=max(a*xb*xu+(1-a)*max(gami-1,gn1),xn);  % prior SNR
            v=0.5*xi.*gami./(1+xi);	% note that this is 0.5*vk in [1]
            gi=(0.277+2*v)./gami; 	% accurate to 0.02 dB for v>0.5
            mv=v<0.5;
            if any(mv)
                vmv=v(mv);
                gi(mv)=kk*sqrt(vmv).*((0.5+vmv).*besseli(0,vmv)+vmv.*besseli(1,vmv))./(gami(mv).*exp(vmv));
            end
            g(i,:)=gi;              % save gain for later
            x(i,:)=xi;              % save prior SNR
            xu=gami.*gi.^2;         % unsmoothed prior SNR
        end
    end
    if qq.bt>=0
        g=g>qq.bt;
    end
    g=qq.mx+(1-qq.mx)*g;                    % mix in some of the input
    se=(irfft((yf.*g).',nf).').*repmat(w,nr,1);     % inverse dft and apply output window
    ss=zeros(ni*(nr+no-1),no);                      % space for overlapped output speech
    ss(1:ni*(no-1),end)=ssv;
    for i=1:no
        nm=nf*(1+floor((nr-i)/no));         % number of samples in this set
        ss(1+(i-1)*ni:nm+(i-1)*ni,i)=reshape(se(i:no:nr,:)',nm,1);
    end
    ss=sum(ss,2);
    if nargout>2 && ~isempty(tf)
        gg=zeros(nr,nf2,length(tf));  % make space
        for i=1:length(tf)
            switch tf(i)
                case 'i'            % 'i' = input power spectrum
                    gg(:,:,i)=yp;
                case 'I'            % 'i' = input power spectrum
                    gg(:,:,i)=yf;
                case 'n'            % 'n' = noise power spectrum
                    gg(:,:,i)=dp;
                case 'z'            % 'z' = posterior SNR (i.e. (S+N)/N )
                    gg(:,:,i)=gam;
                case 'x'            % 'x' = prior SNR
                    gg(:,:,i)=x;
                case 'g'            % 'g' = gain
                    gg(:,:,i)=g;
                case 'o'            % 'o' = output power spectrum
                    gg(:,:,i)=yp.*g.^2;
                case 'O'            % 'o' = output power spectrum
                    gg(:,:,i)=yf.*g;
            end
        end
    end
end
if nargout==2 || nargout==5
    if nr
        zo.ssv=ss(end-ni*(no-1)+1:end);    % save the output tail for next time
        ss(end-ni*(no-1)+1:end)=[];        % only output the frames that are completed
    else
        zo.ssv=ssv;  %
    end
    zo.si=s(length(ss)+1:end);      % save the tail end of the input speech signal
    zo.fs=fs;                       % save sample frequency
    zo.qq=qq;                       % save local parameters
    zo.qp=qp;                       % save estnoisem parameters
    zo.ze=ze;                       % save state of noise estimation
    zo.xu=xu;
    if nargout==2
        gg=zo;                      % 2nd of two arguments is zo
    end
elseif rf==0
    ss=ss(1:length(s));             % trim to the correct length if not an exact number of frames
end
if ~nargout && nr>0
    ffax=ff/1000;
    ax=zeros(4,1);
    ax(1)=subplot(223);
    imagesc(tt,ffax,20*log10(g)');
    colorbar;
    axis('xy');
    title(sprintf('Filter Gain (dB): ta=%.2g',qq.ta));
    xlabel('Time (s)');
    ylabel('Frequency (kHz)');

    ax(2)=subplot(222);
    imagesc(tt,ffax,10*log10(yp)');
    colorbar;
    axis('xy');
    title('Noisy Speech (dB)');
    xlabel('Time (s)');
    ylabel('Frequency (kHz)');

    ax(3)=subplot(224);
    imagesc(tt,ffax,10*log10(yp.*g.^2)');
    colorbar;
    axis('xy');
    title('Enhanced Speech (dB)');
    xlabel('Time (s)');
    ylabel('Frequency (kHz)');

    ax(4)=subplot(221);
    imagesc(tt,ffax,10*log10(dp)');
    colorbar;
    axis('xy');
    title('Noise Estimate (dB)');
    xlabel('Time (s)');
    ylabel('Frequency (kHz)');
    linkaxes(ax);
end


%% downloads

% data from: http://download.alleninstitute.org/informatics-archive/current-release/mouse_ccf/

% nrrd reader from: https://uk.mathworks.com/matlabcentral/fileexchange/34653-nrrd-format-file-reader

% structure tree from:
% http://api.brain-map.org/api/v2/data/query.csv?criteria=model::Structure,rma::criteria,[ontology_id$eq1],rma::options[order$eq%27structures.graph_order%27][num_rows$eqall]

%% sanitize structure tree

sanitizeStructureTree('query.csv', 'structure_tree_safe_2017.csv');
st = loadStructureTree('structure_tree_safe_2017.csv');

%% convert annotation volume to index version
% This cell can take a while, both for loading and doing the conversion

% av = nrrdread('annotation_10.nrrd');
% st = loadStructureTree('structure_tree_safe.csv');

avI = av;
ind = st.index;
id = st.id;
idS = sparse(double(id), ones(size(id)), double(ind), double(max(id)),1);
avI(av==0) = 997;
tic; avS = idS(avI); toc
avS = full(avS);
avI = reshape(avS, size(av));
avI = uint16(avI+1);

% running this for the 2017 version, I have to also add this line:
avI = permute(avI, [2 1 3]);

% writeNPY(avI, 'annotation_volume_10um_by_index.npy')

%% make colormap from structure_tree based on index

q = st.color_hex_triplet;

q(cellfun(@numel,q)==5) = {'019399'}; % special case where leading zero was evidently dropped
c1 = cellfun(@(x)hex2dec(x(1:2)), q, 'uni', false);
c2 = cellfun(@(x)hex2dec(x(3:4)), q, 'uni', false);
c3 = cellfun(@(x)hex2dec(x(5:6)), q, 'uni', false);
cmap = horzcat(vertcat(c1{:}),vertcat(c2{:}),vertcat(c3{:}))./255;

% save allen_ccf_colormap.mat cmap


function test_ft_appendfreq

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

% make some dummy frequency structures
freq1.label = {'1';'2'};
freq1.freq  = 1:10;
freq1.time  = 1:5;
freq1.dimord = 'chan_freq_time';
freq1.powspctrm = randn(2,10,5);

cfg = [];
cfg.parameter = 'powspctrm';

freq2         = freq1;
cfg.appenddim = 'rpt';
freqrpt       = ft_appendfreq(cfg, freq1, freq2);
cfg.appenddim = 'auto';
freqrptauto   = ft_appendfreq(cfg, freq1, freq2);

freq2         = freq1;
freq2.label   = {'3';'4'};
cfg.appenddim = 'chan';
freqchan      = ft_appendfreq(cfg, freq1, freq2);
cfg.appenddim = 'auto';
freqchanauto  = ft_appendfreq(cfg, freq1, freq2);

freq2         = freq1;
freq2.freq    = 11:20;
cfg.appenddim = 'freq';
freqfreq      = ft_appendfreq(cfg, freq1, freq2);
if ~isfield(freqfreq,'freq')
  error('freq field is not appeneded: see bugs 1984 and 2187');
end

cfg.appenddim = 'auto';
freqfreqauto  = ft_appendfreq(cfg, freq1, freq2);
if ~isfield(freqfreqauto,'freq')
  error('freq field is not appeneded: see bugs 1984 and 2187');
end

freq2         = freq1;
freq2.time    = 6:10;
cfg.appenddim = 'time';
freqtime      = ft_appendfreq(cfg, freq1, freq2);
if ~isfield(freqfreqauto,'freq')
  error('freq field is not appeneded: see bugs 1984 and 2187');
end

cfg.appenddim = 'auto';
freqtimeauto  = ft_appendfreq(cfg, freq1, freq2);
if ~isfield(freqtimeauto,'freq')
  error('freq field is not appeneded: see bugs 1984 and 2187');
end

% now test for numerical inaccurracies, should concatenate across 'rpt'
freq2          = freq1;
freq2.time     = freq1.time+0.0000001;
cfg.appenddim  = 'auto';
freqrpt2       = ft_appendfreq(cfg, freq1, freq2);
if ~isfield(freqrpt2,'freq')
  error('freq field is not appeneded: see bugs 1984 and 2187');
end

%% test for data with labels shuffled around
freq1 = [];
freq1.label = {'1';'2'};
freq1.freq  = 1:10;
freq1.time  = 1:5;
freq1.dimord = 'chan_freq_time';
freq1.powspctrm = randn(2,10,5);

freq2 = freq1;
freq2.label = {'2';'1'};
freq2.powspctrm = randn(2,10,5);

freqshuffled = ft_appendfreq(cfg, freq1, freq2);

if ~strcmp(freqshuffled.dimord, 'rpt_chan_freq_time')
  error('unexpected dimord when appending freqs with differently permuted labels');
end
if ~isfield(freqshuffled,'freq')
  error('freq field is not appeneded: see bugs 1984 and 2187');
end

% now check whether channels were correctly appended
[a,b] = match_str(freq1.label, freqshuffled.label);
x1 = freq1.powspctrm(a(1),:,:);
y1 = freqshuffled.powspctrm(1,b(1),:,:);

[a,b] = match_str(freq2.label, freqshuffled.label);
x2 = freq2.powspctrm(a(1),:,:);
y2 = freqshuffled.powspctrm(2,b(1),:,:);

if ~all(x1(:) == y1(:)) || ~all(x2(:) == y2(:))
  error('data was wrongly appended when channel labels are differently ordered in input arguments');
end


1     % problem
4     % grid parameter
1     % outflow boundary
2     % discretisation
0.01  % viscosity parameter
3     % Picard/Newton/hybrid linearization
2     % number of Picard iterations
4     % number of Newton iterations
1.d-5 % nonlinear tolerance
0.25  % Stokes stabilization parameter
1     % uniform/exponential streamlines

%% Data file for test problem NS1


function om_write_cond(condfile,c,names)
%   OM_WRITE_COND
%       [] = OM_WRITE_COND(CONDFILE,C)
%
%   Write conductivity file for OpenMEEG
%
%   Authors: Alexandre Gramfort alexandre.gramfort@inria.fr

% Copyright (C) 2010-2017, OpenMEEG developers

ndomains = length(c);

if nargin < 3
    names = {};
    for k=1:ndomains
        names{k} = ['domain', num2str(k)];
    end
end

if ndomains ~= length(names)
    error('Number of conductivities is not equal to the number of domain names.');
end

cfid = fopen(condfile, 'w');
if cfid == -1
    error(['Failed to open file ''',condfile,'''.']);
end

fprintf(cfid,'# Properties Description 1.0 (Conductivities)\n\n');
fprintf(cfid,'air         0.0\n');

for k=1:ndomains
    fprintf(cfid, '%s       %f\n', names{k}, c(k));
end

fclose(cfid);

end %  function


function c = tapas_align_priors_fields(c)
% Aligns parameter fields with the explicit prior definitions with the
% content of the vectors c.priormus and c.priorsas (vice-versa of function
% 'tapas_align_priors.m').
%
%   Example:
%   >> c_prc = tapas_ehgf_binary_config;
%   >> c_prc.priormus(13) = -2;
%   >> c_prc = tapas_align_priors_fields(c_prc)
%
% --------------------------------------------------------------------------------------------------
% Copyright (C) 2020 Christoph Mathys, TNU, UZH & ETHZ
%
% This file is part of the HGF toolbox, which is released under the terms of the GNU General Public
% Licence (GPL), version 3. You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version). For further details, see the file
% COPYING or <http://www.gnu.org/licenses/>.

% Get fieldnames. If a name ends on 'mu', that field defines a prior mean.
% If it ends on 'sa', it defines a prior variance.
names = fieldnames(c);
pm = 0;
ps = 0;

% Loop over fields and overwrite fiels whose name ends on 'mu or 'sa'
for i = 1:length(names)
    if regexp(names{i}, 'mu$')
        c.(names{i}) = c.priormus(pm+1:pm+length(c.(names{i})));
        pm = pm+length(c.(names{i}));
    elseif regexp(names{i}, 'sa$')
        c.(names{i}) = c.priorsas(ps+1:ps+length(c.(names{i})));
        ps = ps+length(c.(names{i}));
    end
end

end


function [TorF, vstr, rdate] = have_feature_opti_clp()
%HAVE_FEATURE_OPTI_CLP  Detect availability/version info for OPTI_CLP
%
%   Feature detection function implementing 'opti_clp' tag for HAVE_FEATURE
%   to detect availability/version of the version of CLP (COIN-OR Linear
%   Programming solver) distributed with OPTI Toolbox
%   (https://www.inverseproblem.co.nz/OPTI/).
%
%   See also HAVE_FEATURE, HAVE_FEATURE_CLP, QPS_MASTER, CLP.

%   MP-Opt-Model
%   Copyright (c) 2004-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MP-Opt-Model.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://github.com/MATPOWER/mp-opt-model for more info.

TorF = exist('opti_clp', 'file') == 2 && exist('clp', 'file') == 3;
vstr = '';
rdate = '';
if TorF
    str = evalc('clp');
    pat = 'CLP: COIN-OR Linear Programming \[v([^\s,]+), Built ([^\],])+(,[^\]]*)*\]';  %% OPTI, Giorgetti/Currie
    [s,e,tE,m,t] = regexp(str, pat);
    if ~isempty(t)
        vstr = t{1}{1};
        rdate = datestr(t{1}{2}, 'dd-mmm-yyyy');
    end
end


function Obs = matchFeature(Sen,Raw,Obs)

% MATCHFEATURE  Match feature.
% 	Obs = MATCHFEATURE(Sen,Raw,Obs) matches one feature in Raw to the predicted
% 	feature in Obs.

%   Copyright 2008-2009 Joan Sola @ LAAS-CNRS.

switch Obs.ltype(4:6)
    case 'Pnt'
        rawDataLmks = Raw.data.points;
        R = Sen.par.cov;
    case 'Lin'
        rawDataLmks = Raw.data.segments;
        R = blkdiag(Sen.par.cov,Sen.par.cov);
    otherwise
        error('??? Unknown landmark type ''%s''.',Obs.ltype);
end

switch Raw.type

    case {'simu','dump'}

        id  = Obs.lid;
        idx = find(rawDataLmks.app==id);

        if ~isempty(idx)
            Obs.meas.y   = rawDataLmks.coord(:,idx);
            Obs.meas.R   = R;
            Obs.measured = true;
            Obs.matched  = true;
        else
            Obs.meas.y   = zeros(size(Obs.meas.y));
            Obs.meas.R   = R;
            Obs.measured = false;
            Obs.matched  = false;
        end

    case 'image'
        error('??? Feature matching for Raw data type ''%s'' not implemented yet.', Raw.type)

    otherwise

        error('??? Unknown Raw data type ''%s''.',Raw.type)

end

% ========== End of function - Start GPL license ==========

%   # START GPL LICENSE

%---------------------------------------------------------------------
%
%   This file is part of SLAMTB, a SLAM toolbox for Matlab.
%
%   SLAMTB 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.
%
%   SLAMTB 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 SLAMTB.  If not, see <http://www.gnu.org/licenses/>.
%
%---------------------------------------------------------------------

%   SLAMTB is Copyright:
%   Copyright (c) 2008-2010, Joan Sola @ LAAS-CNRS,
%   Copyright (c) 2010-2013, Joan Sola,
%   Copyright (c) 2014-2015, Joan Sola @ IRI-UPC-CSIC,
%   SLAMTB is Copyright 2009
%   by Joan Sola, Teresa Vidal-Calleja, David Marquez and Jean Marie Codol
%   @ LAAS-CNRS.
%   See on top of this file for its particular copyright.

%   # END GPL LICENSE


function out = ftimes(a,b)
    out = bsxfun(@times,a,b);
end


function y = bwblkslv(L,b) %#ok
% BWBLKSLV Solves block sparse upper-triangular system.
%    y = bwblkslv(L,b) yields the same result as
%              y(L.perm,:) = L.L'\b
%    However, BWBLKSLV is faster than the built-in operator "\",
%    because it uses dense linear algebra and loop-unrolling on
%    supernodes.
%
%    Typical use, with X sparse m x m positive definite and b is m x n:
%            L = sparchol(symbchol(X),X);
%            y = bwblkslv(L,fwblkslv(L,b));
%    Then y solves X*y=b.
%
% See also symbchol, fwblkslv, mldivide, mrdivide

% This file is part of CholTool 1.00
% Copyright (C) 1998 Jos F. Sturm
% CRL, McMaster University, Canada.
% Supported by the Netherlands Organization for Scientific Research (NWO).
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

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


function [lstmStates, trainData, attnInfos] = rnnLayerForward(W_rnn, W_emb, prevState, input, masks, params, rnnFlags, trainData, model, charData)
% Running Multi-layer RNN for one time step.
% Input:
%   W_rnn: recurrent connections of multiple layers, e.g., W_rnn{ll}.
%   prevState: previous hidden state, e.g., for LSTM, prevState.c{ll}, prevState.h{ll}.
%   input: indices for the current batch
%   isTest: 1 -- don't store intermediate results in each state
%   isAttn: for attention, require attnData to be non-empty, has
%     attnData.srcHidVecsOrig and attnData.srcLens.
%   isDecoder: 0 -- encoder, 1 -- decoder
% Output:
%   nextState
%
% Thang Luong @ 2015, <lmthang@stanford.edu>

T = size(input, 2);
lstmStates = cell(T, 1);

% attention, encoder
attnInfos = cell(T, 1);
if rnnFlags.attn && rnnFlags.decode == 0
  assert(T == params.numSrcHidVecs);
  trainData.srcHidVecsOrig = zeroMatrix([params.lstmSize, params.curBatchSize, T], params.isGPU, params.dataType); % params.numSrcHidVecs
end

for tt=1:T % time
  if rnnFlags.charSrcRep && rnnFlags.decode == 0 % char representation, encoder
    inputEmb = zeroMatrix([params.lstmSize, params.curBatchSize], params.isGPU, params.dataType);

    % charData.rareFlags: to know which words are rare
    % charData.rareWordReps: the actual rare word representations
    % rareWordMap: to find out indices in rareWordReps
    rareIds = find(charData.rareFlags(:, tt));
    freqIds = find(~charData.rareFlags(:, tt));

    if params.assert
      assert(all(ismember(rareIds, find(masks(:, tt)==1))));
    end

    % embeddings for rare words
    if ~isempty(rareIds)
      inputEmb(:, rareIds) = charData.rareWordReps(:, charData.rareWordMap(input(rareIds, tt)));
    end

    % embeddings for frequent words
    inputEmb(:, freqIds) = W_emb(:, input(freqIds, tt));
  else
    inputEmb = W_emb(:, input(:, tt));
  end

  % multi-layer RNN
  [prevState, attnInfos{tt}] = rnnStepLayerForward(W_rnn, inputEmb, prevState, masks(:, tt), params, rnnFlags, trainData, model);

  % encoder, attention
  if rnnFlags.attn && rnnFlags.decode == 0
    trainData.srcHidVecsOrig(:, :, tt) = prevState{end}.h_t;
  end

  % store all states
  lstmStates{tt} = prevState;
end


function [returnVar,msg] = RemoveDCfromDat(fname,nbChan)

% USAGE:
%     RemoveDCfromDat(fbasename,nbChan)
%     This function removes DC from dat files by computing the average of
%     the first 1e6 samples (or less if file is smaller)
% INPUTS:
%     fname: dat file name
%     nbChan: total number of channels in dat file
%
% Adrien Peyrache 2011

fprintf('Removing baseline from %s\n',fname)
try
    infoFile = dir(fname);

    chunk = 1e6;
    nbChunks = floor(infoFile.bytes/(nbChan*chunk*2));
    warning off
    if nbChunks==0
        chunk = infoFile.bytes/(nbChan*2);
    end
    m = memmapfile(fname,'Format','int16','Repeat',chunk*nbChan,'writable',true);
    d = m.Data;
    d = reshape(d,[nbChan chunk]);
    meanD = mean(d,2);
    d = d-int16(meanD*ones(1,chunk));
    m.Data = d(:);
    clear d m

    for ix=1:nbChunks-1
    %    h=waitbar(ix/(nbChunks-1));
        m = memmapfile(fname,'Format','int16','Offset',ix*chunk*nbChan*2,'Repeat',chunk*nbChan,'writable',true);
        d = m.Data;
        d = reshape(d,[nbChan chunk]);
        d = d-int16(meanD*ones(1,chunk));
        m.Data = d(:);
        clear d m
    end
    %close(h)

    newchunk = infoFile.bytes/(2*nbChan)-nbChunks*chunk;

    if newchunk
        m = memmapfile(fname,'Format','int16','Offset',nbChunks*chunk*nbChan*2,'Repeat',newchunk*nbChan,'writable',true);
        d = m.Data;
        d = reshape(d,[nbChan newchunk]);
        d = d-int16(meanD*ones(1,newchunk));
        m.Data = d(:);
     clear d m
    end
    warning on
    returnVar = 1;
    msg = '';

catch
%     keyboard
    returnVar = 0;
    msg = lasterr;
end
clear m


function pts2 = grFaceToPolygon(varargin)
%GRFACETOPOLYGON Compute the polygon corresponding to a graph face
%
%   PTS2 = grFaceToPolygon(NODES, EDGES, FACES, INDF)
%   PTS2 = grFaceToPolygon(NODES, FACES, INDF)
%   Where NODES, EDGES, and FACES are internal data of graph, and INDF is
%   the index of the face to extract. The result is the (ordered) set of
%   points composing the face.
%
%
%   PTS2 = grFaceToPolygon(GRAPH, INDF)
%   use structure representation for graph. The structure GRAPH must
%   contain data for fields 'nodes' and 'faces'.
%
%   If several indices face indices are specified, result is a cell array
%   of polygons.
%
%   The number of columns of PTS2 is the same as for NODES.
%
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2005-11-30
% Copyright 2005 INRA - CEPIA Nantes - MIAJ (Jouy-en-Josas).

%   HISTORY
%   27/07/2007: cleanup code

if length(varargin)==2
    % argument is a graph structure
    graph = varargin{1};
    nodes = graph.nodes;
    faces = graph.faces;
    indf  = varargin{2};

elseif length(varargin)==3
    % arguments are nodes, faces and indices
    nodes = varargin{1};
    faces = varargin{2};
    indf  = varargin{3};

elseif length(varargin)==4
    % arguments are nodes, edges, faces and indices, we forget edges
    nodes = varargin{1};
    faces = varargin{3};
    indf  = varargin{4};
end

if iscell(faces)
    % faces is a cell array
    if length(indf)==1
        face = faces{indf};
        pts2 = nodes(face, :);
    else
        pts2 = cell(length(indf), 1);
        for i=1:length(indf)
            face = faces{indf(i)};
            pts2{i} = nodes(face, :);
        end
    end
else
    % faces is an indices array: all faces have same number of vertices
    if length(indf)==1
        face = faces(indf, :);
        pts2 = nodes(face, :);
    else
        pts2 = cell(length(indf), 1);
        for i=1:length(indf)
            face = faces(indf(i), :);
            pts2{i} = nodes(face, :);
        end
    end
end


%% Create an artificial set of QRS detections, based on multilead QRS detections created with wavedet algorithm.
% This is an auxiliar function for the ECGtask_QRS_detections_post_process.
% *wavedetMix* use the output of wavedet algorithm to perform a  multilead
% composition. The result of this algorithm is a new set of detections
% based on the concatenation of the ""best"" detections found for each
% 20-seconds window in a recording. So, this algorithm generates *new* QRS
% detection series, as described in [add reference].
%
%
%   all_detections = wavedetMix(struct_in, ECG_header, start_end_this_segment )
%
% Arguments:
%
%      + struct_in: the structure which results from loading the result of
%                   the QRS detection task used for invoking wavedet:
%
%                   cached_filenames = ECG_w.GetCahchedFileName('QRS_detection');
%                   struct_in = load(cached_filenames{1});
%
%      +ECG_header: [struct] OPTIONAL.
%
%             Description of the ECG typically available in the
%             ECG_header. Structure with fields:
%
%               -freq: Sampling rate in Hz. (1)
%
%               -nsig: Number of ECG leads. (size(ECG,2))
%
%               -nsamp: Number of ECG samples. (size(ECG,1))
%
%      + start_end_this_segment: an array with the first and last sample
%                                indexes.
%
% Output:
%
%      + all_detections: struct with the artificial detections named with
%                        prefix "wavedetMix_ECGmix".
%
% Example
%
%     ECG_w.ECGtaskHandle = 'QRS_detections_post_process';
%     % Mix QRS detections strategy function
%     ECG_w.ECGtaskHandle.post_proc_func = 'wavedet_QRS_detection_mix';
%     ECG_w.ECGtaskHandle.payload = load(cached_filenames{1});
%     ECG_w.ECGtaskHandle.CalculatePerformance = true;
%     ECG_w.Run;
%
% See also ECGtask_QRS_detections_post_process, mixartif, best_m_lead, qrs_detection_and_correction
%
% Author: Mariano Llamedo Soria llamedom@electron.frba.utn.edu.ar
% Version: 0.1 beta
% Birthdate: 01/01/2014
% Last update: 14/07/2015
% Copyright 2008-2015
%
function all_detections = wavedetMix(struct_in, ECG_header, start_end_this_segment )

    all_detections = [];

    % attemp to build a better detection from single-lead detections.

    AnnNames = struct_in.series_quality.AnnNames(:,1);
    detector_name = cellfun( @(a)( strtok(a, '_')), AnnNames, 'UniformOutput', false);

    aux_idx = find(strcmpi(detector_name, 'wavedet'));

    if( isempty(aux_idx) )
        return
    end

    all_annotations = {};
    for ii = rowvec(aux_idx)
        all_annotations = [all_annotations; {struct_in.(struct_in.series_quality.AnnNames{ii,1}).time}];
    end

    [ ratios, estimated_labs ] = CalcRRserieRatio(all_annotations, ECG_header, start_end_this_segment);

    [~, best_detections_idx] = sort(ratios, 'descend');

    % generate artificial annotations combining K best annotations
    aux_idx = best_detections_idx(1:min(10, length(best_detections_idx)) );
    artificial_annotations = combine_anns(all_annotations(aux_idx), estimated_labs(aux_idx), ECG_header );

    for ii = 1:length(artificial_annotations)
        aux_str = ['wavedetMix_ECGmix' num2str(ii)];
        all_detections.(aux_str) = artificial_annotations(ii);
    end


function [data,units] = compute_min_wing_length(trx,n)

flies = trx.exp2flies{n};
nflies = numel(flies);
data = cell(1,nflies);
for i = 1:nflies,
  fly = flies(i);

  data{i} = min(trx(fly).wing_lengthl_mm,trx(fly).wing_lengthr_mm);

end
units = parseunits('mm');


function h = twVisualizeRFs(view, rois, dt, scans);
%
% h = twVisualizeRFs(view, [rois=all], [dt='Averages'], [scans=1:2];
%
% Visualize the location of RF esimates for each voxel in the
% specified ROIs, from a traveling wave analysis.
%
% scans: 2x1 matrix of [polar angle, eccentricity] scans, from which to
% take estimates. Retinotopic mapping parameters should be set for each of
% these (retinoSetParams; menu ColorMap | Set Retinotopy Parameters...).
%
% ras, 03/2007.
if notDefined('view'),	view = getCurView;			end
if notDefined('rois'),	rois = 1:length(view.ROIs);	end
if notDefined('dt'),	dt = 'Averages';			end
if notDefined('scans'),	scans = [1 2];				end

rois = tc_roiStruct(view, rois);

anal = twEstimateRFs(view, rois, dt, scans);

figure('Color', 'w', 'Name', ' Traveling Wave pRFs');
nrows = ceil(sqrt(length(rois)));
ncols = ceil(length(rois)/nrows);
for r = 1:length(rois)
	subplot(nrows, ncols, r);
	retinoPlot([], []);  % puts up grid
	plot(anal.x0{r}, anal.y0{r}, 'k.', 'MarkerSize', 1);
	grid on, axis([-10 10 -14 14]);
	axis square; axis equal;
	title(rois(r).name, 'FontSize', 14, 'FontName', 'Helvetica');
end

return