function rtk=udbias_rtkins(rtk,obsr,obsb,nav,ind)

global glc;
tt=rtk.tt;  nf=rtk.NF; MAXSAT=glc.MAXSAT; NFREQ=glc.NFREQ;
sat=ind.sat; ns=ind.ns; ir=ind.ir; ib=ind.ib;

% detect cycle slip
for i=1:ns

    for f=1:rtk.opt.nf
        tmp=rtk.sat(sat(i)).slip(f);
        rtk.sat(sat(i)).slip(f)=bitand(tmp,252);%0xFC=252
    end

    % detect cycle slip using loss of lock indicator (LLI)
    rtk = detslip_LLI(rtk,obsr,ir(i),1);
    rtk = detslip_LLI(rtk,obsb,ib(i),2);

    % detect cycle slip using geometry-free method
    rtk = detslip_gf_L1L2(rtk,obsr(ir(i)),obsb(ib(i)),nav);
    rtk = detslip_gf_L1L5(rtk,obsr(ir(i)),obsb(ib(i)),nav);

    % detect cycle slip using doppler integration method
    %rtk = detslip_dop(rtk,obsr(i),1);
    %rtk = detslip_dop(rtk,obsb(i),2);

end

% update ambiguity
for f=1:nf

    % reset ambiguity if instantaneous AR mode or expire obs outage counter
    for i=1:MAXSAT
        rtk.sat(i).outc(f)=rtk.sat(i).outc(f)+1;
        if rtk.sat(i).outc(f)>rtk.opt.maxout,reset=1;else,reset=0;end

        if rtk.opt.modear==glc.ARMODE_INST && rtk.x(rtk.ib+i)~=0
            rtk=initx(rtk,0,0,rtk.ib+(f-1)*MAXSAT+i);
        elseif reset==1 && rtk.x(rtk.ib+i)~=0
            rtk=initx(rtk,0,0,rtk.ib+(f-1)*MAXSAT+i);
            rtk.sat(i).outc(f)=0;
        end

        if rtk.opt.modear~=glc.ARMODE_INST && reset==1
            rtk.sat(i).lock(f)=-rtk.opt.minlock;
        end
    end

    % reset ambiguity if detecting cycle slip
    for i=1:ns
        j=rtk.ib+(f-1)*MAXSAT+sat(i);
        rtk.P(j,j)=rtk.P(j,j)+rtk.opt.prn(1)^2*abs(tt);
        slip=rtk.sat(sat(i)).slip(f);
        if rtk.opt.ionoopt==glc.IONOOPT_IFLC
            slip=bitor(slip,rtk.sat(sat(i)).slip(f));
        end
        if rtk.opt.modear==glc.ARMODE_INST||~bitand(slip,1),continue;end
        rtk.x(j)=0;
        rtk.sat(sat(i)).lock(f)=-rtk.opt.minlock;
    end

    bias=zeros(ns,1);

    % estimate approximate ambiguity by code adn phase comparison method
    j=0; offset=0;
    for i=1:ns
        if rtk.opt.ionoopt~=glc.IONOOPT_IFLC
            cp=sdobs(obsr(ir(i)),obsb(ib(i)),f);
            pr=sdobs(obsr(ir(i)),obsb(ib(i)),NFREQ+f);
            lami=nav.lam(sat(i),f);
            if cp==0||pr==0||lami<=0,continue;end
            bias(i)=cp-pr/lami;
        else
            cp1=sdobs(obsr(ir(i)),obsb(ib(i)),1);
            cp2=sdobs(obsr(ir(i)),obsb(ib(i)),2);
            pr1=sdobs(obsr(ir(i)),obsb(ib(i)),NFREQ+1);
            pr2=sdobs(obsr(ir(i)),obsb(ib(i)),NFREQ+2);
            lam1=nav.lam(sat(i),1);
            lam2=nav.lam(sat(i),2);
            if cp1==0||cp2==0||pr1==0||pr2==0||lam1<=0||lam2<=0,continue;end

            C1= lam2^2/(lam2^2-lam1^2);
            C2=-lam1^2/(lam2^2-lam1^2);
            bias(i)=(C1*lam1*cp1+C2*lam2*cp2)-(C1*pr1+C2*pr2);
        end

        if rtk.x(rtk.ib+(f-1)*MAXSAT+sat(i))~=0
            offset=offset+(bias(i)-rtk.x(rtk.ib+(f-1)*MAXSAT+sat(i)));
            j=j+1;
        end
    end

    % correct phase-bias offset to enssure phase-code coherency
    if j>0
        for i=1:MAXSAT
            idx=rtk.ib+(f-1)*MAXSAT+i;
            if rtk.x(idx)~=0
                rtk.x(idx)=rtk.x(idx)+offset/j;
            end
        end
    end

    % set initial ambiguity
    for i=1:ns
        idx=rtk.ib+(f-1)*MAXSAT+sat(i);
        if bias(i)==0 || rtk.x(idx)~=0,continue;end
        rtk=initx(rtk,bias(i),rtk.opt.std(1)^2,idx);
    end

end

return


function [Population,T,best] = BSPTreeConstruction(Problem,P,T,best)
% Construction of the binary space partition tree

%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    Population = [];
    for i = 1 : size(P,1)
        if isempty(T)
            Population = [Population,Problem.Evaluation(P(i,:))];
            T    = NODE(P(i,:),1);
            best = struct('dec',P(i,:),'fitness',FitnessSingle(Population(end)),'level',1);
        else
            SubT = T;
            while ~isempty(SubT.left)
                if P(i,SubT.level) == 0
                    SubT = SubT.left;
                else
                    SubT = SubT.right;
                end
            end
            if SubT.level <= size(P,2)
                if P(i,SubT.level) == SubT.node(SubT.level)
                    if sum(P(i,:)~=best.dec) < sum(SubT.node~=best.dec)
                        P(i,SubT.level) = ~P(i,SubT.level);
                    else
                        SubT.node(SubT.level) = ~SubT.node(SubT.level);
                        Population = [Population,Problem.Evaluation(SubT.node)];
                        if FitnessSingle(Population(end)) < best.fitness
                            best = struct('dec',Population(end).dec,'fitness',FitnessSingle(Population(end)),'level',SubT.level+1);
                        end
                    end
                end
                if SubT.node(SubT.level) == 0
                    SubT.left  = NODE(SubT.node,SubT.level+1);
                    SubT.right = NODE(P(i,:),SubT.level+1);
                else
                    SubT.left  = NODE(P(i,:),SubT.level+1);
                    SubT.right = NODE(SubT.node,SubT.level+1);
                end
                Population = [Population,Problem.Evaluation(P(i,:))];
                if FitnessSingle(Population(end)) < best.fitness
                    best = struct('dec',Population(end).dec,'fitness',FitnessSingle(Population(end)),'level',SubT.level+1);
                end
            end
        end
    end
end


function handle = imageVisualise(imageVals, imageSize, transpose, negative, ...
				 scale)

% IMAGEVISUALISE Helper code for showing an image during 2-D visualisation.
% FORMAT
% DESC is a helper function for plotting image data using latent
% variable models.
% ARG imageValues : the values to set the image data to.
% ARG imageSize : the size of the image.
% ARG transpose : whether the resized image needs to be transposed
% (default 1, which is yes).
% ARG negative : whether to display the negative of the image
% (default 0, which is no).
% ARG scale : whether or not to use the imagesc function (defaults
% to 1, which is yes).
% RETURN handle : a the handle to the image data.
%
% COPYRIGHT : Neil D. Lawrence, 2003, 2004, 2006
%
% SEEALSO : imageModify, lvmResultsDynamic

% MLTOOLS

if nargin < 3
  transpose = 1;
end
if nargin< 4
  negative = 0;
end
if nargin < 5
  scale = 1;
end
if negative
  imageVals = -imageVals;
end
imageData = reshape(imageVals, imageSize(1), imageSize(2));
if transpose
  imageData = imageData';
end
if scale
  handle = imagesc(imageData);
else
  handle = image(imageData);
end
colormap gray


% LORENZ system
% Visualization for dependency on noise level

clear all, close all, clc

SystemModel = 'LORENZ';

figpath = '../FIGURES/'; mkdir(figpath)
datapath = ['../DATA/EX_',SystemModel,'_Dependencies/'];
addpath('../utils');

%% Paramaters
NARXtraining = 'trainbr'; %'trainlm',trainbr
InputSignalType = 'sphs'; %sphs,sine2
Ntrain_vec = 3000; %1000;
N_LENGTHS = length(Ntrain_vec);

eta_vec = [0.01 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 0.45 0.5];
N_ETA = length(eta_vec);

Nmodels = N_ETA*N_LENGTHS;

Nr = 50;
Nt = 1000; % length(tv);
Nvar = 3;
%% Load all models
ResultsALL(1:Nmodels,3) = struct('err', zeros(Nr,1), 'errM', zeros(Nr,1), 'xA', zeros(Nt,Nvar), 'xB', zeros(Nt,Nvar,Nr),'Ttraining',zeros(Nr,1));

count = 0;
for iN = 1:N_LENGTHS
    for iNoise = 1:N_ETA
        count = count + 1;

        %         ModelName = 'DMDc';
        %         datapath1 = [datapath,'DMDc/'];
        %         filename = fullfile(datapath1,['EX_LOTKA_SI_',ModelName,'_',InputSignalType,'_N',sprintf('%04g',Ntrain_vec(iN)),'_Eta',sprintf('%03g',100*eta_vec(iNoise)),'_STATS.mat']);
        %         load(filename);
        %         ResultsALL(count,1) = Results;
        ResultsALL(count,1) = struct('err', zeros(Nr,1), 'errM', zeros(Nr,1), 'xA', zeros(Nt,Nvar), 'xB', zeros(Nt,Nvar,Nr),'Ttraining',zeros(Nr,1));

        ModelName = 'SINDYc';
        datapath1 = [datapath,'SINDYc/'];
        filename = fullfile(datapath1,['EX_',SystemModel,'_SI_',ModelName,'_',InputSignalType,'_N',sprintf('%04g',Ntrain_vec(iN)),'_Eta',sprintf('%03g',100*eta_vec(iNoise)),'_STATS.mat']);
        load(filename);
        ResultsALL(count,2) = Results;

        ModelName = 'NARX';
        datapath1 = [datapath,'NARX/',NARXtraining,'/'];
        filename = fullfile(datapath1,['EX_',SystemModel,'_SI_',ModelName,'_',InputSignalType,'_N',sprintf('%04g',Ntrain_vec(iN)),'_Eta',sprintf('%03g',100*eta_vec(iNoise)),'_STATS.mat']);
        load(filename);
        ResultsALL(count,3) = Results;
    end
end

%%
clear ph
ccolors = [1 0 0; 0 1 0; 0.7,0.7,1];
symbols = {'o', 'd', 's'};
xx = 1:0.1:11;%0:0.01:0.6;
yy = zeros(3,length(xx));
err = zeros(Nr,N_ETA,3);
for iM = 1:3
    for i = 1:N_ETA, err(1:Nr,i,iM) = ResultsALL(i,iM).err(1:Nr); end
    if iM == 2
        xm = zeros(1,N_ETA);
        for k = 1:N_ETA
            TF = isnan(err(1:Nr,k,iM));
            xm(k) = median(err(TF==0,k,iM),1);
        end
    else
        xm = median(err(1:Nr,:,iM),1);
    end
    yy(iM,:) = spline(1:11,xm,xx); %eta_vec(:)
end
figure; hold on
data = err(1:Nr,eta_vec==0.4,2);% sine 0.4, sphs 0.45: 278.4062
% ylimregion = median(data(isnan(data)==0))
ylimregion = 300;
fillh1 = fill([0.1 11.9 11.9 0.1], [10 10 ylimregion.*ones(1,2)],0.9*ones(1,3));
fillh1.EdgeColor = 0.9*ones(1,3); fillh1.FaceAlpha = 0.5;
%ph(1)=plot(xx,yy(1,:),'-r','LineWidth',1); hold on,
ph(2)=plot(xx(1:end),yy(2,1:end),'-g','LineWidth',1);
ph(3)=plot(xx(1:end),yy(3,1:end),'-','Color',[0.7,0.7,1],'LineWidth',1);
ph(1) = [];
% plot([0,12],max(err(1:Nr,eta_vec==0.3,2)).*ones(1,2),'-k')
for iM = 2:3
    boxplot(err(:,:,iM),'PlotStyle','compact','Colors',ccolors(iM,:), 'Symbol', symbols{iM}, ... %, 'Labels', num2str(eta_vec'), eta_vec
        'Widths',0.1); hold on
    delete(findobj(gca,'Type','text'))
end
set(gca,'xtick',[1:2:11],'xticklabel',num2str(eta_vec(1:2:end)'),'Position',[0.2 0.22 0.75 0.73])
xlim([0 12]), ylim([0 1300])
xt = xlabel('Eta'); xt.Position = [115 -20 -0.1];
ylabel('MSE')
set(gca,'LineWidth',1, 'FontSize',14)
set(gcf,'Position',[100 100 300 200])
set(gcf,'PaperPositionMode','auto'),
print('-depsc2', '-painters', '-loose', '-cmyk', [figpath,'EX_',SystemModel,'_PREDPERF_',InputSignalType,'_N',sprintf('%04g',Ntrain_vec(iN)),'_noise_',NARXtraining,'_noleg.eps']);

% l1 = legend(ph,'DMDc','SINDYc','NARX');
l1 = legend(ph,'SINDYc','NARX');
set(l1,'Location','NorthWest')
l1.Position = [l1.Position(1)-0.01 l1.Position(2)+0.02 l1.Position(3)-0.01 l1.Position(4)];
print('-depsc2', '-painters', '-loose', '-cmyk', [figpath,'EX_',SystemModel,'_PREDPERF_',InputSignalType,'_N',sprintf('%04g',Ntrain_vec(iN)),'_noise_',NARXtraining,'.eps']);

%%
clear ph
ccolors = [1 0 0; 0 1 0; 0.7,0.7,1];
symbols = {'o', 'd', 's'};
xx = 1:0.1:11;%0:0.01:0.6;
yy = zeros(3,length(xx));
err = zeros(Nr,N_ETA,3);
for iM = 1:3
    for i = 1:N_ETA, err(1:Nr,i,iM) = ResultsALL(i,iM).errM(1:Nr); end
    if iM == 2
        xm = zeros(1,N_ETA);
        for k = 1:N_ETA
            TF = isnan(err(1:Nr,k,iM));
            xm(k) = median(err(TF==0,k,iM),1);
        end
    else
        xm = median(err(1:Nr,:,iM),1);
    end
    yy(iM,:) = spline(1:11,xm,xx); %eta_vec(:)
end
figure; hold on
fillh1 = fill([0.1 11.9 11.9 0.1], [10 10 ylimregion.*ones(1,2)],0.9*ones(1,3));
fillh1.EdgeColor = 0.9*ones(1,3); fillh1.FaceAlpha = 0.5;
% ph(1)=plot(xx,yy(1,:),'-r','LineWidth',1); hold on,
ph(2)=plot(xx(1:end),yy(2,1:end),'-g','LineWidth',1);
ph(3)=plot(xx(1:end),yy(3,1:end),'-','Color',[0.7,0.7,1],'LineWidth',1);
ph(1) = [];
% plot([0,12],max(err(1:Nr,eta_vec==0.3,2)).*ones(1,2),'-k')
for iM = 2:3
    boxplot(err(:,:,iM),'PlotStyle','compact','Colors',ccolors(iM,:), 'Symbol', symbols{iM}, ... %, 'Labels', num2str(eta_vec'), eta_vec
        'Widths',0.1); hold on
    delete(findobj(gca,'Type','text'))
end
set(gca,'xtick',[1:2:11],'xticklabel',num2str(eta_vec(1:2:end)'),'Position',[0.2 0.22 0.75 0.73])
xlim([0 12]), ylim([0 1300])
xt = xlabel('Eta'); xt.Position = [115 -20 -0.1];
ylabel('MSE')
set(gca,'LineWidth',1, 'FontSize',14)
set(gcf,'Position',[100 100 300 200])
set(gcf,'PaperPositionMode','auto'),
print('-depsc2', '-painters', '-loose', '-cmyk', [figpath,'EX_',SystemModel,'_PREDPERF_',InputSignalType,'_N',sprintf('%04g',Ntrain_vec(iN)),'_noiseM_',NARXtraining,'_noleg.eps']);

% l1 = legend(ph,'DMDc','SINDYc','NARX');
l1 = legend(ph,'SINDYc','NARX');
set(l1,'Location','NorthWest')
% l1.Position = [l1.Position(1)-0.06 l1.Position(2)-0.07 l1.Position(3)-0.01 l1.Position(4)];
% l1.Position = [l1.Position(1)+0.08 l1.Position(2)-0.08 l1.Position(3)-0.01 l1.Position(4)];
l1.Position = [l1.Position(1)-0.01 l1.Position(2)+0.02 l1.Position(3)-0.01 l1.Position(4)];
print('-depsc2', '-painters', '-loose', '-cmyk', [figpath,'EX_',SystemModel,'_PREDPERF_',InputSignalType,'_N',sprintf('%04g',Ntrain_vec(iN)),'_noiseM_',NARXtraining,'.eps']);

%% Normalized error
clear LegLoc
LOG_SCALE = 0;
data2plot = zeros(Nr,N_ETA,3);
% for iN = 1:N_LENGTHS
for iNoise = 1:N_ETA
    for iR = 1:Nr
        for iM = 1:3
            data2plot(iR,iNoise,iM) = mean( sum( abs(ResultsALL(iNoise,iM).xA - ResultsALL(iNoise,iM).xB(:,:,iR))./abs(ResultsALL(iNoise,iM).xA) ,2)  );
            %data2plot(iR,iNoise,iM) = mean( abs(sum( (ResultsALL(iNoise,iM).xA - ResultsALL(iNoise,iM).xB(:,:,iR))./ResultsALL(iNoise,iM).xA ,2)) );
        end
    end
end
% end

PostName = 'RelErr';
ytext = 'Avg. Rel. Error';
yaxlim = [0 14];
shaded_region = 0;
VIZ_ERROR_STATS

%%
iNoise = 1; iM = 3;
figure, hold on
plot(ResultsALL(iNoise,iM).xA,'-k')
for i = 1:Nr
    plot(ResultsALL(iNoise,iM).xB(:,:,iR),'--r');%,'Color',[0.7,0.7,0.7])
end
%%
ModelSelection = {'DMDc','SINDYc', 'NARX'};
dt = 0.01;
ccolors = [1 0 0; 0 1 0; 0.7,0.7,1];
tspan = [1:Nt].*dt+30;
iM = 3;
data2plot = zeros(Nt,N_ETA,3);

for iM = 2:3
    PostName = ['_TS_',ModelSelection{iM}];
    for iNoise = 1:N_ETA
        f1 = figure('visible','off');hold on, box on
        xshift = [-35,0,+20];
        for iVar = 1:Nvar
            %data2plot(iT,iNoise,iM) = (ResultsALL(iNoise,iM).xA - ResultsALL(iNoise,iM).xB(:,:,iR));
            %boxplot(squeeze(ResultsALL(iNoise,iM).xB(1:10:end,1,:))')
            Xstats = squeeze(ResultsALL(iNoise,iM).xB(1:1:end,iVar,:))';
            Ystats = prctile(Xstats,[25 50 75],1);

            X=[tspan(1:end),fliplr(tspan(1:end))];                %#create continuous x value array for plotting
            Y=[Ystats(1,:)+xshift(iVar),fliplr(Ystats(3,:))+xshift(iVar)];              %#create y values for out and then back
            fillh1 = fill(X,Y,ccolors(iM,:));                  %#plot filled area
            fillh1.EdgeColor = ccolors(iM,:);
            fillh1.FaceAlpha = 0.3;
            fillh1.EdgeAlpha = 0.3;

            plot(tspan,Ystats(2,:)+xshift(iVar),'-','Color',ccolors(iM,:),'LineWidth',1)
            %                 plot(tspan,Ystats(1,:),'--','Color',ccolors(iM,:))
            %                 plot(tspan,Ystats(3,:),'--','Color',ccolors(iM,:))
            plot(tspan,ResultsALL(iNoise,iM).xA(1:1:end,iVar)+xshift(iVar),'-k','LineWidth',1)%,'Color',[0.7,0.7,0.7])
        end
        ylim([-60 65])
        ylabel('xi'), xlabel('Time')
        set(gca,'LineWidth',1, 'FontSize',14)
        set(gcf,'Position',[100 100 300 200])
        set(gcf,'PaperPositionMode','auto'),
        drawnow
        print('-depsc2', '-painters', '-loose', '-cmyk', [figpath,'EX_',SystemModel,'_PREDPERF_',InputSignalType,'_N',sprintf('%04g',Ntrain_vec(iN)),'_noise',sprintf('%03g',100*eta_vec(iNoise)),'_',NARXtraining,'_',PostName,'_noleg.eps']);
        close(f1);

    end
end

%% Training time
LOG_SCALE = 1;
data2plot = zeros(Nr,N_ETA,3);
% for iN = 1:N_LENGTHS
for iNoise = 1:N_ETA
    for iR = 1:Nr
        for iM = 1:3
            data2plot(iR,iNoise,iM) = ResultsALL(iNoise,iM).Ttraining(iR);
        end
    end
end
% end

clear YSCALE_SET
PostName = 'TrainTime';
ytext = 'Training Time [s]';
yaxlim = [0 max(data2plot(:))];
shaded_region = 0;
LegLoc = 'NorthEast';
VIZ_ERROR_STATS

% Zoom
% PostName = 'TrainTimeZOOM';
% yaxlim = [0 0.04];
% VIZ_ERROR_STATS
%% Prediction horizon
dt = 0.01;
clear ph
ccolors = [1 0 0; 0 1 0; 0.7,0.7,1];
ERR_RADIUS = 0.1;
PredHor_Ball = zeros(Nr,N_ETA,Nmodels);
PredHor_Max = zeros(Nr,N_ETA,Nmodels);
%Err_SMAPE = zeros(Nr,N_ETA,Nmodels);
Err_Ratio = zeros(Nr,N_ETA,Nmodels);
for iM = 2:3
    for iNoise = 1:N_ETA
        for iR = 1:Nr
            tmp =  (ResultsALL(iNoise,iM).xA - ResultsALL(iNoise,iM).xB(:,:,iR))./ResultsALL(iNoise,iM).xA ;
            TF = abs(tmp)>0.1;
            idx = [];
            for iVar = 1:Nvar
                idx = [idx ; find(TF(:,iVar)==1,1,'first')];
            end
            PredHor_Max(iR,iNoise,iM) = max(idx);

%             tmp2 = sqrt(sum(tmp.^2,2));
            tmp2 = sqrt(sum(abs((ResultsALL(iNoise,iM).xA - ResultsALL(iNoise,iM).xB(:,:,iR))).^2,2));
            idx = find(tmp2>3,1,'first');
            PredHor_Ball(iR,iNoise,iM) = idx-1;

            %Err_SMAPE(iR,iNoise,iM) =  sum(sum(abs(sum(ResultsALL(iNoise,iM).xB(:,:,iR)-ResultsALL(iNoise,iM).xA)./sum(ResultsALL(iNoise,iM).xA + ResultsALL(iNoise,iM).xB(:,:,iR)))./Nt))./Nvar;
            Err_Ratio(iR,iNoise,iM) =  sum(sum( abs((ResultsALL(iNoise,iM).xB(:,:,iR)./ResultsALL(iNoise,iM).xA))  )./Nt)./Nvar;

        end
    end
end

%%
data2plot = (PredHor_Ball).*dt;
PostName = 'PredHoriz_Ball';
ytext = 'Pred. Horizon';
yaxlim = [10^-3 10^1];
%yaxlim = [0 10];
LOG_SCALE = 1;
YSCALE_SET = 1;
shaded_region = 0;
LegLoc = 'NorthEast';
VIZ_ERROR_STATS

return
data2plot = PredHor_Max;
PostName = 'PredHoriz_Max';
ytext = 'Pred. Horizon';
yaxlim = [10^-1 10^3];
LOG_SCALE = 1;
YSCALE_SET = 1;
shaded_region = 0;
LegLoc = 'NorthEast';
VIZ_ERROR_STATS

data2plot = Err_Ratio;
PostName = 'Err_Ratio';
ytext = 'Error';
yaxlim = [10^-1 10^1];
LOG_SCALE = 1;
YSCALE_SET = 1;
shaded_region = 0;
LegLoc = 'NorthEast';
VIZ_ERROR_STATS


function [out1] = points_on_line(inp1, inp2, inp3, inp4, inp5)
out1 = [];
ns = getNamespace();
if isempty(ns)
    return;
end
if strcmp(ns, 'AtlasViewerGUI')
    if nargin == 0
        [out1] = points_on_line_AtlasViewerGUI();
    elseif nargin == 1
        [out1] = points_on_line_AtlasViewerGUI(inp1);
    elseif nargin == 2
        [out1] = points_on_line_AtlasViewerGUI(inp1, inp2);
    elseif nargin == 3
        [out1] = points_on_line_AtlasViewerGUI(inp1, inp2, inp3);
    elseif nargin == 4
        [out1] = points_on_line_AtlasViewerGUI(inp1, inp2, inp3, inp4);
    elseif nargin == 5
        [out1] = points_on_line_AtlasViewerGUI(inp1, inp2, inp3, inp4, inp5);
    end
elseif strcmp(ns, 'Homer3') || strcmp(ns, 'DataTreeClass')
    if nargin == 0
        [out1] = points_on_line_Homer3();
    elseif nargin == 1
        [out1] = points_on_line_Homer3(inp1);
    elseif nargin == 2
        [out1] = points_on_line_Homer3(inp1, inp2);
    elseif nargin == 3
        [out1] = points_on_line_Homer3(inp1, inp2, inp3);
    elseif nargin == 4
        [out1] = points_on_line_Homer3(inp1, inp2, inp3, inp4);
    end
end

% ---------------------------------------------------------
function [p3] = points_on_line_AtlasViewerGUI(p1, p2, crop, mode, gridsize)

%
% USAGE:
%
%    p3 = points_on_line_AtlasViewerGUI(p1,p2,crop,mode)
%
% DESCRIPTION:
%
%    Function takes 2 points in 3d, p1 and p2, and a crop length
%    and finds a point on the line formed by extending p1,p2 by the
%    amount (or fraction of p1-p2 distance) crop extends away from p1.
%
%    Positive crop crops p1,p2 by the crop amount.
%    Negative crop extends p1,p2 by the crop amount.
%
%    mode = 'relative' means crop is the distance p3 extends away from p1 relative
%    to the distance between p1 and p2. This is the default if no mode is provided.
%
%    mode = 'absolute' means crop is the absolute distance (in unit length) that
%    p3 extends away from p1.
%
%    mode = 'all' returns the set of all points at intervals 1/crop on the line
%    segment between p1 and p2.
%
% AUTHOR: Jay Dubb (jdubb@nmr.mgh.harvard.edu)
% DATE:   7/7/2012
%

if ~exist('mode','var') || isempty(mode)
    mode = 'relative';
end
if ~exist('gridsize','var') || isempty(gridsize)
    gridsize = 0;
end

p3 = p1;

if isempty(p1) || isempty(p2)
    return;
end
if all(p1==p2)
    return;
end

if ~exist('crop','var') || isempty(crop)
    crop = set_line_crop_AtlasViewerGUI(p2, p1, gridsize);
end

dx0 = p1(1)-p2(1);
dy0 = p1(2)-p2(2);
dz0 = p1(3)-p2(3);
dr = (dx0*dx0 + dy0*dy0 + dz0*dz0)^0.5;
if strcmp(mode, 'relative')
    crop = crop*dr;
    dx = crop*dx0/dr;
    dy = crop*dy0/dr;
    dz = crop*dz0/dr;
elseif strcmp(mode, 'absolute')
    crop = crop/dr;
    dx = crop*dx0;
    dy = crop*dy0;
    dz = crop*dz0;
elseif strcmp(mode, 'all')
    if crop > 1
        return;
    end
    ii=1;
	step = crop;
    while (step*ii)<1
        crop = (step*ii)*dr;
        dx(ii) = crop*dx0/dr;
        dy(ii) = crop*dy0/dr;
        dz(ii) = crop*dz0/dr;
        ii=ii+1;
    end
end

for ii=1:length(dx)
    p3(ii,1) = p1(1)-dx(ii);
    p3(ii,2) = p1(2)-dy(ii);
    p3(ii,3) = p1(3)-dz(ii);
end

% ------------------------------------------------------------------------
function [gapRelative] = set_line_crop_AtlasViewerGUI(p1, p2, gridsize)
gapRelative = .05;

if isempty(p1) || isempty(p2)
    return;
end

% Set desired absolute gap distance
gapAbsolute  = 1;
lineSize     = dist3(p1, p2);

% Get relative gap distance
gapRelative = gapAbsolute / lineSize;
% fprintf('Line gap: relative = %0.2f, absolute: %0.2f\n', gapRelative, gapAbsolute);

if gapRelative > .10
    gapRelative = .02;
end

% ---------------------------------------------------------
function [p3] = points_on_line_Homer3(p1, p2, step, mode)

%
% USAGE:
%
%    p3 = points_on_line_Homer3(p1,p2,step,mode)
%
% DESCRIPTION:
%
%    Function takes 2 points in 3d, p1 and p2, and a step length
%    and finds a point on the line formed by extending p1,p2 by the
%    amount (or fraction of p1-p2 distance) step extends away from p1.
%
%    Positive step crops p1,p2 by the step amount.
%    Negative step extends p1,p2 by the step amount.
%
%    mode = 'relative' means step is the distance p3 extends away from p1 relative
%    to the distance between p1 and p2. This is the default if no mode is provided.
%
%    mode = 'absolute' means step is the absolute distance (in unit length) that
%    p3 extends away from p1.
%
%    mode = 'all' returns the set of all points at intervals 1/step on the line
%    segment between p1 and p2.
%
% AUTHOR: Jay Dubb (jdubb@nmr.mgh.harvard.edu)
% DATE:   7/7/2012
%

if ~exist('mode','var')
    mode = 'relative';
end

p3 = p1;

if all(p1==p2)
    return;
end

dx0 = p1(1)-p2(1);
dy0 = p1(2)-p2(2);
dz0 = p1(3)-p2(3);
dr = (dx0*dx0 + dy0*dy0 + dz0*dz0)^0.5;
if strcmp(mode, 'relative')
    crop = step*dr;
    dx = crop*dx0/dr;
    dy = crop*dy0/dr;
    dz = crop*dz0/dr;
elseif strcmp(mode, 'absolute')
    crop = step/dr;
    dx = crop*dx0;
    dy = crop*dy0;
    dz = crop*dz0;
elseif strcmp(mode, 'all')
    if step > 1
        return;
    end
    ii=1;
    while (step*ii)<1
        crop = (step*ii)*dr;
        dx(ii) = crop*dx0/dr;
        dy(ii) = crop*dy0/dr;
        dz(ii) = crop*dz0/dr;
        ii=ii+1;
    end
end

for ii=1:length(dx)
    p3(ii,1) = p1(1)-dx(ii);
    p3(ii,2) = p1(2)-dy(ii);
    p3(ii,3) = p1(3)-dz(ii);
end


function handle = skelVargplvmVisualise(yVal, chan, skel, padding)

% SKELVISUALISE For drawing a skel representation of 3-D data.
% FORMAT
% DESC draws a skeleton representation in a 3-D plot.
% ARG channels : the channels to update the skeleton with.
% ARG skel : the skeleton structure.
% RETURN handle : a vector of handles to the plotted structure.
%
% SEEALSO : skelVargplvmModify
%
% COPYRIGHT : Neil D. Lawrence, 2005, 2006
% MODIFICATIONS: Andreas C. Damianou, 2014

% SHEFFIELDML

if nargin<4
  padding = 0;
end
if isempty(yVal)
    channels = chan(1,:);
else
    channels = demCmu35VargplvmLoadChannels(yVal,skel);
end
channels = [channels zeros(1, padding)];
vals = skel2xyz(skel, channels);
connect = skelConnectionMatrix(skel);

indices = find(connect);
[I, J] = ind2sub(size(connect), indices);
handle(1) = plot3(vals(:, 1), vals(:, 3), vals(:, 2), '.');
axis ij % make sure the left is on the left.
set(handle(1), 'markersize', 20);
%/~
%set(handle(1), 'visible', 'off')
%~/
hold on
grid on
for i = 1:length(indices)
  handle(i+1) = line([vals(I(i), 1) vals(J(i), 1)], ...
              [vals(I(i), 3) vals(J(i), 3)], ...
              [vals(I(i), 2) vals(J(i), 2)]);
  set(handle(i+1), 'linewidth', 2);
end
axis equal
xlabel('x')
ylabel('z')
zlabel('y')
axis on


function computeAllPredictionRF_batchHN(pathExperiments,expNumber,maxOrder,nBoot,imbalance,nBatch,matlabPATH,seed)
% -------------------------------------------------------------------------
% function computeAllPrediction_HN(pathWORK,fSetName,outcomes,freedomMat,maxOrder,nBoot,imbalance,nBatch,matlabPATH)
% -------------------------------------------------------------------------
% DESCRIPTION:
% This function computes prediction performance estimation for a given
% feature set type, and for all model orders of all experiments with
% different degrees of freedom. See ref. [1,2] for more details.
% -------------------------------------------------------------------------
% REFERENCE:
% [1] Vallieres, M. et al. (2015). FDG-PET/CT radiomics models for the
%     early prediction of different tumour outcomes in head and neck cancer.
%     The Journal of Nuclear Medicine, aa(bb), xxx-yyy.
%     doi:
% [2] Vallieres, M. et al. (2015). A radiomics model from joint FDG-PET and
%     MRI texture features for the prediction of lung metastases in soft-tissue
%     sarcomas of the extremities. Physics in Medicine and Biology, 60(14),
%     5471-5496. doi:10.1088/0031-9155/60/14/5471
% -------------------------------------------------------------------------
% INPUTS:
% 1. pathExperiments: Full path to where all experiments need to be
%                     performed.
%                     --> Ex: /myProject/WORKSPACE/RESULTS
% 2. expNumber: Number of the single experiment to perform
%                  --> Ex: 4
% 3. maxOrder: Integer specifying the maximal model order to construct.
%              --> Ex: 10
% 4. nBoot: Number of bootstrap samples to use.
%           --> Ex: 100
% 5. imbalance: String specifying the type of imbalance-adjustement strategy
%               employed. Either 'IABR' for imbalance-adjusted bootstrap
%               resampling (see ref.[1]), or 'IALR' for imbalance-adjusted
%               logistic regression (see ref.[2]).
%               --> Ex: 'IALR'
% 6. nBatch: Number of parallel batch.
%            --> Ex: 8
% 7. matlabPATH: Full path to the MATLAB excutable on the system.
%                --> 'matlab' if a symbolic link to the matlab executable
%                     was previously created.
% -------------------------------------------------------------------------
% OUTPUTS: Prediction performance results are saved in a folder named 'RESULTS' in the
% corresponding folder of each experiment (e.g. 'Experiment1', 'Experiment2', etc.)
% -------------------------------------------------------------------------
% AUTHOR(S): Martin Vallieres <mart.vallieres@gmail.com>
% -------------------------------------------------------------------------
% HISTORY:
% - Creation: March 2016
%--------------------------------------------------------------------------
% STATEMENT:
% This file is part of <https://github.com/mvallieres/radiomics/>,
% a package providing MATLAB programming tools for radiomics analysis.
% --> Copyright (C) 2015  Martin Vallieres
%
%    This package is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    This package is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with this package.  If not, see <http://www.gnu.org/licenses/>.
% -------------------------------------------------------------------------

startpath = pwd;

% INITIALIZATON
time = 60; % Number of seconds to wait before checking if parallel computations are done
cd(fullfile(pathExperiments,['Experiment',num2str(expNumber)])), load('training')
pathModels = fullfile(pwd,'MODELS'); mkdir('RESULTS'), cd('RESULTS'), pathResults = pwd;
mkdir('batchLog_Results'), cd('batchLog_Results'), pathBatch = pwd;
nameOutcomes = fieldnames(training); nOutcomes = numel(nameOutcomes);
for o = 1:nOutcomes
    outcomes.(nameOutcomes{o}) = training.(nameOutcomes{o}).outcome;
end
setNames = fieldnames(training.(nameOutcomes{1}).variables);
[param] = batchExperiments(setNames,outcomes,nBatch); nBatch = length(param);

% PRODUCE BATCH COMPUTATIONS
save('workspace','pathModels','pathResults','training','param','maxOrder','nBoot','imbalance','seed'), pause(5);
for i = 1:nBatch
    nameScript = ['batch',num2str(i),'_script.m'];
    fid = fopen(nameScript,'w');
    fprintf(fid,'load(''workspace'')\n');
    for j = 1:numel(param{i})
        fprintf(fid,['computeAllPredictionRF_HN(pathModels,pathResults,training,param{',num2str(i),'}{',num2str(j),'},maxOrder,nBoot,imbalance,seed)\n']);
    end
    fprintf(fid,['system(''touch batch',num2str(i),'_end'');\n']);
    fprintf(fid,'clear all');
    fclose(fid);
    system([matlabPATH,' -nojvm -nodisplay -nodesktop -nosplash < ',nameScript,' >& ',nameScript(1:end-1),'log &']);
end

% WAITING LOOP
waitBatch(pathBatch,time,nBatch)
delete('workspace.mat')

cd(startpath)
end


function [sec,day]=time2sec(time)

ep=time2epoch(time);
sec=ep(4)*3600+ep(5)*60+ep(6);
ep(4)=0;ep(5)=0;ep(6)=0;
day=epoch2time(ep);

return


function engine = hmm_2TBN_inf_engine(bnet, varargin)
% HMM_2TBN_INF_ENGINE Inference engine for DBNs which uses the forwards-backwards algorithm.
% engine = hmm_2TBN_inf_engine(bnet, ...)
%
% The DBN is converted to an HMM with a single meganode, but the observed nodes remain factored.
% This can be faster than jtree if the num. hidden nodes is low, because of lower constant factors.
%
% All hidden nodes must be discrete.
% All observed nodes are assumed to be leaves.
% The parents of each observed leaf are assumed to be a subset of the hidden nodes within the same slice.
% The only exception is if bnet is an AR-HMM, where the parents are assumed to be self in the
% previous slice (continuous), plus all the discrete nodes in the current slice.

%% Optional arguments
%% ndx_type - 'B', 'D', or 'SD', used in marginal_family [ 'SD' ]

ndx_type = 'SD';
ss = bnet.nnodes_per_slice;

% parse optional params
args = varargin;
nargs = length(args);
if nargs > 0
  for i=1:2:nargs
    switch args{i},
     %case 'ndx_type', ndx_type = args{i+1};
     otherwise,
      error(['invalid argument name ' args{i}]);
    end
  end
end

% Stuff to do with speeding up marginal_family
%engine.ndx_type = ndx_type;

[int, engine.persist, engine.transient] = compute_interface_nodes(bnet.intra, bnet.inter);
engine.persist_bitv = zeros(1, ss);
engine.persist_bitv(engine.persist) = 1;

ns = bnet.node_sizes(:);
ns(bnet.observed) = 1;
ns(bnet.observed+ss) = 1;
engine.eff_node_sizes = ns;

% for n=1:ss
%   dom = 1:(2*ss); % domain of xi(:,:,1)
%   fam = family(bnet.dag, n+ss);
%   engine.marg_fam2_ndx_id(n) = add_ndx(dom, fam, ns, ndx_type);

%   dom = 1:ss; % domain of gamma(:,:,1)
%   fam = family(bnet.dag, n);
%   engine.marg_fam1_ndx_id(n) = add_ndx(dom, fam, ns, ndx_type);

%   engine.marg_singleton_ndx_id(n) = add_ndx(dom, n, ns, ndx_type);
% end

for o=bnet.observed(:)'
  %if bnet.equiv_class(o,1) ~= bnet.equiv_class(o,2)
  %  error(['observed node ' num2str(o) ' is not tied'])
  %end
  cs = children(bnet.dag, o);
  if ~isempty(cs)
    error(['observed node ' num2str(o) ' is not allowed children'])
  end
end

[engine.startprob, engine.transprob, engine.obsprob] = dbn_to_hmm(bnet);

% This is where we will store the results between enter_evidence and marginal_nodes
engine.one_slice_marginal = [];
engine.two_slice_marginal = [];

ss = length(bnet.intra);
engine.maximize = [];
engine.evidence = [];
engine.node_sizes = [];

% avoid the need to do bnet_from_engine, which is slow
engine.slice_size = ss;
engine.parents = bnet.parents;

engine.bel = [];
engine = class(engine, 'hmm_2TBN_inf_engine', inf_engine(bnet));


classdef findquar < ZmapHGridFunction
    % description of this function
    %
    % in the function that generates the figure where this function can be called:
    %
    %     % create some menu items...
    %     h=sample_ZmapFunction.AddMenuItem(hMenu,@catfn) %create subordinate to menu item with handle hMenu
    %     % create the rest of the menu items...
    %
    %  once the menu item is clicked, then sample_ZmapFunction.interative_setup(true,true) is called
    %  meaning that the user will be provided with a dialog to set up the parameters,
    %  and the results will be automatically calculated & plotted once they hit the "GO" button
    %

    properties
        inDaytime         (24,1) logical    = false(24,1) % true for hours that are "daytime" hours
        localNoonEstimate (1,1)  double     = 12; % estimate time where local noon is. used with dayLength
        dayLength         (1,2)  double   {mustBePositive}    = [4, 6] % hours BEFORE noon to hours AFTER noon
    end

    properties(Constant)
        PlotTag         = 'QuarryRatios'
        ReturnDetails   = cell2table({...VariableNames, VariableDescriptions, VariableUnits
            'day_night_ratio',      'Day-Night event ratio', '';
            'day_night_ratio_norm', 'Day-Night event ratio (normalized by hrs in day)', '';
            'n_day',                'Number of events during day','';
            'n_night',              'Number of events during night',''...
            }, 'VariableNames', {'Names','Descriptions','Units'})

        CalcFields      = {'day_night_ratio','day_night_ratio_norm','n_day','n_night'}
        DayColor        = [0.8 0.8 0.2] % for histogram
        NightColor      = [0.1 0.0 0.6] % for histogram

        ParameterableProperties = ["inDaytime" "localNoonEstimate" "dayLength" "NodeMinEventCount"];
        References="";
    end

    methods
        function obj=findquar(zap,varargin) %CONSTRUCTOR
            % create a [...]

            obj@ZmapHGridFunction(zap, 'day_night_ratio_norm');
            report_this_filefun();

            obj.CalcLocalNoon();
            obj.NodeMinEventCount = 20;
            % set the deafult days & nights based on  local noon and the "day" length
            dayStart = mod(obj.localNoonEstimate - obj.dayLength(1),24);
            dayEnd = mod(obj.localNoonEstimate + obj.dayLength(2),24);
            eachHour = 0:23;
            if dayStart < dayEnd
                obj.inDaytime = dayStart <= eachHour  & eachHour < dayEnd;
            else
                obj.inDaytime = dayStart <= eachHour | eachHour < dayEnd;
            end

            obj.parseParameters(varargin);
            obj.StartProcess();
        end

        function InteractiveSetup(obj)
            % allow user to determine grid and selection parameters

            obj.InteractiveSetup_part2();

        end

        function InteractiveSetup_part2(obj)
            % allow user to define which hours are in a "day"

            fifhr = figure(...
                'Name','Daytime (explosion) hours',...
                'NumberTitle','off', ...
                'NextPlot','new', ...
                'units','points',...
                'Visible','on', ...
                'Tag','fifhr',...
                'Position',[ 100 100 500 650]);
            axis off
            ax = gca;

            uicontrol(fifhr,'Style','text','String','Detect Quarry Events',...
                'FontWeight','Bold','FontSize',14,'Units','points','Position',[50 620 300 20]);

            set(ax,'NextPlot','add');
            hax = axes(fifhr,'Units','points','pos', [50 320 300 270]);
            eventHours = obj.ToHourlyCategorical(obj.RawCatalog.Date.Hour);

            dayHist = histogram(hax,eventHours,'DisplayName','day','FaceColor',obj.DayColor);
            set(hax,'NextPlot','add');

            nightHist = histogram(hax,eventHours,'DisplayName','night','FaceColor', obj.NightColor);
            title(' Select the daytime hours and then "GO"')
            [X,N,B] = histcounts(obj.RawCatalog.Date.Hour,-0.5:1:24.5);
            %[X,~,B] = histcounts(eventHours);
            %[X,~] = hist(obj.RawCatalog.Date.Hour,-0.5:1:24.5);

            xlabel(hax,'Hr of the day')
            ylabel(hax,'Number of events per hour')

            evsel=EventSelectionChoice(fifhr,'evsel', [40,100], obj.EventSelector);

            chkpos = @(n)[.80 1-n/28-0.03 .17 1/26];
            for i = 24:-1:1
                hHourly(i)=uicontrol(fifhr,'Style','checkbox',...
                    'string',[num2str(i-1) ' - ' num2str(i) ],...
                    'Units','normalized',...
                    'Position',chkpos(i),'tag',num2str(i),...
                    'Callback', @(~,~)cb_flip(i));
            end

            obj.CalcLocalNoon();
            dayStart = mod(obj.localNoonEstimate - obj.dayLength(1),24);
            dayEnd = mod(obj.localNoonEstimate + obj.dayLength(2),24);
            eachHour = 0:23;
            if dayStart < dayEnd
                obj.inDaytime = dayStart <= eachHour  & eachHour < dayEnd;
            else
                obj.inDaytime = dayStart <= eachHour | eachHour < dayEnd;
            end
            % turn on checkboxes according to their percentile score
            %  idx = X(1:end-1) > prctile2(X,60); % then set values from this

            for hr = 1:24
                hHourly(hr).Value = obj.inDaytime(hr);
            end
            update_histograms();
            %nightHist.Data(obj.inDaytime)=nan;
            legend(hax,'show');

            if isempty(findobj(fifhr, 'Tag', 'quarryinfo'))
                add_menu_divider();
                uimenu(fifhr,'Label','Info',...
                MenuSelectedField(), @(~,~)web(['file:' ZmapGlobal.Data.hodi '/help/quarry.htm'], '-browser'),...
                 'tag', 'quarryinfo');
            end

            uicontrol(fifhr,'style','pushbutton','String','GO','Callback',@cb_go,...
            'Position',[330 10 60 25]);

            uicontrol(fifhr,'style','pushbutton','String','Cancel','Callback',@(~,~)close,...
            'Position',[400 10 60 25]);

            function cb_flip(i)
                obj.inDaytime(i) = ~obj.inDaytime(i);
                update_histograms();
            end
            function update_histograms()
                dayCats = obj.ToHourlyCategorical(find(obj.inDaytime)-1);
                nightCats = obj.ToHourlyCategorical(find(~obj.inDaytime)-1);
                dayHist.Data = eventHours(ismember(eventHours, dayCats));
                nightHist.Data = eventHours(ismember(eventHours, nightCats));
            end
            function cb_go(~,~)

                obj.EventSelector = EventSelectionParameters.fromStruct(evsel.toStruct());
                obj.inDaytime=logical([hHourly.Value]); %same as idx
                close;
                obj.doIt();
            end

        end

        function results=Calculate(obj)
            % once the properties have been set, either by the constructor or by interactive_setup

            close(findobj('Tag','fifhr'));

            ld = sum(obj.inDaytime);

            assert(ld ~= 0, 'No daytime hours chosen. This calculation will have no meaning.');
            assert(ld ~= 24, 'No nighttime hours chosen. This calculation will have no meaning.');

            ln = sum(~obj.inDaytime);
            daynight_hr_ratio=ld/ln;

            % loop over all points in polygon. Evaluated for earthquakes that may extend outside
            % the points.
            %{
            [valueMap,nEv,r]=gridfun(@calculate_day_night_ratio, obj.RawCatalog, mygrid, obj.EvtSel);
            bvg=[valueMap(mygrid.ActivePoints), mygrid.ActiveGrid, r(mygrid.ActivePoints)];
            %}

            obj.gridCalculations(@calculate_day_night_ratio);

            if nargout
                results=obj.Result.values;
            end

            % plot the results
            % obj.oldratios and valueMap (initially ) is the b-value matrix

            %obj.oldratios = valueMap;

            % results of the calculation should be stored in fields belonging to obj.Result

            %obj.Result.bvg=bvg;
            %obj.Result.msg='bvg is [daynightratios x y maxdist_km]';
            %obj.Result.valueMap=valueMap;

            function val = calculate_day_night_ratio(catalog)
                hrofday= hour(catalog.Date);
                nDay= sum(obj.inDaytime(hrofday+1));
                nNight = catalog.Count - nDay;
                myratio = (nDay / nNight);
                normalizedRatioByHoursInDay = myratio * daynight_hr_ratio;
                val=[myratio normalizedRatioByHoursInDay nDay nNight];
            end
        end

        function ModifyGlobals(obj)
            % change the ZmapGlobal variable, if appropriate
            % obj.ZG.SOMETHING = obj.Result.SOMETHING
        end

        function CalcLocalNoon(obj)
            catMedianLatitude = median(obj.RawCatalog.Longitude);
            obj.localNoonEstimate = round( catMedianLatitude  / 15) + 12;
        end

    end %methods

    methods(Static)
        function h = AddMenuItem(parent, zapFcn, varargin)
            % create a menu item that will be used to call this function/class
            label = 'Find Quarry Events';
            h = uimenu(parent, 'Label', label,...
                'MenuSelectedFcn', @(~,~)XYfun.findquar(zapFcn()),...
                varargin{:});
        end

        function ct = ToHourlyCategorical(val)
            ct = categorical(val, 0:23, 'ordinal', true);
        end
    end % static methods

end %classdef

%% Callbacks

% All callbacks should set values within the same field. Leave
% the gathering of values to the SetValuesFromDialog button.

function cb_info(~,~)
    web(['file:' ZmapGlobal.Data.hodi '/help/quarry.htm'], '-browser') ;
end


function res = bf_inverse_deflect(BF, S)
% Used DeFleCT framework to compute spatial filters.
% Copyright (C) 2013 Wellcome Trust Centre for Neuroimaging

% Vladimir Litvak, using the code from Matti Stenroos and Olaf Hauk
% http://imaging.mrc-cbu.cam.ac.uk/meg/AnalyzingData/DeFleCT_SpatialFiltering_Tools
%
% Please cite:
% Hauk O, Stenroos M.
% A framework for the design of flexible cross-talk functions for spatial filtering of EEG/MEG data: DeFleCT.
% Human Brain Mapping 2013
% $Id: bf_inverse_deflect.m 7703 2019-11-22 12:06:29Z guillaume $

%--------------------------------------------------------------------------
if nargin == 0

    list = cfg_entry;
    list.tag = 'list';
    list.name = 'List vertex indices';
    list.strtype = 'n';
    list.num = [1 Inf];
    list.help = {'Specify sources of interest by listing vertex indices.'};

    pos = cfg_entry;
    pos.tag = 'pos';
    pos.name = 'MNI coordinates';
    pos.strtype = 'r';
    pos.num = [1 3];
    pos.help = {'Locations for the VOI center in MNI coordinates'};
    pos.val = {};

    radius = cfg_entry;
    radius.tag = 'radius';
    radius.name = 'Radius';
    radius.strtype = 'r';
    radius.num = [1 1];
    radius.val = {0};
    radius.help = {'Radius (in mm) for the VOI (leave 0 for closest point)'};

    voi = cfg_branch;
    voi.tag = 'voi';
    voi.name = 'VOI';
    voi.val = {pos, radius};

    passband = cfg_repeat;
    passband.tag = 'passband';
    passband.name = 'Passband sources';
    passband.num  = [1 Inf];
    passband.values = {voi, list};

    stopband = cfg_repeat;
    stopband.tag = 'stopband';
    stopband.name = 'Stopband sources';
    stopband.num  = [0 Inf];
    stopband.values = {voi, list};

    svdpassband = cfg_entry;
    svdpassband.tag = 'svdpassband';
    svdpassband.name = 'SVD passband';
    svdpassband.strtype = 'w';
    svdpassband.num = [1 1];
    svdpassband.val = {0};
    svdpassband.help = {'Number of components to summarise the passband in.,',...
        'Leave at zero for no SVD.'};

    svdstopband = cfg_entry;
    svdstopband.tag = 'svdstopband';
    svdstopband.name = 'SVD stopband';
    svdstopband.strtype = 'w';
    svdstopband.num = [1 1];
    svdstopband.val = {0};
    svdstopband.help = {'Number of components to summarise the stopband in.,',...
        'Leave at zero for no SVD.'};

    forcepassband         = cfg_menu;
    forcepassband.tag     = 'forcepassband';
    forcepassband.name    = 'Force passband';
    forcepassband.help    = {'Forces the output for all passband components '};
    forcepassband.labels  = {'yes', 'no'};
    forcepassband.values  = {1, 0};
    forcepassband.val = {0};

    label = cfg_entry;
    label.tag = 'label';
    label.name = 'Label';
    label.strtype = 's';
    label.help = {'Label for the output source'};

    usecov         = cfg_menu;
    usecov.tag     = 'usecov';
    usecov.name    = 'Use covariance matrix';
    usecov.help    = {'Use covariance matrix for pre-whitening'};
    usecov.labels  = {'yes', 'no'};
    usecov.values  = {1, 0};
    usecov.val = {1};

    filter = cfg_branch;
    filter.tag = 'filter';
    filter.name = 'Filter';
    filter.val = {label, passband,  svdpassband, forcepassband, stopband, svdstopband, usecov};

    filters = cfg_repeat;
    filters.tag = 'filters';
    filters.name = 'Filters';
    filters.num  = [1 Inf];
    filters.values = {filter};

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

    trunc = cfg_entry;
    trunc.tag = 'trunc';
    trunc.name = 'Truncation parameter';
    trunc.strtype = 'w';
    trunc.num = [1 1];
    trunc.val = {0};
    trunc.help = {'The number of (smallest) singular values of the covariance matrix that are set to ',...
        'zero before making the whitener. For example, if the data has been SSP-projected, it needs to be at least the number of ',...
        'components projected away.'};

    deflect     = cfg_branch;
    deflect.tag  = 'deflect';
    deflect.name = 'DeFleCT';
    deflect.val  = {filters, snr, trunc};
    deflect.help = {'DeFleCT spatial filter design framework by Matti Stenroos and Olaf Hauk',...
        'http://imaging.mrc-cbu.cam.ac.uk/meg/AnalyzingData/DeFleCT_SpatialFiltering_Tools',...
        'Please cite:'...
        'Hauk O, Stenroos M.',...
        'A framework for the design of flexible cross-talk functions for spatial filtering of EEG/MEG data: DeFleCT.',...
        'Human Brain Mapping 2013'};
    res = deflect;

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

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

L = [];
Li = {};
for i = 1:numel(S.L)
    cL    = U'*S.L{i};
    Li{i} = size(L, 2)+(1:size(cL, 2));
    L  =[L cL];
end

mnipos = spm_eeg_inv_transform_points(BF.data.transforms.toMNI,  BF.sources.pos);

nfilt = numel(S.filter);

W     = cell(1, nfilt);
label = {};

spm('Pointer', 'Watch');drawnow;
spm_progress_bar('Init', nfilt, ['Computing ' S.modality ' filters']); drawnow;
if nfilt > 100, Ibar = floor(linspace(1, nfilt,100));
else Ibar = 1:nfilt; end

for i = 1:nfilt
    filter = S.filter(i);
    if ~filter.svdpassband
        filter.svdpassband = [];
    end

     if ~filter.svdstopband
        filter.svdstopband = [];
    end

    passband = get_vertices(filter.passband, mnipos);
    stopband = get_vertices(filter.stopband, mnipos);

    passband = cat(2, Li{passband});

    stopband = cat(2, Li{stopband});

    if filter.usecov
        W{i} = DeFleCT(passband, filter.svdpassband, filter.forcepassband, stopband, filter.svdstopband,...
            L, C, S.snr, S.trunc);
    else
        W{i} = DeFleCT(passband, filter.svdpassband, filter.forcepassband, stopband, filter.svdstopband,...
            L, [], S.snr, eye(size(L, 1)));
    end

    label{i} = filter.label;

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

spm_progress_bar('Clear');

disp('Note: it is crucial to visualise the filter-cosstalk functions to verify correct design.');

res.W     = W;
res.label = label;

function vertices = get_vertices(band, mnipos)

vertices = [];
for j = 1:numel(band)
    switch char(fieldnames(band{j}))
        case 'voi'
            pnt = band{j}.voi.pos;
            rad = band{j}.voi.radius;

            dist = sqrt(sum((mnipos - repmat(pnt, size(mnipos, 1), 1)).^2, 2));

            if ~rad
                [mindist, ind] = min(dist);
                if mindist>30
                    error('There are no sources within 3cm of the specified location');
                end
            else
                ind = find(dist<=rad);
            end
        case 'list'
            ind = band{j}.list;
    end

    vertices = [vertices; ind(:)];
end


function [D] = spm_eeg_invert_classic_mix(D,val,Qpriors,surfind,ugainfiles)
%function [D] = spm_eeg_invert_classic_mix(D,val,Qpriors,surfind,ugainfiles)
%%
% ReML inversion of multiple posterior current variances from previous
% iterations spm_eeg_invert_classic or spm_eeg_invert
% ReML estimation of regularisation hyperparameters using the
% spatiotemporal hierarchy implicit in EEG/MEG data
%
% D contains the data and inversion parameters (see
% spm_eeg_invert.m/spm_eeg_invert_classic.m)
% val the inversion index
% Qpriors is N solutions of rows by Nd variance estimates
% surfind is N solutions long and contains indices into ugainfiles to these priors with different lead field structures
%% ugainfiles are the SPMgain matrices for the different surfaces
%
% Output D will have a solution which is optimal REML mixture of Qpriors
%
% Created by:
%               Gareth Barnes - g.barnes@ucl.ac.uk
%
% This version is for single subject single modality analysis and therefore
% contains none of the associated scaling factors.
%
% $Id: spm_eeg_invert_classic_mix.m 6077 2014-06-30 16:55:03Z spm $

Nl = length(D);

if Nl>1,
    error('function only defined for a single subject');
end;

% D - SPM data structure
%==========================================================================
if nargin > 1
    D.val = val;
elseif ~isfield(D, 'val')
    D.val = 1;
end

val=D.val;

inverse   = D.inv{val}.inverse;

% forward model
%--------------------------------------------------------------------------

% defaults
%--------------------------------------------------------------------------

try, type = inverse.type;   catch, type = 'GS';     end
try, s    = inverse.smooth; catch, s    = 0.6;      end
try, Np   = inverse.Np;     catch, Np   = 256;      end
try, Nr   = inverse.Nr;     catch, Nr   = 16;       end %% requested number of temporal modes, could be changed depending on svd
try, xyz  = inverse.xyz;    catch, xyz  = [0 0 0];  end
try, rad  = inverse.rad;    catch, rad  = 128;      end
try, hpf  = inverse.hpf;    catch, hpf  = 48;       end %% need to one day put these the correct way round
try, lpf  = inverse.lpf;    catch, lpf  = 0;        end
try, sdv  = inverse.sdv;    catch, sdv  = 4;        end
try, Han  = inverse.Han;    catch, Han  = 1;        end
try, woi  = inverse.woi;    catch, woi  = [];       end
try, Nm   = inverse.Nm;     catch, Nm   = [];       end
try, Nt   = inverse.Nt;     catch, Nt   = [];       end %% fixed number of temporal modes
try, Ip   = inverse.Ip;     catch, Ip   = [];       end
try, SHUFFLELEADS=inverse.SHUFFLELEADS;catch, SHUFFLELEADS=[];end

% defaults
%--------------------------------------------------------------------------
%type = inverse.type;    % Type of inversion scheme

% get specified modalities to invert (default to all)

%--------------------------------------------------------------------------
modalities = D.inv{val}.forward.modality;       % MEG in this case

Nmax  = 16;         % max number of temporal modes

% check lead fields and get number of dipoles (Nd) and channels (Nc)
%==========================================================================

if inverse.Nm~=length(inverse.Ic{1}),
    disp('Using reduced spatial modes');
    if length(unique(surfind))>1,
        error('Cannot merge different surface files with reduced spatial modes at the moment');
    end;
    U=inverse.U{1};
else
    disp('Using all spatial modes');
    U=eye(inverse.Nm);
end;

fprintf('Checking leadfields')

usurfind=unique(surfind);
Nsurf=length(usurfind);
if Nsurf~=size(ugainfiles,1); %% number of different surfaces
    error('need a lead field file for each surface');
end;

L=[];
g_ind=zeros(Nsurf,2); %% index start and end of each set of lead fields
for f=1:Nsurf; %% load in  all leadfield

    fname = deblank(ugainfiles(f,:));
    G = load(fullfile(fname)); % Relative path

    label = G.label;
    g_ind(f,1)=size(L,2)+1; %% number of lead fields per surface
    L     =[L G.G];
    g_ind(f,2)=size(L,2); %% number of lead fields per surface
    clear G;

end;

if size(modalities,1)>1,
    error('not defined for multiple modalities');
end;
Ic  = setdiff(D.indchantype(modalities), badchannels(D));
Nd    = size(L,2);      % Number of dipoles

fprintf(' - done\n')

% check for (e.g., empty-room) sensor components (in Qe)
%==========================================================================
QE = 1;                     % No empty room noise measurement

%==========================================================================
% Spatial projectors - keep these to map directly to channels for now
%==========================================================================

A=U;
UL=U*L;

clear L

Nm    = size(UL,1);         % Number of spatial projectors

% Report
%----------------------------------------------------------------------
fprintf('Using %d spatial modes',Nm)

% No dipole is eliminated
%--------------------------------------------------------------------------
Is    = 1:Nd;               % Accepted dipoles
%Ns    = length(Is);         % Ns = Nd in this case

%==========================================================================
% Temporal projector
%==========================================================================
AY    = {};                                      % pooled response for MVB
AYYA  = 0;                                       % pooled response for ReML

% Time-window of interest
%----------------------------------------------------------------------

if isempty(woi)
    w      = 1000*[min(D.time) max(D.time)];
else
    w=woi; %% in milliseconds
end;

It     = (w/1000 - D.timeonset)*D.fsample + 1;
It     = max(1,It(1)):min(It(end), length(D.time));
It     = fix(It);

% Peristimulus time
%----------------------------------------------------------------------
pst    = 1000*D.time;                   % peristimulus time (ms)
pst    = pst(It);                       % windowed time (ms)
dur    = (pst(end) - pst(1))/1000;      % duration (s)
dct    = (It - It(1))/2/dur;            % DCT frequencies (Hz)
Nb     = length(It);                    % number of time bins

% Serial correlations
%----------------------------------------------------------------------
K      = exp(-(pst - pst(1)).^2/(2*sdv^2));
K      = toeplitz(K);
qV     = sparse(K*K');

% Confounds and temporal subspace
%----------------------------------------------------------------------

T      = spm_dctmtx(Nb,Nb);         % use plot(T) here!

j      = find( (dct >= lpf) & (dct <= hpf) ); %% THis is the wrong way round but leave for nowfor compatibility with spm_eeg_invert
T      = T(:,j);                    % Apply the filter to discrete cosines
dct    = dct(j);                    % Frequencies accepted

%% Hanning window
%----------------------------------------------------------------------

if Han
    W  = sparse(1:Nb,1:Nb,spm_hanning(Nb)); %% use hanning unless specified
else
    W=1;
end;

% get trials or conditions
%----------------------------------------------------------------------
try
    trial = D.inv{D.val}.inverse.trials;
catch
    trial = D.condlist;
end
Ntrialtypes=length(trial);
% get temporal covariance (Y'*Y) to find temporal modes
%======================================================================
%MY    = cell(Nmod,1);                        % mean response
YTY   = sparse(0);                           % accumulator

% get (spatially aligned) data
%------------------------------------------------------------------

YY    = 0;
%    MY{m} = 0;
N=0;
badtrialind=D.badtrials;
for j = 1:Ntrialtypes,                          % pool over conditions
    c     = D.indtrial(trial{j});     % and trials
    c=setxor(c,badtrialind);
    length(c)
    Nk    = length(c);
    for k = 1:Nk
        Y     = A*D(Ic,It,c(k));

        YY    = YY + Y'*Y;
        N     = N + 1;
    end
end
YY=YY./N;

% Apply any Hanning and filtering
%------------------------------------------------------------------
YY         = W'*YY*W;     % Hanning
YTY         = T'*YY*T;     % Filter

%======================================================================

if isempty(Nt),

    [U E]  = spm_svd(YTY,exp(-8));          % get temporal modes
    if isempty(U),
        warning('nothing found using spm svd, using svd');
        [U E]  = svd(YTY);          % get temporal modes
    end;
    E      = diag(E)/trace(YTY);            % normalise variance
    Nr     = min(length(E),Nmax);           % number of temporal modes
    Nr=max(Nr,1); %% use at least one mode
else
    [U E]  = svd(YTY);          % get temporal modes

    E      = diag(E)/trace(YTY);            % normalise variance
    disp('Fixed number of temporal modes');
    Nr=Nt;
end;

V      = U(:,1:Nr);                     % temporal modes
VE     = sum(E(1:Nr));                  % variance explained

fprintf('Using %i temporal modes, ',Nr)
fprintf('accounting for %0.2f percent average variance\n',full(100*VE))

% projection and whitening
%----------------------------------------------------------------------
S      = T*V;                           % temporal projector
Vq     = S*pinv(S'*qV*S)*S';            % temporal precision

% get spatial covariance (Y*Y') for Gaussian process model
%======================================================================

%======================================================================
%======================================================================

% loop over Ntrialtypes trial types
%----------------------------------------------------------------------
UYYU = 0;
AYYA=0;
Nn    =0;                             % number of samples
AY={};
Ntrials=0;
for j = 1:Ntrialtypes,

    UY{j} = sparse(0);
    c       = D.indtrial(trial{j});
    Nk      = length(c);

    % loop over epochs
    %------------------------------------------------------------------
    for k = 1:Nk

        % stack (scaled aligned data) over modalities
        %--------------------------------------------------------------

        Y       = D(Ic,It,c(k))*S;
        Y=A*Y; %% CHANGE

        % accumulate first & second-order responses
        %--------------------------------------------------------------
        Nn       = Nn + Nr;         % number of samples
        %Y           = spm_cat(MY);           % contribution to ERP, Y and MY are the same for 1 modality
        YY          = Y*Y';                  % and covariance
        Ntrials=Ntrials+1;
        %YYep{k}=YY;%% one for each trial and condition

        % accumulate statistics (subject-specific)
        %--------------------------------------------------------------
        UY{j}     = UY{j} + Y;           % condition-specific ERP
        UYYU     = UYYU + YY;          % subject-specific covariance

        % and pool for optimisation of spatial priors over subjects
        %--------------------------------------------------------------
        AY{end + 1} = Y;                     % pooled response for MVB
        AYYA        = AYYA    + YY;          % pooled response for ReML

    end
end

AYYA=AYYA./Nn;
AY=spm_cat(AY);

% assuming equal noise over subjects (Qe) and modalities AQ
%--------------------------------------------------------------------------
AQeA   = A*QE*A';           % Note that here it is A*A'
Qe{1}  = AQeA/(trace(AQeA)); % it means IID noise in virtual sensor space

% Inverse solution
%==========================================================================
QP     = {};
LQP    = {};
LQPL   = {};

for j=1:size(Qpriors,1),
    % Accumulate empirical priors (New set of patches for the second inversion)
    %------------------------------------------------------------------

    disp(sprintf('Adding prior set %d of %d',j,size(Qpriors,1)));
    dum=sparse(zeros(1,Nd));

    dum(g_ind(surfind(j),1):g_ind(surfind(j),2))=Qpriors(j,:);

    qp=sparse(diag(dum)); %% qp is Nd*Nd
    QP{j}=sparse(diag(qp));
    LQP{j}=UL*qp;
    LQPL{j} = LQP{j}*UL';
    clear qp
end;

%==========================================================================
% Step 2: Re-estimate for each subject separately (fusing all modalities)
%==========================================================================

fprintf('Inverting subject 1\n')

% generate sensor component (Qe) per modality
%----------------------------------------------------------------------
AQeA  = A*QE*A';                % Again it is A*A'
AQ    = AQeA/(trace(AQeA));

% using spatial priors
%----------------------------------------------------------------------
Np    = length(LQPL);       % Final number of priors
Ne    = length(Qe);         % Sensor noise prior
Q     = [Qe LQPL];

% re-do ReML (with informative hyperpriors)
% Here is performed the second inversion
%======================================================================

Q0          = exp(-2)*trace(AYYA)*AQ/trace(AQ);
[Cy,h,Ph,F] = spm_reml_sc(AYYA,[],Q,1,-4,16,Q0);

% Data ID
%----------------------------------------------------------------------
% When should I use the data ID?
% For comparison purposes it is necessary to guarantee that the IDs have
% the same value.
%
% When using the same dataset but different lead field matrices is a good
% example of fail, because the spatial projector will generate different
% virtual sensors, and therefore different data for the inversion.
ID    = spm_data_id(YY);

% Covariance: sensor space - Ce and source space - L*Cp
%----------------------------------------------------------------------
Cp    = sparse(0);
LCp   = sparse(0);
hp    = h(Ne + (1:Np));
for j = 1:Np
    Cp  =  Cp + hp(j)*QP{j};
    LCp = LCp + hp(j)*LQP{j};
end

% MAP estimates of instantaneous sources
%======================================================================
% This is equivalent to M = Cp*UL'*inv(Qe + UL*Cp*UL'))
% with Cp the posterior source covariance (with optimal h values)
M     = LCp'/Cy;

% conditional variance (leading diagonal)
% Cq    = Cp - Cp*L'*iC*L*Cp;
%----------------------------------------------------------------------
Cq    = Cp - sum(LCp.*M')';

% evaluate conditional expectation
%----------------------------------------------------------------------
% evaluate conditional expectation (of the sum over trials)
%----------------------------------------------------------------------
SSR   = 0;
SST   = 0;
J     = {};

for j = 1:Ntrialtypes

    % trial-type specific source reconstruction
    %------------------------------------------------------------------
    J{j} = M*UY{j};

    % sum of squares
    %------------------------------------------------------------------
    SSR  = SSR + sum(var((UY{j} - UL*J{j}))); %% changed variance calculation
    SST  = SST + sum(var( UY{j}));

end

% J = M*Y;
%
% % sum of squares
% %------------------------------------------------------------------
% SSR  = sum(var((Y - UL*J),0,2));
% SST  = sum(var(Y,0,2));

% accuracy; signal to noise (over sources)
%======================================================================
R2   = 100*(SST - SSR)/SST;
fprintf('Percent variance explained %.2f (%.2f)\n',full(R2),full(R2*VE));

% Save results
% DEMO: WARNING! These results are not coincident in format with
%                those generated in the SPM8
%======================================================================
inverse.type   = type;                 % inverse model
inverse.M      = M;                    % MAP projector (reduced)
inverse.J   = J;                    % Conditional expectation
inverse.Y      = Y;                    % ERP data (reduced)
inverse.L      = UL;                   % Lead-field (reduced)
inverse.qC     = Cq;                   % spatial covariance
inverse.qV     = Vq;                   % temporal correlations
inverse.T      = S;                    % temporal projector
inverse.U      = {A};                    % spatial projector
inverse.Is     = Is;                   % Indices of active dipoles
inverse.It     = It;                   % Indices of time bins
try
    inverse.Ic{1}     = Ic;                   % Indices of good channels
catch
    inverse.Ic    = Ic;                   % Indices of good channels
end;
inverse.Nd     = Nd;                   % number of dipoles
inverse.pst    = pst;                  % peristimulus time
inverse.dct    = dct;                  % frequency range
inverse.F      = F;                    % log-evidence
inverse.ID     = ID;                   % data ID
inverse.R2     = R2;                   % variance explained (reduced)
inverse.VE     = R2*VE;                % variance explained
inverse.woi    = w;                    % time-window inverted

inverse.modality = modalities;         % modalities inverted

% save in struct
%----------------------------------------------------------------------
D.inv{val}.inverse = inverse;
D.inv{val}.method  = 'Imaging';

% display
%======================================================================
spm_eeg_invert_display(D);
drawnow

return


function parse_data_pl2(filename)

% Requires Matlab Offline SDK (Plexon Inc) in the Matlab searchpath
% Based in code written by Azriel Ghadooshahy, Jan 2016

%Gather relevant info
pl2 = PL2GetFileIndex(filename);
[unused, fname, ext] = fileparts(filename);

%List of possible different continuous sources
%query source-channels for whether or not recording was enabled
source_names_cont = cellfun(@(x) x.SourceName,pl2.AnalogChannels,'uniformoutput',0); %it's possible that they haven't the same size
cont_record_chs = cellfun(@(x) x.RecordingEnabled,pl2.AnalogChannels,'uniformoutput',1);

%Load PL2 recorded continuous data
source_string = 'WB'; %could also be 'SPKC' or 'FP'
inds_in_source = ismember(source_names_cont,source_string);
inds_in_source = find(inds_in_source & cont_record_chs);
sourcenums = cellfun(@(x) x.Channel,pl2.AnalogChannels(inds_in_source),'uniformoutput',1);
%cdat = cell(1,numel(sourcenums));
channels = sourcenums;
fprintf('%d channels in the file\n', numel(sourcenums) )

for n = 1:numel(sourcenums)
    num_in_source = sourcenums(n);
    handler = PL2AdBySource(filename,source_string,num_in_source);
    lts = handler.FragCounts;
    sr = handler.ADFreq;
    fout = fopen([fname '_' num2str(num_in_source) '.pl2ch'],'w');
    fwrite(fout,handler.Values,'double');
    fclose(fout);
    fprintf('Channel %d out. \n', num_in_source);
end

save('pl2_meta_data','sr','lts','channels')


function t=gpst2time(week,sec)

gpst0=[1980,1, 6,0,0,0]; %gps time reference

t0=epoch2time(gpst0);

if sec<-1e9||sec>1e9,sec=0;end

t.time=t0.time+week*7*86400+fix(sec);
t.sec=sec-fix(sec);

return;


function data = ReadChoreSpineFile(filename)

nspinepts = 11;
nparams = 2*nspinepts + 2;

data = [];

fid = fopen(filename,'r');
if fid < 1,
  error('Could not open file %s for reading',filename);
end

ids = [];
expname = '';
while true,
  l = fgetl(fid);
  if ~ischar(l),
    break;
  end
  if isempty(l),
    continue;
  end

  % first word is the experiment name
  [expnamecurr,count,~,nextindex] = sscanf(l,'%s',1);
  if count < 1,
    warning('Could not read experiment name from line >%s<',l);
    continue;
  end
  if ~isempty(expname) && ~strcmp(expname,expnamecurr),
    warning('Experiment name %s does not match previous experiment name %s',expnamecurr,expname);
  end

  % read in the rest of the data
  l = l(nextindex:end);
  [datacurr,count] = sscanf(l,'%f',nparams);
  if count < nparams,
    warning('Could not parse data from line >%s<',l);
    continue;
  end

  id = datacurr(1);
  timestamps = datacurr(2);
  value = datacurr(3:2+nspinepts*2);
  x = value(1:2:end-1);
  y = value(2:2:end);

  idi = find(id == ids,1);
  if isempty(idi),
    idi = numel(ids)+1;
    newdata = struct('id',id,'timestamps',timestamps,'xspine',x(:),'yspine',y(:));
    if isempty(ids),
      data = newdata;
    else
      data(idi) = newdata;
    end
    ids(idi) = id;
  else
    data(idi).timestamps(end+1) = timestamps;
    data(idi).xspine(:,end+1) = x;
    data(idi).yspine(:,end+1) = y;
  end

end

% sort by ids
[ids,order] = sort(ids); %#ok<ASGLU>
data = data(order);

% sort by timestamps
for i = 1:numel(data),
  [data(i).timestamps,order] = sort(data(i).timestamps);
  data(i).xspine = data(i).xspine(:,order);
  data(i).yspine = data(i).yspine(:,order);
end

fclose(fid);


function test_bug1652

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_datatype_segmentation

cd(dccnpath('/home/common/matlab/fieldtrip/data/test/bug1652'));

load seg1.mat
% this contains TPMs
seg1_i  = ft_datatype_segmentation(seg1, 'segmentationstyle', 'indexed');
seg1_p  = ft_datatype_segmentation(seg1, 'segmentationstyle', 'probabilistic');
% seg1_ib = ft_datatype_segmentation(seg1, 'hasbrain', 'yes', 'segmentationstyle', 'indexed')  % this one is not supported due to the combination of the TPMs with the brain
seg1_pb = ft_datatype_segmentation(seg1, 'hasbrain', 'yes', 'segmentationstyle', 'probabilistic');
clear seg1*

load seg2.mat
% this one has three BEM tissues
% note that the skull and scalp are not consistent (one is cumulative, the other exclusive)
seg2_i  = ft_datatype_segmentation(seg2, 'segmentationstyle', 'indexed');
seg2_p  = ft_datatype_segmentation(seg2, 'segmentationstyle', 'probabilistic');
seg2_ib = ft_datatype_segmentation(seg2, 'hasbrain', 'yes', 'segmentationstyle', 'indexed');
seg2_pb = ft_datatype_segmentation(seg2, 'hasbrain', 'yes', 'segmentationstyle', 'probabilistic');
clear seg2*

load seg3.mat
% this contains three cumulative or overlapping BEM tissues
seg3_i  = ft_datatype_segmentation(seg3, 'segmentationstyle', 'indexed');
seg3_p  = ft_datatype_segmentation(seg3, 'segmentationstyle', 'probabilistic');
seg3_ib = ft_datatype_segmentation(seg3, 'hasbrain', 'yes', 'segmentationstyle', 'indexed');
seg3_pb = ft_datatype_segmentation(seg3, 'hasbrain', 'yes', 'segmentationstyle', 'probabilistic');
clear seg3*

load seg4.mat
% this contains three exclusive BEM tissues
seg4_i  = ft_datatype_segmentation(seg4, 'segmentationstyle', 'indexed');
seg4_p  = ft_datatype_segmentation(seg4, 'segmentationstyle', 'probabilistic');
seg4_ib = ft_datatype_segmentation(seg4, 'hasbrain', 'yes', 'segmentationstyle', 'indexed');
seg4_pb = ft_datatype_segmentation(seg4, 'hasbrain', 'yes', 'segmentationstyle', 'probabilistic');
clear seg4*

load seg5.mat
% this one is an indexed representation of the BEM tissues, without labels
seg5_i  = ft_datatype_segmentation(seg5, 'segmentationstyle', 'indexed');
seg5_p  = ft_datatype_segmentation(seg5, 'segmentationstyle', 'probabilistic');

seg5.seglabel = {'scalp', 'skull', 'brain'};
seg5_ib = ft_datatype_segmentation(seg5, 'hasbrain', 'yes', 'segmentationstyle', 'indexed')         % this fails without the labels;
seg5_pb = ft_datatype_segmentation(seg5, 'hasbrain', 'yes', 'segmentationstyle', 'probabilistic')   % this fails without the labels;
clear seg5*

load seg6.mat
% this only contains a single boolean brain
seg6_i  = ft_datatype_segmentation(seg6, 'segmentationstyle', 'indexed');
seg6_p  = ft_datatype_segmentation(seg6, 'segmentationstyle', 'probabilistic');
seg6_ib = ft_datatype_segmentation(seg6, 'hasbrain', 'yes', 'segmentationstyle', 'indexed');
seg6_pb = ft_datatype_segmentation(seg6, 'hasbrain', 'yes', 'segmentationstyle', 'probabilistic');
clear seg6*

% try it with the AFNI atlas
atlas = ft_read_atlas('TTatlas+tlrc.BRIK');
atlas_i  = ft_datatype_segmentation(atlas, 'segmentationstyle', 'indexed');
atlas_p  = ft_datatype_segmentation(atlas, 'segmentationstyle', 'probabilistic');


% teststat - EEGLAB statistical testing function
%
% Statistics are critical for inference testing in Science. It is thus
% primordial to make sure than all the statistics implemented are
% robust and at least bug free. Statistical function using complex
% formulas are inherently prone to bugs. EEGLAB functions are all the
% more prone to bugs given that they only use complex Matlab code to
% avoid loops and speed up computation.
%
% This test function does not guarantee that EEGLAB statistical functions
% are bug free. It does assure though that bugs are unlikely and minor
% if they are present.
%
% This function test 3 things.
%
% * First, it checks that for vector inputs the EEGLAB functions return
%   the same output as other reference functions from the Matlab statistical
%   toolbox or from other packages tested against the SPSS software for
%   repeated measure ANOVA (rm_anova2 function).
%
% * Second, it checks that array inputs with different number of dimensions
%   (from 1 to 3) the EEGLAB function return the same output.
%
% * Third, it checks that the permutation and bootstrap methods shuffle
%   the data properly by running multiple tests.

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

function teststat;

% testing paired t-test
% ---------------------
a = { rand(1,10) rand(1,10)+0.5 };
[t df pvals surog] = statcond(a, 'mode', 'param', 'verbose', 'off', 'paired', 'on');
[h p tmp stats] = ttest(a{1}, a{2});
fprintf('Statistics paired statcond    t-value %2.2f df=%d p=%0.4f\n', t, df, pvals);
fprintf('Statistics paired ttest func. t-value %2.2f df=%d p=%0.4f\n', stats.tstat, stats.df, p);
assertsame([t stats.tstat], [df stats.df], [pvals p]);
disp('--------------------');

% testing unpaired t-test
% -----------------------
[t df pvals surog] = statcond(a, 'mode', 'param', 'verbose', 'off', 'paired', 'off');
[h p tmp stats] = ttest2(a{1}, a{2});
fprintf('Statistics paired statcond     t-value %2.2f df=%d p=%0.4f\n', t, df, pvals);
fprintf('Statistics paired ttest2 func. t-value %2.2f df=%d p=%0.4f\n', stats.tstat, stats.df, p);
assertsame([t stats.tstat], [df stats.df], [pvals p]);
disp('--------------------');

% testing paired 1-way ANOVA
% --------------------------
a = { rand(1,10) rand(1,10) rand(1,10)+0.2; rand(1,10) rand(1,10)+0.2 rand(1,10) };
[F df pvals surog] = statcond(a(1,:), 'mode', 'param', 'verbose', 'off', 'paired', 'on');
z = zeros(10,1); o = ones(10,1); t = ones(10,1)*2;
stats = rm_anova2(  [ a{1,1}';a{1,2}';a{1,3}'], repmat([1:10]', [3 1]), [o;o;o], [z;o;t], {'a','b'});
fprintf('Statistics 1-way paired statcond        F-value %2.2f df1=%d df2=%d p=%0.4f\n', F, df(1), df(2), pvals);
fprintf('Statistics 1-way paired rm_avova2 func. F-value %2.2f df1=%d df2=%d p=%0.4f\n', stats{3,5}, stats{3,3}, stats{6,3}, stats{3,6});
assertsame([F stats{3,5}], [df(1) stats{3,3}], [df(2) stats{6,3}], [pvals stats{3,6}]);
disp('--------------------');

% testing paired 2-way ANOVA
% --------------------------
[F df pvals surog] = statcond(a, 'mode', 'param', 'verbose', 'off', 'paired', 'on');
z = zeros(10,1); o = ones(10,1); t = ones(10,1)*2;
stats = rm_anova2(  [ a{1,1}';a{1,2}';a{1,3}';a{2,1}';a{2,2}';a{2,3}' ], ...
            repmat([1:10]', [6 1]), [o;o;o;z;z;z], [z;o;t;z;o;t], {'a','b'});
fprintf('Statistics 2-way paired statcond        F-value %2.2f df1=%d df2=%d p=%0.4f\n', F{3}, df{3}(1), df{3}(2), pvals{3});
fprintf('Statistics 2-way paired rm_avova2 func. F-value %2.2f df1=%d df2=%d p=%0.4f\n', stats{4,5}, stats{4,3}, stats{7,3}, stats{4,6});
assertsame([F{3} stats{4,5}], [df{3}(1) stats{4,3}], [df{3}(2) stats{7,3}], [pvals{3} stats{4,6}]);
disp('--------------------');

% testing 1-way unpaired ANOVA
% ----------------------------
[F df pvals surog] = statcond(a(1,:), 'mode', 'param', 'verbose', 'off', 'paired', 'off');
[p stats] = anova1( [ a{1,1}' a{1,2}' a{1,3}' ],{}, 'off');
fprintf('Statistics 1-way unpaired statcond     F-value %2.2f df1=%d df2=%d p=%0.4f\n', F, df(1), df(2), pvals);
fprintf('Statistics 1-way unpaired anova1 func. F-value %2.2f df1=%d df2=%d p=%0.4f\n', stats{2,5}, stats{2,3}, stats{3,3}, stats{2,6});
assertsame([F stats{2,5}], [df(1) stats{2,3}], [df(2) stats{3,3}], [pvals stats{2,6}]);
disp('--------------------');

% testing 2-way unpaired ANOVA
% ----------------------------
[F df pvals surog] = statcond(a, 'mode', 'param', 'verbose', 'off', 'paired', 'off');
[p stats] = anova2( [ a{1,1}' a{1,2}' a{1,3}'; a{2,1}' a{2,2}' a{2,3}' ], 10, 'off');
fprintf('Statistics 2-way paired statcond       F-value %2.2f df1=%d df2=%d p=%0.4f\n', F{3}, df{3}(1), df{3}(2), pvals{3});
fprintf('Statistics 1-way unpaired anova2 func. F-value %2.2f df1=%d df2=%d p=%0.4f\n', stats{4,5}, stats{4,3}, stats{5,3}, stats{4,6});
assertsame([F{3} stats{4,5}], [df{3}(1) stats{4,3}], [df{3}(2) stats{5,3}], [pvals{3} stats{4,6}]);
disp('--------------------');

% testing different dimensions in statcond
% ----------------------------------------
a = { rand(1,10)      rand(1,10)+0.5      rand(1,10)};
b = { rand(10,10)     rand(10,10)+0.5     rand(10,10)};     b{1}(4,:)     = a{1}; b{2}(4,:)     = a{2}; b{3}(4,:)     = a{3};
c = { rand(5,10,10)   rand(5,10,10)+0.5   rand(5,10,10)};   c{1}(2,4,:)   = a{1}; c{2}(2,4,:)   = a{2}; c{3}(2,4,:)   = a{3};
d = { rand(2,5,10,10) rand(2,5,10,10)+0.5 rand(2,5,10,10)}; d{1}(1,2,4,:) = a{1}; d{2}(1,2,4,:) = a{2}; d{3}(1,2,4,:) = a{3};
[t1 df1 pvals1] = statcond(a(1:2), 'mode', 'param', 'verbose', 'off', 'paired', 'on');
[t2 df2 pvals2] = statcond(b(1:2), 'mode', 'param', 'verbose', 'off', 'paired', 'on');
[t3 df3 pvals3] = statcond(c(1:2), 'mode', 'param', 'verbose', 'off', 'paired', 'on');
[t4 df4 pvals4] = statcond(d(1:2), 'mode', 'param', 'verbose', 'off', 'paired', 'on');
fprintf('Statistics paired statcond t-test dim1 t-value %2.2f df=%d p=%0.4f\n', t1, df1, pvals1);
fprintf('Statistics paired statcond t-test dim2 t-value %2.2f df=%d p=%0.4f\n', t2(4), df2, pvals2(4));
fprintf('Statistics paired statcond t-test dim3 t-value %2.2f df=%d p=%0.4f\n', t3(2,4), df3, pvals3(2,4));
fprintf('Statistics paired statcond t-test dim4 t-value %2.2f df=%d p=%0.4f\n', t4(1,2,4), df4, pvals4(1,2,4));
assertsame([t1 t2(4) t3(2,4) t4(1,2,4)], [df1 df2 df3 df4], [pvals1 pvals2(4) pvals3(2,4) pvals4(1,2,4)]);
disp('--------------------');
[t1 df1 pvals1] = statcond(a(1:2), 'mode', 'param', 'verbose', 'off', 'paired', 'off');
[t2 df2 pvals2] = statcond(b(1:2), 'mode', 'param', 'verbose', 'off', 'paired', 'off');
[t3 df3 pvals3] = statcond(c(1:2), 'mode', 'param', 'verbose', 'off', 'paired', 'off');
[t4 df4 pvals4] = statcond(d(1:2), 'mode', 'param', 'verbose', 'off', 'paired', 'off');
fprintf('Statistics unpaired statcond t-test dim1 t-value %2.2f df=%d p=%0.4f\n', t1, df1, pvals1);
fprintf('Statistics unpaired statcond t-test dim2 t-value %2.2f df=%d p=%0.4f\n', t2(4), df2, pvals2(4));
fprintf('Statistics unpaired statcond t-test dim3 t-value %2.2f df=%d p=%0.4f\n', t3(2,4), df3, pvals3(2,4));
fprintf('Statistics unpaired statcond t-test dim4 t-value %2.2f df=%d p=%0.4f\n', t4(1,2,4), df4, pvals4(1,2,4));
assertsame([t1 t2(4) t3(2,4) t4(1,2,4)], [df1 df2 df3 df4], [pvals1 pvals2(4) pvals3(2,4) pvals4(1,2,4)]);
disp('--------------------');
[t1 df1 pvals1] = statcond(a, 'mode', 'param', 'verbose', 'off', 'paired', 'on');
[t2 df2 pvals2] = statcond(b, 'mode', 'param', 'verbose', 'off', 'paired', 'on');
[t3 df3 pvals3] = statcond(c, 'mode', 'param', 'verbose', 'off', 'paired', 'on');
[t4 df4 pvals4] = statcond(d, 'mode', 'param', 'verbose', 'off', 'paired', 'on');
fprintf('Statistics paired statcond anova 1-way dim1 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t1, df1(1), df1(2), pvals1);
fprintf('Statistics paired statcond anova 1-way dim2 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t2(4), df2(1), df2(2), pvals2(4));
fprintf('Statistics paired statcond anova 1-way dim3 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t3(2,4), df3(1), df3(2), pvals3(2,4));
fprintf('Statistics paired statcond anova 1-way dim4 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t4(1,2,4), df4(1), df4(2), pvals4(1,2,4));
assertsame([t1 t2(4) t3(2,4) t4(1,2,4)], [df1 df2 df3 df4], [pvals1 pvals2(4) pvals3(2,4) pvals4(1,2,4)]);
disp('--------------------');
[t1 df1 pvals1] = statcond(a, 'mode', 'param', 'verbose', 'off', 'paired', 'off');
[t2 df2 pvals2] = statcond(b, 'mode', 'param', 'verbose', 'off', 'paired', 'off');
[t3 df3 pvals3] = statcond(c, 'mode', 'param', 'verbose', 'off', 'paired', 'off');
[t4 df4 pvals4] = statcond(d, 'mode', 'param', 'verbose', 'off', 'paired', 'off');
fprintf('Statistics unpaired statcond anova 1-way dim1 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t1, df1(1), df1(2), pvals1);
fprintf('Statistics unpaired statcond anova 1-way dim2 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t2(4), df2(1), df2(2), pvals2(4));
fprintf('Statistics unpaired statcond anova 1-way dim3 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t3(2,4), df3(1), df3(2), pvals3(2,4));
fprintf('Statistics unpaired statcond anova 1-way dim4 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t4(1,2,4), df4(1), df4(2), pvals4(1,2,4));
assertsame([t1 t2(4) t3(2,4) t4(1,2,4)], [df1 df2 df3 df4], [pvals1 pvals2(4) pvals3(2,4) pvals4(1,2,4)]);
disp('--------------------');
a(2,:) = a; a{1} = a{1}/2;
b(2,:) = b; b{1} = b{1}/2;
c(2,:) = c; c{1} = c{1}/2;
d(2,:) = d; d{1} = d{1}/2;
[t1 df1 pvals1] = statcond(a, 'mode', 'param', 'verbose', 'off', 'paired', 'on');
[t2 df2 pvals2] = statcond(b, 'mode', 'param', 'verbose', 'off', 'paired', 'on');
[t3 df3 pvals3] = statcond(c, 'mode', 'param', 'verbose', 'off', 'paired', 'on');
[t4 df4 pvals4] = statcond(d, 'mode', 'param', 'verbose', 'off', 'paired', 'on');
fprintf('Statistics paired statcond anova 2-way dim1 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t1{3}, df1{3}(1), df1{3}(2), pvals1{3});
fprintf('Statistics paired statcond anova 2-way dim2 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t2{3}(4), df2{3}(1), df2{3}(2), pvals2{3}(4));
fprintf('Statistics paired statcond anova 2-way dim3 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t3{3}(2,4), df3{3}(1), df3{3}(2), pvals3{3}(2,4));
fprintf('Statistics paired statcond anova 2-way dim4 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t4{3}(1,2,4), df4{3}(1), df4{3}(2), pvals4{3}(1,2,4));
assertsame([t1{3} t2{3}(4) t3{3}(2,4) t4{3}(1,2,4)], [df1{3}(1) df2{3}(1) df3{3}(1) df4{3}(1)], [df1{3}(2) df2{3}(2) df3{3}(2) df4{3}(2)], [pvals1{3} pvals2{3}(4) pvals3{3}(2,4) pvals4{3}(1,2,4)]);
disp('--------------------');
[t1 df1 pvals1] = statcond(a, 'mode', 'param', 'verbose', 'off', 'paired', 'off');
[t2 df2 pvals2] = statcond(b, 'mode', 'param', 'verbose', 'off', 'paired', 'off');
[t3 df3 pvals3] = statcond(c, 'mode', 'param', 'verbose', 'off', 'paired', 'off');
[t4 df4 pvals4] = statcond(d, 'mode', 'param', 'verbose', 'off', 'paired', 'off');
fprintf('Statistics unpaired statcond anova 2-way dim1 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t1{3}, df1{3}(1), df1{3}(2), pvals1{3});
fprintf('Statistics unpaired statcond anova 2-way dim2 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t2{3}(4), df2{3}(1), df2{3}(2), pvals2{3}(4));
fprintf('Statistics unpaired statcond anova 2-way dim3 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t3{3}(2,4), df3{3}(1), df3{3}(2), pvals3{3}(2,4));
fprintf('Statistics unpaired statcond anova 2-way dim4 t-value %2.2f df1=%d df2=%d p=%0.4f\n', t4{3}(1,2,4), df4{3}(1), df4{3}(2), pvals4{3}(1,2,4));
assertsame([t1{3} t2{3}(4) t3{3}(2,4) t4{3}(1,2,4)], [df1{3}(1) df2{3}(1) df3{3}(1) df4{3}(1)], [df1{3}(2) df2{3}(2) df3{3}(2) df4{3}(2)], [pvals1{3} pvals2{3}(4) pvals3{3}(2,4) pvals4{3}(1,2,4)]);
disp('--------------------');

% testing shuffling and permutation for bootstrap
% -----------------------------------------------
clear a;
m1 = [1:10];
m2 = [1:10]+100;
m3 = [1:10]+1000;
a{1} = { m1 m2 };
a{2} = { m1 m2 m3 };
a{3} = { [ zeros(9,10); m1] [ zeros(9,10); m2] };
a{4} = { [ zeros(9,10); m1] [ zeros(9,10); m2] [ zeros(9,10); m3] };
tmpa = zeros(9,8,10); tmpa(end,end,:) = m1;
tmpb = zeros(9,8,10); tmpb(end,end,:) = m2;
tmpc = zeros(9,8,10); tmpc(end,end,:) = m3;
a{5} = { tmpa tmpb };
a{6} = { tmpa tmpb tmpc };

for method = 1:2
    if method == 2, opt = {'arraycomp', 'off'}; else opt = {}; end
    for dim = 1:length(a)
        [sa1] = statcond(a{dim}, 'mode', 'bootstrap', 'verbose', 'off', 'paired', 'on',  'returnresamplingarray', 'on', opt{:}, 'naccu', 10);
        [sa2] = statcond(a{dim}, 'mode', 'perm'     , 'verbose', 'off', 'paired', 'on',  'returnresamplingarray', 'on', opt{:}, 'naccu', 10);
        [sa3] = statcond(a{dim}, 'mode', 'bootstrap', 'verbose', 'off', 'paired', 'off', 'returnresamplingarray', 'on', opt{:}, 'naccu', 10);
        [sa4] = statcond(a{dim}, 'mode', 'perm'     , 'verbose', 'off', 'paired', 'off', 'returnresamplingarray', 'on', opt{:}, 'naccu', 10);

        % select data
        nd = ndims(sa1{1});
        if nd == 2 && size(sa1{1},2) > 1
            for t=1:length(sa1),
                sa1{t} = sa1{t}(end,:);
                sa2{t} = sa2{t}(end,:);
                sa3{t} = sa3{t}(end,:);
                sa4{t} = sa4{t}(end,:);
            end
        elseif nd == 3
            for t=1:length(sa1),
                sa1{t} = squeeze(sa1{t}(end,end,:));
                sa2{t} = squeeze(sa2{t}(end,end,:));
                sa3{t} = squeeze(sa3{t}(end,end,:));
                sa4{t} = squeeze(sa4{t}(end,end,:));
            end
        elseif nd == 4
            for t=1:length(sa1),
                sa1{t} = squeeze(sa1{t}(end,end,end,:));
                sa2{t} = squeeze(sa2{t}(end,end,end,:));
                sa3{t} = squeeze(sa3{t}(end,end,end,:));
                sa4{t} = squeeze(sa4{t}(end,end,end,:));
            end
        end

        % for paired bootstrap, we make sure that the resampling has only shuffled between conditions
        % for instance [101 2 1003 104 ...] is an acceptable sequence
        if all(rem(sa1{1}(:)',10) == [1:9 0]) && all(rem(sa1{2}(:)',10) == [1:9 0])
            fprintf('Bootstrap paired dim%d resampling method %d Pass\n', dim, method);
        else  error('Bootstrap paired resampling Error');
        end
        % for paired permutation, in addition, we make sure that the sum across condition is constant
        % which is not true for bootstrap
        msa = meansa(sa2); msa = msa(:)-msa(1);
        if all(rem(sa1{1}(:)',10) == [1:9 0]) && all(rem(sa1{2}(:)',10) == [1:9 0]) && ...
            all(round(msa) == [0:9]') && length(unique(sa2{1})) == 10 && length(unique(sa2{2})) == 10
            fprintf('Permutation paired dim%d resampling method %d Pass\n', dim, method);
        else  error('Permutation paired resampling Error');
        end
        % for unpaired bootstrap, only make sure there are enough unique
        % values
        if length(unique(sa3{1})) > 3 && length(unique(sa3{2})) > 3
             fprintf('Bootstrap unpaired dim%d reampling method %d Pass\n', dim, method);
        else   error('Bootstrap unpaired reampling Error');
        end
        % for unpaired permutation, the number of unique values must be 10
        % and the sum must be constant (not true for bootstrap)
        if length(unique(sa4{1})) == 10 && length(unique(sa4{2})) == 10 && ( floor(mean(meansa(sa4))) == 55 || floor(mean(meansa(sa4))) == 372 )
             fprintf('Permutation unpaired dim%d reampling method %d Pass\n', dim, method);
        else   error('Permutation unpaired reampling Error');
        end

        disp('------------------------');
    end
end

% function to check
function assertsame(varargin)

for ind = 1:length(varargin)
    if length(varargin{1}) > 2
        for tmpi = 1:length(varargin{1})-1
            assertsame(varargin{1}(tmpi:tmpi+1));
        end
        return;
    else
        if (varargin{ind}(1)-varargin{ind}(2)) > abs(mean(varargin{ind}))*0.01
            error('Test failed');
        end
    end
end
disp('Test pass');

function [meanmat] = meansa(mat)

meanmat = zeros(size(mat{1}));
for index = 1:length(mat)
    meanmat = meanmat+mat{index}/length(mat);
end

function stats = rm_anova2(Y,S,F1,F2,FACTNAMES)
%
% function stats = rm_anova2(Y,S,F1,F2,FACTNAMES)
%
% Two-factor, within-subject repeated measures ANOVA.
% For designs with two within-subject factors.
%
% Parameters:
%    Y          dependent variable (numeric) in a column vector
%    S          grouping variable for SUBJECT
%    F1         grouping variable for factor #1
%    F2         grouping variable for factor #2
%    F1name     name (character array) of factor #1
%    F2name     name (character array) of factor #2
%
%    Y should be a 1-d column vector with all of your data (numeric).
%    The grouping variables should also be 1-d numeric, each with same
%    length as Y. Each entry in each of the grouping vectors indicates the
%    level # (or subject #) of the corresponding entry in Y.
%
% Returns:
%    stats is a cell array with the usual ANOVA table:
%      Source / ss / df / ms / F / p
%
% Notes:
%    Program does not do any input validation, so it is up to you to make
%    sure that you have passed in the parameters in the correct form:
%
%       Y, S, F1, and F2 must be numeric vectors all of the same length.
%
%       There must be at least one value in Y for each possible combination
%       of S, F1, and F2 (i.e. there must be at least one measurement per
%       subject per condition).
%
%       If there is more than one measurement per subject X condition, then
%       the program will take the mean of those measurements.
%
% Aaron Schurger (2005.02.04)
%   Derived from Keppel & Wickens (2004) "Design and Analysis" ch. 18
%

%
% Revision history...
%
% 11 December 2009 (Aaron Schurger)
%
% Fixed error under "bracket terms"
% was: expY = sum(Y.^2);
% now: expY = sum(sum(sum(MEANS.^2)));
%

stats = cell(4,5);

F1_lvls = unique_bc(F1);
F2_lvls = unique_bc(F2);
Subjs = unique_bc(S);

a = length(F1_lvls); % # of levels in factor 1
b = length(F2_lvls); % # of levels in factor 2
n = length(Subjs); % # of subjects

INDS = cell(a,b,n); % this will hold arrays of indices
CELLS = cell(a,b,n); % this will hold the data for each subject X condition
MEANS = zeros(a,b,n); % this will hold the means for each subj X condition

% Calculate means for each subject X condition.
% Keep data in CELLS, because in future we may want to allow options for
% how to compute the means (e.g. leaving out outliers > 3stdev, etc...).
for i=1:a % F1
    for j=1:b % F2
        for k=1:n % Subjs
            INDS{i,j,k} = find(F1==F1_lvls(i) & F2==F2_lvls(j) & S==Subjs(k));
            CELLS{i,j,k} = Y(INDS{i,j,k});
            MEANS(i,j,k) = mean(CELLS{i,j,k});
        end
    end
end

% make tables (see table 18.1, p. 402)
AB = reshape(sum(MEANS,3),a,b); % across subjects
AS = reshape(sum(MEANS,2),a,n); % across factor 2
BS = reshape(sum(MEANS,1),b,n); % across factor 1

A = sum(AB,2); % sum across columns, so result is ax1 column vector
B = sum(AB,1); % sum across rows, so result is 1xb row vector
S = sum(AS,1); % sum across columns, so result is 1xs row vector
T = sum(sum(A)); % could sum either A or B or S, choice is arbitrary

% degrees of freedom
dfA = a-1;
dfB = b-1;
dfAB = (a-1)*(b-1);
dfS = n-1;
dfAS = (a-1)*(n-1);
dfBS = (b-1)*(n-1);
dfABS = (a-1)*(b-1)*(n-1);

% bracket terms (expected value)
expA = sum(A.^2)./(b*n);
expB = sum(B.^2)./(a*n);
expAB = sum(sum(AB.^2))./n;
expS = sum(S.^2)./(a*b);
expAS = sum(sum(AS.^2))./b;
expBS = sum(sum(BS.^2))./a;
expY = sum(sum(sum(MEANS.^2))); %sum(Y.^2);
expT = T^2 / (a*b*n);

% sums of squares
ssA = expA - expT;
ssB = expB - expT;
ssAB = expAB - expA - expB + expT;
ssS = expS - expT;
ssAS = expAS - expA - expS + expT;
ssBS = expBS - expB - expS + expT;
ssABS = expY - expAB - expAS - expBS + expA + expB + expS - expT;
ssTot = expY - expT;

% mean squares
msA = ssA / dfA;
msB = ssB / dfB;
msAB = ssAB / dfAB;
msS = ssS / dfS;
msAS = ssAS / dfAS;
msBS = ssBS / dfBS;
msABS = ssABS / dfABS;

% f statistic
fA = msA / msAS;
fB = msB / msBS;
fAB = msAB / msABS;

% p values
pA = 1-fcdf(fA,dfA,dfAS);
pB = 1-fcdf(fB,dfB,dfBS);
pAB = 1-fcdf(fAB,dfAB,dfABS);

% return values
stats = {'Source','SS','df','MS','F','p';...
         FACTNAMES{1}, ssA, dfA, msA, fA, pA;...
         FACTNAMES{2}, ssB, dfB, msB, fB, pB;...
         [FACTNAMES{1} ' x ' FACTNAMES{2}], ssAB, dfAB, msAB, fAB, pAB;...
         [FACTNAMES{1} ' x Subj'], ssAS, dfAS, msAS, [], [];...
         [FACTNAMES{1} ' x Subj'], ssBS, dfBS, msBS, [], [];...
         [FACTNAMES{1} ' x ' FACTNAMES{2} ' x Subj'], ssABS, dfABS, msABS, [], []};

 return