function [r, iclust, lam] = drawClusters(ops, r, mPix, mLam, Ly, Lx)

icell = size(mPix,2);
iclust = zeros(Ly, Lx);

lam      = zeros(Ly, Lx);
for i = icell:-1:1
    ipos = find(mPix(:,i)>0);
    ipix = lam(mPix(ipos,i))+1e-4 < mLam(ipos,i);
    iclust(mPix(ipos(ipix),i)) = i;
    lam(mPix(ipos(ipix),i))      = mLam(ipos(ipix),i);
end

% if nargin>5
%     lam = I;
% end

r = cat(1, r, rand(icell+1-numel(r), 1));

if ops.fig
%     figure(2)
    clf
    Sat = ones(Ly, Lx);
    H = zeros(Ly, Lx);

    H(iclust>0) = r(iclust(iclust>0));

    V = max(0, min(.75 * reshape(lam, Ly, Lx)/mean(lam(lam>1e-10)), 1));
    H = reshape(H, Ly, Lx);
    rgb_image = hsv2rgb(cat(3, H, Sat, V));
    imagesc(rgb_image)
    axis off
end

drawnow


function aux_cs2(params, hParentFigure)
% function aux_FMD(params, hParentFigure);
%-------------------------------------------
%
% Incoming variables:
% params        : all variables
% hParentFigure : Handle of the parent figure
%
% Thomas van Stiphout, thomas@sed.ethz.ch
% last update: 7.9.2005

report_this_filefun(mfilename('fullpath'));

disp('here we go for a cross section');
view(0,90);
params2=params;
params.nDx=5;
params.nDy=5;
% ask for coordinates
% vSecLim1=[-153.60 61.10]
% vSecLim2=[-149.20 60.17]
% vSecLim1=[-153.00 62.00]
% vSecLim2=[-151.00 59.00]
vSecLim1=[-154.01 60.88]
vSecLim2=[-150.50 60.37]
% vSecLim1 = ginput(1);
% vSecLim2 = ginput(1);
dist_=deg2km(distance(vSecLim1(2),vSecLim1(1),vSecLim2(2),vSecLim2(1)));
azimuth_=azimuth(vSecLim1(2),vSecLim1(1),vSecLim2(2),vSecLim2(1));

% round length of cross section to multiple of nDx
[vSecLim2(2),vSecLim2(1)]=reckon('gc',vSecLim1(2),vSecLim1(1),km2deg(params.nDx*(round(dist_/params.nDx))),azimuth_);

vDist_=km2deg(0:params.nDx:params.nDx*(round(dist_/params.nDx)))';
vOnes_=ones(length(vDist_),1);
mPolygon(:,1)=vSecLim1(1)*ones(length(vDist_),1);
mPolygon(:,2)=vSecLim1(2)*ones(length(vDist_),1);
vAzimuth_=azimuth_*vOnes_;
[params.vY, params.vX]=reckon('gc',mPolygon(:,2),mPolygon(:,1),vDist_,vAzimuth_(:));
vDepth_=[40:5:120]';
params.mPolygon=reshape(ones(length(vDepth_),1)*params.vX',length(vDepth_)*length(mPolygon),1);
% vOrigin_=(max(params.mPolygon)+min(params.mPolygon))./2;
% mOrigin_=ones(size(params.mPolygon(:,1),1),1)*vOrigin_;
% distance(mOrigin_(:,2),params.mPolygon(:,1),mOrigin_(:,2),mOrigin_(:,1));
params.mPolygon(:,2)=reshape(ones(length(vDepth_),1)*params.vY',length(vDepth_)*length(mPolygon),1);
params.mPolygon(:,3)=reshape(vDepth_*ones(1,size(mPolygon,1)),size(mPolygon,1)*size(vDepth_,1),1);

parmas.mValueGrid=params.mPolygon(:,3);
params.mValueGrid(isnan(params.mPolygon(:,3)),:)=nan;
params.mX=reshape(params.mPolygon(:,1),length(vDepth_),size(params.mPolygon,1)/length(vDepth_));
params.mY=reshape(params.mPolygon(:,2),length(vDepth_),size(params.mPolygon,1)/length(vDepth_));
params.mZ=reshape(params.mPolygon(:,3),length(vDepth_),size(params.mPolygon,1)/length(vDepth_));
[Nx,Ny,Nz]=surfnorm(params.mX,params.mY,-params.mZ);
% vAzimuth2_=repmat(vAzimuth_,1,size(params.mX,1))';
% vAzimuth2_=repmat(vAzimuth_,size(params.mPolygon(:,1),1)/size(vAzimuth_,1),1);
% [Y_, X_]=reckon('gc',params.mY,params.mX,ones(size(vAzimuth2_))*km2deg(30),vAzimuth2_+90);
% Nx=params.mX-X_;
% Ny=params.mY-Y_;
params.mT=reshape(Nx,size(params.mPolygon,1),1);
params.mT(:,2)=reshape(Ny,size(params.mPolygon,1),1);
params.mT(:,3)=reshape(Nz,size(params.mPolygon,1),1);

% mT_1=reshape(params.mT(:,1),17,23)
% mT_2=reshape(params.mT(:,2),17,23)
% mT_3=reshape(params.mT(:,3),17,23)
% hold on;quiver3(params.mX(:),params.mY(:),-params.mZ(:),mT_1,mT_2,mT_3,2,'r')

params.mValueGrid=params.mPolygon(:,3);

params.vUsedNodes=ones(size(params.mPolygon,1),1);
Name=cellstr('Cylindrical Volume Sampling');
for ii=1:length(Name)
    if strcmp(Name(ii),'Cylindrical Volume Sampling')
        disp(Name(ii));
        params.sComment=strcat(Name(ii),' Cross-Section Vertical');
        [params.caNodeIndices2 params.vResolution2]=ex_CreateIndexCatalogCylinder(params.mCatalog,params.mPolygon,params.mT,...
            params.vUsedNodes,params.bCylSmpModeN,params.fCylSmpValue,params.fCylSmpBnd);
        if ((params.bCylSmpModeN==1) && (params.bCylSmpModeR==0))
            params.vcsGridNames(6) = cellstr(char('Resolution [R]'));
        else
            params.vcsGridNames(6) = cellstr(char('Resolution [N]'));
        end
    elseif strcmp(Name(ii),'3D Spherical Volume Sampling')
        disp(Name(ii));
        params.sComment=strcat(Name(ii),' Depth=',num2str(params.vPercentiles(nLayer)));
        % nGriddingMode = 3 means 3D sphere around polygonpoint
        params.nGriddingMode=3;
        % select
        % Create Indices to catalog and select quakes in time period
        [params.caNodeIndices2 params.vResolution2] = ex_CreateIndexCatalog3D(params.mCatalog, params.mPolygon, '1', params.n3DGriddingMode, ...
            params.f3DSmpValue, params.f3DSmpBnd, params.fSizeRectHorizontal, params.fSizeRectDepth);
        if ((params.b3DSmpModeN==1) && (params.b3DSmpModeR==0))
            params.vcsGridNames(6) = cellstr(char('Resolution [R]'));
        else
            params.vcsGridNames(6) = cellstr(char('Resolution [N]'));
        end
        % clear indices where not enough quakes for depth estimation
        for i=1:length(params.mPolygon)
            if isnan(params.mPolygon(i,3))
                params.caNodeIndices2{i}=[];
            end
        end
    else
        disp('Something is going wrong');
    end

% for testing sampling volumes
% hold on;i=300;plot3(params.mCatalog(params.caNodeIndices2{i},1),params.mCatalog(params.caNodeIndices2{i},2),-params.mCatalog(params.caNodeIndices2{i},7),'xr')

    % Calculation of bValue
    for i=1:length(params.mPolygon)
        if ~isempty(params.mCatalog(params.caNodeIndices2{i},:))
            % function [fBValue, fStdDev, fAValue, fMeanMag] =  calc_bvalue(mCatalog, fBinning)
            [params.mValueGrid(i,2),params.mValueGrid(i,3),params.mValueGrid(i,4),params.mValueGrid(i,5),] =  calc_bvalue(params.mCatalog(params.caNodeIndices2{i},:));
            params.mValueGrid(i,6)=max(params.vResolution2{i});
            % set values to NaN, when radius of sampling volume increase limit
            if (params.mValueGrid(i,6) > 20) %params.fCylSmp)
                params.mValueGrid(i,2:5)=nan;
            end
        else
            % create NaN's in mValueGrid, where strike is not defined
            params.mValueGrid(i,:)=nan;
        end

    end

    params.vcsGridNames(1:6) = cellstr(char(...
        'Depth Level',...               %   1
        'b-Value',...                   %   2
        'Standard Deviation',...        %   3
        'A-Value',...                   %   4
        'Mean Magnitude',...            %   5
        'Resolution [km]'));            %   6

    params.bMap=2;
    params.mValueGrid(isnan(params.mValueGrid(:,1)),:)=nan;
    params.mPlotValues=reshape(params.mValueGrid(:,2),size(params.mX,1),size(params.mX,2));
    hold on; surf(params.mX,params.mY,-params.mZ,params.mPlotValues);
    shading interp;
%     hold on;i=300;plot3(params.mCatalog(params.caNodeIndices2{i},1),params.mCatalog(params.caNodeIndices2{i},2),-params.mCatalog(params.caNodeIndices2{i},7),'k');
%     vResults((nLayer-1)*length(Name)+ii)=params;
end
% mPolygon1=ones(size(mPolygon(:,1),1),1)*mPolygon(:,1)';
% mPolygon2=(ones(size(mPolygon(:,1),1),1)*mPolygon(:,2)')';
% vPolygon1=reshape(mPolygon1,length(mPolygon1)*length(mPolygon2),1);
% vPolygon2=reshape(mPolygon2,length(mPolygon1)*length(mPolygon2),1);
% params.mZ_=(ones(size(vPolygon1,1),1))*vDepth_';
% vDepth_=reshape(params.mZ_,size(params.mZ_,1)*size(params.mZ_,2),1)
% mPoly1=ones(size(vDepth_,1)/size(vPolygon1,1),1)*vPolygon1';
% mPoly1=reshape(mPoly1',length(vDepth_),1);
% mPoly2=ones(size(vDepth_,1)/size(vPolygon2,1),1)*vPolygon2';
% mPoly2=reshape(mPoly2',length(vDepth_),1);

view(3);


function out = find_closest_region(atl, input_xyz_coord)
% Find the closest atlas region to an input [x, y, z] mm coordinate
%
% First line: One-line summary description of function
%
% :Usage:
% ::
%
%     out = find_closest_region(atlas_obj, input_xyz_coord)
%
%
% :Inputs:
%
%   **atlas_obj:**
%        An atlas-class object
%
%   **input_xyz_coord:**
%        A row vector with x, y, z coordinates in mm
%
% :Outputs:
%
%   **out:**
%        A structure containing:
%
%
% Example:
% Find the Glasser 2016 parcel containing a coordinate and display it
% --------------------------------------------------------------------
% atl = load_atlas('glasser');
% input_xyz_coord = [-18 12 -22];
% out = find_closest_region(atl, input_xyz_coord);
% disp(out)
% orthviews(out.closest_region_obj);
% spm_orthviews('reposition', input_xyz_coord)
%
% Note: requires dist.m from Matlab neural net toolbox to work correctly.
% It is very fast.
% There are many replacements that could be added, but this is the current
% implementation.

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

out = struct();

if ~isrow(input_xyz_coord)
    input_xyz_coord = input_xyz_coord';
end

if ~isrow(input_xyz_coord)
    error('Input a row vector with [x y z] coordinates in mm');
end

% transform all coordinates in object into mm
mmcoords = voxel2mm(atl.volInfo.xyzlist', atl.volInfo.mat);

% find closest
out.d = dist(input_xyz_coord , mmcoords(:,~atl.removed_voxels));

[out.mind, out.wh] = min(out.d);

out.region_number = atl.dat(out.wh);

if length(unique(out.region_number)) > 1
    warning('More than one region is equally close to input coordinate.');
end

out.closest_label = atl.labels{out.region_number};

out.closest_region_obj = select_atlas_subset(atl, out.region_number);

end % function


%	OVERVIEW:
%       This demonstration analyzes a segment of 5-minutes 'raw' data
%       with known atrial fibrillation to show the operation of the
%       AF detection algorithm.
%   OUTPUT:
%       HRV Metrics exported to .cvs files
%
%   DEPENDENCIES & LIBRARIES:
%       https://github.com/cliffordlab/PhysioNet-Cardiovascular-Signal-Toolbox
%   REFERENCE:
%       Vest et al. "An Open Source Benchmarked HRV Toolbox for Cardiovascular
%       Waveform and Interval Analysis" Physiological Measurement (In Press), 2018.
%	REPO:
%       https://github.com/cliffordlab/PhysioNet-Cardiovascular-Signal-Toolbox
%   ORIGINAL SOURCE AND AUTHORS:
%       Giulia Da Poian
%	COPYRIGHT (C) 2018
%   LICENSE:
%       This software is offered freely and without warranty under
%       the GNU (v3 or later) public license. See license file for
%       more information
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clear; clc; close all;

run(['..' filesep 'startup.m'])

% Remove old files generated by this demo
OldFolder = [pwd,filesep, 'OutputData', filesep, 'ResultsAFData'];
if exist(OldFolder, 'dir')
    rmdir(OldFolder, 's');
    fprintf('Old Demo Folder deleted \n');
end

HRVparams = InitializeHRVparams('demoAF'); % include the project name
HRVparams.poincare.on = 0; % Poincare analysis off for this demo
HRVparams.DFA.on = 0; % DFA analysis off for this demo
HRVparams.MSE.on = 0; % MSE analysis off for this demo
HRVparams.HRT.on = 0; % HRT analysis off for this demo

[subjectIDs,filesTBA] = GenerateListOfFilesTBA(HRVparams.ext,...
                                                    HRVparams.readdata,0);
idx = find(strcmp(subjectIDs,'TestAFdata'));
i_patient = idx;

% 1. Load Raw Patient Data

load(filesTBA{i_patient});
% 2. Analyze data using HRV PhysioNet Cardiovascular Signal Toolbox
[results, resFilename] = Main_HRV_Analysis(signal(:,1),[],'ECGWaveform',...
                                          HRVparams,subjectIDs(i_patient));

% 3. Compare generated output file with the reference one

currentFile = strcat(HRVparams.writedata, filesep, resFilename.HRV, '.csv');
referenceFile = strcat('ReferenceOutput', filesep, 'AFDemo.csv');
testHRV = CompareOutput(currentFile,referenceFile);

% 3. Load QRS annotation saved by Main_HRV_Analysis
annotName = strcat(HRVparams.writedata, filesep, 'Annotation',filesep,...
                                                    subjectIDs(i_patient));
jqrs_ann = read_ann( annotName{1} , 'jqrs');
wqrs_ann = read_ann( annotName{1} , 'wqrs');

% For demo pourpose recompute bsqi
[sqijw, StartIdxSQIwindows] = bsqi(jqrs_ann,wqrs_ann,HRVparams);

HRVparams.gen_figs = 1;
% Plot detected beats
if HRVparams.gen_figs
    Plot_SignalDetection_SQI(time, signal(:,1), jqrs_ann, sqijw,'ECG')
end

if testHRV
    fprintf('** DemoRawDataAF: TEST SUCCEEDED ** \n ')
    fprintf('A file named %s.csv \n has been saved in %s \n', ...
    resFilename.HRV, HRVparams.writedata);
else
    fprintf('** DemoRawDataAF: TEST FAILED ** \n')
end


function annolist = compute_det_bbox(expidx,annolist,nms_thresh,det_thresh,bbox_offset)

fprintf('compute_det_bbox()\n');

p = exp_params(expidx);
predDir = p.multicutDir;

nmissing = 0;
bVis = false;
imgidxs_missing = [];
pidx = 13; % neck
headSize = p.refHeight/8;

n = 0;

for imgidx = 1:length(annolist)

    fprintf('.');
    keypointsAll(imgidx).imgname = annolist(imgidx).image.name;
    fname = [predDir '/imgidx_' padZeros(num2str(imgidx),4) '_cidx_1_14'];
    img = imread(annolist(imgidx).image.name);
    try
        load(fname,'unLab','unPos','unProb');
    catch
        annolist(imgidx).annorect(1).bbox = [];
        annolist(imgidx).annorect(2:end) = [];
        imgidxs_missing = [imgidxs_missing; imgidx];
        nmissing = nmissing + 1;
        continue;
    end

    bbox = [unPos(:,1) - 1.5*headSize unPos(:,2) - headSize,...
                 unPos(:,1) + 1.5*headSize unPos(:,2) + 7*headSize];

    bbox(:,1) = bbox(:,1) - bbox_offset;
    bbox(:,2) = bbox(:,2) - bbox_offset;
    bbox(:,3) = bbox(:,3) + bbox_offset;
    bbox(:,4) = bbox(:,4) + bbox_offset;

    bbox = [bbox unProb(:,pidx)];
    bbox(bbox(:,5) < det_thresh,:) = [];

    if (isempty(bbox))
        annolist(imgidx).annorect(1).bbox = [];
        annolist(imgidx).annorect(2:end) = [];
        continue;
    end

    I = nms(bbox,nms_thresh);
    bbox = bbox(I,:);
    bbox(:,1) = max(bbox(:,1),1);
    bbox(:,2) = max(bbox(:,2),1);
    bbox(3) = min(bbox(3),size(img,2));
    bbox(4) = min(bbox(4),size(img,1));

    n = n + size(bbox,1);
    for ridx = 1:size(bbox)
        annolist(imgidx).annorect(ridx).bbox = bbox(ridx,1:4);
    end

    if (size(bbox,1) < length(annolist(imgidx).annorect))
        annolist(imgidx).annorect(size(bbox,1)+1:end) = [];
    end
    if (bVis)
        colors = {'r','g','b','c','m','y'};
        markers = {'+','o','s'}; %,'x','.','-','s','d'
        img = imread(annolist(imgidx).image.name);
        figure(100); clf; imagesc(img); axis equal; hold on;
        for ridx = 1:size(bbox,1)
            bb = annolist(imgidx).annorect(ridx).bbox;
            rectangle('Pos',[bb(:,1) bb(:,2) bb(:,3)-bb(:,1) bb(:,4)-bb(:,2)],'edgeColor',colors{mod(ridx,6)+1},'LineWidth',5);
            axis off;
        end
    end

    if (~mod(imgidx, 100))
        fprintf(' %d/%d\n',imgidx,length(annolist));
    end
end
fprintf(' done\n');
fprintf('# bbox: %d\n',n);
fprintf('nmissing: %d\n',nmissing);

end


%SpatialMomentum Spatial momentum class
%
% Concrete subclass of SpatialF6 and represents the
% translational and rotational momentum of a rigid-body moving in 3D space.
%
%          SpatialVec6 (abstract handle class)
%            |
%            +--- SpatialM6 (abstract)
%            |     |
%            |     +---SpatialVelocity
%            |     +---SpatialAcceleration
%            |
%            +---SpatialF6 (abstract)
%                 |
%                 +---SpatialForce
%                 +---SpatialMomentum
%
% Methods::
%  SpatialMomentum    ^constructor invoked by subclasses
%  new                construct new concrete class of same type
%  double             ^convert to a 6xN double
%  char               ^convert to string
%  cross              ^^cross product
%  display            ^display in human readable form
%
% Operators::
%  +          ^add spatial vectors of the same type
%  -          ^subtract spatial vectors of the same type
%  -          ^unary minus of spatial vectors
%
% Notes:
%  - ^ is inherited from SpatialVec6.
%  - ^^ is inherited from SpatialM6.
%
% References::
%
%  - Robot Dynamics Algorithms, R. Featherstone, volume 22,
%    Springer International Series in Engineering and Computer Science,
%    Springer, 1987.
%  - A beginner's guide to 6-d vectors (part 1), R. Featherstone,
%    IEEE Robotics Automation Magazine, 17(3):83-94, Sep. 2010.
%
% See also SpatialVec6, SpatialF6, SpatialForce.

% Copyright (C) 1993-2019 Peter I. Corke
%
% This file is part of The Spatial Math Toolbox for MATLAB (SMTB).
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the "Software"), to deal
% in the Software without restriction, including without limitation the rights
% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
% of the Software, and to permit persons to whom the Software is furnished to do
% so, subject to the following conditions:
%
% The above copyright notice and this permission notice shall be included in all
% copies or substantial portions of the Software.
%
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
% FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
% COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
% IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
% CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
%
% https://github.com/petercorke/spatial-math

classdef SpatialMomentum < SpatialF6
        methods
        function n = new(a, val)
            %SpatialMomentum.new Construct a new object of the same type
            %
            % A2 = A.new(X) creates a new object of the same type as A, with the value
            % X (6x1).
            %
            % Notes::
            %  - Serves as a dynamic constructor.
            %  - This method is polymorphic across all SpatialVec6 derived classes, and
            %    allows easy creation of a new object of the same class as an existing
            %    one without needing to explicitly determine its type.
            n = SpatialMomentum(val);
        end
    end
end


function F = uminus( F )
%- Unary minus of a CHEBFUN2V
%   -F returns the CHEBFUN2V negated componentwise.
%
%   UMINUS(F) is called by the syntax -F.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

% Empty check:
if (isempty( F ) )
    return
end

% Take uminus of each component:
F.components = cellfun( @uminus, F.components, 'UniformOutput', false );

end


function [ali, vocab] = readKaldiAlignmentText_struct(file_name)
lines = my_cat(file_name);

vocab = [];
for i=1:length(lines)
    PrintProgress(i,length(lines),1000);
    idx = regexp(lines{i}, ' ');
    uttName = lines{i}(1:idx(1)-1);
    ali.(['U_' uttName]) = str2num(lines{i}(idx(1)+1:end))';
    vocab = [vocab; ali.(['U_' uttName])];
    if mod(i,100)==0
        vocab = unique(vocab);
    end
end
vocab = unique(vocab);
end


function makelegend (offset, namedisplay, xlabel_my, ylabel_my)
% function makelegend (offset, namedisplay, xlabel_my, ylabel_my)
% sep = .1:.1:2;
% offset = [10 100 1000];
kk = 1;
% t{1} = namedisplay;

% t{2} = 'ICA';

for ii=1:1
    for jj= 1:length(offset)
%         l{kk} = [t{ii} 'offset ' num2str(offset(jj))];
%         l{kk} = [t{ii} num2str(offset(jj,:))];
%         l{kk}=namedisplay{jj};
        l{kk}=[namedisplay  num2str(offset(jj))];
        kk = kk+1;
    end
end

legend(l)
xlabel (xlabel_my)
ylabel (ylabel_my)
% xlabel('separation [pixels]')
% ylabel('loc err [pixels]')
grid on
% xlim([0 10])
% ylabel('loc err / separation')


%% SPARSE_FSU uses the fsuClusterMatlab command to run the SPARSE "computation".
%
%  Discussion:
%
%    The arguments to fsuClusterMatlab mean:
%
%    '~/matlab/sparse_parfor' allows us to specify an output directory;
%
%    [] allows us to specify switches to the MOAB queue handler, such as more time.
%
%    'p" indicates this is a "parfor" job;
%
%    'w' indicates that the MATLAB session should wait for completion;
%
%    workers is the number of processors requested;
%
%    @sparse_fun indicates the function we want to execute;
%
%    { n } contains input arguments to the function.
%
%    The function "sparse_fun" must correspond to a MATLAB M-file "sparse_fun.m"
%    and that file must be in MATLAB's path.
%
%    The easiest way to ensure that the file is in MATLAB's path is to
%    create a subdirectory called "matlab" immediately below your home directory,
%    and place the function file there (as well as any other files needed
%    by the job).
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 May 2012
%
%  Author:
%
%    John Burkardt
%
  workers = 4;

  tic

  results = fsuClusterMatlab ( '~/matlab/sparse_parfor', [], 'p', 'w', workers, ...
    @sparse_fun, { } );

  toc

  A_sparse = results{1};
%
%  Plot the results.
%
  spy ( A_sparse );


% This script plots the Gaussian sensing matrices generated by
% ex_generate_sample_sensing_matrices.m script.
% Please run the dependencies before running this script.

%% Initialization code
clear all; close all; clc;
% Let us load sample Rademacher sensing matrices
load('bin/gaussian_sensing_matrices.mat');

[numMatrices, numSets] = size(gaussianSensingMatrices);

% We pickup the first set
phis = gaussianSensingMatrices(:, 1);
spx.graphics.figure.full_screen;
for i=1:numMatrices
    % We pickup the matrix
    phi  = phis{i};
    % We get its size
    [M, N]  = size(phi);
    % We draw the matrix
    subplot(111);
    imagesc(phi) ;
    colormap(gray);
    axis image;
    xlabel(sprintf('\\Phi [%dx%d]', M, N));
    pause;
end


function model = rmSearchFit_twoGaussiansDoG(model,data,params,wProcess,t)
% rmSearchFit_twoGaussiansDoG - wrapper for 'fine' two DoG Gaussian fit
%
% model = rmSearchFit_twoGaussiansDoG(model,prediction,data,params);
%
% Second gaussian negative only.
%
% 2008/01 SOD: split of from rmSearchFit.

% add upper and lower limit:
expandRange    = params.analysis.fmins.expandRange;

% fminsearch options
searchOptions = params.analysis.fmins.options;
vethresh      = params.analysis.fmins.vethresh;

% convert to double just in case
params.analysis.X = double(params.analysis.X);
params.analysis.Y = double(params.analysis.Y);
params.analysis.allstimimages = double(params.analysis.allstimimages);

% amount of negative fits
nNegFit  = 0;
trends   = t.trends;
t_id     = t.dcid+2;

% get starting upper and lower range and reset TolFun
% (raw rss computation (similar to norm) and TolFun adjustments)
[range TolFun] = rmSearchFit_range(params,model,data);

% initialize
if ~isfield(model,'rss2')
    model.rss2 = zeros(size(model.rss));
end

if ~isfield(model,'rssPos')
    model.rsspos = zeros(size(model.rss));
end

if ~isfield(model,'rssNeg')
    model.rssneg = zeros(size(model.rss));
end

%-----------------------------------
% Go for each voxel
%-----------------------------------
progress = 0;tic;
for ii = 1:numel(wProcess),

    % progress monitor (10 dots)
    if floor(ii./numel(wProcess)*10)>progress,
        % print out estimated time left
        if progress==0,
            esttime = toc.*10;
            if floor(esttime./3600)>0,
                fprintf(1,'[%s]:Estimated processing time: %d voxels: %d hours.\n',...
                    mfilename,numel(wProcess),ceil(esttime./3600));
            else
                fprintf(1,'[%s]:Estimated processing time: %d voxels: %d minutes.\n',...
                    mfilename,numel(wProcess),ceil(esttime./60));
            end;
            fprintf(1,'[%s]:Nonlinear optimization (x,y,sigma):',mfilename);
        end;
        fprintf(1,'.');drawnow;
        progress = progress + 1;
    end;

    % volume index
    vi = wProcess(ii);
    vData = double(data(:,ii));

    % reset tolFun: Precision of evaluation function.
    % We define RMS improvement relative to the initial raw 'no-fit' data
    % RMS. So, 1 means stop if there is less than 1% improvement on the fit:
    searchOptions.TolFun = TolFun(ii);

    % actual fitting routine
    if searchOptions.MaxIter>0
        outParams = ...
            fmincon(@(x) rmModelSearchFit_twoGaussiansDoG(x,vData,...
            params.analysis.X,...
            params.analysis.Y,...
            params.analysis.allstimimages,trends),...
            range.start(:,vi),[],[],[],[],range.lower(:,vi),range.upper(:,vi),...
            @(x) distanceCon(x,range.start(:,vi),range.step(:,vi).*expandRange,params.analysis.minSigmaRatio),searchOptions);
    else
        outParams = range.start(:,vi);
    end

    % make predictions
    Xv = params.analysis.X - outParams(1);   % positive x0 moves center right
    Yv = params.analysis.Y - outParams(2);   % positive y0 moves center up
    rf(:,1) = exp( (Yv.*Yv + Xv.*Xv) ./ (-2.*(outParams(3).^2)) );
    rf(:,2) = exp( (Yv.*Yv + Xv.*Xv) ./ (-2.*(outParams(4).^2)) );

    % test 1 gaussian alone (must be done prior to with second gaussian)
    if searchOptions.MaxIter==0
        % without second gaussian
        X = [params.analysis.allstimimages*rf(:,1) trends];
        b = pinv(X)*vData;
        % force positive fit (is a constraint in the rmModelSearchFit_twoGaussian, so it should return here to get the right values)
        b(1) = abs(b(1));
        rss2  = norm(vData-X*b).^2;
        % make only the positive and the negative rf
        % find out where the rf is positive and where it is negative
        % for the positive rf put all the negative rf-values to zero, for
        % the negative rf put all the positive rf-values to zero.
        X = [params.analysis.allstimimages*rf trends];
        b    = pinv(X)*vData;

        % force positive fit
        b(1) = abs(b(1));
        %force negative b2 fit
        b(2) = -(abs(b(2)));

        rfBeta = b(1).*rf(:,1) + b(2).*rf(:,2);
        posInd = rfBeta > 0;
        negInd = rfBeta < 0;
        rfPos = rf;
        rfNeg = rf;
        rfPos(negInd,1) = 0;
        rfPos(negInd,2) = 0;
        rfNeg(posInd,1) = 0;
        rfNeg(posInd,2) = 0;
        XPos = [params.analysis.allstimimages*rfPos trends];
        XNeg = [params.analysis.allstimimages*rfNeg trends];
        rssPos = norm(vData-XPos*b).^2;
        rssNeg = norm(vData-XNeg*b).^2;

        %rfBeta = rf*b(1:2);
        %rssPos = norm(vData-max(rfBeta,0)).^2;
        %rssNeg = norm(vData-min(rfBeta,0)).^2;

%         if length(rssPos)==0
%             disp('rssPos is empty!');
%             rssPos = 1;
%         end
    end

    % with second gaussian
    X = [params.analysis.allstimimages*rf trends];
    b    = pinv(X)*vData;
    % force positive fit
    b(1) = abs(b(1));
    %force negative b2 fit
    b(2) = -(abs(b(2)));
    rss  = norm(vData-X*b).^2;

    % store results only if the first beta is positive, somehow fmincon
    % outputs negative fits. If the fit is negative keep old (grid) fit.
    if b(1)>0 && b(1)>-b(2) && b(2) <=0,
        model.x0(vi)   = outParams(1);
        model.y0(vi)   = outParams(2);
        model.s(vi)    = outParams(3);
        model.s_major(vi)    = outParams(3);
        model.s_minor(vi)    = outParams(3);
        model.s_theta(vi)    = 0;
        model.s2(vi)   = outParams(4);
        model.rss(vi)  = rss;
        model.b([1 2 t_id],vi) = b;
        if searchOptions.MaxIter==0
            model.rss2(vi) = rss2;
            model.rsspos(vi) = rssPos;
            model.rssneg(vi) = rssNeg;
        end
    else
        % change the percent variance explained to be just under the
        % current vethresh. So it counts as a 'coarse'-fit but can still be
        % included in later 'fine'-fits
        model.rss(vi)  = (1-max((vethresh-0.01),0)).*model.rawrss(vi);
        nNegFit = nNegFit + 1;
        if searchOptions.MaxIter==0
            model.rss2(vi)  = (1-max((vethresh-0.01),0)).*model.rawrss(vi);
            model.rsspos(vi)  = (1-max((vethresh-0.01),0)).*model.rawrss(vi);
            model.rssneg(vi)  = (1-max((vethresh-0.01),0)).*model.rawrss(vi);
        end
    end;
end;

% end time monitor
et  = toc;
if floor(et/3600)>0,
    fprintf(1,'Done [%d hours].\n',ceil(et/3600));
else
    fprintf(1,'Done [%d minutes].\n',ceil(et/60));
end;
fprintf(1,'[%s]:Removed negative fits: %d (%.1f%%).\n',...
    mfilename,nNegFit,nNegFit./numel(wProcess).*100);

return;

%-----------------------------------
% make sure that the pRF can only be moved "step" away from original
% poisiton "startParams"
% For the two Gaussian model we add the additional constraint that the
% second Gaussian is at least twice as large as the first.
function [C, Ceq]=distanceCon(x,startParams,step,minRatio)
Ceq = [];
dist = x([1 2])-startParams([1 2]);
C(1) = sqrt(dist(1).^2+dist(2).^2) - step;
C(2) = minRatio - 0.001 - x(4)./x(3);
return;
%-----------------------------------


function prob = precalcgpstruct(prob)
prob.b = full(prob.b);
try
    % In 2013a they changed the logic in the output. Tell MATLAB to use old
    % style
    [aa,bb,cc] = unique(prob.map,'legacy');
catch
    % If we have an old version, MATLAB would barf at the legacy flag
    [aa,bb,cc] = unique(prob.map);
end

if aa(1)==1
    bb=[0 bb(1:end)'];
end
indsi = [];
indsj = [];
vals = [];
for i = 1:max(prob.map)
    ind = [(bb(i)+1):(bb(i+1))];
    indsj = [indsj ind];
end
indsi = prob.map(prob.map>0);
vals = prob.b(prob.map>0);
prob.B = sparse(indsi,indsj,vals,max(prob.map),size(prob.A,1));

ind = find(prob.map==0);
prob.Afun = prob.A(ind,:);
prob.bfun = prob.b(ind);


function box_plot ( point_filename, header )

%*****************************************************************************80
%
%% BOX_PLOT plots integer pairs as filled boxes.
%
%  Discussion:
%
%    The input file contains pairs of integer coordinates.
%
%  Usage:
%
%    box_plot ( 'point_file_name' )
%
%    reads 5 values per line (x,y,r,g,b) from the file,
%    and plots a box of color rgb at position xy.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 January 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string POINT_FILENAME, the name of the file containing the
%    coordinates of the points.
%
%    Input, string HEADER, an optional title for the plot.
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'BOX_PLOT\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Read a file of POINT_NUM points in 2 dimensions;\n' );
  fprintf ( 1, '  Display the points in a MATLAB graphics window.\n' );
%
%  First argument is the point file.
%
  if ( nargin < 1 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'BOX_PLOT:\n' );
    point_filename = input ( '  Enter the name of the point file: ' );
  end
%
%  Second item is the optional header.
%
  if ( nargin < 2 )
    header = s_escape_tex ( point_filename );
  end
%
%  Read the data.
%
  [ dim_num, point_num ] = r8mat_header_read ( point_filename );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Read the header of "%s".\n', point_filename );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Data dimension DIM_NUM   = %d\n', dim_num );
  fprintf ( 1, '  Number of points POINT_NUM  = %d\n', point_num );

  xyrgb = r8mat_data_read ( point_filename, dim_num, point_num );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Read the data in "%s".\n', point_filename );
%
%  Extract the XY data and guarantee that the data is integral.
%
  xy(1:2,1:point_num) = round ( xyrgb(1:2,1:point_num) );

  i4mat_transpose_print_some ( 2, point_num, xy, 1, 1, ...
    2, 5, '  A portion of the XY data:' );
%
%  Extract the RGB data.
%
  rgb(1:3,1:point_num) = xyrgb(3:5,1:point_num);

  r8mat_transpose_print_some ( 3, point_num, rgb, 1, 1, ...
    3, 5, '  A portion of the RGB data:' );
%
%  Make the plot.
%
  x_data_min = min ( xy(1,:) );
  x_data_max = max ( xy(1,:) );
  y_data_min = min ( xy(2,:) );
  y_data_max = max ( xy(2,:) );

  x_plot_min = x_data_min - 0.5;
  x_plot_max = x_data_max + 0.5;

  y_plot_min = y_data_min - 0.5;
  y_plot_max = y_data_max + 0.5;

  x_plot_range = x_plot_max - x_plot_min;
  y_plot_range = y_plot_max - y_plot_min;

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Data Min:  %12f  %12f\n', x_data_min, y_data_min );
  fprintf ( 1, '  Data Max:  %12f  %12f\n', x_data_max, y_data_max );

  margin = 0.025 * max ( x_plot_range, y_plot_range );

  x_axes_min = x_plot_min - margin;
  x_axes_max = x_plot_max + margin;
  y_axes_min = y_plot_min - margin;
  y_axes_max = y_plot_max + margin;

  clf
%
%  Every box starts out WHITE.
%
  for x = x_data_min : x_data_max

    for y = y_data_min : y_data_max

      a = x - 0.44;
      b = x + 0.44;
      c = y - 0.44;
      d = y + 0.44;

      patch ( [ a, b, b, a ], [ c, c, d, d ], 'w', 'EdgeColor', 'none' );

    end

  end
%
%  Now draw boxes of the user's selected color.
%
  for point = 1 : point_num

    a = xy(1,point) - 0.44;
    b = xy(1,point) + 0.44;
    c = xy(2,point) - 0.44;
    d = xy(2,point) + 0.44;
    patch ( [ a, b, b, a ], [ c, c, d, d ], rgb(1:3,point)', 'EdgeColor', 'none');

  end
%
%  TEMPORARY!
%  Draw a line to indicate desired accuracy level for sparse grids.
%
  if ( 0 )
    line ( [-0.5, 7.5 ], [ 7.5, -0.50 ], 'LineWidth', 3, 'Color', 'w' )
  end
  if ( 0 )
    line ( [-0.5, 9.5 ], [ 9.5, -0.50 ], 'LineWidth', 3, 'Color', 'w' )
  end
  if ( 0 )
    line ( [-0.5, 11.5 ], [ 11.5, -0.50 ], 'LineWidth', 3, 'Color', 'w' )
  end
  if ( 1 )
    line ( [-0.5, 13.5 ], [ 13.5, -0.50 ], 'LineWidth', 3, 'Color', 'w' )
  end
%
%  The TITLE function will interpret underscores in the title.
%  We need to unescape such escape sequences!
%
  if ( 0 )
    xlabel ( '<--- I --->', 'Fontsize', 16 )
    ylabel ( '<--- J --->', 'Fontsize', 16 )
    title ( header, 'Fontsize', 24 )
  end

  axis ( [ x_axes_min, x_axes_max, y_axes_min, y_axes_max ] );
  axis equal
  axis square
  axis tight

  plot_filename = filename_ext_swap ( point_filename, 'png' );
  print ( '-dpng', plot_filename );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  A copy of this image was saved as "%s"\n', plot_filename );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'BOX_PLOT\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end
function column_num = file_column_count ( input_file_name )

%*****************************************************************************80
%
%% FILE_COLUMN_COUNT counts the columns in the first line of a file.
%
%  Discussion:
%
%    The file is assumed to be a simple text file.
%
%    Most lines of the file are presumed to consist of COLUMN_NUM words,
%    separated by spaces.  There may also be some blank lines, and some
%    comment lines, which have a "#" in column 1.
%
%    The routine tries to find the first non-comment non-blank line and
%    counts the number of words in that line.
%
%    If all lines are blanks or comments, it goes back and tries to analyze
%    a comment line.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    21 February 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string INPUT_FILE_NAME, the name of the file.
%
%    Output, integer COLUMN_NUM, the number of columns in the file.
%
  FALSE = 0;
  TRUE = 1;
%
%  Open the file.
%
  input_unit = fopen ( input_file_name );

  if ( input_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'FILE_COLUMN_COUNT - Error!\n' );
    fprintf ( 1, '  Could not open the file "%s".\n', input_file_name );
    error ( 'FILE_COLUMN_COUNT - Error!' );
  end
%
%  Read one line, but skip blank lines and comment lines.
%  Use FGETL so we drop the newline character!
%
  got_one = FALSE;

  while ( 1 )

    line = fgetl ( input_unit );

    if ( line == -1 )
      break;
    end

    if ( s_len_trim ( line ) == 0 )

    elseif ( line(1) == '#' )

    else
      got_one = TRUE;
      break;
    end

  end

  fclose ( input_unit );

  if ( got_one == FALSE )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'FILE_COLUMN_COUNT - Warning!\n' );
    fprintf ( 1, '  The file does not seem to contain any data.\n' );
    column_num = -1;
    return;
  end

  column_num = s_word_count ( line );

  return
end
function filename_new = filename_ext_swap ( filename, ext )

%*****************************************************************************80
%
%% FILENAME_EXT_SWAP replaces the current "extension" of a file name.
%
%  Discussion:
%
%    The "extension" of a filename is the string of characters
%    that appears after the LAST period in the name.  A file
%    with no period, or with a period as the last character
%    in the name, has a "null" extension.
%
%  Example:
%
%          Input           Output
%    ================     =============
%    FILENAME     EXT     FILENAME_NEW
%
%    bob.for      obj     bob.obj
%    bob.bob.bob  txt     bob.bob.txt
%    bob          yak     bob.yak
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    15 August 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string FILENAME, a file name.
%    On output, the extension of the file has been changed.
%
%    Input, string EXT, the extension to be used on the output
%    copy of FILE_NAME, replacing the current extension if any.
%
%    Output, string FILENAME_NEW, a copy of the input file name,
%    with the new extension.
%
  filename_len = length ( filename );

  ext_len = length ( ext );

  period = filename_len + 1;

  for i = filename_len : -1 : 1
    if ( filename(i:i) == '.' )
      period = i;
      break
    end
  end

  filename_new(1:period-1) = filename(1:period-1);
  filename_new(period) = '.';
  filename_new(period+1:period+ext_len) = ext(1:ext_len);

  return
end
function row_num = file_row_count ( input_file_name )

%*****************************************************************************80
%
%% FILE_ROW_COUNT counts the number of row records in a file.
%
%  Discussion:
%
%    Each input line is a "RECORD".
%
%    The records are divided into three groups:
%
%    * BLANK LINES (nothing but blanks)
%    * COMMENT LINES (begin with a '#')
%    * DATA RECORDS (anything else)
%
%    The value returned by the function is the number of data records.
%
%    By the way, if the MATLAB routine FGETS is used, instead of
%    FGETL, then the variable LINE will include line termination
%    characters, which means that a blank line would not actually
%    have zero characters.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    31 December 2006
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string INPUT_FILE_NAME, the name of the input file.
%
%    Output, integer ROW_NUM, the number of rows found.
%
  input_unit = fopen ( input_file_name );

  if ( input_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'FILE_ROW_COUNT - Error!\n' );
    fprintf ( 1, '  Could not open the file "%s".\n', input_file_name );
    error ( 'FILE_ROW_COUNT - Error!' );
  end

  blank_num = 0;
  comment_num = 0;
  row_num = 0;

  record_num = 0;

  while ( 1 )

    line = fgetl ( input_unit );

    if ( line == -1 )
      break;
    end

    record_num = record_num + 1;
    record_length = s_len_trim ( line );

    if ( record_length <= 0 )
      blank_num = blank_num + 1;
    elseif ( line(1) == '#' )
      comment_num = comment_num + 1;
    else
      row_num = row_num + 1;
    end

  end

  fclose ( input_unit );

  return
end
function i4mat_transpose_print_some ( m, n, a, ilo, jlo, ihi, jhi, title )

%*****************************************************************************80
%
%% I4MAT_TRANSPOSE_PRINT_SOME prints some of an I4MAT, transposed.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    21 June 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer M, N, the number of rows and columns.
%
%    Input, integer A(M,N), an M by N matrix to be printed.
%
%    Input, integer ILO, JLO, the first row and column to print.
%
%    Input, integer IHI, JHI, the last row and column to print.
%
%    Input, string TITLE, an optional title.
%
  incx = 10;

  if ( 0 < s_len_trim ( title ) )
    fprintf ( 1, '\n' );
    fprintf ( 1, '%s\n', title );
  end

  for i2lo = max ( ilo, 1 ) : incx : min ( ihi, m )

    i2hi = i2lo + incx - 1;
    i2hi = min ( i2hi, m );
    i2hi = min ( i2hi, ihi );

    inc = i2hi + 1 - i2lo;

    fprintf ( 1, '\n' );
    fprintf ( 1, '  Row: ' );
    for i = i2lo : i2hi
      fprintf ( 1, '%7d  ', i );
    end
    fprintf ( 1, '\n' );
    fprintf ( 1, '  Col\n' );
    fprintf ( 1, '\n' );

    j2lo = max ( jlo, 1 );
    j2hi = min ( jhi, n );

    for j = j2lo : j2hi

      fprintf ( 1, '%5d  ', j );
      for i2 = 1 : inc
        i = i2lo - 1 + i2;
        fprintf ( 1, '%7d  ', a(i,j) );
      end
      fprintf ( 1, '\n' );

    end

  end

  return
end
function table = r8mat_data_read ( input_filename, m, n )

%*****************************************************************************80
%
%% R8MAT_DATA_READ reads data from an R8MAT file.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    27 January 2006
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string INPUT_FILENAME, the name of the input file.
%
%    Input, integer M, N, the number of rows and columns of data.
%
%    Output, real TABLE(M,N), the point coordinates.
%
  table = zeros ( m, n );
%
%  Build up the format string for reading M real numbers.
%
  string = ' ';

  for i = 0 : m
    string = strcat ( string, ' %f' );
  end

  input_unit = fopen ( input_filename );

  if ( input_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'R8MAT_DATA_READ - Error!\n' );
    fprintf ( 1, '  Could not open the file.\n' );
    error ( 'R8MAT_DATA_READ - Error!' );
  end

  i = 0;

  while ( i < n )

    line = fgets ( input_unit );

    if ( line == -1 )
      break;
    end

    if ( line(1) == '#' )

    elseif ( s_len_trim ( line ) == 0 )

    else

      [ x, count ] = sscanf ( line, string );

      if ( count == m )
        i = i + 1;
        table(1:m,i) = x(1:m);
      end

    end

  end

  fclose ( input_unit );

  return
end
function [ m, n ] = r8mat_header_read ( input_filename )

%*****************************************************************************80
%
%% R8MAT_HEADER_READ reads the header from an R8MAT file.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 October 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string INPUT_FILENAME, the name of the input file.
%
%    Output, integer M, the spatial dimension.
%
%    Output, integer N, the number of points.
%
  m = file_column_count ( input_filename );

  if ( m <= 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'R8MAT_HEADER_READ - Fatal error!\n' );
    fprintf ( 1, '  There was some kind of I/O problem while trying\n' );
    fprintf ( 1, '  to count the number of data columns in\n' );
    fprintf ( 1, '  the file %s.\n', input_filename );
  end

  n = file_row_count ( input_filename );

  if ( n <= 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'R8MAT_HEADER_READ - Fatal error!\n' );
    fprintf ( 1, '  There was some kind of I/O problem while trying\n' );
    fprintf ( 1, '  to count the number of data rows in\n' );
    fprintf ( 1, '  the file %s\n', input_filename );
  end

  return
end
function r8mat_transpose_print_some ( m, n, a, ilo, jlo, ihi, jhi, title )

%*****************************************************************************80
%
%% R8MAT_TRANSPOSE_PRINT_SOME prints some of an R8MAT, transposed.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    23 May 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer M, N, the number of rows and columns.
%
%    Input, real A(M,N), an M by N matrix to be printed.
%
%    Input, integer ILO, JLO, the first row and column to print.
%
%    Input, integer IHI, JHI, the last row and column to print.
%
%    Input, string TITLE, an optional title.
%
  incx = 5;

  if ( 0 < s_len_trim ( title ) )
    fprintf ( 1, '\n' );
    fprintf ( 1, '%s\n', title );
  end

  for i2lo = max ( ilo, 1 ) : incx : min ( ihi, m )

    i2hi = i2lo + incx - 1;
    i2hi = min ( i2hi, m );
    i2hi = min ( i2hi, ihi );

    inc = i2hi + 1 - i2lo;

    fprintf ( 1, '\n' );
    fprintf ( 1, '  Row: ' );
    for i = i2lo : i2hi
      fprintf ( 1, '%7d       ', i );
    end
    fprintf ( 1, '\n' );
    fprintf ( 1, '  Col\n' );

    j2lo = max ( jlo, 1 );
    j2hi = min ( jhi, n );

    for j = j2lo : j2hi

      fprintf ( 1, '%5d ', j );
      for i2 = 1 : inc
        i = i2lo - 1 + i2;
        fprintf ( 1, '%12f', a(i,j) );
      end
      fprintf ( 1, '\n' );

    end

  end

  return
end
function s2 = s_escape_tex ( s1 )

%*****************************************************************************80
%
%% S_ESCAPE_TEX de-escapes TeX escape sequences.
%
%  Discussion:
%
%    In particular, every occurrence of the characters '\', '_',
%    '^', '{' and '}' will be replaced by '\\', '\_', '\^',
%    '\{' and '\}'.  A TeX interpreter, on seeing these character
%    strings, is then likely to return the original characters.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 January 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S1, the string to be de-escaped.
%
%    Output, string S2, a copy of the string, modified to avoid TeX escapes.
%
  s1_length = length ( s1 );

  s1_pos = 0;
  s2_pos = 0;
  s2 = [];

  while ( s1_pos < s1_length )

    s1_pos = s1_pos + 1;

    if ( s1(s1_pos) == '\' || ...
         s1(s1_pos) == '_' || ...
         s1(s1_pos) == '^' || ...
         s1(s1_pos) == '{' || ...
         s1(s1_pos) == '}' )
      s2_pos = s2_pos + 1;
      s2 = strcat ( s2, '\' );
    end

    s2_pos = s2_pos + 1;
    s2 = strcat ( s2, s1(s1_pos) );

  end

  return
end
function len = s_len_trim ( s )

%*****************************************************************************80
%
%% S_LEN_TRIM returns the length of a character string to the last nonblank.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 June 2003
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S, the string to be measured.
%
%    Output, integer LEN, the length of the string up to the last nonblank.
%
  len = length ( s );

  while ( 0 < len )
    if ( s(len) ~= ' ' )
      return
    end
    len = len - 1;
  end

  return
end
function word_num = s_word_count ( s )

%*****************************************************************************80
%
%% S_WORD_COUNT counts the number of "words" in a string.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    30 January 2006
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S, the string to be examined.
%
%    Output, integer WORD_NUM, the number of "words" in the string.
%    Words are presumed to be separated by one or more blanks.
%
  FALSE = 0;
  TRUE = 1;

  word_num = 0;
  s_length = length ( s );

  if ( s_length <= 0 )
    return;
  end

  blank = TRUE;

  for i = 1 : s_length

    if ( s(i) == ' ' )
      blank = TRUE;
    elseif ( blank == TRUE )
      word_num = word_num + 1;
      blank = FALSE;
    end

  end

  return
end
function timestamp ( )

%*****************************************************************************80
%
%% TIMESTAMP prints the current YMDHMS date as a timestamp.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  t = now;
  c = datevec ( t );
  s = datestr ( c, 0 );
  fprintf ( 1, '%s\n', s );

  return
end


%%

addpath(genpath('..'));
addpath(genpath('../../../../scripts'));

resDir = getResDir;
dataDir = getDataDir;

challenge = 2; % 2D MOT 2015
% challenge = 5; % MOT16

% eval all
challenge = 2; % 2D MOT 2015
challenge = 5; % MOT16

detectorName = 'acf';
detectorName = 'dpm';
detectorName = 'fasterrcnndet-th-0';
% detectorName = '';

sequences=[];
% allSeq={'TUD-Stadtmitte'};
% sequences='PETS09-S2L1';
% sequences={'TUD-Stadtmitte','PETS09-S2L1'};
allSeq = parseSequences([0 challenge],dataDir);
% allSeq = {'MOT16-01'}

    dt0=[];
    gt0=[];
% for each sequence
allFrCnt=0;
for seq=allSeq

    [seqName, seqFolder, imgFolder, imgExt, F, dirImages] ...
        = getSeqInfo(seq, dataDir);

%     detFolder = [dataDir,seqName,filesep,'det',filesep];
%     detFile = [detFolder,'det.txt'];
    [detFolder, detFile]=getDetInfo(seqName,dataDir,detectorName);

%     if ~exist(detFile,'file'), continue; end

    gtFolder= [dataDir,seqName,filesep,'gt',filesep];
    gtFile = [gtFolder,'gt.txt'];

    detRaw=dlmread(detFile);
    gtRaw=dlmread(gtFile);

    for t=1:F
        allFrCnt=allFrCnt+1;
        exdet=find(detRaw(:,1)==t);
        bbox=detRaw(exdet,3:7);
        dt0{allFrCnt}=bbox;

        exgt=find(gtRaw(:,1)==t & gtRaw(:,8)==1);
        gt0{allFrCnt}=[gtRaw(exgt,3:6) zeros(length(exgt),1)];

    end
end

allSeq = parseSequences([1 challenge],dataDir);
% allSeq = {'MOT16-02'}

    dt1=[];
    gt1=[];

% for each sequence
allFrCnt1=0;
for seq=allSeq

    [seqName, seqFolder, imgFolder, imgExt, F, dirImages] ...
        = getSeqInfo(seq, dataDir);

%     detFolder = [dataDir,seqName,filesep,'det',filesep];
%     detFile = [detFolder,'det.txt'];
    [detFolder, detFile]=getDetInfo(seqName,dataDir,detectorName);
%     if ~exist(detFile,'file'), continue; end

    gtFolder= [dataDir,seqName,filesep,'gt',filesep];
    gtFile = [gtFolder,'gt.txt'];

    detRaw=dlmread(detFile);
    gtRaw=dlmread(gtFile);

    for t=1:F
        allFrCnt1=allFrCnt1+1;
        exdet=find(detRaw(:,1)==t);
        bbox=detRaw(exdet,3:7);
        dt1{allFrCnt1}=bbox;

        exgt=find(gtRaw(:,1)==t & gtRaw(:,8)==1);
        gt1{allFrCnt1}=[gtRaw(exgt,3:6) zeros(length(exgt),1)];

    end
end

% lims=[3.1e-3 1e1 .05 1];
lims=[0 1 0 1];
ref=10.^(-2:.25:0);
ref=0:.1:1;

%%
clf; hold on; box on;

% Training Set
[gt,dt]=bbGt('evalRes',gt0,dt0);
[fp,tp,score,miss] = bbGt('compRoc',gt,dt,0,ref);

% Test Set
[gt,dt]=bbGt('evalRes',gt1,dt1);
[fp1,tp1,score1,miss1] = bbGt('compRoc',gt,dt,0,ref);

set(gca,'FontSize',12)
plot(fp,tp,'linewidth',2);
plot(fp1,tp1,'linewidth',2,'color','r');

opX=fp(end); opY=tp(end);
plot(opX,opY,'.','MarkerSize',25);
opX1=fp1(end); opY1=tp1(end);
plot(opX1,opY1,'.','MarkerSize',25,'color','r');

%%
fs=22;
set(gca,'FontSize',fs);
text(opX+.25,opY+.1,sprintf('Rcll: %.1f %%\nPrc: %.1f %%',opX*100,opY*100),'VerticalAlignment','top','HorizontalAlignment','right','FontSize',fs-4);
text(opX1-.05,opY1-.025,sprintf('Rcll: %.1f %%\nPrc: %.1f %%',opX1*100,opY1*100),'VerticalAlignment','top','HorizontalAlignment','right','FontSize',fs-4);
xlim(lims(1:2)); ylim(lims(3:4));

xlabel('Recall'); ylabel('Precision');
title('Detector Performance');
legend('Training Set','Test Set');

% export_fig 'det-dollar.pdf' -png -pdf;
% saveas(gcf,'det-dollar.pdf');
% saveas(gcf,'det-dollar.png');
% export_fig 'det-dollar.pdf' -transparent;
pdfFileName = sprintf('det-%s.pdf',detectorName);
export_fig(pdfFileName, '-transparent');
% export_fig '../../../../../../papers/2015/arxiv-benchmark/figures/det-dollar.pdf' -transparent;

% miss=exp(mean(log(max(1e-10,1-miss)))); roc=[score fp tp];
% figure(show); plotRoc([fp tp],'logx',1,'logy',0,'xLbl','fppi',...
%   'lims',lims,'color','g','smooth',1,'fpTarget',ref);
% title(sprintf('log-average miss rate = %.2f%%',miss*100));


function [Knots_n] = refine_linear_grid_list(Knots, old_spacing, ds, volsz, varargin)
    k_down = 0.5;
%     new_vol_sz = [];
    if nargin >= 5
        k_down = varargin{1};
    end

    nd = numel(ds);
    if nd == 2
        Knots_sz = ceil(volsz ./ old_spacing) + 1;
        Knots_n = zeros([Knots_sz, 2, size(Knots, 4)]);
        for i = 1 : size(Knots, 4)
            Knots_n(:,:,:, i) = refine_linear_grid_2d(Knots(:,:,:, i), old_spacing, ds, volsz, k_down);
        end
    elseif nd == 3
        Knots_sz = ceil(volsz ./ old_spacing) + 1;
        Knots_n = zeros([Knots_sz, 3, size(Knots, 5)]);
        for i = 1 : size(Knots, 5)
            Knots_n(:,:,:,:, i) = refine_linear_grid_3d(Knots(:,:,:,:, i), old_spacing, ds, volsz, k_down);
        end
    end
end


function [s, S_l, S_t] = pluckerSegment(l,t)

% PLUCKERSEGMENT Segment from Plucker line and endpoint abscissas.
%   PLUCKERSEGMENT(L,T) returns a segment [p1;p2] of two endpoints given a
%   Plucker line L and its two endpoint abscissas in T.

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

[e1,e2,E1_l,E2_l,E1_t1,E2_t2] = pluckerEndpoints(l,t(1),t(2));

s = [e1;e2];

if nargout > 1
    S_l = [E1_l;E2_l];
    if nargout > 2
        S_t = [E1_t1 E1_t2
            E2_t1;E2_t2];
    end
end

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

%   # START GPL LICENSE

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

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

%   # END GPL LICENSE


function dObj = pathObjective(u)
% dObj = pathObjective(u)
%
% Computes the integrand of the objective function, in this case,
% minimizing the integral of acceleration squared
%
% INPUTS:
%   u = [u1;u2];
%
% OUTPUTS:
%   dOBj = ddx.^2
%

% u1 = u(1,:);  % Unused
u2 = u(2,:);

dObj = u2.^2;

end


function Torques(nlp, sys)

    domains = sys.Gamma.Nodes.Domain;

    for i=1:numel(domains)
        domain = domains{i};

        u = domain.Inputs.Control.u;
        u2r = tovector(norm(u).^2);
        u2r_fun = SymFunction(['torque_' sys.Gamma.Nodes.Name{i}],u2r,{u});
        rs_phase = getPhaseIndex(nlp,sys.Gamma.Nodes.Name{i});
        addRunningCost(nlp.Phase(rs_phase),u2r_fun,{'u'});

    end
    nlp.update;
end


function [x,info] = mgfracLapP1P2(A,b,elem,option,varargin)
%% MGFRACLAPP1P2 multigrid solvers for fractional Laplacian
%
%
% See also mg
%
% Documentation in Help browser ifem mgdoc
%
% Copyright (C) Long Chen. See COPYRIGHT.txt for details.

tic;

%% Size of systems
Ndof = length(b);               % number of dof
N = max(elem(:));               % number of nodes
Nydof = Ndof/N;                 % number of dof in the extend direction
Ny = (Nydof + 1)/2;             % number of nodes in the extend direction
% NT = size(elem,1);                 % number of elements
dim = size(elem,2)-1;

%% Options
% Assign default values to unspecified parameters
if ~exist('option','var'),
    option = [];
end
option = mgoptions(option,Ndof);    % parameters
x0 = option.x0;
N0 = option.N0/5;
tol = option.tol;
maxIt = option.solvermaxit;
mu = option.smoothingstep;
solver = option.solver;
% preconditioner = option.preconditioner;
preconditioner = 'none';
coarsegridsolver = option.coarsegridsolver;
printlevel = option.printlevel;
option.smoother = 'LINE';

%% Fixed dof
isFixDof = [];
if isfield(option,'freeDof') % freeDof is given
   isFreeDof = false(N,1);
   isFreeDof(option.freeDof) = true;
   NA = size(A,1);
   if NA > length(option.freeDof)
       isFixDof = true(NA,1);
       isFixDof(isFreeDof) = false;
   end
else % Find free dof and eliminate isolated dof
    deg = sum(spones(A));  % degree
    isFreeDof = false(Ndof,1);
    isFreeDof(deg>1) = true;
    isFixDof = ~isFreeDof;
    isFixDof(deg == 0) = false;
end
if any(isFixDof) % a bigger matrix is given
    xD = zeros(Ndof,1);
    xD(isFixDof) = b(isFixDof)./diag(A(isFixDof,isFixDof));
    A = A(isFreeDof,isFreeDof);
end
if length(b) > sum(isFreeDof)
    b = b(isFreeDof);
end
if length(x0) > sum(isFreeDof)
    x0 = x0(isFreeDof);
    option.x0 = x0;
end
isFreeNode = isFreeDof(1:N); % default choice for P1

%% Hierarchical Structure of Mesh
%  hierarchical structure for linear element.
if dim == 2  % 2-D
    [HB, NL, level] = HBstructure(elem,N0);
end
if dim == 3  % 3-D
    if nargin > 4
        HBmesh = varargin{end}; % need HB for bisection refinement
        [HB, NL, level] = HBstructure3(elem,N0,HBmesh);
    else % no HBmesh is given. only work for the red uniform refinement
        [HB, NL, level] = HBstructure3(elem,N0);
    end
end

%% Transfer operators between multilevel meshes for P1 element
% standard prolongation and restriction operator for P1 element
[Pro,Res] = transferoperator(HB,NL,isFreeNode);
for j = 1:level-1
    Pro{j} = kron(speye(Nydof-1,Nydof-1),Pro{j}); % for each level in y direction
    Res{j+1} = Pro{j}';
end
clear HB

%% Matrices in each level
Ai = cell(level,1);
Ai{level} = A;
for j = level:-1:2
    Ai{j-1} = Res{j}*Ai{j}*Pro{j-1};           % Ac = Res*Af*Pro
    switch option.smoother
        case 'GS'
            Bi{j} = tril(Ai{j});        % Forward Gauss-Seidel   B = D+L
            BBi{j} = triu(Ai{j});       % Backward Gauss-Seidel BB = D+U
        case 'LINE'
            NxNy = size(Ai{j},1);
            Nx = NxNy/(Nydof-1);
            di = zeros(NxNy,4);
            di(:,1) = full(diag(Ai{j}))/2; % half of the main diagoal
            temp = full(diag(Ai{j},Nx)); % next vertex in the extend direction
            di(1:length(temp),2) = temp;
            temp = full(diag(Ai{j},Nx*(Ny-2))); %
            di(1:length(temp),3) = temp;
            temp = full(diag(Ai{j},Nx*(Ny-1))); % middle point in the extend direction
            di(1:length(temp),4) = temp;
            halfBi = spdiags(di,[0 -Nx -Nx*(Ny-2) -Nx*(Ny-1)],NxNy,NxNy);
            Bi{j} = halfBi + halfBi';
            L{j} = chol(Bi{j},'lower');
            R{j} = L{j}';
%             Bi{j} = spdiags(diag(Ai{j}),0,size(Ai{j},1),size(Ai{j},1));        %
%             BBi{j} = Bi{j};       % Jacobi iteration
    end
end

%% MG cycles
% initial set up
k = 1;
x = x0;
r = b - A*x;
nb = norm(b);
err = zeros(maxIt,2);
if nb > eps  % nb is non-zero
    err(1,:) = norm(r)/nb;
else
    err(1,:) = norm(r);
end
switch solver
    case 'VCYCLE'
        if printlevel >= 1
            fprintf('Multigrid Vcycle Iteration \n')
        end
        while (max(err(k,:)) > tol) && (k <= maxIt)
            k = k + 1;
            % Step 2: Compute Br by one Vcylce MG
            Br = vcycle(r);
            % Step 3: Correct the solution
            x = x + Br;
            % Step 1: Form residual r
            r = r - A*Br;
            err(k,1) = sqrt(abs(Br'*r/(x'*b))); % approximate relative error in energy norm
            err(k,2) = norm(r)/nb; % relative error of the residual in L2-norm
            if printlevel >= 2
                fprintf('#dof: %8.0u,  #nnz: %8.0u, MG Vcycle iter: %2.0u, err = %8.4e\n',...
                         Ndof, nnz(A), k-1, max(err(k,:)));
            end
        end
        err = err(1:k,:);
        itStep = k-1;
    case 'WCYCLE'
        if printlevel >= 1
            fprintf('Multigrid Wcycle Iteration \n')
        end
        while (max(err(k,:)) > tol) && (k <= maxIt)
            k = k + 1;
            % Step 2: Compute Br by one Vcylce MG
            Br = wcycle(r);
            % Step 3: Correct the solution
            x = x + Br;
            err(k,1) = sqrt(abs(Br'*r/(x'*b))); % approximate relative error in energy norm
            % Step 1: Form residual r
            r = r - A*Br;
            err(k,2) = norm(r)/nb; % relative error of the residual in L2-norm
            if printlevel >= 2
                fprintf('#dof: %8.0u,  #nnz: %8.0u, MG Wcycle iter: %2.0u, err = %8.4e\n',...
                         Ndof, nnz(A), k-1, max(err(k,:)));
            end
        end
        err = err(1:k,:);
        itStep = k-1;
end

%% Krylov space method
% set up preconditioner
switch preconditioner
    case 'V'
        prefunc = @vcycle;
        if printlevel >= 1
            fprintf('Multigrid V-cycle Preconditioner with ')
        end
    case 'W'
        prefunc = @wcycle;
        if printlevel >= 1
            fprintf('Multigrid W-cycle Preconditioner with ')
        end
end
switch solver
    case 'CG'
        if printlevel >= 1
            fprintf('Conjugate Gradient Method\n')
        end
        [x,flag,err,itStep] = pcg(A,b,tol,maxIt,prefunc,[],x0);
    case 'MINRES'
        if printlevel >= 1
            fprintf('Minimum Residual Method \n')
        end
        [x,flag,err,itStep] = minres(A,b,tol,maxIt,prefunc,[],x0);
    case 'GMRES'
        if printlevel >= 1
            fprintf('General Minimum Residual Method\n')
        end
        if isfield(option,'restart')
            restart = option.restart;
        else
            restart = min(N,10);
        end
        [x,flag,err,itStep] = gmres(A,b,restart,tol,maxIt,prefunc,[],x0);
        itStep = (itStep(1)-1)*restart + itStep(2);
end

%% Modify x to include fix dof
if any(isFixDof)
    xD(isFreeDof) = x;
    x = xD;
end

%% Output
if k > maxIt
    flag = 1;
else
    flag = 0;
end
time = toc;
if printlevel >= 2
    fprintf('#dof: %8.0u, level: %2.0u,   coarse grid %2.0u, #nnz: %8.0u\n',...
              Ndof, level, size(Ai{1},1), nnz(Ai{1}))
end
if printlevel >= 1
    fprintf('#dof: %8.0u,  #nnz: %8.0u, smoothing: %2.0u, iter: %2.0u,   err = %8.4e,   time = %4.2g s\n',...
                 Ndof, nnz(A), mu, itStep, max(err(end,:)), time)
end
if (flag == 1) && (printlevel>0)
   fprintf('NOTE: the iterative method does not converge! \n');
end
info = struct('solverTime',time,'itStep',itStep,'error',err,'flag',flag,'stopErr',max(err(end,:)));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% subfunctions vcycle, wcycle, fcycle, bpx
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Vcycle MG
    function Br = vcycle(r,J)        % solve equations Ae = r in each level
    if nargin<=1
        J = level;
    end
    ri = cell(J,1);            % record residual in each level
    ei = cell(J,1);            % record err in each level
    ri{J} = r;
    for i = J:-1:2
        ei{i} = linesmoother(ri{i},i);   % pre-smoothing
        for s = 1:mu-1           % extra mu-1 steps smoothing
            ei{i} = ei{i} + linesmoother(ri{i}-Ai{i}*ei{i},i);
        end
        ri{i-1} = Res{i}*(ri{i} - Ai{i}*ei{i});
    end
    if strcmp(coarsegridsolver,'direct')
        ei{1} = Ai{1}\ri{1}; % direct solver in the coarest level
    else                         % iterative solver in the coarest level
        D = spdiags(diag(Ai{1}),0,size(Ai{1},1),size(Ai{1},1));
        [ei{1},flag] = pcg(Ai{1},ri{1},1/size(Ai{1},1),1000,D);
    end
    for i = 2:J
        ei{i} = ei{i} + Pro{i-1}*ei{i-1};
        ei{i} = ei{i} + linesmoother(ri{i}-Ai{i}*ei{i},i);
        for s = 1:mu-1
            ei{i} = ei{i} + linesmoother(ri{i}-Ai{i}*ei{i},i); % post-smoothing
        end
    end
    Br = ei{J};
    end

%% Wcycle MG
    function e = wcycle(r,J)        % solve equations Ae = r in each level
    if nargin<=1
        J = level;
    end
    if J == 1
        e = Ai{J}\r;   % exact solver in the coaresest grid
        return
    end
    % fine grid pre-smoothing
    e = Bi{J}\r;        % pre-smoothing
    for s = 1:mu-1        % extra mu-1 steps smoothing
        e = e + Bi{J}\(r-Ai{J}*e);
    end
    % coarse grid correction twice
    rc = Res{J}*(r - Ai{J}*e);
    ec = wcycle(rc,J-1);
    ec = ec + wcycle(rc - Ai{J-1}*ec,J-1);
    e = e + Pro{J-1}*ec;
    % fine grid post-smoothing
    e = e + BBi{J}\(r-Ai{J}*e);
    for s = 1:mu-1
        e = e + BBi{J}\(r-Ai{J}*e); % post-smoothing
    end
    end

%% Line smoother
    function e = linesmoother(r,J)
%         NxNy = length(r);
%         Nx = NxNy/(Ny-1);
%         e = zeros(NxNy,1);
%         for vi = 1:Nx
%             linedof = vi + 0:Nx:NxNy-1;
%             e(linedof) = Ai{J}(linedof,linedof)\r(linedof);
%         end
%         e = Bi{J}\r;
        e = R{J}\(L{J}\r);
        e = 0.75*e;
    end
end


function [corrTime] = check_t(time)

% SYNTAX:
%   [corrTime] = check_t(time);
%
% INPUT:
%   time = GPS time
%
% OUTPUT:
%   corrTime = corrected GPS time
%
% DESCRIPTION:
%   Function accounting for beginning or end of week crossover. From the
%   Interface Specification document revision E (IS-GPS-200E), page 93.

%--- * --. --- --. .--. ... * ---------------------------------------------
%               ___ ___ ___
%     __ _ ___ / __| _ | __|
%    / _` / _ \ (_ |  _|__ \
%    \__, \___/\___|_| |___/
%    |___/                    v 1.0RC1
%
%--------------------------------------------------------------------------
%  Copyright (C) 2021 Geomatics Research & Development srl (GReD)
%  Written by:
%  Contributors:     ...
%  A list of all the historical goGPS contributors is in CREDITS.nfo
%--------------------------------------------------------------------------
%
%   This program is free software: you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation, either version 3 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You should have received a copy of the GNU General Public License
%   along with this program.  If not, see <http://www.gnu.org/licenses/>.
%
%--------------------------------------------------------------------------
% 01100111 01101111 01000111 01010000 01010011
%--------------------------------------------------------------------------

%----------------------------------------------------------------------------------------------
%                           goGPS v0.4.3
%
% Copyright (C) Kai Borre
% Kai Borre 04-01-96
%
% Adapted by Mirko Reguzzoni, Eugenio Realini, 2009
%----------------------------------------------------------------------------------------------

half_week = 302400;     % seconds

corrTime = time;
corrTime(time > half_week) =time(time > half_week) - 2*half_week;
corrTime(time < - half_week) =time(time < - half_week) + 2*half_week;
% if time > half_week
%     corrTime = time - 2*half_week;
% elseif time < -half_week
%     corrTime = time + 2*half_week;
% end


function test_bug2197

% MEM 1gb
% WALLTIME 00:10:00
% DEPENDENCY ft_selectdata

freq = [];
freq.labelcmb = {
  '1' '1'
  '1' '2'
  '1' '3'
  '1' '4'
  '1' '5'
  '1' '6'
  %  '2' '1'
  %  '2' '2'
  '2' '3'
  '2' '4'
  '2' '5'
  '2' '6'
  };
freq.cumtapcnt = ones(15,1);
freq.freq      = 1:7;
freq.crsspctrm = randn(15,10,7);
% freq.crsspctrmdimord = 'rpt_chancmb_freq'; % this is not needed

cfg = [];
cfg.avgoverrpt = 'yes';
output = ft_selectdata(cfg, freq);
assert(size(output.crsspctrm,1)==10)

cfg = [];
cfg.avgoverchancmb = 'yes';
output = ft_selectdata(cfg, freq);
assert(size(output.crsspctrm,2)==1)

cfg = [];
cfg.avgoverrpt = 'yes';
cfg.avgoverchancmb = 'yes';
output = ft_selectdata(cfg, freq);
assert(size(output.crsspctrm,1)==1)
assert(size(output.crsspctrm,2)==7) % frequencies

cfg = [];
cfg.avgoverrpt = 'yes';
cfg.avgoverchancmb = 'yes';
cfg.foilim = [3 5];
output = ft_selectdata(cfg, freq);
assert(size(output.crsspctrm,1)==1)
assert(size(output.crsspctrm,2)==3) % frequencies


function [cl,clpos,clneg,clrpos,clrneg] = cluster_sigregions(cl,pthr,varargin)
% [cl,clpos,clneg,clrpos,clrneg] = cluster_ttest(clusters,pthr,[behavioral regressor])
% tor wager  Oct 9, 2003
%
% does t-tests on cluster timeseries and all voxels
% which should contain group data (e.g., con* data)
%
% if optional behavioral regressor is entered,
% computes cluster extent nonparametric p-values, and reports
% extent npm p-values for intercept and behavioral reg.
%
% writes output to cluster_ttest_output.txt

fid = fopen('cluster_ttest_output.txt','a');

k=1;
if length(varargin) > 0, beh = varargin{1};,k=size(beh,2);,end

outstr1 = []; outstr2 = []; outstr3 = []; outstr4 = [];
try,outstr = sprintf('\n%s\n',[cl(1).title ' ' cl(1).imP(1,:)]);
catch, outstr = sprintf('\n%s\n',[cl(1).title ' ' cl(1).imnames(1,:)]);,
end
outstr = [outstr sprintf('\nCl.\tVoxels\tThreshold\tMask\tData\t\n')];
outstr1 = [outstr1 sprintf('\tx\ty\tz\tVoxels\tCluster corr. p.\tMax. t\tCorrected p\tDirection of effect\tr\n')];
outstr2 = outstr1; outstr3 = outstr1; outstr4 = outstr1;

for i = 1:length(cl)

% df = n - k    primary threshold
tthr1 = abs(tinv(pthr,size(cl(i).all_data,1) - k));

% ----------------------------------------
% * do nonparametric permutation
% ----------------------------------------
if ~isfield(cl(i),'npm_ttest'),cl(i).npm_ttest = [];,end
if isfield(cl(i).npm_ttest,'tmax') & isfield(cl(i).npm_ttest,'textmax')
    tthr = cl(i).npm_ttest.tthr ;
    rthr = cl(i).npm_ttest.rthr ;
    tnegthr = cl(i).npm_ttest.tnegthr ;
    rnegthr = cl(i).npm_ttest.rnegthr ;
    tmax = cl(i).npm_ttest.tmax ;
    tmin = cl(i).npm_ttest.tmin ;
    rmax = cl(i).npm_ttest.rmax ;
    rmin = cl(i).npm_ttest.rmin ;
    textmax = cl(i).npm_ttest.textmax ;
    rextmax = cl(i).npm_ttest.rextmax ;
else

[tthr,rthr,tnegthr,rnegthr,tmax,rmax,tmin,rmin,textmax,rextmax] = ...
    npm_ttest(cl(i).all_data,1000,beh,pthr,cl(i).XYZ);
close

cl(i).npm_ttest.tthr = tthr;
cl(i).npm_ttest.rthr = rthr;
cl(i).npm_ttest.tnegthr = tnegthr;
cl(i).npm_ttest.rnegthr = rnegthr;
cl(i).npm_ttest.tmax = tmax;
cl(i).npm_ttest.rmax = rmax;
cl(i).npm_ttest.textmax = textmax;
cl(i).npm_ttest.rextmax = rextmax;
cl(i).npm_ttest.tmin = tmin;
cl(i).npm_ttest.rmin = rmin;

end

%outstr = [outstr sprintf('%3.0f\t%3.0f\t%3.4f\t%s\t%s\t\n',i,cl(i).numVox,pthr,cl(i).P,cl(i).imP(1,:))];

% ----------------------------------------
% * get sig clusters
% ----------------------------------------

clpos(i).from_cluster = i;
clpos(i).M = cl(i).M;
clpos(i).voxSize = cl(i).voxSize;
clpos(i).threshold = tthr1;
clpos(i).title = 'Positive effects';

clrpos(i).from_cluster = i;
clrpos(i).M = cl(i).M;
clrpos(i).voxSize = cl(i).voxSize;
clrpos(i).threshold = tthr1;
clrpos(i).title = 'Positive correlations';

if isfield(cl(i).ttest,'t'), sig = cl(i).ttest.t > tthr1;,
else, warning(['No t field for cl(' num2str(i) ]), sig = [0;0];
end

if any(sig(1,:))
    clpos(i).XYZ = cl(i).XYZ(:,find(sig(1,:)));
    clpos(i).XYZmm = cl(i).XYZmm(:,find(sig(1,:)));
    clpos(i).Z = cl(i).Z(:,find(sig(1,:)));
    clpos(i).t = cl(i).ttest.t(:,find(sig(1,:)));
    gopos(i) = 1;

    % print table entry
    wcl = spm_clusters(clpos(i).XYZ);
    clpos(i).clusters = wcl;
    for j = 1:max(wcl)

        wh = find(wcl==j);

        % corrected p

        xyz = mean(clpos(i).XYZmm(:,wh),2)';
        if length(xyz) == 1, xyz = clpos(i).XYZmm(:,wh)';,end
        nv = length(wh);

        if length(wh)>1,max_t = max(clpos(i).t(:,wh)'); max_t = max_t(1);,
        else, max_t = clpos(i).t(1,wh);
        end

        clpos(i).center = xyz;

        extcor_p = 1 - (sum(textmax <= nv) ./ length(textmax));
        max_p = 1 - (sum(tmax <= max_t) ./ length(tmax));

        outstr1 = [outstr1 sprintf('%3.0f\t%3.0f\t%3.0f\t%3.0f\t%3.0f\t%3.4f\t%3.2f\t%3.4f\t+\n', ...
            clpos(i).from_cluster,xyz(1),xyz(2),xyz(3),nv,extcor_p,max_t,max_p)];
    end

else
    gopos(i) = 0;
end

if any(sig(2,:))
    clrpos(i).XYZ = cl(i).XYZ(:,find(sig(2,:)));
    clrpos(i).XYZmm = cl(i).XYZmm(:,find(sig(2,:)));
    clrpos(i).Z = cl(i).Z(:,find(sig(2,:)));
    clrpos(i).t = cl(i).ttest.t(:,find(sig(2,:)));
    gorpos(i) = 1;

    % print table entry
    wcl = spm_clusters(clrpos(i).XYZ);
    clrpos(i).clusters = wcl;
    for j = 1:max(wcl)

        wh = find(wcl==j);

        % corrected p

        xyz = mean(clrpos(i).XYZmm(:,wh),2)';
        if length(xyz) == 1, xyz = clrpos(i).XYZmm(:,wh)';,end
        nv = length(wh);

        tmp = cl(i).all_data(:,find(sig(2,:)));
        tmp = tmp(:,wh);
        tmp = corrcoef([tmp beh]);
        tmp = tmp(end,1:end-1);
        max_r = max(tmp);
        if max_r > .99, warning('problem?'),keyboard,end

        if length(wh)>1,max_t = max(clrpos(i).t(:,wh)'); max_t = max_t(2);,
        else, max_t = clrpos(i).t(2,wh);
        end
        clrpos(i).center = xyz;

        extcor_p = 1 - sum(rextmax <= nv) ./ length(rextmax);
        max_p = 1 - sum(rmax <= max_t) ./ length(rmax);

        outstr2 = [outstr2 sprintf('%3.0f\t%3.0f\t%3.0f\t%3.0f\t%3.0f\t%3.4f\t%3.2f\t%3.4f\t+\t%3.2f\n', ...
            clrpos(i).from_cluster,xyz(1),xyz(2),xyz(3),nv,extcor_p,max_t,max_p,max_r)];
    end

else
    gorpos(i) = 0;
end

% negative

clneg(i).from_cluster = i;
clneg(i).M = cl(i).M;
clneg(i).voxSize = cl(i).voxSize;
clneg(i).threshold = tthr1;
clneg(i).title = 'Negative effects';

clrneg(i).from_cluster = i;
clrneg(i).M = cl(i).M;
clrneg(i).voxSize = cl(i).voxSize;
clrneg(i).threshold = tthr1;
clrneg(i).title = 'Negative correlations';

if isfield(cl(i).ttest,'t'), sig = cl(i).ttest.t < -tthr1;,
else, warning(['No t field for cl(' num2str(i) ]), sig = [0;0];
end

if any(sig(1,:))
    clneg(i).XYZ = cl(i).XYZ(:,find(sig(1,:)));
    clneg(i).XYZmm = cl(i).XYZmm(:,find(sig(1,:)));
    clneg(i).Z = cl(i).Z(:,find(sig(1,:)));
    clneg(i).t = cl(i).ttest.t(:,find(sig(1,:)));
    goneg(i) = 1;

    % print table entry
    wcl = spm_clusters(clneg(i).XYZ);
    clneg(i).clusters = wcl;
    for j = 1:max(wcl)

        wh = find(wcl==j);

        % corrected p

        xyz = mean(clneg(i).XYZmm(:,wh),2)';
        if length(xyz) == 1, xyz = clpos(i).XYZmm(:,wh)';,end
        nv = length(wh);

        if length(wh)>1,max_t = min(clneg(i).t(:,wh)'); max_t = max_t(1);,
        else, max_t = clneg(i).t(1,wh);
        end

        clneg(i).center = xyz;

        extcor_p = 1 - sum(textmax <= nv) ./ length(textmax);
        max_p = 1 - sum(tmin >= max_t) ./ length(tmin);

        outstr3 = [outstr3 sprintf('%3.0f\t%3.0f\t%3.0f\t%3.0f\t%3.0f\t%3.4f\t%3.2f\t%3.4f\t-\n', ...
            clneg(i).from_cluster,xyz(1),xyz(2),xyz(3),nv,extcor_p,max_t,max_p)];
    end

else
    goneg(i) = 0;
end

if any(sig(2,:))
    clrneg(i).XYZ = cl(i).XYZ(:,find(sig(2,:)));
    clrneg(i).XYZmm = cl(i).XYZmm(:,find(sig(2,:)));
    clrneg(i).Z = cl(i).Z(:,find(sig(2,:)));
    clrneg(i).t = cl(i).ttest.t(:,find(sig(2,:)));
    gorneg(i) = 1;

    % print table entry
    wcl = spm_clusters(clrneg(i).XYZ);
    clrneg(i).clusters = wcl;
    for j = 1:max(wcl)

        wh = find(wcl==j);

        % corrected p

        xyz = mean(clrneg(i).XYZmm(:,wh),2)';
        if length(xyz) == 1, xyz = clrneg(i).XYZmm(:,wh)';,end
        nv = length(wh);

        if length(wh)>1,max_t = min(clrneg(i).t(:,wh)'); max_t = max_t(2);,
        else, max_t = clrneg(i).t(2,wh);
        end

        tmp = cl(i).all_data(:,find(sig(2,:)));
        tmp = tmp(:,wh);
        tmp = corrcoef([tmp beh]);
        tmp = tmp(end,1:end-1);
        max_r = min(tmp);
        if max_r > .99, warning('problem?'),keyboard,end

        clrneg(i).center = xyz;

        extcor_p = 1 - sum(rextmax <= nv) ./ length(rextmax);
        max_p = 1 - sum(rmin >= max_t) ./ length(rmin);

        outstr4 = [outstr4 sprintf('%3.0f\t%3.0f\t%3.0f\t%3.0f\t%3.0f\t%3.4f\t%3.2f\t%3.4f\t-\t%3.2f\t\n', ...
            clrneg(i).from_cluster,xyz(1),xyz(2),xyz(3),nv,extcor_p,max_t,max_p,max_r)];
    end

else
    gorneg(i) = 0;
end

end % loop through clusters

outstr = [outstr sprintf('\n')];
outstr1 = [outstr1 sprintf('\n')];
outstr2 = [outstr2 sprintf('\n')];
outstr3 = [outstr3 sprintf('\n')];
outstr4 = [outstr4 sprintf('\n')];

disp([outstr outstr1 outstr2 outstr3 outstr4])
outstr(outstr == '\') = '_';
fprintf(fid,[outstr outstr1 outstr2 outstr3 outstr4]);
fclose(fid);

% Make montage
gomontage = 0;

if gomontage
try

if ~isempty(clpos) & ~isempty(clneg)
    montage_clusters([],cl(unique(cat(2,[clpos.from_cluster clneg.from_cluster]))),clpos,clneg,{'k' 'r' 'b'},'nooverlap')
    %hh=get(gcf,'Children');
    %for i = 1:length(hh),axes(hh(i));, h = findobj(gca,'FaceColor',[0 0 0]);, set(h,'FaceAlpha',.5) ,end
elseif ~isempty(clpos)
    montage_clusters([],cl(cat(2,clpos.from_cluster)),clpos,{'k' 'r'},'nooverlap')
elseif ~isempty(clneg)
    montage_clusters([],cl,clneg,{'k' 'b'},'nooverlap')
else
    disp('No main contrast effects')
end

if ~isempty(clrpos) & ~isempty(clrneg)
    montage_clusters([],cl(unique(cat(2,[clrpos.from_cluster clrneg.from_cluster]))),clrpos,clrneg,{'k' 'r' 'b'},'nooverlap')
elseif ~isempty(clrpos)
    montage_clusters([],cl(cat(2,clrpos.from_cluster)),clrpos,{'k' 'r'},'nooverlap')
elseif ~isempty(clrneg)
    montage_clusters([],cl(cat(2,clrneg.from_cluster)),clrneg,{'k' 'b'},'nooverlap')
else
    disp('No correlation effects')
end

catch
    disp('error with montage')
end
end

try, clpos = redefine_clusters(clpos);,catch,end
try, clrpos = redefine_clusters(clrpos);,catch,end
try, clneg = redefine_clusters(clneg);,catch,end
try, clrneg = redefine_clusters(clrneg);,catch,end

return


function A11 = synA11Qmax(A00, sizeA11, cmin)
%-----------------------------------------------------------------------------
%
% For each point of colour 11 this function assigns the maximum value at the
% neighbouring gridpoints of colour 00.
%
% Design and implementation by:
% Dr. Paul M. de Zeeuw <Paul.de.Zeeuw@cwi.nl>  http://homepages.cwi.nl/~pauldz/
% Last Revision: December 12, 2001.
% (c) 1998-2002 Stichting CWI, Amsterdam
%-----------------------------------------------------------------------------
[n00, m00]=size(A00);
if nargin == 3
  o=[0 0];
  if ~all(size(o) == size(sizeA11))
    error(' synA11Qmax - unexpected dimensions of sizeA11 ')
  else
    clear o;
    n11=sizeA11(1);
    m11=sizeA11(2);
  end
elseif nargin == 2
  n11=n00-1;
  m11=m00-1;
else
  error(' synA11Qmax - number of arguments should be either 2 or 3 ')
end
%[n11, m11]=size(A11);
if m11 == m00-1
  if n11 == n00-1
    S = max(stripL(A00), stripR(A00));
    A11=max(stripD(S), stripU(S));
  elseif n11 == n00
    S = max(stripL(A00), stripR(A00));
    A11=max(S, stripU(extD(S, cmin)));
  else
    disp([' size A00 = ' int2str(size(A00)) ' size A11 = ' int2str([n11 m11])]);
    error(' synA11Qmax - A00 and target A11 do not match ');
  end
elseif m11 == m00
  if n11 == n00-1
    S = max(stripL(extR(A00, cmin)), A00);
    A11=max(stripD(S), stripU(S));
  elseif n11 == n00
    S = max(stripL(extR(A00, cmin)), A00);
    A11=max(S, stripU(extD(S, cmin)));
  else
    disp([' size A00 = ' int2str(size(A00)) ' size A11 = ' int2str([n11 m11])]);
    error(' synA11Qmax - A00 and target A11 do not match ');
  end
else
  disp([' size A00 = ' int2str(size(A00)) ' size A11 = ' int2str([n11 m11])]);
  error(' synA11Qmax - A00 and target A11 do not match ');
end
%------------------------------------------------------------------------------


function t = uminus(t)
%UMINUS Unary minus for ktensor.
%
%   See also KTENSOR.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2012) Sandia Corporation. Under the terms of Contract
% DE-AC04-94AL85000, there is a non-exclusive license for use of this
% work by or on behalf of the U.S. Government. Export of this data may
% require a license from the United States Government.
% The full license terms can be found in the file LICENSE.txt

t.lambda = -t.lambda;


function out=mp_euler(precision)

if nargin==0
 out=mpEuler(mp(0));
else
 out=mpEuler(mp(precision));
end


tic
nt0 = ops.nt0;

if ~isempty(ops.chanMap)
    load(ops.chanMap);
    chanMapConn = chanMap(connected>1e-6);
else
    chanMapConn = 1:ops.Nchan;
end
batch_path = fullfile(root, 'batches');
if ~exist(batch_path, 'dir')
    mkdir(batch_path);
end
NchanTOT = ops.NchanTOT;

d = dir(fullfile(root, fname));
ops.sampsToRead = floor(d.bytes/NchanTOT/2);

NT          = 128*1024+ ops.ntbuff;
NTbuff      = NT + 4*ops.ntbuff;
Nbatch      = ceil(d.bytes/2/NchanTOT /(NT-ops.ntbuff));

% load data into patches, filter, compute covariance, write back to
% disk

fprintf('Time %3.0fs. Loading raw data... \n', toc);
fid = fopen(fullfile(root, fname), 'r');
ibatch = 0;
Nchan = ops.Nchan;

Nchans = ops.Nchan;
ts = [1:1:nt0]';

clear stimes
% for iNN = 1:size(rez.W,2)
%     stimes{iNN} = rez.st3pos(rez.st3pos(:,2)==iNN,1);
% end
stimes = gtimes;

Wraw = zeros(nt0, Nchans, numel(stimes));

while 1
    ibatch = ibatch + 1;

    offset = max(0, 2*NchanTOT*((NT - ops.ntbuff) * (ibatch-1) - 2*ops.ntbuff));
    if ibatch==1
        ioffset = 0;
    else
        ioffset = ops.ntbuff;
    end
    fseek(fid, offset, 'bof');
    buff = fread(fid, [NchanTOT NTbuff], '*int16');

    if isempty(buff)
        break;
    end
    nsampcurr = size(buff,2);
    if nsampcurr<NTbuff
        buff(:, nsampcurr+1:NTbuff) = repmat(buff(:,nsampcurr), 1, NTbuff-nsampcurr);
    end

    offset = (NT-ops.ntbuff)*(ibatch-1)-64 - 40;

    buff = buff(chanMapConn,:)';
    %
    for iNN = 1:numel(stimes)
        st = stimes{iNN} - offset;
        st(st<0) = [];
        st(st>NT-ops.ntbuff) = [];

        if ~isempty(st)
            inds = repmat(st', nt0, 1) + repmat(ts, 1, numel(st));

            Wraw(:,:,iNN) = Wraw(:,:,iNN) + ...
                squeeze(sum(reshape(buff(inds, :), nt0, numel(st), Nchans),2));
        end
    end

end
fclose(fid);

for iNN = 1:numel(stimes)
     Wraw(:,:,iNN) = Wraw(:,:,iNN)/numel(stimes{iNN});
end
fprintf('Time %3.2f. Mean waveforms computed... \n', toc);


function bc_start(mCatalog, hFigure, bMap, vCoastline, vFaults, rContainer, sName)
    % Starts the probabilistic forecast testing.
    %
    % bc_start(mCatalog, hFigure, bMap, rContainer)
    % ------------------------------------------------------
    % Starts the probabilistic forecast testing. The function invokes the parameter dialog, calls the
    %   calculation function and invokes the dialog for displaying the results
    %
    % Input parameters:
    %   mCatalog      Earthquake catalog to use for the testing
    %   hFigure       Handle of figure where the user should select the grid (i.e. the seismicity map)
    %   bMap          Map/cross-section switch. If the testing is carried out on a map set bMap = true,
    %                 on a cross-section set bMap = false
    %   rContainer    Just a container (structure proposed) to store any variables that should be available in the
    %                 probabilistic forecast testing code
    %
    % Danijel Schorlemmer
    % June 26, 2003

    report_this_filefun();

    % Launch GUI
    hMenuFig = bc_options(bMap);

    % Set up parameter struct and store input parameters
    params.mCatalog = mCatalog;
    params.sCatalogName = sName;
    params.bMap = bMap;
    params.vFaults = vFaults;
    params.vCoastline = vCoastline;
    params.rContainer = rContainer;

    % Analyze Output
    if ~ishandle(hMenuFig)
        answer = 0;
    else
        handles = guidata(hMenuFig);
        answer = handles.answer;
        % OK pressed
        if answer == 1
            % Get parameter values from the gui
            if get(handles.radNumber, 'Value') == 1
                rOptions.nGriddingMode = 0;
                rOptions.nNumberEvents = str2double(get(handles.txtNumber, 'String'));
                rOptions.fRadius = 0;
                rOptions.fSizeRectX = 0;
                rOptions.fSizeRectY = 0;
                rOptions.nMinimumNumber = 0;
                rOptions.fMaximumRadius = str2double(get(handles.txtMaximumRadius, 'String'));
            elseif get(handles.radRadius, 'Value') == 1
                rOptions.nGriddingMode = 1;
                rOptions.nNumberEvents = 0;
                rOptions.fRadius = str2double(get(handles.txtRadius, 'String'));
                rOptions.fSizeRectX = 0;
                rOptions.fSizeRectY = 0;
                rOptions.nMinimumNumber = str2double(get(handles.txtMinimumNumber, 'String'));
                rOptions.fMaximumRadius = 0;
            else % rectangle
                rOptions.nGriddingMode = 2;
                rOptions.nNumberEvents = 0;
                rOptions.fRadius = 0;
                rOptions.fSizeRectX = str2double(get(handles.txtSizeRectX, 'String'));
                rOptions.fSizeRectY = str2double(get(handles.txtSizeRectY, 'String'));
                rOptions.nMinimumNumber = str2double(get(handles.txtMinimumNumber, 'String'));
                rOptions.fMaximumRadius = 0;
            end
            rOptions.nCalculateMC = get(handles.cboCalculateMC, 'Value');
            rOptions.bConstrainMc = get(handles.chkConstrainMc, 'Value');
            rOptions.fMcMin = str2double(get(handles.txtMcMin, 'String'));
            rOptions.fMcMax = str2double(get(handles.txtMcMax, 'String'));
            if get(handles.cboBinning, 'Value') == 1
                rOptions.fBinning = 0.1;
            else
                rOptions.fBinning = 0.01;
            end

            params.rOptions = rOptions;

            % Options section
            params.bGridEntireArea = get(handles.chkGridEntireArea, 'Value');
            params.fSpacingX = str2double(get(handles.txtSpacingX, 'String'));
            params.fSpacingY = str2double(get(handles.txtSpacingY, 'String'));
            params.bUtsuTest = get(handles.chkUtsuTest, 'Value');
            params.fGamma = str2double(get(handles.txtGamma, 'String'));
            bSaveParameter = get(handles.chkSaveParameter, 'Value');
            if bSaveParameter
                sSaveParameter = get(handles.lblSaveParameter, 'String');
            end
            params.sComment = 'BeCubed';

            % Remove figure from memory
            delete(hMenuFig);

            % Select grid
            [params.mPolygon, params.vX, params.vY, params.vUsedNodes] = ex_selectgrid(hFigure, params.fSpacingX, params.fSpacingY, params.bGridEntireArea);

            % Validate polygonsize
            if length(params.vX) < 4  ||  length(params.vY) < 4
                errordlg('Selection is too small. Please select a larger polygon.');
                return;
            end

            % Create Indices to catalog
            params.rOptions.caNodeIndices = ex_CreateIndexCatalog(params.mCatalog, params.mPolygon, params.bMap, ...
                params.rOptions.nGriddingMode, params.rOptions.nNumberEvents, params.rOptions.fRadius, ...
                params.rOptions.fSizeRectX, params.rOptions.fSizeRectY);

            if bSaveParameter
                % Save parameters
                save(sSaveParameter, 'params');
            else
                % Perform the calculation
                [params] = bc_calc(params);
                % Display the results
                gui_result(params);
            end
        else
            delete(hMenuFig);
        end
    end
end


function line=plotLineROI(view, smoothStep, flip, titlename, plotFlag)
% plotLineROI - plot current map along a line ROI
%
% line=plotLineROI(view, smoothStep, flip, titlename, plotFlag);
%
% Arguments:
%  view : mrVista view struct
%  smoothStep : averaging steps across neighboring vertices [default=0]
%  flip       : flip line [default=false]
%  titlename  : title for plot
%
% Outputs:
%  line.x     : distance across cortical surface
%  line.y     : values in current view
%
% 2007/09 SOD: wrote it.
if ~exist('view','var') || isempty(view),
    view = getSelectedGray;
end
if ~exist('smoothStep','var') || isempty(smoothStep),
    smoothStep = 0;
else
    if smoothStep==-1, % aks subject
        ttltxt = sprintf('Enter number of smoothing steps [0 = no smoothing]');
        smoothStep = inputdlg('Number larger than 0, recommended range [0-5]:',ttltxt,1,{'0'});
        smoothStep = str2double(smoothStep{1});
        if isempty(smoothStep), smoothStep = 0; end
   end
end
if ~strcmp(view.viewType,'Gray'),
    error('This function is only defined for the Gray view');
end
if ~exist('flip','var') || isempty(flip),
    flip = false;
end
if ~exist('titlename','var') || isempty(titlename),
   titlename = [];
end
if ~exist('plotFlag','var') || isempty(plotFlag),
    plotFlag = 1;
end

mrGlobals;

% get ROI coords
roi = view.ROIs(view.selectedROI);

% get dimensions
mmPerPix = readVolAnatHeader(vANATOMYPATH);

% get all gray coords, nodes and edges
%coords  = double(viewGet(view,'coords'));
nodes   = double(view.nodes);
edges   = double(view.edges);
numNeighbors = double(view.nodes(4,:));
edgeOffsets  = double(view.nodes(5,:));

% Get nearest gray node
allNodeIndices = zeros(1,size(roi.coords,2));
for ii=1:size(roi.coords,2)
    grayNode = find(nodes(2,:) == roi.coords(1,ii) & ...
                    nodes(1,:) == roi.coords(2,ii) & ...
                    nodes(3,:) == roi.coords(3,ii));

    % Catch errors.
    if(isempty(grayNode))
        error('No gray nodes were found!');
    end
    if(length(grayNode)>1)
        fprintf('[%s]: WARNING- coord %d - more than one grayNode found!\n',mfilename,ii);
        grayNode = grayNode(1);
    end
    allNodeIndices(ii) = grayNode;
end

% HACK: find starting point:
% Define as the point that has the largest distance to
% one other point in the line with the fewest direct neighbors.
% This will in most cases be the end or the beginning.
allDist = zeros(numel(allNodeIndices));
for n=1:numel(allNodeIndices),
    tmp = mrManDist(nodes, edges, allNodeIndices(n), mmPerPix, -1, 0);
    allDist(:,n)    = tmp(allNodeIndices);
end

%figure;imagesc(allDist)

% nodes distances
distNodes   = zeros(numel(allNodeIndices),1);
for n=1:numel(distNodes)-1
    distNodes(n+1,1) = allDist(n,n+1);
end
distNodes =cumsum(abs(distNodes));

% get current map
curMap =  double(view.(view.ui.displayMode){view.curScan});

% smooth
if smoothStep,
    numNeighbors = numNeighbors(:);
    if ~strcmpi('ph',view.ui.displayMode),
        for n=1:smoothStep,
            curMap = sumOfNeighbors(curMap,edges,edgeOffsets,numNeighbors)./(numNeighbors+1);
        end
    else
        % phase data, so go complex, smooth and go back
        curMap = -exp(i*curMap).*double(view.co{view.curScan});
        cm_r   = real(curMap);
        cm_i   = imag(curMap);
        for n=1:smoothStep,
            cm_r = sumOfNeighbors(cm_r,edges,edgeOffsets,numNeighbors)./(numNeighbors+1);
            cm_i = sumOfNeighbors(cm_i,edges,edgeOffsets,numNeighbors)./(numNeighbors+1);
        end
        curMap = angle(cm_r+cm_i*i)+pi;
    end;
end

%%%% PLOT CODE BELOW

% line data
line.y   = curMap(allNodeIndices);
line.x   = distNodes;
line.y = line.y(:);
line.x = line.x(:);
if flip,
    line.x   = abs(line.x-max(line.x));
end

% ras 05/2008: if the user is plotting phase data, and if there are
% retinotopy params set (e.g. for mapping polar angle or eccentricity),
% auto-convert the phase values to the appropriate parameter
if strcmp(view.ui.displayMode, 'ph')
	rparams = retinoGetParams(view);
	if ~isempty(rparams)  % these parameters have been set
		if isequal(lower(rparams.type), 'polar_angle')
			% map from phase to polar angle
			line.y = polarAngle(line.y, rparams);
		else
			% assume eccentricity: map to eccentricity
			line.y = eccentricity(line.y, rparams);
		end

		% temporarily set the display mode to map, and the map name and units
		% to the relevant values (this should not propagate to the global view
		% variable)
		view.ui.displayMode = 'map';
		view.mapName = rparams.type;
		view.mapUnits = 'degrees';
	end
end

% Plot if requested
if plotFlag==1
    if strcmp(view.ui.displayMode,'ph')
        if (max(line.y)-min(line.y))>6
            % line data
            line.y   = pi-line.y;
            %line.coords = coords(:,sampleNodes);
            %line.index  = sampleNodes;
            % plot
            figure;
            hold on;
            plot(line.x,mod(line.y,2*pi)-pi,'ko-');
            plot([0 ceil(max(line.x)/10)*10],[0 0],'k');

            ylim([-pi pi])
        else
            line.y   = line.y-pi;
            % plot
            newGraphWin;
            hold on;
            plot(line.x,line.y,'ko-');
            plot([0 ceil(max(line.x)/10)*10],[0 0],'k');
            ylim([-pi pi])
        end
    else
        newGraphWin;
        hold on;
        plot(line.x,line.y,'ko-');
    end
    if ~isempty(titlename),
        title(titlename);
    end

    if isequal(view.ui.displayMode, 'map')
        ylabelText = sprintf('%s (%s)', view.mapName, view.mapUnits);
    else
        ylabelText = view.ui.displayMode;
    end
    ylabel(ylabelText, 'FontSize', 14, 'Interpreter', 'none');
    xlabel('distance (mm)', 'FontSize', 14, 'Interpreter', 'none');

    % kalanit wanted to add this -- don't blame me!
    set(gcf, 'Color', 'w');

    % add a button to flip the line along the X axis, in case the hack
    % didn't correctly identify the start and end points
    cb = ['tmp = get(gca, ''Children''); ' ...
          'set(tmp(end), ''XData'', fliplr(get(tmp(end), ''XData''))); ' ...
          'clear tmp '];
    uicontrol('Style', 'pushbutton', 'Units', 'norm', ...
              'Position', [.7 .02 .1 .05], 'String', 'Flip L/R', ...
              'Callback', cb);
end

return


function [val] = optGeneFitness(rxn_vector_matrix, model, targetRxn, rxnListInput, isGeneList)
% The fitness function
%
% USAGE:
%
%    [val] = optGeneFitness(rxn_vector_matrix, model, targetRxn, rxnListInput, isGeneList)
%
% INPUTS:
%    rxn_vector_matrix:    reactions vectors in a matrix
%    model:                model structure
%    targetRxn:            target reactions
%    rxnListInput:         list of reactions
%    isGeneList:           bolean checking if it is a gene list
%
% OUTPUT:
%    val:                  fitness value

global MaxKnockOuts
%size(rxn_vector_matrix)

popsize = size(rxn_vector_matrix,1);
val = zeros(1,popsize);

%rxnGeneMat is a required field for this function if rxnList is a gene List, so if it does not exist,
%build it.
if isGeneList && ~isfield(model,'rxnGeneMat')
    model = buildRxnGeneMat(model);
end

for i = 1:popsize
    rxn_vector = rxn_vector_matrix(i,:);
    rxnList = rxnListInput(logical(rxn_vector));

    %see if we've done this before
    val_temp = memoize(rxn_vector);
    if ~ isempty(val_temp)
        val(i) = val_temp;
        continue;
    end

    % check to see if mutations is above the max number allowed
    nummutations = sum(rxn_vector);
    if nummutations > MaxKnockOuts
        continue;
    end

	% generate knockout.
    if isGeneList
        modelKO = deleteModelGenes(model, rxnList);
    else % is reaction list
        [isValidRxn,removeInd] = ismember(rxnList,model.rxns);
        removeInd = removeInd(isValidRxn);
        modelKO = model;
        modelKO.ub(removeInd) = 0;
        modelKO.lb(removeInd) = 0;
    end

    % find growthrate;
%     slnKO = optimizeCbModel(modelKO);
%     growthrate1 = slnKO.f; %max growth rate.
    if exist('LPBasis', 'var')
        modelKO.LPBasis = LPBasis;
    end

    [slnKO, LPOUT] = solveCobraLPCPLEX(modelKO, 0,1);
    LPBasis = LPOUT.LPBasis;
    growthrate = slnKO.obj;

    % check to ensure that GR is above a certain value
    if growthrate < .10
        continue;
    end

%    display('second optimization');
    % find the lowesest possible production rate (a hopefully high number)
    % at the max growth rate minus some set factor gamma (a growth rate slightly
    % smaller than the max). A positive value will eliminate solutions where the
    % production envelope has a vertical line at the max GR, a "non-unique"
    % solution. Set value to zero if "non-unique" solutions are not an issue.
    gamma = 0.01; % proportional to Grwoth Rate (hr-1), a value around 0.5 max.

    %find indicies of important vectors
    indBOF = find(modelKO.c);
    indTar = findRxnIDs(modelKO, targetRxn);
    % generate a model with a fixed max KO growth rate
    modelKOsetGR = modelKO;
    modelKOsetGR.lb(indBOF) = growthrate - gamma; % this growth rate is required as lb.
    modelKOsetGR.c = zeros(size(modelKO.c));
    modelKOsetGR.c(indTar) = -1; % minimize for this variable b/c we want to look at the very minimum production.

    % find the minimum production rate for the targeted reaction.

%     slnKOsetGR = optimizeCbModel(modelKOsetGR);
%     minProdAtSetGR1 = -slnKOsetGR.f;  % This should be a negative value b/c of the minimization setup, so -1 is necessary.

    if exist('LPBasis2', 'var')
        modelKOsetGR.LPBasis = LPBasis2;
    end

    [slnKOsetGR, LPOUT2] = solveCobraLPCPLEX(modelKOsetGR, 0,1);
    LPBasis2 = LPOUT2.LPBasis;
    minProdAtSetGR = -slnKOsetGR.obj;

    % objective function for optGene algorithm = val (needs to be a negative value, since it is
    % a minimization)
    val(i) = -minProdAtSetGR;
    % penalty for a greater number of mutations
    % val(i) = -minProdAtSetGR * (.98^nummutations);
    % select best substrate-specific productivity
    % val(i) = -minProdAtSetGR * (.98^nummutations) * growthrate;

    % check to prevent very small values from being considerered improvments
    if val(i) > -1e-3
        val(i) = 0;
    end

    memoize(rxn_vector, val(i));
end

return;

%% Memoize
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% MEMOIZE %%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% internal function to speed things up.

function [value] =  memoize(gene_vector, value)
global HTABLE
hashkey = num2str(gene_vector);
hashkey = strrep(hashkey,' ',''); % cut out white space from string (more space efficient).

if nargin == 1
    value = HTABLE.get(hashkey);
    return;
else
    if HTABLE.size() > 10000
        HTABLE = java.util.Hashtable;  %reset the hashtable if more than 10,000 entries.
    end
    HTABLE.put(hashkey, value);
    value = [];
    return;
end
return