function [positionDecodingMaxCorr] = bz_positionDecodingMaxCorr(varargin)
% USAGE
%   [] = bz_positionDecodingMaxCorr()
%
% INPUTS
%
%   spikes
%
%   behavior
%
%   lfp
%
%   smoothingRange
%
%   plotting
%
%   saveMat
%
% OUTPUTS
%
%   positionDecodingMaxCorr     cellinfo struct with the following fields
%                      .UID
%                      .region
%                      .sessionName
%                      .results{1:nCells}
%                      .tau
%                      .condition
%
%
%
%
% SEE
%
% written by david tingley, 2017

%% parse inputs
p = inputParser();
addRequired(p,'spikes',@isstruct);
addRequired(p,'behavior',@isstruct);
addRequired(p,'lfp',@isstruct);
addRequired(p,'smoothingRange',@isvector);

addParameter(p,'plotting',@islogical);
addParameter(p,'saveMat',@islogical);
parse(p,varargin{:})

spikes = p.Results.spikes;
behavior = p.Results.behavior;
lfp = p.Results.lfp;
smoothingRange = p.Results.smoothingRange;
plotting = p.Results.plotting;
saveMat = p.Results.saveMat;

%% set up data format and popinfo struct that will be returned

positionDecodingMaxCorr.UID = spikes.UID;
positionDecodingMaxCorr.region = spikes.region;
positionDecodingMaxCorr.sessionName = spikes.sessionName; % session name

conditions = unique(behavior.events.trialConditions);
nCells = length(spikes.times);
positionSamplingRate = behavior.samplingRate;

% find a better way to get spike phase relationship...
[firingMaps] = bz_firingMap1D(spikes,behavior,5);
[phaseMaps] = bz_phaseMap1D(spikes,behavior,lfp,5);
[b a] = butter(3,[4/625 12/625],'bandpass');
theta_phases = angle(hilbert(FiltFiltM(b,a,double(lfp.data))));
% iterate through conditions and compile spike trains and spike-phase
% trains
for cond = conditions
    trials = find(behavior.events.trialConditions==cond);
    intervals = behavior.events.trialIntervals(trials,:);
    for t = 1:length(trials)
        trial = trials(t);
        spk_trains{cond}{t} = zeros(nCells,ceil((intervals(t,2)-intervals(t,1))*1000)); % assumes intervals are in seconds, rounds to nearest millisecond
        phase_trains{cond}{t} = zeros(nCells,ceil((intervals(t,2)-intervals(t,1))*1000));

        for cell = 1:nCells
            if ~isempty(phaseMaps.phaseMaps{cond}{cell})
                f = find(phaseMaps.phaseMaps{cond}{cell}(:,2)==t);
                if ~isempty(f)
                for s=1:length(f)
                    phase_trains{cond}{t}(cell,ceil(phaseMaps.phaseMaps{cond}{cell}(f(s),5)*1000)) = ...
                        phaseMaps.phaseMaps{cond}{cell}(f(s),end);
                end
                end
            end
            sp = find(InIntervals(spikes.times{cell},intervals(t,:)));
            spk_trains{cond}{t}(cell,ceil((spikes.times{cell}(sp)-intervals(t,1))*1000+.00001))=1;
        end

%         position{cond}{t} = interp1(1:length(behavior.events.trials{trial}.x)...
%             ,behavior.events.trials{trial}.mapping,1:positionSamplingRate/1000:length(...
%             behavior.events.trials{trial}.x));
        nBins = size(spk_trains{cond}{t},2);
        nPos = length(behavior.events.trials{trial}.x);
        position{cond}{t} = interp1(1:length(behavior.events.trials{trial}.x)...
            ,behavior.events.trials{trial}.mapping,1:(nPos-1)/nBins:length(...
            behavior.events.trials{trial}.x)); % the -1 gaurantees the length to be longer than the above spk/phase trains
        position{cond}{t} = position{cond}{t}(1:length(spk_trains{cond}{t}));
        take = FindInInterval(lfp.timestamps,intervals(t,:));
        theta{cond}{t} = makeLength(theta_phases(take(1):take(2)),length(position{cond}{t}));
    end
end

%% set up MaxCorr decoder
positionDecodingMaxCorr.results = table;

disp('running models...')
warning off % max cl model returns warning with NaNs and Inf values..
for cond = conditions
    r = randperm(length(phase_trains{cond}));
    for iter = 1:5%length(r)
        r = circshift(r,1);
    for wind = smoothingRange
        for cell = 1:nCells
            phase_trains_smooth=[];
            rates_trains_smooth = [];
            position_train = [];
            theta_train = [];
            for t = 1:length(phase_trains{cond})-1
                phase_trains_smooth=[phase_trains_smooth; circ_smoothTS(phase_trains{cond}{r(t)}(cell,:),wind,'method','mean','exclude',0)];
                rates_trains_smooth = [rates_trains_smooth; smooth(spk_trains{cond}{r(t)}(cell,:),wind)*wind];
                position_train = [position_train; position{cond}{r(t)}'];
                theta_train = [theta_train, theta{cond}{r(t)}];
            end
            phase_trains_smooth_train(cell,:) = phase_trains_smooth;
            rates_trains_smooth_train(cell,:) = rates_trains_smooth;
            phase_trains_smooth_test(cell,:)=[...
                circ_smoothTS(phase_trains{cond}{r(end)}(cell,:),wind,'method','mean','exclude',0)];
            rates_trains_smooth_test(cell,:) = [...
                smooth(spk_trains{cond}{r(end)}(cell,:),wind)*wind];

        end
        position_test = position{cond}{r(end)};
        theta_test = theta{cond}{r(end)};

        %% rate coding model
        cl = max_correlation_coefficient_CL;
        cl = train(cl,[rates_trains_smooth_train; theta_train],round(position_train));

        for ts = 1:length(position_test)
           yfit_rate(ts) = test(cl,[round(rates_trains_smooth_test(:,ts));theta_test(ts)]);
        end
        struct.mse_rate = mean((yfit_rate-position_test).^2);
        % chance rate
        rr = randperm(length(theta_train));
        rrr = randperm(length(theta_test));
        cl = max_correlation_coefficient_CL;
        cl = train(cl,[rates_trains_smooth_train(:,rr); theta_train],round(position_train));

        for ts = 1:length(position_test)
           yfit_chance_rate(ts) = test(cl,[round(rates_trains_smooth_test(:,rrr(ts)));theta_test(ts)]);
        end
        struct.mse_chance_rate = mean((yfit_chance_rate-position_test).^2);

        %% phase coding model

        % discretize phase_trains here...
        phase_trains_smooth_train_cos = cos(phase_trains_smooth_train);
        phase_trains_smooth_train_sin = sin(phase_trains_smooth_train);
        phase_trains_smooth_test_cos = cos(phase_trains_smooth_test);
        phase_trains_smooth_test_sin = sin(phase_trains_smooth_test);

        phase_trains_smooth_train(phase_trains_smooth_train==0)=nan;
        phase_trains_smooth_test(phase_trains_smooth_test==0)=nan;
        phase_trains_smooth_train = discretize(phase_trains_smooth_train,-pi:.1:pi);
        phase_trains_smooth_test = discretize(phase_trains_smooth_test,-pi:.1:pi);
        phase_trains_smooth_train(isnan(phase_trains_smooth_train))=0;
        phase_trains_smooth_test(isnan(phase_trains_smooth_test))=0;

        phase_trains_smooth_train_cos(phase_trains_smooth_train_cos==0)=nan;
        phase_trains_smooth_test_cos(phase_trains_smooth_test_cos==0)=nan;
        phase_trains_smooth_train_cos = discretize(phase_trains_smooth_train_cos,-1:.1:1);
        phase_trains_smooth_test_cos = discretize(phase_trains_smooth_test_cos,-1:.1:1);
        phase_trains_smooth_train_cos(isnan(phase_trains_smooth_train_cos))=0;
        phase_trains_smooth_test_cos(isnan(phase_trains_smooth_test_cos))=0;

        phase_trains_smooth_train_sin(phase_trains_smooth_train_sin==0)=nan;
        phase_trains_smooth_test_sin(phase_trains_smooth_test_sin==0)=nan;
        phase_trains_smooth_train_sin = discretize(phase_trains_smooth_train_sin,-1:.1:1);
        phase_trains_smooth_test_sin = discretize(phase_trains_smooth_test_sin,-1:.1:1);
        phase_trains_smooth_train_sin(isnan(phase_trains_smooth_train_sin))=0;
        phase_trains_smooth_test_sin(isnan(phase_trains_smooth_test_sin))=0;

        % non-transformed circular decoding
        cl = max_correlation_coefficient_CL;
        cl = train(cl,[phase_trains_smooth_train; theta_train],round(position_train));

        for ts = 1:length(position_test)
           yfit_circ(ts) = test(cl,[phase_trains_smooth_test(:,ts);theta_test(ts)]);
        end
        struct.mse_phase = mean((yfit_circ-position_test).^2);

        % cos and sin transformed circular decoding
        cl = max_correlation_coefficient_CL;
        cl = train(cl,[phase_trains_smooth_train_cos; theta_train],round(position_train));

        for ts = 1:length(position_test)
           yfit_cos(ts) = test(cl,[phase_trains_smooth_test_cos(:,ts);theta_test(ts)]);
        end
        struct.mse_phase_cos = mean((yfit_cos-position_test).^2);

        cl = max_correlation_coefficient_CL;
        cl = train(cl,[phase_trains_smooth_train_sin; theta_train],round(position_train));

        for ts = 1:length(position_test)
           yfit_sin(ts) = test(cl,[phase_trains_smooth_test_sin(:,ts);theta_test(ts)]);
        end
        struct.mse_phase_sin = mean((yfit_sin-position_test).^2);

        % all phase models in one...
        cl = max_correlation_coefficient_CL;
        all_phase_train = [phase_trains_smooth_train_cos;phase_trains_smooth_train_sin];
        all_phase_test =  [phase_trains_smooth_test_cos;phase_trains_smooth_test_sin];
        cl = train(cl,[all_phase_train; theta_train],round(position_train));

        for ts = 1:length(position_test)
           yfit_circ_all(ts) = test(cl,[all_phase_test(:,ts);theta_test(ts)]);
        end
        struct.mse_phase_all = mean((yfit_circ_all-position_test).^2);

        % chance phase
        cl = max_correlation_coefficient_CL;
        all_phase_train = [phase_trains_smooth_train_cos;phase_trains_smooth_train_sin];
        all_phase_test =  [phase_trains_smooth_test_cos;phase_trains_smooth_test_sin];
        cl = train(cl,[all_phase_train(:,rr); theta_train],round(position_train));

        for ts = 1:length(position_test)
           yfit_chance(ts) = test(cl,[all_phase_test(:,rrr(ts));theta_test(ts)]);
        end
        struct.mse_chance = mean((yfit_chance-position_test).^2);

        %% put data into struct/table
        struct.tau = wind;
        struct.condition = cond;
        struct.iter = iter;
        struct.trialOrder = r;
        positionDecodingMaxCorr.results = [positionDecodingMaxCorr.results;struct2table(struct)];
        if plotting
            clf
            subplot(2,2,1)
            t_rate = varfun(@mean,positionDecodingMaxCorr.results,'InputVariables','mse_rate',...
            'GroupingVariables',{'tau','condition'});
            t_phase = varfun(@mean,positionDecodingMaxCorr.results,'InputVariables','mse_phase',...
            'GroupingVariables',{'tau','condition'});
            t_phase_cos = varfun(@mean,positionDecodingMaxCorr.results,'InputVariables','mse_phase_cos',...
            'GroupingVariables',{'tau','condition'});
            t_phase_sin = varfun(@mean,positionDecodingMaxCorr.results,'InputVariables','mse_phase_sin',...
            'GroupingVariables',{'tau','condition'});
            t_chance = varfun(@mean,positionDecodingMaxCorr.results,'InputVariables','mse_chance',...
            'GroupingVariables',{'tau','condition'});
            t_chance_s = varfun(@std,positionDecodingMaxCorr.results,'InputVariables','mse_chance',...
            'GroupingVariables',{'tau','condition'});
            t_chance_rate = varfun(@mean,positionDecodingMaxCorr.results,'InputVariables','mse_chance_rate',...
            'GroupingVariables',{'tau','condition'});
            t_chance_s_rate = varfun(@std,positionDecodingMaxCorr.results,'InputVariables','mse_chance_rate',...
            'GroupingVariables',{'tau','condition'});
            t_rate_s = varfun(@std,positionDecodingMaxCorr.results,'InputVariables','mse_rate',...
            'GroupingVariables',{'tau','condition'});
            t_phase_s = varfun(@std,positionDecodingMaxCorr.results,'InputVariables','mse_phase',...
            'GroupingVariables',{'tau','condition'});
            t_phase_cos_s = varfun(@std,positionDecodingMaxCorr.results,'InputVariables','mse_phase_cos',...
            'GroupingVariables',{'tau','condition'});
            t_phase_sin_s = varfun(@std,positionDecodingMaxCorr.results,'InputVariables','mse_phase_sin',...
            'GroupingVariables',{'tau','condition'});
            tab = join(join(join(join(t_rate,t_phase),t_chance),t_phase_cos),t_phase_sin);
            tab_s = join(join(join(join(t_rate_s,t_phase_s),t_chance_s),t_phase_sin_s),t_phase_cos_s);
            rows = find(tab.condition==cond);

            title('MaxCorr decoding of pos, r-rate, g-phase')
%             iterRows = positionDecodingMaxCorr.iter == iter;
%             plot(positionDecodingMaxCorr.results.tau,...
%                 positionDecodingMaxCorr.results.mse_rate,'r')
%             hold on
%             plot(positionDecodingMaxCorr.results.tau,...
%                 positionDecodingMaxCorr.results.mse_phase_all,'g')
%             hold off
%             boundedline(tab.tau,t_chance_rate.mean_mse_chance_rate(rows),t_chance_s_rate.std_mse_chance_rate(rows),'k')
            boundedline(tab.tau,tab.mean_mse_chance(rows),tab_s.std_mse_chance(rows),'k')
            boundedline(tab.tau,tab.mean_mse_phase_cos(rows),tab_s.std_mse_phase_cos(rows),'g')
            boundedline(tab.tau,tab.mean_mse_rate(rows),tab_s.std_mse_rate(rows),'r')
%             set(gca,'xscale','log')
            subplot(2,2,2)
            boundedline(tab.tau,tab.mean_mse_phase(rows),tab_s.std_mse_phase(rows),'.g')
            boundedline(tab.tau,tab.mean_mse_phase_sin(rows),tab_s.std_mse_phase_sin(rows),'--g')
            boundedline(tab.tau,tab.mean_mse_phase_cos(rows),tab_s.std_mse_phase_cos(rows),'g')
%             subplot(2,2,3)
%             plot(positionDecodingMaxCorr.results.tau,...
%                 positionDecodingMaxCorr.results.mse_phase_sin,'g')
%             subplot(2,2,4)
%             plot(positionDecodingMaxCorr.results.tau,...
%                 positionDecodingMaxCorr.results.mse_phase,'g')
            pause(.001)
        end
        clear *train *test yfit*
        disp(['finished with window: ' num2str(wind) ' out of ' num2str(smoothingRange(end)) ' total'])
    end
    end
    disp(['finished with condition: ' num2str(cond) ' out of ' num2str(length(conditions)) ' total'])
    positionDecodingMaxCorr.dateRun = date;
    if saveMat
       save([spikes.sessionName '.positionDecodingMaxCorr.popinfo.mat'],'positionDecodingMaxCorr')
    end
end


% child script of canlab_glm_publish
% runs robust_results_batch in publishable manner
% runs in directory containing robust* directories

%% prep
z = '________________________________________________________________________________________________________';
assignin('base','z',z);
if ~exist('thresh','var'), thresh = [.001 .005 .05]; assignin('base','thresh',thresh); end
if ~exist('size','var'), size = [5 1 1]; assignin('base','size',size); end

if exist('EXPT','var')
    for i = 1:length(EXPT.SNPM.P)
        robregdirs{i} = fullfile(pwd,sprintf('robust%04d',i));
        connames{i} = EXPT.SNPM.connames(i,:);
    end
else
    d = filenames('robust[0-9][0-9][0-9][0-9]','absolute');
    if isempty(d), d{1} = pwd; end
    for i = 1:numel(d)
        robregdirs{i} = d{i};
        load(fullfile(robregdirs{i},'SETUP.mat'));
        load(fullfile(fileparts(SETUP.files(1,:)),'SPM.mat'));
        c = regexprep(SETUP.files(1,:),'.*con_0*([0-9]*)\.nii','$1');
        connames{i} = SPM.xCon(str2num(c)).name;
    end
end

%% write script
scriptfile = 'robfit_results.m';
scriptfileabs = fullfile(pwd,scriptfile);
fid = fopen(scriptfile,'w');

for i = 1:length(robregdirs)
    fprintf(fid,'%%%% contrast(%d) %s\n',i,connames{i});
    fprintf(fid,'cd(''%s'')\n',robregdirs{i});
    fprintf(fid,'fprintf(''%%s\\n%%s\\n%%s\\n%%s\\n%%s\\n%%s\\n'',z,z,''%s'',''%s'',z,z)\n',connames{i},robregdirs{i});

    fprintf(fid,'try\n');
    maskimg = fullfile(robregdirs{i}, 'rob_tmap_0001.img'); % any image in space with non-zero vals for all vox would do
    %fprintf(fid,'robust_results_batch(''thresh'', thresh, ''size'', size, ''prune'', ''mask'', ''%s'');\n',maskimg);
    fprintf(fid,'robust_results_batch;\n');

    fprintf(fid,'catch exc\n');
    fprintf(fid,'disp(getReport(exc,''extended''))\n');
    fprintf(fid,'end\n');
end
fprintf(fid,'close all\n');

fclose(fid);

%% publish script
outputdir = fullfile(pwd, 'Robust_Regression_Results_html');
mkdir(outputdir);

p = struct('useNewFigure', false, 'maxHeight', 1500, 'maxWidth', 1200, ...
    'outputDir', outputdir, 'showCode', false);

fout = publish(scriptfile, p);
fprintf('Created robfit results directory:\n%s\nHTML report: %s\n', outputdir, fout);

%% clean up
close all
delete(scriptfileabs)


function [bool, score] = score_find_in_cache(cache,j,ps,scoring_fn)
% [bool, score] = score_find_in_cache(cache,j,ps,scoring_fn)
%
% francois.olivier.c.h@gmail.com

%tic
L=size(cache,1);
N=size(cache,2)-3;

if N<1
  bool=0;
  score=0;
  return
end

parents=zeros(1,N+1);
parents(ps)=1;parents(N+1)=j;

switch scoring_fn
  case 'bic',
    fn=1;
  case 'bayesian',
    fn=2;
  otherwise,
    fn=3;
    %error(['unrecognized scoring fn ' scoring_fn]);
end

%parent = str2num(num2str(parents,'%1d'));
%[tmp y]=find(cache(:,N+3)==fn);
%if ~isempty(tmp)
%  [tmp2 y]=find(str2num(num2str(cache(tmp,1:N+1),'%1d'))==parent);
%  candidats=tmp(tmp2);
%else
%  candidats=[];
%end

[tmp y]=find(cache(2:L,N+3)==fn);
tmp=tmp+1;
[tmp2 y]=find(cache(tmp,N+1)==j);
candidats=tmp(tmp2);
if ~isempty(candidats)
  for i=1:N      % N=size(cache,2)-3;
    if ~isempty(candidats)
      [tmp2 y]=find(cache(tmp,i)==parents(i));
      candidats=intersect(candidats,tmp(tmp2));
    end
  end
end

%Tpre=toc

if ~isempty(candidats)
  bool=1;
else
  bool=0;
end

if bool
  score=cache(candidats(1),N+2);
else
  score=0;
end


function varargout = Sim_Sensitivity_Analysis_GUI(varargin)
% SIM_SENSITIVITY_ANALYSIS_GUI MATLAB code for Sim_Sensitivity_Analysis_GUI.fig
%      SIM_SENSITIVITY_ANALYSIS_GUI, by itself, creates a new SIM_SENSITIVITY_ANALYSIS_GUI or raises the existing
%      singleton*.
%
%      H = SIM_SENSITIVITY_ANALYSIS_GUI returns the handle to a new SIM_SENSITIVITY_ANALYSIS_GUI or the handle to
%      the existing singleton*.
%
%      SIM_SENSITIVITY_ANALYSIS_GUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in SIM_SENSITIVITY_ANALYSIS_GUI.M with the given input arguments.
%
%      SIM_SENSITIVITY_ANALYSIS_GUI('Property','Value',...) creates a new SIM_SENSITIVITY_ANALYSIS_GUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before Sim_Sensitivity_Analysis_GUI_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to Sim_Sensitivity_Analysis_GUI_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help Sim_Sensitivity_Analysis_GUI

% Last Modified by GUIDE v2.5 27-Jul-2017 17:23:32
if moxunit_util_platform_is_octave, warndlg('Graphical user interface not available on octave... use command lines instead'); return; end

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
    'gui_Singleton',  gui_Singleton, ...
    'gui_OpeningFcn', @Sim_Sensitivity_Analysis_GUI_OpeningFcn, ...
    'gui_OutputFcn',  @Sim_Sensitivity_Analysis_GUI_OutputFcn, ...
    'gui_LayoutFcn',  [] , ...
    'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before Sim_Sensitivity_Analysis_GUI is made visible.
function Sim_Sensitivity_Analysis_GUI_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hObject;
handles.Model = varargin{1};
if ~isfield(handles,'opened')
    % clear axe
    axes(handles.SimVaryAxe)

    % fill table
    Nparam=length(handles.Model.xnames);
    FitOptTable(:,1)=handles.Model.xnames(:);
    if isprop(handles.Model,'fx') && ~isempty(handles.Model.fx),    FitOptTable(:,2)=mat2cell(~logical(handles.Model.fx(:)),ones(Nparam,1)); end

    if isprop(handles.Model,'ub') && ~isempty(handles.Model.ub)
        FitOptTable(:,4)=mat2cell(handles.Model.lb(:),ones(Nparam,1));
        FitOptTable(:,5)=mat2cell(handles.Model.ub(:),ones(Nparam,1));
    end
    if isprop(handles.Model,'st') && ~isempty(handles.Model.st)
        FitOptTable(:,3)=mat2cell(handles.Model.st(:),ones(Nparam,1));
    elseif size(FitOptTable,2)==5
        FitOptTable(:,3) = mat2cell(mean(cat(2,handles.Model.lb(:),handles.Model.ub(:)),2),ones(Nparam,1));
    else
        FitOptTable(:,3) = mat2cell(ones(Nparam,1),ones(Nparam,1));
    end

    if size(FitOptTable,2)<5
        FitOptTable(:,4)=mat2cell(cell2mat(FitOptTable(:,3))/2,ones(Nparam,1));
        FitOptTable(:,5)=mat2cell(cell2mat(FitOptTable(:,3))*2,ones(Nparam,1));
    end
    set(handles.SimVaryOptTable,'Data',FitOptTable)
    % fill parameters
    set(handles.SimVaryPlotX,'String',handles.Model.xnames')
    set(handles.SimVaryPlotY,'String',handles.Model.xnames')

    % Options
    if isprop(handles.Model,'Sim_Single_Voxel_Curve_buttons')
        opts = handles.Model.Sim_Single_Voxel_Curve_buttons;
    else
        opts = {'SNR',50};
    end
    if isprop(handles.Model,'Sim_Sensitivity_Analysis_buttons'), opts = cat(2,opts,handles.Model.Sim_Sensitivity_Analysis_buttons);
    else
        opts = cat(2,opts,{'# of run',20});
    end

    handles.options = GenerateButtonsWithPanels(opts,handles.OptionsPanel);
    handles.opened = 1;

    % Create CALLBACK for buttons
    ff = fieldnames(handles.options);
    for ii=1:length(ff)
        %set(handles.OptionsPanel_handle.(ff{ii}),'Callback',@(src,event) ModelOptions_Callback(handles));
        switch get(handles.options.(ff{ii}),'Style')
            case 'togglebutton'
                set(handles.options.(ff{ii}),'Callback',@(src,event) ModelSimOptions_Callback(handles));
        end
    end

end
% Update handles structure
guidata(hObject, handles);

% UIWAIT makes Sim_Sensitivity_Analysis_GUI wait for user response (see UIRESUME)
% uiwait(handles.Simu);

% --- Outputs from this function are returned to the command line.
function varargout = Sim_Sensitivity_Analysis_GUI_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

% --------------------------------------------------------------------
function FileMenu_Callback(hObject, eventdata, handles)
% hObject    handle to FileMenu (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% --------------------------------------------------------------------
function OpenMenuItem_Callback(hObject, eventdata, handles)
% hObject    handle to OpenMenuItem (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
file = uigetfile('*.fig');
if ~isequal(file, 0)
    open(file);
end

% --------------------------------------------------------------------
function PrintMenuItem_Callback(hObject, eventdata, handles)
% hObject    handle to PrintMenuItem (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
printdlg(handles.Simu)

% --------------------------------------------------------------------
function CloseMenuItem_Callback(hObject, eventdata, handles)
% hObject    handle to CloseMenuItem (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
selection = questdlg(['Close ' get(handles.Simu,'Name') '?'],...
    ['Close ' get(handles.Simu,'Name') '...'],...
    'Yes','No','Yes');
if strcmp(selection,'No')
    return;
end

delete(handles.Simu)

% --- Executes on selection change in popupmenu1.
function popupmenu1_Callback(hObject, eventdata, handles)
% hObject    handle to popupmenu1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = get(hObject,'String') returns popupmenu1 contents as cell array
%        contents{get(hObject,'Value')} returns selected item from popupmenu1

% --- Executes during object creation, after setting all properties.
function popupmenu1_CreateFcn(hObject, eventdata, handles)
% hObject    handle to popupmenu1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

set(hObject, 'String', {'plot(rand(5))', 'plot(sin(1:0.01:25))', 'bar(1:.5:10)', 'plot(membrane)', 'surf(peaks)'});

% --- Executes on selection change in SimVaryPlotX.
function SimVaryPlotX_Callback(hObject, eventdata, handles)
SimVaryPlotResults(handles)

% --- Executes during object creation, after setting all properties.
function SimVaryPlotX_CreateFcn(hObject, eventdata, handles)
% hObject    handle to SimVaryPlotX (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in SimVaryPlotY.
function SimVaryPlotY_Callback(hObject, eventdata, handles)
SimVaryPlotResults(handles)

% --- Executes during object creation, after setting all properties.
function SimVaryPlotY_CreateFcn(hObject, eventdata, handles)
% hObject    handle to SimVaryPlotY (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in SimVaryUpdate.
function SimVaryUpdate_Callback(hObject, eventdata, handles)
Model_new = getappdata(0,'Model');
if ~isempty(Model_new) && strcmp(class(Model_new),class(handles.Model))
    handles.Model = Model_new;
end
FitOptTable = get(handles.SimVaryOptTable,'Data'); FitOptTable(:,2)=mat2cell(~[FitOptTable{:,2}]',ones(size(FitOptTable,1),1), 1);
FitOptTable = cell2struct(FitOptTable,{'xnames','fx','st','lb','ub'},2);
Opts = button_handle2opts(handles.options);
handles.SimVaryResults = handles.Model.Sim_Sensitivity_Analysis(FitOptTable,Opts);
SetSimVaryResults(handles)
guidata(hObject, handles);

% --- Executes on button press in Save.
function Save_Callback(hObject, eventdata, handles)
if isfield(handles,'SimVaryResults')
    Method = class(handles.Model);
    [FileName,PathName] = uiputfile([Method '_SimResults.mat']);
    if PathName == 0, return; end
    SimVaryResults = handles.SimVaryResults;
    save(fullfile(PathName,FileName),'SimVaryResults')
end

% --- Executes on button press in Options panel.
function ModelSimOptions_Callback(handles)
xtable = get(handles.SimVaryOptTable,'Data');
x=cell2mat(xtable(~cellfun(@isempty,xtable(:,3)),3))';
xnew = SimOpt(handles.Model,x,button_handle2opts(handles.options));
if ~isempty(xnew) % update the ParamTable in the GUI
    Nparam = length(handles.Model.xnames);
    xtable(1:Nparam,3) = mat2cell(xnew',ones(Nparam,1));
    set(handles.SimVaryOptTable,'Data',xtable);
end

function Load_Callback(hObject, eventdata, handles)
Method = class(handles.Model);
[FileName,PathName] = uigetfile([Method '_SimResults.mat']);
if PathName == 0, return; end
load(fullfile(PathName,FileName));
handles.SimVaryResults = SimVaryResults;
SetSimVaryResults(handles)
guidata(hObject, handles);

function SetSimVaryResults(handles)
ff=fieldnames(handles.SimVaryResults);
set(handles.SimVaryPlotX,'String',ff);
ff=fieldnames(handles.SimVaryResults.(ff{1}));
set(handles.SimVaryPlotY,'String',ff(~ismember(ff,{'x','fit'})));
SimVaryPlotResults(handles)

function SimVaryPlotResults(handles)
if isfield(handles,'SimVaryResults')
    Xaxis = get(handles.SimVaryPlotX,'String'); Xaxis = Xaxis{get(handles.SimVaryPlotX,'Value')};
    Yaxis = get(handles.SimVaryPlotY,'String'); Yaxis = Yaxis{get(handles.SimVaryPlotY,'Value')};
    SimVaryPlot(handles.SimVaryResults,Xaxis,Yaxis)
end

function SimVaryOptTable_CellEditCallback(hObject, eventdata, handles)


%kdtrans 'three dimensional distance transform '
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros dtrans.pane file
%
% Parameters:
% InputFile: i 'Input ', required: 'First Input data object'
% OutputFile: od 'Distance Output', required: '3D Map of distances'
% OutputFile: ov 'Distance Vector ', required: '3D Map of distances (as vectors'
%
% Example: [od, ov] = kdtrans(i, {'i','';'od','';'ov',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% dtrans - three dimensional distance transform
%
%  DESCRIPTION
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
%
%  RESTRICTIONS
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1996-2003, Rainer Heintzmann,  All rights reserved.
%

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

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


classdef KeyVal < handle
%KEYVAL A class that encapsulates a key and a value, which could be an
%       instance of a handle class. It is assumed that standard comparison
%       operations can be performed on the keys. This class is useful for
%       inserting elements into a BinaryHeap or other data structure that
%       requires a key and a value.
%
%DEPENDENCIES: NONE
%
%Instances of the KeyVal class can be compared to each other by key or to
%other objects that have the same type of key. For example,
%keyVal1<keyVal2 will compare the two objects by their keys.
%
%December 2013 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

    properties
       key
       value
    end
    methods
        function newKeyVal=KeyVal(key,val)
        %KEYVAL The constructor method.
            if(nargin<2)
                val=[];
            end
            if(nargin<1)
                key=[];
            end

            newKeyVal.key=key;
            newKeyVal.value=val;
        end

        function val=lt(obj1,obj2)
        %%LT Less than comparison

            if(isa(obj1,'KeyVal')==true&&isa(obj2,'KeyVal')==true)
                val=obj1.key<obj2.key;
            elseif(isa(obj1,'KeyVal')==true)
                val=obj1.key<obj2;
            else
                val=obj1<obj2.key;
            end
        end

        function val=gt(obj1,obj2)
        %%GT Greater than comparison

            if(isa(obj1,'KeyVal')==true&&isa(obj2,'KeyVal')==true)
                val=obj1.key>obj2.key;
            elseif(isa(obj1,'KeyVal')==true)
                val=obj1.key>obj2;
            else
                val=obj1>obj2.key;
            end
        end

        function val=le(obj1,obj2)
        %%LE Less than or equal to comparison

            if(isa(obj1,'KeyVal')==true&&isa(obj2,'KeyVal')==true)
                val=obj1.key<=obj2.key;
            elseif(isa(obj1,'KeyVal')==true)
                val=obj1.key<=obj2;
            else
                val=obj1<=obj2.key;
            end
        end

        function val=ge(obj1,obj2)
        %%GE Greater than or equal to comparison

            if(isa(obj1,'KeyVal')==true&&isa(obj2,'KeyVal')==true)
                val=obj1.key>=obj2.key;
            elseif(isa(obj1,'KeyVal')==true)
                val=obj1.key>=obj2;
            else
                val=obj1>=obj2.key;
            end
        end

        function val=ne(obj1,obj2)
        %%NE Not equal to comparison

            if(isa(obj1,'KeyVal')==true&&isa(obj2,'KeyVal')==true)
                val=obj1.key~=obj2.key;
            elseif(isa(obj1,'KeyVal')==true)
                val=obj1.key~=obj2;
            else
                val=obj1~=obj2.key;
            end
        end

        function val=eq(obj1,obj2)
        %%EQ Equal to comparison

            if(isa(obj1,'KeyVal')==true&&isa(obj2,'KeyVal')==true)
                val=obj1.key==obj2.key;
            elseif(isa(obj1,'KeyVal')==true)
                val=obj1.key==obj2;
            else
                val=obj1==obj2.key;
            end
        end

        function objCopy=copy(obj)
        %%COPY Create a new KeyVal class where the keys and values are
        %      duplicates of those in this class. This is a shallow copy.
        %      We do not call the copy function on handle class values to
        %      make deep copies.

            objCopy=KeyVal(obj.key,obj.value);
        end
    end
end

%LICENSE:
%
%The source code is in the public domain and not licensed or under
%copyright. The information and software may be used freely by the public.
%As required by 17 U.S.C. 403, third parties producing copyrighted works
%consisting predominantly of the material produced by U.S. government
%agencies must provide notice with such work(s) identifying the U.S.
%Government material incorporated and stating that such material is not
%subject to copyright protection.
%
%Derived works shall not identify themselves in a manner that implies an
%endorsement by or an affiliation with the Naval Research Laboratory.
%
%RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE
%SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY THE NAVAL
%RESEARCH LABORATORY FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE ACTIONS
%OF RECIPIENT IN THE USE OF THE SOFTWARE.


function dat=readmptiff(fname)
%
% vol=readmptiff(fname)
%
% load a volume from a multi-page TIFF file
%
% author: Qianqian Fang, <q.fang at neu.edu>
%
% input:
%      fname: input file name
%
% output:
%      dat: output, data read from the TIFF file
%
% -- this function is part of iso2mesh toolbox (http://iso2mesh.sf.net)
%

info = imfinfo(fname);
nslice = length(info);
if(nslice<=0)
    error('no data found in the tiff');
end

for i = 1:nslice
    dat(:,:,i) = imread(fname, i);
end


function newlp = mrRefreshInplanes(lp,obXM,obYM,curInplane,deleteFlag)
% function newlp = mrRefreshInplanes(lp,obXM,obYM,curInplane,deleteFlag)
% ---------------------------------------------------
% Function: refreshes the inplane grid image replacing old handles with
% new ones derived from obXM and obYM
% Author: SPG
% Date: 2.26.97
% Notes: object handling in matlab is seriously screwed up. So be wary of
% altering any delete(lp) calls here or elsewhere, because I don't think
% logic applies to them.

global sagwin

figure(sagwin);

if deleteFlag == 1
  for i=1:length(lp)
    delete(lp(i));
  end
end

if ~isempty(lp)
 for i=1:length(lp)
   if i == curInplane
        newlp(i)=line(obXM(i,:),obYM(i,:),'Color','r');
   else
        newlp(i)=line(obXM(i,:),obYM(i,:),'Color','b');
   end
  end
else
 newlp = [];
end


function modelRet = modelTest(modelType, numIn, varargin)

% MODELTEST Run some tests on the specified model.
% FORMAT
% DESC runs some tests on the specified model to ensure it is
% correctly implemented.
% ARG modelType : type of model to test. For example, 'linear' or
% 'mlp'.
% RETURN model : the model that was generated for the tests.
%
% SEEALSO : modelCreate
%
% COPYRIGHT : Neil D. Lawrence,  2006

% MLTOOLS

%if exist([modelType 'Test']) == 2
%  feval([modelType 'Test'])
%end
if ~isstruct(modelType)
  if nargin < 2
    numIn = 4;
  end
  numData = 20;
  numOut = 3;

  % Generate some x positions.
  x = randn(numData, numIn);
  x2 = randn(numData, numIn);
  options = modelOptions(modelType);
  model = modelCreate(modelType, numIn, numOut, options);
  model = modelParamInit(model);
  model.X = x;
  model.y = modelOut(model, x2);

  % Set the parameters randomly.
  params = modelExtractParam(model);
  params = randn(size(params))./sqrt(randn(size(params)).^2);
  model = modelExpandParam(model, params);
else
  model = modelType;
end

% Check model parameter gradient.
modelGradientCheck(model, varargin{:});

if exist([model.type 'OutputGrad'])==2;
  epsilon = 1e-6;
  [params, names] = modelExtractParam(model);
  if length(names) == 0
    for i = 1:model.numParams
      names{i} = ['Param ' num2str(i)];
    end
  end
  origParams = params;
  Lplus = zeros(size(model.X, 1), model.numParams, model.outputDim);
  Lminus = zeros(size(model.X, 1), model.numParams, model.outputDim);
  for i = 1:length(params);
    params = origParams;
    params(i) = origParams(i) + epsilon;
    model = modelExpandParam(model, params);
    Lplus(:, i, :) = reshape(modelOut(model, model.X), ...
                             size(model.X, 1), 1, model.outputDim);
    params(i) = origParams(i) - epsilon;
    model = modelExpandParam(model, params);
    Lminus(:, i, :) = reshape(modelOut(model, model.X), ...
                              size(model.X, 1), 1, model.outputDim);
  end
  params = origParams;
  model = modelExpandParam(model, params);
  gLDiff = .5*(Lplus - Lminus)/epsilon;
  g = modelOutputGrad(model, model.X);

  outParamMaxDiff = max(max(max(abs(gLDiff-g))));
  if outParamMaxDiff > 2*epsilon
    l = 0;
    for i = 1:length(names)
      if l < length(names{i})
        l = length(names{i});
      end
    end

    fprintf([char(repmat(32, 1, l)) '\tanalytic   diffs     delta\n']);
    for i = 1:length(names)
      spaceLen = l - length(names{i});
      space = char(repmat(32, 1, spaceLen));
      fprintf([space names{i} ':\t%4.6f\t%4.6f\t%4.6f\n'], ...
              g(i), gLDiff(i), gLDiff(i) - g(i));
    end
  end
  fprintf('Output param max diff: %2.6f.\n', outParamMaxDiff);
else
  fprintf('No grad of output with respect to param implemented.\n');
end

if exist([model.type 'OutputGradX'])==2;
  epsilon = 1e-6;
  X = model.X;
  origX = X;
  Lplus = zeros(size(model.X, 1), size(model.X, 2), model.outputDim);
  Lminus = zeros(size(model.X, 1), size(model.X, 2), model.outputDim);
  for i = 1:size(model.X, 2)
    X = origX;
    X(:, i) = origX(:, i) + epsilon;
    Lplus(:, i, :) = reshape(modelOut(model, X), ...
                             size(model.X, 1), 1, model.outputDim);
    X(:, i) = origX(:, i) - epsilon;
    Lminus(:, i, :) = reshape(modelOut(model, X), ...
                              size(model.X, 1), 1, model.outputDim);
  end
  X = origX;
  gLDiff = .5*(Lplus - Lminus)/epsilon;
  g = modelOutputGradX(model, X);

  outputXMaxDiff = max(max(max(abs(gLDiff-g))));
  if outputXMaxDiff > 2*epsilon
    fprintf('gX\n')
    disp(g)
    fprintf('gXDiff\n')
    disp(gLDiff)
  end
  fprintf('X max diff: %2.6f.\n', outputXMaxDiff);
else
  fprintf('No grad of output with respect to X implemented.\n');
end
if nargout > 0
  modelRet = model;
else
  modelDisplay(model);
end


function [origin,site,arrival,ray] = dbload(dbName)

%DBLOAD extracts travel times from a database
% [ORIGIN,SITE,ARRIVAL,RAY] = DBLOAD(DBNAME) reads an Antelope database
% DBNAME and creates structures with information needed to explore the
% traveltime and ray coverage of an earthquake catalog. DBNAME must contain
% the following tables: origin, event, assoc, arrival and site Antelope
% database tables.
%
%
% -- OUTPUT ARGUMENTS --
%
% ORIGIN
% This is a minimally populated catalog object (see help catalog) that
% describes the earthquake hypocenters. It includes the fields lat, lon,
% depth (km, positive down), origin time (Matlab datenum format), magnitude
% (Ml) and origin id (orid). One element for each earthquake.
%
% ARRIVAL
% This structure describes the phase arrivals. Fields include station name
% (sta), phase name (iphase), travel time (seconds), timeRes (modeled
% travel time residual. specifically it is the observed travel time minus
% the model predicted travel time) and orid. One element for each pahse
% arrival.
%
% RAY
% This structure crudely describes the ray path coverage. It's elements are
% the same length as the elements of arrival. They include originLat,
% otiginLon, originDepth (km, positive down), siteLat, siteLon, siteElev
% (km, positive down) and flatDist (the horizontal distance in km between
% the origin and and site. RAY contains information that is redundant to
% other structures. it exists to allow faster plotting of ray paths.
%
% STATION
% This structure descibes the stations. Fields include sta (station name),
% lat, lon, elevation. STATION has one element for each station. Only
% stations that have at least one phase arrival are included.
%
%
% CAVEATS
% Only P and S phase arrivals are loaded from the database since the goal
% of the ttimes package is to prepare local/regional scale tomography data.
% Because there are so many ways users might wish to cull the dataset, this
% is best done directly on the database before final application of this
% function. No subsetting functions are included here.
%
% See also ttimes.map ttimes.depth_section ttimes.tt_curve
% ttimes.arrival_histogram ttimes.write_lotos ttimes.do_all

% Author: Michael West, Geophysical Institute, Univ. of Alaska Fairbanks
% $Date$
% $Revision$

% CHECK FOR VALID DATABASE
if ~admin.antelope_exists
   error('This function requires the Antelope toolbox for Matlab');
end

try
    db = dbopen(dbName,'r');
    dbclose(db);
catch
    error(['Could not open database: ' dbName]);
end

% FOR DEBUGGING
%  dbName = '/Users/west/FIELDDATA/doc/database/origin/2009april-2010april/reviewed';
%  [origin,site,arrival,ray] = ttimes.dbload(dbName);

%% ACCESS DATABASE
% CREATE DATABASE VIEW
try
    % Entire database
    db = dbopen(dbName,'r');

    % Event view
    db = dblookup_table(db,'origin');
    db1 = dblookup_table(db,'event');
    db = dbjoin(db,db1);
    db = dbsubset(db,'orid==prefor');
    nEvents = dbquery(db,'dbRECORD_COUNT');
    oridList = dbgetv(db,'orid');
    %disp(['Number of origins: ' num2str(nEvents) ]);
    [tmp.lat,tmp.lon,tmp.depth,tmp.time,tmp.ml,tmp.orid,tmp.nass] = dbgetv(db,'origin.lat','origin.lon','origin.depth','origin.time','origin.ml','origin.orid','origin.nass');
    tmp.time = epoch2datenum(tmp.time);
    f = find(tmp.ml < -2);
    tmp.ml(f)=-2;
    f = find(tmp.nass < 0);
    tmp.nass(f)=0;
    origin = catalog;
    origin = set(origin,'LAT',tmp.lat,'LON',tmp.lon,'DEPTH',tmp.depth,'DNUM',tmp.time,'mag',tmp.ml,'ORID',tmp.orid,'NASS',tmp.nass);

    % Arrival view
    db1 = dblookup_table(db,'assoc');
    db = dbjoin(db,db1);
    db1 = dblookup_table(db,'arrival');
    db = dbjoin(db,db1);
    db = dbsubset(db,'iphase=="S" || iphase=="P"');
    db1 = dblookup_table(db,'site');
    db = dbjoin(db,db1);
    nArrivals = dbquery(db,'dbRECORD_COUNT');
    %disp(['Number of arrivals: ' num2str(nArrivals) ]);
    [arrival.sta,arrival.iphase,arrival.time,arrival.originTime,arrival.timeres,arrival.orid] = dbgetv(db,'arrival.sta','arrival.iphase','arrival.time','origin.time','timeres','orid');
    arrival.time = epoch2datenum(arrival.time);
    arrival.originTime = epoch2datenum(arrival.originTime);
    arrival.travelTime = 86400*(arrival.time-arrival.originTime);
    f = find(arrival.timeres==-999);
    arrival.timeres(f) = NaN;
    arrival.predTravelTime = arrival.travelTime + arrival.timeres;

    % Ray view
    [ray.originLat,ray.originLon,ray.originDepth,ray.siteLat,ray.siteLon,ray.siteElev] = dbgetv(db,'origin.lat','origin.lon','origin.depth','site.lat','site.lon','site.elev');
    ray.siteElev = -1*ray.siteElev;
    ray.flatDist = deg2km(distance(ray.originLat,ray.originLon,ray.siteLat,ray.siteLon));

    % Site view
    [tmp.sta,tmp.lon,tmp.lat,tmp.elev] = dbgetv(db,'site.sta','site.lon','site.lat','site.elev');
    tmp.elev = -1*tmp.elev;
    site = [];
    [site.sta,m,~] = unique(tmp.sta);
    site.lat = tmp.lat(m);
    site.lon = tmp.lon(m);
    site.elev = tmp.elev(m);

catch
    error(['Problems with one or more database tables (origin, event, assoc, arrival, site)']);
end
dbclose(db);

% % CREATE TRAVELTIME
% for n = 1:numel(origin.orid)
%     f = find(arrival.orid==origin.orid(n));
%     arrival.travelTime(f) = 86400*(arrival.time(f)-origin.dnum(n));
% end
% arrival.travelTime = arrival.travelTime';
% arrival.predTravelTime = arrival.travelTime + arrival.timeres;


function z=vecr(fit)

z = fit.fit_points.kappa;

return;


function [psth] = ft_spike_psth(cfg, spike)

% FT_SPIKE_PSTH computes the peristimulus histogram of spiketrains.
%
% Use as
%   [psth] = ft_spike_psth(cfg, spike)
%
% The input SPIKE should be organised as either the spike datatype,
% obtained from FT_SPIKE_MAKETRIALS, or the raw datatype, containing binary
% spike trains, obtained from FT_APPENDSPIKE or FT_CHECKDATA. In this case
% the raw datatype is converted to the spike datatype.
%
% Configurations:
%   cfg.binsize          =  [binsize] in sec or string.
%                          If 'scott', we estimate the optimal bin width
%                          using Scott's formula (1979). If 'sqrt', we take
%                          the number of bins as the square root of the
%                          number of observations. The optimal bin width is
%                          derived over all neurons; thus, this procedure
%                          works best if the input contains only one neuron
%                          at a time.
%   cfg.outputunit       = 'rate' (default) or 'spikecount' or
%                          'proportion'. If 'rate', we
%                          convert the output per trial to firing rates
%                          (spikes/sec). If 'spikecount', we count the
%                          number spikes per trial. If 'proportion', we
%                          normalize the area under the PSTH to 1.
%   cfg.spikechannel     = See FT_CHANNELSELECTION for details. cfg.trials
%                          is vector of indices (e.g., 1:2:10)
%                          logical selection of trials (e.g., [1010101010])
%                          'all' (default), selects all trials
%   cfg.vartriallen      = 'yes' (default)
%                          Accept variable trial lengths and use all
%                          available trials and the samples in every trial.
%                          Missing values will be ignored in the
%                          computation of the average and the variance and
%                          stored as NaNs in the output psth.trial. 'no'
%                          Only select those trials that fully cover the
%                          window as specified by cfg.latency and discard
%                          those trials that do not.
%   cfg.latency          = [begin end] in seconds
%                          'maxperiod' (default), i.e., maximum period
%                          available 'minperiod', i.e., the minimal period
%                          all trials share, 'prestim' (all t<=0) 'poststim'
%                          (all t>=0).
%   cfg.keeptrials       = 'yes' or 'no' (default)
%   cfg.trials           =  numeric or logical selection of trials (default = 'all')
%
% Outputs:
%   Psth is a timelock datatype (see FT_DATATYPE_TIMELOCK)
%     Psth.time        = center histogram bin points
%	    Psth.fsample     = 1/binsize;
%     Psth.avg         = contains average PSTH per unit
%     Psth.trial       = contains PSTH per unit per trial
%     Psth.var         = contains variance of PSTH per unit across trials
%
% For subsequent processing you can use
%   FT_SPIKE_PLOT_PSTH    : plot only the PSTH, for a single neuron
%   FT_TIMELOCKSTATISTICS : compute statistics on the PSTH
%   FT_SPIKE_PLOT_RASTER  : plot PSTH with raster for one or more neurons
%   FT_SPIKE_JPSTH        : compute the JPSTH

%  Copyright (C) 2010-2013, Martin Vinck
%
% 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 provenance spike

% control input spike structure and convert to spike if raw structure
spike = ft_checkdata(spike,'datatype', 'spike', 'feedback', 'yes');

% get the default options
cfg.outputunit   = ft_getopt(cfg, 'outputunit','rate');
cfg.binsize      = ft_getopt(cfg, 'binsize','scott');
cfg.spikechannel = ft_getopt(cfg, 'spikechannel', 'all');
cfg.trials       = ft_getopt(cfg, 'trials', 'all');
cfg.latency      = ft_getopt(cfg, 'latency','maxperiod');
cfg.vartriallen  = ft_getopt(cfg, 'vartriallen', 'yes');
cfg.keeptrials   = ft_getopt(cfg, 'keeptrials', 'no');

% ensure that the options are valid
cfg = ft_checkopt(cfg,'outputunit',   'char',  {'rate', 'spikecount'});
cfg = ft_checkopt(cfg,'binsize',     {'char',  'doublescalar'});
cfg = ft_checkopt(cfg,'spikechannel',{'cell',  'char', 'double'});
cfg = ft_checkopt(cfg,'latency',     {'char',  'ascendingdoublebivector'});
cfg = ft_checkopt(cfg,'trials',      {'char',  'doublevector', 'logical'});
cfg = ft_checkopt(cfg,'vartriallen' , 'char', {'yes', 'no'});
cfg = ft_checkopt(cfg,'keeptrials'  , 'char', {'yes', 'no'});

cfg = ft_checkconfig(cfg, 'allowed', {'outputunit', 'binsize', 'spikechannel', 'trials', 'latency', 'vartriallen', 'keeptrials'});

% get the number of trials or convert to indices
cfg        = trialselection(cfg,spike);

% select the unit - this should be done with channelselection function
cfg.spikechannel = ft_channelselection(cfg.spikechannel, spike.label);
spikesel         = match_str(spike.label, cfg.spikechannel);
nUnits           = length(spikesel);
if nUnits==0, error('no spikechannel selected by means of cfg.spikechannel'); end

% determine the duration of each trial
begTrialLatency = spike.trialtime(cfg.trials,1); % remember: already selected on trial here
endTrialLatency = spike.trialtime(cfg.trials,2);
trialDur 	    	= endTrialLatency - begTrialLatency;

% select the latencies, use the same modular function in all the scripts
cfg = latencyselection(cfg,begTrialLatency,endTrialLatency);

% compute the optimal bin width if desired
if ischar(cfg.binsize)
  h = zeros(1,nUnits);
  for iUnit = 1:nUnits
    unitIndx       = spikesel(iUnit); % select the unit
    spikesInWin    = spike.time{unitIndx}>=cfg.latency(1) & spike.time{unitIndx}<=cfg.latency(2); % get spikes in trial

    % automatically determine an 'optimal' binwidth
    N              = sum(spikesInWin);
    if strcmp(cfg.binsize,'scott')
      sd           = nanstd(spike.time{unitIndx}(spikesInWin));
      h(iUnit)     = 3.49*sd./(N^(1/3));
    elseif strcmp(cfg.binsize,'sqrt')
      k            = ceil(sqrt(N));
      h(iUnit)     = (cfg.latency(2)-cfg.latency(1))/k;
    else
      error('unsupported option for cfg.binsize');
    end
  end
  cfg.binsize = nanmean(h);
end

% do some error checking on the binsize
if cfg.binsize<=0 || cfg.binsize>(cfg.latency(2)-cfg.latency(1))
  error('cfg.binsize should be greater than zero and not exceed the trialduration');
end

% end of trial should be late enough, beginning should be early enough
fullDur       = trialDur>=cfg.binsize; % trials which have full duration
overlaps      = endTrialLatency>=(cfg.latency(1)+cfg.binsize) & begTrialLatency<=(cfg.latency(2)-cfg.binsize);
if strcmp(cfg.vartriallen,'no') % only select trials that fully cover our latency window
  startsLater    = single(begTrialLatency) > (single(cfg.latency(1)) + 0.0001); % last factor just for rounding errors
  endsEarlier    = single(endTrialLatency) < (single(cfg.latency(2)) - 0.0001);
  hasWindow      = ~(startsLater | endsEarlier); % it should not start later or end earlier
else
  hasWindow     = ones(1,length(cfg.trials));
end
trialSel        = fullDur(:) & overlaps(:) & hasWindow(:);
cfg.trials      = cfg.trials(trialSel); % note that endTrialLatency was of length cfg.trials
if isempty(cfg.trials), warning('No trials were selected after latency selection'); end
nTrials         = length(cfg.trials);
begTrialLatency = begTrialLatency(trialSel); % note that begTrialLatency was of length cfg.trials here
endTrialLatency = endTrialLatency(trialSel);

% create the bins, we start arbitrarily at cfg.latency(1)
bins  = cfg.latency(1) : cfg.binsize : cfg.latency(end);
nBins = length(bins);

% preallocate before computing the psth, otherwise, compute stuff 'on the run'
if strcmp(cfg.keeptrials,'yes'), singleTrials = NaN(nTrials,nUnits,nBins-1); end
[s,ss]   = deal(zeros(nUnits, nBins-1)); %sum, and sum of squared in the loop, to get mean & var

% preallocate and compute degrees of freedom
allStartEarlier =  all(begTrialLatency<=cfg.latency(1));
allEndLater     =  all(endTrialLatency>=cfg.latency(2));
if  ~ (allStartEarlier && allEndLater),
  dof = zeros(1,nBins-1);
else
  dof = ones(1,nBins-1)*nTrials; % if all exceed latency, then this is dof
end

for iTrial = 1:nTrials
  origTrial = cfg.trials(iTrial);
  if  ~ (allStartEarlier && allEndLater) % select bins and count dof + 1
    binSel = begTrialLatency(iTrial)<=bins(1:end-1) & endTrialLatency(iTrial)>=bins(2:end);
    dof(binSel)      = dof(binSel) + 1;
  else
    binSel           = 1:(nBins-1); % always deselect the last bin
  end

  for iUnit = 1:nUnits
    unitIndx      = spikesel(iUnit); % select the unit
    spikesInTrial = (spike.trial{unitIndx}==origTrial); % get spikes in trial
    spikeTimes    = spike.time{unitIndx}(spikesInTrial);

    % compute the psth
    trialPsth   = histc(spikeTimes(:), bins); % we deselect the last bin per default
    trialPsth   = trialPsth(:)'; % force into row vec
    if isempty(trialPsth), trialPsth = zeros(1,length(bins)); end

    % convert to firing rates if requested, with spikecount do nothing
    if strcmp(cfg.outputunit,'rate'),
      trialPsth = trialPsth/cfg.binsize;
    elseif strcmp(cfg.outputunit,'proportion'),
      trialPsth = trialPsth./nansum(trialPsth);
    end

    % compute the sum and the sum of squares for the var and the mean on the fly
    s(iUnit,binSel)  = s(iUnit,binSel)   + trialPsth(binSel); % last bin is single value
    ss(iUnit,binSel) = ss(iUnit,binSel)  + trialPsth(binSel).^2;

    if strcmp(cfg.keeptrials,'yes'),
      singleTrials(iTrial,iUnit,binSel) = trialPsth(binSel);
    end
  end
end

% get the results
dof            = dof(ones(nUnits,1),:);
psth.avg       = s ./ dof;
psth.var       = (ss - s.^2./dof)./(dof-1); % since sumPsth.^2 ./ dof = dof .* (sumPsth/dof).^2
psth.dof       = dof; % combined with psth.var we can get SEM
psth.fsample   = 1/(cfg.binsize);   % might be more compatible with feeding psth in other funcs
psth.time      = bins(1:end-1) + 0.5*cfg.binsize;
psth.label     = spike.label(spikesel);
if (strcmp(cfg.keeptrials,'yes'))
  psth.trial  = singleTrials;
  psth.dimord = 'rpt_chan_time';
else
  psth.dimord = 'chan_time';
end
if isfield(spike,'sampleinfo'), psth.sampleinfo = spike.sampleinfo(cfg.trials,:); end
if isfield(spike,'trialinfo'),  psth.trialinfo  = spike.trialinfo(cfg.trials,:);  end

% do the general cleanup and bookkeeping at the end of the function

ft_postamble previous   spike
ft_postamble provenance psth
ft_postamble history    psth

%%%%%%%%% SUB FUNCTIONS %%%%%%%%%
function [cfg] = latencyselection(cfg,begTrialLatency,endTrialLatency)

if strcmp(cfg.latency,'minperiod')
  cfg.latency = [max(begTrialLatency) min(endTrialLatency)];
elseif strcmp(cfg.latency,'maxperiod')
  cfg.latency = [min(begTrialLatency) max(endTrialLatency)];
elseif strcmp(cfg.latency,'prestim')
  cfg.latency = [min(begTrialLatency) 0];
elseif strcmp(cfg.latency,'poststim')
  cfg.latency = [0 max(endTrialLatency)];
end
% check whether the time window fits with the data
if (cfg.latency(1) < min(begTrialLatency)), cfg.latency(1) = min(begTrialLatency);
  warning('Correcting begin latency because it is before all trial beginnings');
end
if (cfg.latency(2) > max(endTrialLatency)), cfg.latency(2) = max(endTrialLatency);
  warning('Correcting end latency because it is after all trial ends');
end

function [cfg] = trialselection(cfg,spike)

nTrials = size(spike.trialtime,1);
if  strcmp(cfg.trials,'all')
  cfg.trials = 1:nTrials;
elseif islogical(cfg.trials) || all(cfg.trials==0 | cfg.trials==1)
  cfg.trials = find(cfg.trials);
end
cfg.trials = sort(cfg.trials(:));
if max(cfg.trials)>nTrials,
  error('maximum trial number in cfg.trials should not exceed number of rows of spike.trialtime');
end
if isempty(cfg.trials), error('No trials were selected by you, rien ne va plus'); end


function model = lleReconstruct(lleInfo, y)

% LLERECONSTRUCT Reconstruct an LLE form component parts.
% FORMAT
% DESC takes component parts of an LLE model and reconstructs the
% LLE model. The component parts are normally retrieved from a
% saved file.
% ARG lleInfo : the active set and other information stored in a structure.
% ARG y : the output target training data for the LLE.
% RETURN model : an LLE model structure that combines the component
% parts.
%
% SEEALSO : lleDeconstruct, lleCreate
%
% COPYRIGHT : Neil D. Lawrence, 2009

% MLTOOLS

  model = lleInfo;
  model.Y = y;

end


% global parameters (modified based on the original MDP code)
function opt = globals()

opt.root = pwd;

% path for MOT benchmark
mot_paths = {'data/', ''};
for i = 1:numel(mot_paths)
    if exist(mot_paths{i}, 'dir')
        opt.mot = mot_paths{i};
        break;
    end
end

opt.mot2d = 'MOT16';
opt.results_dir = 'results/';
opt.mot2d_train_seqs = {'MOT16-02', 'MOT16-04', 'MOT16-05', 'MOT16-09', 'MOT16-10', 'MOT16-11', 'MOT16-13'};
opt.mot2d_train_nums = [600, 1050, 837, 525, 654, 900, 750];
opt.mot2d_test_seqs = {'MOT16-01', 'MOT16-03', 'MOT16-06', 'MOT16-07', 'MOT16-08', 'MOT16-12', 'MOT16-14'};
opt.mot2d_test_nums = [450, 1500, 1194, 500, 625, 900, 750];

addpath(fullfile(opt.root, 'devkit', 'utils'));
addpath([opt.root '/3rd_party/libsvm-3.20/matlab']);
addpath([opt.root '/3rd_party/Hungarian']);

% tracking parameters
opt.aspect_ratio_thre = 0.6;    % aspect ratio threshold in target association
opt.distance_thre = 2;        % distance threshold in target association, multiple of the width of target
opt.det_overlap_thre = 0.5;        % overlap with detection
opt.tracking_score_thre = 0.18;
opt.termination_thre = 2;
opt.association_score_thre = 0.6;
opt.exit_thre = 0.3;
opt.initialization_thre = 0.25;
opt.overlap_sup = 0.7;

% scene context
opt.backgrounds = cell(1,7);
opt.backgrounds{1} = [240, 570, 540, 760; 1, 1, 1920, 400]; % [x1, y1, x2, y2]
opt.backgrounds{2} = [1, 1, 155, 460; 1610, 670, 1710, 770; 700, 445, 760, 520; 1270, 210, 1360, 300; 1760, 900, 1830, 1040; 1455, 770, 1515, 890];
opt.backgrounds{7} = [1, 1, 1920, 450];
opt.h_max = cell(1,7);
opt.h_max{2} = 315;
opt.h_min = cell(1,7);
opt.fps = [30, 30, 14, 30, 30, 30, 25];

% tracking state: START -> ACTIVATED -> TRACKED -> LOST -> STOP
opt.STATE_START = 4;
opt.STATE_ACTIVATED = 2;
opt.STATE_TRACKED = 1;
opt.STATE_LOST = 3;
opt.STATE_STOP = 5;


function check_for_cd_arcs(onodes, cnodes, dag)
% CHECK_FOR_CD_ARCS Raise an error if there are any C->D links where the C node is hidden.
% check_for_cd_arcs(onodes, cnodes, dag)
%
% We cannot convert the logistic/softmax function (C->D CPD) to a Gaussian potential
% unless we use the variational approximation discussed in
% "A variational approximation for Bayesian networks with discrete and continuous latent
% variables", K. Murphy, UAI 1999.

n = length(dag);
hnodes = mysetdiff(1:n, onodes);
chid = myintersect(cnodes, hnodes);
dnodes = mysetdiff(1:n, cnodes);
for i=chid(:)'
  dcs = myintersect(children(dag, i), dnodes);
  if ~isempty(dcs)
    error(['hidden cts node ' num2str(i) ' has a discrete child']);
  end
end


function this = MrDataNd_split_epoch(this)
%Tests split_epoch by creating artificial trials for fmri_short example
%
%   Y = MrUnitTest()
%   run(Y, 'MrDataNd_split_epoch');
%
% This is a method of class MrUnitTest.
%
% IN
%
% OUT
%
% EXAMPLE
%   MrDataNd_split_epoch
%
%   See also MrUnitTest

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

doPlotRoi = 0;
doPlotTrialsActiveVoxel = true; % plot active voxel for all events

%% Load short fMRI example
pathExample = tapas_uniqc_get_path('examples');
%pathExample = fullfile(pathExample, 'nifti', 'rest');
%fileExample = fullfile(pathExample, 'fmri_short.nii');
pathExample = fullfile(pathExample, 'nifti', 'paradigm_visual');
fileExample = fullfile(pathExample, 'fmri.nii.gz');
fileBehav = fullfile(pathExample, 'behav.mat');
x = MrImage(fileExample);

TR = 3; % s

% update erroneous TR
x.dimInfo.set_dims('t', 'resolutions', TR, 'samplingWidths', TR, ...
    'firstSamplingPoint', 0);

%% Create mask for time series evaluation; central voxel in all slices

nSamplesXY = x.dimInfo.nSamples({'x', 'y'});

M = x.select('t',1);

%iActiveVoxelXY = round([nSamplesXY/2, nSamplesXY/2]);
idxActiveVoxel = [67 109 7]; % visual voxel
M.data(:) = 0;

% spherical ROI around active voxel
M.data(idxActiveVoxel(1), idxActiveVoxel(2), idxActiveVoxel(3)) = 1;
M = M.imdilate(strel('sphere', 5), '3D');

%% Split into epochs
% alternative [onsets, durations, names] = ...
%        get_multiple_conditions_visual('bevav.log')
% and use onsets{1} and durations{1} for the 10 blocks
load(fileBehav);
onsetTimes = relativeTimeBlockStartSeconds(1:4:end); % first blocks of same kind

newPeriStimulusOnsets = 10; % number of bins, if single number, duration of stimulation block: 14.925 s

y = x.split_epoch(onsetTimes, newPeriStimulusOnsets);

%% Plot all PST time courses from active voxel
if doPlotTrialsActiveVoxel
    stringTitle = sprintf('All trials from active voxel [%d %d %d]', ...
        idxActiveVoxel(1), idxActiveVoxel(2), idxActiveVoxel(3));
    figure('Name', stringTitle);
    ally = squeeze(y.data(idxActiveVoxel(1),idxActiveVoxel(2),idxActiveVoxel(3),:,:));
    plot(y.dimInfo.samplingPoints{4}, ally);
    hold all;
    meany = mean(ally,2);
    stdy = std(ally,0,2);
    plot(y.dimInfo.samplingPoints{4}, meany, 'g-', 'LineWidth',4)
    plot(y.dimInfo.samplingPoints{4}, meany-stdy,'k:', 'LineWidth',2)
    plot(y.dimInfo.samplingPoints{4}, meany+stdy,'k:', 'LineWidth',2)
    title(stringTitle);
end

%% evaluate time series: extract roi from both raw and epoched data
x.extract_rois(M);
x.compute_roi_stats();

y.extract_rois(M);
y.compute_roi_stats();

% plot with corresponding time vector
if doPlotRoi
    x.rois{1}.plot()
    y.rois{1}.plot()
end

%% Actual unit test

expSolution = 0;
actSolution.data = 0;

absTol = 10e-7;

%% verify equality of expected and actual solution
% import matlab.unittests to apply tolerances for objects
this.verifyEqual(actSolution.data, expSolution, 'absTol', absTol);


function WriteLDRStack(stack, name, format)
%
%       WriteLDRStack(dir_name, format)
%
%       This function writes an LDR stack into a set of LDR images
%
%        Input:
%           -stack: the stack to be written
%           -name: the folder name where the stack is stored.
%           -format: an LDR format for reading LDR images.
%
%        Output:
%           -exposure: a stack of exposure values from images in dir_name
%
%     Copyright (C) 2019  Francesco Banterle
%
%     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/>.
%

n = size(stack, 4);

for i=1:n
    imwrite(stack(:,:,:,i), [name, '_', num2str(100000 + i), '.', format]);
end

end


function makefigure(y, ThreeDee, PlotOrClose)
% Copyright (c) 2009, The MathWorks, Inc.
%
% Creates / updates /closes a MATLAB figure
persistent figureHandle;

if ishandle(figureHandle)
    % If figure exists, use it
    figure(figureHandle);
    if (nargin > 2)&&(PlotOrClose < -eps)
        % close the figure if needed
        close(figureHandle);
        return;
    end;
else
    % If figure doesn't exist and plotting is required, create it.
    if (nargin > 2)&&(PlotOrClose > eps)
        figureHandle = figure;
    else
        return;
    end;
end;

% Clear the figure and plot in 2D or 3D
clf;
if ThreeDee
    surf(y);
else
    plot(y);
end;


% dipfit_nonlinear() - perform nonlinear dipole fit on one of the components
%                   to improve the initial dipole model. Only selected dipoles
%                   will be fitted.
%
% Usage:
%  >> EEGOUT = dipfit_nonlinear( EEGIN, optarg)
%
% Inputs:
%    ...
%
% Optional inputs are specified in key/value pairs and can be:
%    ...
%
% Output:
%    ...
%
% Author: Robert Oostenveld, SMI/FCDC, Nijmegen 2003
%         Thanks to Nicolas Robitaille for his help on the CTF MEG
%         implementation

% SMI, University Aalborg, Denmark http://www.smi.auc.dk/
% FC Donders Centre, University Nijmegen, the Netherlands http://www.fcdonders.kun.nl

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [EEGOUT] = dipfit_nonlinear( EEG, varargin )
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% convert the optional arguments into a configuration structure that can be
% understood by FIELDTRIPs dipolefitting function
if nargin>2
  cfg = struct(varargin{:});
else
  help dipfit_nonlinear
  return
end

% specify the FieldTrip DIPOLEFITTING configuration
cfg.model      = 'moving';
cfg.gridsearch = 'no';
if ~isfield(cfg, 'nonlinear')
  % if this flag is set to 'no', only the dipole moment will be fitted
  cfg.nonlinear  = 'yes';
end
% add some additional settings from EEGLAB to the configuration
tmpchanlocs    = EEG.chanlocs;
cfg.channel    = { tmpchanlocs(EEG.dipfit.chansel).labels };
if isfield(EEG.dipfit, 'vol')
    cfg.vol        = EEG.dipfit.vol;
elseif isfield(EEG.dipfit, 'hdmfile')
    cfg.hdmfile    = EEG.dipfit.hdmfile;
else
    error('no head model in EEG.dipfit')
end

if isfield(EEG.dipfit, 'elecfile') & ~isempty(EEG.dipfit.elecfile)
    cfg.elecfile = EEG.dipfit.elecfile;
end
if isfield(EEG.dipfit, 'gradfile') & ~isempty(EEG.dipfit.gradfile)
    cfg.gradfile = EEG.dipfit.gradfile;
end

% set up the initial dipole model based on the one in the EEG structure
cfg.dip.pos = EEG.dipfit.model(cfg.component).posxyz;
cfg.dip.mom = EEG.dipfit.model(cfg.component).momxyz';
cfg.dip.mom = cfg.dip.mom(:);

% convert the EEGLAB data structure into a structure that looks as if it
% was computed using FIELDTRIPs componentanalysis function
comp = eeglab2fieldtrip(EEG, 'componentanalysis', 'dipfit');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  Added code to handle CTF data with multipleSphere head model           %
%  This code is copy-pasted in dipfit_gridSearch, dipfit_nonlinear        %
%  The flag .isMultiSphere is used by dipplot                             %
%  Nicolas Robitaille, January 2007.                                      %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%Do some trick to force fieldtrip to use the multiple sphere model
if strcmpi(EEG.dipfit.coordformat, 'CTF')
   cfg = rmfield(cfg, 'channel');
   comp = rmfield(comp, 'elec');
   cfg.gradfile = EEG.dipfit.chanfile;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% END                                                                     %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% fit the dipoles to the ICA component(s) of interest using FIELDTRIPs
% dipolefitting function

currentPath = pwd;
ptmp = which('ft_prepare_vol_sens');
ptmp = fileparts(ptmp);
if isempty(ptmp), error('Path to "forward" folder of Fieldtrip missing'); end;
cd(fullfile(ptmp, 'private'));
try,
    if exist('hlp_microcache','file')
        source = hlp_microcache('dipfit',@ft_dipolefitting,cfg, comp);
    else
        source = ft_dipolefitting(cfg, comp);
    end
catch,
    cd(currentPath);
    lasterr
    error(lasterr);
end;
cd(currentPath);

% reformat the output dipole sources into EEGLABs data structure
EEG.dipfit.model(cfg.component).posxyz  = source.dip.pos;
EEG.dipfit.model(cfg.component).momxyz  = reshape(source.dip.mom, 3, length(source.dip.mom)/3)';
EEG.dipfit.model(cfg.component).diffmap = source.Vmodel - source.Vdata;
EEG.dipfit.model(cfg.component).sourcepot = source.Vmodel;
EEG.dipfit.model(cfg.component).datapot   = source.Vdata;
EEG.dipfit.model(cfg.component).rv        = source.dip.rv;
%EEG.dipfit.model(cfg.component).rv = sum((source.Vdata - source.Vmodel).^2) / sum( source.Vdata.^2 );

EEGOUT = EEG;


% Init Script
% Remarks:
%   1.  sa
% TODO:
% 	1.  ds
% Release Notes
% - 1.0.000     08/11/2016  Royi Avital
%   *   First release.
%

%% General Parameters
close('all');
clear();
clc();

% set(0, 'DefaultFigureWindowStyle', 'docked');
% defaultLoosInset = get(0, 'DefaultAxesLooseInset');
% set(0, 'DefaultAxesLooseInset', [0.05, 0.05, 0.05, 0.05]);

figPosSmall     = [100, 100, 400, 300];
figPosMedium    = [100, 100, 800, 600];
figPosLarge     = [100, 100, 960, 720];
figPosDefault   = [100, 100, 560, 420];

fontSizeTitle   = 14;
fontSizeAxis    = 12;
fontSizeString  = 12;

lineWidthThin   = 1;
lineWidthNormal = 3;
lineWidthThick  = 4;

markerSizeSmall     = 4;
markerSizeNormal    = 8;
markerSizeLarge     = 10;

% https://www.mathworks.com/help/matlab/graphics_transition/why-are-plot-lines-different-colors.html
% https://www.mathworks.com/matlabcentral/answers/160332
mColorOrder = get(groot, 'DefaultAxesColorOrder');

randomNumberStream  = RandStream('mlfg6331_64', 'NormalTransform', 'Ziggurat');
subStreamNumber     = round(sum(clock()));
subStreamNumber     = 1620;
set(randomNumberStream, 'Substream', subStreamNumber);
RandStream.setGlobalStream(randomNumberStream);

FALSE   = 0;
TRUE    = 1;

OFF     = 0;
ON      = 1;


function stats = log_iterates(problem, x, stats)
% function stats = log_iterates(problem, x, stats)
%
% This small helper function is used to log the sequence of iterates
% generated by the Riemannian Staircase

stats.Yvals = x';

end


function cobj2 = subset(cobj, varargin)
    %CATALOG.SUBSET Create a new catalogObject by subsetting based
    %on indices.
    % Usage:
    %   cobj.subset('indices', [])
    % or:
    %   cobj.subset('start_time', [], 'end_time', [])
    % can also just give one of start_time or end_time

    %if nargin>0
        % Parse required, optional and param-value pair arguments,
        % set default values, and add validation conditions
        p = inputParser;
        p.addParameter('start_time', [], @isnumeric) % positional
        p.addParameter('end_time', [], @isnumeric)
        p.addParameter('indices', [], @isnumeric)
        p.parse(varargin{:});
        fields = fieldnames(p.Results);
        for i=1:length(fields)
            field=fields{i};
            val = p.Results.(field);
            eval(sprintf('%s = val;',field));
        end
    %end

%     datestr(min(cobj.otime))
%     datestr(max(cobj.otime))
%     datestr(start_time)
%     datestr(end_time)

    if isempty(indices)
        i1 = 1:numel(cobj.otime);
        if start_time
            i1 = find(cobj.otime >= start_time);
            debug.print_debug(1,sprintf('Found %d events after %s',numel(i1), datestr(start_time)));
        end
        i2 = 1:numel(cobj.otime);
        if end_time
            i2 = find(cobj.otime <= end_time);
            debug.print_debug(1,sprintf('Found %d events before %s',numel(i1), datestr(end_time)));
        end
        indices = intersect(i1, i2);
    end

    cobj2 = cobj;
    N = numel(cobj.otime);
    debug.print_debug(1,sprintf('Subsetting from %d events to %d events',N, numel(indices)));
    cobj2.otime = cobj.otime(indices);
    if numel(cobj.lon)==N
        cobj2.lon = cobj.lon(indices);
    end
    if numel(cobj.lat)==N
        cobj2.lat = cobj.lat(indices);
    end
    if numel(cobj.depth)==N
        cobj2.depth = cobj.depth(indices);
    end
    if numel(cobj.mag)==N
        cobj2.mag = cobj.mag(indices);
    end
    if numel(cobj.magtype)==N
        dummy=[];
%         try % there is a limit on subsetting cell array
%         cobj2.magtype = cobj.magtype{indices};
%         end
        for c=1:numel(indices)
            dummy{c} = cobj.magtype{indices(c)};
        end
        cobj2.magtype = dummy;
        clear dummy
    end
    if numel(cobj.etype)==N
        dummy=[];
        for c=1:numel(indices)
            dummy{c} = cobj.etype{indices(c)};
        end
        cobj2.etype = dummy;
        clear dummy;
    end
    if numel(cobj.arrivals)==N
        cobj2.arrivals = cobj.arrivals(indices);
    end
    if numel(cobj.waveforms)==N
        cobj2.waveforms = cobj.waveforms(indices);
%         counter = 1;
%         indices
%         for thisindex=indices
%             cobj2.waveforms{counter} = cobj.waveforms{thisindex};
%             counter = counter + 1;
%         end
    end
    if numel(cobj.ontime)==N
        cobj2.ontime = cobj.ontime(indices);
    end
    if numel(cobj.offtime)==N
        cobj2.offtime = cobj.offtime(indices);
    end

    %% Added by Glenn Thompson 2018-05-01 to add a request start & end time
    if isempty(start_time)
        cobj2.request.start_time = min(cobj2.otime);
    else
        cobj2.request.start_time = start_time;
    end
    if isempty(end_time)
        cobj2.request.end_time = max(cobj2.otime);
    else
        cobj2.request.end_time = end_time;
    end

end


function plotacq(chan)
%PLOTACQ Plots a channel structure generated from loadacq
%  (c) 2003 Mihai Moldovan
%   M.Moldovan@mfi.ku.dk

fig_hndl=figure(...
            'Units','normalized',...
             'Color',get(0,'defaultUicontrolBackgroundColor'),...
            'Name','Acqknowledge import',...
            'NumberTitle','off',...
            'Resize','on',...
            'WindowStyle','normal',...
            'PaperUnits','normalized',...
            'PaperOrientation','Landscape',...
            'PaperPositionMode','manual',...
            'PaperPosition',[0 0 1 1],...
            'PaperType','A4');

% --------------------------------------------------------------------
% plot all channels
% --------------------------------------------------------------------

n=length(chan);

for i=1:n
    ax_hndl=subplot(n,1,i);
    set(ax_hndl,'FontUnits','points','FontName','Arial','FontSize',7,'NextPlot','add','LineWidth',1);

    y=chan(i).data;
    x=(1:length(y));
    x=x.*chan(i).ms/1000;
    plot (x,y,'Color',chan(i).color);

    t=ylabel([chan(i).name ' (' chan(i).units ')']);
    set (t,'Rotation',0,'HorizontalAlignment','right','FontWeight','bold');

    if i~=n
        set(ax_hndl,'XTickLabel',{})
    else
        xlabel ('Time (seconds)')
    end

    mk=chan(i).mdata;
    for j=1:length(mk)
        x=mk(j).*chan(i).ms/1000;
        plot ([x x],ylim,'k--')
    end
end

% --------------------------------------------------------------------
% save the metafile
% --------------------------------------------------------------------

   [ST,I] = dbstack;
   n=length(ST);

   mfile=ST(n).name;

   [file_path mname emxt mversn] = fileparts(mfile);
   meta=[file_path filesep mname '.emf'];

   %print -dwinc for color
   print ( '-dmeta', meta);

%return
%-----------------------------------------------


function varargout=sort(varargin)
%SORT (overloaded)
%
% [t,loc] = sort(x)
%
% The variable t will be the sorted version of x.
%
% SORT is implemented in the nonlinear operator framework using a big-M
% model.

switch class(varargin{1})

    case 'double'
        error('Overloaded SDPVAR/SORT CALLED WITH DOUBLE. Report error')

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

        if 0
            error('')
        end

        y = [];

        update = varargin{1};
        for j = 1:length(update)
           y = [y;yalmip('define',mfilename,varargin{:},j)];
        end
        varargout{1} = y;

    case 'char' % YALMIP send 'graph' when it wants the epigraph or hypograph
        switch varargin{1}
            case {'milp','graph'}
                % Description using epigraphs
                t = varargin{2};
                X = varargin{3};

                % Call external to allow subsrefs in classs
                [F,vars] = pwadynamics_internal(t,varargin{3:end-1});

                varargout{1} = F;
                varargout{2} = struct('convexity','milp','monotonicity','milp','definiteness','milp');
                varargout{3} = X;

                % Inofficial way to model several nonlinear variables in
                % one call
                varargout{2}.models = vars;

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


% --------------------------------------------------------------------------
function per_frame_annotation(root, folder_index)
% Read per-frame XML annotations and write bbox and track info on txt files
% Argument is folder_index [0-4]
% e.g. per_frame_annotations('/path/to/ILSVRC2015/', 0)
% --------------------------------------------------------------------------

    addpath(genpath('../..'));
    i = folder_index + 3;

    CLASS_IDS = {'n02691156','n02419796','n02131653','n02834778','n01503061','n02924116','n02958343','n02402425','n02084071','n02121808', ...
                     'n02503517','n02118333','n02510455','n02342885','n02374451','n02129165','n01674464','n02484322','n03790512','n02324045', ...
                     'n02509815','n02411705','n01726692','n02355227','n02129604','n04468005','n01662784','n04530566','n02062744','n02391049'};

%     CLASS_NAMES = {'airplane','antelope','bear','bicycle','bird','bus','car','cattle','dog','domestic_cat', ...
%                    'elephant','fox','giant_panda','hamster','horse','lion', 'lizard','monkey','motorcycle','rabbit', ...
%                    'red_panda','sheep','snake','squirrel','tiger','train','turtle','watercraft','whale','zebra'};

    OLD_FOLDERS = {'ILSVRC2015_VID_train_0000','ILSVRC2015_VID_train_0001','ILSVRC2015_VID_train_0002','ILSVRC2015_VID_train_0003','val'};
    NEW_FOLDERS = {'a','b','c','d','e'};

    root_anno = [root 'Annotations/VID/train'];
    root_imgs = [root 'Data/VID/train'];
    slash = '/';

    dir_root_anno = dir(root_anno);
    dir_root_anno = {dir_root_anno.name};
    % we always start from 3 because at 1 we have '.' and at 2 '..'
    level1 = [root_anno slash dir_root_anno{i}];
    dir_level1 = dir(level1);
    dir_level1 = {dir_level1.name};
    % j iterates across videos
    for j=3:numel(dir_level1)
        level2 = [root_anno slash dir_root_anno{i} slash dir_level1{j}];
        dir_level2 = dir(level2);
        dir_level2 = {dir_level2.name};
        xml_path = [root_anno slash dir_root_anno{i} slash dir_level1{j} slash dir_level2{3}];
        struct_from_xml = xml2struct_custom(xml_path);
        % get frame size from first frame of the video
        frame_sz = [str2double(struct_from_xml.annotation.size.height.Text), str2double(struct_from_xml.annotation.size.width.Text)];

        % k iterates across frames
        for k=3:numel(dir_level2)
            fprintf('Processing i: %d j: %d k: %d\n', i-3, j-3, k-3);
            xml_path = [root_anno slash dir_root_anno{i} slash dir_level1{j} slash dir_level2{k}];
            struct_from_xml = xml2struct_custom(xml_path);
            dir_level2_img = strrep(dir_level2{k}, '.xml', '.JPEG');
            im_path = [root_imgs slash dir_root_anno{i} slash dir_level1{j} slash dir_level2_img];
            im_anno_path = strrep(im_path, '.JPEG', '.txt');
            fid = fopen(im_anno_path,'w');
            % check if the frame contains objects at all
            if isfield(struct_from_xml.annotation, 'object')
                n_objects = numel(struct_from_xml.annotation.object);
                % k iterates across objects
                for o=1:n_objects
                    if n_objects==1
                        o_class = struct_from_xml.annotation.object(o).name.Text;
                        o_xmax = str2double(struct_from_xml.annotation.object(o).bndbox.xmax.Text);
                        o_xmin = str2double(struct_from_xml.annotation.object(o).bndbox.xmin.Text);
                        o_ymax = str2double(struct_from_xml.annotation.object(o).bndbox.ymax.Text);
                        o_ymin = str2double(struct_from_xml.annotation.object(o).bndbox.ymin.Text);
                        trackid = str2double(struct_from_xml.annotation.object(o).trackid.Text);
                    else
                        o_class = struct_from_xml.annotation.object{o}.name.Text;
                        o_xmax = str2double(struct_from_xml.annotation.object{o}.bndbox.xmax.Text);
                        o_xmin = str2double(struct_from_xml.annotation.object{o}.bndbox.xmin.Text);
                        o_ymax = str2double(struct_from_xml.annotation.object{o}.bndbox.ymax.Text);
                        o_ymin = str2double(struct_from_xml.annotation.object{o}.bndbox.ymin.Text);
                        trackid = str2double(struct_from_xml.annotation.object{o}.trackid.Text);
                    end
                    % convert ImageNet WNID of the class to integer [1-30]
                    [~, o_class] = ismember(o_class, CLASS_IDS);
                    o_sz = [o_ymax - o_ymin + 1 , o_xmax - o_xmin + 1];

                    fprintf(fid, '%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%s\n', ...
                        i, j, k, o, trackid, o_class, ...
                        frame_sz(2), frame_sz(1),  ...
                        o_xmin, o_ymin, o_sz(2), o_sz(1), im_path);
                end
            else
                    fprintf(fid, '%d,%d,%d,%d,%d,%s\n', ...
                        i, j, k, ...
                        frame_sz(2), frame_sz(1), im_path);
            end
            fclose(fid);
        end
    end
end


function test_pull433

% MEM 2gb
% WALLTIME 00:20:00
% DEPENDENCY

cd(dccnpath('/home/common/matlab/fieldtrip/data/test/pull433'));
load('SubjectUCI29_elec_tal_f.mat', 'elec_tal_f');
load('SubjectUCI29_hull_lh.mat', 'mesh');

% keepchannel
elec_tal_fr = elec_tal_f;
grids = {'LPG*', 'LTG*'};
for g = 1:numel(grids)
  cfg             = [];
  cfg.channel     = grids{g};
  cfg.keepchannel = 'yes';            % <-
  cfg.elec        = elec_tal_fr;
  cfg.method      = 'headshape';
  cfg.headshape   = mesh;
  cfg.warp        = 'dykstra2012';
  elec_tal_fr = ft_electroderealign(cfg);
end
assert(isequal(numel(elec_tal_fr.label), 152)); % realigned + unused is 152 elecs

% do not keepchannel
elec_tal_fr = elec_tal_f;
grids = {'LPG*'};
cfg             = [];
cfg.channel     = grids{1};
cfg.keepchannel = 'no';             % <-
cfg.elec        = elec_tal_fr;
cfg.method      = 'headshape';
cfg.headshape   = mesh;
cfg.warp        = 'dykstra2012';
elec_tal_fr = ft_electroderealign(cfg);
assert(isequal(numel(elec_tal_fr.label), 64)); % realigned LPG has 64 elecs


function ebsd = subGrid(ebsd,ind)
% indexing of EBSD data
%
% Syntax
%   subGrid(ebsd,ind)
%

id = ebsd.id(ind);

% determine bounding rectangle
if islogical(ind)
  yMin = find(any(ind,2),1,"first");
  yMax = find(any(ind,2),1,"last");
  xMin = find(any(ind,1),1,"first");
  xMax = find(any(ind,1),1,"last");
else
  [x,y] = ind2sub(ebsd,ind);
  yMin = min(y(:));
  yMax = max(y(:));
  xMin = min(x(:));
  xMax = max(x(:));
end

mask = false(size(ebsd));
mask(yMin:yMax,xMin:xMax) = true;

ebsd = subSet(ebsd,mask,'keepGrid');
ebsd = reshape(ebsd,yMax-yMin+1,xMax-xMin+1);

% fill with NaN
nanId = ~ismember(ebsd.id,id);
ebsd.phaseId(nanId) = NaN;
ebsd.rotations(nanId) = NaN;


function featureNamesNew=featureNamesNewFromOld(featureNamesOld, ...
                                                scoreFeaturesOld, ...
                                                scoreFeaturesNew)
% Figures out the feature names in the new feature lexicon, given the old
% feature names, the old scoreFeatures, and the new
% scoreFeatures.

% figure out which of the old were retained, which of the new are not
% present in the old
[kept,added]= ...
  setDifferencesScoreFeatures(scoreFeaturesOld,scoreFeaturesNew);

% Get a list of the deleted feature names
scoreFeatureNamesOld={scoreFeaturesOld(:).scorefilename};
scoreFeatureNamesDeleted=scoreFeatureNamesOld(~kept);

% Make a function that computes whether a feature name was kept
featureNameKept=@(featureName)(~ismember(featureName,scoreFeatureNamesDeleted));

% Get the feature names common to both old a new by filtering the old
% list
featureNamesCommon= ...
  cellFilter(featureNameKept,featureNamesOld);

% Get the score feature names that are truly novel
scoreBaseNameListNew={scoreFeaturesNew(:).scorefilename};
featureNamesAdded=scoreBaseNameListNew(added);

% Merge the common and added lists
featureNamesNew = ...
  [featureNamesCommon;featureNamesAdded];

end


function [xV, yV, segNum] = redoSection(hCERR)
%function [xV, yV, segNum] = redoSection(hCERR)
%'Snip' & Redo a section of the active contour.
%Directions:  click (Button 1) once where the redone section should begin,
%             then click again where the section should end.  After the section
%             is deleted, fill in from the first point to the second, with
%             Button 1 creating points and button 2 closing the contour.
%
%Called by contourControls.
%LM:  2 April 02, JOD.
%
% 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/>.

figure(hCERR)

%Get the start point:

hPlot = getActiveSegment;
segS = get(hPlot,'userdata');
xV = segS.GUI_xV;
yV = segS.GUI_yV;
segNum = segS.segNum;

hold on
[x, y, button]  = ginput(1);

if isempty(button)
  xV = [];
  yV = [];
  return
end

switch button  %Maybe more options in the future?

  case 1

    rV = ((x - xV).^2 + (y - yV).^2 ).^0.5;
    indV = find(rV == min(rV));
    ind_a = indV(1);

end

%Now get the ending point:
[x, y, button]  = ginput(1);

if isempty(button)
  xV = [];
  yV = [];
  return
end

switch button

  case 1 %get nearest point

    rV = ((x - xV).^2 + (y - yV).^2 ).^0.5;
    indV = find(rV == min(rV));
    ind_b = indV(1);

end

%reorganize xV and yV:
%ind_b becomes the first point, and ind_a becomes the last point.
%Also: snip the shortest path in terms of number of points.
len = length(xV);
if ind_b > ind_a
  %which path is smallest?
  path1 = ind_b - ind_a;
  path2 = ind_a + (len - ind_b);
  if path1 <= path2
    xV = [xV(ind_b:end),xV(1:ind_a)];
    yV = [yV(ind_b:end),yV(1:ind_a)];
  else
    xV = [xV(ind_a:ind_b)];
    yV = [yV(ind_a:ind_b)];
    xV = fliplr(xV);
    yV = fliplr(yV);
  end
else  %ind_a > ind_b
  %which path is smallest?
  path1 = ind_a - ind_b;
  path2 = ind_b + (len - ind_a);
  if path1 <= path2
    xV = [xV(ind_a:end),xV(1:ind_b)];
    yV = [yV(ind_a:end),yV(1:ind_b)];
    xV = fliplr(xV);
    yV = fliplr(yV);
  else
    xV = [xV(ind_b:ind_a)];
    yV = [yV(ind_b:ind_a)];
  end
end

%Plot remaining segment
delete(hPlot)
hPlot2 = plot(xV,yV,'rs-');  %plot closed contour
set(hPlot2,'markersize',4)

%Go into new segment mode:
xLast = xV(end);
yLast = yV(end);

finished = 0;
hLineV = [];
while ~finished
  [x, y, button] = ginput(1);
  if button == 3
    finished = 1;
  else
    xV = [xV, x];
    yV = [yV, y];
    h = plot([xLast, x],[yLast, y],'rs-');
    set(h,'markersize',4)
    hLineV = [hLineV, h];
    xLast = x;
    yLast = y;
  end

end

delete(hLineV)
delete(hPlot2)

x2V = [xV, xV(1)];
y2V = [yV, yV(1)];

hPlot = plot(x2V,y2V,'rs-');
set(hPlot,'markersize',4)

hold off

%segmentsS contains all the information about the plotted segments - it gets written into
%the userdata portion of any segment.

segS.active = 1;
segS.hPlot  = hPlot;
segS.GUI_xV = xV;
segS.GUI_yV = yV;

set(hPlot,'tag','newSegment')
set(hPlot,'userdata',segS)


function isWrite(I, fName)
	typ = whos('I');
	typ = typ.class;
	f = fopen(fName, 'w');
	getMatlabStr(typ);
	fwrite(f, [1, size(I,2), size(I,1), size(I, 3), getMatlabStr(typ)], 'uint32');
	I = permute(I, [3 2 1]);
	fwrite(f, I(:), typ);
	fclose(f);
end

function i = getMatlabStr(str)
	switch str
		case 'single', i = 0;
		case 'double', i = 1;
		case 'uint8', i = 2;
    	case 'int8', i = 3;
    	case 'uint16', i = 4;
    	case 'int16', i = 5;
    	case 'uint32', i = 6;
    	case 'int32', i = 7;
    	case 'uint64', i = 8;
    	case 'int64', i = 9;
	end
end