function [F,pm] = spm_vb_roi_basis (VOI_fnames,SPM,bases,model)
% Compare Hemodynamic Basis sets for a cluster of interest
% FORMAT [F,pm] = spm_vb_roi_basis (VOI_fnames,SPM,bases,model)
%
% VOI_fname     VOI filenames eg. VOI_fnames{1}='Test_VOI.mat'
%
% SPM           SPM data structure (this must be loaded in from an 
%               SPM.mat file). If this field is not specified this function
%               will prompt you for the name of an SPM.mat file
%
% bases         Specifies which basis sets to compare:
%
%               'all'   - the 7 default types (see help spm_get_bf)
%               'fir'   - Finite Impulse Response with variable number of bins
%               'fh'    - Fourier + Hanning window with variable number of bins
%               'user'  - user specified models set by model variable 
%                         (see below). This allows a user-specified set of
%                         models to be compared.
%
%               The default option is 'all'
%
% model         For ith basis set specify
%
%               model(i).name - see help spm_get_bf
%               model(i).sname - short name to be used in results histogram 
%               model(i).order - number of basis functions/number of bins
%               model(i).length - overall window length in seconds
%
%               for i=1..number of models
%
%               This variable only needs to be specified if the bases option
%               is set to 'user'.
%
%               Typical function usages: 
%
%               [F,pm]=spm_vb_roi_basis('Test_VOI.mat');
%               [F,pm]=spm_vb_roi_basis('Test_VOI.mat',SPM);
%               [F,pm]=spm_vb_roi_basis('Test_VOI.mat',SPM,'fir');
%               [F,pm]=spm_vb_roi_basis('Test_VOI.mat',SPM,'user',model);
%
% F             model evidences 
% pm            posterior model probability
%
% See W. Penny et al. (2007). Bayesian Model Comparison of Spatially 
% Regularised General Linear Models. Human Brain Mapping.
%__________________________________________________________________________

% Will Penny 
% Copyright (C) 2005-2022 Wellcome Centre for Human Neuroimaging


%-Check input parameters
%--------------------------------------------------------------------------
if ~nargin
    [VOI_fnames, sts] = spm_select([1 Inf],'^VOI.*\.mat$','select VOIs');
    if ~sts, F = []; pm = []; return; end
end
VOI_fnames = cellstr(VOI_fnames);
if nargin < 2
    [Pf, sts] = spm_select(1,'^SPM\.mat$','Select SPM.mat');
    if ~sts, return; end
    swd = spm_file(Pf,'fpath');
    load(fullfile(swd,'SPM.mat'))
end
if nargin < 3, bases = 'all'; end

%-Check parameters
%--------------------------------------------------------------------------
if strcmpi(bases,'user') && nargin ~= 4
    error('Models not specified.');
end

nsess = length(SPM.Sess);
nVOIs = length(VOI_fnames);
if nsess~=nVOIs
    error('SPM design specified for %d sessions and %d VOI files specified.',nsess,nVOIs);
end

%-Load VOIs
%--------------------------------------------------------------------------
for p=1:nVOIs
    load(VOI_fnames{p});
    data_sess(p).Y=xY.y;
end
xyz  = xY.XYZmm;
N    = size(xyz,2);
xyz  = SPM.xVol.M\[xyz;ones(1,size(xyz,2))];
xyz  = xyz(1:3,:);
vxyz = spm_vb_neighbors(xyz',1);

% Set number of AR coefficients
%--------------------------------------------------------------------------
try 
    SPM.PPM.AR_P;
catch
    SPM.PPM.AR_P = 3;
end

% Specify type of prior for regression coefficients
%--------------------------------------------------------------------------
try
    SPM.PPM.priors.W;
catch
    if N==1
        SPM.PPM.priors.W = 'Voxel - Shrinkage';
    else
        SPM.PPM.priors.W = 'Spatial - GMRF';
    end
end

% Specify type of prior for AR coefficients
%--------------------------------------------------------------------------
try
    SPM.PPM.priors.A;
catch
    if N==1
        SPM.PPM.priors.A = 'Voxel - Shrinkage';
    else
        SPM.PPM.priors.A = 'Spatial - GMRF';
    end
end

% Get matrices that will remove low-frequency drifts 
% if high pass filters have been specified
%--------------------------------------------------------------------------
for s=1:nsess
    sess_nScan = length(SPM.xX.K(s).row);
    if size(SPM.xX.K(s).X0,2) > 0
        X0 = SPM.xX.K(s).X0;
        hpf(s).R0 = eye(sess_nScan)-X0*pinv(X0);
    else
        hpf(s).R0 = eye(sess_nScan);
    end    
end

% Set optimisation parameters
%--------------------------------------------------------------------------
try
    SPM.PPM.maxits;
catch
    SPM.PPM.maxits = 16;
end
try
    SPM.PPM.tol;
catch
    SPM.PPM.tol = 0.00001;
end

% Specify basis functions
%--------------------------------------------------------------------------
window_length = 32; % length in seconds

switch bases
    case 'fir'
        window_length = 20; % length in seconds
        bins = [1:1:10];
        for i=1:length(bins)
            model(i).name   = 'Finite Impulse Response';
            model(i).sname  = int2str(bins(i));
            model(i).order  = bins(i); 
            model(i).length = window_length; 
        end
    case 'fh'
        window_length = 20; % length in seconds
        bins = [1:1:10];
        for i=1:length(bins)
            model(i).name   = 'Fourier set (Hanning)';
            model(i).sname  = int2str(bins(i));
            model(i).order  = bins(i); 
            model(i).length = window_length; 
        end
    case 'all'
        model(1).name   = 'hrf';
        model(1).sname  = 'Inf-1';
        model(1).order  = 1;
        model(1).length = window_length; 
        
        model(2).name   = 'hrf (with time derivative)';
        model(2).sname  = 'Inf-2';
        model(2).order  = 2;
        model(2).length = window_length;
        
        model(3).name   = 'hrf (with time and dispersion derivatives)';
        model(3).sname  = 'Inf-3';
        model(3).order  = 3;  
        model(3).length = window_length;                
        
        model(4).name   = 'Fourier set';
        model(4).sname  = 'F';
        model(4).order  = 5;
        model(4).length = window_length;
        
        model(5).name   = 'Fourier set (Hanning)';
        model(5).sname  = 'FH';
        model(5).order  = 5;
        model(5).length = window_length;
        
        model(6).name   = 'Gamma functions';
        model(6).sname  = 'Gamm3';
        model(6).order  = 3;  
        model(6).length = window_length;                
        
        model(7).name   = 'Finite Impulse Response';
        model(7).sname  = 'FIR';
        model(7).order  = 10; 
        model(7).length = window_length;        
    case 'user'
        disp('Using user-specified models.');
    otherwise
        error('Unknown bases option.');
end

% Fit models
%==========================================================================
for m=1:length(model)
    fprintf('Model %d (%s)\n',m,model(m).name);                             %-#
    
    % Switch basis functions
    %----------------------------------------------------------------------
    SPM.xBF.name   = model(m).name;
    SPM.xBF.order  = model(m).order;
    SPM.xBF.length = model(m).length;
    SPM.xBF        = spm_get_bf(SPM.xBF);
    
    SPM = spm_fmri_design(SPM,0);  % 0 to override writing of SPM.mat file
    
    Ev = 0;
    % Loop over sessions
    %======================================================================
    for s=1:nsess
        fprintf('Session %d\n',s);                                      %-#
        
        % Design matrix
        %------------------------------------------------------------------
        X = SPM.xX.X(SPM.Sess(s).row,SPM.Sess(s).col);
        X = [X ones(length(SPM.Sess(s).row),1)]; % Add one constant 
        
        slice = spm_vb_init_volume (X,SPM.PPM.AR_P);
        slice = spm_vb_set_priors(slice,SPM.PPM.priors,vxyz);
        
        slice.maxits        = SPM.PPM.maxits;
        slice.tol           = SPM.PPM.tol;
        slice.compute_det_D = 1;
        slice.verbose       = 1;
        slice.update_w      = 1;
        slice.update_lambda = 1;
        slice.update_F      = 1;
    
        % Filter data to remove low frequencies
        %------------------------------------------------------------------
        R0Y = hpf(s).R0 * data_sess(s).Y;
        
        % Variational Bayes for GLM-AR modelling
        %------------------------------------------------------------------
        slice = spm_vb_glmar(R0Y,slice);
        
        % Add up evidence from different sessions
        %------------------------------------------------------------------
        Ev = Ev + slice.F;
    end
    
    F(m) = Ev;
end

% Display results
%==========================================================================
Fm    = F - mean(F);
Fnorm = F - min(F);
pm    = exp(Fm)./sum(exp(Fm));
if any(isnan(pm))
    [pF,pi] = max(F);
    pm      = zeros(size(pi));
    pm(pi)  = 1;
end

figure;
bar(pm);
set(gca,'XTickLabel',{model.sname});
ylabel('Posterior model probability');
set(gca,'FontSize',12);

figure;
bar(Fnorm);
set(gca,'XTickLabel',{model.sname});
ylabel('Log Evidence');
set(gca,'FontSize',12);
