function OutputFiles = bst_project_sources( ResultsFile, destSurfFile, isAbsoluteValues, isInteractive )
% BST_PROJECT_SOURCES: Project source files on a different surface (currents or timefreq).
%
% USAGE:  OutputFiles = bst_project_sources( ResultsFile, DestSurfFile, isAbsoluteValues=0, isInteractive=1 )
%
% INPUT:
%    - ResultsFile      : Relative path to sources file to reproject
%    - destSurfFile     : Relative path to destination surface file
%    - isAbsoluteValues : If 1, interpolate absolute values of the sources instead of relative values
%    - isInteractive    : If 1, displays questions and dialog boxes
%                         If 0, consider that it is running from the process interface

% @=============================================================================
% 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, 2010-2016

%% ===== PARSE INPUTS ======
if (nargin < 4) || isempty(isInteractive)
    isInteractive = 1;
end
if (nargin < 3) || isempty(isAbsoluteValues)
    isAbsoluteValues = 0;
end

%% ===== GROUP BY SURFACES =====
% Group the results files to process by the surface on which they were computed
% Objective: Computing only once the transformation for all the files in the same group
ResultsGroups = {};
SurfaceGroups = {};
nGroup = 0;
OutputFiles = {};
errMsg = [];
HeadModelType = [];
% Display progress bar
if isInteractive
    bst_progress('start', 'Project sources', 'Initialization...');
end
% Get file type: results or timefreq
isTimefreq = strcmpi(file_gettype(ResultsFile{1}), 'timefreq');
% For each sources file: get surface
for iRes = 1:length(ResultsFile)
    % Read surface file
    if isTimefreq
        ResMat = in_bst_timefreq(ResultsFile{iRes}, 0, 'SurfaceFile', 'DataType', 'DataFile', 'HeadModelType');
        % Check the data type: timefreq must be source/surface based, and no kernel-based file
        if ~strcmpi(ResMat.DataType, 'results')
            errMsg = 'Only cortical maps can be projected.';
            bst_report('Error', 'process_project_sources', ResultsFile{iRes}, errMsg);
            continue;
        elseif ~isempty(strfind(ResultsFile{iRes}, '_KERNEL_'))
            errMsg = 'Cannot re-project kernel-based time-frequency cortical maps.';
            bst_report('Error', 'process_project_sources', ResultsFile{iRes}, errMsg);
            continue;
        elseif isempty(ResMat.SurfaceFile) && ~isempty(ResMat.DataFile)
            ResAssocMat = in_bst_results(ResMat.DataFile, 0, 'SurfaceFile');
            ResMat.SurfaceFile = ResAssocMat.SurfaceFile;
        end
        % Load related source file
        if ~isempty(ResMat.DataFile) && isempty(ResMat.HeadModelType)
            [AssociateMat,AssociateFile] = in_bst_results(ResMat.DataFile, 0, 'HeadModelType');
            ResMat.HeadModelType = AssociateMat.HeadModelType;
        end
    else
        ResMat = in_bst_results(ResultsFile{iRes}, 0, 'SurfaceFile', 'HeadModelType');
    end

    % Default HeadModelType: surface
    if ~isfield(ResMat, 'HeadModelType') || isempty(ResMat.HeadModelType)
        ResMat.HeadModelType = 'surface';
    % Else : Check the type of grid (skip volume head models)
    elseif ismember(ResMat.HeadModelType, {'volume'})
        wrnMsg = ['To project source grids, see online tutorial "Group analysis: Subjects corergistration":' 10 ...
                  'https://neuroimage.usc.edu/brainstorm/Tutorials/CoregisterSubjects#Volume_source_models' 10 ...
                  'Skipping file: "' ResultsFile{iRes} '"...'];
        if isInteractive
            disp(wrnMsg);
        else
            bst_report('Error', 'process_project_sources', ResultsFile{iRes}, wrnMsg);
        end
        continue;
    end
    % Check head model type: must be the same for all the files
    if isempty(HeadModelType)
        HeadModelType = ResMat.HeadModelType;
    elseif ~isempty(ResMat.HeadModelType) && ~isequal(HeadModelType, ResMat.HeadModelType)
        errMsg = 'All the source files must be of the type (surface, volume or mixed).';
        bst_report('Error', 'process_project_sources', ResultsFile{iRes}, errMsg);
        continue;
    end

    % Associated surface not defined: error
    if isempty(ResMat.SurfaceFile)
        errMsg = 'Associated surface file is not defined.';
        bst_report('Error', 'process_project_sources', ResultsFile{iRes}, errMsg);
        continue;
    end
    % Check that it is not the destination surface
    if file_compare(ResMat.SurfaceFile, destSurfFile)
        if isInteractive
            disp(['BST> WARNING: Source and destination surfaces are the same for file: ' ResultsFile{iRes}]);
        else
            errMsg = 'Source and destination surfaces are the same.';
            bst_report('Error', 'process_project_sources', ResultsFile{iRes}, errMsg);
        end
        continue;
    end
    % Look for surface filename in SurfaceGroups
    iGroup = find(file_compare(ResMat.SurfaceFile, SurfaceGroups));
    % If does not exist yet: create it
    if isempty(iGroup)
        nGroup = nGroup + 1;
        SurfaceGroups{nGroup} = ResMat.SurfaceFile;
        ResultsGroups{nGroup} = ResultsFile(iRes);
    % Group exist: add file to the group
    else
        ResultsGroups{iGroup}{end+1} = ResultsFile{iRes};
    end
end
% If destination surface = source surface for all files
if (nGroup == 0)
    if isempty(errMsg)
        errMsg = ['Source and destination surfaces are the same for all the selected files.' 10 'Nothing to project...'];
    end
    if isInteractive
        bst_error(errMsg, 'Project sources', 0);
        bst_progress('stop');
    else
        bst_report('Error', 'process_project_sources', ResultsFile, errMsg);
    end
    return;
end
% Get protocol folders
ProtocolInfo = bst_get('ProtocolInfo');

%% ===== PROJECT SOURCES =====
isStopWarped = [];
iUpdatedStudies = [];
% Process each surface group
for iGroup = 1:nGroup
    % ===== GET INTERPOLATION =====
    srcSurfFile = SurfaceGroups{iGroup};
    if isInteractive
        bst_progress('start', 'Project sources', 'Loading surfaces...');
    end
    % Compute interpolation
    [WmatSurf, sSrcSubj, sDestSubj, srcSurfMat, destSurfMat, isStopWarped] = tess_interp_tess2tess(srcSurfFile, destSurfFile, isInteractive, isStopWarped);
    % Source subject and destination subject are the same
    isSameSubject = file_compare(sSrcSubj.FileName, sDestSubj.FileName);

    % ===== CREATE GROUP ANALYSIS SUBJECT =====
    % If src and dest subjects are not the same: create a "group analysis" subject
    if ~isSameSubject
        % If the destination is the group analysis subject: replace its name
        if strcmpi(sSrcSubj.Name, bst_get('DirDefaultSubject'))
            sSrcSubj.Name = bst_get('NormalizedSubjectName');
        end
        % If the destination is the group analysis subject: replace its name
        if strcmpi(sDestSubj.Name, bst_get('DirDefaultSubject'))
            sDestSubj = bst_get('NormalizedSubject');
            sDestSubj.Name = bst_get('NormalizedSubjectName');
        end
    end

    % ===== PROCESS EACH FILE =====
    nFile = length(ResultsGroups{iGroup});
    if isInteractive
        bst_progress('start', 'Project sources', 'Projecting sources...', 0, nFile);
    end
    % Process each results file in group
    for iFile = 1:nFile
        % Progress bar
        ResultsFile = ResultsGroups{iGroup}{iFile};
        if isInteractive
            bst_progress('inc', 1);
        end
        bst_progress('text', sprintf('Processing file #%d/%d: %s', iFile, nFile, ResultsFile));

        % ===== OUTPUT STUDY =====
        % Get source study
        [sSrcStudy, iSrcStudy] = bst_get('AnyFile', ResultsFile);
        % If result has to be save in "group analysis" subject
        if ~isSameSubject
            % New condition name
            NewCondition = strrep(sSrcStudy.Condition{1}, '@raw', '');
            % Get condition
            [sDestStudy, iDestStudy] = bst_get('StudyWithCondition', [sDestSubj.Name '/' NewCondition]);
            % Create condition if doesnt exist
            if isempty(iDestStudy)
                iDestStudy = db_add_condition(sDestSubj.Name, NewCondition, 0);
                if isempty(iDestStudy)
                    error(['Cannot create condition: "' normSubjName '/' NewCondition '".']);
                end
                sDestStudy = bst_get('Study', iDestStudy);
            end
        % Else: use the source study as output study
        else
            sDestStudy = sSrcStudy;
            iDestStudy = iSrcStudy;
        end

        % ===== LOAD INPUT FILE =====
        % Time-freq files
        if isTimefreq
            % Load file
            ResultsMat = in_bst_timefreq(ResultsFile, 0);
            ResFile = ResultsFile;
            % Change number of sources
            ResultsMat.RowNames = 1:size(ResultsMat.TF,1);
        % Source files: Read full
        else
            % Load file
            [ResultsMat,ResFile] = in_bst_results(ResultsFile, 1);
            % If it depends on the data file: try to use the comment of the data file
            if ~isempty(ResultsMat.DataFile) && strcmpi(file_gettype(ResultsMat.DataFile), 'data')
                % Find parent file in database
                [sStudy, iStudy, iData] = bst_get('DataFile', ResultsMat.DataFile);
                % If file was found: use its comment
                if ~isempty(sStudy) && ~isempty(sStudy.Data(iData).Comment)
                    ResultsMat.Comment = sStudy.Data(iData).Comment;
                end
            end
            % Unconstrained sources: Make a flat map
            if (ResultsMat.nComponents ~= 1)
                % Display warning before flattening, as this is not obvious
                strWarn = 'Unconstrained source maps are flattened (norm of the three orientations) before projection.';
                bst_report('Warning', 'process_project_sources', ResultsFile, strWarn);
                disp(['BST> Warning: ' strWarn]);
                % Apply norm of the three orientations
                ResultsMat = process_source_flat('Compute', ResultsMat);
            % Compute absolute values
            elseif isAbsoluteValues
                ResultsMat.ImageGridAmp = abs(ResultsMat.ImageGridAmp);
            end

            ResultsMat.ChannelFlag = [];
            ResultsMat.GoodChannel = [];
        end
        % Remove link with original file
        ResultsMat.DataFile = [];
        % Check if the file was reprojected on an atlas
        if isfield(ResultsMat, 'Atlas') && ~isempty(ResultsMat.Atlas)
            wrnMsg = ['Cannot process atlas-based source files: Skipping file "' ResultsFile '"...'];
            if isInteractive
                disp(wrnMsg);
            else
                bst_report('Error', 'process_project_sources', ResultsFile, wrnMsg);
            end
            continue;
        end

        % ===== INTERPOLATION MATRIX =====
        % Surface source model: Simply use the surface-surface interpolation
        if strcmpi(HeadModelType, 'surface')
            Wmat = WmatSurf;
        % Mixed source models: Compute volume grid interpolations
        elseif strcmpi(HeadModelType, 'mixed')
            % Load MRI files
            sMriSrc  = in_mri_bst(sSrcSubj.Anatomy(sSrcSubj.iAnatomy).FileName);
            sMriDest = in_mri_bst(sDestSubj.Anatomy(sDestSubj.iAnatomy).FileName);
            % Compute interpolation
            [Wmat, destGridAtlas, destGridLoc, destGridOrient] = tess_interp_mixed(ResultsMat, WmatSurf, srcSurfMat, destSurfMat, sMriSrc, sMriDest, isInteractive);
            % Update output structure
            ResultsMat.GridAtlas  = destGridAtlas;
            ResultsMat.GridLoc    = destGridLoc;
            ResultsMat.GridOrient = destGridOrient;
%             % Check if there is a "Source model" atlas available
%             iModelSrc  = find(strcmpi({srcSurfMat.Atlas.Name}, 'Source model'));
%             iModelDest = find(strcmpi({destSurfMat.Atlas.Name}, 'Source model'));
%             if isempty(iModelDest) && ~isempty(iModelSrc)
%                 destSurfMat.Atlas(end+1) = srcSurfMat.Atlas(iModelSrc);
%             end
        else
            error(['Unsupported head model type: ' HeadModelType]);
        end

        % ===== PROJECT SOURCE MAPS =====
        % Time-freq file
        if isTimefreq
            % Apply interpolation matrix
            tmpTF = zeros(size(Wmat,1), size(ResultsMat.TF,2), size(ResultsMat.TF,3));
            for iFreq = 1:size(ResultsMat.TF,3)
                tmpTF(:,:,iFreq) = Wmat * ResultsMat.TF(:,:,iFreq);
            end
            ResultsMat.TF = tmpTF;
            % PAC: Apply interpolation to all measures
            if isfield(ResultsMat, 'sPAC') && ~isempty(ResultsMat.sPAC)
                if isfield(ResultsMat.sPAC, 'NestingFreq') && ~isempty(ResultsMat.sPAC.NestingFreq)
                    ResultsMat.sPAC.NestingFreq = Wmat * ResultsMat.sPAC.NestingFreq;
                end
                if isfield(ResultsMat.sPAC, 'NestedFreq') && ~isempty(ResultsMat.sPAC.NestedFreq)
                    ResultsMat.sPAC.NestedFreq = Wmat * ResultsMat.sPAC.NestedFreq;
                end
                if isfield(ResultsMat.sPAC, 'DirectPAC') && ~isempty(ResultsMat.sPAC.DirectPAC)
                    tmpTF = zeros(size(Wmat,1), size(ResultsMat.sPAC.DirectPAC,2), size(ResultsMat.sPAC.DirectPAC,3), size(ResultsMat.sPAC.DirectPAC,4));
                    for iLow = 1:size(ResultsMat.sPAC.DirectPAC,3)
                        for iHigh = 1:size(ResultsMat.sPAC.DirectPAC,4)
                            tmpTF(:,:,iLow,iHigh) = Wmat * ResultsMat.sPAC.DirectPAC(:,:,iLow,iHigh);
                        end
                    end
                    ResultsMat.sPAC.DirectPAC = tmpTF;
                end
            end
            ResultsMat.HeadModelType = HeadModelType;
            if ~isempty(ResultsMat.GridLoc) && (length(ResultsMat.RowNames) ~= size(ResultsMat.GridLoc,1))
                ResultsMat.RowNames = 1:size(ResultsMat.GridLoc,1);
            elseif isequal(ResultsMat.DataType, 'results') && isnumeric(ResultsMat.RowNames) && (length(ResultsMat.RowNames) ~= size(ResultsMat.TF,1))
                ResultsMat.RowNames = 1:size(ResultsMat.TF,1);
            end
        % Source file
        else
            % Apply interpolation matrix
            ResultsMat.ImageGridAmp = muliplyInterp(Wmat, double(ResultsMat.ImageGridAmp), ResultsMat.nComponents);

            % Apply interpolation to standart deviation matrix
            if isfield(ResultsMat, 'Std') && ~isempty(ResultsMat.Std)
                ResultsMat.Std = muliplyInterp(Wmat, double(ResultsMat.Std), ResultsMat.nComponents);
            end
            ResultsMat.ImagingKernel = [];
        end

        % === SAVE NEW RESULTS ===
        % Get source filename
        [tmp__, oldBaseName] = bst_fileparts(ResFile);
        % Remove KERNEL tag for saving full source files
        if ~isempty(strfind(oldBaseName, '_KERNEL_')) && isfield(ResultsMat, 'ImageGridAmp') && ~isempty(ResultsMat.ImageGridAmp)
            oldBaseName = strrep(oldBaseName, '_KERNEL', '');
        end
        % Prepare structure to be saved
        ResultsMat.SurfaceFile = destSurfFile;
        if ~isSameSubject
            ResultsMat.Comment = [sSrcSubj.Name '/' ResultsMat.Comment];
            newResultsFile = sprintf('%s_%s.mat', oldBaseName, file_standardize(sSrcSubj.Name));
        else
            ResultsMat.Comment = [ResultsMat.Comment ' | ' destSurfMat.Comment];
            newResultsFile = sprintf('%s_%dV.mat', oldBaseName, length(destSurfMat.Vertices));
        end
        % Surface file
        ResultsMat.SurfaceFile = file_win2unix(destSurfFile);
        % History: project source
        ResultsMat = bst_history('add', ResultsMat, 'project', ['Project sources: ' srcSurfFile ' => ' ResultsMat.SurfaceFile]);
        % Build full filename
        newResultsFileFull = bst_fullfile(ProtocolInfo.STUDIES, bst_fileparts(sDestStudy.FileName), newResultsFile);
        newResultsFileFull = file_unique(newResultsFileFull);
        newResultsFile = file_short(newResultsFileFull);
        % Save new results file
        bst_save(newResultsFileFull, ResultsMat, 'v6');

        % === ADD FILE IN DATABASE ===
        % Create Results/Timefreq structure for database
        if isTimefreq
            sNewResults = db_template('Timefreq');
            sNewResults.FileName = newResultsFile;
            sNewResults.Comment  = ResultsMat.Comment;
            sNewResults.DataFile = ResultsMat.DataFile;
            sNewResults.DataType = ResultsMat.DataType;
            % If filename already exists in this study
            iExistingRes = find(file_compare({sDestStudy.Timefreq.FileName}, newResultsFile));
            if ~isempty(iExistingRes)
                % Replace previous Results
                sDestStudy.Timefreq(iExistingRes) = sNewResults;
            else
                % Add new result
                sDestStudy.Timefreq(end + 1) = sNewResults;
            end
        else
            sNewResults = db_template('Results');
            sNewResults.FileName = newResultsFile;
            sNewResults.Comment  = ResultsMat.Comment;
            sNewResults.DataFile = ResultsMat.DataFile;
            sNewResults.isLink   = 0;
            sNewResults.HeadModelType = HeadModelType;
            % If filename already exists in this study
            iExistingRes = find(file_compare({sDestStudy.Result.FileName}, newResultsFile));
            if ~isempty(iExistingRes)
                % Replace previous Results
                sDestStudy.Result(iExistingRes) = sNewResults;
            else
                % Add new result
                sDestStudy.Result(end + 1) = sNewResults;
            end
        end
        % Update study in database
        bst_set('Study', iDestStudy, sDestStudy);
        iUpdatedStudies = [iUpdatedStudies, iDestStudy];
        % Add to list of returned files
        OutputFiles{end+1} = newResultsFile;
    end
end

%% ===== UDPATE DISPLAY =====
if isInteractive
    bst_progress('stop');
end
if isempty(OutputFiles)
    return;
end
% Update node
panel_protocols('UpdateNode', 'Study', unique(iUpdatedStudies));
% Select first output study
panel_protocols('SelectStudyNode', iUpdatedStudies(1));
% Select first output file
panel_protocols('SelectNode', [], OutputFiles{1});
% Save database
db_save();

end

%% ===== APPLY INTERPOLATION MATRIX =====
function B = muliplyInterp(W, A, nComponents)
    switch (nComponents)
        case {0, 1}
            B = double(W * A);
        case 2
            B = zeros(2 * size(W,1), size(A,2));
            B(1:2:end,:) = double(W * A(1:2:end,:));
            B(2:2:end,:) = double(W * A(2:2:end,:));
        case 3
            B = zeros(3 * size(W,1), size(A,2));
            B(1:3:end,:) = double(W * A(1:3:end,:));
            B(2:3:end,:) = double(W * A(2:3:end,:));
            B(3:3:end,:) = double(W * A(3:3:end,:));
    end
    B = double(B);
end


function [newMap] = colorSubsystemCD(map, model, subsystem, color, areaWidth)
% Color and increase areaWidth of every reaction in a specific subsystem
%
% USAGE:
%
%   [newMap] = colorSubsystemCD(map, model, subsystem, color, areaWidth);
%
% INPUTS:
%   map:            File from CellDesigner parsed to MATLAB format
%   model:          COBRA model structure
%   subsystem:      Name of a subsystem as a String
%
% OPTIONAL INPUTS:
%   color:          Color desired for reactions in CAPITALS
%   areaWidth:          Width desired for reactions
%
% OUTPUT:
%   newMap          MATLAB structure of map with reaction modifications
%
% .. Authors:
%       - A.Danielsdottir 17/07/2017 LCSB. Belval. Luxembourg
%       - N.Sompairac - Institut Curie, Paris, 11/10/2017.

    if nargin < 5
        areaWidth = 8;
    end
    if nargin < 4
        color = 'RED';
    end

    newMap = map;
    rxnList = model.rxns(ismember([model.subSystems{:}]', subsystem));
    colors = createColorsMap;

    index = find(ismember(newMap.rxnName, rxnList));
    for j = index'
        newMap.rxnColor{j, 1} = colors(color);
        newMap.rxnWidth{j, 1} = areaWidth;
    end

    % Use the existence of reactant lines to check if the map has the
    % complete structure, and if so change also secondary lines.
    if any(strcmp('rxnReactantLineColor', fieldnames(newMap))) == 1
        for j = index'
            if ~isempty(newMap.rxnReactantLineColor{j})
                for k = 1:length(newMap.rxnReactantLineColor{j})
                    newMap.rxnReactantLineColor{j, 1}{k, 1} = colors(color);
                    newMap.rxnReactantLineWidth{j, 1}{k, 1} = areaWidth;
                end
            end
            if ~isempty(newMap.rxnProductLineColor{j})
                for m = 1:1:length(newMap.rxnProductLineColor{j})
                    newMap.rxnProductLineColor{j, 1}{m, 1} = colors(color);
                    newMap.rxnProductLineWidth{j, 1}{m, 1} = areaWidth;
                end
            end
        end
    end

end


clear; clc;
disp('compile native libraries')
mex -O -largeArrayDims sparse_inp.c
mex -O -largeArrayDims sparse_update.c
disp('done compiling.')
test_consist1();
test_consist2();


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This file is part of OLPS: http://OLPS.stevenhoi.org/
% Original authors: Doyen Sahoo
% Contributors: Bin LI, Steven C.H. Hoi
% Change log:
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [ ] = experimenterMenu( job )

    % The job must contain:
    % 1. Array of algorithm IDs
    % 2. Default parameters for each algorithm
    % 3. The dataset choice

    % Read configuration
    load ../GUI/config/config.mat;

    menuId = 3; % Experimenter Menu
    displayMenu(menuId); %

    prompt = 'Please enter your choice (1-5):';
    choice = input(prompt);

    switch(choice),
        case 1,
            % Select Algorithms
            job     = selectAlgorithms (job);
            experimenterMenu( job );

        case 2,
            % Set Parameters
            disp('The current job is:');
            displayExperimenterJob(job);
            prompt = 'Which Algorithm Parameters do you want to change: ';
            choice = input(prompt);
            [ parameters ] = selectParameters(job.algorithmId(choice));

            p = length(parameters);
            for i = 1:1:p
                job.parameters(choice,i) = num2cell(parameters(i));
            end
            experimenterMenu(job);

        case 3
            % Select dataset
            [ dataId ] = dataSelectMenu(dataList );
            if dataId ~= -1
                job.datasetId   = dataId;
                DL              = char(dataList);
                job.dataset     = DL(job.datasetId,:);
            end
            experimenterMenu( job );

        case 4,
            % Look at current job set by the user
            displayExperimenterJob(job);
            experimenterMenu( job);

        case 5,
            % START EXECUTION
            fprintf('Executing Algorithms...\n');
            nAlgos  = length(job.algorithmId);

            % Load the configuration
            load ../GUI/config/config.mat;
            % Add the strategy library
            addpath('../GUI/lib');
            addpath('../Strategy');
            % Confirm the dataset
            load(strcat('../Data/', char(dataName(job.datasetId))));

            % Setting options
            opts.quiet_mode = 1; opts.display_interval = 500;
            opts.log_mode = 1; opts.mat_mode = 1;
            opts.analyze_mode = 1;
            opts.his = 0;
            opts.progress = 1;

            for i = 1:1:nAlgos
                % Construct input for the i-th algo, and execute

                msg = 'Running the ';
                msg = strcat(msg, num2str(i));
                msg = strcat(msg, '-th Algorithm ...');
                disp(msg);

                % Confirm the algorithm
                strategy_name = char(algorithmName(job.algorithmId(i)));
                % Confirm the parameters
                inputs = (job.parameters(i,:));

                strategy_fun = [strategy_name '(1, data, inputs, opts)'];
                [stats(:, i), cumprod_ret(:,i), daily_ret(:,i), daily_portfolio{i}] = eval(strategy_fun);
                returns = daily_ret - 1;
                portfolio = daily_portfolio;
                chosenStrategy = algorithmList{job.algorithmId};
            end

            % Construct the results data structure
            r.daily_ret             = daily_ret-1;
            r.cum_ret               = cumprod(daily_ret);
            r.daily_portfolio       = daily_portfolio;
            r.selectedAlgorithms    = job.algorithmId;
            r.dataFrequency         = dataFrequency(job.datasetId);
            displayTable2(r);
            resultManager2(r,job);

        case 6,
            disp('Exiting Experimenter --> to Home');
            homeMenu;

        otherwise,
            disp('ERROR: Please enter a valid input');
            experimenterMenu;
    end
end

%% Menu for Selecting Dataset
function [ dataId ] = dataSelectMenu(dataList )
% Display algorithm lsit, and ask user to select the method

    menuId = 5; % DataList
    displayMenu(menuId);
    numberOfDatasets = length(dataList);

    prompt  = strcat('Please enter your choice of Dataset (1-', num2str(numberOfDatasets));
    prompt  = strcat(prompt, '):');
    choice  = input(prompt);

    if choice >= 1 && choice <= numberOfDatasets
        dataId  = choice;
        msg     = strcat('You have selected: ', dataList(dataId));
        fprintf('\n');
        disp(char(msg));
        disp('Returning back to Algorithm Analyser...');
    else
        disp('ERROR: Please enter a valid input');
        dataId = dataSelectMenu( dataList );
    end
end

function [ job ] = selectAlgorithms( job )

    load ../GUI/config/config.mat;
    menuId = 9; % AlgorithmList for Experimenter
    displayMenu(menuId);
    numberOfAlgorithms  = length(algorithmList);
    numberSelected      = length(job.algorithmId);
    disp('Currently Selected Algorithms:');
    disp(job.algorithmId);

    msg         = 'Please Enter the Strategy IDs that you want to compare (1:';
    msg         = strcat(msg, num2str(numberOfAlgorithms));
    msg         = strcat(msg, ')');
    msg         = strcat(msg,'\nEg. To compare Strategies 1, 3, 4, 5, type: [1, 3, 4, 5]\n');
    selected    = input(msg);

    job.algorithmId = sort(selected);
    job.algorithmId = unique(selected);
    job.parameters  = {};
    % Add parameters
    numberSelected = length(job.algorithmId);
    for i = 1:1:numberSelected
        job.parameters(i,:) = defaultParameters(job.algorithmId(i),:);
    end
end

function [ ] = displayExperimenterJob( job )

    load ../GUI/config/config.mat;
    fprintf('\n');
    fprintf('________________________________________');
    fprintf('\n\t\t\t CURRENT JOB \n');

    nAlgos = length(job.algorithmId);
    fprintf('Algorithms: \n');
    fprintf('______________\n');
    for i = 1:1:nAlgos
        id = job.algorithmId(i);
        msg = strcat(num2str(i), '.');
        msg = strcat(msg,algorithmList{id});
        fprintf(msg);
        fprintf('\n');
        displayParameters(job, i);
        fprintf('______________\n');
    end

    fprintf('\n');
    fprintf(strcat('Dataset: \t', char(dataList(job.datasetId))));
    fprintf('\n');

    fprintf('________________________________________');
    fprintf('\n');
end

function [ ] = displayParameters( job, index )
    load ../GUI/config/config.mat;

    names           = algorithmParameters(job.algorithmId(index),:);
    numParameters   = length(cell2mat((job.parameters(index,:))));

    for i = 1:1:numParameters
        line = char(names(i));
        line = strcat(line, '\t=\t');
        line = strcat(line, num2str(cell2mat(job.parameters(index,i))));
        line = strcat(line, '\n');
        fprintf(line);
    end
end

function [ parameters ] = selectParameters(algoId)
% The interface for the user to input parameters for the algorithm
% currently selected.

    load ../GUI/config/config.mat;
    disp('________________________________________________________');
    disp('Please Enter the new values of parameters for Algorithm:');
    algo    = char(algorithmList(algoId));
    fprintf(strcat(strcat('Algorithm:\t',algo), '\n'));

    defaultParameters   = cell2mat(defaultParameters(algoId,:));
    numberOfParmeters   = length(defaultParameters);

    for i = 1:1:numberOfParmeters

        parameterName   = algorithmParameters(algoId, i);
        parameterName   = parameterName{1};

        msg = strcat(num2str(i), ')');
        msg = strcat(msg, parameterName);
        msg = strcat(msg, '(current value = ');
        msg = strcat(msg, num2str(defaultParameters(i)));
        msg = strcat(msg, '): ');

        parameters(i) = input(msg);

    end
    disp('________________________________________________________');
end


function [vid_h_org, vid_l_bic] = load_video(dirFile,nFrames,upscale,part,param)

vid_h_org = [];
vid_l_bic = [];

for i = 1:nFrames
    filename = sprintf('original/Frame %03d.png', i);
    fullname = strcat(dirFile,filename);
    tmp = im2double(imread(fullname,'png'));
    [M N] = size(tmp(:,:,1));
    switch part
        case 1
            vid_h_org{i} = tmp;
        case 2
            vid_h_org{i} = imresize(tmp, 1/2);
        case 3 % half x half (288x352)
            vid_h_org{i} = tmp(1:M/2,1:N/2,:);
        case 4 % quarter x quarter (144x176)
            vid_h_org{i} = tmp(1:M/4,1:N/4,:);
        case 5 % 64x64
            vid_h_org{i} = tmp(65:128,1:64,:);
        case 6 % 32x64
            vid_h_org{i} = tmp(65:96,1:64,:);
    end
    vid_l_bic{i} = imresize(vid_h_org{i}, 1/upscale);
end

if param.SHOW_IMAGE
    figure(1), imshow(vid_h_org{1}); title('original (frame1)');
end


function varargout=randfilt(varargin)
%
% For calling details please see v_randfilt.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_randfilt.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: randfilt.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_randfilt(varargin{:});
else
    v_randfilt(varargin{:});
end


classdef KSPTOT_AppOptions < handle
    %KSPTOT_AppOptions Summary of this class goes here
    %   Detailed explanation goes here

    properties
        %KSPTOT Options
        bodiesinifile
        rtshostname
        timesystem char
        gravparamtype char

        plotmaxdeltav double
        porkchopptsaxes double
        porkchopnumsynperiods double
        departplotnumoptiters double
        quant2opt char

        %LVD Options
        lvdrecentmsncasefiles(1,:) char = '';
    end

    events
        GravParamTypeUpdated
        TimeSystemUpdated
    end

    methods
        function obj = KSPTOT_AppOptions()

        end
    end
end


% Imports a ROS bag cotaining event data recorded with the rpg_dvs_ros
% driver into the same workspace structure as ImportAedat uses.
%
% Code taken from ConvertRosbagToAedat, written by Guillermo Gallego
%
% RPG DVS/DAVIS driver for ROS:
% https://github.com/uzh-rpg/rpg_dvs_ros
% Currently, the code assumes that the ROS data is published/stored in the
% dafault topic names: /dvs/events, /dvs/image_raw and /dvs/imu
%
% To read ROS bags, you need to have in the matlab path the library
% https://github.com/bcharrow/matlab_rosbag/releases
%
% AEDAT 2.0 format is explained in:
% https://inilabs.com/support/software/fileformat/#h.4ydb2xpu03ik
% Timestamps tick is 1 microsecond
%
% Input:
% aedat struct, containing at least field 'importParams',
% containing at least field 'filePath': full name and path of the ROS bag (dataset) to read
%
% Output:
% aedat: data structure used in AedatTools with information and
% content of the input dataset.
%
% Guillermo Gallego
% e-mail: guillermo.gallego@ifi.uzh.ch

function aedat = ImportRosbag(aedat)

if ~isfield(aedat, 'importParams') || ~isfield(aedat.importParams, 'filePath')
    error('No filename')
end

% Load a bag and get information about it
bag = ros.Bag.load(aedat.importParams.filePath);
bag.info()

% Start to fill in aedat structure, for conversion
aedat.data = [];

%% Default ROS topics with the published data
topic_events = '/dvs/events';
topic_images = '/dvs/image_raw';
topic_imu = '/dvs/imu';

%% Get first timestamp of the bag so that it is subtracted from all timestamps
% and hence the 32 bits of the timestamps are better used
bag.resetView({topic_events, topic_images, topic_imu});
msg = bag.read();
% IMU or image messages have the timestamp in the header
% Event messages have header timestamp empty
if isfield(msg, 'events')
    % first message is a packet of events
    time_first_sec_uint32 = uint32( msg.events(3,1) );
else
    % first message is image or IMU
    time_first_sec_uint32 = msg.header.stamp.sec;
end

margin = 10; % some margin. Maybe some events happen before this time
if time_first_sec_uint32 > margin
    time_first_sec_uint32 = time_first_sec_uint32 - margin;
end
bag.resetView({topic_events, topic_images, topic_imu});

%% Frames (i.e., images)
disp('Reading image topic from ROS bag');
msgs = bag.readAll(topic_images);
num_msgs = length(msgs);
disp(['Found ' num2str(num_msgs) ' frames']);
if (num_msgs > 0)
    aedat.data.frame = []; % create images struct
    aedat.data.frame.numEvents = num_msgs; % number of frames
    disp('Converting APS-frame messages...');
    img_width = double(msgs{1}.width);
    img_height = double(msgs{1}.height);
    v_zero = zeros(num_msgs,1);
    v_one = ones(num_msgs,1);
    aedat.data.frame.xPosition = uint16(v_zero);
    aedat.data.frame.yPosition = uint16(v_zero);
    aedat.data.frame.xLength = uint16(img_width * v_one); % 240
    aedat.data.frame.yLength = uint16(img_height* v_one); % 180
    for ii = 1:num_msgs
        % timestamp: remove offset, convert to microseconds and cast to uint32
        time_us = double(msgs{ii}.header.stamp.sec - time_first_sec_uint32) * 1e6 ...
            + double(msgs{ii}.header.stamp.nsec) / 1e3; % microseconds
        aedat.data.frame.timeStampStart(ii) = uint32(time_us);
        aedat.data.frame.timeStampEnd(ii) = uint32(time_us);

        img = reshape(msgs{ii}.data,img_width,img_height)';
        img = double(img) * 4; % convert from 8 bits to 10 bits: [0,255] to [0,1023]
        img = flipud(img);
        if (img_width == 346)
            % miniDAVIS346 needs to flip left-right events and frames
            img = fliplr(img);
        end
        aedat.data.frame.samples{ii,1} = img; % cell array with the grayscale values
    end
    % column vectors
    aedat.data.frame.timeStampStart = aedat.data.frame.timeStampStart';
    aedat.data.frame.timeStampEnd = aedat.data.frame.timeStampEnd';
    disp('...done!');
end

%% IMU
disp('Reading IMU topic from ROS bag');
msgs = bag.readAll(topic_imu);
num_msgs = length(msgs);
disp(['Found ' num2str(num_msgs) ' IMU samples']);
if (num_msgs > 0)
    aedat.data.imu6 = []; % create IMU struct
    aedat.data.imu6.numEvents = num_msgs; % number of measurements
    disp('Converting IMU messages...');
    % Column vectors
    v_zero = zeros(num_msgs,1);
    aedat.data.imu6.timeStamp = uint32(v_zero);
    aedat.data.imu6.accelX = v_zero;
    aedat.data.imu6.accelY = v_zero;
    aedat.data.imu6.accelZ = v_zero;
    aedat.data.imu6.gyroX = v_zero;
    aedat.data.imu6.gyroY = v_zero;
    aedat.data.imu6.gyroZ = v_zero;
    aedat.data.imu6.temperature = 28 + v_zero; % centigrades
    for ii = 1:num_msgs
        % timestamp: remove offset, convert to microseconds and cast to uint32
        time_us = double(msgs{ii}.header.stamp.sec - time_first_sec_uint32) * 1e6 ...
            + double(msgs{ii}.header.stamp.nsec) / 1e3; % microseconds
        aedat.data.imu6.timeStamp(ii) = uint32(time_us);

        aedat.data.imu6.accelX(ii) = msgs{ii}.linear_acceleration(1);
        aedat.data.imu6.accelY(ii) = msgs{ii}.linear_acceleration(2);
        aedat.data.imu6.accelZ(ii) = msgs{ii}.linear_acceleration(3);
        aedat.data.imu6.gyroX(ii) = msgs{ii}.angular_velocity(1);
        aedat.data.imu6.gyroY(ii) = msgs{ii}.angular_velocity(2);
        aedat.data.imu6.gyroZ(ii) = msgs{ii}.angular_velocity(3);
        % aedat.data.imu6.temperature(ii) = 0;
    end

    % Conversion of units.
    % Acceleration is imported as m/s^2, and aedat wants it in multiples of g
    gravity = 9.8; % m/s^2
    aedat.data.imu6.accelX = aedat.data.imu6.accelX / gravity;
    aedat.data.imu6.accelY = aedat.data.imu6.accelY / gravity;
    aedat.data.imu6.accelZ = aedat.data.imu6.accelZ / gravity;
    % Angular velocity is imported as rad/s, and aedat expects deg/s
    rad_in_deg = 180 / pi; % degrees in one radian
    aedat.data.imu6.gyroX = aedat.data.imu6.gyroX * rad_in_deg;
    aedat.data.imu6.gyroY = aedat.data.imu6.gyroY * rad_in_deg;
    aedat.data.imu6.gyroZ = aedat.data.imu6.gyroZ * rad_in_deg;

    disp('...done!');
end

%% Events
disp('Reading event topic from ROS bag');
msgs = bag.readAll(topic_events);
num_msgs = length(msgs);
disp(['Found ' num2str(num_msgs) ' event messages']);
if (num_msgs > 0)
    aedat.data.polarity = []; % create events struct
    disp('Converting event messages...');

    % Get size of the event sensor
    ev_sensor_width = double(msgs{1}.width);
    ev_sensor_height = double(msgs{1}.height);

    % Compute number of events
    numEvents = 0;
    for ii = 1:num_msgs
        numEvents = numEvents + size(msgs{ii}.events,2);
    end
    disp(['Number of events = ' num2str(numEvents)]);
    aedat.data.polarity.numEvents = numEvents;

    % Allocate memory for all events. Read events
    idx_firt_ev_msg = 1;
    for ii = 1:num_msgs
        if mod(ii,100) == 0
            disp(['Message ' num2str(ii) ' of ' num2str(num_msgs)]);
        end
        num_ev_msg = size(msgs{ii}.events,2);
        idx = idx_firt_ev_msg + (0:num_ev_msg-1)';
        idx_firt_ev_msg = idx_firt_ev_msg + num_ev_msg;

        % Read (x, y, t, polarity) of the events

        % timestamp: remove offset, convert to microseconds and cast to uint32
        time_us = (msgs{ii}.events(3,:) - double(time_first_sec_uint32)) * 1e6; % microseconds
        aedat.data.polarity.timeStamp(idx) = uint32(time_us);

        if (ev_sensor_width == 128) || (ev_sensor_width == 346)
            % DVS and miniDAVIS346 need to flip events. Don't ask why
            aedat.data.polarity.x(idx) = uint16(ev_sensor_width-1 -msgs{ii}.events(1,:));
        else
            aedat.data.polarity.x(idx) = uint16(msgs{ii}.events(1,:));
        end
        aedat.data.polarity.y(idx) = uint16(ev_sensor_height-1 -msgs{ii}.events(2,:));
        aedat.data.polarity.polarity(idx) = logical(msgs{ii}.events(4,:));
    end
    % column vectors
    aedat.data.polarity.timeStamp = aedat.data.polarity.timeStamp';
    aedat.data.polarity.x = aedat.data.polarity.x';
    aedat.data.polarity.y = aedat.data.polarity.y';
    aedat.data.polarity.polarity = aedat.data.polarity.polarity';
    disp('...done!');
end

%% Fill in additional information for aedat file
aedat.info = [];

% Set sensor size
if exist('ev_sensor_width','var') && exist('ev_sensor_height','var')
    % Get the sensor size from the event topic
    aedat.info.deviceAddressSpace = [ev_sensor_width, ev_sensor_height];
elseif exist('img_width','var') && exist('img_height','var')
    % Get the sensor size from the image topic
    aedat.info.deviceAddressSpace = [img_width, img_height];
else
    error('Could not determine the sensor size from the events or images');
end

% Set the type of sensor used, according to resolution
% See file BasicSourceName.m
sensor_size = aedat.info.deviceAddressSpace;
if (sensor_size(1) == 240) && (sensor_size(2) == 180)
    aedat.info.source = 'Davis240C';
elseif (sensor_size(1) == 346) && (sensor_size(2) == 260)
    aedat.info.source = 'Davis346BMono';
elseif (sensor_size(1) == 128) && (sensor_size(2) == 128)
    aedat.info.source = 'Dvs128';
else
    error(['Unknown sensor type for resolution: ' ...
        num2str(sensor_size(1)) ' x ' num2str(sensor_size(2)) ' pixels']);
end

% Fill in standard info
aedat = NumEventsByType(aedat);
aedat = FindFirstAndLastTimeStamps(aedat);


% PutSegyHeader : Writes SEG-Y header to disk.
% PutSegyHeader(segyid,SegyHeader)
%
  % (C) 2001-2016, Thomas Mejer Hansen, thomas.mejer.hansen@gmail.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
%
function SegyHeader=PutSegyHeader(segyid,SegyHeader);

NA=0;

if isfield(SegyHeader,'Rev')==0
  SegyHeader.Rev=GetSegyHeaderBasics;
end

if (isfield(SegyHeader,'DataSampleFormat')==0)&(isfield(SegyHeader,'SegyFormatRevisionNumber')==0)
  SegyHeader.DataSampleFormat=5; % '5'->4-byte IEEE floating point
  SegyHeader.SegyFormatRevisionNumber=256;
  SegymatVerbose([mfilename,' : Using datasample format : ',SegyHeader.Rev(2).DataSampleFormat(SegyHeader.DataSampleFormat).name],1)
  PrintSegyFormatRevsisionNumber(SegyHeader,1);
end

% SET Revsion number. Always use revision 1, if not otherwise specified.
if (isfield(SegyHeader,'SegyFormatRevisionNumber')==0)
  SegyHeader.SegyFormatRevisionNumber=256;
  PrintSegyFormatRevsisionNumber(SegyHeader,1);
end

% SET DATA SAMPLE FORMAT IF NOT SPECIFIED
% Rev0->IBM FLOATING POINT
% Rev1->IEEE FLOATING POINT
if (isfield(SegyHeader,'DataSampleFormat')==0)
  if SegyHeader.SegyFormatRevisionNumber==0
    SegyHeader.DataSampleFormat=1; % '1'->IBM floating point
    SegymatVerbose([mfilename,' : Using datasample format : ',SegyHeader.Rev(1).DataSampleFormat(SegyHeader.DataSampleFormat).name],1)
  else
    SegyHeader.DataSampleFormat=5; % '5'->4-byte IEEE floating point
    SegymatVerbose([mfilename,' : Using datasample format : ',SegyHeader.Rev(2).DataSampleFormat(SegyHeader.DataSampleFormat).name],1)
  end
end

if isfield(SegyHeader,'TextualFileHeader')
  % MAKE SURE LENGTH IF Text.. is 3200
  if length(SegyHeader.TextualFileHeader)<3200
    dummyTXT=SegyHeader.TextualFileHeader;
    SegyHeader.TextualFileHeader=zeros(3200,0);
    SegyHeader.TextualFileHeader(1:length(dummyTXT))=dummyTXT;
  end
else
  SegyHeader.TextualFileHeader=sprintf('%3200s','SEGY READER (tmh@gfy.ku.dk)');
end

if ~isfield(SegyHeader,'Job'), SegyHeader.Job=NA; end
if ~isfield(SegyHeader,'Line'), SegyHeader.Line=NA; end
if ~isfield(SegyHeader,'Reel'), SegyHeader.Reel=NA; end
if ~isfield(SegyHeader,'DataTracePerEnsemble'), SegyHeader.DataTracePerEnsemble=NA;end
if ~isfield(SegyHeader,'AuxiliaryTracePerEnsemble'), SegyHeader.AuxiliaryTracePerEnsemble=0;end
if ~isfield(SegyHeader,'dt'), SegyHeader.dt=4000; end
if ~isfield(SegyHeader,'dtOrig'), SegyHeader.dtOrig=NA; end
if ~isfield(SegyHeader,'ns'), SegyHeader.ns=NA; end
if ~isfield(SegyHeader,'nsOrig'), SegyHeader.nsOrig=NA; end
if ~isfield(SegyHeader,'DataSampleFormat'), SegyHeader.DataSampleFormat=5; end % '5'->4-byte IEEE floating point
if ~isfield(SegyHeader,'EnsembleFold'), SegyHeader.EnsembleFold=NA; end
if ~isfield(SegyHeader,'TraceSorting'), SegyHeader.TraceSorting=NA; end
if ~isfield(SegyHeader,'VerticalSumCode'), SegyHeader.VerticalSumCode=NA; end
if ~isfield(SegyHeader,'SweepFrequencyStart');SegyHeader.SweepFrequencyStart=NA; end
if ~isfield(SegyHeader,'SweepFrequencyEnd');SegyHeader.SweepFrequencyEnd=NA; end
if ~isfield(SegyHeader,'SweepLength');SegyHeader.SweepLength=NA; end
if ~isfield(SegyHeader,'SweepType');SegyHeader.SweepType=NA; end
if ~isfield(SegyHeader,'SweepChannel');SegyHeader.SweepChannel=NA; end
if ~isfield(SegyHeader,'SweepTaperlengthStart');SegyHeader.SweepTaperlengthStart=NA; end
if ~isfield(SegyHeader,'SweepTaperLengthEnd');SegyHeader.SweepTaperLengthEnd=NA; end
if ~isfield(SegyHeader,'TaperType');SegyHeader.TaperType=NA; end
if ~isfield(SegyHeader,'CorrelatedDataTraces');SegyHeader.CorrelatedDataTraces=NA; end
if ~isfield(SegyHeader,'BinaryGain');SegyHeader.BinaryGain=NA; end
if ~isfield(SegyHeader,'AmplitudeRecoveryMethod');SegyHeader.AmplitudeRecoveryMethod=NA; end
if ~isfield(SegyHeader,'MeasurementSystem');SegyHeader.MeasurementSystem=1; end %1-Meters, 2-Feet
if ~isfield(SegyHeader,'ImpulseSignalPolarity');SegyHeader.ImpulseSignalPolarity=NA; end
if ~isfield(SegyHeader,'VibratoryPolarityCode');SegyHeader.VibratoryPolarityCode=NA; end
% 3261-3500 UNASSIGNED
if ~isfield(SegyHeader,'Unassigned1');SegyHeader.Unassigned1=NA*ones(1,120); end

if ~isfield(SegyHeader,'FixedLengthTraceFlag');SegyHeader.FixedLengthTraceFlag=1; end % ALL TRACES HAVE THE SAME dt AND ns
if ~isfield(SegyHeader,'NumberOfExtTextualHeaders'); SegyHeader.NumberOfExtTextualHeaders=0; end % WE DO NOT YET USE TEXTURAL HEADERS as can be done according to draft 6
% 3506-3600 UNASSIGNED
if ~isfield(SegyHeader,'Unassigned2');SegyHeader.Unassigned2=NA*ones(1,47); end

% IF EXTENDED TEXTUAL FILE HEADERS EXISTS THEN WRITE THEM TO DISK

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% WRITE TO DISK
%

fseek(segyid,0,'bof');

fwrite(segyid,SegyHeader.TextualFileHeader(1:3200),'uchar');         % 1-3200
fwrite(segyid,SegyHeader.Job,'int32');                           % 3204

fwrite(segyid,SegyHeader.Line,'int32');                          % 3208
fwrite(segyid,SegyHeader.Reel,'int32');                          % 3212
fwrite(segyid,SegyHeader.DataTracePerEnsemble,'int16');        % 3214
fwrite(segyid,SegyHeader.AuxiliaryTracePerEnsemble,'int16');   % 3216
fwrite(segyid,SegyHeader.dt,'uint16');                          % 3218
fwrite(segyid,SegyHeader.dtOrig,'uint16');                      % 3220
fwrite(segyid,SegyHeader.ns,'uint16');                          % 3222
fwrite(segyid,SegyHeader.nsOrig,'uint16');                      % 3224
fwrite(segyid,SegyHeader.DataSampleFormat,'int16');            % 3226
fwrite(segyid,SegyHeader.EnsembleFold,'int16');
fwrite(segyid,SegyHeader.TraceSorting,'int16');               % 3228
fwrite(segyid,SegyHeader.VerticalSumCode,'int16');            % 3230

fwrite(segyid,SegyHeader.SweepFrequencyStart,'int16');        % 3232
fwrite(segyid,SegyHeader.SweepFrequencyEnd,'int16');          % 3234
fwrite(segyid,SegyHeader.SweepLength,'int16');                % 3236
fwrite(segyid,SegyHeader.SweepType,'int16');                  % 3238
fwrite(segyid,SegyHeader.SweepChannel,'int16');               % 3240
fwrite(segyid,SegyHeader.SweepTaperlengthStart,'int16');               % 3242
fwrite(segyid,SegyHeader.SweepTaperLengthEnd,'int16');               % 3244
fwrite(segyid,SegyHeader.TaperType,'int16');               % 3246

fwrite(segyid,SegyHeader.CorrelatedDataTraces,'int16');               % 3248

fwrite(segyid,SegyHeader.BinaryGain,'int16');               % 3250
fwrite(segyid,SegyHeader.AmplitudeRecoveryMethod,'int16');               % 3252

fwrite(segyid,SegyHeader.MeasurementSystem,'int16');               % 3254

fwrite(segyid,SegyHeader.ImpulseSignalPolarity,'int16');               % 3256
fwrite(segyid,SegyHeader.VibratoryPolarityCode,'int16');               % 3258

% 3261-3500 UNASSIGNED1 => (120 int32 = 240 bytes)
fwrite(segyid,SegyHeader.Unassigned1,'int16');               % 3260
%SegymatVerbose(ftell(segyid),10);
%fseek(segyid,3500,'bof');
fwrite(segyid,SegyHeader.SegyFormatRevisionNumber,'uint16');   % 3500
fwrite(segyid,SegyHeader.FixedLengthTraceFlag,'int16');        % 3502
fwrite(segyid,SegyHeader.NumberOfExtTextualHeaders,'uint16');        % 3504

% 3506-3600 UNASSIGNED2 => 94/2=47 int16
fwrite(segyid,SegyHeader.Unassigned2,'int16');               % 3506

%
%
%
if SegyHeader.NumberOfExtTextualHeaders>0
  n=SegyHeader.NumberOfExtTextualHeaders;
  SegymatVerbose(sprintf('Writing %d Extended Textual File Headers',n));
  if isfield(SegyHeader,'ExtTextualHeader')
    % MAKE SURE LENGTH IF Text.. is 3200*n
    if length(SegyHeader.ExtTextualHeader)<(3200*n)
      dummyTXT=SegyHeader.ExtTextualHeader;
      SegyHeader.ExtTextualHeader=zeros(n*3200,0);
      SegyHeader.ExtTextualHeader(1:length(dummyTXT))=dummyTXT;
    end
  else
    SegyHeader.ExtTextualHeader=sprintf('%3200s','SEGY READER (tmh@gfy.ku.dk)');
    for i=2:n,
      SegyHeader.ExtTextualHeader=[SegyHeader.ExtTextualHeader,sprintf('%3200s','SEGY READER (tmh@gfy.ku.dk)')];
    end
  end
  % WRITE TEXTUAL FILE HEADER
  fwrite(segyid,SegyHeader.ExtTextualHeader(1:(n*3200)),'uchar');         % 1:(n*3200)
end

Revision=SegyHeader.SegyFormatRevisionNumber;
if Revision>0, Revision=1; end
Format=SegyHeader.Rev(Revision+1).DataSampleFormat(SegyHeader.DataSampleFormat).name;
SegymatVerbose([mfilename,' - SegyRevision ',sprintf('%0.4g',Revision),', ',Format],2)


function jFrame = gui_edit_channel( ChannelFile )
% GUI_EDIT_CHANNEL: Load, edit and save a channel file.
%
% USAGE: gui_edit_channel( ChannelFile )

% @=============================================================================
% 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-2018

global GlobalData;

% Progress bar
bst_progress('start', 'Channel editor', 'Initialization...');
% Check if a "Channel Editor" panel already exists
panel = bst_get('Panel', 'ChannelEditor');
% If panel exists
if ~isempty(panel)
    % Close it
    gui_hide(panel);
end
% Create new panel
bstPanel = panel_channel_editor('CreatePanel', ChannelFile);
if isempty(bstPanel)
    bst_progress('stop');
    return;
end
% Show panel in a Java window
bstContainer = gui_show(bstPanel, 'JavaWindow', ['Channel editor: ' ChannelFile], [], 0, 0, 1);
if isempty(bstContainer)
    return;
end

% Get current layout
[jBstArea, FigArea, nScreens, jFigArea, jInsets] = gui_layout('GetScreenBrainstormAreas');
% Place this figure on the screen to take all the possible figure space
jFrame = bstContainer.handle{1};
jFrame.setLocation(jFigArea.getX(), jFigArea.getY() - jInsets.bottom);
jFrame.setSize(jFigArea.getWidth(), jFigArea.getHeight());

% Set selected sensors
if ~isempty(GlobalData.DataViewer.SelectedRows)
    panel_channel_editor('SetChannelSelection', GlobalData.DataViewer.SelectedRows, 0);
end
% Progress bar
bst_progress('stop');


function ind = subsind(ebsd,subs)
% subindexing of EBSD data
%

% ordinary indexing by id
if (ischar(subs{1}) && subs{1}(1) == ':') || ...
    (isnumeric(subs{1}) && ~islogical(subs{1}))
  ind = reshape(1:length(ebsd),size(ebsd));

  ind = subsref(ind,struct('type','()','subs',{subs}));
  return

end

ind = subsind@EBSD(ebsd,subs);


function printDecodeResults(decodeData, candidates, candScores, alignInfo, params, isOutput, prefixSent)
  batchSize = size(candScores, 2);
  startId = decodeData.startId;

  % output translations
  [maxScores, bestIndices] = max(candScores, [], 1); % stackSize * batchSize
  for ii = 1:batchSize
    bestId = bestIndices(ii);
    translation = candidates{ii}{bestId};
    assert(isempty(find(translation>params.tgtVocabSize, 1)));

    if isOutput
      printSent(params.fid, translation(1:end-1), params.tgtVocab, ''); % remove <t_eos>
    end

    % log
    printSrc(params.logId, decodeData, ii, params, startId+ii-1);
    printRef(params.logId, decodeData, ii, params, startId+ii-1);
    printSent(params.logId, translation, params.tgtVocab, ['  tgt ' num2str(startId+ii-1) ': ']);
    if params.prefixDecoder
      printSent(params.logId, prefixSent, params.tgtVocab, ['  pre ' num2str(startId+ii-1) ': ']);
    end
    % align
    if params.align
      alignment = alignInfo{ii}{bestId};
      printAlign(params.logId, translation, decodeData, alignment, params, ii, startId+ii-1, 1);
      if isOutput
        printSentAlign(params.alignId, translation, decodeData, alignment, ii, params);
      end
    end
    fprintf(params.logId, '  score %g\n', maxScores(ii));

    % debug
    printSrc(2, decodeData, ii, params, startId+ii-1);
    printRef(2, decodeData, ii, params, startId+ii-1);
    printSent(2, translation, params.tgtVocab, ['  tgt ' num2str(startId+ii-1) ': ']);
    if params.prefixDecoder
      printSent(2, prefixSent, params.tgtVocab, ['  pre ' num2str(startId+ii-1) ': ']);
    end
    % align
    if params.align
      printAlign(2, translation, decodeData, alignment, params, ii, startId+ii-1, 1);
    end
    fprintf(2, '  score %g\n', maxScores(ii));
  end
end

function printSentAlign(fid, translation, data, alignment, ii, params)
  srcLen = data.srcLens(ii);
  if params.isReverse
    alignment = srcLen-alignment;
  end

  tgtLen = length(translation);
  for i = 1:(tgtLen-1)
    srcPos = alignment(i+1);
    assert((1 <= srcPos) && (srcPos <= srcLen), sprintf('Assertion failed: srcPos = %d, srcLen = %d', srcPos, srcLen));
    fprintf(fid, '%d-%d ', srcPos-1, i-1); % base 0
  end
  fprintf(fid, '\n');
end

function printAlign(fid, translation, data, alignment, params, ii, sentId, printWords)
  mask = data.srcMask(ii, :);
  srcLen = data.srcLens(ii);

  if params.isReverse
    alignment = srcLen-alignment;
  end

  tgtLen = length(translation);
  if printWords
    src = data.srcInput(ii,mask);
    if params.isReverse
      src = src(end:-1:1);
    end
    fprintf(fid, 'pairs %d: ', sentId);
    for i = 1:(tgtLen-1)
      srcPos = alignment(i+1);
      assert((1 <= srcPos) && (srcPos <= srcLen), sprintf('Assertion failed: srcPos = %d, srcLen = %d', srcPos, srcLen));
      fprintf(fid, '%s-%s ', params.srcVocab{src(srcPos)}, params.tgtVocab{translation(i)});
    end
    fprintf(fid, '\n');
  end

  fprintf(fid, 'align %d: ', sentId);
  for i = 1:(tgtLen-1)
    srcPos = alignment(i+1);
    assert((1 <= srcPos) && (srcPos <= srcLen));
    fprintf(fid, '%d-%d ', srcPos-1, i-1); % base 0
  end
  fprintf(fid, '\n');

end

function printSrc(fid, data, ii, params, sentId)
  mask = data.srcMask(ii,:);
  src = data.srcInput(ii,mask);
  printSent(fid, src, params.srcVocab, ['  src ' num2str(sentId) ': ']);

  if params.isReverse
    printSent(fid, src(end:-1:1), params.srcVocab, [' rsrc ' num2str(sentId) ': ']);
  end
end

function printRef(fid, data, ii, params, sentId)
  mask = data.tgtMask(ii, :);
  ref = data.tgtOutput(ii,mask);
  printSent(fid, ref, params.tgtVocab, ['  ref ' num2str(sentId) ': ']);
end


function [opt, isdefault]= opt_setDefaults(opt, props, check)
%OPT_SETDEFAULTS - Set default values according to a property spec list
%
%Synopsis:
%  [OPT, ISDEFAULT]= opt_setDefaults(OPT, PROPSPEC)
%  [OPT, ISDEFAULT]= opt_setDefaults(OPT, PROPSPEC, CHECK)
%
%Arguments:
%  OPT:      STRUCT of optional properties
%  PROPSPEC: PROPSPECLIST - Property specification list, i.e., CELL of size
%      [N 2] or [N 3], with the first column all being strings.
%  CHECK:    BOOL - Evokes type checking according to the third column of
%      PROPSPEC
%
%Returns:
%  OPT: STRUCT with added properties from the property specification list
%          PROPSPEC
%  ISDEFAULT: STRUCT with the same fields as OPT. Each field has a
%          boolean value indicating whether the default value from PROPSPEC
%          was taken (i.e., that property was not a field of the input OPT).
%
%Description:
%  PROPSPEC is a property specification list that defines default values
%  for a list of properties. The struct OPT is filled with all missing
%  properties from PROPSPEC, but existing fields of OPT are not overwritten
%  by the respective default values.
%  The function makes a case-insensitive match of field of OPT to the
%  property names in PROPLIST. In the case of a match, the variant of
%  PROPSPEC is used.
%
%See also opt_checkProplist, opt_proplistToStruct.
%
%Examples:
%  opt= struct('linewidth',3, 'color','k')
%  props= {'LineWidth', 2;  'Color',[0 0 1];  'LineStyle','--'}
%  [opt, isdefault]= opt_setDefaults(opt, props)
%
%  % If the first input variable (OPT) is not a variable itself, but a field
%  % of a struct, it has to passed as a string:
%  S.opt= opt_setDefaults('S.opt', props);

% 06-2012 Benjamin Blankertz

misc_checkType(opt, 'STRUCT|CHAR');
misc_checkType(props, 'PROPSPEC');
misc_checkTypeIfExists('check', 'BOOL');

if nargin<3,
  check= 0;
end

if ischar(opt),
  structname= opt;
  opt= evalin('caller', opt);
  check= 1;
else
  structname= '';
end

% Perform a case correction in the STRUCT opt, and
% Set 'isdefault' to ones for the field already present in 'opt'
isdefault= [];
if ~isempty(opt),
  for Fld=fieldnames(opt)',
    fld= Fld{1};
    idx= find(strcmpi(fld, props(:,1)));
    if length(idx)>1,
      error('Case ambiguity in propertylist');
    elseif ~isempty(idx) && ~strcmp(fld, props{idx,1}),
      % rename field in opt to match case with props
      oldfld= fld;
      fld= props{idx,1};
      [opt.(fld)]= opt.(oldfld);
      opt= rmfield(opt, oldfld);
    end
    isdefault.(fld)= 0;
  end
end

for k= 1:size(props,1),
  fld= props{k,1};
  if ~isfield(opt, fld),
    %% if opt is a struct *array*, the fields of all elements need to
    %% be set. This is done with the 'deal' function.
    [opt.(fld)]= deal(props{k,2});
    isdefault.(fld)= 1;
  end
end

if check,
  if check==2,
    tcstate= bbci_typechecking('on');
  end
  if isempty(structname),
    structname= inputname(1);
  end
  opt_checkProplist(opt, props, structname);
  if check==2,
    bbci_typechecking(tcstate);
  end
end


% Initialize a test suite using test functions in the body of a function
%
% This function is not intended to be used directly; instead, it should be
% used at the top of a '.m'-file where the subfunctions may contain test
%
% To include subfunctions as tests and return a test-suite based on them,
% use the following layout:
%
%     function test_suite=my_test_of_abs
%         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_abs_scalar
%         assertTrue(abs(-1)==1)
%         assertEqual(abs(-NaN),NaN);
%         assertEqual(abs(-Inf),Inf);
%         assertEqual(abs(0),0)
%         assertElementsAlmostEqual(abs(-1e-13),0)
%
%     function test_abs_vector
%         assertEqual(abs([-1 1 -3]),[1 1 3]);
%
%     function test_abs_exceptions
%         if moxunit_util_platform_is_octave()
%             assertExceptionThrown(@()abs(struct),'');
%         else
%             assertExceptionThrown(@()abs(struct),...
%                                    'MATLAB:UndefinedFunction');
%         end
%
% After suite=my_test_of_abs(), suite will be a test suite testing
% the test_abs_scalar and test_abs_vector subfunctions
%
% Each test function should either start with 'test_' or end with '_test',
% and have no output arguments
%
% It is absolutely necessary that the main function has one output, and
% that the output variable is named 'test_suite'
%
% NNO Jan 2014

    get_example_syntax=@()sprintf('%s\n',...
                            '',...
                            '    function test_suite=test_foo',...
                            '    % tests for function ''foo''',...
                            ['        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_foo1',...
                            '        % your test code here',...
                            '',...
                            '    function test_foo2',...
                            '        % your test code here'...
                            );

    e=lasterror();
    [call_stack, idx] = dbstack('-completenames');
    if numel(call_stack)==1
        example_syntax=get_example_syntax();

        error(['The script ''%s'' must be called from within '...
                    'another function, typically using the '...
                    'following syntax:\n\n%s'...
                    ],...
                    call_stack(1).name,...
                    example_syntax);
    end

    caller_fn=call_stack(idx+1).file;
    sub_func_struct=moxunit_util_mfile_subfunctions(caller_fn);

    has_error=false;

    if moxunit_util_platform_supports('localfunctions_in_script')
        n_sub_func=numel(sub_func_struct);

        handle_candidates=cell(n_sub_func,1);
        for k=1:n_sub_func
            handle_candidates{k}=str2func(sub_func_struct(k).name);
        end

    else
        if ~exist('test_functions','var')
            func_name=call_stack(2).name;
            example_syntax=get_example_syntax();

            func_error=@()error(...
                    ['In %s:\nThe variable ''test_functions'' is '...
                    'not assigned and this version\nof Matlab does '...
                    'not support the assignment of function handles\n'...
                    'through calls by functions. \nAdapt the function '...
                    '%s so that it resembles the following '...
                    'syntax:\n%s'],...
                    func_name, func_name, example_syntax);
            handle_candidates={func_error};
            has_error=true;
        else
            handle_candidates=test_functions;
        end
    end

    test_re=moxunit_util_get_test_name_regexp();

    n_sub_func=numel(sub_func_struct);
    sub_func_names=arrayfun(@(i)sub_func_struct(i).name,1:n_sub_func,...
                            'UniformOutput',false);

    n_handles=numel(handle_candidates);
    test_suite=MOxUnitTestSuite();

    for k=1:n_handles
        handle=handle_candidates{k};

        add_test=false;

        if has_error
            name=call_stack(1).name;
            add_test=true;
        else
            name=func2str(handle);
            if moxunit_util_regexp_matches(name,test_re)
                idx=find(strcmp(name,sub_func_names));
                if ~isempty(idx)
                    assert(numel(idx)==1, 'name match should be unique');
                    add_test=sub_func_struct(idx).nargout==0;
                end
            end
        end

        if add_test
            test_case=MOxUnitFunctionHandleTestCase(...
                                                name,...
                                                caller_fn, handle);
            test_suite=addTest(test_suite, test_case);
        end

    end

    % If not called from another function, execute the test directly
    % and remove the test_suite variable
    if numel(call_stack)==2
        disp(run(test_suite));

        % Avoid showing "ans = MOxUnitTestSuite object: 1-by-1"
        % when run without explicitly assigning output to a variable
        clear test_suite;
    end


function varargout = process_swap_headcoils(varargin)
% PROCESS_SWAP_HEADCOILS: Correct channel names for swapped head localization coils.

% @=============================================================================
% 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: Marc Lalancette, 2019

eval(macro_method);
end

function sProcess = GetDescription() %#ok<DEFNU>
    % Description of the process
    sProcess.Comment     = 'Swap head coils (CTF)';
    sProcess.Description = 'https://neuroimage.usc.edu/brainstorm/Tutorials/HeadMotion#Fixing_swapped_head_coils';
    sProcess.Category    = 'Custom';
    sProcess.SubGroup    = {'Import', 'Channel file'};
    sProcess.Index       = 52;
    % Definition of the input accepted by this process
    sProcess.InputTypes  = {'raw', 'data'};
    sProcess.OutputTypes = {'raw', 'data'};
    sProcess.nInputs     = 1;
    sProcess.nMinFiles   = 1;
    sProcess.isSeparator = 1;
    % Options
    sProcess.options.Na.Type    = 'checkbox';
    sProcess.options.Na.Comment = 'Nasion';
    sProcess.options.Na.Value   = 0;
    sProcess.options.Le.Type    = 'checkbox';
    sProcess.options.Le.Comment = 'Left ear';
    sProcess.options.Le.Value   = 0;
    sProcess.options.Re.Type    = 'checkbox';
    sProcess.options.Re.Comment = 'Right ear';
    sProcess.options.Re.Value   = 0;
    sProcess.options.reverse.Type    = 'checkbox';
    sProcess.options.reverse.Comment = 'Reverse order (when swapping all 3 coils)';
    sProcess.options.reverse.Value   = 0;
    %     sProcess.options.display.Type    = 'checkbox';
    %     sProcess.options.display.Comment = 'Display "before" and "after" alignment figures.';
    %     sProcess.options.display.Value   = 0;

end

function Comment = FormatComment(sProcess)
    Comment = sProcess.Comment;
    Na = sProcess.options.Na.Value;
    Le = sProcess.options.Le.Value;
    Re = sProcess.options.Re.Value;
    if Na && Le && Re
        if sProcess.options.reverse.Value
            Comment = [Comment, ': Na<-Le<-Re'];
        else
            Comment = [Comment, ': Na->Le->Re'];
        end
    elseif Na && Le
        Comment = [Comment, ': Na<->Le'];
    elseif Na && Re
        Comment = [Comment, ': Na<->Re'];
    elseif Le && Re
        Comment = [Comment, ': Le<->Re'];
    end

end

function OutputFiles = Run(sProcess, sInputs)
    OutputFiles = {sInputs.FileName};

    Na = sProcess.options.Na.Value;
    Le = sProcess.options.Le.Value;
    Re = sProcess.options.Re.Value;
    if Na + Le + Re < 2
        bst_report('Warning', sProcess, sInputs, 'Fewer than 2 coils selected, nothing to do.');
        return;
    end

    nInFiles = length(sInputs);
    [UniqueChan, iUniqFiles] = unique({sInputs.ChannelFile});
    nFiles = numel(iUniqFiles);
    if nFiles < nInFiles
        bst_report('Warning', sProcess, sInputs, ...
            'Multiple inputs were found for a single channel file. Only the first one will be used for swapping head coils.');
    end

    if Na && Le && Re
        if sProcess.options.reverse.Value
            Comment = 'Na<-Le<-Re';
            iBef = 1:12;
            iAft = [5:12, 1:4];
        else
            Comment = 'Na->Le->Re';
            iBef = [5:12, 1:4];
            iAft = 1:12;
        end
    elseif Na && Le
        Comment = 'Na<->Le';
        iBef = 1:8;
        iAft = [5:8, 1:4];
    elseif Na && Re
        Comment = 'Na<->Re';
        iBef = [1:4, 9:12];
        iAft = [9:12, 1:4];
    elseif Le && Re
        Comment = 'Le<->Re';
        iBef = 5:12;
        iAft = [9:12, 5:8];
    end

    bst_progress('start', 'Swap head coils', ' ', 0, nFiles);
    for iFile = iUniqFiles(:)' % no need to repeat on same channel file.

        ChannelMat = in_bst_channel(sInputs(iFile).ChannelFile);
        bst_progress('inc', 1);

        % Check the input is CTF.
        DataMat = in_bst_data(sInputs(iFile).FileName, 'Device');
        if ~strcmp(DataMat.Device, 'CTF')
            bst_report('Error', sProcess, sInputs(iFile), ...
                'Swap head coils is currently only available for CTF data.');
            continue;
        end

        HluChan = {'HLC0011', 'HLC0012', 'HLC0013', 'HLC0018', ...
            'HLC0021', 'HLC0022', 'HLC0023', 'HLC0028', ...
            'HLC0031', 'HLC0032', 'HLC0033', 'HLC0038'}; % usual order
        [Unused, iHlu] = ismember(HluChan, {ChannelMat.Channel.Name});
        if numel(iHlu) < numel(HluChan)
            bst_report('Error', sProcess, sInputs(iFile), 'Head coil channels not found.');
            continue;
        end

        for i = 1:numel(iBef)
            ChannelMat.Channel(iHlu(iBef(i))).Name = HluChan{iAft(i)};
        end

        ChannelMat = bst_history('add', ChannelMat, 'edit', ...
            ['Swapped head coils: ', Comment]);

        % Save channel file. Need to save before adjusting because LoadHlu
        % gets the channel info from file.
        bst_save(file_fullpath(sInputs(iFile).ChannelFile), ChannelMat, 'v7');

        %         % Attempt to adjust the initial/reference head position.
        %         [ChannelMat, Failed] = process_adjust_coordinates('AdjustHeadPosition', ...
        %             ChannelMat, sInputs(iFile), sProcess);
        %         if ~Failed
        %             % Save channel file.
        %             bst_save(file_fullpath(sInputs(iFile).ChannelFile), ChannelMat, 'v7');
        %             % Show new alignment.
        %             channel_align_manual(sInputs(iFile).ChannelFile, 'MEG', 0);
        %         % else Already noted in report.
        %         end

    end % file loop
    bst_progress('stop');

    OutputFiles = bst_process('CallProcess', 'process_adjust_coordinates', OutputFiles, [], ...
        'reset', 0, 'head', 1, 'bad', 1, 'points', 0, 'remove', 0, 'display', 1);

end


function [gradnew] = ft_convert_grad(grad, amplitude, distance, scaling)

% FT_CONVERT_GRAD is deprecated, please use ft_datatype_sens

% DEPRECATED by roboos on 1 July 2013
% see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=963 for more details
% this function can be completely removed medio 2014
warning('this function is deprecated, please use ft_datatype_sens');

% at the time of writing this code, this is only supported in the "upcoming" version, not the "latest/2011v2"
gradnew = ft_datatype_sens(grad, 'version', 'upcoming', 'amplitude', amplitude, 'distance', distance, 'scaling', scaling);


function dfdupfigure(dffig)
%DFDUPFIGURE Make a duplicate, editable copy of the distribution fitting figure

%   $Revision: 1.1.6.5 $  $Date: 2004/03/26 13:30:58 $
%   Copyright 2003-2004 The MathWorks, Inc.

% Copy the regular axes, not the legend axes
f = figure;
ax = findall(dffig,'Type','axes','Tag','main');
copyobj(ax,f);
newax = findall(f,'Type','axes','Tag','main');

% Adjust layout in new figure, but don't add axis controls
dfadjustlayout(f,'off');

for i=1:length(ax)
   % Remove any context menus and callbacks associated with the old figure
   set(findall(newax(i),'Type','line'),...
       'DeleteFcn','','UIContextMenu',[],'ButtonDownFcn','');

   % Make a new legend based on the original, if any
   [legh,unused,h0,txt] = legend(ax(i));
   if length(h0)>0
      c0 = get(ax(i),'Child');
      c1 = get(newax(i),'Child');
      h1 = h0;
      for j=length(h0):-1:1
         k = find(c0==h0(j));
         if isempty(k)
            h1(j) = [];
            txt(j) = [];
         else
            % Convert to lineseries
            h1(j) = hgline2lineseries(c1(k(1)));
         end
      end

      % It's hard to match the old legend position adequately because the
      % two figure sizes may be very different.  Since the original legend
      % positions were TL or TR, we'll just pick whichever of these is
      % closest to the current position.  If the user moved the legend in
      % the original figure, he or she may need to do the same here.
      oldpos = get(legh,'Position');
      if oldpos(1)<.4
         newpos = 'NW';
      else
         newpos = 'NE';
      end
      legend(newax(i),h1,txt,'Location', newpos);
   end
end


function v = roiToggleFilledPerimeter(v);
%
%  v = roiToggleFilledPerimeter(v);
%
%Author: Wandell
%Purpose:
%   Toggle the fill perimeter drawing state.  When on, the perimeters are
%   always continuous.  When off, some perimeters appear as a set of open
%   loops.
%
% v = FLAT{1};

t = viewGet(v,'filledperimeterstate');
if isempty(t), t = 0; end
v = viewSet(v,'filledperimeterstate',1 - t);

return;


function run_experiment(imdb_video)
%RUN_EXPERIMENT
%	contains the parameters that are specific to the current experiment.
% 	These are the parameters that change frequently and should not be committed to
% 	the repository but should be saved with the results of the experiment.

	% Parameters that should have no effect on the result.
	opts.prefetch = false;
	opts.gpus = 1;

	% Parameters that should be recorded.
	% opts.foo = 'bla';

	if nargin < 1
	    imdb_video = [];
    end
    opts.expDir = 'data_gray';
    opts.augment.grayscale = 0.25;
	experiment(imdb_video, opts);

end


% ------------------------------------------------------------------------
%  Copyright (C)
%  Universitat Politecnica de Catalunya BarcelonaTech (UPC) - Spain
%  University of California Berkeley (UCB) - USA
%
%  Jordi Pont-Tuset <jordi.pont@upc.edu>
%  Pablo Arbelaez <arbelaez@berkeley.edu>
%  June 2014
% ------------------------------------------------------------------------
% This file is part of the MCG package presented in:
%    Arbelaez P, Pont-Tuset J, Barron J, Marques F, Malik J,
%    "Multiscale Combinatorial Grouping,"
%    Computer Vision and Pattern Recognition (CVPR) 2014.
% Please consider citing the paper if you use this code.
% ------------------------------------------------------------------------

% Check that 'mcg_root' has been set
if ~exist(mcg_root,'dir')
    error('Error installing the package, try updating the value of mcg_root in the file "mcg_root.m"')
end

% Check that 'mcg_root' has the needed folder
if ~exist(fullfile(mcg_root,'lib'),'dir')
    error('Error installing the package, the folder "lib" not found, have you compiled it? See build.m')
end
if ~exist(fullfile(mcg_root,'src'),'dir')
    error('Error installing the package, the folder "src" not found')
end

% Install own lib
addpath(mcg_root);
addpath(fullfile(mcg_root,'lib'));
addpath(fullfile(mcg_root,'scripts'));
addpath(fullfile(mcg_root,'datasets'));
addpath(genpath(fullfile(mcg_root,'src')));

%% Check that the needed functions are compiled
% Included in our code
needed_files = {'mex_assess_one_sel','mex_base_perimeters','mex_fast_features',...
                'mex_fast_intersections', 'mex_fast_reduction', 'mex_box_reduction',...
                'mex_get_tree_cands', 'mex_prune_tree_to_regions',...
                'mex_max_margin', 'mex_hole_filling',...
                'mex_intersect_hierarchies','mex_cands2masks','mex_cands2labels','mex_ucm2hier',...
                'paretofront',...                  % Included from paretofront
                'mexRF_train', 'mexRF_predict',... % Included from RF_Reg_C
                'convConst','gradientMex','imPadMex','imResampleMex','rgbConvertMex',... % Included from piotr_toolbox
                'edgesDetectMex',...               % Included from structured_forest
                'buildW', 'mex_contour_sides', 'ucm_mean_pb',... % Included from BSR
                };
for ii=1:length(needed_files)
    if exist(needed_files{ii})~=3 %#ok<EXIST>
        error(['The needed function (' needed_files{ii} ') not found. Have you built the package properly?'])
    end
end

%% Check that the databases are available and show a warning if not
dbs        = {'pascal2012',    'SBD',   'COCO'};
im_folders = {'JPEGImages', 'images', 'images'};
all_ok = 1;
for ii=1:length(dbs)
    db = dbs{ii};
    if ~exist(fullfile(database_root_dir(db), im_folders{ii}),'dir')
        all_ok = 0;
        disp(['WARNING: Database ' db ' (folder ' im_folders{ii} ') not found in ' database_root_dir(db)])
    end
end

if ~all_ok
    disp('-- You can disable this warning in install.m --')
end

%% Clear
clear ii needed_files;
disp('-- Successful installation of MCG. Enjoy! --');


function vl_test_print(varargin)

addpath(fullfile(vl_rootnn(), 'examples', 'mnist'));

net = cnn_mnist_init('networkType', 'dagnn');
net.print(varargin{:});

end


function [] = v2structDemo1()
%  V2STRUCTDEMO1 is a demo function showing some examples for using the function V2STRUCT
%
%% Last update:
%    30.06.2011, Adi N.

%%
fprintf(['\nRunning demo function with examples for using the function vs2truct:\n',...
        'Press any key between breaks.\n']);
pause()
fprintf(['\nInitialize demo variables:\n',...
         'x = zeros(3); x2 = ones(3); y = ''Testing123''; z = cell(2,3);\n',...
         'fieldNames1 = {''fieldNames'',''x'',''y'',''z''};\n',...
         'fieldNames2 = {''fieldNames'',''a'',''b'',''c''};\n',...
         'fieldNames3 = {''fieldNames'',''x''};\n',...
         'nameOfStruct2Update = ''S'';\n']);
pause()
x = zeros(3); x2 = ones(3); y = 'Testing123'; z = cell(2,3);
fieldNames1 = {'fieldNames','x','y','z'};
fieldNames2 = {'fieldNames','a','b','c'};
fieldNames3 = {'fieldNames','x'};
nameOfStruct2Update = 'S';

fprintf(['\nExamples for packing and unpacking:\n',...
         '\nPacking:\n']);
pause()
fprintf('\nExample 1: Variables x,y and z are packed to structure S\n');
fprintf('S = v2struct(x,y,z) ');
pause()
S = v2struct(x,y,z)

pause()
fprintf(['Example 2: Field names defined according to the cell array fieldNames.\n',...
         'variables with the names in fieldNames must exist.\n']);
clear S
fprintf('S = v2struct(fieldNames1)');
pause()
S = v2struct(fieldNames1)

pause()
fprintf('Example 3: Same as the first but arguments are passed explicitly\n');
clear S
fprintf('S = v2struct(zeros(3),''Testing123'',cell(2,3),fieldNames1)');
pause()
S = v2struct(zeros(3),'Testing123',cell(2,3),fieldNames1)

pause()
fprintf(['Example 4: Field names defined by content of fieldNames2 while the values are\n',...
         'set according to the passed arguments. In this case the structure S returned would\n'...
         'be: S.a=x, S.b=y, S.c=z\n']);
clear S
fprintf('S = v2struct(x,y,z,fieldNames2)');
pause()
S = v2struct(x,y,z,fieldNames2)

pause()
fprintf(['Example 5: Update structure S. The fields that would be updated are according to content\n',...
         'of fieldNames3. Note that you must pass a variable with the name\n',...
         '''nameOfStruct2Update'' placed before ''fieldNames3''. This variable should\n',...
         'contain the name of the structure you want to update as a string. Also note\n',...
         'that if you set an output structure name which is different than the one stated\n'...
         'in nameOfStruct2Update a new structure would be created and the structure that\n'...
         'was meant to be updated would not get updated.']);
fprintf(['S.oldField = ''field to be saved for future use''\n',...
        'S = v2struct(x2,nameOfStruct2Update,fieldNames3)\n']);
pause()
clear S
S.oldField = 'field to be saved for future use'
S = v2struct(x2,nameOfStruct2Update,fieldNames3)

pause()
fprintf('Example 6: Pack all variables in caller workspace.\n');
fprintf('S = v2struct');
pause()
S = v2struct

%%
pause()
fprintf(['\nExamples for Unpacking:\n']);
pause()

fprintf(['\nFisrt clear variables from ''packing'' and initialize variables for\n',...
         '''unpacking'':\n',...
         'clear all\n',...
         'S.x = zeros(3); S.y = ''Testing123''; S.z = cell(2,3);\n',...
         'fieldNames3 = {''fieldNames'',''x'',''z''};\n'])

clear all
S.x = zeros(3); S.y = 'Testing123'; S.z = cell(2,3); fieldNames3 = {'fieldNames','x','z'};

pause()
fprintf(['\nExample 1: Create or overwrite variables x, y, z in the caller environment\n',...
         'with the contents of the corresponding named fields.\n']);
pause()
fprintf(['v2struct(S)\n']);
pause()

v2struct(S)

fprintf(['\nExample 2: Assign the contents of the fields of the scalar structure S to\n',...
         'the variables a,b,c rather than overwriting variables in the caller. If there\n',...
         'are fewer output variables than there are fields in S, the remaining fields\n',...
         'are not extracted.\n']);
pause()
fprintf(['[a,b,c] = v2struct(S)\n']);

pause()

[a,b,c] = v2struct(S)

fprintf(['\nExample 3: Create or overwrite variables x and z in the caller with the\n',...
         'contents of the corresponding named fields.\n']);
pause()
fprintf(['v2struct(S,fieldNames3)\n']);
pause()
v2struct(S,fieldNames3)

fprintf(['\nExample 4: Assign the contents of the fields ''x'' and ''z'' defined by\n',...
         'fieldNames3 of the scalar structure S to the variables a and b rather than\n',...
         'overwriting variables in the caller. If there are fewer output variables than\n',...
         'there are fields in S, the remaining fields are not extracted.\n']);
pause()
fprintf(['[a,b] = v2struct(S,fieldNames3)\n']);
pause()
[a,b] = v2struct(S,fieldNames3)

fprintf(['\nExample 5: Unpack variable ''z'' only without overwriting variable ''x''. Note\n',...
         'the addition of the field named ''avoidOverWrite'' to the structure to be\n',...
         'unpacked. This is mandatory in order to make this functionality work. The\n',...
         'contents of this field can be anything, it does not matter.\n']);

pause()
fprintf(['S.avoidOverWrite = ''foo(contents does not matter)'';\n',...
         'x = ''do not overwrite me'';\n',...
         'clear y\n']);
pause()
S.avoidOverWrite = 'foo(contents does not matter)';
x = 'do not overwrite me';
v2struct(S)
S

fprintf('\nend of v2structDemo1\n');


function [varargout] = isequaln(varargin)

% ISEQUALN is a drop-in replacement for the same function that was
% introduced in MATLAB R2012a.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% try to automatically remove incorrect compat folders from the path, see https://github.com/fieldtrip/fieldtrip/issues/899

if isempty(strfind(mfilename('fullpath'), matlabroot))
  % automatic cleanup does not work when FieldTrip is installed inside the MATLAB path, see https://github.com/fieldtrip/fieldtrip/issues/1527

  alternatives = which(mfilename, '-all');
  if ~iscell(alternatives)
    % this is needed for octave, see https://github.com/fieldtrip/fieldtrip/pull/1171
    alternatives = {alternatives};
  end

  keep = true(size(alternatives));
  for i=1:numel(alternatives)
    keep(i) = keep(i) && ~any(alternatives{i}=='@');  % exclude methods from classes
    keep(i) = keep(i) && alternatives{i}(end)~='p';   % exclude precompiled files
  end
  alternatives = alternatives(keep);

  if exist(mfilename, 'builtin') || any(strncmp(alternatives, matlabroot, length(matlabroot)) & cellfun(@isempty, strfind(alternatives, fullfile('private', mfilename))))
    % remove this directory from the path
    p = fileparts(mfilename('fullpath'));
    warning('removing "%s" from your path, see http://bit.ly/2SPPjUS', p);
    rmpath(p);
    % call the original MATLAB function
    if exist(mfilename, 'builtin')
      [varargout{1:nargout}] = builtin(mfilename, varargin{:});
    else
      [varargout{1:nargout}] = feval(mfilename, varargin{:});
    end
    return
  end

end % automatic cleanup of compat directories

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% this is where the actual replacement code starts
% function tf = isequaln(varargin)

tf = isequalwithequalnans(varargin{:});

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% deal with the output arguments

varargout = {tf};


clear; clc; close all;

addpath('../libs/exportFig');
addpath('../libs/fun4MeanShift');
addpath('../libs/layerExt');
addpath('../libs/myFunctions/');
path_to_matconvnet = '../libs/matconvnet-1.0-beta23_modifiedDagnn';
run(fullfile(path_to_matconvnet, 'matlab', 'vl_setupnn'));
addpath(genpath(fullfile('dependencies', 'matconvnet','examples')));

% set GPU
gpuId = 3;
gpuDevice(gpuId);
%% read matconvnet model
load('imdb_complete_on_server.mat');
imdb.meta.meanvalue = reshape(imdb.meta.meanvalue,[1 1 3]);
imdb.path_to_image = '/home/skong2/dataset/';
imdb.path_to_annotation = '/home/skong2/dataset/';

path_to_model = 'main001_ft4COCO_baseline_v1';
modelName = 'pairMMAbsReg_net-epoch-1.mat';

netbasemodel = load( fullfile('./exp', path_to_model, modelName) );
netbasemodel = netbasemodel.net;
netbasemodel = dagnn.DagNN.loadobj(netbasemodel);
netbasemodel.move('gpu') ;
netbasemodel.mode = 'normal'; % {test, normal} !! normal --> per-instance normalization
netbasemodel.conserveMemory = 1;

netbasemodel.removeLayer('obj_MM');
netbasemodel.removeLayer('obj_reg');
netbasemodel.removeLayer('output_cosSim');
netbasemodel.removeLayer('output_l2norm');

sName = 'res9_conv';
res9_conv = netbasemodel.layers(netbasemodel.getLayerIndex(sName)).outputIndexes;
netbasemodel.vars(res9_conv).precious = 1;

lName = 'output_l2norm';
netbasemodel.addLayer(lName, L2normalization(), sName, lName) ;
sName = lName;
outputIdx_l2norm = netbasemodel.layers(netbasemodel.getLayerIndex('output_l2norm')).outputIndexes;
netbasemodel.vars(outputIdx_l2norm).precious = 1;

loopNum = 16;
predInstanceMaskMat_loop0 = cell(1,3);
predInstanceMaskMat_loops = cell(loopNum,3);

% alpha = 0.5;
% GaussianBandwidth = 1-alpha;
GaussianBandwidth = 0.2;

sName_l2norm = lName;
for loopIdx = 1:loopNum
    [netbasemodel, sName, sName_l2norm] = addOneLoop_forMeanShiftGrouping(netbasemodel, sName_l2norm, loopIdx, GaussianBandwidth);

    keepLayerName = sprintf('loop%d_meanshift_S_is_XX', loopIdx);
    netbasemodel.layers(netbasemodel.getLayerIndex(keepLayerName)).block.analyzeGradient = false;

    keepLayerName = sprintf('loop%d_meanshift_Y_l2norm', loopIdx);
    netbasemodel.vars(netbasemodel.layers(netbasemodel.getLayerIndex(keepLayerName)).outputIndexes).precious = 1;

    rmLayerName = sprintf('loop%d_meanshift_cosSim', loopIdx);
    netbasemodel.removeLayer(rmLayerName); % remove layer
end
%% visualize single image
idxList = 1:length(imdb.val_image);
for idx = idxList
    %% read image and annotation
    cur_path_to_image = fullfile(imdb.path_to_image, imdb.val_image{idx});
    cur_path_to_annot = fullfile(imdb.path_to_annot, imdb.val_annot{idx});
    cur_path_to_image = strrep(cur_path_to_image,'\','/');
    cur_path_to_annot = strrep(cur_path_to_annot,'\','/');

    imgOrg = imread(cur_path_to_image);
    cur_segMap = load(cur_path_to_annot);
    cur_instMap = cur_segMap.gtMat.instMap;
    cur_segMap = cur_segMap.gtMat.segMap;
    gtOrg = cur_instMap;

    sz = size(gtOrg);
    reSZ = round(sz/8)*8;
    img = imresize(imgOrg, reSZ);

    instMap_div8 = imresize(cur_instMap, reSZ/8, 'nearest');
    img = bsxfun(@minus, single(img), imdb.meta.meanvalue) ;
    inputs = {'data', gpuArray(single(img))};
    netbasemodel.eval(inputs) ;
    %% gather result
    keepLayerName = 'output_l2norm';
    keepLayerName = netbasemodel.layers(netbasemodel.getLayerIndex(keepLayerName)).outputIndexes;
    feaMap = gather(netbasemodel.vars(keepLayerName).value);

    feaMapSize = size(feaMap);
    randRGB4Pred1 = reshape(feaMap, [], size(feaMap,3));
    rng(777); randProj = randn(feaMapSize(3), 3);
    randRGB4Pred1 = randRGB4Pred1*randProj;
    randRGB4Pred1 = reshape( randRGB4Pred1, [feaMapSize(1), feaMapSize(2), 3] );
    randRGB4Pred1 = rescaleFeaMap(randRGB4Pred1);

    rng(77); randProj = randn(feaMapSize(3), 3);
    randRGB4Pred2 = reshape(feaMap, [], size(feaMap,3));
    randRGB4Pred2 = randRGB4Pred2*randProj;
    randRGB4Pred2 = reshape( randRGB4Pred2, [feaMapSize(1), feaMapSize(2), 3] );
    randRGB4Pred2 = rescaleFeaMap(randRGB4Pred2);

    rng(7); randProj = randn(feaMapSize(3), 3);
    randRGB4Pred3 = reshape(feaMap, [], size(feaMap,3));
    randRGB4Pred3 = randRGB4Pred3*randProj;
    randRGB4Pred3 = reshape( randRGB4Pred3, [feaMapSize(1), feaMapSize(2), 3] );
    randRGB4Pred3 = rescaleFeaMap(randRGB4Pred3);

    randRGB4Pred1 = imresize(randRGB4Pred1, [size(imgOrg,1),size(imgOrg,2)]);
    randRGB4Pred2 = imresize(randRGB4Pred2, [size(imgOrg,1),size(imgOrg,2)]);
    randRGB4Pred3 = imresize(randRGB4Pred3, [size(imgOrg,1),size(imgOrg,2)]);

    %     imwrite(uint8(255*randRGB4Pred1), sprintf('%s/valId%04d/randRGB4Pred1.png', ...
    %         prefix, idx));
    %     imwrite(uint8(255*randRGB4Pred2), sprintf('%s/valId%04d/randRGB4Pred2.png', ...
    %         prefix, idx));
    %     imwrite(uint8(255*randRGB4Pred3), sprintf('%s/valId%04d/randRGB4Pred3.png', ...
    %         prefix, idx));
    %% after some loops of mean shift
    keepLayerName = sprintf('loop%d_meanshift_Y_l2norm', loopNum);
    keepLayerName = netbasemodel.layers(netbasemodel.getLayerIndex(keepLayerName)).outputIndexes;
    feaMap = gather(netbasemodel.vars(keepLayerName).value);

    feaMapSize = size(feaMap);
    randRGB4Pred1_afterMShift = reshape(feaMap, [], size(feaMap,3));
    rng(777); randProj = randn(feaMapSize(3), 3);
    randRGB4Pred1_afterMShift = randRGB4Pred1_afterMShift*randProj;
    randRGB4Pred1_afterMShift = reshape( randRGB4Pred1_afterMShift, [feaMapSize(1), feaMapSize(2), 3] );
    randRGB4Pred1_afterMShift = rescaleFeaMap(randRGB4Pred1_afterMShift);

    rng(77); randProj = randn(feaMapSize(3), 3);
    randRGB4Pred2_afterMShift = reshape(feaMap, [], size(feaMap,3));
    randRGB4Pred2_afterMShift = randRGB4Pred2_afterMShift*randProj;
    randRGB4Pred2_afterMShift = reshape( randRGB4Pred2_afterMShift, [feaMapSize(1), feaMapSize(2), 3] );
    randRGB4Pred2_afterMShift = rescaleFeaMap(randRGB4Pred2_afterMShift);

    rng(7); randProj = randn(feaMapSize(3), 3);
    randRGB4Pred3_afterMShift = reshape(feaMap, [], size(feaMap,3));
    randRGB4Pred3_afterMShift = randRGB4Pred3_afterMShift*randProj;
    randRGB4Pred3_afterMShift = reshape( randRGB4Pred3_afterMShift, [feaMapSize(1), feaMapSize(2), 3] );
    randRGB4Pred3_afterMShift = rescaleFeaMap(randRGB4Pred3_afterMShift);

    randRGB4Pred1_afterMShift = imresize(randRGB4Pred1_afterMShift, [size(imgOrg,1),size(imgOrg,2)]);
    randRGB4Pred2_afterMShift = imresize(randRGB4Pred2_afterMShift, [size(imgOrg,1),size(imgOrg,2)]);
    randRGB4Pred3_afterMShift = imresize(randRGB4Pred3_afterMShift, [size(imgOrg,1),size(imgOrg,2)]);

    figHandler = figure(1);
    set(figHandler, 'Position', [100 100 1500 800]) % [1 1 width height]
    subplot(3,3,1); imshow(imgOrg); title('imgOrg');
    subplot(3,3,2); imagesc(cur_segMap); axis off image; title('segMap');
    subplot(3,3,3); imagesc(cur_instMap); axis off image; title('instMap');

    subplot(3,3,4); imagesc(randRGB4Pred1); axis off image; title('randRGB4Pred1');
    subplot(3,3,5); imagesc(randRGB4Pred2); axis off image; title('randRGB4Pred2');
    subplot(3,3,6); imagesc(randRGB4Pred3); axis off image; title('randRGB4Pred3');
    subplot(3,3,7); imagesc(randRGB4Pred1_afterMShift); axis off image; title('randRGB4Pred1_afterMShift','Interpreter','none');
    subplot(3,3,8); imagesc(randRGB4Pred2_afterMShift); axis off image; title('randRGB4Pred2_afterMShift','Interpreter','none');
    subplot(3,3,9); imagesc(randRGB4Pred3_afterMShift); axis off image; title('randRGB4Pred3_afterMShift','Interpreter','none');
    drawnow;
end
%% leaving blank
%{
%}