function msfun_realtime_pacer(block)
% Help for Writing Level-2 M-File S-Functions:
%   web([docroot '/toolbox/simulink/sfg/f7-67622.html']
%   http://www.mathworks.com/access/helpdesk/help/toolbox/simulink/sfg/f7-67622.html

% Copyright 2009, The MathWorks, Inc.

% instance variables
mySimTimePerRealTime = 1;
myRealTimeBaseline = 0;
mySimulationTimeBaseline = 0;
myResetBaseline = true;
myTotalBurnedTime = 0;
myNumUpdates = 0;

setup(block);

%% ---------------------------------------------------
    function setup(block)
        % Register the number of ports.
        block.NumInputPorts  = 0;
        block.NumOutputPorts = 0;

        % Set up the states
        block.NumContStates = 0;
        block.NumDworks = 0;

        % Register the parameters.
        block.NumDialogPrms     = 1; % scale factor
        block.DialogPrmsTunable = {'Nontunable'};

        % Block is fixed in minor time step, i.e., it is only executed on major
        % time steps. With a fixed-step solver, the block runs at the fastest
        % discrete rate.
        block.SampleTimes = [0 1];

        block.SetAccelRunOnTLC(false); % run block in interpreted mode even w/ Acceleration

        % methods called during update diagram/compilation.
        block.RegBlockMethod('CheckParameters', @CheckPrms);

        % methods called at run-time
        block.RegBlockMethod('Start', @Start);
        block.RegBlockMethod('Update', @Update);
        block.RegBlockMethod('SimStatusChange', @SimStatusChange);
        block.RegBlockMethod('Terminate', @Terminate);
    end

%%
    function CheckPrms(block)
        try
            validateattributes(block.DialogPrm(1).Data, {'double'},{'real', 'scalar', '>', 0});
        catch %#ok<CTCH>
            throw(MSLException(block.BlockHandle, ...
                'Simulink:Parameters:BlkParamUndefined', ...
                'Enter a number greater than 0'));
        end
    end

%%
    function Start(block)
        mySimTimePerRealTime = block.DialogPrm(1).Data;
        myTotalBurnedTime = 0;
        myNumUpdates = 0;
        myResetBaseline = true;
        if strcmp(pause('query'),'off')
            fprintf('%s: Enabling MATLAB PAUSE command\n', getfullname(block.BlockHandle));
            pause('on');
        end
    end

%%
    function Update(block)
        if  myResetBaseline
            myRealTimeBaseline = tic;
            mySimulationTimeBaseline = block.CurrentTime;
            myResetBaseline = false;
        else
            if isinf(mySimTimePerRealTime)
                return;
            end
            elapsedRealTime = toc(myRealTimeBaseline);
            differenceInSeconds = ((block.CurrentTime - mySimulationTimeBaseline) / mySimTimePerRealTime) - elapsedRealTime;
            if differenceInSeconds >= 0
                pause(differenceInSeconds);
                myTotalBurnedTime = myTotalBurnedTime + differenceInSeconds;
                myNumUpdates = myNumUpdates + 1;
            end
        end
    end

%%
    function SimStatusChange(block, status)
        if status == 0,
            % simulation paused
            fprintf('%s: Pausing real time execution of the model (simulation time = %g sec)\n', ...
                getfullname(block.BlockHandle), block.CurrentTime);
        elseif status == 1
            % Simulation resumed
            fprintf('%s: Continuing real time execution of the model\n', ...
                getfullname(block.BlockHandle));
            myResetBaseline = true;
        end
    end

%%
    function Terminate(block)
        if myNumUpdates > 0
            fprintf('%s: Average idle real time per major time step = %g sec\n', ...
                getfullname(block.BlockHandle),  myTotalBurnedTime / myNumUpdates);
        end
    end

end


function AX = normAxes(obj, AX, varargin);
% normAxes: set all axes within a figure to have the same axes.
%
%	AX = normAxes(obj, AX, [options]);
%
% AX = normAxes(obj) sets all axes that are children of
% the specified object to have the same, maximal axes. Returns
% AX, these maximal axes. obj defaults to gcf.
%
% If you only want to normalize some axes within the figure
% (E.g., for making figure papers), you can pass obj as a
% vector of handles to those axes.
%
% You can also manually specify the axis bounds
% by specifying AX as a second argument. The format
% is [xmin xmax ymin ymax].
%
% Options include:
%
%	'xonly': will normalize each subplot only along the X axis, leaving the
%	Y axis range of each subplot as it was before. In this case, if you
%	don't pass in a value for the AX argument, it will default to the max
%	range across all axes; otherwise, it will only pay attention to the
%	first two elements of AX.
%
%	'yonly': will normalize each subplot only along the Y axis, leaving the
%	X axis range of each subplot as it was before. In this case, if you
%	don't pass in a value for the AX argument, it will default to the max
%	range across all axes; otherwise, it will only pay attention to the
%	third and fourth elements of AX.
%
%	'zoom': rather than setting the axis range AX based on the maximum
%	range across all subplots, the code will set the axis range based on
%	the minimum range across subplots. This will generally cause most
%	subplots to have data outside the plotted range, but will prevent any
%	subplot from have the data compressed in a small part of the axis
%	range.
%
%
% ras 06/05.
% ras 10/09: added optional inputs, made more sophisticated (for better or
% worse :).
if ~exist('obj', 'var') | isempty(obj), obj = get(gca, 'Parent'); end

if length(obj)==1
    haxes = findobj('Type','axes','Parent',obj);
else
    haxes = obj;
end

if isempty(haxes), AX = []; return; end

%% flags for optional behaviors
maxRange = 1; % default axis range is the max across subplots
xOnly = 0;
yOnly = 0;

% parse the options
for ii = 1:length(varargin)
	switch lower(varargin{ii})
		case 'zoom', maxRange = 0;
		case 'xonly', xOnly = 1;
		case 'yonly', yOnly = 1;
		otherwise, warning('Unrecognized option: %s', varargin{ii});
	end
end

if ~exist('AX','var') | isempty(AX)
	% get a default axis range across subplots
    for i = 1:length(haxes)
        axes(haxes(i));
        a(i,:) = axis;
	end

	if maxRange==1
	    % take the maximum axis range across all subplots
		AX = [min(a(:,1)) max(a(:,2)) min(a(:,3)) max(a(:,4))];
	else
		% take the minimum axis range across all subplots.
	    AX = [max(a(:,1)) min(a(:,2)) max(a(:,3)) min(a(:,4))];
	end
end

for i = 1:length(haxes)
    axes(haxes(i));

	if xOnly==1
		% set x range only
		tmpAX = axis;
		tmpAX(1:2) = AX(1:2);
	elseif yOnly==1
		% set y range only
		tmpAX = axis;
		tmpAX(3:4) = AX(3:4);
	else
		tmpAX = AX;
	end

	axis(tmpAX);
end

return


function clu = updateclu(clu,ix,newclu)
% updates identities in parts of a clu file

%% INPUTS

% clu - N x 1 vector of cluster identities for each extracted waveform
% ix - M x 1 vector of indices where new identities will be assigned
% newclu - integer value for the new cluster identity

%% OUTPUTS
% clu - N x 1 vector of updated cluster identities

% updated 2017/02/24 by David Tingley

for ii=1:length(ix)
    clu(clu==ix(ii))=newclu;
end

% ix = unique(clu);
% for ii=1:length(ix)
%     clu(clu==ix(ii))=ii;
% end


      function result = eq(A, B)
         %eq  equal for ChannelTags
         %expect that both parts are ChannelTags
         %
         % wildcards (simple '*' for fields) are automatically matched, so
         % be careful when comparing wildcards!
         %
         % empty fields are treated as intentionally empty.
         %
         % to ignore wildcards altogether, compare the fields individually!
         %
         % Wildcards must be in a scalar.
         %
         % See also matching

         %either A or B is scholar, or they are same size
         %eq is called once for each A (tested Nov16,2015)
         assert(all(size(A)==size(B)) || numel(A)==1 || numel(B)==1,...
            'Size of A and B must be equal, unless either is a scalar');

         stamatches = comparefield({A.station}, {B.station});
         chamatches = comparefield({A.channel}, {B.channel});
         locmatches = comparefield({A.location}, {B.location});
         netmatches = comparefield({A.network}, {B.network});
         result = stamatches & chamatches & locmatches & netmatches;
         if numel(A) == 1
            result = reshape(result,size(B));
         else
            result = reshape(result,size(A));
         end
      end

      function matchIdx = comparefield(A,B)
         % any field
         matchIdx = strcmp(A,B) | strcmp(A,'*') | strcmp(B,'*');
      end


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


function dd_process_scp(dbname,scpfile,varargin)

%DD_PROCESS_SCP Process correlations by station and channel
%
% DD_PROCESS_SCP(DBNAME,SCP_FILE) cross correlates arrivals for the same
% phase and station. SCP_FILE follows the format written by the program
% DD_MAKE_SCP. For each line in an SCP_FILE, DD_PROCESS_SCP reads all
% available waveforms, performs cross correlations and stores the results
% is a temporary directory. If no directory name is specified the files are
% written into TMP_MATDD_CORR.
%
% DD_PROCESS_SCP(DBNAME,SCP_FILE,DIRNAME) same as above, except
% that the correlation files are written into a directory named DIRNAME.

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

% CHECK FOR VALID DATABASE
try
    db = dbopen(dbname,'r');
    dbclose(db);
catch
    error(['Could not open database: ' dbname]);
end

% CHECK INPUTS
if nargin==3
    directoryname = varargin{1};
elseif nargin==2
    directoryname = 'TMP_MATDD_CORR';
else
    error('Incorrect number of inputs');
end

% READ AND PARSE SCP FILE
try
    fid = fopen(scpfile);
catch
   error(['Unable to open scp file: ' scpfile]);
end
% check for header file
C = textscan(fid,'%s %s %s %s %s %s %s %s %s %s',1);
test1 = C{4};
test2 = C{8};
test1 = str2num(test1{1});
test2 = str2num(test2{1});
if ~isempty(test1) || ~isempty(test2)
    error('SCP file is formatted incorrectly or missing a header line');
end
C = textscan(fid,'%s %s %s %n %n %n %n %n %n %n');
fclose(fid);
sta = C{1};
chan = C{2};
iphase = C{3};
npick = C{4};
pretrig = C{5};
posttrig = C{6};
minCorr = C{7};
maxLag = C{8};
hpf = C{9};
lpf = C{10};
clear C test1 test2

% CREATE OUTPUT DIRECTORY IF NEEDED
tmp = exist(directoryname,'dir');
if (tmp~=7)
    disp(['Creating directory: ' directoryname ' ...']);
    mkdir(directoryname);
end

% CYCLE THROUGH ALL SCP LINES
for n =1:length(sta)
    if npick(n)>3
        [W,tracesFound] = load_by_orid(dbname,sta{n},chan{n},iphase{n},pretrig(n),posttrig(n));
        if tracesFound && ~isempty(W)
            [linenum,linestr,C,minimumCorrelation,maximumLag] = correlate(W,pretrig(n),posttrig(n),hpf(n),lpf(n),sta{n},iphase{n},minCorr(n),maxLag(n));
            save([directoryname '/corr_' sta{n} '_' chan{n} '_' iphase{n}],'C','linenum','linestr','minimumCorrelation','maximumLag');
        end
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% LOAD DATA FOR AN INDIVIDUAL STATION, CHANNEL, IPHASE TRIPLET

function [W,tracesFound] = load_by_orid(dbname,STA,CHAN,IPHASE,pretrig,posttrig)

W = [];

% LOAD VALUES FROM DATABASE
try
    db = dbopen(dbname,'r');
    db = dblookup_table(db,'origin');
    db1 = dblookup_table(db,'event');
    db = dbjoin(db,db1);
    db = dbsubset(db,'orid==prefor');
    db1 = dblookup_table(db,'assoc');
    db = dbjoin(db,db1);
    db1 = dblookup_table(db,'arrival');
    db = dbjoin(db,db1);
catch
    error(['Could not open all required database tables in: ' dbname]);
end

% subset required rows
db = dbsubset(db,['sta=="' STA '"']);
db = dbsubset(db,['iphase=="' IPHASE '"']);
tracesFound= dbquery(db,'dbRECORD_COUNT')
if tracesFound == 0
    warning(['No arrivals found. Skipping ' STA '_' CHAN ' ' IPHASE']);
    return
end

% nrecords = dbquery(db,'dbRECORD_COUNT')
[or_time,orid,ar_time] = dbgetv(db,'origin.time','orid','arrival.time');
ar_time = epoch2datenum(ar_time);
or_time = epoch2datenum(or_time);
dbclose(db)

% LOAD WAVEFORMS
disp(['Loading ' STA '_' CHAN ' ' IPHASE ' phase (' num2str(numel(ar_time)) ' arrivals) ...']);
ds = datasource('antelope',dbname);
for n = 1:numel(ar_time)
    scnl = scnlobject(STA,CHAN);
    startTime = ar_time(n)+(pretrig-3)/86400;
    endTime = ar_time(n)+(posttrig+3)/86400;
   try
      w = waveform(ds,scnl,startTime,endTime);
      w = addfield(w,'ORID',orid(n));
      w = addfield(w,'ORIGIN_TIME',or_time(n));
      w = addfield(w,'ARRIVAL_TIME',ar_time(n));
      W = cat(1,W,w);
   catch
      disp(['    Not able to load arrival at ' datestr(ar_time(n),31) '   (no. ' num2str(n) ')' ]);
   end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% CORRELATE WAVEFORMS

function [linenum,linestr,C,minimumCorrelation,maximumLag] = correlate(W,pretrig,posttrig,hpf,lpf,sta,iphase,minCorr,maxLag)

orid = get(W,'ORID');
ar_time = get(W,'ARRIVAL_TIME');
C = correlation(W,ar_time);
C = butter(C,[hpf lpf]);
C = xcorr(C,[pretrig posttrig],'interp');
corr = get(C,'CORR');
lag = get(C,'LAG');

% PRE-ALLOCATE ARRAYS
numberOfRows = sum(1:numel(orid)-1);
linestr = repmat({'placeHolder'},[numberOfRows 1]);
linenum = zeros(numberOfRows,1);
minimumCorrelation = -999 * ones(numberOfRows,1);
maximumLag = -999 * ones(numberOfRows,1);

% WRITE STRINGS OF CORRELATION VALUES
rowNumber = 0;
fprintf('   writing cross correlation pairs:       ');
for n = 1:length(orid)
    for m = n+1:length(orid)
        rowNumber = rowNumber+1;
        params = sprintf('%-8s %6.3f %6.3f %-3s' , sta , lag(n,m) , (corr(n,m))^2 , iphase );
        linenum(rowNumber,1:2) = [orid(n) orid(m)];
        linestr(rowNumber) = {params};
        minimumCorrelation(rowNumber) = minCorr;
        maximumLag(rowNumber) = maxLag;
    end
    fprintf('\b\b\b\b\b\b%5.0f%%',rowNumber/numberOfRows*100);
end
fprintf('\n');


function [timestamps] = ufmf_read_timestamps(header,t0,t1)

FRAME_CHUNK = 1;

fp = header.fid;

if nargin < 2,
  t0 = 1;
end
if nargin < 3,
  t1 = header.nframes;
end

timestamps = nan(1,t1-t0+1);
for t = t0:t1,
  fseek(fp,header.frame2file(t),'bof');

  % read in the chunk type: 1
  chunktype = fread(fp,1,'uchar');
  if chunktype ~= FRAME_CHUNK,
    error('Expected chunktype = %d at start of frame, got %d',FRAME_CHUNK,chunktype);
  end
  % read in timestamp: 8
  timestamps(t-t0+1) = fread(fp,1,'double');
end


function v = zvector(varargin)
% vector (0,0,1)

v = vector3d(0,0,1,varargin{:});


%% QUAD_JOB_ITHACA divides the quadrature problem into tasks.
%
%  Discussion:
%
%    Each task is given a portion of the interval [0,1] over which
%    to integrate.
%
%    Each task returns the estimated integral over its subinterval.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    27 March 2010
%
%  Author:
%
%    John Burkardt
%
  clear

  fprintf ( 1, '\n' );
  fprintf ( 1, 'QUAD_JOB_ITHACA\n' );
  fprintf ( 1, '  Set up and execute a job of independent tasks.\n' );
  fprintf ( 1, '  The computation of an integral over [0,1] is divided\n' );
  fprintf ( 1, '  into tasks integrating from A to B.\n' );
  fprintf ( 1, '  The integral estimate is the sum of the task results.\n' );
%
%  Define the job.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Define the job:\n' );

  job = createJob ( ...
    'configuration', 'ithaca_2009b', ...
    'FileDependencies', { 'quad_task.m' } );

  task_num = 4;
  n = 100001;
  n_per_task = 1 + ( n - 1 ) / task_num;
%
%  Define the tasks that constitute the job.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Define %d tasks:\n', task_num );

  for task = 1 : task_num
    a = ( task - 1 ) / task_num;
    b =   task       / task_num;
    task_id = createTask ( job, @quad_task, 1, { n_per_task, a, b } );
  end
%
%  Submit the job.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Submit the job:\n' );

  submit ( job );
%
%  Wait for results.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Wait for job to finish:\n' );

  timestamp ( );
  wait ( job );
  timestamp ( );
%
%  The following commands will capture and print error messages
%  from the tasks, if something bad occurs.
%
  errmsgs = get ( job.Tasks, {'ErrorMessage'} );
  nonempty = ~cellfun ( @isempty, errmsgs );
  celldisp ( errmsgs(nonempty) );
%
%  Retrieve the output from all tasks.
%
  results = getAllOutputArguments ( job );
%
%  The output is a cell array.
%  We much prefer a MATLAB matrix!
%
  results = cell2mat ( results );
%
%  Sum the results to get the estimate.
%
  quad = sum ( results(:,1) );
  exact = pi;
  err = abs ( quad - exact );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Exact integral = %f\n', exact );
  fprintf ( 1, '  Estimate =       %f\n', quad );
  fprintf ( 1, '  Error =          %e\n', err );
%
%  Clean up by freeing memory associated with the job.
%
  destroy ( job );
%
%  Terminate;
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'QUAD_JOB_ITHACA:\n' );
  fprintf ( 1, '  Normal end of execution.\n' );


function chunk = utl_buffer(chunk,buffer,desired_length)
% Append a chunk to a buffer and trim the buffer to the desired length.
% Buffer = utl_buffer(Chunk,Buffer,DesiredLength)
%
% In:
%   Chunk : a chunk of data (continuous EEGLAB dataset struct)
%
%   Buffer : a buffer of previous data (continuous EEGLAB dataset struct)
%            each non-empty time-series field present in the buffer must have the same number of
%            channels as the corresponding field in the chunk
%
%   DesiredLength : the number of samples of desired output
%
% Out:
%   Buffer : the updated and trimmed buffer
%
%                                Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                2013-11-12

% input validation
utl_check_fields(chunk,{'data','event','xmax','srate'},'chunk','signal');
utl_check_fields(buffer,{'data','event'},'buffer','signal');
if ~isempty(chunk.event)
    if ~isfield(chunk.event,'latency')
        error('The chunk is missing the required .event.latency field.'); end
    latency_numels = cellfun('prodofsize',{chunk.event.latency});
    if any(latency_numels == 0)
        error('The given chunk has one or more events with empty .latency field. This is not permitted.');
    elseif any(latency_numels ~= 1)
        error('The given chunk has one or more events with a .latency value that is not a scalar. This is not permitted.');
    end
end

% concatenate markers if necessary
if (desired_length ~= size(chunk.data,2)) && (~isempty(buffer.event) || ~isempty(chunk.event))
    if size(chunk.data,2) > desired_length
        if ~isempty(chunk.event)
            % shift the latency of the markers based on how many samples we have to cut
            latency = [chunk.event.latency] - (size(chunk.data,2)-desired_length);
            [chunk.event.latency] = arraydeal(latency);
            % remove excess markers
            chunk.event(latency<0.5) = [];
        end
    else
        if ~isempty(chunk.event)
            % shift the latency of the chunk's markers based on how many samples we have to prepend
            [chunk.event.latency] = arraydeal([chunk.event.latency]+min(size(buffer.data,2),(desired_length-size(chunk.data,2))));
        end
        if ~isempty(buffer.event)
            % shift the latency of the buffer's markers based on how many samples we cut from that
            latency = [buffer.event.latency] - max(0,(size(buffer.data,2)+size(chunk.data,2)-desired_length));
            [buffer.event.latency] = arraydeal(latency);
            % concatenate markers
            if isempty(chunk.event)
                chunk.event = buffer.event(latency>=0.5);
            else
                try
                    chunk.event = [buffer.event(latency>=0.5) chunk.event];
                catch e
                    fprintf('WARNING: Trying to concatenate incompatible event structs in the buffer (%s) and the incoming chunk (%s); dropping buffer contents; error message: %s\n',hlp_tostring(fieldnames(buffer.event)),hlp_tostring(fieldnames(chunk.event)),e.message);
                end
            end
        end
    end
end

% for each time-series field in the chunk...
for fld = utl_timeseries_fields(chunk)
    field = fld{1};

    % make sure that we have the requested field in the previous buffer to avoid special cases below
    if ~isfield(buffer,field)
        buffer.(field) = []; end

    % if some other amount of data than what's in the chunk was requested
    if desired_length ~= size(chunk.(field),2)
        if size(chunk.(field),2) < desired_length
            try
                if size(buffer.(field),2) == desired_length
                    % we can do an in-place update without reallocations
                    chunk.(field) = cat(2,buffer.(field)(:,size(chunk.(field),2)+1:end,:,:,:,:,:,:),chunk.(field));
                else
                    % append new samples & cut excess data
                    chunk.(field) = cat(2,buffer.(field),chunk.(field));
                    if size(chunk.(field),2) > desired_length
                        chunk.(field) = chunk.(field)(:,end-desired_length+1:end,:,:,:,:,:,:); end
                end
            catch e
                error('Error trying to concatenate time-series field .%s of buffer (size=%s) and incoming chunk (size=%s); error message: %s.',field,hlp_tostring(size(buffer.(field))),hlp_tostring(size(chunk.field)),e.message);
            end
        else
            % if the chunk is longer than what's requested cut the excess data
            chunk.(field) = chunk.(field)(:,end-desired_length+1:end,:,:,:,:,:,:);
        end
    end
end

% update time-related meta-data
chunk.pnts = size(chunk.data,2);
chunk.xmin = chunk.xmax - (chunk.pnts-1)/chunk.srate;


function G = setupgraph(G,b,s)

if s==1
    for i=1 : size(G,1)
        for j=1 :size(G,1)
            if G(i,j)==0
                G(i,j)=b;
            end
        end
    end
end
if s==2
    for i=1 : size(G,1)
        for j=1 : size(G,1)
            if G(i,j)==b
                G(i,j)=0;
            end
        end
    end
end


function y = cvx_isnonzero( x, full )
error( nargchk( 1, 2, nargin ) );
y = any( x.basis_, 1 );
if nargin < 2,
    y = all( y );
else
    y = cvx_reshape( y, x.size_ );
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 asa103_test ( )

%*****************************************************************************80
%
%% ASA103_TEST tests ASA103.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ASA103_TEST\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the ASA103 library.\n' );

  asa103_test01 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ASA103_TEST\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


function writedata (x, y, yMax, yMin, p, filename, commentStr)
% WRITEDATA creates txt file with parameters and computed values
% writedata (x, y, yMax, yMin, p, filename, commentStr)
% x - values on x-axis
% y - values on y-axis
% p - parameters used for computation
% filename - name of the txt file
% commentStr - comment string
fid = fopen([filename '.txt'],'wt');

if nargin>6
    fprintf(fid,'%s \n', commentStr);
end

fprintf(fid,'Computation: %s \n\n', datestr(now));

fprintf(fid,'Parameters:\n');

fn =fieldnames(p);
for ii = 1: length(fn)
    name = fn{ii};
    value = getfield(p,fn{ii});
    if ischar (value)
        fprintf (fid, [name ' = ' value '\n']);
    else
        fprintf (fid, [name ' = %g \n'], value);
    end
end

fprintf (fid,'\nX \t\t\t Y \n');
fprintf (fid,'------------------\n');

for ii=1:length(y)
    fprintf (fid,'%-8.3f \t %-8.3f \n', x(ii), y(ii));
end

fclose(fid);

%envelopes

if ~isempty(yMax)
    fid = fopen([filename '_envelope_Max.txt'],'wt');
    if nargin>6
        fprintf(fid,'%s \n', commentStr);
    end
    fprintf(fid,'Computation: %s \n\n', datestr(now));
    fprintf(fid,'Maximum of %g simulations of Poisson process\n\n', p.Nsimul);
    fprintf (fid,'x \t\t\t max y \n');
    fprintf (fid,'------------------\n');
    for ii=1:length(y)
        fprintf (fid,'%-8.3f \t %-8.3f \n', x(ii), yMax(ii));
    end
    fclose(fid);
end

if ~isempty(yMin)
    fid = fopen([filename '_envelope_Min.txt'],'wt');
    if nargin>6
        fprintf(fid,'%s \n', commentStr);
    end
    fprintf(fid,'Computation: %s \n\n', datestr(now));
    fprintf(fid,'Minimum of %g simulations of Poisson process\n\n', p.Nsimul);
    fprintf (fid,'xK \t\t\t min K \n');
    fprintf (fid,'------------------\n');
    for ii=1:length(y)
        fprintf (fid,'%-8.3f \t %-8.3f \n', x(ii), yMin(ii));
    end
    fclose(fid);
end


function [results_obj, stats, indx] = searchlight(dat, varargin)
% Run searchlight multivariate prediction/classification on an image_vector
% or fmri_data object OR two objects, for cross-prediction.
%
% :Usage:
% ::
%
%    [list outputs here] = function_name(list inputs here, [optional inputs])
%    [results_obj, stats, indx] = searchlight(dat, [optional inputs])
%
%
% :Features:
%  - Runs searchlight with standard, pre-defined algorithms
%  - Custom-entry definition of holdout sets
%  - Can re-use searchlight spheres after initial definition
%  - Custom-entry definition of any spheres/regions of interest
%  - Uses Matlab's parallel processing toolbox (parfor)
%
% Type help image_vector.searchlight to display this help information
%
% ..
%     Author and copyright information:
%
%     Copyright (C) 2014  Tor Wager and...
%
%     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/>.
% ..
%
%
% :Inputs:
%
%   **dat:**
%        image_vector or fmri_data object with data
%
%   **dat.Y:**
%        required: true outcomes for each observation (image) in dat
%
% :Optional Inputs:* Keyword followed by input variable:
%
%   **r:**
%        searchlight radius, voxels
%   **dat2:**
%        second dataset, for cross-prediction
%   **indx:**
%        sparse logical matrix. each COLUMN is index of inclusion sets for each region/sphere in searchlight
%        This takes a long time to calculate, but can be saved and
%        re-used for a given mask
%   **holdout_set:**
%        Followed by integer vector of which observations belong to which
%        holdout set, for cross-validation. This is passed into fmri_data.predict.m.  Default is
%        empty.
%
% :Outputs:
%
%   **results_obj:**
%        fmri_data object with results maps
%
%   **stats:**
%        selected statistics for each sphere in searchlight
%
%   **indx:**
%        sparse logical matrix. each COLUMN is index of inclusion sets for each region/sphere in searchlight
%        * this can be re-used for all data with the same mask/structure. *
%
%
% :Examples:
% ::
%
%    % Define a sensible gray-matter mask:
%    dat = fmri_data(which('scalped_avg152T1_graymatter.img'));
%    dat = threshold(dat, [.8 Inf], 'raw-between');
%    dat = trim_mask(dat);
%
%    % Create fake data and holdout indicator index vector
%    dat.dat = randn(dat.volInfo.n_inmask, 30);
%    dat.Y = dat.dat(111111, :)' + .3 * randn(30, 1);
%    holdout_set = ones(6, 1); for i = 2:5, holdout_set = [holdout_set; i*ones(6, 1)]; end
%
%    % Run, and run again with existing indx
%    pool = parpool(12);  % initialize parallel processing (12 cores)
%    [results_obj, stats, indx] = searchlight(dat, 'holdout_set', holdout_set);
%    results_obj = searchlight(dat, 'holdout_set', holdout_set, 'indx', indx);
%
% :See also:
% region.m, fmri_data.predict.m
%
% ..
%    Programmers' notes:
%    List dates and changes here, and author of changes
% ..

% ..
% DEFAULTS AND INPUTS
% ..

r = 5; % For defining regions
indx = [];      % cell; with logical index of inclusion sets for each region/sphere in searchlight

% For prediction/classification
algorithm_name = 'cv_lassopcr';
holdout_set = [];
results_obj = [];

% process variable arguments
for i = 1:length(varargin)
    if ischar(varargin{i})
        switch varargin{i}
            % functional commands
            case {'r', 'indx', 'algorithm_name', 'dat2', 'holdout_set'}
                str = [varargin{i} ' = varargin{i + 1};'];
                eval(str)
                varargin{i} = [];
                varargin{i + 1} = [];

            case {'cross_predict'}
                algorithm_name = varargin{i};

            otherwise
                % use all other inputs as optional arguments to specific
                % functions, to be interpreted by them
                predfun_inputs{end + 1} = varargin{i};

                if (i+1) <= length(varargin) && ~ischar(varargin{i + 1})
                    predfun_inputs{end + 1} = varargin{i + 1};
                end

        end
    end
end

n = dat.volInfo.n_inmask;

%% Set up indices for spherical searchlight, if not entered previously

if isempty(indx)

    indx = searchlight_sphere_prep(dat, r);

else

    fprintf('Using input indx to define regions/spheres...\n');

end

%% Check for data and return if empty

if ~isa(dat, 'fmri_data') || isempty(dat.Y)

    fprintf('Returning indx only: No data in dat.Y to predict or data is not an fmri_data object');

    return

end

%% Run cross-predict (or other) function

% Get rough time estimate first
predict_time_estimate(dat, indx, algorithm_name, holdout_set);

t = tic;
fprintf('Running prediction in each region...');

% parfor i = 1:n
%
%     indxcell{i} = indx(:, i);
%
% end

output_val = cell(1, n);

parfor i = 1:n

    output_val{i} = predict_wrapper(dat, indx(:, i), algorithm_name, holdout_set);

end

e = toc(t);

[hour, minute, second] = sec2hms(e);
fprintf(1,'Done in %3.0f hours %3.0f min %2.0f sec\n',hour, minute, second);

%% Save results map(s) in object

results_obj = mean(dat);
results_obj.dat = cat(1, output_val.cverr{:});

end % function

% -------------------------------------------------------------------------
% -------------------------------------------------------------------------
%
% Sub-functions
%
% -------------------------------------------------------------------------
% -------------------------------------------------------------------------

% SPHERE PREP
% -------------------------------------------------------------------------

function indx = searchlight_sphere_prep(dat, r)

n = dat.volInfo.n_inmask;
indx = cell(1, n);

t = tic;
fprintf('Setting up seeds...');

parfor i = 1:n
    seed{i} = dat.volInfo.xyzlist(i, :);
end

e = toc(t);
fprintf('Done in %3.2f sec\n', e);

% Set up indices for spherical searchlight
% -------------------------------------------------------------------------
% These could be indices for ROIs, user input, previously saved indices...

% First, a rough time estimate:
% -------------------------------------------------------------------------
fprintf('Searchlight sphere construction can take 20 mins or more! (est: 20 mins with 8 processors/gray matter mask)\n');
fprintf('It can be re-used once created for multiple analyses with the same region definitions\n');
fprintf('Getting a rough time estimate for how long this will take...\n');

n_to_run = min(500, n);
t = tic;
parfor i = 1:n_to_run

    mydist = sum([dat.volInfo.xyzlist(:, 1) - seed{i}(1) dat.volInfo.xyzlist(:, 2) - seed{i}(2) dat.volInfo.xyzlist(:, 3) - seed{i}(3)] .^ 2, 2);
    indx{i} = mydist <= r.^2;

end
e = toc(t);
estim = e * n / n_to_run;

[hour, minute, second] = sec2hms(estim);
fprintf(1,'\nEstimate for whole brain = %3.0f hours %3.0f min %2.0f sec\n',hour, minute, second);

% Second, do it for all voxels/spheres:
% -------------------------------------------------------------------------

t = tic;

fprintf('Constructing spheres for each seed...');

%infdist = inf * ones(size(dat.volInfo.xyzlist(:, 1), 1), 1);

parfor i = 1:n

    mydist = sum([dat.volInfo.xyzlist(:, 1) - seed{i}(1) dat.volInfo.xyzlist(:, 2) - seed{i}(2) dat.volInfo.xyzlist(:, 3) - seed{i}(3)] .^ 2, 2);
    indx{i} = mydist <= r.^2;

end

e = toc(t);
fprintf('Done in %3.2f sec\n', e);

% Make sparse matrix
t = tic;
fprintf('Sparsifying region indices...');

indxcat = cat(2, indx{:});
indxcat = sparse(indxcat);

e = toc(t);
fprintf('Done in %3.2f sec\n', e);

% NOTE: IdenTICAL but twice as slow
% indx1 = cell(1, n);
% tic
% parfor i = 1:1000
%     indx1{i} = logical(iimg_xyz2spheres(seed{i}, dat.volInfo.xyzlist, r));
% end
% toc

end % searchlight_sphere_prep

% PREDICTION
% -------------------------------------------------------------------------

function output_val = predict_wrapper(dat, indx, algorithm_name, holdout_set)
% This function wraps predict.m to use its functionality.
% It could be extended to handle optional inputs, etc.
% Right now it is basic.
% Note: pass in indx{i}, which becomes indx here, for ONE
% region/searchlight sphere

dat.dat = dat.dat(indx, :);
dat.removed_voxels(~indx) = true;

[cverr, stats] = predict(dat, 'algorithm_name', algorithm_name, 'nfolds', holdout_set, 'useparallel', 0, 'verbose', 0);

% Parse output
% Only storing important info and full data weight map - we will probably
% want xval weight maps too at some point. We will also probably want a
% p-value and standard errors for accuracy too.

output_val = struct;
switch algorithm_name
    case 'cv_svm'
        output_val.cverr = stats.cverr;
        output_val.dist_from_hyperplane_xval = stats.dist_from_hyperplane_xval;
        output_val.weight_obj = stats.weight_obj;
        output_val.intercept = stats.other_output{3};

    case 'cv_lassopcr'
        output_val.yfit = stats.yfit;
        output_val.pred_outcome_r = stats.pred_outcome_r;
        output_val.weight_obj = stats.weight_obj;
        output_val.intercept = stats.other_output{3};
end

end % subfunction

% PREDICTION time estimate
% -------------------------------------------------------------------------

function predict_time_estimate(dat, indx, algorithm_name, holdout_set)

t = tic;
fprintf('Getting rough time estimate: Running prediction for up to 500 voxels...');

n = dat.volInfo.n_inmask;
output_val = cell(1, n);

n_to_run = min(500, n);

parfor i = 1:n_to_run

    output_val{i} = predict_wrapper(dat, indx(:, i), algorithm_name, holdout_set);

end

e = toc(t);
fprintf('Done in %3.2f sec\n', e);

estim = e * n / n_to_run;

[hour, minute, second] = sec2hms(estim);
fprintf(1,'Estimate for whole brain = %3.0f hours %3.0f min %2.0f sec\n',hour, minute, second);

end

% Convert time
% -------------------------------------------------------------------------

function [hour, minute, second] = sec2hms(sec)
%SEC2HMS  Convert seconds to hours, minutes and seconds.
%
%   [HOUR, MINUTE, SECOND] = SEC2HMS(SEC) converts the number of seconds in
%   SEC into hours, minutes and seconds.

hour   = fix(sec/3600);      % get number of hours
sec    = sec - 3600*hour;    % remove the hours
minute = fix(sec/60);        % get number of minutes
sec    = sec - 60*minute;    % remove the minutes
second = sec;
end

% % WANI'S CROSS-CLASSIFICATION FUNCTION - to edit and integrate
% % -------------------------------------------------------------------------
%
% function [acc, p, se, stats1 stats2] = cv_svm_cross_subf(data1, data2, cv_assign, dobalanced, balanced_ridge, doscale)
%
% % run cv_svm on train data and test data
%
% if doscale
%     data1 = rescale(data1, 'zscoreimages');
%     data2 = rescale(data2, 'zscoreimages');
% end
%
% % preallocate some variables
% predicted11 = NaN(size(data1.Y));
% predicted12 = NaN(size(data2.Y));
% predicted21 = NaN(size(data1.Y));
% predicted22 = NaN(size(data2.Y));
%
% dist_from_hyper11 = NaN(size(data1.Y));
% dist_from_hyper12 = NaN(size(data2.Y));
% dist_from_hyper21 = NaN(size(data1.Y));
% dist_from_hyper22 = NaN(size(data2.Y));
%
% % get cv assignment
% u = unique(cv_assign);
% nfolds = length(u);
% [trIdx, teIdx] = deal(cell(1, nfolds));
%
% for i = 1:length(u)
%     teIdx{i} = cv_assign == u(i);
%     trIdx{i} = ~teIdx{i};
% end
%
% stats1.Y = data1.Y;
% stats2.Y = data2.Y;
%
% % Use all
% trainobj1 = data(double(data1.dat'),data1.Y);
% trainobj2 = data(double(data2.dat'),data2.Y);
%
% svmobj1 = svm({'optimizer="andre"','C=1','child=kernel'});
% if dobalanced, svmobj1.balanced_ridge = balanced_ridge; end
% [~, svmobj1] = train(svmobj1, trainobj1);
%
% svmobj2 = svm({'optimizer="andre"','C=1','child=kernel'});
% if dobalanced, svmobj2.balanced_ridge = balanced_ridge; end
% [~, svmobj2] = train(svmobj2, trainobj2);
%
% % 1) weights
% stats1.all{1} = get_w(svmobj1)';
% stats2.all{1} = get_w(svmobj2)';
% % 2) intercepts
% stats1.all{2} = svmobj1.b0;
% stats2.all{2} = svmobj2.b0;
%
% stats1.all_descrip = {'1:weights 2:intercept 3:distance from hyperplane for test data1 4: dist for data2'};
% stats2.all_descrip = {'1:weights 2:intercept 3:distance from hyperplane for test data2 4: dist for data1'};
%
% % Cross-val loop starts here
%
% for i = 1:numel(teIdx)
%
%     % Prepare the hot-warm and Rej-friend data in Spider format
%     trainobj1 = data(double(data1.dat'),data1.Y);
%     trainobj2 = data(double(data2.dat'),data2.Y);
%
%     % Select training and test data - trainobj, testobj
%     testobj1 = trainobj1;
%     testobj2 = trainobj2;
%
%     trainobj1.X = trainobj1.X(trIdx{i}, :);
%     trainobj1.Y = trainobj1.Y(trIdx{i}, :);
%
%     trainobj2.X = trainobj2.X(trIdx{i}, :);
%     trainobj2.Y = trainobj2.Y(trIdx{i}, :);
%
%     testobj1.X = testobj1.X(teIdx{i}, :);
%     testobj1.Y = testobj1.Y(teIdx{i}, :);
%
%     testobj2.X = testobj2.X(teIdx{i}, :);
%     testobj2.Y = testobj2.Y(teIdx{i}, :);
%
%
%     %-------------------------------------------------------------------
%     % Train on data1 and test on data1 and data2
%
%     % Set up an SVM object
%     svmobj1 = svm({'optimizer="andre"','C=1','child=kernel'});
%
%     if dobalanced
%         svmobj1.balanced_ridge = balanced_ridge;
%     end
%
%     % train on hw data set
%     [~, svmobj1] = train(svmobj1, trainobj1);
%
%     % Test on both HW and RF test set
%
%     testobj11 = test(svmobj1, testobj1);
%     testobj12 = test(svmobj1, testobj2);
%
%     w = get_w(svmobj1)';
%     b0 = svmobj1.b0;
%
%     dist11 = testobj1.X * w + b0;
%     dist12 = testobj2.X * w + b0;
%
%     if ~isequal((dist11>0)*2-1,testobj11.X)
%         error('something is wrong');
%     elseif ~isequal((dist12>0)*2-1,testobj12.X)
%         error('something is wrong');
%     end
%
%     % Save predictions (cross-val)
%     predicted11(teIdx{i}) = testobj11.X;
%     predicted12(teIdx{i}) = testobj12.X;
%
%
%     %-------------------------------------------------------------------
%     % Train on RF and test on HW and RF
%
%     % Set up an SVM object
%     svmobj2 = svm({'optimizer="andre"','C=1','child=kernel'});
%
%     if dobalanced
%         svmobj2.balanced_ridge = balanced_ridge;
%     end
%     % train on rf data set
%     [~, svmobj2] = train(svmobj2, trainobj2);
%
%     % Test on both HW and RF test set
%
%     testobj21 = test(svmobj2, testobj1);
%     testobj22 = test(svmobj2, testobj2);
%
%     w = get_w(svmobj2)';
%     b0 = svmobj2.b0;
%
%     dist21 = testobj1.X * w + b0;
%     dist22 = testobj2.X * w + b0;
%
%     if ~isequal((dist21>0)*2-1,testobj21.X)
%         error('something is wrong');
%     elseif ~isequal((dist22>0)*2-1,testobj22.X)
%         error('something is wrong');
%     end
%
%     % Save predictions (cross-val)
%     predicted21(teIdx{i}) = testobj21.X;
%     predicted22(teIdx{i}) = testobj22.X;
%
%     % get stats from svmobj
%     % 1) weights
%     stats1.cvoutput{i,1} = get_w(svmobj1)';
%     stats2.cvoutput{i,1} = get_w(svmobj2)';
%     % 2) intercepts
%     stats1.cvoutput{i,2} = svmobj1.b0;
%     stats2.cvoutput{i,2} = svmobj2.b0;
%     % 3) distance from hyperplane for test data 1 and 2
%     stats1.cvoutput{i,3} = testobj1.X * stats1.cvoutput{i,1} + stats1.cvoutput{i,2};
%     stats1.cvoutput{i,4} = testobj2.X * stats1.cvoutput{i,1} + stats1.cvoutput{i,2};
%
%     stats2.cvoutput{i,3} = testobj1.X * stats2.cvoutput{i,1} + stats2.cvoutput{i,2};
%     stats2.cvoutput{i,4} = testobj2.X * stats2.cvoutput{i,1} + stats2.cvoutput{i,2};
%
%     stats1.cvoutput_descrip = {'1:weights 2:intercept 3:distance from hyperplane for test data1 4: dist for data2'};
%     stats2.cvoutput_descrip = {'1:weights 2:intercept 3:distance from hyperplane for test data2 4: dist for data1'};
%
%     dist_from_hyper11(teIdx{i}) = stats1.cvoutput{i,3};
%     dist_from_hyper12(teIdx{i}) = stats1.cvoutput{i,4};
%     dist_from_hyper21(teIdx{i}) = stats2.cvoutput{i,3};
%     dist_from_hyper22(teIdx{i}) = stats2.cvoutput{i,4};
% end
%
% stats1.yfit = predicted11;
% stats2.yfit = predicted22;
% stats1.testfit = predicted12;
% stats2.testfit = predicted21;
%
% stats1.all{3} = dist_from_hyper11;
% stats1.all{4} = dist_from_hyper12;
% stats2.all{3} = dist_from_hyper22;
% stats2.all{4} = dist_from_hyper21;
%
% % RO on H vs. W
% % res_temp = binotest(predicted11(1:(length(predicted11)/2)) ==
% %data1.Y(1:(length(predicted11)/2)), 0.5);
% % test_results.accuracy(1,1) = res_temp.prop;
% % test_results.accuracy_se(1,1) = res_temp.SE;
% % test_results.accuracy_p(1,1) = res_temp.p_val;
% %
% % res_temp = binotest(predicted12(1:(length(predicted12)/2)) ==
% %data2.Y(1:(length(predicted12)/2)), 0.5);
% % test_results.accuracy(1,2) = res_temp.prop;
% % test_results.accuracy_se(1,2) = res_temp.SE;
% % test_results.accuracy_p(1,2) = res_temp.p_val;
% %
% % res_temp = binotest(predicted21(1:(length(predicted21)/2)) ==
% %data1.Y(1:(length(predicted21)/2)), 0.5);
% % test_results.accuracy(1,3) = res_temp.prop;
% % test_results.accuracy_se(1,3) = res_temp.SE;
% % test_results.accuracy_p(1,3) = res_temp.p_val;
% %
% % res_temp = binotest(predicted22(1:(length(predicted22)/2)) ==
% %data2.Y(1:(length(predicted22)/2)), 0.5);
% % test_results.accuracy(1,4) = res_temp.prop;
% % test_results.accuracy_se(1,4) = res_temp.SE;
% % test_results.accuracy_p(1,4) = res_temp.p_val;
%
% subjn = numel(teIdx);
% outcome = [true(subjn,1); false(subjn,1)];
%
% hvsw_dist11 = stats1.all{3}(1:(subjn*2));
% rvsf_dist12 = stats1.all{4}(1:(subjn*2));
% hvsw_dist21 = stats2.all{4}(1:(subjn*2));
% rvsf_dist22 = stats2.all{3}(1:(subjn*2));
%
%
% % ROC = roc_plot(hvsw_dist11, outcome, 'threshold', 0);
% % test_results.accuracy_thresh0(1) = ROC.accuracy;
% % test_results.accuracy_thresh0_se(1) = ROC.accuracy_se;
% % test_results.accuracy_thresh0_p(1) = ROC.accuracy_p;
%
% try
%     ROC = roc_plot(hvsw_dist11, outcome, 'twochoice');
%     acc(1) = ROC.accuracy;
%     se(1) = ROC.accuracy_se;
%     p(1) = ROC.accuracy_p;
% catch err
%     % ROC = roc_plot(hvsw_dist11, outcome, 'twochoice');
%     acc(1) = NaN;
%     se(1) = NaN;
%     p(1) = NaN;
% end
%
% %
% % ROC = roc_plot_wani(rvsf_dist12, outcome, 'threshold', 0);
% % test_results.accuracy_thresh0(2) = ROC.accuracy;
% % test_results.accuracy_thresh0_se(2) = ROC.accuracy_se;
% % test_results.accuracy_thresh0_p(2) = ROC.accuracy_p;
% %
% try
%     ROC = roc_plot(rvsf_dist12, outcome, 'twochoice');
%     acc(2) = ROC.accuracy;
%     se(2) = ROC.accuracy_se;
%     p(2) = ROC.accuracy_p;
% catch err
%     acc(2) = NaN;
%     se(2) = NaN;
%     p(2) = NaN;
% end
% %
% %
% % ROC = roc_plot(hvsw_dist21, outcome, 'threshold', 0);
% % test_results.accuracy_thresh0(3) = ROC.accuracy;
% % test_results.accuracy_thresh0_se(3) = ROC.accuracy_se;
% % test_results.accuracy_thresh0_p(3) = ROC.accuracy_p;
% %
% try
%     ROC = roc_plot(hvsw_dist21, outcome, 'twochoice');
%     acc(3) = ROC.accuracy;
%     se(3) = ROC.accuracy_se;
%     p(3) = ROC.accuracy_p;
% catch err
%     acc(3) = NaN;
%     se(3) = NaN;
%     p(3) = NaN;
% end
%
% % ROC = roc_plot(rvsf_dist22, outcome, 'threshold', 0);
% % test_results.accuracy_thresh0(4) = ROC.accuracy;
% % test_results.accuracy_thresh0_se(4) = ROC.accuracy_se;
% % test_results.accuracy_thresh0_p(4) = ROC.accuracy_p;
% try
%     ROC = roc_plot(rvsf_dist22, outcome, 'twochoice');
%     acc(4) = ROC.accuracy;
%     se(4) = ROC.accuracy_se;
%     p(4) = ROC.accuracy_p;
% catch err
%     acc(4) = NaN;
%     se(4) = NaN;
%     p(4) = NaN;
% end
%
% close;

% end


classdef Scalar3d
    % SCALAR3D represents a 3D arary of scalar values.  It can represents a single
    % directional component of a 3D vector field (e.g. Ex of E).
	% The fields are always evaluated at the primary grid points (grid kind =
	% GT.prim)

    properties (SetAccess = immutable)
		% numerical properties
        array  % 3D array
        grid3d  % instance of Grid3d
		gt_array  % [x_gridtype y_gridtype z_gridtype]: array of instances of GT
        osc  % instance of Oscillation

		% extra properties
		physQcell  % {PhysQ, int; PhysQ, int; ...}: representation of physical quanity
		unitvalue  % unit value of physical quantity
		name  % name of this quantity: "E_x", "H_y", etc. in LaTeX equation format
	end

    methods
        function this = Scalar3d(array, grid3d, gt_array, osc, physQcell, name)
			chkarg(istypesizeof(grid3d, 'Grid3d'), '"grid3d" should be instance of Grid3d.');
			this.grid3d = grid3d;

			chkarg(istypesizeof(gt_array, 'GT', [1 Axis.count]), ...
				'"gt_array" should be length-%d row vector with GT as elements.', Axis.count);
			this.gt_array = gt_array;

			N = grid3d.N + int(gt_array);
			chkarg(istypesizeof(array, 'complex', N), ...
				'"array" should be %d-by-%d-by-%d array with complex elements.', N(Axis.x), N(Axis.y), N(Axis.z));
			this.array = array;

			chkarg(istypesizeof(osc, 'Oscillation'), '"osc" should be instance of Oscillation.');
			this.osc = osc;

			if nargin < 5  % no physQ
				physQcell = PhysQ.arbitrary;
			end
			chkarg(istypesizeof(physQcell, 'PhysQ') || isphysQcell(physQcell), ...
				'"physQcell" should be instance of PhysQ, or cell array {PhysQ, int; PhysQ, int; ...}.');
			if istypesizeof(physQcell, 'PhysQ')
				physQcell = {physQcell, 1};
			end
			this.physQcell = physQcell;
			this.unitvalue = osc.unit.value(this.physQcell);

			if nargin < 6  % no name
				name = '';
			end
			chkarg(ischar(name), '"name" should be string.');
            this.name = name;
		end

		function l_cell = lall(this)
			l_cell = this.grid3d.lall(Axis.elems + Axis.count*subsindex(this.gt_array));
		end

		function l_cell = lg(this)
			l_cell = this.grid3d.lg(Axis.elems + Axis.count*subsindex(this.gt_array));
		end

		function l_cell = l(this)
			l_cell = this.grid3d.l(Axis.elems + Axis.count*subsindex(this.gt_array));
		end

		function [array, l_cell] = data_expanded(this)
			l_cell = this.lall;
			array = this.array;
		end

		function [array, l_cell] = data_ghost_expanded(this)
			l_cell = this.lg;
			ind = cell(1, Axis.count);

			for w = Axis.elems
				ind{w} = 1:(this.grid3d.N(w)+1);
			end
			array = this.array(ind{:});
		end

		function [array, l_cell] = data_original(this)
			l_cell = this.l;
			ind = cell(1, Axis.count);

			for w = Axis.elems
				if this.gt_array(w) == GT.prim
					ind{w} = 1:this.grid3d.N(w);
				else  % this.gt_array(w) == GT.dual
					ind{w} = 2:(this.grid3d.N(w)+1);
				end
			end
			array = this.array(ind{:});
		end

		function [val, loc] = value(this, x, y, z)
			% Return the values of this Scalar3d along a line.  The line should
			% be along one of the x, y, z directions, so at least two of the
			% given x, y, z should be scalar.
			loc = {x, y, z};
			lavail = this.l;  % available locations
			num_len1 = 0;  % at least two of x, y, z should be scalar
			for w = Axis.elems
				coord_w = loc{w};
				chkarg(isempty(coord_w) || isvector(coord_w) && istypeof(coord_w, 'real'), ...
				'"%s" should be empty or real vector.', char(w));
				if isempty(coord_w)
					coord_w = lavail{w};  % if empty, use all available locations
				else
					chkarg(this.grid3d.comp(w).contains(coord_w), '"%s" should be inside grid.', char(w));
					coord_w = sort(coord_w);
				end
				loc{w} = coord_w;
				if length(coord_w) == 1
					num_len1 = num_len1 + 1;
				end
			end
			chkarg(num_len1 >= 2, 'Points should be along Cartesian direction.');

			lall = this.lall;
			ind = cell(1, Axis.count);

			for w = Axis.elems
				loc_min = loc{w}(1);
				indw_min = ismembc2(loc_min, lall{w});
				if indw_min == 0
					indw_min = find(lall{w} < loc_min, 1, 'last');
				end

				loc_max = loc{w}(end);
				indw_max = ismembc2(loc_max, lall{w});
				if indw_max == 0
					indw_max = find(lall{w} > loc_max, 1, 'first');
				end

				ind{w} = indw_min:indw_max;
			end

			isindlen1 = [length(ind{Axis.x}), length(ind{Axis.y}), length(ind{Axis.z})] == 1;
			if all(isindlen1)
				val = this.array(ind{:});
			else
				for w = Axis.elems
					if isindlen1(w) % ndgrid() needs two data points to interpolate with
						indw = ind{w};
						if indw >= 2
							ind{w} = [indw - 1, indw];
						else
							ind{w} = [indw, indw + 1];
						end
					end
				end

				l = cell(1, Axis.count);
				for w = Axis.elems
					l{w} = lall{w}(ind{w}(1):ind{w}(end));
				end
				[X, Y, Z] = ndgrid(l{:});
				V = this.array(ind{:});
				[Xi, Yi, Zi] = ndgrid(loc{:});
				val = interpn(X, Y, Z, V, Xi, Yi, Zi);
			end
		end
	end
end


function viewNeighborsAuto(inputImages, inputSignals, neighborsCell, varargin)
	% View the neighboring cells, their traces and trace correlations.
	% Biafra Ahanonu
	% started 2013.11.01
	% inputs
		% inputImages - [x y nCells] matrices containing each set of filters
		% inputSignals - [nFilters frames] matrices containing each set of filter traces
		% neighborsCell - {nCells 1} cell array of [nNeighborId 1] vectors of neighbor IDs for each cell matching indices in inputImages
	% outputs
		%
	% changelog
		% 2018 - updated interface, speed improvements.
		% 2019.05.28 [13:49:31] - No longer use montage to create montage, use loops plus cat and cell arrays to improve speed, reduce use of montage(), and make outlines crisp (on 2018b they would become expanded with montage).
		% 2019.05.28 [15:15:43] - General improvements to GUI clarity.
		% 2019.06.18 [14:54:34] - Added support for spatial correlations
		% 2021.08.08 [19:30:20] - Updated to handle CIAtah v4.0 switch to all functions inside ciapkg package.
	% TODO
		%

	import ciapkg.api.* % import CIAtah functions in ciapkg package API.

	%========================
	options.plottingOn = 0;
	options.overlapradius = 10;
	% overlap radius in pixels (so convert properly)
	options.overlapDistance = 10;
	% 'centroid', 'imdilate'
	options.neighborMethod = 'centroid';
	% Input pre-computed x,y coordinates for objects in images
	options.xCoords = [];
	options.yCoords = [];
	%
	options.inputImagesThres = [];
	%
	options.startCellNo = 1;
	%
	options.cropSizeLength = 20;
	% get options
	options = getOptions(options,varargin);
	% display(options)
	% unpack options into current workspace
	% fn=fieldnames(options);
	% for i=1:length(fn)
	%     eval([fn{i} '=options.' fn{i} ';']);
	% end
	%========================

	if isempty(neighborsCell)
		copts = options;
		neighborsCell = identifyNeighborsAuto(inputImages, inputSignals,'options',copts);
	end

	% cell vector info
	cellvec(1) = 1;
	cellvec(2) = size(inputImages,3);
	valid = zeros(1,cellvec(2));

	openFigure(21,'full');
		clf

	exitLoop = 0;
	nCells = cellvec(2);
	cellnum = options.startCellNo;
	cropSizeLength = options.cropSizeLength;
	usePadding = 1;
	xCoords = [];
	yCoords = [];

	rowP = 3;
	colP = 3;

	% instructions
	instructionStr =  ['Controls: left/right arrow:forward/back | e:exit | g:(goto cell #)' 10 ' cell #s low-high from top to bottom | top trace = this cell' 10];

	set(21, 'KeyPressFcn', @(source,eventdata) figure(21));
	while exitLoop==0
		directionOfNextChoice = 0;
		thisFilt = squeeze(inputImages(:,:,cellnum));
		if issparse(thisFilt)
			thisFilt = full(thisFilt);
		end
		nList = [cellnum neighborsCell{cellnum,1}(:)'];
		% nList
		% montage of nearby cells
		subplot(rowP,colP,1)
			rgbImage = [];
			nImgs = inputImages(:,:,nList);
			if issparse(nImgs)
				nImgs = full(nImgs);
			end
			nMatchCells = size(nImgs,3);

			objCutMovie = getObjCutMovie(nImgs,thisFilt,'createMontage',0,'extendedCrosshairs',0,'crossHairVal',NaN,'outlines',1,'waitbarOn',0,'cropSize',cropSizeLength,'addPadding',usePadding,'xCoords',xCoords,'yCoords',yCoords,'outlineVal',NaN);
			objCutMovie = vertcat(objCutMovie{:});
			[thresholdedImages boundaryIndices] = thresholdImages(objCutMovie(:,:,1),'binary',1,'getBoundaryIndex',1,'threshold',0.35,'imageFilter','','waitbarOn',0,'normalizationType','zeroToOne','removeUnconnected',1,'boundaryHoles','noholes');

			for zz = 1:size(nImgs,3)
				tmpImg = squeeze(objCutMovie(:,:,zz));
				tmpImg([boundaryIndices{:}]) = NaN;

				% tmpImg = squeeze(nanmean(...
				%     insertText(tmpImg,[0 0],num2str(nList(zz)),...
				%     'BoxColor',[0 0 0],...
				%     'TextColor',[1e10 1e10 1e10],...
				%     'AnchorPoint','LeftTop',...
				%     'FontSize',8,...
				%     'BoxOpacity',0)...
				% ,3));
				% tmpImg(tmpImg>1e7) = NaN;
				% figure;imagesc(tmpImg)
				objCutMovie(:,:,zz) = tmpImg;
			end
			clear objCutMovie2;
			objCutMovie2(:,:,1,:) = objCutMovie;
			% montage(objCutMovie2)

			croppedPeakImagesCell = {};
			[xPlot yPlot] = getSubplotDimensions(size(objCutMovie,3));
			for iii = 1:xPlot*yPlot
				if iii>size(objCutMovie,3)
					croppedPeakImagesCell{iii} = NaN(size(objCutMovie(:,:,1)));
				else
					croppedPeakImagesCell{iii} = objCutMovie(:,:,iii);
				end
			end
			mNum = 1;
			g = cell([xPlot 1]);
			rowNum = 1;

			xyLoc = ones([nMatchCells 2]);
			xyLoc(:,2) = [3];
			xyLoc(:,1) = [2];

			cellNoHere = 1;
			for xNo = 1:xPlot
				for yNo = 1:yPlot
					g{rowNum} = cat(2,g{rowNum},croppedPeakImagesCell{mNum});

					if sum(isnan(croppedPeakImagesCell{mNum}(:)))~=numel(croppedPeakImagesCell{mNum}(:))&&cellNoHere>1&&yNo>1
						xyLoc(cellNoHere,:) = [xyLoc(cellNoHere-1,1)+options.cropSizeLength*2+1 xyLoc(cellNoHere,2)];
					end
					cellNoHere = cellNoHere+1;
					mNum = mNum + 1;
				end

				xyLoc(cellNoHere:end,2) = [xyLoc(cellNoHere:end,2)+options.cropSizeLength*2+1];
				xyLoc(cellNoHere:end,1) = [2];
				rowNum = rowNum + 1;
			end
			croppedPeakImages2 = cat(1,g{:});

			% croppedPeakImages2 = getimage;
			imAlpha = ones(size(croppedPeakImages2));
			imAlpha(isnan(croppedPeakImages2))=0;
			imagesc(croppedPeakImages2,'AlphaData',imAlpha);
			set(gca,'color',[0 0 0]);
			colormap(gca,customColormap([]))
			title(['neighboring cell ID #s (white)' 10 'top-left = selected cell' 10 '#s increase L->R and T->B'])
			% title(['neighboring cells | top-left = selected cell, #s increase L->R and T->B'])
			axis equal tight
			box off

			% xyLoc
			for zz = 1:size(nImgs,3)
				text(xyLoc(zz,1),xyLoc(zz,2),num2str(nList(zz)),'Color',[1 1 1],'FontSize',options.cropSizeLength/2)
			end

		% plot the traces
		subplot(rowP,colP,[2:3 5:6 8:9])
			% nList = [cellnum neighborsCell{cellnum,1}(:)'];
			% plotSignalsGraph(inputSignals, 'plotList', flipdim(nList(:),1),'newAxisColorOrder','','minAdd',0,'maxIncrementPercent',1.1);
			plotSignalsGraph(inputSignals, 'plotList', flipdim(nList(:),1),'newAxisColorOrder','lines','minAdd',0,'maxIncrementPercent',1.1);
			axis tight
			xlabel('Time (frames)')
			ylabel('Cell activity')
			title('Activity traces for selected and neighboring cells (Zoom enabled)')
			legend(strsplit(num2str(nList),' '),'Location','southoutside','Orientation','horizontal')
			% ciapkg.overloaded.suptitle(instructionStr);
			zoom on

		% plot temporal correlations
		subplot(rowP,colP,4)
			z0 = corr(inputSignals(nList(:),:)');
			imagesc(z0)
			colorbar
			colormap(gca,customColormap([]))
			% colorbar; colormap jet;
			% colormap hot

			% imagesc(l);
			xlabel('Cell ID #s');
			ylabel('Cell ID #s');
			xticks(1:length(nList))
			xticklabels(nList)
			yticks(1:length(nList))
			yticklabels(nList)
			title(['cell-cell activity trace correlations' 10 'cell #' num2str(nList(1)) ' = this cell']);
			box off; axis equal tight
			caxis([0 1])
			% datacursormode on

		% plot spatial correlations
		subplot(rowP,colP,7)

			nCellsH = length(nList);
			fracMaxVal = 0.2;
			tmpImgs = inputImages(:,:,nList);
			if issparse(tmpImgs)
				tmpImgs = full(tmpImgs);
			end
			for cInd1 = 1:nCellsH
				tmpImgs1 = tmpImgs(:,:,cInd1);
				tmpImgs1(tmpImgs1<(nanmax(tmpImgs1(:))*fracMaxVal)) = 0;
				tmpImgs(:,:,cInd1) = tmpImgs1;
			end

			cEst = permute(tmpImgs, [3 1 2]);
			cEst = reshape(cEst, [size(cEst,1), numel(inputImages(:,:,1))]);
			% figure;imagesc(cEst);pause
			corrImgMatrix = 1-squareform(pdist(single(cEst>0),'jaccard'));

			spatialCorr = z0*0;
			spatialCorr2 = z0*0;
			for cInd1 = 1:nCellsH
				cImg1 = tmpImgs(:,:,cInd1);
				cImg1_2 = inputImages(:,:,nList(cInd1));
				for cInd2 = 1:nCellsH
					if cInd2==cInd1
						spatialCorr(cInd1,cInd2) = 1;
					end
					if cInd2>cInd1
						continue;
					end
					cImg2 = tmpImgs(:,:,cInd2);
					cImg2_2 = inputImages(:,:,nList(cInd2));

					% cImg1(cImg1<(nanmax(cImg1(:))*fracMaxVal)) = 0;
					% cImg2(cImg2<(nanmax(cImg2(:))*fracMaxVal)) = 0;

					c1Pixels = find(cImg1>0);
					c2Pixels = find(cImg2>0);
					thisOverlap=length(intersect(c1Pixels,c2Pixels));
					thisOverlap1=thisOverlap/length(c1Pixels);
					thisOverlap2=thisOverlap/length(c2Pixels);

					spatialCorr(cInd1,cInd2) = thisOverlap1;
					spatialCorr(cInd2,cInd1) = thisOverlap2;

					c1Pixels = find(cImg1_2>0);
					c2Pixels = find(cImg2_2>0);
					thisOverlap=length(intersect(c1Pixels,c2Pixels));
					thisOverlap1=thisOverlap/length(c1Pixels);
					thisOverlap2=thisOverlap/length(c2Pixels);

					spatialCorr2(cInd1,cInd2) = thisOverlap1;
					spatialCorr2(cInd2,cInd1) = thisOverlap2;
				end
			end
			imagesc(cat(2,spatialCorr,corrImgMatrix,spatialCorr2));
			colorbar
			colormap(gca,customColormap([]))
			% colorbar; colormap jet;
			% colormap hot

			% imagesc(l);
			xlabel('Cell ID #s');
			ylabel('Cell ID #s');
			nListLen = length(nList);
			xticks(1:(nListLen*3))
			xticklabels([nList; nList; nList])
			yticks(1:length(nList))
			yticklabels(nList)
			title(['cell-cell image correlations']);
			box off; axis equal tight
			hold on;
			% plot([nListLen+0.5 nListLen+0.5],get(gca,'YLim'),'k-','LineWidth',1);
			% plot([nListLen*2+0.5 nListLen*2+0.5],get(gca,'YLim'),'k-','LineWidth',1);
			hold off;
			% datacursormode on
			caxis([0 1])

		ciapkg.overloaded.suptitle([sprintf('cell # %d/%d',cellnum,nCells) 10 instructionStr],'plotregion',0.9);
		set(findall(gcf,'-property','FontSize'),'FontSize',13);
		% [x,y,reply]=ginput(1);

		set(gcf,'currentch','3');
		keyIn = get(gcf,'CurrentCharacter');
		figure(21)

		while strcmp(keyIn,'3')
			keyIn = get(gcf,'CurrentCharacter');
			pause(0.05);
		end
		reply = double(keyIn);
		set(gcf,'currentch','3');

		[valid directionOfNextChoice exitLoop cellnum] = respondToUserInput(reply,cellnum,valid,directionOfNextChoice,exitLoop,nCells);

		cellnum=cellnum+directionOfNextChoice;
		% loop if user gets to either end
		if cellnum<=0
			cellnum = nCells;
		elseif i>nCells;
			cellnum = 1;
		end
	end
	close(21)

end

function [valid directionOfNextChoice exitLoop i] = respondToUserInput(reply,i,valid,directionOfNextChoice,exitLoop,nCells)
	% decide what to do based on input (not a switch due to multiple comparisons)
	if isequal(reply, 3)|isequal(reply, 110)|isequal(reply, 31)
		% n key or right click
		directionOfNextChoice=1;
		% display('invalid IC');
		% set(fig1,'Color',[0.8 0 0]);
		valid(i) = 0;
	elseif isequal(reply, 28)
		% go back, left
		directionOfNextChoice=-1;
	elseif isequal(reply, 29)
		% go forward, right
		directionOfNextChoice=1;
	elseif isequal(reply, 101)
		exitLoop=1;
		% user clicked 'f' for finished, exit loop
		% i=nCells+1;
	elseif isequal(reply, 103)
		% if user clicks 'g' for goto, ask for which IC they want to see
		icChange = inputdlg('enter signal #'); icChange = str2num(icChange{1});
		if icChange>nCells|icChange<1
			% do nothing, invalid command
		else
			i = icChange;
			directionOfNextChoice = 0;
		end
	elseif isequal(reply, 115)
		% 's' if user wants to get ride of the rest of the ICs
		display(['classifying the following signals as bad: ' num2str(i) ':' num2str(nCells)])
		valid(i:nCells) = 0;
		exitLoop=1;
	elseif isequal(reply, 121)|isequal(reply, 1)|isequal(reply, 30)
		% y key or left click
		directionOfNextChoice=1;
		% display('valid IC');
		% set(fig1,'Color',[0 0.8 0]);
		valid(i) = 1;
	else
		% forward=1;
		% valid(i) = 1;
	end
end


function O = renderCluster_ui4(O)
% :Usage:
% ::
%
%    O = renderCluster_ui4(O)
%
% :Inputs:
%
%   **O**
%
%   **O.head:**
%        name of head to use, no .img extension
%
%   **O.surf:**
%        'y' or 'n': image surface
%
%   **O.sets:**
%        number of sets
%
%   **O.getfrom:**
%        cell array of where to get clusters from: 'workspace' 'file' etc.
%
%   **O.varname:**
%        cell array of variable names
%
%   **O.color:**
%        cell array of colors - strings or vectors
%
%   **O.numbers:**
%        'y' or 'n': add numbers to plot
%
%   also need individual fields named contents of varname, which contain clusters

if ~isfield(O,'clusterAlpha'),O.clusterAlpha = .7;, end
if ~isfield(O,'coords'),O.coords = [30 30 -5];, end
if ~isfield(O,'whichcuts'),O.whichcuts = 'z';, end
if ~isfield(O,'dohead'),O.dohead = 1;, end

%------------------------------------------------------------------------------
% Get head, if not default
%------------------------------------------------------------------------------
cflag = 0;
while cflag == 0
    if ~isfield(O,'head')
        a = input('Use default head single_subj_T1...?  (type default or file name, no .img extension)','s');
    else a = O.head;
    end

    switch a
    case 'default', fileName = 'single_subj_T1';
    otherwise fileName = a;
    end
    if exist([fileName '.img']) == 2,
	cflag = 1;
    else
	disp(['Can''t locate file: ' fileName '.img'])
    O = rmfield(O,'head');
    end
end

%------------------------------------------------------------------------------
% Add surface?
%------------------------------------------------------------------------------
cflag = 0;
while cflag == 0
    if ~isfield(O,'surf')
        a = input('Add brain surface (y\n\filename,no .img extension)...?','s');
    else a = O.surf;
    end

    switch a
    case 'y', fileName2 = ['surf_' fileName];, dosurf = 1;
    case 'n', fileName2 = [];, cflag = 1;, dosurf = 0;
    otherwise fileName2 = a;, dosurf = 1;
    end
    if dosurf & exist([fileName2 '.mat']) == 2,
	    cflag = 1;
    elseif dosurf
	    disp(['Can''t locate file: ' fileName '.mat'])
        O = rmfield(O,'surf');
    end
end

if ~isfield(O,'sets')
    numSets = input('Enter number of cluster sets: ');
else numSets = O.sets;
end

%------------------------------------------------------------------------------
% Add numbers?
%------------------------------------------------------------------------------
cflag = 0;
while cflag == 0
    if ~isfield(O,'numbers')
        addNums = input('Add numbers to plot? ','s');
    else addNums = O.numbers;
    end
    cflag = 1;
end

for i = 1:numSets

    disp(['Cluster Set ' num2str(i)])
    disp('_______________________________________________')

    %------------------------------------------------------------------------------
    % Get clusters, if necessary
    %------------------------------------------------------------------------------
    cflag = 0;
    while cflag == 0
       if ~isfield(O,'getfrom')
            a = input('Get clusters from...?  (workspace,file,figure)','s');
        else
            a = O.getfrom{i};
        end

       switch a
       case 'workspace',
            cflag = 1;
            if ~isfield(O,'varname')
                varname = input('Enter name of workspace variable: ','s');
                eval(['clusters = ' varname])
            else
                varname = O.varname{i};
                eval(['clusters = O.' varname ';'])
            end

            if isempty(clusters),disp('No clusters or not a valid variable name.'),
                cflag=0;
                O = rmfield(O,'varname');
            end
       case 'file', clusters = imageCluster('getclusters');, cflag = 1;
       case 'figure', clusters = imageCluster('getfigclusters');, cflag = 1;
       otherwise disp(['Not a valid choice...type entry string with no quotes.'])
       end
    end

    if ~isfield(O,'color')
        mycolor = input('Enter color string in single quotes or color vector for clusters: ');
    else
        mycolor = O.color{i};
    end

    cH = [];
    for j = 1:length(clusters)
        cH(j) = imageCluster('cluster',clusters(j),'color',mycolor,'alpha',O.clusterAlpha); drawnow
        set(cH(j),'Tag',['set' num2str(i) 'cluster' num2str(j)])
    end

    clusterHandles{i} = cH;

    if strcmp(addNums,'y')
          numberHandles{i} = cl_line_plots(clusters);
    end

end

%------------------------------------------------------------------------------
% * lighting stuff
%------------------------------------------------------------------------------
lighting gouraud;
[az,el] = view;
myLight = lightangle(az,el);
set(myLight,'Tag','myLight')
rotate3d on

% set callback to light follow the camera
%------------------------------------------------------------------------------
if exist('lightFollowView') == 2
     set(gcf, 'WindowButtonUpFcn', 'lightFollowView');
else
     warning('Cannot find lightFollowView.m to set light position.')
end
axis vis3d
axis image
drawnow

%------------------------------------------------------------------------------
% * head surface
%------------------------------------------------------------------------------
if dosurf
    p = [];
    eval(['load ' fileName2])
    try
        p(end+1) = patch('Faces',faces,'Vertices',vertices,'FaceColor',[.5 .5 .5],'EdgeColor','none','SpecularStrength',.2,'FaceAlpha',.5,'SpecularExponent',200);
    catch
        p(end+1) = patch('Faces',faces,'Vertices',vertices,'FaceColor',[.5 .5 .5],'EdgeColor','none','SpecularStrength',.2,'SpecularExponent',200);
    end
    axis vis3d
    axis image
    drawnow
    O.p = p;
end

O.clusterHandles = clusterHandles;
O.numberHandles = numberHandles;

if O.dohead
    [D,Ds,hdr,p,coords,X,Y,Z] = tor_3d('coords',O.coords,'whichcuts',O.whichcuts);
    set(gcf,'Color','k');axis off;colormap(gray)
end


function region = p05_region ( )

%*****************************************************************************80
%
%% P05_REGION returns the name of the integration region for problem 05.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 March 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string REGION, the name of the integration region.
%
  region = 'box';

  return
end


function camPaths = dtiLoadCaminoPaths(filename, xform, bEndOnly)
%
% camPaths = dtiLoadCaminoPaths(filename)
%
% Loads fiber pathways from a Camino .Bfloat file.
%
% Notes: Pathways are assumed to be stored in the following Camino format:
% [<N>, <seed point index>, <x_1>, <y_1>, <z_1>,...,<x_numPoints>, <y_N>,
% <z_N>, <N>,...,<z_N>]
%
%
% HISTORY:
% 2007.09.07 Written by Anthony Sherbondy
% 2010.04.19 AJS made the code much faster by removing function calls and
% preallocating cell array.

% %% Endpoints only?
% if ieNotDefined('bEndOnly')
%     bEndOnly = 0;
% end

%% Open file and read all raw data in
fid = fopen(filename,'rb','b');
rawPaths = fread(fid,'float'); fclose(fid);

%% Create pathway structure
camPaths.statHeader(1).agg_name = 'Length';
camPaths.pathwayInfo = [];
camPaths.pathways = {};

%% First read off all pathway sizes
buffer_size = length(rawPaths);
v_num_points = nan(buffer_size,1);
v_sptr = zeros(buffer_size,1);
sPtr = 1;
pp = 1;
while sPtr < buffer_size
    v_num_points(pp) = rawPaths(sPtr);
    v_sptr(pp) = (sPtr);
    sPtr = sPtr+3*v_num_points(pp)+2;
    pp = pp + 1;
end

%% Get acutal number of pathways represented in buffers
v_sptr = v_sptr(~isnan(v_num_points) & v_num_points>=3);
v_num_points = v_num_points(~isnan(v_num_points) & v_num_points>=3);

%% Now lets go and read all the pathways
camPaths.pathways = cell(numel(v_num_points),1);
%pct_step = 10;
%pct = pct_step;
%step = floor(length(v_num_points)/(100/pct_step));
for pp=1:length(v_num_points)
    sPtr = v_sptr(pp);
    numPoints = v_num_points(pp);
    camPaths.pathways{pp,1} = reshape(rawPaths(sPtr+2:sPtr+1+3*numPoints),3,numPoints);
%     if pp > step * pct
%         pct = floor(pp / step);
%         fprintf(1,'\n%3d percent file processed...', pct);
%         pct = pct + pct_step;
%     end
end

return;


function dumpIfileHeader(ifileName)
% dumpIfileHeader(ifileName)
%
% Displays some of the GE header fields for the given I-file
% (eg. 'I.001') in human-readable format.
%
% REQUIRES:
%  GE2SPM tools- eg. addpath /usr/local/matlab/toolbox/mri/filters/GE2SPM/
%   -or-
%  matlab's DICOM tools (part of the image processing toolbox in matlab
%  version >= 6.5)
%
% HISTORY:
%  2002.06.07 RFD (bob@white.stanford.edu) wrote it.
%  2004.07.01 RFD: we now use Junjie's readImageHeader, so that this
%  function will work with either GE I-files or DICOM files.

if(nargin<1)
    help(mfilename);
    return;
end

[su_hdr,ex_hdr,se_hdr,im_hdr] = readImageHeader(ifileName);

disp(sprintf('Exam #: %d', ex_hdr.ex_no));
% GE timestamp is a unix timestamp- # of seconds since 1970.01.01 00:00:00
% eg. yr = round(1970+ex_hdr.ex_datetime/60/60/24/365.25); ...
disp(sprintf('Exam timestamp: %d', ex_hdr.ex_datetime));
disp(sprintf('Hospital name: %s', char(ex_hdr.hospname')));
disp(sprintf('Field strength: %0.1f Tesla', ex_hdr.magstrength/10000));
disp(sprintf('Patient ID: %s', char(ex_hdr.patid')));
disp(sprintf('Patient name: %s', char(ex_hdr.patname')));
disp(sprintf('Patient weight: %0.1f Kg', ex_hdr.patweight/1000));
disp(sprintf('Patient age: %0.0f years', ex_hdr.patage));
disp(sprintf('History: %s', char(ex_hdr.hist')));
disp(sprintf('Exam description: %s', char(ex_hdr.ex_desc')));

disp(sprintf('PSD iname: %s', char(im_hdr.psd_iname')));
disp(sprintf('Scan Time: %0.1f minutes', im_hdr.sctime/1000000/60));
disp(sprintf('FOV: %0.1f', im_hdr.dfov));
disp(sprintf('X,Y dim: %d, %d', im_hdr.dim_X, im_hdr.dim_Y));
disp(sprintf('X,Y pixels: %d, %d', im_hdr.imatrix_X, im_hdr.imatrix_Y));
disp(sprintf('nSlices: %d @ %0.4f mm thickness', im_hdr.slquant, im_hdr.slthick));
disp(sprintf('in-plane voxel size: x=%0.4f mm, y=%0.4fmm', im_hdr.pixsize_X, im_hdr.pixsize_Y));
disp(sprintf('TR: %0.1f ms', im_hdr.tr));
disp(sprintf('TI: %0.1f ms', im_hdr.ti));
disp(sprintf('TE: %0.1f ms (%d echos)', im_hdr.te, im_hdr.numecho));
disp(sprintf('flip: %d deg', im_hdr.mr_flip));
disp(sprintf('NEX: %f', im_hdr.nex));
disp(sprintf('SAR average: %f, peak: %f', im_hdr.saravg, im_hdr.sarpeak));

return;


% STD_CHANTOPO - plot ERP/spectral/ERSP topoplot at a specific
%                  latency/frequency.
% Usage:
%          >> std_chantopo( data, 'key', 'val', ...)
% Inputs:
%  data  -  [cell array] mean data for each subject group and/or data
%           condition. These arrays are usually returned by function
%           std_erspplot and std_erpplot. For example
%
%           >> data = { [1x64x12] [1x64x12 }; % 2 groups of 12 subjects, 64 channels
%           >> std_chantopo(data, 'chanlocs', 'chanlocfile.txt');
%
% Scalp map plotting option (mandatory):
%  'chanlocs'    - [struct] channel location structure
%
% Other scalp map plotting options:
%  'chanlocs'    - [struct] channel location structure
%  'topoplotopt' - [cell] topoplot options. Default is { 'style', 'both',
%                  'shading', 'interp' }. See topoplot help for details.
%  'ylim'        - [min max] ordinate limits for ERP and spectrum plots
%                  {default: all available data}
%  'caxis'       - [min max] same as above
%
% Optional display parameters:
%  'datatype'    - ['erp'|'spec'] data type {default: 'erp'}
%  'titles'      - [cell array of string] titles for each of the subplots.
%                  { default: none}
%  'subplotpos'  - [addr addc posr posc] perform plotting in existing figure.
%                  Add "addr" rows, "addc" columns and plot the scalp
%                  topographies starting at position (posr,posc).
%
% Statistics options:
%  'groupstats'  - [cell] One p-value array per group {default: {}}
%  'condstats'   - [cell] One p-value array per condition {default: {}}
%  'interstats'  - [cell] Interaction p-value arrays {default: {}}
%  'threshold'   - [NaN|real<<1] Significance threshold. NaN -> plot the
%                  p-values themselves on a different figure. When possible,
%                  significance regions are indicated below the data.
%                  {default: NaN}
%  'binarypval'  - ['on'|'off'] if a threshold is set, show only significant
%                  channels as red dots. Default is 'off'.
%
% Author: Arnaud Delorme, CERCO, CNRS, 2006-
%
% See also: POP_ERSPPARAMS, POP_ERPPARAMS, POP_SPECPARAMS, STATCOND

% Copyright (C) 2006 Arnaud Delorme
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function std_chantopo(data, varargin)

pgroup = [];
pcond  = [];
pinter = [];
if nargin < 2
    help std_chantopo;
    return;
end

opt = finputcheck( varargin, { 'ylim'        'real'    []              [];
                               'titles'      'cell'    []              cell(20,20);
                               'threshold'   'real'    []              NaN;
                               'chanlocs'    'struct'  []              struct('labels', {});
                               'groupstats'  'cell'    []              {};
                               'condstats'   'cell'    []              {};
                               'interstats'  'cell'    []              {};
                               'effect'      'string' { 'main','marginal' }   'marginal';
                               'subplotpos'  'integer' []              [];
                               'topoplotopt' 'cell'    []              { 'style', 'both' };
                               'binarypval'  'string'  { 'on','off' }  'on';
                               'datatype'    'string'  { 'ersp','itc','erp','spec' }    'erp';
                               'caxis'       'real'    []              [] }, 'std_chantopo', 'ignore'); %, 'ignore');
if ischar(opt), error(opt); end
if ~isempty(opt.ylim), opt.caxis = opt.ylim; end
if isnan(opt.threshold), opt.binarypval = 'off'; end
if strcmpi(opt.binarypval, 'on'), opt.ptopoopt = { 'style' 'blank' }; else opt.ptopoopt = opt.topoplotopt; end

% remove empty entries
datapresent = ~cellfun(@isempty, data);
for c = size(data,1):-1:1, if sum(datapresent(c,:)) == 0, data(c,:) = []; opt.titles(c,:) = []; if ~isempty(opt.groupstats), opt.groupstats(c) = []; end; end; end
for g = size(data,2):-1:1, if sum(datapresent(:,g)) == 0, data(:,g) = []; opt.titles(:,g) = []; if ~isempty(opt.condstats ), opt.condstats( g) = []; end; end; end

nc = size(data,1);
ng = size(data,2);
if nc >= ng, opt.transpose = 'on';
else         opt.transpose = 'off';
end

% plotting parameters
% ------------------
if ng > 1 && ~isempty(opt.groupstats), addc = 1; else addc = 0; end
if nc > 1 && ~isempty(opt.condstats ), addr = 1; else addr = 0; end
if ~isempty(opt.subplotpos)
     if strcmpi(opt.transpose, 'on'), opt.subplotpos = opt.subplotpos([2 1 4 3]); end
     addr = opt.subplotpos(1);
     addc = opt.subplotpos(2);
     posr = opt.subplotpos(4);
     posc = opt.subplotpos(3);
else posr = 0;
     posc = 0;
end

% compute significance mask
% -------------------------
pinterplot = {};
if strcmpi(opt.effect, 'marginal') || ng == 1 || nc == 1
    if ~isnan(opt.threshold) && ( ~isempty(opt.groupstats) || ~isempty(opt.condstats) )
        pcondplot  = opt.condstats;
        pgroupplot = opt.groupstats;
        maxplot = 1;
    else
        for ind = 1:length(opt.condstats),  pcondplot{ind}  = -log10(opt.condstats{ind}); end
        for ind = 1:length(opt.groupstats), pgroupplot{ind} = -log10(opt.groupstats{ind}); end
        maxplot = 3;
    end
elseif strcmpi(opt.effect, 'main') && ~isempty(opt.interstats)
    if ~isnan(opt.threshold) && ( ~isempty(opt.groupstats) || ~isempty(opt.condstats) )
        pcondplot  = { opt.interstats{2} };
        pgroupplot = { opt.interstats{1} };
        pinterplot = opt.interstats{3};
        maxplot = 1;
    else
        if ~isempty(opt.interstats{2}), pcondplot  = { -log10(opt.interstats{2}) }; end
        if ~isempty(opt.interstats{1}), pgroupplot = { -log10(opt.interstats{1}) }; end
        if ~isempty(opt.interstats{3}), pinterplot = -log10(opt.interstats{3}); end
        maxplot = 3;
    end
end

% adjust figure size
% ------------------
if isempty(opt.subplotpos)
    fig = figure('color', 'w');
    pos = get(fig, 'position');
    set(fig, 'position', [ pos(1)+15 pos(2)+15 pos(3)/2.5*(nc+addr), pos(4)/2*(ng+addc) ]);
    pos = get(fig, 'position');
    if strcmpi(opt.transpose, 'off'), set(gcf, 'position', [ pos(1) pos(2) pos(4) pos(3)]);
    else                              set(gcf, 'position', pos);
    end
end

% topoplot
% --------
tmpc = [inf -inf];
for c = 1:nc
    for g = 1:ng
        hdl(c,g) = mysubplot(nc+addr, ng+addc, c, g, opt.transpose);
        if ~isempty(data{c,g})
            tmpplot = double(mean(data{c,g},3));
            if ~isreal(tmpplot(1)), tmpplot = abs(tmpplot); end % comes second for processing single trials
            if ~all(isnan(tmpplot))
                if ~isreal(tmpplot), error('This function cannot plot complex values'); end
                topoplot( tmpplot, opt.chanlocs, opt.topoplotopt{:});
                if isempty(opt.caxis)
                    tmpc = [ min(min(tmpplot), tmpc(1)) max(max(tmpplot), tmpc(2)) ];
                else
                    caxis(opt.caxis);
                end
                title(opt.titles{c,g}, 'interpreter', 'none');
            else
                axis off;
            end
        else
            axis off;
        end

        % statistics across groups
        % -------------------------
        if strcmpi(opt.effect, 'marginal') || (strcmpi(opt.effect, 'main') && c == 1)
            if g == ng && ng > 1 && ~isempty(opt.groupstats)
                if strcmpi(opt.effect, 'main') && nc>1, centerc = nc/2-0.5; else centerc = 0; end
                hdl(c,g+1) = mysubplot(nc+addr, ng+addc, c+centerc, ng + 1, opt.transpose);
                pgroupplot{c}(pgroupplot{c} <0) = 0;
                topoplot( pgroupplot{c}, opt.chanlocs, opt.ptopoopt{:});
                title(opt.titles{c,g+1}, 'interpreter', 'none');
                caxis([-maxplot maxplot]);
            end
        end
    end
end

% color scale
% -----------
if isempty(opt.caxis)
    for c = 1:nc
        for g = 1:ng
            axes(hdl(c,g));
            caxis(tmpc);
        end
    end
end

for g = 1:ng
    % statistics across conditions
    % -----------------------------
    if strcmpi(opt.effect, 'marginal') || (strcmpi(opt.effect, 'main') && g == 1)
        if ~isempty(opt.condstats) && nc > 1
            if strcmpi(opt.effect, 'main') && ng>1, centerg = ng/2-0.5; else centerg = 0; end
            hdl(nc+1,g) = mysubplot(nc+addr, ng+addc, nc+addr, g+centerg, opt.transpose);
            pcondplot{g}(pcondplot{g} < 0) = 0;
            topoplot( pcondplot{g}, opt.chanlocs, opt.ptopoopt{:});
            title(opt.titles{nc+1,g}, 'interpreter', 'none');
            caxis([-maxplot maxplot]);
        end
    end
end

% statistics across group and conditions
% ---------------------------------------
if ~isempty(opt.condstats) && ~isempty(opt.groupstats) && ng > 1 && nc > 1 && ~isempty(pinterplot)
    hdl(nc+1,ng+1) = mysubplot(nc+addr, ng+addc, nc+addr, ng+1, opt.transpose);
    pinterplot(pinterplot<0) = 0;
    topoplot( pinterplot, opt.chanlocs, opt.ptopoopt{:});
    title(opt.titles{nc+1,ng+1}, 'interpreter', 'none');
    caxis([-maxplot maxplot]);
end

% color bars
% ----------
if isnan(opt.threshold(1)) && (nc ~= size(hdl,1) || ng ~= size(hdl,2))
    try
        axes(hdl(end,end));
        cbar_signif(ng, maxplot);
    catch
        cbar_signif(ng, maxplot);
    end
end
axes(hdl(nc,ng));
cbar_standard(opt.datatype, ng);

% remove axis labels
% ------------------
for c = 1:size(hdl,1)
    for g = 1:size(hdl,2)
        if g ~= 1 && size(hdl,2) ~=1, ylabel(''); end
        if c ~= size(hdl,1) && size(hdl,1) ~= 1, xlabel(''); end
    end
end

% colorbar for ERSP and scalp plot
% --------------------------------
function cbar_standard(datatype, ng);
    pos = get(gca, 'position');
    tmpc = caxis;
    fact = fastif(ng == 1, 40, 20);
    tmp = axes('position', [ pos(1)+pos(3)+pos(3)/fact pos(2) pos(3)/fact pos(4) ]);
    set(gca, 'unit', 'normalized');
    if strcmpi(datatype, 'itc')
         cbar(tmp, 0, tmpc, 10); ylim([0.5 1]);
    else cbar(tmp, 0, tmpc, 5);
    end

% colorbar for significance
% -------------------------
function cbar_signif(ng, maxplot);
    % Retrieving Defaults
    icadefs;

    pos = get(gca, 'position');
    tmpc = caxis;
    fact = fastif(ng == 1, 40, 20);
    tmp = axes('position', [ pos(1)+pos(3)+pos(3)/fact pos(2) pos(3)/fact pos(4) ]);
    map = colormap(DEFAULT_COLORMAP);
    n = size(map,1);
    cols = [ceil(n/2):n]';
    image([0 1],linspace(0,maxplot,length(cols)),[cols cols]);
    %cbar(tmp, 0, tmpc, 5);
    tick = linspace(0, maxplot, maxplot+1);
    set(gca, 'ytickmode', 'manual', 'YAxisLocation', 'right', 'xtick', [], ...
        'ytick', tick, 'yticklabel', round(10.^-tick*1000)/1000);
    xlabel('');
    colormap(DEFAULT_COLORMAP);

% mysubplot (allow to transpose if necessary)
% -------------------------------------------
function hdl = mysubplot(nr,nc,r,c,subplottype)

    cmargin = 0.2/nc;
    rmargin = 0.2/nr;
    if strcmpi(subplottype, 'transpose') || strcmpi(subplottype, 'on'),   hdl = subplot('position',[(r-1)/nr+rmargin (nc-c)/nc+cmargin 1/nr-2*rmargin 1/nc-2*cmargin]);
    elseif strcmpi(subplottype, 'normal') || strcmpi(subplottype, 'off'), hdl = subplot('position',[(c-1)/nc+cmargin (nr-r)/nr+rmargin 1/nc-2*cmargin 1/nr-2*rmargin]);
    elseif strcmpi(subplottype, 'noplot'), hdl = gca;
    else error('Unknown subplot type');
    end


function ind = id2ind(ebsd,id)
% find ind such that ebsd.id(ind) == id
%
% Syntax
%   ind = id2ind(ebsd,id)
%
% Input
%  ebsd - @EBSD
%  id - a list of id's as stored in ebsd.id
%
% Output
%  ind - a list indeces such that ebsd.id(ind) == id

[~,ind] = ismember(id,ebsd.id);


% union_bc - union backward compatible with Matlab versions prior to 2013a

% Copyright (C) 2013 Arnaud Delorme
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [C,IA,IB] = union_bc(A,B,varargin)

errorFlag = error_bc;

v = version;
indp = find(v == '.');
v = str2num(v(1:indp(2)-1));
if v > 7.19, v = floor(v) + rem(v,1)/10; end

if nargin > 2
    ind = strmatch('legacy', varargin);
    if ~isempty(ind)
        varargin(ind) = [];
    end
end

if v >= 7.14
    [C,IA,IB] = union(A,B,varargin{:},'legacy');
    if errorFlag
        [C2,IA2,IB2] = union(A,B,varargin{:});
        if (~isequal(C, C2) || ~isequal(IA, IA2) || ~isequal(IB, IB2))
            warning('backward compatibility issue with call to union function');
        end
    end
else
    [C,IA,IB] = union(A,B,varargin{:});
end


% This .m file "view_maxz.m" plots the maxz LTA values calculated
% with maxzlta.m or other similar values as a color map
% needs re3, gx, gy, stri
%

report_this_filefun(mfilename('fullpath'));

% define size of the plot etc.
%
co = 'w';

% Find out of figure already exists
%
[existFlag,figNumber]=figure_exists('b-value cross-section',1);
newbmapcWindowFlag=~existFlag;

% This is the info window text
%
ttlStr='The Z-Value Map Window                        ';
hlpStr1zmap= ...
    ['                                                '
    ' This window displays seismicity rate changes   '
    ' as z-values using a color code. Negative       '
    ' z-values indicate an increase in the seismicity'
    ' rate, positive values a decrease.              '
    ' Some of the menu-bar options are               '
    ' described below:                               '
    '                                                '
    ' Threshold: You can set the maximum size that   '
    '   a volume is allowed to have in order to be   '
    '   displayed in the map. Therefore, areas with  '
    '   a low seismicity rate are not displayed.     '
    '   edit the size (in km) and click the mouse    '
    '   outside the edit window.                     '
    'FixAx: You can chose the minimum and maximum    '
    '        values of the color-legend used.        '
    'Polygon: You can select earthquakes in a        '
    ' polygon either by entering the coordinates or  '
    ' defining the corners with the mouse            '];
hlpStr2zmap= ...
    ['                                                '
    'Circle: Select earthquakes in a circular volume:'
    '      Ni, the number of selected earthquakes can'
    '      be edited in the upper right corner of the'
    '      window.                                   '
    ' Refresh Window: Redraws the figure, erases     '
    '       selected events.                         '

    ' zoom: Selecting Axis -> zoom on allows you to  '
    '       zoom into a region. Click and drag with  '
    '       the left mouse button. type <help zoom>  '
    '       for details.                             '
    ' Aspect: select one of the aspect ratio options '
    ' Text: You can select text items by clicking.The'
    '       selected text can be rotated, moved, you '
    '       can change the font size etc.            '
    '       Double click on text allows editing it.  '
    '                                                '
    '                                                '];

% Set up the Seismicity Map window Enviroment
%
if newbmapcWindowFlag
    bmapc = figure_w_normalized_uicontrolunits( ...
        'Name','b-value cross-section',...
        'NumberTitle','off', ...
        'MenuBar','none', ...
        'backingstore','on',...
        'Visible','off', ...
        'Position',[ (fipo(3:4) - [600 400]) ZmapGlobal.Data.map_len]);
    % make menu bar
    matdraw

    add_symbol_menu('eqc_plot');

    uicontrol('Units','normal',...
        'Position',[.0 .93 .08 .06],'String','Print ',...
         'Callback','myprint')

    callbackStr= ...
        ['f1=gcf; f2=gpf; set(f1,''Visible'',''off'');close(bmapc);', ...
        'if f1~=f2, figure_w_normalized_uicontrolunits(map);done; end'];

    uicontrol('Units','normal',...
        'Position',[.0 .75 .08 .06],'String','Close ',...
         'Callback','eval(callbackStr)')

    uicontrol('Units','normal',...
        'Position',[.0 .85 .08 .06],'String','Info ',...
         'Callback','zmaphelp(ttlStr,hlpStr1zmap,hlpStr2zmap)')

    options = uimenu('Label',' Select ');
    uimenu(options,'Label','Refresh ', 'Callback','view_bv2')
    uimenu(options,'Label','Select EQ in Circle',...
         'Callback',' h1 = gca;ho=false;cicros;watchoff(bmapc)')
    uimenu(options,'Label','Select EQ in Circle - Overlay existing plot', 'Callback','h1 = gca;ho=true;cicros;watchoff(bmapc)')

    op1 = uimenu('Label',' Tools ');
    uimenu(op1,'Label','Fix color (z) scale', 'Callback','fixax2 ')
    uimenu(op1,'Label','Histogram of b-values', 'Callback','zhist')
    uimenu(op1,'Label','Show  b-value Map', 'Callback',' re3 = old; view_bv2')
    uimenu(op1,'Label','Show  b(mean) map', 'Callback',' re3 = 0.4343./(meg-min(newa(:,6))); view_bv2')
    uimenu(op1,'Label','Show  mean magnitude map', 'Callback',' re3 = meg; view_bv2')
    uimenu(op1,'Label','Show  mag of completness map', 'Callback',' re3 = old1; view_bv2')
    uimenu(op1,'Label','Show Resolution Map', 'Callback','re3 = r; view_bv2')
    uimenu(op1,'Label','Show Grid ',...
         'Callback',' [X,Y] = meshgrid(gx,gy);hold on;plot(X,Y,''+k'')')
    uimenu(op1,'Label','Show Circles ', 'Callback','plotcirc')
    uimenu(op1,'Label','Colormap InvertGray', 'Callback','g=gray; g = g(64:-1:1,:);colormap(g);brighten(.4)')
    uimenu(op1,'Label','shading flat', 'Callback','axes(hzma); shading flat')
    uimenu(op1,'Label','shading interpolated',...
         'Callback','axes(hzma); shading interp')

    uicontrol('Units','normal',...
        'Position',[.92 .80 .08 .05],'String','set ni',...
         'Callback','ni=str2num(get(set_nia,''String''));''String'',num2str(ni);')

    set_nia = uicontrol('style','edit','value',ni,'string',num2str(ni));
    set(set_nia,'Callback',' ');
    set(set_nia,'units','norm','pos',[.94 .85 .06 .05],'min',10,'max',10000);
    nilabel = uicontrol('style','text','units','norm','pos',[.90 .85 .04 .05]);
    set(nilabel,'string','ni:','background',[.7 .7 .7]);

    % tx = text(0.07,0.95,[name],'Units','Norm','FontSize',18,'Color','k','FontWeight','bold');

    tresh = max(max(r)); re4 = re3;
    nilabel2 = uicontrol('style','text','units','norm','pos',[.60 .92 .25 .06]);
    set(nilabel2,'string','MinRad (in km):','background',color_fbg);
    set_ni2 = uicontrol('style','edit','value',tresh,'string',num2str(tresh),...
        'background','y');
    set(set_ni2,'Callback','tresh=str2double(get(set_ni2,''String'')); set(set_ni2,''String'',num2str(tresh))');
    set(set_ni2,'units','norm','pos',[.85 .92 .08 .06],'min',0.01,'max',10000);

    uicontrol('Units','normal',...
        'Position',[.95 .93 .05 .05],'String','Go ',...
         'Callback','think;pause(1);re4 =re3; view_bv2')

end   % This is the end of the figure setup

% Now lets plot the color-map of the z-value
%
figure_w_normalized_uicontrolunits(bmapc)
delete(gca)
delete(gca)
delete(gca)
try
    delete(sizmap)
catch ME
    error_handler(ME, ' ');
end
reset(gca)
cla
hold off
watchon;
set(gca,'visible','off','FontSize',ZmapGlobal.Data.fontsz.m,'FontWeight','bold',...
    'FontWeight','bold','LineWidth',1.5,...
    'Box','on','SortMethod','childorder')

rect = [0.18,  0.00, 0.7, 0.75];
rect1 = rect;

% set values gretaer tresh = nan
%
re4 = re3;
l = r > tresh;
re4(l) = zeros(1,length(find(l)))*nan;

% plot image
%
orient portrait
%set(gcf,'PaperPosition', [2. 1 7.0 5.0])

axes('position',rect)
hold on
pco1 = pcolor(gx,gy,re4);

axis([ min(gx) max(gx) min(gy) max(gy)])
axis image
hold on
shading interp
h = hsv(64);
    h = h(57:-1:1,:);
    colormap(h)

if fre == 1
    caxis([fix1 fix2])
end

ylabel('depth in [km]','FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m)

% ploeqc = plot(newa(:,length(newa(1,:))),-newa(:,7),'.k')

if ~isempty(maix)
    pl = plot(maix,maiy,'*k')
    set(pl,'MarkerSize',12,'LineWidth',2)
end

%if ~isempty(maex)
pl = plot(maex,-maey,'xw')
set(pl,'MarkerSize',10,'LineWidth',2)
%end

set(gca,'visible','on','FontSize',ZmapGlobal.Data.fontsz.m,'FontWeight','bold',...
    'FontWeight','bold','LineWidth',1.5,...
    'Box','on','TickDir','out')
h1 = gca;
hzma = gca;

% Create a colobar
%
h5 = colorbar('vert');
set(h5,'Pos',[0.80 0.40 0.02 0.15],...
    'FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m)
%h5 = colorbar('horiz');
%set(h5,'Pos',[0.25 0.05 0.5 0.05],...
%'FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m)

% Make the figure visible
%
set(gca,'visible','on','FontSize',ZmapGlobal.Data.fontsz.m,'FontWeight','bold',...
    'FontWeight','bold','LineWidth',1.5,...
    'Box','on','TickDir','out')

rect = [0.18,  -0.20, 0.7, 0.75];
rect1 = rect;

% set values gretaer tresh = nan
%
re4 = ret;
l = r > tresh;
re4(l) = zeros(1,length(find(l)))*nan;
axes('position',rect)
hold on
pco1 = pcolor(gx,gy,re4);

axis([ min(gx) max(gx) min(gy) max(gy)])
axis image
hold on
shading interp
h = hsv(64);
h = h(57:-1:1,:);
colormap(h)
%end
caxis([20 200])

xlabel('Distance in [km]','FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m)
ylabel('depth in [km]','FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m)

% plot overlay
%
% ploeqc = plot(newa(:,length(newa(1,:))),-newa(:,7),'.k')

pl = plot(maex,-maey,'xw')
set(pl,'MarkerSize',10,'LineWidth',2)

set(gca,'visible','on','FontSize',ZmapGlobal.Data.fontsz.m,'FontWeight','bold',...
    'FontWeight','bold','LineWidth',1.5,...
    'Box','on','TickDir','out')
h1 = gca;
hzma = gca;

% Create a colobar
%
h5 = colorbar('vert');
set(h5,'Pos',[0.80 0.10 0.02 0.15],...
    'FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m)

% Make the figure visible
%
set(gca,'visible','on','FontSize',ZmapGlobal.Data.fontsz.m,'FontWeight','bold',...
    'FontWeight','bold','LineWidth',1.5,...
    'Box','on','TickDir','out')

rect = [0.18,  0.40, 0.7, 0.75];
axes('position',rect)
hold on
ploeqc = plot(newa(:,length(newa(1,:))),-newa(:,7),'+r');
hold on
set(ploeqc,'Tag','eqc_plot','MarkerSize',8,'LineWidth',1)
hold on

axis([ min(gx) max(gx) min(gy) max(gy)])
axis image
hold on

ylabel('depth in [km]','FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m)

% plot overlay
%
if ~isempty(maix)
    pl = plot(maix,maiy,'*k')
    set(pl,'MarkerSize',12,'LineWidth',2)
end

%if ~isempty(maex)
pl = plot(maex,-maey,'kx')
set(pl,'MarkerSize',10,'LineWidth',2)
%end

set(gca,'visible','on','FontSize',ZmapGlobal.Data.fontsz.m,'FontWeight','bold',...
    'FontWeight','bold','LineWidth',1.5,...
    'Box','on','TickDir','out','Color',[1 1 0.6])

figure_w_normalized_uicontrolunits(bmapc);
watchoff(bmapc)
done


function b = triangulation_isequal(face,faced)

% triangulation_isequal - true if two triangulations are equals
%
%   b = triangulation_isequal(face,faced)
%
%   Copyright (c) 2008 Gabriel Peyre

I = setdiff(sort(face)',sort(faced)', 'rows');
b = isempty(I);


function varargout = cstructdecode(buf, varargin);

% CSTRUCTDECODE decodes a structure from a uint8 buffer
%
% See READ_NEURALYNX_NEV for an example

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

if ~isa(buf, 'uint8')
  error('incorrect type of input data, should be uint8');
end

nbytes = numel(buf);
nfield = length(varargin);

wordsize = zeros(1,nfield);
for i=1:nfield
  switch varargin{i}
  case 'uint8'
    wordsize(i) = 1;
  case 'int8'
    wordsize(i) = 1;
  case 'uint16'
    wordsize(i) = 2;
  case 'int16'
    wordsize(i) = 2;
  case 'uint32'
    wordsize(i) = 4;
  case 'int32'
    wordsize(i) = 4;
  case 'uint64'
    wordsize(i) = 8;
  case 'int64'
    wordsize(i) = 8;
  case {'float32' 'single'}
    varargin{i} = 'single';
    wordsize(i) = 4;
  case {'float64' 'double'}
    varargin{i} = 'double';
    wordsize(i) = 8;
  otherwise
    if strncmp(varargin{i}, 'char', 4)
      if length(varargin{i})>4
        % assume a string like 'char128' which means 128 characters
        wordsize(i) = str2num(varargin{i}(5:end));
        varargin{i} = 'char';
      else
        wordsize(i) = 1;
      end
    else
      error('incorrect type specification');
    end
  end
end

pklen = sum(wordsize);
pknum = nbytes/sum(wordsize);

buf = reshape(buf, pklen, pknum);

for i=1:nfield
  rowbeg = sum(wordsize(1:(i-1)))+1;
  rowend = sum(wordsize(1:(i-0)))+0;
  sel = buf(rowbeg:rowend,:);
  if strcmp(varargin{i}, 'char')
    varargout{i} = char(sel)';
  else
    varargout{i} = typecast(sel(:), varargin{i});
  end
end