function export_mri( BstMriFile, OutputMriFile )
% EXPORT_MRI: Export a MRI to one of the supported file formats.
%
% USAGE:  export_mri( BstMriFile, OutputMriFile=[ask] )
%         export_mri( sMri,       OutputMriFile=[ask] )
% INPUT:
%     - BstMriFile    : Full path to input Brainstorm MRI file to be exported
%     - sMri          : Brainstorm MRI structure
%     - OutputMriFile : Full path to target file (extension will determine the format)

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

% ===== PARSE INPUTS =====
if (nargin < 1) || isempty(BstMriFile)
    error('Brainstorm:InvalidCall', 'Invalid use of export_mri()');
end
if (nargin < 2)
    OutputMriFile = [];
end

% ===== LOAD MRI FILE =====
% Show progress bar
isProgress = bst_progress('isVisible');
if ~isProgress
    bst_progress('start', 'Export MRI', 'Loading input file');
end
% Load MRI
if ischar(BstMriFile)
    sMri = in_mri_bst(BstMriFile);
else
    sMri = BstMriFile;
    BstMriFile = [];
end
if ~isProgress
    bst_progress('stop');
end

% ===== SELECT OUTPUT FILE =====
if isempty(OutputMriFile)
    % Get default directories and formats
    LastUsedDirs = bst_get('LastUsedDirs');
    DefaultFormats = bst_get('DefaultFormats');
    % Export extension
    if isempty(DefaultFormats.MriOut)
        DefaultFormats.MriOut = 'Analyze';
    end
    switch DefaultFormats.MriOut
        case 'GIS',     ExportExt = '.ima';
        case 'Analyze', ExportExt = '.img';
        case 'CTF',     ExportExt = '.mri';
        case 'Nifti1',  ExportExt = '.nii';
        case 'FT-MRI',  ExportExt = '.mat';
        otherwise,      ExportExt = '.nii';
    end
    % Build default output filename
    if ~isempty(BstMriFile)
        [BstPath, BstBase, BstExt] = bst_fileparts(BstMriFile);
    else
        BstBase = 'export';
    end
    DefaultOutputFile = bst_fullfile(LastUsedDirs.ExportAnat, [BstBase, ExportExt]);
    DefaultOutputFile = strrep(DefaultOutputFile, '_subjectimage', '');
    DefaultOutputFile = strrep(DefaultOutputFile, 'subjectimage_', '');
    % Put MRI file
    [OutputMriFile, FileFormat, FileFilter] = java_getfile( 'save', ...
        'Export MRI...', ...             % Window title
        DefaultOutputFile, ...       % Default directory
        'single', 'files', ...           % Selection mode
        bst_get('FileFilters', 'mriout'), ...
        DefaultFormats.MriOut);
    % If no file was selected: exit
    if isempty(OutputMriFile)
        return
    end
    % Save new default export path
    LastUsedDirs.ExportAnat = bst_fileparts(OutputMriFile);
    bst_set('LastUsedDirs', LastUsedDirs);
    % Save default export format
    DefaultFormats.MriOut = FileFormat;
    bst_set('DefaultFormats',  DefaultFormats);
end

% ===== SAVE MRI =====
[OutputPath, OutputBase, OutputExt] = bst_fileparts(OutputMriFile);
% Show progress bar
if ~isProgress
    bst_progress('start', 'Export MRI', ['Export MRI to file "' [OutputBase, OutputExt] '"...']);
end
% Switch between file formats
switch lower(OutputExt)
    case '.ima'
        out_mri_gis(sMri, OutputMriFile);
    case {'.img', '.nii'}
        out_mri_nii(sMri, OutputMriFile);
    case '.mri'
        out_mri_ctf(sMri, OutputMriFile);
    case '.mat'
        ftMri = out_fieldtrip_mri(sMri);
        bst_save(OutputMriFile, ftMri, 'v7');
    otherwise
        error(['Unsupported file extension : "' OutputExt '"']);
end
% Hide progress bar
if ~isProgress
    bst_progress('stop');
end


classdef TestMedianBlur
    %TestMedianBlur

    properties (Constant)
        im = fullfile(mexopencv.root(),'test','blox.jpg');
    end

    methods (Static)
        function test_1
            img = imread(TestMedianBlur.im);
            result = cv.medianBlur(img);
            validateattributes(result, {class(img)}, {'size',size(img)});
        end

        function test_2
            img = imread(TestMedianBlur.im);
            result = cv.medianBlur(img, 'KSize',7);
            validateattributes(result, {class(img)}, {'size',size(img)});
        end

        function test_3
            img = imread(fullfile(mexopencv.root(),'test','fruits.jpg'));
            result = cv.medianBlur(img, 'KSize',11);
            validateattributes(result, {class(img)}, {'size',size(img)});
        end

        function test_error_argnum
            try
                cv.medianBlur();
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end
    end

end


function p = emptyNumericalModel;
p.F_struc = [];
p.K.f = 0;
p.K.l = 0;
p.K.q = 0;
p.K.s = 0;


function stop = optiplotfval(iter,fval,~)
%OPTIPLOTVAL  Plot objective vs iterations
%
%   Default plotting callback for scalar objectives
%
%   Based on MATLAB's optimplotfval

persistent liter

%Ensure always create a new plot
if(isempty(liter))
    liter = Inf;
end

%Never stop from this function
stop = false;

%Only plot scalars
if(length(fval) > 1)
    fval = norm(fval);
end

%Check for new solver run
if(iter <= liter)
    h = plot(iter,fval,'b*');
    title(sprintf('Current Function Value: %g',fval));
    xlabel('Iteration /  Function Evaluation');
    set(h,'Tag','optiplotf1');
    ylabel('Function Value')
else
    h = findobj(get(gca,'Children'),'Tag','optiplotf1');
    newX = [get(h,'Xdata') iter];
    newY = [get(h,'Ydata') fval];
    set(h,'Xdata',newX, 'Ydata',newY);
    set(get(gca,'Title'),'String',sprintf('Current Function Value: %g',fval));
end

%Save for future comparison
liter = iter;

%Call drawnow to refresh the screen
drawnow;


classdef substrTest < TestCase
    methods
        function this = substrTest(methodName)
            this = this@TestCase(methodName);
        end

        function testEmptyString(~)
            s = '';
            assertEqual(s(1:0), substr('', 1, 0));
            assertExceptionThrown(@() substr('', 1, 1), 'MATLAB:badsubscript');
            assertExceptionThrown(@() substr('', 0, 0), 'MATLAB:badsubscript');
        end

        function testWholeString(~)
            assertEqual('abc', substr('abc', 1, 0));
        end

        function testPartOfString(~)
            assertEqual('bc', substr('abcd', 2, 3));
        end

        function testPartOfStringFromEnd(~)
            assertEqual('bc', substr('abcd', 2, -1));
        end
    end
end

function result = substr(s, i, j)
    result = edu.stanford.covert.util.substr(s, i, j);
end


function reconstruct(obj, varargin)
% RECONSTRUCT Remove deactivated points from object.
% ------------------------------------------------------------------------------
% OUTPUT
% 1 [obj]
%   Updated object without deactivated points.
% ------------------------------------------------------------------------------
% EXAMPLES
% 1 Thin out of point cloud.
%   pc = pointCloud('Lion.xyz');
%   pc.select('UniformSampling', 2);
%   pc.reconstruct;
% ------------------------------------------------------------------------------
% philipp.glira@gmail.com
% ------------------------------------------------------------------------------

% Start ------------------------------------------------------------------------

procHierarchy = {'POINTCLOUD' 'RECONSTRUCT'};
msg('S', procHierarchy);
msg('I', procHierarchy, sprintf('Point cloud label = ''%s''', obj.label));

% Create new object with only active points ------------------------------------

% Remove deactivated points from coordinates
obj.X = obj.X(obj.act,:);

% Remove deactivated points from attributes
if isstruct(obj.A)

    % Note: attributes can not be updated field by field due to validation
    % function 'set.A' in pointCloud

    A = obj.A;  % OLD attribute structure
    obj.A = []; % NEW attribute structure

    % Fill NEW attribute structure with values from OLD attribute structure
    att = fields(A);
    for a = 1:numel(att)
        obj.A.(att{a}) = A.(att{a})(obj.act);
        A = rmfield(A, att{a}); % save memory
    end

end

% Update act vector
obj.act = obj.act(obj.act);

% End --------------------------------------------------------------------------

msg('E', procHierarchy);

end


function MIMICII_data_importer
% MIMICII_data_importer imports data from the MIMIC II database for use
% with RRest, a toolbox of respiratory rate algorithms.
%
%               MIMICII_data_importer
%
%	Inputs:
%       none
%                       just specify the relevant paths in the
%                       "universal_parameters" function below.
%
%	Outputs:
%       a single file containing all the data is written to the path
%       specified by "up.paths.analysis_path".
%
%   Requirements:
%       This requires the WFDB Toolbox, which can be downloaded from:
%           https://physionet.org/physiotools/matlab/wfdb-app-matlab/
%       data download is performed automatically using the script below.
%
%   Further Information:
%       This version of the MIMICII_data_importer is provided to facilitate
%       reproduction of the analysis performed in:
%           Charlton P.H. et al., "Waveform Analysis to Estimate
%           Respiratory Rate" [In Press]
%       Further information on this study can be obtained at:
%           http://peterhcharlton.github.io/RRest/waveform_analysis.html
%       In addition, further information on RRest, including future
%       versions, can be obtained at:
%           http://peterhcharlton.github.io/RRest/index.html
%
%   Comments, Questions, Criticisms, Feedback, Contributions:
%       See: http://peterhcharlton.github.io/RRest/contributions.html
%
%   Version:
%       v.1 - published on 23rd Feb 2016 by Peter Charlton
%
%   Licence:
%       please see the accompanying file named "LICENSE"
%

%% Setup
up = universal_parameters;

%% Download data
download_data(up);

%% Identify patient stays
pt_stays = identify_pt_stays(up);

%% Extract data from files on computer
data = extract_from_mimic_ii(pt_stays, up);

%% Save data in common format
save_data_in_common_format(data, up);

%% Identify sub-groups of neonates and adults
% This isn't necessary to obtain the data, but creates a plot used in the
% book chapter.
results = sub_group_identification(up);

end

function up = universal_parameters

fprintf('\n -- Setting up Universal Parameters')

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%% PARAMETERS TO BE SPECIFIED %%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Specify the root data directory (where the data will be stored)
up.paths.data_root = 'C:\Documents\Data\mimicii\';
up.paths.data_save_folder = 'C:\Documents\Data\';

% Specify the web address of the data to be downloaded
rel_database = 'mimic2wdb';
up.paths.database_dir = ['http://physionet.org/physiobank/database/', rel_database];

% Please note that your system may require the slashes in file paths to be
% of the opposite direction. In which case, change the following:
slash = '\';

% if you want .eps illustrations, then do as follows:
up.eps_figs = 0;  % set this to 1
if up.eps_figs
    % download 'export_fig' from:
    % http://uk.mathworks.com/matlabcentral/fileexchange/23629-export-fig
    % add the path of your download:
    export_fig_dir_path = 'C:\Users\pc13\Documents\GitHub\phd\Tools\Other Scripts\export_fig\';
    addpath(export_fig_dir_path)
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%   OTHER PARAMETERS   %%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%   (don't need editing)   %%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% extraction definitions
up.extraction.period = 600;    % period of waveform data to extract (in s)
up.extraction.rel_sigs = {'II', 'PLETH', 'RESP'};    % required signals
up.extraction.rel_nums = {'HR', 'PULSE', 'RESP'};    % required numerics
up.no_pt_stays = 100;

% database definitions
up.mimic_db.version = 3;
up.mimic_db.part = 0;

% paths
up.paths.file_location = [up.paths.data_root, 'physionet.org\physiobank\database\', rel_database, '\', num2str(up.mimic_db.version), num2str(up.mimic_db.part), '\'];
up.paths.analysis_path = [up.paths.data_root, 'Analysis_files', slash 'Data_for_Analysis', slash ];
up.paths.plots = [up.paths.data_root, 'Analysis_files', slash 'Results', slash 'Figures', slash ];
up.paths.records_filepath = [up.paths.analysis_path, 'RECORDS'];

% url paths
up.paths.url.records = [up.paths.database_dir, '/', num2str(up.mimic_db.version), num2str(up.mimic_db.part), '/', 'RECORDS'];

% Add all functions within the directory
addpath(genpath(fileparts(mfilename('fullpath'))));

% check that all the required folders exist. If not, create them:
req_folders = {up.paths.data_root, up.paths.analysis_path, up.paths.plots};
displayed_msg = 0;
for req_folder_no = 1 : length(req_folders)
    curr_folder = req_folders{req_folder_no};
    if ~exist(curr_folder, 'dir')
        if displayed_msg == 0
            fprintf('\n -- Creating folder in which to store data and analysis')
            displayed_msg = 1;
        end
        mkdir(curr_folder)
    end
end

% Check that the WFDB Matlab Toolbox has been installed
if ~exist('getWfdbClass', 'file')
    error('Couldn''t find the WFDB Matlab Toolbox. Please install as described at the top of the file.')
end

end

function download_data(up)

fprintf('\n -- Downloading Data')

%% set current directory to that of wget:
cd(up.paths.data_root)

%% Find out what records are available:
% download list of records
outfilename = websave(up.paths.records_filepath,up.paths.url.records);

% form list of records from downloaded file
records = load(up.paths.records_filepath);

%% Download each record
rel_records = records(1:up.no_pt_stays);

for rec_no = 1 : length(rel_records)

    % specify record
    record = rel_records(rec_no);

    % specify download location
    down_loc = [up.paths.database_dir, '/', num2str(up.mimic_db.version), num2str(up.mimic_db.part), '/', num2str(record), '/', 'RECORDS'];

    % set save location
    save_folder = [up.paths.file_location, num2str(record), '\'];
    save_loc = [save_folder, 'RECORDS'];
    if ~exist(save_folder, 'dir')
        mkdir(save_folder)
    end

    % download RECORDS file for this record
    outfilename = websave(save_loc,down_loc);

    % find out what individual files are in this record:
    fileID = fopen(save_loc);
    file_names = textscan(fileID, '%s %*[^\n]'); file_names = file_names{1};
    fclose(fileID);

    for file_no = 1 : length(file_names)

        % download header file
        curr_file_name = [file_names{file_no}, '.hea'];
        down_loc = [up.paths.database_dir, '/', num2str(up.mimic_db.version), num2str(up.mimic_db.part), '/', num2str(record), '/', curr_file_name];
        save_loc = [save_folder, curr_file_name];
        outfilename = websave(save_loc,down_loc);

        if ~strcmp(file_names{file_no}, num2str(record))
            % also download data file
            curr_file_name = [file_names{file_no}, '.dat'];
            down_loc = [up.paths.database_dir, '/', num2str(up.mimic_db.version), num2str(up.mimic_db.part), '/', num2str(record), '/', curr_file_name];
            save_loc = [save_folder, curr_file_name];
            outfilename = websave(save_loc,down_loc);
        end
    end

end

end

function pt_stays = identify_pt_stays(up)

fprintf('\n -- Identifying Patient Stays')

% Folders (each one is a patient stay)
dirs = dir(up.paths.file_location);

elim_els = ones(length(dirs),1);
for s = 1:length(dirs)
    if length(dirs(s).name) < 3
        elim_els(s) = 0;
    end
end

dirs = dirs(logical(elim_els'));

pt_stays = extractfield(dirs, 'name');

end

function data = extract_from_mimic_ii(pt_stays, up)
%
% Based on RDSAMP, part of the WFDB Toolbox. Further details are available
% at:
%       http://physionet.org/physiotools/matlab/wfdb-app-matlab/
%
% Reads MIMIC II data and outputs it as a structure of .t and .v values.

fprintf('\n -- Extracting Data from MIMIC II files')

if up.no_pt_stays > length(pt_stays)
    warning('There are fewer ICU stay datasets than requested')
end
no_pt_stays = min([up.no_pt_stays, length(pt_stays)]);

extraction_stats.no_pt_stays = no_pt_stays;
extraction_stats.no_records_searched = 0;
extraction_stats.no_records_without_signals = 0;
extraction_stats.no_records_without_num = 0;
extraction_stats.no_records_with_sigs_and_num = 0;

for pt_stay_no = 1 : no_pt_stays

    % set current dir
    dir_path = [up.paths.file_location, pt_stays{pt_stay_no}, '\'];
    cd(dir_path)

    % check to see if there are any files
    temp = dir([dir_path, pt_stays{pt_stay_no}, '_0*.hea']);
    if ~isempty(temp)
        records = extractfield(temp, 'name'); clear temp
    else
        extraction_stats.no_records_searched = extraction_stats.no_records_searched+1;
        extraction_stats.no_records_without_signals = extraction_stats.no_records_without_signals+1;
        continue
    end
    clear dir_path

    remaining_time_to_extract = up.extraction.period;

    for record_no = 1 : length(records)

        % setup java
        persistent javaWfdbExec config
        if(isempty(javaWfdbExec))
            [javaWfdbExec,config]=getWfdbClass('rdsamp');
        end

        %Remove file extension
        record_str = records{record_no}(1:(end-4));

        % Extract file information (including which signals are present)
        [siginfo,Fs]=extract_file_info(record_str);

        % Identify relevant signals
        sig_inds = 1:siginfo.no_sigs;
        sig_log = zeros(length(sig_inds),1);
        for sig_no = 1 : length(sig_inds)
            if sum(strcmp(up.extraction.rel_sigs, siginfo.sig_names(sig_no)))
                sig_log(sig_no) = 1;
            end
        end

        % skip if this doesn't have both the required signals
        if sum(sig_log) ~= length(up.extraction.rel_sigs)
            clear current_waves extracted_data Fs ListCapacity siginfo signalList javaWfdbExec config wfdb_argument
            continue
        end

        % create wfdb argument
        N0 = 1;
        wfdb_argument={'-r',record_str,'-Ps','-f',['s' num2str(N0-1)]};

        % Make command to only extract the required signals
        signalList = sig_inds(logical(sig_log));
        if(~isempty(signalList))
            wfdb_argument{end+1}='-s ';
            %-1 is necessary because WFDB is 0 based indexed.
            for sInd=1:length(signalList)
                wfdb_argument{end+1}=[num2str(signalList(sInd)-1)];
            end
        end

        % determine how many samples to extract from this file
        remaining_samples_to_extract = remaining_time_to_extract*Fs;
        N=siginfo.no_samps;
        if remaining_samples_to_extract < N
            N = remaining_samples_to_extract;
        end
        remaining_time_to_extract = remaining_time_to_extract - (N/Fs);

        % skip if we don't require any more data
        if N == 0
            clear current_waves extracted_data Fs ListCapacity siginfo signalList javaWfdbExec config wfdb_argument
            break
        end

        % additional bits of wfdb_argument
        wfdb_argument{end+1}='-t';
        wfdb_argument{end+1}=['s' num2str(N)];

        % extract data
        extracted_data=javaWfdbExec.execToDoubleArray(wfdb_argument);
        clear wfdb_argument

        %% Re-format data for output

        waves.fs = siginfo.fs;

        % store this new bit of the wave
        current_waves = fieldnames(waves);
        signalNames = siginfo.sig_names(signalList);
        for wave_no = 1 : length(up.extraction.rel_sigs)
            rel_sig_ind = find(strcmp(signalNames, up.extraction.rel_sigs{wave_no}));
            if ~strcmp(current_waves, up.extraction.rel_sigs{wave_no})
                eval(['waves.' up.extraction.rel_sigs{wave_no} '.t = extracted_data(:, 1);']);
                eval(['waves.' up.extraction.rel_sigs{wave_no} '.v = extracted_data(:, rel_sig_ind+1);']);
            else
                eval(['current_last_time = waves.' up.extraction.rel_sigs{wave_no} '.t(end);']);
                eval(['waves.' up.extraction.rel_sigs{wave_no} '.t = [waves.' up.extraction.rel_sigs{wave_no} '.t; current_last_time + (1/Fs) + extracted_data(:, 1)];']);
                eval(['waves.' up.extraction.rel_sigs{wave_no} '.v = [waves.' up.extraction.rel_sigs{wave_no} '.v; extracted_data(:, rel_sig_ind+1)];']);
            end
        end
        clear current_waves extracted_data Fs ListCapacity siginfo signalList javaWfdbExec config

    end

    %% Extract corresponding numerics

    if exist('waves', 'var')

        % setup java
        persistent javaWfdbExec_num config_num
        if(isempty(javaWfdbExec_num))
            [javaWfdbExec_num,config_num]=getWfdbClass('rdsamp');
        end

        filepath = [pt_stays{pt_stay_no}, 'n'];

        if exist([up.paths.file_location, pt_stays{pt_stay_no}, '\', filepath, '.hea'], 'file')

            % Extract file information (including which signals are present)
            [numinfo,Fs]=extract_file_info(filepath);
            loc = numinfo.loc;

            % Identify relevant numerics
            num_inds = 1:numinfo.no_sigs;
            num_log = zeros(length(num_inds),1);
            for num_no = 1 : length(num_inds)
                if sum(strcmp(up.extraction.rel_nums, numinfo.sig_names(num_no)))
                    num_log(num_no) = 1;
                end
            end

            % skip if this doesn't have both the required signals
            if sum(num_log) == length(up.extraction.rel_nums)

                numerics.fs = numinfo.fs;

                % create wfdb argument
                N0 = 1;
                N = up.extraction.period*numerics.fs;
                wfdb_argument={'-r',filepath,'-Ps','-f',['s' num2str(N0-1)]};

                % Make command to only extract the required signals
                numList = num_inds(logical(num_log));
                if(~isempty(numList))
                    wfdb_argument{end+1}='-s ';
                    %-1 is necessary because WFDB is 0 based indexed.
                    for sInd=1:length(numList)
                        wfdb_argument{end+1}=[num2str(numList(sInd)-1)];
                    end
                end

                % Additional wfdb_argument bits
                wfdb_argument{end+1}='-t';
                wfdb_argument{end+1}=['s' num2str(N)];

                % extract data
                extracted_data=javaWfdbExec_num.execToDoubleArray(wfdb_argument);
                clear wfdb_argument

                %% Re-format data for output

                % store this new bit of the wave
                current_numerics = fieldnames(numerics);
                numNames = numinfo.sig_names(numList);
                for wave_no = 1 : length(up.extraction.rel_nums)
                    rel_num_ind = find(strcmp(numNames, up.extraction.rel_nums{wave_no}));
                    if ~strcmp(current_numerics, up.extraction.rel_nums{wave_no})
                        eval(['numerics.' up.extraction.rel_nums{wave_no} '.t = extracted_data(:, 1);']);
                        eval(['numerics.' up.extraction.rel_nums{wave_no} '.v = extracted_data(:, rel_num_ind+1);']);
                    else
                        eval(['current_last_time = numerics.' up.extraction.rel_nums{wave_no} '.t(end);']);
                        eval(['numerics.' up.extraction.rel_nums{wave_no} '.t = [numerics.' up.extraction.rel_nums{wave_no} '.t; current_last_time + (1/Fs) + extracted_data(:, 1)];']);
                        eval(['numerics.' up.extraction.rel_nums{wave_no} '.v = [numerics.' up.extraction.rel_nums{wave_no} '.v; extracted_data(:, rel_num_ind+1)];']);
                    end
                end

            end

        end

        clear current_numerics extracted_data Fs ListCapacity numinfo numList javaWfdbExec_num config_num

    end

    %% Find extraction statistics
    extraction_stats.no_records_searched = extraction_stats.no_records_searched+1;
    if ~exist('numerics', 'var')
        extraction_stats.no_records_without_num = extraction_stats.no_records_without_num+1;
    end
    if ~exist('waves', 'var')
        extraction_stats.no_records_without_signals = extraction_stats.no_records_without_signals+1;
    end

    %% Store data for this patient stay in the output
    if exist('waves', 'var') && exist('numerics', 'var')
        extraction_stats.no_records_with_sigs_and_num = extraction_stats.no_records_with_sigs_and_num+1;
        data{extraction_stats.no_records_with_sigs_and_num}.loc = loc;
        data{extraction_stats.no_records_with_sigs_and_num}.ID = pt_stays{pt_stay_no};
        data{extraction_stats.no_records_with_sigs_and_num}.waves = waves;
        data{extraction_stats.no_records_with_sigs_and_num}.numerics = numerics;
        clear waves numerics
    end

end

%% Find out how many records had the required duration signals
total_records = length(data);
recs_w_req_duration = zeros(total_records,1);
for s = 1  : length(data)
    if sum(strcmp(fieldnames(data{1,s}), 'waves'))
        if length(data{1,s}.waves.II.t) == up.extraction.period*data{1,s}.waves.fs ...
            && length(data{1,s}.waves.PLETH.t) == up.extraction.period*data{1,s}.waves.fs ...
            && length(data{1,s}.waves.RESP.t) == up.extraction.period*data{1,s}.waves.fs
            recs_w_req_duration(s) = 1;
        end
    end
end

%% Only output those records with the required duration
extraction_stats.no_records_with_req_duration = sum(recs_w_req_duration);
data = data(logical(recs_w_req_duration));

%% Create Pie Chart of extraction stats

% bar chart
ftsize = 14;
figure('Position', [200, 200, 800, 450])
labels = {'Signals or numerics absent', 'Shorter than 10 mins', 'Included in analysis'};
piedata(3) = extraction_stats.no_records_with_req_duration;
piedata(2) = extraction_stats.no_records_with_sigs_and_num - extraction_stats.no_records_with_req_duration;
piedata(1) = extraction_stats.no_records_searched - extraction_stats.no_records_with_sigs_and_num;
p = pie(piedata);
for s = 2:2: length(p)
    p(s).FontSize = ftsize;
end
set(gca, 'FontSize', ftsize)
legend(labels, 'Location', 'southeastoutside')
title('Reasons for exclusion of records', 'FontSize', ftsize)
% save
save_name = 'record_exclusion';
savepath = [up.paths.plots, save_name, '.png'];
set(gcf,'PaperUnits','inches');
set(gcf,'PaperPosition',[1 1 8 4.5]);
print(gcf, savepath, '-dpng')
close

end

function [headers, Fs] = extract_file_info(filepath)

%% Obtain info on signals

fileID = fopen([filepath, '.hea']);
header_lines = textscan(fileID,'%s','Delimiter','\n'); header_lines = header_lines{1,1};
fclose all;

% Extract the relevant header information
temp.top_line = textscan(header_lines{1}, '%s', 'delimiter', sprintf(' ')); temp.top_line = temp.top_line{1,1};  % adapted from http://uk.mathworks.com/matlabcentral/newsreader/view_thread/249016
headers.no_sigs = str2double(temp.top_line{2});
headers.fs = str2double(temp.top_line{3});
headers.no_samps = str2double(temp.top_line{4});

% extract signal names
headers.sig_names = cell(0);
for sig_no = 1 : headers.no_sigs
    temp.curr_line = textscan(header_lines{1+sig_no}, '%s', 'delimiter', sprintf(' ')); temp.curr_line = temp.curr_line{1,1};  % adapted from http://uk.mathworks.com/matlabcentral/newsreader/view_thread/249016
    headers.sig_names = [headers.sig_names; temp.curr_line{end}];
end

% extract location
loc_line = header_lines{end};
headers.loc = loc_line(13:end);

% putting in a format for rdsamp

Fs = headers.fs;

end

function save_data_in_common_format(old_data, up)

fprintf('\n -- Saving data in appropriate format')

for subj_el = 1:length(old_data)

    SID = old_data{1,subj_el}.ID;
    loc = old_data{1,subj_el}.loc;

    % insert group name
    if strcmp(loc, 'nicu')
        data(1,subj_el).group = 'neonate';
    else
        data(1,subj_el).group = 'adult';
    end

    % Insert fixed params

    data(1,subj_el).fix.id = SID;
    data(1,subj_el).fix.loc = loc;
    data(1,subj_el).fix.ventilation = 'unknown';
    data(1,subj_el).fix.recording_conditions = 'critical care';

    % insert PPG signal
    ppg = old_data{1,subj_el}.waves.PLETH;
    data(1,subj_el).ppg.v = ppg.v;
    clear ppg
    data(1,subj_el).ppg.fs = old_data{1,subj_el}.waves.fs;
    % insert EKG signal
    ekg = old_data{1,subj_el}.waves.II;
    data(1,subj_el).ekg.v = ekg.v;
    clear ekg
    data(1,subj_el).ekg.fs = old_data{1,subj_el}.waves.fs;
    % insert RESP signal
    resp = old_data{1,subj_el}.waves.RESP;
    data(1,subj_el).ref.resp_sig.imp.v = resp.v;
    clear resp
    data(1,subj_el).ref.resp_sig.imp.fs = old_data{1,subj_el}.waves.fs;
    data(1,subj_el).ref.resp_sig.imp.method = 'thoracic impedance measured using clinical monitor';

    % insert numerics
    data(1,subj_el).ref.params.rr.t = old_data{1,subj_el}.numerics.RESP.t;
    data(1,subj_el).ref.params.rr.v = old_data{1,subj_el}.numerics.RESP.v;
    data(1,subj_el).ref.params.rr.method = 'derived from thoracic impedance measured using clinical monitor';
    data(1,subj_el).ref.params.rr.units.t = 's';
    data(1,subj_el).ref.params.rr.units.v = 'breaths/min';
    data(1,subj_el).ref.params.hr.t = old_data{1,subj_el}.numerics.HR.t;
    data(1,subj_el).ref.params.hr.v = old_data{1,subj_el}.numerics.HR.v;
    data(1,subj_el).ref.params.hr.method = 'derived from ecg measured using clinical monitor';
    data(1,subj_el).ref.params.hr.units.t = 's';
    data(1,subj_el).ref.params.hr.units.v = 'beats/min';
    data(1,subj_el).ref.params.pr.t = old_data{1,subj_el}.numerics.PULSE.t;
    data(1,subj_el).ref.params.pr.v = old_data{1,subj_el}.numerics.PULSE.v;
    data(1,subj_el).ref.params.pr.method = 'derived from ppg measured using clinical monitor';
    data(1,subj_el).ref.params.pr.units.t = 's';
    data(1,subj_el).ref.params.pr.units.v = 'beats/min';

end

% Save to file
save([up.paths.data_save_folder, 'mimicii_data'], 'data')

end

function results = sub_group_identification(up)

%% Load data
load([up.paths.data_save_folder, 'mimicii_data'], 'data')

%% Split into sub-groups and identify data for each
sub_group = zeros(length(data),1);   % zero for neonates, one for adults
n_rrs = []; a_rrs = [];
for s = 1 : length(data)
    if strcmp(data(1,s).group, 'neonate')
        n_rrs = [n_rrs; data(1,s).ref.params.rr.v];
    else
        a_rrs = [a_rrs; data(1,s).ref.params.rr.v];
        sub_group(s) = 1;
    end
end
results.sub_group = sub_group;

%% Plot histograms

% generate data of prop of rrs in each category:
xbins1 = -1:120;
rrs.a.tot = sum(~isnan(a_rrs));
rrs.a.bins = nan(length(xbins1),1);
rrs.n.tot = sum(~isnan(n_rrs));
rrs.n.bins = nan(length(xbins1),1);
for s = 1:length(xbins1)
    rel_rr_range = [(xbins1(s)-0.5),(xbins1(s)+0.5)];
    rel_a_rrs = a_rrs(a_rrs>rel_rr_range(1) & a_rrs<=rel_rr_range(2));
    rel_n_rrs = n_rrs(n_rrs>rel_rr_range(1) & n_rrs<=rel_rr_range(2));
    rrs.a.bins(s) = length(rel_a_rrs)/rrs.a.tot;
    rrs.n.bins(s) = length(rel_n_rrs)/rrs.n.tot;
end

% bar chart
ftsize = 14;
paper_size = [9, 3.5];
figure('Position', [200, 200, 100*paper_size(1), 100*paper_size(2)])
b = bar(xbins1, [rrs.a.bins, rrs.n.bins], 1.2);
b(1).FaceColor = [0,0,1];
b(1).EdgeColor = [0,0,1];
b(2).FaceColor = [1, 0.6, 0.6];
b(2).EdgeColor = [1, 0.6, 0.6];
xlim([-1 xbins1(end)])
ylim([0 1.1*max([rrs.a.bins; rrs.n.bins])])
xlabel('Impedance RR numeric [bpm]', 'FontSize', ftsize)
ylabel('Proportion of Measurements', 'FontSize', ftsize)
set(gca, 'YTick', [], 'FontSize', ftsize)
legend(b, {'Adults', 'Neonates'})

%% save histograms
save_name = 'adults_vs_neonates';
savepath = [up.paths.plots, save_name];
PrintFigs(gcf, paper_size, savepath, up)

end

function PrintFigs(h, paper_size, savepath, up)
set(h,'PaperUnits','inches');
set(h,'PaperSize', [paper_size(1), paper_size(2)]);
set(h,'PaperPosition',[0 0 paper_size(1) paper_size(2)]);
print(h,'-dpdf',savepath)
print(h,'-dpng',savepath)

if up.eps_figs
    export_fig(savepath, '-eps')
end
close all
end


function [errCode, errMsgs] = compareEEG(EEG1, EEG2, dataFlg)
tol = 1E-10;
errCode = 0;
errMsgs = {};
%% Check data
if size(EEG1.data, 1) ~= size(EEG2.data, 1)
    errCode = errCode + 1;
    errMsgs{end + 1} = 'data channel numbers do not agree';
elseif size(EEG1.data, 2) ~= size(EEG2.data, 2)
    errCode = errCode + 1;
    errMsgs{end + 1} = 'data frame numbers do not agree';
elseif dataFlg && sum(sum(abs(EEG1.data - EEG2.data))) > tol
    errCode = errCode + 1;
    errMsgs{end + 1} = 'data values do not agree';
end

%% Check times
if size(EEG1.times, 1) ~= size(EEG2.times, 1)
    errCode = errCode + 1;
    errMsgs{end + 1} = 'times sizes do not agree';
elseif size(EEG1.times, 2) ~= size(EEG2.times, 2)
    errCode = errCode + 1;
    errMsgs{end + 1} = 'times sizes not agree';
elseif sum(sum(abs(EEG1.times - EEG2.times))) > 0
    errCode = errCode + 1;
    errMsgs{end + 1} = 'times values do not agree';
end

%% Check timestamps
if (isfield(EEG1.etc, 'timestamp'))
    if size(EEG1.etc.timestamp, 1) ~= size(EEG2.etc.timestamp, 1)
        errCode = errCode + 1;
        errMsgs{end + 1} = 'timestamp sizes do not agree';
    elseif size(EEG1.etc.timestamp, 2) ~= size(EEG2.etc.timestamp, 2)
        errCode = errCode + 1;
        errMsgs{end + 1} = 'timestamp sizes not agree';
    elseif sum(sum(abs(EEG1.etc.timestamp - EEG2.etc.timestamp))) > tol
        errCode = errCode + 1;
        errMsgs{end + 1} = 'timestamp values do not agree';
    end
end

%% Check events
if length(EEG1.event) ~= length(EEG2.event)
    errCode = errCode + 1;
    errMsgs{end + 1} = 'event sizes do not agree';
else
    if sum(~strcmpi(strtrim({EEG1.event.type}), strtrim({EEG2.event.type}))) > 0
        errCode = errCode + 1;
        errMsgs{end + 1} = 'event type do not agree';
    end
    if sum(sum(abs(cell2mat({EEG1.event.latency}) - cell2mat({EEG2.event.latency})))) > 0
        errCode = errCode + 1;
        errMsgs{end + 1} = 'event latencies do not agree';
    end
    if isfield(EEG1.event, 'usertags') && ...
        sum(~strcmpi(strtrim({EEG1.event.usertags}), strtrim({EEG2.event.usertags}))) > 0
           errCode = errCode + 1;
          errMsgs{end + 1} = 'event usertags do not agree';
    end
end
%% check chanlocs
if length(EEG1.chanlocs) ~= length(EEG2.chanlocs)
    errCode = errCode + 1;
    errMsgs{end + 1} = 'chanlocs sizes do not agree';
else
    if sum(~strcmpi(strtrim({EEG1.chanlocs.type}), strtrim({EEG2.chanlocs.type}))) > 0
        errCode = errCode + 1;
        errMsgs{end + 1} = 'chanlocs type do not agree';
    end
    if sum(~strcmpi(strtrim({EEG1.chanlocs.labels}), strtrim({EEG2.chanlocs.labels}))) > 0
        errCode = errCode + 1;
        errMsgs{end + 1} = 'chanlocs labels do not agree';
    end
    if sum(sum(abs(cell2mat({EEG1.chanlocs.X}) - cell2mat({EEG1.chanlocs.X})))) > tol
        errCode = errCode + 1;
        errMsgs{end + 1} = 'chanlocs X do not agree';
    end
    if sum(sum(abs(cell2mat({EEG1.chanlocs.Y}) - cell2mat({EEG1.chanlocs.Y})))) > tol
        errCode = errCode + 1;
        errMsgs{end + 1} = 'chanlocs Y do not agree';
    end
    if sum(sum(abs(cell2mat({EEG1.chanlocs.Z}) - cell2mat({EEG1.chanlocs.Z})))) > tol
        errCode = errCode + 1;
        errMsgs{end + 1} = 'chanlocs Z do not agree';
    end
    if sum(sum(abs(cell2mat({EEG1.chanlocs.theta}) - cell2mat({EEG1.chanlocs.theta})))) > tol
        errCode = errCode + 1;
        errMsgs{end + 1} = 'chanlocs theta do not agree';
    end
    if sum(sum(abs(cell2mat({EEG1.chanlocs.radius}) - cell2mat({EEG1.chanlocs.radius})))) > tol
        errCode = errCode + 1;
        errMsgs{end + 1} = 'chanlocs radius do not agree';
    end
    if sum(sum(abs(cell2mat({EEG1.chanlocs.sph_theta}) - cell2mat({EEG1.chanlocs.sph_theta})))) > tol
        errCode = errCode + 1;
        errMsgs{end + 1} = 'chanlocs sph_theta do not agree';
    end
    if sum(sum(abs(cell2mat({EEG1.chanlocs.sph_phi}) - cell2mat({EEG1.chanlocs.sph_phi})))) > 0
        errCode = errCode + 1;
        errMsgs{end + 1} = 'chanlocs sph_phi do not agree';
    end
end


function set9701a(m)
% sets parameters of DT3152 according to
% http://cmp.felk.cvut.cz/cmp/hardware/pulnix.html#TM-9701analog
% where m is a initialized handle to a framegrabber

% input parameters check
if nargin < 1,
	error('Not enough input arguments!');
end

if nargin > 1,
	error('Too many input arguments!');
end

for i=0:3
   setfg(m,'InputChannel',i)
   setfg(m,'FrameType','NonInterlaced')
   setfg(m,'VideoType','Composite')
   setfg(m,'ClockSource','internal')
   setfg(m,'ClockFreq',14318180)
   setfg(m,'TotalPixPerLine',909)

   setfg(m,'backporchstart',60)
   setfg(m,'clampstart',95)
   setfg(m,'clampend',100)

   setfg(m,'FirstActivePixel',126)
   setfg(m,'ActivePixelCount',760)

   setfg(m,'TotalLinesperFld',524)
   setfg(m,'FirstActiveLine',33)
   setfg(m,'ActiveLineCount',484)

   setfg(m,'FrameLeft',0)
   setfg(m,'HorFrameInc',1)
   setfg(m,'FrameWidth',760)
   setfg(m,'FrameTop',0)
   setfg(m,'VerFrameInc',1)
   setfg(m,'FrameHeight',484)
end

setfg(m,'InputChannel',0)


close all; clear all; clc

% include tclab.m for initialization
tclab;

% Write data to the digital pin
disp('LED on and off repeatedly for 5 seconds')
for i = 0:5
    led(1)
    pause(0.5);
    led(0)
    pause(0.5);
end

% Change the brightness from maximum to minimum using the
%  digital pin's PWM duty cycle.
disp('LED dimming from bright to off over 10 seconds')
for brightness = 1:-0.1:0
    led(brightness);
    pause(1.0);
end

disp('LED Test Complete')


classdef TestGraphSegmentation
    %TestGraphSegmentation

    methods (Static)
        function test_1
            img = imread(fullfile(mexopencv.root(),'test','fruits.jpg'));
            gs = cv.GraphSegmentation('K',300);
            assert(isequal(gs.K,300));
            L = gs.processImage(img);
            validateattributes(L, {'int32'}, ...
                {'size',[size(img,1) size(img,2)]});
        end
    end

end


function filum_test03 ( )

%*****************************************************************************80
%
%% TEST03 tests FILE_COLUMN_COUNT.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    06 June 2007
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST03\n' );
  fprintf ( 1, '  FILE_COLUMN_COUNT counts the columns in a file.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  It is assumed that the file contains a number of lines,\n' );
  fprintf ( 1, '  with each line containing the same number of words.\n' );
  fprintf ( 1, '  The task is to determine the number of words in a line,\n' );
  fprintf ( 1, '  that is, the number of "columns" of text.\n' );

  filename = 'filum_prb_4by5.txt';

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Examining the file "%s"\n', filename );

  column_num = file_column_count ( filename );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Number of columns = %d\n', column_num );

  return
end


function aistats2012_mohsst5_results()

%
% DATA
%

disp('--- Results for UNIFORM case ---')
show_results('data', 1);
disp('Kronecker GP')
show_results('gpkron', 1, 'results_aistats2012_mohsst5_gpkron_uniform_20110528');
disp('Kronecker GP (2 covfuncs)')
show_results('gpkron2', 1, 'results_aistats2012_mohsst5_gpkron-cov2_uniform_20111010');
disp('VB PCA')
show_results('pca', 1, 'results_aistats2012_mohsst5_vbpca_uniform_20111007');
disp('GPFA')
show_results('gpfa', 1, 'results_aistats2012_mohsst5_gpfa_uniform_20111006');

disp('--- Results for PATTERN case ---')
show_results('data', 2);
disp('Kronecker GP')
show_results('gpkron', 2, 'results_aistats2012_mohsst5_gpkron_pattern_20110528');
disp('Kronecker GP (2 covfuncs)')
show_results('gpkron2', 2, 'results_aistats2012_mohsst5_gpkron-cov2_pattern_20111010');
disp('VB PCA')
show_results('pca', 2, 'results_aistats2012_mohsst5_vbpca_pattern_20111007');
disp('GPFA')
show_results('gpfa', 2, 'results_aistats2012_mohsst5_gpfa_pattern_20111006');

return

% $$$ GP1 = load([dir 'results_aistats2012_mohsst5_gpkron-cov2_uniform_20110930']);
% $$$ % $$$ GP1 = load([dir 'results_aistats2012_mohsst5_gpkron-cov2_uniform_20110907']);
% $$$ % $$$ GP2 = load([dir 'results_aistats2012_mohsst5_gpkron-cov2_pattern_20110908']);
% $$$ PCA1 = load([dir 'results_aistats2012_mohsst5_vbpca_uniform_20110601']);
% $$$ PCA2 = load([dir 'results_aistats2012_mohsst5_vbpca_pattern_20110601']);
% $$$ GPFA1 = load([dir 'results_aistats2012_mohsst5_gpfa_uniform_20110921']);
% $$$ GPFA2 = load([dir 'results_aistats2012_mohsst5_gpfa_pattern_20111001']);
% $$$
% $$$ [gp1_rmse_train, gp1_rmse_test] = aistats2012_mohsst5_rmse(GP1.F, 1);
% $$$ fprintf('GP, uniform: train=%.4f and test=%.4f\n', gp1_rmse_train, gp1_rmse_test);
% $$$ [pca1_rmse_train, pca1_rmse_test] = aistats2012_mohsst5_rmse(PCA1.F, 1);
% $$$ fprintf('PCA, uniform: train=%.4f and test=%.4f\n', pca1_rmse_train, pca1_rmse_test);
% $$$ [pca2_rmse_train, pca2_rmse_test] = aistats2012_mohsst5_rmse(PCA2.F, 2);
% $$$ fprintf('PCA, pattern: train=%.4f and test=%.4f\n', pca2_rmse_train, pca2_rmse_test);
% $$$ [gpfa1_rmse_train, gpfa1_rmse_test] = aistats2012_mohsst5_rmse(GPFA1.F, 1);
% $$$ fprintf('GPFA, pattern: train=%.4f and test=%.4f\n', gpfa2_rmse_train, gpfa2_rmse_test);
% $$$ [gpfa2_rmse_train, gpfa2_rmse_test] = aistats2012_mohsst5_rmse(GPFA2.F, 2);
% $$$ fprintf('GPFA, pattern: train=%.4f and test=%.4f\n', gpfa2_rmse_train, gpfa2_rmse_test);
return

% $$$ Y = GP1.Ytest;
% $$$ I = ~isnan(GP1.Ytrain);
% $$$ Y(I) = GP1.Ytrain(I);
% $$$
% $$$ data = mohsst5_loaddata();
% $$$ [LON,LAT] = meshgrid(data.longitude, data.latitude);
% $$$ weights = 1./cosd(LAT(:));
% $$$ weights = mohsst5_remove_land(weights);
% $$$
% $$$ %
% $$$ % Means (uniform)
% $$$ %
% $$$
% $$$ t = 800;
% $$$ % t = 1200;
% $$$
% $$$ cl = max(max(abs(Y(:,t))), ...
% $$$          max(abs(GP1.F(:,t))));
% $$$ % $$$ cl = max(max(abs(Y(:,t))), ...
% $$$ % $$$          max(max(abs(GP1.F(:,t))), ...
% $$$ % $$$              max(abs(PCA1.F(:,t)))));
% $$$
% $$$ dir = '/home/jluttine/papers/gpkron/figures_aistats2012/';
% $$$
% $$$ fig();
% $$$ mohsst5_mapplot(GP1.F(:,t));
% $$$ colormap_redblue();
% $$$ polish(gca);
% $$$ set(gca, 'clim', [-cl cl]);
% $$$ print('-depsc2', [dir 'fig_sst_gp_mean']);
% $$$
% $$$ % $$$ figure
% $$$ % $$$ mohsst5_mapplot(PCA1.F(:,t))
% $$$ % $$$ colormap_redblue();
% $$$ % $$$ polish(gca);
% $$$ % $$$ set(gca, 'clim', [-cl cl]);
% $$$ % $$$ print('-depsc2', [dir 'fig_sst_pca_mean']);
% $$$
% $$$ %
% $$$ % DATA
% $$$ %
% $$$
% $$$ fig()
% $$$ mohsst5_mapplot(Y(:,t))
% $$$ colormap_redblue();
% $$$ polish(gca);
% $$$ set(gca, 'clim', [-cl cl]);
% $$$ print('-depsc2', [dir 'fig_sst_data']);
% $$$
% $$$ %
% $$$ % STD (uniform)
% $$$ %
% $$$
% $$$ burnin = 3;
% $$$ GPstd = sqrt(GP1.stdF(:,t).^2 + weights*mean(GP1.results.theta(end,burnin:end).^2));
% $$$ % $$$ PCAstd = sqrt(PCA1.stdF(:,t).^2 + 1./PCA1.results.Tau(:,t));
% $$$
% $$$ % $$$ fig()
% $$$ % $$$ plot(GPstd(:))
% $$$ % $$$ return
% $$$
% $$$ % $$$ fig()
% $$$ % $$$ %plot(GPstd(:))
% $$$ % $$$ plot(GP1.stdF(:))
% $$$ % $$$ min(GP1.stdF(:))
% $$$ % $$$ size(GP1.results.theta)
% $$$ % $$$ min(weights(:)*mean(GP1.results.theta(end,1000:end).^2))
% $$$
% $$$
% $$$ cl = max(GPstd(:));
% $$$ % $$$ cl = max( max(GPstd), max(PCAstd) );
% $$$
% $$$ fig()
% $$$ mohsst5_mapplot(GPstd);
% $$$ colormap_scale();
% $$$ polish(gca);
% $$$ set(gca, 'clim', [0 cl]);
% $$$ print('-depsc2', [dir 'fig_sst_gp_std']);
% $$$
% $$$ % $$$ figure
% $$$ % $$$ mohsst5_mapplot(PCAstd);
% $$$ % $$$ colormap_scale();
% $$$ % $$$ polish(gca);
% $$$ % $$$ set(gca, 'clim', [0 cl]);
% $$$ % $$$ print('-depsc2', [dir 'fig_sst_pca_std']);
% $$$
% $$$ disp(datestr(data.time(t)));
% $$$
% $$$ % return
% $$$
% $$$ %return
% $$$
% $$$ %
% $$$ % Means (pattern)
% $$$ %
% $$$
% $$$ t = 1429;
% $$$
% $$$ cl = max(abs(GP2.F(:,t)));
% $$$ % $$$ cl = max( max(abs(GP2.F(:,t))), max(abs(PCA2.F(:,t))) );
% $$$
% $$$ % GP
% $$$
% $$$ fig()
% $$$ mohsst5_mapplot(GP2.F(:,t));
% $$$ colormap_redblue();
% $$$ polish(gca);
% $$$ set(gca, 'clim', [-cl cl]);
% $$$ print('-depsc2', [dir 'fig_sst_pattern_gp_mean']);
% $$$
% $$$ % $$$ % PCA
% $$$ % $$$
% $$$ % $$$ figure
% $$$ % $$$ mohsst5_mapplot(PCA2.F(:,t))
% $$$ % $$$ colormap_redblue();
% $$$ % $$$ polish(gca);
% $$$ % $$$ set(gca, 'clim', [-cl cl]);
% $$$ % $$$ print('-depsc2', [dir 'fig_sst_pattern_pca_mean']);
% $$$
% $$$ % Data
% $$$
% $$$ fig()
% $$$ mohsst5_mapplot(Y(:,t))
% $$$ colormap_redblue();
% $$$ polish(gca);
% $$$ set(gca, 'clim', [-cl cl]);
% $$$ print('-depsc2', [dir 'fig_sst_pattern_data']);
% $$$
% $$$ % $$$ figure
% $$$ % $$$ mohsst5_mapplot(PCA2.Ytrain(:,t))
% $$$ % $$$ colormap_redblue();
% $$$ % $$$ polish(gca);
% $$$ % $$$ set(gca, 'clim', [-cl cl]);
% $$$ % $$$ print('-depsc2', [dir 'fig_sst_pattern_train']);
% $$$
% $$$ disp(datestr(data.time(t)));
% $$$
% $$$ % $$$ figure
% $$$ % $$$ EGP = abs(Y-GP2.F);
% $$$ % $$$ EPCA = abs(Y-PCA2.F);
% $$$ % $$$ mohsst5_mapplot(EGP(:,t)-EPCA(:,t))
% $$$ % $$$ colormap_redblue();
% $$$ % $$$ polish(gca);
% $$$ % $$$ %set(gca, 'clim', [-cl cl]);
% $$$
% $$$ % $$$ figure
% $$$ % $$$ mohsst5_mapplot(E2(:,t))
% $$$ % $$$ colormap_scale();
% $$$ % $$$ polish(gca);
% $$$ %set(gca, 'clim', [-cl cl]);
% $$$
% $$$ figure()
% $$$ burnin = ceil(size(GP2.results.theta,2)/2);
% $$$ plot_scatterhist(GP2.results.theta(:,burnin:end)');
% $$$
% $$$ figure()
% $$$ subplot(1,2,1)
% $$$ semilogy(GP2.results.theta');
% $$$ subplot(1,2,2)
% $$$ plot(acorr(GP2.results.theta(:,burnin:end)'));
% $$$
% $$$ return
% $$$
% $$$ %
% $$$ % STD (pattern)
% $$$ %
% $$$
% $$$ GPstd = sqrt(GP2.stdF(:,t).^2 + weights*mean(GP2.results.theta(4,1000:end).^2));
% $$$ PCAstd = sqrt(PCA2.stdF(:,t).^2 + 1./PCA2.results.Tau(:,t));
% $$$
% $$$ cl = max( max(GPstd), max(PCAstd) );
% $$$ %cl = max( max(GP2.stdF(:,t)), max(PCA2.stdF(:,t)) );
% $$$
% $$$ figure
% $$$ mohsst5_mapplot(GPstd);
% $$$ colormap_scale();
% $$$ polish(gca);
% $$$ set(gca, 'clim', [0 cl]);
% $$$ print('-depsc2', [dir 'fig_sst_pattern_gp_std']);
% $$$
% $$$ figure
% $$$ mohsst5_mapplot(PCAstd);
% $$$ colormap_scale();
% $$$ polish(gca);
% $$$ set(gca, 'clim', [0 cl]);
% $$$ print('-depsc2', [dir 'fig_sst_pattern_pca_std']);
% $$$
% $$$ return

function show_results(model, testset, filename)

dir = '/home/jluttine/papers/gpkron/figures/';
printfile = [dir 'fig_sst'];
if testset == 1
  teststring = 'uniform';
  t = 800;
else
  teststring = 'pattern';
  t = 1429;
end

if nargin >= 3
  % Load results
  dir = '/home/jluttine/matlab/publications/aistats2012/';
  Q = load([dir filename], 'F');
  % RMSE
  [rmse_train, rmse_test] = aistats2012_mohsst5_rmse(Q.F, testset);
  fprintf('train=%.4f and test=%.4f\n', rmse_train, rmse_test);
  F = Q.F(:,t);
  plot_map(F);
  printfile = sprintf('%s_%s_%s', printfile, teststring, model);
  print('-depsc2', printfile);
  title([teststring ' ' model]);
else
  [Ytrain, Ytest, Itrain, Itest] = aistats2012_mohsst5_sets(testset);
  F = Ytrain;
  F(Itest) = Ytest(Itest);
  plot_map(F(:,t));
  print('-depsc2', sprintf('%s_%s_data', printfile, teststring));
  title([teststring ' data']);
  plot_map(Ytrain(:,t));
  print('-depsc2', sprintf('%s_%s_train', printfile, teststring));
  title([teststring ' train']);
end

function plot_map(F)
% Plot reconstruction
cl = 3.3;
f = fig();
mohsst5_mapplot(F);
colormap_redblue();
polish(gca);
set(gca, 'clim', [-cl cl]);
% NaNs to grey
whitebg(f, [0.7 0.7 0.7]);

function polish(hax)
hcb = colorbar('SouthOutside');
set(hcb, 'Units', 'normalized');
set_figure_size(10,8);
set_colorbar_position(hcb, hax, 0.03, 0.07);

function f = fig()
f = figure('Position', [1 300 400 300]);


% Author: Guosheng Lin (guosheng.lin@gmail.com)

% This file shows how to perform training on your own dataset.

% 1. Training demo on PASCAL VOC 2012 dataset

% We here demonstrate the training on the original PASCAL VOC 2012 dataset for semantic segmentation.
% Before running this demo file for training, you need to
% download the PASCAL VOC 2012 dataset and place it at:
% ../datasets/voc2012_trainval

% 2. Training on other dataset:

% other datasets can be handled in a similar way as the VOC2012 dataset.
% Basically the users need to provide a file to describe your dataset:
% my_gen_ds_info_[your dataset name].m
% please refer to my_gen_ds_info_voc.m for details

% 3. Training instructions:

% Stage-1: using a fixed learning rate for training until the performance
% get stable on the validation set. You need to manually stop the running of this training code.

% Stage-2: chose one cached model, initialize from this model, and using a
% lower learning rate (e.g., multiplied by 0.1) to perform further training.

% For example, using the following setting for loading an existed model and
% using a lower learning rate:
% run_config.trained_model_path='../cache_data/voc2012_trainval/model_20161219094311_example/model_cache/epoch_70';
% run_config.learning_rate=5e-5;

% Please refer to the following demo file for perform further training with lower learning rate:
% demo_refinenet_train_reduce_learning_rate.m

% 4. Verify your trained model with performance evaluation:

% This demo file shows the training on the original PASCAL VOC 2012 dataset for semantic segmentation.
% This dataset consists of 1464 training images and 1449 validation images.
% For this dataset, the training will take around 3 days using a Titan-X card,
% including the training with a decreased learning rate.

% After training, the intersection over union (IoU) score of the trained model is supposed to be around 0.691.

% If you cannot get similar result, please verify whether you are using our modified version of MatConvNet,
% for which you need to replace the modified files in the original MatConvNet and compile after replacement.
% Details can be found at ./my_matconvnet_resnet/README.txt

function demo_refinenet_train()

rng('shuffle');

addpath('./my_utils');
dir_matConvNet='../libs/matconvnet/matlab';
run(fullfile(dir_matConvNet, 'vl_setupnn.m'));

run_config=[];
ds_config=[];

run_config.use_gpu=true;
% run_config.use_gpu=false;
run_config.gpu_idx=1;

% use a random model name:
model_name=['model_' datestr(now, 'YYYYmmDDHHMMSS')];

% or specify a model_name for training, if the cached snapshot files existed, it will resume training
% model_name='model_20161219094311_example';

% update the model name when reducing learning rate for training, e.g.,
% model_name='model_20161219094311_example_epoch70_low_learn_rate';

ds_name='voc2012_trainval';
gen_ds_info_fn=@my_gen_ds_info_voc;

% control the size of input images
run_config.input_img_short_edge_min=450;
run_config.input_img_short_edge_max=1100;

run_config.input_img_scale=1;

ds_config.use_dummy_gt=false;
run_config.use_dummy_gt=ds_config.use_dummy_gt;
ds_config.use_custom_data=false;

ds_config.ds_name=ds_name;
ds_config.gen_ds_info_fn=gen_ds_info_fn;
ds_config.ds_info_cache_dir=fullfile('../datasets', ds_name);

run_config.root_cache_dir=fullfile('../cache_data', ds_name, model_name);
mkdir_notexist(run_config.root_cache_dir);

run_config.model_name=model_name;

diary_dir=run_config.root_cache_dir;
mkdir_notexist(diary_dir);
diary(fullfile(diary_dir, 'output.txt'));
diary on

run_dir_name=fileparts(mfilename('fullpath'));
[~, run_dir_name]=fileparts(run_dir_name);
run_config.run_dir_name=run_dir_name;
run_config.run_file_name=mfilename();

fprintf('\n\n\n=====================================================================\n');
disp('gen ds_info');

disp('ds_config:');
disp(ds_config);

ds_info=gen_dataset_info(ds_config);

my_diary_flush();

fprintf('\n\n\n=====================================================================\n');
disp('run network');

run_config.run_evaonly=false;

% settings for training:

run_config.trained_model_path=[];
run_config.learning_rate=5e-4;

% init from a cached model
% e.g., can be used for resuming network training with a lower learning rate by
% initilizing from a cached model.
% the following is an example for loading a cached model and using a lower learning
% to continue the training

% please refer to the example script: demo_refinenet_train_reduce_learning_rate.m

% run_config.trained_model_path='../cache_data/voc2012_trainval/model_20161219094311_example/model_cache/epoch_70';
% run_config.learning_rate=5e-5;

run_config.epoch_num=600;

% turn on this option to cache all data into memory, if it's possible
% run_config.cache_data_mem=true;
run_config.cache_data_mem=false;

% random crop training:
run_config.crop_box_size=400;

% for cityscape, using a larger crop:
% run_config.crop_box_size=600;

% evaluate step: do evaluation every 5 epochs, can be set to 10:
run_config.eva_run_step=5;
run_config.snapshot_step=1;

% choose ImageNet pre-trained resnet:
run_config.init_resnet_layer_num=50;
% run_config.init_resnet_layer_num=101;
% run_config.init_resnet_layer_num=152;

% generate network
run_config.gen_network_fn=@gen_network_main;

run_config.gen_net_opts_fn=@gen_net_opts_model_type1;
% run_config.gen_net_opts_fn=@gen_net_opts_model_type2;

% uncomment the following for debug:
% select a subset for both training and evaluation.
% ds_info.train_idxes=ds_info.train_idxes(1:5);
% ds_info.test_idxes=ds_info.train_idxes;
% run_config.snapshot_step=inf;

train_opts=run_config.gen_net_opts_fn(run_config, ds_info.class_info);

disp('train_opts:');
disp(train_opts);

disp('train_opts.eva_param:');
disp(train_opts.eva_param);

my_diary_flush();

imdb=my_gen_imdb(train_opts, ds_info);

data_norm_info=[];
data_norm_info.image_mean=128;

imdb.ref.data_norm_info=data_norm_info;

if run_config.use_gpu
	gpu_num=gpuDeviceCount;
	if gpu_num>=1
		gpuDevice(run_config.gpu_idx);
    else
        error('no gpu found!');
	end
end

[net_config, net_exp_info]=prepare_running_model(train_opts);

% net_config can be changed here before running the network

my_net_tool(train_opts, imdb, net_config, net_exp_info);

fprintf('\n\n--------------------------------------------------\n\n');
disp('results are saved in:');
disp(run_config.root_cache_dir);

my_diary_flush();
diary off

end


function disp(f)
% DISP - Filterobject disp overloaded operator

% VERSION: 1.0 of filter objects
% AUTHOR: Celso Reyes
% LASTUPDATE: 1/30/2007

if numel(f) > 1;
    disp(' ');
    DispStr = sprintf('%d',size(f,1));
    for n = 2 : numel(size(f))
        DispStr = sprintf('%sx%d', DispStr, size(f,n));
    end
    disp(sprintf('%s %s object with fields:', DispStr, class(f)));
    disp('    type');
    disp('    cutoff');
    disp('    poles');
else
    switch f.type
        case 'B'
            typename = 'Bandpass';
        case 'L'
            typename = 'Low-pass';
        case 'H'
            typename = 'High-pass';
    end;
    disp(['      type: ' f.type ' (' typename ')']);
    disp(['    cutoff: ' num2str(f.cutoff) ' Hz']);
    disp(['     poles: ' num2str(f.poles)]);
end;


function varargout = sample(f, varargin)
%SAMPLE   Sample a CLASSICFUN on an "appropriate" grid.
%   VALUES = SAMPLE(F, N) returns a vector VALUES of the values of F at N
%   "appropriately-chosen" points.  What "appropriately-chosen" means depends
%   on the type of representation on which F is ultimately based.
%
%   [VALUES, POINTS] = SAMPLE(F, N) returns also the vector POINTS at which the
%   values were computed.
%
%   [...] = SAMPLE(F) uses N = LENGTH(F).

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

    [varargout{1:nargout}] = sample(f.onefun, varargin{:});
    if ( nargout > 1 )
        varargout{2} = f.mapping.For(varargout{2});
    end
end


function conv2conv_f()
    global config mem;
    curr_layer_idx = config.misc.current_layer;
    mem.layer_inputs{curr_layer_idx} = mem.activations{curr_layer_idx-1};
end


function [objfiles, timestamp] = cs_make (f, docomplex)
%CS_MAKE compiles CXSparse for use in MATLAB.
%   Usage:
%       cs_make
%       [objfiles, timestamp] = cs_make (f, docomplex)
%
%   With no input arguments, or with f=0, only those files needing to be
%   compiled are compiled (like the Unix/Linux/GNU "make" command, but not
%   requiring "make").  If f is a nonzero number, all files are compiled.
%   If f is a string, only that mexFunction is compiled.  For example,
%   cs_make ('cs_add') just compiles the cs_add mexFunction.  This option is
%   useful when developing a single new mexFunction.  This function can only be
%   used if the current directory is CXSparse/MATLAB/CSparse.  Returns a list of
%   the object files in CXSparse, and the latest modification time of any source
%   codes.
%
%   NOTE: if your compiler does not support the ANSI C99 complex type (most
%   notably Microsoft Windows), the CXSparse mexFunctions will not support
%   complex sparse matrices.  The complex case is not attempted if docomplex is
%   zero.
%
%   To add a new function and its MATLAB mexFunction to CXSparse:
%
%       (1) Create a source code file CXSparse/Source/cs_mynewfunc.c.
%       (2) Create a help file, CXSparse/MATLAB/CSparse/cs_mynewfunc.m.
%           This is very useful, but not strictly required.
%       (3) Add the prototype of cs_mynewfunc to CXSparse/Include/cs.h.
%       (4) Create its MATLAB mexFunction, CXSparse/MATLAB/cs_mynewfunc_mex.c.
%       (5) Edit cs_make.m, and add 'cs_mynewfunc' to the 'cs' and 'csm' lists.
%       (6) Type 'cs_make' in the CXSparse/MATLAB/CSparse directory.
%           If all goes well, your new function is ready for use in MATLAB.
%
%       (7) Optionally add 'cs_mynewfunc' to CXSparse/Source/Makefile
%           and CXSparse/MATLAB/CSparse/Makefile, if you want to use the
%           Unix/Linux/GNU make command instead of cs_make.m.  See where
%           'cs_add' and 'cs_add_mex' appear in those files, and add
%           'cs_mynewfunc' accordingly.
%       (8) Optionally add 'cs_mynewfunc' to Tcov/Makefile, and add additional
%           test code to cs_test.c, and add MATLAB test code to MATLAB/Test/*.
%
%   Example:
%       cs_make                  % compile everything
%       cs_make ('cs_chol') ;    % just compile cs_chol mexFunction
%
%   See also MEX.

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

if (nargin < 1)
    f = 0 ;
end
if (nargin < 2)
    docomplex = 1 ;
end

try
    % ispc does not appear in MATLAB 5.3
    pc = ispc ;
catch
    % if ispc fails, assume we are on a Windows PC if it's not unix
    pc = ~isunix ;
end

if (pc)
    docomplex = 0 ;
end

if (docomplex == 0)
    % do not attempt to compile with complex matrices
    [objfiles, timestamp] = cs_make_helper (f, 0) ;
else
    try
        % try with complex support
        [objfiles, timestamp] = cs_make_helper (f, 1) ;
    catch
        % oops - that failed, try without complex support
        fprintf ('retrying without complex matrix support\n') ;
        [objfiles, timestamp] = cs_make_helper (f, 0) ;
    end
end

if (f > 0)
    fprintf ('CXSparse successfully installed.\n') ;
end


function [mneObj, DataMat, ChannelMat, iChannels] = out_mne_data(DataFiles, ObjType, ChannelFile, SensorTypes)
% OUT_MNE_DATA: Converts a data file or a set of data files into a MNE-Python object (Raw, Epoched or Evoked)
%
% USAGE:  [mneObj, DataMat, ChannelMat, iChannels] = out_mne_data( DataFiles, ObjType, ChannelFile=[], SensorTypes/iChannels=[]);
%         [mneObj, DataMat, ChannelMat, iChannels] = out_mne_data( DataMat,   ObjType, ChannelMat=[],  SensorTypes/iChannels=[]);
%
% INPUTS:
%    - DataFiles    : String or cell-array of strings, relative path(s) to data file(s) available in the database
%    - DataMat      : Brainstorm data file structure (if multiple files, the F matrix matrix must be [nEpochs, nChans, nTime])
%    - ObjType      : Class of the returned MNE-Python object {'Raw', 'Epoched', 'Evoked'}
%    - ChannelFile  : Relative path to a channel file available in the database (if not provided: look for it based on the DataFile)
%    - ChannelMat   : Brainstorm channel file structure
%    - iChannels    : Vector of selected channel indices
%    - SensorTypes  : Names or types of channels, separated with commas

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

%% ===== PARSE INPUTS =====
if (nargin < 4) || isempty(SensorTypes)
    SensorTypes = [];
end
if (nargin < 3) || isempty(ChannelFile)
    ChannelMat  = [];
    ChannelFile = [];
elseif isstruct(ChannelFile)
    ChannelMat   = ChannelFile;
    ChannelFile = [];
else
    ChannelMat = [];
end
if isempty(DataFiles)
    error('No input data files.');
elseif ischar(DataFiles)
    DataFiles = {DataFiles};
    DataMat = [];
elseif isstruct(DataFiles)
    DataMat = DataFiles;
    DataFiles = [];
end
% Only 'Epoched' objects can have multiple data files in input
if ~ismember(ObjType, {'Raw', 'Epoched', 'Evoked'})
    error('ObjType must be one of the following types of data: ''Raw'', ''Epoched'', ''Evoked''');
elseif (length(DataFiles) > 1) && ~strcmpi(ObjType, 'Epoched')
    error('Only "Epoched" objects accept multiple input files.');
end
% Check that data files are available in the database
MeasDate = [];
if ~isempty(DataFiles) && isappdata(0, 'BrainstormRunning')
    sStudy = bst_get('DataFile', DataFiles{1});
    % Get study date
    if isempty(sStudy)
        warning(['File not found in database: ' DataFiles{1}]);
    else
        MeasDate = sStudy.DateOfStudy;
    end
end

%% ===== LOAD CHANNEL FILE =====
% Get ChannelFile if not provided
if isempty(ChannelFile) && isempty(ChannelMat)
    if ~isempty(DataFiles)
        ChannelFile = bst_get('ChannelFileForStudy', DataFiles{1});
    else
        error('Missing ChannelMat or ChannelFile in input.');
    end
end
% Load channel file
if ~isempty(ChannelFile) && isempty(ChannelMat)
    ChannelMat = in_bst_channel(ChannelFile);
end
% Make sure that the channel file is defined
if isempty(ChannelMat)
    error('No channel file available for the input files.');
end
% Find sensors by names/types
if ~isempty(SensorTypes)
    if ischar(SensorTypes)
        iChannels = channel_find(ChannelMat.Channel, SensorTypes);
        if isempty(iChannels)
            error(['Channels not found: ' SensorTypes]);
        end
    elseif isnumeric(SensorTypes)
        iChannels = SensorTypes;
    else
        error('Invalid input type for parameter "SensorTypes".');
    end
% Default channel selection: all
else
    iChannels = 1:length(ChannelMat.Channel);
end

%% ===== LOAD DATA =====
% Load data file
if ~isempty(DataFiles)
    epochsComment = cell(1,length(DataFiles));
    % Loop on input files
    for iFile = 1:length(DataFiles)
        % Load .mat files
        tmpData = in_bst_data(DataFiles{iFile});
        % Raw files: Read entire recordings
        if isstruct(tmpData.F)
            sFile = tmpData.F;
            RemoveBaseline = 'no';
            UseSsp = 1;
            [tmpData.F, tmpData.Time] = panel_record('ReadRawBlock', sFile, ChannelMat, 1, tmpData.Time([1 end]), 0, 1, RemoveBaseline, UseSsp, iChannels);
            tmpData.Events = sFile.events;
            % Get date
            if isfield(sFile, 'acq_date') && ~isempty(sFile.acq_date)
                MeasDate = sFile.acq_date;
            end
        % Imported data: Keep only selected
        else
            tmpData.F = tmpData.F(iChannels,:);
        end
        tmpData.ChannelFlag = tmpData.ChannelFlag(iChannels);
        % Concatenate all data in the same structure (F = [nEpoch x nChan x nTime])
        if strcmpi(ObjType, 'Epoched')
            tmpData.F = reshape(tmpData.F, 1, size(tmpData.F,1), size(tmpData.F,2));
            if (iFile == 1)
                DataMat = tmpData;
            else
                if ~isequal(size(DataMat.F(1,:,:)), size(tmpData.F))
                    error('All input data must have the same dimensions.');
                end
                DataMat.F = cat(1, DataMat.F, tmpData.F);
                DataMat.ChannelFlag(tmpData.ChannelFlag ~= 1) = -1;
            end
            epochsComment{iFile} = str_remove_parenth(tmpData.Comment, '(');
            epochsComment{iFile} = str_remove_parenth(epochsComment{iFile}, '[');
        else
            DataMat = tmpData;
        end
    end
% Data structures passed in input
else
    % No epochs classification
    epochsComment = [];
    % Select data channels
    DataMat.F = DataMat.F(iChannels,:);
    DataMat.ChannelFlag = DataMat.ChannelFlag(iChannels);
end

%% ===== CREATE INFO OBJECT =====
% Create info object
mneInfo = out_mne_channel(ChannelFile, iChannels);
% Unlocking Info object
mneSetStatus = py.getattr(mneInfo, '__setstate__');
mneSetStatus(py.dict(pyargs('_unlocked', true)));
% Sampling frequency
mneInfo{'sfreq'} = 1 ./ (DataMat.Time(2) - DataMat.Time(1));
% Description
mneInfo{'description'} = DataMat.Comment;
% Bad channels
iBad = find(DataMat.ChannelFlag == -1);
if ~isempty(iBad)
    mneInfo{'bads'} = py.list({ChannelMat.Channel(iBad).Name});
end
% Mark projectors as applied (data loaded with UseSSP=1)
for iProj = 1:length(mneInfo{'projs'})
    mneInfo{'projs'}{iProj}{'active'} = py.bool(true);
end
% Measurement date
if ~isempty(MeasDate)
    try
        % Read date string to a py.datetime object
        dt = py.dateutil.parser.parse(MeasDate);
        % Convert to UTC
        tz = py.datetime.datetime.now().astimezone().tzinfo;
        dt = dt.replace(pyargs('tzinfo', tz));
        dt = dt.astimezone(py.datetime.timezone(py.datetime.timedelta(0)));
        mneInfo{'meas_date'} = dt;
    catch
    end
end
% Locking Info object again
mneSetStatus(py.dict(pyargs('_unlocked', false)));

% Object: Raw
switch ObjType
    % RAW:  https://www.nmr.mgh.harvard.edu/mne/stable/generated/mne.io.Raw.html
    case 'Raw'
        % Create Raw object
        first_samp = round(DataMat.Time(1) .* mneInfo{'sfreq'});
        mneObj = py.mne.io.RawArray(pyargs(...
            'data',       bst_mat2py(DataMat.F), ...
            'info',       mneInfo, ...
            'first_samp', first_samp));

        % Add events
        for iEvt = 1:length(DataMat.Events)
            % No occurrences: skip
            if isempty(DataMat.Events(iEvt).times)
                continue;
            end
            % Get onsets
            annotOnset = DataMat.Events(iEvt).times(1,:);
            % Extended events / simple events
            if (size(DataMat.Events(iEvt).times,1) == 2)
                annotDuration = DataMat.Events(iEvt).times(2,:) - DataMat.Events(iEvt).times(1,:);
            else
                annotDuration = 0 .* annotOnset;
            end
            % Add annotations to MNE objet
            mneObj.annotations.append(annotOnset, annotDuration, repmat({DataMat.Events(iEvt).label}, 1, size(annotOnset,2)));
        end

    case 'Epoched'
        % Sort trials by type, based on the comment of the files
        evts = uint32([(1:size(DataMat.F, 1))', repmat([0, 1], size(DataMat.F, 1), 1)]);
        event_id = py.dict();
        if ~isempty(epochsComment)
            uniqueTypes = unique(epochsComment);
            for iType = 1:length(uniqueTypes)
                evts(strcmpi(epochsComment, uniqueTypes{iType}), 3) = iType;
                event_id{uniqueTypes{iType}} = uint32(iType);
            end
        end
        % Create Epoched object from concatenated trials
        mneObj = py.mne.EpochsArray(pyargs(...
            'data',     DataMat.F, ...
            'info',     mneInfo, ...
            'events',   bst_mat2py(evts, 1), ...
            'tmin',     DataMat.Time(1), ...
            'event_id', event_id));

    case 'Evoked'
        % Create Evoked object
        mneObj = py.mne.EvokedArray(pyargs(...
            'data',    DataMat.F, ...
            'info',    mneInfo, ...
            'tmin',    DataMat.Time(1), ...
            'comment', DataMat.Comment, ...
            'nave',    uint32(DataMat.nAvg)));
end


function [vertices, faces] = mergeMeshVertices(vertices, faces, vertexInds, varargin)
%MERGEMESHVERTICES Merge two vertices and removes eventual degenerated faces.
%
%   output = mergeMeshVertices(input)
%
%   Example
%   mergeMeshVertices
%
%   See also
%

% ------
% Author: David Legland
% e-mail: david.legland@inra.fr
% Created: 2019-01-31,    using Matlab 9.5.0.944444 (R2018b)
% Copyright 2019 INRA - Cepia Software Platform.

newPos = vertices(vertexInds(1), :);
if nargin > 3
    newPos = varargin{1};
end

vertices(vertexInds(1), :) = newPos;
vertices(vertexInds(2:end), :) = NaN;

% replace face-vertex indices by index of first vertex
faces(ismember(faces, vertexInds)) = vertexInds(1);

% need to check existence of degenerated faces with same vertex twice
nFaces = size(faces, 1);
dgnFaces = false(nFaces, 1);
dims = [1 2;1 3;2 3];
for i = 1:3
    dgnFaces = dgnFaces | faces(:,dims(i,1)) == faces(:,dims(i,2));
end

% remove degenerated faces
faces(dgnFaces, :) = [];


function value = i4_huge ( )

%*****************************************************************************80
%
%% I4_HUGE returns a "huge" I4.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    10 April 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer VALUE, a huge integer.
%
  value = 2147483647;

  return
end


% Compiles all mex routines that are part of toolbox.
%
% If you get warnings about "omp.h", your compiler may lack default OpenMp
% support (for info about OpenMP see http://en.wikipedia.org/wiki/OpenMP).
% To compile without OpenMP alter code below to 'useOmp(:)=0'; and re-run
% toolboxCompile. Note that this will disable parallelization and make some
% routines (in particular training certain classifier) much slower.
%
% USAGE
%  toolboxCompile
%
% INPUTS
%
% OUTPUTS
%
% EXAMPLE
%
% See also
%
% Piotr's Computer Vision Matlab Toolbox      Version 3.30
% Copyright 2014 Piotr Dollar.  [pdollar-at-gmail.com]
% Licensed under the Simplified BSD License [see external/bsd.txt]

% compile options including openmp support for C++ files
opts = {'-output'};
if(exist('OCTAVE_VERSION','builtin')), opts={'-o'}; end
if( ispc ), optsOmp={'OPTIMFLAGS="$OPTIMFLAGS','/openmp"'}; else
  optsOmp={'CXXFLAGS="\$CXXFLAGS','-fopenmp"'};
  optsOmp=[optsOmp,'LDFLAGS="\$LDFLAGS','-fopenmp"'];
end
optsOmp=[optsOmp '-DUSEOMP'];

% list of files (missing /private/ part of directory)
fs={'channels/convConst.cpp', 'channels/gradientMex.cpp',...
  'channels/imPadMex.cpp', 'channels/imResampleMex.cpp',...
  'channels/rgbConvertMex.cpp', 'classify/binaryTreeTrain1.cpp', ...
  'classify/fernsInds1.c', 'classify/forestFindThr.cpp',...
  'classify/forestInds.cpp', 'classify/meanShift1.c',...
  'detector/acfDetect1.cpp', 'images/assignToBins1.c',...
  'images/histc2c.c', 'images/imtransform2_c.c', ...
  'images/nlfiltersep_max.c', 'images/nlfiltersep_sum.c', ...
  'videos/ktComputeW_c.c', 'videos/ktHistcRgb_c.c', ...
  'videos/opticalFlowHsMex.cpp' };
n=length(fs); useOmp=zeros(1,n); if(~ismac), useOmp([6 9])=1; end

% compile every funciton in turn (special case for dijkstra)
disp('Compiling Piotr''s Toolbox.......................');
rd=fileparts(mfilename('fullpath')); rd=rd(1:end-9); tic;
errmsg=' -> COMPILE FAILURE: ''%s'' %s\n';
for i=1:n
  try %#ok<ALIGN>
    [d,f1,e]=fileparts(fs{i}); f=[rd '/' d '/private/' f1];
    if(useOmp(i)), optsi=[optsOmp opts]; else optsi=opts; end
    fprintf(' -> %s\n',[f e]); mex([f e],optsi{:},[f '.' mexext]);
  catch err, fprintf(errmsg,[f1 e],err.message); end
end
try %#ok<ALIGN>
  d=[rd '/matlab/private/']; fprintf(' -> %s\n',[d 'dijkstra1.cpp']);
  mex([d 'fibheap.cpp'], [d 'dijkstra1.cpp'], '-largeArrayDims', ...
    opts{:}, [d 'dijkstra1.' mexext]);
catch err, fprintf(errmsg,[f1 e],err.message); end
disp('..................................Done Compiling'); toc;