function [timeqrs,indexes,tol,messages]=qrscandidatesnew(timeqrs1,timeqrs2,timeqrs3,heasig,tol,messages)
% [timeqrs,indexes]=qrscandidates(timeqrs1,timeqrs2,timeqrs3,heasig,tol)
%
% Construction QRS positions candidates vector from 3 single detections vectors
% a QRS is admitted as candidate if:
%   - it was found in 3 leads and the middle mark differ less than tol from the others
%   - it was found in 2 leads and the marks differ less than tol
%
% marks that not fullfill the above are replaced by NaN and a QRS positions
% candidates vector is constructed with the detections in each lead in one
% line, one QRS in each column
%
% INPUT:
% timeqrs1,timeqrs2,timeqrs3  -  line vector swith single lead detections
%                                (in samples)
% heasig - header information
% tol - maximum distance to be admited as same complex (in sec)
%       by default half of the default refractary period tol = 0.275/2 sec
%
% OUTPUT:
% timeqrs - QRS positions candidates vector
% indexes - beats corresponding to the QRS positions candidates vector
%
% Rute Almeida  14.APR.2005
% Last update: 26JUL2011
%
% MATLAB Version R13
if nargin<6
    messages.status=1;
end
if ~isfield(messages,'warnings'), messages.warnings=[]; end
spf=heasig.spf_ecg; %24.MAR.09
if nargin==4
    tol=ceil(0.275/2*heasig.freq*spf); %24.MAR.09
elseif nargin<4
    messages.errors=[messages.errors {'Fatal error in qrscandidatesnew: not enough inputs.'}];
    warning(char(messages.errors(end)))
    messages.errors_desc=[messages.errors_desc 'Mandatory inputs not defined.'];
    messages.status=0;
    return
end
indexes=[];
indexes1=1:length(timeqrs1);
indexes2=1:length(timeqrs2);
indexes3=1:length(timeqrs3);
timeqrs=[];
lengthaux=([length(timeqrs1) length(timeqrs2) length(timeqrs3)]);

for g=1:min(lengthaux)
    [aux auxi]=sort([timeqrs1(g) timeqrs2(g) timeqrs3(g)]);
    if aux(1)>(aux(2)-tol-1)
        if (aux(2)+tol+1)>aux(3)
            timeqrs=[timeqrs [timeqrs1(g);timeqrs2(g);timeqrs3(g)]]; %#ok<AGROW>
            indexes=[indexes [indexes1(g);indexes2(g);indexes3(g)]]; %#ok<AGROW>
        else
            if auxi(3)==1
                timeqrs1(g+1:end+1)=timeqrs1(g:end);
                indexes1(g+1:end+1)= indexes1(g:end);
                indexes1(g)=NaN;
                timeqrs1(g)=NaN;
            else if auxi(3)==2
                    timeqrs2(g+1:end+1)=timeqrs2(g:end);
                    indexes2(g+1:end+1)= indexes2(g:end);
                    timeqrs2(g)=NaN;
                    indexes2(g)=NaN;
                else
                    timeqrs3(g+1:end+1)=timeqrs3(g:end);
                    indexes3(g+1:end+1)= indexes3(g:end);
                    timeqrs3(g)=NaN;
                    indexes3(g)=NaN;
                end
            end
            timeqrs=[timeqrs [timeqrs1(g);timeqrs2(g);timeqrs3(g)]]; %#ok<AGROW>
            indexes=[indexes [indexes1(g);indexes2(g);indexes3(g)]]; %#ok<AGROW>
        end
    else

        if auxi(1)==1
            g1=g+1;
            flag=0;
            while  g1<=length(timeqrs1) && flag==0 && timeqrs1(g1)<(aux(2)+tol+1)
                if (timeqrs1(g1)>(aux(2)-tol-1))
                    flag=1;
                    timeqrs1(g:end)=[timeqrs1(g1:end) NaN*ones(1,(g1-g))];
                    indexes1(g:end)=[indexes1(g1:end) NaN*ones(1,(g1-g))];
                end
                g1=g1+1;
            end
            if flag==0
                if g1>length(timeqrs1)
                    timeqrs1(g:end)= NaN*ones(1,length(timeqrs1(g:end)));
                    indexes1(g:end)= NaN*ones(1,length(timeqrs1(g:end)));
                else
                    timeqrs1(g:end)=[timeqrs1((g1-1):end) NaN*ones(1,(g1-1-g))];
                    indexes1(g:end)=[indexes1((g1-1):end) NaN*ones(1,(g1-1-g))];
                    timeqrs1(g)=NaN;
                    indexes1(g)=NaN;
                end
            end
        elseif auxi(1)==2
            g1=g+1;
            flag=0;
            while  g1<=length(timeqrs2) && flag==0 && timeqrs2(g1)<(aux(2)+tol+1)
                if (timeqrs2(g1)>(aux(2)-tol-1))
                    flag=1;
                    timeqrs2(g:end)=[timeqrs2(g1:end) NaN*ones(1,(g1-g))];
                    indexes2(g:end)=[indexes2(g1:end) NaN*ones(1,(g1-g))];
                end
                g1=g1+1;
            end
            if flag==0
                if g1>length(timeqrs1)
                    timeqrs2(g:end)= NaN*ones(1,length(timeqrs2(g:end)));
                    indexes2(g:end)= NaN*ones(1,length(timeqrs2(g:end)));
                else
                    timeqrs2(g:end)=[timeqrs2((g1-1):end) NaN*ones(1,(g1-1-g))];
                    indexes2(g:end)=[indexes2((g1-1):end) NaN*ones(1,(g1-1-g))];
                    timeqrs2(g)=NaN;
                    indexes2(g)=NaN;
                end
            end
        else
            g1=g+1;
            flag=0;
            while  g1<=length(timeqrs3) && flag==0 && timeqrs3(g1)<(aux(2)+tol+1)
                if (timeqrs3(g1)>(aux(2)-tol-1))
                    flag=1;
                    timeqrs3(g:end)=[timeqrs3(g1:end) NaN*ones(1,(g1-g))];
                    indexes3(g:end)=[indexes3(g1:end) NaN*ones(1,(g1-g))];
                end
                g1=g1+1;
            end
            if flag==0
                if g1>length(timeqrs1)
                    timeqrs3(g:end)= NaN*ones(1,length(timeqrs3(g:end)));
                    indexes3(g:end)= NaN*ones(1,length(timeqrs3(g:end)));
                else
                    timeqrs3(g:end)=[timeqrs3((g1-1):end) NaN*ones(1,(g1-1-g))];
                    indexes3(g:end)=[indexes3((g1-1):end) NaN*ones(1,(g1-1-g))];
                    timeqrs3(g)=NaN;
                    indexes3(g)=NaN;
                end
            end
        end

        if aux(3)-aux(2)>(tol+1)
            if auxi(3)==1
                timeqrs1(g+1:end+1)=timeqrs1(g:end);
                indexes1(g+1:end+1)= indexes1(g:end);
                indexes1(g)=NaN;
                timeqrs1(g)=NaN;
            else if auxi(3)==2
                    timeqrs2(g+1:end+1)=timeqrs2(g:end);
                    indexes2(g+1:end+1)= indexes2(g:end);
                    timeqrs2(g)=NaN;
                    indexes2(g)=NaN;
                else
                    timeqrs3(g+1:end+1)=timeqrs3(g:end);
                    indexes3(g+1:end+1)= indexes3(g:end);
                    timeqrs3(g)=NaN;
                    indexes3(g)=NaN;
                end
            end
        else
            flag=1;
        end
        if flag==1
            timeqrs=[timeqrs [timeqrs1(g);timeqrs2(g);timeqrs3(g)]]; %#ok<AGROW>
            indexes=[indexes [indexes1(g);indexes2(g);indexes3(g)]]; %#ok<AGROW>
        else
            timeqrs1(g)=NaN;indexes1(g)=NaN;
            timeqrs2(g)=NaN;indexes2(g)=NaN;
            timeqrs3(g)=NaN;indexes3(g)=NaN;
        end
    end
end
lengthaux=([length(timeqrs1) length(timeqrs2) length(timeqrs3)]);
if isempty(g)
    g=0;
end
aux1=find(lengthaux-g >0);
%remains beats in all 3 leads
while length(aux1)==3
%     intervalaux=(g+1):(min(lengthaux(aux1)));
    for g=(g+1):(min(lengthaux(aux1)))
        [aux auxi]=sort([timeqrs1(g) timeqrs2(g) timeqrs3(g)]);
        if aux(1)>(aux(2)-tol-1)
            if (aux(2)+tol+1)>aux(3)
                timeqrs=[timeqrs [timeqrs1(g);timeqrs2(g);timeqrs3(g)]];  %#ok<AGROW>
                indexes=[indexes [indexes1(g);indexes2(g);indexes3(g)]];  %#ok<AGROW>
            else
                if auxi(3)==1
                    timeqrs1(g+1:end+1)=timeqrs1(g:end);
                    indexes1(g+1:end+1)= indexes1(g:end);
                    indexes1(g)=NaN;
                    timeqrs1(g)=NaN;
                else if auxi(3)==2
                        timeqrs2(g+1:end+1)=timeqrs2(g:end);
                        indexes2(g+1:end+1)= indexes2(g:end);
                        timeqrs2(g)=NaN;
                        indexes2(g)=NaN;
                    else
                        timeqrs3(g+1:end+1)=timeqrs3(g:end);
                        indexes3(g+1:end+1)= indexes3(g:end);
                        timeqrs3(g)=NaN;
                        indexes3(g)=NaN;
                    end
                end
                timeqrs=[timeqrs [timeqrs1(g);timeqrs2(g);timeqrs3(g)]];  %#ok<AGROW>
                indexes=[indexes [indexes1(g);indexes2(g);indexes3(g)]];  %#ok<AGROW>
            end
        else
            if auxi(1)==1
                g1=g+1;
                flag=0;
                while  g1<=length(timeqrs1) && flag==0 && timeqrs1(g1)<(aux(2)+tol+1)
                    if (timeqrs1(g1)>(aux(2)-tol-1))
                        flag=1;
                        timeqrs1(g:end)=[timeqrs1(g1:end) NaN*ones(1,(g1-g))];
                        indexes1(g:end)=[indexes1(g1:end) NaN*ones(1,(g1-g))];
                    end
                    g1=g1+1;
                end
                if flag==0
                    if g1>length(timeqrs1)
                        timeqrs1(g:end)=NaN*ones(1,length(timeqrs1(g:end)));
                        indexes1(g:end)=NaN*ones(1,length(timeqrs1(g:end)));
                    else
                        timeqrs1(g:end)=[timeqrs1((g1-1):end) NaN*ones(1,(g1-1-g))];
                        indexes1(g:end)=[indexes1((g1-1):end) NaN*ones(1,(g1-1-g))];
                        timeqrs1(g)=NaN;
                        indexes1(g)=NaN;
                    end
                end
            elseif auxi(1)==2
                g1=g+1;
                flag=0;
                while  g1<=length(timeqrs2) && flag==0 && timeqrs2(g1)<(aux(2)+tol+1)
                    if (timeqrs2(g1)>(aux(2)-tol-1))
                        flag=1;
                        timeqrs2(g:end)=[timeqrs2(g1:end) NaN*ones(1,(g1-g))];
                        indexes2(g:end)=[indexes2(g1:end) NaN*ones(1,(g1-g))];
                    end
                    g1=g1+1;
                end
                if flag==0
                    if g1>length(timeqrs1)
                        timeqrs2(g:end)=NaN*ones(1,length(timeqrs2(g:end)));
                        indexes2(g:end)=NaN*ones(1,length(timeqrs2(g:end)));
                    else
                        timeqrs2(g:end)=[timeqrs2((g1-1):end) NaN*ones(1,(g1-1-g))];
                        indexes2(g:end)=[indexes2((g1-1):end) NaN*ones(1,(g1-1-g))];
                        timeqrs2(g)=NaN;
                        indexes2(g)=NaN;
                    end
                end
            else
                g1=g+1;
                flag=0;
                while  g1<=length(timeqrs3) && flag==0 && timeqrs3(g1)<(aux(2)+tol+1)
                    if (timeqrs3(g1)>(aux(2)-tol-1))
                        flag=1;
                        timeqrs3(g:end)=[timeqrs3(g1:end) NaN*ones(1,(g1-g))];
                        indexes3(g:end)=[indexes3(g1:end) NaN*ones(1,(g1-g))];
                    end
                    g1=g1+1;
                end
                if flag==0
                    if g1>length(timeqrs1)
                        timeqrs3(g:end)=NaN*ones(1,length(timeqrs3(g:end)));
                        indexes3(g:end)=NaN*ones(1,length(timeqrs3(g:end)));
                    else
                        timeqrs3(g:end)=[timeqrs3((g1-1):end) NaN*ones(1,(g1-1-g))];
                        indexes3(g:end)=[indexes3((g1-1):end) NaN*ones(1,(g1-1-g))];
                        timeqrs3(g)=NaN;
                        indexes3(g)=NaN;
                    end
                end
            end
            if aux(3)-aux(2)>(tol+1)
                if auxi(3)==1
                    timeqrs1(g+1:end+1)=timeqrs1(g:end);
                    indexes1(g+1:end+1)= indexes1(g:end);
                    indexes1(g)=NaN;
                    timeqrs1(g)=NaN;
                else if auxi(3)==2
                        timeqrs2(g+1:end+1)=timeqrs2(g:end);
                        indexes2(g+1:end+1)= indexes2(g:end);
                        timeqrs2(g)=NaN;
                        indexes2(g)=NaN;
                    else
                        timeqrs3(g+1:end+1)=timeqrs3(g:end);
                        indexes3(g+1:end+1)= indexes3(g:end);
                        timeqrs3(g)=NaN;
                        indexes3(g)=NaN;
                    end
                end
            else
                flag=1;
            end
            if flag==1
                timeqrs=[timeqrs [timeqrs1(g);timeqrs2(g);timeqrs3(g)]];  %#ok<AGROW>
                indexes=[indexes [indexes1(g);indexes2(g);indexes3(g)]];  %#ok<AGROW>
            else
                timeqrs1(g)=NaN;indexes1(g)=NaN;
                timeqrs2(g)=NaN;indexes2(g)=NaN;
                timeqrs3(g)=NaN;indexes3(g)=NaN;
            end
        end
    end
    lengthaux=([length(timeqrs1) length(timeqrs2) length(timeqrs3)]);
    aux1=find(lengthaux-g >0);
end
[min1i,min1]=min(find(~isnan(timeqrs1(end:-1:1)))); %#ok<NASGU,MXFND>
[min2i,min3]=min(find(~isnan(timeqrs2(end:-1:1)))); %#ok<NASGU,MXFND>
[min3i,min3]=min(find(~isnan(timeqrs3(end:-1:1)))); %#ok<NASGU,MXFND>
timeqrs1(length(timeqrs1)-min1i+2:end)=[];
timeqrs2(length(timeqrs2)-min2i+2:end)=[];
timeqrs3(length(timeqrs3)-min3i+2:end)=[];
lengthaux=([length(timeqrs1) length(timeqrs2) length(timeqrs3)]);
aux1=find(lengthaux-g >0);
%remaining beats in 2 leads
if length(aux1)>1
    for intervalauxi=(g+1):(min(lengthaux(aux1)));
        if aux1(1)==1
            if aux1(2)==2
                [aux auxi]=sort([timeqrs1(intervalauxi) timeqrs2(intervalauxi)]);
                if aux(1)>(aux(2)-tol-1)
                    timeqrs=[timeqrs [timeqrs1(intervalauxi);timeqrs2(intervalauxi);NaN]];  %#ok<AGROW>
                    indexes=[indexes [indexes1(intervalauxi);indexes2(intervalauxi);NaN]];  %#ok<AGROW>
                else
                    if auxi(2)==2
                        timeqrs2(intervalauxi+1:end+1)=timeqrs2(intervalauxi:end);
                        indexes2(intervalauxi+1:end+1)= indexes2(intervalauxi:end);
                        timeqrs2(intervalauxi)=NaN;
                        indexes2(intervalauxi)=NaN;
                    elseif auxi(2)==1
                        timeqrs1(intervalauxi+1:end+1)=timeqrs1(intervalauxi:end);
                        indexes1(intervalauxi+1:end+1)= indexes1(intervalauxi:end);
                        timeqrs1(intervalauxi)=NaN;
                        indexes1(intervalauxi)=NaN;
                    end
                end
            elseif aux1(2)==3
                [aux auxi]=sort([timeqrs1(intervalauxi) timeqrs3(intervalauxi)]);
                if aux(1)>(aux(2)-tol-1)
                    timeqrs=[timeqrs [timeqrs1(intervalauxi);NaN;timeqrs3(intervalauxi)]];  %#ok<AGROW>
                    indexes=[indexes [indexes1(intervalauxi);NaN;indexes3(intervalauxi)]];  %#ok<AGROW>
                else
                    if auxi(2)==2 %25SET08
                        timeqrs3(intervalauxi+1:end+1)=timeqrs3(intervalauxi:end);
                        indexes3(intervalauxi+1:end+1)= indexes3(intervalauxi:end);
                        timeqrs3(intervalauxi)=NaN;
                        indexes3(intervalauxi)=NaN;
                    elseif auxi(2)==1
                        timeqrs1(intervalauxi+1:end+1)=timeqrs1(intervalauxi:end);
                        indexes1(intervalauxi+1:end+1)= indexes1(intervalauxi:end);
                        timeqrs1(intervalauxi)=NaN;
                        indexes1(intervalauxi)=NaN;
                    end
                end
            end
        elseif aux1(1)==2
            [aux auxi]=sort([timeqrs2(intervalauxi) timeqrs3(intervalauxi)]);
            if aux(1)>(aux(2)-tol-1)
                timeqrs=[timeqrs [NaN;timeqrs2(intervalauxi);timeqrs3(intervalauxi)]];  %#ok<AGROW>
                indexes=[indexes [NaN;indexes2(intervalauxi);indexes3(intervalauxi)]];  %#ok<AGROW>
            else
                if auxi(2)==1%25SET08
                    timeqrs2(intervalauxi+1:end+1)=timeqrs2(intervalauxi:end);
                    indexes2(intervalauxi+1:end+1)= indexes2(intervalauxi:end);
                    timeqrs2(intervalauxi)=NaN;
                    indexes2(intervalauxi)=NaN;
                elseif auxi(2)==2%25SET08
                    timeqrs3(intervalauxi+1:end+1)=timeqrs3(intervalauxi:end);
                    indexes3(intervalauxi+1:end+1)= indexes3(intervalauxi:end);
                    timeqrs3(intervalauxi)=NaN;
                    indexes3(intervalauxi)=NaN;
                end
            end
        end
    end
    lengthaux=([length(timeqrs1) length(timeqrs2) length(timeqrs3)]);
    if isempty(intervalauxi);
        intervalauxi=g;
    end
    aux1=find(lengthaux-intervalauxi >0);
    %remains beats in 2 leads
    while length(aux1)==2
        intervalauxi=intervalauxi+1;
        if aux1(1)==1
            if aux1(2)==2
                [aux auxi]=sort([timeqrs1(intervalauxi) timeqrs2(intervalauxi)]);
                if aux(1)>(aux(2)-tol-1)
                    timeqrs=[timeqrs [timeqrs1(intervalauxi);timeqrs2(intervalauxi);NaN]];  %#ok<AGROW>
                    indexes=[indexes [indexes1(intervalauxi);indexes2(intervalauxi);NaN]];  %#ok<AGROW>
                else
                    if auxi(2)==2
                        timeqrs2(intervalauxi+1:end+1)=timeqrs2(intervalauxi:end);
                        indexes2(intervalauxi+1:end+1)= indexes2(intervalauxi:end);
                        timeqrs2(intervalauxi)=NaN;
                        indexes2(intervalauxi)=NaN;
                    elseif auxi(2)==1
                        timeqrs1(intervalauxi+1:end+1)=timeqrs1(intervalauxi:end);
                        indexes1(intervalauxi+1:end+1)= indexes1(intervalauxi:end);
                        timeqrs1(intervalauxi)=NaN;
                        indexes1(intervalauxi)=NaN;
                    end
                end
            elseif aux1(2)==3
                [aux auxi]=sort([timeqrs1(intervalauxi) timeqrs3(intervalauxi)]);
                if aux(1)>(aux(2)-tol-1)
                    timeqrs=[timeqrs [timeqrs1(intervalauxi);NaN;timeqrs3(intervalauxi)]];  %#ok<AGROW>
                    indexes=[indexes [indexes1(intervalauxi);NaN;indexes3(intervalauxi)]];  %#ok<AGROW>
                else
                    if auxi(2)==3
                        timeqrs3(intervalauxi+1:end+1)=timeqrs3(intervalauxi:end);
                        indexes3(intervalauxi+1:end+1)= indexes3(intervalauxi:end);
                        timeqrs3(intervalauxi)=NaN;
                        indexes3(intervalauxi)=NaN;
                    elseif auxi(2)==1
                        timeqrs1(intervalauxi+1:end+1)=timeqrs1(intervalauxi:end);
                        indexes1(intervalauxi+1:end+1)= indexes1(intervalauxi:end);
                        timeqrs1(intervalauxi)=NaN;
                        indexes1(intervalauxi)=NaN;
                    end
                end
            end
        elseif aux1(1)==2
            [aux auxi]=sort([timeqrs2(intervalauxi) timeqrs3(intervalauxi)]);
            if aux(1)>(aux(2)-tol-1)
                timeqrs=[timeqrs [NaN; timeqrs2(intervalauxi);timeqrs3(intervalauxi)]];  %#ok<AGROW>
                indexes=[indexes [NaN; indexes2(intervalauxi);indexes3(intervalauxi)]];  %#ok<AGROW>
            else
                if auxi(2)==2
                    timeqrs2(intervalauxi+1:end+1)=timeqrs2(intervalauxi:end);
                    indexes2(intervalauxi+1:end+1)= indexes2(intervalauxi:end);
                    timeqrs2(intervalauxi)=NaN;
                    indexes2(intervalauxi)=NaN;
                elseif auxi(2)==3
                    timeqrs3(intervalauxi+1:end+1)=timeqrs3(intervalauxi:end);
                    indexes3(intervalauxi+1:end+1)= indexes3(intervalauxi:end);
                    timeqrs3(intervalauxi)=NaN;
                    indexes3(intervalauxi)=NaN;
                end
            end
        end
        lengthaux=([length(timeqrs1) length(timeqrs2) length(timeqrs3)]);
        aux1=find(lengthaux-intervalauxi >0);
    end
    lengthaux=([length(timeqrs1) length(timeqrs2) length(timeqrs3)]);
    g=intervalauxi;
    aux1=find(lengthaux-g >0);
end
%NOTE THAT ONLY ALIGNED ONES ARE CONSIDERED!!!!!!!!!!!!!!!!!!
intervalaux=(g+1):(min(lengthaux(aux1)));
if length(aux1)>1
    timeqrs1((min(lengthaux(aux1)))+1:end)=[];
    timeqrs2((min(lengthaux(aux1)))+1:end)=[];
    timeqrs3((min(lengthaux(aux1)))+1:end)=[];
    indexes1((min(lengthaux(aux1)))+1:end)=[];
    indexes2((min(lengthaux(aux1)))+1:end)=[];
    indexes3((min(lengthaux(aux1)))+1:end)=[];
    if ~ismember(1,aux1)
        timeqrs1(intervalaux)=NaN*ones(size(intervalaux));
        indexes1(intervalaux)=NaN*ones(size(intervalaux));
        aux=[timeqrs2(intervalaux); timeqrs3(intervalaux) ];
    end
    if ~ismember(2,aux1)
        timeqrs2(intervalaux)=NaN*ones(size(intervalaux));
        indexes2(intervalaux)=NaN*ones(size(intervalaux));
        aux=[timeqrs1(intervalaux); timeqrs3(intervalaux) ];
    end
    if ~ismember(3,aux1)
        timeqrs3(intervalaux)=NaN*ones(size(intervalaux));
        indexes3(intervalaux)=NaN*ones(size(intervalaux));
        aux=[timeqrs1(intervalaux); timeqrs2(intervalaux) ];
    end
    timeqrs=[timeqrs [timeqrs1(intervalaux(abs(diff(aux))<(tol+1)));timeqrs2(intervalaux(abs(diff(aux))<(tol+1)));timeqrs3(intervalaux(abs(diff(aux))<(tol+1)))]];
    indexes=[indexes [indexes1(intervalaux(abs(diff(aux))<(tol+1)));indexes2(intervalaux(abs(diff(aux))<(tol+1)));indexes3(intervalaux(abs(diff(aux))<(tol+1)))]];
%     indexes1(intervalaux(abs(diff(aux))>=(tol+1) | isnan(diff(aux))))=[];
%     indexes2(intervalaux(abs(diff(aux))>=(tol+1) | isnan(diff(aux))))=[];
%     indexes3(intervalaux(abs(diff(aux))>=(tol+1) | isnan(diff(aux))))=[];
%     timeqrs1(intervalaux(abs(diff(aux))>=(tol+1) | isnan(diff(aux))))=[];
%     timeqrs2(intervalaux(abs(diff(aux))>=(tol+1) | isnan(diff(aux))))=[];
%     timeqrs3(intervalaux(abs(diff(aux))>=(tol+1) | isnan(diff(aux))))=[];
else
%     timeqrs1((min(lengthaux(aux1))):end)=[];
%     timeqrs2((min(lengthaux(aux1))):end)=[];
%     timeqrs3((min(lengthaux(aux1))):end)=[];
%     indexes1((min(lengthaux(aux1))):end)=[];
%     indexes2((min(lengthaux(aux1))):end)=[];
%     indexes3((min(lengthaux(aux1))):end)=[];
end
if ~isempty(indexes) %17ABRIL08
indexes=indexes(:,~isnan(indexes(1,:))| ~isnan(indexes(2,:))|~isnan(indexes(3,:)));
end
timeqrs(:,(size(indexes,2)+1):end)=[];


function [estimate] = ft_inverse_eloreta(sourcemodel, sens, headmodel, dat, C, varargin)

% FT_INVERSE_ELORETA estimates the source activity using eLORETA
%
% Use as
%   [estimate] = ft_inverse_eloreta(sourcemodel, sens, headmodel, dat, cov, ...)
% where
%   sourcemodel is the input source model, see FT_PREPARE_SOURCEMODEL
%   sens        is the gradiometer or electrode definition, see FT_DATATYPE_SENS
%   headmodel   is the volume conductor definition, see FT_PREPARE_HEADMODEL
%   dat         is the data matrix with the ERP or ERF
%   cov         is the data covariance or cross-spectral density matrix
% and
%   estimate    contains the estimated source parameters
%
% Additional input arguments should be specified as key-value pairs and can include
%   'keepfilter'       = remember the spatial filter,    can be 'yes' or 'no'
%   'keepleadfield'    = remember the forward computation,  can be 'yes' or 'no'
%   'keepmom'          = remember the dipole moment,        can be 'yes' or 'no'
%   'lambda'           = scalar, regularisation parameter (default = 0.05)
%
% These options influence the forward computation of the leadfield
%   'reducerank'      = 'no' or number  (default = 3 for EEG, 2 for MEG)
%   'backproject'     = 'yes' or 'no', in the case of a rank reduction this parameter determines whether the result will be backprojected onto the original subspace (default = 'yes')
%   'normalize'       = 'no', 'yes' or 'column' (default = 'no')
%   'normalizeparam'  = parameter for depth normalization (default = 0.5)
%   'weight'          = number or Nx1 vector, weight for each dipole position to compensate for the size of the corresponding patch (default = 1)
%
% If the dipole definition only specifies the dipole location, a rotating dipole
% (regional source) is assumed on each location. If a dipole moment is specified, its
% orientation will be used and only the strength will be fitted to the data.
%
% This implements:
% - R.D. Pascual-Marqui; Discrete, 3D distributed, linear imaging methods of electric
%   neuronal activity. Part 1: exact, zero error localization. arXiv:0710.3341
%   2007-October-17, http://arxiv.org/pdf/0710.3341
%
% See also FT_SOURCEANALYSIS, FT_PREPARE_HEADMODEL, FT_PREPARE_SOURCEMODEL

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

if mod(nargin-5,2)
  % the first 5 arguments are fixed, the other arguments should come in pairs
  ft_error('invalid number of optional arguments');
end

% get the optional input arguments, or use defaults
keepfilter      = ft_getopt(varargin, 'keepfilter', 'no');
keepmom         = ft_getopt(varargin, 'keepmom', 'yes');
keepleadfield   = ft_getopt(varargin, 'keepleadfield', 'no');
lambda          = ft_getopt(varargin, 'lambda', 0.05);

% construct the low-level options for the leadfield computation as key-value pairs, these are passed to FT_COMPUTE_LEADFIELD
leadfieldopt = {};
leadfieldopt = ft_setopt(leadfieldopt, 'reducerank',     ft_getopt(varargin, 'reducerank'));
leadfieldopt = ft_setopt(leadfieldopt, 'backproject',    ft_getopt(varargin, 'backproject'));
leadfieldopt = ft_setopt(leadfieldopt, 'normalize',      ft_getopt(varargin, 'normalize'));
leadfieldopt = ft_setopt(leadfieldopt, 'normalizeparam', ft_getopt(varargin, 'normalizeparam'));
leadfieldopt = ft_setopt(leadfieldopt, 'weight',         ft_getopt(varargin, 'weight'));

% convert the yes/no arguments to the corresponding logical values
keepfilter     = istrue(keepfilter);
keepmom        = istrue(keepmom);
keepleadfield  = istrue(keepleadfield);

% flags to avoid calling isfield repeatedly in the loop over grid positions (saves a lot of time)
hasmom        = isfield(sourcemodel, 'mom');
hasleadfield  = isfield(sourcemodel, 'leadfield');
hasfilter     = isfield(sourcemodel, 'filter');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% find the dipole positions that are inside/outside the brain
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if ~isfield(sourcemodel, 'inside')
  if hasfilter
    sourcemodel.inside = ~cellfun(@isempty, sourcemodel.filter);
  elseif hasleadfield
    sourcemodel.inside = ~cellfun(@isempty, sourcemodel.leadfield);
  else
    sourcemodel.inside = ft_inside_headmodel(sourcemodel.pos, headmodel);
  end
end

% convert to logical representation
sourcemodel = fixinside(sourcemodel);

% keep the original details on inside and outside positions
originside = sourcemodel.inside;
origpos    = sourcemodel.pos;

% select only the dipole positions inside the brain for scanning
sourcemodel.pos    = sourcemodel.pos(originside,:);
sourcemodel.inside = true(size(sourcemodel.pos,1),1);

if hasmom
  sourcemodel.mom = sourcemodel.mom(:,originside);
end

if hasfilter
  ft_info('using precomputed filters\n');
  sourcemodel.filter = sourcemodel.filter(originside);
elseif hasleadfield
  ft_info('using precomputed leadfields\n');
  sourcemodel.leadfield = sourcemodel.leadfield(originside);
else
  ft_info('computing forward model on the fly\n');
  if hasmom
    for i=size(sourcemodel.pos,1)
      % compute the leadfield for a fixed dipole orientation
      sourcemodel.leadfield{i} = ft_compute_leadfield(sourcemodel.pos(i,:), sens, headmodel, leadfieldopt{:}) * sourcemodel.mom(:,i);
    end
  else
    for i=1:size(sourcemodel.pos,1)
      % compute the leadfield
      sourcemodel.leadfield{i} = ft_compute_leadfield(sourcemodel.pos(i,:), sens, headmodel, leadfieldopt{:});
    end
  end
end

% use existing filters, or compute them
if ~hasfilter
  % deal with reduced rank
  % check the rank of the leadfields, and project onto the lower dimensional
  % subspace if the number of columns per leadfield > rank: this to avoid
  % numerical issues in the filter computation
  rank_lf = zeros(1,size(sourcemodel.pos,1));
  for i=1:size(sourcemodel.pos,1)
    rank_lf(i) = rank(sourcemodel.leadfield{i});
  end
  if ~all(rank_lf==rank_lf(1))
    ft_error('the forward solutions have a different rank for each location, which is not supported');
  end
  if rank_lf(1)<size(sourcemodel.leadfield{1})
    ft_notice('the forward solutions have a rank of %d, but %d orientations\n',rank_lf(1),size(sourcemodel.leadfield{1},2));
    ft_notice('projecting the forward solutions on the lower dimensional subspace\n');
    for i=1:size(sourcemodel.pos,1)
      [u,s,v{i}] = svd(sourcemodel.leadfield{i}, 'econ');
      sourcemodel.leadfield{i} = sourcemodel.leadfield{i}*v{i}(:,1:rank_lf(i));
    end
  end

  % convert the leadfield into Nchan*Ndip*Nori
  [Nchan, Nori] = size(sourcemodel.leadfield{1});
  Ndip          = numel(sourcemodel.leadfield);
  leadfield     = permute(reshape(cat(2,sourcemodel.leadfield{:}),Nchan,Nori,Ndip),[1 3 2]);

  filt = mkfilt_eloreta(leadfield, lambda);
  for i=1:size(sourcemodel.pos,1)
    sourcemodel.filter{i,1} = squeeze(filt(:,i,:))';
  end
end

% get the power
siz_C  = [size(C) 1 1]; % C can have both a freq and time dimension
sourcemodel.pow = zeros([size(sourcemodel.pos,1),siz_C(3:4)]);
sourcemodel.ori = cell(size(sourcemodel.pos,1),1);
for i=1:size(sourcemodel.pos,1)
  sourcemodel.ori{i} = zeros([size(sourcemodel.filter{i},1) siz_C(3:4)]);
  for j=1:siz_C(3)
    for k=1:siz_C(4)
      csd               = sourcemodel.filter{i}*C(:,:,j,k)*sourcemodel.filter{i}';
      [u,s,v]           = svd(real(csd));
      sourcemodel.pow(i,j,k)    = s(1);
      sourcemodel.ori{i}(:,j,k) = u(:,1);
    end
  end
end

% get the dipole moment
if keepmom && ~isempty(dat)
  siz = [size(dat) 1];
  % remove the dipole moment from the input
  if hasmom
    sourcemodel = rmfield(sourcemodel, 'mom');
  end
  for i=1:size(sourcemodel.pos,1)
    sourcemodel.mom{i} = reshape(sourcemodel.filter{i}*dat(:,:), [size(sourcemodel.filter{i},1) siz(2:end)]);
  end
end

% reassign the estimated values over the inside and outside grid positions
estimate.inside  = originside;
estimate.pos     = origpos;
if isfield(sourcemodel, 'pow')
  estimate.pow( originside,:,:) = sourcemodel.pow;
  estimate.pow(~originside,:,:) = nan;
end
if isfield(sourcemodel, 'ori') % here ori is cell
  estimate.ori( originside) = sourcemodel.ori;
  estimate.ori(~originside) = {[]};
end
if isfield(sourcemodel, 'leadfield') && keepleadfield
  estimate.leadfield( originside) = sourcemodel.leadfield;
  estimate.leadfield(~originside) = {[]};
end
if isfield(sourcemodel, 'filter') && keepfilter
  estimate.filter( originside) = sourcemodel.filter;
  estimate.filter(~originside) = {[]};
end
if isfield(sourcemodel, 'mom') && keepmom
  estimate.mom( originside) = sourcemodel.mom;
  estimate.mom(~originside) = {[]};
end


function q = quaternion(sym)

q = quaternion(sym.properGroup.rot);

end


classdef SetRectangularlSensorAzAngleAction < AbstractEventAction
    %SetRectangularlSensorAzAngleAction Summary of this class goes here
    %   Detailed explanation goes here

    properties
        sensor RectangularSensor
        sensorAzAngle(1,1) double {mustBeGreaterThan(sensorAzAngle, 0)} = deg2rad(10);
    end

    properties(Constant)
        emptyVarArr = AbstractOptimizationVariable.empty(0,1);
    end

    methods
        function obj = SetRectangularlSensorAngleAction(sensor, sensorAzAngle)
            if(nargin > 0)
                obj.sensor = sensor;
                obj.sensorAzAngle = sensorAzAngle;
            end

            obj.id = rand();
        end

        function newStateLogEntry = executeAction(obj, stateLogEntry)
            newStateLogEntry = stateLogEntry;
            sensorState = newStateLogEntry.getSensorStateForSensor(obj.sensor);
            sensorState.setSensorAzAngle(obj.sensorAzAngle);
        end

        function initAction(obj, initialStateLogEntry)
            %nothing
        end

        function name = getName(obj)
            name = sprintf('Set Sensor Azimuth Half-Angle (%s => %0.3f deg)', obj.sensor.name, rad2deg(obj.sensorAzAngle));
        end

        function tf = usesStage(obj, stage)
            tf = false;
        end

        function tf = usesEngine(obj, engine)
            tf = false;
        end

        function tf = usesTank(obj, tank)
            tf = false;
        end

        function tf = usesEngineToTankConn(obj, engineToTank)
            tf = false;
        end

        function tf = usesStopwatch(obj, stopwatch)
            tf = false;
        end

        function tf = usesExtremum(obj, extremum)
            tf = false;
        end

        function tf = usesTankToTankConn(obj, tankToTank)
            tf = false;
        end

        function tf = usesSensor(obj, sensor)
            tf = obj.sensor == sensor;
        end

        function [tf, vars] = hasActiveOptimVar(obj)
            tf = false;
            vars = obj.emptyVarArr;
        end
    end

    methods(Static)
        function addActionTf = openEditActionUI(action, lv)
            lvdData = lv.lvdData;
            [~, sensors] = lvdData.sensors.getListboxStr();

            if(not(isempty(sensors)) && any([sensors.typeEnum] == SensorEnum.RectangularSensor))
                output = AppDesignerGUIOutput({false});
                lvd_EditActionSetRectangularSensorAzAngleGUI_App(action, lvdData, output);
                addActionTf = output.output{1};
            else
                addActionTf = false;
                warndlg('There are no rectangular sensors in this scenario.  Create one first.','Cannot Create Action','modal');
            end
        end
    end
end


% forcelocs() - rotate location in 3-D so specified electrodes
%               match specified locations.
%               CAUTION: Only for use on electrodes in
%               and remaining in the upper spherical hemisphere,
%               otherwise it will work improperly. Written primarily for
%               adjusting all electrodes homogenously with Cz.
%
% Usage:
%   >> chanlocs = forcelocs( chanlocs ); % pop-up window mode
%   >> chanlocs = forcelocs( chanlocs, loc1, loc2, ... );
% Example:
%   >> chanlocs = forcelocs( chanlocs, { 0.78, 'x', 'A1' }, { 0.023, 'x', ...
%   'B1','B2','Cz' } );
%
% Inputs:
%   chanlocs  - EEGLAB channel structure. See help readlocs()
%
% Optional inputs:
%   loc1      - cell array: { location, axis, channame1, channame2, .. }
%               'location' is new cartesian coordinate of channame1 along 'axis'
%               'axis' is either
%                 'X'   New x-coordinate of mean of channame1, channame2,
%                       etc. Used to calculate the X-Z plane angle by
%                       which to rotate all channels.
%                       Note that all rotations are to the corresponding positive
%                       Z-value, since theta=atan(z/x).
%                 'Y'   New x-coordinate of mean of channame1, channame2,
%                       etc.
%
%               'channame#'  Name of channel(s) to be rotated, as they appear in
%                       chanlocs.label
%   loc2      - same as loc1
%
% Outputs:
%   chanlocs  - updated EEGLAB channel structure.
%
%
% Author: Arnaud Delorme, CNL / Salk Institute, 15 April 2003
%
% See also: readlocs()

% Copyright (C) 2003 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function [chanlocs,options] = forcelocs( chanlocs, varargin)

    NENTRY = 1; % number of lines in GUI
    FIELDS = { 'X' 'Y' };

    options = [];
    if nargin < 1
        help forcelocs;
        return;
    end;
    if nargin < 2
        geom = { [0.4 1 1 0.3] };
        uilist = { { 'style' 'text' 'string' 'X/Y value' 'tag' 'valstr' } ...
                   { 'style' 'text' 'string' 'Coordinate' } ...
                   { 'style' 'text' 'string' 'Electrode list' } ...
                   { } };
        for index = 1:NENTRY
            tag = [ 'c' int2str(index) ];
            geom = { geom{:}  [0.3 1 1 0.3] };
            uilist = { uilist{:} { 'style' 'edit' 'string' fastif(index==1, '0','') } ...
                       { 'style' 'listbox' 'string' 'X (rotate X-Z plane)|Y (rotate Y-Z plane)' ...
                         'callback' [ 'if get(gco, ''value'') == 1,' ...
                                      '     set(findobj(gcbf, ''tag'', ''valstr''), ''string'', ''Y value'');' ...
                                      'else set(findobj(gcbf, ''tag'', ''valstr''), ''string'', ''X value'');' ...
                                      'end;' ] } ...
                       { 'style' 'edit' 'string'  fastif(index==1, 'Cz','') 'tag' tag } ...
                       { 'style' 'pushbutton' 'string' 'Pick' ...
                         'callback', [ 'tmp3 = get(gcbf, ''userdata'');' ...
                                       '[tmp1 tmp2] = pop_chansel({tmp3.labels}, ''selectionmode'', ''single'');' ...
                                       'if ~isempty(tmp1) set(findobj(gcbf, ''tag'', ''' tag '''), ''string'', tmp2); end;' ...
                                       'clear tmp1 tmp2;' ] } };
        end;

        results = inputgui( geom, uilist, 'pophelp(''forcelocs'');', 'Force electrode location -- forcelocs()', chanlocs );
        if length(results) == 0, return; end;

        options = {};
        for index = 1:NENTRY
            tmpi = 3*(index-1)+1;
            if ~isempty(results{tmpi})
                tmpchans = parsetxt(results{tmpi+2});
                options = { options{:} { str2num(results{tmpi}) FIELDS{results{tmpi+1}} tmpchans{:} }};
            end;
        end;
    else
        options = varargin;
    end;

    % scan all locations
    % ------------------
    channelnames = lower(strvcat({chanlocs.labels}));
    for index = 1:length(options)

        val   = options{index}{1};
        type  = options{index}{2};
        chans = getchans(options{index}(3:end), channelnames);

        % rotate X-Z plane
        % ----------------
        if strcmpi(type, 'x')
            curx   = mean([ chanlocs(chans).X ]);
            curz   = mean([ chanlocs(chans).Z ]);
            newx = val;
            rotangle = solvesystem(curx, curz, newx);

            for chanind = 1:length(chanlocs)
                [chanlocs(chanind).X chanlocs(chanind).Z]= rotation(chanlocs(chanind).X, chanlocs(chanind).Z, rotangle);
            end;
            chanlocs = convertlocs(chanlocs, 'cart2all');
        end;

        % rotate Y-Z plane
        % ----------------
        if strcmpi(type, 'y')
            cury   = mean([ chanlocs(chans).Y ]);
            curz   = mean([ chanlocs(chans).Z ]);
            newy = val;
            rotangle = solvesystem(cury, curz, newy);

            for chanind = 1:length(chanlocs)
                [chanlocs(chanind).Y chanlocs(chanind).Z]= rotation(chanlocs(chanind).Y, chanlocs(chanind).Z, rotangle);
            end;
            chanlocs = convertlocs(chanlocs, 'cart2all');
        end;

    end;

% get channel indices
% -------------------
function chanlist = getchans(chanliststr, channelnames);
    chanlist = [];
    for index = 1:length(chanliststr)
        i = strmatch (lower(chanliststr{index}), channelnames, 'exact');
        chanlist  = [chanlist i];
    end;

% function rotate coordinates
% ---------------------------
function [X,Y] = rotation(x,y,rotangle)
    X = real((x+j*y)*exp(j*rotangle));
    Y = imag((x+j*y)*exp(j*rotangle));

% function solvesyst
% ------------------
function theta = solvesystem(x,y,nx)
    % Original Solution
    %eq(1,:) = [x -y]; res(1) = nx;
    %eq(2,:) = [y x];  res(2) = sqrt(x^2+y^2-nx^2);
    %sol = eq\res';
    %theta = atan2(sol(2), sol(1));

    % simplified solution
    ny = sqrt(x^2+y^2-nx^2);
    ang1 = angle(x+j*y);
    ang2 = angle(nx+j*ny);
    theta = ang2-ang1;

    % Even simpler solution     Toby 03/05/2007
    % theta = atan(y/x);


clc;
clear;
%path='C:\Users\Administrator\Desktop\mat-cvpr17_v1\ECSSD\';
path='./PR_results/';
dirpath=dir([path '*.mat']);
method1 = cell(length(dirpath),3);

str=['r','r','b','b','c','c','m','m','k','k','y','y','g','g','r','r','m','m','k','k','r','r','r','r','r'];

rr=[];
Fmeasure=[];
aAUC=[];
method2 = cell(length(dirpath),1);
for i=1:length(dirpath)
  load([path dirpath(i).name]);
  Fmeasure=[Fmeasure,mFmeasure];
  aAUC=[aAUC,AUC];                     %AUC 图像修改部分
%  method2(i)=alg_dir{i}(1);
  method2{i}=dirpath(i).name(1:end-4);

end
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%
        figure(5);
        barMsra = [Fmeasure' aAUC'];
        bar(barMsra );
        set( gca, 'xtick', 1:1:length(dirpath) ),

        set( gca ,'xticklabels',  method2 , 'fontsize', 8 );
        legend('Precision','Recall','Fmeasure','AUC');      %AUC 图像修改部分
        %legend('Precision','Recall','Fmeasure');
              grid on;
   %     saveas(  figure(5), [basedir,'SED1_bar.fig']);

% xlabel('Recall');
% ylabel('Precision');
%legend(dirpath(1).name(5:end),dirpath(2).name(5:end),dirpath(3).name(5:end),dirpath(4).name(5:end),dirpath(5).name(5:end),dirpath(6).name(5:end),dirpath(7).name(5:end),dirpath(8).name(5:end),dirpath(9).name(5:end),dirpath(10).name(5:end),dirpath(11).name(5:end),dirpath(12).name(5:end),dirpath(13).name(5:end),dirpath(14).name(5:end),dirpath(15).name(5:end),dirpath(16).name(5:end),dirpath(17).name(5:end),dirpath(18).name(5:end),dirpath(19).name(5:end),dirpath(20).name(5:end),dirpath(21).name(5:end));
%legend(dirpath(1).name(8:end-4),dirpath(2).name(8:end-4),dirpath(3).name(8:end-4),dirpath(4).name(8:end-4),dirpath(5).name(8:end-4),dirpath(6).name(8:end-4),dirpath(7).name(8:end-4),dirpath(8).name(8:end-4),dirpath(9).name(8:end-4),dirpath(10).name(8:end-4),dirpath(11).name(8:end-4),dirpath(12).name(8:end-4),dirpath(13).name(8:end-4),dirpath(14).name(8:end-4));
%legend(dirpath(1).name(1:end-4),dirpath(2).name(1:end-4),dirpath(3).name(1:end-4),dirpath(4).name(1:end-4),dirpath(5).name(1:end-4),dirpath(6).name(1:end-4),dirpath(7).name(1:end-4),dirpath(8).name(1:end-4))%,dirpath(9).name(1:end-4),dirpath(10).name(1:end-4),dirpath(11).name(1:end-4));%,dirpath(12).name(1:end-4),dirpath(13).name(1:end-4));
%legend(str(1,:),str(2,:),str(3,:),str(4,:),str(5,:),str(6,:),str(7,:),str(8,:),str(9,:),str(10,:),str(11,:),str(12,:),str(13,:),str(14,:),str(15,:),str(16,:),str(17,:));
%legend(dirpath(1).name(2:end-4),dirpath(2).name(2:end-4),dirpath(3).name(2
%legend(dirpath(1).name(1:end-4),dirpath(2).name(1:end-4),dirpath(3).name(1:end-4),dirpath(4).name(1:end-4),...
%dirpath(5).name(1:end-4),dirpath(6).name(1:end-4))%,dirpath(7).name(1:end-4),dirpath(8).name(1:end-4),dirpath(9).name(1:end-4),...
% dirpath(10).name(1:end-4),dirpath(11).name(1:end-4),dirpath(12).name(1:end-4),dirpath(13).name(1:end-4),...
% dirpath(14).name(1:end-4),dirpath(15).name(1:end-4),dirpath(16).name(1:end-4),dirpath(17).name(1:end-4),...
% dirpath(18).name(1:end-4),dirpath(19).name(1:end-4),dirpath(20).name(1:end-4),dirpath(21).name(1:end-4))%,...
%dirpath(22).name(1:end-4),dirpath(23).name(1:end-4));
grid on;
% save 300 AUC;


function varargout = process_spike_triggered_average( varargin )
% PROCESS_SPIKE_TRIGGERED_AVERAGE: Computes the spike triggered average.
% Select a time window around the spikes of a specific neuron and average the LFPs of each electrode

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

eval(macro_method);
end

%% ===== GET DESCRIPTION =====
function sProcess = GetDescription()
    % Description the process
    sProcess.Comment     = 'Spike triggered average';
    sProcess.FileTag     = 'STA';
    sProcess.Category    = 'Custom';
    sProcess.SubGroup    = 'Electrophysiology';
    sProcess.Index       = 1230;
    sProcess.Description = 'https://neuroimage.usc.edu/brainstorm/e-phys/functions#Spike_triggered_average';
    % Definition of the input accepted by this process
    sProcess.InputTypes  = {'data'};
    sProcess.OutputTypes = {'data'};
    sProcess.nInputs     = 1;
    sProcess.nMinFiles   = 2;
    % Options: Segment around spike
    sProcess.options.timewindow.Comment  = 'Spike time window: ';
    sProcess.options.timewindow.Type     = 'range';
    sProcess.options.timewindow.Value    = {[-0.150, 0.150],'ms',[]};
    % Options: Parallel Processing
    sProcess.options.parallel.Comment = 'Parallel processing';
    sProcess.options.parallel.Type    = 'checkbox';
    sProcess.options.parallel.Value   = 0;
end

%% ===== FORMAT COMMENT =====
function Comment = FormatComment(sProcess)
    Comment = sProcess.Comment;
end

%% ===== RUN =====
function OutputFiles = Run(sProcess, sInputs)
    % Initialize returned values
    OutputFiles = {};
    % Get options
    isParallel = sProcess.options.parallel.Value;
    TimeWindow = sProcess.options.timewindow.Value{1};

    % ===== LOAD INPUTS =====
    % Loads all the data outside of the parfor, so it doesn't fail
    nTrials = length(sInputs);
    DataMats = cell(1, nTrials);
    ChannelFlag = [];
    for iFile = 1:length(sInputs)
        DataMats{iFile} = in_bst_data(sInputs(iFile).FileName);
        if isempty(ChannelFlag)
            ChannelFlag = DataMats{iFile}.ChannelFlag;
        else
            ChannelFlag(DataMats{iFile}.ChannelFlag == -1) = -1;
        end
    end
    % Check time window
    if TimeWindow(1)>=0 || TimeWindow(2)<=0
        bst_report('Error', sProcess, sInputs, 'The time-selection must be around the spikes.');
        return;
    elseif (TimeWindow(1) <= DataMats{1}.Time(1)) && (TimeWindow(2) >= DataMats{1}.Time(end))
        bst_report('Error', sProcess, sInputs, 'The spike window has to be smaller than the trial window.');
        return;
    end
    % Sampling frequency
    sampling_rate = round(abs(1. / (DataMats{1}.Time(2) - DataMats{1}.Time(1))));
    % Load channel file
    ChannelMat = in_bst_channel(sInputs(1).ChannelFile);

    % === START COMPUTATION ===
    % Input time window
    time_segmentAroundSpikes = linspace(TimeWindow(1), TimeWindow(2), abs(TimeWindow(2))* sampling_rate + abs(TimeWindow(1))* sampling_rate + 1);
    % Get LPFs
    LFP_trials = cell(1, nTrials);
    if isParallel
        parfor iFile = 1:nTrials
            LFP_trials{iFile} = get_LFPs(DataMats{iFile}, ChannelMat, TimeWindow, time_segmentAroundSpikes, sampling_rate);
        end
    else
        for iFile = 1:nTrials
            LFP_trials{iFile} = get_LFPs(DataMats{iFile}, ChannelMat, TimeWindow, time_segmentAroundSpikes, sampling_rate);
        end
    end

    % ===== COMPUTE SPIKE TRIGGERED AVERAGE =====
    % The Spike Triggered Average should be a 3d matrix
    % Number of neurons x Frequencies x Electrodes
    % Ultimately the user will select the NEURON that wants to be displayed,
    % and a 2D image with the other two dimensions will appear, showing the
    % coherence of the spikes of that neuron with the LFPs on every
    % electrode on all frequencies.

    % Create a cell that holds all of the labels and one for the unique labels
    % This will be used to take the averages using the appropriate indices
    all_labels = {};
    labelsNeurons = {}; % Unique neuron labels (each trial might have different number of neurons). We need everything that appears.
    for iFile = 1:nTrials
        for iNeuron = 1:length(LFP_trials{iFile})
            all_labels{iNeuron,iFile} = LFP_trials{iFile}(iNeuron).label;
            labelsNeurons{end+1} = LFP_trials{iFile}(iNeuron).label;
        end
    end
    labelsNeurons = unique(labelsNeurons,'stable');

    % Compute STA per individual neuron
    for iNeuron = 1:length(labelsNeurons)
        % For each TRIAL, get the index of the label that corresponds to the appropriate neuron.
        for ii = 1:size(all_labels,1)
            for jj = 1:size(all_labels,2)
                logicalEvents(ii,jj) = strcmp(all_labels{ii,jj}, labelsNeurons{iNeuron});
            end
        end

        iEvents = zeros(size(all_labels,2),1);
        for iFile = 1:size(all_labels,2)
            temp = find(logicalEvents(:,iFile));
            if ~isempty(temp)
                iEvents(iFile) = temp;
            else
                iEvents(iFile) = 0; % This shows that that neuron didn't fire any spikes on that trial
            end
        end

        % Compute the averages of the appropriate indices
        STA_single_neuron = zeros(length(ChannelMat.Channel), length(time_segmentAroundSpikes));
        std_single_neuron = zeros(length(ChannelMat.Channel), length(time_segmentAroundSpikes));
        divideBy = 0;
        for iFile = 1:size(all_labels,2)
            if iEvents(iFile)~=0
                STA_single_neuron = STA_single_neuron + LFP_trials{iFile}(iEvents(iFile)).nSpikes * LFP_trials{iFile}(iEvents(iFile)).avgLFP; % The avgLFP are sum actually.
                divideBy = divideBy + LFP_trials{iFile}(iEvents(iFile)).nSpikes;

                % Here I have the assumption that the LFPs on all trials
                % have homogeneity in their variance (Cohen, 1988, p.67):
                % http://www.utstat.toronto.edu/~brunner/oldclass/378f16/readings/CohenPower.pdf
                % https://www.statisticshowto.datasciencecentral.com/pooled-standard-deviation/
                std_single_neuron = std_single_neuron + (LFP_trials{iFile}(iEvents(iFile)).nSpikes-1) * LFP_trials{iFile}(iEvents(iFile)).stdLFP.^2;
            end
        end
        % Divide by total number of averages
        STA_single_neuron = (STA_single_neuron./divideBy)';
        std_single_neuron = sqrt(std_single_neuron./(divideBy - size(all_labels,2)));

        % Get meaningful label from neuron name
        better_label = panel_spikes('GetChannelOfSpikeEvent', labelsNeurons{iNeuron});
        neuron = panel_spikes('GetNeuronOfSpikeEvent', labelsNeurons{iNeuron});
        if ~isempty(neuron)
            better_label = [better_label ' #' num2str(neuron)];
        end

        % ===== SAVE FILE =====
        % Prepare output file structure
        FileMat = db_template('datamat');
        FileMat.F           = STA_single_neuron';
        FileMat.Time        = time_segmentAroundSpikes;
        FileMat.Std         = 2 .* std_single_neuron; % MULTIPLY BY 2 TO GET 95% CONFIDENCE (ASSUMING NORMAL DISTRIBUTION)
        FileMat.Comment     = ['Spike Triggered Average: ' str_remove_parenth(DataMats{1}.Comment) ' (' better_label ')'];
        FileMat.DataType    = 'recordings';
        FileMat.ChannelFlag = ChannelFlag;
        FileMat.Device      = DataMats{1}.Device;
        FileMat.nAvg        = 1;
        FileMat.History     = DataMats{1}.History;

        % Add history field
        FileMat = bst_history('add', FileMat, 'compute', ['Spike Triggered Average: [' num2str(TimeWindow(1)) ', ' num2str(TimeWindow(2)) '] ms']);
        for iFile = 1:length(sInputs)
            FileMat = bst_history('add', FileMat, 'average', [' - ' sInputs(iFile).FileName]);
        end

        % Get output study
        [tmp, iTargetStudy] = bst_process('GetOutputStudy', sProcess, sInputs);
        sTargetStudy = bst_get('Study', iTargetStudy);
        % Output filename
        FileName = bst_process('GetNewFilename', bst_fileparts(sTargetStudy.FileName), 'data_STA');
        OutputFiles = {FileName};
        % Save output file and add to database
        bst_save(FileName, FileMat, 'v6');
        db_add_data(iTargetStudy, FileName, FileMat);
    end
end

%% ===== GET LFP =====
% Get the events that show neurons activity
function all = get_LFPs(trial, ChannelMat, TimeWindow, time_segmentAroundSpikes, sampling_rate)
    spikeEvents = []; % The spikeEvents variable holds the indices of the events that correspond to spikes.

    allChannelEvents = cellfun(@(x) panel_spikes('GetChannelOfSpikeEvent', x), {trial.Events.label}, 'UniformOutput', 0);
    for ielectrode = 1:length(ChannelMat.Channel)
        iEvents = find(strcmp(allChannelEvents, ChannelMat.Channel(ielectrode).Name)); % Find the index of the spike-events that correspond to that electrode (Exact string match)
        if ~isempty(iEvents)
            spikeEvents(end+1:end+length(iEvents)) = iEvents;
        end
    end

    % Get segments around each spike, FOR EACH NEURON
    all = struct();
    for iNeuron = 1:length(spikeEvents) % iNeuron is the iEvent
        % Check that the entire segment around the spikes [-150,150]ms is inside the trial segment and keep only those events
        iSel = trial.Events(spikeEvents(iNeuron)).times > trial.Time(1)   + abs(TimeWindow(1)) & ...
               trial.Events(spikeEvents(iNeuron)).times < trial.Time(end) - abs(TimeWindow(2));
        events_within_segment = round(trial.Events(spikeEvents(iNeuron)).times(iSel) .* sampling_rate);

        % Create a matrix that holds all the segments around the spike of that neuron, for all electrodes.
        allSpikeSegments_singleNeuron_singleTrial = zeros(length(events_within_segment),length(ChannelMat.Channel),length(time_segmentAroundSpikes));
        for ispike = 1:length(events_within_segment)
            allSpikeSegments_singleNeuron_singleTrial(ispike,:,:) = trial.F(:, ...
                round(abs(trial.Time(1))*sampling_rate) + events_within_segment(ispike) - round(abs(TimeWindow(1)) * sampling_rate) + 1 : ...
                round(abs(trial.Time(1))*sampling_rate) + events_within_segment(ispike) + round(abs(TimeWindow(2)) * sampling_rate) + 1);
        end

        all(iNeuron).label   = trial.Events(spikeEvents(iNeuron)).label;
        all(iNeuron).nSpikes = length(events_within_segment);
        all(iNeuron).avgLFP  = squeeze(sum(allSpikeSegments_singleNeuron_singleTrial,1));
        all(iNeuron).stdLFP  = squeeze(std(allSpikeSegments_singleNeuron_singleTrial,[],1));
        all(iNeuron).Used    = 0; % This indicates if this entry has already been used for computing the SFC (some spikes might not appear on every trial imported, so a new Neuron should be identified on a later trial).
    end

    % Check if any events had no spikes in the time-region of interest and remove them!
    %  Some spikes might be on the edges of the trial. Ultimately, the
    %  Spikes Channel i events would be considered in the STA (I mean the event group, not the events themselves),
    %  but there would be a zeroed avgLFP included. Get rid of those events
    iEventsToRemove = find([all.nSpikes]==0);
    all = all(~ismember(1:length(all),iEventsToRemove));
end


function [model, directions] = directionalityStats(model, directions, cumNormProbCutoff, printLevel)
% Build Boolean vectors with reaction directionality statistics
%
% USAGE:
%
%    [model, directions] = directionalityStats(model, directions, cumNormProbCutoff, printLevel)
%
% INPUTS:
%    model:                 a structue of boolean vectors with different directionality
%                           assignments where some vectors contain subsets of others with field:
%
%                             * .directions
%
%    directions:            structure with field:
%
%                             * .forwardProbability
%
%                           qualitatively assigned internal reaction direactions
%
%                             * .forwardRecon
%                             * .reverseRecon
%                             * .reversibleRecon
%                             * .equilibriumRecon
%
%                           quantitatively assigned internal reaction direactions
%                           thermodynamic data is lacking
%
%                             * .forwardThermo
%                             * .reverseThermo
%                             * .reversibleThermo
%                             * .uncertainThermo
%                             * .equilibriumThermo
%
% OPTIONAL INPUT
%    cumNormProbCutoff:     {0.2} cutoff for probablity that reaction is
%                           reversible within this cutoff of 0.5
%    printLevel:            -1 to print out to file,
%                           0 to silent,
%                           1 to print out to command window
%
% OUTPUT:
%    directions:            a structue of boolean vectors with different directionality
%                           assignments where some vectors contain subsets of others
%
%                           qualtiative -> quantiative changed reaction directions
%
%                             * .forward2Forward
%                             * .forward2Reverse
%                             * .forward2Reversible
%                             * .forward2Uncertain
%                             * .reversible2Forward
%                             * .reversible2Reverse
%                             * .reversible2Reversible
%                             * .reversible2Uncertain
%                             * .reverse2Forward
%                             * .reverse2Reverse
%                             * .reverse2Reversible
%                             * .reverse2Uncertain
%                             * .tightened
%
%                           subsets of qualtiatively forward  -> quantiatively reversible
%
%                             * .forward2Reversible_bydGt0
%                             * .forward2Reversible_bydGt0LHS
%                             * .forward2Reversible_bydGt0Mid
%                             * .forward2Reversible_bydGt0RHS
%                             * .forward2Reversible_byConc_zero_fixed_DrG0
%                             * .forward2Reversible_byConc_negative_fixed_DrG0
%                             * .forward2Reversible_byConc_positive_fixed_DrG0
%                             * .forward2Reversible_byConc_negative_uncertain_DrG0
%                             * .forward2Reversible_byConc_positive_uncertain_DrG0
%
% .. Author: - Ronan M.T. Fleming

if ~exist('cumNormProbCutoff','var')
    directions.cumNormProbCutoff=0.2;
else
    directions.cumNormProbCutoff=cumNormProbCutoff;
end
%must be symmetric about 50:50 to be logically consistent
cumNormProbFwdUpper=0.5+directions.cumNormProbCutoff;
cumNormProbFwdLower=0.5-directions.cumNormProbCutoff;

if ~exist('printLevel','var')
    printLevel=0;
end
if ~exist('fileName','var')
    fileName='directionalityStats.txt';
end

DrGtMin=model.DrGtMin;
DrGtMax=model.DrGtMax;
if any(DrGtMin>DrGtMax)
    error('DrGtMin greater than DrGtMax');
end

DrGtNaNBool=(isnan(model.DrGtMax) | isnan(model.DrGtMin)) & model.SIntRxnBool;
if any(DrGtNaNBool)
    warning([int2str(nnz(DrGtNaNBool)) ' DrGt are NaN']);
end

nEqualDrGt=nnz(DrGtMin==DrGtMax & DrGtMin~=0);
if any(nEqualDrGt)
    fprintf('%s\n',[num2str(nEqualDrGt) '/' num2str(length(DrGtMin)) ' reactions with DrGtMin=DrGtMax~=0' ]);
end

nZeroDrGt=nnz(DrGtMin==0 & DrGtMax==0);
if any(nZeroDrGt)
    fprintf('%s\n',[num2str(nZeroDrGt) '/' num2str(length(DrGtMin)) ' reactions with DrGtMin=DrGtMax=0' ]);
end

[~,nRxn]=size(model.S);

% qualitatively assigned directions
forwardRecon=directions.forwardRecon;
reverseRecon=directions.reverseRecon;
reversibleRecon=directions.reversibleRecon;
% quantitatively assigned directions
forwardThermo=directions.forwardThermo;
reverseThermo=directions.reverseThermo;
reversibleThermo=directions.reversibleThermo;
uncertainThermo=directions.uncertainThermo;

%%%%%%CHANGES IN REACTION DIRECTIONS%%%%%%%%%%%
%thermodynamic constraints tightened
tightened=model.lb<model.lb_reconThermo & model.ub_reconThermo<model.ub;

reversible2Forward=reversibleRecon & forwardThermo;
reversible2Reverse=reversibleRecon & reverseThermo;
reversible2Reversible=reversibleRecon & reversibleThermo;
reversible2Uncertain=reversibleRecon & uncertainThermo;

forward2Reverse=forwardRecon & reverseThermo;
forward2Reversible=forwardRecon & reversibleThermo;
forward2Forward=forwardRecon & forwardThermo;
forward2Uncertain=forwardRecon & uncertainThermo;

reverse2Reverse =  reverseRecon & reverseThermo;
reverse2Forward   =  reverseRecon & forwardThermo;
reverse2Reversible =  reverseRecon & reversibleThermo;
reverse2Uncertain  =  reverseRecon & uncertainThermo;

%%%%%%CAUSES TO CHANGES IN REACTION DIRECTIONS%%%%%%%%%%%
% model.DrGtMax = model.DrGt0Max + gasConstant*T*(R'*log(model.concMax) - F'*log(model.concMin));
% model.DrGtMin = model.DrGt0Min + gasConstant*T*(R'*log(model.concMin) - F'*log(model.concMax));
% model.DrGtMaxMeanConc = model.DrGt0Max + gasConstant*T*(R-F)'*log((model.concMax+model.concMin)/2);
% model.DrGtMinMeanConc = model.DrGt0Min + gasConstant*T*(R-F)'*log((model.concMax+model.concMin)/2);

forward2Reversible_bydGt0=forwardRecon & reversibleThermo & model.DrGtMin<0 & model.DrGtMax>0; % dGfGCforward2ReversibleBool_bydGt0

forward2Reversible_byConc_negative_fixed_DrG0 = forwardRecon & reversibleThermo & model.DrGt0Min==model.DrGt0Max & model.DrGtMax<=0; %dGfGCforward2ReversibleBool_byConc_No_dGt0ErrorLHS
forward2Reversible_byConc_positive_fixed_DrG0 = forwardRecon & reversibleThermo & model.DrGt0Min==model.DrGt0Max & model.DrGtMin>0; %dGfGCforward2ReversibleBool_byConc_No_dGt0ErrorRHS

forward2Reversible_bydGt0LHS=forward2Reversible_bydGt0 & directions.forwardProbability>cumNormProbFwdUpper; %dGfGCforward2ReversibleBool_bydGt0LHS
forward2Reversible_bydGt0Mid=forward2Reversible_bydGt0 & directions.forwardProbability>=cumNormProbFwdLower & directions.forwardProbability<=cumNormProbFwdUpper;%dGfGCforward2ReversibleBool_bydGt0Mid
forward2Reversible_bydGt0RHS=forward2Reversible_bydGt0 & directions.forwardProbability<cumNormProbFwdLower; %dGfGCforward2ReversibleBool_bydGt0RHS

forward2Reversible_byConc_negative_uncertain_DrG0 = forwardRecon & reversibleThermo & model.DrGt0Min~=model.DrGt0Max & model.DrGt0Max<0; %dGfGCforward2ReversibleBool_byConcLHS
forward2Reversible_byConc_positive_uncertain_DrG0 = forwardRecon & reversibleThermo & model.DrGt0Min~=model.DrGt0Max & model.DrGt0Min>0; %dGfGCforward2ReversibleBool_byConcRHS

forward2Reversible_byConc_zero_fixed_DrG0 = forwardRecon & reversibleThermo & model.DrGt0Min==0 & model.DrGt0Max==0;%new to v2

if printLevel<0
    fid=fopen(fileName,'w');
else
    fid=1;
end

if printLevel~=0
    fprintf(fid,'%s\n','Qualitative internal reaction directionality:');
    fprintf(fid,'%10s\t%s\n',int2str(nnz(model.SIntRxnBool)),' internal reconstruction reaction directions.');
    fprintf(fid,'%10s\t%s\n',int2str(nnz(forwardRecon)), ' forward reconstruction assignment.');
    fprintf(fid,'%10s\t%s\n',int2str(nnz(reverseRecon)), ' reverse reconstruction assignment.');
    fprintf(fid,'%10s\t%s\n',int2str(nnz(reversibleRecon)), ' reversible reconstruction assignment.');
    fprintf(fid,'\n');

    fprintf(fid,'%s\n','Quantitative internal reaction directionality:');
    fprintf(fid,'%10s\t%s\n',int2str(nnz(model.SIntRxnBool)),' internal reconstruction reaction directions.');
    fprintf(fid,'%10s\t%s\n',int2str(nnz(forwardThermo)+nnz(reverseThermo)+nnz(reversibleThermo)),  ' of which have a thermodynamic assignment.');
    fprintf(fid,'%10s\t%s\n',int2str(nnz(uncertainThermo)),  ' of which have no thermodynamic assignment.');
    fprintf(fid,'%10s\t%s\n',int2str(nnz(forwardThermo)), ' forward thermodynamic only assignment.');
    fprintf(fid,'%10s\t%s\n',int2str(nnz(reverseThermo)), ' reverse thermodynamic only assignment.');
    fprintf(fid,'%10s\t%s\n',int2str(nnz(reversibleThermo)), ' reversible thermodynamic only assignment.');
    fprintf(fid,'\n');

    fprintf(fid,'%s\n','Qualitiative vs Quantitative:');
    fprintf(fid,'%10i\t%s\n',nnz(reversible2Reversible),' Reversible -> Reversible');
    fprintf(fid,'%10i\t%s\n',nnz(reversible2Forward),' Reversible -> Forward');
    fprintf(fid,'%10i\t%s\n',nnz(reversible2Reverse),' Reversible -> Reverse');
    fprintf(fid,'%10i\t%s\n',nnz(reversible2Uncertain),' Reversible -> Uncertain');
    fprintf(fid,'%10i\t%s\n',nnz(forward2Forward),' Forward -> Forward');
    fprintf(fid,'%10i\t%s\n',nnz(forward2Reverse),' Forward -> Reverse');
    fprintf(fid,'%10i\t%s\n',nnz(forward2Reversible),' Forward -> Reversible');
    fprintf(fid,'%10i\t%s\n',nnz(forward2Uncertain),' Forward -> Uncertain');
    fprintf(fid,'%10i\t%s\n',nnz(reverse2Reversible),' Reverse -> Reverse');
    fprintf(fid,'%10i\t%s\n',nnz(reverse2Forward),' Reverse -> Forward');
    fprintf(fid,'%10i\t%s\n',nnz(reverse2Reversible),' Reverse -> Reversible');
    fprintf(fid,'%10i\t%s\n',nnz(reverse2Uncertain),' Reversible -> Uncertain');
    fprintf(fid,'\n');

    fprintf(fid,'%s\n','Breakdown of relaxation of reaction directionality, Qualitiative vs Quantitative:');
    %total number of qualitatively forward reactions that are
    %quantitatively reversible
    fprintf(fid,'%10i\t%s\n',nnz(forward2Reversible),' qualitatively forward reactions that are quantitatively reversible (total).');
    %qualitatively forward reactions that are quantitatively reversible by
    %the range of dGt0
    fprintf(fid,'%10i\t%s%s\n',nnz(forward2Reversible_bydGt0LHS),' of which are quantitatively reversible by range of dGt0. ',['P(\Delta_{r}G^{\primeo}<0) > ' num2str(cumNormProbFwdUpper)]);
    %qualitatively reverse reactions that are quantitatively
    %reversible by concentration alone (with dGt0 error)
    fprintf(fid,'%10i\t%s%s\n',nnz(forward2Reversible_bydGt0Mid),' of which are quantitatively reversible by range of dGt0. ',[num2str(cumNormProbFwdLower) '< P(\Delta_{r}G^{\primeo}<0) < ' num2str(cumNormProbFwdUpper)]);
    %qualitatively reverse reactions that are quantitatively
    %reversible by concentration alone (with dGt0 error)
    fprintf(fid,'%10i\t%s%s\n',nnz(forward2Reversible_bydGt0RHS),' of which are quantitatively reversible by range of dGt0. ',['P(\Delta_{r}G^{\primeo}<0) < ' num2str(cumNormProbFwdLower)]);
    %qualitatively forward reactions that are quantitatively
    %reversible by concentration alone (no dGt0 error)
    fprintf(fid,'%10i\t%s\n',nnz(forward2Reversible_byConc_zero_fixed_DrG0),' of which are quantitatively forward by fixed dGr0t, but reversible by concentration alone (zero fixed DrGt0).');
    %qualitatively reverse reactions that are quantitatively
    %reversible by concentration alone (with dGt0 error)
    fprintf(fid,'%10i\t%s\n',nnz(forward2Reversible_byConc_negative_fixed_DrG0),' of which are quantitatively reverse by dGr0t, but reversible by concentration (negative fixed DrGt0).');
    %qualitatively reverse reactions that are quantitatively
    %reversible by concentration alone (with dGt0 error)
    fprintf(fid,'%10i\t%s\n',nnz(forward2Reversible_byConc_positive_fixed_DrG0),' of which are quantitatively forward by dGr0t, but reversible by concentration (positve fixed DrGt0).');
    %qualitatively reverse reactions that are quantitatively
    %reversible by concentration alone (with dGt0 error)
    fprintf(fid,'%10i\t%s\n',nnz(forward2Reversible_byConc_negative_uncertain_DrG0),' of which are quantitatively reverse by dGr0t, but reversible by concentration (uncertain negative DrGt0).');
    %qualitatively reverse reactions that are quantitatively
    %reversible by concentration alone (with dGt0 error)
    fprintf(fid,'%10i\t%s\n',nnz(forward2Reversible_byConc_positive_uncertain_DrG0),' of which are quantitatively forward by dGr0t, but reversible by concentration (uncertain positive DrGt0).');
end
if printLevel<0
    fclose(fid);
end

%changed directions
directions.forward2Forward=forward2Forward;
directions.forward2Reverse=forward2Reverse;
directions.forward2Reversible=forward2Reversible;
directions.forward2Uncertain=forward2Uncertain;
directions.reversible2Forward=reversible2Forward;
directions.reversible2Reverse=reversible2Reverse;
directions.reversible2Reversible=reversible2Reversible;
directions.reversible2Uncertain=reversible2Uncertain;
directions.reverse2Forward=reverse2Forward;
directions.reverse2Reverse=reverse2Reverse;
directions.reverse2Reversible=reverse2Reversible;
directions.reverse2Uncertain=reverse2Uncertain;

directions.tightened=tightened;

%all forward reversible classes
directions.forward2Reversible_bydGt0=forward2Reversible_bydGt0;
directions.forward2Reversible_bydGt0LHS=forward2Reversible_bydGt0LHS;
directions.forward2Reversible_bydGt0Mid=forward2Reversible_bydGt0Mid;
directions.forward2Reversible_bydGt0RHS=forward2Reversible_bydGt0RHS;

directions.forward2Reversible_byConc_zero_fixed_DrG0=forward2Reversible_byConc_zero_fixed_DrG0;
directions.forward2Reversible_byConc_negative_fixed_DrG0=forward2Reversible_byConc_negative_fixed_DrG0;
directions.forward2Reversible_byConc_positive_fixed_DrG0=forward2Reversible_byConc_positive_fixed_DrG0;
directions.forward2Reversible_byConc_negative_uncertain_DrG0=forward2Reversible_byConc_negative_uncertain_DrG0;
directions.forward2Reversible_byConc_positive_uncertain_DrG0=forward2Reversible_byConc_positive_uncertain_DrG0;


function out = brighterremap(x)
% BRIGHTERREMAP Brighter set of parameters for density remap
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

    out = uint8( amplitudetodensity(x,60,40) );
end
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////


% -------------------------------------------------------------------------------------------------
function [bboxes,fps, ground_truth] = tracker2(varargin)
%TRACKER
%   is the main function that performs the tracking loop
%   Default parameters are overwritten by VARARGIN
%
%   Luca Bertinetto, Jack Valmadre, Joao F. Henriques, 2016
% -------------------------------------------------------------------------------------------------
    % These are the default hyper-params for SiamFC-3S
    % The ones for SiamFC (5 scales) are in params-5s.txt
    p.numScale = 3;
    p.scaleStep = 1.0375;
    p.scalePenalty = 0.9745;
    p.scaleLR = 0.59; % damping factor for scale update
    p.responseUp = 16; % upsampling the small 17x17 response helps with the accuracy
    p.windowing = 'cosine'; % to penalize large displacements
    p.wInfluence = 0.176; % windowing influence (in convex sum)
    p.net = '2016-08-17.net.mat';
    %% execution, visualization, benchmark
    p.video = 'vot15_bag';
    p.visualization = false;
    p.gpus = 1;
    p.bbox_output = false;
    p.fout = -1;
    %% Params from the network architecture, have to be consistent with the training
    p.exemplarSize = 127;  % input z size
    p.instanceSize = 255;  % input x size (search region)
    p.scoreSize = 17;
    p.totalStride = 8;
    p.contextAmount = 0.5; % context amount for the exemplar
    p.subMean = false;
    %% SiamFC prefix and ids
    p.prefix_z = 'a_'; % used to identify the layers of the exemplar
    p.prefix_x = 'b_'; % used to identify the layers of the instance
    p.prefix_join = 'xcorr';
    p.prefix_adj = 'adjust';
    p.id_feat_z = 'a_feat';
    p.id_score = 'score';
    % Get environment-specific default paths.
    p.net_base_path = '../models/';
    p.seq_base_path = '../demo-sequences/';
    p.seq_vot_base_path = '/path/to/VOT/evaluation/sequences/'; % (optional)
    p.stats_path = '/home/ethan/dxp/ours/Siam_adapt/models/ILSVRC2015.stats.mat'; % (optional)
    % added parameters
    p.load_video_info = @load_video_info_kcf;
    % Overwrite default parameters with varargin
    p = vl_argparse(p, varargin);
% -------------------------------------------------------------------------------------------------

load_video_info_fun = p.load_video_info;
% p.video = video;
%     % Get environment-specific default paths.
%     p = env_paths_tracking(p);
    % Load ImageNet Video statistics
    if exist(p.stats_path,'file')
        stats = load(p.stats_path);
    else
        warning('No stats found at %s', p.stats_path);
        stats = [];
    end
    % Load two copies of the pre-trained network
    net_z = load_pretrained([p.net_base_path p.net], p.gpus);
    net_x = load_pretrained([p.net_base_path p.net], []);
    [imgFiles, targetPosition, targetSize, ground_truth] = load_video_info_fun(p.seq_base_path, p.video);
    nImgs = numel(imgFiles);
    startFrame = 1;
    % Divide the net in 2
    % exemplar branch (used only once per video) computes features for the target
    remove_layers_from_prefix(net_z, p.prefix_x);
    remove_layers_from_prefix(net_z, p.prefix_join);
    remove_layers_from_prefix(net_z, p.prefix_adj);
    % instance branch computes features for search region x and cross-correlates with z features
    remove_layers_from_prefix(net_x, p.prefix_z);
    zFeatId = net_z.getVarIndex(p.id_feat_z);
    scoreId = net_x.getVarIndex(p.id_score);
    % get the first frame of the video
    im = gpuArray(single(imgFiles{startFrame}));
    % if grayscale repeat one channel to match filters size
	if(size(im, 3)==1)
        im = repmat(im, [1 1 3]);
    end
    % Init visualization
    videoPlayer = [];
    if p.visualization && isToolboxAvailable('Computer Vision System Toolbox')
        videoPlayer = vision.VideoPlayer('Position', [100 100 [size(im,2), size(im,1)]+30]);
    end
    % get avg for padding
    avgChans = gather([mean(mean(im(:,:,1))) mean(mean(im(:,:,2))) mean(mean(im(:,:,3)))]);

    wc_z = targetSize(2) + p.contextAmount*sum(targetSize);
    hc_z = targetSize(1) + p.contextAmount*sum(targetSize);
    s_z = sqrt(wc_z*hc_z);
    scale_z = p.exemplarSize / s_z;
    % initialize the exemplar
    [z_crop, ~] = get_subwindow_tracking(im, targetPosition, [p.exemplarSize p.exemplarSize], [round(s_z) round(s_z)], avgChans);
    if 0
        imwrite(uint8(gather(z_crop)),'test_z.png');
    end
    if p.subMean
        z_crop = bsxfun(@minus, z_crop, reshape(stats.z.rgbMean, [1 1 3]));
    end
    d_search = (p.instanceSize - p.exemplarSize)/2;
    pad = d_search/scale_z;
    s_x = s_z + 2*pad;
    % arbitrary scale saturation
    min_s_x = 0.2*s_x;
    max_s_x = 5*s_x;

    switch p.windowing
        case 'cosine'
            window = single(hann(p.scoreSize*p.responseUp) * hann(p.scoreSize*p.responseUp)');
        case 'uniform'
            window = single(ones(p.scoreSize*p.responseUp, p.scoreSize*p.responseUp));
    end
    % make the window sum 1
    window = window / sum(window(:));
    scales = (p.scaleStep .^ ((ceil(p.numScale/2)-p.numScale) : floor(p.numScale/2)));
    % evaluate the offline-trained network for exemplar z features
    net_z.eval({'exemplar', z_crop});
    z_features = net_z.vars(zFeatId).value;
    z_features = repmat(z_features, [1 1 1 p.numScale]);

    bboxes = zeros(nImgs, 4);
    % start tracking
time = 0;
    tic;
    for i = startFrame:nImgs
        if i>startFrame
            % load new frame on GPU
            im = gpuArray(single(imgFiles{i}));
   			% if grayscale repeat one channel to match filters size
    		if(size(im, 3)==1)
        		im = repmat(im, [1 1 3]);
    		end
            scaledInstance = s_x .* scales;
            scaledTarget = [targetSize(1) .* scales; targetSize(2) .* scales];
            % extract scaled crops for search region x at previous target position
            x_crops = make_scale_pyramid(im, targetPosition, scaledInstance, p.instanceSize, avgChans, stats, p);
            if 0
                imwrite(uint8(gather(x_crops(:,:,:,2))),'test_x.png');
            end
            % evaluate the offline-trained network for exemplar x features
%             tic
            [newTargetPosition, newScale] = tracker_eval(net_x, round(s_x), scoreId, z_features, x_crops, targetPosition, window, p);
%             toc
            targetPosition = gather(newTargetPosition);
            % scale damping and saturation
            s_x = max(min_s_x, min(max_s_x, (1-p.scaleLR)*s_x + p.scaleLR*scaledInstance(newScale)));
            targetSize = (1-p.scaleLR)*targetSize + p.scaleLR*[scaledTarget(1,newScale) scaledTarget(2,newScale)];
        else
            % at the first frame output position and size passed as input (ground truth)
        end

        rectPosition = [targetPosition([2,1]) - targetSize([2,1])/2, targetSize([2,1])];
        % output bbox in the original frame coordinates
        oTargetPosition = targetPosition; % .* frameSize ./ newFrameSize;
        oTargetSize = targetSize; % .* frameSize ./ newFrameSize;
        bboxes(i, :) = [oTargetPosition([2,1]) - oTargetSize([2,1])/2, oTargetSize([2,1])];

        if p.visualization
            if isempty(videoPlayer)
                figure(1), imshow(im/255);
                figure(1), rectangle('Position', rectPosition, 'LineWidth', 4, 'EdgeColor', 'y');
                drawnow
                fprintf('Frame %d\n', startFrame+i);
            else
                im = gather(im)/255;
                im = insertShape(im, 'Rectangle', rectPosition, 'LineWidth', 4, 'Color', 'yellow');
                % Display the annotated video frame using the video player object.
                step(videoPlayer, im);
            end
        end

        if p.bbox_output
            fprintf(p.fout,'%.2f,%.2f,%.2f,%.2f\n', bboxes(i, :));
        end

    end

    time = time + toc;
    bboxes = bboxes(startFrame : i, :);
    fps = nImgs/time;
end


classdef testHorizontalLaminate < TestSequentialLaminateTestedWithNumerics

    methods (Access = public)

        function obj = testHorizontalLaminate()
            obj.compute();
        end

    end

    methods (Access = protected)

        function loadLaminateDirection(obj)
            d = [0 1 0];
            dir = Vector3D;
            dir.setValue(d);
            dir.normalize()
            obj.LaminateDirection = dir;
        end

        function loadFiberDirection(obj)
            d = [1 0 0];
            dir = Vector3D;
            dir.setValue(d);
            dir.normalize()
            obj.FiberDirection = dir;
        end

    end

end


function [scan3dd] = elec_load_scan_3ddasc(filename)

% elec_load_scan_3ddasc - read ascii export of Neuroscan 3DD file
%
% Load an ascii electrode file and return
% the electrode labels and coordinates.  This
% function can read and return Cartesian (x,y,z)
% and/or spherical (theta,phi,r) coordinates.
%
% [scan3dd] = elec_load_scan_3ddasc(filename)
%
% where:
%
% file = '<path><filename>' with row format '%s %d %f %f %f'
%
% The file format is that of NeuroScan 3Dspace ascii
% export files.  Each row of the file comprises an electrode label,
% an electrode type code (see below), and the x,y,z coordinates (cm).
% Each field is separated by spaces.  For example,
%
% Fz    69  Xcm Ycm Zcm
%
% Example result:
%
% scan3dd =
%
%      label: {1x128 cell}
%          x: [128x1 double]
%          y: [128x1 double]
%          z: [128x1 double]
%        hsp: [1617x3 double]
%     nasion: [-0.0333 9.0341 0]
%        lpa: [-6.9128 0 0]
%        rpa: [6.9128 0 0]
%     origin: [0 0 0]
%        ref: [0 9.9341 0]
%
% All coordinates are in centimeters.
%
% Notes:
%
% i) Type is defined as follows (from Neuroscan 3Dspace ascii export):
%
%           Electrode               Type
%           ---------               ----
%           Nasion                   110 (or 78)
%           Left                     108 (or 76)
%           Right                    114 (or 82)
%           electrodes                69
%           Centroid (origin)         99 (or 67; eg <0,0,0>)
%           Ref                      120 (or 88)
%           Scalp Points (hsp)        32
%
%

% $Revision: 1.1 $ $Date: 2009-04-28 22:13:55 $

% Licence:  GNU GPL, no express or implied warranties
% History:  08/1999, Darren.Weber_at_radiology.ucsf.edu
%           08/2003, Darren.Weber_at_radiology.ucsf.edu
%                    complete rewrite, replacing elec_load.m
%                    new version of 3Dspace exports different type numbers ;-)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ver = '$Revision: 1.1 $';
fprintf('\nELEC_LOAD_SCAN3DDASC [v %s]\n',ver(11:15));

tic;

[path,name,ext] = fileparts(filename);
file = fullfile(path,[name ext]);

fprintf('...loading electrodes from:\n\t%s\n', file);

scan3dd = read_3dd(file);

fprintf('...loaded %d electrodes\n', size(scan3dd.x,1));

t = toc; fprintf('...done (%6.2f sec).\n\n',t);

return

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function scan3dd = read_3dd(file),

scan3dd.label = [];
scan3dd.x = [];
scan3dd.y = [];
scan3dd.z = [];
scan3dd.hsp = [];

fid = fopen(file);
if fid < 0,
  msg = sprintf('cannot open file: %s\n',file);
  error(msg);
end

% 3DD ascii files contain position information for
% fiducial, sensor, and head shape fields.

% First get the fiducial points by reading the whole file
% (clumsy, but exhaustive search for field indicators).

% Fiducial points are required for MRI registration. They are
% the nasion, left and right preauricular points, eg:

%      Nasion	78	-0.033340	9.034104	0.000000
%      Left	76	-6.912818	-0.000000	0.000000
%      Right	82	6.912818	0.000000	-0.000000

fprintf('...searching for fiducials...');

n = 0;
while n < 5,
  tmp = fgetl(fid);
  if tmp < 0, break; end

  tmp = lower(tmp);

  if strfind(tmp,'nasion'),
    tmp = sscanf(tmp,'%s %d %f %f %f');
    scan3dd.nasion = [tmp(end-2) tmp(end-1) tmp(end)];
    n = n + 1;
    continue;
  end
  if strfind(tmp,'left'),
    tmp = sscanf(tmp,'%s %d %f %f %f');
    scan3dd.lpa = [tmp(end-2) tmp(end-1) tmp(end)];
    n = n + 1;
    continue;
  end
  if strfind(tmp,'right'),
    tmp = sscanf(tmp,'%s %d %f %f %f');
    scan3dd.rpa = [tmp(end-2) tmp(end-1) tmp(end)];
    n = n + 1;
    continue;
  end
  if strfind(tmp,'centroid'),
    tmp = sscanf(tmp,'%s %d %f %f %f');
    scan3dd.origin = [tmp(end-2) tmp(end-1) tmp(end)];
    n = n + 1;
    continue;
  end
  if strfind(tmp,'ref'),
    tmp = sscanf(tmp,'%s %d %f %f %f');
    scan3dd.ref = [tmp(end-2) tmp(end-1) tmp(end)];
    n = n + 1;
    continue;
  end
end

frewind(fid);
fprintf('done\n');

fprintf('...searching for electrodes...');

ok = 1;
while ok,
  tmp = fgetl(fid);
  if tmp < 0, break; end

  if strfind(lower(tmp),'nasion'),   continue; end
  if strfind(lower(tmp),'left'),     continue; end
  if strfind(lower(tmp),'right'),    continue; end
  if strfind(lower(tmp),'centroid'), continue; end
  if strfind(lower(tmp),'ref'),      continue; end

  tmp = sscanf(tmp,'%s %d %f %f %f');

  if tmp(end-3) == 69,
    scan3dd.label{end+1} = char(tmp(1:end-4))';
    scan3dd.x(end+1,1) = tmp(end-2);
    scan3dd.y(end+1,1) = tmp(end-1);
    scan3dd.z(end+1,1) = tmp(end);
    continue;
  end
  if strfind(char(tmp(1:end-4))','32'),
    break;
    % found a head shape point
    scan3dd.hsp(end+1,:) = [tmp(end-2),tmp(end-1),tmp(end)];
    continue;
  end
end

frewind(fid);
fprintf('done\n');

fprintf('...searching for head shape points...');

ok = 1;
while ok,
  tmp = fgetl(fid);
  if tmp < 0, break; end

  if strfind(lower(tmp),'nasion'),   continue; end
  if strfind(lower(tmp),'left'),     continue; end
  if strfind(lower(tmp),'right'),    continue; end
  if strfind(lower(tmp),'centroid'), continue; end
  if strfind(lower(tmp),'ref'),      continue; end
  if strfind(lower(tmp),'69'),       continue; end

  tmp = sscanf(tmp,'%d %f %f %f');

  if tmp(end-3) == 32,
    % found a head shape point
    scan3dd.hsp(end+1,:) = [tmp(end-2),tmp(end-1),tmp(end)];
    continue;
  end
end

frewind(fid);
fprintf('done\n');

fclose(fid);

return


function ap = context_test(dataset, cls)
% Rescore detections on the test dataset using the context
% rescoring SVMs trained by context_train.m.
%   ap = context_test(dataset, cls)
%
% Return value
%   ap          AP score for context rescoring
%
% Arguments
%   dataset     Dataset to context rescore
%   cls         Object class to rescore (if not given, all are rescored)

% AUTORIGHTS
% -------------------------------------------------------
% Copyright (C) 2011-2012 Ross Girshick
% Copyright (C) 2008, 2009, 2010 Pedro Felzenszwalb, Ross Girshick
%
% This file is part of the voc-releaseX code
% (http://people.cs.uchicago.edu/~rbg/latent/)
% and is available under the terms of an MIT-like license
% provided in COPYING. Please retain this notice and
% COPYING if you use this file (or a portion of it) in
% your project.
% -------------------------------------------------------

conf = voc_config();
cachedir = conf.paths.model_dir;
VOCopts  = conf.pascal.VOCopts;
VOCyear  = conf.pascal.year;

if nargin < 1
  dataset = conf.eval.test_set;
end

if nargin < 2
  cls = [];
end

% Get detections, filter bounding boxes, and context feature vectors
% to be rescored
[ds_all, bs_all, X] = context_data(dataset, VOCyear);

ids = textread(sprintf(VOCopts.imgsetpath, dataset), '%s');
numids = length(ids);
numcls = length(VOCopts.classes);
ap = zeros(numcls, 1);

fprintf('Rescoring detections\n');
if ~isempty(cls)
  cls_inds = strmatch(cls, VOCopts.classes, 'exact');
else
  cls_inds = 1:numcls;
end

ap = nan(numcls, 1);

for c = cls_inds
  cls = VOCopts.classes{c};
  fprintf('%d/%d %s ', c, numcls, cls);
  try
    load([cachedir cls '_boxes_' dataset '_context_' VOCyear]);
  catch
    load([cachedir cls '_context_classifier']);
    pos_ind = find(model.Label == 1);
    for i = 1:numids
      if ~isempty(X{c,i})
        [~, ~, s] = svmpredict(ones(size(X{c,i},1), 1), X{c,i}, model);
        s = model.Label(1)*s;
        ds_all{c}{i}(:,end) = s;
        bs_all{c}{i}(:,end) = s;
      end
    end
    ds = ds_all{c};
    bs = bs_all{c};
    save([cachedir cls '_boxes_' dataset '_context_' VOCyear], 'ds', 'bs');
  end
  ap(c) = pascal_eval(cls, ds, dataset, VOCyear, ['context_' VOCyear]);
  fprintf(' %.3f\n', ap(c));
end

fprintf('average = %f\n', nanmean(ap));


function test_bug2986

% MEM 3gb
% WALLTIME 00:20:00
% DEPENDENCY ft_volumerealign ft_volumereslice

load standard_mri

% convert to 'cm' to show what happens
mri = ft_convert_units(mri, 'cm');

% reslice to standard (improves solutions)
mri =  ft_volumereslice([], mri);

% load headshape
load(fullfile(dccnpath('/home/common/matlab/fieldtrip/data/test'),'bug2986.mat'));

% for quick check feed in fiducial positions
fiducial = [];
fiducial.nas = [131 215 85];
fiducial.lpa =  [41 108 84];
fiducial.rpa = [213 107 80];
fiducial.zpoint = [131 125 195];

% coarse realignment based on fiducials first
cfg          = [];
cfg.method   = 'fiducial';
cfg.fiducial = fiducial;
cfg.coordsys = 'neuromag';
mri          = ft_volumerealign(cfg,mri);

% make automatic coregistration based on headshape
% the coregistration looks fine (depending on how well you defined the
% fiducials of course) - don't change anything in the interactive menu to
% avoid that that's the problem
cfg           = [];
cfg.method    = 'headshape';
cfg.headshape.headshape = shape;
cfg.headshape.interactive    = 'no';
cfg.headshape.icp = 'yes';
cfg.coordsys  = 'neuromag';
mri_aligned   = ft_volumerealign(cfg, mri);

cfg.headshape.shape = ft_convert_units(shape, 'm');
mri_aligned2  = ft_volumerealign(cfg, mri);
mri_aligned3  = ft_volumerealign(cfg, ft_convert_units(mri, 'mm'));

%% check based on fiducial + headshape alignment
% segment the scalp to check the alignment
cfg        = [];
cfg.output = 'scalp';
cfg.smooth = 2;
seg_align  = ft_volumesegment(cfg, mri_aligned);
seg_align2  = ft_volumesegment(cfg, mri_aligned2);
seg_align3  = ft_volumesegment(cfg, mri_aligned3);

% build headmodel
cfg             = [];
cfg.method      = 'singleshell';
cfg.numvertices = 2000;
hdm    = ft_prepare_headmodel(cfg, seg_align);
hdm2   = ft_prepare_headmodel(cfg, seg_align2);
hdm3   = ft_prepare_headmodel(cfg, seg_align3);

% now plot
figure; hold on
ft_plot_headmodel(ft_convert_units(hdm, 'cm'),'edgecolor','none','facecolor','w');
ft_plot_headshape(shape);

figure; hold on
ft_plot_headmodel(ft_convert_units(hdm2, 'cm'),'edgecolor','none','facecolor','w');
ft_plot_headshape(shape);

figure; hold on
ft_plot_headmodel(ft_convert_units(hdm3, 'cm'),'edgecolor','none','facecolor','w');
ft_plot_headshape(shape);