function selective_average_interactive_view_init(imgs, onsets, scans_per_sess, TR, hp_length, t, basepts, plotstes)
% :Usage:
% ::
%
%    selective_average_interactive_view_init(imgs, onsets, 20, 1:2, 1);
%
% Initialize point-and-click data extraction and plotting of selective
% averages
%
% :Inputs:
%
%   **imgs:**
%        cell array of image files, one cell per subject
%
%        imgs is cell array of time series image names for each subject
%
%   **onsets:**
%        cell array of onsets
%
%        Each cell contains its own cell array, with one cell per
%        condition.
%
%   **t:**
%        time points in average to estimate
%
%   **basepts:**
%        indices of baseline points to subtract from individual averages
%
%   **plotstes:**
%        plot standard errors: 1 or 0

    disp('Initializing Selective Average interactive viewer') % need to do the stuff below only once

    disp('-------------------------------------------------')

    %     disp('Loading mediation_SETUP.mat')
    %     [SETUP, imgs, wh_is_image, name] = load_mediation_setup;

    N = length(imgs);

    % Setting up filtering
    % ------------------------------------------------------
    fprintf('Setting up high-pass filtering (dummy params for first 2 time points per run): ');
    % %     I = cell(1, N);
    % %     S = cell(1, N);
    tic

    for i = 1:N
        [tmp, I, S] = hpfilter(rand(sum(scans_per_sess), 1), TR, hp_length, scans_per_sess, [], 1:2);
    end

    fprintf(' %3.0f s\n', toc)

    % ------------------------------------------------------
    V = cell(1, N);
    fprintf('Mapping image volumes to memory: ');
    tic
    for i = 1:N
        fprintf('%3.0f ', i);
        V{i} = spm_vol(imgs{i});
    end

    fprintf(' %3.0f s\n', toc)

    % ------------------------------------------------------

    disp('Registering graphics callback with SPM registry')

    callback_handle = @(str, pos, reg, hReg) selavg_interactive_callback_wrapper(str, pos, reg, hReg);

    hSpmFig = spm_figure('GetWin', 'Graphics');

    hReg = uicontrol(hSpmFig, 'Style', 'Text', 'String', 'InteractiveViewer hReg', ...
        'Position', [100 200 100 025], 'Visible', 'Off', ...
        'FontName', 'Times', 'FontSize', 14, 'FontWeight', 'Bold', ...
        'HorizontalAlignment', 'Center');

    hReg = spm_XYZreg('InitReg', hReg, V{1}(1).mat, V{1}(1).dim(1:3)');
    spm_XYZreg('Add2Reg', hReg, 0, callback_handle);
    spm_orthviews('Register', hReg);

    %fh = findobj('Tag', 'Graphics');
    %set(fh, 'WindowButtonUpFcn', callback_handle);

    disp('Ready!')

    % inline

    function selavg_interactive_callback_wrapper(str, pos, reg, hReg)

        switch str
            case 'SetCoords'
                selavg_interactive_callback(pos, onsets, V, t, basepts, plotstes, S, scans_per_sess, I);

            otherwise
                disp('Unknown callback command from spm_XYZreg');
        end

    end

end

function selavg_interactive_callback(pos, onsets, V, t, basepts, plotstes, S, scans_per_sess, I)
    %% Done each time you click

    % %     %pos = spm_orthviews('Pos');
    % %     vox = (mm2voxel(pos', V{1}(1)))';
    % %     vox(4) = 1;
    % %
    % %     fprintf('Position: %3.0f %3.0f %3.0f\n', pos(1), pos(2), pos(3));
    % %     go = input('Plot selective averages for this voxel? (1 or 0) : ');

    % %     if go
    % % %         % Load data for this voxel
    % % %         % -----------------------------------------------------
    % % %         N = length(V);
    % % %
    % % %         fprintf('Loading voxel data for all subjects: ');
    % % %         for i = 1:N, fprintf('%3.0f ', i); braindata{i} = spm_get_data(V{i}, vox); end

    % Load data and get selective averages for each subject
    % -----------------------------------------------------
    [group_avgs, group_stes, subject_avgs, subject_stes, braindata] = selective_average_group( ...
        V, onsets, pos, 't', t, 'basepts', basepts, 'plotstes', plotstes, 'S', S, 'scans', scans_per_sess, 'I', I);

    if ~isempty(group_avgs)

        disp('-------------------------------------------------------');
        disp('Assigning group_avgs and stes in base workspace.');
        disp('(and subject_avgs and subject_stes)');
        disp('Assigning braindata to base workspace: Timeseries for each subject');
        disp('-------------------------------------------------------');
        disp(' ')

        assignin('base', 'group_avgs', group_avgs);
        assignin('base', 'group_stes', group_stes);
        assignin('base', 'subject_avgs', subject_avgs);
        assignin('base', 'subject_stes', subject_stes);
        assignin('base', 'braindata', braindata);

    end
    % %     end
end

function [SETUP, imgs, wh_is_image, name] = load_mediation_setup

    SETUP = [];
    imgs = [];

    fname = [pwd filesep 'mediation_SETUP.mat'];
    if exist(fname,'file')
        load(fname);

        % try to find names (single level)
        if exist('SETUP','var') && isfield(SETUP, 'M') && ischar(SETUP.M)
            imgs = SETUP.M;
            name = 'From mediation_SETUP SETUP.M';
            wh_is_image = 'M';

        elseif exist('SETUP','var') && isfield(SETUP, 'X') && ischar(SETUP.X)
            imgs = SETUP.X;
            name = 'From mediation_SETUP SETUP.X';
            wh_is_image = 'X';

        elseif exist('SETUP','var') && isfield(SETUP, 'Y') && ischar(SETUP.Y)
            imgs = SETUP.Y;
            name = 'From mediation_SETUP SETUP.Y';
            wh_is_image = 'Y';

        end

        % try to find names: multi-level
        if isfield(SETUP, 'data')
            switch SETUP.cmdstring
                case 'Search for mediators'
                    imgs = SETUP.data.M;
                    name = 'Multilevel, from SETUP.data.M';
                    wh_is_image = 'M';

                case 'Search for indirect influences'
                    imgs = SETUP.data.X;
                    name = 'Multilevel, from SETUP.data.X';
                    wh_is_image = 'X';

                case 'Search for mediated outcomes'
                    imgs = SETUP.data.Y;
                    name = 'Multilevel, from SETUP.data.Y';
                    wh_is_image = 'Y';

                otherwise
                    error('Unknown cmdstring: "%s".', cmdstring);
            end

            if ~iscell(imgs) || ~ischar(imgs{1})
                imgs = []; % invalid data here
            end

        end

        if isempty(imgs)
            fprintf(1,'Could not find image list.\n');
        end

    else
        fprintf(1,'Go to valid mediation directory with SETUP.mat to use interactive plotting.\n');
    end

end


function [Dtest,modelF,allF]=spm_eeg_invertiter(Dtest,Npatchiter,funcname,patchind)

%  Function to perform several MSP type inversions with different
%  pseudo-randomly selected priors- in this case single cortical patches
%
% Npatchiter: number of iterations
% funcname is name of MSP alogorithm: current (spm_eeg_invert) or classic (spm_eeg_invert_classic)
% patchind is an optional list of indices of vertices which will be patch
% centres. patchind will have size Npatchiter*Np (where Np is number of patches set in
% inverse.Np )
% if  Dtest{1}.inv{val}.inverse.mergeflag==1 then merges Npatchiter posterior current
% distributions, else replaces posterior with best of the iterations.
% __________________________________________________________________________
% Copyright (C) 2010 Wellcome Trust Centre for Neuroimaging
%
% Gareth Barnes
% $Id: spm_eeg_invertiter.m 6367 2015-03-09 15:02:25Z gareth $

if nargin<2,
    Npatchiter=[];
end;

if nargin<3,
    error('No function call specified');
end;

if nargin<4,
    patchind=[];
end;
if isempty(Npatchiter),
    Npatchiter=16;
end;

if numel(Dtest)>1,
    error('only works with single datasets at the moment');
end;

val=Dtest{1}.val;

Nvert=size(Dtest{1}.inv{val}.mesh.tess_mni.vert,1);
Np=Dtest{1}.inv{val}.inverse.Np;

allF=zeros(Npatchiter,1);

fprintf('Checking leadfields');

[L Dtest{1}] = spm_eeg_lgainmat(Dtest{1});  % Generate/load lead field- this stops it being done at each iteration

if isempty(patchind),
    disp('Reseting random number seed ! and then generating random patch centres ');
    rand('state',0);

    %% make random patch centers, except on the first iteration when we keep to a fixed stepsize
    for f=1:Npatchiter,
        tmp=randperm(Nvert);
        allIp(f).Ip=tmp(1:Np);
    end;
    allIp(1).Ip=[]; %% fix the step size of the first patch set (uses default MSP indices)
else
    for f=1:Npatchiter,
        allIp(f).Ip=patchind(f,:);
    end;
end;

modelF=[];
bestF=-Inf;
for patchiter=1:Npatchiter,
    %Din=Dtest{1};
    %Dout=Din;
    Ip=allIp(patchiter).Ip;
    disp(sprintf('patchiter %d/%d',patchiter,Npatchiter));
    switch funcname,
        case 'Classic',
            Dtest{1}.inv{val}.inverse.Ip=Ip;
            Dtest{1}    = spm_eeg_invert_classic(Dtest{1});
        case 'Current',
            warning('Patch centres are currently fixed for this algorithm (iteration will have no effect!)');
            Dtest{1}   = spm_eeg_invert(Dtest{1}); %
            %Dout.inv{val}.inverse.Ip=Ip;
        otherwise
            error('unknown function');
    end;
    if (Dtest{1}.inv{val}.inverse.mergeflag==1), %% will need all posteriors to merge them (could consider getting rid of worst ones here to save memory
        modelF(patchiter).inverse=Dtest{1}.inv{val}.inverse;
    else %% just keep track of best inversion
        if Dtest{1}.inv{val}.inverse.F>bestF,
            modelF(1).inverse=Dtest{1}.inv{val}.inverse;
            bestF=Dtest{1}.inv{val}.inverse.F;
        end;
    end;
    allF(patchiter)=Dtest{1}.inv{val}.inverse.F;
end; % for patchiter

%% will use these to merge posteriors or take best one

[bestF,bestind]=max(allF);
disp('model evidences relative to maximum:')

sort(allF-bestF)

%% for 1 iteration or for best solution
Dtest{1}.inv{val}.inverse=modelF(1).inverse; %% return best model (only 1 model saved in this option)
Dtest{1}.inv{val}.inverse.allF=allF;

if Npatchiter>1, %% keep iterations if more than 1

    if (Dtest{1}.inv{val}.inverse.mergeflag==1)
        Dtest{1}.inv{val}.inverse=modelF(bestind).inverse; % start with best model so far
        Qpriors=sparse(zeros(Npatchiter,size(modelF(1).inverse.qC,1)));
        for patchiter=1:Npatchiter,
            Qpriors(patchiter,:)=modelF(patchiter).inverse.qC;
        end;
        disp('Merging posterior distributions..');
        ugainfiles=Dtest{1}.inv{val}.gainmat;
        surfind=ones(Npatchiter,1);
        %% now mix the posteriors
        [Dtest{1}] = spm_eeg_invert_classic_mix(Dtest{1},val,Qpriors,surfind,ugainfiles);

        Dtest{1}.inv{val}.comment{1}=sprintf('Merged posterior of %d solutions',Npatchiter);
        mixF=Dtest{1}.inv{val}.inverse.F;
        if mixF-bestF<0
            warning('Merged solution is worse than the best');
        end;
        disp(sprintf('Improvement (when +ve) over best iteration %3.2f',mixF-bestF));

    else % NO merge - just take the best

        disp('Using best patch set to current estimate');
        Dtest{1}.inv{val}.comment{1}=sprintf('Best F of %d solutions',Npatchiter);
    end; % if BMA

end;

spm_eeg_invert_display(Dtest{1});


function out = spm_run_fmri_est(job)
% Estimate parameters of a specified model
% SPM job execution function
% takes a harvested job data structure and call SPM functions to perform
% computations on the data.
% Input:
% job    - harvested job data structure (see matlabbatch help)
% Output:
% out    - computation results, usually a struct variable.
%__________________________________________________________________________
% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging

% $Id: spm_run_fmri_est.m 7354 2018-06-22 10:44:22Z guillaume $

%-Load SPM.mat file
%--------------------------------------------------------------------------
load(job.spmmat{1},'SPM');
if ~exist('SPM','var')
    error('The MAT-file does not contain an SPM variable.');
end
out.spmmat = job.spmmat;

%-Move to the directory where the SPM.mat file is
%--------------------------------------------------------------------------
original_dir = pwd;
cd(fileparts(job.spmmat{:}));

%==========================================================================
%                       R E M L   E S T I M A T I O N
%==========================================================================
if isfield(job.method,'Classical')

    %-ReML estimation of the model
    %----------------------------------------------------------------------
    SPM = spm_spm(SPM);

    %-Automatically set up contrasts for factorial designs
    %----------------------------------------------------------------------
    if isfield(SPM,'factor') && ~isempty(SPM.factor) && SPM.factor(1).levels > 1

        Ic = [];

        %-Generate contrasts
        %------------------------------------------------------------------
        cons = spm_design_contrasts(SPM);

        %-Create F-contrasts
        %------------------------------------------------------------------
        for i=1:length(cons)
            con       = cons(i).c;
            name      = cons(i).name;
            STAT      = 'F';
            [c,I]     = spm_conman('ParseCon',con,SPM.xX.xKXs,STAT);
            if all(I)
                DxCon = spm_FcUtil('Set',name,STAT,'c',c,SPM.xX.xKXs);
                if isempty(SPM.xCon)
                    SPM.xCon = DxCon;
                else
                    SPM.xCon(end+1) = DxCon;
                end
                Ic = [Ic length(SPM.xCon)];
            end
        end

        %-Create t-contrasts
        %------------------------------------------------------------------
        for i=1:length(cons)
            % Create a t-contrast for each row of each F-contrast
            % The resulting contrast image can be used in a 2nd-level analysis
            Fcon          = cons(i).c;
            STAT          = 'T';
            for r=1:size(Fcon,1)
                con       = Fcon(r,:);
                str       = cons(i).name;
                if strncmp('Interaction',str,11)
                    name  = ['Positive ',str,'_',int2str(r)];
                else
                    sp1   = find(isspace(str), 1);
                    name  = ['Positive',str(sp1:end),'_',int2str(r)];
                end

                [c,I]     = spm_conman('ParseCon',con,SPM.xX.xKXs,STAT);
                if all(I)
                    DxCon = spm_FcUtil('Set',name,STAT,'c',c,SPM.xX.xKXs);
                    if isempty(SPM.xCon)
                        SPM.xCon = DxCon;
                    else
                        SPM.xCon(end+1) = DxCon;
                    end
                    Ic = [Ic length(SPM.xCon)];
                end
            end
        end

        %-Estimate constrasts
        %------------------------------------------------------------------
        if ~isempty(Ic)
            spm('FnBanner','spm_contrasts.m');
            SPM = spm_contrasts(SPM,Ic);
        end

    end

    %-Residuals
    %----------------------------------------------------------------------
    if job.write_residuals
        VRes = spm_write_residuals(SPM,NaN);
    end

    %-Computation results
    %----------------------------------------------------------------------
    %out.spmvar = SPM;
    out.beta  = spm_file({SPM.Vbeta(:).fname}','path',SPM.swd);
    out.mask  = {fullfile(SPM.swd,SPM.VM.fname)};
    out.resms = {fullfile(SPM.swd,SPM.VResMS.fname)};
    if job.write_residuals
        out.res = spm_file({VRes(:).fname}','path',SPM.swd);
    end
    cd(original_dir);
    fprintf('Done\n');
    return
end

if job.write_residuals
    warning('Save residuals option is only implemented for classical inference.');
    job.write_residuals = false;
end

%==========================================================================
%        B A Y E S I A N   2nd   L E V E L   E S T I M A T I O N
%==========================================================================
if isfield(job.method,'Bayesian2')

    SPM = spm_spm_Bayes(SPM);

    %out.spmvar = SPM;
    cd(original_dir);
    fprintf('Done\n');
    return
end

%==========================================================================
%        B A Y E S I A N   1st   L E V E L   E S T I M A T I O N
%==========================================================================

%-Analyse specific slices or whole volume
%--------------------------------------------------------------------------
switch char(fieldnames(job.method.Bayesian.space))
  case 'volume'
      SPM.PPM.space_type  = 'volume';
      SPM.PPM.block_type  = lower(job.method.Bayesian.space.volume.block_type);
  case 'slices'
      SPM.PPM.space_type  = 'slices';
      SPM.PPM.AN_slices   = job.method.Bayesian.space.slices.numbers;
      SPM.PPM.block_type  = lower(job.method.Bayesian.space.slices.block_type);
  case 'clusters'
      SPM.PPM.space_type  = 'clusters';
      SPM.PPM.clustermask = job.method.Bayesian.space.clusters.mask;
      SPM.PPM.block_type  = lower(job.method.Bayesian.space.clusters.block_type);
  otherwise
      SPM.PPM.space_type  = 'volume';
      SPM.PPM.block_type  = 'slices';
end

%-Regression coefficient priors
%--------------------------------------------------------------------------
switch job.method.Bayesian.signal
    case 'UGL'
        SPM.PPM.priors.W  = 'Spatial - UGL';
    case 'GMRF'
        SPM.PPM.priors.W  = 'Spatial - GMRF';
    case 'LORETA'
        SPM.PPM.priors.W  = 'Spatial - LORETA';
    case 'WGL'
        SPM.PPM.priors.W  = 'Spatial - WGL';
    case 'Global'
        SPM.PPM.priors.W  = 'Voxel - Shrinkage';
    case 'Uninformative'
        SPM.PPM.priors.W  = 'Voxel - Uninformative';
    otherwise
        error('Unknown prior for W in Bayesian 1st level estimation.');
end

%-Number of AR coefficients
%--------------------------------------------------------------------------
SPM.PPM.AR_P              = job.method.Bayesian.ARP;

%-AR coefficient priors
%--------------------------------------------------------------------------
if isfield(job.method.Bayesian.noise,'UGL')
    SPM.PPM.priors.A      = 'Spatial - UGL';
elseif isfield(job.method.Bayesian.noise,'GMRF')
    SPM.PPM.priors.A      = 'Spatial - GMRF';
elseif isfield(job.method.Bayesian.noise,'LORETA')
    SPM.PPM.priors.A      = 'Spatial - LORETA';
elseif isfield(job.method.Bayesian.noise,'tissue_type')
    SPM.PPM.priors.A      = 'Discrete';
    SPM.PPM.priors.SY     = char(job.method.Bayesian.noise.tissue_type);
elseif isfield(job.method.Bayesian.noise,'Robust')
    SPM.PPM.priors.A      = 'Robust';
    SPM.PPM.AR_P          = 0;
    SPM.PPM.update_F      = 1;
end

%-Define an empty contrast
%--------------------------------------------------------------------------
NullCon      = spm_FcUtil('Set','','P','c',[],1);
NullCon.X0   = [];
NullCon.iX0  = [];
NullCon.X1o  = [];
NullCon.eidf = 1;

SPM.xCon     = [];
%-Set up contrasts for 2nd-level ANOVA
%--------------------------------------------------------------------------
if strcmp(job.method.Bayesian.anova.second,'Yes') && isfield(SPM,'factor')
    cons = spm_design_contrasts(SPM);
    for i=1:length(cons)
        % Create a simple contrast for each row of each F-contrast
        % The resulting contrast image can be used in a 2nd-level analysis
        Fcon = cons(i).c;
        for r=1:size(Fcon,1)
            % Normalise contrast st. sum of positive elements is 1
            % and sum of negative elements is 1
            con = Fcon(r,:);
            con = con / length(find(con==1));

            % Change name
            str = cons(i).name;
            sp1 = find(str==' ', 1);
            if strcmp(str(1:11),'Interaction')
                name = ['Positive ',str,'_',int2str(r)];
            else
                name = ['Positive',str(sp1:end),'_',int2str(r)];
            end

            DxCon = NullCon;
            DxCon.name = name;
            DxCon.c = con';

            if isempty(SPM.xCon)
                SPM.xCon = DxCon;
            else
                SPM.xCon(end+1) = DxCon;
            end
        end
    end
end

%-Set up user-specified simple contrasts
%--------------------------------------------------------------------------
K               = size(SPM.xX.X,2);
for c = 1:length(job.method.Bayesian.gcon)
    DxCon       = NullCon;
    DxCon.name  = job.method.Bayesian.gcon(c).name;
    convec      = job.method.Bayesian.gcon(c).convec(:);
    if length(convec) == K
        DxCon.c = convec;
    elseif length(convec) < K
        fprintf('Zero padding.');                                       %-#
        DxCon.c = [convec; zeros(K-length(convec),1)];
    else
        warning(['User-specified contrast nb %d has %d entries '...
            'but there are %d regressors - ignored.'], c,length(convec),K);
        DxCon   = [];
    end

    if isempty(SPM.xCon)
        SPM.xCon = DxCon;
    else
        SPM.xCon(end+1) = DxCon;
    end
end

%-Compute log evidence maps
%--------------------------------------------------------------------------
if strcmp(job.method.Bayesian.LogEv,'Yes')
    SPM.PPM.update_F      = 1;
    SPM.PPM.compute_det_D = 1;
end

%-1st level Bayesian ANOVA ?
%--------------------------------------------------------------------------
bayes_anova = 0;
if strcmp(job.method.Bayesian.anova.first,'Yes')
    bayes_anova           = 1;
    SPM.PPM.update_F      = 1; % Compute evidence for each model
    SPM.PPM.compute_det_D = 1;
end

%-Variational Bayes estimation
%--------------------------------------------------------------------------
SPM = spm_spm_vb(SPM);

%-Bayesian ANOVA using model comparison
%--------------------------------------------------------------------------
if bayes_anova
    % We don't want to estimate contrasts for each different model
    SPM.xCon = [];
    spm_vb_ppm_anova(SPM);
end

%out.spmvar = SPM;
cd(original_dir);
fprintf('Done\n')


function [model, grChek] = vargplvmOptimise(model, display, iters, varargin)

% VARGPLVMOPTIMISE Optimise the VARGPLVM.
% FORMAT
% DESC takes a given GP-LVM model structure and optimises with
% respect to parameters and latent positions.
% ARG model : the model to be optimised.
% ARG display : flag dictating whether or not to display
% optimisation progress (set to greater than zero) (default value 1).
% ARG iters : number of iterations to run the optimiser
% for (default value 2000).
% RETURN model : the optimised model.
%
% SEEALSO : vargplvmCreate, vargplvmLogLikelihood,
% vargplvmLogLikeGradients, vargplvmObjective, vargplvmGradient
%
% COPYRIGHT : Michalis K. Titsias, 2009
%
% COPYRIGHT : Neil D. Lawrence, 2005, 2006

% VARGPLVM

if nargin < 3
    iters = 2000;
    if nargin < 2
        display = 1;
    end
end

options = optOptions;
params = modelExtractParam(model);
if length(varargin) == 2
    if strcmp(varargin{1}, 'gradcheck')
        assert(islogical(varargin{2}));
        %options(9) = varargin{2};
        doGradchek = varargin{2};
        if doGradchek
            [gradient, delta] = feval('gradchek', params, @vargplvmObjective, @vargplvmGradient, model);
            deltaf = gradient - delta;
            d=norm(deltaf - gradient)/norm(gradient + deltaf);
            d1=norm(deltaf - gradient,1)/norm(gradient + deltaf,1);
            grRatio = sum(abs(gradient ./ deltaf)) / length(deltaf);
            fprintf(1,' Norm1 difference: %d\n Norm2 difference: %d\n Ratio: %d\n',d1,d, grRatio);
            grChek = {delta, gradient, deltaf, d, d1};
        else
            grChek = [];
        end
    end
end

options(2) = 0.1*options(2);
options(3) = 0.1*options(3);

if display
    options(1) = 1;
 %   if length(params) <= 100
 %       options(9) = 1;
 %   end
end
options(14) = iters;

if iters > 0
    if isfield(model, 'optimiser') && ~isa(model.optimiser, 'function_handle')
        if isfield(model, 'optimiser')
            optim = str2func(model.optimiser);
        else
            optim = str2func('scg');
        end

        if strcmp(func2str(optim), 'optimiMinimize')
            % Carl Rasmussen's minimize function
            params = optim('vargplvmObjectiveGradient', params, options, model);
        elseif strcmp(func2str(optim), 'scg2')
            % NETLAB style optimization with a slight modification so that an
            % objectiveGradient can be used where applicable, in order to re-use
            % precomputed quantities.
            params = optim('vargplvmObjectiveGradient', params,  options,  'vargplvmGradient', model);
        else
            % NETLAB style optimization.
            params = optim('vargplvmObjective', params,  options,  'vargplvmGradient', model);
        end
    elseif isfield(model, 'optimiser') && isa(model.optimiser, 'function_handle')
        f = fcnchk(model.optimiser);
        params = f(model);
    else
        error('vargplvmOptimise: Invalid optimiser setting.');
    end
    %model = vargplvmExpandParam(model, params);
    model = modelExpandParam(model, params);

    % Check if SNR of the optimised model is reasonable (ortherwise a
    % bad local minimum might have been found)
    if isfield(model, 'throwSNRError')
        svargplvmCheckSNR({vargplvmShowSNR(model)}, [], [], model.throwSNRError);
    else
        svargplvmCheckSNR({vargplvmShowSNR(model)});
    end
end


function make_noise_model
%% Input params about your paths and data
%start by building a rez structure -- will be used to call the whitening
%and filtering functions in KS2

%these need to match the current location of KS2 and npy

addpath(genpath('D:\KS2\Kilosort2-master')) % path to kilosort folder
addpath('D:\KS2\npy-matlab-master\')

% params normally read in from a config file. These need to match the model
% data set from which the noise will be extracted.

% sample rate
ops.fs = 30000;
ops.bitPerUV = 0.42667;

% chanMap for your input data set. Make sure it includes reference channels
% where they occur in the data
ops.chanMap = 'D:\SC026_080819_g0_Imec2\SC026_noise_model\neuropixPhase3B1_kilosortChanMap.mat';
[~,chanMapName,~] = fileparts(ops.chanMap);

%path to your data file; results will also be written to this folder
rootZ = 'D:\SC026_080819_g0_Imec2\SC026_noise_model\';
%name of the binary file
dataName = 'SC026_080819_g0_tcat.imec2.ap.bin';

%directory for temporary whitened data filt
rootH = 'D:\KS2\kilosort_datatemp\';
ops.trange = [0 inf]; % time range to use when extracting the whitening matrix
ops.NchanTOT    = 385; % total number of channels in your recording, including digital
%Time to sample in sec, need to sample at least enough to freq down to the high pass limit
clipDur = 0.25;
%%

% frequency for high pass filtering (150)
ops.fshigh = 150;

%processing params usually read in from config. These should not be changed
ops.GPU                 = 1; % has to be 1, no CPU version yet, sorry
ops.useRAM              = 0;
ops.ntbuff              = 64;    % samples of symmetrical buffer for whitening and spike detection
ops.NT                  = 64*1024+ ops.ntbuff; % must be multiple of 32 + ntbuff. This is the batch size (try decreasing if out of memory).
ops.whiteningRange      = 32; % number of channels to use for whitening each channel
ops.nSkipCov            = 25; % compute whitening matrix from every N-th batch
ops.scaleproc           = 100;   % int16 scaling of whitened data

ops.fproc       = fullfile(rootH, 'temp_wh.imec.ap.bin'); % proc file on a fast SSD

ops.fbinary = fullfile(rootZ, dataName);
ops.minfr_goodchannels = 0; %don't remove any channels due to low firing rate

% call preprocessDataSub to filter data and create the whitening matrix.
ops.trange = [0 60]; % time range to use when extracting the whitening matrix
[rez, ops] = preprocessDataForNoise(ops);

%calculate fft for each channel in the whitened data (stored in ops.fproc)
tic;
[fftSamp, nT_fft] = sampFFT( rez, clipDur );
fprintf( 'time to calc fft: %f\n', toc );
%use the fft to generate noise for each channel for a time period
%Can only make batches of nT points at a time

    noiseT = 2.2;           %in seconds, chosen for ~66000 points
    noiseSamp = noiseT*rez.ops.fs;
    nChan = numel(rez.ops.chanMap);
    eNoise = zeros( noiseSamp, nChan, 'single' );

    noiseBatch = ceil(noiseSamp/nT_fft);
    lastWind = noiseSamp - (noiseBatch-1)*nT_fft; %in samples
    fprintf( 'noiseSamp, batchSamp, lastWind: %d, %d, %d\n', noiseSamp, nT_fft, lastWind);

    for j = 1:nChan
            for i = 1:noiseBatch-1
                tStart = (i-1)*nT_fft+1;
                tEnd = i * nT_fft;
                eNoise(tStart:tEnd,j) = fftnoise(fftSamp(:,j),1);
            end
            %for last batch, call one more time and truncate
            tempNoise = fftnoise(fftSamp(:,j),1);
            tStart = (noiseBatch-1)*nT_fft+1;
            tEnd = noiseSamp;
            eNoise(tStart:tEnd,j) = tempNoise(1:lastWind);
    end

    selectChan = [10,11,12,13,14];

    tR = [4200:5200]; %just looking at 1000 samples
    h = figure(1);
    for k = 1:numel(selectChan)
        currNoise = eNoise(tR,selectChan(k));
        plot( tR, currNoise + k*500 );
        hold on;
    end
    title("1000 samples of generated noise, before unwhitening");
    hold off

    %unwhiten this noise array
    eNoise_unwh = eNoise/rez.Wrot;

    %to get the final noise array, map to an array including all channels
    nAllChan = max(rez.ops.chanMap);
    eNoise_final = zeros(noiseSamp, nAllChan, 'single');
    eNoise_final(:,rez.ops.chanMap) = eNoise_unwh;

    tR = [4200:5200]; %plot 1000 samples post unwhitening
    h = figure(2);
    for k = 1:numel(selectChan)
        currNoise = eNoise_final(tR,selectChan(k));
        plot( tR, currNoise + k*50 );
        hold on;
    end
    title('1000 samples of generated noise, after unwhitening');
    hold off

    nm.chanMapName = chanMapName;
    nm.fft = fftSamp;
    nm.nt = nT_fft;
    nm.Wrot = rez.Wrot;
    nm.chanMap = rez.ops.chanMap;
    nm.bitPerUV =  rez.ops.bitPerUV;

%save rez file
fprintf('Saving rez file  \n');
fname = fullfile(rootZ, 'rez.mat');
save(fname, 'rez', '-v7.3');

%save noise model file
fprintf('Saving nm file  \n');
fname = fullfile(rootZ, 'noiseModel.mat');
save(fname, 'nm', '-v7.3');

end

function [rez, ops] = preprocessDataForNoise(ops)

%build rez structure -- code taken from preprocessDataSub
%Only changes are to skip checking for low spike rate samples and
%write out the data as rows = time -- just a convenience so it
%it can be read in using the same code

ops.nt0 	= getOr(ops, {'nt0'}, 61);
ops.nt0min  = getOr(ops, 'nt0min', ceil(20 * ops.nt0/61));

NT       = ops.NT ;
NchanTOT = ops.NchanTOT;

bytes = get_file_size(ops.fbinary);
nTimepoints = floor(bytes/NchanTOT/2);
ops.tstart = ceil(ops.trange(1) * ops.fs);
ops.tend   = min(nTimepoints, ceil(ops.trange(2) * ops.fs));
ops.sampsToRead = ops.tend-ops.tstart;
ops.twind = ops.tstart * NchanTOT*2;

Nbatch      = ceil(ops.sampsToRead /(NT-ops.ntbuff));
ops.Nbatch = Nbatch;

[chanMap, xc, yc, kcoords, NchanTOTdefault] = loadChanMap(ops.chanMap);
ops.NchanTOT = getOr(ops, 'NchanTOT', NchanTOTdefault);
ops.igood = true(size(chanMap));

ops.Nchan = numel(chanMap);
ops.Nfilt = getOr(ops, 'nfilt_factor', 4) * ops.Nchan;

rez.ops         = ops;
rez.xc = xc;
rez.yc = yc;

rez.xcoords = xc;
rez.ycoords = yc;

rez.ops.chanMap = chanMap;
rez.ops.kcoords = kcoords;

NTbuff      = NT + 4*ops.ntbuff;

% by how many bytes to offset all the batches
rez.ops.Nbatch = Nbatch;
rez.ops.NTbuff = NTbuff;
rez.ops.chanMap = chanMap;

%build whitening matrix. This function filters before calculating the
%cross correlation

tic;

fprintf('Time %3.0fs. Computing whitening matrix.. \n', toc);

Wrot = get_whitening_matrix(rez);

%Apply the whitening matrix to a subset of the original data

ops.tstart = ceil(ops.trange(1) * ops.fs);
ops.tend   = min(nTimepoints, ceil(ops.trange(2) * ops.fs));
ops.sampsToRead = ops.tend-ops.tstart;
ops.twind = ops.tstart * NchanTOT*2;
Nbatch      = ceil(ops.sampsToRead /(NT-ops.ntbuff));
ops.Nbatch = Nbatch;

fprintf('Time %3.0fs. Loading raw data and applying filters... \n', toc);

fid         = fopen(ops.fbinary, 'r');
if ~ops.useRAM
    fidW        = fopen(ops.fproc,   'w');
    DATA = [];
else
    DATA = zeros(NT, rez.ops.Nchan, Nbatch, 'int16');
end
% load data into batches, filter, compute covariance
if isfield(ops,'fslow')&&ops.fslow<ops.fs/2
    [b1, a1] = butter(3, [ops.fshigh/ops.fs,ops.fslow/ops.fs]*2, 'bandpass');
elseif isfield(ops,'fshigh')
    [b1, a1] = butter(3, ops.fshigh/ops.fs*2, 'high');
end

for ibatch = 1:Nbatch
    offset = max(0, ops.twind + 2*NchanTOT*((NT - ops.ntbuff) * (ibatch-1) - 2*ops.ntbuff));
    if offset==0
        ioffset = 0;
    else
        ioffset = ops.ntbuff;
    end
    fseek(fid, offset, 'bof');

    buff = fread(fid, [NchanTOT NTbuff], '*int16');
    if isempty(buff)
        break;
    end
    nsampcurr = size(buff,2);
    if nsampcurr<NTbuff
        buff(:, nsampcurr+1:NTbuff) = repmat(buff(:,nsampcurr), 1, NTbuff-nsampcurr);
    end

    if ops.GPU
        dataRAW = gpuArray(buff);
    else
        dataRAW = buff;
    end
    dataRAW = dataRAW';
    dataRAW = single(dataRAW);
    dataRAW = dataRAW(:, chanMap);

    % subtract the mean from each channel
    dataRAW = dataRAW - mean(dataRAW, 1);

    if (isfield(ops,'fshigh'))
        datr = filter(b1, a1, dataRAW);
        datr = flipud(datr);
        datr = filter(b1, a1, datr);
        datr = flipud(datr);
    else
        datr = dataRAW;
    end

    % CAR, common average referencing by median
    if getOr(ops, 'CAR', 1)
        datr = datr - median(datr, 2);
    end

    datr = datr(ioffset + (1:NT),:);

    %apply whitening
    datr    = datr * Wrot;

    if ops.useRAM
        DATA(:,:,ibatch) = gather_try(datr);
    else
        datcpu  = gather_try(int16(datr));
        %next step will be reading in this file to get FTs
        %Most convenient for that process to have the data in the original
        %format (row = time, column = channel index)
        fwrite(fidW, datcpu', 'int16');
    end
end

Wrot        = gather_try(Wrot);
rez.Wrot    = Wrot;

fclose(fidW);
fclose(fid);

end

function [fftSamp, nT] = sampFFT( rez, clipDur )

    ops = rez.ops;

    %get file of whitened data
    datFile = ops.fproc;

    %read in some data
    nChansInFile = numel(ops.chanMap);  % channels in whitenened data, excludes ref chans in original
    d = dir(ops.fproc);
    nSamps = d.bytes/2/nChansInFile;
    tSkip = 1.0; % skip first tSkip seconds

    sampStart = round(ops.fs*tSkip);
    nClipSamps = round(ops.fs*clipDur);
    mmf = memmapfile(datFile, 'Format', {'int16', [nChansInFile nSamps], 'x'});
    thisDat = (double(mmf.Data.x(:, (1:nClipSamps)+sampStart)));
    %subtract the DC
    thisDat = bsxfun(@minus, thisDat, mean(thisDat,2));
    [~,nT] = size(thisDat);
    %data is formatted as Nchan rows by nt columns. fft returns the
    %transform of the columns, so transpose
    fftSamp = fft(thisDat');

end

function noise=fftnoise(f,Nseries)
% Generate noise with a given power spectrum.
% Useful helper function for Monte Carlo null-hypothesis tests and confidence interval estimation.
%
% noise=fftnoise(f[,Nseries])
%
% INPUTS:
% f: the fft of a time series (must be a column vector)
% Nseries: number of noise series to generate. (default=1)
%
% OUTPUT:
% noise: surrogate series with same power spectrum as f. (each column is a surrogate).
%
%   --- Aslak Grinsted (2009)
if nargin<2
    Nseries=1;
end
f=f(:);     %ensures f is a column vector
N=length(f);
Np=floor((N-1)/2);
phases=rand(Np,Nseries)*2*pi;
phases=complex(cos(phases),sin(phases)); % this was the fastest alternative in my tests.
f=repmat(f,1,Nseries);
f(2:Np+1,:)=f(2:Np+1,:).*phases;
f(end:-1:end-Np+1,:)=conj(f(2:Np+1,:));
noise=real(ifft(f,[],1));

end


function D = spm_eeg_average(S)
% Average each channel over trials or trial types
% FORMAT D = spm_eeg_average(S)
%
% S        - optional input struct
%    fields of S:
% D        - MEEG object or filename of M/EEG mat-file with epoched data
% S.robust      - (optional) - use robust averaging
%                 .savew  - save the weights in an additional dataset
%                 .bycondition - compute the weights by condition (1,
%                                default) or from all trials (0)
%                 .ks     - offset of the weighting function (default: 3)
% S.prefix     - prefix for the output file (default - 'm')
%
% Output:
% D        - MEEG object (also written on disk)
%__________________________________________________________________________
% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging

% Stefan Kiebel
% $Id: spm_eeg_average.m 7125 2017-06-23 09:49:29Z guillaume $

SVNrev = '$Rev: 7125 $';

%-Startup
%--------------------------------------------------------------------------
spm('FnBanner', mfilename, SVNrev);
spm('FigName','M/EEG averaging'); spm('Pointer','Watch');

%-Get input parameters
%--------------------------------------------------------------------------
if ~isfield(S, 'prefix'),       S.prefix = 'm';           end
if ~isfield(S, 'robust'),       S.robust = 0;             end

%-Configure robust averaging
%--------------------------------------------------------------------------
if isstruct(S.robust)
    if ~isfield(S.robust, 'savew'),        S.robust.savew =  0;        end
    if ~isfield(S.robust, 'bycondition'),  S.robust.bycondition = 0;   end
    if ~isfield(S.robust, 'ks'),           S.robust.ks =  3;           end
    if ~isfield(S.robust, 'removebad'),    S.robust.removebad =  0;    end

    robust      = 1;
    savew       = S.robust.savew;
    bycondition = S.robust.bycondition;
    ks          = S.robust.ks;
    removebad   = S.robust.removebad;
else
    robust = 0;
end

%-Get MEEG object
%--------------------------------------------------------------------------
D = spm_eeg_load(S.D);

montage_ind = D.montage('getindex');
D           = D.montage('switch', 0);

%-Check that there is any good data available
%--------------------------------------------------------------------------
if ntrials(D)==0 || isempty(indtrial(D, D.condlist, 'GOOD'))
    warning('No good trials for averaging were found. Nothing to do.');
    return;
end

%-Redirect to Time-Frequency averaging if necessary
%--------------------------------------------------------------------------
if strncmpi(D.transformtype,'TF',2) % TF and TFphase
    D = spm_eeg_average_TF(S);
    return
end

%-Generate new MEEG object with new files
%--------------------------------------------------------------------------
Dnew = clone(D, [S.prefix fname(D)], [D.nchannels D.nsamples D.nconditions]);
Dnew = type(Dnew, 'evoked');

if robust && savew
    Dw = clone(D, ['W' fname(D)]);
end

%-Do the averaging
%--------------------------------------------------------------------------
cl   = D.condlist;

ni = zeros(1, D.nconditions);
for i = 1:D.nconditions
    w = indtrial(D, deblank(cl{i}), 'GOOD');
    ni(i) = length(w);
    if ni(i) == 0
        warning('%s: No trials for trial type %d', D.fname, cl{i});
    end
end

goodtrials  = indtrial(D, cl, 'GOOD');
chanind     = D.indchantype({'MEEG', 'LFP'});

if prod(size(D))*8 < spm('memory')

    %-Average everything at once if there is enough memory
    %======================================================================
    spm_progress_bar('Init', D.nconditions, 'Averages done');
    if D.nconditions > 100, Ibar = floor(linspace(1, D.nconditions, 100));
    else Ibar = 1:D.nconditions; end

    if robust && ~bycondition
        W1      = ones(D.nchannels, D.nsamples, length(goodtrials));
        Y       = D(chanind, :, goodtrials);
        if removebad
            bad    = badsamples(D, chanind, ':', goodtrials);
            Y(bad) = NaN;
        end
        [Y, W2] = spm_robust_average(Y, 3, ks);
        W1(chanind, :, :) = W2;
        if savew
            Dw(:, :, goodtrials) = W1;
        end
        W = zeros(size(D));
        W(:, :, goodtrials) = W1;
    end

    for i = 1:D.nconditions

        w = indtrial(D, deblank(cl{i}), 'GOOD');

        if isempty(w)
            continue;
        end

        if ~robust
            Dnew(:, :, i) = mean(D(:, :, w), 3);
        else
            if bycondition
                W       = ones(D.nchannels, D.nsamples, length(w));
                Y       = D(chanind, :, w);
                if removebad
                    bad     = badsamples(D, chanind, ':', w);
                    Y(bad)  = NaN;
                end
                [Y, W1] = spm_robust_average(Y, 3, ks);
                W(chanind, :, :)    = W1;
                Dnew(chanind, :, i) = Y;
                if length(chanind)<D.nchannels
                    Dnew(setdiff(1:D.nchannels, chanind), :, i) = mean(D(setdiff(1:D.nchannels, chanind), :, w), 3);
                end
                if savew
                    Dw(:, :, w)   = W;
                end
            else
                X = D(:, :, w);
                X(isnan(X))      = 0;
                Dnew(:, :, i) = ...
                    sum(W(:, :, w).*X, 3)./sum(W(:, :, w), 3);
            end
        end

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

    end  % for i = 1:D.nconditions
else
    %-Averaging by channel
    %======================================================================
    spm_progress_bar('Init', D.nchannels, 'Channels completed');
    if D.nchannels > 100, Ibar = floor(linspace(1, D.nchannels, 100));
    else Ibar = [1:D.nchannels]; end
    for j = 1:D.nchannels
        if robust && ~bycondition
            if ismember(j, chanind)
                Y       = D(j, :, goodtrials);
                if removebad
                    bad     = badsamples(D, j, ':', goodtrials);
                    Y(bad)  = NaN;
                end
                [Y, W1] = spm_robust_average(Y, 3, ks);
                W = zeros([1 D.nsamples D.ntrials]);
                W(1, :, goodtrials) = W1;
            else
                W1 = ones(1, D.nsamples, length(goodtrials));
            end

            if savew
                Dw(j, :, goodtrials) = W1;
            end
        end

        for i = 1:D.nconditions

            w = indtrial(D, deblank(cl{i}), 'GOOD');

            if isempty(w)
                continue;
            end

            if ~robust || ~ismember(j, chanind)
                Dnew(j, :, i) = mean(D(j, :, w), 3);
            else
                if bycondition
                    Y       = D(j, :, w);
                    if removebad
                        bad     = badsamples(D, j, ':', w);
                        Y(bad)  = NaN;
                    end
                    [Y, W] = spm_robust_average(Y, 3, ks);
                    Dnew(j, :, i) = Y;
                    if savew
                        Dw(j, :, w)   = W;
                    end
                else
                    X = D(j, :, w);
                    X(isnan(X))      = 0;
                    Dnew(j, :, i) = ...
                        sum(W(1, :, w).*X, 3)./sum(W(1, :, w), 3);
                end
            end

        end  % for i = 1:D.nconditions
        if ismember(j, Ibar), spm_progress_bar('Set', j); end
    end
end

spm_progress_bar('Clear');

%-Update some header information
%--------------------------------------------------------------------------
Dnew = conditions(Dnew, ':', cl);
Dnew = repl(Dnew, ':', ni);
Dnew = montage(Dnew, 'switch', montage_ind);

%-Display averaging statistics
%--------------------------------------------------------------------------
fprintf('%s: Number of replications per contrast:\n', Dnew.fname);      %-#
for i = 1:D.nconditions
    fprintf('  average %s: %d trials\n', cl{i}, ni(i));                 %-#
end

if robust
    disp('Robust averaging might have introduced high frequencies in the data. It is advised to re-apply low-pass filter.');
end

%-Save new evoked M/EEG dataset
%--------------------------------------------------------------------------
Dnew = Dnew.history(mfilename, S);
save(Dnew);

if robust && savew
    Dw = Dw.history(mfilename, S);
    save(Dw);
end

D = Dnew;

%-Cleanup
%--------------------------------------------------------------------------
fprintf('%-40s: %30s\n','Completed',spm('time'));                       %-#
spm('FigName','M/EEG averaging: done'); spm('Pointer','Arrow');


function [net, opts, in_name, in_dim] = resnet50(opts)
opts.imageSize = 224;
opts.maxGpuImgs = 90;  % # of images that a 12GB GPU can hold

net = load(fullfile(opts.localDir, 'models', 'imagenet-resnet-50-dag.mat'));
net = dagnn.DagNN.loadobj(net) ;

% remove softmax, fc
net.removeLayer('prob');
net.removeLayer('fc1000');

% freeze pretrained layers
if opts.lastLayer
    for i = 1:numel(net.params)
        net.params(i).learningRate = 0;
        net.params(i).weightDecay  = 0;
    end
end

in_name = 'pool5';
in_dim = 2048;
end


function [K] = ku0u0(x, xp, hyp, ubar, ubarp, dt, i)

logsigma = hyp(1);
logtheta = hyp(2);

a1 = hyp(3);
a2 = hyp(4);
a3 = hyp(5);
a4 = hyp(6);

n_x = size(x,1);
n_xp = size(xp,1);

x = repmat(x,1,n_xp);
xp = repmat(xp',n_x,1);

ubar = repmat(ubar,1,n_xp);
ubarp = repmat(ubarp',n_x,1);

switch i

case 0

K=exp(1).^(logsigma+(-8).*logtheta+(-1/2).*exp(1).^((-1).*logtheta).*(x+( ...
  -1).*xp).^2).*(exp(1).^(2.*logtheta).*(exp(1).^(2.*logtheta).*(exp(1).^( ...
  2.*logtheta).*(exp(1).^(2.*logtheta)+a1.*dt.*exp(1).^logtheta.*(a1.*dt.* ...
  ubar.*ubarp+(-1).*(ubar+(-1).*ubarp).*(x+(-1).*xp))+(-1).*a1.^2.*dt.^2.* ...
  ubar.*ubarp.*(x+(-1).*xp).^2)+a2.*dt.*exp(1).^logtheta.*((-2).*exp(1).^( ...
  2.*logtheta)+exp(1).^logtheta.*(3.*a1.*dt.*(ubar+(-1).*ubarp)+2.*(x+(-1) ...
  .*xp)).*(x+(-1).*xp)+(-1).*a1.*dt.*(ubar+(-1).*ubarp).*(x+(-1).*xp).^3)+ ...
  a2.^2.*dt.^2.*(3.*exp(1).^(2.*logtheta)+(-6).*exp(1).^logtheta.*(x+(-1) ...
  .*xp).^2+(x+(-1).*xp).^4))+(-1).*a1.*a3.*dt.^2.*exp(1).^(2.*logtheta).*( ...
  ubar+ubarp).*(3.*exp(1).^(2.*logtheta)+(-6).*exp(1).^logtheta.*(x+(-1).* ...
  xp).^2+(x+(-1).*xp).^4)+a3.^2.*dt.^2.*(15.*exp(1).^(3.*logtheta)+(-45).* ...
  exp(1).^(2.*logtheta).*(x+(-1).*xp).^2+15.*exp(1).^logtheta.*(x+(-1).* ...
  xp).^4+(-1).*(x+(-1).*xp).^6))+a4.*dt.*exp(1).^(2.*logtheta).*((-2).* ...
  a2.*dt.*(15.*exp(1).^(3.*logtheta)+(-45).*exp(1).^(2.*logtheta).*(x+(-1) ...
  .*xp).^2+15.*exp(1).^logtheta.*(x+(-1).*xp).^4+(-1).*(x+(-1).*xp).^6)+ ...
  exp(1).^logtheta.*(6.*exp(1).^(3.*logtheta)+(-3).*exp(1).^(2.*logtheta) ...
  .*(5.*a1.*dt.*(ubar+(-1).*ubarp)+4.*(x+(-1).*xp)).*(x+(-1).*xp)+(-1).* ...
  a1.*dt.*(ubar+(-1).*ubarp).*(x+(-1).*xp).^5+2.*exp(1).^logtheta.*(x+(-1) ...
  .*xp).^3.*(5.*a1.*dt.*(ubar+(-1).*ubarp)+x+(-1).*xp)))+a4.^2.*dt.^2.*( ...
  105.*exp(1).^(4.*logtheta)+(-420).*exp(1).^(3.*logtheta).*(x+(-1).*xp) ...
  .^2+210.*exp(1).^(2.*logtheta).*(x+(-1).*xp).^4+(-28).*exp(1) ...
  .^logtheta.*(x+(-1).*xp).^6+(x+(-1).*xp).^8));

case 1 % logsigma

K=exp(1).^(logsigma+(-8).*logtheta+(-1/2).*exp(1).^((-1).*logtheta).*(x+( ...
  -1).*xp).^2).*(exp(1).^(2.*logtheta).*(exp(1).^(2.*logtheta).*(exp(1).^( ...
  2.*logtheta).*(exp(1).^(2.*logtheta)+a1.*dt.*exp(1).^logtheta.*(a1.*dt.* ...
  ubar.*ubarp+(-1).*(ubar+(-1).*ubarp).*(x+(-1).*xp))+(-1).*a1.^2.*dt.^2.* ...
  ubar.*ubarp.*(x+(-1).*xp).^2)+a2.*dt.*exp(1).^logtheta.*((-2).*exp(1).^( ...
  2.*logtheta)+exp(1).^logtheta.*(3.*a1.*dt.*(ubar+(-1).*ubarp)+2.*(x+(-1) ...
  .*xp)).*(x+(-1).*xp)+(-1).*a1.*dt.*(ubar+(-1).*ubarp).*(x+(-1).*xp).^3)+ ...
  a2.^2.*dt.^2.*(3.*exp(1).^(2.*logtheta)+(-6).*exp(1).^logtheta.*(x+(-1) ...
  .*xp).^2+(x+(-1).*xp).^4))+(-1).*a1.*a3.*dt.^2.*exp(1).^(2.*logtheta).*( ...
  ubar+ubarp).*(3.*exp(1).^(2.*logtheta)+(-6).*exp(1).^logtheta.*(x+(-1).* ...
  xp).^2+(x+(-1).*xp).^4)+a3.^2.*dt.^2.*(15.*exp(1).^(3.*logtheta)+(-45).* ...
  exp(1).^(2.*logtheta).*(x+(-1).*xp).^2+15.*exp(1).^logtheta.*(x+(-1).* ...
  xp).^4+(-1).*(x+(-1).*xp).^6))+a4.*dt.*exp(1).^(2.*logtheta).*((-2).* ...
  a2.*dt.*(15.*exp(1).^(3.*logtheta)+(-45).*exp(1).^(2.*logtheta).*(x+(-1) ...
  .*xp).^2+15.*exp(1).^logtheta.*(x+(-1).*xp).^4+(-1).*(x+(-1).*xp).^6)+ ...
  exp(1).^logtheta.*(6.*exp(1).^(3.*logtheta)+(-3).*exp(1).^(2.*logtheta) ...
  .*(5.*a1.*dt.*(ubar+(-1).*ubarp)+4.*(x+(-1).*xp)).*(x+(-1).*xp)+(-1).* ...
  a1.*dt.*(ubar+(-1).*ubarp).*(x+(-1).*xp).^5+2.*exp(1).^logtheta.*(x+(-1) ...
  .*xp).^3.*(5.*a1.*dt.*(ubar+(-1).*ubarp)+x+(-1).*xp)))+a4.^2.*dt.^2.*( ...
  105.*exp(1).^(4.*logtheta)+(-420).*exp(1).^(3.*logtheta).*(x+(-1).*xp) ...
  .^2+210.*exp(1).^(2.*logtheta).*(x+(-1).*xp).^4+(-28).*exp(1) ...
  .^logtheta.*(x+(-1).*xp).^6+(x+(-1).*xp).^8));

case 2 % logtheta

K=exp(1).^(logsigma+(-8).*logtheta+(-1/2).*exp(1).^((-1).*logtheta).*(x+( ...
  -1).*xp).^2).*(exp(1).^(3.*logtheta).*(exp(1).^(2.*logtheta).*(6.* ...
  a2.^2.*dt.^2.*(exp(1).^logtheta+(-1).*(x+(-1).*xp).^2)+exp(1) ...
  .^logtheta.*(4.*exp(1).^(2.*logtheta)+3.*a1.*dt.*exp(1).^logtheta.*(a1.* ...
  dt.*ubar.*ubarp+(-1).*(ubar+(-1).*ubarp).*(x+(-1).*xp))+(-2).*a1.^2.* ...
  dt.^2.*ubar.*ubarp.*(x+(-1).*xp).^2)+a2.*dt.*((-6).*exp(1).^(2.* ...
  logtheta)+2.*exp(1).^logtheta.*(3.*a1.*dt.*(ubar+(-1).*ubarp)+2.*(x+(-1) ...
  .*xp)).*(x+(-1).*xp)+(-1).*a1.*dt.*(ubar+(-1).*ubarp).*(x+(-1).*xp).^3)) ...
  +2.*exp(1).^logtheta.*(exp(1).^(2.*logtheta).*(exp(1).^(2.*logtheta)+ ...
  a1.*dt.*exp(1).^logtheta.*(a1.*dt.*ubar.*ubarp+(-1).*(ubar+(-1).*ubarp) ...
  .*(x+(-1).*xp))+(-1).*a1.^2.*dt.^2.*ubar.*ubarp.*(x+(-1).*xp).^2)+a2.* ...
  dt.*exp(1).^logtheta.*((-2).*exp(1).^(2.*logtheta)+exp(1).^logtheta.*( ...
  3.*a1.*dt.*(ubar+(-1).*ubarp)+2.*(x+(-1).*xp)).*(x+(-1).*xp)+(-1).*a1.* ...
  dt.*(ubar+(-1).*ubarp).*(x+(-1).*xp).^3)+a2.^2.*dt.^2.*(3.*exp(1).^(2.* ...
  logtheta)+(-6).*exp(1).^logtheta.*(x+(-1).*xp).^2+(x+(-1).*xp).^4))+(-6) ...
  .*a1.*a3.*dt.^2.*exp(1).^(2.*logtheta).*(ubar+ubarp).*(exp(1).^logtheta+ ...
  (-1).*(x+(-1).*xp).^2)+15.*a3.^2.*dt.^2.*(3.*exp(1).^(2.*logtheta)+(-6) ...
  .*exp(1).^logtheta.*(x+(-1).*xp).^2+(x+(-1).*xp).^4)+(-2).*a1.*a3.* ...
  dt.^2.*exp(1).^logtheta.*(ubar+ubarp).*(3.*exp(1).^(2.*logtheta)+(-6).* ...
  exp(1).^logtheta.*(x+(-1).*xp).^2+(x+(-1).*xp).^4))+2.*exp(1).^(2.* ...
  logtheta).*(exp(1).^(2.*logtheta).*(exp(1).^(2.*logtheta).*(exp(1).^(2.* ...
  logtheta)+a1.*dt.*exp(1).^logtheta.*(a1.*dt.*ubar.*ubarp+(-1).*(ubar+( ...
  -1).*ubarp).*(x+(-1).*xp))+(-1).*a1.^2.*dt.^2.*ubar.*ubarp.*(x+(-1).*xp) ...
  .^2)+a2.*dt.*exp(1).^logtheta.*((-2).*exp(1).^(2.*logtheta)+exp(1) ...
  .^logtheta.*(3.*a1.*dt.*(ubar+(-1).*ubarp)+2.*(x+(-1).*xp)).*(x+(-1).* ...
  xp)+(-1).*a1.*dt.*(ubar+(-1).*ubarp).*(x+(-1).*xp).^3)+a2.^2.*dt.^2.*( ...
  3.*exp(1).^(2.*logtheta)+(-6).*exp(1).^logtheta.*(x+(-1).*xp).^2+(x+(-1) ...
  .*xp).^4))+(-1).*a1.*a3.*dt.^2.*exp(1).^(2.*logtheta).*(ubar+ubarp).*( ...
  3.*exp(1).^(2.*logtheta)+(-6).*exp(1).^logtheta.*(x+(-1).*xp).^2+(x+(-1) ...
  .*xp).^4)+a3.^2.*dt.^2.*(15.*exp(1).^(3.*logtheta)+(-45).*exp(1).^(2.* ...
  logtheta).*(x+(-1).*xp).^2+15.*exp(1).^logtheta.*(x+(-1).*xp).^4+(-1).*( ...
  x+(-1).*xp).^6))+2.*a4.*dt.*exp(1).^(2.*logtheta).*((-2).*a2.*dt.*(15.* ...
  exp(1).^(3.*logtheta)+(-45).*exp(1).^(2.*logtheta).*(x+(-1).*xp).^2+15.* ...
  exp(1).^logtheta.*(x+(-1).*xp).^4+(-1).*(x+(-1).*xp).^6)+exp(1) ...
  .^logtheta.*(6.*exp(1).^(3.*logtheta)+(-3).*exp(1).^(2.*logtheta).*(5.* ...
  a1.*dt.*(ubar+(-1).*ubarp)+4.*(x+(-1).*xp)).*(x+(-1).*xp)+(-1).*a1.*dt.* ...
  (ubar+(-1).*ubarp).*(x+(-1).*xp).^5+2.*exp(1).^logtheta.*(x+(-1).*xp) ...
  .^3.*(5.*a1.*dt.*(ubar+(-1).*ubarp)+x+(-1).*xp)))+(exp(1).^(2.*logtheta) ...
  .*(exp(1).^(2.*logtheta).*(exp(1).^(2.*logtheta).*(exp(1).^(2.*logtheta) ...
  +a1.*dt.*exp(1).^logtheta.*(a1.*dt.*ubar.*ubarp+(-1).*(ubar+(-1).*ubarp) ...
  .*(x+(-1).*xp))+(-1).*a1.^2.*dt.^2.*ubar.*ubarp.*(x+(-1).*xp).^2)+a2.* ...
  dt.*exp(1).^logtheta.*((-2).*exp(1).^(2.*logtheta)+exp(1).^logtheta.*( ...
  3.*a1.*dt.*(ubar+(-1).*ubarp)+2.*(x+(-1).*xp)).*(x+(-1).*xp)+(-1).*a1.* ...
  dt.*(ubar+(-1).*ubarp).*(x+(-1).*xp).^3)+a2.^2.*dt.^2.*(3.*exp(1).^(2.* ...
  logtheta)+(-6).*exp(1).^logtheta.*(x+(-1).*xp).^2+(x+(-1).*xp).^4))+(-1) ...
  .*a1.*a3.*dt.^2.*exp(1).^(2.*logtheta).*(ubar+ubarp).*(3.*exp(1).^(2.* ...
  logtheta)+(-6).*exp(1).^logtheta.*(x+(-1).*xp).^2+(x+(-1).*xp).^4)+ ...
  a3.^2.*dt.^2.*(15.*exp(1).^(3.*logtheta)+(-45).*exp(1).^(2.*logtheta).*( ...
  x+(-1).*xp).^2+15.*exp(1).^logtheta.*(x+(-1).*xp).^4+(-1).*(x+(-1).*xp) ...
  .^6))+a4.*dt.*exp(1).^(2.*logtheta).*((-2).*a2.*dt.*(15.*exp(1).^(3.* ...
  logtheta)+(-45).*exp(1).^(2.*logtheta).*(x+(-1).*xp).^2+15.*exp(1) ...
  .^logtheta.*(x+(-1).*xp).^4+(-1).*(x+(-1).*xp).^6)+exp(1).^logtheta.*( ...
  6.*exp(1).^(3.*logtheta)+(-3).*exp(1).^(2.*logtheta).*(5.*a1.*dt.*(ubar+ ...
  (-1).*ubarp)+4.*(x+(-1).*xp)).*(x+(-1).*xp)+(-1).*a1.*dt.*(ubar+(-1).* ...
  ubarp).*(x+(-1).*xp).^5+2.*exp(1).^logtheta.*(x+(-1).*xp).^3.*(5.*a1.* ...
  dt.*(ubar+(-1).*ubarp)+x+(-1).*xp)))+a4.^2.*dt.^2.*(105.*exp(1).^(4.* ...
  logtheta)+(-420).*exp(1).^(3.*logtheta).*(x+(-1).*xp).^2+210.*exp(1).^( ...
  2.*logtheta).*(x+(-1).*xp).^4+(-28).*exp(1).^logtheta.*(x+(-1).*xp).^6+( ...
  x+(-1).*xp).^8)).*((-8)+(1/2).*exp(1).^((-1).*logtheta).*(x+(-1).*xp) ...
  .^2)+28.*a4.^2.*dt.^2.*exp(1).^logtheta.*(15.*exp(1).^(3.*logtheta)+( ...
  -45).*exp(1).^(2.*logtheta).*(x+(-1).*xp).^2+15.*exp(1).^logtheta.*(x+( ...
  -1).*xp).^4+(-1).*(x+(-1).*xp).^6)+a4.*dt.*exp(1).^(3.*logtheta).*(6.* ...
  exp(1).^(3.*logtheta)+(-30).*a2.*dt.*(3.*exp(1).^(2.*logtheta)+(-6).* ...
  exp(1).^logtheta.*(x+(-1).*xp).^2+(x+(-1).*xp).^4)+2.*exp(1).^logtheta.* ...
  (9.*exp(1).^(2.*logtheta)+(-3).*exp(1).^logtheta.*(5.*a1.*dt.*(ubar+(-1) ...
  .*ubarp)+4.*(x+(-1).*xp)).*(x+(-1).*xp)+(x+(-1).*xp).^3.*(5.*a1.*dt.*( ...
  ubar+(-1).*ubarp)+x+(-1).*xp))+(-3).*exp(1).^(2.*logtheta).*(5.*a1.*dt.* ...
  (ubar+(-1).*ubarp)+4.*(x+(-1).*xp)).*(x+(-1).*xp)+(-1).*a1.*dt.*(ubar+( ...
  -1).*ubarp).*(x+(-1).*xp).^5+2.*exp(1).^logtheta.*(x+(-1).*xp).^3.*(5.* ...
  a1.*dt.*(ubar+(-1).*ubarp)+x+(-1).*xp)));

case 3 % a1

K=dt.*exp(1).^(logsigma+(-5).*logtheta+(-1/2).*exp(1).^((-1).*logtheta).*( ...
  x+(-1).*xp).^2).*(exp(1).^(2.*logtheta).*(exp(1).^logtheta.*(2.*a1.*dt.* ...
  ubar.*ubarp.*(exp(1).^logtheta+(-1).*(x+(-1).*xp).^2)+(-1).*exp(1) ...
  .^logtheta.*(ubar+(-1).*ubarp).*(x+(-1).*xp))+(-1).*a2.*dt.*(ubar+(-1).* ...
  ubarp).*((-3).*exp(1).^logtheta+(x+(-1).*xp).^2).*(x+(-1).*xp))+(-1).* ...
  a3.*dt.*exp(1).^logtheta.*(ubar+ubarp).*(3.*exp(1).^(2.*logtheta)+(-6).* ...
  exp(1).^logtheta.*(x+(-1).*xp).^2+(x+(-1).*xp).^4)+a4.*dt.*(ubar+(-1).* ...
  ubarp).*((-15).*exp(1).^(2.*logtheta)+10.*exp(1).^logtheta.*(x+(-1).*xp) ...
  .^2+(-1).*(x+(-1).*xp).^4).*(x+(-1).*xp));

case 4 % a2

K=dt.*exp(1).^(logsigma+(-6).*logtheta+(-1/2).*exp(1).^((-1).*logtheta).*( ...
  x+(-1).*xp).^2).*(exp(1).^(2.*logtheta).*(exp(1).^logtheta.*((-2).*exp( ...
  1).^(2.*logtheta)+exp(1).^logtheta.*(3.*a1.*dt.*(ubar+(-1).*ubarp)+2.*( ...
  x+(-1).*xp)).*(x+(-1).*xp)+(-1).*a1.*dt.*(ubar+(-1).*ubarp).*(x+(-1).* ...
  xp).^3)+2.*a2.*dt.*(3.*exp(1).^(2.*logtheta)+(-6).*exp(1).^logtheta.*(x+ ...
  (-1).*xp).^2+(x+(-1).*xp).^4))+(-2).*a4.*dt.*(15.*exp(1).^(3.*logtheta)+ ...
  (-45).*exp(1).^(2.*logtheta).*(x+(-1).*xp).^2+15.*exp(1).^logtheta.*(x+( ...
  -1).*xp).^4+(-1).*(x+(-1).*xp).^6));

case 5 % a3

K=dt.^2.*exp(1).^(logsigma+(-6).*logtheta+(-1/2).*exp(1).^((-1).*logtheta) ...
  .*(x+(-1).*xp).^2).*((-1).*a1.*exp(1).^(2.*logtheta).*(ubar+ubarp).*(3.* ...
  exp(1).^(2.*logtheta)+(-6).*exp(1).^logtheta.*(x+(-1).*xp).^2+(x+(-1).* ...
  xp).^4)+2.*a3.*(15.*exp(1).^(3.*logtheta)+(-45).*exp(1).^(2.*logtheta).* ...
  (x+(-1).*xp).^2+15.*exp(1).^logtheta.*(x+(-1).*xp).^4+(-1).*(x+(-1).*xp) ...
  .^6));

case 6 % a4

K=dt.*exp(1).^(logsigma+(-8).*logtheta+(-1/2).*exp(1).^((-1).*logtheta).*( ...
  x+(-1).*xp).^2).*(exp(1).^(2.*logtheta).*((-2).*a2.*dt.*(15.*exp(1).^( ...
  3.*logtheta)+(-45).*exp(1).^(2.*logtheta).*(x+(-1).*xp).^2+15.*exp(1) ...
  .^logtheta.*(x+(-1).*xp).^4+(-1).*(x+(-1).*xp).^6)+exp(1).^logtheta.*( ...
  6.*exp(1).^(3.*logtheta)+(-3).*exp(1).^(2.*logtheta).*(5.*a1.*dt.*(ubar+ ...
  (-1).*ubarp)+4.*(x+(-1).*xp)).*(x+(-1).*xp)+(-1).*a1.*dt.*(ubar+(-1).* ...
  ubarp).*(x+(-1).*xp).^5+2.*exp(1).^logtheta.*(x+(-1).*xp).^3.*(5.*a1.* ...
  dt.*(ubar+(-1).*ubarp)+x+(-1).*xp)))+2.*a4.*dt.*(105.*exp(1).^(4.* ...
  logtheta)+(-420).*exp(1).^(3.*logtheta).*(x+(-1).*xp).^2+210.*exp(1).^( ...
  2.*logtheta).*(x+(-1).*xp).^4+(-28).*exp(1).^logtheta.*(x+(-1).*xp).^6+( ...
  x+(-1).*xp).^8));

otherwise

        K = zeros(n_x, n_xp);
end

if K == 0

    K = zeros(n_x, n_xp);

end

end


function k = fileKernDiagCompute(kern, x)

% FILEKERNDIAGCOMPUTE Compute diagonal of FILE kernel.
% FORMAT
% DESC computes the diagonal of the kernel matrix for the stored file kernel given a design matrix of inputs.
% ARG kern : the kernel structure for which the matrix is computed.
% ARG index : indices of the diagonal to return.
% RETURN k : a vector containing the diagonal of the kernel matrix
% computed at the given points.
%
% SEEALSO : fileKernParamInit, kernDiagCompute, kernCreate, fileKernCompute
%
% COPYRIGHT : Neil D. Lawrence, 2005, 2006

% KERN

k = kern.variance*fileKernRead(kern, x, 'diag');


function [ Temp,e,Geopot,P,longrid,latgrid] = aps_weather_model_nan_check( Temp,e,Geopot,P,longrid,latgrid);
% Function which fills in the gaps in the weather model data with the
% nearest neighbor value, or from the level above.
%
%     Copyright (C) 2016  Bekaert David
%     davidbekaert.com
%
%     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.,
%     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%
% By David Bekaert
% April 2016

% getting the pressure
Pressure_level = squeeze(P(1,1,:));
lon = double(longrid(:,:,1));
lat = double(latgrid(:,:,1));

% step_levels
% define it in such a way we loop from the upper atmopshere to the lower atmosphere
step_level = [length(Pressure_level):-1:1]';
if Pressure_level(1)<Pressure_level(end) % first level is top APS
    step_level = [1:length(Pressure_level)]';
end

% looping though and use TEMP as inital check for nan
n_pixels = size(P,1)*size(P,2);
for k=1:length(Pressure_level)
    ix_nan = isnan(Temp(:,:,step_level(k)));
    n_nan = sum(sum(ix_nan));

    % check if there are any NaN values
    if n_nan<n_pixels-3
        temp_data = Temp(:,:,step_level(k));
        Temp(:,:,step_level(k)) = griddata(reshape(lon(~ix_nan),[],1),reshape(lat(~ix_nan),[],1),double(reshape(temp_data(~ix_nan),[],1)),lon,lat,'nearest');

        temp_data = e(:,:,step_level(k));
        e(:,:,step_level(k)) = griddata(reshape(lon(~ix_nan),[],1),reshape(lat(~ix_nan),[],1),double(reshape(temp_data(~ix_nan),[],1)),lon,lat,'nearest');

    % check if all are NaN values
    elseif n_nan==n_pixels
        if k==1
            error('Weird seems like the top of the atmopshere has no data')
        end
        Temp(:,:,step_level(k))=Temp(:,:,step_level(k-1));
        e(:,:,step_level(k))=e(:,:,step_level(k-1));
    else
        Temp(:,:,step_level(k))=nanmean(nanmean(Temp(:,:,step_level(k))));
        e(:,:,step_level(k))=nanmean(nanmean(e(:,:,step_level(k))));

    end
end


% ---------------------------------------------------------------
% |Jelle C.J. Veraa, Stock Bar chart plotter function, 3/28/2009 |
% |inspired by and some code from:                               |
% |Nagi Hatoum, Candlestick chart ploter (sic) function, 5/29/03 |
% ---------------------------------------------------------------
%
% Important: date plotting subroutine needs 'tlabel' by Carlos Adrian
%   Vargas Aguilera
%   Available at the MATLAB Central File Exchange site, File ID: #19314
%   http://www.mathworks.com/matlabcentral/fileexchange/19314
%
% function barChartPlot(O,H,L,C)
%          barChartPlot(O,H,L,C,date)
%          barChartPlot(O,H,L,C,date,colorLine)
%          barChartPlot([O H L C])
%          barChartPlot([O H L C],date)
%          barChartPlot([O H L C],date,colorLine)
%
% To use colors without a date, put '0' as date
%     i.e. barChartPlot(OHLC,0,'g');
%
% Required inputs: column vectors of O(pen), H(igh), L(ow)
% and C(lose) prices of commodity.
% Alternative: [rowsx4] OHLC matrix
%
% optional inputs [default]:
% - date: serial date number (make with 'datenum') [no dates, index#]
% - colorLine: Color for lines                     ['k']
%
% Note: identical inputs as required for cndlV2 except for colors

function barChartPlot(varargin)
% See if we have [OHLC] or seperate vectors and retrieve our
% required variables (Feel free to make this code more pretty ;-)
isMat = size(varargin{1},2);
indexShift = 0;
useDate = 0;

if isMat == 4,
    O = varargin{1}(:,1);
    H = varargin{1}(:,2);
    L = varargin{1}(:,3);
    C = varargin{1}(:,4);
else
    O = varargin{1};
    H = varargin{2};
    L = varargin{3};
    C = varargin{4};
    indexShift = 3;
end

if nargin+isMat < 7,
    colorLine = 'k';
else
    colorLine = varargin{3+indexShift};
end

if nargin+isMat < 6
    date = (1:length(O))';
else
    if varargin{2+indexShift} ~= 0
        date = varargin{2+indexShift};
        useDate = 1;
    else
        date = (1:length(O))';
    end
end

% Get the length of the data
l=length(O);
% Start plotting
hold on
% Draw line from Low to High%%%%%%%%%%%%%%%%%
for i=1:l
   line([date(i) date(i)], [L(i) H(i)],'Color',colorLine)
end

% w = Width of body, change multiplier to draw body thicker or thinner
% the 'min' ensures no errors on weekends ('time gap Fri. Mon.' > wanted
% spacing)
w=.4*min([(date(2)-date(1)) (date(3)-date(2))]);
% Draw open/close marks
 for i=1:l
    xOpen=[date(i)-w date(i)];
    xClose=[date(i)+w date(i)];
    yOpen=[O(i) O(i)];
    yClose=[C(i) C(i)];
    line(xOpen,yOpen,'Color',colorLine);
    line(xClose,yClose,'Color',colorLine);
 end

%%%%%%%%%% if dates supplied, put them on the x axis%%%%%%%%%%
if (nargin+isMat > 5) && useDate,
    tlabel('x');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
hold off


function tex_responses = compute_texton_response(im, tim)

if isempty(tim)
    tex_responses = [];
    return;
end

tex_responses = zeros(size(im, 1), size(im, 2), numel(tim));

fims = fbRun(tim, im);

for i = 1:length(fims)
    tex_responses(:, :, i) = abs(fims{i});
end


function test_suite = test_partitions
% tests for partitioning functions
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #
    try % assignment of 'localfunctions' is necessary in Matlab >= 2016
        test_functions=localfunctions();
    catch % no problem; early Matlab versions can use initTestSuite fine
    end
    initTestSuite;

function test_nfold_partitioner()
    ds=cosmo_synthetic_dataset('nchunks',5,'ntargets',4);

    p=cosmo_nfold_partitioner(ds);
    assertEqual(p, cosmo_nfold_partitioner(ds.sa.chunks));

    fns={'train_indices';'test_indices'};
    assertEqual(fns, fieldnames(p));
    for k=1:5
        test_indices=(k-1)*4+(1:4);
        train_indices=setdiff(1:20,test_indices);
        for j=1:2
            fn=fns{j};
            if j==1
                v=train_indices;
            else
                v=test_indices;
            end
            w=p.(fn);
            assertEqual(w{k}, v');
        end
    end

function test_nchoosek_partitioner()
    ds=cosmo_synthetic_dataset('nchunks',5,'ntargets',4);

    p=cosmo_nfold_partitioner(ds);
    q=cosmo_nchoosek_partitioner(ds,1);
    assertEqual(p,q);

    q=cosmo_nchoosek_partitioner(ds,.2);
    assertEqual(p,q);

    p=cosmo_nchoosek_partitioner(ds,3);
    q=cosmo_nchoosek_partitioner(ds,.6);

    assertEqual(p,q);
    assertFalse(isequal(p, cosmo_nchoosek_partitioner(ds,.4)));

    q2=cosmo_nchoosek_partitioner(ds.sa.chunks,3);
    assertEqual(p,q2);

    fns={'train_indices';'test_indices'};
    for j=1:2
        fn=fns{j};
        counts=zeros(20,1);

        v=p.(fn);
        assertEqual(size(v),[1 10]);

        for k=1:numel(v)
            w=v{k};
            counts(w)=counts(w)+1;
        end
        assertEqual(counts,ones(20,1)*j*2+2);
    end

function test_nchoosek_partitioner_half()
    offsets=[0 floor(rand()*10+20)];
    for offset=offsets
        for nchunks=2:4:10

            ds=cosmo_synthetic_dataset('nchunks',nchunks,'ntargets',3);
            ds.sa.chunks=ds.sa.chunks+offset;

            p=cosmo_nchoosek_partitioner(ds,'half');
            combis=nchoosek(1:nchunks,nchunks/2);

            n=size(combis,1);
            assertEqual(numel(p.train_indices),n/2);
            assertEqual(numel(p.test_indices),n/2);

            for k=1:n/2
                tr_idx=find(cosmo_match(ds.sa.chunks-offset,...
                                                        combis(k,:)));
                te_idx=find(cosmo_match(ds.sa.chunks-offset,...
                                                        combis(n-k+1,:)));

                assertEqual(p.train_indices{k},tr_idx);
                assertEqual(p.test_indices{k},te_idx);
            end
        end
    end

function test_nchoosek_partitioner_grouping()
    for nchunks=[2 5]
        ds=cosmo_synthetic_dataset('nchunks',nchunks,'ntargets',6);
        ds.sa.modality=mod(ds.sa.targets,2)+1;
        ds.sa.targets=floor(ds.sa.targets/2);

        for n_test=1:(nchunks-1)
            for moda_idx=1:4

                if moda_idx==3
                    modas={1 2};
                    moda_arg={1 2};
                elseif moda_idx==4
                    modas={1,2};
                    moda_arg=[];
                else
                    modas={moda_idx};
                    moda_arg=moda_idx;
                end

                n_moda=numel(modas);

                p=cosmo_nchoosek_partitioner(ds,n_test,'modality',...
                                                            moda_arg);
                combis=nchoosek(1:nchunks,n_test);
                n_combi=size(combis,1);

                n_folds=numel(p.train_indices);
                assertEqual(numel(p.test_indices),n_folds);
                assertEqual(n_folds,n_combi*n_moda);

                % each fold must be present exactly once
                visited_count=zeros(1,n_folds);
                for m=1:n_moda
                    for j=1:n_combi
                        tr_msk=~cosmo_match(ds.sa.chunks,combis(j,:)) & ...
                                    ~cosmo_match(ds.sa.modality,modas{m});
                        te_msk=cosmo_match(ds.sa.chunks,combis(j,:)) & ...
                                    cosmo_match(ds.sa.modality,modas{m});
                        tr_idx=find_fold(p.train_indices,tr_msk);
                        te_idx=find_fold(p.test_indices,te_msk);
                        assertEqual(tr_idx,te_idx);
                        visited_count(tr_idx)=visited_count(tr_idx)+1;
                    end
                end

                assertEqual(visited_count,ones(1,n_folds));

                % also possible with indices
                p2=cosmo_nchoosek_partitioner(ds.sa.chunks,n_test,...
                                            ds.sa.modality,moda_arg);
                assertEqual(p,p2);

            end
        end
    end

function pos=find_fold(folds, msk)
    idxs=find(msk);
    n=numel(folds);

    pos=[];
    for k=1:n
        if isequal(sort(folds{k}(:)),sort(idxs(:)))

            % no duplicates
            assert(isempty(pos));
            pos=k;
        end
    end
    assert(~isempty(pos));

function assert_disjoint(vs,i,j)
    common=intersect(vs(i),vs(j));
    if ~isempty(common)
        assertFalse(true,sprintf('element in common: %d', common(1)));

    end
function test_nchoosek_partitioner_exceptions()
    aet=@(varargin)assertExceptionThrown(@()...
                        cosmo_nchoosek_partitioner(varargin{:}),'');
    for nchunks=2:3
        ds=cosmo_synthetic_dataset('nchunks',nchunks,'ntargets',4);

        aet(ds,-1);
        aet(ds,0);
        aet(ds,1.01);
        aet(ds,[1 1]);
        aet(ds,.99);
        aet(struct,1);
        aet(ds,'foo');
        aet(ds,.5,'foo');
        aet(ds,struct);
        aet(ds,1,1,1);
        aet(ds.sa.chunks,1,'chunks',1);
        aet(ds.sa.chunks,1,'chunks',1,'chunks');

        ds.sa.modality=3; % size mismatch
        aet(ds,1,'modality',1);

    end


function t_most_suc(quiet, create_plots, create_pdfs, savedir)
%T_MOST_SUC  Tests of stochastic unit commitment optimizations.
%
%   T_MOST_SUC(QUIET, CREATE_PLOTS, CREATE_PDFS, SAVEDIR)
%   Can generate summary plots and save them as PDFs in a directory of
%   your choice.
%   E.g. t_most_suc(0, 1, 1, '~/Downloads/suc_plots')

%   MOST
%   Copyright (c) 2015-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MOST.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://github.com/MATPOWER/most for more info.

if nargin < 4
    savedir = '.';              %% save in current working directory by default
    if nargin < 3
        create_pdfs = 0;        %% do NOT save plots to PDF files
        if nargin < 2
            create_plots = 0;   %% do NOT create summary plots of results
            if nargin < 1
                quiet = 0;      %% verbose by default
            end
        end
    end
end
if create_plots
    if create_pdfs
        fname = 'suc-ex';
    else
        fname = '';
    end
    pp = 0;     %% plot counter
end

solvers = {'CPLEX', 'GLPK', 'GUROBI', 'MOSEK', 'OT'};
fcn = {'cplex', 'glpk', 'gurobi', 'mosek', 'intlinprog'};
% solvers = {'CPLEX'};
% fcn = {'cplex'};
% solvers = {'OT'};
% fcn = {'intlinprog'};
% solvers = {'GUROBI'};
% fcn = {'gurobi'};
% solvers = {'DEFAULT'};
% fcn = {'most'};
ntests = 37;
t_begin(ntests*length(solvers), quiet);

if quiet
    verbose = 0;
else
    verbose = 0;
end
% verbose = 2;

if have_feature('octave')
    if have_feature('octave', 'vnum') >= 4
        file_in_path_warn_id = 'Octave:data-file-in-path';
    else
        file_in_path_warn_id = 'Octave:load-file-in-path';
    end
    s1 = warning('query', file_in_path_warn_id);
    warning('off', file_in_path_warn_id);
end

casefile = 'ex_case3b';
solnfile =  't_most_suc_soln';
soln = load(solnfile);
mpopt = mpoption;
mpopt = mpoption(mpopt, 'out.gen', 1);
mpopt = mpoption(mpopt, 'verbose', verbose);
% mpopt = mpoption(mpopt, 'opf.violation', 1e-6, 'mips.gradtol', 1e-8, ...
%         'mips.comptol', 1e-8, 'mips.costtol', 1e-8);
mpopt = mpoption(mpopt, 'model', 'DC');
mpopt = mpoption(mpopt, 'most.price_stage_warn_tol', 10);

%% solver options
if have_feature('cplex')
    %mpopt = mpoption(mpopt, 'cplex.lpmethod', 0);       %% automatic
    %mpopt = mpoption(mpopt, 'cplex.lpmethod', 1);       %% primal simplex
    mpopt = mpoption(mpopt, 'cplex.lpmethod', 2);       %% dual simplex
    %mpopt = mpoption(mpopt, 'cplex.lpmethod', 3);       %% network simplex
    %mpopt = mpoption(mpopt, 'cplex.lpmethod', 4);       %% barrier
    mpopt = mpoption(mpopt, 'cplex.opts.mip.tolerances.mipgap', 0);
    mpopt = mpoption(mpopt, 'cplex.opts.mip.tolerances.absmipgap', 0);
    mpopt = mpoption(mpopt, 'cplex.opts.threads', 2);
end
if have_feature('glpk')
    mpopt = mpoption(mpopt, 'glpk.opts.mipgap', 0);
    mpopt = mpoption(mpopt, 'glpk.opts.tolint', 1e-10);
    mpopt = mpoption(mpopt, 'glpk.opts.tolobj', 1e-10);
end
if have_feature('gurobi')
    %mpopt = mpoption(mpopt, 'gurobi.method', -1);       %% automatic
    %mpopt = mpoption(mpopt, 'gurobi.method', 0);        %% primal simplex
    mpopt = mpoption(mpopt, 'gurobi.method', 1);        %% dual simplex
    %mpopt = mpoption(mpopt, 'gurobi.method', 2);        %% barrier
    mpopt = mpoption(mpopt, 'gurobi.threads', 2);
    mpopt = mpoption(mpopt, 'gurobi.opts.MIPGap', 0);
    mpopt = mpoption(mpopt, 'gurobi.opts.MIPGapAbs', 0);
end
if have_feature('mosek')
    sc = mosek_symbcon;
    %mpopt = mpoption(mpopt, 'mosek.lp_alg', sc.MSK_OPTIMIZER_FREE);            %% default
    %mpopt = mpoption(mpopt, 'mosek.lp_alg', sc.MSK_OPTIMIZER_INTPNT);          %% interior point
    %mpopt = mpoption(mpopt, 'mosek.lp_alg', sc.MSK_OPTIMIZER_PRIMAL_SIMPLEX);  %% primal simplex
    mpopt = mpoption(mpopt, 'mosek.lp_alg', sc.MSK_OPTIMIZER_DUAL_SIMPLEX);     %% dual simplex
    %mpopt = mpoption(mpopt, 'mosek.lp_alg', sc.MSK_OPTIMIZER_FREE_SIMPLEX);    %% automatic simplex
    %mpopt = mpoption(mpopt, 'mosek.opts.MSK_DPAR_MIO_TOL_X', 0);
    mpopt = mpoption(mpopt, 'mosek.opts.MSK_IPAR_MIO_NODE_OPTIMIZER', sc.MSK_OPTIMIZER_DUAL_SIMPLEX);
    mpopt = mpoption(mpopt, 'mosek.opts.MSK_IPAR_MIO_ROOT_OPTIMIZER', sc.MSK_OPTIMIZER_DUAL_SIMPLEX);
    mpopt = mpoption(mpopt, 'mosek.opts.MSK_DPAR_MIO_TOL_ABS_RELAX_INT', 1e-9);
    %mpopt = mpoption(mpopt, 'mosek.opts.MSK_DPAR_MIO_TOL_REL_RELAX_INT', 0);
    mpopt = mpoption(mpopt, 'mosek.opts.MSK_DPAR_MIO_TOL_REL_GAP', 0);
    mpopt = mpoption(mpopt, 'mosek.opts.MSK_DPAR_MIO_TOL_ABS_GAP', 0);
end
if have_feature('intlinprog')
    %mpopt = mpoption(mpopt, 'linprog.Algorithm', 'interior-point');
    %mpopt = mpoption(mpopt, 'linprog.Algorithm', 'active-set');
    %mpopt = mpoption(mpopt, 'linprog.Algorithm', 'simplex');
    mpopt = mpoption(mpopt, 'linprog.Algorithm', 'dual-simplex');
    %mpopt = mpoption(mpopt, 'intlinprog.RootLPAlgorithm', 'primal-simplex');
    mpopt = mpoption(mpopt, 'intlinprog.RootLPAlgorithm', 'dual-simplex');
    mpopt = mpoption(mpopt, 'intlinprog.TolCon', 1e-9);
    mpopt = mpoption(mpopt, 'intlinprog.TolGapAbs', 0);
    mpopt = mpoption(mpopt, 'intlinprog.TolGapRel', 0);
    mpopt = mpoption(mpopt, 'intlinprog.TolInteger', 1e-6);
    %% next line is to work around a bug in intlinprog
    % (Technical Support Case #01841662)
    mpopt = mpoption(mpopt, 'intlinprog.LPPreprocess', 'none');
end
if ~verbose
    mpopt = mpoption(mpopt, 'out.all', 0);
end
% mpopt = mpoption(mpopt, 'out.all', -1);

%% define named indices into data matrices
[PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
    VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
[GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
    MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
    QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
[F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
    TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
    ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
[PW_LINEAR, POLYNOMIAL, MODEL, STARTUP, SHUTDOWN, NCOST, COST] = idx_cost;
[CT_LABEL, CT_PROB, CT_TABLE, CT_TBUS, CT_TGEN, CT_TBRCH, CT_TAREABUS, ...
    CT_TAREAGEN, CT_TAREABRCH, CT_ROW, CT_COL, CT_CHGTYPE, CT_REP, ...
    CT_REL, CT_ADD, CT_NEWVAL, CT_TLOAD, CT_TAREALOAD, CT_LOAD_ALL_PQ, ...
    CT_LOAD_FIX_PQ, CT_LOAD_DIS_PQ, CT_LOAD_ALL_P, CT_LOAD_FIX_P, ...
    CT_LOAD_DIS_P, CT_TGENCOST, CT_TAREAGENCOST, CT_MODCOST_F, ...
    CT_MODCOST_X] = idx_ct;

%% load base case file
mpc = loadcase(casefile);

nb = size(mpc.bus, 1);
nl = size(mpc.branch, 1);
ng = size(mpc.gen, 1);

xgd = loadxgendata('ex_xgd_uc', mpc);
[iwind, mpc, xgd] = addwind('ex_wind_uc', mpc, xgd);
profiles_d = getprofiles('ex_wind_profile_d', iwind);
profiles_d = getprofiles('ex_load_profile', profiles_d);
profiles_s = getprofiles('ex_wind_profile', iwind);
profiles_s = getprofiles('ex_load_profile', profiles_s);
nt = size(profiles_d(1).values, 1);

mpc0 = mpc;
xgd0 = xgd;

for s = 1:length(solvers)
    if ~have_feature(fcn{s})    %% check if we have the solver
        t_skip(ntests, sprintf('%s not installed', solvers{s}));
    else
        mpopt = mpoption(mpopt, 'opf.dc.solver', solvers{s});
        mpopt = mpoption(mpopt, 'most.solver', mpopt.opf.dc.solver);
        mpopt = mpoption(mpopt, 'most.storage.cyclic', 1);

        mpc = mpc0;
        xgd = xgd0;

        t = sprintf('%s : deterministic : ', solvers{s});
        mdi = loadmd(mpc, nt, xgd, [], [], profiles_d);
        mdo = most(mdi, mpopt);
        ms = most_summary(mdo);
        t_ok(mdo.QP.exitflag > 0, [t 'success']);
        ex = soln.determ;
        t_is(ms.f, ex.f, 8, [t 'f']);
        t_is(ms.Pg, ex.Pg, 8, [t 'Pg']);
        t_is(ms.Rup, ex.Rup, 8, [t 'Rup']);
        t_is(ms.Rdn, ex.Rdn, 8, [t 'Rdn']);
        t_is(ms.Pf, ex.Pf, 8, [t 'Pf']);
        t_is(ms.u, ex.u, 8, [t 'u']);
        t_is(ms.lamP, ex.lamP, 8, [t 'lamP']);
        t_is(ms.muF, ex.muF, 8, [t 'muF']);
        % determ = most_summary(mdo);
        if create_plots
            pp = pp + 1;
            plot_case('Base : Deterministic', mdo, ms, 500, 150, savedir, pp, fname);
        end
        % keyboard;

        t = sprintf('%s : individual trajectories : ', solvers{s});
        transmat_s = cell(1, nt);
        I = speye(3);
        [transmat_s{:}] = deal(I);
        transmat_s{1} = [ 0.158655253931457; 0.682689492137086; 0.158655253931457 ];
        mdi = loadmd(mpc, transmat_s, xgd, [], [], profiles_s);
        mdi = filter_ramp_transitions(mdi, 0.1);
        mdo = most(mdi, mpopt);
        ms = most_summary(mdo);
        t_ok(mdo.QP.exitflag > 0, [t 'success']);
        ex = soln.transprob1;
        t_is(ms.f, ex.f, 5, [t 'f']);
        t_is(ms.Pg, ex.Pg, 6, [t 'Pg']);
        t_is(ms.Rup, ex.Rup, 6, [t 'Rup']);
        t_is(ms.Rdn, ex.Rdn, 6, [t 'Rdn']);
        t_is(ms.Pf, ex.Pf, 6, [t 'Pf']);
        t_is(ms.u, ex.u, 8, [t 'u']);
        % t_is(ms.lamP, ex.lamP, 5, [t 'lamP']);
        % t_is(ms.muF, ex.muF, 5, [t 'muF']);
        % transprob1 = most_summary(mdo);
        if create_plots
            pp = pp + 1;
            plot_case('Individual Trajectories', mdo, ms, 500, 150, savedir, pp, fname);
        end
        % keyboard;

        t = sprintf('%s : full transition probabilities : ', solvers{s});
%        transmat_sf = transmat_s;
        transmat_sf = ex_transmat(nt);
%         transmat_sf = cell(1, nt);
%         T = [ 0.158655253931457; 0.682689492137086; 0.158655253931457 ];
%         [transmat_sf{:}] = deal(T * ones(1,3));
%         transmat_sf{1} = T;
        mdi = loadmd(mpc, transmat_sf, xgd, [], [], profiles_s);
%        mdi = filter_ramp_transitions(mdi, 0.9);
        mdo = most(mdi, mpopt);
        ms = most_summary(mdo);
        t_ok(mdo.QP.exitflag > 0, [t 'success']);
        ex = soln.transprobfull;
        t_is(ms.f, ex.f, 3, [t 'f']);
        t_is(ms.Pg, ex.Pg, 3, [t 'Pg']);
        t_is(ms.Rup, ex.Rup, 3, [t 'Rup']);
        t_is(ms.Rdn, ex.Rdn, 3, [t 'Rdn']);
        t_is(ms.Pf, ex.Pf, 8, [t 'Pf']);
        t_is(ms.u, ex.u, 8, [t 'u']);
        % t_is(ms.lamP, ex.lamP, 5, [t 'lamP']);
        % t_is(ms.muF, ex.muF, 5, [t 'muF']);
        % transprobfull = most_summary(mdo);
        if create_plots
            pp = pp + 1;
            plot_case('Full Transition Probabilities', mdo, ms, 500, 150, savedir, pp, fname);
        end
        % keyboard;

        t = sprintf('%s : full transition probabilities + cont : ', solvers{s});
        mdi = loadmd(mpc, transmat_sf, xgd, [], 'ex_contab', profiles_s);
%        mdi = filter_ramp_transitions(mdi, 0.9);
        mdo = most(mdi, mpopt);
        ms = most_summary(mdo);
        t_ok(mdo.QP.exitflag > 0, [t 'success']);
        ex = soln.transprobcont;
        t_is(ms.f, ex.f, 3.5, [t 'f']);
        t_is(ms.Pg, ex.Pg, 6, [t 'Pg']);
        t_is(ms.Rup, ex.Rup, 6, [t 'Rup']);
        t_is(ms.Rdn, ex.Rdn, 6, [t 'Rdn']);
        t_is(ms.Pf, ex.Pf, 6, [t 'Pf']);
        t_is(ms.u, ex.u, 8, [t 'u']);
        % t_is(ms.lamP, ex.lamP, 5, [t 'lamP']);
        % t_is(ms.muF, ex.muF, 5, [t 'muF']);
        % transprobcont = most_summary(mdo);
        if create_plots
            pp = pp + 1;
            plot_case('+ Contingencies', mdo, ms, 500, 150, savedir, pp, fname);
        end
        % keyboard;

        t = sprintf('%s : + storage : ', solvers{s});
        if mpopt.out.all
            fprintf('Add storage\n');
        end
        [iess, mpc, xgd, sd] = addstorage('ex_storage', mpc, xgd);
        mdi = loadmd(mpc, transmat_sf, xgd, sd, 'ex_contab', profiles_s);
        mdo = most(mdi, mpopt);
        ms = most_summary(mdo);
        t_ok(mdo.QP.exitflag > 0, [t 'success']);
        ex = soln.wstorage;
        t_is(ms.f, ex.f, 3, [t 'f']);
        t_is(ms.Pg, ex.Pg, 3, [t 'Pg']);
        t_is(ms.Rup, ex.Rup, 3, [t 'Rup']);
        t_is(ms.Rdn, ex.Rdn, 4, [t 'Rdn']);
        t_is(ms.Pf, ex.Pf, 3, [t 'Pf']);
        t_is(ms.u, ex.u, 8, [t 'u']);
        % t_is(ms.lamP, ex.lamP, 5, [t 'lamP']);
        % t_is(ms.muF, ex.muF, 5, [t 'muF']);
        % wstorage = most_summary(mdo);
        if create_plots
            pp = pp + 1;
            plot_case('+ Storage', mdo, ms, 500, 150, savedir, pp, fname);
            create_plots = 0;   %% don't do them again
        end
        % keyboard;
    end
end

if have_feature('octave')
    warning(s1.state, file_in_path_warn_id);
end

t_end;

% save t_most_suc_soln determ transprob1 transprobfull transprobcont wstorage
% determ.u
% transprob1.u
% transprobcont.u
% transprobfull.u
% wstorage.u

function h = plot_case(label, md, ms, maxq, maxp, mypath, pp, fname)

if nargin < 8
    fname = '';
end

%% colors:  blue     red               yellow           purple            green
cc = {[0 0.45 0.74], [0.85 0.33 0.1], [0.93 0.69 0.13], [0.49 0.18 0.56], [0.47 0.67 0.19]};

ig = (1:3)';
id = 4;
iw = 5;
is = 6;

subplot(3, 1, 1);
md.mpc = rmfield(md.mpc, 'genfuel');
plot_uc(md, [], 'title', label);
ylabel('Unit Commitment', 'FontSize', 16);
ah = gca;
ah.YAxisLocation = 'left';

subplot(3, 1, 2);
x = (1:ms.nt)';
Pg = md.results.ExpectedDispatch;
y1 = Pg(ig, :)';
if ms.ng == 6
    y1 = [y1 max(-Pg(is, :), 0)' max(Pg(is, :), 0)'];
end
y2 = -sum(Pg([id; iw], :), 1)';
[ah1, h1, h2] = plotyy(x, y1, x, y2);
axis(ah1(1), [0.5 12.5 0 maxq]);
axis(ah1(2), [0.5 12.5 0 maxq]);
% ah1(1).XLim = [0.5 12.5];
% ah1(2).XLim = [0.5 12.5];
% ah1(1).YLim = [0 300];
% ah1(2).YLim = [0 450];
ah1(1).YTickMode = 'auto';
ah1(2).YTickMode = 'auto';
ah1(1).XTick = 1:12;
nn = 3;
for j = 1:3
    h1(j).LineWidth = 2;
    h1(j).Color = cc{j};
end
if ms.ng == 6
    h1(4).LineWidth = 2;
    h1(4).Color = cc{5};
    h1(4).LineStyle = ':';
    h1(5).LineWidth = 2;
    h1(5).Color = cc{5};
end
h2.LineWidth = 2;
h2.Color = cc{4};
h2.LineStyle = ':';
ah1(2).YColor = cc{4};
%title('Generation & Net Load', 'FontSize', 16);
ylabel(ah1(1), 'Generation, MW', 'FontSize', 16);
ylabel(ah1(2), 'Net Load, MW', 'FontSize', 16);
xlabel('Period', 'FontSize', 16);
set(ah1(1), 'FontSize', 14);
set(ah1(2), 'FontSize', 14);
if ms.ng == 6
    legend('Gen 1', 'Gen 2', 'Gen 3', 'Storage Charge', 'Storage Discharge', 'Location', [0.7 0.6 0 0]);
else
    legend('Gen 1', 'Gen 2', 'Gen 3', 'Location', [0.7 0.58 0 0]);
end

subplot(3, 1, 3);
if length(size(ms.lamP)) == 4
    elamP = sum(sum(ms.lamP, 4), 3) ./ (ones(ms.nb,1) * md.StepProb);
%     elamP = sum(sum(ms.lamP, 4), 3);
elseif length(size(ms.lamP)) == 3
    elamP = sum(ms.lamP, 3);
else
    elamP = ms.lamP;
end

y1 = elamP';
plot(x, y1, 'LineWidth', 2);
% title('Nodal Price', 'FontSize', 16);
ylabel('Nodal Price, $/MWh', 'FontSize', 16);
xlabel('Period', 'FontSize', 16);
axis([0.5 12.5 0 maxp]);
ah = gca;
set(ah, 'FontSize', 14);
ah.XTick = 1:12;
legend('Bus 1', 'Bus 2', 'Bus 3', 'Location', [0.7 0.28 0 0]);

if nargin > 7 && ~isempty(fname)
    h = gcf;
    set(h, 'PaperSize', [11 8.5]);
    set(h, 'PaperPosition', [0.25 0.25 10.5 8]);
    print('-dpdf', fullfile(mypath, sprintf('%s-%d', fname, pp)));
end


function t_most_30b_3_1_0(quiet)
%T_MOST_30B_3_1_0  Tests for MOST.

%   MOST
%   Copyright (c) 2009-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MOST.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://github.com/MATPOWER/most for more info.

if nargin < 1
    quiet = 0;
end

n_tests = 39;

t_begin(n_tests, quiet);

casename = 't_case30_most';
fudging = struct( ...       %% paramters for fudging reserve contract for sopf2
    'fudge',    0.05, ...   %% initial value (MW)
    'step',     0.01, ...   %% if necessary, increase by this amount and retry (MW)
    'lim',      0.1);       %% upper limit (MW), give up if no convergence
                            %% with fudge equal to this limit

%% options
mpopt = mpoption('verbose', 0, 'out.all', 0);
mpopt = mpoption(mpopt, 'opf.violation', 5e-7, 'mips.comptol', 5e-8);
if have_feature('linprog')
    if have_feature('linprog_ds')
        mpopt = mpoption(mpopt, 'linprog.Algorithm', 'dual-simplex');
    else
        mpopt = mpoption(mpopt, 'linprog.Algorithm', 'simplex');
    end
end
mpoptac = mpoption(mpopt, 'model', 'AC');
mpoptdc = mpoption(mpopt, 'model', 'DC');
mpopt = mpoption(mpopt, 'most.solver', 'DEFAULT');

%% turn off warnings
s7 = warning('query', 'MATLAB:nearlySingularMatrix');
s6 = warning('query', 'MATLAB:nearlySingularMatrixUMFPACK');
warning('off', 'MATLAB:nearlySingularMatrix');
warning('off', 'MATLAB:nearlySingularMatrixUMFPACK');

%% define named indices into data matrices
[PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
    VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
[GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
    MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
    QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
[F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
    TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
    ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
[CT_LABEL, CT_PROB, CT_TABLE, CT_TBUS, CT_TGEN, CT_TBRCH, CT_TAREABUS, ...
    CT_TAREAGEN, CT_TAREABRCH, CT_ROW, CT_COL, CT_CHGTYPE, CT_REP, ...
    CT_REL, CT_ADD, CT_NEWVAL, CT_TLOAD, CT_TAREALOAD, CT_LOAD_ALL_PQ, ...
    CT_LOAD_FIX_PQ, CT_LOAD_DIS_PQ, CT_LOAD_ALL_P, CT_LOAD_FIX_P, ...
    CT_LOAD_DIS_P, CT_TGENCOST, CT_TAREAGENCOST, CT_MODCOST_F, ...
    CT_MODCOST_X] = idx_ct;

%% reserve and delta offers
xgd_table.colnames = {
    'PositiveActiveReservePrice', ...
            'PositiveActiveReserveQuantity', ...
                    'NegativeActiveReservePrice', ...
                            'NegativeActiveReserveQuantity', ...
                                    'PositiveActiveDeltaPrice', ...
                                            'NegativeActiveDeltaPrice', ...
};
xgd_table.data = [
    10.1    15      10.0    15      0.1     0.0;
    10.3    30      10.2    30      0.3     0.2;
    10.5    20      10.4    20      0.5     0.4;
    10.7    25      10.6    25      0.7     0.6;
    20.1    25      20.0    25      60.1    60.0;
    20.3    15      20.2    15      15.1    15.0;
    20.5    30      20.4    30      60.3    60.2;
    20.7    15      20.6    15      15.3    15.2;
    30.1    15      30.0    15      60.3    60.4;
    30.3    30      30.2    30      30.1    30.0;
    30.5    25      30.4    25      60.7    60.6;
    30.7    30      30.6    30      30.3    30.2;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
    0.001   50      0.002   50      0       0;
];

%% contingency table
% label probty  type        row column      chgtype newvalue
contab = [
%     1   0.002   CT_TBRCH    1   BR_STATUS   CT_REP  0;      %% line 1-2
%     2   0.002   CT_TBRCH    2   BR_STATUS   CT_REP  0;      %% line 1-3, all power from gen1 flows via gen2
%     3   0.002   CT_TBRCH    3   BR_STATUS   CT_REP  0;      %% line 2-4, a path to loads @ buses 7 & 8
%     4   0.002   CT_TBRCH    5   BR_STATUS   CT_REP  0;      %% line 2-5, a path to loads @ buses 7 & 8
%     5   0.002   CT_TBRCH    6   BR_STATUS   CT_REP  0;      %% line 2-6, a path to loads @ buses 7 & 8
%     6   0.002   CT_TBRCH    36  BR_STATUS   CT_REP  0;      %% line 28-27, tie line between areas 1 & 3
%     7   0.002   CT_TBRCH    15  BR_STATUS   CT_REP  0;      %% line 4-12, tie line between areas 1 & 2
%     8   0.002   CT_TBRCH    12  BR_STATUS   CT_REP  0;      %% line 6-10, tie line between areas 1 & 3
%     9   0.002   CT_TBRCH    14  BR_STATUS   CT_REP  0;      %% line 9-10, tie line between areas 1 & 3
%     10  0.002   CT_TGEN     1   GEN_STATUS  CT_REP  0;      %% gen 1 at bus 1
%     11  0.002   CT_TGEN     2   GEN_STATUS  CT_REP  0;      %% gen 2 at bus 2
%     12  0.002   CT_TGEN     3   GEN_STATUS  CT_REP  0;      %% gen 3 at bus 22
%     13  0.002   CT_TGEN     4   GEN_STATUS  CT_REP  0;      %% gen 4 at bus 27
%     14  0.002   CT_TGEN     5   GEN_STATUS  CT_REP  0;      %% gen 5 at bus 23
%     15  0.002   CT_TGEN     6   GEN_STATUS  CT_REP  0;      %% gen 6 at bus 13
%     20  0.010   CT_TGEN     0   PMIN        CT_REL  1.1;    %% 10% load increase
%     20  0.010   CT_TGEN     0   QMIN        CT_REL  1.1;
%     21  0.010   CT_TGEN     0   PMIN        CT_REL  0.9;    %% 10% load decrease
%     21  0.010   CT_TGEN     0   QMIN        CT_REL  0.9;
];
clist = [];
nc = length(clist);

%% load the case
mpc = loadcase(casename);
gbus = mpc.gen(:, GEN_BUS);
mpc.gen(:, RAMP_30) = Inf;      %% avoid binding ramp reserves in period 1

%%-----  get OPF results  -----
rdc = rundcopf(mpc, mpoptdc);
% rac = runopf(mpc, mpoptac);
% save t_most4_soln rdc rac -v6
% s = load('t_most4_soln');
s.rdc = rdc;
% s.rac = rac;

%%-----  set up data for DC run (most)  -----
ng = size(mpc.gen, 1);      %% number of gens
nt = 3;
xgd = loadxgendata(xgd_table, mpc);
md = loadmd(mpc, nt, xgd);

%%-----  do DC run (most)  -----
r = most(md, mpopt);

%%-----  test the results  -----
t = 'success1';
t_ok(s.rdc.success, t);
t = 'success2';
t_is(r.QP.exitflag, 1, 12, t);

t = 'f';
t_is(r.results.f/sum(r.StepProb), s.rdc.f, 4, t);

for tt = 1:nt

t = sprintf('(t=%d) Pg : base', tt);
t_is(r.flow(tt,1,1).mpc.gen(:, PG), s.rdc.gen(:, PG), 5, t);

t = sprintf('(t=%d) gen : base', tt);
t_is(r.flow(tt,1,1).mpc.gen(:,1:MU_PMIN), s.rdc.gen(:,1:MU_PMIN), 3, t);

t = sprintf('(t=%d) energy prices', tt);
t_is(r.results.GenPrices(:,tt), s.rdc.bus(gbus, LAM_P), 6, t);

t = sprintf('(t=%d) Pc', tt);
t_is(r.results.Pc(:,tt), s.rdc.gen(:, PG), 4, t);

t = sprintf('(t=%d) Gmin', tt);
t_is(r.results.Pc(:,tt) - r.results.Rpm(:,tt), s.rdc.gen(:, PG), 4, t);

t = sprintf('(t=%d) Gmax', tt);
t_is(r.results.Pc(:,tt) + r.results.Rpp(:,tt), s.rdc.gen(:, PG), 4, t);

t = sprintf('(t=%d) upward contingency reserve quantities', tt);
t_is(r.results.Rpp(:,tt), zeros(ng, 1), 4, t);

t = sprintf('(t=%d) downward contingency reserve quantities', tt);
t_is(r.results.Rpm(:,tt), zeros(ng, 1), 4, t);

t = sprintf('(t=%d) upward contingency reserve prices', tt);
t_is(r.results.RpmPrices(:,tt), xgd.NegativeActiveReservePrice, 6, t);

t = sprintf('(t=%d) downward contingency reserve prices', tt);
t_is(r.results.RpmPrices(:,tt), xgd.NegativeActiveReservePrice, 6, t);

t = sprintf('(t=%d) Rpmax_pos', tt);
vv = r.om.get_idx();
Rpmax_pos = (r.QP.lambda.upper(vv.i1.Rpp(tt):vv.iN.Rpp(tt)) - r.QP.lambda.lower(vv.i1.Rpp(tt):vv.iN.Rpp(tt))) / mpc.baseMVA;
t_is(Rpmax_pos, zeros(ng, 1), 6, t);

t = sprintf('(t=%d) Rpmax_neg', tt);
Rpmax_neg = (r.QP.lambda.upper(vv.i1.Rpm(tt):vv.iN.Rpm(tt)) - r.QP.lambda.lower(vv.i1.Rpm(tt):vv.iN.Rpm(tt))) / mpc.baseMVA;
t_is(Rpmax_neg, zeros(ng, 1), 6, t);

end

% g1 = s.rdc.base.gen(:, PG);
% g2 = r.flow(1,1,1).mpc.gen(:, PG);
% for k = 1:nc
%     g1 = [ g1 s.rdc.cont(k).gen(:, PG) ];
%     g2 = [ g2 r.flow(1,1,k+1).mpc.gen(:, PG) ];
% end
% [m,n] = size(g1);
% for j = 1:n
%     fprintf('\n');
%     for i = 1:m
%         fprintf('%9.2f  %9.2f\n', g1(i,j), g2(i,j));
%     end
% end

%%-----  do AC run (most)  -----
%mostac;

%% turn warnings back on
warning(s7.state, 'MATLAB:nearlySingularMatrix');
warning(s6.state, 'MATLAB:nearlySingularMatrixUMFPACK');

t_end;


classdef ParamDCLFDCBF < handle
    properties
        alpha
        gamma
        P % weight for Lyapunov function
        uWeight
        sWeight
    end
    methods
        function self = ParamDCLFDCBF(alpha, gamma, P, u_weight, s_weight)
            self.alpha = alpha;
            self.gamma = gamma;
            self.P = P;
            self.uWeight = u_weight;
            self.sWeight = s_weight;
        end
    end
end


function ctf = sortrtctf(ctfds)

RESPTHRESH = 10^7;

if nargin < 1
    ctfds = '';
end

ctf = ctf_read(ctfds);

stim_chan = find(strcmp(ctf.sensor.label,'STIM'));

if (length(stim_chan) == 1)
    stim_data = ctf.data(:,stim_chan,:);
else
    error('ERROR: could not properly locate STIM channel');
end

RTs = [];
for i = 1:size(stim_data,3)
    tmp = stim_data(:,1,i);
    RTs(end+1) = min(find(tmp > RESPTHRESH));
end

[RTs_sorted,RTsx] = sort(RTs);

ctf.data = ctf.data(:,:,RTsx);


function r = subsasgn(r,s,b)
%SUBSASGN     Implements subscripted assignments for hessians
%
%  example  r(2,:) = b
%

% written  04/04/04     S.M. Rump
% modified 04/06/05     S.M. Rump  rounding unchanged
% modified 05/09/07     S.M. Rump  assignment r(:)=...
% modified 08/26/12     S.M. Rump  global variables removed
% modified 09/26/12     S.M. Rump  index handling (thanks to Matthew Weinstein)
%

  N = getappdata(0,'INTLAB_HESSIAN_NUMVAR');

  if length(s)>1
    error('multiple indexing for hessian assignment not allowed')
  end

  if strcmp(s.type,'()')     % assignment r(i) = b

    rEmpty = isempty(r);     % assignment r(i) = b for empty r
    if isempty(b)
      % does not work in Matlab 5.3 for sparse r
      r.x(s.subs{:}) = [];
      value = zeros(size(r.x));
      value(s.subs{:}) = 1;
      index = find(value);
      r.dx( : , index ) = [];
      r.hx( : , index ) = [];
      return
    end

    if ~isa(b,'hessian')
      b = hessian(b);
    end

    if ~rEmpty
      resultIsintval = isa(r.x,'intval');
      if ~resultIsintval & isa(b.x,'intval')
        r = intval(r);
        resultIsintval = 1;
      end
      sizeincreased = 0;
      if length(s.subs)==1              % single index
        if ~isequal(s.subs{1},':')      % not r(:)=...
          if size(r.x,1)==1             % row vector
            sizeincreased = ( s.subs{1}>size(r.x,2) );
          else
            sizeincreased = ( s.subs{1} > prod(size(r.x)) );
          end
          if sizeincreased
            srx = size(r.x);
            if length(srx)==2
              if all(prod(srx)~=srx)
                error('matrix cannot be resized by assignment a(I) = b')
              end
            else
              error('attempt to grow size of array along ambiguous dimension')
            end
          end
        end
      else                            % multiple index
        for i=1:length(s.subs)
          if ~isequal(s.subs{i},':')
            sizeincreased = sizeincreased | ( s.subs{i} > size(r.x,i) );
          end
        end
      end
      if sizeincreased                % size increased, adapt .x and .dx and .hx
        rx = r.x;
        rdx = r.dx;
        rhx = r.hx;
        value = ones(size(r.x));
        value( s.subs{:} ) = 0;
        r.x = zeros(size(value));
        INTLAB_HESSIAN_SPARSE = getappdata(0,'INTLAB_HESSIAN_SPARSE');
        if N<INTLAB_HESSIAN_SPARSE
          r.dx = zeros(N,prod(size(value)));
          r.hx = zeros(N*N,prod(size(value)));
        else
          r.dx = sparse([],[],[],N,prod(size(value)));
          r.hx = sparse([],[],[],N*N,prod(size(value)));
      end
        if resultIsintval
          r.x = intval(r.x);
          r.dx = intval(r.dx);
          r.hx = intval(r.hx);
        end
        index = find(value);
        r.x( index ) = rx;
        r.dx( : , index ) = rdx;
        r.hx( : , index ) = rhx;
      end
    else                     % assignment r(i) = b for empty r
      resultIsintval = isa(b.x,'intval');
      r.x(s.subs{:}) = 0;
      INTLAB_HESSIAN_SPARSE = getappdata(0,'INTLAB_HESSIAN_SPARSE');
      if N<INTLAB_HESSIAN_SPARSE
        r.dx = zeros(N,prod(size(r.x)));
        r.hx = zeros(N*N,prod(size(r.x)));
      else
        r.dx = sparse([],[],[],N,prod(size(r.x)));
        r.hx = sparse([],[],[],N*N,prod(size(r.x)));
      end
      if resultIsintval
        r.x = intval(r.x);
        r.dx = intval(r.dx);
        r.hx = intval(r.hx);
      end
    end
    r.x( s.subs{:} ) = b.x;
    value = reshape(1:prod(size(r.x)),size(r.x));
    index = value( s.subs{:} );
    if ( prod(size(b.x))==1 ) & ( length(index)~=1 )
      r.dx(:,index) = b.dx(:,ones(1,length(index)));
      r.hx(:,index) = b.hx(:,ones(1,length(index)));
    else
      r.dx(:,index) = b.dx;
      r.hx(:,index) = b.hx;
    end
    if rEmpty
      r = class(r,'hessian');
    end
  else
    error('invalid index reference for hessian')
  end

  % avoid Matlab 6.5f bug:
  % a = sparse([],[],[],1,1); a = reshape(a,1,1); abs(a)
  % produces  9.6721e-317  or similar number in underflow range
  if prod(size(r.x))==1
    r.x = full(r.x);
  end
  if prod(size(r.dx))==1
    r.dx = full(r.dx);
  end
  if prod(size(r.hx))==1
    r.hx = full(r.hx);
  end