function clear_except(varargin)

% The following function clears the command workspace except the
% variables specified by the user.

error(nargchk(1,inf,nargin)); % Checks for zero input arguments

s = evalin('caller','who'); % Get contents of command workspace

cnt = 0; % Count that keeps track of no. of inputs
for ii = 1:1:nargin
    for jj = 1:1:length(s)
        if strcmp(varargin{ii},s{jj}) % Compare command workspace contents with the user specified variables.
            cnt = cnt + 1;
            index(cnt) = jj;
        end
    end
end

if cnt < nargin
        error('MATLAB:clear_except:Unidentified', ... % If any of the input arguments not present in workspace generate an error.
        'One of the variables not present in the workspace');
end

e = length(s)-cnt; % This variable ensures if somebody by mistake calls this function with
                   % all variables of workspace as input arguments then the variables should
                   % not be cleared.

t ={};
for k = 1:1:nargin % Create the cell array of the variables that need to be cleared.
    for ii = 1:1:index(k)-1;
        t(ii) = {[s{ii} ' ']};
    end
    for ii = index(k)+1:1:length(s)
        t(ii) = {[s{ii} ' ']};
    end
    s = t;
    clear t;
end
if e == 0 % If e is zero, it implies that all the variables present in the workspace
          % have been given as input arguments to the function and hence
          % all of them needs to be preserved.
    return;
else
    evalin('caller',['clear ',s{:}]); % Clear the variables that are not in the input argument list.
end


function gmt_master(sOutput)

hAxes = gca;

gmt_init(hAxes, sOutput);

vKids = get(hAxes, 'Children');

for nCnt = length(vKids):-1:1
  sType = lower(get(vKids(nCnt), 'Type'));
  switch sType
  case 'surface'
    gmt_pcolor(vKids(nCnt), sOutput, num2str(nCnt));
  case 'line'
    gmt_xy(vKids(nCnt), sOutput, num2str(nCnt));
  end
end

gmt_done(sOutput);


function wstruct = swing(wsize,color,ax)

% SWING  Create a graphics structure with a wing shape.
%   WSTRUCT = SWING(WSIZE,COLR,AX) creates a structure for a 'patch'
%   graphic object correspoinding to a wing of size WSIZE, color COLR, in
%   axes AX.
%
%   See also WING, PATCH.

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

if nargin < 3
    ax = gca;
end

wstruct = wing(wsize);
wstruct.handle = patch(...
    'parent'   ,ax,...
    'vertices' ,wstruct.vert,...
    'faces'    ,wstruct.faces,...
    'linewidth',2,...
    'facecolor','none',...
    'edgecolor',color,...
    'visible'  ,'on');

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

%   # START GPL LICENSE

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

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

%   # END GPL LICENSE


classdef tPanelSettings < matlab.unittest.TestCase

    methods (Test, TestTags = {'Git'})
        function tPanelIRFt56(tc)
            opts = BEARsettings(4, 'ExcelFile', 'data.xlsx');

            fcn = @() setProp(opts, 'IRFt',5);
            tc.verifyError(fcn, 'bear:settings:PANELsettings:UnusedIRFt')

            fcn = @() setProp(opts, 'IRFt',6);
            tc.verifyError(fcn, 'bear:settings:PANELsettings:UnusedIRFt')
        end

        function tPanel1IRFt1(tc)
            opts = BEARsettings(4, 'ExcelFile', 'data.xlsx');
            opts.panel = 1;
            tc.verifyEqual(bear.PANELtype(1), opts.panel);

            fcn = @() setProp(opts, 'IRFt',2);
            tc.verifyError(fcn, 'bear:settings:PANELsettings:WrongIRFt')

            fcn = @() setProp(opts, 'IRFt',3);
            tc.verifyError(fcn, 'bear:settings:PANELsettings:WrongIRFt')

            fcn = @() setProp(opts, 'IRFt',4);
            tc.verifyError(fcn, 'bear:settings:PANELsettings:WrongIRFt')

        end

        function tPanel234IRFt234(tc)
            opts = BEARsettings(4, 'ExcelFile', 'data.xlsx');
            opts.panel = 2;
            tc.verifyEqual(bear.PANELtype(2), opts.panel);

            opts.IRFt = 1;
            tc.verifyEqual(bear.IRFtype(1), opts.IRFt);
            opts.IRFt = 2;
            tc.verifyEqual(bear.IRFtype(2), opts.IRFt);
            opts.IRFt = 3;
            tc.verifyEqual(bear.IRFtype(3), opts.IRFt);
            opts.IRFt = 4;
            tc.verifyEqual(bear.IRFtype(4), opts.IRFt);

            opts.panel = 3;
            tc.verifyEqual(bear.PANELtype(3), opts.panel);

            opts.IRFt = 1;
            tc.verifyEqual(bear.IRFtype(1), opts.IRFt);
            opts.IRFt = 2;
            tc.verifyEqual(bear.IRFtype(2), opts.IRFt);
            opts.IRFt = 3;
            tc.verifyEqual(bear.IRFtype(3), opts.IRFt);
            opts.IRFt = 4;
            tc.verifyEqual(bear.IRFtype(4), opts.IRFt);

            opts.panel = 2;
            tc.verifyEqual(bear.PANELtype(2), opts.panel);

            opts.IRFt = 1;
            tc.verifyEqual(bear.IRFtype(1), opts.IRFt);
            opts.IRFt = 2;
            tc.verifyEqual(bear.IRFtype(2), opts.IRFt);
            opts.IRFt = 3;
            tc.verifyEqual(bear.IRFtype(3), opts.IRFt);
            opts.IRFt = 4;
            tc.verifyEqual(bear.IRFtype(4), opts.IRFt);

        end

        function tPanel56(tc)
            opts = BEARsettings(4, 'ExcelFile', 'data.xlsx');
            opts.panel = 5;
            tc.verifyEqual(bear.PANELtype(5), opts.panel);
        end

        function tSwitchPanels(tc)
            opts = BEARsettings(4, 'ExcelFile', 'data.xlsx');
            opts.panel = 1;
            tc.verifyEqual(bear.PANELtype(1), opts.panel);
            tc.verifyEqual(bear.IRFtype(1), opts.IRFt);

            opts.panel = 3;
            tc.verifyEqual(bear.PANELtype(3), opts.panel);
            tc.verifyEqual(bear.IRFtype(1), opts.IRFt);
            opts.IRFt = 2;
            tc.verifyEqual(bear.IRFtype(2), opts.IRFt);

            opts.panel = 5;
            tc.verifyEqual(bear.PANELtype(5), opts.panel);
            tc.verifyEqual(bear.IRFtype(1), opts.IRFt);
        end
    end

end

function s = setProp(s, prop, value)
s.(prop) = value;
end


function GCO_BuildLib(Options)
% GCO_BuildLib    Attempt to compile and link the GCO_MATLAB library.
%    GCO_BuildLib is used internally by all other GCO_MATLAB commands
%    to recompile the wrapper library if it is not yet built.
%
%    YOU DO NOT NEED TO EXPLICITLY CALL THIS FUNCTION, unless you want to
%    customise the build settings via GCO_BuildLib(Options).
%    Default options:
%      Options.Debug=0        % optimised, detailed checking disabled
%      Options.EnergyType32=0 % 64-bit energy counter, 32-bit energy terms
%
%    Example:
%      % Enable detailed assertions (e.g. than energy does not go up
%      % during expansion) and use 32-bit energy counters (slightly faster)
%      GCO_BuildLib(struct('Debug',1,'EnergyType32',1));
%

if (nargin < 1)
    Options = struct();
end
if (~isfield(Options,'Debug')), Options.Debug = 0; end
if (~isfield(Options,'EnergyType32')), Options.EnergyType32 = 0; end
if (~isfield(Options,'Force')), Options.Force = 1; end

MEXFLAGS = '';
if (strcmp(computer(),'GLNXA64') || strcmp(computer(),'PCWIN64') || strcmp(computer(),'MACI64'))
    MEXFLAGS = [MEXFLAGS ' -largeArrayDims -DA64BITS'];
end
if (Options.Debug)
    MEXFLAGS = [MEXFLAGS ' -g'];
end
if (Options.EnergyType32)
    MEXFLAGS = [MEXFLAGS ' -DGCO_ENERGYTYPE32'];
end
if (strcmp(computer(),'PCWIN')) % link with libut for user interruptibility
    MEXFLAGS = [MEXFLAGS ' -D_WIN32 "' matlabroot() '\extern\lib\win32\microsoft\libut.lib"' ];
elseif (strcmp(computer(),'PCWIN64'))
    MEXFLAGS = [MEXFLAGS ' -D_WIN64 "' matlabroot() '\extern\lib\win64\microsoft\libut.lib"' ];
else
    MEXFLAGS = [MEXFLAGS ' -lut' ];
end

LIB_NAME = 'gco_matlab';
GCOMATDIR = fileparts(mfilename('fullpath'));
GCODIR = fileparts(GCOMATDIR);
OUTDIR = [ GCOMATDIR filesep 'bin' ];
[status msg msgid] = mkdir(GCOMATDIR, 'bin'); % Create bin directory
addpath(OUTDIR);                              % and add it to search path
if (~Options.Force && exist('gco_matlab')==3)
    return;
end
clear gco_matlab;

mexcmd = ['mex ' MEXFLAGS ' -outdir ''' OUTDIR ''' -output ' LIB_NAME ' ' ];

% Append all source file names to the MEX command string
SRCCPP = {
    [GCOMATDIR filesep 'gco_matlab.cpp'],
    [GCODIR filesep 'GCoptimization.cpp'],
    [GCODIR filesep 'graph.cpp'],
    [GCODIR filesep 'maxflow.cpp'],
    [GCODIR filesep 'LinkedBlockList.cpp']
    };
for f=1:length(SRCCPP)
    mexcmd = [mexcmd ' ''' SRCCPP{f} ''' '];
end

eval(mexcmd);  % compile and link in one step

end


function varargout=readsph(varargin)
%
% For calling details please see v_readsph.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_readsph.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: readsph.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_readsph(varargin{:});
else
    v_readsph(varargin{:});
end


function uTest_FiltFiltM(doSpeed)
% Unit test: FiltFiltM
% This is a routine for automatic testing. It is not needed for processing and
% can be deleted or moved to a folder, where it does not bother.
%
% uTest_FiltFiltM(doSpeed)
% INPUT:
%   doSpeed: If ANY(doSpeed) is TRUE, the speed is measured. Optional.
% OUTPUT:
%   On failure the test stops with an error.
%
% Tested: Matlab 6.5, 7.7, 7.8, WinXP
% Author: Jan Simon, Heidelberg, (C) 2009-2011 matlab.THISYEAR(a)nMINUSsimon.de

% $JRev: R-k V:010 Sum:VKPp090JCPL7 Date:19-Jul-2011 19:40:07 $
% $License: BSD (use/copy/change/redistribute on own risk, mention the author) $
% $File: Tools\UnitTests_\uTest_FiltFiltM.m $

% Init: ========================================================================
ErrHead = ['JSimon:', mfilename, ':TestFailed'];

if nargin == 0 || any(doSpeed)
   TestTime = 2.0;  % sec
else
   TestTime = 0.5;  % sec
end

% ==============================================================================
disp(['==== Test FiltFiltM  ', datestr(now, 0)]);
disp(['  Version: ', which('FiltFiltM')]);
pause(0.01);  % Flush events

fprintf('\nKnown answer tests:\n');
B = [];
A = [];
Y = FiltFiltM(B, A, []);
if ~isempty(Y)
   error(ErrHead, ['*** ', mfilename, ': Bad reply for empty signal']);
end
disp('  ok: all input empty');

B = [];
A = [];
X = rand(1000, 1);
Y = FiltFiltM(B, A, X);
if ~isempty(Y)
   error(ErrHead, ['*** ', mfilename, ': Bad reply for empty parameters']);
end
disp('  ok: empty parameters');

% [B, A] = ButterParam(2, 0.2, 'low')
B = [0.06745527, 0.1349105, 0.06745527];
A = [1, -1.142981, 0.4128016];
Y = FiltFiltM(B, A, []);
if ~isempty(Y)
   error(ErrHead, ...
      ['*** ', mfilename, ': Bad reply for empty signal with parameters']);
end
disp('  ok: empty signal');

Y = FiltFiltM(B, A, X);
Z = filtfilt(B, A, X);
if ~isequal(size(Y), size(Z)) || any(abs(Y - Z) > 10 * eps)
   error(ErrHead, ...
      ['*** ', mfilename, ': Bad result for [1000 x 1]']);
end
disp('  ok: [N x 1] vector');

Xt = reshape(X, 1, []);
Y  = FiltFiltM(B, A, Xt);
if ~isequal(size(Y), size(Xt)) || any(abs(Y(:) - Z(:)) > 10 * eps)
   error(ErrHead, ...
      ['*** ', mfilename, ': Bad result for [1 x 1000]']);
end
disp('  ok: [1 x N] vector');

X = [X, X];
Y = FiltFiltM(B, A, X);
Z = filtfilt(B, A, X);
if ~isequal(size(Y), size(Z)) || any(abs(Y(:) - Z(:)) > 10 * eps)
   error(ErrHead, ...
      ['*** ', mfilename, ': Bad result for [1000 x 2]']);
end
disp('  ok: 2D array, 1st dim');

X = transpose(X);
Y = FiltFiltM(B, A, X, 2);
Z = transpose(Z);
if ~isequal(size(Y), size(Z)) || any(abs(Y(:) - Z(:)) > 10 * eps)
   error(ErrHead, ...
      ['*** ', mfilename, ': Bad result for [2 x 1000], 2nd dim']);
end
disp('  ok: 2D array, 2nd dim');

X = rand(20, 30, 40);
Y = FiltFiltM(B, A, X);
Z = filtfilt(B, A, X);
if ~isequal(size(Y), size(Z)) || any(abs(Y(:) - Z(:)) > 10 * eps)
   error(ErrHead, ...
      ['*** ', mfilename, ': Bad result for [20 x 30 x 40]']);
end

Y = FiltFiltM(B, A, X, 2);
Z = ipermute(filtfilt(B, A, permute(X, [2,1,3])), [2,1,3]);
if ~isequal(size(Y), size(Z)) || any(abs(Y(:) - Z(:)) > 10 * eps)
   error(ErrHead, ...
      ['*** ', mfilename, ': Bad result for [20 x 30 x 40], 2nd dim']);
end

Y = FiltFiltM(B, A, X, 3);
Z = ipermute(filtfilt(B, A, permute(X, [3,1,2])), [3,1,2]);
if ~isequal(size(Y), size(Z)) || any(abs(Y(:) - Z(:)) > 10 * eps)
   error(ErrHead, ...
      ['*** ', mfilename, ': Bad result for [20 x 30 x 40], 3rd dim']);
end
disp('  ok: 3D array, 1st, 2nd, 3rd dim');

X = rand(1000, 1);
Y = FiltFiltM(B, A, X);
Z = FiltFiltM(B, A, reshape(X, 1, 1, []), []);
if ~isequal(size(Z), [1, 1, numel(X)]) || any(abs(Y(:) - Z(:)) > 10 * eps)
   error(ErrHead, ['*** ', mfilename, ...
      ': Bad result for [1 x 1 x 1000], 1st non-singelton']);
end
disp('  ok: [1 x 1 x N] array, 1st non-singelton');

% FILTER does not support SINGLES in Matlab 6.5:
try
   y = filter(B, A, single(ones(1, 100)));   %#ok<NASGU>
   FILTERforSINGLE = true;
catch
   FILTERforSINGLE = false;
   lasterr('');
end

if FILTERforSINGLE
   X  = rand(1000, 2);
   Y  = FiltFiltM(B, A, X);
   Xs = single(X);
   Ys = FiltFiltM(B, A, Xs);
   Zs = filtfilt(B, A, Xs);
   if ~isequal(size(Ys), size(Zs))
      error(ErrHead, ['*** ', mfilename, ': Bad result for SINGLE']);
   end
   epsSingle    = 1.192092895507813e-007;
   errFiltFiltM = max(abs(double(Ys(:)) - Y(:))) / epsSingle;
   errFILTFILT  = max(abs(double(Zs(:)) - Y(:))) / epsSingle;
   if any(errFiltFiltM > 10)
      error(ErrHead, ['*** ', mfilename, ': Bad result for SINGLE']);
   end
   disp('  ok: SINGLE array');
   fprintf(['      Difference to DOUBLE divided by EPS(SINGLE(1)):\n', ...
      '      FilterM: %g, FILTER: %g\n'], errFiltFiltM, errFILTFILT);

else
   v = sscanf(version, '%d.', 2);
   fprintf('  ok: FILTER does not accept SINGLE in Matlab %d.%d\n', v);
end

% ------------------------------------------------------------------------------
tooLazy = false;
fprintf('\nProvoke problems:\n');
try
   Y = FiltFiltM(B, A, rand(4));  %#ok<NASGU>
   tooLazy = true;
catch
   disp('  ok: Too short signal in dim 1 caught.');
end
if tooLazy
   error(ErrHead, ['*** ', mfilename, ': Too short signal accepted.']);
end

try
   Y = FiltFiltM(B, A, rand(4), 2);  %#ok<NASGU>
   tooLazy = true;
catch
   disp('  ok: Too short signal in dim 2 caught.');
end
if tooLazy
   error(ErrHead, ['*** ', mfilename, ': Too short signal accepted.']);
end

try
   Y = FiltFiltM(B, A, rand(1, 100), 3);  %#ok<NASGU>
   tooLazy = true;
catch
   disp('  ok: Dim out of range caught.');
end
if tooLazy
   error(ErrHead, ['*** ', mfilename, ': Dim out of range accepted.']);
end

try
   Y = FiltFiltM(B, A, rand(1, 100), -3.1);  %#ok<NASGU>
   tooLazy = true;
catch
   disp('  ok: Not integer Dim caught.');
end
if tooLazy
   error(ErrHead, ['*** ', mfilename, ': Not integer Dim accepted.']);
end

% Time test: -------------------------------------------------------------------
% Results on a Pentium-M 1500 MHz, 512MB RAM, WinXP, Matlab 2009a:
% Number of loops to get about 2 seconds run time
% 1000000 x 1:  6 loops,  FILTFILT: 1.930 sec,  FiltFiltM: 0.385 sec  ==> 20.0%
% 100000 x 1:  70 loops,  FILTFILT: 2.077 sec,  FiltFiltM: 0.488 sec  ==> 23.5%
% 10000 x 10:  82 loops,  FILTFILT: 1.996 sec,  FiltFiltM: 0.600 sec  ==> 30.0%
% 1000 x 100:  50 loops,  FILTFILT: 2.761 sec,  FiltFiltM: 0.518 sec  ==> 18.7%
% 100 x 100:  100 loops,  FILTFILT: 1.935 sec,  FiltFiltM: 0.079 sec  ==>  4.1%
% 100 x 1000:  12 loops,  FILTFILT: 2.303 sec,  FiltFiltM: 0.130 sec  ==>  5.6%

% A 4th order Butterworth filter: [B, A] = Butter(4, 0.25, 'low')
B = [0.0102094807912032, 0.0408379231648126, 0.0612568847472189, ...
   0.0408379231648126, 0.0102094807912032];
A = [1.0, -1.96842778693852, 1.73586070920889, -0.724470829507363, ...
   0.120389599896245];
fprintf('\n== Speed test with Butterworth filter of order %d:\n', ...
   length(B) - 1);

fprintf('Number of loops determined for about %g seconds run time\n', TestTime);

TestSize = {[1e6, 1], [1e5, 1], [1e4, 10], [1e3, 100], [100, 100], [100, 1e3]};
for iTest = 1:length(TestSize)
   % Create test data:
   aSize = TestSize{iTest};
   x     = rand(aSize(1), aSize(2));
   msg   = sprintf('  %d x %d:', aSize);
   fprintf('%-14s', msg);
   drawnow;

   % Run test of original function:
   iTime = cputime;
   nLoop = 0;
   while cputime - iTime < 1
      nLoop = nLoop + 1;
      origy = filtfilt(B, A, x);  %#ok<NASGU>
      clear('origy');
   end
   nLoop = max(2, ceil(nLoop * TestTime));
   fprintf('%5d loops\n', nLoop);

   % Run test for vectorized function:
   tic;
   for i = 1:nLoop
      origy = filtfilt(B, A, x);  %#ok<NASGU>
      clear('origy');
   end
   elapsed0 = toc;
   fprintf('    FILTFILT:  %8.3f sec\n', elapsed0);

   % Run test for vectorized function:
   tic;
   for i = 1:nLoop
      newy = FiltFiltM(B, A, x);  %#ok<NASGU>
      clear('newy');
   end
   elapsed1 = toc;
   fprintf('    FiltFiltM: %8.3f sec', elapsed1);
   fprintf('  ==> %.1f%%\n', 100 * elapsed1 / elapsed0);

   % Compare the results - usually the results are identical, but small round
   % off errors would be ok:
   origy = filtfilt(B, A, x);
   newy  = FiltFiltM(B, A, x);
   if isequal(origy, newy)
      fprintf('    Results are identical\n\n');
   elseif all(abs(origy(:) - newy(:)) < 10 * eps)
      fprintf('    Results are equal within 10*eps\n\n');
   else
      error(ErrHead, 'Different results - DO NOT USE FiltFiltM!');
   end
end

% Bye:
disp('== FiltFiltM passed the tests.');

return;


function res = sensors(this, type, newsens)
% Sets and gets sensor fields for EEG and MEG
% returns empty matrix if no sensors are defined.
% FORMAT res = sensors(this, type, newsens)
%   type - 'EEG' or 'MEG'
% _______________________________________________________________________
% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging

% Vladimir Litvak
% $Id: sensors.m 6829 2016-07-07 10:16:46Z vladimir $

if nargin<2
    error('Sensor type (EEG or MEG) must be specified');
end

switch lower(type)
    case 'eeg'
        if nargin < 3
            if isfield(this.sensors, 'eeg')
                res = this.sensors.eeg;
            else
                res = [];
            end
        else
            this.sensors(1).eeg = newsens;
            res = check(this);
        end
    case 'meg'
        if nargin < 3
            if isfield(this.sensors, 'meg')
                res = this.sensors.meg;
            else
                res = [];
            end
        else
            this.sensors(1).meg = newsens;
            res = check(this);
        end
    case 'src'
        if nargin < 3
            if isfield(this.sensors, 'src')
                res = this.sensors.src;
            else
                res = [];
            end
        else
            this.sensors(1).src = newsens;
            res = check(this);
        end
    otherwise
        error('Unsupported sensor type');
end

if  nargin < 3 && ~isempty(res) && ismember(lower(type), {'eeg', 'meg'}) && this.montage.Mind > 0
    sens = res;
    montage = this.montage.M(this.montage.Mind);
    if  ~isempty(intersect(sens.label, montage.labelorg))
        sensmontage = montage;
        [sel1, sel2] = spm_match_str(sens.label, sensmontage.labelorg);
        sensmontage.labelorg = sensmontage.labelorg(sel2);
        sensmontage.tra = sensmontage.tra(:, sel2);
        selempty  = find(all(sensmontage.tra == 0, 2));
        sensmontage.tra(selempty, :) = [];
        sensmontage.labelnew(selempty) = [];

        if isfield(sensmontage, 'chantypeorg')
            sensmontage.chantypeorg = sensmontage.chantypeorg(sel2);
        end
        if isfield(sensmontage, 'chanunitorg')
            sensmontage.chanunitorg = sensmontage.chanunitorg(sel2);
        end
        if isfield(sensmontage, 'chantypenew')
            sensmontage.chantypenew(selempty) = [];
        end
        if isfield(sensmontage, 'chanunitnew')
            sensmontage.chanunitnew(selempty) = [];
        end

        chanunitorig = sens.chanunit(sel1);
        chantypeorig = sens.chantype(sel1);
        labelorg     = sens.label;

        keepunused   = 'no'; % not sure if this is good for all cases

        sens = ft_apply_montage(sens, sensmontage, 'keepunused', keepunused);

        if strcmpi(type, 'MEG')
            if isfield(sens, 'balance') && ~isequal(sens.balance.current, 'none')
                balance = ft_apply_montage(getfield(sens.balance, sens.balance.current), sensmontage, 'keepunused', keepunused);
            else
                balance = sensmontage;
            end

            sens.balance.custom = balance;
            sens.balance.current = 'custom';
        end

        % If all the original channels contributing to a new channel have
        % the same units, transfer them to the new channel. This might be
        % wrong if the montage itself changes the units by scaling the data.
        if isfield(sens, 'chanunit')
            chanunit = sens.chanunit;
        else
            chanunit = repmat({'unknown'}, numel(sens.label), 1);
        end

        if isfield(sens, 'chantype')
            chantype = sens.chantype;
        else
            chantype = repmat({'unknown'}, numel(sens.label), 1);
        end

        for j = 1:numel(sens.label)
            k = strmatch(sens.label{j}, sensmontage.labelnew, 'exact');
            if ~isempty(k)
                if isequal(chanunit{j}, 'unknown')
                    unit = unique(chanunitorig(~~abs(sensmontage.tra(k, :))));
                    if numel(unit)==1
                        chanunit(j) = unit;
                    elseif strcmpi(type, 'MEG')
                        chanunit{j} = 'T';
                    else
                        chanunit{j} = 'V';
                    end
                end

                if isequal(chantype{j}, 'unknown')
                    ctype = unique(chantypeorig(~~abs(sensmontage.tra(k, :))));
                    if numel(ctype)==1
                        chantype(j) = ctype;
                    elseif strcmpi(type, 'MEG')
                        chantype{j} = 'megmag';
                    else
                        chantype{j} = 'eeg';
                    end
                end
            else %channel was not in the montage, but just copied
                k = strmatch(sens.label{j}, labelorg, 'exact');
                if isequal(chanunit{j}, 'unknown')
                    chanunit(j) = chanunitorig(k);
                end
                if isequal(chantype{j}, 'unknown')
                    chantype(j) = chantypeorig(k);
                end
            end
        end

        sens.chanunit = chanunit;
        sens.chantype = chantype;
    end

    if strcmpi(type, 'MEG')
        res = ft_datatype_sens(sens, 'amplitude', 'T', 'distance', 'mm');
    else
        res = ft_datatype_sens(sens, 'amplitude', 'V', 'distance', 'mm');
    end
end


function menucros() % autogenerated function wrapper
    %  menucros allows the user to establish parameters for zmaps
    %
    % turned into function by Celso G Reyes 2017
    error('replaced (enveloped) by magrcro');
    ZG=ZmapGlobal.Data; % used by get_zmap_globals
    report_this_filefun(mfilename('fullpath'));

    %issue a warning if no grid exist
    if ~exist('cumuall', 'var')
        ZmapMessageCenter.set_message('Warning', ' You have to create a grid first!')
        return
    end

    % This is the info window text
    %
    ttlStr='The various z-value maps             ';
    hlpStr1= ...
        ['                                                          '
        ' This window allows you to calculate various z-value maps:'
        ' Once you have created a grid you can apply               '
        ' several different statistics to it. See the              '
        ' User Guide for additional information                    '
        '                                                          '
        ' Maxz-LTA: Uses the LTA statistic and calculates a LTA    '
        ' z-value map for each time-step. Only the maximum value   '
        ' for all time at each grid point is finally plotted in the'
        ' map. Thsi allows to find the most outstanding decreases  '
        ' in the entire catalog.                                   '
        ' ANIMATION: Will produca a movie of several z-value maps  '
        ' at differnt times. Either the LTA or AS statistic will be'
        ' used. ! Uses large amounts of memory!                    '
        ' TIMECUT: Will display one z-value map for a specified    '
        ' time, using LTA, AS, Rubberband or Percent.              '
        '                                                          '
        ' ALARM: Will calculate an Alarm cube using LTA or         '
        ' Rubberband. If any z-value (all time and space) exceeds a'
        ' threshold an alarm is declared and plotted as a "o" in   '
        ' cube representing time and space. Will first calculate   '
        ' Histogram of all z-value                                 '
        '                                                          '];

    hlpStr2= ...
        ['                                                '
        '                                                '];

    % make the interface
    %

    figure(mess);
    report_this_filefun(mfilename('fullpath'));
    clf
    in2 ='input';
    set(gcf,'Name','ZMAP Parameters');
    set(gca,'visible','off');
    set(gcf,'Units','points','pos',[200 200 220 350 ])

    te = text(0.1,0.90,'You can choose from the \newlinefollowing options:');
    set(te,'FontSize',ZmapGlobal.Data.fontsz.m,'FontWeight','bold')

    te3 = text(0.15,0.38,'Timecuts') ;
    set(te3,'FontSize',ZmapGlobal.Data.fontsz.m,'Color','r','FontWeight','bold')

    LTA2_button=uicontrol('BackGroundColor',[0.8 0.8 0.8]','Style','Pushbutton',...
        'Position',[.10 .35 .45 .04 ],...
        'Units','normalized',...
        'callback',@(~,~)show_cro('lta',in2),...
        'String','LTA ');

    AS2_button=uicontrol('BackGroundColor',[0.8 0.8 0.8]','Style','Pushbutton',...
        'Position',[.10 .28 .45 .04 ],...
        'Units','normalized',...
        'callback',@(~,~)show_cro('ast',in2),...
        'String','AS ');

    per_button=uicontrol('BackGroundColor',[0.8 0.8 0.8]','Style','Pushbutton',...
        'Position',[.10 .20 .45 .04 ],...
        'Units','normalized',...
        'callback',@(~,~)show_cro('per',in2),...
        'String','Percent ');

    rub_button=uicontrol('BackGroundColor',[0.8 0.8 0.8]','Style','Pushbutton',...
        'Position',[.10 .12 .45 .04 ],...
        'Units','normalized',...
        'callback',@(~,~)show_cro('rub',in2),...
        'String','Rubberband');

    uicontrol('Style','Pushbutton',...
        'Position',[.70 .01 .25 .08 ],...
        'Units','normalized','Callback',@(~,~)ZmapMessageCenter(),'String','Cancel');

    uicontrol('Units','normal',...
        'Position',[.1 .01 .25 .08],'String','Info ',...
        'callback',@callbackfun_009)

    watchoff

    function callbackfun_009(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        zmaphelp(ttlStr,hlpStr1,hlpStr2);
    end

    function callbackfun_010(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        ZmapMessageCenter();
        drawnow;
        incube;
    end

end


function x = touch( p, x, iseq )
global cvx___
if nargin < 3, iseq = false; end

if isa( x, 'cvx' ),
    p  = index( p );
    b  = cvx_basis( x );
    y  = any( b, 2 );
    if iseq,
    	cvx___.canslack( y ) = false;
    end
    v  = cvx___.problems( p ).t_variable;
    nv = size( v, 1 );
    ny = length( y );
    if ny < nv,
        y( nv, : ) = 0;
    elseif nv < ny,
        y = y( 1 : nv, : );
    end
    cvx___.problems( p ).t_variable = v | y;
end

% Copyright 2010 Michael C. Grant and Stephen P. Boyd.
% See the file COPYING.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function estimateCombinedRF_batchHN(pathRF,nSplit,nBoot,testSplit,testCost,seed,matlabPATH)

startpath = pwd;

% INITIALIZATIONS
cd(pathRF)
load('clinicalPARAM') % parameters gets out of there
training = load('training'); training = struct2cell(training); training = training{1};
nameOutcomes = fieldnames(training.outcomes); nOutcomes = numel(nameOutcomes);
fSetNames = fieldnames(training.textures.(nameOutcomes{1})); nFset = numel(fSetNames);
comb = cell(1,nOutcomes);
for o = 1:nOutcomes
    comb{o} = {parameters.clinical.(nameOutcomes{o})};
end
time = 60;
mkdir('batchLog_RF'), cd('batchLog_RF'), pathBatch = pwd;

% PRODUCE BATCH COMPUTATIONS FOR RF ESTIMATION
batch = 0;
save('workspace','pathRF','nameOutcomes','fSetNames','comb','testCost','nSplit','testSplit','nBoot','seed'), pause(2);
for o = 1:nOutcomes
    for f = 1:nFset
        batch = batch + 1;
        nameScript = ['batch',num2str(batch),'_script.m'];
        fid = fopen(nameScript,'w');
        fprintf(fid,'load(''workspace'')\n');
        fprintf(fid,['[indClinic,bestCost] = estimateCombinedRF(pathRF,nameOutcomes{',num2str(o),'},fSetNames{',num2str(f),'},comb{',num2str(o),'},testCost,nSplit,testSplit,nBoot,seed);\n']);
        fprintf(fid,['save(''result_batch',num2str(batch),''',''indClinic'',''bestCost'')\n']);
        fprintf(fid,['system(''touch batch',num2str(batch),'_end'');\n']);
        fprintf(fid,'clear all');
        fclose(fid);
        system([matlabPATH,' -nojvm -nodisplay -nodesktop -nosplash < ',nameScript,' >& ',nameScript(1:end-1),'log &']);
    end
end

% WAITING LOOP
waitBatch(pathBatch,time,nOutcomes*nFset)
delete('workspace.mat')

% GROUP RESULTS IN THE 'training' STRUCT
cd(pathBatch)
batch = 0;
for o = 1:nOutcomes
    for f = 1:nFset
        batch = batch + 1;
        load(['result_batch',num2str(batch)]) % Variables 'indClinic' and 'bestCost' gets out of there
        training.clinical.bestAdd.(nameOutcomes{o}).(fSetNames{f}) = indClinic;
        training.cost.(nameOutcomes{o}).(fSetNames{f}) = bestCost;
        delete(['result_batch',num2str(batch),'.mat'])
        clear indClinic bestCost
    end
end
cd(pathRF), save('training','training')

cd(startpath)
end


function timer_tictoc_test ( )

%*****************************************************************************80
%
%% TIMER_TICTOC_TEST uses TIC and TOC as the timer.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    16 June 2006
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TIMER_TICTOC\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Demonstrate the use of the TIC routine.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  TIC and TOC are built-in MATLAB routines.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  To measure and print elapsed wallclock time:\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '    tic;\n' );
  fprintf ( 1, '    THINGS TO BE TIMED;\n' );
  fprintf ( 1, '    toc;\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  To store elapsed wallclock time:\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '    tic;\n' );
  fprintf ( 1, '    THINGS TO BE TIMED;\n' );
  fprintf ( 1, '    wallclock = toc;\n' );

  timer_tictoc_test01 ( );
  timer_tictoc_test02 ( );
  timer_tictoc_test03 ( );
  timer_tictoc_test04 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TIMER_TICTOC\n' );
  fprintf ( 1, '  Normal end of execution.\n' );

  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


%% t_meshShow
%
% This script loads a mesh and calls mrMesh to show it.
%
%
% See also:  t_meshFromClass
%
% (c) VISTASOFT, Stanford

%% Load an existing mesh and show it
tmp = load(fullfile(mrvDataRootPath,'anatomy','anatomyNIFTI','leftMesh.mat'));
msh = tmp.msh; clear tmp
msh = meshSet(msh,'actor',33);

windowID = 1000;
msh = meshSet(msh,'window id',1000);
meshVisualize(msh);

%% End


function [net,stats] = cnn_train_dicnn_dag(net, imdb, getBatch, varargin)
%CNN_DICNN_TRAIN_DAG Demonstrates training a CNN using the DagNN wrapper
%    CNN_TRAIN_DAG() is similar to CNN_TRAIN(), but works with
%    the DagNN wrapper instead of the SimpleNN wrapper.

% Copyright (C) 2014-16 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).
addpath(fullfile(vl_rootnn, 'examples'));

opts.expDir = fullfile('data','exp') ;
opts.continue = true ;
opts.batchSize = 256 ;
opts.numSubBatches = 1 ;
opts.train = [] ;
opts.val = [] ;
opts.gpus = [] ;
opts.prefetch = false ;
opts.epochSize = inf;
opts.numEpochs = 300 ;
opts.learningRate = 0.001 ;
opts.weightDecay = 0.0005 ;

opts.solver = [] ;  % Empty array means use the default SGD solver
[opts, varargin] = vl_argparse(opts, varargin) ;
if ~isempty(opts.solver)
  assert(isa(opts.solver, 'function_handle') && nargout(opts.solver) == 2,...
    'Invalid solver; expected a function handle with two outputs.') ;
  % Call without input arguments, to get default options
  opts.solverOpts = opts.solver() ;
end

opts.momentum = 0.9 ;
opts.saveSolverState = true ;
opts.nesterovUpdate = false ;
opts.randomSeed = 0 ;
opts.profile = false ;
opts.parameterServer.method = 'mmap' ;
opts.parameterServer.prefix = 'mcn' ;

opts.derOutputs = {'objective', 1} ;
opts.extractStatsFn = @extractStats ;
opts.plotStatistics = true;
opts.postEpochFn = [] ;  % postEpochFn(net,params,state) called after each epoch; can return a new learning rate, 0 to stop, [] for no change
opts = vl_argparse(opts, varargin) ;

if ~exist(opts.expDir, 'dir'), mkdir(opts.expDir) ; end
if isempty(opts.train), opts.train = find(imdb.images.set==1) ; end
if isempty(opts.val), opts.val = find(imdb.images.set==2) ; end
if isscalar(opts.train) && isnumeric(opts.train) && isnan(opts.train)
  opts.train = [] ;
end
if isscalar(opts.val) && isnumeric(opts.val) && isnan(opts.val)
  opts.val = [] ;
end

% -------------------------------------------------------------------------
%                                                            Initialization
% -------------------------------------------------------------------------

evaluateMode = isempty(opts.train) ;
if ~evaluateMode
  if isempty(opts.derOutputs)
    error('DEROUTPUTS must be specified when training.\n') ;
  end
end

% -------------------------------------------------------------------------
%                                                        Train and validate
% -------------------------------------------------------------------------

modelPath = @(ep) fullfile(opts.expDir, sprintf('net-epoch-%d.mat', ep));
modelFigPath = fullfile(opts.expDir, 'net-train.pdf') ;

start = opts.continue * findLastCheckpoint(opts.expDir) ;
if start >= 1
  fprintf('%s: resuming by loading epoch %d\n', mfilename, start) ;
  [net, state, stats] = loadState(modelPath(start)) ;
else
  state = [] ;
end

for epoch=start+1:opts.numEpochs

  % Set the random seed based on the epoch and opts.randomSeed.
  % This is important for reproducibility, including when training
  % is restarted from a checkpoint.

  rng(epoch + opts.randomSeed) ;
  prepareGPUs(opts, epoch == start+1) ;

  % Train for one epoch.
  params = opts ;
  params.epoch = epoch ;
  params.learningRate = opts.learningRate(min(epoch, numel(opts.learningRate))) ;
  params.train = opts.train(randperm(numel(opts.train))) ; % shuffle
  params.train = params.train(1:min(opts.epochSize, numel(opts.train)));
  params.val = opts.val(randperm(numel(opts.val))) ;
  params.imdb = imdb ;
  params.getBatch = getBatch ;

  if numel(opts.gpus) <= 1
    [net, state] = processEpoch(net, state, params, 'train') ;
    [net, state] = processEpoch(net, state, params, 'val') ;
    if ~evaluateMode
      saveState(modelPath(epoch), net, state) ;
    end
    lastStats = state.stats ;
  else
    spmd
      [net, state] = processEpoch(net, state, params, 'train') ;
      [net, state] = processEpoch(net, state, params, 'val') ;
      if labindex == 1 && ~evaluateMode
        saveState(modelPath(epoch), net, state) ;
      end
      lastStats = state.stats ;
    end
    lastStats = accumulateStats(lastStats) ;
  end

  stats.train(epoch) = lastStats.train ;
  stats.val(epoch) = lastStats.val ;
  clear lastStats ;
  saveStats(modelPath(epoch), stats) ;

  if opts.plotStatistics
    switchFigure(1) ; clf ;
    plots = setdiff(...
      cat(2,...
      fieldnames(stats.train)', ...
      fieldnames(stats.val)'), {'num', 'time'}) ;
    for p = plots
      p = char(p) ;
      values = zeros(0, epoch) ;
      leg = {} ;
      for f = {'train', 'val'}
        f = char(f) ;
        if isfield(stats.(f), p)
          tmp = [stats.(f).(p)] ;
          values(end+1,:) = tmp(1,:)' ;
          leg{end+1} = f ;
        end
      end
      subplot(1,numel(plots),find(strcmp(p,plots))) ;
      plot(1:epoch, values','o-') ;
      xlabel('epoch') ;
      title(p) ;
      legend(leg{:}) ;
      grid on ;
    end
    drawnow ;
    print(1, modelFigPath, '-dpdf') ;
  end

  if ~isempty(opts.postEpochFn)
    if nargout(opts.postEpochFn) == 0
      opts.postEpochFn(net, params, state) ;
    else
      lr = opts.postEpochFn(net, params, state) ;
      if ~isempty(lr), opts.learningRate = lr; end
      if opts.learningRate == 0, break; end
    end
  end
end

% With multiple GPUs, return one copy
if isa(net, 'Composite'), net = net{1} ; end

% -------------------------------------------------------------------------
function [net, state] = processEpoch(net, state, params, mode)
% -------------------------------------------------------------------------
% Note that net is not strictly needed as an output argument as net
% is a handle class. However, this fixes some aliasing issue in the
% spmd caller.

% initialize with momentum 0
if isempty(state) || isempty(state.solverState)
  state.solverState = cell(1, numel(net.params)) ;
  state.solverState(:) = {0} ;
end

% move CNN  to GPU as needed
numGpus = numel(params.gpus) ;
if numGpus >= 1
  net.move('gpu') ;
  for i = 1:numel(state.solverState)
    s = state.solverState{i} ;
    if isnumeric(s)
      state.solverState{i} = gpuArray(s) ;
    elseif isstruct(s)
      state.solverState{i} = structfun(@gpuArray, s, 'UniformOutput', false) ;
    end
  end
end
if numGpus > 1
  parserv = ParameterServer(params.parameterServer) ;
  net.setParameterServer(parserv) ;
else
  parserv = [] ;
end

% profile
if params.profile
  if numGpus <= 1
    profile clear ;
    profile on ;
  else
    mpiprofile reset ;
    mpiprofile on ;
  end
end

num = 0 ;
epoch = params.epoch ;
subset = params.(mode) ;
adjustTime = 0 ;

stats.num = 0 ; % return something even if subset = []
stats.time = 0 ;

start = tic ;
for t=1:params.batchSize:numel(subset)
  fprintf('%s: epoch %02d: %3d/%3d:', mode, epoch, ...
          fix((t-1)/params.batchSize)+1, ceil(numel(subset)/params.batchSize)) ;
  batchSize = min(params.batchSize, numel(subset) - t + 1) ;

  for s=1:params.numSubBatches
    % get this image batch and prefetch the next
    batchStart = t + (labindex-1) + (s-1) * numlabs ;
    batchEnd = min(t+params.batchSize-1, numel(subset)) ;
    batch = subset(batchStart : params.numSubBatches * numlabs : batchEnd) ;
    num = num + numel(batch) ;
    if numel(batch) == 0, continue ; end

    inputs = params.getBatch(params.imdb, batch) ;

    if params.prefetch
      if s == params.numSubBatches
        batchStart = t + (labindex-1) + params.batchSize ;
        batchEnd = min(t+2*params.batchSize-1, numel(subset)) ;
      else
        batchStart = batchStart + numlabs ;
      end
      nextBatch = subset(batchStart : params.numSubBatches * numlabs : batchEnd) ;
      params.getBatch(params.imdb, nextBatch) ;
    end

    if strcmp(mode, 'train')
      net.mode = 'normal' ;
      net.accumulateParamDers = (s ~= 1) ;
      net.eval(inputs, params.derOutputs, 'holdOn', s < params.numSubBatches) ;
    else
      net.mode = 'test' ;
      net.eval(inputs) ;
    end
  end

  % Accumulate gradient.
  if strcmp(mode, 'train')
    if ~isempty(parserv), parserv.sync() ; end
    state = accumulateGradients(net, state, params, parserv) ;
  end

  % Get statistics.
  time = toc(start) + adjustTime ;
  batchTime = time - stats.time ;
  stats.num = num ;
  stats.time = time ;
  stats = params.extractStatsFn(stats,net) ;
  currentSpeed = batchSize / batchTime ;
  averageSpeed = (t + batchSize - 1) / time ;
  if t == 3*params.batchSize + 1
    % compensate for the first three iterations, which are outliers
    adjustTime = 4*batchTime - time ;
    stats.time = time + adjustTime ;
  end

  fprintf(' %.1f (%.1f) Hz', averageSpeed, currentSpeed) ;
  for f = setdiff(fieldnames(stats)', {'num', 'time'})
    f = char(f) ;
    fprintf(' %s: %.3f', f, stats.(f)) ;
  end
  fprintf('\n') ;
end

% Save back to state.
state.stats.(mode) = stats ;
if params.profile
  if numGpus <= 1
    state.prof.(mode) = profile('info') ;
    profile off ;
  else
    state.prof.(mode) = mpiprofile('info');
    mpiprofile off ;
  end
end
if ~params.saveSolverState
  state.solverState = [] ;
else
  for i = 1:numel(state.solverState)
    s = state.solverState{i} ;
    if isnumeric(s)
      state.solverState{i} = gather(s) ;
    elseif isstruct(s)
      state.solverState{i} = structfun(@gather, s, 'UniformOutput', false) ;
    end
  end
end

net.reset() ;
net.move('cpu') ;

% -------------------------------------------------------------------------
function state = accumulateGradients(net, state, params, parserv)
% -------------------------------------------------------------------------
numGpus = numel(params.gpus) ;
otherGpus = setdiff(1:numGpus, labindex) ;

den = params.numSubBatches * max(numGpus,1) ;

for p=1:numel(net.params)

  if ~isempty(parserv)
    parDer = parserv.pullWithIndex(p) ;
  else
    parDer = net.params(p).der ;
  end

  switch net.params(p).trainMethod

    case 'average' % mainly for batch normalization
      thisLR = net.params(p).learningRate ;
      net.params(p).value = vl_taccum(...
          1 - thisLR, net.params(p).value, ...
          (thisLR/den/net.params(p).fanout),  parDer) ;

    case 'gradient'
      thisDecay = params.weightDecay * net.params(p).weightDecay ;
      thisLR = params.learningRate * net.params(p).learningRate ;

      if thisLR>0 || thisDecay>0
        % Normalize gradient and incorporate weight decay.
        parDer = vl_taccum(1/den, parDer, ...
                           thisDecay, net.params(p).value) ;

        if isempty(params.solver)
          % Default solver is the optimised SGD.
          % Update momentum.
          state.solverState{p} = vl_taccum(...
            params.momentum, state.solverState{p}, ...
            -1, parDer) ;

          % Nesterov update (aka one step ahead).
          if params.nesterovUpdate
            delta = params.momentum * state.solverState{p} - parDer ;
          else
            delta = state.solverState{p} ;
          end

          % Update parameters.
          net.params(p).value = vl_taccum(...
            1,  net.params(p).value, thisLR, delta) ;

        else
          % call solver function to update weights
          [net.params(p).value, state.solverState{p}] = ...
            params.solver(net.params(p).value, state.solverState{p}, ...
            parDer, params.solverOpts, thisLR) ;
        end
      end
    otherwise
      error('Unknown training method ''%s'' for parameter ''%s''.', ...
        net.params(p).trainMethod, ...
        net.params(p).name) ;
  end
end

% -------------------------------------------------------------------------
function stats = accumulateStats(stats_)
% -------------------------------------------------------------------------

for s = {'train', 'val'}
  s = char(s) ;
  total = 0 ;

  % initialize stats stucture with same fields and same order as
  % stats_{1}
  stats__ = stats_{1} ;
  names = fieldnames(stats__.(s))' ;
  values = zeros(1, numel(names)) ;
  fields = cat(1, names, num2cell(values)) ;
  stats.(s) = struct(fields{:}) ;

  for g = 1:numel(stats_)
    stats__ = stats_{g} ;
    num__ = stats__.(s).num ;
    total = total + num__ ;

    for f = setdiff(fieldnames(stats__.(s))', 'num')
      f = char(f) ;
      stats.(s).(f) = stats.(s).(f) + stats__.(s).(f) * num__ ;

      if g == numel(stats_)
        stats.(s).(f) = stats.(s).(f) / total ;
      end
    end
  end
  stats.(s).num = total ;
end

% -------------------------------------------------------------------------
function stats = extractStats(stats, net)
% -------------------------------------------------------------------------
sel = find(cellfun(@(x) isa(x,'dagnn.Loss'), {net.layers.block})) ;
for i = 1:numel(sel)
  if net.layers(sel(i)).block.ignoreAverage, continue; end;
  stats.(net.layers(sel(i)).outputs{1}) = net.layers(sel(i)).block.average ;
end

% -------------------------------------------------------------------------
function saveState(fileName, net_, state)
% -------------------------------------------------------------------------
net = net_.saveobj() ;
save(fileName, 'net', 'state') ;

% -------------------------------------------------------------------------
function saveStats(fileName, stats)
% -------------------------------------------------------------------------
if exist(fileName)
  save(fileName, 'stats', '-append') ;
else
  save(fileName, 'stats') ;
end

% -------------------------------------------------------------------------
function [net, state, stats] = loadState(fileName)
% -------------------------------------------------------------------------
load(fileName, 'net', 'state', 'stats') ;
net = dagnn.DagNN.loadobj(net) ;
if isempty(whos('stats'))
  error('Epoch ''%s'' was only partially saved. Delete this file and try again.', ...
        fileName) ;
end

% -------------------------------------------------------------------------
function epoch = findLastCheckpoint(modelDir)
% -------------------------------------------------------------------------
list = dir(fullfile(modelDir, 'net-epoch-*.mat')) ;
tokens = regexp({list.name}, 'net-epoch-([\d]+).mat', 'tokens') ;
epoch = cellfun(@(x) sscanf(x{1}{1}, '%d'), tokens) ;
epoch = max([epoch 0]) ;

% -------------------------------------------------------------------------
function switchFigure(n)
% -------------------------------------------------------------------------
if get(0,'CurrentFigure') ~= n
  try
    set(0,'CurrentFigure',n) ;
  catch
    figure(n) ;
  end
end

% -------------------------------------------------------------------------
function clearMex()
% -------------------------------------------------------------------------
clear vl_tmove vl_imreadjpeg ;

% -------------------------------------------------------------------------
function prepareGPUs(opts, cold)
% -------------------------------------------------------------------------
numGpus = numel(opts.gpus) ;
if numGpus > 1
  % check parallel pool integrity as it could have timed out
  pool = gcp('nocreate') ;
  if ~isempty(pool) && pool.NumWorkers ~= numGpus
    delete(pool) ;
  end
  pool = gcp('nocreate') ;
  if isempty(pool)
    parpool('local', numGpus) ;
    cold = true ;
  end

end
if numGpus >= 1 && cold
  fprintf('%s: resetting GPU\n', mfilename)
  clearMex() ;
  if numGpus == 1
    gpuDevice(opts.gpus)
  else
    spmd
      clearMex() ;
      gpuDevice(opts.gpus(labindex))
    end
  end
end


%  INTERNAL FUNCTION: Computes kron(T1,T2)*vec(X)
%
%


function planC = dose2CERR(doseNew,doseError,fractionGroupID,doseEdition,description,register,regParamsS,overWrite,assocScanUID,planC)
%function dose2CERR(doseNew,doseError,fractionGroupID,doseEdition,description,register,regParamsS,overWrite,planC)
%Use this function to put a new dose distribution into CERR.
%See test_dose2CERR in the putNewDose subdirectory for an example of its use.
%doseNew - 3-D array of dose values.
%doseError - estimate of standard deviation for Monte Carlo plans (can be left empty if not applicable, i.e. [])
%fractionGroupID - unique ID as a function of the number of fractions.
%doseEdition - another ID, see the RTOG specification.
%description - Short description string if desired.
%register - 'CT' or blank (defaults to CT), or non-CT.  If CT, registration geomtrical
%information is taken from the CT scan.  Otherwise, registration data is taken from regParamsS:
%regParamsS should contain geometric registration data including the following fields:
%regParamsS.horizontalGridInterval = 0.2 (say)  (x voxel width)
%regParamsS.verticalGridInterval   = 0.2 (say)  (y voxel width)
%regParamsS.coord1OFFirstPoint     = 0.5 (say)  (x value of center of upper left voxel on all slices)
%regParamsS.coord2OFFirstPoint     = 25  (say)  (y value of center of upper left voxel on all slices
%regParamsS.zValues                = [0.5 1.0 1.5 2.0 ...] (say) (z values of all slices)
%
%If overWrite = 'yes', overwrites the last written dose distribution.
%(x,y,z) are in the AAPM/RTOG coordinate system.
%El Naqa & Deasy, Feb 03.
%Latest Modifications: 7 March 03, JOD; input can be non-registered to CT scan.  Now using regParamsS.
%                      31 July 03, JOD, corrected use of fraction group ID.
%                       5  Nov 03, JOD, added overwrite flag
%                      12  Oct 06, APA, corrected horizontal/vertical grid interval assignment
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

if ~exist('planC','var')
    global planC
end
indexS=planC{end};
W = size(doseNew);
if ismatrix(doseNew) %Single slice
    temp = nan(W(1),W(2),3);
    temp(:,:,2) = doseNew;
    doseNew = temp;
    W(3) = 3;
end

%How many old dose distributions?
prevSets = length(planC{indexS.dose});

setIndex = prevSets + 1;

if nargin > 7 & strcmpi(overWrite,'yes')
  setIndex = prevSets;
end

%Get latest dose structure:
% [headerInitS, commentInitS, scanInitS, structureInitS, beamGeometryInitS, beamsInitS, digitalFilmInitS, doseInitS, ...
%            DVHInitS, seedGeometryInitS, RTTreatmentInitS, importLogInitS, planInitC, garbage] = initializeCERR;
doseInitS = initializeCERR('dose');
minDose = min(doseNew(:));
if minDose >= 0
    doseInitS(1).doseArray = doseNew;
else
    doseInitS(1).doseArray = doseNew - minDose;
    doseInitS(1).doseOffset = -minDose;
end
doseInitS(1).imageNumber=  '';
doseInitS(1).imageType='DOSE';
doseInitS(1).caseNumber=1;
doseInitS(1).patientName='';
doseInitS(1).doseNumber= setIndex;
doseInitS(1).doseType='PHYSICAL';
doseInitS(1).doseUnits='GRAYS';
doseInitS(1).doseScale=1;
doseInitS(1).fractionGroupID= fractionGroupID;
doseInitS(1).numberOfTx= '';
doseInitS(1).orientationOfDose='TRANSVERSE';
doseInitS(1).numberRepresentation=  '';
doseInitS(1).numberOfDimensions=length(W);
doseInitS(1).sizeOfDimension1=W(2);
doseInitS(1).sizeOfDimension2=W(1);
doseInitS(1).sizeOfDimension3=W(3);
if ~isempty(description)
  doseInitS(1).doseDescription=description;
end
if ~isempty(doseEdition)
  doseInitS(1).doseEdition= doseEdition;
end
doseInitS(1).unitNumber='';
doseInitS(1).writer='';
doseInitS(1).dateWritten='';
doseInitS(1).planNumberOfOrigin='';
doseInitS(1).planEditionOfOrigin='';
doseInitS(1).studyNumberOfOrigin='';
doseInitS(1).versionNumberOfProgram='';
doseInitS(1).xcoordOfNormaliznPoint='';
doseInitS(1).ycoordOfNormaliznPoint='';
doseInitS(1).zcoordOfNormaliznPoint='';
doseInitS(1).doseAtNormaliznPoint='';
doseInitS(1).coord3OfFirstPoint= '';   %Not used in CERR
doseInitS(1).depthGridInterval = '';
doseInitS(1).assocScanUID = assocScanUID;
doseInitS(1).doseUID = createUID('DOSE');

%Monte Carlo specific:
if ~isempty(doseError)
  doseInitS(1).doseError=doseError;
end

numDoses = length(planC{indexS.dose});
for i = 1 : numDoses
  origS = planC{indexS.dose}(i);
  tmpS(i) = backFillFieldNames(doseInitS,origS);
end

if numDoses > 0
  planC{indexS.dose} = tmpS;
end

if nargin > 5 & strcmpi(register,'CT')

    scanNum = getAssociatedScan(assocScanUID,planC);

    grid2Units = planC{indexS.scan}(scanNum).scanInfo(1).grid2Units;
    grid1Units = planC{indexS.scan}(scanNum).scanInfo(1).grid1Units;
    doseInitS(1).horizontalGridInterval = grid2Units;
    doseInitS(1).verticalGridInterval= - abs(grid1Units);

    abGrid1Units = abs(grid1Units);
    abGrid2Units = abs(grid2Units);

    xOffset = planC{indexS.scan}(scanNum).scanInfo(1).xOffset;
    yOffset = planC{indexS.scan}(scanNum).scanInfo(1).yOffset;

    CTWidth = planC{indexS.scan}(scanNum).scanInfo(1).sizeOfDimension2;
    CTHeight = planC{indexS.scan}(scanNum).scanInfo(1).sizeOfDimension1;

    doseInitS(1).coord1OFFirstPoint=  xOffset - (CTWidth/2) * abGrid2Units + abGrid2Units/2;
    doseInitS(1).coord2OFFirstPoint=  yOffset + (CTHeight/2) * abGrid1Units - abGrid1Units/2;

    % get from CT info:

    zValues = [planC{indexS.scan}(scanNum).scanInfo(:).zValue];
    doseInitS(1).zValues = zValues;
    doseInitS(1).delivered='';

elseif nargin > 6 & strcmpi(register,'UniformCT')

    scanNum = getAssociatedScan(assocScanUID,planC);

    uniformInfoS = planC{indexS.scan}(scanNum).uniformScanInfo;
    %[CTUniform3D, uniformInfoS] = getUniformizedCTScan;

    grid2Units = uniformInfoS.grid2Units;
    grid1Units = uniformInfoS.grid1Units;
    doseInitS(1).horizontalGridInterval = grid2Units;
    doseInitS(1).verticalGridInterval= - abs(grid1Units);

    abGrid1Units = abs(grid1Units);
    abGrid2Units = abs(grid2Units);

    xOffset = uniformInfoS.xOffset;
    yOffset = uniformInfoS.yOffset;

    CTWidth = uniformInfoS.sizeOfDimension2;
    CTHeight = uniformInfoS.sizeOfDimension1;

    doseInitS(1).coord1OFFirstPoint=  xOffset - (CTWidth/2) * abGrid2Units + abGrid2Units/2;
    doseInitS(1).coord2OFFirstPoint=  yOffset + (CTHeight/2) * abGrid1Units - abGrid1Units/2;

    % get from CT info:

    %sizeArray = getUniformizedSize(planC)
    sizeArray = getUniformScanSize(planC{indexS.scan}(scanNum));
    numSlices = sizeArray(3);
%    numSlices = size(CTUniform3D,3);

    zFirst = uniformInfoS.firstZValue;

    sliceThickness = uniformInfoS.sliceThickness;

    zLast = (numSlices - 1) * sliceThickness + zFirst;

    zValues = zFirst : sliceThickness: zLast;

    doseInitS(1).zValues = zValues;
    doseInitS(1).delivered='';

elseif nargin > 6 & ~strcmpi(register,'UniformCT') & ~strcmpi(register,'CT')

  doseInitS(1).horizontalGridInterval = regParamsS.horizontalGridInterval;
  doseInitS(1).verticalGridInterval   = regParamsS.verticalGridInterval;
  doseInitS(1).coord1OFFirstPoint     = regParamsS.coord1OFFirstPoint;
  doseInitS(1).coord2OFFirstPoint     = regParamsS.coord2OFFirstPoint;
  doseInitS(1).zValues                = regParamsS.zValues;

else

  error('Inputs to dose2CERR are incorrect')

end

% %Update the CERR dose menu
% try
%   putDoseMenu(stateS.handle.CERRSliceViewer, planC, indexS);
% end

planC{indexS.dose} = dissimilarInsert(planC{indexS.dose},doseInitS, setIndex,[]);  %This way future field additions are automatically included.


function [mesh, cfg] = ft_prepare_mesh(cfg, data)

% FT_PREPARE_MESH creates a triangulated surface mesh or tetrahedral/hexahedral
% volume mesh that can be used as geometrical description for a volume conduction
% model. The mesh can either be created manually from anatomical MRI data or can be
% generated starting from a segmented MRI. This function can also be used to create a
% cortex hull, i.e. the smoothed envelope around the pial surface created by
% freesurfer.
%
% Use as
%   mesh = ft_prepare_mesh(cfg)
%   mesh = ft_prepare_mesh(cfg, mri)
%   mesh = ft_prepare_mesh(cfg, seg)
%
% Configuration options:
%   cfg.method      = string, can be 'interactive', 'projectmesh', 'iso2mesh', 'isosurface',
%                     'headshape', 'hexahedral', 'tetrahedral','cortexhull', 'fittemplate'
%   cfg.tissue      = cell-array with strings representing the tissue types, or numeric vector with integer values
%   cfg.numvertices = numeric vector, should have same number of elements as the number of tissues
%
% When providing an anatomical MRI or a segmentation, you should specify
%   cfg.downsample  = integer number (default = 1, i.e. no downsampling), see FT_VOLUMEDOWNSAMPLE
%   cfg.spmversion  = string, 'spm2', 'spm8', 'spm12' (default = 'spm8')
%
% For method 'headshape' you should specify
%   cfg.headshape   = a filename containing headshape, a Nx3 matrix with surface
%                     points, or a structure with a single or multiple boundaries
%
% For method 'cortexhull' you should not give input data, but specify
%   cfg.headshape   = string, filename containing the pial surface computed by freesurfer recon-all
%
% For method 'fittemplate' you should specify
%   cfg.headshape   = a filename containing headshape
%   cfg.template    = a filename containing headshape
% With this method you are fitting the headshape from the configuration to the template;
% the resulting affine transformation is applied to the input mesh (or set of meshes),
% which is subsequently returned as output variable.
%
%
% To facilitate data-handling and distributed computing you can use
%   cfg.inputfile   =  ...
%   cfg.outputfile  =  ...
% If you specify one of these (or both) the input data will be read from a *.mat
% file on disk and/or the output data will be written to a *.mat file. These mat
% files should contain only a single variable, corresponding with the
% input/output structure.
%
% Example
%   mri             = ft_read_mri('Subject01.mri');
%
%   cfg             = [];
%   cfg.output      = {'scalp', 'skull', 'brain'};
%   segmentation    = ft_volumesegment(cfg, mri);
%
%   cfg             = [];
%   cfg.tissue      = {'scalp', 'skull', 'brain'};
%   cfg.numvertices = [800, 1600, 2400];
%   mesh            = ft_prepare_mesh(cfg, segmentation);
%
%   cfg             = [];
%   cfg.method      = 'cortexhull';
%   cfg.headshape   = '/path/to/surf/lh.pial';
%   cfg.fshome      = '/path/to/freesurfer dir';
%   cortex_hull     = ft_prepare_mesh(cfg);
%
% See also FT_VOLUMESEGMENT, FT_PREPARE_HEADMODEL, FT_PLOT_MESH

% Undocumented functionality: at this moment it allows for either
%   mesh = ft_prepare_mesh(cfg)             or
%   mesh = ft_prepare_mesh(cfg, headmodel)
% but more consistent would be to specify a volume conduction model with
%   cfg.headmodel     = structure with volume conduction model, see FT_PREPARE_HEADMODEL
%   cfg.headshape     = name of file containing the volume conduction model, see FT_READ_HEADMODEL
%
% Undocumented options, I have no clue why they exist
%   cfg.method = {'singlesphere' 'concentricspheres' 'localspheres'}

% Copyrights (C) 2009-2012, Robert Oostenveld & Cristiano Micheli
% Copyrights (C) 2012-2013, Robert Oostenveld & Lilla Magyari
%
% 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
ft_preamble trackconfig

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

% we cannot use nargin, because the data might have been loaded from cfg.inputfile
hasdata = exist('data', 'var');

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'forbidden', {'numcompartments', 'outputfile', 'sourceunits', 'mriunits'});

% get the options
cfg.downsample  = ft_getopt(cfg, 'downsample', 1);      % default is no downsampling
cfg.numvertices = ft_getopt(cfg, 'numvertices', 3000);  % set the default
cfg.smooth      = ft_getopt(cfg, 'smooth');             % no default
cfg.spmversion  = ft_getopt(cfg, 'spmversion', 'spm8');

% Translate the input options in the appropriate default for cfg.method
if isfield(cfg, 'headshape') && ~isempty(cfg.headshape)
  cfg.method = ft_getopt(cfg, 'method', 'headshape');
elseif hasdata && ~strcmp(ft_headmodeltype(data), 'unknown')
  cfg.method = ft_getopt(cfg, 'method', ft_headmodeltype(data));
elseif hasdata
  cfg.method = ft_getopt(cfg, 'method', 'projectmesh');
else
  cfg.method = ft_getopt(cfg, 'method', []);
end

if hasdata && cfg.downsample~=1
  % optionally downsample the anatomical volume and/or tissue segmentations
  tmpcfg = keepfields(cfg, {'downsample', 'showcallinfo'});
  data = ft_volumedownsample(tmpcfg, data);
  % restore the provenance information and put back cfg.smooth
  tmpsmooth = cfg.smooth;
  [cfg, data] = rollback_provenance(cfg, data);
  cfg.smooth = tmpsmooth;
end

switch cfg.method
  case 'interactive'
    % this makes sense with a non-segmented MRI as input
    % call the corresponding helper function
    mesh = prepare_mesh_manual(cfg, data);

  case {'projectmesh', 'iso2mesh', 'isosurface'}
    % this makes sense with a segmented MRI as input
    % call the corresponding helper function
    mesh = prepare_mesh_segmentation(cfg, data);

  case 'headshape'
    % call the corresponding helper function
    mesh = prepare_mesh_headshape(cfg);

  case 'hexahedral'
    % the MRI is assumed to contain a segmentation
    % call the corresponding helper function
    mesh = prepare_mesh_hexahedral(cfg, data);

  case 'tetrahedral'
    % the input data is assumed to contain a segmentation
    % call the corresponding helper function
    mesh = prepare_mesh_tetrahedral(cfg, data);

  case {'singlesphere' 'concentricspheres'}
    % the input data is assumed to contain a spherical head model
    data = ft_datatype_headmodel(data);   % ensure that it is consistent and up-to-date
    data = ft_determine_units(data);      % ensure that it has units

    if length(data.r)>1 && numel(cfg.numvertices)==1
      % use the same number of vertices for each tissue
      cfg.numvertices = repmat(cfg.numvertices, length(data.r));
    end

    mesh = [];
    for i=1:length(data.r)
      ft_info('triangulating sphere %d in the volume conductor\n', i);
      [pos, tri] = mesh_sphere(cfg.numvertices(i));
      mesh(i).pos(:,1) = pos(:,1)*data.r(i) + data.o(1);
      mesh(i).pos(:,2) = pos(:,2)*data.r(i) + data.o(2);
      mesh(i).pos(:,3) = pos(:,3)*data.r(i) + data.o(3);
      mesh(i).tri = tri;
    end

  case 'cortexhull'
    mesh = prepare_mesh_cortexhull(cfg);

  case 'fittemplate'
    M   = prepare_mesh_fittemplate(cfg.headshape.pos, cfg.template.pos);
    orig.mri = data;
    orig = ft_transform_geometry(M, orig);
    mesh = orig.data;

  otherwise
    ft_error('unsupported cfg.method')
end

% copy the geometrical units from the input to the output
if ~isfield(mesh, 'unit') && hasdata && isfield(data, 'unit')
  for i=1:numel(mesh)
    mesh(i).unit = data.unit;
  end
elseif ~isfield(mesh, 'unit')
  mesh = ft_determine_units(mesh);
end

% copy the coordinate system from the input to the output
if ~isfield(mesh, 'coordsys') && hasdata && isfield(data, 'coordsys')
  for i=1:numel(mesh)
    mesh(i).coordsys = data.coordsys;
  end
end

% smooth the mesh
if ~isempty(cfg.smooth)
  cfg.headshape = mesh;
  cfg.numvertices = [];
  mesh = prepare_mesh_headshape(cfg);
end

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


function y = cvx_constant( x )
narginchk(1,1);
y = x;

% Copyright 2005-2016 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function [result, why] = structeq(struct1, struct2, funh2string, ignorenan)
% STRUCTEQ performs an equality comparison between two structures by
% recursively comparing the elements of the struct array, their fields and
% subfields. This function requires companion function CELLEQ to compare
% two cell arrays.
%
% USAGE:
%
% structeq(struct1, struct2)
%       Performs a comparison and returns true if all the subfields and
%       properties of the structures are identical. It will fail if
%       subfields include function handles or other objects which don't
%       have a defined eq method.
%
% [iseq, info] = structeq(struct1, struct2)
%       This syntax returns a logical iseq and a second output info which
%       is a structure that contains a field "Reason" which gives you a
%       text stack of why the difference occurred as well as a field
%       "Where" which contains the indices and subfields of the structure
%       where the comparison failed. If iseq is true, info contains empty
%       strings in its fields.
%
% [...] = structeq(struct1, struct2, funh2string, ignorenan)
%       Illustrates an alternate syntax for the function with additional
%       input arguments. See the help for CELLEQ for more information on the
%       meaning of the arguments
%
% METHOD:
% 1. Compare sizes of struct arrays
% 2. Compare numbers of fields
% 3. Compare field names of the arrays
% 4. For every element of the struct arrays, convert the field values into
% a cell array and do a cell array comparison recursively (this can result
% in multiple recursive calls to CELLEQ and STRUCTEQ)
%
% EXAMPLE:
% % Compare two handle graphics hierarchies
% figure;
% g = surf(peaks(50));
% rotate3d
% hg1 = handle2struct(gcf);
% set(g,'XDataMode', 'manual');
% hg2 = handle2struct(gcf);
%
% structeq(hg1, hg2)
% [iseq, info] = structeq(hg1, hg2)
% [iseq, info] = structeq(hg1, hg2, true)

if nargin < 3
    funh2string = false;
end
if nargin < 4
    ignorenan = false;
end

why = struct('Reason','','Where','');

if any(size(struct1) ~= size(struct2))
    result = false;
    why = struct('Reason','Sizes are different',Where,'');
    return
end

fields1 = fieldnames(struct1);
fields2 = fieldnames(struct2);

% Check field lengths
if length(fields1) ~= length(fields2)
    result = false;
    why = struct('Reason','Number of fields are different','Where','');
    return
end

% Check field names
result = celleq(fields1,fields2);
result = all(result);
if ~result
    why = struct('Reason','Field names are different','Where','');
    return
end

for i = 1:numel(struct1)
    props1 = struct2cell(struct1(i));
    props2 = struct2cell(struct2(i));
    [result, subwhy] = celleq(props1,props2,funh2string,ignorenan);
    result = all(result);
    if ~result

        [fieldidx, subwhy.Where] = strtok(subwhy.Where, '}');
        fieldidx = str2double(fieldidx(2:end));
        %str2double(regexp(subwhy.Where,'{([0-9]+)}','tokens','once'));
        where = sprintf('(%d).%s%s',i,fields1{fieldidx},subwhy.Where(2:end));
        why = struct('Reason',sprintf('Properties are different <- %s',subwhy.Reason),'Where',where);
        return
    end
end


function [status, result] = lrsSpecifyRows(fileNameIn)
%read the number of rows of data in the file and replace the **** with the
%number of rows

if ~contains(fileNameIn,filesep)
    fileNameIn = [pwd filesep fileNameIn];
end

fid = fopen(fileNameIn,'r+');
if fid<0
    disp(fileNameOut)
    error('Could not open lrs output file.');
end

countRows = 0;
while 1
    tline = fgetl(fid);
    if countRows ~=0
        countRows = countRows + 1;
    end
    if strcmp(tline, 'begin')
        countRows = 1;
    elseif strcmp(tline, 'end')
        break
    elseif ~ischar(tline)
        error('Could not read lrs output file.');
    end
end
nRows = countRows -3;

%open the file and write the number of rows and columns
%The procedure to change the text in files under Linux/Unix using sed:
%Use Stream EDitor (sed) as follows:
%sed -i 's/old-text/new-text/g' input.txt
%The s is the substitute command of sed for find and replace
%It tells sed to find all occurrences of ‘old-text’ and replace with ‘new-text’ in a file named input.txt
[status, result] =  system(['sed -i ''s/\*\*\*\*\*/' int2str(nRows) '/g'' ' fileNameIn]);
if status == 1
    disp(result)
    error(['sed failed on file ' fileNameIn]);
end

end


classdef PTKAirwaysLabelledByLobe < PTKPlugin
    % PTKAirwaysLabelledByLobe. Plugin to visualise the airway tree labelled
    % according to lobe
    %
    %     This is a plugin for the Pulmonary Toolkit. Plugins can be run using
    %     the gui, or through the interfaces provided by the Pulmonary Toolkit.
    %     See PTKPlugin.m for more information on how to run plugins.
    %
    %     Plugins should not be run directly from your code.
    %
    %     PTKAirwaysLabelledByLobe calls the PTKAirways plugin to segment the
    %     airway tree and the PTKAirwayCentreline plguin to obtain the airway
    %     centreline. It then calls the library function PTKGetAirwaysLabelledByLobe
    %     to allocate each broncus to the unique lobe it serves. Bronchi serving
    %     more than one lobe are not displayed.
    %
    %     The resulting image is a labelled image with nonzero values
    %     representing bronchi allocated to the following lobes:
    %         1 - Upper right lobe
    %         2 - Mid right lobe
    %         4 - Lower right lobe
    %         5 - Upper left lobe
    %         6 - Lower left lobe
    %         3 - Lobe could not be determined with certainty
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2012.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    properties
        ButtonText = 'Airways <br>by lobe'
        ToolTip = 'Shows airways coloured by lobe, derived from analysis of the airway centreline'
        Category = 'Airways'

        AllowResultsToBeCached = true
        AlwaysRunPlugin = false
        PluginType = 'ReplaceOverlay'
        HidePluginInDisplay = false
        FlattenPreviewImage = true
        PTKVersion = '1'
        ButtonWidth = 6
        ButtonHeight = 2
        GeneratePreview = true
        Visibility = 'Developer'
        Version = 2

        EnableModes = MimModes.EditMode
        SubMode = MimSubModes.ColourRemapEditing
        EditRequiresPluginResult = true
    end

    methods (Static)
        function results = RunPlugin(dataset, reporting)
            results_image = dataset.GetTemplateImage(PTKContext.LungROI);
            [airway_results, airway_image] = dataset.GetResult('PTKAirways');
            centreline_results = dataset.GetResult('PTKAirwayCentreline');

            % Generate a map of all the bronchi (one mapped colour for each bronchus)
            [airway_mapped_image, labelled_centreline] = PTKMapAirwayCentrelineToImage(centreline_results, airway_image);

            % Find the airways for each lobe
            start_branches = PTKGetAirwaysLabelledByLobe(results_image, labelled_centreline, reporting);

            airway_mapping = PTKAirwaysLabelledByLobe.GetAirwayMappingForLobes(start_branches);
            airway_mapped_image.ChangeColorLabelMap(airway_mapping);

            results = [];
            results.AirwaysByLobeImage = airway_mapped_image;
            results.StartBranches = start_branches;
        end

        function start_branches = GetLobarStartBranchesFromAirwayMap(current_start_branches, airway_mapped_image)

            tree_root = current_start_branches.Trachea;
            left_upper_lobe = [];
            left_lower_lobe = [];
            right_upper_lobe = [];
            right_mid_lobe = [];
            right_lower_lobe = [];
            left_uncertain = [];

            % Generate the mapping for the lobes
            bronchi_to_do = CoreStack(tree_root);
            while ~bronchi_to_do.IsEmpty
                next_bronchus = bronchi_to_do.Pop;
                bronchus_label = next_bronchus.BronchusIndex;
                bronchus_mapping = airway_mapped_image.ColorLabelMap(bronchus_label + 1);
                if bronchus_mapping == 7
                    bronchi_to_do.Push(next_bronchus.Children);
                else
                    switch bronchus_mapping
                        case PTKColormapLabels.LeftUpperLobe
                            left_upper_lobe = [left_upper_lobe, next_bronchus];

                        case PTKColormapLabels.LeftLowerLobe
                            left_lower_lobe = [left_lower_lobe, next_bronchus];

                        case PTKColormapLabels.RightUpperLobe
                            right_upper_lobe = [right_upper_lobe, next_bronchus];

                        case PTKColormapLabels.RightLowerLobe
                            right_lower_lobe = [right_lower_lobe, next_bronchus];

                        case PTKColormapLabels.RightMiddleLobe
                            right_mid_lobe = [right_mid_lobe, next_bronchus];

                        case 3
                            left_uncertain = [left_uncertain, next_bronchus];
                    end
                end
            end

            start_branches = [];
            start_branches.Trachea = current_start_branches.Trachea;
            start_branches.Left = current_start_branches.Left;
            start_branches.Right = current_start_branches.Right;
            start_branches.LeftLower = left_lower_lobe;
            start_branches.LeftUpper = left_upper_lobe;
            start_branches.RightUpper = right_upper_lobe;
            start_branches.RightLower = right_lower_lobe;
            start_branches.RightMid = right_mid_lobe;
            start_branches.LeftUncertain = left_uncertain;
        end

        function airway_mapping = GetAirwayMappingForLobes(start_branches)

            airway_mapping = [];

            % Map the whole tree initially to 0 to take into account any
            % parent parenches of the lobar bronchi
            airway_mapping = PTKAirwaysLabelledByLobe.MapTheseBranchesToLabel(airway_mapping, start_branches.Trachea, 0);

            % Map the labels to the lobar colours
            airway_mapping = PTKAirwaysLabelledByLobe.MapTheseBranchesToLabel(airway_mapping, start_branches.LeftUpper, PTKColormapLabels.LeftUpperLobe);
            airway_mapping = PTKAirwaysLabelledByLobe.MapTheseBranchesToLabel(airway_mapping, start_branches.LeftLower, PTKColormapLabels.LeftLowerLobe);
            airway_mapping = PTKAirwaysLabelledByLobe.MapTheseBranchesToLabel(airway_mapping, start_branches.RightUpper, PTKColormapLabels.RightUpperLobe);
            airway_mapping = PTKAirwaysLabelledByLobe.MapTheseBranchesToLabel(airway_mapping, start_branches.RightLower, PTKColormapLabels.RightLowerLobe);
            airway_mapping = PTKAirwaysLabelledByLobe.MapTheseBranchesToLabel(airway_mapping, start_branches.RightMid, PTKColormapLabels.RightMiddleLobe);
            airway_mapping = PTKAirwaysLabelledByLobe.MapTheseBranchesToLabel(airway_mapping, start_branches.LeftUncertain, 3);
            airway_mapping = PTKAirwaysLabelledByLobe.MapTheseBranchesToLabel(airway_mapping, start_branches.RightUncertain, 3);
            airway_mapping(airway_mapping == 0) = 7;
            airway_mapping(1) = 0;
        end

        function airway_mapping = MapTheseBranchesToLabel(airway_mapping, branch_list, label)
            branches_to_label = CoreStack(branch_list);
            while ~branches_to_label.IsEmpty
                branch = branches_to_label.Pop;
                airway_mapping(branch.BronchusIndex + 1) = label;
                branches_to_label.Push(branch.Children);
            end
        end

        function results = GenerateImageFromResults(airway_results, ~, ~)
            results = airway_results.AirwaysByLobeImage;
        end

        function results = GetEditedResult(saved_result, edited_result_image, ~)
            start_branches = PTKAirwaysLabelledByLobe.GetLobarStartBranchesFromAirwayMap(saved_result.StartBranches, edited_result_image);

            results = [];
            results.AirwaysByLobeImage = edited_result_image;
            results.StartBranches = start_branches;
        end

    end
end


function VBA_spm_defaults
% Set the defaults which are used by SPM
%__________________________________________________________________________
%
% If you want to customise some defaults for your installation, do not
% modify this file directly, but create a file named spm_my_defaults.m
% instead, accessible from MATLAB search path; e.g., it can be saved in
% MATLAB Startup Folder: userhome/Documents/MATLAB.
%
% Example: create the following file to change the image file extension:
% ----------- file /home/karl/Documents/MATLAB/spm_my_defauls.m -----------
% global defaults
% defaults.images.format = 'img';
%--------------------------------------------------------------------------
%
% spm_defaults should not be called directly in any script or function
% (apart from SPM internals).
% To load the defaults, use spm('Defaults',modality).
% To get/set the defaults, use spm_get_defaults.
%
%                 ** This file should not be edited **
%__________________________________________________________________________
% Copyright (C) 1994-2014 Wellcome Trust Centre for Neuroimaging

% SPM
% $Id: spm_defaults.m 6221 2014-09-30 20:52:29Z guillaume $

global defaults

% Command Line Usage default
%==========================================================================
defaults.cmdline  = 0;

% User Interface defaults
%==========================================================================
defaults.ui.monitor = NaN;
defaults.ui.colour  = [0.58 0.77 0.57];
defaults.ui.fs      = 14;  % unused
defaults.ui.print   = 'ps';
defaults.renderer   = 'zbuffer';

% File format specific
%==========================================================================
% Note that defaults.analyze.flip is no longer used.  Specifying the
% left/right handedness of the voxel indices is now done entirely by
% spm_flip_analyze_images.m
defaults.images.format  = 'nii'; % options: 'img', 'nii'
defaults.mat.format     = '-v6'; % options: '-mat', '-v6', '-v7.0', '-v7.3'

% Toolboxes defaults
%==========================================================================
defaults.tbx.dir = { fullfile(spm('Dir'),'toolbox') };

% DICOM Import defaults
%==========================================================================
defaults.dicom.root = 'flat'; % Folder hierarchy

% fMRI design defaults
%==========================================================================
defaults.stats.fmri.t   = 16;
defaults.stats.fmri.t0  = 8;
defaults.stats.fmri.hpf = 128;
defaults.stats.fmri.cvi = 'AR(1)';

% Mask defaults
%==========================================================================
defaults.mask.thresh    = 0.8;

% Stats defaults
%==========================================================================
defaults.stats.maxmem      = 2^26;
defaults.stats.maxres      = 64;
defaults.stats.resmem      = false;
defaults.stats.fmri.ufp    = 0.001;  % Upper tail F-probability
defaults.stats.pet.ufp     = 0.05;
defaults.stats.eeg.ufp     = 0.05;
defaults.stats.topoFDR     = 1;
defaults.stats.rft.nonstat = 0;
defaults.stats.results.volume.distmin =  8;
defaults.stats.results.volume.nbmax   =  3;
defaults.stats.results.svc.distmin    =  4;
defaults.stats.results.svc.nbmax      = 16;
defaults.stats.results.mipmat         = {fullfile(spm('dir'),'MIP.mat')};

% Filename prefix defaults
%==========================================================================
defaults.slicetiming.prefix     = 'a';
defaults.realign.write.prefix   = 'r';
defaults.coreg.write.prefix     = 'r';
defaults.unwarp.write.prefix    = 'u';
defaults.normalise.write.prefix = 'w';
defaults.smooth.prefix          = 's';

% Realignment defaults
%==========================================================================
defaults.realign.estimate.quality = 0.9;
defaults.realign.estimate.interp  = 2;
defaults.realign.estimate.wrap    = [0 0 0];
defaults.realign.estimate.sep     = 4;
defaults.realign.estimate.fwhm    = 5;
defaults.realign.estimate.rtm     = 1;
defaults.realign.write.mask       = 1;
defaults.realign.write.interp     = 4;
defaults.realign.write.wrap       = [0 0 0];
defaults.realign.write.which      = [2 1];

% Unwarp defaults
%==========================================================================
defaults.unwarp.estimate.rtm      = 0;
defaults.unwarp.estimate.fwhm     = 4;
defaults.unwarp.estimate.basfcn   = [12 12];
defaults.unwarp.estimate.regorder = 1;
defaults.unwarp.estimate.regwgt   = 1e5;
defaults.unwarp.estimate.foe      = [4 5];
defaults.unwarp.estimate.soe      = [];
defaults.unwarp.estimate.rem      = 1;
defaults.unwarp.estimate.jm       = 0;
defaults.unwarp.estimate.noi      = 5;
defaults.unwarp.estimate.expround = 'Average';
%
% Unwarp uses defaults.realign.write
% defaults for writing.
%

% Coregistration defaults
%==========================================================================
defaults.coreg.estimate.cost_fun = 'nmi';
defaults.coreg.estimate.sep      = [4 2];
defaults.coreg.estimate.tol      = [0.02 0.02 0.02 0.001 0.001 0.001 0.01 0.01 0.01 0.001 0.001 0.001];
defaults.coreg.estimate.fwhm     = [7 7];
defaults.coreg.write.interp      = 4;
defaults.coreg.write.wrap        = [0 0 0];
defaults.coreg.write.mask        = 0;

% Spatial Normalisation defaults
%==========================================================================
defaults.normalise.write.preserve   = 0;
defaults.normalise.write.bb         = [[-78 -112 -70];[78 76 85]];
defaults.normalise.write.vox        = [2 2 2];
defaults.normalise.write.interp     = 4;

% Old Spatial Normalisation defaults
%==========================================================================
defaults.old.normalise.estimate.smosrc  = 8;
defaults.old.normalise.estimate.smoref  = 0;
defaults.old.normalise.estimate.regtype = 'mni';
defaults.old.normalise.estimate.weight  = '';
defaults.old.normalise.estimate.cutoff  = 25;
defaults.old.normalise.estimate.nits    = 16;
defaults.old.normalise.estimate.reg     = 1;
defaults.old.normalise.write.preserve   = 0;
defaults.old.normalise.write.bb         = [[-78 -112 -70];[78 76 85]];
defaults.old.normalise.write.vox        = [2 2 2];
defaults.old.normalise.write.interp     = 1;
defaults.old.normalise.write.wrap       = [0 0 0];
defaults.old.normalise.write.prefix     = 'w';

% VBM Preprocessing defaults
%==========================================================================
defaults.old.preproc.tpm     = cellstr(char(...
    fullfile(spm('Dir'),'toolbox','OldSeg','grey.nii'),...
    fullfile(spm('Dir'),'toolbox','OldSeg','white.nii'),...
    fullfile(spm('Dir'),'toolbox','OldSeg','csf.nii'))); % Prior probability maps
defaults.old.preproc.ngaus          = [2 2 2 4]'; % Gaussians per class
defaults.old.preproc.warpreg        = 1;          % Warping Regularisation
defaults.old.preproc.warpco         = 25;         % Warp Frequency Cutoff
defaults.old.preproc.biasreg        = 0.0001;     % Bias regularisation
defaults.old.preproc.biasfwhm       = 60;         % Bias FWHM
defaults.old.preproc.regtype        = 'mni';      % Affine Regularisation
defaults.old.preproc.fudge          = 5;          % Fudge factor, can not be set in batch GUI
defaults.old.preproc.samp           = 3;          % Sampling distance
defaults.old.preproc.output.GM      = [0 0 1];
defaults.old.preproc.output.WM      = [0 0 1];
defaults.old.preproc.output.CSF     = [0 0 0];
defaults.old.preproc.output.biascor = 1;
defaults.old.preproc.output.cleanup = 0;

% Smooth defaults
%==========================================================================
defaults.smooth.fwhm = [8 8 8];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%-Prevent users from making direct calls to spm_defaults
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
persistent runOnce
try
    if ~isdeployed && isempty(runOnce)
        d = dbstack;
        if isempty(intersect({'spm','spm_get_defaults'},{d.name}))
            fprintf(['Direct calls to spm_defauts are deprecated.\n' ...
                'Please use spm(''Defaults'',modality) ' ...
                'or spm_get_defaults instead.\n']);
            runOnce = 1;
        end
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%-Execute user-specified defaults files
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
def = defaults;
user_defaults = 'spm_my_defaults.m';
if exist(user_defaults,'file')
    if isdeployed && exist(fullfile(spm('Dir'),user_defaults),'file')
        user_defaults_file = cellstr(fullfile(spm('Dir'),user_defaults));
    else
        user_defaults_file = which(user_defaults,'-ALL');
    end
    for i=1:numel(user_defaults_file)
        try
            spm('run', user_defaults_file{i});
        catch
            lr = lasterror;
            warning(lr.message);
        end
    end
    if spm_check_version('matlab','8.0') >= 0, my_isequaln = @isequaln;
    else my_isequaln = @isequalwithequalnans; end
    if ~my_isequaln(def,defaults)
        fprintf('Defaults settings have been modified by file(s):\n');
        for i=1:numel(user_defaults_file)
            fprintf('  %s\n',user_defaults_file{i});
        end
        fn0 = fieldnames(def);
        mf = fn0(~cellfun(@(x) my_isequaln(def.(x),defaults.(x)),fn0));
        if ~isempty(mf)
            fprintf('Modified fields: ');
            for i=1:numel(mf)
                fprintf('%s ',mf{i});
            end
            fprintf('\n');
        end
    end
end


function obj = setVertexProperties(obj, vertex, varargin)
% Sets the values of vertex properties
%
% Parameters:
%  vertex: the names of the vertices to be configured. It must be a cell string or a
%  character array.
%  @type cellstr
%  PropName: a character vector specifiy the name of a vertex property
%  for the added vertices. It must be given as a ''Name''-''Value'' pairs.
%  PropValue: the values of the vertex properties specified by the
%  ''PropName''. It must be scalar or a cell array with the the same length
%  of the number of the vertices to be added. If it is a scalar, all edges
%  will be assign this scalar value.
%  Use syntex
%  @verbatim sys =  addVertex(sys, Vert, PropName,PropValue,...) @endverbatim
%  @type char
%
% @note A struct can be used to replace the (PropName, PropValue) inputs.
% To be valid input, the structure must have fields with the same name as
% vertex properties. For mutilple nodes, use the array of structures instead of
% the structure of arrays. Invalid fields in the structure will be ignored,
% and missing properties will be added with their default values.

% check if the specified vertices exist in the graph
vert = findnode(obj.Gamma, vertex);
if any(find(~vert))
    error('The following vertices are NOT found in the graph: %s\n',...
        implode(vertex(~vert),', '));
end

nNode = numel(vert);

if ~ischar(varargin{1})
    error(['The thrid argument is expected to be a character vector.\n',...
        'Instead it is a %s'], class(varargin{1}));
end

% create a struct from the input ''Name-Value'' pair arguments
% create a struct array from the input
props = struct(varargin{:});
% if not a column array, convert to column array
if ~iscolumn(props)
    props = props';
end

if length(props) == 1 && nNode > 1
    % if the property value is a scalar, but the number of edges is greater
    % than one, create a structure array to replicate the property value
    for i=2:nNode
        props(i) = props(1);
    end
end

assert(length(props)==nNode,...
    'The number of property values ''%d'' must match the number of nodes ''%d''.\n',...
    length(props), nNode);
propNames = fieldnames(props);

valid_props = obj.VertexProperties;
% first check if these fields are valid property names
check_flags = cellfun(@(x)any(strcmp(x, valid_props.Name)), propNames);
if ~ all(check_flags)
    warning('The following input parameters are not valid properties, they will be not added to the graph: %s\n',...
        implode(propNames(~check_flags),', '));
end
% remove invalid fields
props = rmfield(props, propNames(~check_flags));

% get updated field names
propNames = fieldnames(props);

prop_pos = cellfun(@(x)find(strcmp(x, valid_props.Name)), propNames);

% go through all vertex properties to check if the value of a certain
% property is given
for i=1:numel(propNames)

    % if a property exists in the input argument, validate its
    % value
    HybridSystem.validatePropAttribute(propNames{i},...
        {props.(propNames{i})},...
        valid_props.Type{prop_pos(i)},valid_props.Attribute{prop_pos(i)});

    % if the value is not numeric or a cell, convert it to cell to
    % prevent future concatenation goes wrong
    for j=1:numel(vert)
        k = vert(j);
        if iscell(obj.Gamma.Nodes.(propNames{i})(j))
            obj.Gamma.Nodes.(propNames{i}){k} = props(j).(propNames{i});
        else
            obj.Gamma.Nodes.(propNames{i})(k) = props(j).(propNames{i});
        end
    end

end

end