% fig2: anat averages from paired regressors: sensory/motor correlations
% plots a pair of regressors in a graded double colormap, saves as tiff
% stacks, and also saves anat average plot as tiff file.
% (compare to fig2A_correlation_1reg_with_hist for more details)

clear all; close all; clc

outputDir = GetOutputDataDir;

%% Init load
hfig = figure;
InitializeAppData(hfig);
ResetDisplayParams(hfig);

%% set params
thres_reg_const = 0.5;
% M_reg_thres = {0.5,0.5,0.5};

isKeepTopPrct = 0; % init, can override
isMotorseed = 0; % init, can override

for setflag = 9
    % reset
    ResetDisplayParams(hfig);

    switch setflag
        case 1 % Phototaxis
            %             stimrange = 1;
            M_stimrange = GetStimRange('P');
            M_regtypeflag = [1,1,2]; % 0 for VAR, 1 for stim and 2 for motor
            M_reg_name = {'PT','HalfField','PT_SwimLR'};
            M_reg_range = {[3,2],[5,6],[1,3]};
            M_fishrange = {[1:18],[1:7],[1:3,5:18]};

        case 2 % OMR
            %             stimrange = 2;
            M_stimrange = GetStimRange('O');
            M_regtypeflag = [1,1,2]; % 1 for stim and 2 for motor
            M_reg_name = {'OMR_FwBw','OMR_LR','OMR_SwimLR'};
            M_reg_range =  {[7,6],[9,8],[1,3]};
            M_fishrange = {[8:18],[8:18],[8:18]};

        case 3 % Looming
            %             stimrange = 5;
            M_stimrange = GetStimRange('L');
            M_regtypeflag = [1,2]; % 1 for stim and 2 for motor
            M_reg_name = {'Loom_LR','Loom_SwimLR'};
            M_reg_range =  {[11,12],[1,3]};
            M_fishrange = {[9:15,17:18],[9:15,17:18]};

        case 4 % Dark Flash (black-white)
            %             stimrange = 3;
            M_stimrange = GetStimRange('D');
            M_regtypeflag = [1,2]; % 1 for stim and 2 for motor
            M_reg_name = {'DF_BW','DF_SwimLR'};
            M_reg_range =  {[1,4],[1,3]};
            M_fishrange = {[1:5,12:15,17:18],[12:15,17:18]}; % up till 7/10
%             M_fishrange = {[12:15,17:18],[12:15,17:18]}; % up till 7/10

%             % from VAR:

        case 5 % ABN
            M_regtypeflag = [0];
            M_stimrange = GetStimRange();%('2');
%             M_reg_name = {'ABN_top1%_defstimrange'};
            M_reg_name = {'ABN_reg0.5_defstimrange'};
            M_clus_range = {[12,1]};
            range = GetFishRange('e');%[1:8,11,12,14:17]
            M_fishrange = {range};%{[1:12,14:18]};

%             isKeepTopPrct = 1;
%             prct_const = 1;

        case 6 % Fw
            M_regtypeflag = [0];
            M_stimrange = GetStimRange();%('2');
            M_reg_name = {'Fw_seed_reg2%_defS'};
%             M_reg_name = {'Fw_reg0.5_defS'};
            M_clus_range = {[11,4]};
            M_fishrange = {[1:3,5:18]};

            isKeepTopPrct = 1;
            prct_const = 2;

        case 7 % HBO 4 stripes
            M_regtypeflag = [0,0];
            M_stimrange = GetStimRange();%('2');
            M_reg_name = {'HBO-L2_reg1%_tRes_defS','HBO-R2_reg1%_tRes_defS'};
            M_clus_range = {[10,2],[10,3]};
            M_fishrange = {[1:3,5:18],[1:3,5:18]};

            isKeepTopPrct = 1;
            prct_const = 1;
            setappdata(hfig,'isTrialRes',1);

        case 8 % HBO 2 halves
            M_regtypeflag = [0,0];
            M_stimrange = GetStimRange();%('2');
            M_reg_name = {'HBO2_reg1%_tRes_defS'};
            M_clus_range = {[10,5]};
            M_fishrange = {[1:3,5:18]};

            isKeepTopPrct = 1;
            prct_const = 1;
            setappdata(hfig,'isTrialRes',1);

        case 9 % spontaneous
            M_stimrange = GetStimRange('S'); % spontaneous
            M_regtypeflag = [2]; % 1 for stim and 2 for motor
            M_reg_name = {'spt_SwimLR_notmotorseed_top2%'};
            M_reg_range =  {[1,3]}; % {[1,2]} for ismotorseed = 1
            M_fishrange = {[8:15,17:18]};

            isMotorseed = 0; % 1
            isKeepTopPrct = 1;
            prct_const = 2;
    end

    n_reg = length(M_reg_name);
    M_fishrange_im = M_fishrange;

    range = 1:18; % init,M_fishrange below specifies actual range #oldcode
    IM_full = cell(n_reg,18);

    %%

%     [M_fishrange_im,fishrange_load] = CheckIfLoadFish(M_fishrange,M_ClusterIDs,M_stimrange);
% [cIX_load,gIX_load,M,stim,behavior,M_0] = LoadSingleFishDefault(i_fish,hfig,M_ClusterIDs{i_set},M_stimrange{i_set});
    for i_fish = range
        if ismember(i_fish,cell2mat(M_fishrange))
            ClusterIDs = [1,1];%GetClusterIDs('all');
            stimrange = M_stimrange{i_fish};
            % load fish data
            if isempty(stimrange)
                [cIX_load,gIX_load,M,stim,behavior,M_0] = LoadSingleFishDefault(i_fish,hfig,ClusterIDs);
            else
                [cIX_load,gIX_load,M,stim,behavior,M_0] = LoadSingleFishDefault(i_fish,hfig,ClusterIDs,stimrange);
            end
        end

        %% Load stim/motor
        for i_set = 1:n_reg

            if ~ismember(i_fish,M_fishrange{i_set})
                continue;
            end

            reg_thres = thres_reg_const; %M_reg_thres{i_set};

            %% Get Regressors
            if M_regtypeflag(i_set)==0
                ClusterIDs = M_clus_range{i_set};%[12,1];% GetClusterIDs('all');
                [cIX,gIX] = LoadCluster_Direct(i_fish,ClusterIDs(1),ClusterIDs(2));
                M = UpdateIndices_Manual(hfig,cIX,gIX);
                Reg = FindClustermeans(gIX,M);

            elseif M_regtypeflag(i_set)==1
                fishset = getappdata(hfig,'fishset');
                [~,names,regressors] = GetStimRegressor(stim,fishset,i_fish);

                reg_range = M_reg_range{i_set}; % left/right pair
                Reg = regressors(reg_range,:);

            elseif M_regtypeflag(i_set)==2
%                 isMotorseed = 0;
                setappdata(hfig,'isMotorseed',isMotorseed);
                [~,~,behavior] = UpdateTimeIndex(hfig);
                [~,names,regressors] = GetMotorRegressor(behavior,i_fish);

                reg_range = M_reg_range{i_set}; % left/right pair
                Reg = regressors(reg_range,:);
            end

            %% Regression
            % code adapted from 'best regressor regression' code 'AllRegsRegression'

            if isempty(Reg)
                M_fishrange_im{i_set} = setdiff(M_fishrange_im{i_set} ,i_fish);
                continue;
            end

            Corr = corr(Reg',M_0');

            if isKeepTopPrct
                % keep best regression only
                [Corr_rows,corr_max] = ConvertCorrToBestRegRows(Corr);

                % top x percentile
                nCells_total = size(M_0,1);
%                 prct_const = 1;
                [CIX,RegThres] = ChooseTopPercentOfFish(nCells_total,prct_const,Corr_rows);

                if length(CIX)==1
                    cIX = CIX{1};
                    % get map color
                    reg_thres = 0.25;
                    gIX = MapXto1Dcolormap(corr_max(cIX),[reg_thres,1],64);
                else
                    cIX1 = CIX{1};
                    cIX2 = CIX{2};

                    % get map color
                    clrIX1 = MapXto1Dcolormap(corr_max(cIX1),[reg_thres,1],64);
                    clrIX2 = MapXto1Dcolormap(corr_max(cIX2),[reg_thres,1],64);
                    %     clrIX1 = MapXto1Dcolormap(corr_max(cIX1),[reg_thres1,1],64);
                    %     clrIX2 = MapXto1Dcolormap(corr_max(cIX2),[reg_thres2,1],64);

                    cIX = [cIX1;cIX2];
                    %     if isempty(cIX)
                    %         M_fishrange_im{i_set} = setdiff(M_fishrange_im{i_set} ,i_fish); %#ok<SAGROW>
                    %         continue;
                    %     end

                    clrIX = [clrIX1;clrIX2];
                    gIX_offset = [ones(size(cIX1));2*ones(size(cIX2))];
                    gIX = clrIX+(gIX_offset-1)*64;
                    %     gIX = [clrIX1;64+clrIX2];
                    numK = length(unique(gIX));
                end

            else
                %%
                [corr_max,IX_regtype] = max(Corr,[],1);
                cIX = find(corr_max>reg_thres)';
                gIX_offset = IX_regtype(cIX)';
                clrIX = MapXto1Dcolormap(corr_max(cIX),[reg_thres,1],64);

                if isempty(cIX)
                    M_fishrange_im{i_set} = setdiff(M_fishrange_im{i_set} ,i_fish);
                    continue;
                end

                gIX = clrIX+(gIX_offset-1)*64;
                numK = length(unique(gIX));
            end

            %% make double colormap
            clr1 = [1,0,0];
            clr1_ = [0.7,0.5,0.5];
            clr2 = [0,1,1];
            clr2_ = [0.5,0.7,0.7];
            numC = 64;
            clrmap1 = Make1DColormap([clr1_;clr1],numC);
            clrmap2 = Make1DColormap([clr2_;clr2],numC);
            clrmap = [clrmap1;clrmap2];

            %% make figure
            I = LoadCurrentFishForAnatPlot(hfig,cIX,gIX,clrmap);
            [h,im_full] = DrawCellsOnAnat(I);

            %         % add 2 colorbars
            % %         AddColorbarToAnat(clrmap,cmin,cmax)
            % %         colormap(clrmap1);
            % %         caxis([reg_thres,1])
            % %         colorbar('Location','manual','Position',[0.8,0.7,0.05,0.15],'Units','normalized')
            %         ax = axes('Position',[0.75,0.8,0.05,0.15],'Units','normalized');
            %         DrawCustomColorbar(clrmap1,[reg_thres,1],2,ax);
            %
            %         ax = axes('Position',[0.9,0.8,0.05,0.15],'Units','normalized');
            %         DrawCustomColorbar(clrmap2,[reg_thres,1],2,ax);
            %
            %% save figure
            close(h);
            IM_full{i_set,i_fish} = im_full;

        end
    end

    %% save as tiff stack
    for i_set = 1:n_reg
        range_im = M_fishrange_im{i_set};
        tiffdir = fullfile(outputDir,[M_reg_name{i_set},'_allfish.tiff']);
        IM = IM_full(i_set,range_im);

        SaveImToTiffStack(IM,tiffdir);
    end

    %% [for later] plot from tiff stack
    isPlotfromtiffstack = 0;

    if isPlotfromtiffstack
        IM_full = cell(n_reg,18);
        for i_set = 1:n_reg
            %% get tiff-stack path
            tiffdir = fullfile(outputDir,[M_reg_name{i_set},'_allfish.tiff']);

            %% load
            range_load = 1:17;
            for i_fish = range_load
                im = double(imread(tiffdir,i_fish))./255;
                IM_full{i_set,i_fish} = im;
%                 IM_full{i_set,i_fish} = im(317:1236,1:621,:);
            end
        end
    end

    %% make average plots
    % M_k_scale = {1,1.5,1};
    % M_k_contrast = {1.2,1.5,1.2};

    for i_set = 1:n_reg
        range_im = M_fishrange_im{i_set};%[1:3,5:7];%[1:3,5:18];
        cellarray = IM_full(i_set,range_im);

        % adjust params for visualization
        k_scale = 0.7;%1/1.5;%M_k_scale{i_set};
        k_contrast = 1.1;%M_k_contrast{i_set};

        [h_anat,im_avr] = AverageAnatPlot(cellarray,k_contrast,k_scale);

        tiffdir = fullfile(outputDir,[M_reg_name{i_set},'_avr.tiff']);
        imwrite(im_avr, tiffdir, 'compression','none','writemode','overwrite');
    end

end


function out = reconSpyr(coeff, filter)

% Reconstruct the image from steerable pyramid
% Input:
%        coeff:     the cell structured pyramid
%       filter:     filter, typically sp3.mat, sp1.mat, sp5.mat
%
% Output:
%          out:     reconstructed image

load(filter,'lo0filt','hi0filt','lofilt','bfilts');

res = reconSpyrLevs(coeff(2:length(coeff)),lofilt, bfilts);
temp = upConv(res, lo0filt,[1 1]);

highpass = upConv( coeff{1}, hi0filt,[1 1]);

out=highpass+temp;


function [hh] = plotEmissionParams( varargin )

MAX_K   = 12;
MIN_THR = 0.01;

% ================================================ Process User Input
if isstruct( varargin{1} )
    if isfield( varargin{1}, 'ThetaM' )
        theta = varargin{1}.ThetaM.theta;
    elseif isfield( varargin{1}, 'theta' ) % || isprop(varargin{1},'theta')
        theta = varargin{1}.theta;
    else
        theta = varargin{1};
    end
    if isfield( varargin{1}, 'stateSeq' )
        stateSeq = varargin{1}.stateSeq;
    end

    for ll = 2:length( varargin )
       curArg = varargin{ll};
       if ishandle(curArg)
           figH = curArg;
       elseif isobject(curArg);
           data = curArg;
       end
    end

elseif isobject( varargin{1} )
    if isprop( varargin{1}, 'theta' )
        theta = varargin{1}.theta;
    end
else
    jobID = varargin{1};
    taskID = varargin{2};
    DATA = loadSamplerOutput( jobID, taskID, {'iters', 'Psi'} );
    data = loadSamplerInfo( jobID, taskID, {'data'} );

    if length( varargin ) >= 3
        queryIter = varargin{3};
        [~, idx] = min( abs( queryIter - DATA.iters.Psi ) );
    else
        idx = length( DATA.Psi );
    end
    Psi = DATA.Psi( idx );
    theta = Psi.theta;
    stateSeq = Psi.stateSeq;

    if length( varargin ) >= 4
        objIDs = varargin{4};
    end
end

K = length( theta );

if ~exist('figH','var')
    figH = gca;
end

if exist( 'stateSeq', 'var' )
    Zall = horzcat( stateSeq(:).z );
    N = length( Zall );
    [Zcounts, sortIDs] = sort( histc( Zall, 1:K ), 'descend' );
    sortIDs = sortIDs( Zcounts > 0 );
    K = length( sortIDs );
    K = min( K, MAX_K );
    theta = theta( sortIDs(1:K) );
else

    K = min( K, MAX_K );
    theta = theta( 1:K );
end

fNames = fieldnames(theta);
if fNames{1} == 'mu'
    obsType = 'Gaussian';
elseif fNames{1} == 'A'
    obsType = 'AR-Gaussian';
elseif fNames{1} == 'logp'
    obsType = 'Multinomial';
end

switch obsType
    case 'Multinomial'

        Px = exp( vertcat( theta(:).logp ) );
        set( gcf, 'Units', 'normalized', 'Position', [0 0.5 0.25 0.5] );
        imagesc( figH, Px, [0 0.01] );
        set( gca, 'Position', [0.1 0.1 0.8 0.06*K] );
    case 'Gaussian'

        if exist( 'data', 'var' )
            X = data.Xdata;
            plot(figH, X(1,:), X(2,:), 'k.' );
        end

        for kk = 1:K
            Mu(kk,:) = theta(kk).mu;
            invSigma(:,:,kk) = theta(kk).invSigma;
        end
        plotGauss( Mu, invSigma, 1, jet( MAX_K ), figH );

        B = 1.6;
        axis( [-B B -B B] );

    case 'AR-Gaussian'
        D = size( theta(1).A, 1);
        for kk = 1:K
            Mu(kk,:) = [ mean( diag( theta(kk).A ) )  zeros( 1, D-1) ];
            invSigma(:,:,kk) = theta(kk).invSigma;
        end
        plotGauss( Mu, 1000*invSigma, 1, jet(MAX_K), figH );

    case 'Bernoulli'
        error( 'TO DO' );
    case 'Multinomial'
        error( 'TO DO' );
end

hold off;
drawnow;


function [Ain, Cin, bin, fin, center] = initialize_components(Y, K, tau, options, P)

% Initalize components using a greedy approach followed by hierarchical
% alternative least squares (HALS) NMF. Optional use of spatio-temporal
% downsampling to boost speed.

%Input:
%Y          d1 x d2 x T movie, raw data
%K          number of neurons to extract (default value: 30)
%tau        standard deviation of neuron size (default value: 5)

%options    fine-tuning parameters (optional)
%           options.init_method: method of initialization ('greedy','sparse_NMF','HALS')
%           options.
%           options.nIter: number of iterations for shape tuning (default 5)
%           options.gSiz: size of kernel (default 2*tau + 1)
%           options.ssub: spatial downsampling factor (default 1)
%           options.tsub: temporal downsampling factor (default 1)
%           options.nb: rank of background component (default 1)
%           options.save_memory: flag for processing data in chunks to save memory (default 0)
%           options.windowSiz: size of spatial window when computing the median (default 32 x 32)
%           options.chunkSiz: number of timesteps to be processed simultaneously if on save_memory mode (default: 100)
%           options.med_app: number of timesteps to be interleaved for fast (approximate) median calculation (default: 1, no approximation)
%           options.rem_prct: percentile to be removed before initialization (default: 20)

% P         parameter struct used for normalization by noise and user feed component centroids (optional)

%
%Output:
%Ain        (d1*d2) x K matrix, location of each neuron
%Cin        T x K matrix, calcium activity of each neuron
%center     K x 2 matrix, inferred center of each neuron
%bin        (d1*d2) X nb matrix, initialization of spatial background
%fin        nb X T matrix, initalization of temporal background
%res        d1 x d2 x T movie, residual
%
%Authors: Eftychios A. Pnevmatikakis and Pengchen Zhou, with inputs from Weijian Yang

defoptions = CNMFSetParms;
if nargin < 4 || isempty(options); options = defoptions; end
if nargin < 2 || isempty(K)
    K = 30;
    fprintf('Number of components to be detected not specified. Using the default value 30. \n');
end
if nargin < 3 || isempty(tau)
    options.gSig = 5;
    fprintf('Standard deviation for neuron not specified. Using the default value 5. \n');
else options.gSig = tau;
end

if ~isfield(options,'init_method'); options.init_method = 'greedy'; end
if ~isfield(options,'rem_prct') || isempty(options.rem_prct); options.rem_prct = defoptions.rem_prct; end
% downsample the data

if ~isfield(options, 'ssub'); options.ssub = 1; end; ssub = options.ssub;
if ssub == 1; fprintf('No spatial downsampling is performed. Consider spatial downsampling if the field of view is very large. \n'); end
if ~isfield(options, 'tsub'), options.tsub = 1; end; tsub = options.tsub;
if tsub == 1; fprintf('No temporal downsampling is performed. Consider temporal downsampling if the recording is very long. \n'); end

if ~isfield(options,'noise_norm') || isempty(options.noise_norm)
    options.noise_norm = defoptions.noise_norm; % normalization by noise (true if P is present)
end

if nargin < 5
    if options.noise_norm
        warning('Normalization by noise value is not performed since noise values are not provided. \n');
    end
    options.noise_norm = false;
end

ndimsY = ndims(Y)-1;
sY = size(Y);
d = sY(1:ndimsY);
T = sY(end);

if options.noise_norm
    mY = mean(Y,ndims(Y));
    norm_image = mY + median(mY(:)) + 1e-4;
    min_noise = norm_image;
    %min_noise = prctile(P.sn(P.sn>0),options.noise_norm_prctile);
    %Y = bsxfun(@times,Y,reshape(1./max(P.sn,min_noise),d));
    Y = bsxfun(@times,Y,reshape(1./double(min_noise),d));
end

ds = d;
ds(1:2) = ceil(d(1:2)/ssub); % do not subsample along z axis
%d1s = ceil(d1/ssub);        %size of downsampled image
%d2s = ceil(d2/ssub);
Ts = floor(T/tsub);         %reduced number of frames
% spatial downsampling
fprintf('starting resampling \n')
if ssub~=1;
    if ndimsY == 2; Y_ds = imresize(Y, [ds(1), ds(2)], 'box'); end
    if ndimsY == 3;
        Y_ds = zeros([ds(1:2),T,ds(end)]);
        for z = 1:ds(3)
            Y_ds(:,:,:,z) = imresize(squeeze(Y(:,:,z,:)), [ds(1), ds(2)], 'box');
        end
        Y_ds = permute(Y_ds,[1,2,4,3]);
    end
else
    Y_ds = Y;
end
% temporal downsampling
if tsub~=1
    if ndimsY == 2; Y_ds = squeeze(mean(reshape(Y_ds(:, :, 1:(Ts*tsub)),ds(1), ds(2), tsub, Ts), 3)); end
    if ndimsY == 3; Y_ds = squeeze(mean(reshape(Y_ds(:, :, :, 1:(Ts*tsub)),ds(1), ds(2), ds(3), tsub, Ts), 4)); end
end

options_ds = options;
options_ds.d1 = ds(1);
options_ds.d2 = ds(2);

if strcmpi(options.init_method,'greedy')
    % run greedy method
    if nargin < 5 || ~isfield(P,'ROI_list')
        ROI_list = [];
    else
        ROI_list = round(P.ROI_list/ssub);
        K = size(ROI_list,1);
    end
    fprintf('Initializing components with greedy method \n');
    [Ain, Cin, bin, fin] = greedyROI(Y_ds, K, options, ROI_list);
elseif strcmpi(options.init_method, 'greedy_corr')
    fprintf('Initializing components with greedy_corr method \n');
    [Ain, Cin, bin, fin] = greedyROI_corr(Y_ds, K, options);
elseif strcmpi(options.init_method,'sparse_NMF')
    % run sparse_NMF method
    fprintf('Initializing components with sparse NMF \n');
    [Ain,Cin,bin,fin] = sparse_NMF_initialization(Y_ds,K,options_ds);
elseif strcmpi(options.init_method,'HALS')
    fprintf('Initializing components with HALS \n');
    [Ain,Cin,bin,fin] = HALS_initialization(Y_ds,K,options_ds);
else
    error('Unknown initialization method')
end

% refine with HALS
fprintf('Refining initial estimates with HALS...');
[Ain, Cin, bin, fin] = HALS(Y_ds, full(Ain), Cin, bin, fin, options_ds);
fprintf('  done \n');
%% upsample Ain, Cin, bin, fin
if nargout == 5
    if ndimsY == 2; center = ssub*com(Ain,ds(1),ds(2)); else center = ssub*com(Ain,ds(1),ds(2),ds(3)); end
end

Ain = imresize(reshape(full(Ain), [ds(1),ds(2), size(Ain,2)*prod(ds)/ds(1)/ds(2)]),[d(1),d(2)]); %,prod(d)/d(1)/d(2)*sum(K)]);
Ain = max(sparse(reshape(Ain, prod(d), [])),0);

bin = imresize(reshape(bin,[ds(1),ds(2), options.nb*prod(ds)/ds(1)/ds(2)]),[d(1),d(2)]);
bin = max(double(reshape(bin,prod(d),[])),0);

if options.noise_norm
    %Ain = bsxfun(@times,Ain,double(max(P.sn(:),min_noise)));
    %bin = bsxfun(@times,bin,max(P.sn(:),min_noise));
    Ain = bsxfun(@times,Ain,double(min_noise(:)));
    bin = bsxfun(@times,bin,double(min_noise(:)));
end
Cin = max(imresize(Cin, [size(Cin, 1), Ts*tsub]),0);
fin = max(imresize(fin, [options.nb, Ts*tsub]),0);
if T ~= Ts*tsub
    Cin = padarray(Cin, [0, T-Ts*tsub], 'post');
    fin = padarray(fin, [0, T-Ts*tsub], fin(end), 'post');
end


init_fig;

% c
axes('position', [.05, .57, .95, .37]);
hold on;
plot(y, 'color', col{8}/255);
alpha(.7);
plot(true_c, 'color', col{3}/255, 'linewidth', 1.5);
plot(c_oasis, '-.', 'color', col{5}/255);
if plot_cvx && exist('c_cvx', 'var')
    plot(c_cvx, '-.', 'color', col{7}/255);
end
axis tight;
xlim([0, 2000]);
set(gca, 'xtick', [0, 25, 50, 75]*30);
set(gca, 'xticklabel', []);
set(gca, 'ytick', 0:2);
ylabel('Fluor.');
box off;
if plot_cvx
    legend('Data', 'Truth', 'OASIS', 'CVX', 'location', 'northeast', 'orientation', 'horizental');
else
    legend('Data', 'Truth', 'OASIS', 'location', 'northeast', 'orientation', 'horizental');
end
% s
axes('position', [.05, .18, .95, .37]);
hold on;
plot(true_s, 'color', col{3}/255, 'linewidth', 1.5);
plot(s_oasis, '-.', 'color', col{5}/255);
if plot_cvx && exist('s_cvx', 'var')
    plot(s_cvx, '-.', 'color', col{7}/255);
end
axis tight;
xlim([0, 2000]);
set(gca, 'xtick', [0, 25, 50, 75]*30);
set(gca, 'xticklabel', get(gca, 'xtick')/30);
set(gca, 'ytick', [0,1]);
xlabel('Time [s]');
ylabel('Activity.');


classdef FourthOrderVoigtPlaneStressRotator < FourthOrderVoigtRotator

    methods (Access = public)

        function obj = FourthOrderVoigtPlaneStressRotator(angle,dir)
            obj.compute(angle,dir)
        end

    end

    methods (Access = protected,Static)

        function r = createStressRotator(a,d)
            r = StressVoigtPlaneStressRotator(a,d);
        end

    end

end


addpath Codes1D
addpath Codes2D
addpath Codes3D
addpath ServiceRoutines
addpath CFD1D
addpath CFD2D
addpath Grid/
addpath Grid/CFD
addpath Grid/3D
addpath Grid/CNS2D
addpath Grid/Euler2D
addpath Grid/Maxwell2D
addpath Grid/Other

cpt = cputime;

EulerDriver1D
figure; plot(x,Ener); drawnow; pause(.1);

PoissonCDriver1D
figure; plot(x,u); drawnow; pause(.1);

AdvecDriver1D
figure; plot(x,u); drawnow; pause(.1);

BurgersDriver1D
figure; plot(x,u); drawnow; pause(.1);

HeatDriver1D
figure; plot(x,u); drawnow; pause(.1);

MaxwellDriver1D
figure; plot(x,E); drawnow; pause(.1);

CurvedCNSDriver2D
figure; PlotField2D(N, x, y, Q(:,:,4)); drawnow; pause(.1);

CurvedPoissonIPDGDriver2D
figure; PlotField2D(N, x, y, u); drawnow; pause(.1);

CurvedEulerDriver2D
figure; PlotField2D(N, x, y, Q(:,:,4)); drawnow; pause(.1);

MaxwellCurvedDriver2D
figure; PlotField2D(N, x, y, Ez); drawnow; pause(.1);

CurvedINSDriver2D
figure; PlotField2D(N, x, y, PR); drawnow; pause(.1);

MaxwellDriver2D
figure; PlotField2D(N, x, y, Ez); drawnow; pause(.1);

EulerDriver2D
figure; PlotField2D(N, x, y, Q(:,:,4)); drawnow; pause(.1);

MaxwellHNonConDriver2D
figure; PlotField2D(N, x, y, Ez); drawnow; pause(.1);

EulerShockDriver2D
figure; PlotField2D(N, x, y, Q(:,:,4)); drawnow; pause(.1);

PoissonDriver2D
figure; PlotField2D(N, x, y, u); drawnow; pause(.1);

MaxwellPNonConDriver2D

AdvecDriver3D
figure; PlotContour3D(N, u, linspace(0, 1, 5)); drawnow; pause(.1);

MaxwellDriver3D
figure; PlotContour3D(3*N, Ez, linspace(-1, 1, 10)); drawnow; pause(.1);

PoissonIPDGDriver3D
figure; PlotContour3D(3*N, u, linspace(.1, 1, 10)); drawnow; pause(.1);
hold on
PlotSlice3D(2*N, u, 'x', .4);
hold off

alldemostook = cputime-cpt


function varargout = grSimplifyBranches(nodes, edges)
%GRSIMPLIFYBRANCHES Replace branches of a graph by single edges
%
%   [NODES2 EDGES2] = grSimplifyBranches(NODES, EDGES)
%   renvoie une version simplifiee d'un graphe, en ne gardant que les
%   points multiples et les aretes reliant les points multiples.
%
%   -----
%
%   author : David Legland
%   INRA - TPV URPOI - BIA IMASTE
%   created the 13/08/2003.
%

%   HISTORY :
%   10/02/2004 : doc
%   17/01/2006 : uses faster method to find neighbour edges
%   18/01/2006 : replace call to subfunctions by inlining -> faster

Mnodes = [];    % size Nn*2 -> nodes coordinates
Sedges = [];    % size Ne*2 -> indices of nodes
Mpoints = [];   % size Nn*1 -> indices of Multiple points
                %     in nodes input array

branch = [];    % size Nb*2 (variable)

Nn = 0;
Ne = 0;
Nb = 0;

% look for the first multiple point
p = 1;
while length(find(edges(:,1) == p | edges(:,2) == p)) < 3
    p = p + 1;
end

Mpoints(1) = p;
Mnodes(1, 1:2) = nodes(p, 1:2);
Nn = Nn + 1;

% add the branches of the first multiple point
neighbours = find(edges(:,1)==p | edges(:,2)==p);
for b = 1:length(neighbours)
    Nb = Nb+1;
    edge = edges(neighbours(b),:);
    if edge(1) == p
        branch(Nb, 1:2) = [p edge(2)]; %#ok<AGROW>
    else
        branch(Nb, 1:2) = [p edge(1)]; %#ok<AGROW>
    end
end

% process each branch, until there is no more branch to process.
% b is index of current branch
b = 0;
while b < length(branch)
    b = b+1;

    % check if the branch is valid
    if branch(b, 1) == 0
        continue;
    end

    % initialize iteration
    pNode = branch(b, 1);
    node = branch(b,2);
    neighbours = find(edges(:,1) == node | edges(:,2) == node);

%     disp(sprintf('node %3d (%03d ; %03d) -> %3d (%03d ; %03d)', ...
%         Mnode, nodes(Mnode, 1), nodes(Mnode, 2), ...
%         node, nodes(node, 1), nodes(node, 2)));

    while length(neighbours) < 3
        % look for the next point on the current branch
        next = 0;
        for n = 1:length(neighbours)
            edge = edges(neighbours(n), :);
            if edge(1)~= node && edge(1)~= pNode
                next = edge(1);
                break;
            end
            if edge(2)~= node && edge(2)~= pNode
                next = edge(2);
                break;
            end
        end

        pNode = node;
        node = next;
        neighbours = find(edges(:,1) == node | edges(:,2) == node);
    end

    % node is now  the next multiple point, and pNode contains the last
    % point of the branch.

    % check if the multiple point has already been processed
    index = find(Mpoints==node);
    if ~isempty(index)
        % find the branch starting with node, and with pNode has
        % second point, and set it to [0 0] to avoid it to be
        % processed again
        %disp('remove branch');
        for b2 = 1:Nb
            if branch(b2, 1) == node && branch(b2, 2) == pNode
                %disp('find branch');
                branch(b2, 1:2) = 0; %#ok<AGROW>
                break;
            end
        end

    else
        % add the multiple point to the list of points
        %disp('add point');
        Nn = Nn+1;
        Mnodes(Nn, 1:2) = nodes(node, 1:2); %#ok<AGROW>
        index = Nn;
        Mpoints(Nn) = node; %#ok<AGROW>

        % add each neighbour of the new multiple point (but not
        % the neighbour containing pNode) to the list of branches
        for n = 1:length(neighbours)
            edge = edges(neighbours(n), :);
            if edge(1) ~= pNode && edge(2) ~= pNode
                %disp('add a branch');
                Nb = Nb + 1;
                if edge(1) == node
                    branch(Nb, 1:2) = [node edge(2)]; %#ok<AGROW>
                else
                    branch(Nb, 1:2) = [node edge(1)]; %#ok<AGROW>
                end
            end
        end
    end

    %disp('add new Edge');
    Ne = Ne + 1;
    Sedges(Ne, 1:2) = [find(Mpoints == branch(b,1)), index]; %#ok<AGROW>
end

% process output depending on how many arguments are needed
if nargout == 1
    out{1} = Mnodes;
    out{2} = Sedges;
    varargout{1} = out;
end

if nargout == 2
    varargout{1} = Mnodes;
    varargout{2} = Sedges;
end

return;


function test_failed = test_libltfat_gabdual(varargin)
test_failed = 0;

fprintf(' ===============  %s ================ \n',upper(mfilename));

definput.flags.complexity={'double','single'};
[flags]=ltfatarghelper({},definput,varargin);
dataPtr = [flags.complexity, 'Ptr'];

Larr = [12  15  120  120];
aarr = [3   3    10   10];
Marr = [6   5    20   20];

for do_complex = 0:1
    complexstring = '';
    if do_complex, complexstring = 'complex'; end
    for idx = 1:numel(Larr)
        L = Larr(idx);
        a = aarr(idx);
        M = Marr(idx);

            if do_complex
                z = cast(randn(L,1)+1i*randn(L,1),flags.complexity);
                zi = complex2interleaved(z);
                zout = randn(size(zi),flags.complexity);

                ziPtr = libpointer(dataPtr,zi);
                zoutPtr = libpointer(dataPtr,zout);
            else
                z = cast(randn(L,1),flags.complexity);
                zi = z;
                zout = randn(size(zi),flags.complexity);

                ziPtr = libpointer(dataPtr,zi);
                zoutPtr = libpointer(dataPtr,zout);
            end

            trueres = gabdual(z,a,M);

            funname = makelibraryname('gabdual_long',flags.complexity,do_complex);
            status = calllib('libltfat',funname, ziPtr,L,a,M,zoutPtr);

            if do_complex
                res = norm(trueres - interleaved2complex(zoutPtr.Value));
            else
                res = norm(trueres - zoutPtr.Value);
            end

            [test_failed,fail]=ltfatdiditfail(res+status,test_failed);
            fprintf(['GABDUAL OP L:%3i, %s %s %s %s\n'],L,flags.complexity,complexstring,ltfatstatusstring(status),fail);

            status = calllib('libltfat',funname,ziPtr,L,a,M,ziPtr);

            if do_complex
                res = norm(trueres - interleaved2complex(ziPtr.Value));
            else
                res = norm(trueres - ziPtr.Value);
            end

            [test_failed,fail]=ltfatdiditfail(res+status,test_failed);
            fprintf(['GABDUAL IP L:%3i, %s %s %s %s\n'],L,flags.complexity,complexstring,ltfatstatusstring(status),fail);

            if do_complex
                z = cast(randn(M,1)+1i*randn(M,1),flags.complexity);
                zi = complex2interleaved(z);
                zout = randn(size(zi),flags.complexity);

                ziPtr = libpointer(dataPtr,zi);
                zoutPtr = libpointer(dataPtr,zout);
            else
                z = cast(randn(M,1),flags.complexity);
                zi = z;
                zout = randn(size(zi),flags.complexity);

                ziPtr = libpointer(dataPtr,zi);
                zoutPtr = libpointer(dataPtr,zout);
            end

            trueres = gabdual(z,a,M);

            funname = makelibraryname('gabdual_painless',flags.complexity,do_complex);
            status = calllib('libltfat',funname, ziPtr,M,a,M,zoutPtr);

            if do_complex
                res = norm(trueres - interleaved2complex(zoutPtr.Value));
            else
                res = norm(trueres - zoutPtr.Value);
            end

            [test_failed,fail]=ltfatdiditfail(res+status,test_failed);
            fprintf(['GABDUAL PAINLESS OP L:%3i, %s %s %s %s\n'],L,flags.complexity,complexstring,ltfatstatusstring(status),fail);

            status = calllib('libltfat',funname,ziPtr,M,a,M,ziPtr);

            if do_complex
                res = norm(trueres - interleaved2complex(ziPtr.Value));
            else
                res = norm(trueres - ziPtr.Value);
            end

            [test_failed,fail]=ltfatdiditfail(res+status,test_failed);
            fprintf(['GABDUAL PANLESS IP L:%3i, %s %s %s %s\n'],L,flags.complexity,complexstring,ltfatstatusstring(status),fail);

    end
end


% Helper function for decom.m, run DECOM method at regular time intervals.
%
% Octave compatible
%
% (please see decom.m for documentation and HOWTO_egg.m for a usage example)
%
%
% Copyright (c) 2013 University of Crete - Computer Science Department
%
% License
%  This file is under the LGPL license,  you can
%  redistribute it and/or modify it under the terms of the GNU Lesser General
%  Public License as published by the Free Software Foundation, either version 3
%  of the License, or (at your option) any later version. This file is
%  distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
%  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
%  PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
%  details.
%
% This function is part of the Covarep project: http://covarep.github.io/covarep
%
% Author
%  Gilles Degottex <degottex@csd.uoc.gr>
%

function [Oqeggmess, f0mess, npicferms, npicouvers, atimes] = decom_sig(s, fs, f0s, method)

    if nargin<3; f0s=[]; f0=[]; end
    if nargin<4; method = []; end

    winLen=2*round(20/1000*fs /2)+1;
    winShift=round(5/1000*fs);

    % Do processing
    start=1;
    stop=start+winLen-1;
    cnt=1;

    while stop <= length(s)

        % Get windowed frame
        x_frame = s(start:stop);
        atimes(cnt) = (0.5*(stop+start))/fs;

        if ~isempty(f0s) && size(f0s,2)>1
            f0 = interp1(f0s(:,1), f0s(:,2), atimes(cnt), 'nearest', 'extrap');
        end

        [Oqeggmess(cnt), f0mess(cnt), npicferms(cnt), npicouvers(cnt)] = decom(x_frame, fs, f0, method);

        % Increment
        start=start+winShift-1;
        stop=start+winLen-1;
        cnt=cnt+1;
    end

return


function [ a2, b2 ] = i4vec2_sorted_uniquely ( n1, a1, b1, n2 )

%*****************************************************************************80
%
%% I4VEC2_SORTED_UNIQUELY copies unique elements from a sorted I4VEC2.
%
%  Discussion:
%
%    An I4VEC2 is a pair of I4VEC's.
%
%    An I4VEC is a vector of I4's.
%
%    Entry K of an I4VEC2 is the pair of values located
%    at the K-th entries of the two I4VEC's.
%
%    Item I is stored as the pair A1(I), A2(I).
%
%    The items must have been sorted, or at least it must be the
%    case that equal items are stored in adjacent vector locations.
%
%    If the items were not sorted, then this routine will only
%    replace a string of equal values by a single representative.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 July 2014
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N1, the number of items.
%
%    Input, integer A1(N1), B1(N1), the array of items.
%
%    Input, integer N2, the number of unique items.
%
%    Output, integer A2(N2), B2(N2), the array of unique items.
%
  a2 = zeros(n2,1);
  b2 = zeros(n2,1);

  i1 = 1;
  i2 = 1;
  a2(i2) = a1(i1);
  b2(i2) = b1(i1);

  for i1 = 2 : n1

    if ( a1(i1) ~= a2(i2) || b1(i1) ~= b2(i2) )

      i2 = i2 + 1;

      a2(i2) = a1(i1);
      b2(i2) = b1(i1);

    end

  end

  return
end


filename='Gripping_quad_fine';
 ptype = 'MACRO';
method = 'SIMPALL';
materialType = 'ISOTROPIC';
initial_case = 'full';
cost = {'nonadjoint_compliance'};
weights = [1, 0.1];
constraint = {'volumeConstraint'};
constraint_case = 'INEQUALITY';
optimizer = 'PROJECTED GRADIENT'; incrementFactor = 1;
filterType = 'P1';

nsteps = 1;
Vfrac_final = 0.75;
optimality_final = 1e-3;
constr_final =1e-3;

Vfrac_initial = 1;
optimality_initial = 1e-3;
constr_initial = 1e-3;
TOL.rho_plus = 1;
TOL.rho_minus = 0;
TOL.E_plus = 1;
TOL.E_minus = 1e-3;
TOL.nu_plus = 1/3;
TOL.nu_minus = 1/3;


function [ mSynCat, vMain] = calc_SynCat(nNbkg,vSynCat,nSynCat_,nSynMode, vAfter,vEtas,mCatalog,bPSQ,vPSQ,mPSQ)
    % calculates a synthetic catalog with a backgroundrate based number of earthquakes in the catalog of the period before starting date.
    %
    % Example: [mSynCat, vMain] = calc_SynCat(2500,2.5,2.5,8,100,'January 1,1980','December 31,1990',6.5,1,0,a);
    %
    % This function (calc_SynCat) calculates a synthetic catalog with a
    % backgroundrate based number of earthquakes in the catalog of the period
    % before starting date. This function is doing the following:
    % 1) creates a synthetic catalog with background rate based on input parameters.
    % 2) calculate omori-type aftershock and add this to the background catalog,
    % that was created by the properties of the inputbackground catalog. Therefore
    % the program package ETESProject by karen Felzer was used.
    %
    % Author: van Stiphout, Thomas
    % Email: vanstiphout@sed.ethz.ch
    % Created: 2. Mar 2007
    % Changed: -
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %  Variables
    % Input:
    % nNbkg         Number of events in background catalog during assigned period
    % vSynCat       Vektor with contraints on synthetic catalog
    %                   1-4: fMinLon fMaxLon fMinLat fMaxLat in degree
    %                   5-6: fMinDepth fMaxDepth  in km
    %                   7-8: fMinTime fMaxTime (duration of catalog)
    %                   9:   fRate Reduction of earthquakes for entire catalog
    %                          (0.75 = 25% reduction) in period (fT-fTw) - fT
    %                   10:  fBValue           b-value of the catalog
    %                   11:  fMc Magnitude of Completness (minimum Magnitude in Catalog)
    %                   12:  fIncMagnitude increment steps
    % nSynCat_      1: only backgorund, 2: background + ETAS
    % nSynMode      Type of synthetic catalog 0:homogeneous distr; 1:based
    %                on real catalog 2:hypocenter based on real catalog, magnitude and focal
    %                time is randomly computed
    % vAfter        Definition/Constraints for Aftershocks
    %                   1: Mmin: Minimum earthquake magnitude to report and simulate
    %                   2: MminR: Minimum earthquake magnitude for reporting
    %                       in the output catalog
    %                   3: maxm: Maximum earthquake magnitude
    %                   4: DMax: Maximum distance for aftershocks
    %                   5: magb: Cutoff magnitude for the point source vs. plane source
    %                       representation of the mainshock
    % vEtas         Parameters for ETAS:[CX, P, A] standard=[0.095, 1.34, 0.008]
    % mCatalog      Declustered catalog needed only for nSynMode=1
    % bPSQ          with (1) or without (0) PSQ
    % vPSQ          values for PSQ (lon, lat, N, Tw, T)
    %
    % Output:
    % SynCat Simulated ETES catalog [yr lon lat month day mag depth hrs min sec]
    % vMain            Vector with assignments if main (true) or aftershock (false)
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    % initialize:
    clear FaultParam;

    % background:
    fBValue=vSynCat(10);
    fMc=vSynCat(11);
    fInc=vSynCat(12);
    fMinLat=vSynCat(3);
    fMaxLat=vSynCat(4);
    fMinLon=vSynCat(1);
    fMaxLon=vSynCat(2);
    fMinDepth=vSynCat(5);
    fMaxDepth=vSynCat(6);
    nRchange=vSynCat(9);
    [fYr1, nMn1, nDay1, nHr1, nMin1, nSec1]=decyear2mat(vSynCat(7));
    [fYr2, nMM2, nDD2, nHH2, nMN2, nSS2]=decyear2mat(vSynCat(8));

    % vAfter
    Mmin=vAfter(1);
    MminR=vAfter(2);
    maxm=vAfter(3);
    DMax=vAfter(4);
    magb=vAfter(5);
    FaultParam=[0 0 0 0 0 0 0];

    % vEtas
    CX=vEtas(1);
    P=vEtas(2);
    A=vEtas(3);

    switch nSynCat_
        case 1
            % create background rate
            mSynCat=syn_catalog(nNbkg, fBValue, fMc, fInc, fMinLat,fMaxLat,...
                fMinLon,fMaxLon,fMinDepth,fMaxDepth, fYr1,fYr2,nSynMode,...
                mCatalog);
            if bPSQ
                mSynCat=sr_makePSQ(mSynCat,vPSQ(2),vPSQ(3),vPSQ(4),...
                    vPSQ(1),mPSQ);
            end
            %       mSynCat(:,1)=mSynCat(randperm(size(mSynCat,1))',1);
            vMain=ones(nNbkg,1);
        case 2   % create background rate + ETAS
            nNbkgA=floor(nNbkg/(1+nRchange)*1);
            nNbkgB=ceil(nNbkg/(1+nRchange)*nRchange);
            if nRchange == 1
                mCat=syn_catalog(nNbkg, fBValue, fMc, fInc, fMinLat,fMaxLat,...
                    fMinLon,fMaxLon,fMinDepth,fMaxDepth, fYr1,fYr2,nSynMode,...
                    mCatalog);
            else
                mCatA=syn_catalog(nNbkgA, fBValue, fMc, fInc, fMinLat,fMaxLat,...
                    fMinLon,fMaxLon,fMinDepth,fMaxDepth,fYr1,(fYr1+fYr2)/2,...
                    nSynMode,mCatalog);
                mCatB=syn_catalog(nNbkgB, fBValue, fMc, fInc, fMinLat,fMaxLat,...
                    fMinLon,fMaxLon,fMinDepth,fMaxDepth,(fYr1+fYr2)/2,fYr2,...
                    nSynMode,mCatalog);
                mCat=[mCatA;mCatB];
            end
            %         mCat(:,1)=mCat(randperm(size(mCat,1))',1);
            [Y,Idx]=sort(mCat(:,3),1);
            mCat=mCat(Idx,:);
            if bPSQ
                mCat=sr_makePSQ(mCat,vPSQ(2),vPSQ(3),vPSQ(4),...
                    vPSQ(1),mPSQ);
            end
            mCat1=[fix(mCat(:,3)) mCat(:,4) mCat(:,5) mCat(:,8) mCat(:,9) rand(size(mCat,1),1)*60 mCat(:,2) mCat(:,1) mCat(:,7) mCat(:,6)];
            %         mCat1(:,1)=mCat1(:,1)-(max(mCat1(:,1))-min(mCat1(:,1)));
            %  [N,Mmax,catalog,IDAll,HistoryAll] = ETESProject2(cat1,RateGrid2,0.095,1.34,0.008,Mmin,MminR,maxm,DMax,sYr1,sYr2,6.5,FaultParam)
            [N,Mmax,catalog,IDAll,HistoryAll] = ETESProject3(mCat1,vEtas,vAfter,fYr1,fYr2,FaultParam);

            mSynCat(:,1) = catalog(:,8); % lon
            mSynCat(:,2) = catalog(:,7);  % lat
            mSynCat(:,3) = catalog(:,1);  % years
            mSynCat(:,4) = catalog(:,2);  % month
            mSynCat(:,5) = catalog(:,3);  % day
            mSynCat(:,6) = catalog(:,10); % mag
            mSynCat(:,7) = catalog(:,9);  % depth
            mSynCat(:,8) = catalog(:,4);  % hours
            mSynCat(:,9) = catalog(:,5);  % minutes
            mSynCat(:,10) = catalog(:,6);  % seconds

            mSynCat(:,3) = decyear([mSynCat(:,3) mSynCat(:,4) mSynCat(:,5) ...
                mSynCat(:,8) mSynCat(:,9) mSynCat(:,10)]); % yrs decimal
            size(mSynCat)
            vMain=(catalog(:,12)==0);
    end
    % disp('cat fertig')
end


function [bnet, LL, engine] = learn_params_em(engine, evidence, max_iter, thresh)
% LEARN_PARAMS_EM Set the parameters of each adjustable node to their ML/MAP values using batch EM.
% [bnet, LLtrace, engine] = learn_params_em(engine, data, max_iter, thresh)
%
% data{i,l} is the value of node i in case l, or [] if hidden.
%   Suppose you have L training cases in an O*L array, D, where O is the num observed
%   scalar nodes, and N is the total num nodes.
%   Then you can create 'data' as follows, where onodes is the index of the observable nodes:
%      data = cell(N, L);
%      data(onodes,:) = num2cell(D);
%   Of course it is possible for different sets of nodes to be observed in each case.
%
% We return the modified bnet and engine.
% To see the learned parameters for node i, use the construct
%   s = struct(bnet.CPD{i}); % violate object privacy
% LLtrace is the learning curve: the vector of log-likelihood scores at each iteration.
%
% max_iter specifies the maximum number of iterations. Default: 10.
%
% thresh specifies the thresold for stopping EM. Default: 1e-3.
% We stop when |f(t) - f(t-1)| / avg < threshold,
% where avg = (|f(t)| + |f(t-1)|)/2 and f is log lik.

if nargin < 3, max_iter = 10; end
if nargin < 4, thresh = 1e-3; end

verbose = 1;

loglik = 0;
previous_loglik = -inf;
converged = 0;
num_iter = 1;
LL = [];

while ~converged & (num_iter <= max_iter)
  [engine, loglik] = EM_step(engine, evidence);
  if verbose, fprintf('EM iteration %d, ll = %8.4f\n', num_iter, loglik); end
  num_iter = num_iter + 1;
  converged = em_converged(loglik, previous_loglik, thresh);
  previous_loglik = loglik;
  LL = [LL loglik];
end
if verbose, fprintf('\n'); end

bnet = bnet_from_engine(engine);

%%%%%%%%%

function [engine, loglik] = EM_step(engine, cases)

bnet = bnet_from_engine(engine); % engine contains the old params that are used for the E step
CPDs = bnet.CPD; % these are the new params that get maximized
num_CPDs = length(CPDs);
adjustable = zeros(1,num_CPDs);
for e=1:num_CPDs
  adjustable(e) = adjustable_CPD(CPDs{e});
end
adj = find(adjustable);
n = length(bnet.dag);

for e=adj(:)'
  CPDs{e} = reset_ess(CPDs{e});
end

loglik = 0;
ncases = size(cases, 2);
for l=1:ncases
  evidence = cases(:,l);
  [engine, ll] = enter_evidence(engine, evidence);
  loglik = loglik + ll;
  hidden_bitv = zeros(1,n);
  hidden_bitv(isemptycell(evidence))=1;
  for i=1:n
    e = bnet.equiv_class(i);
    if adjustable(e)
      fmarg = marginal_family(engine, i);
      CPDs{e} = update_ess(CPDs{e}, fmarg, evidence, bnet.node_sizes, bnet.cnodes, hidden_bitv);
    end
  end
end

for e=adj(:)'
  CPDs{e} = maximize_params(CPDs{e});
end

engine = update_engine(engine, CPDs);


function varargout = clipMeshVertices(v, f, b, varargin)
%CLIPMESHVERTICES Clip vertices of a surfacic mesh and remove outer faces
%
%   [V2, F2] = clipMeshVertices(V, F, B)
%   Clip a mesh represented by vertex array V and face array F, with the
%   box represented by B. The result is the set of vertices contained in
%   the box, and a new set of faces corresponding to original faces with
%   all vertices within the box.
%
%   [V2, F2] = clipMeshVertices(..., 'shape','sphere') Specify the shape.
%   Default is 'box'. But it's also possible to use a 'sphere'.
%
%   [V2, F2] = clipMeshVertices(..., 'inside',false) removes the inner
%   faces instead of the outer faces.
%
%   Example
%     [v, f] = createSoccerBall;
%     f = triangulateFaces(f);
%     box = [0 2 -1 2 -.5 2];
%     [v2, f2] = clipMeshVertices(v, f, box, 'inside', false);
%     figure('color','w'); view(3); axis equal
%     drawMesh(v, f, 'faceColor', 'none', 'faceAlpha', .2);
%     drawBox3d(box)
%     drawMesh(v2, f2, 'faceAlpha', .7);
%
%   See also
%   meshes3d, clipPoints3d
%
% ------
% Author: David Legland, oqilipo
% e-mail: david.legland@grignon.inra.fr
% Created: 2011-04-07,    using Matlab 7.9.0.529 (R2009b)
% Copyright 2011 INRA - Cepia Software Platform.

% if input is given as a structure, parse fields
if isstruct(v)
    if nargin > 2; varargin = [b, varargin]; end
    b = f;
    f = v.faces;
    v = v.vertices;
end

parser = inputParser;
validStrings = {'box','sphere'};
addParameter(parser,'shape','box',@(x) any(validatestring(x, validStrings)));
addParameter(parser,'inside',true,@islogical);
parse(parser,varargin{:});

% clip the vertices
[v2, indVertices] = clipPoints3d(v, b,...
    'shape', parser.Results.shape, 'inside', parser.Results.inside);

% create index array for face indices relabeling
refInds = zeros(size(indVertices));
for i = 1:length(indVertices)
    refInds(indVertices(i)) = i;
end

% select the faces with all vertices within the box
if isnumeric(f)
    % Faces given as numeric array
    indFaces = sum(~ismember(f, indVertices), 2) == 0;
    f2 = refInds(f(indFaces, :));

elseif iscell(f)
    % Faces given as cell array
    nFaces = length(f);
    indFaces = false(nFaces, 1);
    for i = 1:nFaces
        indFaces(i) = sum(~ismember(f{i}, indVertices), 2) == 0;
    end
    f2 = f(indFaces, :);

    % re-label indices of face vertices (keeping horizontal index array)
    for i = 1:length(f2)
        f2{i} = refInds(f2{i})';
    end
end

switch nargout
    case 1
        mesh2.vertices=v2;
        mesh2.faces=f2;
        varargout{1}=mesh2;
    case 2
        varargout{1}=v2;
        varargout{2}=f2;
end


function [p,r] = cs_scc (A)                                                 %#ok
%CS_SCC strongly-connected components of a square sparse matrix.
%   [p,r] = cs_scc(A) finds a permutation p so that A(p,p) is permuted into
%   block upper triangular form.  The diagonal of A is ignored.  The kth block
%   is given by A (s,s) where s = r(k):r(k+1)-1.  A must be square.
%   For bipartite or rectangular graphs, use cs_scc2.
%
%   Example:
%       Prob = UFget ('HB/arc130') ; A = Prob.A ; [p r] = cs_scc (A) ;
%       cspy (A (p,p)) ;
%
%   See also CS_DMPERM, DMPERM, CS_SCC2.

%   Copyright 2006-2007, Timothy A. Davis.
%   http://www.cise.ufl.edu/research/sparse

error ('cs_scc mexFunction not found') ;


function img = imMergeLabels(img, lbls, varargin)
%IMMERGELABELS Merge regions in a labeled image
%
%   Deprecated: replaced by the "imMergeRegions" function.
%
%   Usage:
%   LBL2 = imMergeLabels(IMG, LABELS);
%   IMG is a label image, LABELS are the labels of the regions to be
%   merged. IMG can be 2D or 3D.
%   The indices of regions are set to the same value, and the boundary
%   between the regions is also merged to the new region, preserving
%   topology of adjacent regions.
%   The function uses morphologial operation, processing time can be
%   consuming.
%
%   LBL2 = imMergeLabels(IMG, LABELS, SE);
%   Specify the structuring element used for morphological detection of the
%   boundary.
%
%   Example:
%   lbl = [1 1 0 3 3;1 1 0 3 3;1 0 2 0 3;0 2 2 2 0];
%   lbl2 = imMergeLabels(lbl, [1 2])
%   lbl2 =
%        1     1     0     3     3
%        1     1     0     3     3
%        1     1     1     0     3
%        1     1     1     1     0
%
%   See Also
%     imMergeRegions
%

% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2007-08-07
% Copyright 2007 INRA - BIA PV Nantes - MIAJ Jouy-en-Josas.

% simply call the new function
img = imMergeRegions(img, lbls, varargin{:});


function tapas_sem_plot_fits(fits, dt)
%% Plot the fits of the model.
%
% Input
%       data        -- Structure of the data of a single subject.
%       fits        -- Fits struct array
%       dt          -- Factor to normalize the area
% Output
%

% aponteeduardo@gmail.com
% copyright (C) 2019
%

n = 1;

n = n + 1;
if nargin < n
    dt = 1;
end

nconds = numel(fits);

for i = 1:nconds

    ax = subplot(nconds, 2, (i - 1) * 2 + 1);
    hold on;

    plot(fits(i).t, fits(i).pro * dt, 'k', 'linewidth', 2)

    ax = subplot(nconds, 2, (i - 1) * 2 + 2);
    hold on;
    plot(fits(i).t, fits(i).anti * dt, 'k', 'linewidth', 2)
end

end


% This subroutine assigns creates a grid with
% spacing dx,dy (in degreees). The size will
% be selected interactiVELY. The bvalue in each
% volume around a grid point containing ni earthquakes
% will be calculated as well as the magnitude
% of completness
%   Stefan Wiemer 1/95

display ('This is /src/bdepth_ratio_auto.m');

global no1 bo1 inb1 inb2

if sel == 'in'
    % get the grid parameter
    % initial values
    %
    dx = 0.1;
    dy = 0.1 ;
    ni = 1000;
    Nmin = 50;
    stan2 = nan;
    stan = nan;
    prf = nan;
    av = nan;
    mid_point = 5;
    top_zonet = 0;
    top_zoneb = 5;
    bot_zonet = 7;
    bot_zoneb = 15;
    topstan2 = nan;
    botstan2 = nan;
    topstan = nan;
    botstan = nan;
    topav = nan;
    botav = nan;

    % make the interface
    %
    figure_w_normalized_uicontrolunits(...
        'Name','Depth Ratio Grid Input Parameter',...
        'NumberTitle','off', ...
        'MenuBar','none', ...
        'NextPlot','new', ...
        'units','points',...
        'Visible','off', ...
        'Position',[ wex+200 wey-200 650 300]);
    axis off
    labelList2=[' Automatic Mcomp (max curvature) | Fixed Mc (Mc = Mmin) | Automatic Mcomp (90% probability) | Automatic Mcomp (95% probability) | Best (?) combination (Mc95 - Mc90 - max curvature)'];

    labelPos = [0.2 0.60 0.6  0.08];
    hndl2=uicontrol(...
        'Style','popup',...
        'Position',labelPos,...
        'Units','normalized',...
        'String',labelList2,...
        'Callback','inb2 =get(hndl2,''Value''); ');

    % set(hndl2,'value',5);

    % creates a dialog box to input grid parameters
    %
    %

    % mid_point_field=uicontrol('Style','edit',...
    %     'Position',[.47 .80 .12 .08],...
    %     'Units','normalized','String',num2str(mid_point),...
    %     'Callback','mid_point=str2double(get(mid_point_field,''String'')); set(mid_point_field,''String'',num2str(mid_point));');

    top_zonet_field=uicontrol('Style','edit',...
        'Position',[.36 .80 .06 .06],...
        'Units','normalized','String',num2str(top_zonet),...
        'Callback','top_zonet=str2double(get(top_zonet_field,''String'')); set(top_zonet_field,''String'',num2str(top_zonet));');
    top_zoneb_field=uicontrol('Style','edit',...
        'Position',[.36 .74 .06 .06],...
        'Units','normalized','String',num2str(top_zoneb),...
        'Callback','top_zoneb=str2double(get(top_zoneb_field,''String'')); set(top_zoneb_field,''String'',num2str(top_zoneb));');

    bot_zonet_field=uicontrol('Style','edit',...
        'Position',[.78 .80 .06 .06],...
        'Units','normalized','String',num2str(bot_zonet),...
        'Callback','bot_zonet=str2double(get(bot_zonet_field,''String'')); set(bot_zonet_field,''String'',num2str(bot_zonet));');
    bot_zoneb_field=uicontrol('Style','edit',...
        'Position',[.78 .74 .06 .06],...
        'Units','normalized','String',num2str(bot_zoneb),...
        'Callback','bot_zoneb=str2double(get(bot_zoneb_field,''String'')); set(bot_zoneb_field,''String'',num2str(bot_zoneb));');

    freq_field=uicontrol('Style','edit',...
        'Position',[.30 .50 .12 .08],...
        'Units','normalized','String',num2str(ni),...
        'Callback','ni=str2double(get(freq_field,''String'')); set(freq_field,''String'',num2str(ni));set(tgl2,''value'',0); set(tgl1,''value'',1)');

    freq_field0=uicontrol('Style','edit',...
        'Position',[.70 .50 .12 .08],...
        'Units','normalized','String',num2str(ra),...
        'Callback','ra=str2double(get(freq_field0,''String'')); set(freq_field0,''String'',num2str(ra)) ; set(tgl2,''value'',1); set(tgl1,''value'',0)');

    freq_field2=uicontrol('Style','edit',...
        'Position',[.30 .40 .12 .08],...
        'Units','normalized','String',num2str(dx),...
        'Callback','dx=str2double(get(freq_field2,''String'')); set(freq_field2,''String'',num2str(dx));');

    freq_field3=uicontrol('Style','edit',...
        'Position',[.30 .30 .12 .08],...
        'Units','normalized','String',num2str(dy),...
        'Callback','dy=str2double(get(freq_field3,''String'')); set(freq_field3,''String'',num2str(dy));');

    tgl1 = uicontrol('Style','checkbox',...
        'string','Number of Events:',...
        'Position',[.09 .50 .2 .08], 'Callback','set(tgl2,''value'',0)',...
        'Units','normalized');

    set(tgl1,'value',1);

    tgl2 =  uicontrol('Style','checkbox',...
        'string','OR: Constant Radius',...
        'Position',[.47 .50 .2 .08], 'Callback','set(tgl1,''value'',0)',...
        'Units','normalized');

    freq_field4=uicontrol('Style','edit',...
        'Position',[.30 .20 .12 .08],...
        'Units','normalized','String',num2str(Nmin),...
        'Callback','Nmin=str2double(get(freq_field4,''String'')); % set(freq_field4,''String'',num2str(Nmin));');

    close_button=uicontrol('Style','Pushbutton',...
        'Position',[.60 .05 .15 .12 ],...
        'Units','normalized','Callback','close;done','String','Cancel');

    go_button1=uicontrol('Style','Pushbutton',...
        'Position',[.20 .05 .15 .12 ],...
        'Units','normalized',...
        'Callback',' inb1 =get(hndl2,''Value'');tgl1 =get(tgl1,''Value'');tgl2 =get(tgl2,''Value'');close,sel =''ca'', bdepth_ratio',...
        'String','Go');
    Nmin;
    text(...
        'Color',[0 0 0 ],...
        'EraseMode','normal',...
        'Position',[0.20 .75 0 ],...
        'Rotation',0 ,...
        'FontSize',ZmapGlobal.Data.fontsz.m ,...
        'FontWeight','bold',...
        'String','Please choose an Mc estimation option   ');

    mid_txt=text(...
        'Color',[0 0 0 ],...
        'EraseMode','normal',...
        'Position',[0.24 1.0 0 ],...
        'Rotation',0 ,...
        'FontSize',ZmapGlobal.Data.fontsz.m ,...
        'FontWeight','bold',...
        'String','Depth limits for depth ratio calculation  ');

    top_txt=text(...
        'Color',[0 0 0 ],...
        'EraseMode','normal',...
        'Position',[-0.10 .85 0 ],...
        'Rotation',0 ,...
        'FontSize',ZmapGlobal.Data.fontsz.m ,...
        'FontWeight','bold',...
        'String','Top and bottom for TOP zone(km):');

    bot_txt=text(...
        'Color',[0 0 0 ],...
        'EraseMode','normal',...
        'Position',[0.40 .85 0 ],...
        'Rotation',0 ,...
        'FontSize',ZmapGlobal.Data.fontsz.m ,...
        'FontWeight','bold',...
        'String','Top and bottom for BOTTOM zone(km):');

    txt3 = text(...
        'Color',[0 0 0 ],...
        'EraseMode','normal',...
        'Position',[0.30 0.64 0 ],...
        'Rotation',0 ,...
        'FontSize',ZmapGlobal.Data.fontsz.m ,...
        'FontWeight','bold',...
        'String',' Grid Parameter');
    txt5 = text(...
        'Color',[0 0 0 ],...
        'EraseMode','normal',...
        'Position',[-0.06 0.40 0 ],...
        'Rotation',0 ,...
        'FontSize',ZmapGlobal.Data.fontsz.m ,...
        'FontWeight','bold',...
        'String','Spacing in x (dx) in deg:');

    txt6 = text(...
        'Color',[0 0 0 ],...
        'EraseMode','normal',...
        'Position',[-0.06 0.29 0 ],...
        'Rotation',0 ,...
        'FontSize',ZmapGlobal.Data.fontsz.m ,...
        'FontWeight','bold',...
        'String','Spacing in y (dy) in deg:');

    txt7 = text(...
        'Color',[0 0 0 ],...
        'EraseMode','normal',...
        'Position',[-0.06 0.17 0 ],...
        'Rotation',0 ,...
        'FontSize',ZmapGlobal.Data.fontsz.m ,...
        'FontWeight','bold',...
        'String','Min. No. of events > Mc:');

    set(gcf,'visible','on');
    watchoff

end   % if nargin ==0

% get the grid-size interactively and
% calculate the b-value in the grid by sorting
% thge seimicity and selectiong the ni neighbors
% to each grid point

if sel == 'ca'
    selgp
    itotal = length(newgri(:,1));
    if length(gx) < 4  ||  length(gy) < 4
        errordlg('Selection too small! (Dx and Dy are in degreees! ');
        return
    end

    zmap_message_center.set_info(' ','Running bdepth_ratio... ');think
    %  make grid, calculate start- endtime etc.  ...
    %
    t0b = min(a.Date)  ;
    n = a.Count;
    teb = a(n,3) ;
    tdiff = round((teb - t0b)*365/par1);
    loc = zeros(3, length(gx)*length(gy));

    % loop over  all points
    %
    i2 = 0.;
    i1 = 0.;
    bvg = [];
    allcount = 0.;
    nobv = 0;
    wai = waitbar(0,' Please Wait ...  ');
    set(wai,'NumberTitle','off','Name','b-value grid - percent done');;
    drawnow

    % sort by depth

    % [s,is] = sort(a.Depth);
    % adepth = a(is(:,1),:);

    % find row index of ratio midpoint
    l = a.Depth >= top_zonet & a.Depth <  top_zoneb;
    top_zone = a.subset(l);

    l = a.Depth >= bot_zonet & a.Depth <  bot_zoneb;
    bot_zone = a.subset(l);

    %
    % overall b-value
    [bv magco stan av me mer me2,  pr] =  bvalca3(top_zone,inb1,inb2);
    tbo1 = bv; tno1 = length(top_zone(:,1));

    [bv magco stan av me mer me2,  pr] =  bvalca3(bot_zone,inb1,inb2);
    bbo1 = bv; bno1 = length(bot_zone(:,1));

    depth_ratio = tbo1/bbo1;

    disp(depth_ratio);

    % loop over all points
    for i= 1:length(newgri(:,1))
        x = newgri(i,1);y = newgri(i,2);
        allcount = allcount + 1.;
        i2 = i2+1;

        % calculate distance from center point and sort wrt distance
        l = sqrt(((a.Longitude-x)*cos(pi/180*y)*111).^2 + ((a.Latitude-y)*111).^2) ;
        [s,is] = sort(l);
        b = a(is(:,1),:) ;       % re-orders matrix to agree row-wise

        if tgl1 == 0   % take point within r
            l3 = l <= ra;
            b = a.subset(l3);      % new data per grid point (b) is sorted in distanc  (from center point)
            rd = ra;
        else
            % take first ni points
            b = b(1:ni,:);      % new data per grid point (b) is sorted in distance
            l2 = sort(l); rd = l2(ni);

        end

        %estimate the completeness and b-value
        newt2 = b;

        % sort by depth

        l = b(:,7) >= top_zonet & b(:,7) <  top_zoneb;
        topb = b(l,:);

        l = b(:,7) >= bot_zonet & b(:,7) <  bot_zoneb;
        botb = b(l,:);

       if length(topb) >= Nmin  && length(botb) >= Nmin

            if inb1 == 3
                newt2 = topb;
                mcperc_ca3;
                l = topb(:,6) >= Mc90-0.05; magco = Mc90;
                n1 = length(topb(l,:));
                if length(topb(l,:)) >= Nmin
                    [topbv magco stan av me mer me2,  pr] =  bvalca3(topb(l,:),2,2);
                    [topav2 topbv2 topstan2 ] =  bmemag(topb(l,:));
                else  topbv = nan; topbv2 = nan, magco = nan; av = nan; topav2 = nan;
                    nobv = nobv + 1;
                end
                newt2 = botb;
                mcperc_ca3;
                l = botb(:,6) >= Mc90-0.05; magco = Mc90;
                n2 = length(botb(l,:));
                if length(botb(l,:)) >= Nmin
                    [botbv magco stan av me mer me2,  pr] =  bvalca3(botb(l,:),2,2);
                    [botav2 botbv2 botstan2 ] =  bmemag(botb(l,:));

                else  botbv = nan; botbv2 = nan; magco = nan; av = nan; botav2 = nan;
                    nobv = nobv + 1;
                end

            elseif inb1 == 4
                newt2 = topb;
                mcperc_ca3;
                l = topb(:,6) >= Mc95-0.05; magco = Mc95;
                n1 = length(topb(l,:));

                if length(topb(l,:)) >= Nmin
                    [topbv magco topstan topav topme topmer topme2,  toppr] =  bvalca3(topb(l,:),2,2);
                    [topav2 topbv2 topstan2 ] =  bmemag(topb(l,:));
                else
                    topbv = nan; topbv2 = nan, magco = nan; topav = nan; topav2 = nan;
                    nobv = nobv + 1;
                end
                newt2 = botb;
                mcperc_ca3;
                l = botb(:,6) >= Mc90-0.05; magco = Mc95;
                n2 = length(botb(l,:));

                if length(botb(l,:)) >= Nmin
                    [botbv magco botstan botav botme botmer botme2,  botpr] =  bvalca3(botb(l,:),2,2);
                    [botav2 botbv2 botstan2 ] =  bmemag(botb(l,:));
                else
                    botbv = nan; botbv2 = nan, magco = nan; botav = nan; botav2 = nan;
                    nobv = nobv + 1;
                end

            elseif inb1 == 5
                newt2 = topb;
                mcperc_ca3;
                if isnan(Mc95) == 0
                    magco = Mc95;
                elseif isnan(Mc90) == 0
                    magco = Mc90;
                else
                    [bv magco stan av me mer me2,  pr] =  bvalca3(b,1,1);
                end

                l = topb(:,6) >= magco-0.05;
                n1 = length(topb(l,:));
                if length(topb(l,:)) >= Nmin
                    [topbv magco topstan topav topme topmer topme2,  toppr] =  bvalca3(topb(l,:),2,2);
                    [topav2 topbv2 topstan2 ] =  bmemag(topb(l,:));
                else
                    topbv = nan; topbv2 = nan, magco = nan; topav = nan; topav2 = nan;
                    nobv = nobv + 1;
                end

                newt2 = botb;
                mcperc_ca3;
                l = botb(:,6) >= magco-0.05;
                n2 = length(botb(l,:));

                if length(botb(l,:)) >= Nmin
                    [botbv magco botstan botav botme botmer botme2,  botpr] =  bvalca3(botb(l,:),2,2);
                    [botav2 botbv2 botstan2 ] =  bmemag(botb(l,:));
                else
                    botbv = nan; botbv2 = nan, magco = nan; botav = nan; bottopav2 = nan;
                    nobv = nobv + 1;
                end

            elseif inb1 == 1
                % newt2 = topb;
                % mcperc_ca3;
                [topbv magco topstan topav topme topmer topme2,  toppr] =  bvalca3(topb,1,1);
                l = topb(:,6) >= magco-0.05;
                if length(topb(l,:)) >= Nmin
                    [topav2 topbv2 topstan2 ] =  bmemag(topb(l,:));
                    n1 = length(topb(l,:));
                else
                    topbv = nan; topbv2 = nan; magco = nan; topav = nan; topav2 = nan;
                    n1 = nan;

                    nobv = nobv + 1;
                end
                %    newt2 = botb;
                %    mcperc_ca3;
                [botbv magco botstan botav botme botmer botme2,  botpr] =  bvalca3(botb,1,1);
                l = botb(:,6) >= magco-0.05;
                if length(botb(l,:)) >= Nmin
                    [botav2 botbv2 botstan2 ] =  bmemag(botb(l,:));
                    n2 = length(botb(l,:));

                else
                    botbv = nan; botbv2 = nan; magco = nan; botav = nan; botav2 = nan;
                    n2 = nan;
                    nobv = nobv + 1;
                end

            elseif inb1 == 2
                [topbv magco topstan topav topme topmer topme2,  toppr] =  bvalca3(topb,2,2);
                n1 = length(topb);
                [topav2 topbv2 topstan2 ] =  bmemag(topb);

                [botbv magco botstan botav botme botmer botme2,  botpr] =  bvalca3(botb,2,2);

                n2 = length(botb);
                [botav2 botbv2 botstan2 ] =  bmemag(botb);

            end

        else
            topbv = nan; topbv2 = nan; magco = nan; topav = nan; topav2 = nan;
            botbv = nan; botbv2 = nan; magco = nan; botav = nan; botav2 = nan;
            nobv = nobv + 1;

        end

        bv = topbv/botbv; bv2 = topbv2/botbv2; stan2 = topstan2/botstan2; av = topav/botav;
        stan = topstan/botstan;
        n = n1+n2; bo1 = topbv; b2 = botbv;
        da = -2*n*log(n) + 2*n1*log(n1+n2*bo1/b2) + 2*n2*log(n1*b2/bo1+n2) - 2;
        pr = (1  -  exp(-da/2-2))*100;

        bvg = [bvg ; bv magco x y rd bv2 av pr topbv botbv];
        waitbar(allcount/itotal)

    end

    snobv = num2str(nobv);
    spnobv = num2str((nobv/allcount)*100.0);
    disp(['Not enough EQs to calculate b values for ', snobv, ' gridnodes. This is ',spnobv,'% of the total'])

    save tmpncal.mat
    quit

    % for newgr
    %save cnssgrid.mat
    %quit
    % save data
    %
    catSave3 =...
        [ 'zmap_message_center.set_info(''Save Grid'',''  '');think;',...
        '[file1,path1] = uiputfile(fullfile(hodi, ''eq_data'', ''*.mat''), ''Grid Datafile Name?'') ;',...
        ' sapa2 = [''save '' path1 file1 '' bvg gx gy dx dy par1 tdiff t0b teb a main faults mainfault coastline yvect xvect tmpgri ll depth_ratio top_zonet top_zoneb bot_zoneb bot_zonet''];',...
        ' if length(file1) > 1, eval(sapa2),end , done']; eval(catSave3)

    close(wai)
    watchoff

    % plot the results
    % old and re3 (initially ) is the b-value matrix
    %
    normlap2=ones(length(tmpgri(:,1)),1)*nan;
    normlap2(ll)= bvg(:,1);
    re3=reshape(normlap2,length(yvect),length(xvect));

    normlap2(ll)= bvg(:,5);
    r=reshape(normlap2,length(yvect),length(xvect));

    normlap2(ll)= bvg(:,6);
    meg=reshape(normlap2,length(yvect),length(xvect));

    normlap2(ll)= bvg(:,2);
    old1=reshape(normlap2,length(yvect),length(xvect));

    %  normlap2(ll)= bvg(:,7);
    %  pro=reshape(normlap2,length(yvect),length(xvect));

    normlap2(ll)= bvg(:,7);
    avm=reshape(normlap2,length(yvect),length(xvect));

    %  normlap2(ll)= bvg(:,9);
    %  stanm=reshape(normlap2,length(yvect),length(xvect));

    normlap2(ll)= bvg(:,8);
    Prmap=reshape(normlap2,length(yvect),length(xvect));

    normlap2(ll)= bvg(:,9);
    top_b=reshape(normlap2,length(yvect),length(xvect));

    normlap2(ll)= bvg(:,10);
    bottom_b=reshape(normlap2,length(yvect),length(xvect));

    old = re3;

    % View the b-value map
    view_bdepth

end   % if sel = na

% Load exist b-grid
if sel == 'lo'
    [file1,path1] = uigetfile(['*.mat'],'b-value gridfile');
    if length(path1) > 1
        think
        load([path1 file1])
        normlap2=ones(length(tmpgri(:,1)),1)*nan;

        normlap2(ll)= bvg(:,1);
        re3=reshape(normlap2,length(yvect),length(xvect));

        normlap2(ll)= bvg(:,5);
        r=reshape(normlap2,length(yvect),length(xvect));

        normlap2(ll)= bvg(:,6);
        meg=reshape(normlap2,length(yvect),length(xvect));

        normlap2(ll)= bvg(:,2);
        old1=reshape(normlap2,length(yvect),length(xvect));

        %  normlap2(ll)= bvg(:,7);
        %  pro=reshape(normlap2,length(yvect),length(xvect));

        normlap2(ll)= bvg(:,7);
        avm=reshape(normlap2,length(yvect),length(xvect));

        %  normlap2(ll)= bvg(:,9);
        % stanm=reshape(normlap2,length(yvect),length(xvect));

        normlap2(ll)= bvg(:,8);
        Prmap=reshape(normlap2,length(yvect),length(xvect));

        normlap2(ll)= bvg(:,9);
        top_b=reshape(normlap2,length(yvect),length(xvect));

        normlap2(ll)= bvg(:,10);
        bottom_b=reshape(normlap2,length(yvect),length(xvect));

        old = re3;

        view_bdepth
    else
        return
    end
end


function f = tan(f)
%TAN   Tangent of a CHEBFUN3T object.

% 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

op = @(x,y,z) tan(feval(f, x, y, z));     % Resample
f = chebfun3t(op, f.domain);              % Call constructor.

end


% ------------------------------------------------------------------------
%  Copyright (C)
%  Universitat Politecnica de Catalunya BarcelonaTech (UPC) - Spain
%  University of California Berkeley (UCB) - USA
%
%  Jordi Pont-Tuset <jordi.pont@upc.edu>
%  Pablo Arbelaez <arbelaez@berkeley.edu>
%  June 2014
% ------------------------------------------------------------------------
% This file is part of the MCG package presented in:
%    Arbelaez P, Pont-Tuset J, Barron J, Marques F, Malik J,
%    "Multiscale Combinatorial Grouping,"
%    Computer Vision and Pattern Recognition (CVPR) 2014.
% Please consider citing the paper if you use this code.
% ------------------------------------------------------------------------
function boxes = labels2boxes(superpixels, labels)

% Get boxes of the superpixels
tmp = regionprops(superpixels,'BoundingBox');
tmp = cat(1,tmp.BoundingBox);
sp_bboxes = [tmp(:,2)+0.5, tmp(:,1)+0.5, tmp(:,2)+tmp(:,4)-0.5, tmp(:,1)+tmp(:,3)-0.5];

% Compute the boxes of the labels from those of the superpixels
boxes = zeros(length(labels),4);
for ii=1:length(labels)
    curr_sp_bboxes = sp_bboxes(labels{ii},:);
    boxes(ii,1) = min(curr_sp_bboxes(:,1));
    boxes(ii,2) = min(curr_sp_bboxes(:,2));
    boxes(ii,3) = max(curr_sp_bboxes(:,3));
    boxes(ii,4) = max(curr_sp_bboxes(:,4));
end


function [H, inls] = at_prosac_p3p(x1, x2, udists, TN, TLmax, tol, doLO, conf)

num_points = 3;
if nargin < 7
  conf = .95;     % in case, conf is not specified.
end;
len = size(x1,2);    % the maxinum number of points, i.e. "N" in PROSAC paper.
max_i = 3; % the number of inliers.
k_star = TN;  % the maximum number for terminating iteration. "n*" in PROSAC paper.

t = 0;
n_sub = num_points; % the number of subset points corresponds to "n" in PROSAC paper.
Tn = prosac_avsamplen(num_points,len,TN); % compute the average sampling number Tn'.
n_star = len; % the number of sampling=iteration corresponds to "n*" in PROSAC paper.

if ~exist('prosac_ImnP3P.mat','file') %|| len > 20000
  Imn = zeros(1,len);
  %%%%adhoc = round(len*(1-conf));
  adhoc = 0;
  for ii = 1:num_points+adhoc
    Imn(ii) = len;
  end
  for ii = num_points+1+adhoc:len
    Imn(ii) = prosac_nonrandom(num_points,ii,conf,0.1,len);
    fprintf('%d\n',ii)
  end
else
  r = load('prosac_ImnP3P.mat');
  Imn = r.Imn; clear r;
end;

H = [];
inls = [];

[~, sindx] = sort(udists);
tmax = TLmax;

x1h = x1;
x2h = x2;

x1h(end+1,:) = 1 ;
x2h(end+1,:) = 1 ;

while (t < k_star && t < tmax)
  t = t+1; %msg(1,'%d\n',t);
  if (t == Tn(n_sub) && n_sub < n_star)
    n_sub = n_sub + 1;
  end

  p_sample = sindx(prosac_rsample(num_points,Tn,t,n_sub));

  x1in = x1h(:,p_sample);
  x2in = x2h(:,p_sample);

  y = [x1in; x2in];

  pf = P3PSolver(y);

  e = PerspRepErr(P,X,K)

%   y = xf(:,i); % get a sample
%   pf = fitF(y); % fit a model
  r  = resF(pf,xr,cnstr); % eval residuals & constraints
  il = abs(r)<=maxres; % inliers
  if size(il,1)>1 % there are more alternative models returned by fitF
    in = sum(il,2); % inlier #
    [in,ix] = max(in);
    il = il(ix,:); % select the best inliers
    r = r(ix,:); % select the residuals
    pf = pf{ix}; % select the best model
  else
    in = sum(il); % inlier #
    if ~isempty(pf)
      if iscell(pf)
        pf = pf{1};
      end
    end
  end

  S1 = centering(x1in) ;
  S2 = centering(x2in) ;
  x1c = S1 * x1in ;
  x2c = S2 * x2in ;
  M = [x1c, zeros(size(x1c)) ;
    zeros(size(x1c)), x1c ;
    bsxfun(@times, x1c,  -x2c(1,:)), bsxfun(@times, x1c,  -x2c(2,:))] ;
  if any(isnan(M(:))), continue; end;
  if any(isinf(M(:))), continue; end;
  [H21,D] = svd(M,'econ') ;
  H21 = reshape(H21(:,end),3,3)' ;
  H21 = S2 \ H21 * S1 ;
  H21 = H21 ./ H21(end) ;

%   H21 = u2H([x2h(:,p_sample); x1h(:,p_sample)]);
%   if isempty(H21), continue; end;
%   H21 = H21 ./ H21(end);

  x1p = H21 * x1h;
  x1p = [x1p(1,:) ./ x1p(3,:) ; x1p(2,:) ./ x1p(3,:)] ;

%   tol = th * sqrt(det(H21(1:2,1:2)));
  dist2 = sum((x2 - x1p).^2,1) ;
  v = dist2 < tol^2;
  no_i = sum(v);

  if( max_i < no_i)
    if doLO && no_i > 4
      bH = u2H([x2h(:,v); x1h(:,v)]);
      bH = bH ./ bH(end);

      x1p = bH * x1h;
      x1p = [x1p(1,:) ./ x1p(3,:) ; x1p(2,:) ./ x1p(3,:)] ;
%       tol = th * sqrt(det(bH(1:2,1:2)));
      bdist2 = sum((x2 - x1p).^2,1) ;
      bv = bdist2 < tol^2;
      no_ib = sum(bv);
      if no_ib > no_i
        no_i = no_ib;
        H21 = bH;
        v = bv;
%         fprintf(1,'LO succeeded\n');
      end;
    end;
    max_i = no_i;
    H = H21;
    inls = find(v);

    %% STEP 6 maximality of iteration
    for cn = num_points:len
      Icn = sum(v(1:cn));
      kcn = nsamples(Icn, cn, num_points, conf);%msg(1,'kcn=%f\n',kcn);
      %                inlfrc = [inlfrc, Icn/cn];
      if cn < n_sub
        kcn = kcn - (t - Tn(cn));
      end;
      if Icn >= Imn(cn) && kcn < k_star
        n_star = cn;
        k_star = kcn;
      end;
    end;

%     k_star = nsamples(max_i, len, num_points, conf);
%     fprintf(1,'PROSAC(H) iter=%d, #inl=%d, k_star=%2.2f\n',t,max_i,k_star);
  end;
end;
% fprintf(1,'PROSAC(H) iter=%d, #inl=%d, k_star=%2.2f\n',t,max_i,k_star);

function urs_indx = prosac_rsample(m,Tn,t,n)
% prosac sampling
if Tn(n) > t
  tmp = randperm(n-1);
  urs_indx = [tmp(1:m-1),n];
else
  tmp = randperm(n-1);
  urs_indx = tmp(1:m);
  %msg(1,'why?\n');
end

function [SampleCnt, q] = nsamples(ni, ptNum, pf, conf)
%SampleCnt calculates number of samples needed to be done

q  = prod (((ni-pf+1) : ni) ./ ((ptNum-pf+1) : ptNum));
if q < eps
  SampleCnt = Inf;
else
  %   SampleCnt  = log(1 - conf) / log(1 - q);
  if q > conf
    SampleCnt = 1;
  else
    SampleCnt  = log(1 - conf) / log(1 - q);
  end;
end;

function Imin = prosac_nonrandom(m,n,conf,beta,len)
% compute the Imin whch express the non-randomness.

phi = 1-conf;
ii = (m:n);
Rn(ii) = binopdf(ii-m,n-m,beta); % see Eq. (7) in PROSAC paper.
for j = m:n
  if sum(Rn(j:n)) < phi
    Imin = j; break;   % see Eq. (8) in PROSAC paper.
  else
      Imin = len;
  end
end


function res = bf_inverse_nutmeg(BF, S)
% Interface to NUTMEG inverse methods
% http://www.nitrc.org/plugins/mwiki/index.php/nutmeg:MainPage
% Copyright (C) 2015 Wellcome Trust Centre for Neuroimaging

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

%--------------------------------------------------------------------------
if nargin == 0
    method = cfg_menu;
    method.tag = 'method';
    method.name = 'Method';
    method.labels = {
        'sLORETA'
        'swLORETA'
        'dSPM'};
    method.values = method.labels;
    method.help = {'Select one of NUTMEG methods'};

    snr = cfg_entry;
    snr.tag = 'snr';
    snr.name = 'SNR';
    snr.strtype = 'e';
    snr.num = [0 0];
    snr.val = {[]};
    snr.help = {'The assumed ratio of variances of signal and noise,',...
        'used for setting the regularisation parameter.'};

    regularisation = cfg_entry;
    regularisation.tag = 'regularisation';
    regularisation.name = 'Regularisation parameter';
    regularisation.strtype = 'e';
    regularisation.num = [0 0];
    regularisation.val = {[]};
    regularisation.help = {'Optional regularization parameter.'};

    nutmeg      = cfg_branch;
    nutmeg.tag  = 'nutmeg';
    nutmeg.name = 'NUTMEG methods';
    nutmeg.val  = {method, snr, regularisation};
    nutmeg.help = {'Methods ported from NUTMEG toolbox',...
        'See http://www.nitrc.org/plugins/mwiki/index.php/nutmeg:MainPage'};

    res = nutmeg;

    return
elseif nargin < 2
    error('Two input arguments are required');
end

C     =  BF.features.(S.modality).C;
U     =  BF.features.(S.modality).U;

L = S.L;
W = cell(size(L));
nvert = numel(W);

data.Ryy = C;
flags    = [];
if ~isempty(S.snr)
    flags.snr = S.snr;
end
if ~isempty(S.regularisation)
    flags.gamma = S.regularisation;
end

LL = [];
spm('Pointer', 'Watch');drawnow;
spm_progress_bar('Init', nvert, ['Preparing ' S.modality ' leadfields']); drawnow;
if nvert > 100, Ibar = floor(linspace(1, nvert,100));
else Ibar = 1:nvert; end

for i = 1:nvert
    lf = U'*L{i};

    LL = cat(3, LL, lf);

    if ismember(i, Ibar)
        spm_progress_bar('Set', i); drawnow;
    end
end

switch S.method
    case 'sLORETA'
        w = nut_sLORETA(LL,data,flags);
    case 'swLORETA'
        w = nut_swLORETA(LL,data,flags);
    case  'dSPM'
        w = nut_dSPM(LL,data,flags);
end

spm_progress_bar('Init', nvert, ['Preparing ' S.modality ' filters']); drawnow;
if nvert > 100, Ibar = floor(linspace(1, nvert,100));
else Ibar = 1:nvert; end

for i = 1:nvert
    W{i} = spm_squeeze(w(:, :, i), 3)';

    if ismember(i, Ibar)
        spm_progress_bar('Set', i); drawnow;
    end
end

spm_progress_bar('Clear');

res.W = W;


function result=cosmo_dim_generalization_measure(ds,varargin)
% measure generalization across pairwise combinations over time (or any other dimension)
%
% result=cosmo_dim_generalization_measure(ds,varargin)
%
% Inputs:
%   ds                  dataset struct with d being a sample dimension, and
%                       with ds.sa.chunks==1 for samples to use for
%                       training and ds.sa.chunks==2 for those to use for
%                       testing. Other values for chunks are not allowed.
%   'measure',m         function handle to apply to combinations of samples
%                       in the input dataset ds, such as
%                       - @cosmo_correlation_measure
%                       - @cosmo_crossvalidation_measure
%                       - @cosmo_target_dsm_corr_measure
%   'dimension',d       dimension along which to generalize. Typically this
%                       will be 'time' for MEEG data
%   'radius',r          radius used for the d dimension. For example, when
%                       set to r=4 with d='time', then 4*2+1 time points
%                       are used to asses generalization, (except on the
%                       edges). Note that when using a radius>0, it is
%                       assumed that splits of the dataset by dimension d
%                       have corresponding elements in the same order
%                       (such as provided by cosmo_dim_transpose).
%   'nproc', np         Use np parallel threads. (Multiple threads may
%                       speed up computations). If parallel processing is
%                       not available, or if this option is not provided,
%                       then a single thread is used.
%   K,V                 any other key-value pairs necessary for the measure
%                       m, for example 'classifier' if
%                       m=@cosmo_crossvalidation_measure.
%
% Output:
%    result             dataset with ['train_' d] and ['test_' d] as sample
%                       dimensions, i.e. these are in ds.a.sdim.labels
%                       result.samples is Nx1, where N=K*J is the number of
%                       combinations of (1) the K points in ds with
%                       chunks==1 and different values in dimension d, and
%                       (2) the J points in ds with chunks==2 and different
%                       values in dimension d.
%
% Examples:
%     % Generalization over time
%     sz='big';
%     train_ds=cosmo_synthetic_dataset('type','timelock','size',sz,...
%                                              'nchunks',2,'seed',1);
%     test_ds=cosmo_synthetic_dataset('type','timelock','size',sz,...
%                                              'nchunks',3,'seed',2);
%     % set chunks
%     train_ds.sa.chunks(:)=1;
%     test_ds.sa.chunks(:)=2;
%     %
%     % construct the dataset
%     ds=cosmo_stack({train_ds, test_ds});
%     %
%     % make time a sample dimension
%     dim_label='time';
%     ds_time=cosmo_dim_transpose(ds,dim_label,1);
%     %
%     % set measure and its arguments
%     measure_args=struct();
%     %
%     % use correlation measure
%     measure_args.measure=@cosmo_correlation_measure;
%     % dimension of interest is 'time'
%     measure_args.dimension=dim_label;
%     %
%     % run time-by-time generalization analysis
%     dgm_ds=cosmo_dim_generalization_measure(ds_time,measure_args,...
%                                               'progress',false);
%     %
%     % the output has train_time and test_time as sample dimensions
%     cosmo_disp(dgm_ds.a)
%     %|| .sdim
%     %||   .labels
%     %||     { 'train_time'  'test_time' }
%     %||   .values
%     %||     { [  -0.2        [  -0.2
%     %||         -0.15          -0.15
%     %||          -0.1           -0.1
%     %||           :              :
%     %||             0              0
%     %||          0.05           0.05
%     %||           0.1 ]@7x1      0.1 ]@7x1 }
%
%
%     % Searchlight example
%     % (This example requires FieldTrip)
%     cosmo_skip_test_if_no_external('fieldtrip');
%     %
%     sz='big';
%     train_ds=cosmo_synthetic_dataset('type','timelock','size',sz,...
%                                              'nchunks',2,'seed',1);
%     test_ds=cosmo_synthetic_dataset('type','timelock','size',sz,...
%                                              'nchunks',3,'seed',2);
%     % set chunks
%     train_ds.sa.chunks(:)=1;
%     test_ds.sa.chunks(:)=2;
%     %
%     % construct the dataset
%     ds=cosmo_stack({train_ds, test_ds});
%     %
%     % make time a sample dimension
%     dim_label='time';
%     ds_time=cosmo_dim_transpose(ds,dim_label,1);
%     %
%     % set measure and its arguments
%     measure_args=struct();
%     %
%     % use correlation measure
%     measure_args.measure=@cosmo_correlation_measure;
%     % dimension of interest is 'time'
%     measure_args.dimension=dim_label;
%     %
%     % only to make this example run fast, most channels are eliminated
%     % (there is no other reason to do this step)
%     ds_time=cosmo_slice(ds_time,ds_time.fa.chan<=20,2);
%     ds_time=cosmo_dim_prune(ds_time);
%     %
%     % define neighborhood for channels
%     nbrhood=cosmo_meeg_chan_neighborhood(ds_time,...
%                                 'chantype','meg_combined_from_planar',...
%                                 'count',5,'label','dataset');
%     %
%     % run searchlight with generalization measure
%     measure=@cosmo_dim_generalization_measure;
%     dgm_sl_ds=cosmo_searchlight(ds_time,nbrhood,measure,measure_args,...
%                                                 'progress',false);
%     %
%     % the output has train_time and test_time as sample dimensions,
%     % and chan as feature dimension
%     cosmo_disp(dgm_sl_ds.a,'edgeitems',1)
%     %|| .fdim
%     %||   .labels
%     %||     { 'chan' }
%     %||   .values
%     %||     { { 'MEG0112+0113' ... 'MEG0712+0713'   }@1x7 }
%     %|| .meeg
%     %||   .samples_type
%     %||     'timelock'
%     %||   .samples_field
%     %||     'trial'
%     %||   .samples_label
%     %||     'rpt'
%     %|| .sdim
%     %||   .labels
%     %||     { 'train_time'  'test_time' }
%     %||   .values
%     %||     { [ -0.2        [ -0.2
%     %||           :             :
%     %||          0.1 ]@7x1     0.1 ]@7x1 }
%
%
% Notes:
%   - this function can be used together with searchlight
%   - to make a dimension d a sample dimension from a feature dimension
%     (usually necessary before running this function), or the other way
%     around (usually necessary after running this function), use
%     cosmo_dim_transpose.
%   - a 'partition' argument should not be provided, because this function
%     generates them itself. The partitions are generated so that there
%     is a single fold; samples with chunks==1 are always used for training
%     and those with chunks==2 are used for testing (e.g. when using
%     m=@cosmo_crossvalidation_measure). In the case of using
%     m=@cosmo_correlation_measure, this amounts to split-half
%     correlations.
%
% See also: cosmo_correlation_measure, cosmo_crossvalidation_measure
%           cosmo_target_dsm_corr_measure, cosmo_searchlight,
%           cosmo_dim_transpose
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #

    defaults=struct();
    defaults.radius=0;
    defaults.progress=1;
    defaults.check_partitions=false;
    defaults.nproc=1;
    opt=cosmo_structjoin(defaults,varargin);

    cosmo_check_dataset(ds);
    check_input(ds,opt);

    % get training and test set
    halves=split_dataset_in_train_and_test(ds);

    % split the data in two halves
    [train_values,train_splits]=split_half_by_dimension(halves{1},opt);
    [test_values,test_splits]=split_half_by_dimension(halves{2},opt);

    halves=[]; % let GC do its work

    % get number of processes available
    nproc_available=cosmo_parallel_get_nproc_available(opt);

    % Matlab needs newline character at progress message to show it in
    % parallel mode; Octave should not have newline character
    environment=cosmo_wtf('environment');
    progress_suffix=get_progress_suffix(environment);

    % split training data in multiple parts, so that each thread can do a
    % subset of all the work
    % set options for each worker process
    worker_opt_cell=cell(1,nproc_available);
    block_size=ceil(length(train_values)/nproc_available);
    first=1;
    for p=1:nproc_available
        last=min(first+block_size-1,length(train_values));
        block_idxs=first:last;

        worker_opt=struct();
        worker_opt.train_splits=train_splits(block_idxs);
        worker_opt.train_values=train_values(block_idxs);
        worker_opt.train_values_ori=train_values;
        worker_opt.train_values_idx=block_idxs;
        worker_opt.test_splits=test_splits;
        worker_opt.test_values=test_values;
        worker_opt.opt=opt;
        worker_opt.worker_id=p;
        worker_opt.nworkers=nproc_available;
        worker_opt.progress=opt.progress;
        worker_opt.progress_suffix=progress_suffix;
        worker_opt_cell{p}=worker_opt;
        first=last+1;
    end

    % Run process for each worker in parallel
    % Note that when using nproc=1, cosmo_parcellfun does actually not
    % use any parallellization; the result is a cell with a single element.
    result_map_cell=cosmo_parcellfun(opt.nproc,...
                                     @run_with_worker,...
                                    worker_opt_cell,...
                                    'UniformOutput',false);

    result=cosmo_stack(result_map_cell,1);
    cosmo_check_dataset(result);

function result=run_with_worker(worker_opt)
% run dimgen using the options in worker_opt

    train_splits = worker_opt.train_splits;
    train_values = worker_opt.train_values;
    train_values_ori = worker_opt.train_values_ori;
    train_values_idx = worker_opt.train_values_idx;
    test_splits = worker_opt.test_splits;
    test_values = worker_opt.test_values;
    opt = worker_opt.opt;
    worker_id=worker_opt.worker_id;
    nworkers=worker_opt.nworkers;
    progress=worker_opt.progress;
    progress_suffix=worker_opt.progress_suffix;

    % set partitions in case a crossvalidation or correlation measure is
    % used
    ntrain_elem=cellfun(@(x)size(x.samples,1),train_splits);
    ntest_elem=cellfun(@(x)size(x.samples,1),test_splits);
    opt.partitions=struct();
    opt.partitions.train_indices=cell(1);
    opt.partitions.test_indices=cell(1);

    % remove the dimension and measure arguments from the input
    dimension=opt.dimension;
    measure=opt.measure;

    opt=rmfield(opt,'dimension');
    opt=rmfield(opt,'measure');

    train_label=['train_' dimension];
    test_label=['test_' dimension];

    % see if progress has to be shown
    show_progress=~isempty(progress) && ...
                        progress && ...
                        worker_id==1;
    if show_progress
        prev_progress_msg='';
        clock_start=clock();
    end

    % allocate space for output
    ntrain=numel(train_values);
    ntest=numel(test_values);

    result_cell=cell(ntrain*ntest,1);

    % last non-empty row in result_cell
    pos=0;

    for k=1:ntrain
        % update partitions train set
        opt.partitions.train_indices{1}=1:ntrain_elem(k);
        for j=1:ntest
            % update partitions test set
            opt.partitions.test_indices{1}=ntrain_elem(k)+...
                                                (1:ntest_elem(j));
            % merge training and test dataset
            ds_merged=cosmo_stack({train_splits{k},test_splits{j}},...
                                                        1,1,false);

            opt.partitions=cosmo_balance_partitions(opt.partitions,...
                                            ds_merged,opt);

            % apply measure
            ds_result=measure(ds_merged,opt);

            % set dimension attributes
            nsamples=size(ds_result.samples,1);
            ds_result.sa.(train_label)=repmat(train_values_idx(k),...
                                            nsamples,1);
            ds_result.sa.(test_label)=repmat(j,nsamples,1);

            % store result
            pos=pos+1;
            result_cell{pos}=ds_result;
        end

        if show_progress
            if nworkers>1
                if k==ntrain
                    % other workers may be slower than first worker
                    msg=sprintf(['worker %d has completed; waiting for '...
                                    'other workers to finish...%s'],...
                                    worker_id, progress_suffix);
                else
                    % can only show progress from a single worker;
                    % therefore show progress of first worker
                    msg=sprintf('for worker %d / %d%s', worker_id, ...
                                    nworkers, progress_suffix);
                end
            else
                % no specific message
                msg='';
            end
            prev_progress_msg=cosmo_show_progress(clock_start, ...
                            k/ntrain, msg, prev_progress_msg);
        end

    end

    % merge results into a dataset
    result=cosmo_stack(result_cell,1,'drop_nonunique');
    if isfield(result,'sa') && isfield(result.sa,dimension)
        result.sa=rmfield(result.sa,dimension);
    end

    % set dimension attributes in the sample dimension
    result=add_sample_attr(result, {train_label;test_label},...
                                    {train_values_ori;test_values});

function check_input(ds,opt)
    % ensure input is kosher
    cosmo_isfield(opt,{'dimension','measure'},true);

    dimension=opt.dimension;
    dim_pos=cosmo_dim_find(ds,dimension,true);
    if dim_pos~=1
        error(['''%s'' must be a sample dimension (not a feature) '...
                    'dimension. To make ''%s'' a sample dimension in '...
                    'a dataset struct ds, use\n\n'...
                    '  cosmo_dim_transpose(ds,''%s'',1);'],...
                    dimension,dimension,dimension);
    end

    measure=opt.measure;
    if ~isa(measure,'function_handle')
        error('the ''measure'' argument must be a function handle');
    end

    if isfield(opt,'partitions')
        error(['the partitions argument is not allowed for this '...
                    'function, because it generates partitions itself.'...
                    'The dataset should have two chunks, with '...
                    'chunks set to 1 for the training set and '...
                    'set to 2 for the testing set']);
    end

function halves=split_dataset_in_train_and_test(ds)
    % return cell with {train_ds,test_ds}
    halves=cosmo_split(ds,'chunks',1);
    if numel(halves)~=2 || ...
            halves{1}.sa.chunks(1)~=1 || ...
            halves{2}.sa.chunks(1)~=2
        error(['chunks must be 1 (for the training set) or 2'...
                '(for the testing set)' ]);
    end

function [values,splits]=split_half_by_dimension(ds,opt)
    % split dataset by ds.a.(opt.dimension)
    dimension=opt.dimension;
    ds_pruned=cosmo_dim_prune(ds,'labels',{dimension},'dim',1);
    ds_tr=cosmo_dim_transpose(ds_pruned,dimension,2);

    nbrhood=cosmo_interval_neighborhood(ds_tr,dimension,opt);
    assert(isequal(nbrhood.a.fdim.labels,{dimension}));

    counts=cellfun(@numel,nbrhood.neighbors);

    keep_nbrs=find(counts==max(counts));

    % remove dimension information
    ds_tr=remove_fa_field(ds_tr,dimension);

    values=nbrhood.a.fdim.values{1}(keep_nbrs);
    sz=size(values);
    if sz(1)==1
        values=values';
    elseif sz(2)~=1
        error('dimension %s must be a row vector', dimension);
    end

    n=numel(keep_nbrs);
    splits=cell(n,1);

    for k=1:n
        idx=nbrhood.neighbors{keep_nbrs(k)};
        splits{k}=cosmo_slice(ds_tr,idx,2,false);
    end

function ds=add_sample_attr(ds, dim_labels, dim_values)
    if ~isfield(ds,'a') || ~isfield(ds.a,'sdim')
        ds.a.sdim=struct();
        ds.a.sdim.labels=cell(1,0);
        ds.a.sdim.values=cell(1,0);
    end

    ds.a.sdim.values=[ds.a.sdim.values(:); dim_values]';
    ds.a.sdim.labels=[ds.a.sdim.labels(:); dim_labels]';

function ds=remove_fa_field(ds,label)
    if isfield(ds.fa,label);
        ds.fa=rmfield(ds.fa,label);
    end

    [dim, index, attr_name, dim_name]=cosmo_dim_find(ds,...
                                                label,false);
    if ~isempty(dim)
        sfdim=ds.a.(dim_name);
        m=~cosmo_match(sfdim.labels,label);
        sfdim.values=sfdim.values(m);
        sfdim.labels=sfdim.labels(m);
        ds.a.(dim_name)=sfdim;
    end

function suffix=get_progress_suffix(environment)
    % Matlab needs newline character at progress message to show it in
    % parallel mode; Octave should not have newline character

    switch environment
        case 'matlab'
            suffix=sprintf('\n');
        case 'octave'
            suffix='';
    end


% mtimesx_sparse does sparse matrix multiply of two inputs
%******************************************************************************
%
%  MATLAB (R) is a trademark of The Mathworks (R) Corporation
%
%  Function:    mtimesx_sparse
%  Filename:    mtimesx_sparse.m
%  Programmer:  James Tursa
%  Version:     1.00
%  Date:        September 27, 2009
%  Copyright:   (c) 2009 by James Tursa, All Rights Reserved
%
%  This code uses the BSD License:
%
%  Redistribution and use in source and binary forms, with or without
%  modification, are permitted provided that the following conditions are
%  met:
%
%     * Redistributions of source code must retain the above copyright
%       notice, this list of conditions and the following disclaimer.
%     * Redistributions in binary form must reproduce the above copyright
%       notice, this list of conditions and the following disclaimer in
%       the documentation and/or other materials provided with the distribution
%
%  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
%  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
%  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
%  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
%  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
%  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
%  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
%  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
%  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
%  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%  POSSIBILITY OF SUCH DAMAGE.
%
%--
%
% mtimesx_sparse is a helper function for mtimesx and is not intended to be called
% directly by the user.
%
% ---------------------------------------------------------------------------------------------------------------------------------

function result = mtimesx_sparse(a,transa,b,transb)
if( transa == 'N' )
    if( transb == 'N' )
        result = a * b;
    elseif( transb == 'G' )
        result = a * conj(b);
    elseif( transb == 'T' )
        result = a * b.';
    else
        result = a * b';
    end
elseif( transa == 'G' )
    if( transb == 'N' )
        result = conj(a) * b;
    elseif( transb == 'G' )
        result = conj(a) * conj(b);
    elseif( transb == 'T' )
        result = conj(a) * b.';
    else
        result = conj(a) * b';
    end
elseif( transa == 'T' )
    if( transb == 'N' )
        result = a.' * b;
    elseif( transb == 'G' )
        result = a.' * conj(b);
    elseif( transb == 'T' )
        result = a.' * b.';
    else
        result = a.' * b';
    end
else
    if( transb == 'N' )
        result = a' * b;
    elseif( transb == 'G' )
        result = a' * conj(b);
    elseif( transb == 'T' )
        result = a' * b.';
    else
        result = a' * b';
    end
end
end