% PURPOSE  : Assign events to bins
%
% FORMAT   :
%
% EEG  = pop_binlister( EEG , parameters);
%
% INPUTS   :
%
% EEG           - input dataset
%
% The available parameters are as follows:
%
%     'BDF'         - name of the text file containing your bin descriptions (formulas).
%     'ImportEL'	  - (optional) name of the text file, to import, that contain the event information to process,
%                     according to ERPLAB format (see tutorial).
%
%     'ExportEL' 	  - (optional) name of the text file, to export, that will contain the upgraded event information,
%                     according to ERPLAB format (see tutorial).

%     'Resetflag'   - set (all) flags to zero before starting binlister process. 'on'=reset;  'off':keep as it is.
%
%     'Forbidden'	  - array of event codes (numeric). If any of these codes is among a set of codes successfully captured by a bin
%                     this "capture" will be disable.
%     'Ignore'      - array of event codes (numeric) to be ignored. Binlister will be blind to them.
%
%     'UpdateEEG'   - after binlister process you can move the upgraded event information to EEG.event field. 'on'=update, 'off'=keep as it is.
%     'Warning'     - 'on'- warn if EVENTLIST will be overwritten. 'off' - do not warn if EVENTLIST will be overwritten.
%     'SendEL2'     - once binlister ends its work, you can send a copy of the resulting EVENTLIST structure to:
%                    'Text'           - send to text file
%                    'EEG'            - send to EEG structure
%                    'EEG&Text'       - send to EEG & text file
%                    'Workspace'      - send to Matlab workspace,
%                    'Workspace&Text' - send to Workspace and text file,
%                    'Workspace&EEG'  - send to workspace and EEG,
%                    'All'- send to all of them.
%     'Report'      - 'on'= create report about binlister performance, 'off'= do not create a report.
%     'Saveas'      - (optional) open GUI for saving dataset. 'on'/'off'
%
%
%
% OUTPUTS  :
%
% EEG            - updated output dataset
%
% EXAMPLE  :
%
% EEG  = pop_binlister( EEG , 'BDF', '/Users/etfoo/Documents/MATLAB/Test_Data/binlister_demo_2.txt', 'ExportEL', ...
%                      '/Users/etfoo/Documents/MATLAB/Test_output.txt', 'Forbidden',  12, 'Ignore',  10, 'ImportEL',...
%                      '/Users/etfoo/Documents/MATLAB/Test.txt', 'Saveas','on', 'SendEL2', 'All', 'UpdateEEG', 'on', 'Warning', 'on');
%
%
% See also menuBinListGUI.m binlister.m
%
% *** This function is part of ERPLAB Toolbox ***
% Author: Javier Lopez-Calderon and Steven Luck
% Center for Mind and Brain
% University of California, Davis,
% Davis, CA
% 2009

%b8d3721ed219e65100184c6b95db209bb8d3721ed219e65100184c6b95db209b
%
% ERPLAB Toolbox
% Copyright ? 2007 The Regents of the University of California
% Created by Javier Lopez-Calderon and Steven Luck
% Center for Mind and Brain, University of California, Davis,
% javlopez@ucdavis.edu, sjluck@ucdavis.edu
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.

function [EEG, com] = pop_binlister_fast(EEG, varargin)
global ALLEEG
global CURRENTSET
com = '';
if nargin < 1
        help pop_binlister
        return
end
if isobject(EEG) % eegobj
        whenEEGisanObject % calls a script for showing an error window
        return
end
if nargin==1
        if iseegstruct(EEG) && length(EEG)>1
                msgboxText = 'Unfortunately, binlister does not work with multiple datasets';
                title      = 'ERPLAB: multiple inputs';
                errorfound(msgboxText, title);
                return
        end
        if isfield(EEG.event, 'type')
                if ~all(cellfun(@isnumeric, { EEG.event.type }))
                        msgboxText = ['Some or all of your events contain only a text-based event label, '...
                                'and not a numeric event code.  ERPLAB must have a numeric code '...
                                'for every event (a text label can also be present).  For labels such as "S14", '...
                                'you can automatically create an equivalent numeric event code (e.g., 14) by '...
                                'checking the box labeled "Create numeric equivalents of nonnumeric event codes '...
                                'when possible" when creating the EventList.\n\nFor labels that cannot be automatically '...
                                'converted (e.g., "RESP"), or for ambiguous cases (e.g., when you have both "S14" and '...
                                '"R14"), you can flexibly create numeric versions using the Advanced button at EVENTLIST GUI.'];
                        title      = 'ERPLAB: Warning';
                        errorfound(sprintf(msgboxText), title);
                        return
                end
        end
        def  = erpworkingmemory('pop_binlister');
        if isempty(def)
                def = {'' '' '' 0 [] [] 0 0 0 1 0};
        end
        try
                ERPX = evalin('base', 'ERP');
        catch
                ERPX = [];
        end

        %
        % Call a GUI
        %
        packarray = menuBinListGUI(EEG, ERPX, def);

        if isempty(packarray)
                disp('User selected Cancel')
                return
        end

        file1      = packarray{1};         % bin descriptor file
        file2      = packarray{2};         % external eventlist (read event list from)
        file3      = packarray{3};         % text file containing the updated EVENTLIST (Write resulting eventlist to)
        flagrst    = packarray{4};         % 1 means reset flags
        forbiddenCodeArray = packarray{5};
        ignoreCodeArray    = packarray{6};
        updevent   = packarray{7};
        option2do  = packarray{8};         % See  option2do below
        reportable = packarray{9};         % 1 means create a report about binlister work.
        iswarning  = packarray{10};        % 1 means create a report about binlister work.
        getfromerp = packarray{11};
        indexEL    = packarray{12};

        if isempty(file2) || strcmpi(file2,'no') || strcmpi(file2,'none')
                if getfromerp
                        if isempty(ERPX)
                                msgboxText =  'You do not have any loaded ERPset yet.';
                                title = 'ERPLAB: no data';
                                errorfound(msgboxText, title);
                                return
                        end
                        EEGaux = EEG;
                        EEG    = ERPX;
                end
                if isfield(EEG, 'EVENTLIST')
                        %if length(EEG.EVENTLIST)>1
                        %        prompt    = {'Enter  EVENLIST index:'};
                        %        dlg_title = 'Multiple EVENTLIST at EEG were detected';
                        %        num_lines = 1;
                        %        def       = {'1'};
                        %        answer    = inputvalue(prompt,dlg_title,num_lines,def);
                        %        if isempty(answer)
                        %                disp('User selected Cancel')
                        %                return
                        %        end
                        %        indexEL = str2num(answer{1});
                        %else
                        %        indexEL = 1;
                        %end

                        if isfield(EEG.EVENTLIST, 'eventinfo')
                                if isempty(EEG.EVENTLIST(indexEL).eventinfo)
                                        msgboxText = ['EVENTLIST.eventinfo structure is empty!\n'...
                                                'Use Create EVENTLIST before BINLISTER'];
                                        title = 'ERPLAB: Error';
                                        errorfound(sprintf(msgboxText), title);
                                        return
                                end
                        else
                                msgboxText =  ['EVENTLIST.eventinfo structure was not found!\n'...
                                        'Use Create EVENTLIST before BINLISTER'];
                                title = 'ERPLAB: Error';
                                errorfound(sprintf(msgboxText), title);
                                return
                        end
                else
                        msgboxText =  ['EVENTLIST structure was not found!\n'...
                                'Use Create EVENTLIST before BINLISTER'];
                        title = 'ERPLAB: Error';
                        errorfound(sprintf(msgboxText), title);
                        return
                end
                logfilename = 'no';
                logpathname = '';
                file2 = [logpathname logfilename];
                disp('For LOGFILE, user selected INTERNAL')
        end

        erpworkingmemory('pop_binlister', {file1, file2, file3, flagrst, forbiddenCodeArray, ignoreCodeArray,...
                updevent, option2do, reportable, iswarning, getfromerp, indexEL});

        if flagrst==1
                strflagrst = 'on';
        else
                strflagrst = 'off';
        end
        if updevent==1
                strupdevent = 'on';
        else
                strupdevent = 'off';
        end
        switch option2do
                case 0
                        msgboxText = 'Where should I send the update EVENTLIST???\n Pick an option.';
                        title = 'ERPLAB: Error';
                        errorfound(sprintf(msgboxText), title);
                        return
                case 1
                        stroption2do = 'Text';
                case 2
                        stroption2do = 'EEG';
                case 3
                        stroption2do = 'EEG&Text';
                case 4
                        stroption2do = 'Workspace';
                case 5
                        stroption2do = 'Workspace&Text';
                case 6
                        stroption2do = 'Workspace&EEG';
                case 7
                        stroption2do = 'All';
        end
        if reportable==1
                strreportable = 'on';
        else
                strreportable = 'off';
        end
        if iswarning==1
                striswarning = 'on';
        else
                striswarning = 'off';
        end
        if ~getfromerp
                EEG.setname = [EEG.setname '_bins']; %suggest a new name
        end

        %
        % Somersault
        %
        [EEG, com] = pop_binlister(EEG, 'BDF', file1, 'ImportEL', file2, 'ExportEL', file3, 'Resetflag', strflagrst, 'Forbidden', forbiddenCodeArray,...
                'Ignore', ignoreCodeArray, 'UpdateEEG', strupdevent, 'SendEL2', stroption2do,'Report', strreportable, 'Warning', striswarning,...
                'Saveas', 'on', 'IndexEL', indexEL, 'History', 'gui');
        if getfromerp
                EEG = EEGaux;
        end
        return
end

%
% Parsing inputs
%
p = inputParser;
p.FunctionName  = mfilename;
p.CaseSensitive = false;
p.addRequired('EEG');
% option(s)
p.addParamValue('BDF', '', @ischar);
p.addParamValue('ImportEL', 'none', @ischar);
p.addParamValue('ExportEL', 'none', @ischar);
p.addParamValue('Resetflag', 'off', @ischar);% 'on', 'off'
p.addParamValue('Forbidden', [], @isnumeric);
p.addParamValue('Ignore', [], @isnumeric);
p.addParamValue('UpdateEEG', 'off', @ischar);% 'on', 'off'
p.addParamValue('SendEL2', 'EEG', @ischar);  %
p.addParamValue('Report', 'off', @ischar);   % 'on', 'off'
p.addParamValue('Warning', 'off', @ischar);  % 'on', 'off'
p.addParamValue('Saveas', 'off', @ischar);   % 'on', 'off'
p.addParamValue('IndexEL', 1, @isnumeric);   % integer
p.addParamValue('Voutput', 'EEG', @ischar);  % 'EEG' (which contains EVENTLIST) or 'EVENTLIST' (EVENTLIST only)
p.addParamValue('History', 'script', @ischar); % history from scripting

p.parse(EEG, varargin{:});

if length(EEG)>1
        msgboxText =  'ERPLAB says: Unfortunately, this function does not work with multiple datasets';
        error(msgboxText);
end

file1      = p.Results.BDF;              % bin descriptor file
file2      = p.Results.ImportEL;         % external eventlist (read event list from)
file3      = p.Results.ExportEL;         % text file containing the updated EVENTLIST (Write resulting eventlist to)
indexEL    = p.Results.IndexEL;          % EVENTLIST's index (in case of multiple EVENTLISTs)
outputv    = p.Results.Voutput;          % 'EEG' (which contains EVENTLIST) or 'EVENTLIST' (EVENTLIST only)

if strcmpi(p.Results.Resetflag, 'on')
        flagrst = 1;
else
        flagrst = 0;
end
if strcmpi(p.Results.Warning, 'on')
        iswarning = 1;
else
        iswarning = 0;
end
switch p.Results.SendEL2
        case 'Text'
                option2do = 1;
        case 'EEG'
                option2do = 2;
        case 'EEG&Text'
                option2do = 3;
        case 'Workspace'
                option2do = 4;
        case 'Workspace&Text'
                option2do = 5;
        case 'Workspace&EEG'
                option2do = 6;
        case {'All', 'Workspace&EEG&Text', 'Workspace&Text&EEG', 'EEG&Text&Workspace', 'EEG&Workspace&Text', 'Text&Workspace&EEG', 'Text&EEG&Workspace'}
                option2do = 7;
        otherwise
                %option2do = 0;
                error('ERPLAB says: You must specify what to do with the updated EVENTLIST.')
end
if isempty(file2) || strcmpi(file2,'no') || strcmpi(file2,'none')
        if isfield(EEG, 'EVENTLIST')
                if isfield(EEG.EVENTLIST, 'eventinfo')
                        if isempty(EEG.EVENTLIST(indexEL).eventinfo)
                                msgboxText = ['ERPLAB says: EVENTLIST.eventinfo structure is empty!\n'...
                                        'Use Create EVENTLIST before BINLISTER'];
                                error(sprintf(msgboxText));
                        end
                else
                        msgboxText =  ['ERPLAB says: EVENTLIST.eventinfo structure was not found!\n'...
                                'Use Create EVENTLIST before BINLISTER'];
                        error(sprintf(msgboxText));
                end
        else
                msgboxText =  ['ERPLAB says: EVENTLIST structure was not found!\n'...
                        'Use Create EVENTLIST before BINLISTER'];
                error(sprintf(msgboxText));
        end
        if ~isempty(EEG.EVENTLIST(indexEL)) && iswarning==1
                binaux    = [EEG.EVENTLIST(indexEL).eventinfo.bini];
                binhunter = binaux(binaux>0); %8/19/2009

                if ~isempty(binhunter) && ismember_bc2(option2do, [2 3 6 7])
                        msgboxText =  ['This dataset already has assigned bins.\n'...;
                                'Would you like to overwrite these bins?'];
                        title = 'ERPLAB: WARNING';
                        button =askquest(sprintf(msgboxText), title);
                        if strcmpi(button,'no')
                                disp('User canceled')
                                return
                        end
                end
        end

        %
        % Check for alphanumeric event codes
        %
        codelist = {EEG.EVENTLIST(indexEL).eventinfo.code};
        if nnz(cellfun(@ischar, codelist))>0
                msgboxText = ['Your dataset still has alphanumeric/string codes.\n\n'...
                        'You may try either eliminating nonnumeric information (see Create EVENTLIST)\n'...
                        'or remapping your events (see Create EVENTLIST Advanced)'];
                %title = 'ERPLAB: BDF Parsing Error';
                %errorfound(sprintf(msgboxText), title);
                %return
                error(msgboxText);
        end
        % save original EVENTLIST
        %ELaux = EEG.EVENTLIST(indexEL); % store original EVENTLIST

        %
        %  Reset Flags?
        %
        if flagrst==1
                % reset artifact flags
                EEG = resetflag(EEG, 255, indexEL);
        elseif flagrst==2
                % reset user flags
                EEG = resetflag(EEG, 65280, indexEL);
        elseif flagrst==3
                % reset ALL flags
                EEG = resetflag(EEG, indexEL);
        end
end

forbiddenCodeArray = p.Results.Forbidden;
ignoreCodeArray    = p.Results.Ignore;

if strcmpi(p.Results.UpdateEEG, 'on')
        updevent = 1;
else
        updevent = 0;
end
if strcmpi(p.Results.Report, 'on')
        reportable = 1;
else
        reportable = 0;
end
if ismember_bc2({p.Results.Saveas}, {'on','yes'})
        issaveas    = 1;
else
        issaveas    = 0;
end
if strcmpi(outputv, 'EVENTLIST') || strcmpi(outputv, 'EL')
        Voutput = 1; % EVENTLIST
else
        Voutput = 0; % EEG
end
if strcmpi(p.Results.History,'implicit')
        shist = 3; % implicit
elseif strcmpi(p.Results.History,'script')
        shist = 2; % script
elseif strcmpi(p.Results.History,'gui')
        shist = 1; % gui
else
        shist = 0; % off
end

%
% subroutine
%
%
% Call (neo)binlister
%
if reportable % workaround for a faster binlister... 02/28/12 JLC
        [EEG, EVENTLIST, binofbins, isparsenum] = binlister(EEG, file1, file2, file3, forbiddenCodeArray, ignoreCodeArray, reportable);
else
        [EEG, EVENTLIST, binofbins, isparsenum] = neobinlister2_fast(EEG, file1, file2, file3, forbiddenCodeArray, ignoreCodeArray, 0);
end
if isparsenum==0
        % parsing was not approved
        msgboxText = ['Bin descriptor file contains errors!\n'...
                'For details, please read command window messages.'];
        title = 'ERPLAB: BDF Parsing Error';
        errorfound(sprintf(msgboxText), title);
        %EEG.EVENTLIST(indexEL) = ELaux;
        return
end
if nnz(binofbins)>=1
        if ~isempty(EVENTLIST)
                if Voutput==1 % EVENTLIST is the output only (for scripting)
                        clear EEG
                        EEG = EVENTLIST;
                        return
                end
                if iseegstruct(EEG) && ismember_bc2(option2do, [2 3 6 7])
                        EEG =  pasteeventlist(EEG, EVENTLIST, 1, indexEL);
                        if updevent && issaveas
                                EEG = pop_overwritevent(EEG, 'code', 'History', 'off');
                        elseif updevent && ~issaveas
                                EEG = pop_overwritevent(EEG, 'code', 'History', 'off');
                        end
                end
                if ismember_bc2(option2do, [4 5 6 7])
                        assignin('base','EVENTLIST',EVENTLIST);  % send EVENTLIST structure to WORKSPACE, August 22, 2008
                        disp('EVENTLIST structure was sent to WORKSPACE.')
                end
                if ismember_bc2(option2do, [1 3 5 7]) && ~isempty(file2) && ~strcmpi(file2,'no') && ~strcmpi(file2,'none')
                        disp('A text file version of your EVENTLIST was created.')
                end

                %
                % Generate equivalent command (for history)
                %
                skipfields = {'EEG', 'ERP', 'Saveas', 'Warning', 'History'};
                fn  = fieldnames(p.Results);
                com = sprintf( '%s  = %s( %s ', inputname(1), mfilename, inputname(1));
                for q=1:length(fn)
                        fn2com = fn{q};
                        if ~ismember_bc2(fn2com, skipfields)
                                fn2res = p.Results.(fn2com);
                                if ~isempty(fn2res)
                                        if ischar(fn2res)
                                                if ~strcmpi(fn2res,'off') && ~strcmpi(fn2res,'no') && ~strcmpi(fn2res,'none')
                                                        com = sprintf( '%s, ''%s'', ''%s''', com, fn2com, fn2res);
                                                end
                                        else
                                                if iscell(fn2res)
                                                        fn2resstr = vect2colon(cell2mat(fn2res), 'Sort','on');
                                                        fnformat = '{%s}';
                                                else
                                                        fn2resstr = vect2colon(fn2res, 'Sort','on');
                                                        fnformat = '%s';
                                                end
                                                com = sprintf( ['%s, ''%s'', ' fnformat], com, fn2com, fn2resstr);
                                        end
                                end
                        end
                end
                com = sprintf( '%s );', com);
        else
                msgboxText = ['Bin descriptor file contains errors!\n'...
                        'For details, please read command window messages.'];
                title = 'ERPLAB: BDF Parsing Error';
                errorfound(sprintf(msgboxText), title);
                EEG.EVENTLIST(indexEL) = ELaux;
                return
        end
else
        msgboxText =  ['Bins were not found!\n'...
                'Try with other BDF or modify the current one.'];
        title = 'ERPLAB: Binlister Error';
        errorfound(sprintf(msgboxText), title);
        disp('binlister process was cancel.')
        %EEG.EVENTLIST(indexEL) = ELaux;
        return
end
% get history from script. EEG
switch shist
        case 1 % from GUI
                com = sprintf('%s %% GUI: %s', com, datestr(now));
                %fprintf('%%Equivalent command:\n%s\n\n', com);
                displayEquiComERP(com);
        case 2 % from script
                EEG = erphistory(EEG, [], com, 1);
        case 3
                % implicit
        otherwise %off or none
                com = '';
end

%
% Completion statement
%
msg2end

if issaveas && ismember_bc2(option2do, [2 3 6 7]) && iseegstruct(EEG)
        [ALLEEG, EEG, CURRENTSET] = pop_newset( ALLEEG, EEG, CURRENTSET);
end
if exist('ALLEEG', 'var')
        if ~isfield(ALLEEG,'data')
                [ALLEEG(1:length(ALLEEG)).data] = deal([]);
        end
end
return


function cloudInterface( src, event )
% interface function for several animation display functions
%
% USAGE
%  cloudInterface( src, event )
%
% INPUTS
%
% OUTPUTS
%
% EXAMPLE
%
% See also CLOUDBOUNDARY
%
% Vincent's Structure From Motion Toolbox      Version NEW
% Copyright (C) 2008-2010 Vincent Rabaud.  [vrabaud-at-cs.ucsd.edu]
% Please email me if you find bugs, or have suggestions or questions!
% Licensed under the Lesser GPL [see external/lgpl.txt]

userData=get(gcf,'UserData');

anim = userData.anim; cam = userData.cam; hCam = userData.hCam;
hPoint = userData.hPoint; hConn = userData.hConn; hGT = userData.hGT;

if userData.isIndep
  animRange = 1;
else
  animRange = 1:numel(anim);
end

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

% Deal with a pressed key to change the view or quit the animation
diffView=[0 0];
if ~isfield(event,'Key') || ~any(strcmp(event.Key,userData.possibleKey))
  event.Key='';
end
switch event.Key
  case 'c', % Show the connectivity
    userData.showConn = ~userData.showConn;
  case 'f', % Show the first point
    userData.showFirst = ~userData.showFirst;
  case 'g', % Show the ground truth
    userData.showGT = ~userData.showGT;
  case 'i', % make a view independent from the other ones
    userData.isIndep=~userData.isIndep;
  case 'p', % toggle between pretty axes
    userData.showPrettyAxes=~userData.showPrettyAxes;
  case 'q',
    userData.doReturn=1;
  case 'r', % rotate the axes
    for i=animRange
      if ~isempty(anim{i}.S)
        anim{i}.S = anim{i}.S([2 3 1],:,:);
        anim{i}.R = anim{i}.R(:,[2 3 1],:);
        anim{i}.t = anim{i}.t([2 3 1],:);
        for j=1:2
          tmp = [ get(hPoint{i}(j),'XData'); get(hPoint{i}(j),'YData'); ...
            get(hPoint{i}(j),'ZData') ];
          set(hPoint{i}(j),'XData',tmp(2,:));
          set(hPoint{i}(j),'YData',tmp(3,:));
          set(hPoint{i}(j),'ZData',tmp(1,:));
          tmp = [ get(hGT{i}(j),'XData'); get(hGT{i}(j),'YData'); ...
            get(hGT{i}(j),'ZData') ];
          set(hGT{i}(j),'XData',tmp(2,:));
          set(hGT{i}(j),'YData',tmp(3,:));
          set(hGT{i}(j),'ZData',tmp(1,:));
        end
      end
    end
  case 't', % Show the title
    userData.showTitle = ~userData.showTitle;
  case {'1','2','3'} % switch 2D/3D view
    if userData.camMode==str2double(event.Key) && src>=0 && ...
        any(strcmp( 'g', userData.possibleKey ))
      userData.alignGT = ~userData.alignGT;
    else
      for i=animRange; cam{i}(userData.camMode).axis = axis; end
      userData.camMode = str2double(event.Key);
      for i=animRange
        switch userData.camMode
          case 1,
            axis( cam{i}(userData.camMode).gca, 'on', 'vis3d' );
            set(gcf,'Color',0.8*[1 1 1]);
            if ~isempty(hCam{i})
              set(reshape(hCam{i}(:,1:8),[],1),'Visible','on');
            end
          case 2,
            axis( cam{i}(userData.camMode).gca, 'off', 'equal' );
            set(gcf,'Color',[1 1 1]);
            if ~isempty(hCam{i})
              set(reshape(hCam{i}(:,1:8),[],1),'Visible','off');
            end
          case 3,
            axis( cam{i}(userData.camMode).gca, 'on', 'vis3d' );
            set(gcf,'Color',[1 1 1]);
            if ~isempty(hCam{i})
              set(reshape(hCam{i}(:,1:8),[],1),'Visible','on');
            end
        end
      end

      for i=animRange
        axis( cam{i}(userData.camMode).gca, cam{i}(userData.camMode).axis);
        if userData.camMode~=2
          set( cam{i}(userData.camMode).gca, 'CameraPositionMode', 'auto');
        else
          set( cam{i}(userData.camMode).gca, 'CameraPosition', [0 -5 0] );
        end
        set( cam{i}(userData.camMode).gca, 'CameraTarget', ...
          cam{i}(userData.camMode).target );
      end
    end
  case 'numpad0' % re-center the camera
    for i=animRange; cam{i}(userData.camMode).diff=0; end
  case 'subtract', % slow down the speed
    userData.fps = userData.fps-5;
    if userData.fps<0; userData.fps=1; end
  case 'add', % increase the speed
    userData.fps = userData.fps+5;
  case 'space', % pause
    userData.doPause = ~userData.doPause;
  case 'leftarrow',
    diffView = [ 10 0 ];
  case 'rightarrow',
    diffView = [ -10 0];
  case 'uparrow',
    diffView = [ 0 -10];
  case 'downarrow',
    diffView = [ 0 10 ];
end

% Update the look of the data
offon = {'off' 'on'};
for i=animRange
  cam{i}(userData.camMode).diff = cam{i}(userData.camMode).diff + diffView;

  % Set some stuff visible or not
  set(hPoint{i}(2),'Visible',offon{1+userData.showFirst});
  set(get(cam{i}(userData.camMode).gca,'Title'),'Visible',...
    offon{1+userData.showTitle});

  if (~isempty(hGT)) && (~isempty(hGT{i}))
    if hGT{i}(1)>=0
      set(hGT{i}(1),'Visible',offon{1+userData.showGT});
    end
    if (length(hGT{i}) >=2 ) && (hGT{i}(2)>=0)
      set(hGT{i}(2),'Visible',offon{1+userData.showGT*userData.showFirst});
    end
  end
  if (~isempty(hConn))
    set(hConn{i},'Visible',offon{1+userData.showConn});
  end
end

if userData.camMode~=2 || isempty(event.Key)
  for i=animRange
    set( cam{i}(userData.camMode).gca, 'View', ...
      cam{i}(userData.camMode).view + cam{i}(userData.camMode).diff);

    if userData.showPrettyAxes
      set(cam{i}(userData.camMode).gca,'XTick',[],'YTick',[],'ZTick',[],...
        'LineWidth',3);
    else
      set(cam{i}(userData.camMode).gca,'XTickMode','auto','YTickMode',...
        'auto','ZTickMode','auto','LineWidth',1);
    end
  end
end

% Save the data back
userData.anim = anim; userData.cam = cam; userData.hPoint = hPoint;
userData.hGT = hGT;

set(gcf,'UserData',userData);


%Analysis of process runtimes
%
% Author: Jonathan Karr, jkarr@stanford.edu
% Affiliation: Covert Lab, Department of Bioengineering, Stanford University
% Last updated: 1/12/2011
classdef RunTime
    methods (Static)
        function run(fileName)
            profSummary = edu.stanford.covert.cell.sim.analysis.RunTime.calcProcessRunTimes();
            subtotals = ...
                [profSummary.evolveState]' + ...
                [profSummary.calcResourceRequirements_Current]' + ...
                [profSummary.copyToState]' + ...
                [profSummary.copyFromState]';
            total = sum(subtotals);

            fid = fopen(fileName, 'w');
            fprintf(fid, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n');
            fprintf(fid, '\n');
            fprintf(fid, '\t\n');
            fprintf(fid, '\t\t<title>%s</title>\n', 'Profile Summary');
            fprintf(fid, '\t\t\n');
            fprintf(fid, '\t\n');
            fprintf(fid, '\t\n');
            fprintf(fid, '\t\t
\n');
            fprintf(fid, '\t\t\t
\n');
            fprintf(fid, '\t\t\t\t
\n');
            fprintf(fid, '\t\t\t\t\t%s	\n', 'Process');
            fprintf(fid, '\t\t\t\t\t%s	\n', 'Evolve State');
            fprintf(fid, '\t\t\t\t\t%s	\n', 'Substrate Requirements');
            fprintf(fid, '\t\t\t\t\t%s	\n', 'Copy from State');
            fprintf(fid, '\t\t\t\t\t%s	\n', 'Copy to State');
            fprintf(fid, '\t\t\t\t\t%s	\n', 'Percent');
            fprintf(fid, '\t\t\t\t
\n');
            fprintf(fid, '\t\t\t
\n');
            fprintf(fid, '\t\t\t
\n');
            for i = 1:numel(profSummary)
                fprintf(fid, '\t\t\t\t
\n');
                fprintf(fid, '\t\t\t\t\t%s	\n', profSummary(i).name);
                fprintf(fid, '\t\t\t\t\t%.3f	\n', profSummary(i).evolveState);
                fprintf(fid, '\t\t\t\t\t%.3f	\n', profSummary(i).calcResourceRequirements_Current);
                fprintf(fid, '\t\t\t\t\t%.3f	\n', profSummary(i).copyFromState);
                fprintf(fid, '\t\t\t\t\t%.3f	\n', profSummary(i).copyToState);
                fprintf(fid, '\t\t\t\t\t%.1f	\n', subtotals(i)/total*100);
                fprintf(fid, '\t\t\t\t
\n');
            end
            fprintf(fid, '\t\t\t
\n');
            fprintf(fid, '\t\t\t
\n');
            fprintf(fid, '\t\t\t\t\t%s	\n', 'Percent');
            fprintf(fid, '\t\t\t\t\t%.1f	\n', sum([profSummary.evolveState])/total*100);
            fprintf(fid, '\t\t\t\t\t%.1f	\n', sum([profSummary.calcResourceRequirements_Current])/total*100);
            fprintf(fid, '\t\t\t\t\t%.1f	\n', sum([profSummary.copyFromState])/total*100);
            fprintf(fid, '\t\t\t\t\t%.1f	\n', sum([profSummary.copyToState])/total*100);
            fprintf(fid, '\t\t\t\t\t%.1f	\n', 100);
            fprintf(fid, '\t\t\t
\n');
            fprintf(fid, '\t\t
\n');
            fprintf(fid, '\t\n');
            fprintf(fid, '\n');
            fclose(fid);
        end

        function times = calcProcessRunTimes(profData)
            if ~exist('profData', 'var')
                profData = profile('info');
            end

            functionNames = {profData.FunctionTable.FunctionName};

            names = {};
            for i = 1:numel(profData.FunctionTable)
                processClass = regexp(profData.FunctionTable(i).FunctionName, '(.*?)>.*?\.evolveState$', 'tokens');
                if isempty(processClass); continue;
                end

                names = [names; processClass{1}(1)]; %#ok<AGROW>
            end
            names = [{'Process'}; sort(names)];

            times = struct;
            for i = 1:numel(names)
                times(i).name = names{i};

                %evolveState
                idx = find(strcmp(functionNames, [times(i).name '>' times(i).name '.evolveState']), 1);
                if ~isempty(idx)
                    times(i).evolveState = profData.FunctionTable(idx).TotalTime;
                else
                    times(i).evolveState = 0;
                end

                %copyFromState
                idx = find(strcmp(functionNames, [times(i).name '>' times(i).name '.copyFromState']), 1);
                if ~isempty(idx)
                    times(i).copyFromState = profData.FunctionTable(idx).TotalTime;
                else
                    times(i).copyFromState = 0;
                end

                %copyToState
                idx = find(strcmp(functionNames, [times(i).name '>' times(i).name '.copyToState']), 1);
                if ~isempty(idx)
                    times(i).copyToState = profData.FunctionTable(idx).TotalTime;
                else
                    times(i).copyToState = 0;
                end

                %calcResourceRequirements_Current
                idx = find(strcmp(functionNames, [times(i).name '>' times(i).name '.calcResourceRequirements_Current']), 1);
                if ~isempty(idx)
                    times(i).calcResourceRequirements_Current = profData.FunctionTable(idx).TotalTime;
                else
                    times(i).calcResourceRequirements_Current = 0;
                end
            end
        end
    end
end


%PRWAITBARONCE Generate single prwaitbar message
%
%	PRWAITBARONCE(STRING,PAR)
%
% INPUT
%   STRING  - String with text to be written in the waitbar,
%             e.g. '%i x %i eigenvalue decomposition: '.
%             This will be parsed by S = SPRINTF(STRING,PAR{:});
%   PAR     - scalar or cell array with parameter values
%
% This routine has to be used in combination with PRWAITBAR(0), e.g.:
%
%  prwaitbaronce('%i x %i eigenvalue decomposition ... ',{n,n})
%  [Q,L] = eig(H);
%  prwaitbar(0)
%
% It makes clear to the user what is happening in case progress cannot be
% accessed.

% Copyright: R.P.W. Duin, r.p.w.duin@37steps.com

function prwaitbaronce(ss,par)

	if nargin < 2
		prwaitbar(2,ss);
	elseif ~iscell(par)
		prwaitbar(2,sprintf(ss,par));
	else
		prwaitbar(2,sprintf(ss,par{:}));
	end

return


function t = readsqdinfo(t,fileinfo,acq_offset,raw_offset)
% t = readsqdinfo(t,fileinfo,acq_offset,raw_offset); Read info from sqd-file
% and write it to ACQPARAM object

SEEK_SET=-1;    % Start of the file for fseek: -1 => at the beginning

if ischar(fileinfo) % If filename is passed
    % open file as binary and little endian
    fid = fopen(fileinfo,'rb','l');
    if fid==-1,
        disp('File not found');
        [f,p] = uigetfile('*.sqd','MEG160 files');
        if ((~isstr(f)) | ~min(size(f))), return; end;
        fname = [p f];
        fid = fopen(fname,'rb','l');
    end;
elseif isnumeric(fileinfo)% If filepointer is passed
    if fileinfo>0
        fid = fileinfo;
    else
        error('Invalid fid');
    end;
end;

% Initialize the offsets
switch nargin
case 2
    % Get offset of acquisition parameters
    fseek( fid, 128, SEEK_SET );
    acq_offset = fread(fid,1,'long');
    % Get Acquisition type
    fseek(fid,acq_offset,SEEK_SET);
    t.AcquisitionType       = fread(fid,1,'long');
    % Get Raw Offset
    fseek(fid,t.Private.Offset2Raw(t.AcquisitionType),SEEK_SET);
    raw_offset  = fread(fid,1,'long');
case 3
    % Get Acquisition type
    fseek(fid,acq_offset,SEEK_SET);
    t.AcquisitionType       = fread(fid,1,'long');
    % Get Raw Offset
    fseek(fid,t.Private.Offset2Raw(t.AcquisitionType),SEEK_SET);
    raw_offset  = fread(fid,1,'long');
end;
%Save Offsets
t.RawOffset         = raw_offset;

% Read acquisition type
fseek( fid, acq_offset, SEEK_SET );
t.AcquisitionType       = fread(fid,1,'long');
t.SampleRate            = fread(fid,1,'double');
t.Datatype              = t.Private.Datatypes{t.AcquisitionType};

switch t.AcquisitionType
    case 1
        % Read acquisition parameters
        t.SampleInfo.SamplesAcquired    = fread(fid,1,'long');
        t.SampleInfo.ActSamplesAcquired = fread(fid,1,'long');
        t.SampleInfo.SamplesAvailable   = t.SampleInfo.ActSamplesAcquired;
    case {2,3}
        % Read acquisition parameters
        t.SampleInfo.FrameLength        = fread(fid,1,'long');
        t.SampleInfo.SamplesAvailable   = t.SampleInfo.FrameLength;
        t.SampleInfo.PreTrigger         = fread(fid,1,'long');
        t.SampleInfo.AverageCount       = fread(fid,1,'long');
        t.SampleInfo.ActAverageCount    = fread(fid,1,'long');
end;
if ischar(fileinfo);fclose(fid);end;
return;


function res = vl_simplenn(net, x, dzdy, res, varargin)
%VL_SIMPLENN  Evaluate a SimpleNN network.
%   RES = VL_SIMPLENN(NET, X) evaluates the convnet NET on data X.
%   RES = VL_SIMPLENN(NET, X, DZDY) evaluates the convnent NET and its
%   derivative on data X and output derivative DZDY.
%
%   This function process networks using the SimpleNN wrapper
%   format. Such networks are 'simple' in the sense that they consist
%   of a linear sequence of computational layers. You can use the
%   `dagnn.DagNN` wrapper for more complex topologies, or write your
%   own wrapper around MatConvNet computational blocks for even
%   greater flexibility.
%
%   The format of the network structure NET and of the result
%   structure RES are described in some detail below. Most networks
%   expect the input data X to be standardized, for example by
%   rescaling the input image(s) and subtracting a mean. Doing so is
%   left to the user, but information on how to do this is usually
%   contained in the `net.meta` field of the NET structure (see
%   below).
%
%   The NET structure needs to be updated as new features are
%   introduced in MatConvNet; use the `VL_SIMPLENN_TIDY()` function
%   to make an old network current, as well as to cleanup and check
%   the structure of an existing network.
%
%   Networks can run either on the CPU or GPU. Use VL_SIMPLENN_MOVE()
%   to move the network parameters between these devices.
%
%   To print or obtain summary of the network structure, use the
%   VL_SIMPLENN_DISPLAY() function.
%
%   VL_SIMPLENN_DISPLAY(..., 'OPT', VAL, ...) takes the following
%   options:
%
%   `Mode`:: `normal`
%      Specifies the mode of operation. It can be either `'normal'` or
%      `'test'`. In test mode, dropout and batch-normalization are
%      bypassed. Note that, when a network is deployed, it may be
%      preferable to *remove* such blocks altogether.
%
%   `ConserveMemory`:: `true`
%      Aggressively delete intermediate results. This in practice has
%      a very small performance hit and allows training much larger
%      models. However, it can be useful to disable it for
%      debugging.
%
%   `CuDNN`:: `true`
%      Use CuDNN when available.
%
%   `Accumulate`:: `false`
%      Accumulate gradients in back-propagation instead of rewriting
%      them. This is useful to break the computation in sub-batches.
%
%   ## The result format
%
%   SimpleNN returns the result of its calculations in the RES
%   structure array. RES(1) contains the input to the network, while
%   RES(2), RES(3), ... contain the output of each layer, from first
%   to last. Each entry has the following fields:
%
%   - `res(i+1).x`: the output of layer `i`. Hence `res(1).x` is the
%     network input.
%
%   - `res(i+1).aux`: any auxiliary output data of layer i. For example,
%     dropout uses this field to store the dropout mask.
%
%   - `res(i+1).dzdx`: the derivative of the network output relative
%     to the output of layer `i`. In particular `res(1).dzdx` is the
%     derivative of the network output with respect to the network
%     input.
%
%   - `res(i+1).dzdw`: a cell array containing the derivatives of the
%     network output relative to the parameters of layer `i`. It can
%     be a cell array for multiple parameters.
%
%   ## The network format
%
%   The network is represented by the NET structure, which contains
%   two fields:
%
%   - `net.layers` is a cell array with the CNN layers.
%
%   - `net.meta` is a grab-bag of auxiliary application-dependent
%     information, including for example details on how to normalize
%     input data, the class names for a classifiers, or details of
%     the learning algorithm. The content of this field is ignored by
%     VL_SIMPLENN().
%
%   SimpleNN is aware of the following layers:
%
%   Convolution layer::
%     The convolution layer wraps VL_NNCONV(). It has fields:
%
%     - `layer.type` contains the string `'conv'`.
%     - `layer.weights` is a cell array with filters and biases.
%     - `layer.stride` is the sampling stride (e.g. 1).
%     - `layer.pad` is the padding (e.g. 0).
%
%   Convolution transpose layer::
%     The convolution transpose layer wraps VL_NNCONVT(). It has fields:
%
%     - `layer.type` contains the string `'convt'`.
%     - `layer.weights` is a cell array with filters and biases.
%     - `layer.upsample` is the upsampling factor (e.g. 1).
%     - `layer.crop` is the amount of output cropping (e.g. 0).
%
%   Max pooling layer::
%     The max pooling layer wraps VL_NNPOOL(). It has fields:
%
%     - `layer.type` contains the string `'pool'`.
%     - `layer.method` is the pooling method (either 'max' or 'avg').
%     - `layer.pool` is the pooling size (e.g. 3).
%     - `layer.stride` is the sampling stride (usually 1).
%     - `layer.pad` is the padding (usually 0).
%
%   Normalization (LRN) layer::
%     The normalization layer wraps VL_NNNORMALIZE(). It has fields:
%
%     - `layer.type` contains the string `'normalize'` or `'lrn'`.
%     - `layer.param` contains the normalization parameters (see VL_NNNORMALIZE()).
%
%   Spatial normalization layer::
%     The spatial normalization layer wraps VL_NNSPNORM(). It has fields:
%
%     - `layer.type` contains the string `'spnorm'`.
%     - `layer.param` contains the normalization parameters (see VL_NNSPNORM()).
%
%   Batch normalization layer::
%     This layer wraps VL_NNBNORM(). It has fields:
%
%     - `layer.type` contains the string `'bnorm'`.
%     - `layer.weights` contains is a cell-array with, multiplier and
%       biases, and moments parameters
%
%     Note that moments are used only in `'test'` mode to bypass batch
%     normalization.
%
%   ReLU and Sigmoid layers::
%     The ReLU layer wraps VL_NNRELU(). It has fields:
%
%     - `layer.type` contains the string `'relu'`.
%     - `layer.leak` is the leak factor (e.g. 0).
%
%     The sigmoid layer is the same, but for the sigmoid function,
%     with `relu` replaced by `sigmoid` and no leak factor.
%
%   Dropout layer::
%     The dropout layer wraps VL_NNDROPOUT(). It has fields:
%
%     - `layer.type` contains the string `'dropout'`.
%     - `layer.rate` is the dropout rate (e.g. 0.5).
%
%     Note that the block is bypassed in `test` mode.
%
%   Softmax layer::
%     The softmax layer wraps VL_NNSOFTMAX(). It has fields
%
%     - `layer.type` contains the string`'softmax'`.
%
%   Log-loss layer and softmax-log-loss::
%     The log-loss layer wraps VL_NNLOSS(). It has fields:
%
%     - `layer.type` contains `'loss'`.
%     - `layer.class` contains the ground-truth class labels.
%
%     The softmax-log-loss layer wraps VL_NNSOFTMAXLOSS() instead. it
%     has the same parameters, but `type` contains the `'softmaxloss'`
%     string.
%
%   P-dist layer::
%     The p-dist layer wraps VL_NNPDIST(). It has fields:
%
%     - `layer.type` contains the string  `'pdist'`.
%     - `layer.p` is the P parameter of the P-distance (e.g. 2).
%     - `layer.noRoot` it tells whether to raise the distance to
%     the P-th power (e.g. `false`).
%     - `layer.epsilon` is the regularization parameter for the derivatives.
%
%   Custom layer::
%     This can be used to specify custom layers.
%
%     - `layer.type` contains the string `'custom'`.
%     - `layer.forward` is  a function handle computing the block.
%     - `layer.backward` is a function handle computing the block derivative.
%
%     The first function is called as
%
%          res(i+1) = layer.forward(layer, res(i), res(i+1))
%
%     where RES is the structure array specified before. The second function is
%     called as
%
%          res(i) = layer.backward(layer, res(i), res(i+1))
%
%     Note that the `layer` structure can contain additional custom
%     fields if needed.
%
%   See also: dagnn.DagNN, VL_SIMPLENN_TIDY(),
%   VL_SIMPLENN_DISPLAY(), VL_SIMPLENN_MOVE().

% Copyright (C) 2014-15 Andrea Vedaldi.
% All rights reserved.
%
% This file is part of the VLFeat library and is made available under
% the terms of the BSD license (see the COPYING file).

opts.res = [] ;
opts.conserveMemory = false ;
opts.sync = false ;
opts.mode = 'normal' ;
opts.accumulate = false ;
opts.cudnn = true ;
opts.backPropDepth = +inf ;
opts = vl_argparse(opts, varargin);

n = numel(net.layers) ;

if (nargin <= 2) || isempty(dzdy)
  doder = false ;
else
  doder = true ;
end

if opts.cudnn
  cudnn = {'CuDNN'} ;
else
  cudnn = {'NoCuDNN'} ;
end

switch lower(opts.mode)
  case 'normal'
    testMode = false ;
  case 'test'
    testMode = true ;
  otherwise
    error('Unknown mode ''%s''.', opts. mode) ;
end

gpuMode = isa(x, 'gpuArray') ;

if nargin <= 3 || isempty(res)
  res = struct(...
    'x', cell(1,n+1), ...
    'dzdx', cell(1,n+1), ...
    'dzdw', cell(1,n+1), ...
    'aux', cell(1,n+1), ...
    'time', num2cell(zeros(1,n+1)), ...
    'backwardTime', num2cell(zeros(1,n+1))) ;
end
res(1).x = x ;

% -------------------------------------------------------------------------
%                                                              Forward pass
% -------------------------------------------------------------------------

for i=1:n
  l = net.layers{i} ;
  res(i).time = tic ;
  switch l.type
    case 'conv'
      res(i+1).x = vl_nnconv(res(i).x, l.weights{1}, l.weights{2}, ...
        'pad', l.pad, ...
        'stride', l.stride, ...
        l.opts{:}, ...
        cudnn{:}) ;

    case 'convt'
      res(i+1).x = vl_nnconvt(res(i).x, l.weights{1}, l.weights{2}, ...
        'crop', l.crop, ...
        'upsample', l.upsample, ...
        'numGroups', l.numGroups, ...
        l.opts{:}, ...
        cudnn{:}) ;

    case 'pool'
      res(i+1).x = vl_nnpool(res(i).x, l.pool, ...
        'pad', l.pad, 'stride', l.stride, ...
        'method', l.method, ...
        l.opts{:}, ...
        cudnn{:}) ;

    case {'normalize', 'lrn'}
      res(i+1).x = vl_nnnormalize(res(i).x, l.param) ;

    case 'softmax'
      res(i+1).x = vl_nnsoftmax(res(i).x) ;

    case 'loss'
      res(i+1).x = vl_nnloss(res(i).x, l.class) ;

    case 'softmaxloss'
      res(i+1).x = vl_nnsoftmaxloss(res(i).x, l.class) ;

    case 'relu'
      if l.leak > 0, leak = {'leak', l.leak} ; else leak = {} ; end
      res(i+1).x = vl_nnrelu(res(i).x,[],leak{:}) ;

    case 'sigmoid'
      res(i+1).x = vl_nnsigmoid(res(i).x) ;

    case 'noffset'
      res(i+1).x = vl_nnnoffset(res(i).x, l.param) ;

    case 'spnorm'
      res(i+1).x = vl_nnspnorm(res(i).x, l.param) ;

    case 'dropout'
      if testMode
        res(i+1).x = res(i).x ;
      else
        [res(i+1).x, res(i+1).aux] = vl_nndropout(res(i).x, 'rate', l.rate) ;
      end

    case 'bnorm'
      if testMode
        res(i+1).x = vl_nnbnorm(res(i).x, l.weights{1}, l.weights{2}, 'moments', l.weights{3}) ;
      else
        res(i+1).x = vl_nnbnorm(res(i).x, l.weights{1}, l.weights{2}) ;
      end

    case 'pdist'
      res(i+1) = vl_nnpdist(res(i).x, l.p, 'noRoot', l.noRoot, 'epsilon', l.epsilon) ;

    case 'custom'
      res(i+1) = l.forward(l, res(i), res(i+1)) ;

    otherwise
      error('Unknown layer type ''%s''.', l.type) ;
  end

  % optionally forget intermediate results
  forget = opts.conserveMemory ;
  forget = forget & (~doder || strcmp(l.type, 'relu')) ;
  forget = forget & ~(strcmp(l.type, 'loss') || strcmp(l.type, 'softmaxloss')) ;
  forget = forget & (~isfield(l, 'rememberOutput') || ~l.rememberOutput) ;
  if forget
    res(i).x = [] ;
  end

  if gpuMode & opts.sync
    wait(gpuDevice) ;
  end
  res(i).time = toc(res(i).time) ;
end

% -------------------------------------------------------------------------
%                                                             Backward pass
% -------------------------------------------------------------------------

if doder
  res(n+1).dzdx = dzdy ;
  for i=n:-1:max(1, n-opts.backPropDepth+1)
    l = net.layers{i} ;
    res(i).backwardTime = tic ;
    switch l.type

      case 'conv'
        [res(i).dzdx, dzdw{1}, dzdw{2}] = ...
          vl_nnconv(res(i).x, l.weights{1}, l.weights{2}, res(i+1).dzdx, ...
          'pad', l.pad, ...
          'stride', l.stride, ...
          l.opts{:}, ...
          cudnn{:}) ;

      case 'convt'
        [res(i).dzdx, dzdw{1}, dzdw{2}] = ...
          vl_nnconv(res(i).x, l.weights{1}, l.weights{2}, res(i+1).dzdx, ...
          'crop', l.crop, ...
          'upsample', l.upsample, ...
          'numGroups', l.numGroups, ...
          l.opts{:}, ...
          cudnn{:}) ;

      case 'pool'
        res(i).dzdx = vl_nnpool(res(i).x, l.pool, res(i+1).dzdx, ...
                                'pad', l.pad, 'stride', l.stride, ...
                                'method', l.method, ...
                                l.opts{:}, ...
                                cudnn{:}) ;

      case {'normalize', 'lrn'}
        res(i).dzdx = vl_nnnormalize(res(i).x, l.param, res(i+1).dzdx) ;

      case 'softmax'
        res(i).dzdx = vl_nnsoftmax(res(i).x, res(i+1).dzdx) ;

      case 'loss'
        res(i).dzdx = vl_nnloss(res(i).x, l.class, res(i+1).dzdx) ;

      case 'softmaxloss'
        res(i).dzdx = vl_nnsoftmaxloss(res(i).x, l.class, res(i+1).dzdx) ;

      case 'relu'
        if l.leak > 0, leak = {'leak', l.leak} ; else leak = {} ; end
        if ~isempty(res(i).x)
          res(i).dzdx = vl_nnrelu(res(i).x, res(i+1).dzdx, leak{:}) ;
        else
          % if res(i).x is empty, it has been optimized away, so we use this
          % hack (which works only for ReLU):
          res(i).dzdx = vl_nnrelu(res(i+1).x, res(i+1).dzdx, leak{:}) ;
        end

      case 'sigmoid'
        res(i).dzdx = vl_nnsigmoid(res(i).x, res(i+1).dzdx) ;

      case 'noffset'
        res(i).dzdx = vl_nnnoffset(res(i).x, l.param, res(i+1).dzdx) ;

      case 'spnorm'
        res(i).dzdx = vl_nnspnorm(res(i).x, l.param, res(i+1).dzdx) ;

      case 'dropout'
        if testMode
          res(i).dzdx = res(i+1).dzdx ;
        else
          res(i).dzdx = vl_nndropout(res(i).x, res(i+1).dzdx, ...
                                     'mask', res(i+1).aux) ;
        end

      case 'bnorm'
        [res(i).dzdx, dzdw{1}, dzdw{2}, dzdw{3}] = ...
          vl_nnbnorm(res(i).x, l.weights{1}, l.weights{2}, res(i+1).dzdx) ;
        % multiply the moments update by the number of images in the batch
        % this is required to make the update additive for subbatches
        % and will eventually be normalized away
        dzdw{3} = dzdw{3} * size(res(i).x,4) ;

      case 'pdist'
        res(i).dzdx = vl_nnpdist(res(i).x, l.p, res(i+1).dzdx, ...
                                 'noRoot', l.noRoot, 'epsilon', l.epsilon) ;
      case 'custom'
        res(i) = l.backward(l, res(i), res(i+1)) ;

    end % layers

    switch l.type
      case {'conv', 'convt', 'bnorm'}
        if ~opts.accumulate
          res(i).dzdw = dzdw ;
        else
          for j=1:numel(dzdw)
            res(i).dzdw{j} = res(i).dzdw{j} + dzdw{j} ;
          end
        end
        dzdw = [] ;
    end
    if opts.conserveMemory
      res(i+1).dzdx = [] ;
    end
    if gpuMode & opts.sync
      wait(gpuDevice) ;
    end
    res(i).backwardTime = toc(res(i).backwardTime) ;
  end
end


function [res] = fiff_pick_types_evoked(orig,meg,eeg,stim,include,exclude)
%
% [res] = fiff_pick_types_evoked(orig,meg,eeg,stim,include,exclude)
%
% Pick desired channels types from evoked-response data
%
% orig      - The original data
% meg       - Include MEG channels
% eeg       - Include EEG channels
% stim      - Include stimulus channels
% include   - Additional channels to include (if empty, do not add any)
% exclude   - Channels to exclude (if empty, do not exclude any)
%
%

%
%   Author : Matti Hamalainen, MGH Martinos Center
%   License : BSD 3-clause
%
%
%   Revision 1.10  2008/06/12 19:59:19  msh
%   Fixed the help text
%
%   Revision 1.9  2007/12/23 17:01:24  msh
%   Fixed error handling multiple datasets
%
%   Revision 1.8  2006/04/26 00:14:24  msh
%   Return empty structure from fiff_pick_channels evoked and fiff_pick_types_evoked if there is no match.
%   Accuracy checking was incorrect in mne_add_coil_defs
%
%   Revision 1.7  2006/04/23 15:29:40  msh
%   Added MGH to the copyright
%
%   Revision 1.6  2006/04/21 11:33:17  msh
%   Added raw segment reading routines
%
%   Revision 1.5  2006/04/20 23:33:20  msh
%   Separated fiff_pick_channels and fiff_pick_types from the _evoked versions
%
%   Revision 1.4  2006/04/17 11:52:15  msh
%   Added coil definition stuff
%
%   Revision 1.3  2006/04/15 12:21:00  msh
%   Several small improvements
%
%   Revision 1.2  2006/04/14 15:49:49  msh
%   Improved the channel selection code and added ch_names to measurement info.
%
%   Revision 1.1  2006/04/14 00:45:42  msh
%   Added channel picking and fiff_invert_transform
%
%

me='MNE:fiff_pick_types_evoked';

if nargin == 5
    exclude = [];
elseif nargin == 4
    include = [];
    exclude = [];
elseif nargin == 3
    include = [];
    exclude = [];
    stim    = false;
elseif nargin == 2
    include = [];
    exclude = [];
    stim    = false;
    eeg     = false;
elseif nargin ~= 6
    error(me,'Incorrect number of arguments');
end

sel = fiff_pick_types(orig.info,meg,eeg,stim,include,exclude);

if isempty(sel)
    res = [];
    fprintf(1,'Warning : No channels match the selection.\n');
    return;
end

res = orig;
res.info.chs      = res.info.chs(sel);
res.info.ch_names = res.info.ch_names(sel);
%
%   Create the reduced data set
%
for k = 1:length(res.evoked)
    res.evoked(k).epochs = res.evoked(k).epochs(sel,:);
end
res.info.nchan    = length(sel);

return;

end


function comparisonTable = compareInchis(model, inchis, met)
% Compare inchi strings. Each inchi string is given a score based on its similarity
% to the chemical formula and charge of the metabolite in the model. Factors such
% as stereochemistry, if it is a standard inchi, and its similarity to the other
% inchis are also considered.
%
% USAGE:
%
%    comparisonTable = compareInchis(model, inchis, met)
%
% INPUT:
%    model:     COBRA model
%                   *.mets - 1xm list of metabolite IDs
%                   *.metFormulas - 1xm list of metabolite Formulas
%                   *.metCharges - 1xm list of metabolite charges
%    inchis:    List of InChIs to compare
%    met:       Metabolite ID in the model
%
% OUTPUTS:
%    comparisonTable: Table containing the information used for each InChI
%

if isrow(inchis)
    inchis = inchis';
end
mets = regexprep(model.mets, '(\[\w\])', '');

% Prepare the table with inchi data
nRows = length(inchis);
varTypes = {'double', 'logical', 'string', 'string', 'logical', 'double', 'logical',...
    'logical', 'logical', 'double', 'double', 'logical', 'double', 'logical', 'string'};
varNames = {'scores', 'rGroup', 'InChI', 'metFormula', 'formulaOkBool', 'netCharge',...
    'chargeOkBool', 'stereochemicalSubLayers', 'standard', 'sourceSimilarity', ...
    'mainLayerSimilarity', 'isotopicLayer', 'layers', 'inchiWithMoreLayers', 'mainLayer'};
comparisonTable = table('Size', [nRows length(varTypes)], 'VariableTypes', varTypes,...
    'VariableNames', varNames);

emptyBool = cellfun(@isempty, inchis);
comparisonTable.InChI = inchis;

% Get InChI data
for i = 1:length(inchis)
    if ~emptyBool(i)
        inchiLayersDetail = getInchiData(inchis{i});
        comparisonTable.layers(i) = inchiLayersDetail.layers;
        comparisonTable.standard(i) = inchiLayersDetail.standard;
        comparisonTable.metFormula(i) = inchiLayersDetail.metFormula;
        comparisonTable.mainLayer(i) = inchiLayersDetail.mainLayer;
        comparisonTable.netCharge(i) = inchiLayersDetail.netCharge;
        comparisonTable.stereochemicalSubLayers(i) = inchiLayersDetail.stereochemicalSubLayers;
        comparisonTable.isotopicLayer(i) = inchiLayersDetail.isotopicLayer;
    end
end

% Charge comparison
% Compares the net charge in the InChI with the charge in the corresponding
% metabolite in the model.
if isfield(model, 'metCharges')
    modelMetCharge = unique(model.metCharges(ismember(mets, met)));
    comparisonTable.chargeOkBool = ~emptyBool & comparisonTable.netCharge == modelMetCharge;
end
if isfield(model, 'metCharge')
    modelMetCharge = unique(model.metCharge(ismember(mets, met)));
    comparisonTable.chargeOkBool = ~emptyBool & comparisonTable.netCharge == modelMetCharge;
end

% Formula comparison
% Compares the formula with the formula in the corresponding metabolite in the
% model. Hydrogens should be ignored because they are considered in the charge
% or isotopic layers.
modelMetFormula = unique(model.metFormulas(ismember(mets, met)));
% Remove the R groups from the formula
rGroup = ["X", "Y", "*", "FULLR"];
if contains(modelMetFormula, rGroup)
    if isempty(regexprep(modelMetFormula, rGroup, ''))
        modelMetFormula = 'H';
    else
        modelMetFormula = editChemicalFormula(modelMetFormula);
    end
end
% Check if the formulas match
comparisonTable.formulaOkBool = ismember(regexprep(comparisonTable.metFormula, ...
    'H\d*', ''), regexprep(modelMetFormula, 'H\d*', ''));

% Source similarity
% For each InChI is calculated the number of equal InChIs divided between
% the number of InChIs
inchis(emptyBool) = {'noData'};
for i = 1:length(inchis)
    if ~emptyBool(i)
        comparisonTable.sourceSimilarity(i) = sum(ismember(inchis, inchis(i))) / sum(~emptyBool);
    end
end

% Main layer similarity
% For each InChI is calculated the the number of equal main layer similarity
% divided between the number of InChIs
for i = 1:length(inchis)
    if ~emptyBool(i)
        comparisonTable.mainLayerSimilarity(i) = sum(ismember(comparisonTable.mainLayer, ...
            comparisonTable.mainLayer(i))) / sum(~emptyBool);
    end
end

% InChI with more layers (stereochemistry and charge)
comparisonTable.inchiWithMoreLayers = comparisonTable.layers == max(comparisonTable.layers);

% Final score
% Priority will be given to molecules that have the same chemical formula as
% the corresponding metabolite in the model, excluding hydrogen and non-chemical
% atoms.
comparisonTable.scores = comparisonTable.chargeOkBool + (comparisonTable.formulaOkBool * 10)...
    + comparisonTable.stereochemicalSubLayers + comparisonTable.standard + ...
    comparisonTable.sourceSimilarity + comparisonTable.mainLayerSimilarity + ...
    comparisonTable.inchiWithMoreLayers;

end


%> @brief Convert a general cell array matrix to a string
%> @author Eric Cousineau <eacousineau@gmail.com>, AMBER Lab, under Dr.
%> Aaron Ames
%> @param X cell array
%> @param varargin Arguments to propagate to general2str()
function [str] = cell2str(X, varargin)
s = size(X);
func = @(x) general2str(x, varargin{:});
raw = cellfun(func, X, 'UniformOutput', false);
rows = cell(s(1), 1);
for i = 1:s(1)
    rows{i} = implode(raw(i, :), ', ');
end
str = ['{\n', indent(strjoin(rows', ';\n'), '\t'), ';\n}'];
end


% APM Retrieve an Option Value (Tag)
%
% response = apm_tag(server,app,name)
%
% Function apm_tag retrieves an option specification from
%   the APM server with the following arguments:
%
%   server = address of server
%      app = application name
%     name = option name
% response = option value
%
% Either global options (NLC.option_name) or parameter/variable
%   options (NAME.option_name) are able to be retrieved with this
%   function. A full list of available options with their default
%   values are available here:
%
% Global Options:
%    http://apmonitor.com/wiki/index.php/Main/DbsGlobal
%
% Variable Options:
%    http://apmonitor.com/wiki/index.php/Main/DbsVariable
%
function response = apm_tag(server,app,name)
   app = lower(deblank(app));

    % Web-server URL base
    url_base = [deblank(server) '/online/get_tag.php'];

    % Send request to web-server
    params = ['?p=' urlencode(app) '&n=' urlencode(name)];
    url = [url_base params];
    % Send request to web-server
    response = str2num(urlread_apm(url));


%This Progra, develop by Renoald Tang
%University Teknologi Malaysia, Photogrammetry and Laser scanning group
%for academic purpose
%Email:renoald@live.com
function varargout = AMLS(varargin)
% AMLS M-file for AMLS.fig
%      AMLS, by itself, creates a new AMLS or raises the existing
%      singleton*.
%
%      H = AMLS returns the handle to a new AMLS or the handle to
%      the existing singleton*.
%
%      AMLS('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in AMLS.M with the given input arguments.
%
%      AMLS('Property','Value',...) creates a new AMLS or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before AMLS_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to AMLS_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 AMLS

% Last Modified by GUIDE v2.5 01-Jul-2004 00:11:31

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @AMLS_OpeningFcn, ...
                   'gui_OutputFcn',  @AMLS_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 AMLS is made visible.
function AMLS_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to AMLS (see VARARGIN)

% Choose default command line output for AMLS
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);
%axes(handles.axes1)
%axis off
%axes(handles.axes3)
%axis off

% UIWAIT makes AMLS wait for user response (see UIRESUME)
% uiwait(handles.figure1);

% --- Outputs from this function are returned to the command line.
function varargout = AMLS_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;

% --- Executes on button press in openbutton.
function openbutton_Callback(hObject, eventdata, handles)
% hObject    handle to openbutton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

[FileName,PathName] = uigetfile({'*.xyz'},'Select the Point clouds');
%combine the filename and pathname
directory=strcat(PathName ,FileName);
%.xyz check file extension
ext=findstr(FileName,'.xyz');
n=isempty(ext);
if n==0
    point=dlmread(directory);
end
n=length(point);
    dlmwrite('point.xyz', point, 'delimiter', '\t','precision', 6);
 %setappdata(AMLS,'point1',point);
 axes(handles.axes1)
 axis on
plot3(point(:,1),point(:,2),point(:,3),'r.')
grid on
num= num2str(n);
set(handles.text2,'String',num);

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

% Hints: get(hObject,'String') returns contents of edit1 as text
%        str2double(get(hObject,'String')) returns contents of edit1 as a double
input = str2num(get(hObject,'String'));
if (isempty(input))
     set(hObject,'String','2')
end
guidata(hObject, handles);

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

% Hint: edit 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 Computebutton.
function Computebutton_Callback(hObject, eventdata, handles)
% hObject    handle to Computebutton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
para = get(handles.edit1,'String');
parameter=str2num(para);
myname='point.xyz';
out='mypoint';
command=sprintf('NormFet.exe %s  %s -nml -ftr \n',myname,out);
system(command);
lastfile='mypoint_bbr2.50_nn8.xyznw';
outfile='output';
factor=parameter;
command2=sprintf('AMLS.exe %s %s -hr %d\n',lastfile,outfile,factor);
system(command2);
f1='output_adpmls_hr';
f2='.00.xyz';
finalfile=strcat(f1,para,f2);
%disp(finalfile)
surface=dlmread(finalfile);
setappdata(AMLS,'surface',surface);
axes(handles.axes3)
axis on
plot3(surface(:,1),surface(:,2),surface(:,3),'g.');
grid on
% --- Executes on button press in savebutton.
function savebutton_Callback(hObject, eventdata, handles)
% hObject    handle to savebutton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
[file1,path1] = uiputfile({'*.xyz'},'Save file name');
%combine the filename and pathname

directory=strcat(path1,file1);
mypoint=getappdata(AMLS,'surface');
dlmwrite(directory, mypoint, 'delimiter', '\t', ...
         'precision', 6);

% --- Executes on button press in exitbutton.
function exitbutton_Callback(hObject, eventdata, handles)
% hObject    handle to exitbutton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
delete(gcf)

% --- Executes on button press in clearpushbutton.
function clearpushbutton_Callback(hObject, eventdata, handles)
% hObject    handle to clearpushbutton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
arrayfun(@cla,findall(0,'type','axes'));


% saves images of individual estimated components....
function varout = check_profiles(sep5, offset5, pathname, prename, niter)
p.path = pathname;

for kk5 = 1: length(offset5)
    for ll5=1 : length(sep5)
        p.namedir = [prename num2str(100*sep5(ll5)) 'offset_' num2str(offset5(kk5))];
        cd ([p.path p.namedir])
        load ([p.namedir '-iter_1'])
        %         ims(psf);
        %         SaveImageFULL('psf', 'pf');
        is = imarfun('imsum',dpixc_ind);
        prof = double(is(:,15));
        varout(kk5, ll5,:) = prof;
% % %         for mm5=1:niter
% % %             varout = bg;
% % %             imstiled(icapixNMF{mm5}(:,:,1:2));
% % %             close all
% % %         end
    end
end


function tsss = tbx_cfg_tsss
% Configuration file for toolbox 'TSSS'
%_______________________________________________________________________
% Copyright (C) 2014 Wellcome Trust Centre for Neuroimaging

% Vladimir Litvak
% $Id: tbx_cfg_tsss.m 7703 2019-11-22 12:06:29Z guillaume $

tbxdir = fileparts(mfilename('fullpath'));

if ~isdeployed, addpath(tbxdir); end

components = {
    'tsss_config'
    'tsss_config_momentspace'
    };

tsss = cfg_choice;
tsss.tag  = 'tsss';
tsss.name = 'TSSS';
tsss.help = {'Temporal Signal Space Separation (TSSS) toolbox'};

for i = 1:numel(components)
  tsss.values{i} = feval(components{i});
end


function p = addEquality(p,row)
% Equalities on top so easy
p.F_struc = [row;p.F_struc];
p.K.f = p.K.f + size(row,1);


function output = strjoin(input, separator)
%STRJOIN Concatenate an array into a single string.
%
%     S = strjoin(C)
%     S = strjoin(C, separator)
%
% Description
%
% S = strjoin(C) takes an array C and returns a string S which concatenates
% array elements with comma. C can be a cell array of strings, a character
% array, a numeric array, or a logical array. If C is a matrix, it is first
% flattened to get an array and concateneted. S = strjoin(C, separator) also
% specifies separator for string concatenation. The default separator is comma.
%
% Examples
%
%     >> str = strjoin({'this','is','a','cell','array'})
%     str =
%     this,is,a,cell,array
%
%     >> str = strjoin([1,2,2],'_')
%     str =
%     1_2_2
%
%     >> str = strjoin({1,2,2,'string'},'\t')
%     str =
%     1 2 2 string
%

  if nargin < 2, separator = ','; end
  assert(ischar(separator), 'Invalid separator input: %s', class(separator));
  separator = strrep(separator, '%', '%%');

  output = '';
  if ~isempty(input)
    if ischar(input)
      input = cellstr(input);
    end
    if isnumeric(input) || islogical(input)
      output = [repmat(sprintf(['%.15g', separator], input(1:end-1)), ...
                       1, ~isscalar(input)), ...
                sprintf('%.15g', input(end))];
    elseif iscellstr(input)
      output = [repmat(sprintf(['%s', separator], input{1:end-1}), ...
                       1, ~isscalar(input)), ...
                sprintf('%s', input{end})];
    elseif iscell(input)
      output = strjoin(cellfun(@(x)strjoin(x, separator), input, ...
                               'UniformOutput', false), ...
                       separator);
    else
      error('strjoin:invalidInput', 'Unsupported input: %s', class(input));
    end
  end
end


function [vertices, keypoints, smpl_parameter] = read_body_recon(reconstruction_dir)
    vertices = import_vertices_keypoints([reconstruction_dir, '/smpl_vertex.txt']);
    keypoints = import_vertices_keypoints([reconstruction_dir, '/keypoints.txt']);
    smpl_parameter = import_params([reconstruction_dir, '/smpl_parameter.txt']);
end

function vertices = import_vertices_keypoints(filename)
dataLines = [1, Inf];
opts = delimitedTextImportOptions("NumVariables", 3);
opts.DataLines = dataLines;
opts.Delimiter = " ";
opts.VariableNames = ["VarName1", "VarName2", "VarName3"];
opts.VariableTypes = ["double", "double", "double"];
opts.ExtraColumnsRule = "ignore";
opts.EmptyLineRule = "read";
opts.ConsecutiveDelimitersRule = "join";
opts.LeadingDelimitersRule = "ignore";
vertices = readtable(filename, opts);
vertices = table2array(vertices);
end

function params = import_params(filename, dataLines)
if nargin < 2
    dataLines = [1, Inf];
end
opts = delimitedTextImportOptions("NumVariables", 1);
opts.DataLines = dataLines;
opts.Delimiter = ",";
opts.VariableNames = "VarName1";
opts.VariableTypes = "double";
opts.ExtraColumnsRule = "ignore";
opts.EmptyLineRule = "read";
params = readtable(filename, opts);
params = table2array(params);
end


function [gKern, gVarmeans, gVarcovars] = kernVardistPsi0Gradient(kern, vardist, covGrad)

% KERNVARDISTPSI0GRADIENT description.
% VARGPLVM

    if ~strcmp(kern.type,'cmpnd')
       %
       fhandle = str2func([kern.type 'VardistPsi0Gradient']);
       [gKern, gVarmeans, gVarcovars] = fhandle(kern, vardist, covGrad);

       % Transformations
       gKern = paramTransformPsi0(kern, gKern);
       %
    else % the kernel is cmpnd
       %
       fhandle = str2func([kern.comp{1}.type 'VardistPsi0Gradient']);
       [gKern, gVarmeans, gVarcovars] = fhandle(kern.comp{1}, vardist, covGrad);
       % Transformations
       gKern = paramTransformPsi0(kern.comp{1}, gKern);
       %
       for i = 2:length(kern.comp)
           %
           fhandle = str2func([kern.comp{i}.type 'VardistPsi0Gradient']);
           [gKerni, gVarmeansi, gVarcovarsi] = fhandle(kern.comp{i}, vardist, covGrad);

           % Transformations
           gKerni = paramTransformPsi0(kern.comp{i}, gKerni);

           gVarmeans = gVarmeans + gVarmeansi;
           gVarcovars = gVarcovars + gVarcovarsi;
           gKern = [gKern gKerni];
           %
       end
       %
    end
end

% variational variances are positive (This should rather go to
% vargplvmLogLikeGradients)
%gVarcovars = (gVarcovars(:).*vardist.covars(:))';

%-----------------------------------------------------
% This applies transformations
% This must be done similar to kernGradient at some point
% function gK = paramTransformPsi0(kern, gK)
% %
% %
%     if strcmp(kern.type,'rbfardjit') | strcmp(kern.type,'rbfard2') | strcmp(kern.type,'bias') | strcmp(kern.type,'white')
%         gK(1) = gK(1)*kern.variance;
%     elseif strcmp(kern.type,'linard2')
%         gK(1:end) = gK(1:end).*kern.inputScales;
%     end
% end

function gKern = paramTransformPsi0(kern, gKern)

    fhandle = str2func([kern.type 'KernExtractParam']);
    params  = fhandle(kern);

    if length(kern.transforms) > 1
        for i=1:length(kern.transforms)
            fhandle = str2func([kern.transforms(i).type 'Transform']);
            if ~isfield(kern.transforms(i), 'transformsettings')
                gKern(kern.transforms(i).index) = gKern(kern.transforms(i).index).*fhandle(params(kern.transforms(i).index), 'gradfact');
            else
                gKern(kern.transforms(i).index) = gKern(kern.transforms(i).index).*fhandle(params(kern.transforms(i).index), 'gradfact', kern.transforms(i).transformsettings);
            end
        end
    else
        fhandle = str2func([kern.transforms.type 'Transform']);
        if ~isfield(kern.transforms, 'transformsettings')
            gKern(kern.transforms.index) = gKern(kern.transforms.index).*fhandle(params(kern.transforms.index), 'gradfact');
        else
            gKern(kern.transforms.index) = gKern(kern.transforms.index).*fhandle(params(kern.transforms.index), 'gradfact', kern.transforms.transformsettings);
        end
    end

end


classdef ElasticityMicroDefinedByLevelSet < CompositeResultsPrinter

    methods (Access = public)

        function obj = ElasticityMicroDefinedByLevelSet(d)
            obj.simulationStr = 'ElasticityMicroDefinedByLevelSet';
            obj.init(d);
        end

    end

    methods (Access = protected)

        function createPrinters(obj,d)
            obj.printers{1} = ResultsPrinter.create('DensityGauss',d);
            obj.printers{2} = ResultsPrinter.create('LevelSet',d);
            obj.printers{3} = ResultsPrinter.create('ElasticityMicro',d);
        end

        function storeFieldsToPrint(obj,d)
            obj.storeDensityGaussFields(d);
            obj.storeLevelSetFields(d);
            obj.storeMicroFields(d);
        end

    end

    methods (Access = protected)

        function storeDensityGaussFields(obj,d)
            di.fields = d.dens;
            obj.printers{1}.storeFieldsToPrint(di);
        end

        function storeLevelSetFields(obj,d)
            di.x = d.levelSet;
            obj.printers{2}.storeFieldsToPrint(di);
        end

        function storeMicroFields(obj,d)
            d.fields = d.microVar;
            obj.printers{3}.storeFieldsToPrint(d);
            obj.printers{3}.setStrVariablesMicroCase([])
        end

    end

end


function sliceBrowser(slice_figure, processed_images_folder, f, reference_size)
% -----------------------------------------------------------------
% browser to go through histology along with the reference browser
%-----------------------------------------------------------------

% initialize user data variables held by the figure
processed_images = dir([processed_images_folder filesep '*.tif']);
ud_slice.processed_image_names = natsortfiles({processed_images.name});
total_num_files = size(processed_images,1); disp(['found ' num2str(total_num_files) ' processed slice images']);
ud_slice.total_num_files = total_num_files;
ud_slice.break = 0;
ud_slice.slice_num = 1;
ud_slice.key = 1;
ud_slice.pointList = [];
ud_slice.pointHands = [];
ud_slice.getPoint = 0;
ud_slice.ref_size = reference_size(2:3);

ud_slice.processed_images = processed_images;
ud_slice.processed_images_folder = processed_images_folder;
ud_slice.sliceAx = axes('Position', [0.05 0.05 0.9 0.9]);
hold(ud_slice.sliceAx, 'on');
set(ud_slice.sliceAx, 'HitTest', 'off');
ud_slice.im = plotTVslice(zeros(ud_slice.ref_size, 'uint8'));

% create functions needed to interact with the figure
set(ud_slice.im, 'ButtonDownFcn', @(slice_figure,k)sliceClickCallback(slice_figure, k));
set(slice_figure, 'KeyPressFcn', @(slice_figure, keydata)SliceAtlasHotkeyFcn(slice_figure, keydata, f));
set(slice_figure, 'UserData', ud_slice)

% adjust figure to user's screen size
try; screen_size = get(0,'ScreenSize'); screen_size = [max(screen_size(3:4)) min(screen_size(3:4))]./[2560 1440];
catch; screen_size = [1900 1080]./[2560 1440];
end
set(slice_figure,'Position', [150*screen_size(1) 660*screen_size(2) 880*screen_size(1) 650*screen_size(2)])
movegui(slice_figure,'onscreen')

% set up first slice image
ud_slice = updateSliceImage(ud_slice);

% ------------------------------------------------
% Clicking function to register transform points
% ------------------------------------------------
function sliceClickCallback(im, keydata)
f = get(get(im, 'Parent'), 'Parent');
ud = get(f, 'UserData');

if ud.getPoint
    clickX = round(keydata.IntersectionPoint(1));
    clickY = round(keydata.IntersectionPoint(2));

    ud.pointList(end+1, :) = [clickX, ud.ref_size(1) - clickY];
    ud.pointHands(end+1) = plot(ud.sliceAx, clickX, clickY, 'ro', 'color', [0 .5 0],'linewidth',2,'markers',4);

     if clickX < 100 && (ud.ref_size(1) - clickY) < 100 % if click in corner, break
        ud.pointList = [];
        set(ud.pointHands(:), 'Visible', 'off');
     end

end
set(f, 'UserData', ud);

% ------------------------
% react to keyboard press
% ------------------------
function SliceAtlasHotkeyFcn(fig, keydata, f)

ud = get(fig, 'UserData');

% left arrow -- go to previous slice
if strcmp(keydata.Key,'leftarrow')
    if ud.slice_num > 1
        ud.slice_num = ud.slice_num - 1;
        ud = updateSliceImage(ud);
    end

% right arrow -- go to next slice
elseif strcmp(keydata.Key,'rightarrow')
    if ud.slice_num < ud.total_num_files
        ud.slice_num = ud.slice_num + 1;
        ud = updateSliceImage(ud);
    end
% d -- delete current transform points
elseif strcmp(keydata.Key,'d')
%     disp('current transform points deleted')
%     set(ud.pointHands(:), 'Visible', 'off');
%     ud.pointList = [];

    % Try to delete only most recent point
    set(ud.pointHands(end), 'Visible', 'off');
    ud.pointHands = ud.pointHands(1:end-1);
    ud.pointList = ud.pointList(1:end-1,:);
    disp('transform point deleted')
% t -- transform point mode
elseif strcmp(keydata.Key,'t')
    ud.getPoint = ~ud.getPoint;
        if ud.getPoint; disp('transform point mode!'); end
else
% otherwise -- call function to atlas browser
    figure(f);
    fcn = get(f, 'KeyPressFcn');
    fcn(f, keydata);
end

set(fig, 'UserData', ud);

function ud = updateSliceImage(ud)

    title_ending = '';

    processed_image_name = ud.processed_image_names{ud.slice_num};
    current_slice_image = flip(imread(fullfile(ud.processed_images_folder, processed_image_name)),1);
    % reduce to 3 channels at most
    color_channels = min( 3, size(current_slice_image,3));
    current_slice_image = current_slice_image(:,:,1:color_channels);
    % reduce to reference atlas size
    if size(current_slice_image,1) > ud.ref_size(1)+2 || size(current_slice_image,2) > ud.ref_size(2)+2
        disp(['shrinking image to reference size ' num2str(ud.ref_size(1)) ' x ' num2str(ud.ref_size(2)) ' pxl'])
        current_slice_image = imresize(current_slice_image, ud.ref_size);
    end
    set(ud.im, 'CData', current_slice_image);

    file_transformations = fullfile(ud.processed_images_folder, 'transformations\\' ,...
                            [processed_image_name(1:end-4) '_transform_data.mat']);

    set(ud.pointHands(:), 'Visible', 'off');
    ud.pointList = [];

    if exist(file_transformations,'file')
        % load transform data
        transform_data = load(file_transformations);
        transform_data = transform_data.save_transform;
        if ~isempty(transform_data.transform_points{2})
            ud.pointList = transform_data.transform_points{2};
            title_ending = ' (transform points loaded)';
        end
    end
    title(['Slice Viewer -- Slice ' num2str(ud.slice_num) '/' num2str(ud.total_num_files) title_ending])


function [muqOrig SqOrig] = modelPriorKernGrad(dynModel)
% MODELPRIORKERNGRAD
% see vargpTimeDynamicsPriorKernGrad. This function here is just a wrapper.
% VARGPLVM

fhandle = str2func([dynModel.type 'PriorKernGrad']);
[muqOrig SqOrig] = fhandle(dynModel);

% if isfield(model, 'paramGroups')
%  g = g*model.paramGroups;
% end


function [cfg] = ft_layoutplot(cfg, data)

% FT_LAYOUTPLOT makes a figure with the 2-D layout of the channel positions
% for topoplotting and the individual channel axes (i.e. width and height
% of the subfigures) for multiplotting. A correct 2-D layout is a
% prerequisite  for plotting the topographical distribution of the
% potential or field distribution, or for plotting timecourses in a
% topographical arrangement.
%
% This function uses the same configuration options as prepare_layout and
% as the topoplotting and multiplotting functions. The difference is that
% this function plots the layout without any data, which facilitates
% the validation of your 2-D layout.
%
% Use as
%   ft_layoutplot(cfg, data)
%
% There are several ways in which a 2-D layout can be made: it can be read
% directly from a *.lay file, it can be created based on 3-D electrode or
% gradiometer positions in the configuration or in the data, or it can be
% created based on the specification of an electrode of gradiometer file.
%
% You can specify either one of the following configuration options
%   cfg.layout      = filename containg the layout
%   cfg.rotate      = number, rotation around the z-axis in degrees (default = [], which means automatic)
%   cfg.projection  = string, 2D projection method can be 'stereographic', 'ortographic', 'polar', 'gnomic' or 'inverse' (default = 'orthographic')
%   cfg.elec        = structure with electrode positions or filename, see FT_READ_SENS
%   cfg.grad        = structure with gradiometer definition or filename, see FT_READ_SENS
%   cfg.opto        = structure with optode definition or filename, see FT_READ_SENS
%   cfg.output      = filename to which the layout will be written (default = [])
%   cfg.montage     = 'no' or a montage structure (default = 'no')
%   cfg.image       = filename, use an image to construct a layout (e.g. usefull for ECoG grids)
%   cfg.box         = string, 'yes' or 'no' whether box should be plotted around electrode (default = 'yes')
%   cfg.mask        = string, 'yes' or 'no' whether the mask should be plotted (default = 'yes')
%   cfg.visible     = string, 'on' or 'off' whether figure will be visible (default = 'on')
%   cfg.figure      = 'yes' or 'no', whether to open a new figure. You can also specify a figure handle from FIGURE, GCF or SUBPLOT. (default = 'yes')
%   cfg.position    = location and size of the figure, specified as [left bottom width height] (default is automatic)
%   cfg.renderer    = string, 'opengl', 'zbuffer', 'painters', see RENDERERINFO (default is automatic, try 'painters' when it crashes)
%
% Alternatively the layout can be constructed from either
%   data.elec     structure with electrode positions
%   data.grad     structure with gradiometer definition
%
% Alternatively, you can specify
%   cfg.layout = 'ordered'
% which will give you a 2-D ordered layout. Note that this is only suited
% for multiplotting and not for topoplotting.
%
% To facilitate data-handling and distributed computing you can use
%   cfg.inputfile   =  ...
% If you specify this option the input data will be read from a *.mat
% file on disk. This mat files should contain only a single variable named 'data',
% corresponding to the input structure.
%
% See also FT_PREPARE_LAYOUT, FT_TOPOPLOTER, FT_TOPOPLOTTFR, FT_MULTIPLOTER, FT_MULTIPLOTTFR

% Undocumented options
%   cfg.montage

% Copyright (C) 2006-2008, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

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

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

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

% the data can be passed as input argument or can be read from disk
hasdata = exist('data', 'var');

if hasdata
  % check if the input data is valid for this function
  data = ft_checkdata(data);
end

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'renamed', {'elecfile', 'elec'});
cfg = ft_checkconfig(cfg, 'renamed', {'gradfile', 'grad'});
cfg = ft_checkconfig(cfg, 'renamed', {'optofile', 'opto'});
cfg = ft_checkconfig(cfg, 'renamed', {'newfigure', 'figure'});

% set the defaults
cfg.box       = ft_getopt(cfg, 'box', 'yes');
cfg.mask      = ft_getopt(cfg, 'mask', 'yes');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% extract or generate the layout information
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

tmpcfg = keepfields(cfg, {'layout', 'channel', 'rows', 'columns', 'commentpos', 'skipcomnt', 'scalepos', 'skipscale', 'projection', 'viewpoint', 'rotate', 'width', 'height', 'elec', 'grad', 'opto', 'showcallinfo', 'trackcallinfo', 'trackusage', 'trackdatainfo', 'trackmeminfo', 'tracktimeinfo', 'checksize'});
if hasdata
  layout = ft_prepare_layout(tmpcfg, data);
else
  layout = ft_prepare_layout(tmpcfg);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% plot all details pertaining to the layout in one figure
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% open a new figure with the specified settings
h = open_figure(keepfields(cfg, {'figure', 'position', 'visible', 'renderer'}));

if isfield(cfg, 'image') && ~isempty(cfg.image)
  % start with the background image
  fprintf('reading background image from %s\n', cfg.image);
  img = imread(cfg.image);
  img = flipdim(img, 1); % in combination with "axis xy"

  bw = 1;

  if bw
    % convert to greyscale image
    img = mean(img, 3);
    imagesc(img);
    colormap gray
  else
    % plot as RGB image
    image(img);
  end
  axis equal
  axis off
  axis xy
end

ft_plot_layout(layout, 'point', true, 'box', cfg.box, 'label', true, 'mask', cfg.mask, 'outline', true);

% the following code can be used to verify a bipolar montage, given the
% layout of the monopolar channels
if isfield(cfg, 'montage') && ~isempty(cfg.montage)
  fprintf('plotting an arrow for each of the bipolar electrode pairs\n');
  % the arrow begins at the +1 electrode
  % the arrow ends   at the -1 electrode
  for i=1:length(cfg.montage.labelnew)
    begindx = find(cfg.montage.tra(i,:)==+1);
    endindx = find(cfg.montage.tra(i,:)==-1);
    if ~numel(begindx)==1 || ~numel(endindx)==1
      % the re-referenced channel does not seem to be a bipolar pair
      continue
    end
    % find the position of the begin and end of the arrow
    beglab = cfg.montage.labelold{begindx};
    endlab = cfg.montage.labelold{endindx};
    begindx = find(strcmp(layout.label, beglab)); % the index in the layout
    endindx = find(strcmp(layout.label, endlab)); % the index in the layout
    if ~numel(begindx)==1 || ~numel(endindx)==1
      % one of the channels in the bipolar pair does not seem to be in the layout
      continue
    end

    begpos = layout.pos(begindx,:);
    endpos = layout.pos(endindx,:);
    arrow(begpos, endpos, 'Length', 5)

  end % for all re-referenced channels
end % if montage

% this is needed for the figure title
if isfield(cfg, 'dataname') && ~isempty(cfg.dataname)
  dataname = cfg.dataname;
elseif isfield(cfg, 'inputfile') && ~isempty(cfg.inputfile)
  dataname = cfg.inputfile;
elseif nargin>1
  dataname = arrayfun(@inputname, 2:nargin, 'UniformOutput', false);
else
  dataname = {};
end

% set the figure window title
if ~isempty(dataname)
  set(h, 'Name', sprintf('%d: %s: %s', double(h), mfilename, join_str(', ', dataname)));
else
  set(h, 'Name', sprintf('%d: %s', double(h), mfilename));
end
set(h, 'NumberTitle', 'off');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% deal with the output
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% do the general cleanup and bookkeeping at the end of the function
ft_postamble debug
ft_postamble previous data
ft_postamble provenance
ft_postamble savefig

% add a menu to the figure, but only if the current figure does not have subplots
menu_fieldtrip(gcf, cfg, false);

if ~ft_nargout
  % don't return anything
  clear cfg
end


function infrasoundEventOut = auto_measure_amplitudes(infrasoundEvent, wevent, titleStr, predicted_traveltime_seconds, figureOutDirectory)
numEvents = numel(infrasoundEvent);
close all
min_traveltime = min(predicted_traveltime_seconds);
relative_traveltimes = predicted_traveltime_seconds - min_traveltime;
infrasoundEventOut = [];
for eventNumber=1:numEvents
    thisEvent = infrasoundEvent(eventNumber);
    thisW=wevent{eventNumber};

    thisEvent = auto_measure_minmax3(thisW, thisEvent, relative_traveltimes)
    ah=get(gcf,'Children');
    title(ah(7),sprintf('Event %d',eventNumber));

    feval('print', '-dpng', sprintf('%s/%s_%03d',figureOutDirectory, titleStr, eventNumber) );
    close
    infrasoundEventOut = [infrasoundEventOut thisEvent];
end


%%*****************************************************************************
%% HSDsqlpcheckconvg: check convergence.
%%
%% ZpATynorm, AX, normX, normZ are with respect to the
%% original variables, not the HSD variables.
%%
%% SDPT3: version 3.1
%% Copyright (c) 1997 by
%% K.C. Toh, M.J. Todd, R.H. Tutuncu
%% Last Modified: 16 Sep 2004
%%*****************************************************************************

function [param,breakyes,use_olditer,msg] = HSDsqlpcheckconvg(param,runhist)

termcode    = param.termcode;
iter        = param.iter;
obj         = param.obj;
relgap      = param.relgap;
gap         = param.gap;
prim_infeas = param.prim_infeas;
dual_infeas = param.dual_infeas;
mu          = param.mu;
prim_infeas_bad = param.prim_infeas_bad;
dual_infeas_bad = param.dual_infeas_bad;
printlevel  = param.printlevel;
stoplevel   = param.stoplevel;
inftol      = param.inftol;
gaptol      = param.gaptol;
kap         = param.kap;
tau         = param.tau;
theta       = param.theta;
breakyes    = 0;
use_olditer = 0;
msg         = [];
infeas      = max(prim_infeas,dual_infeas);
prim_infeas_min = min(param.prim_infeas_min, max(prim_infeas,1e-10));
dual_infeas_min = min(param.dual_infeas_min, max(dual_infeas,1e-10));
%%
err = max(infeas,relgap);
if (obj(2) > 0); homRd = param.ZpATynorm/obj(2); else homRd = inf; end
if (obj(1) < 0); homrp = norm(param.AX)/(-obj(1)); else homrp = inf; end
if (param.normX > 1e15*param.normX0 || param.normZ > 1e15*param.normZ0)
    termcode = 3;
    breakyes = 1;
end
if (homRd < min(1e-6,1e-2*sqrt(err*inftol)) && tau < 1e-4 ...
        && prim_infeas > 0.5*runhist.pinfeas(iter)) ...
        || (homRd < 10*tau && tau < 1e-7)
    termcode = 1;
    breakyes = 1;
end
if (homrp < min(1e-6,1e-2*sqrt(err*inftol)) && tau < 1e-4 ...
        && dual_infeas > 0.5*runhist.dinfeas(iter)) ...
        || (homrp < 10*tau && tau < 1e-7)
    termcode = 2;
    breakyes = 1;
end
if (err < gaptol)
    msg = sprintf('Stop: max(relative gap,infeasibilities) < %3.2e',gaptol);
    if (printlevel); fprintf('\n  %s',msg); end
    termcode = 0;
    breakyes = 1;
end
min_prim_infeas = min(runhist.pinfeas(1:iter));
prim_infeas_bad = prim_infeas_bad + (prim_infeas > ...
    max(1e-10,5*min_prim_infeas) && (min_prim_infeas < 1e-2));
if (mu < 1e-6)
    idx = max(1,iter-1): iter;
elseif (mu < 1e-3);
    idx = max(1,iter-2): iter;
else
    idx = max(1,iter-3): iter;
end
idx2 = max(1,iter-4): iter;
gap_ratio2 = runhist.gap(idx2+1)./runhist.gap(idx2);
gap_slowrate = min(0.8,max(0.6,2*mean(gap_ratio2)));
gap_ratio = runhist.gap(idx+1)./runhist.gap(idx);
pstep = runhist.step(iter+1);
if (infeas < 1e-4 || prim_infeas_bad) && (relgap < 1e-3) ...
        && (iter > 5) && (prim_infeas > (1-pstep/2)*runhist.pinfeas(iter))
    gap_slow = all(gap_ratio > gap_slowrate) && (relgap < 1e-3);
    min_pinfeas = min(runhist.pinfeas);
    if (relgap < 0.1*infeas) ...
            && ((runhist.step(iter+1) < 0.5) || (min_pinfeas < min(1e-6,0.1*prim_infeas))) ...
            && (dual_infeas > 0.9*runhist.dinfeas(iter) || (dual_infeas < 1e-2*gaptol))
        msg = 'Stop: relative gap < infeasibility';
        if (printlevel); fprintf('\n  %s',msg); end
        termcode = -1;
        breakyes = 1;
    elseif (gap_slow) && (infeas > 0.9*runhist.infeas(iter)) ...
            && (theta < 1e-8)
        msg = 'Stop: progress is too slow';
        if (printlevel); fprintf('\n  %s',msg); end
        termcode = -5;
        breakyes = 1;
    end
elseif (prim_infeas_bad) && (iter >50) && all(gap_ratio > gap_slowrate)
    msg = 'Stop: progress is bad';
    if (printlevel); fprintf('\n  %s',msg); end
    termcode = -5;
    breakyes = 1;
elseif (infeas < 1e-8) && (gap > 1.2*mean(runhist.gap(idx)))
    msg = 'Stop: progress is bad*';
    if (printlevel); fprintf('\n  %s',msg); end
    termcode = -5;
    breakyes = 1;
end
if (err < 1e-3) && (iter > 10) ...
        && (runhist.pinfeas(iter+1) > 0.9*runhist.pinfeas(max(1,iter-5))) ...
        && (runhist.dinfeas(iter+1) > 0.9*runhist.dinfeas(max(1,iter-5))) ...
        && (runhist.relgap(iter+1)  > 0.1*runhist.relgap(max(1,iter-5)));
    msg = 'Stop: progress is bad**';
    if (printlevel); fprintf('\n  %s',msg); end
    termcode = -5;
    breakyes = 1;
end
if (infeas > 100*max(1e-12,min(runhist.infeas)) && relgap < 1e-4)
    msg = 'Stop: infeas has deteriorated too much';
    if (printlevel); fprintf('\n  %s, %3.1e',msg,infeas); end
    use_olditer = 1;
    termcode = -7;
    breakyes = 1;
end
if (min(runhist.infeas) < 1e-4 || prim_infeas_bad) ...
        && (max(runhist.infeas) > 1e-4) && (iter > 5)
    relgap2 = abs(diff(obj))/(1+mean(abs(obj)));
    if (relgap2 < 1e-3);
        step_short = all(runhist.step(iter:iter+1) < 0.1) ;
    elseif (relgap2 < 1)
        idx = max(1,iter-3): iter+1;
        step_short = all(runhist.step(idx) < 0.05);
    else
        step_short = 0;
    end
    if (step_short)
        msg = 'Stop: steps too short consecutively';
        if (printlevel); fprintf('\n  %s',msg); end
        termcode = -5;
        breakyes = 1;
    end
end
if (iter > 3 && iter < 20) && (max(runhist.step(max(1,iter-3):iter+1)) < 1e-3) ...
        && (infeas > 1) && (min(homrp,homRd) > 1000*inftol)
    if (stoplevel >= 2)
        msg = 'Stop: steps too short consecutively';
        if (printlevel); fprintf('\n  %s',msg); end
        termcode = -5;
        breakyes = 1;
    end
end
if (pstep < 1e-4) && (err > 1.1*max(runhist.relgap(iter),runhist.infeas(iter)))
    msg = 'Stop: steps are too short';
    if (printlevel); fprintf('\n  %s',msg); end
    use_olditer = 1;
    termcode = -5;
    breakyes = 1;
end
if (iter == param.maxit)
    termcode = -6;
    msg = 'Stop: maximum number of iterations reached';
    if (printlevel); fprintf('\n  %s',msg); end
end
if (infeas < 1e-8 && relgap < 1e-10 && kap < 1e-13 && theta < 1e-15)
    msg = 'Stop: obtained accurate solution';
    if (printlevel); fprintf('\n  %s',msg); end
    termcode = 0;
    breakyes = 1;
end
param.prim_infeas_bad = prim_infeas_bad;
param.prim_infeas_min = prim_infeas_min;
param.dual_infeas_bad = dual_infeas_bad;
param.dual_infeas_min = dual_infeas_min;
param.termcode = termcode;
%%*****************************************************************************