classdef SubcellsMesher < handle

    properties (GetAccess = public, SetAccess = protected)
        subcells
    end

    properties (GetAccess = protected, SetAccess = protected)
        coord_iso
        coord_global
        levelSet
        connec
    end

    properties (Access = private)
    end

    properties (GetAccess = protected, SetAccess = private)
        mesh
        interior_coord_iso
        cutPoints
        nCutPoints
        cell_nodes
        cell_connec
        cell_levelSet
        boundary_levelSet
        coordsBackground
        posNodes
        levelSetBackground

    end

    methods (Access = protected, Abstract)

        computeCoordinates(obj)
        computeConnectivities(obj)
        computeLevelSet(obj)

    end

    methods (Access = public, Static)

        function obj = create(cParams)
            f = SubcellsMesherFactory();
            obj = f.create(cParams);
        end

    end

    methods (Access = public)

        function computeSubcells(obj,cParams)

            cellConnec = cParams.cellConnec;
            cutPoints  = cParams.cutPoints;

            obj.saveInputs(cellConnec,cutPoints);
            obj.computeLevelSet();
            obj.computeCoordinates();
            obj.computeConnectivities();
            obj.packResultsInStruct();
        end

    end

    methods (Access = protected)

        function init(obj,cParams)
            obj.posNodes = cParams.posNodes;
            obj.levelSetBackground = cParams.levelSetBackground;
            obj.coordsBackground = cParams.coordsBackground;
        end
    end

    methods (Access = protected, Static)

        function connectivities = computeDelaunay(coordinates)
            DT = delaunayTriangulation(coordinates);
            connectivities = DT.ConnectivityList;
        end

        function w = patch(u,v)
            w = [u;v];
        end

    end

    methods (Access = private)

        function saveInputs(obj,cell_connec,cutPoints)
            obj.cell_connec = cell_connec;
            obj.cutPoints = cutPoints;
        end

        function packResultsInStruct(obj)
            obj.subcells.levelSet     = obj.levelSet;
            obj.subcells.coord_iso    = obj.coord_iso;
            obj.subcells.coord_global = obj.coord_global;
            obj.subcells.connec       = obj.connec;

            obj.subcells.nNodes       = size(obj.coord_iso,1);
            obj.subcells.nSubcells    = size(obj.connec,1);
        end

    end

    methods

        function coord = get.interior_coord_iso(obj)
            coord = obj.patch(obj.cell_nodes,obj.cutPoints.ISO);
        end

        function n = get.nCutPoints(obj)
            n = size(obj.cutPoints.ISO,1);
        end

        function nodes = get.cell_nodes(obj)
            nodes = obj.posNodes;
        end

        function lvlSet = get.cell_levelSet(obj)
            lvlSet = obj.levelSetBackground(obj.cell_connec);
        end

        function lvlSet = get.boundary_levelSet(obj)
            lvlSet = zeros(obj.nCutPoints,1);
        end

    end
end


% check whether the sequences are of the same length.
% The sequences are aligned from begining. If some sequence is shorter, it
% will be padded with a big negative number, i.e. -1e10, in the first dimension.
%
function [data2, mask, variableLength] = ExtractVariableLengthTrajectory(data, mask)
if nargin<2
    mask = squeeze(data(1,:,:))== -1e10;
end

[D,T,N] = size(data);
if T==1 || N==1
    mask = mask';
end
if sum(sum(mask))==0    % all have equal length
    variableLength = 0;
else
    variableLength = 1;
end
for i=1:N
    data2{i} = data(:,mask(:,i)==0,i);
end
end


function x = tril( x, k )

%   Disciplined convex/geometric programming information for TRIL:
%       TRIL imposes no convexity restrictions on its arguments.

%
% Check inputs
%

if nargin < 2, k = 0; end
s = x.size_;
if length( s ) > 2,
    cvx_throw( 'The first argument must be 2-D.' );
elseif ~isnumeric( k ) || length( k ) ~= 1,
    cvx_throw( 'The second argument must be an integer scalar.' );
end

%
% Zero out the elements outside of the desired triangle
%

b = x.basis_;
b( :, ~tril(ones(s),k) ) = 0;
x = cvx( s, b );

% Copyright 2005-2014 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function handles = plotCluster3D(hObject, handles)

plotDimensions = get(handles.lstPlotDimensions, 'Value');
plotTime       = get(handles.chkPlotDisplayTime, 'Value');

FigureTitle = 'Clustered Data';
if isequal(plotTime, 1)
    FigureTitle = [FigureTitle ...
        sprintf(' (clustered in %.2fs)', handles.timeClustering)];
end

[handles, handles.figCluster] = openPlotFigure(hObject, handles, ...
    'Clustered Data (3D)', FigureTitle);

view(3);

cols = handles.PlotColors;

if handles.NumberOfClusters > 7
    cols = repmat(cols, 1, ...
        1 + ceil(handles.NumberOfClusters / size(cols, 2)));
    warning('Not enough colors. Colors will repeat.');
end

for ii = 1:handles.NumberOfClusters
    currentColor = [cols(mod(ii, size(cols, 2))) getPlotMarkerStyle()];

    scatter3(handles.Data(plotDimensions(1), handles.ClusteredData(:, ii) == 1), ...
            handles.Data(plotDimensions(2), handles.ClusteredData(:, ii) == 1), ...
            handles.Data(plotDimensions(3), handles.ClusteredData(:, ii) == 1), ...
            getPlotMarkerSize(), currentColor);
end

hold off;

guidata(hObject, handles);


function f  = replace_chromosome(intermediate_chromosome,pro,pop)
%% replace_chromosome(intermediate_chromosome,pro,pop)
% This function replaces the chromosomes based on rank and crowding
% distance. Initially until the population size is reached each front is
% added one by one until addition of a complete front which results in
% exceeding the population size. At this point the chromosomes in that
% front is added subsequently to the population based on crowding distance.

%
%  Copyright (c) 2009, Aravind Seshadri
%  All rights reserved.
%
%  Redistribution and use in source and binary forms, with or without
%  modification, are permitted provided that the following conditions are
%  met:
%
%     * Redistributions of source code must retain the above copyright
%       notice, this list of conditions and the following disclaimer.
%     * Redistributions in binary form must reproduce the above copyright
%       notice, this list of conditions and the following disclaimer in
%       the documentation and/or other materials provided with the distribution
%
%  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
%  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
%  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
%  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
%  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
%  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
%  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
%  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
%  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
%  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%  POSSIBILITY OF SUCH DAMAGE.

[N,V] = size(intermediate_chromosome);
switch pro
        case 1
        M = 2;
        V = 6;
    case 2
        M = 3;
        V = 12;
end

% Get the index for the population sort based on the rank
[temp,index] = sort(intermediate_chromosome(:,M + V + 1));

% Now sort the individuals based on the index
for i = 1 : N
    sorted_chromosome(i,:) = intermediate_chromosome(index(i),:);
end

% Find the maximum rank in the current population
max_rank = max(intermediate_chromosome(:,M + V + 1));

% Start adding each front based on rank and crowing distance until the
% whole population is filled.
previous_index = 0;
for i = 1 : max_rank
    current_index = max(find(sorted_chromosome(:,M + V + 1) == i));
    if current_index > pop
        remaining = pop - previous_index;
        temp_pop = ...
            sorted_chromosome(previous_index + 1 : current_index, :);
        [temp_sort,temp_sort_index] = ...
            sort(temp_pop(:, M + V + 2),'descend');
        for j = 1 : remaining
            f(previous_index + j,:) = temp_pop(temp_sort_index(j),:);
        end
        return;
    elseif current_index < pop
        f(previous_index + 1 : current_index, :) = ...
            sorted_chromosome(previous_index + 1 : current_index, :);
    else
        f(previous_index + 1 : current_index, :) = ...
            sorted_chromosome(previous_index + 1 : current_index, :);
        return;
    end
    previous_index = current_index;
end


filename='Gripping_quad_fine';
 ptype = 'MACRO';
method = 'SIMPALL';
materialType = 'ISOTROPIC';
initial_case = 'full';
cost = {'nonadjoint_compliance'};
weights = [1, 0.1];
constraint = {'volumeConstraint'};
constraint_case = 'INEQUALITY';
optimizer = 'IPOPT'; incrementFactor = 1;
filterType = 'P1';

nsteps = 1;
Vfrac_final = 0.75;
optimality_final = 1e-3;
constr_final =1e-3;

Vfrac_initial = 1;
optimality_initial = 1e-3;
constr_initial = 1e-3;
TOL.rho_plus = 1;
TOL.rho_minus = 0;
TOL.E_plus = 1;
TOL.E_minus = 1e-3;
TOL.nu_plus = 1/3;
TOL.nu_minus = 1/3;


function volumeRendering(command)
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

global planC stateS;
indexS = planC{end};

[origin, spacing, center] = getScanOriginSpacing(planC{indexS.scan}(stateS.scanSet));

scanData = planC{indexS.scan}(stateS.scanSet).scanArray;
%scanData = planC{indexS.dose}(stateS.doseSet).doseArray;
% spacing = [1 1 3];

switch upper(command)

    case 'MIP'
        colormap = [];
%         scanData=GPReduce2(scanData,2,0);
        sampleRatio = 2;
        scanData = scanData(1:sampleRatio:end, 1:sampleRatio:end, 1:sampleRatio:end);
        Render3D_MIP(uint16(permute(scanData,[3,1,2])),colormap', 1, [spacing(3),spacing(1),spacing(2)]*10, 1);

    case 'MIP2'
        colormap = [];
        cData3M = scanDoseFusion();
        cData3M = permute(cData3M, [4,1,2,3]);
        [m,n,o,p] = size(cData3M);
        cData3M = reshape(cData3M, [n,o,p*m]);
        alphaRatio = 30;
        Render3D_MIP(uint16(cData3M),colormap', 2, spacing*10, alphaRatio);

    case 'VR1'
%         colormap = [  0.0     0.0   0.0   0.0   0.0;  ...
%                        200.0   0     0     0.8   0.02;  ...
%                        400.0   0.0   1.0   0.0   .8;  ...
%                        600.0   1.0   1.0   0.0   .6; ...
%                        800.0   1.0   0.0   0.0   .7; ...
%                       1000.0   0.0   1.0   1.0   1; ];

        [strVol, colormap] = generateStructVolume();
        sagOn  = 0;
        axOn   = 1;
        corOn  = 1;
        skinOn = 0;
        boneOn = 1;
        sagPos = 130;
        axPos  = 30;
        corPos = 100;
        tRange1 = 2500;
        tRange2 = 1500;
        tRange3 = 1500;
        skinAlpha = 0.3;
        boneAlpha = 0.8;
        Render3D_S(uint16(strVol(:,:,20:end)),colormap', 2, spacing, ...
            sagOn, axOn, corOn, skinOn, boneOn, sagPos, axPos, corPos, tRange1, tRange2, tRange3, skinAlpha, boneAlpha);

    case 'VR2'
        colormap = [   0    1    1   1    .0  ...
                      255   1    1   1    .0  ...
                      800   .9   .9  .9   .1  ...
                      1000  .9   .9  .3   .1  ...
                      1010  1   1  1   1  ...
                      1020  1   1  1   1  ...
                      1030  1   1  1   1  ...
                      1040  1   1  1   1  ...
                      1050  .6   .0  .6   .7  ...
                      1060  .6   .0  .6   .7  ...
                      1070  .6   .0  .6   .7  ...
                      1080  .0   .9  .0   1  ...
                      1090  .0   .6  .0   1  ...
                      1100  .0   .3  .0   1  ...
                      1150  .0   .8  .0   .1  ...
                      1200  .0   .4  .0   .9  ...
                      1500  .0   .6  .0   .9  ...
                      2000  .0   .8  .8   .9  ...
                      4000  1    1   1    1.0 ];

%         scanData = smooth3(scanData, 'gaussian');
        Render3D_V(uint16(scanData(:,:,40:end)),colormap', 2, spacing);

end


function res = spm_eeg_regressors_tfpower(S)
% Generate regressors from power in TF dataset
% S                     - input structure
% fields of S:
%    S.D                - M/EEG object
%
%    Additional parameters can be defined specific for each plugin
% Output:
%  res -
%   If no input is provided the plugin returns a cfg branch for itself
%
%   If input is provided the plugin returns
%______________________________________________________________________________________
% Copyright (C) 2014 Wellcome Trust Centre for Neuroimaging

% Vladimir Litvak

SVNrev = '$Rev: 6188 $';

if nargin == 0
    %--------------------------------------------------------------------------
    % TF power dataset
    %--------------------------------------------------------------------------
    Dtf        = cfg_files;
    Dtf.tag    = 'Dtf';
    Dtf.name   = 'TF power dataset name';
    Dtf.filter = 'mat';
    Dtf.num    = [1 1];
    Dtf.help   = {'Select the M/EEG mat file containing TF power data'};

    %--------------------------------------------------------------------------
    % timewin
    %--------------------------------------------------------------------------
    timewin         = cfg_entry;
    timewin.tag     = 'timewin';
    timewin.name    = 'Time window';
    timewin.help    = {['Start and stop of the time window [ms]. ' ...
        '(Used only for summarised epoched cases)']};
    timewin.strtype = 'r';
    timewin.num     = [1 2];
    timewin.val     = {[-Inf Inf]};

    %--------------------------------------------------------------------------
    % freqwin
    %--------------------------------------------------------------------------
    freqwin         = cfg_entry;
    freqwin.tag     = 'freqwin';
    freqwin.name    = 'Frequency window';
    freqwin.help    = {'Start and stop of the frequency window (Hz).'};
    freqwin.strtype = 'r';
    freqwin.num     = [1 2];
    freqwin.val     = {[-Inf Inf]};

    %--------------------------------------------------------------------------
    % average
    %--------------------------------------------------------------------------
    average = cfg_menu;
    average.tag = 'average';
    average.name = 'Average over frequency';
    average.labels = {'Yes', 'No'};
    average.val = {1};
    average.values = {1,0};
    average.help = {'Average over the frequency window to produce one regressor',...
        'or output each frequency as a separate regressor'};

    %--------------------------------------------------------------------------
    % standardize
    %--------------------------------------------------------------------------
    standardize = cfg_menu;
    standardize.tag = 'standardize';
    standardize.name = 'Standardize';
    standardize.labels = {'Yes', 'No'};
    standardize.val = {0};
    standardize.values = {1,0};
    standardize.help = {'Standardize (zscore) regressor values'};

    %--------------------------------------------------------------------------
    % regname
    %--------------------------------------------------------------------------
    regname         = cfg_entry;
    regname.tag     = 'regname';
    regname.name    = 'Regressor name';
    regname.help    = {'Specify the string to be used as regressor name.'};
    regname.strtype = 's';
    regname.num     = [1 Inf];
    regname.val     = {'TFpower'};

    tfpower = cfg_branch;
    tfpower.tag = 'tfpower';
    tfpower.name = 'Time-frequency power';
    tfpower.val = {Dtf, spm_cfg_eeg_channel_selector, timewin, freqwin, average, standardize, regname};

    res = tfpower;

    return
end

%-Startup
%--------------------------------------------------------------------------
spm('sFnBanner', mfilename, SVNrev);
spm('FigName','Time-frequency power regressors');

if ~isfield(S, 'timewin'),      S.timewin  = [-Inf Inf];    end
if ~isfield(S, 'freqwin'),      S.freqwin  = [-Inf Inf];    end

if iscell(S.Dtf)
    S.Dtf = char(S.Dtf);
end

Dtf  = spm_eeg_load(S.Dtf);
D    = spm_eeg_load(S.D);

if ~isequal(Dtf.transformtype, 'TF');
    error('Time-frequency power dataset is expected as input.')
end

freqind = Dtf.indfrequency(min(S.freqwin)):Dtf.indfrequency(max(S.freqwin)); %BW
if isempty(freqind) || any(isnan(freqind))
    error('Selected frequency window is invalid.');
end

chanind = setdiff(Dtf.selectchannels(spm_cfg_eeg_channel_selector(S.channels)), Dtf.badchannels);

if isempty(chanind)
    error('No channels were selected');
end

if isequal(D.type, 'continuous')

    if ~isequal(Dtf.type, 'continuous') || (D.time(1) < Dtf.time(1)) || (D.time(end)>Dtf.time(end))
        error('All times of the input dataset should be within the power dataset.');
    end

    data = spm_squeeze(mean(Dtf(chanind, freqind, :), 1), [1 3]);

    if S.average
        data = mean(data, 1);
    end

    if D.fsample ~= Dtf.fsample
        [data, alpha] = spm_timeseries_resample(data, D.fsample/Dtf.fsample);
    else
        alpha = 1;
    end

    start = round(alpha*Dtf.indsample(D.time(1)));

    data = data(:, start:(start+D.nsamples-1));

else
    if D.ntrials ~= Dtf.ntrials
        error('Trial numbers should be equal between input and power dataset.');
    end

    if S.summarise
        timeind = D.indsample(1e-3*(min(S.timewin))):D.indsample(1e-3*(max(S.timewin)));
        if isempty(timeind) || any(isnan(timeind))
            error('Selected time window is invalid.');
        end
    else
        timeind = 1:D.nsamples;
    end

    data = spm_squeeze(mean(Dtf(chanind, freqind, timeind, :), 1), 1);

    if S.average
        data = mean(data, 1);
    end

    if S.summarise
        data = spm_squeeze(mean(data, 2), 2);
    else
        data = reshape(data, size(data, 1), []);
    end
end

data = data';

if S.standardize
    data = (data - repmat(mean(data, 1), size(data, 1), 1))./repmat(std(data, 1), size(data, 1), 1);
end

res.R     = data;

if S.average
    res.names = {S.regname};
else
    freq = Dtf.frequencies(freqind);
    for i = 1:length(freq)
        res.names{i} = sprintf('%s_%.1fHz', S.regname, freq(i));
    end
end

spm('FigName','Time-frequency power regressors: done');


classdef comp2periodz < ZmapHGridFunction
    % COMP2PERIODZ compares seismicity rates for two time periods
    % The differences are as z- and beta-values and as percent change.

    properties
        periodA_start   datetime % start time for period 1
        periodA_end     datetime % end time for period 1
        periodB_start   datetime % start time for period 2
        periodB_end     datetime % end time for period 2
        binsize duration            = ZmapGlobal.Data.bin_dur;
    end

    properties(Constant)
        PlotTag = 'comp2periodz';
        ReturnDetails = cell2table({ ... VariableNames, VariableDescriptions, VariableUnits
            ...
            ... % these are returned by the calculation function
            'z_value',              'z-value',          '';...           #1 'valueMap'
            'pct_change',           'percent change',   'pct';... #2  'per'
            'beta_value',           'Beta value map',   '';...     #3 'beta_map'
            'Number_of_Events_1',   'Number of events in first period', '';... #4
            'Number_of_Events_2',   'Number of events in second period', '';... #5
            ...
            }, 'VariableNames', {'Names','Descriptions','Units'})

        CalcFields={...
            'z_value',              'pct_change',   'beta_value',...
            'Number_of_Events_1',   'Number_of_Events_2'}

        ParameterableProperties = ["periodA_start" "periodA_end" "periodB_start" "periodB_end" "binsize"];

        References="";
    end

    methods
        function obj=comp2periodz(zap, varargin)
            % COMP2PERIODZ compares seismicity rates for two time periods.
            % The differences are as z- and beta-values and as percent change.
            %   Stefan Wiemer 1/95
            %   Rev. R.Z. 4/2001

            obj@ZmapHGridFunction(zap, 'z_value');
            report_this_filefun();

            t0b = min(obj.RawCatalog.Date);
            teb = max(obj.RawCatalog.Date);
            obj.periodA_start = t0b;
            obj.periodB_end = teb;
            obj.periodA_end = t0b + (teb-t0b)/2;
            obj.periodB_start = obj.periodA_end+minutes(0.01);

            obj.parseParameters(varargin);

            obj.StartProcess();

        end

        function InteractiveSetup(obj)

            % get two time periods, along with grid and event parameters
            zdlg=ZmapDialog();
            zdlg.AddHeader('Please define two time periods to compare');
            zdlg.AddEdit('periodA_start','start period 1',  obj.periodA_start,'start time for period 1');
            zdlg.AddEdit('periodA_end',  'end period 1',    obj.periodA_end,'end time for period 1');
            zdlg.AddEdit('periodB_start','start period 2',  obj.periodB_start,'start time for period 2');
            zdlg.AddEdit('periodB_end',  'end period 2',    obj.periodB_end,'end time for period 2');
            zdlg.AddDurationEdit('binsize','Bin Size',      obj.binsize,'number of days in each bin',@days);
            obj.AddDialogOption(zdlg,'EventSelector');
            zdlg.Create('Name', 'Please choose rate change estimation option','WriteToObj',obj,'OkFcn',@obj.doIt);
        end

        function results=Calculate(obj)

            assert(obj.periodA_start < obj.periodA_end,'Period 1 starts before it ends');
            assert(obj.periodB_start < obj.periodB_end,'Period 2 starts before it ends');

            %  make grid, calculate start- endtime etc.  ...

            lt =  (obj.RawCatalog.Date >= obj.periodA_start &  obj.RawCatalog.Date < obj.periodA_end) ...
                | (obj.RawCatalog.Date >= obj.periodB_start &  obj.RawCatalog.Date <= obj.periodB_end);
            obj.RawCatalog = obj.RawCatalog.subset(lt);

            interval1_bins = obj.periodA_start : obj.binsize : obj.periodA_end; % starts
            interval2_bins = obj.periodB_start : obj.binsize : obj.periodB_end; % starts
            interval1_edges = [interval1_bins, interval1_bins(end)+obj.binsize];
            interval2_edges = [interval2_bins, interval2_bins(end)+obj.binsize];

            obj.gridCalculations(@calculation_function);

            obj.Result.period1.dateRange=[obj.periodA_start obj.periodA_end];
            obj.Result.period2.dateRange=[obj.periodB_start obj.periodB_end];

            if nargout
                results=obj.Result.values;
            end
            % save data

            % plot the results
            % old and valueMap (initially ) is the z-value matrix

            %det =  'ast';
            %ZG.shading_style = 'interp';
            % View the b-value map: view_ratecomp.m
            %    which could create a topography overlay ala dramap_z.m
            %
            %

            function out=calculation_function(catalog)
                % calulate values at a single point
                % calculate distance from center point and sort wrt distance

                idx_back =  catalog.Date >= obj.periodA_start &  catalog.Date < obj.periodA_end ;
                [cumu1, ~] = histcounts(catalog.Date(idx_back),interval1_edges);

                idx_after =  catalog.Date >= obj.periodB_start &  catalog.Date <= obj.periodB_end ;
                [cumu2, ~] = histcounts(catalog.Date(idx_after),interval2_edges);

                mean1 = mean(cumu1);        % mean seismicity rate in first interval
                mean2 = mean(cumu2);        % mean seismicity rate in second interval
                sum1 = sum(cumu1);          % number of earthquakes in the first interval
                sum2 = sum(cumu2);          % number of earthquakes in the second interval
                var1 = cov(cumu1);          % variance of cumu1
                var2 = cov(cumu2);          % variance of cumu2
                % remark (db): cov and var calculate the same value when applied to a vector
                ncu1 = length(interval1_bins);         % number of bins in first interval
                ncu2 = length(interval2_bins);         % number of bins in second interval

                % compute the z value "as":
                as = (mean1 - mean2)/ sqrt(var1/ncu1 +var2/ncu2);

                % calculate the percentage
                per = -((mean1-mean2)./mean1)*100;

                % beta nach reasenberg & simpson 1992, time of second interval normalised by time of first interval
                bet = (sum2-sum1*ncu2/ncu1)/sqrt(sum1*(ncu2/ncu1));

                out = [as  per bet sum1 sum2];

            end
        end
        function ModifyGlobals(obj)
            obj.ZG.bvg = obj.Result.values;
        end
    end %methods

    methods(Static)
        function h = AddMenuItem(parent, zapFcn, varargin)
            % create a menu item
            label = 'Compare two periods (z, beta, probabilty)';
            h =  uimenu(parent, 'Label', label,...
                'MenuSelectedFcn', @(~,~)XYfun.comp2periodz(zapFcn()),...
                varargin{:});
        end
    end % static methods
end % classdef


clear
cleanFile = 'DataSet/TIMIT_10_TEST-White+5db.wav';
enhancedFile_1 = 'Enhanced/out_TIMIT_10_TEST_IRMDNN_0308_10.wav';
[snr_mean, segsnr_mean]= comp_snr(cleanFile, enhancedFile_1);


function visualizemodel(model, components, layers)
% Visualize a mixture of star models.
%   visualizemodel(model)
%
% Arguments
%   model       Model to visualize
%   components  Which components to draw

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

clf;
if nargin < 2
  components = 1:length(model.rules{model.start});
end

if nargin < 3
  layers = 1;
end

k = 1;
for i = components
  for layer = layers
    visualizecomponent(model, i, length(layers)*length(components), k, layer);
    k = k+1;
  end
end

function visualizecomponent(model, c, nc, k, layer)

rhs = model.rules{model.start}(c).rhs;
root = -1;
parts = [];
defs = {};
anchors = {};
% assume the root filter is first on the rhs of the start rules
if model.symbols(rhs(1)).type == 'T'
  % handle case where there's no deformation model for the root
  root = model.symbols(rhs(1)).filter;
else
  % handle case where there is a deformation model for the root
  root = model.symbols(model.rules{rhs(1)}(layer).rhs).filter;
end
for i = 2:length(rhs)
  defs{end+1} = model_get_block(model, model.rules{rhs(i)}(layer).def);
  anchors{end+1} = model.rules{model.start}(c).anchor{i};
  fi = model.symbols(model.rules{rhs(i)}(layer).rhs).filter;
  parts = [parts fi];
end
% make picture of root filter
pad = 2;
bs = 20;
w = foldHOG(model_get_block(model, model.filters(root)));
scale = max(w(:));
im = HOGpicture(w, bs);
im = imresize(im, 2);
im = padarray(im, [pad pad], 0);
im = uint8(im * (255/scale));

% draw root
numparts = length(parts);
if numparts > 0
  subplot(nc,3,1+3*(k-1));
else
  subplot(nc,1,k);
end
imagesc(im)
colormap gray;
axis equal;
axis off;

% draw parts and deformation model
if numparts > 0
  def_im = zeros(size(im));
  def_scale = 500;
  for i = 1:numparts
    % part filter
    w = model_get_block(model, model.filters(parts(i)));
    p = HOGpicture(foldHOG(w), bs);
    p = padarray(p, [pad pad], 0);
    p = uint8(p * (255/scale));
    % border
    p(:,1:2*pad) = 128;
    p(:,end-2*pad+1:end) = 128;
    p(1:2*pad,:) = 128;
    p(end-2*pad+1:end,:) = 128;
    % paste into root
    x1 = (anchors{i}(1))*bs+1;
    y1 = (anchors{i}(2))*bs+1;
    x2 = x1 + size(p, 2)-1;
    y2 = y1 + size(p, 1)-1;
    im(y1:y2, x1:x2) = p;

    % deformation model
    probex = size(p,2)/2;
    probey = size(p,1)/2;
    for y = 2*pad+1:size(p,1)-2*pad
      for x = 2*pad+1:size(p,2)-2*pad
        px = ((probex-x)/bs);
        py = ((probey-y)/bs);
        v = [px^2; px; py^2; py];
        p(y, x) = defs{i} * v * def_scale;
      end
    end
    def_im(y1:y2, x1:x2) = p;
  end

  % plot parts
  subplot(nc,3,2+3*(k-1));
  imagesc(im);
  colormap gray;
  axis equal;
  axis off;

  % plot deformation model
  subplot(nc,3,3+3*(k-1));
  imagesc(def_im);
  colormap gray;
  axis equal;
  axis off;
end

set(gcf, 'Color', 'white')


function atlasStore(vw, images, whichAtlas, curSlice)
% Store angle and ecc atlas data into an atlas datatype in a flat view
% (incorporated from "atlasCreate.m").
%
% atlasStore(vw, images, whichAtlas, curSlice)
%
% Example
%   vw = FLAT{1};
%   atlasStore(vw,images,[],[]);
%
% Author: KA, BW

global dataTYPES

% Check arguments
if notDefined('vw'),            vw = getCurView; end
if notDefined('images'),        error('images must be defined'); end
if notDefined('whichAtlas'),    whichAtlas = atlasSelectAtlas; end
if notDefined('curSlice'),      curSlice = viewGet(vw, 'Current Slice'); end

sz = viewGet(vw,'anatSize');
atlasAngle = imresize(images.dA2,sz(1)/size(images.dA2,1),'Method','nearest');
atlasEcc = imresize(images.dA1,sz(1)/size(images.dA1,1),'Method','nearest');
areasImg = imresize(double(images.dareasImg),sz(1)/size(images.dareasImg,1),'Method','nearest');

atlasTypeList = {'angle', 'eccentricity'};
nAtlases = length(atlasTypeList);
atlasDim = dataSize(vw,1);

% If needed, create a new atlas.  Otherwise take the existing atlas
if whichAtlas == 0   % Create a new Atlas
    % Build the atlas sub-directory and data type.
    [atlasName,whichAtlas] = addAtlas2DataTYPE;
else
    atlasName = dataTYPES(whichAtlas).name;
end

% update dataTYPES
% Copy the params from the first scan of the current data type (usually
% Averages or some other readl data) into the dataTYPE we will use for the
% new atlas.
wedgePhaseShift=0;
ringPhaseShift = 0;
retPhases = [0 pi*2 pi/2 pi];

dtCopy(vw.curDataType,whichAtlas,atlasTypeList,curSlice,...
    [wedgePhaseShift,ringPhaseShift],retPhases);

% Init the atlasView with the data in the currently selected atlas view.
atlasView = atlasInit(vw,atlasName,nAtlases,whichAtlas,atlasDim);

% These are the atlas data.  There is a problem with the atlasAngle at one
% edge.  Look into why.
atlasView.ph{1}(:,:,curSlice) = atlasAngle;
atlasView.ph{2}(:,:,curSlice) = atlasEcc;

% This is the shape which gets deformed as the atlas fitting proceeds.  The
% edges are used as an overlay on the data so you can see the boundaries.
atlasView.co{1}(:,:,curSlice) = round(areasImg);
atlasView.co{2}(:,:,curSlice) = round(areasImg);

atlasView.amp{1}(:,:,curSlice) = zeros(size(atlasAngle));
atlasView.amp{2}(:,:,curSlice) = zeros(size(atlasEcc));

% Save files and update information in the atlas view.
saveSession;
saveCorAnal(atlasView,[],[],[],1);

return;


function r = mtimes(a,b,takeRight)
% orientation times Miller and orientation times orientation
%
% Syntax
%   o = o1 * o2
%   r = o * h
%   h = inv(o) * r
%
% Input
%  o - @orientation
%  h - @Miller indice
%  r - @vector3d
%
% See also
% orientation/times

% this is some shortcut for internal use
if nargin == 3
  r = mtimes@rotation(a,b,takeRight);
  return
end

% special case multiplication with +-1
if isnumeric(a) || isnumeric(b)
  r = mtimes@rotation(a,b);
  return
end

% orientation times symmetry
if isa(b,'symmetry')
  r = mtimes@quaternion(a,b.rot,0);
  return
end

% ensure inner symmetries coincide
[a, left, right] = ensureSym(a,b);

% orientation times object
if ~isa(b,'quaternion')
  r = rotate_outer(b,a);
  return
end

% rotation multiplication
r = mtimes@quaternion(a,b,isa(b,'orientation'));

% convert back to orientation
if isa(right,'crystalSymmetry') || isa(left,'crystalSymmetry')
  r.CS = right;
  r.SS = left;
else % otherwise it is only a rotation anymore
  r = rotation(r);
end

end


function varargout = openopt_fun(varargin)

persistent params

if nargin>1
    params = varargin{2};
    return
end

if ischar(varargin{1})
    switch varargin{1}
        case 'getStartPoint'
            varargout{1} = params.x0;
            return
        case 'getOptimPoint'
            varargout{1} =[];
            return
    end
end

xevaled = zeros(1,length(params.c));
xevaled(params.linearindicies) = varargin{1};

% Apply the precomputed evaluation scheme (if necessary)
xevaled = apply_recursive_evaluation(params,xevaled);

xevaled = xevaled(:);
varargout{1} = params.f + (params.c'+xevaled'*params.Q)*xevaled;


%%% void show_results(matrix,matrix,matrix,matrix,int,int,int)
% I - Input sequence
% L - Low-rank sequence
% S - Sparse sequence
% O - Outliers sequence
% nFrame - Number of frames
% vidHeight - Video height
% vidWidth - Video width
%
function show_results(I,L,S,O,nFrame,vidHeight,vidWidth)
  warning('off','all');
  clf;
  for i = 1:nFrame
    Input = reshape(I(:,i),vidHeight,vidWidth);
    %Input = uint8(Input);

    if(size(L) == size(I))
      LowRank = reshape(L(:,i),vidHeight,vidWidth);
      %LowRank1 = reshape(L(:,i),vidHeight,vidWidth);
      %LowRank = mat2gray(LowRank1);
      %LowRank = im2uint8(LowRank);
    else
      LowRank = uint8(zeros(size(Input)));
    end

    if(size(S) == size(I))
      Sparse = reshape(S(:,i),vidHeight,vidWidth);
      %Sparse1 = reshape(S(:,i),vidHeight,vidWidth);
      %Sparse = mat2gray(Sparse1);
      %Sparse = im2uint8(Sparse);
    else
      Sparse = uint8(zeros(size(Input)));
    end

    if(~isempty(O))
      Outlier = reshape(O(:,i),vidHeight,vidWidth);
      %Outlier1 = reshape(O(:,i),vidHeight,vidWidth);
      %Outlier = mat2gray(Outlier1);
      %Outlier = im2uint8(Outlier);
      %Outlier = medfilt2(Outlier, [5 5]);
    else
      Outlier = uint8(zeros(size(Input)));
    end

    subplot(2,3,1), imshow(Input,[]), title('Input (I)');
    subplot(2,3,2), imshow(LowRank,[]), title('Low Rank (L)');
    subplot(2,3,3), imshow(Sparse,[]), title('Sparse (S)');
    subplot(2,3,4), imshow(Outlier,[]), title('Outliers (O)');
    subplot(2,3,5), imshow(medfilt2(Outlier, [5 5]),[]), title('Filtered Outliers');
    %disp(i);
    pause(0.01);
  end
  warning('on','all');
end


function fn_handle = GiveMeFunctionHandle(cfnParams)
% GiveMeFunctionHandle  Returns a function handle for computing classification accuracy
%
%---INPUTS:
% cfnParams, parameters for the classification, e.g., set with
%           GiveMeDefaultClassificationParams.

% ------------------------------------------------------------------------------
% Copyright (C) 2020, Ben D. Fulcher <ben.d.fulcher@gmail.com>,
% <http://www.benfulcher.com>
%
% If you use this code for your research, please cite the following two papers:
%
% (1) B.D. Fulcher and N.S. Jones, "hctsa: A Computational Framework for Automated
% Time-Series Phenotyping Using Massive Feature Extraction, Cell Systems 5: 527 (2017).
% DOI: 10.1016/j.cels.2017.10.001
%
% (2) B.D. Fulcher, M.A. Little, N.S. Jones, "Highly comparative time-series
% analysis: the empirical structure of time series and their methods",
% J. Roy. Soc. Interface 10(83) 20130048 (2013).
% DOI: 10.1098/rsif.2013.0048
%
% This work is licensed under the Creative Commons
% Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of
% this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/ or send
% a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View,
% California, 94041, USA.
% ------------------------------------------------------------------------------

% Set empty function handle:
fn_handle = [];

%-------------------------------------------------------------------------------
% Set the function handle to compute the accuracy/loss measure:
%-------------------------------------------------------------------------------
if strcmp(cfnParams.whatClassifier,'fast-linear')
    fn_loss = @(yTest,yPredict) BF_LossFunction(yTest,yPredict,cfnParams.whatLoss,cfnParams.classLabels);
    fn_handle = @(XTrain,yTrain,XTest,yTest) fn_loss(yTest,classify(XTest,XTrain,yTrain,'linear'));
    return
end

%-------------------------------------------------------------------------------
% Binary model (easier), we can do it in one line:
%-------------------------------------------------------------------------------
if cfnParams.numClasses==2
    % Set the loss function:
    fn_loss = @(yTest,yPredict) BF_LossFunction(yTest,yPredict,cfnParams.whatLoss,cfnParams.classLabels);

    switch cfnParams.whatClassifier
    case 'knn'
        fn_handle = @(XTrain,yTrain,XTest,yTest) fn_loss(yTest,predict(fitcknn(XTrain,yTrain),XTest));
    case 'tree'
        fn_handle = @(XTrain,yTrain,XTest,yTest) fn_loss(yTest,predict(fitctree(XTrain,yTrain),XTest));
    case {'linear','linclass'}
        if cfnParams.doReweight
            fn_handle = @(XTrain,yTrain,XTest,yTest) ...
                        fn_loss(yTest,predict(fitcdiscr(XTrain,yTrain,'FillCoeffs','off',...
                                    'SaveMemory','on','Weights',InverseProbWeight(yTrain)),XTest));
        else
            fn_handle = @(XTrain,yTrain,XTest,yTest) ...
                        fn_loss(yTest,predict(fitcdiscr(XTrain,yTrain,'FillCoeffs','off',...
                                    'SaveMemory','on'),XTest));
        end
    case {'svm','svm-linear','svm-linear-highdim'}
        % This one uses the fitclinear function (fast; suited for high-dimensional datasets)
        if cfnParams.doReweight
            fn_handle = @(XTrain,yTrain,XTest,yTest) fn_loss(yTest,predict(fitclinear(XTrain,yTrain,...
                                    'KernelFunction','linear','Weights',InverseProbWeight(yTrain)),XTest));
        else
            fn_handle = @(XTrain,yTrain,XTest,yTest) fn_loss(yTest,predict(fitclinear(XTrain,yTrain,...
                                    'KernelFunction','linear'),XTest));
        end
    case {'svm-linear-lowdim'}
        % This one uses the fitcsvm function (slower; suited for low-dimensional datasets)
        if cfnParams.doReweight
            fn_handle = @(XTrain,yTrain,XTest,yTest) fn_loss(yTest,predict(fitcsvm(XTrain,yTrain,...
                                    'KernelFunction','linear','Weights',InverseProbWeight(yTrain)),XTest));
        else
            fn_handle = @(XTrain,yTrain,XTest,yTest) fn_loss(yTest,predict(fitcsvm(XTrain,yTrain,...
                                    'KernelFunction','linear'),XTest));
        end
    case 'svm-rbf'
        if cfnParams.doReweight
            fn_handle = @(XTrain,yTrain,XTest,yTest) fn_loss(yTest,predict(fitcsvm(XTrain,yTrain,...
                                    'KernelFunction','rbf','Weights',InverseProbWeight(yTrain)),XTest));
        else
            fn_handle = @(XTrain,yTrain,XTest,yTest) fn_loss(yTest,predict(fitcsvm(XTrain,yTrain,...
                                    'KernelFunction','rbf'),XTest));
        end
    case 'diaglinear'
        if cfnParams.doReweight
            fn_handle = @(XTrain,yTrain,XTest,yTest) fn_loss(yTest,predict(fitcnb(XTrain,yTrain,...
                                                    'Weights',InverseProbWeight(yTrain)),XTest));
        else
            fn_handle = @(XTrain,yTrain,XTest,yTest) fn_loss(yTest,predict(fitcnb(XTrain,yTrain),XTest));
        end
    otherwise
        warning('Unknown classifier: ''%s''',cfnParams.whatClassifier);
    end
end

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

if isempty(fn_handle)
    % Multiclass, have to use the Cfn function (which is slower to use as a function handle)
    % OR: unknown classifier set above
    fn_handle = @(XTrain,yTrain,XTest,yTest) ...
        GiveMeCfn(XTrain,yTrain,XTest,yTest,cfnParams,false);
end

end


function [solution, metabolite]=consumeSomething(model,ignoreMets,isNames,minNrFluxes,params,ignoreIntBounds)
% consumeSomething
%   Tries to consume any metabolite using as few reactions as possible.
%   The intended use is when you want to make sure that you model cannot
%   consume anything without producing something. It is intended to be used
%   with no active exchange reactions.
%
%   model           a model structure
%   ignoreMets      either a cell array of metabolite IDs, a logical vector
%                   with the same number of elements as metabolites in the model,
%                   of a vector of indexes for metabolites to exclude from
%                   this analysis (opt, default [])
%   isNames         true if the supplied mets represent metabolite names
%                   (as opposed to IDs). This is a way to delete
%                   metabolites in several compartments at once without
%                   knowing the exact IDs. This only works if ignoreMets
%                   is a cell array (opt, default false)
%   minNrFluxes     solves the MILP problem of minimizing the number of
%                   fluxes instead of the sum. Slower, but can be
%                   used if the sum gives too many fluxes (opt, default
%                   false)
%   params          parameter structure as used by getMILPParams (opt)
%   ignoreIntBounds	true if internal bounds (including reversibility)
%                   should be ignored. Exchange reactions are not affected.
%                   This can be used to find unbalanced solutions which are
%                   not possible using the default constraints (opt,
%                   default false)
%
%   solution        flux vector for the solution
%   metabolite      the index of the metabolite(s) which was consumed. If
%                   possible only one metabolite is reported, but there are
%                   situations where metabolites can only be consumed in
%                   pairs (or more)
%
%   NOTE: This works by forcing at least 1 unit of "any metabolites" to be
%   consumed and then minimize for the sum of fluxes. If more than one
%   metabolite is consumed, it picks one of them to be consumed and then
%   minimizes for the sum of fluxes.
%
%   Usage: [solution, metabolite]=consumeSomething(model,ignoreMets,isNames,...
%               minNrFluxes,params,ignoreIntBounds)

if nargin<2
    ignoreMets=[];
elseif ~islogical(ignoreMets) && ~isnumeric(ignoreMets)
    ignoreMets=convertCharArray(ignoreMets);
end
if nargin<3
    isNames=false;
end
if nargin<4
    minNrFluxes=false;
end
if nargin<5
    params.relGap=0.8;
end
if nargin<6
    ignoreIntBounds=false;
end

if isNames==true && ~isempty(ignoreMets)
    %Check that metsToRemove is a cell array
    if iscellstr(ignoreMets)==false
        EM='Must supply a cell array of strings if isNames=true';
        dispEM(EM);
    end
end

if isNames==false
    indexesToIgnore=getIndexes(model,ignoreMets,'mets');
else
    indexesToIgnore=[];
    for i=1:numel(ignoreMets)
        indexesToIgnore=[indexesToIgnore;find(strcmp(ignoreMets(i),model.metNames))];
    end
end

%Change all internal reactions to be unbounded in both directions
if ignoreIntBounds==true
    [~, I]=getExchangeRxns(model);
    nonExc=true(numel(model.rxns),1);
    nonExc(I)=false;
    model=setParam(model,'lb',nonExc,-1000);
    model=setParam(model,'ub',nonExc,1000);
    model=setParam(model,'rev',nonExc,1);
end

solution=[];
metabolite=[];

nRxns=numel(model.rxns);
nMets=numel(model.mets);

%Add uptake reactions for all metabolites
model.S=[model.S speye(nMets)];

%Add so that they all consume a fake metabolite
model.S=[model.S;[sparse(1,nRxns) ones(1,nMets)*-1]];

%Change so that the ignoreMets have a coefficient 0 in their reactions.
%Does not remove the actual reaction to make mapping easier later
model.S(:,indexesToIgnore+nRxns)=0;

%Add an uptake reaction for this last fake metabolite
model.S(size(model.S,1),size(model.S,2)+1)=1;
model.b=[model.b;zeros(1,size(model.b,2))];
model.lb=[model.lb;zeros(nMets,1);1];
model.ub=[model.ub;inf(nMets+1,1)];
model.rev=[model.rev;zeros(nMets+1,1)];
model.c=zeros(size(model.S,2),1);

%Add padding to the reaction annotation to prevent an error in solveLP
padding=1:numel(model.rev);
padding=num2cell(padding)';
padding=cellfun(@num2str,padding,'uniformoutput',false);
model.rxns=padding;
model.rxnNames=padding;
model.eccodes=padding;
model.rxnMiriams=padding;
model.grRules=padding;
if isfield(model,'genes')
    model.rxnGeneMat=sparse(numel(model.rev),numel(model.genes));
end
model.subSystems=padding;
model.rxnFrom=padding;
model.rxnComps=ones(numel(model.rev),1);
model.rxnNotes=padding;
model.rxnReferences=padding;
model.rxnConfidenceScores=NaN(numel(model.rev),1);

sol=solveLP(model,1);
if any(sol.x)
    %It could be that several metabolites were consumed in order to get the
    %best solution. The setdiff is to avoid including the last fake
    %metabolite
    I=setdiff(find(sol.x(nRxns+1:end)>0.1),size(model.S,1));

    if any(I) %This should always be true
        %Change the coefficients so that only the first is consumed. This
        %is not always possible, but it is tested for since it it results
        %in more easily interpretable results

        oldS=model.S;
        foundSingle=false;
        %Test if any of the metabolites could be consumed on their own
        for i=1:numel(I)
            model.S=oldS;
            J=nRxns+1:numel(model.lb)-1;
            J(I(i))=[];
            model.S(:,J)=0;
            sol=solveLP(model);
            if any(sol.x)
                foundSingle=true;
                break;
            end
        end
        %This means that there was no metabolite which could be consumed on
        %its own. Then let all the consumeable metabolites be consumed.
        if foundSingle==false
            model.S=oldS;
        end
        if minNrFluxes==true
            %Has to add names for the rxns to prevent an error in
            %minNrFluxes
            model.rxns=cell(numel(model.lb),1);
            model.rxns(:)={'TEMP'};
            model.mets=cell(size(model.b,1),1);
            model.mets(:)={'TEMP'};
            sol=solveLP(model,3,params);
        else
            sol=solveLP(model,1);
        end
        solution=sol.x(1:nRxns);
        metabolite=find(sol.x(nRxns+1:end-1)>0.1);
    end
end
end


%DemoMV.m
% OVERVIEW, Main script, runs the eval_mvm_twa script which calls the ComputeMVM and ComputeTWA in the Tools/MVM and Tools/TWA subfolders respectively.
%
% The expected output for this example script is given below.
% The results for MVM analysis are stored in the MVMResult structure and TWA analysis are stored in the TWAResult structure.
% The fields of each structure with expected values are listed below.
%
%   Structure.Field                 Expected value
%   MVMResult.energyinband_array    6.60e-07
%   MVMResult.sqi_array             0.9975
%   MVMResult.heart_rate_est_arr    80.11
%
%   TWAResult.HR            [80.32,80.21,79.79,80.65,80.65,80.43,80,80,80.21,80.32,80,79.47]
%   TWAResult.VAlt          [38.84,40.10,37.81,37.38,37.70,38.14,39.32,39.74,38.31,40.39,39.07,42.20]
%   TWAResult.VAlt_Sig      [38.84,40.10,37.81,37.38,37.70,38.14,39.32,39.74,38.31,40.39,39.07,42.20]
%   TWAResult.Noise_Median  [4.28,3.92,4.40,3.75,3.68,4.14,3.00,3.21,4.15,3.95,3.78,7.20]
%   TWAResult.Noise_95      [11.19,10.75,9.61,12.67,11.69,9.72,9.15,9.84,10.29,11.03,9.89,19.40]
%   TWAResult.VAltPt        [132,116,115,125,116,122,130,117,91,111,101,159]
%   TWAResult.successful    1
%
%   REPO:
%       https://github.com/cliffordlab/PhysioNet-Cardiovascular-Signal-Toolbox
%   ORIGINAL SOURCE AND AUTHORS:
%       Written by Ismail Sadiq
%	COPYRIGHT (C) 2019
%   LICENSE:
%       This software is offered freely and without warranty under
%       the GNU (v3 or later) public license. See license file for
%       more information. The license may be found in
%       the Documents folder of the Physionet-Cardiovascular-Signal-Toolbox.

% Add path to the readheader function
addpath(genpath('../../PhysioNet-Cardiovascular-Signal-Toolbox-master/'))
% Load data
sig = load('../Tools/ECG_Analysis_Tools/MV/Demos/testdata/twa/sample_ecg_twam');
siginfo = readheader('../Tools/ECG_Analysis_Tools/MV/Demos/testdata/twa/sample_ecg_twam.hea');
fs = siginfo.freq;
ecg = (sig.val - siginfo.adczero)./siginfo.gain; % Adjust signal according to gain and dc offset
clear sig siginfo
if (size(ecg,2) > size(ecg,1))
   ecg = ecg';
end

% Load annotations
ann.QRSon = read_ann('../Tools/ECG_Analysis_Tools/MV/Demos/testdata/twa/sample_ecg_twa','qrson')'; ann.Q = read_ann('../Tools/ECG_Analysis_Tools/MV/Demos/testdata/twa/sample_ecg_twa','q')'; ann.R = read_ann('../Tools/ECG_Analysis_Tools/MV/Demos/testdata/twa/sample_ecg_twa','r')'; ann.S = read_ann('../Tools/ECG_Analysis_Tools/MV/Demos/testdata/twa/sample_ecg_twa','s')'; ann.QRSoff = read_ann('../Tools/ECG_Analysis_Tools/MV/Demos/testdata/twa/sample_ecg_twa','qrsoff')'; ann.Toff = read_ann('../Tools/ECG_Analysis_Tools/MV/Demos/testdata/twa/sample_ecg_twa','toff')';
% Compute MVM and TWA in sample ECG.
%ann.Q = [];
[MVMResult,TWAResult] = eval_mvm_twa(ecg,ann,fs);


function tests = test_imBoxFilter(varargin)
% Test suite for function imBoxFilter.
%
%   Test case for the file imBoxFilter
%
%   Example
%   test_imBoxFilter
%
%   See also
%

% ------
% Author: David Legland
% e-mail: david.legland@inra.fr
% Created: 2018-11-22,    using Matlab 8.6.0.267246 (R2015b)
% Copyright 2018 INRA - Cepia Software Platform.

tests = functiontests(localfunctions);

function test_SquareUInt8_5x5(testCase) %#ok<*DEFNU>
% Test call of function without argument

img = zeros([20, 20], 'uint8');
img(6:15, 6:15) = 255;
dims = [5 5];

res = imBoxFilter(img, dims);

assertEqual(testCase, size(res), size(img));
assertEqual(testCase, class(res), class(img));

function test_SquareFloat_5x5(testCase) %#ok<*DEFNU>
% Test call of function without argument

img = zeros([20, 20], 'uint8');
img(6:15, 6:15) = 255;
dims = [5 5];

resRef = imBoxFilter(img, dims);
res = uint8(imBoxFilter(double(img), dims));

assertEqual(testCase, res, resRef);

function test_CubeFloat_7x5x3(testCase) %#ok<*DEFNU>
% Test call of function without argument

img = zeros([40 40 40], 'uint8');
img(11:30, 11:30, 11:30) = 255;
dims = [7 5 3];

resRef = imBoxFilter(img, dims);
res = uint8(imBoxFilter(double(img), dims));

assertEqual(testCase, res, resRef);


%MATCHGMS  GMS (Grid-based Motion Statistics) feature matching strategy
%
%     matchesGMS = cv.matchGMS(size1, keypoints1, size2, keypoints2, matches1to2)
%     matchesGMS = cv.matchGMS(..., 'OptionName', optionValue, ...)
%
% ## Input
% * __size1__ Size of first image `[w,h]`.
% * __keypoints1__ Keypoints from the first source image. A 1-by-N structure
%   array with the following fields:
%   * __pt__ coordinates of the keypoint `[x,y]`
%   * __size__ diameter of the meaningful keypoint neighborhood
%   * __angle__ computed orientation of the keypoint (-1 if not applicable).
%     Its possible values are in a range [0,360) degrees. It is measured
%     relative to image coordinate system (y-axis is directed downward), i.e
%     in clockwise.
%   * __response__ the response by which the most strong keypoints have been
%     selected. Can be used for further sorting or subsampling.
%   * __octave__ octave (pyramid layer) from which the keypoint has been
%     extracted.
%   * **class_id** object id that can be used to clustered keypoints by an
%     object they belong to.
% * __size2__ Size of second image `[w,h]`.
% * __keypoints2__ Keypoints from the second source image. Same format as
%   `keypoints1`.
% * __matches1to2__ Input 1-nearest neighbor matches from the first image to
%   the second one. A 1-by-M structure array with the following fields:
%   * __queryIdx__ query descriptor index (zero-based index)
%   * __trainIdx__ train descriptor index (zero-based index)
%   * __imgIdx__ train image index (zero-based index)
%   * __distance__ distance between descriptors (scalar)
%
% ## Output
% * __matchesGMS__ Matches returned by the GMS matching strategy.
%
% ## Options
% * __WithRotation__ Take rotation transformation into account. default false
% * __WithScale__ Take scale transformation into account. default false
% * __ThresholdFactor__ The higher, the less matches. default 6.0
%
% GMS feature matching strategy by [Bian2017gms].
%
% ## Notes
% * Since GMS works well when the number of features is large, we recommend to
%   use cv.ORB features and set `FastThreshold` to 0 to get as many features
%   as possible quickly.
% * If matching results are not satisfying, please add more features (we use
%   10000 for images with 640x480 size).
% * If your images have big rotation and scale changes, please set
%   `WithRotation` or `WithScale` to true.
%
% ## References
% [Bian2017gms]:
% > JiaWang Bian, Wen-Yan Lin, Yasuyuki Matsushita, Sai-Kit Yeung, Tan Dat
% > Nguyen, and Ming-Ming Cheng. "GMS: Grid-based motion statistics for fast,
% > ultra-robust feature correspondence".
% > In IEEE Conference on Computer Vision and Pattern Recognition, 2017.
%
% See also: cv.FeatureDetector, cv.DescriptorMatcher, cv.drawMatches
%


function jewelersLoupe(hFig)
%JEWELERSLOUPE modifies a figure to enable a Jeweler's Loupe tool.
%   JEWELERSLOUPE(FIG) will modify the figure with handle FIG to allow a
%   jeweler's loupe tool, which magnifies the axes by a factor of 4, to
%   appear whenever a user clicks on an axes. Dragging will cause the loupe
%   to follow the cursor. The tool assumes that any axes clicked will be a
%   linear 2-D axes. Performance will degrade as the amount of data in the
%   axes increates. If no figure is given, the loupe will appear in the
%   current figure.
%
%   Example:
%   plot(magic(3));
%   jewelersLoupe(gcf);
%
%   See also PAN, ZOOM.

%   Copyright 2008 The MathWorks, Inc.

% If a figure has not been passed in,
if nargin < 1
    hFig = gcf;
end

% Make sure we have a valid figure:
if ~ishandle(hFig) || ~strcmpi(get(hFig,'Type'),'figure')
    error('JEWELERSLOUPE:INVALIDFIGURE',...
        'The first input argument must be a valid figure.');
end

% Set up the callback for the loupe:
set(hFig,'WindowButtonDownFcn',@localCreateLoupe);

%------------------------------------------------------------------------%
function localCreateLoupe(hFig,evd) %#ok<INUSD>
% The loupe will appear for the current axes.
hAx = get(hFig,'CurrentAxes');

% If the axes is empty, we won't do anything.
if isempty(hAx)
    return;
end

% The loupe is implemented in terms of a separate axes:
hLoupe = axes('Parent',hFig,'Tag','loupe','HandleVisibility','off',...
    'XTickLabel','','YTickLabel','','XTick',[],'YTick',[],'Box','on');
% Set up the initial loupe position:
localUpdateLoupePosition(hFig,hLoupe);

% Copy the contents of the axes into the loupe:
copyobj(get(hAx,'Children'),hLoupe);

% We will zoom by a factor of 4 into the loupe based on the current point
% in the axes.
localDoZoom(hLoupe,hAx);

% Set callbacks for motion and button up:
set(hFig,'WindowButtonMotionFcn',{@localMoveLoupe,hAx,hLoupe});
set(hFig,'WindowButtonUpFcn',{@localCleanUp,hLoupe});

%------------------------------------------------------------------------%
function localMoveLoupe(hFig,evd,hAx,hLoupe) %#ok<INUSL>
% Move the loupe based on the current point:
localUpdateLoupePosition(hFig,hLoupe);

% Perform the zoom operation on the axes:
localDoZoom(hLoupe,hAx);

%------------------------------------------------------------------------%
function localCleanUp(hFig,evd,hLoupe) %#ok<INUSL>
% Clean up after the loupe has finished execution:

% Remove the callbacks:
set(hFig,'WindowButtonMotionFcn','');
set(hFig,'WindowButtonUpFcn','');

% Delete the loupe:
delete(hLoupe);

%------------------------------------------------------------------------%
function localUpdateLoupePosition(hFig,hLoupe)
% Moves the loupe based on the current point in the figure:

% The loupe should be centered on the current location and take up 25% of
% the figure space.
oldUnits = get(hFig,'Units');
set(hFig,'Units','Normalized');
mousePoint = get(hFig,'CurrentPoint');
set(hFig,'Units',oldUnits);
loupePosition = [(mousePoint-.125) .25 .25];
set(hLoupe,'Position',loupePosition);

%------------------------------------------------------------------------%
function localDoZoom(hLoupe,hAx)
% First, calculate the center based on the current point in the axes:
newCenter = get(hAx,'CurrentPoint');
% We are assuming a 2-D axes, so we will take the first two coordinates.
newCenter = newCenter(1,1:2);

% Zoom in by a factor of 4 around the given center point.
center_x = newCenter(1);
center_y = newCenter(2);

% Start by zooming the X-limits:
origXLim = get(hAx,'XLim');
xmin = origXLim(1);
xmax = origXLim(2);
dx = diff(origXLim);
newdx = dx * (1/4);
newdx = min(newdx,xmax-xmin);
newXLim = [center_x-newdx/2 center_x+newdx/2];

% Next, zoom the Y-limits:
origYLim = get(hAx,'YLim');
ymin = origYLim(1);
ymax = origYLim(2);
dy = diff(origYLim);
newdy = dy * (1/4);
newdy = min(newdy,ymax-ymin);
newYLim = [center_y-newdy/2 center_y+newdy/2];

% Update the limits:
set(hLoupe,'XLim',newXLim,'YLim',newYLim);


classdef TestBitwiseOr
    %TestBitwiseOr

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

    methods (Static)
        function test_rgb_images
            img1 = cv.imread(TestBitwiseOr.im, 'ReduceScale',2);
            img2 = cv.cvtColor(img1, 'RGB2HSV');

            % rectangular mask
            [h,w,~] = size(img1);
            mask = false([h w]);
            mask(100:h-100,100:w-100) = true;

            out = cv.bitwise_or(img1, img2);
            validateattributes(out, {class(img1)}, {'size',size(img1)});
            expected = my_bitwise_or(img1, img2);
            assert(isequal(out, expected));

            out = cv.bitwise_or(img1, img2, 'Mask',mask);
            validateattributes(out, {class(img1)}, {'size',size(img1)});
            expected = my_bitwise_or(img1, img2, mask);
            assert(isequal(out, expected));

            out = cv.bitwise_or(img1, img2, 'Mask',mask, 'Dest',img1);
            validateattributes(out, {class(img1)}, {'size',size(img1)});
            expected = my_bitwise_or(img1, img2, mask, img1);
            assert(isequal(out, expected));
        end

        function test_float_images
            img1 = cv.imread(TestBitwiseOr.im, 'ReduceScale',2);
            img1 = single(img1) ./ 255;
            img2 = cv.cvtColor(img1, 'RGB2HSV');
            img2(:,:,1) = img2(:,:,1) ./ 360;

            % circular mask
            [h,w,~] = size(img1);
            [X,Y] = meshgrid(1:w,1:h);
            c = fix([w h]/2); r = 50;
            mask = ((X-c(1)).^2 + (Y-c(2)).^2) < r^2;

            out = cv.bitwise_or(img1, img2);
            validateattributes(out, {class(img1)}, {'size',size(img1)});
            expected = my_bitwise_or(img1, img2);
            assert(isequaln(out, expected));

            out = cv.bitwise_or(img1, img2, 'Mask',mask);
            validateattributes(out, {class(img1)}, {'size',size(img1)});
            expected = my_bitwise_or(img1, img2, mask);
            assert(isequaln(out, expected));

            out = cv.bitwise_or(img1, img2, 'Mask',mask, 'Dest',img1);
            validateattributes(out, {class(img1)}, {'size',size(img1)});
            expected = my_bitwise_or(img1, img2, mask, img1);
            assert(isequaln(out, expected));
        end

        function test_vectors
            A = uint8([250 253 0]);
            B = uint8([1 2 255]);
            mask = [true false true];

            % uint8([251 255 255])
            out = cv.bitwise_or(A, B);
            validateattributes(out, {class(A)}, {'size',size(A)});
            expected = bitor(A, B);
            assert(isequal(out, expected));

            % uint8([251 0 255])
            out = cv.bitwise_or(A, B, 'Mask',mask);
            validateattributes(out, {class(A)}, {'size',size(A)});
            expected = bitor(A, B);
            expected(~mask) = 0;
            assert(isequal(out, expected));

            % uint8([251 253 255])
            out = cv.bitwise_or(A, B, 'Mask',mask, 'Dest',A);
            validateattributes(out, {class(A)}, {'size',size(A)});
            expected = bitor(A, B);
            expected(~mask) = A(~mask);
            assert(isequal(out, expected));
        end

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

end

function out = my_bitwise_or(src1, src2, mask, dst)
    %MY_BITWISE_OR  Similar to cv.bitwise_or using core MATLAB functions

    if nargin < 3, mask = true(size(src1,1), size(src1,2)); end
    if nargin < 4, dst = zeros(size(src1), class(src1)); end

    % calculate bitwise OR
    if isinteger(src1)
        out = bitor(src1, src2);
    elseif isfloat(src1)
        if isa(src1, 'double')
            klass = 'uint64';
        elseif isa(src1, 'single')
            klass = 'uint32';
        end
        out = bitor(typecast(src1(:), klass), typecast(src2(:), klass));
        out = reshape(typecast(out, class(src1)), size(src1));
    end

    % apply masking
    for k=1:size(out,3)
        out_slice = out(:,:,k);
        dst_slice = dst(:,:,k);
        out_slice(~mask) = dst_slice(~mask);
        out(:,:,k) = out_slice;
    end
end


function [CTmaterial materialNames] = generateMaterialMap(CTdensity, materialMap);

% JC Feb 2007
% Assign material numbers based on the density (g/cm3).
% Use to show material numbers/names in CERR GUI.

% Usage:
% [CTmaterial] = generateMaterialMap(materialMap, planC, scanNumber);

% output:
    % CTmaterial := same size as the uniformized CT scan, containing
    % material numbers.
    % materialNames := defined material names: eg. 'Air'    'Lung'
    % 'Water'    'Bone'

% input:
% >> materialMap(1)
% ans =
%           name: 'Air'
%     minDensity: 0
%     maxDensity: 0.0500

CTmaterial = zeros(size(CTdensity));
materialNames = cell(size(materialMap));

for i = 1 : length(materialMap),
    CTmaterial(materialMap(i).minDensity <= CTdensity & CTdensity < materialMap(i).maxDensity) = i;
    materialNames{i} = getfield(materialMap, {1,i}, 'name');
end

% If CTmaterial still has "0" elements, it means that the "materialMap"
% doesn't cover the whole CT values.
x = ismember(unique(CTmaterial), [1:length(materialMap)]);
if ismember(0,x)
warning('Input materialMap does NOT cover the whole CT scan values. Please check the CT values for voxels with "0" material number')
end

return;


%SHOWFIGS Show all figures on the screen
%
%  SHOWFIGS(K)
%
% Use K figures on a row

function showfigs(k)

h = sort(get(0,'children'));  % handles for all figures
n = length(h);                % number of figure
if nargin == 0
	k = ceil(sqrt(n));          % figures to be shown
end
s = 0.95/k;   % screen stitch
r = 0.93;     % image size reduction
t = 0.055;    % top gap
b = 0.005;    % border gap
fig = 0;
set(0,'units','pixels');
monpos = get(0,'monitorposition');
monpos = monpos(1,:);
for i=1:k
	for j=1:k
		fig = fig+1;
		if fig > n, break; end
		set(h(fig),'units','pixels','position',[(j-1)*s+b,(1-t)-i*s,s*r,s*r]*monpos(4));
		figure(h(fig));
	end
end
for j=n:-1:1, figure(h(j)); end


function k = whitefixedKernDiagCompute(kern, x)

% WHITEFIXEDKERNDIAGCOMPUTE Compute diagonal of WHITEFIXED kernel.
% FORMAT
% DESC computes the diagonal of the kernel matrix for the fixed parameter white noise kernel given a design matrix of inputs.
% ARG kern : the kernel structure for which the matrix is computed.
% ARG x : input data matrix in the form of a design matrix.
% RETURN k : a vector containing the diagonal of the kernel matrix
% computed at the given points.
%
% SEEALSO : whitefixedKernParamInit, kernDiagCompute, kernCreate, whitefixedKernCompute
%
% COPYRIGHT : Nathaniel J. King, 2006

% KERN

k = whiteKernDiagCompute(kern, x);


filename='Cylinder_Tetrahedra_Linear_Unstructured';
ptype = 'MACRO';
method = 'SIMPALL';
materialType = 'ISOTROPIC';
initial_case = 'cylinder';
fracRadius = 1-1e-6;
cost = {'compliance'};
weights = [1];
constraint = {'volumeConstraint'};
optimizer = 'SLERP';
designVariable = 'LevelSet';
incrementFactor = 1;
filterType = 'PDE';

nsteps = 1;
Vfrac_final = 1;
Perimeter_target=3.5;
optimality_final =1e-5;
constr_final =1e-5;

BCscale_factor = 0.3;
HJiter0 = 1;
e2 = 5;

Vfrac_initial = 1;
optimality_initial = 5e-2;
constr_initial = 5e-2;

TOL.rho_plus = 1;
TOL.rho_minus = 0;
TOL.E_plus = 1;
TOL.E_minus = 1e-3;

% maxiter = 10;
% maxiter = 1;
TOL.nu_plus = 0.3;
TOL.nu_minus = 0.3;

plotting = false;
printing = false;
monitoring = false;
monitoring_interval = 0;


function [f, d] = getSIFTFeatures(image, edgeThresh)

%convert images to greyscale
if (size(image, 3) == 3)
    Im = single(rgb2gray(image));
else
    Im = single(image);
end

% get features and descriptors
[f, d] = vl_sift(Im, 'EdgeThresh', edgeThresh);

end


function [ score ] = bliinds2_score( image )
%BLIINDS2_SCORE Summary of this function goes here
%   Detailed explanation goes here

    import bliinds2.*

    features = bliinds2_feature_extraction(image);
    score = bliinds_prediction(features);

end


function addframe(vw,img)
%WORKED=ADDFRAME(VW)
%  Writes a video frame.  VW must be a videoWriter object and IMG a 2D
%  numeric array with 1 or 3 channels that is autoconverted to a uint8
%  image as follows:
%
%    type    assumed range
%    ----    -------------
%    uint8   0 to 255
%    double  0 to 1
%    logical 0 to 1
%
%SEE ALSO
%  videoWriter
%
%Copyright (c) 2007 Gerald Dalley
%See "MIT.txt" in the installation directory for licensing details (especially
%when using this library on GNU/Linux).

[h,w,d] = size(img);

if (isa(img, 'uint8'))
  if (h ~= vw.h || w ~= vw.w)
    img = uint8(255*imresize(double(img)/255, [vw.h vw.w]));
  else
    % no changes needed
  end

elseif (isa(img, 'double') || islogical(img))
  if (h ~= vw.h || w ~= vw.w)
    img = uint8(255*imresize(img, [vw.h vw.w]));
  else
    img = uint8(255*img);
  end

else
  error('Invalid image type.');
end

if (d == 1)
  img = repmat(img, [1 1 3]);
end

feval(vw.plugin, 'addframe', vw.handle, img);


% :Usage:
% ::
%
%     OUT = mean_image(input file names, output file name, [weights], [string command args]);
%
% Creates a weighted mean of images based on weights for each image
%
% :Inputs:
%
%   **'normlike':**
%        do in style of mean_warped_image, for norm toolbox;
%        ignore other string arguments
%
%
%   **'reweight':**
%        weight by distance from median in 2nd round of averaging
%
%   **'plot':**
%        plot output
%
%   **'sharpen':**
%        segments and smooths within tissue classes
%
% :Examples:
% ::
%
%    w = filenames('w*T1.img', 'char')
%    w = mean_image(w, 'final_mean.img', [], 'normlike'); % trimmed, weighted best 50%
%
%    worig = filenames('hr*/wT1.img', 'char')           % no weights
%    w = mean_image(worig, 'orig_mean_noweights.img', []);
%
%    mean_image(DB.PP, 'Activation.img', DB.studyweight);
%
%    mean_image(P, 'mean_wmeanw1007.img', ones(size(P, 1), 1), 'sharpen', 'plot', 'reweight');
%
%    P = filenames('w*mr.img', 1);
%
%    % Enter empty inputs for default settings.
%    OUT.P = filenames
%    OUT.dist

function OUT = mean_image(VP, Pout, w, varargin)
    % --------------------------------------
    % inputs
    % --------------------------------------
    dosharp = 0;
    dodist = 0;
    doplot = 0;
    doreweight = 0;
    donormlike = 0;

    dozscore = 0;

    for i = 1:length(varargin)
        if ischar(varargin{i})
            if strcmp(varargin{i}, 'sharpen'), dosharp = 1; end
            %if strcmp(varargin{i}, 'dist'), dodist = 1; end
            if strcmp(varargin{i}, 'plot'), doplot = 1; end
            if strcmp(varargin{i}, 'reweight'), doreweight = 1; end
            if strcmp(varargin{i}, 'normlike'), donormlike = 1; end

            if strcmp(varargin{i}, 'zscore'), dozscore = 1; end
        end
    end

    if isempty(VP)
        VP = spm_vol(spm_get(1, '*', 'Select images'));
    else
        if(iscellstr(VP)),
            VP = char(VP);
        end
        P = VP;
        VP = spm_vol(VP);
    end
    n = length(VP);

    if ~exist('Pout', 'var') || isempty(Pout), Pout = 'mean.nii'; end
    if ~exist('w', 'var') || isempty(w), w = ones(n, 1); end

    OUT.P = VP;

    % --------------------------------------
    % do mean in style of mean_warped_image
    % --------------------------------------
    % output is weights
    if donormlike
        OUT = do_mean_like_mean_warped_image(P, Pout);
        return
    end

    % --------------------------------------
    % make mean image
    % --------------------------------------

    status_string = sprintf('%3d', 0);
    fprintf(['Percent done: ' status_string]);

    switch spm('Ver')
        case 'SPM2'
            % spm_defaults is a script
            disp('WARNING: spm defaults not set for spm2. Make sure your defaults are set correctly');

        case 'SPM5'
            % spm_defaults is a function
            spm_defaults()
        case 'SPM8'
            spm_defaults()
    end

    % initialize output
    V = VP(1);
    V.fname = Pout;
    V.n(1) = 1;    % write to first volume

    dat = zeros(V.dim(1:3));

    % read and weight

    for i = 1:n
        v = iimg_read_vols(VP(i));

        if dozscore
            v = center_scale(v);
        end

        dat = dat + v .* w(i);

        erase_string(status_string);
        status_string = sprintf('%3d', round(i/n*100));
        fprintf(status_string);
    end

    % divide by N
    dat = dat ./ n;

    fprintf('\n');

    % write output
    %strrep required to make file extension correct
    V.fname = strrep(V.fname, '.nii,1', '.nii');
    V.fname = strrep(V.fname, '.img,1', '.img');
    spm_write_vol(V, dat);

    if doplot
        z = round(V.dim(3)./2);
        f1 = figure;
        imagesc(dat(:,:,z));
        axis image;
        axis off;
        title('Mean');  drawnow
    end

    % --------------------------------------
    % Reweight
    % --------------------------------------

    if doreweight
        fprintf(1, ' Reweighting.000');

        for i = 1:n
            fitness(i) = norm_eval_fitness(tempdat, normdat, 0);
        end

        imgMedian = zeros(n, 1);
        imgMean = imgMedian;
        imgStd = imgMedian;

        medianDev = zeros(n, 5);
        newdat = zeros(V.dim(1:3));

        % subtract median from mean image
        [dat, datMedian] = subtract_median(dat);

        % get medians and subtract
        for i = 1:n

            fprintf(1, '\b\b\b%03d', i);

            v = spm_read_vols(spm_vol(deblank(P(i,:))));

            [v, imgMedian(i)] = subtract_median(v);

            %imgMean(i) = mean(vi);
            %imgStd(i) = std(vi);

            % distance from median-centered old mean image
            vi = v - dat;  vi = abs(vi(:));
            vi(isnan(vi) | vi==0) = [];
            if isempty(vi), warning('Image is EXACTLY the median image.'); end

            % get median deviation, and 5th and 95th prctiles
            medianDev(i,:) = prctile(vi, [50 5 20 80 95]);

            % get new weights based on distance from mean image
            w(i) = datMedian./medianDev(i, 1);

            newdat = newdat + v .* w(i);

        end

        newdat = newdat .* sum(w);          % normalize to keep in same scale

        whnull = isnan(newdat) | newdat==0;
        %newdat = newdat + mean(imgMedian);  % add median back in to average
        newdat(whnull) = 0;

        dat = newdat;
        OUT.medianDev = medianDev;
        OUT.prctiles = [50 5 20 80 95];

        if doplot
            tor_fig;
            plot(medianDev(:,1), 'o-');
            ylabel('Med. Abs. Dev from median image');
            xlabel('Image number'); grid on;

            figure(f1); subplot(4, 1, 2);
            imagesc(dat(:,:,z));
            axis image;
            axis off;
            title('Reweighted');drawnow
        end

        % write output
        spm_write_vol(V, dat);
    end

    % --------------------------------------
    % Sharpen
    % --------------------------------------

    if dosharp
        fprintf(1, ' Sharpening: segmenting.');

        defaults.segment.estimate.reg = .1;% was .01;
        VO = spm_segment(Pout, which('T1.mnc'), defaults.segment);

        spm_write_vol(VO(1), VO(1).dat);
        spm_write_vol(VO(2), VO(2).dat);
        spm_write_vol(VO(3), VO(3).dat);

        fprintf(1, ' Lightening white matter.');

        thr = prctile(VO(2).dat(:), 90);
        whiteMask = double(VO(2).dat > thr);

        mystd = .2 .* nanstd(dat(:));
        dat = dat + whiteMask .* mystd;

        % write output
        name = [Pout(1:end-4) '_sharp.img'];
        V.fname = name;
        spm_write_vol(V, dat);

        % make brain mask
        brainMask = double(VO(1).dat>0 | VO(2).dat>0);

        name = [Pout(1:end-4) '_brain.img'];
        V.fname = name;
        spm_write_vol(V, brainMask);

        ovl = dat .* brainMask;
        name = [Pout(1:end-4) '_overlay.img'];
        V.fname = name;
        spm_write_vol(V, ovl);

        if doplot
            figure(f1); subplot(4, 1, 3);
            imagesc(dat(:,:,z));
            axis off;
            axis image;
            title('Sharpened');drawnow

            subplot(4, 1, 4);
            imagesc(ovl(:,:,z));
            axis off;
            axis image;
            title('Overlay');drawnow
        end
    end
end

function [dat, datMedian] = subtract_median(dat)
    vi = dat(:);
    vi(isnan(vi) | vi==0) = [];
    datMedian = median(vi);

    whnull = isnan(dat) | dat==0;

    dat = dat - datMedian;
    dat(whnull) = 0;
end

function v = center_scale(v)
    vi = v(:);
    vi(isnan(vi) | vi==0) = [];
    v = (v - mean(vi)) ./ std(vi);
end

function weights = do_mean_like_mean_warped_image(P, outname)
    spm_defaults;
    defaults.analyze.flip = 0;
    [volTemplate, normdat] = iimg_read_img(P);

    t1 = clock;
    n = size(P, 1);

    % Provisional mean
    % ------------------------------------
    fprintf(1, 'Initial. ');

    normdat(isnan(normdat)) = 0;

    % convert in-mask voxels to mean = gm, so averaging is not distorted by
    % overall intensity differences among images
    % and fitness weights determine relative contribution of images
    means = mean(normdat);      % mean of each image
    gm = mean(means);           % global mean
    scalef = gm ./ means;       % scaling factor to norm each image to grand mean

    for i = 1:n
        normdat(:,i) = normdat(:,i) .* scalef(i);
    end

    meandat = mean(normdat, 2);
    vox = size(meandat, 1);

    fprintf(1, 'Weighted mean of best 50%%. ');
    % Weights based on closeness to mean
    % ------------------------------------
    for i = 1:n
        fitness(i) = norm_eval_fitness(meandat, normdat(:,i), 0);
    end

    mfit = nanmedian(fitness);
    weights = fitness;
    weights(weights < mfit) = 0;

    weights = weights ./ sum(weights);

    if all(weights == 0)
        warning('All weights are zero!')
        weights = ones(1, n);
    end

    % Weighted mean
    % ------------------------------------
    meandat = zeros(vox, 1);
    for i = 1:n

        if weights(i) > 0   % just to save time
            meandat = meandat + weights(i) .* normdat(:,i);
        end

    end

    fprintf(1, 'Done: Writing\n');
    % Write output image
    % This will be the new normalization template
    % ------------------------------------
    meandata = iimg_reconstruct_3dvol(meandat, volTemplate, 'outname', outname);

    fprintf(1, 'Mean warped image completed: %3.0f s\n', etime(clock, t1));

    fprintf(1, '-----------------------------\n');
end


function outPutFeatures = yolov3v4Predict(cfg_file,weight_file,image)
% 功能：yolov3快速输出检测特征，同darknet官网输出结果方式保持一致
% 输入：
%      cfg_file, 指定的cfg后缀的模型描述文件
%      weight_file, 指定的.weights后缀的二进制文件
%      image ：输入网络的图像数据,单张图像(H*W*C)或者批量图像(H*W*C*bs)
% 输出：
%     outPutFeatures： M*(5+nc)或者bs*M*(5+nc)大小
%     ,为bs*M*[x,y,w,h,Pobj,p1,p2,...,pn]大小的形式矩阵，如果是单张图像检测，则输出大小为M*(5+nc)，否则是bs*M*(5+nc),
%     其中，M为检测框的数量，bs为图片数量，nc为训练网络dlnet类别数量，x,y,w,h分别是输入图片上对应的x,y,width,height，Pobj
%     为物体概率，p1,p2,...,pn分别为对应coco.names类别概率
%
% author: cuixingxing
% email:cuixingxing150@gmail.com
% 2020.4.22创建
% 2020.5.2 修改
% 2020.5.13 minor fix
%

persistent dlnet yolovLayerArray netInputSize
if isempty(dlnet)

    %% import network and predict
    [layerGraphYolo,hyperParams] = importDarknetWeights(cfg_file,weight_file);
    dlnet = dlnetwork(layerGraphYolo); % 65秒左右
    % analyzeNetwork(layerGraphYolo)% visualize network
    % exportDarkNetNetwork(dlnet,hyperParams,'temp.cfg','temp.weights')

     %% get yolo index
    yoloIdx = [];
    for i = 1:length(dlnet.Layers)
        currentLayerType = class(dlnet.Layers(i));
        if strcmpi(currentLayerType,'yoloV3Layer')
            yoloIdx = [yoloIdx;i];
        end
    end
    assert(~isempty(yoloIdx),'输入网络非yolov3/4网络！')

    yolovLayerArray = dlnet.Layers(yoloIdx);
    netInputSize = dlnet.Layers(1).InputSize(1:2);
end

inputSize = [size(image,1),size(image,2)];
scale = inputSize./netInputSize;% [heightScale,widthScale]

img = imresize(im2single(image),netInputSize);% [0,1]数据，保持与训练时候同大小和类型
dlX = dlarray(img,'SSCB');% 大小为h*w*c*bs,注意是否归一化要看与训练时候图像一致
if(canUseGPU())
    dlX = gpuArray(dlX);% 推送到GPU上
end

numsYOLO = length(yolovLayerArray);
outFeatureMaps = cell(numsYOLO,1);
[outFeatureMaps{:}] = predict(dlnet,dlX,'Outputs',dlnet.OutputNames);% h*w*c*bs,matlab输出方式排列
outPutFeatures = [];
for i = 1:numsYOLO
    currentYOLOLayer = yolovLayerArray(i);
    currentFeatureMap = outFeatureMaps{i};

    % 由于yolov3Layer类里面predict函数未改变类属性，故重新给属性赋值
    currentYOLOLayer.numY = size(currentFeatureMap,1);
    currentYOLOLayer.numX = size(currentFeatureMap,2);
    currentYOLOLayer.stride = max(currentYOLOLayer.imageSize)./max(currentYOLOLayer.numX,...
        currentYOLOLayer.numY);

    % reshape currentFeatureMap到有意义的维度，h*w*c*bs --> h*w*(5+nc)*na*bs
    % --> bs*na*h*w*(5+nc),最终的维度方式与darknet官网兼容
    bs = size(currentFeatureMap,4);
    h = currentYOLOLayer.numY;
    w = currentYOLOLayer.numX;
    na = currentYOLOLayer.nAnchors;
    nc = currentYOLOLayer.classes;
    currentFeatureMap = reshape(currentFeatureMap,h,w,5+nc,na,bs);% h*w*(5+nc)*na*bs
    currentFeatureMap = permute(currentFeatureMap,[5,4,1,2,3]);% bs*na*h*w*(5+nc)

    [~,~,yv,xv] = ndgrid(1:bs,1:na,0:h-1,0:w-1);% yv,xv大小都为bs*na*h*w，注意顺序，后面做加法维度标签要对应
    gridXY = cat(5,xv,yv);% 第5维上扩展，大小为bs*na*h*w*2, x,y从1开始的索引
    currentFeatureMap(:,:,:,:,1:2) = sigmoid(currentFeatureMap(:,:,:,:,1:2)) + gridXY; % 大小为bs*na*h*w*2,预测对应xy
    anchor_grid = currentYOLOLayer.anchorsUse/currentYOLOLayer.stride; % 此处anchor_grid大小为na*2
    anchor_grid = reshape(anchor_grid,1,currentYOLOLayer.nAnchors,1,1,2);% 此处anchor_grid大小为1*na*1*1*2，方便下面相乘
    currentFeatureMap(:,:,:,:,3:4) = exp(currentFeatureMap(:,:,:,:,3:4)).*anchor_grid;% 大小为bs*na*h*w*2
    currentFeatureMap(:,:,:,:,1:4) = currentFeatureMap(:,:,:,:,1:4)*currentYOLOLayer.stride; % 预测的bboxes
    currentFeatureMap(:,:,:,:,5:end) = sigmoid(currentFeatureMap(:,:,:,:,5:end)); % 预测的scores

    if currentYOLOLayer.classes == 1
        currentFeatureMap(:,:,:,:,6) = 1;
    end
    currentFeatureMap = reshape(currentFeatureMap,bs,[],5+currentYOLOLayer.classes);% bs*N*(5+nc)

    if isempty(outPutFeatures)
        outPutFeatures = currentFeatureMap;
    else
        outPutFeatures = cat(2,outPutFeatures,currentFeatureMap);% bs*M*(5+nc)
    end
end

%% 坐标转换到原始图像上
outPutFeatures = extractdata(outPutFeatures);% bs*M*(5+nc) ,为[x_center,y_center,w,h,Pobj,p1,p2,...,pn]
outPutFeatures(:,:,[1,3]) = outPutFeatures(:,:,[1,3])*scale(2);% x_center,width
outPutFeatures(:,:,[2,4]) = outPutFeatures(:,:,[2,4])*scale(1);% y_center,height
outPutFeatures(:,:,1) = outPutFeatures(:,:,1) -outPutFeatures(:,:,3)/2;%  x
outPutFeatures(:,:,2) = outPutFeatures(:,:,2) -outPutFeatures(:,:,4)/2; % y
outPutFeatures = squeeze(outPutFeatures); % 如果是单张图像检测，则输出大小为M*(5+nc)，否则是bs*M*(5+nc)
if(canUseGPU())
    outPutFeatures = gather(outPutFeatures); % 推送到CPU上
end
end


% prettyPolorScatter
%--------------------------------------------------------------------------
%
% plot with projection an area of the world
%
% POSSIBLE SINTAXES:
%   scatterHandler = prettyPolorScatter(dataScatter, phi, lambda);
%
%   prettyPolorScatter(dataScatter, phi, lambda, shape);
%   prettyPolorScatter(dataScatter, phi, lambda, projection);
%   prettyPolorScatter(dataScatter, phi, lambda, lineCol);
%
%   prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax);
%   prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, shape);
%   prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, projection);
%   prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, lineCol);
%
%   prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, shape, projection);
%   prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, shape, lineCol);
%   prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, projection, shape);
%   prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, projection, lineCol);
%
%   prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, projection, shape, lineCol);
%   prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, shape, projection, lineCol);
%
% EXAMPLE:
%   prettyPolorScatter(dataScatter, phiMin, phiMax, lambdaMin, lambdaMax, 'Miller Cylindrical');
%
% INPUT:
%   dataScatter     array containing the data value (z = colour)
%   phi             array [degree]
%   lambda          array [degree]
%   phiMin          minimum latitude    [degree]
%   phiMax          maximum latitude    [degree]
%   lambdaMin       minimum longitude   [degree]
%   lambdaMax       maximum longitude   [degree]
%   projection      type of projection to be used "standard" is the default
%   shape           shapefile to load as coast (or country) contour
%                       - coast         only coasts coarse
%                       - 50m           1:50000000 scale country contours
%                       - 30m           1:30000000 scale country contours
%                       - 10m           1:10000000 scale country contours
%   lineCol         [1 1 1] array of RGB component to draw the contour lines
%
% DEFAULT VALUES:
%    projection = 'Lambert'
%
% AVAILABLE PROJECTION:
%    * Lambert
%      Stereographic
%      Orthographic
%      Azimuthal Equal-area
%      Azimuthal Equidistant
%      Gnomonic
%      Satellite
%      Albers Equal-Area Conic
%      Lambert Conformal Conic
%      Mercator
%    * Miller Cylindrical
%    * Equidistant Cylindrical (world dataScatter)
%      Oblique Mercator
%      Transverse Mercator
%      Sinusoidal
%      Gall-Peters
%      Hammer-Aitoff
%      Mollweide
%      Robinson
%    * UTM
%
% SEE ALSO:
%   dataScatterPlot, dataScatterPlot3D, scatter
%
% REQUIREMENTS:
%   M_Map: http://www.eos.ubc.ca/~rich/dataScatter.html
%   shape files with contours
%
% VERSION: 2.1
%
% CREDITS:
%   http://www.eos.ubc.ca/~rich/dataScatter.html
%
%   Andrea Gatti
%   DIIAR - Politecnico di Milano
%   2013-12-19
%

function scatterHandler = prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, projection, shape, lineCol)

%shape = 'coast';
%shape = '10m';
%shape = '30m';
%shape = '50m';

% lineCol = [0 0 0];

dataScatter = dataScatter(:);
phi = phi(:);
lambda = lambda(:);

limitsOk = false;

% Manage opening a new figure;
tohold = false;
if length(findall(0,'Type','figure'))>=1
    if ishold
        tohold = true;
    else
        figure;
    end
end

switch (nargin)
    case 3
        shape = 'coast';
        lineCol = [0 0 0];
        if (ischar(phi))
            projection = 'Miller Cylindrical';
            if (sum(strcmp(phi,[{'coast'},{'10m'},{'30m'},{'50m'}])))
                shape = phi;
                if (ischar(lambda))
                    projection = lambda;                              % prettyPolorScatter(dataScatter, shape, projection);
                else
                    lineCol = lambda;                                 % prettyPolorScatter(dataScatter, shape, lineCol);
                end
            else
                projection = phi;
                if (ischar(lambda))
                    shape = lambda;                                   % prettyPolorScatter(dataScatter, projection, shape);
                else
                    lineCol = lambda;                                 % prettyPolorScatter(dataScatter, projection, lineCol);
                end
            end
            phiMin = 90;
            phiMax = -90;
            lambdaMin = -180;
            lambdaMax = 180;

            deltaPhi = (phiMax-phiMin)/size(dataScatter,1);
            deltaLambda = (lambdaMax-lambdaMin)/size(dataScatter,2);

            phi    = (phiMin + deltaPhi/2 : deltaPhi : phiMax - deltaPhi/2)';
            lambda = (lambdaMin + deltaLambda/2 :  deltaLambda :  lambdaMax  - deltaLambda/2)';
        else                                                              % prettyPolorScatter(dataScatter, phi, lambda);
            projection = 'Miller Cylindrical';
            phiMin = max(phi);
            phiMax = min(phi);
            lambdaMin = min(lambda);
            lambdaMax = max(lambda);
        end
    case 4
        shape = 'coast';
        lineCol = [0 0 0];
        projection = 'Miller Cylindrical';
        if (ischar(phiMin))
            if (sum(strcmp(phiMin,[{'coast'},{'10m'},{'30m'},{'50m'}])))  % prettyPolorScatter(dataScatter, phi, lambda, shape);
                shape = phiMin;
            else                                                          % prettyPolorScatter(dataScatter, phi, lambda, projection);
                projection = phiMin;
            end
        elseif (length(phiMin) == 3)                                      % prettyPolorScatter(dataScatter, phi, lambda, lineCol);
            lineCol = phiMin;
        end

        phiMin = max(phi);
        phiMax = min(phi);
        lambdaMin = min(lambda);
        lambdaMax = max(lambda);
    case 5
        shape = 'coast';
        lineCol = [0 0 0];
        projection = 'Miller Cylindrical';
        if (ischar(phiMin))
            if (sum(strcmp(phiMin,[{'coast'},{'10m'},{'30m'},{'50m'}])))
                shape = phiMin;
                if (ischar(phiMax))
                    projection = phiMax;                                  % prettyPolorScatter(dataScatter, phiMin, phiMax, shape, projection);
                else
                    lineCol = phiMax;                                     % prettyPolorScatter(dataScatter, phiMin, phiMax, shape, lineCol);
                end
            else
                projection = phiMin;
                if (ischar(phiMax))
                    shape = phiMax;                                       % prettyPolorScatter(dataScatter, phiMin, phiMax, projection, shape);
                else
                    lineCol = phiMax;                                     % prettyPolorScatter(dataScatter, phiMin, phiMax, projection, lineCol);
                end
            end
            phiMin = max(phi);
            phiMax = min(phi);
            lambdaMin = min(lambda);
            lambdaMax = max(lambda);
        else                                                             %  prettyPolorScatter(dataScatter, phiMin, phiMax, lambdaMin, lambdaMax);
            limitsOk = true;
            lambdaMin = phiMin;
            lambdaMax = phiMax;
            phiMin = phi;
            phiMax = lambda;

            if (phiMin < phiMax)
                tmp = phiMin;
                phiMin = phiMax;
                phiMax = tmp;
            end

            deltaPhi = (phiMax-phiMin)/size(dataScatter,1);
            deltaLambda = (lambdaMax-lambdaMin)/size(dataScatter,2);

            phi    = (phiMin + deltaPhi/2 : deltaPhi : phiMax - deltaPhi/2)';
            lambda = (lambdaMin + deltaLambda/2 :  deltaLambda :  lambdaMax  - deltaLambda/2)';
        end
    case 6
        shape = 'coast';
        lineCol = [0 0 0];
        limitsOk = true;
        projection = 'Lambert';
        if (ischar(lambdaMin))
            if (sum(strcmp(lambdaMin,[{'coast'},{'10m'},{'30m'},{'50m'}])))
                shape = lambdaMin;                                        % prettyPolorScatter(dataScatter, phiMin, phiMax, lambdaMin, lambdaMax, shape);
            else
                projection = lambdaMin;
            end
        elseif (length(lambdaMin) == 3)
            lineCol = lambdaMin;                                          % prettyPolorScatter(dataScatter, phiMin, phiMax, lambdaMin, lambdaMax, lineCol);
        end

        lambdaMax = phiMax;
        lambdaMin = phiMin;
        phiMin = phi;
        phiMax = lambda;

        if (phiMin < phiMax)
            tmp = phiMin;
            phiMin = phiMax;
            phiMax = tmp;
        end

        deltaPhi = (phiMax-phiMin)/size(dataScatter,1);
        deltaLambda = (lambdaMax-lambdaMin)/size(dataScatter,2);

        phi    = (phiMin + deltaPhi/2 : deltaPhi : phiMax - deltaPhi/2)';
        lambda = (lambdaMin + deltaLambda/2 :  deltaLambda :  lambdaMax  - deltaLambda/2)';
    case 7
        shape = 'coast';
        lineCol = [0 0 0];
        limitsOk = true;
        projection = 'Lambert';
        if (ischar(lambdaMin))
            if (sum(strcmp(lambdaMin,[{'coast'},{'10m'},{'30m'},{'50m'}])))
                shape = lambdaMin;
                if (ischar(lambdaMax))
                    projection = lambdaMax;                               % prettyPolorScatter(dataScatter, phiMin, phiMax, lambdaMin, lambdaMax, shape, projection);
                else
                    lineCol = lambdaMax;                                  % prettyPolorScatter(dataScatter, phiMin, phiMax, lambdaMin, lambdaMax, shape, lineCol);
                end
            else
                projection = lambdaMin;
                if (ischar(lambdaMax))
                    shape = lambdaMax;                                    % prettyPolorScatter(dataScatter, phiMin, phiMax, lambdaMin, lambdaMax, projection, shape);
                else
                    lineCol = lambdaMax;                                  % prettyPolorScatter(dataScatter, phiMin, phiMax, lambdaMin, lambdaMax, projection, lineCol);
                end
            end

            lambdaMin = phiMin;
            lambdaMax = phiMax;
            phiMin = phi;
            phiMax = lambda;

            if (phiMin < phiMax)
                tmp = phiMin;
                phiMin = phiMax;
                phiMax = tmp;
            end

            deltaPhi = (phiMax-phiMin)/size(dataScatter,1);
            deltaLambda = (lambdaMax-lambdaMin)/size(dataScatter,2);

            phi    = (phiMin + deltaPhi/2 : deltaPhi : phiMax - deltaPhi/2)';
            lambda = (lambdaMin + deltaLambda/2 :  deltaLambda :  lambdaMax  - deltaLambda/2)';
        else
            projection = 'lambert';                                       % prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax);
        end
    case 8
        shape = 'coast';
        lineCol = [0 0 0];
        limitsOk = true;
        if (ischar(projection))
            if (sum(strcmp(projection,[{'coast'},{'10m'},{'30m'},{'50m'}])))
                shape = projection;                                       % prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, shape);
                projection = 'Lambert';
            else
                % prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, projection);
            end
        elseif (length(projection) == 3)
            lineCol = projection;                                         % prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, lineCol);
            projection = 'Lambert';
        end
    case 9
        lineCol = [0 0 0];
        limitsOk = true;
        if (ischar(projection))
            if (sum(strcmp(projection,[{'coast'},{'10m'},{'30m'},{'50m'}])))
                tmp = shape;
                shape = projection;
                if (ischar(tmp))
                    projection = tmp;                                     % prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, shape, projection);
                else
                    lineCol = tmp;                                        % prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, shape, lineCol);
                    projection = 'UTM';
                end
            else
                if (ischar(shape))
                    % prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, projection, shape);
                else
                    lineCol = shape;                                      % prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, projection, lineCol);
                    shape = 'coast';
                end
            end
        end
    case 10                                                               % prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, projection, shape, lineCol)
        limitsOk = true;
        if (sum(strcmp(projection,[{'coast'},{'10m'},{'30m'},{'50m'}])))   % prettyPolorScatter(dataScatter, phi, lambda, phiMin, phiMax, lambdaMin, lambdaMax, shape, projection, lineCol)
            tmp = shape;
            shape = projection;
            projection = tmp;
        end
end

if (phiMin < phiMax)
    tmp = phiMin;
    phiMin = phiMax;
    phiMax = tmp;
end

lambdaTmp = sort(lambda);
[val, idMax] = max(diff(lambdaTmp));
if (sum(diff(lambdaTmp) == val) == 1) && val > 10
    lambdaTmp(1:idMax) = lambdaTmp(1:idMax)+360;
    if ~limitsOk
        lambdaMax = lambdaTmp(idMax);
        lambdaMin = lambdaTmp(idMax+1);
    end
end

if(lambdaMax<lambdaMin)
    lambdaMax = lambdaMax+360;
end

if (~limitsOk)
    lambdaMin = lambdaMin-3;
    lambdaMax = lambdaMax+3;
    phiMin = min(phiMin+3,90);
    phiMax = max(phiMax-3,-90);
end

projection = 'Transverse Mercator';

% setup the projection
if ~tohold
    if (strcmpi(projection,{'lambert'}) && abs(phiMax==-phiMin))
        projection='Miller Cylindrical';
    end

    if (sum(strcmpi(projection,[{'lambert'},{'UTM'},{'Sinusoidal'},{'Transverse Mercator'},{'Oblique Mercator'},{'Miller Cylindrical'}])))
        m_proj(projection,'long',[lambdaMin lambdaMax],'lat',[phiMax phiMin]);
    else
        m_proj(projection);
    end

    % Printing projection
    fprintf('Using projection: %s\n', projection);

    if sum(diff(lambda)<-200)
        lambda(lambda<0)=lambda(lambda<0)+360;
    end
    % plot the dataScatter
    m_pcolor([lambdaMin lambdaMax],[phiMin phiMax], nan(2));
    % set the light
    shading flat;

end

ids = (lambda<lambdaMin) & (lambda < 0);
lambda(ids) = lambda(ids)+360;

ids = (lambda>lambdaMax);
lambda(ids) = lambda(ids)-360;

hold on;
[xlocal,ylocal] = m_ll2xy(lambda(:),phi(:));
scatterHandler = scatter(xlocal,ylocal,30,dataScatter,'filled'); % <========================= SCATTER function is here

% read shapefile
if (~strcmp(shape,'coast'))
    if (strcmp(shape,'10m'))
        M=m_shaperead('countries_10m');
    elseif (strcmp(shape,'30m'))
        M=m_shaperead('countries_30m');
    else
        M=m_shaperead('countries_50m');
    end
    [xMin,yMin] = m_ll2xy(lambdaMin,phiMin);
    [xMax,yMax] = m_ll2xy(lambdaMax,phiMax);
    for k=1:length(M.ncst)
        lamC = M.ncst{k}(:,1);
        ids = lamC < lambdaMin;
        lamC(ids) = lamC(ids) + 360;
        phiC = M.ncst{k}(:,2);
        [x,y] = m_ll2xy(lamC,phiC);
        if sum(~isnan(x))>1
            x(find(abs(diff(x))>=abs(xMax-xMin)*0.90)+1) = nan; % Romove lines that occupy more than th 90% of the plot
            line(x,y,'color', lineCol);
        end
    end;
else
    m_coast('line','color', lineCol);
end

m_grid('box','fancy','tickdir','in');
drawnow;
if (phiMax >= 0)
    h=get(gca,'Children'); hf = findobj(h(1:end),'Tag','m_grid_fancybox1');
    delete(h(18));
    delete(hf([1:5 8]));
else
    h=get(gca,'Children');
    hf = findobj(h(1:end),'Tag','m_grid_fancybox1');
    %delete(h(18));
    delete(hf([1:4 6 7]));
end

colorbar;

if tohold
    hold on;
else
    hold off;
end