%% DEBUG SIMULATION SETUP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

clear all; close all;

% ADD THE PROGRAM PATHS
addpath('environment');
addpath('objects');
addpath('toolboxes');
addpath('scenarios');

% CODE DEBUG COMMANDS %
% profile on
% profile viewer

fprintf('[SETUP]\tInitialising example script.\n');

%% INITIALISE ANY TOOLBOXES
% IntLab();   % Load Intlab
% OMAS_objectDiagnostics()

%% SIMULATION PARAMETERS
[~, userdir]   = system('echo %USERPROFILE%');  % Get desktop path
sim_outputPath = strcat(userdir,'\desktop\openmas-data');
sim_vebosity   = 1;
sim_warningDistance = 2;
sim_maxDuration = 15;
sim_timeStep    = 0.1;                        % Nominal (0.25s)
sim_idleTimeOut = 5*sim_timeStep;

sim_publishFigures = false;
% sim_publishFigures = true;
sim_figureSet = {'all'};
% sim_figureSet = {'events','plan','inputs','isometric','gif'};
% sim_figureSet = {'plan','inputs','isometric','gif'};
% sim_figureSet = {'isometric','gif'};

%% SCENARIO PARAMETERS
sim_agentNumber     = 5;
sim_agentRadius     = 0.5;
sim_agentOrbit      = 5;
sim_agentVelocity   = 2;
sim_adjacencyMatrix = double(~eye(sim_agentNumber));
sim_waypointOrbit   = 10;
sim_waypointRadius  = 0.1;
sim_offsetAngle     = pi/4;
sim_obstacleNumber  = 3;
sim_noiseSigma      = 0.2;
sim_plotScenario    = true;

%% INITIALISE AGENTS
fprintf('[SETUP]\tAssigning agent definitions:\n');
for index = 1:sim_agentNumber
% BASIC CLASSES
%     agentIndex{index} = objectDefinition('radius',sim_agentRadius);
%     agentIndex{index} = agent('radius',sim_agentRadius);
%     agentIndex{index} = agent_test('radius',sim_agentRadius);
%     agentIndex{index} = agent_2D();
%     agentIndex{index} = agent_2D_test('radius',sim_agentRadius);

    agentIndex{index} = agent_example('radius',sim_agentRadius);

% QUADCOPTER DYNAMICS
%     agentIndex{index} = quadcopter_legacy();
%     agentIndex{index} = quadcopter();
%     agentIndex{index} = quadcopter_formation('adjacencyMatrix',sim_adjacencyMatrix);

% ARdrone DYNAMICS
%     agentIndex{index} = ARdrone_prev();
%     agentIndex{index} = ARdrone('radius',sim_agentRadius);
%     agentIndex{index} = ARdrone_LQR();
%     agentIndex{index} = ARdrone_MPC();

%     agentIndex{index} = fixedWing();
%     agentIndex{index} = globalHawk();
%     agentIndex{index} = boeing737();
%     agentIndex{index} = A10();

%     agentIndex{index} = planetoid();
%     agentIndex{index} = earth();
%     agentIndex{index} = moon();
%     agentIndex{index} = ISS();

% FORMATION CONTROL
%     agentIndex{index} = agent_formation('adjacencyMatrix',sim_adjacencyMatrix);
%     agentIndex{index} = agent_formation_boids();
%     agentIndex{index} = agent_formation_VO();
%     agentIndex{index} = agent_formation_RVO();
%     agentIndex{index} = agent_formation_HRVO();
%     agentIndex{index} = agent_2D_formation_VO('adjacencyMatrix',sim_adjacencyMatrix);
%     agentIndex{index} = agent_2D_formation_RVO();
%     agentIndex{index} = agent_2D_formation_HRVO();
%     agentIndex{index} = agent_2D_formation_ORCA();

% VECTOR SHARING;
%     agentIndex{index} = agent_vectorSharing('radius',sim_agentRadius,'detectionRadius',25);
%     agentIndex{index} = agent_2D_vectorSharing('radius',sim_agentRadius);

% INTERVAL AVOIDANCE
%     agentIndex{index} = agent_interval();
%     agentIndex{index} = agent_IA('radius',sim_agentRadius);
%     agentIndex{index} = agent_2D_IA('radius',sim_agentRadius);

% VELOCITY OBSTACLE METHODS
%     agentIndex{index} = agent_VO('radius',sim_agentRadius);
%     agentIndex{index} = agent_RVO('radius',sim_agentRadius);
%     agentIndex{index} = agent_HRVO('radius',sim_agentRadius);
%     agentIndex{index} = agent_2D_VO('radius',sim_agentRadius);
%     agentIndex{index} = agent_2D_RVO('radius',sim_agentRadius);
%     agentIndex{index} = agent_2D_HRVO('radius',sim_agentRadius);
%     agentIndex{index} = agent_2D_ORCA('radius',sim_agentRadius);
%     agentIndex{index} = agent_2D_VO_withComplex('radius',sim_agentRadius);

% OBSTACLES
%     agentIndex{index} = obstacle();
%     agentIndex{index} = obstacle_cuboid();
%     agentIndex{index} = obstacle_spheroid();
end

for index = 1:sim_obstacleNumber
	% OBSTACLES
%     obstacleIndex{index} = obstacle();
%     obstacleIndex{index} = obstacle_cuboid();
%     obstacleIndex{index} = obstacle_spheroid();
end

%% PLACE AGENT OBJECTS IN PRE-DEFINED SCENARIO
% FORMATION CONTROL TESTS
% [ objectIndex ] = GetScenario_corridor('agents',agentIndex,'adjacencyMatrix',sim_adjacencyMatrix,'plot',sim_plotScenario);
% [ objectIndex ] = GetScenario_formation_split('agents',agentIndex,'agentSpacing',4,'adjacencyMatrix',sim_adjacencyMatrix,'plot',sim_plotScenario,'noiseFactor',sim_noiseSigma);
% [ objectIndex ] = GetScenario_formation_fourObstacles('agents',agentIndex,'obstacleRadius',2,'plot',sim_plotScenario);

% % OBSTACLE TESTS
% [ objectIndex ] = GetScenario_fourCuboidObstacles('agents',agentIndex,'plot',sim_plotScenario);
% [ objectIndex ] = GetScenario_obstacleTrack('agents',agentIndex,'obstacles',obstacleIndex,'plot',sim_plotScenario);

% % AGENT TESTS
% [ objectIndex ] = GetScenario_twoLines('agents',agentIndex,'agentVelocity',sim_agentVelocity,'padding',5,'agentSeparation',sim_agentOrbit,'waypointSeparation',sim_waypointOrbit,'agentVelocity',sim_agentVelocity,'plot',sim_plotScenario);
[ objectIndex ] = GetScenario_concentricRing('agents',agentIndex,'agentOrbit',sim_agentOrbit,'agentVelocity',sim_agentVelocity,'waypointOrbit',sim_waypointOrbit,'waypointRadius',sim_waypointRadius,'plot',sim_plotScenario,'noiseFactor',sim_noiseSigma);
% [ objectIndex ] = GetScenario_concentricRing('agents',agentIndex,'agentOrbit',sim_agentOrbit,'agentVelocity',sim_agentVelocity,'waypointOrbit',sim_waypointOrbit,'offsetAngle',pi/2,'plot',sim_plotScenario,'noiseFactor',sim_noiseSigma);
% [ objectIndex ] = GetScenario_concentricSphere('agents',agentIndex,'agentOrbit',sim_agentOrbit,'agentVelocity',sim_agentVelocity,'waypointOrbit',sim_waypointOrbit,'plot',sim_plotScenario);
% [ objectIndex ] = GetScenario_concentricAngle('agents',agentIndex,'agentOrbit',sim_agentOrbit,'agentVelocity',sim_agentVelocity,'waypointOrbit',sim_waypointOrbit,'angle',sim_offsetAngle,'plot',sim_plotScenario);

% RANDOM TESTS
% [ objectIndex ] = GetScenario_random('objects',agentIndex,'plot',sim_plotScenario);
% [ objectIndex ] = GetScenario_randomNormal('objects',agentIndex,'plot',sim_plotScenario);
% [ objectIndex ] = GetScenario_randomUniform('objects',agentIndex,'is3D',false,'plot',sim_plotScenario);

% WAYPOINT TESTS
% [ objectIndex ] = GetScenario_waypointCurve('agents',agentIndex,'agentVelocity',sim_agentVelocity,'plot',sim_plotScenario);
% [ objectIndex ] = GetScenario_waypoint_90Degrees('agents',agentIndex,'agentVelocity',sim_agentVelocity,'plot',sim_plotScenario);

% % RL TESTS
% [ objectIndex ] = GetScenario_earthOrbit('plot',sim_plotScenario);

%% %%%%%% INITIALISE THE SIMULATION WITH THE OBJECT INDEX %%%%%%%%%%%%%%%%%
[DATA,META] = OMAS_initialise('objects',objectIndex,...
                             'duration',sim_maxDuration,...
                                   'dt',sim_timeStep,...
                          'idleTimeOut',sim_idleTimeOut,...
                              'figures',sim_figureSet,...
                      'warningDistance',sim_warningDistance,...
                            'verbosity',sim_vebosity,...
                           'outputPath',sim_outputPath,...
                          'publishMode',sim_publishFigures);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clearvars -except DATA META
load(strcat(META.outputPath,'META.mat'));
load(strcat(META.outputPath,'EVENTS.mat'));
load(strcat(META.outputPath,'OBJECTS.mat'));

%% EXTRA GRAPHS (DEBUG)
% objectDATA = DATA.objectIndex{1,1}.DATA;
% figure()
% grid on;
% plot(META.TIME.timeVector,objectDATA.inputs)
% xlabel('time (s)');
% legend('Location','southeast');


function L = log_prob_node(CPD, self_ev, pev)
% LOG_PROB_NODE Compute prod_m log P(x(i,m)| x(pi_i,m), theta_i) for node i (root)
% L = log_prob_node(CPD, self_ev, pev)
%
% self_ev{m} is the evidence on this node in case m
% pev{i,m} is the evidence on the i'th parent in case m (ignored)
% We always return L = 0.

L = 0;


%	robot objects can be multiplied r1*r2 which is mechanically equivalent
%	to mounting robot r2 on the end of robot r1.
%

% Ryan Steindl based on Robotics Toolbox for MATLAB (v6 and v9)
%
% Copyright (C) 1993-2011, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com
function r2 = mtimes(r, l)
        %SerialLink.mtimes Join robots
        %
        % R = R1 * R2 is a robot object that is equivalent to mounting robot R2
        % on the end of robot R1.
            if isa(l, 'SerialLink')
                r2 = SerialLink(r);
				x = r2.links;
				for i = 1:length(x)
					new_links(i) = Link(x(i));
				end
				y = l.links;
				for i = 1:length(y)
					new_links(i + length(x)) = Link(y(i));
				end
				r2.links = new_links;
                r2.base = r.base;
                r2.n = length(r2.links);
            elseif isa(l, 'Link')
                r2 = SerialLink(r);
				x = r2.links;
				for i = 1:length(x)
					new_links(i) = Link(x(i));
				end
				for i = 1:length(l)
					new_links(i + length(x)) = Link(l(i));
				end

                r2.links = new_links;
                r2.n = length(r2.links);
            end
        end


basefolder=fileparts( mfilename( 'fullpath' ) );
elapsedtime=zeros(1,5);

%Training setup
setup.scaling=3; % MAGI-ADAPT
setup.nclusters=2048; %default configuration nclusters=2048
setup.overlap=setup.scaling;%min=1 (sliding window), max=psize (no overlap)
setup.psize=3*setup.scaling;
setup.model='ibp';%can be replaced by 'bicubic', etc.
setup.ntrees=16; %for training
setup.nscales=16; %for training
setup.force_trees=true; %force training - trees
setup.force_regs=true; %force training - regressors
setup.nsamples=1500; %per leaf, to compute regressors
setup.trainingfolder=[ basefolder '/data/training' ];
setup.trainingext='*.bmp';
time=tic;

for i = 1:5
setup=nbsrf_training( setup );
elapsedtime(i,1)=toc(time);

end

average=sum(elapsedtime)/5;


%--------------------------------------------------------------------------------------------------------
% The system is created based on the principles described in the following paper
% Jimmy SJ. Ren and Li Xu, "On Vectorization of Deep Convolutional Neural Networks for Vision Tasks",
% The 29th AAAI Conference on Artificial Intelligence (AAAI-15). Austin, Texas, USA, January 25-30, 2015
% email: jimmy.sj.ren@gmail.com
%--------------------------------------------------------------------------------------------------------
addpath applications/
addpath utils/
addpath cuda/
addpath mem/
addpath layers/
addpath layers_adapters/
addpath pipeline/
addpath data/MNIST/

clearvars -global config;
clearvars -global mem;

global config;
denoise_configure();
init(0);

% for gradient checking
img = im2double(imread('sample1.png'));
startpt = 150;
image = config.NEW_MEM((img(startpt:startpt+config.input_size(1)-1, startpt:startpt+config.input_size(2)-1, :)));
label = config.NEW_MEM((image(1:config.output_size(1), 1:config.output_size(2), :)));

image = repmat(image, 1,1,1,config.batch_size);
label = repmat(label, 1,1,1,config.batch_size);

% gradient checking
op_train_pipe(image, label);
computeNumericalGradient(image, label, 1);

% speed test
loop = 100;
tic
for m = 1:loop
    op_train_pipe(image, label);
end
elapse = toc/loop/config.batch_size;
num = 1 / elapse;
fprintf('Process %f samples per second.\n', num);


function params = getParamsKatie()

params = struct;
params.scale = 6;
params.npatchesx = 8;
params.npatchesy = 6;
params.psize = 20; % patch size for hog/hof
params.nbins = 8; % number of bins in hog/hof
params.wd = 0.5; % width of hog features for visualization

params.optflowwinsig = 3;
params.optflowsig = 2;
params.optreliability = 1e-4;

params.blocksize = 500; % block size for parallel features computation.

params.flow_thres = 1;
params.deepscale = 4;
params.deep_thres = 3.5;
params.deepmatching_step = 8;
params.warping_iters = 2;

params.presmoothing = true;
params.smoothing_sigma = 1;

% params.methods = {'deep-sup','hs-sup'};
% params.flownames = {'DS','hs_sup'};


function outputImage = zoom(this, zoom_factor)
% Geometric shear of MrImage
%
%   Y = MrImage()
%   Y.zoom(inputs)
%
% This is a method of class MrImage.
%
% NOTE: This is a method of MrImage rather than MrImageGeometry, because
%       the latter is composed on the fly from affineTransformation and
%       dimInfo to integrate both information and sustain consistency.
%       Thus, the effect will only be visible using the world space plot
%       options, i.e. Y.plot('plotType', 'spmi').
% NOTE: The rotation is *added* to the rotation already defined in the
%       affine transformation matrix, equivalent to the rotation in SPM
%       Display.
% IN
%   zoom_factor            [1,3] zoom factor, i.e., [zx, zy, zz]
%
% OUT
%
% EXAMPLE
%   zoom
%
%   See also MrImage

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

outputImage = this.copyobj();

[outputImage.dimInfo, outputImage.affineTransformation] = ...
    this.geometry.perform_world_space_operation('zoom', zoom_factor, this.dimInfo);
end


function [c, alld] = getVertexColors(xyz, v, actcolor, varargin)
% :Usage:
% ::
%
%    [c, alld] = getVertexColors(xyz, v, actcolor, [basecolor], [mind], 'vert', [xyz2], [actcolor2], 'vert', [xyz3], [actcolor3])
%
% given a point list of XYZ mm coordinates (3 columns)
% and a list of vertices in an isosurface,
% returns FaceVertexCData color values for brain near points and brain not near points.
% c is vertex color specification, 3 columns indicating RGB values
%
% :Inputs:
%
%   **xyz:**
%        a 3-vol list of vertices to color
%
%   **v:**
%        can be a matrix of vertices
%        or a handle to a patch object containing vertices
%        if it's a handle, this function sets the color to interp
%        and the FaceVertexCData to the color matrix c
%
%   **actcolor:**
%        [r g b] activation color
%
%   **basecolor:**
%        [r g b] baseline color - optional.
%
%   **mind:**
%        optional - min distance to color vertex
%        Vertices within mind of an xyz coordinate will be colored
%
%   **colorscale
%       optional.  followed by vector of values by which to multiply input
%       color
%       these are scaled to be between .3 and one.
%
%       if entered, this will make the colors vary by, for example, Z score
%       so Z-scores are an acceptable input.
%
%       cscale should be in the same coordinate order as xyz
%
%       for ADDITIONAL clusters, repeat the 'colorscale', Z argument pair in the function call
%
%       YOU CAN ALSO pass true RGB values for each xyz coordinate in: 'colorscale', rgblist,
%       IF cscale is a 3-vector, it specifies the ACTUAL colors, and is not scaled to .3 - 1
%
%   Following basecolor and mind:
%
%   additional xyz coordinate lists, with syntax:
%   vert', xyz2 [your xyz input], [r g b] color for xyz plot
%
%   also, you can enter 'ovlcolor' followed by [r g b] for overlaps between xyz sets
%   colors will ONLY appear in the overlap color if they share actual coordinates in common,
%   not necessarily if surface vertices are within the specified distance from both sets of coords.
%
% :Examples:
% ::
%
%    % to get a good brain surface, try this:
%    figure
%    p = patch('Faces', faces, 'Vertices', vertices, 'FaceColor', [.5 .5 .5], ...
%            å  'EdgeColor', 'none', 'SpecularStrength', .2, 'FaceAlpha', 1, 'SpecularExponent', 200);
%    lighting gouraud;
%    camlight right
%    axis image;
%    myLight = camlight(0, 0);
%    set(myLight, 'Tag', 'myLight');
%    set(gcf, 'WindowButtonUpFcn', 'lightFollowView');
%    lightfollowview
%    drawnow
%
% ..
% by Tor Wager  August 25, 2002
% ..

    global do_fsavg_right do_fsavg_left ras

    mind = 3;
    basecolor = [.5 .5 .5];
    alld = [];
    xyza = xyz;
    cscale = [];
    allda = [];
    vv = [];
    doalph = 0;
    cscale = [];
    alphascale = {};
    do_fsavg_left = false;
    do_fsavg_right = false;
    doverbose = true;

    % -----------------------------------------------------------------------
    % * set up input arguments
    % -----------------------------------------------------------------------

    if ~isempty(varargin), basecolor = varargin{1}; end

    if length(varargin) > 1, mind = varargin{2}; end

    ind = 1;
    for i = 3:length(varargin)
        if strcmp(varargin{i}, 'vert')
            vv{ind} = varargin{i+1};

            % intersections
            xyzb{ind, 1} = intersect(xyz, vv{ind}, 'rows');
            for j = ind-1:-1:1
                xyzb{ind, j} = intersect(vv{j}, vv{ind}, 'rows');
                xyza = intersect(xyza, xyzb{ind, j}, 'rows');
            end

            cc{ind} = varargin{i+2};
            ind = ind+1;
        elseif strcmp(varargin{i}, 'ovlcolor')
            ocol = varargin{i+1};

        elseif strcmp(varargin{i}, 'alphascale')
            doalph = 1;
            alphascale{1} = varargin{i + 1};

        elseif strcmp(varargin{i}, 'allcolor')
            acol = varargin{i+1};

        elseif strcmp(varargin{i}, 'colorscale')

            cscale{end+1} = varargin{i+1};

            % now do this ahead of time
            %             if min(size(cscale{end})) == 1
            %                 % scale colors (may be necessary) - only if single vector, not RGB values
            %                 cscale{end} = cscale{end} ./ max(cscale{end});
            %             end
            if any(cscale{end} < 0), error('Some color scale values are less than zero.'), end
        elseif strcmp(varargin{i}, 'fsavg_left')
            ras = load(which('lh.avgMapping_allSub_RF_ANTs_MNI152_orig_to_fsaverage.mat'));
            do_fsavg_left = true;
        elseif strcmp(varargin{i}, 'fsavg_right')
            % uses freesurfer inflated brain with Thomas Yeo group's RF_ANTs mapping
            % from MNI to Freesurfer. (https://doi.org/10.1002/hbm.24213)
            ras = load(which('rh.avgMapping_allSub_RF_ANTs_MNI152_orig_to_fsaverage.mat'));
            do_fsavg_right = true;

        elseif strcmp(varargin{i}, 'noverbose')
            doverbose = false;

        end
    end

    if isempty(cscale)
        cscale{1} = ones(size(xyz, 1), 1);
        for i = 1:length(vv)    % additional vertices
            cscale{end+1} = ones(size(vv{i}, 1), 1);
        end
    end

    %if ~isempty(cscale) don't need this.
    %    if length(cscale) < length(vv)
    %        cscale{length(vv)} = [];
    %    end
    %end

    if ishandle(v)
        p = v;
        v = get(p, 'Vertices');
        c = get(p, 'FaceVertexCData');   % get existing colors from surface
    else
        % uh-oh, not a handle!
        warning('Figure handle missing: Figure was closed?')
        p = findobj('Type', 'patch');
        v = get(p(1), 'Vertices');
        c = get(p, 'FaceVertexCData');   % get existing colors from surface
    end

    % if FaceVertexCData is v x 1 matrix, it is mapped to the figure colormap
    % if it is v x 3, it is true color.
    % We can replace the colormapped FaceVertexCData with its true-color
    % equivalent, making it colormap independent.
    % This will allow us to use the existing values and average in new colors
    % for blobs
    if  ishandle(p) && size(v,1) == size(c, 1) && size(c, 2) == 1
        cm = get(gcf, 'Colormap');
        c2 = round((c./max(c)) .* length(cm));
        c2(c2==0)=1;
        c2 = cm(c2, :);
        c = c2;  % this is the true-color equivalent
        clear cm c2
        set(p, 'FaceVertexCData', c);
    end

    bad = any(size(c) - size(v)); % this could occur for various reasons?

    if bad
        c = repmat(basecolor, size(v, 1), 1);
    end

% c = true-color vertices x 3
% v = xyz coords of vertices x 3
% cscale: mapped true colors or index for  xyz, cell with cscale{1} = xyz coords to color x 3 or x 1

    % -----------------------------------------------------------------------
    % * main xyz color change
    % -----------------------------------------------------------------------

    t1 = clock;
    if doverbose, fprintf('Main color vertices: '), end

    c = change_colors(c, xyz, v, mind, cscale, actcolor, p, alphascale, doverbose);
    drawnow();

    % -----------------------------------------------------------------------
    % * additional optional vertices
    % -----------------------------------------------------------------------
    if exist('vv', 'var')
        for j = 1:length(vv)
            if doverbose, fprintf('\nAdditional vertices: '), end

            % cscale:
            % pass in vector of ones length coords for solid color
            % or scalar vals for color mapping
            % pass in cell array

            % cc{j} is color, cscale{j+1} is scaling vals for coords
            c = change_colors(c, vv{j}, v, mind, cscale(j+1), cc{j}, p, alphascale, doverbose);
        end
        drawnow();
    end

    % -----------------------------------------------------------------------
    % * figure out which vertices should be colored with ocol (overlap color)
    % -----------------------------------------------------------------------

    if exist('ocol', 'var') && exist('xyzb', 'var') && ~isempty(cat(1, xyzb{:}))

        alld = zeros(size(v, 1), 1);  % keeps track of overlap vertices
        xyzb = cat(1, xyzb{:});

        t1 = clock;
        if doverbose, fprintf('\nOverlap vertices: '), end

        cscaletmp = {ones(size(xyzb, 1), 1)};
        c = change_colors(c, xyzb, v, mind, cscaletmp, ocol, p, alphascale, doverbose);
        drawnow();

        if doverbose,  fprintf('%3.0f.done in %3.0f s\n', i, etime(clock, t1)), end
    end

    % -----------------------------------------------------------------------
    % * figure out which vertices should be colored with acol (all color)
    % -----------------------------------------------------------------------
    if exist('acol', 'var') && ~isempty(xyza) && length(vv)>1

        xyzall = xyza;
        for i = 2:length(vv)
            xyzall = intersect(xyzall, vv{i}, 'rows');
        end

        t1 = clock;
        if doverbose, fprintf('\nAll overlap vertices: '), end

        cscaletmp = {ones(size(xyzall, 1), 1)};
        c = change_colors(c, xyzall, v, mind, cscaletmp, acol, p, alphascale, doverbose);
        drawnow();

        if doverbose, fprintf('%3.0f.done in %3.0f s\n', i, etime(clock, t1)), end

    end

    % -----------------------------------------------------------------------
    % * final color change
    % -----------------------------------------------------------------------

    if exist('p', 'var')
        set(p, 'FaceColor', 'interp')
        set(p, 'FaceVertexCData', c)
        drawnow()
    end

    %lightFollowView
end

% -----------------------------------------------------------------------
% * SUB-FUNCTIONS
% -----------------------------------------------------------------------

function c = change_colors(c, coords, v, mind, cscale, actcolor, p, alphascale, doverbose)

% c is list of colors. by default, usually [.5 .5 .5] for all colors
% (basecolor)
    global do_fsavg_left do_fsavg_right ras

    if isempty(coords), if doverbose, disp('Coords is empty. Nothing to plot.'), end, return, end

    % select surface vertices that are close to coords
    % vertices that are far will be omitted
    % smallv is a reduced set of vertices
    % --------------------------------------------------------------------
    cmax = max(coords, [], 1);
    cmin = min(coords, [], 1);
    if doverbose, fprintf('%3.0f vertices.  selecting: ', size(v, 1)); end

    wh = any(v - repmat(cmax, size(v, 1), 1) > mind, 2);
    wh2 = any(repmat(cmin, size(v, 1), 1) - v > mind, 2);

    % list vertices to test and possibly change color
    whverts = (1:size(v, 1))';
    whverts(wh | wh2) = [];     % indices of smallv in big (original) list
    if do_fsavg_left || do_fsavg_right
        smallv = ras.ras';
    else
        smallv = v;
    end
    smallv(wh | wh2,:) = [];     % vertices--restricted list

    if doverbose, fprintf('%3.0f\n', size(whverts, 1)); end

    if isempty(smallv), return, end

    % select coords that are close to surface vertices5
    % coords, cscale{1}, and alphascale{1} all have same indices
    % ---------------------------------------------------------------------
    cmax = max(smallv, [], 1);
    cmin = min(smallv, [], 1);
    if doverbose, fprintf('%3.0f coords.  selecting: ', size(coords, 1)); end

    % omit wh and wh2 - outside scope of this coord set
    wh = any(coords - repmat(cmax, size(coords, 1), 1) > mind, 2);
    wh2 = any(repmat(cmin, size(coords, 1), 1) - coords > mind, 2);

    % if cscale is matrix, must select these values of cscale as well!
    if length(cscale) > 0 && size(cscale{1}, 1) == size(coords, 1)
        cscale{1}(wh | wh2,:) = [];
    end

    if length(alphascale) > 0 && size(alphascale{1}, 1) == size(coords, 1)
        alphascale{1}(wh | wh2,:) = [];
    end

    coords(wh | wh2,:) = [];

    if isempty(coords), return, end

    nc = size(coords, 1);
    if doverbose, fprintf('%3.0f\n', nc); end

    % break up coords into list and run
    % ----------------------------------

    % break up coords into list
    xyz2 = {}; indx = 1;
    for kk = 1:1000:nc
        setwh{indx} = (kk:min(nc, kk + 1000 - 1))';
        xyz2{indx} = coords(setwh{indx},:);

        indx = indx + 1;
    end

    if doverbose, fprintf('Running %3.0f sets of coordinates: 000', length(xyz2)); end

    indxval = 1;
    wh_coords_near_surface = false(size(coords, 1), 1);

    for setno = 1:length(xyz2)
        if doverbose, fprintf('\b\b\b%03d', setno); end

        for i = 1:size(xyz2{setno}, 1)
            % i indexes coordinate; e.g., 1000 iterations for a typical
            % coord set
            % find vertices that are within range of point i in set  setno
            % vertex_indices are indices into the ORIGINAL list
            vertex_indices = find_in_radius(xyz2, setno, i, smallv, mind, whverts);

            % two modes:
            % - if cscale{1} is a matrix, treats as rgb values, and put in
            % color stored in cscale.  actcolor is ignored.
            % - if cscale{1} is a vector, treat it as a scaling value for actcolor
            % In either case, indxval should index location of coordinate in FULL
            % list (corresponding to full list in cscale)

            % cscale{1}(i) and alphascale{1}(i) contain unique values for each coord i
            % these are used to map colors for single point i to multiple
            % nearby vertices vertex_indices

            if length(cscale) > 0 && ~isempty(cscale{1})
                mycscale = cscale{1}(setwh{setno}(i), :);  % color for this point, index into full list of coords/scalevals
            else
                mycscale = [];
            end

            if length(alphascale) > 0 && ~isempty(alphascale{1})
                myalphascale = alphascale{1}(setwh{setno}(i), :);  % alpha for this point, index into full list of coords/scalevals

                % adjust by cube of mind, to adjust for overlap in vertices
                % affected by adjacent coords - done now in cluster_surf
                %myalphascale = myalphascale ./ mind^3;

            else
                myalphascale = [];
            end

            c = color_change_vertices(c, mycscale, actcolor, vertex_indices, myalphascale);

            if ~isempty(vertex_indices), wh_coords_near_surface(indxval) = 1; end

            indxval = indxval + 1;
        end
    end % setno

    if exist('p', 'var')
        set(p, 'FaceColor', 'interp')
        set(p, 'FaceVertexCData', c)
        drawnow
    end

end % change_colors

function z = dist_tmp(w, p)

    %
    % if isstr(w)
    %   switch (w)
    %     case 'deriv',
    %       z = '';
    %     otherwise
    %       error('Unrecognized code.')
    %   end
    %   return
    % end

    % CALCULATION
    if nargin == 1
        p = w;
        w = w';
    end

    [S, R] = size(w);
    [R2, Q] = size(p);
    if (R ~= R2), error('Inner matrix dimensions do not match.'), end

    z = zeros(S, Q);
    if (Q<S)
        p = p';
        copies = zeros(1, S);
        for q=1:Q
            z(:,q) = sum((w-p(q+copies,:)).^2, 2);
        end
    else
        w = w';
        copies = zeros(1, Q);
        for i=1:S
            z(i,:) = sum((w(:,i+copies)-p).^2, 1);
        end
    end
    z = sqrt(z);

end

function [vertex_indices, d] = find_in_radius(xyz2, setno, i, smallv, mind, whverts)
    % output: indices of vertices in BIG list, and distances

    % get vertices v within box -- fast method
    wh = find(all(abs(bsxfun(@minus, xyz2{setno}(i,:), smallv)) <= mind, 2));
    d = dist_tmp(smallv(wh,:), xyz2{setno}(i,:)');

    % convert back to big list
    vertex_indices = whverts(wh(d < mind));
end

function c = color_change_vertices(c, mycscale, actcolor, vertex_indices, myalphascale)

% pass in/out larger list c, but update only a few coordinates
% indexed by vertex_indices with a particular color value.

% cscale is ordered from least color
% change to most for graphical/aesthetic purposes, so this function is
% called repetitively to index lower i (less change) to higher i (more
% change) successively.

% two modes: if cscale{1} is a matrix, treats as rgb values, and put in
% color stored in cscale
% if cscale{1} is a vector, treat it as a scaling value for actcolor
% In either case, the ith index point should correspond to the
% coordinate being worked on.

n = length(vertex_indices);

if n
    if length(mycscale) > 1
        % if we have rgb values rather than scaling values
        % this occurs if heatmap = yes and colorscale = no, we pass in rgb values
        % actcolor is ignored

        if isempty(myalphascale)
            % solid colors
            c(vertex_indices,:) = repmat(mycscale, n, 1);
        else
            w = myalphascale;  % the weight for new color vs. old.
            c(vertex_indices, :) = (1-w) .* c(vertex_indices, :) + w .* repmat(mycscale, n, 1);
        end

    else
        % this will scale the activation color in proportion to cscale
        % for each voxel

        w = mycscale;  % the weight for new color vs. old.  1 = all new, 0 = all old
        c(vertex_indices, :) = (1-w) .* c(vertex_indices, :) + w .* repmat(actcolor, n, 1);
    end
end

end


function imsegs2 = bndinfo2imsegs(bndinfo, imsegs1)

tmpseg.segimage = bndinfo.wseg;
if isfield(bndinfo, 'imname')
    tmpseg.imname = bndinfo.imname;
end

stats = regionprops(bndinfo.wseg, 'Area');
tmpseg.npixels = vertcat(stats.Area);
tmpseg.nseg = numel(tmpseg.npixels);
tmpseg.imsize = bndinfo.imsize(1:2);

if exist('imsegs1', 'var') && isfield(imsegs1, 'labels')
    imsegs2 = APPtransferLabels(imsegs1, tmpseg);
else
    imsegs2 = tmpseg;
end

imsegs2 = orderfields(imsegs2);


function cmp_feat_caches(dir1, dir2)
% For comparing new feat cache files to known good
% feat cache files after some change

s = dir([dir1 '/*.mat']);

for i = 1:length(s)
  [a,b,c] = fileparts(s(i).name);
  s1 = [dir1 '/' s(i).name];
  s2 = [dir2 '/' b '.mat'];
  if ~exist(s2)
    fprintf('Skipping %s\n', s(i).name);
    continue;
  end

  d1 = load(s1);
  d2 = load(s2);

  %  gt: [2448x1 logical]
  %  overlap: [2448x20 single]
  %  boxes: [2448x4 single]
  %  feat: [2448x9216 single]
  %  class: [2448x1 uint8]

  assert(sum(abs(d1.gt - d2.gt)) == 0);
  assert(sum(sum(abs(d1.overlap - d2.overlap))) == 0);
  assert(sum(sum(abs(d1.boxes - d2.boxes))) == 0);
  assert(sum(sum(abs(d1.feat - d2.feat))) == 0);
  assert(sum(abs(d1.class - d2.class)) == 0);

  fprintf('%d is ok\n', i);
end


function [infos, f_val, optgap, grad, gnorm, subgrad, subgnorm, smooth_grad, smooth_gnorm] = store_infos(problem, w, options, infos, epoch, grad_calc_count, elapsed_time)
% Function to store statistic information
%
% Inputs:
%       problem         function (cost/grad/hess)
%       w               solution
%       options         options
%       infos           struct to store statistic information
%       epoch           number of outer iteration
%       grad_calc_count number of calclations of gradients
%       elapsed_time    elapsed time from the begining
% Output:
%       infos           updated struct to store statistic information
%       f_val           cost function value
%       outgap          optimality gap
%       grad            gradient
%       gnorm           norm of gradient
%       subgrad         subgradient
%       subgnorm        norm of subgradient
%       smooth_grad     smoothed gradient
%       smooth_gnorm    norm of smoothed gradient
%
% This file is part of SGDLibrary.
%
% Created by H.Kasai on Sep. 25, 2017
% Modified by H.Kasai on Mar. 27, 2017
% Modified by H.Kasai on Oct. 30, 2020

    subgrad = [];
    subgnorm = [];

    if ~epoch

        infos.iter = epoch;
        infos.time = 0;
        infos.grad_calc_count = grad_calc_count;
        f_val = problem.cost(w);
        optgap = f_val - options.f_opt;
        % calculate norm of full gradient
        grad = problem.full_grad(w);
        gnorm = norm(grad);
        if ismethod(problem, 'full_subgrad')
            subgrad = problem.full_subgrad(w);
            subgnorm = norm(subgrad);
            infos.subgnorm = subgnorm;
        end

        if ismethod(problem, 'full_smooth_grad')
            smooth_grad = problem.full_smooth_grad(w);
            smooth_gnorm = norm(smooth_grad);
            infos.smooth_gnorm = smooth_gnorm;
        end

        infos.optgap = optgap;
        infos.best_optgap = optgap;
        infos.absoptgap = abs(optgap);
        infos.gnorm = gnorm;
        infos.cost = f_val;
        infos.best_cost = f_val;
        if ismethod(problem, 'reg')
            infos.reg = problem.reg(w);
        end
        if options.store_w
            infos.w = w;
        end
        if options.store_grad
            infos.grad = grad;
        end

    else

        infos.iter = [infos.iter epoch];
        infos.time = [infos.time elapsed_time];
        infos.grad_calc_count = [infos.grad_calc_count grad_calc_count];

        % calculate optimality gap
        f_val = problem.cost(w);
        optgap = f_val - options.f_opt;
        % calculate norm of full gradient
        grad = problem.full_grad(w);
        gnorm = norm(grad);
        if ismethod(problem, 'full_subgrad')
            subgrad = problem.full_subgrad(w);
            subgnorm = norm(subgrad);
            infos.subgnorm = [infos.subgnorm subgnorm];
        end

        if ismethod(problem, 'full_smooth_grad')
            smooth_grad = problem.full_smooth_grad(w);
            smooth_gnorm = norm(smooth_grad);
            infos.smooth_gnorm = [infos.smooth_gnorm smooth_gnorm];
        end

        infos.optgap = [infos.optgap optgap];
        infos.absoptgap = [infos.absoptgap abs(optgap)];
        if optgap < infos.best_optgap(end)
            infos.best_optgap = [infos.best_optgap optgap];
        else
            infos.best_optgap = [infos.best_optgap infos.best_optgap(end)];
        end
        infos.cost = [infos.cost f_val];
        if f_val < infos.best_cost(end)
            infos.best_cost = [infos.best_cost f_val];
        else
            infos.best_cost = [infos.best_cost infos.best_cost(end)];
        end
        infos.gnorm = [infos.gnorm gnorm];
        if ismethod(problem, 'reg')
            reg = problem.reg(w);
            infos.reg = [infos.reg reg];
        end
        if options.store_w
            infos.w = [infos.w w];
        end
        if options.store_grad
            infos.grad = [infos.grad grad];
        end

    end

end


function [kJ] = J2kJ(J)
% Convert energy or work from joules to joules.
% Chad A. Greene 2012
kJ = J*.001;


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Spherical Harmonic Modeling and Analysis Toolkit (SPHARM-MAT) is a 3D
% shape modeling and analysis toolkit.
% It is a software package developed at Shenlab in Center for Neuroimaging,
% Indiana University (SpharmMat@gmail.com, http://www.iupui.edu/~shenlab/)
% It is available to the scientific community as copyright freeware
% under the terms of the GNU General Public Licence.
%
% Copyright 2009, 2010, ShenLab, Center for Neuroimaging, Indiana University
%
% This file is part of SPHARM-MAT.
%
% SPHARM-MAT 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.
%
% SPHARM-MAT 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 SPHARM-MAT. If not, see <http://www.gnu.org/licenses/>.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Goal:
% Input:
%       inObjectName - File name of an input object
%       resampleFactor - Resampling factor to down- or up-sample a binary
%       object
%       saveBIM - Control flag to determine whether binary volumetric data should be
%       saved as a file for the later use. Its name will be the same as the
%       inObjectName with a different postfix('_bim.mat')
%
% Output:
%       bim - a 3D matrix of binary voxels.
%       mins - lowest coordinate values in x, y, and z axis (1 x 3)
%
% Created by Sungeun Kim (10-09-08)

function [bim, mins] = conv2bim(inObjectName, resampleFactor, saveBIM)

% Create place holders for output
bim = [];
mins = [];

if ~ischar(inObjectName)
    disp('inObjectName should a string of input filename or list of input filenames');
    return;
elseif ~exist(inObjectName, 'file')
    disp('Input object file does not exist');
    return;
end

% Parse input object filename
[path,name,ext] = fileparts(inObjectName);

if strcmp(lower(ext), '.txt')
    token = 'TRACE';
elseif strcmp(lower(ext), '.hdr') | strcmp(lower(ext), '.nii')
    token = 'NIfTI';
else
    disp('This file format can not be processed');
    return;
end

switch (token)
    case 'TRACE'
%        [bim, mins] = zroi2bim(inObjectName, resampleFactor);  %zroi2bim
%        is incomplete and need to be further modified (10-10-08)
    case 'NIfTI'
        [bim, mins] = NIfTI2bim(inObjectName, resampleFactor);
end

% Save binary volumetric object to a new file
if (saveBIM)
    new_name = [name '_bim'];
    save(fullfile(path, new_name), 'bim', 'mins');
end

return;


function [N,Mmax,catalog,IDAll,HistoryAll] = ETESProject3(cat,vEtas,vAfter,StartDateProj,EndDate,FaultParam)

    %This program is like ETESProject.m except that background earthquakes are
    %taken from an input grid, in the same manner as in TotalAftSim.8, instead
    %of smoothed directly from the catalog.  See the companion MakeRateGrid.m
    %program also in this directory.
    %
    %This program starts with A real earthquake catalog and then
    %projects what seismicity will follow further in time.  This is A Monte
    %Carlo modeler -- ideally it should be run multiple times to get average
    %results and error.  It also has A background component.  The background
    %component is set by BckgrndR -- this gives the number of earthquakes that
    %you want each year as
    %background earthquakes.  The background earthquakes will have an r^1.37
    %distribution in one dimension distribution away from hypocenters in the
    %input catalog which are identified as being background earthquakes
    %themselves (e.g. not within one fault length and 10 years of A bigger
    %earthquake).
    %
    %Earthquakes that are smaller than magb are treated as point sources;
    %earthquakes that are larger than magb are modeled as planes.  Where the
    %middle of the fault plane is not well constrained we use the median of the
    %first two days of the aftershock sequence.  For simplicity, large
    %simulated aftershocks are assigned the same focal mechanisms as their
    %mainshocks.  Where the mainshocks are too small for their focal mechanism
    %to be listed we use 75% 332 degree strike aqnd 25% 242 degree strike,
    %based on approximate assesement of trends in the Southern California
    %catalog, with A 90 degree dip.
    %
    %Written by Karen Felzer, 2007.
    %
    %Input:
    %
    % cat: Real eartquake catalog.  Ten column format: year, month, day, hour,
    % minute, second, lat, lon, depth, magnitude.
    %
    %RateGrid: Background rate, spatially varying.  minlon,maxlon, minlat,
    %maxlat, earthquake rate of M>=4.
    %
    %CX, P, A: Omori's law parameters, c, p, and A.  They should be entered
    %as direct triggering parameters, with A recommended p = 1.37.  The value
    %of A should be appropriate for the rate of A mainshock of magnitude M
    %triggering aftershocks of magnitude >=M.  For Mmin = 2.5, we recommend CX = 0.095, P = 1.34, and
    %A = 0.008. (from Felzer and Kilb, in preparation, 2007).
    %
    % Mmin: Minimum earthquake magnitude to report and simulate
    % MminR: Minimum earthquake magnitude for reporting in the output catalog
    % maxm: Maximum earthquake magnitude
    % DMax: Maximum distance for aftershocks
    % EndDate: Last date for the simulated catalog, to be entered as float
    %StartDate; First date for the projected catalog
    % (e.g. 1975.54  'January 1, 2007').  The simulated catalog will begin immediately
    % after the last date in the input catalog cat.
    %
    %magb: Cutoff magnitude for the point source vs. plane source
    %representation of the mainshock
    %
    %FaultParam: Fault parameters for the M>magb earthquakes, listed in order
    %of their occurrence in the catalog.  Columns give fault length, width,
    %strike, dip, year, month, day.
    %
    %
    %OUTPUT:
    %
    %N: total number of aftershocks in the simulated catalog.  Comparing N with
    %the total length of the catalog produced gives the percentage of the total
    %that is aftershocks.
    %
    %MMax: Maximum magnitude in the simulated catalog
    %
    %catalog: The simulated catalog
    %columns 1-10: years, month, day, hour, minute, second, lat, lon, depth,
    %magnitude.  Column 11: ID number for this earthquake.  Column12: If this
    %earthquake is an aftershock, column 12 gives the ID number of its
    %mainshock.  Column 13: If the earthquake is an aftershock, the distance
    %between its epicenter and the nearest point on the fault plane of the
    %mainshock that triggered it.
    %
    %IDAll: The ID numbers for each earthquake; same output as is listed in
    %Column 11 of the catalog
    %
    %HistoryAll: Mainshock of each earthquake; same output as is listed in
    %Column 13 of the catalog.

    %%%%Starting the program
    %set up
    CX=vEtas(1);
    P=vEtas(2);
    A=vEtas(3);

    Mmin=vAfter(1);
    MminR=vAfter(2);
    maxm=vAfter(3);
    DMax=vAfter(4);
    magb=vAfter(5);

    N = zeros(1,1);
    Mmax = zeros(1,1);
    tdistAll = [];

    [fYr1, nMn1, nDay1, nHr1, nMin1, nSec1]=decyear2mat(StartDateProj);
    StartDateProj=datenum(floor(fYr1),nMn1,nDay1,nHr1, nMin1,nSec1);
    [fYr2, nMn2, nDay2, nHr2, nMin2, nSec2]=decyear2mat(EndDate);
    EndDate=datenum(floor(fYr2),nMn2,nDay2,nHr2, nMin2,nSec2);

    T = EndDate - StartDateProj;  %Gives longest time that aftershocks may be generated over; for simplicity all aftershocks will
    %be generated over this time and then be trimmed as needed.

    T3 = EndDate;   %Gives the end time of the simulation

    T2 = StartDateProj;  %The starting date of the projected catalog

    %And limiting the big earthquakes in FaultParam to before the beginning of
    %the simulation

    % tp = datenum(FaultParam(:,5),FaultParam(:,6),FaultParam(:,7));
    % xp = find(tp>T2 | tp<datenum(StartDate));
    % changes vst
    FaultParam = [NaN NaN NaN NaN NaN NaN NaN];
    % FaultParam(xp,:) = [];

    %Finding the average number of aftershocks expected in time T for M - Maft
    %= 0.

    if(P ~= 0)
        NM = (A/(1-P))*((T+CX)^(1-P) - CX^(1-P));
    else
        NM = A*(log(T+CX) - log(CX));
    end

    %Setting up rotation matrices for later so that simulated M>magb mainshocks will have
    %either 332 degree strike or 242 degree strike.  Based on A quick eye
    %assessment of the So Cal fault map, 75% of mainshocks will be assigned the
    %332 strike and 25% the 242 strike.

    z1 = deg2rad(303);
    lambda1 = [cos(z1) sin(z1); -sin(z1) cos(z1)];

    z2 = deg2rad(213);
    lambda2 = [cos(z2) sin(z2); -sin(z2) cos(z2)];

    %And converting catalog times to Julian days

    tdist = datenum(cat(:,1),cat(:,2),cat(:,3),cat(:,4),cat(:,5),cat(:,6));

    m = cat(:,10);

    %eliminating catalog earthquakes that are past the start of the projection

    A=[];
    cat(A,:) = [];
    tdist(A) = [];
    m(A) = [];

    %And changing the lat, lon to xy
    catxy = cat;
    locCen(1) = mean(cat(:,7));
    locCen(2) = mean(cat(:,8));
    catxy(:,7:8) = latlon2xy2(catxy(:,7:8),locCen);
    Locs = [catxy(:,7) catxy(:,8) catxy(:,9)];
    NBack=size(Locs,1);

    %And initiating ID, history, and fault distance tracking matrices, and
    %putting magnitudes in A vector
    ID = [1:1:length(tdist)];
    History = zeros(size(ID));
    FaultDist = -1*ones(size(ID));

    aa2 = find(m>=MminR & tdist>=T2 & tdist<T3);  %we only report earthquakes in the final catalog for m>=MminR

    if(~isempty(aa2))
        tdistAll(1:length(aa2)) = tdist(aa2)';
        LocsAll(1:length(aa2),:) = Locs(aa2,:);
        mAll(1:length(aa2),:) = m(aa2);
        IDAll(1:+length(aa2),:) = ID(aa2)';
        HistoryAll(1:length(aa2),:) = 0;
        FaultDistAll(1:+length(aa2),:) = -1;
    end

    % And doing some final setting up for the ETAS run
    N = 0;
    Mmax = 0;
    ID = ID';
    History = History';
    FaultDist = FaultDist';

    %Now running the ETAS simulation***********%%%%%%%%%%%%

    %The loop gets all of the aftershocks of each earthquake occurring within
    %the specified duration of the catalog and over the minimum magnitude for
    %the simulation

    xm = find(m>=MminR);
    maxID = max(ID);

    countAll = length(tdistAll)+1;

    A = find(m>=Mmin & tdist<=T3);

    NIttr = 1;

    while(~isempty(A))

        IDold = ID(A);

        %Running the small point source and larger extended source earthquakes
        %separtely, through different versions of the aftershock program.
        %First, the small point source earthquakes

        a2 = find(m(A)<magb);

        a2 = A(a2);

        tdistSave = tdist;
        IDSave = ID;
        mSave = m;
        LocsSave = Locs;

        try
            [tdist,m,Locs,ID,History,FaultDist] = GAft3(tdist(a2),maxID,ID(a2),m(a2),Mmin,maxm,NM,T,Locs(a2,:),DMax,P,CX);
        catch
            disp('No point source events');
        end
        %And then doing the larger, plane source earthquakes

        a3 = find(mSave(A)>=magb);

        a3 = A(a3);

        if(~isempty(a3))

            if(NIttr>0)  %These are simulated large earthquakes which need FaultParam assigned.  Doing widths and lengths from Wells & Coppersmith

                FaultParam = BuildFaultParam(mSave(a3),LocsSave(a3,:),lambda1,lambda2);
            end

            %And getting the aftershocks for the big mainshocks

            try
                [tdist2,m2,Locs2,ID2,History2,FaultDist2] = GAft4(tdistSave(a3),maxID,IDSave(a3),mSave(a3),Mmin,maxm,NM,T,LocsSave(a3,:),DMax,FaultParam,P,CX);
            catch
                disp('No plane source events');
            end

        else
            tdist2 = [];
            m2 = [];
            Locs2 = [];
            ID2 = [];
            History2 = [];
            FaultDist2 = [];
        end

        %And putting the results from the two runs together

        tdist = [tdist; tdist2];

        m = [m; m2];
        Locs = [Locs; Locs2];
        ID = [ID ID2];
        History = [History'; History2];
        FaultDist = [FaultDist; FaultDist2];

        maxID = max([maxID max(ID)]);

        A = find(tdist>T2 & tdist<=T3);

        aa2 = find(m(A)>=MminR);  %we only report earthquakes in the final catalog for m>=MminR

        aa2 = A(aa2);

        if(~isempty(aa2))

            tdistAll(countAll:countAll+length(aa2)-1) = tdist(aa2)';

            LocsAll(countAll:countAll+length(aa2)-1,:) = Locs(aa2,:);

            mAll(countAll:countAll+length(aa2)-1,:) = m(aa2);

            IDAll(countAll:countAll+length(aa2)-1,:) = ID(aa2)';

            HistoryAll(countAll:countAll+length(aa2)-1,:) = History(aa2);

            FaultDistAll(countAll:countAll+length(aa2)-1,:) = FaultDist(aa2);

        end

        countAll = countAll+length(aa2);

        N = N + length(aa2);

        if(max(m(A))>Mmax)
            Mmax = max(m(A));
        end

        N;
        Mmax;

        NIttr = NIttr + 1;

    end

    %And translating the results into A traditional earthquake catalog

    % tdays = datenum(StartDate) + tdistAll;

    tvect = datevec(tdistAll);

    latlon = xy2latlon(LocsAll(:,1:2),locCen);

    catalog = [tvect latlon LocsAll(:,3) mAll IDAll HistoryAll FaultDistAll];

    catalog = sortrows(catalog,[1 2 3 4 5 6]);

    %cat = gquakes(catalog,StartDate,EndDate);

    %At this point solving for the background rate, RateGrid, if it was
    %initially input as zero.
end

    %--------------------------------------%%%

    %Getting aftershock times, locations, and mags for point source mainshocks

function [tdist,m,Locs,ID,History,FaultDist] = GAft3(tdist,maxID,IDold,m,Mmin,maxm,NM,T,Locs,DMax,P,CX)

    %First getting the number of aftershocks produced by each mainshock; stored
    %in the vector A.

    A = NM.*10.^(m - Mmin);

    try
        A = poissinv(rand(size(A,1),1),A);
    catch
        poisstest.NM=NM;
        poisstest.A=A;
        poisstest.m=m;
        save poisstest.mat poisstest -mat
        A = poissinv(rand(size(A,1),1),A);
    end

    counter = 1;

    x = find(A>0);

    tnew2 = [];

    %Making A vector with all of the mainshock times and locations

    if(~isempty(x))

        Axx = A(x);
        Axx = cumsum(Axx);
        Sp = [1; Axx(1:end-1)+1];
        Ep = Axx;
        tdist = tdist(x);
        Locs = Locs(x,:);
        xl = Locs(:,1);
        yl = Locs(:,2);
        zl = Locs(:,3);

        %The loop below is the time limiting factor for the whole calculation in
        %matlab

        AddOn = zeros(Axx(end),1);

        for j=1:length(x)

            AddOn(Sp(j):Ep(j)) = tdist(j);
            lx(Sp(j):Ep(j)) = xl(j);
            ly(Sp(j):Ep(j)) = yl(j);
            lz(Sp(j):Ep(j)) = zl(j);
            History(Sp(j):Ep(j)) = IDold(x(j));

        end

        AddDist = [lx' ly' lz'];

        %IN THIS VERSION: For each aftershock that will be produced, listing the
        %location of the mainshock that will produce it.

        %NOTE: COMMENTING THIS OUT RIGHT NOW TO SAVE TIME

        %for j = 1:length(tdist(x))

        %   idx = A(x(j));

        %   LocsT = [Locs(x(j),1)*ones(idx,1) Locs(x(j),2)*ones(idx,1) Locs(x(j),3)*ones(idx,1)];

        %  AddDist(counter:counter+A(x(j))-1,1:3) = LocsT;
        %  History(counter:counter+A(x(j))-1,1) = IDold(x(j));
        %  counter = counter + A(x(j));

        %end

        %Summing the total number of aftershocks

        AX = sum(A);

        %Now getting distances of all of the aftershocks from the faults
        %Allowing A closest approach of 1 m.

        dnew = GPowDistR(1.37,AX,0.001,DMax);

        FaultDist = dnew;

        %Converting the distances into x, y using A random theta.
        %Although not completely accutate, to save computation time
        %just keeping z the same as the generating point on the fault
        %so that we don't need to worry about staying within seismogenic
        %depth.  NOTE: there is code in the program for Joan that can be used
        %to fix this!  GET IT FIXED!!

        theta = rand(length(dnew),1).*2*pi;

        xnew = dnew.*cos(theta);
        ynew = dnew.*sin(theta);
        znew = zeros(length(ynew),1);

        LocsNew = AddDist + [xnew ynew znew];

    end

    %Now generating the aftershock times

    if(~isempty(x))

        %Then calculating times for all of the aftershocks, in terms of time since
        %the mainshock

        %tnew = GPowDistR(1.37,AX,0.0104,T);

        tnew = GPowDistRc(P,CX,AX,0,T);

        %And finally adding each aftershock time to the time of its mainshock to
        %get the absolute time of the aftershock in the catalog

        tnew2 = tnew + AddOn;

    end

    %And assigning the aftershock magnitudes

    if(~isempty(tnew2))

        m = GetMag(length(tnew2),Mmin,maxm);

        tdist = tnew2;
        Locs = LocsNew;

    else
        tdist = [];
        m = [];
        Locs = [];
        ID = [];
        History = [];
        FaultDist = [];
    end

    %And generating ID numbers for all of the aftershocks

    if(~isempty(x))

        ID = [maxID+1:1:maxID+AX+1];
    end
end
    %---------------------------------------

    %Getting aftershock times, locations, and mags for fault plane mainshocks

function [tdist,m,Locs,ID,History,FaultDist] = GAft4(tdist,maxID,IDold,m,Mmin,maxm,NM,T,Locs,DMax,FaultParam,P,CX)

    %First getting the number of aftershocks produced by each mainshock; stored
    %in the vector A.

    A = NM.*10.^(m - Mmin);

    A = poissinv(rand(length(A),1),A);

    counter = 1;

    x = find(A>0);

    tnew2 = [];

    %And setting up the fault plane

    %And for each aftershock that will be produced, picking A random reference
    %point on the mainshock fault that the distance of the aftershock from the
    %fault will be measured from.

    %IN THIS VERSION: For each aftershock that will be produced, listing the
    %location of the mainshock that will produce it.

    for j = 1:length(tdist(x))

        FaultY = FaultParam(j,4);
        FaultZ = FaultParam(j,5);

        YLow = FaultParam(j,2) - FaultY/2;
        ZLow = FaultParam(j,3) - FaultZ/2;

        %And getting points on the fault that will generate the earthquakes

        rpy = rand(A(x(j)),1).*FaultY;
        rpz = rand(A(x(j)),1)*FaultZ;
        rpx = zeros(size(rpy,1),1);

        rpy = rpy - FaultY/2;

        %Then rotating to the proper strike and dip

        %matrix for rotation around strike

        z1 = deg2rad(FaultParam(x(j),6));
        lambda1 = [cos(z1) sin(z1); -sin(z1) cos(z1)];

        z2 = deg2rad(FaultParam(x(j),7) - 90);  %rotation around dip

        if(FaultParam(x(j),6)>180)
            z2 = deg2rad(90-FaultParam(x(j),7));
        end

        lambda2 = [cos(z2) sin(z2); -sin(z2) cos(z2)];

        %And rotating.  Fist going to A 0 degree strike, and then to A 90 degree
        %dip.
        rot = lambda1*[rpx rpy]';

        rpx = rot(1,:)';
        rpy = rot(2,:)';

        rot = lambda2*[rpz rpy]';

        rpz = rot(1,:)';
        rpy = rot(2,:)';

        Lx = rpx + FaultParam(x(j),1);
        Ly = rpy + FaultParam(x(j),2);
        Lz = rpz + FaultParam(x(j),3);

        %And assigning the points on the fault from which aftershocks will be generated
        %And placing ID values in the history matrix

        AddDist(counter:counter+A(x(j))-1,1:3) = [Lx Ly Lz];
        History(counter:counter+A(x(j))-1,1) = IDold(x(j));
        counter = counter + A(x(j));

    end

    if(~isempty(x))

        %Summing the total number of aftershocks

        AX = sum(A);

        %Now getting distances of all of the aftershocks from the faults
        %Allowing A closest approach of 1 m.

        dnew = GPowDistR(1.37,AX,0.001,DMax);

        FaultDist = dnew;

        %Converting the distances into x, y using A random theta.
        %Although not completely accurate, to save computation time
        %just keeping z the same as the generating point on the fault
        %so that we don't need to worry about staying within seismogenic
        %depth.  NOTE: there is code in the program for Joan that can be used
        %to fix this!  GET IT FIXED!!

        theta = rand(length(dnew),1).*2*pi;

        xnew = dnew.*cos(theta);
        ynew = dnew.*sin(theta);
        znew = zeros(length(ynew),1);

        LocsNew = AddDist + [xnew ynew znew];

    end

    %Now generating the aftershock times

    %Making A vector with all of the mainshock times

    counter = 1;

    for j = 1:length(tdist(x))
        AddOn(counter:counter+A(x(j))-1) = tdist(x(j));
        counter = counter + A(x(j));
    end

    if(~isempty(x))

        %Then calculating times for all of the aftershocks, in terms of time since
        %the mainshock

        %tnew = GPowDistR(1.37,AX,0.0104,T);

        tnew = GPowDistRc(P,CX,AX,0,T);

        %And finally adding each aftershock time to the time of its mainshock to
        %get the absolute time of the aftershock in the catalog

        tnew2 = tnew + AddOn';

    end

    %And getting aftershock magnitudes

    if(~isempty(tnew2))

        m = GetMag(length(tnew2),Mmin,maxm);

        tdist = tnew2;
        Locs = LocsNew;

    else
        tdist = [];
        m = [];
        Locs = [];
        ID = [];
        History = [];
        FaultDist = [];
    end

    %And generating ID numbers for all of the aftershocks

    if(~isempty(x))

        ID = [maxID+1:1:maxID+AX+1];
    end
end

    %------------------------------------

    %Getting aftershock magnitudes

function m = GetMag(L,Mmin,maxm)

    m = Mmin - log10(rand(L,1));

    x = find(m>maxm);

    for i=1:length(x)

        while(m(x(i))>maxm)
            m(x(i)) = Mmin - log10(rand(1));

        end
    end
end


classdef TimeDepthPlotter < TimeSomethingPlotter
    % Used to create time-depth plots

    methods
        function obj=TimeDepthPlotter()
            obj@TimeSomethingPlotter('Depth','km');
        end

        function pl=plot(obj,ax,catalog,bigcat)
            % plot plot a time-depth series for this catalog, with symbol sizes representing
            % event size
            % pl = plot(catalog)
            %

            if ~exist('ax','var') || isempty(ax)
                f=figure('Name','Time Depth','NumberTitle','off', ...
                    'Tag',obj.Tags.Figure);
                addAboutMenuItem();
                ax=axes(f);
            end
            obj.ax=ax;

            if isempty(ax.Tag)
                ax.Tag=obj.Tags.Axes;
            end

            ax.Visible = 'off';

            if obj.hasLotsOfEvents(catalog)
                obj.Marker='.';
            else
                obj.Marker='s';
            end
            pl=obj.scatter(catalog);

            obj.prepare_axes(catalog,'YDir','reverse');

            f=ancestor(ax,'figure');
            c=findobj(f,'Tag','TimeDepthContext');
            if isempty(c)
                c=uicontextmenu('Tag','TimeDepthContext');
                uimenu(c,'Label','Use Log Scale','MenuSelectedFcn',@(s,~)logtoggle(s,'Y'));
            end
            ax.YLabel.UIContextMenu=c;

            if exist('bigcat','var')
                obj.overlayBigEvents(bigcat);
            end
            ax.Visible = 'on';

        end

    end
end


function dat = N_class_loss(algo,dat)

  x = dat.X;
  y = dat.X;
%   [1:length(x)]';

  lss = x-y;
  lss(lss ~= 0) = 1;
  lss = sum(lss)/length(x);

  dat=data([get_name(dat) ' -> N_class_loss=' num2str(lss,4) ],[],lss);


classdef shape2d < grain2d

  properties (Dependent=true)
    Vs      % list of vertices
    rho     % radius of polar coords
    theta   % angle of polar coords
  end

  % 1) should be constructed from calcTDF / circdensity (density function from a set of lines)
  % characteristicshape
  % surfor, paror
  % 2) purpose: take advantage of grain functions (long axis direction, aspect ratio..)
  %
  % additional functions I will try to put here: measure of asymmetry
  % nice plotting wrapper (replacing plotTDF)

  methods

    function shape = shape2d(V,CS)
      % list of vertices [x y]

      if nargin == 0, return;end

      N = size(V,1);
      shape.poly = {[1:N,1].'};
      shape.inclusionId = zeros(N,1);

      if nargin>=2
        shape.CSList = {CS};
      else
        shape.CSList = {'notIndexed'};
      end

      shape.phaseId = 1;
      shape.phaseMap = 1;
      shape.id = 1;
      shape.grainSize = 1;

      if isa(V,'grainBoundary') % grain boundary already given
        shape.boundary = V;
      else % otherwise compute grain boundary

        F = [1:N;[2:N 1]].';
        grainId = [zeros(N,1),ones(N,1)];

        shape.boundary = grainBoundary(V,F,grainId,1,...
          1,nan,shape.CSList,shape.phaseMap,1,'noTriplePoints');

      end

    end

    function Vs = get.Vs(shape)
      Vs = shape.boundary.V;
    end

    function theta = get.theta(shape)
      theta = atan2(shape.boundary.V(:,2),shape.boundary.V(:,1));
    end

    function rho = get.rho(shape)
      rho = sqrt(shape.boundary.V(:,2).^2 + shape.boundary.V(:,1).^2);
    end
  end

  methods (Static = true)
    shape = byRhoTheta(rho,theta)
    shape = byFV(F,V,varargin)
  end

end


function filt = filter_with_correction(B,A,dat,dir,usefftfilt)

% FILTER_WITH_CORRECTION applies the filter to the data and corrects
% edge-artifacts for one-pass filtering.
%
% Use as
%   [filt] = filter_with_correction(B,A,dat,dir);
% where
%   B,A        filter coefficients
%   dat        data matrix (Nchans X Ntime)
%   dir        optional filter direction, can be
%                'onepass'                   forward filter only
%                'onepass-reverse'           reverse filter only, i.e. backward in time
%                'twopass'                   zero-phase forward and reverse filter (default)
%                'twopass-reverse'           zero-phase reverse and forward filter
%                'twopass-average'           average of the twopass and the twopass-reverse
%                'onepass-zerophase'         zero-phase forward filter with delay compensation (default for firws, linear-phase symmetric FIR only)
%                'onepass-reverse-zerophase' zero-phase reverse filter with delay compensation
%                'onepass-minphase'          minimum-phase converted forward filter (non-linear!, firws only)
%
% Note that a one- or two-pass filter has consequences for the
% strength of the filter, i.e. a two-pass filter with the same filter
% order will attenuate the signal twice as strong.

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

% convert the data to double precision
% see  http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2653
inputclass = class(dat);
B = double(B);
A = double(A);
dat = double(dat);

poles = roots(A);
if any(abs(poles) >= 1)
  ft_error('Calculated filter coefficients have poles on or outside the unit circle and will not be stable. Try a higher cutoff frequency or a different type/order of filter.');
end

dcGain = sum(B)/sum(A);

[nchan,nsample] = size(dat);

switch dir
  case 'onepass'
    offset = dat(:,1);
    dat = dat - repmat(offset,1,nsample);
    filt = filter(B, A, dat')' + repmat(dcGain*offset, 1, nsample);
  case 'onepass-reverse'
    offset = dat(:,end);
    dat  = fliplr(dat) - repmat(offset,1,nsample);
    filt = filter(B, A, dat')';
    filt = fliplr(filt) + repmat(dcGain*offset, 1, nsample);
  case 'twopass'
    % filtfilt does the correction for us
    filt = filtfilt(B, A, dat')';
  case 'twopass-reverse'
    % filtfilt does the correction for us
    filt = fliplr(filtfilt(B, A, fliplr(dat)')');
  case 'twopass-average'
    % take the average from the twopass and the twopass-reverse
    filt1 = filtfilt(B, A, dat')';
    filt2 = fliplr(filtfilt(B, A, fliplr(dat)')');
    filt  = (filt1 + filt2)/2;
  case 'onepass-zerophase'
    filt = fir_filterdcpadded(B, A, dat', 0, usefftfilt)';
  case 'onepass-reverse-zerophase'
    filt = fliplr(fir_filterdcpadded(B, A, fliplr(dat)', 0, usefftfilt)');
  case 'onepass-minphase'
    filt = fir_filterdcpadded(B, A, dat', 1, usefftfilt)';
  otherwise
    ft_error('unsupported filter direction "%s"', dir);
end

% cast it back into the type of the input data, which can e.g. be single or int32
filt = cast(filt, inputclass);


function model = yalmip2gurobimex(interfacedata)
% Retrieve needed data
options = interfacedata.options;
F_struc = interfacedata.F_struc;
Q       = interfacedata.Q;
c       = interfacedata.c;
K       = interfacedata.K;
integer_variables = interfacedata.integer_variables;
binary_variables = interfacedata.binary_variables;
semicont_variables = interfacedata.semicont_variables;
ub      = interfacedata.ub;
lb      = interfacedata.lb;
x0      = interfacedata.x0;
interfacedata.gettime = 0;
n = length(c);

if ~isempty(ub)
    LB = lb;
    UB = ub;
    LB(binary_variables)  = round(LB(binary_variables));
    UB(binary_variables)  = round(UB(binary_variables));
    LB(integer_variables) = round(LB(integer_variables));
    UB(integer_variables) = round(UB(integer_variables));
else
    LB = [];
    UB = [];
end

if options.showprogress;showprogress('Calling GUROBI',options.showprogress);end

if ~isempty(semicont_variables)
    % Bounds must be placed in LB/UB
    [LB,UB,cand_rows_eq,cand_rows_lp] = findulb(F_struc,K,LB,UB);
    F_struc(K.f+cand_rows_lp,:)=[];
    F_struc(cand_rows_eq,:)=[];
    K.l = K.l-length(cand_rows_lp);
    K.f = K.f-length(cand_rows_eq);

    redundant = find(LB<=0 & UB>=0);
    semicont_variables = setdiff(semicont_variables,redundant);

end

SENSE = 1;     % Minimize
C = full(c);   % Must be full
if size(F_struc,1)>0
    B = full(F_struc(:,1));         % Must be full
    A =-F_struc(:,2:end);
else
    B = [];
    A = [];
end

% Optimized code, make a lot of difference when you make this call 10000
% times in a branch and bound setting...
CTYPE = [char(ones(K.f,1)*61); char(ones(K.l,1)*60)];
VARTYPE = char(ones(length(c),1)*67);
VARTYPE(setdiff(integer_variables,semicont_variables)) = 'I';
VARTYPE(binary_variables)  = 'B';  % Should not happen except from bmibnb
VARTYPE(setdiff(semicont_variables,integer_variables)) = 'S';  % Should not happen except from bmibnb
VARTYPE(intersect(semicont_variables,integer_variables)) = 'N';

% Gurobi assumes semi-continuous variables only can take negative values so
% we negate semi-continuous violating this
NegativeSemiVar = [];
if ~isempty(semicont_variables)
    NegativeSemiVar = find(UB(semicont_variables) < 0);
    if ~isempty(NegativeSemiVar)
        temp = UB(semicont_variables(NegativeSemiVar));
        UB(semicont_variables(NegativeSemiVar)) = -LB(semicont_variables(NegativeSemiVar));
        LB(semicont_variables(NegativeSemiVar)) = -temp;
        A(:,semicont_variables(NegativeSemiVar)) = -A(:,semicont_variables(NegativeSemiVar));
        C(semicont_variables(NegativeSemiVar)) = -C(semicont_variables(NegativeSemiVar));
        if ~isempty(x0)
            x0(NegativeSemiVar) = -NegativeSemiVar;
        end
    end
end

if nnz(Q)>0
    [ii,jj,kk] = find(Q);
    ii = ii-1;
    jj = jj-1;
    comp = computer;
    % According to Wotao's testing
    if isempty(strfind(comp,'64')) | isequal(comp,'GLNXA64') | isequal(comp,'PCWIN64')
        options.gurobi.QP.qrow = int32(ii)';
        options.gurobi.QP.qcol = int32(jj)';
    elseif strfind(comp,'MACI64')
        options.gurobi.QP.qrow = int32(ii)';
        options.gurobi.QP.qcol = int32(jj)';
    else
        options.gurobi.QP.qrow = int64(ii)';
        options.gurobi.QP.qcol = int64(jj)';
    end
    options.gurobi.QP.qval = kk';
end

if ~options.verbose
    options.gurobi.DisplayInterval = 0;
    options.gurobi.Display = 0;
end

if ~isempty(x0)
    options.gurobi.Start = x0(:)';
end

if options.savedebug
    save gurobidebug
end

if ~isempty(K.sos.type)
    options.gurobi.SOS.weights = spalloc(length(c),length(K.sos.type),0);
    for i = 1:length(K.sos.type)
        options.gurobi.SOS.types(i)= int32(str2num(K.sos.type(i)));
        options.gurobi.SOS.weights(K.sos.variables{i},i) = K.sos.weight{i};
    end
end
model.C = C;


function mtrFigureDOCCCorrelations(machineDir, saveDir)

subjVec = {'ss040804','mho040625','bg040719','md040714'};
threshVec = [1000];
paramNames = {'kLength','kSmooth','kMidSD'};
midP = [0 18 0.175];
bSaveImages = 1;

for pp = 1:3
    figure;
    for ss = 1:length(subjVec)
        subjDir = [machineDir subjVec{ss}];

        fgDir = [subjDir '/conTrack/resamp_LDOCC'];
        disp(['cd ' fgDir]);
        cd(fgDir);
        % Correlation between CTs
        if(pp==1)
            mtrPlotCorr('cc_-2',threshVec,paramNames,midP,pp,'b'); hold on;
        else
            mtrPlotCorr('cc',threshVec,paramNames,midP,pp,'b'); hold on;
        end
        % Correlation between CTs and STTs
        %mtrPlotCorr('cc_STT',threshVec,paramNames,midP,1,'g'); hold on;
        % Save out the figures to the image dir

        fgDir = [subjDir '/conTrack/resamp_RDOCC'];
        disp(['cd ' fgDir]);
        cd(fgDir);
        % Correlation between CTs
        if(pp==1)
            mtrPlotCorr('cc_-2',threshVec,paramNames,midP,pp,'b'); hold on;
        else
            mtrPlotCorr('cc',threshVec,paramNames,midP,pp,'b'); hold on;
        end
        oldaxis = axis;
        if pp == 1
            axis([-4 1 0 1]);
        else
            axis([oldaxis(1) oldaxis(2) 0 1]);
        end
        % Correlation between CTs and STTs
        %mtrPlotCorr('cc_STT',threshVec,paramNames,midP,1,'g');
    end
    % Save out the figures to the image dir
    set(gcf,'Position',[395   447   289   240]);
    if bSaveImages
        figFilename = fullfile(saveDir,['param_' paramNames{pp} '_corr.png']);
        set(gcf,'PaperPositionMode','auto');
        print('-dpng', figFilename);
    end
end


classdef SIBEA < ALGORITHM
% <multi> <real/integer/label/binary/permutation>
% Simple indicator-based evolutionary algorithm

%------------------------------- Reference --------------------------------
% E. Zitzler, D. Brockhoff, and L. Thiele, The hypervolume indicator
% revisited: On the design of Pareto-compliant indicators via weighted
% integration, Proceedings of the International Conference on Evolutionary
% Multi-Criterion Optimization, 2007, 862-876.
%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

% This function is written by Liangli Zhen

    methods
        function main(Algorithm,Problem)
            %% Generate random population
            Population = Problem.Initialization();

            %% Optimization
            while Algorithm.NotTerminated(Population)
                MatingPool = randi(length(Population),1,Problem.N);
                Offspring  = OperatorGA(Problem,Population(MatingPool));
                Population = EnvironmentalSelection([Population,Offspring],Problem.N);
            end
        end
    end
end


function TetraFile = fem_hexa2tetra(HexaFile)
% FEM_HEXA2TETRA: Converts hexahedral mesh to tetrahedral mesh
%
% USAGE: TetraFile = fem_hexa2tetra(HexaFile)

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Takfarinas Medani, Francois Tadel, 2020

% Load file
bst_progress('start', 'Convert FEM mesh', ['Loading file "' HexaFile '"...']);
HexaFile = file_fullpath(HexaFile);
FemMat = load(HexaFile);
% Already tetrahedral
if (size(FemMat.Elements,2) == 4)
    disp(['BST> Warning: Mesh is already tetrahedral: ' HexaFile])
    TetraFile = HexaFile;
    return;
end

% Convert to tetrahedral
bst_progress('text', 'Converting to tetrahedral...');
[tetraElem, tetraNode, tetraLabel] = hex2tet(FemMat.Elements, FemMat.Vertices, FemMat.Tissue, 4);
% Update output structure
FemMat.Vertices = tetraNode;
FemMat.Elements = tetraElem(:, [2 1 3 4]);
FemMat.Tissue = tetraLabel;
FemMat.Comment = sprintf('FEM %dV (hexa2tetra, %d layers)', length(FemMat.Vertices), length(FemMat.TissueLabels));
% Add history
FemMat = bst_history('add', FemMat, 'fem_hexa2tetra', 'Converted to tetrahedral');

% Output filename
[fPath, fBase, fExt] = bst_fileparts(HexaFile);
TetraFile = file_unique(bst_fullfile(fPath, [fBase, '_hexa', fExt]));
% Get subject
[sSubject, iSubject] = bst_get('SurfaceFile', HexaFile);
% Save new surface in Brainstorm format
bst_progress('text', 'Saving tetra mesh...');
bst_save(TetraFile, FemMat, 'v7');
db_add_surface(iSubject, TetraFile, FemMat.Comment);

% Close progress bar
bst_progress('stop');


%======================================================================
%SLIC demo
% Copyright (C) 2015 Ecole Polytechnique Federale de Lausanne
% File created by Radhakrishna Achanta
% Please also read the copyright notice in the file slicmex.c
%======================================================================
%Input parameters are:
%[1] 8 bit images (color or grayscale)
%[2] Number of required superpixels (optional, default is 200)
%[3] Compactness factor (optional, default is 10)
%
%Ouputs are:
%[1] labels (in raster scan order)
%[2] number of labels in the image (same as the number of returned
%superpixels
%
%NOTES:
%[1] number of returned superpixels may be different from the input
%number of superpixels.
%[2] you must compile the C file using mex slicmex.c before using the code
%below
%======================================================================
%img = imread('someimage.jpg');
% img = imread('bee.jpg');
% [labels, numlabels] = slicmex(img,500,20);%numlabels is the same as number of superpixels
img = imread('/srv/glusterfs/daid/data/cityscape/leftImg8bit/train/aachen/aachen_000001_000019_leftImg8bit.png');
[labels, numlabels] = slicmex(img,2000,10);%numlabels is the same as number of superpixels
imagesc(labels);


%% Copyright 2012 The MathWorks, Inc.
%% Face Tracking
% Open video file
videoFileReader = vision.VideoFileReader('MWface.avi');

% Read video frame
videoFrame = step(videoFileReader);

% Detect the face
faceDetector = vision.CascadeObjectDetector('MaxSize',[150 150]);
faceBBox     = step(faceDetector,videoFrame);

% Display results
figure; subplot(1,2,1);imshow(videoFrame); hold on;
rectangle('Position',faceBBox(1,:),'LineWidth',2,'EdgeColor',[1 1 0])
[hueChannel,~,~] = rgb2hsv(videoFrame);
subplot(1,2,2);imshow(hueChannel);hold on;
rectangle('Position',faceBBox(1,:),'LineWidth',2,'EdgeColor',[0 1 0])

%% Find a better object for tracking
% Detect the nose
noseDetector = vision.CascadeObjectDetector('Nose');
noseBBox     = step(noseDetector,videoFrame);

% Display results
figure; subplot(1,2,1);imshow(videoFrame); hold on;
rectangle('Position',noseBBox(1,:),'LineWidth',2,'EdgeColor',[1 1 0])
subplot(1,2,2); imshow(hueChannel); hold on;
rectangle('Position',noseBBox(1,:),'LineWidth',2,'EdgeColor',[0 1 0])

%% Set up tracking loop
% Create a tracker object.
tracker = vision.HistogramBasedTracker;

% Initialize the tracker histogram
initializeObject(tracker, hueChannel, noseBBox(1,:));
% figure;bar(tracker.ObjectHistogram);

%%
% Create a video player object for displaying video frames.
videoInfo    = info(videoFileReader);
videoPlayer  = vision.VideoPlayer('Position',[300 300 videoInfo.VideoSize+30]);
boxInserter  = vision.ShapeInserter('BorderColor','Custom',...
    'CustomBorderColor',[255 255 0]);

% Track the face over successive video frames until the video is finished.
while ~isDone(videoFileReader)
    videoFrame = step(videoFileReader);        % Extract the next video frame
    [hueChannel,~,~] = rgb2hsv(videoFrame);    % RGB -> HSV

    % Track using the Hue channel data
    [bbox, ~, score] = step(tracker, hueChannel);

    % Insert a bounding box around the object being tracked
    videoOut = step(boxInserter, videoFrame, bbox);
    % Display the annotated video frame using the video player object
    step(videoPlayer, videoOut);

end

%% Now try to reacquire the face when it reappears
release(tracker);
reset(videoPlayer);
initializeObject(tracker, hueChannel, noseBBox(1,:));

% Track the face over successive video frames until the video is finished.
reset(videoFileReader);
while ~isDone(videoFileReader)
    videoFrame = step(videoFileReader);        % Extract the next video frame
    [hueChannel,~,~] = rgb2hsv(videoFrame);    % RGB -> HSV

    % Track using the Hue channel data
    [bbox, ~, score] = step(tracker, hueChannel);

    % Determine if face is still in the scene using score value
    if score > 0.4
        videoOut = step(boxInserter, videoFrame, bbox);
    else
        videoOut = videoFrame;
        faceBBox = step(faceDetector,videoFrame);     % Find face again
        if ~isempty(faceBBox)
            release(noseDetector);
            noseBBox = step(noseDetector,imcrop(videoFrame,faceBBox(1,:)));
            noseBBox(1:2) = noseBBox(1:2) + faceBBox(1:2);
            release(tracker);
            initializeObject(tracker, hueChannel, noseBBox(1,:));
        end
    end
    % Display the annotated video frame using the video player object
    step(videoPlayer, videoOut);

end
% Release resources
release(videoFileReader);
release(videoPlayer);


function RDt(option, up)
%RDt detects QRS waves in ECG signals.
%	            RDt(option, up)
%
%	Inputs:
%		option          the option which has led to this function being used
%       up              universal parameters structure
%
%	Outputs:
%       ...
%

fprintf('\n--- Detecting QRS waves ');
log_int_respSig = 1;             % Has value 1 unless this is a final respiratory signal

for subj = up.paramSet.subj_list

    sig_type = option(1:3);
    %% Cycle through each signal of this type
    eval(['sigs = up.paramSet.' sig_type '_sigs;']);
    for sig_no = 1 : length(sigs)
        curr_sig = sigs{sig_no};

        %% Skip if this processing has been done previously
        iden_resp_sig_file_ending
        savepath = [up.paths.data_save_folder, num2str(subj), ending];
        filecontents = whos('-file', savepath);
        var_names = extractfield(filecontents, 'name');
        temp = ~cellfun(@isempty, strfind(var_names, [curr_sig, up.paths.filenames.elim_vhf]));
        rel_var_names = var_names(temp);
        for rel_var_name_no = 1 : length(rel_var_names)
            for current_opt_no = 1 : length(up.al.options.RDt)
                temp = strfind(rel_var_names{rel_var_name_no},'_');
                start_el = temp(1); clear temp
                eval(['save_name = ''' curr_sig, up.paths.filenames.qrss, up.al.options.RDt{current_opt_no}, rel_var_names{rel_var_name_no}(start_el:end) ''';']); clear start_el
                exist_log = check_exists(savepath, save_name);
                if exist_log
                    continue
                end

                %% Load relevant data
                loadpath = [up.paths.data_save_folder, num2str(subj), up.paths.filenames.int_respSigs];
                rel_name = rel_var_names{rel_var_name_no};
                load(loadpath, rel_name);
                eval(['s = ' rel_name ';']);
                eval(['fs = ' rel_name '.fs;']);
                s.v = s.v(:);

                %% Eliminate very low frequencies
                s_filt = elim_sub_cardiac(s, up);
                nan_els = isnan(s_filt.v);
                s_filt.t = s_filt.t(~nan_els);
                s_filt.v = s_filt.v(~nan_els);

                %% Detect QRS Waves
                pk_inds = feval(up.al.options.RDt{current_opt_no}, s_filt, fs, subj, up);

                %% Refine detected QRS spikes
                % The detected peaks are currently somewhere in the middle of the R-area, so need to search for the max ecg value within the tolerance either side of the detected peak:
                max_HR_for_qrs = 300;
                tolerance = round(fs/(max_HR_for_qrs/60));
                if ~isempty(pk_inds)
                    % refine the peaks and store in a new variable (ECG_PKS_inds)
                    ref_pk_inds = nan(length(pk_inds),1);
                    for peak_ind = 1 : length(pk_inds)                             % for each peak
                        % Find tolerance limits, centred on the current peak index:
                        if pk_inds(peak_ind) <= tolerance                          % if the peak is right at the start of the recording, set the lower tolerance limit to the start of the recording
                            lower_lim = 1;
                        else
                            lower_lim = pk_inds(peak_ind)-tolerance;
                        end
                        if (length(s.v)-pk_inds(peak_ind)) <= tolerance % if the peak is right at the end of the recording, set the upper tolerance limit to the end of the recording
                            upper_lim = length(s.v);
                        else
                            upper_lim = pk_inds(peak_ind)+tolerance;
                        end
                        % Find the maximum ecg value within the tolerance limits:
                        [~, max_ind] = max(s.v(lower_lim : upper_lim));
                        % Store the index of this maximum value, referenced to the section_data inds:
                        ref_pk_inds(peak_ind) = lower_lim-1+max_ind;
                        clear max_ind
                    end
                    clear peak_ind
                else
                    % if no peaks were detected then give empty results:
                    ref_pk_inds = [];
                end

                %% Eliminate any peaks which are the same
                ref_pk_inds = unique(ref_pk_inds);

                %% Find troughs
                % search 0.1s either side
                troughs.i = nan(length(ref_pk_inds)-1,1);
                search_min = ref_pk_inds - ceil(0.1*fs);
                search_min(search_min<1) = 1;
                search_max = ref_pk_inds + ceil(0.1*fs);
                search_max(search_max>length(s.v)) = 1;
                for peak_ind = 1 : (length(ref_pk_inds)-1)
                    [~, rel_el] = min(s.v(search_min(peak_ind):search_max(peak_ind)));
                    rel_el = search_min(peak_ind)-1+rel_el;
                    troughs.i(peak_ind) = rel_el;
                end

                %% Save processed data
                eval([save_name '.fs = fs;']);
                eval([save_name '.p.v = s.v(ref_pk_inds);']);
                eval([save_name '.p.t = s.t(ref_pk_inds);']);
                eval([save_name '.tr.v = s.v(troughs.i);']);
                eval([save_name '.tr.t = s.t(troughs.i);']);
                % Identify start and end times of raw data (for resampling)
                eval([save_name '.timings.t_start = s.t(1);']);
                eval([save_name '.timings.t_end = s.t(end);']);
                save_or_append_data

            end

        end

    end

end

end

function pk_inds = GC(s, fs, subj, up)

%% This uses Prof Gari Clifford's "rpeakdetect.m" script
% This script can be downloaded from:
%    http://www.mit.edu/~gari/CODE/ECGtools/ecgBag/rpeakdetect.m
%
% The following is an excerpt from the script:
%
% Written by G. Clifford gari@ieee.org and made available under the
% GNU general public license. If you have not received a copy of this
% license, please download a copy from http://www.gnu.org/
%
% Please distribute (and modify) freely, commenting
% where you have added modifications.
% The author would appreciate correspondence regarding
% corrections, modifications, improvements etc.

% download the script if it isn't in the search path
curr_dir = mfilename('fullpath'); curr_dir = curr_dir(1:end-3);
filepath = [curr_dir, 'rpeakdetect.m'];
if ~exist(filepath, 'file')
    url = 'http://www.mit.edu/~gari/CODE/ECGtools/ecgBag/rpeakdetect.m';
    downloadedfilename = websave(filepath,url);
end

[~, ~, ~, pk_inds, ~, ~]  = rpeakdetect(s.v(:),fs);

end


function [A,b,C,P] = update_spatial_components_old(Y,C,f,A_,P,options)

% update spatial footprints and background through Basis Pursuit Denoising
% for each pixel i solve the problem
%   [A(i,:),b(i)] = argmin sum(A(i,:))
%       subject to || Y(i,:) - A(i,:)*C + b(i)*f || <= sn(i)*sqrt(T);
% for each pixel the search is limited to a few spatial components

% INPUTS:
% Y:    raw data
% C:    temporal components
% f:    temporal background
% A_:   current estimate of spatial footprints (used for determining search locations only)
% P:    dataset parameters (used for noise values and interpolated entries)

% options    parameter struct (for noise values and other parameters)

% OUTPUTS:
% A:    new estimate of spatial footprints
% b:    new estimate of spatial background
% C:    temporal components (updated only when spatial components are completely removed)

% Written by:
% Eftychios A. Pnevmatikakis, Simons Foundation, 2015

warning('off', 'MATLAB:maxNumCompThreads:Deprecated');
memmaped = isobject(Y);
if memmaped
    sizY = size(Y,'Y');
    d = prod(sizY(1:end-1));
    T = sizY(end);
else
    [d,T] = size(Y);
end
if nargin < 6 || isempty(options); options = []; end
if ~isfield(options,'d1') || isempty(options.d1); d1 = input('What is the total number of rows? \n'); options.d1 = d1; else d1 = options.d1; end          % # of rows
if ~isfield(options,'d2') || isempty(options.d2); d2 = input('What is the total number of columns? \n'); options.d2 = d2; else d2 = options.d2; end          % # of columns
if ~isfield(options,'d3') || isempty(options.d3); d3 = input('What is the total number of z-planes? \n'); options.d3 = d3; else d3 = options.d3; end          % # of columns
if ~isfield(options,'show_sum'); show_sum = 0; else show_sum = options.show_sum; end            % do some plotting while calculating footprints
if ~isfield(options,'interp'); Y_interp = sparse(d,T); else Y_interp = options.interp; end      % identify missing data
if ~isfield(options,'spatial_parallel'); spatial_parallel = ~isempty(which('parpool')); else spatial_parallel = options.spatial_parallel; end % use parallel toolbox if present
if ~isfield(options,'search_method'); method = []; else method = options.search_method; end     % search method for determining footprint of spatial components
if ~isfield(options,'tsub') || isempty(options.tsub); tsub = 1; else tsub = options.tsub; end  % downsample temporally to estimate A and b

if nargin < 2 || (isempty(A_) && isempty(C))  % at least either spatial or temporal components should be provided
    error('Not enough input arguments')
else
    if ~isempty(C); K = size(C,1); elseif islogical(A_); K = size(A_,2); else K = size(A_2,2) - options.nb; end
end

if nargin < 5 || isempty(P); P = preprocess_data(Y,1); end  % etsimate noise values if not present
if nargin < 4 || isempty(A_);
    IND = ones(d,size(C,1));
else
    if islogical(A_)     % check if search locations have been provided, otherwise estimate them
        IND = A_;
        if isempty(C)
            INDav = double(IND)/diag(sum(double(IND)));
            px = (sum(IND,2)>0);
            f = mean(Y(~px,:));
            b = max(Y*f',0)/norm(f)^2;
            C = max(INDav'*Y - (INDav'*b)*f,0);
        end
    else
        IND = determine_search_location(A_(:,1:K),method,options);
    end
end

K = size(C,1);
if strcmpi(options.spatial_method,'constrained'); A_ = A_(:,1:K); end

Cf = [C;f];
if size(Cf,1) > size(A_,2) && strcmpi(options.spatial_method,'regularized');
    error('When using options.spatial_method = regularized pass [A,b] as an input and not just A');
end

if tsub ~= 1 %&& strcmpi(options.spatial_method,'constrained');
    P.sn_ds = zeros(d,1);
    Ts = floor(T/tsub);
    Cf = squeeze(mean(reshape(Cf(:,1:Ts*tsub),[],tsub,Ts),2));
    f = Cf(end-size(f,1)+1:end,:);
    T = Ts;
    if ~memmaped
        Y = squeeze(mean(reshape(Y(:,1:Ts*tsub),[],tsub,Ts),2));
        if ~isfield(P,'sn_ds');
            [P_ds,Y] = preprocess_data(Y);
            P.sn_ds = P_ds.sn;
        end
        options.sn = P.sn_ds;
    else
        Y_ds = zeros(d,Ts);
        step_size = 2e4;
        for i = 1:step_size:d
            Ytemp = double(Y.Yr(i:min(i+step_size-1,d),:));
            Y_ds(i:min(i+step_size-1,d),:) = squeeze(mean(reshape(Ytemp(:,1:Ts*tsub),[],tsub,Ts),2));
        end
        Y = Y_ds;
        options.sn = get_noise_fft(Y_ds);
    end
else
    options.sn = P.sn;
end

if strcmpi(options.spatial_method,'constrained');
    if spatial_parallel         % solve BPDN problem for each pixel
        Nthr = max(20*maxNumCompThreads,round(d*T/2^24));
        Nthr = min(Nthr,round(d/1e3));
        siz_row = [floor(d/Nthr)*ones(Nthr-mod(d,Nthr),1);(floor(d/Nthr)+1)*ones(mod(d,Nthr),1)];
        indeces = [0;cumsum(siz_row)];
        Yf = cell(Nthr,1);
        A = spalloc(d,size(Cf,1),nnz(IND)+size(f,1)*d);
        for nthr = 1:Nthr
            if memmaped
                Ytemp = double(Y.Yr(indeces(nthr)+1:indeces(nthr+1),:));
                if tsub ~= 1;
                    Ytemp = squeeze(mean(reshape(Ytemp(:,1:Ts*tsub),[],tsub,Ts),2));
                    if ~isfield(P,'sn_ds')
                        [P_ds,Ytemp] = preprocess_data(Ytemp);
                        P.sn_ds(indeces(nthr)+1:indeces(nthr+1)) = P_ds.sn;
                    end
                    sn_temp = P.sn_ds(indeces(nthr)+1:indeces(nthr+1));
                else
                    sn_temp = P.sn(indeces(nthr)+1:indeces(nthr+1));
                end
            else
                Ytemp = Y(indeces(nthr)+1:indeces(nthr+1),:);
                sn_temp = options.sn(indeces(nthr)+1:indeces(nthr+1));
            end
            IND_temp = IND(indeces(nthr)+1:indeces(nthr+1),:);
            Atemp = spalloc(siz_row(nthr),size(Cf,1),nnz(IND_temp));
            Yf{nthr} = Ytemp*f';

            parfor px = 1:siz_row(nthr)
                fn = ~isnan(Ytemp(px,:));       % identify missing data
                ind = find(IND_temp(px,:));
                if ~isempty(ind);
                    ind2 = [ind,K+(1:size(f,1))];
                    [~, ~, a, ~] = lars_regression_noise(Ytemp(px,fn)', Cf(ind2,fn)', 1, sn_temp(px)^2*T);
                    a_sparse = sparse(1,ind2,double(a'));
                    Atemp(px,:) = a_sparse';
                end
            end
            if mod(nthr,50) == 0
                fprintf('%2.1f%% of pixels completed \n', indeces(nthr+1)*100/d);
            end
            %Acell{nthr} = Atemp;
            A(indeces(nthr)+1:indeces(nthr+1),:) = Atemp;
        end
        %A = cell2mat(Acell);
        Yf = cell2mat(Yf);
    else
        A = [zeros(d,K),zeros(d,size(f,1))];
        sA = zeros(d1,d2,d3);
        Yf = Y*f';
        for px = 1:d   % estimate spatial components
            fn = ~isnan(Y(px,:));       % identify missing data
            ind = find(IND(px,:));
            if ~isempty(ind);
                ind2 = [ind,K+(1:size(f,1))];
                [~, ~, a, ~] = lars_regression_noise(Y(px,fn)', Cf(ind2,fn)', 1, options.sn(px)^2*T);
                A(px,ind2) = a';
                sA(px) = sum(a);
            end
            if show_sum
                if mod(px,d1) == 0;
                   figure(20); imagesc(max(sA,[],3)); axis square;
                   title(sprintf('Sum of spatial components (%i out of %i columns done)',round(px/d1),d2)); drawnow;
                end
            end
        end
    end
elseif strcmpi(options.spatial_method,'regularized')

    A = update_spatial_lasso(Y, A_, Cf, IND, options.sn, [], [], options);
    K = size(A,2)-options.nb;
    b = full(A(:,K+1:end));
    A = A(:,1:K);
    C = C(1:K,:);
end

A(isnan(A))=0;
A = sparse(A);
A = threshold_components(A,options);  % post-processing of components

fprintf('Updated spatial components \n');

ff = find(sum(A(:,1:K))==0);           % remove empty components
if ~isempty(ff)
    K = K - length(ff);
    A(:,ff) = [];
    C(ff,:) = [];
    Cf(ff,:) = [];
end

if strcmpi(options.spatial_method,'constrained');
    b = double(max((double(Yf) - A(:,1:K)*double(Cf(1:K,:)*f'))/(f*f'),0));
    A = A(:,1:K);
end


function [y,fs,bits]=wavread(fn,n)
%WAVREAD  Legacy MATLAB function to read .WAV file [Y,FS,BITS]=(FILENAME,NMAX)
% wavread supports multichannel data, with up to 32 bits per sample, and supports reading 24- and 32-bit .wav files.
%
% Usage:
% y = wavread('filename')               loads a WAVE file specified by the string filename, returning
%                                       the sampled data in y. The .wav extension is appended if no
%                                       extension is given. Amplitude values are in the range [-1,+1].
% [y,Fs,bits] = wavread('filename')     returns the sample rate (Fs) in Hertz and the number of bits
%                                       per sample (bits) used to encode the data in the file.
% [...] = wavread('filename',N)         returns only the first N samples from each channel in the file.
% [...] = wavread('filename',[N1 N2])   returns only samples N1 through N2 from each channel in the file.
% siz = wavread('filename','size')      returns the size of the audio data contained in the file in place
%                                       of the actual audio data, returning the vector siz = [samples channels].

%	   Copyright (C) Mike Brookes 2018
%      Version: $Id: wavread.m 10457 2018-03-28 14:32:59Z dmb $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   This program is free software; you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation; either version 2 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if nargin<2
    [y,fs,wm,fx]=readwav(fn);
elseif ischar(n)
    if strcmp(n,'size')
        [y,fs,wm,fx]=readwav(fn,'',0);
        y=fx(4:5); % number of samples and channels
    else
        error('%s is invalid option',n);
    end
elseif length(n)<2
    [y,fs,wm,fx]=readwav(fn,'',n);
else
    [y,fs,wm,fx]=readwav(fn,'',n(2)-n(1)+1,n(1)-1);
end
bits=fx(7); % bits precision


% Wrapper for vl_nnvisibilitymask block
% inputs{1} :   X     : 1 x 3 x n x b (Rotated vertices)
% obj       :   faces : nfaces x 3
% outputs{1}:   y     : 112 x 112 x 3 x b

classdef visibilitymask < dagnn.Layer

    properties
        faces = [];
    end

    methods
        function outputs = forward(obj, inputs, ~)

            useGPU = isa(inputs{1}, 'gpuArray');
            if useGPU
                outputs{1} = gpuArray( vl_nnvisibilitymask(gather(inputs{1}), obj.faces) );
            else
                outputs{1} = vl_nnvisibilitymask(inputs{1}, obj.faces);
            end

        end

        function [derInputs, derParams] = backward(obj, inputs, ~, derOutputs)

            useGPU = isa(inputs{1}, 'gpuArray');
            if useGPU
                derInputs{1} = gpuArray( vl_nnvisibilitymask(gather(inputs{1}), obj.faces, gather(derOutputs{1})) );
            else
                derInputs{1} = vl_nnvisibilitymask(inputs{1}, obj.faces, derOutputs{1});
            end

            derParams = {};
        end

        function outputSizes = getOutputSizes(obj, inputSizes)
            outputSizes = {112 112 3 inputSizes{1}(4)} ; % Note: We may want to set this dynamically as well
        end

        function obj = visibilitymask(varargin)
            obj.load(varargin);
        end
    end
end