function ebsd = fill(ebsd,varargin)
% fill EBSD data by nearest neighbour
%
% Syntax
%   ebsd_filled = fill(ebsd)
%   ebsd_filled = fill(ebsd,grains)
%
% Input
%  ebsd - @EBSD
%  grains - @grain2d
%
% Options
%  extrapolate - extrapolate up the the outer boundaries
%

if ~(isa(ebsd,'EBSDsquare') || isa(ebsd,'EBSDhex')), ebsd = ebsd.gridify; end

% the values to be filled
nanId = isnan(ebsd.phaseId);

if check_option(varargin,'extrapolate')
  opt = 'nearest';
else
  opt = 'none';
end

F = scatteredInterpolant([ebsd.prop.x(~nanId),ebsd.prop.y(~nanId)],...
  find(~nanId),'nearest',opt);

newId = F(ebsd.prop.x(nanId),ebsd.prop.y(nanId));

nanId(nanId) = ~isnan(newId);
newId(isnan(newId)) = [];

% interpolate phaseId
ebsd.phaseId(nanId) = ebsd.phaseId(newId);
ebsd.rotations(nanId) = ebsd.rotations(newId);

% interpolate grainId
try
  ebsd.prop.grainId(nanId) = ebsd.prop.grainId(newId);
end

grains = getClass(varargin,'grain2d',[]);
if isempty(grains), return; end

grains = grains(ismember(grains.id,unique(ebsd.grainId)));

nanId = find(nanId);

% check for whether the pixels are within certain grains
isInside = checkInside(grains,ebsd.subSet(nanId));

% set phase to not indexed if not inside any grain
ebsd.phaseId(nanId(~any(isInside,2))) = 1;
ebsd.grainId(nanId(~any(isInside,2))) = 0;

% the values to be filled
[ebsdId,hostId] = find(isInside);

wrongGrainId = ebsd.grainId(nanId(ebsdId)) ~= grains.id(hostId);

ebsd.phaseId(nanId(ebsdId)) = grains.phaseId(hostId);
ebsd.grainId(nanId(ebsdId)) = grains.id(hostId);
ebsd.rotations(nanId(ebsdId(wrongGrainId))) = grains.meanRotation(hostId(wrongGrainId));

end


%GETSTRUCTURINGELEMENT  Returns a structuring element of the specified size and shape for morphological operations
%
%     elem = cv.getStructuringElement('OptionName', optionValue, ...)
%
% ## Output
% * __elem__ Output structuring element of specified shape and size.
%
% ## Options
% * __Shape__ Element shape, default 'Rect'. Could be one of:
%   * __Rect__ a rectangular structuring element: `E(i,j)=1`
%   * __Cross__ a cross-shaped structuring element: `E(i,j)=1` if
%     `i=Anchor(2)` or `j=Anchor(1)`, `E(i,j)=0` otherwise.
%   * __Ellipse__ an elliptic structuring element, that is, a filled ellipse
%     inscribed into the rectangle `[0, 0, KSize(1), KSize(2)]`.
% * __KSize__ Size of the structuring element `[w,h]`. default [3,3].
% * __Anchor__ Anchor position within the element. The default value (-1,-1)
%   means that the anchor is at the center. Note that only the shape of a
%   cross-shaped element depends on the anchor position. In other cases the
%   anchor just regulates how much the result of the morphological operation
%   is shifted.
%
% The function constructs and returns the structuring element that can be
% further passed to cv.erode, cv.dilate or cv.morphologyEx. But you can also
% construct an arbitrary binary mask yourself and use it as the structuring
% element.
%
% See also: cv.sepFilter2D, cv.getDerivKernels, cv.getGaussianKernel
%


function [PSNR, yRGB_est] = CBM3D(yRGB, zRGB, sigma, profile, print_to_screen, colorspace)
%
%  CBM3D is algorithm for attenuation of additive white Gaussian noise from
%  color RGB images. This algorithm reproduces the results from the article:
%
%  [1] K. Dabov, A. Foi, V. Katkovnik, and K. Egiazarian, "Color image
%   denoising via sparse 3D collaborative filtering with grouping constraint in
%   luminance-chrominance space," submitted to IEEE Int. Conf. Image Process.,
%   January 2007, in review, preprint at http://www.cs.tut.fi/~foi/GCF-BM3D.
%
%  FUNCTION INTERFACE:
%
%  [PSNR, yRGB_est] = CBM3D(yRGB, zRGB, sigma, profile, print_to_screen, colorspace)
%
%  ! The function can work without any of the input arguments,
%   in which case, the internal default ones are used !
%
%  BASIC USAGE EXAMPLES:
%
%     Case 1) Using the default parameters (i.e., image name, sigma, etc.)
%
%      [PSNR, yRGB_est] = CBM3D;
%
%     Case 2) Using an external noisy image:
%
%      % Read an RGB image and scale its intensities in range [0,1]
%      yRGB = im2double(imread('image_House256rgb.png'));
%      % Generate the same seed used in the experimental results of [1]
%      randn('seed', 0);
%      % Standard deviation of the noise --- corresponding to intensity
%      %  range [0,255], despite that the input was scaled in [0,1]
%      sigma = 25;
%      % Add the AWGN with zero mean and standard deviation 'sigma'
%      zRGB = yRGB + (sigma/255)*randn(size(yRGB));
%      % Denoise 'zRGB'. The denoised image is 'yRGB_est', and 'NA = 1'
%      %  because the true image was not provided
%      [NA, yRGB_est] = CBM3D(1, zRGB, sigma);
%      % Compute the putput PSNR
%      PSNR = 10*log10(1/mean((yRGB(:)-yRGB_est(:)).^2))
%      % show the noisy image 'zRGB' and the denoised 'yRGB_est'
%      figure; imshow(min(max(zRGB,0),1));
%      figure; imshow(min(max(yRGB_est,0),1));
%
%     Case 3) If the original image yRGB is provided as the first input
%      argument, then some additional information is printed (PSNRs,
%      figures, etc.). That is, "[NA, yRGB_est] = BM3D(1, zRGB, sigma);" in the
%      above code should be replaced with:
%
%      [PSNR, yRGB_est] = CBM3D(yRGB, zRGB, sigma);
%
%
%  INPUT ARGUMENTS (OPTIONAL):
%     1) yRGB (M x N x 3): Noise-free RGB image (needed for computing PSNR),
%                           replace with the scalar 1 if not available.
%     2) zRGB (M x N x 3): Noisy RGBimage (intensities in range [0,1] or [0,255])
%     3) sigma (double)  : Std. dev. of the noise (corresponding to intensities
%                            in range [0,255] even if the range of zRGB is [0,1])
%     4) profile (char)  : 'np' --> Normal Profile
%                          'lc' --> Fast Profile
%     5) print_to_screen : 0 --> do not print output information (and do
%                                not plot figures)
%                          1 --> print information and plot figures
%     6) colorspace (char): 'opp'   --> use opponent colorspace
%                          'yCbCr' --> use yCbCr colorspace
%
%  OUTPUTS:
%     1) PSNR (double)          : Output PSNR (dB), only if the original
%                                 image is available, otherwise PSNR = 0
%     2) yRGB_est (M x N x 3): Final RGB estimate (in the range [0,1])
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Copyright (c) 2007-2011 Tampere University of Technology.
% All rights reserved.
% This work should only be used for nonprofit purposes.
%
% AUTHORS:
%     Kostadin Dabov, email: dabov _at_ cs.tut.fi
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% In case, there is no input image (zRGB or yRGB), then use the filename
%%%%  below to read an original image (might contain path also). Later,
%%%%  artificial AWGN noise is added and this noisy image is processed
%%%%  by the CBM3D.
%%%%
image_name = [
%    'kodim12.png'
   'image_Lena512rgb.png'
%     'image_House256rgb.png'
%    'image_Peppers512rgb.png'
%    'image_Baboon512rgb.png'
%    'image_F16_512rgb.png'
   ];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%  Quality/complexity trade-off
%%%%
%%%%  'np' --> Normal Profile (balanced quality)
%%%%  'lc' --> Low Complexity Profile (fast, lower quality)
%%%%
%%%%  'high' --> High Profile (high quality, not documented in [1])
%%%%
%%%%  'vn' --> This profile is automatically enabled for high noise
%%%%           when sigma > 40
%%%%
%%%%  'vn_old' --> This is the old 'vn' profile that was used in [1].
%%%%           It gives inferior results than 'vn' in most cases.
%%%%
if (exist('profile') ~= 1)
    profile         = 'np'; %% default profile
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%  Specify the std. dev. of the corrupting noise
%%%%
if (exist('sigma') ~= 1),
   sigma                = 50; %% default standard deviation of the AWGN
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%  Colorspace in which we perform denoising. BM is applied to the first
%%%%  component and the matching information is re-used for the other two.
%%%%
if (exist('colorspace') ~= 1),
    colorspace              = 'opp'; %%% (valid colorspaces are: 'yCbCr' and 'opp')
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Following are the parameters for the Normal Profile.
%%%%

%%%% Select transforms ('dct', 'dst', 'hadamard', or anything that is listed by 'help wfilters'):
transform_2D_HT_name     = 'bior1.5'; %% transform used for the HT filt. of size N1 x N1
transform_2D_Wiener_name = 'dct';     %% transform used for the Wiener filt. of size N1_wiener x N1_wiener
transform_3rd_dim_name   = 'haar';    %% transform used in the 3-rd dim, the same for HT and Wiener filt.

%%%% Hard-thresholding (HT) parameters:
N1                  = 8;   %% N1 x N1 is the block size used for the hard-thresholding (HT) filtering
Nstep               = 3;   %% sliding step to process every next reference block
N2                  = 16;  %% maximum number of similar blocks (maximum size of the 3rd dimension of a 3D array)
Ns                  = 39;  %% length of the side of the search neighborhood for full-search block-matching (BM), must be odd
tau_match           = 3000;%% threshold for the block-distance (d-distance)
lambda_thr2D        = 0;   %% threshold parameter for the coarse initial denoising used in the d-distance measure
lambda_thr3D        = 2.7; %% threshold parameter for the hard-thresholding in 3D transform domain
beta                = 2.0; %% parameter of the 2D Kaiser window used in the reconstruction

%%%% Wiener filtering parameters:
N1_wiener           = 8;
Nstep_wiener        = 3;
N2_wiener           = 32;
Ns_wiener           = 39;
tau_match_wiener    = 400;
beta_wiener         = 2.0;

%%%% Block-matching parameters:
stepFS              = 1;  %% step that forces to switch to full-search BM, "1" implies always full-search
smallLN             = 'not used in np'; %% if stepFS > 1, then this specifies the size of the small local search neighb.
stepFSW             = 1;
smallLNW            = 'not used in np';
thrToIncStep        = 8;  %% used in the HT filtering to increase the sliding step in uniform regions

if strcmp(profile, 'lc') == 1,

    Nstep               = 6;
    Ns                  = 25;
    Nstep_wiener        = 5;
    N2_wiener           = 16;
    Ns_wiener           = 25;

    thrToIncStep        = 3;
    smallLN             = 3;
    stepFS              = 6*Nstep;
    smallLNW            = 2;
    stepFSW             = 5*Nstep_wiener;

end

% Profile 'vn' was proposed in
%  Y. Hou, C. Zhao, D. Yang, and Y. Cheng, 'Comment on "Image Denoising by Sparse 3D Transform-Domain
%  Collaborative Filtering"', accepted for publication, IEEE Trans. on Image Processing, July, 2010.
% as a better alternative to that initially proposed in [1] (which is currently in profile 'vn_old')
if (strcmp(profile, 'vn') == 1) | (sigma > 40),

    N2                  = 32;
    Nstep               = 4;

    N1_wiener           = 11;
    Nstep_wiener        = 6;

    lambda_thr3D        = 2.8;
    thrToIncStep        = 3;
    tau_match_wiener    = 3500;
    tau_match           = 25000;

    Ns_wiener           = 39;

end

% The 'vn_old' profile corresponds to the original parameters for strong noise proposed in [1].
if (strcmp(profile, 'vn_old') == 1) & (sigma > 40),

    transform_2D_HT_name = 'dct';

    N1                  = 12;
    Nstep               = 4;

    N1_wiener           = 11;
    Nstep_wiener        = 6;

    lambda_thr3D        = 2.8;
    lambda_thr2D        = 2.0;
    thrToIncStep        = 3;
    tau_match_wiener    = 3500;
    tau_match           = 5000;

    Ns_wiener           = 39;

end

decLevel = 0;        %% dec. levels of the dyadic wavelet 2D transform for blocks (0 means full decomposition, higher values decrease the dec. number)
thr_mask = ones(N1); %% N1xN1 mask of threshold scaling coeff. --- by default there is no scaling, however the use of different thresholds for different wavelet decompoistion subbands can be done with this matrix

if strcmp(profile, 'high') == 1,

    decLevel     = 1;
    Nstep        = 2;
    Nstep_wiener = 2;
    lambda_thr3D = 2.5;
    vMask = ones(N1,1); vMask((end/4+1):end/2)= 1.01; vMask((end/2+1):end) = 1.07; %% this allows to have different threhsolds for the finest and next-to-the-finest subbands
    thr_mask = vMask * vMask';
    beta         = 2.5;
    beta_wiener  = 1.5;

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Note: touch below this point only if you know what you are doing!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%% Check whether to dump information to the screen or reamin silent
dump_output_information = 1;
if (exist('print_to_screen') == 1) & (print_to_screen == 0),
    dump_output_information = 0;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Create transform matrices, etc.
%%%%
[Tfor, Tinv]   = getTransfMatrix(N1, transform_2D_HT_name, decLevel);  %% get (normalized) forward and inverse transform matrices
[TforW, TinvW] = getTransfMatrix(N1_wiener, transform_2D_Wiener_name); %% get (normalized) forward and inverse transform matrices

if (strcmp(transform_3rd_dim_name, 'haar') == 1) | (strcmp(transform_3rd_dim_name(end-2:end), '1.1') == 1),
    %%% If Haar is used in the 3-rd dimension, then a fast internal transform is used, thus no need to generate transform
    %%% matrices.
    hadper_trans_single_den         = {};
    inverse_hadper_trans_single_den = {};
else
    %%% Create transform matrices. The transforms are later applied by
    %%% matrix-vector multiplication for the 1D case.
    for hpow = 0:ceil(log2(max(N2,N2_wiener))),
        h = 2^hpow;
        [Tfor3rd, Tinv3rd]   = getTransfMatrix(h, transform_3rd_dim_name, 0);
        hadper_trans_single_den{h}         = single(Tfor3rd);
        inverse_hadper_trans_single_den{h} = single(Tinv3rd');
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% 2D Kaiser windows used in the aggregation of block-wise estimates
%%%%
if beta_wiener==2 & beta==2 & N1_wiener==8 & N1==8 % hardcode the window function so that the signal processing toolbox is not needed by default
    Wwin2D = [ 0.1924    0.2989    0.3846    0.4325    0.4325    0.3846    0.2989    0.1924;
        0.2989    0.4642    0.5974    0.6717    0.6717    0.5974    0.4642    0.2989;
        0.3846    0.5974    0.7688    0.8644    0.8644    0.7688    0.5974    0.3846;
        0.4325    0.6717    0.8644    0.9718    0.9718    0.8644    0.6717    0.4325;
        0.4325    0.6717    0.8644    0.9718    0.9718    0.8644    0.6717    0.4325;
        0.3846    0.5974    0.7688    0.8644    0.8644    0.7688    0.5974    0.3846;
        0.2989    0.4642    0.5974    0.6717    0.6717    0.5974    0.4642    0.2989;
        0.1924    0.2989    0.3846    0.4325    0.4325    0.3846    0.2989    0.1924];
    Wwin2D_wiener = Wwin2D;
else
    Wwin2D           = kaiser(N1, beta) * kaiser(N1, beta)'; % Kaiser window used in the aggregation of the HT part
    Wwin2D_wiener    = kaiser(N1_wiener, beta_wiener) * kaiser(N1_wiener, beta_wiener)'; % Kaiser window used in the aggregation of the Wiener filt. part
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% If needed, read images, generate noise, or scale the images to the
%%%% [0,1] interval
%%%%
if (exist('yRGB') ~= 1) | (exist('zRGB') ~= 1)
    yRGB        = im2double(imread(image_name));  %% read a noise-free image
    randn('seed', 0);                          %% generate seed
    zRGB        = yRGB + (sigma/255)*randn(size(yRGB)); %% create a noisy image
else % external images
    image_name = 'External image';

    % convert zRGB to double precision
    zRGB = double(zRGB);

    % convert yRGB to double precision
    yRGB = double(yRGB);

    % if zRGB's range is [0, 255], then convert to [0, 1]
    if (max(zRGB(:)) > 10), % a naive check for intensity range
        zRGB = zRGB / 255;
    end

    % if yRGB's range is [0, 255], then convert to [0, 1]
    if (max(yRGB(:)) > 10), % a naive check for intensity range
        yRGB = yRGB / 255;
    end
end

if (size(zRGB,3) ~= 3) | (size(zRGB,4) ~= 1),
    error('CBM3D accepts only input RGB images (i.e. matrices of size M x N x 3).');
end

% Check if the true image yRGB is a valid one; if not, then we cannot compute PSNR, etc.
yRGB_is_invalid_image = (length(size(zRGB)) ~= length(size(yRGB))) | (size(zRGB,1) ~= size(yRGB,1)) | (size(zRGB,2) ~= size(yRGB,2)) | (size(zRGB,3) ~= size(yRGB,3));
if (yRGB_is_invalid_image),
    dump_output_information = 0;
end

[Xv, Xh, numSlices] = size(zRGB);              %%% obtain image sizes

if numSlices ~= 3
    fprintf('Error, an RGB color image is required!\n');
    return;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Change colorspace, compute the l2-norms of the new color channels
%%%%
[zColSpace l2normLumChrom] = function_rgb2LumChrom(zRGB, colorspace);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Print image information to the screen
%%%%
if dump_output_information == 1,
    fprintf(sprintf('Image: %s (%dx%dx%d), sigma: %.1f\n', image_name, Xv, Xh, numSlices, sigma));
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Step 1. Basic estimate by collaborative hard-thresholding and using
%%%% the grouping constraint on the chrominances.
%%%%
tic;
y_hat = bm3d_thr_color(zColSpace, hadper_trans_single_den, Nstep, N1, N2, lambda_thr2D,...
    lambda_thr3D, tau_match*N1*N1/(255*255), (Ns-1)/2, sigma/255, thrToIncStep, single(Tfor), single(Tinv)', inverse_hadper_trans_single_den, single(thr_mask), 'unused arg', 'unused arg', l2normLumChrom, Wwin2D, smallLN, stepFS );
estimate_elapsed_time = toc;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Step 2. Final estimate by collaborative Wiener filtering and using
%%%% the grouping constraint on the chrominances.
%%%%
tic;
yRGB_est = bm3d_wiener_color(zColSpace, y_hat, hadper_trans_single_den, Nstep_wiener, N1_wiener, N2_wiener, ...
    'unused_arg', tau_match_wiener*N1_wiener*N1_wiener/(255*255), (Ns_wiener-1)/2, sigma/255, 'unused arg', single(TforW), single(TinvW)', inverse_hadper_trans_single_den, 'unused arg', 'unused arg', l2normLumChrom, Wwin2D_wiener, smallLNW, stepFSW );
wiener_elapsed_time = toc;

yRGB_est = double(yRGB_est);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Convert back to RGB colorspace
%%%%
yRGB_est = function_LumChrom2rgb(yRGB_est, colorspace);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Calculate final estimate's PSNR and ISNR, print them, and show the
%%%% denoised image
%%%%
PSNR = 0; %% Remains 0 if the true image yRGB is not available
if (~yRGB_is_invalid_image), % then we assume yRGB is a valid image
    PSNR = 10*log10(1/mean((yRGB(:)-yRGB_est(:)).^2));
end

if dump_output_information == 1,
    fprintf(sprintf('FINAL ESTIMATE (total time: %.1f sec), PSNR: %.2f dB\n', ...
        wiener_elapsed_time + estimate_elapsed_time, PSNR));

    figure, imshow(min(max(zRGB,0),1)); title(sprintf('Noisy %s, PSNR: %.3f dB (sigma: %d)', ...
        image_name(1:end-4), 10*log10(1/mean((yRGB(:)-zRGB(:)).^2)), sigma));

    figure, imshow(min(max(yRGB_est,0),1)); title(sprintf('Denoised %s, PSNR: %.3f dB', ...
        image_name(1:end-4), PSNR));
end

return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Some auxiliary functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [Tforward, Tinverse] = getTransfMatrix (N, transform_type, dec_levels)
%
% Create forward and inverse transform matrices, which allow for perfect
% reconstruction. The forward transform matrix is normalized so that the
% l2-norm of each basis element is 1.
%
% [Tforward, Tinverse] = getTransfMatrix (N, transform_type, dec_levels)
%
%  INPUTS:
%
%   N               --> Size of the transform (for wavelets, must be 2^K)
%
%   transform_type  --> 'dct', 'dst', 'hadamard', or anything that is
%                       listed by 'help wfilters' (bi-orthogonal wavelets)
%                       'DCrand' -- an orthonormal transform with a DC and all
%                       the other basis elements of random nature
%
%   dec_levels      --> If a wavelet transform is generated, this is the
%                       desired decomposition level. Must be in the
%                       range [0, log2(N)-1], where "0" implies
%                       full decomposition.
%
%  OUTPUTS:
%
%   Tforward        --> (N x N) Forward transform matrix
%
%   Tinverse        --> (N x N) Inverse transform matrix
%

if exist('dec_levels') ~= 1,
    dec_levels = 0;
end

if N == 1,
    Tforward = 1;
elseif strcmp(transform_type, 'hadamard') == 1,
    Tforward    = hadamard(N);
elseif (N == 8) & strcmp(transform_type, 'bior1.5')==1 % hardcoded transform so that the wavelet toolbox is not needed to generate it
    Tforward =  [ 0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274;
       0.219417649252501   0.449283757993216   0.449283757993216   0.219417649252501  -0.219417649252501  -0.449283757993216  -0.449283757993216  -0.219417649252501;
       0.569359398342846   0.402347308162278  -0.402347308162278  -0.569359398342846  -0.083506045090284   0.083506045090284  -0.083506045090284   0.083506045090284;
      -0.083506045090284   0.083506045090284  -0.083506045090284   0.083506045090284   0.569359398342846   0.402347308162278  -0.402347308162278  -0.569359398342846;
       0.707106781186547  -0.707106781186547                   0                   0                   0                   0                   0                   0;
                       0                   0   0.707106781186547  -0.707106781186547                   0                   0                   0                   0;
                       0                   0                   0                   0   0.707106781186547  -0.707106781186547                   0                   0;
                       0                   0                   0                   0                   0                   0   0.707106781186547  -0.707106781186547];
elseif (N == 8) & strcmp(transform_type, 'dct')==1 % hardcoded transform so that the signal processing toolbox is not needed to generate it
    Tforward = [ 0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274;
       0.490392640201615   0.415734806151273   0.277785116509801   0.097545161008064  -0.097545161008064  -0.277785116509801  -0.415734806151273  -0.490392640201615;
       0.461939766255643   0.191341716182545  -0.191341716182545  -0.461939766255643  -0.461939766255643  -0.191341716182545   0.191341716182545   0.461939766255643;
       0.415734806151273  -0.097545161008064  -0.490392640201615  -0.277785116509801   0.277785116509801   0.490392640201615   0.097545161008064  -0.415734806151273;
       0.353553390593274  -0.353553390593274  -0.353553390593274   0.353553390593274   0.353553390593274  -0.353553390593274  -0.353553390593274   0.353553390593274;
       0.277785116509801  -0.490392640201615   0.097545161008064   0.415734806151273  -0.415734806151273  -0.097545161008064   0.490392640201615  -0.277785116509801;
       0.191341716182545  -0.461939766255643   0.461939766255643  -0.191341716182545  -0.191341716182545   0.461939766255643  -0.461939766255643   0.191341716182545;
       0.097545161008064  -0.277785116509801   0.415734806151273  -0.490392640201615   0.490392640201615  -0.415734806151273   0.277785116509801  -0.097545161008064];
elseif (N == 8) & strcmp(transform_type, 'dst')==1 % hardcoded transform so that the PDE toolbox is not needed to generate it
    Tforward = [ 0.161229841765317   0.303012985114696   0.408248290463863   0.464242826880013   0.464242826880013   0.408248290463863   0.303012985114696   0.161229841765317;
       0.303012985114696   0.464242826880013   0.408248290463863   0.161229841765317  -0.161229841765317  -0.408248290463863  -0.464242826880013  -0.303012985114696;
       0.408248290463863   0.408248290463863                   0  -0.408248290463863  -0.408248290463863                   0   0.408248290463863   0.408248290463863;
       0.464242826880013   0.161229841765317  -0.408248290463863  -0.303012985114696   0.303012985114696   0.408248290463863  -0.161229841765317  -0.464242826880013;
       0.464242826880013  -0.161229841765317  -0.408248290463863   0.303012985114696   0.303012985114696  -0.408248290463863  -0.161229841765317   0.464242826880013;
       0.408248290463863  -0.408248290463863                   0   0.408248290463863  -0.408248290463863                   0   0.408248290463863  -0.408248290463863;
       0.303012985114696  -0.464242826880013   0.408248290463863  -0.161229841765317  -0.161229841765317   0.408248290463863  -0.464242826880013   0.303012985114696;
       0.161229841765317  -0.303012985114696   0.408248290463863  -0.464242826880013   0.464242826880013  -0.408248290463863   0.303012985114696  -0.161229841765317];
elseif strcmp(transform_type, 'dct') == 1,
    Tforward    = dct(eye(N));
elseif strcmp(transform_type, 'dst') == 1,
    Tforward    = dst(eye(N));
elseif strcmp(transform_type, 'DCrand') == 1,
    x = randn(N); x(1:end,1) = 1; [Q,R] = qr(x);
    if (Q(1) < 0),
        Q = -Q;
    end;
    Tforward = Q';
else %% a wavelet decomposition supported by 'wavedec'
    %%% Set periodic boundary conditions, to preserve bi-orthogonality
    dwtmode('per','nodisp');

    Tforward = zeros(N,N);
    for i = 1:N
        Tforward(:,i)=wavedec(circshift([1 zeros(1,N-1)],[dec_levels i-1]), log2(N), transform_type);  %% construct transform matrix
    end
end

%%% Normalize the basis elements
Tforward = (Tforward' * diag(sqrt(1./sum(Tforward.^2,2))))';

%%% Compute the inverse transform matrix
Tinverse = inv(Tforward);

return;

function [y, A, l2normLumChrom]=function_rgb2LumChrom(xRGB, colormode)
% Forward color-space transformation   ( inverse transformation is function_LumChrom2rgb.m )
%
% Alessandro Foi - Tampere University of Technology - 2005 - 2006   Public release v1.03 (March 2006)
% -----------------------------------------------------------------------------------------------------------------------------------------------
%
% SYNTAX:
%
%   [y A l2normLumChrom] = function_rgb2LumChrom(xRGB, colormode);
%
% INPUTS:
%   xRGB  is RGB image with range [0 1]^3
%
%   colormode = 'opp', 'yCbCr', 'pca', or a custom 3x3 matrix
%
%       'opp'     Opponent color space ('opp' is equirange version)
%       'yCbCr'   The standard yCbCr (e.g. for JPEG images)
%       'pca'     Principal components   (note that this transformation is renormalized to be equirange)
%
% OUTPUTS:
%   y  is color-transformed image (with range typically included in or equal to [0 1]^3, depending on the transformation matrix)
%
%   l2normLumChrom (optional) l2-norm of the transformation (useful for noise std calculation)
%   A  transformation matrix  (used necessarily if colormode='pca')
%
%   NOTES:  -  If only two outputs are used, then the second output is l2normLumChrom, unless colormode='pca';
%           -  'opp' is used by default if no colormode is specified.
%
%
% USAGE EXAMPLE FOR PCA TRANSFORMATION:
%  %%%%  -- forward color transformation --
%    if colormode=='pca'
%       [zLumChrom colormode] = function_rgb2LumChrom(zRGB,colormode); % 'colormode' is assigned a 3x3 transform matrix
%    else
%       zLumChrom = function_rgb2LumChrom(zRGB,colormode);
%    end
%
%  %%%% [ ... ]  Some processing  [ ... ]
%
%  %%%%  -- inverse color transformation --
%    zRGB=function_LumChrom2rgb(zLumChrom,colormode);
%

if nargin==1
    colormode='opp';
end
change_output=0;
if size(colormode)==[3 3]
    A=colormode;
    l2normLumChrom=sqrt(sum(A.^2,2));
else
    if strcmp(colormode,'opp')
        A=[1/3 1/3 1/3; 0.5  0  -0.5; 0.25  -0.5  0.25];
    end
    if strcmp(colormode,'yCbCr')
        A=[0.299   0.587   0.114;   -0.16873660714285  -0.33126339285715   0.5;   0.5  -0.4186875  -0.0813125];
    end
    if strcmp(colormode,'pca')
        A=princomp(reshape(xRGB,[size(xRGB,1)*size(xRGB,2) 3]))';
        A=A./repmat(sum(A.*(A>0),2)-sum(A.*(A<0),2),[1 3]);  %% ranges are normalized to unitary length;
    else
        if nargout==2
            change_output=1;
        end
    end
end

%%%% Make sure that each channel's intensity range is [0,1]
maxV = sum(A.*(A>0),2);
minV = sum(A.*(A<0),2);
yNormal = (reshape(xRGB,[size(xRGB,1)*size(xRGB,2) 3]) * A' - repmat(minV, [1 size(xRGB,1)*size(xRGB,2)])') * diag(1./(maxV-minV)); % put in range [0,1]
y = reshape(yNormal, [size(xRGB,1) size(xRGB,2) 3]);

%%%% The l2-norm of each of the 3 transform basis elements
l2normLumChrom = diag(1./(maxV-minV))*sqrt(sum(A.^2,2));

if change_output
    A=l2normLumChrom;
end

return;

function yRGB=function_LumChrom2rgb(x,colormode)
% Inverse color-space transformation   ( forward transformation is function_rgb2LumChrom.m )
%
% Alessandro Foi - Tampere University of Technology - 2005 - 2006   Public release v1.03 (March 2006)
% -----------------------------------------------------------------------------------------------------------------------------------------------
%
% SYNTAX:
%
%   yRGB = function_LumChrom2rgb(x,colormode);
%
% INPUTS:
%  x  is color-transformed image (with range typically included in or equal to [0 1]^3, depending on the transformation matrix)
%
%  colormode = 'opp', 'yCbCr', or a custom 3x3 matrix (e.g. provided by the forward transform when 'pca' is selected)
%
%       'opp'      opponent color space ('opp' is equirange version)
%       'yCbCr'    standard yCbCr (e.g. for JPEG images)
%
% OUTPUTS:
%   x  is RGB image (with range [0 1]^3)
%
%
% NOTE:    'opp' is used by default if no colormode is specified
%

if nargin==1
    colormode='opp';
end
if size(colormode)==[3 3]
    A=colormode;
    B=inv(A);
else
    if strcmp(colormode,'opp')
        A =[1/3 1/3 1/3; 0.5  0  -0.5; 0.25  -0.5  0.25];
        B =[1 1 2/3;1 0 -4/3;1 -1 2/3];
    end
    if strcmp(colormode,'yCbCr')
        A=[0.299   0.587   0.114;   -0.16873660714285  -0.33126339285715   0.5;   0.5  -0.4186875  -0.0813125];
        B=inv(A);
    end
end

%%%% Make sure that each channel's intensity range is [0,1]
maxV = sum(A.*(A>0),2);
minV = sum(A.*(A<0),2);
xNormal = reshape(x,[size(x,1)*size(x,2) 3]) * diag(maxV-minV) +  repmat(minV, [1 size(x,1)*size(x,2)])'; % put in range [0,1]
yRGB = reshape(xNormal * B', [ size(x,1) size(x,2) 3]);

return;


% SELECT.M          (universal SELECTion)
%
% This function performs universal selection. The function handles
% multiple populations and calls the low level selection function
% for the actual selection process.

%
% Syntax:  SelCh = select(SEL_F, Chrom, FitnV, GGAP, SUBPOP)
%
% Input parameters:
%    SEL_F     - Name of the selection function
%    Chrom     - Matrix containing the individuals (parents) of the current
%                population. Each row corresponds to one individual.
%    FitnV     - Column vector containing the fitness values of the
%                individuals in the population.
%    GGAP      - (optional) Rate of individuals to be selected
%                if omitted 1.0 is assumed
%    SUBPOP    - (optional) Number of subpopulations
%                if omitted 1 subpopulation is assumed
%
% Output parameters:
%    SelCh     - Matrix containing the selected individuals.

% Author:     Hartmut Pohlheim
% History:    10.03.94     file created

function SelCh = select(SEL_F, Chrom, FitnV, GGAP, SUBPOP);

% Check parameter consistency
   if nargin < 3, error('Not enough input parameter'); end

   % Identify the population size (Nind)
   [NindCh,Nvar] = size(Chrom);
   [NindF,VarF] = size(FitnV);
   if NindCh ~= NindF, error('Chrom and FitnV disagree'); end
   if VarF ~= 1, error('FitnV must be a column vector'); end

   if nargin < 5, SUBPOP = 1; end
   if nargin > 4,
      if isempty(SUBPOP), SUBPOP = 1;
      elseif isnan(SUBPOP), SUBPOP = 1;
      elseif length(SUBPOP) ~= 1, error('SUBPOP must be a scalar'); end
   end

   if (NindCh/SUBPOP) ~= fix(NindCh/SUBPOP), error('Chrom and SUBPOP disagree'); end
   Nind = NindCh/SUBPOP;  % Compute number of individuals per subpopulation

   if nargin < 4, GGAP = 1; end
   if nargin > 3,
      if isempty(GGAP), GGAP = 1;
      elseif isnan(GGAP), GGAP = 1;
      elseif length(GGAP) ~= 1, error('GGAP must be a scalar');
      elseif (GGAP < 0), error('GGAP must be a scalar bigger than 0'); end
   end

% Compute number of new individuals (to select)
   NSel=max(floor(Nind*GGAP+.5),2);

% Select individuals from population
   SelCh = [];
   for irun = 1:SUBPOP,
      FitnVSub = FitnV((irun-1)*Nind+1:irun*Nind);
      ChrIx=feval(SEL_F, FitnVSub, NSel)+(irun-1)*Nind;
      SelCh=[SelCh; Chrom(ChrIx,:)];
   end

% End of function


function b = rhs(disc, f)
%RHS   Discretize the right-hand side of a linear system for ULTRAS.
%   B = RHS(DISC, F) returns a discrete version, B,  of the function (or
%   chebmatrix) F, as defined by the discretization DISC.
%
% See also MATRIX, REDUCE.

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

% Developers note: This method works as follows.
%   The original function(s) are discretized, then reduced in dimension the same
%   way as the operator. The constraints are prepended to the top of the vector.

% Create an ULTRAS object from the CHEBMATRIX F:
fDisc = ultraS(f, disc.dimension, disc.domain);
fDisc.outputSpace = disc.outputSpace;

% Instantiate (discretize) the ULTRAS discretisation.
b = cell2mat(instantiate(fDisc));

% Developer note:
%   The continuity conditions go above the constraints. See getConstraints().

% Prepend the values of the constraints and continuity conditions.
L = disc.source;
if ( ~isempty(L.constraint) )
    b = [ L.constraint.values ; b ];
end
if ( ~isempty(L.continuity) )
    b = [ L.continuity.values ; b ];
end

end


function [dStates, contactForces] = dynamics_singleStanceOne(States, Actuators, Parameters)
% function [dStates, Actuators] = dynamics_singleStanceOne(States, Actuators, Parameters)
%
% Computer Generated File -- DO NOT EDIT
%
% This function was created by the function Write_ContinuousDynamics()
% 10-Dec-2013 19:40:47
%
% Dymanics Model: retractable double pendulum biped
% Motion Phase: Single Stance One
%
% Matthew Kelly
% Cornell University
%

x = States(1,:); % (m) Foot One horizontal position
y = States(2,:); % (m) Foot One vertical position
th1 = States(3,:); % (rad) Leg One absolute angle
th2 = States(4,:); % (rad) Leg Two absolute angle
L1 = States(5,:); % (m) Leg One length
L2 = States(6,:); % (m) Leg Two length
dx = States(7,:); % (m/s) Foot One horizontal velocity
dy = States(8,:); % (m/s) Foot One vertical velocity
dth1 = States(9,:); % (rad/s) Leg One absolute angular rate
dth2 = States(10,:); % (rad/s) Leg Two absolute angular rate
dL1 = States(11,:); % (m/s) Leg One extension rate
dL2 = States(12,:); % (m/s) Leg Two extensioin rate

F1 = Actuators(1,:); % (N) Compresive axial force in Leg One
F2 = Actuators(2,:); % (N) Compresive axial force in Leg Two
T1 = Actuators(3,:); % (Nm) External torque applied to Leg One
T2 = 0; %Foot Two not in contact with ground!
Thip = Actuators(5,:); % (Nm) Torque acting on Leg Two from Leg One

m1 = Parameters.m1; % (kg) Foot One mass
m2 = Parameters.m2; % (kg) Foot Two mass
M = Parameters.M; % (kg) Hip mass
g = Parameters.g; % (m/s^2) Gravity

% Constraints for this phase:
ddx = 0; %(m) Foot One horizontal position
ddy = 0; %(m) Foot One vertical position
H2 = 0; %(N) Foot Two, horizontal contact force
V2 = 0; %(N) Foot Two, vertical contact force

dStates = zeros(size(States));
dStates(1:6,:) = States((1+6):(6+6),:);
dStates(7,:) = zeros(1,size(States,2));
dStates(8,:) = zeros(1,size(States,2));
dStates(9,:) = -(L2.*Thip - L2.*T1 + L1.*T2.*cos(th1 - th2) + L1.*Thip.*cos(th1 - th2) - F2.*L1.*L2.*sin(th1 - th2) + 2.*L1.*L2.*M.*dL1.*dth1 + L1.*L2.*M.*ddy.*cos(th1) + L1.*L2.*M.*g.*cos(th1) - L1.*L2.*M.*ddx.*sin(th1))./(L1.^2.*L2.*M);
dStates(10,:) = (L1.*M.*T2 + L1.*M.*Thip - L2.*T1.*m2.*cos(th1 - th2) + L2.*Thip.*m2.*cos(th1 - th2) + L1.*T2.*m2.*cos(th1 - th2).^2 + L1.*Thip.*m2.*cos(th1 - th2).^2 + L1.*T2.*m2.*sin(th1 - th2).^2 + L1.*Thip.*m2.*sin(th1 - th2).^2 + L1.*L2.*M.*V2.*cos(th2) - H2.*L1.*L2.*M.*sin(th2) - F1.*L1.*L2.*m2.*sin(th1 - th2) - 2.*L1.*L2.*M.*dL2.*dth2.*m2 - L1.*L2.*M.*ddy.*m2.*cos(th2) - L1.*L2.*M.*g.*m2.*cos(th2) + L1.*L2.*M.*ddx.*m2.*sin(th2) - L1.*L2.*M.*ddx.*m2.*cos(th1 - th2).*sin(th1) + L1.*L2.*M.*ddx.*m2.*sin(th1 - th2).*cos(th1) + L1.*L2.*M.*ddy.*m2.*sin(th1 - th2).*sin(th1) + L1.*L2.*M.*g.*m2.*sin(th1 - th2).*sin(th1) + L1.*L2.*M.*ddy.*m2.*cos(th1 - th2).*cos(th1) + L1.*L2.*M.*g.*m2.*cos(th1 - th2).*cos(th1))./(L1.*L2.^2.*M.*m2);
dStates(11,:) = -(T2.*sin(th1 - th2) + Thip.*sin(th1 - th2) - F1.*L2 + F2.*L2.*cos(th1 - th2) - L1.*L2.*M.*dth1.^2 + L2.*M.*ddx.*cos(th1) + L2.*M.*ddy.*sin(th1) + L2.*M.*g.*sin(th1))./(L2.*M);
dStates(12,:) = (T1.*m2.*sin(th1 - th2) - Thip.*m2.*sin(th1 - th2) + F2.*L1.*M + H2.*L1.*M.*cos(th2) + L1.*M.*V2.*sin(th2) - F1.*L1.*m2.*cos(th1 - th2) + F2.*L1.*m2.*cos(th1 - th2).^2 + F2.*L1.*m2.*sin(th1 - th2).^2 + L1.*L2.*M.*dth2.^2.*m2 - L1.*M.*ddx.*m2.*cos(th2) - L1.*M.*ddy.*m2.*sin(th2) - L1.*M.*g.*m2.*sin(th2) + L1.*M.*ddx.*m2.*cos(th1 - th2).*cos(th1) + L1.*M.*ddy.*m2.*cos(th1 - th2).*sin(th1) - L1.*M.*ddy.*m2.*sin(th1 - th2).*cos(th1) + L1.*M.*g.*m2.*cos(th1 - th2).*sin(th1) - L1.*M.*g.*m2.*sin(th1 - th2).*cos(th1) + L1.*M.*ddx.*m2.*sin(th1 - th2).*sin(th1))./(L1.*M.*m2);

% contactForces(1,:) == H1 == (N) Foot One, horizontal contact force
% contactForces(2,:) == V1 == (N) Foot One, vertical contact force
% contactForces(3,:) == H2 == (N) Foot Two, horizontal contact force
% contactForces(4,:) == V2 == (N) Foot Two, vertical contact force
contactForces = zeros(4,size(States,2));
contactForces(1,:) = (Thip.*sin(th1) - T1.*sin(th1) + L1.*ddx.*m1 + F1.*L1.*cos(th1))./L1;
contactForces(2,:) = (T1.*cos(th1) - Thip.*cos(th1) + L1.*ddy.*m1 + L1.*g.*m1 + F1.*L1.*sin(th1))./L1;
contactForces(3,:) = zeros(1,size(States,2));
contactForces(4,:) = zeros(1,size(States,2));

end


function test_suite=test_moxunit_fieldtrip_util_parse_walltime
% #   For MOxUnit_fieldtrip's copyright information and license terms,   #
% #   see the COPYING file distributed with MOxUnit_fieldtrip.           #

    try % assignment of 'localfunctions' is necessary in Matlab >= 2016
        test_functions=localfunctions();
    catch % no problem; early Matlab versions can use initTestSuite fine
    end
    initTestSuite;

function varargout=randint(mx)
    n=nargout;
    varargout=arrayfun(@(unused)ceil(rand()*mx),1:n,'UniformOutput',false);

function assert_output(input, expected_output)
    output=moxunit_fieldtrip_util_parse_walltime(input);
    assertEqual(output,expected_output);

function test_fieldtrip_util_parse_walltime
    % seconds
    many_ss=randint(1000);
    assert_output(sprintf('%d',many_ss),...
                                many_ss);

    % hours, minutes, seconds
    [hh,mm,ss]=randint(60);
    assert_output(sprintf('%02d:%02d:%02d',hh,mm,ss),...
                                (hh*60+mm)*60+ss);

    % not a number
    [hh,mm,ss]=randint(60);
    assert_output('foo',[]);

    % should deal with comments after
    assert_output('  3 % comment',3);

function test_fieldtrip_util_parse_walltime_exceptions
    aet=@(varargin)assertExceptionThrown(@()...
            moxunit_fieldtrip_util_parse_walltime(varargin{:}),'');
    % inputs that are not string throw an exception
    aet(struct)
    aet([1 2])
    aet(1);


function plotIPDF(ori,varargin)
% plot orientations into inverse pole figures
%
% Syntax
%   plotIPDF(ori,[r1,r2,r3])
%   plotIPDF(ori,[r1,r2,r3],'points',100)
%   plotIPDF(ori,[r1,r2,r3],'points','all')
%   plotIPDF(ori,[r1,r2,r3],'contourf')
%   plotIPDF(ori,[r1,r2,r3],'antipodal')
%   plotIPDF(ori,data,[r1,r2,r3])
%
% Input
%  ebsd - @EBSD
%  r   - @vector3d specimen directions
%
% Options
%  RESOLUTION - resolution of the plots
%  property   - user defined colorcoding
%  MarkerSize -
%  MarkerFaceColor -
%  MarkerEdgeColor -
%
% Flags
%  antipodal - include <VectorsAxes.html antipodal symmetry>
%  complete  - ignore fundamental region
%  upper     - restrict to upper hemisphere
%  lower     - restrict to lower hemisphere
%  filled    - fill the marker with current color
%
% See also
% S2Grid/plot savefigure Plotting Annotations_demo ColorCoding_demo PlotTypes_demo
% SphericalProjection_demo

[mtexFig,isNew] = newMtexFigure('datacursormode',@tooltip,varargin{:});

% maybe we should call this function with the option add2all
if ~isNew && ~check_option(varargin,'parent') && ...
    ((((ishold(mtexFig.gca) && nargin > 1 && isa(varargin{1},'vector3d') && length(varargin{1})>1))) || check_option(varargin,'add2all'))
  plot(ori,varargin{:},'add2all');
  return
end

% extract data
if check_option(varargin,'property')
  data = get_option(varargin,'property');
  data = reshape(data,[1,length(ori) numel(data)/length(ori)]);
elseif nargin > 1 && ~isa(varargin{1},'vector3d')
  [data,varargin] = extract_data(length(ori),varargin);
  data = reshape(data,[1,length(ori) numel(data)/length(ori)]);
else
  data = [];
end

% find inverse pole figure direction
r = [];
try r = getappdata(mtexFig.currentAxes,'inversePoleFigureDirection'); end
if isempty(r), r = varargin{1}; end
argin_check(r,'vector3d');

%  subsample if needed
if (length(ori)*numSym(ori.CS)*numSym(ori.SS) > 100000 || check_option(varargin,'points')) ...
    && ~check_option(varargin,{'all','contourf','smooth','contour','pcolor'})

  points = fix(get_option(varargin,'points',100000/numSym(ori.CS)/numSym(ori.SS)));
  disp(['  I''m plotting ', int2str(points) ,' random orientations out of ', int2str(length(ori)),' given orientations']);

  samples = discretesample(length(ori),points);
  ori = ori.subSet(samples);
  if ~isempty(data), data = data(:,samples,:); end

end

for ir = 1:length(r)

  if ir>1, mtexFig.nextAxis; end

  % the crystal directions
  rSym = symmetrise(r(ir),ori.SS);
  h = ori(:) \ rSym;

  %  plot
  [~,cax] = h.plot(repmat(data,1,length(rSym)),'symmetrised',...
    'fundamentalRegion','doNotDraw',varargin{:});
  if isNew, mtexTitle(cax(1),char(r(ir),'LaTeX')); end

  % plot annotations
  setappdata(cax,'inversePoleFigureDirection',r(ir));
  set(cax,'tag','ipdf');
  setappdata(cax,'CS',ori.CS);
  setappdata(cax,'SS',ori.SS);

  % TODO: unifyMarkerSize

end

if isNew || check_option(varargin,'figSize')
  mtexFig.drawNow('figSize',getMTEXpref('figSize'),varargin{:});
end

% --------------- Tooltip function ------------------
function txt = tooltip(varargin)

  [r_local,id,value] = getDataCursorPos(mtexFig,length(ori));

  %id = (id-1)/

  h_local = round(Miller(r_local,ori.CS));

  txt{1} = ['id = ' xnum2str(id)];
  txt{2} = ['(h,k,l) = ' char(h_local,'tolerance',3*degree,'commasep')];
  txt{3} = ['Euler = ' char(ori.subSet(id))];
  if ~isempty(value)
    txt{4} = ['value = ' xnum2str(value)];
  end

end

end


function H = cconvmtx2(h)

[block_size, num_blocks] = size(h);
num_elem = block_size*num_blocks;

H1 = spalloc(num_elem, block_size, block_size*nnz(h));
H = spalloc(num_elem, num_elem, num_elem*nnz(h));

% create the first n columns
for col = 1:block_size
    H1(:,col) = reshape(circshift(h, [col-1 0]), num_elem, 1);
end

% construct all blocks in H
for block = 1:num_blocks
    H(:,block_size*(block-1)+1:block_size*block) = circshift(H1, [(block-1)*block_size 0]);
end
end


function [ax, data] = scatterPlot(X, YLbls, markerSize, ax);

% SCATTERPLOT 2-D scatter plot of labelled points.
% FORMAT
% DESC plots a 2-D scatter plot of labelled points.
% ARG X : x points to plot.
% ARG lbls : the labels to plot.
% ARG markerSize : the size of the markers to use.
% ARG ax : the axes to plot on (default create new axes).
% RETURN ax : the axis handle of the plot.
% RETURN data : the handles of the data points.
%
% SEEALSO : plot, getSymbols
%
% COPYRIGHT : Neil D. Lawrence, 2005, 2010

% NDLUTIL

  if nargin < 4
    ax = [];
  end
  if isempty(YLbls)
    symbol = [];
  else
    symbol = getSymbols(size(YLbls,2));
  end

  % Create the plot for the data
  clf
  if isempty(ax)
    ax = axes('position', [0.05 0.05 0.9 0.9]);
  else
    ax = axes(ax);
  end
  hold on

  data = twoDPlot(X, YLbls, symbol);
  for i = 1:2
    minX = min(X(:, i));
    maxX = max(X(:, i));
    xSpan = maxX - minX;
    xLim{i}(1) = minX - 0.1*xSpan;
    xLim{i}(2) = maxX + 0.1*xSpan;
  end
  if nargin>2
    for i = 1:length(data)
      set(data(i), 'markersize', markerSize);
    end
  end
  set(ax, 'xLim', xLim{1});
  set(ax, 'yLim', xLim{2});

  set(ax, 'fontname', 'arial');
  set(ax, 'fontsize', 20);
end

function returnVal = twoDPlot(X, label, symbol)

% GPLVMTWODPLOT Helper function for plotting the labels in 2-D.

  returnVal = [];

  if ~isempty(label)
    for i = 1:size(X, 1)
      labelNo = find(label(i, :));
      try
        returnVal = [returnVal; plot(X(i, 1), X(i, 2), symbol{labelNo})];
      catch
        if strcmp(lasterr, 'Index exceeds matrix dimensions.')
          error(['Only ' num2str(length(symbol)) ' labels supported (it''s easy to add more!)'])
        end
      end
    end
  else
    returnVal = plot(X(:, 1), X(:, 2), 'rx');
  end
end


function PlotPolarityAroundATimeByDensity(aedat, time, numTimePoints, numDensities, minProportionOfPixels, maxProportionOfPixels, contrast, transposeVar, flipVertical, flipHorizontal)

%{
Takes 'aedat' - a data structure containing an imported .aedat file,
as created by ImportAedat, and creates a series of green/red plots of
polarity data.
Plots in Y have different densities (i.e. proportions of pixels). These
densities are distributed exponentially between the min and max parameters
Plots in X have different centre times. The numTimePoints param must be
odd, and the centre plot in X is the one centred at the parameter 'time'.

For numPlots > 1, the proportionOfPixels used to include events around that
time point is varied logarithmically from minProp.. to maxProp.
Defaults are 0.1 and 1.
flipVertical is assumed true, so that y=0 is considered the top of the image.
%}

%% Parameters

if ~exist('time', 'var')
	time = (aedat.info.firstTimeStamp + aedat.info.lastTimeStamp) / 2;
else
    time = time * 1e6;
end

if ~exist('numDensities', 'var')
	numDensities = 3;
end

if ~exist('numTimePoints', 'var')
	numTimePoints = 3;
end
if mod(numTimePoints,2) == 0
	numTimePoints = numTimePoints + 1;
end

if ~exist('distributeBy', 'var')
	distributeBy = 'time';
end

if ~exist('minProportionOfPixels', 'var') ...
        || (exist('minProportionOIfPixels', 'var') ...
            && minProportionOfPixels == 0)
    minProportionOfPixels = 0.001;
end
if ~exist('maxProportionOfPixels', 'var') ...
        || (exist('maxProportionOIfPixels', 'var') ...
            && maxProportionOfPixels == 0)
    maxProportionOfPixels = 0.1;
end

% The 'contrast' for display of events, as used in jAER.
if ~exist('contrast', 'var')
    contrast = 3;
end

%% Unpack

% break out the timeStamps for readability
timeStamp   = aedat.data.polarity.timeStamp;
x           = aedat.data.polarity.x;
y           = aedat.data.polarity.y;
polarity    = aedat.data.polarity.polarity;
numEvents   = aedat.data.polarity.numEvents;

%% Produce plots

% Find eventIndex nearest to timePoint
eventIndex = find(timeStamp >= time, 1, 'first');
if isempty(eventIndex)
    eventIndex = numEvents;
end

numPlots = numDensities * numTimePoints;

if numDensities > 1
    % distribute the
    logMin = log(minProportionOfPixels);
    logMax = log(maxProportionOfPixels);
    logStep = (logMax - logMin) / (numPlots - 1);
    proportionsOfPixels = exp(logMin : logStep : logMax);
    numPixelsInArray = aedat.info.deviceAddressSpace(1) * aedat.info.deviceAddressSpace(2);
    numPixelsToSelectEachWay = ceil(numPixelsInArray * proportionsOfPixels / 2);

    figure
else
    numPixelsToSelectEachWay = minProportionOfPixels; % Arbitrrary choice to use the minimum
end
for densityIndex = 1 : numDensities
    % First do the central timePoint
    firstIndex = max(1, eventIndex - numPixelsToSelectEachWay(plotIndex));
    lastIndex = min(numEvents, eventIndex + numPixelsToSelectEachWay(plotIndex));
    selectedLogical = [false(firstIndex - 1, 1); ...
					true(lastIndex - firstIndex + 1, 1); ...
					false(numEvents - lastIndex, 1)];
    eventsForFrame = struct;
    eventsForFrame.x        = x(selectedLogical);
    eventsForFrame.y        = y(selectedLogical);
    eventsForFrame.polarity = polarity(selectedLogical);
    frame = FrameFromEvents(eventsForFrame, contrast, aedat.info.deviceAddressSpace);
	if exist('transpose', 'var') && transposeVar
        frame = frame';
    end
    image(frame - 1);
    colormap(redgreencmap(contrast * 2 + 1))
	axis equal tight
	if ~exist('flipVertical', 'var') || flipVertical
		set(gca, 'YDir', 'reverse')
    end
    if exist('flipHorizontal', 'var') && flipHorizontal
		set(gca, 'XDir', 'reverse')
    end
	title(['Proportion of pixels: ' num2str(proportionsOfPixels(plotIndex))])

    % Then work outwards from the central time point
    lastIndexUp = lastIndex;
    firstIndexDown = firstIndex;
    for timePointsIndex = (numTimePoints - 1) / 2;
        subplot(numPlotsY, numPlotsX, plotIndex);
        hold all

        firstIndex = max(1, eventIndex - numPixelsToSelectEachWay(plotIndex));
        lastIndex = min(numEvents, eventIndex + numPixelsToSelectEachWay(plotIndex));
        selectedLogical = [false(firstIndex - 1, 1); ...
                        true(lastIndex - firstIndex + 1, 1); ...
                        false(numEvents - lastIndex, 1)];
        eventsForFrame = struct;
        eventsForFrame.x        = x(selectedLogical);
        eventsForFrame.y        = y(selectedLogical);
        eventsForFrame.polarity = polarity(selectedLogical);
        frame = FrameFromEvents(eventsForFrame, contrast, aedat.info.deviceAddressSpace);
        if exist('transpose', 'var') && transposeVar
            frame = frame';
        end
        image(frame - 1);
        colormap(redgreencmap(contrast * 2 + 1))
        axis equal tight
        if ~exist('flipVertical', 'var') || flipVertical
            set(gca, 'YDir', 'reverse')
        end
        if exist('flipHorizontal', 'var') && flipHorizontal
            set(gca, 'XDir', 'reverse')
        end
        title(['Proportion of pixels: ' num2str(proportionsOfPixels(plotIndex))])
    end
end


function [fig_name_tca]=ps_mean_v(ifg_list,n_boot,subtract_switches,use_small_baselines,aps_flag)
%PS_MEAN_V Calculate mean velocities and their standard deviations
%   PS_MEAN_V(IFG_LIST,N_BOOT,SUBTRACT_SWITCHES) where IFG_LIST gives indices
%   of interferograms to be included in the calculation,N_BOOT specifies number
%   of bootstrap iterations and RAMP_FLAG is 1 to subtract orbital ramps
%
%   Andy Hooper, Jan 2008
%
%   ======================================================================
%   06/2009 AH: Subtract orbital ramp if present
%   06/2009 AH: Process smaller chunks to reduce memory needs
%   02/2010 AH: Revert to v3.1 version
%   02/2010 AH: Replace unwrap_ifg_index with drop_ifg_index
%   03/2010 AH: 3rd input changed to 'subtract_switches'
%   03/2010 AH: Use small baselines option added
%   03/2010 AH: var/cov added to inversion
%   05/2010 AH: Include master if there are not ifgs before and after
%   06/2010 AH: small change to ps_mean_v.m
%   03/2014 AH: -a etc added
%   04/2014 DB: fix fig_name_tca output in case no aps correction
%   05/2014 DB: Fix v-doa to v-dao
%   05/2014 DB: For APS related corrections include deramping on the fly
%   05/2014 DB: big fix in case of a nan
%   07/2014 EH: Fix for nanmean in case of single element compared to vector
%   03/2015 DB: Do all deramping on the fly, make consistent for TRAIN release
%   05/2017 DB: use stamps save to save larger variables than 2GB.
%   06/2017 DB: Include the option to choose between chol decompostion for
%               bootstrapping (not to invert covariance often), or conventional
%               bootstrapping requiring to invert covariance matrix for each iteration.
%   ======================================================================

fprintf('Calculating standard deviation of mean velocity...\n')

chol_flag = 'n';

if nargin<1
    ifg_list=[];
end
if nargin<2
    n_boot=100;
end

if nargin<3 | isempty(subtract_switches)
   subtract_switches='';
end

if nargin<4
    use_small_baselines=0;
end

if nargin<5
    aps_flag=1;
end

load psver
psname=['./ps',num2str(psver)];
phuwname=['./phuw',num2str(psver)];
phuwsbresname=['./phuw_sb_res',num2str(psver)];
ifgstdname=['./ifgstd',num2str(psver)];
sclaname=['./scla',num2str(psver)];
apsname=['./tca',num2str(psver)];
tidename=['./tide',num2str(psver)];

mvname=['mv',num2str(psver)];

ps=load(psname);

drop_ifg_index=getparm('drop_ifg_index');
fig_name_tca = '';
if strcmpi(getparm('small_baseline_flag'),'y')
    if use_small_baselines==0
        phuw=load(phuwname,'unwrap_ifg_index_sm');
        if isfield(phuw,'unwrap_ifg_index_sm');
            unwrap_ifg_index=phuw.unwrap_ifg_index_sm;
        else
            unwrap_ifg_index=[1:ps.n_image];
        end
        phuwres=load(phuwsbresname,'sm_cov');
        if isfield(phuwres,'sm_cov');
            ifg_cov=phuwres.sm_cov;
        else
            ifg_cov=eye(ps.n_image);
        end
    else
        unwrap_ifg_index=setdiff([1:ps.n_ifg],drop_ifg_index);
        phuwname=['./phuw_sb',num2str(psver)];
        sclaname=['./scla_sb',num2str(psver)];
        apsname=['./tca_sb',num2str(psver)];
        tidename=['./tide_sb',num2str(psver)];

        phuwres=load(phuwsbresname,'sb_cov');
        if isfield(phuwres,'sb_cov');
            ifg_cov=phuwres.sb_cov;
        else
            ifg_cov=eye(ps.n_ifg);
        end
    end
else
    use_small_baselines=0;
    unwrap_ifg_index=setdiff([1:ps.n_ifg],drop_ifg_index);
    if ~exist([ifgstdname,'.mat'],'file')
        ifg_cov=eye(ps.n_ifg);
    else ifgstd=load(ifgstdname);
      if isfield(ifgstd,'ifg_std');
        ifgvar=(ifgstd.ifg_std*pi/181).^2;
        ifg_cov=diag(ifgvar);
      else
        ifg_cov=eye(ps.n_ifg);
      end
    end
end

uw=load(phuwname);
ph_uw=uw.ph_uw;
clear uw

switch(subtract_switches)
case('')
case('d')
    scla=load(sclaname);
    ph_uw=ph_uw - scla.ph_scla;
    clear scla
case('o')
    [ph_uw] = ps_deramp(ps,ph_uw);
case('a')
    aps=load(apsname);
    [aps_corr,fig_name_tca] = ps_plot_tca(aps,aps_flag);
    ph_uw=ph_uw - aps_corr;
    clear aps aps_corr
case('ao')
    aps=load(apsname);
    [aps_corr,fig_name_tca] = ps_plot_tca(aps,aps_flag);
    ph_uw=ph_uw - aps_corr;
    [ph_uw] = ps_deramp(ps,ph_uw);
    clear aps aps_corr
case('do')
    scla=load(sclaname);
    ph_uw=ph_uw - scla.ph_scla;
    [ph_uw] = ps_deramp(ps,ph_uw);
case('da')
    scla=load(sclaname);
    ph_uw=ph_uw - scla.ph_scla;
    clear scla
    aps=load(apsname);
    [aps_corr,fig_name_tca] = ps_plot_tca(aps,aps_flag);
    ph_uw=ph_uw - aps_corr;
    clear aps aps_corr
case('dat')
    tide=load(tidename);
    scla=load(sclaname);
    ph_uw=ph_uw - scla.ph_scla;
    clear scla
    aps=load(apsname);
    [aps_corr,fig_name_tca] = ps_plot_tca(aps,aps_flag);
    ph_uw=ph_uw - aps_corr-tide.ph_tide;
    clear aps aps_corr
case('dao')
    scla=load(sclaname);
    ph_uw=ph_uw - scla.ph_scla ;
    [ph_uw] = ps_deramp(ps,ph_uw);
    aps=load(apsname);
    [aps_corr,fig_name_tca] = ps_plot_tca(aps,aps_flag);
    ph_uw=ph_uw - aps_corr;
    clear aps aps_corr
otherwise
        error('unknown subtract flags')
end

if use_small_baselines==0
    %AH2CHECK %%%%%%% & unwrap_ifg_index(1)~=ps.master_ix & unwrap_ifg_index(end)~=ps.master_ix
    unwrap_ifg_index=setdiff(unwrap_ifg_index,ps.master_ix);
end

ph_all=zeros(ps.n_ps,1);
ref_ps=ps_setref;
if ~isempty(ifg_list)
    unwrap_ifg_index=intersect(unwrap_ifg_index,ifg_list);
    ifg_list=[];
end
ph_uw=ph_uw(:,unwrap_ifg_index);
ifg_cov=ifg_cov(unwrap_ifg_index,unwrap_ifg_index);
if rank(ifg_cov)<size(ifg_cov,1)
    error('Interferograms included for which there is no unwrapped solution')
end

if use_small_baselines==0
    day=ps.day(unwrap_ifg_index)-ps.master_day;
else
    day=ps.day(ps.ifgday_ix(unwrap_ifg_index,2))-ps.day(ps.ifgday_ix(unwrap_ifg_index,1));
end
N=length(day);
ph_uw=ph_uw-repmat(nanmean(ph_uw(ref_ps,:),1),ps.n_ps,1);
lambda=getparm('lambda');
ph_uw=double(ph_uw/4/pi*lambda*1000)';
G=[ones(N,1),double(day)/365.25] ;

% computing mean velocity
mean_v=lscov(G,ph_uw,ifg_cov)';
mean_v=mean_v(:,2);

% perform the bootstrapping
n=10000; % process n PS at a time
i=1;
mean_v_std=NaN(ps.n_ps,1,'single');
rand_init=sum(100*clock);
n_ifg = size(ph_uw,1);

if strcmpi(chol_flag,'y')
    % cholesky decomposition of the set of linear equations including
    % covariance. This allows to use the decomposition values in a uniform
    % LSQ inversion. i.e. the covariance matrix does not need to be
    % inverted each time.
    ph_uw=chol(inv(ifg_cov))*ph_uw;
    G=chol(inv(ifg_cov))*G;

    % looping over the PS segments
    while i<ps.n_ps
        if i+n< ps.n_ps
           i_end=i+n-1;
        else
           i_end=ps.n_ps;
        end
        ph_bit=ph_uw(:,i:i_end);

        % in-case of nans and only a subset being processed
        ix_non_nan = sum(isnan(ph_bit),1)==0;

        % fix the random generator, such its the same for each segment
        rand('twister',rand_init);

        % skip the segment in case of nan's
        if sum(ix_non_nan)>0
            if sum(ix_non_nan)== length(ix_non_nan)
                [mean_v_dist,boot_ix] = bootstrp(n_boot, @(x) single(lscov(G(x,:),ph_bit(x,:))), [1:N]);
                 temp = std(mean_v_dist(:,2:2:end))';
            else
                [mean_v_dist_temp,boot_ix] = bootstrp(n_boot, @(x) single(lscov(G(x,:),ph_bit(x,ix_non_nan))), [1:N]);
                temp = NaN([size(ph_bit,2) 1]);
                temp(ix_non_nan) = std(mean_v_dist_temp(:,2:2:end))';
                clear mean_v_dist_temp
            end
            mean_v_std(i:i_end) =temp;
        end
        i=i+n;
        fprintf('%d PS processed\n',i-1)
    end

else
    % conventional bootstrapping where the coveriance matrix is inverted on
    % each set PS segments.
    while i<ps.n_ps
        if i+n< ps.n_ps
           i_end=i+n-1;
        else
           i_end=ps.n_ps;
        end
        ph_bit=ph_uw(:,i:i_end);

        % in-case of nans and only a subset being processed
        ix_non_nan = sum(isnan(ph_bit),1)==0;

        % fix the random generator, such its the same for each segment
        rand('twister',rand_init)

        % skip the segment in case of nan's
        if sum(ix_non_nan)>0
            if sum(ix_non_nan)== length(ix_non_nan)
                [mean_v_dist,boot_ix] = bootstrp(n_boot, @(x) single(lscov(G(x,:),ph_bit(x,:),ifg_cov)), [1:N]);
                temp = std(mean_v_dist(:,2:2:end))';
            else
               fprintf('test\n')
               [mean_v_dist_temp,boot_ix] = bootstrp(n_boot, @(x) single(lscov(G(x,:),ph_bit(x,ix_non_nan),ifg_cov(ix_non_nan,ix_non_nan))), [1:N]);
               temp = NaN([size(ph_bit,2) 1]);
               temp(ix_non_nan) = std(mean_v_dist_temp(:,2:2:end))';
               clear mean_v_dist_temp
            end
            mean_v_std(i:i_end) =temp;
        end
        i=i+n;
        fprintf('%d PS processed\n',i-1)
    end
end

stamps_save(mvname,n_boot,subtract_switches,mean_v,mean_v_std)


classdef math_model_opf_acps < mp.math_model_opf_acp
%MP.MATH_MODEL_OPF_ACPS  MATPOWER mathematical model for AC optimal power flow (OPF) problem.
%   ?
%
%   MP.MATH_MODEL_OPF_ACPS ... power flow ...
%
%   Properties
%       ? - ?
%
%   Methods
%       ?

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

%     properties
%     end

    methods
        function tag = form_tag(obj)
            tag = 'acps';
        end

        function name = form_name(obj)
            name = 'AC-polar-power';
        end

        function add_node_balance_constraints(obj, nm, dm, mpopt)
            %% power balance constraints
            nn = nm.node.N;             %% number of nodes
            fcn_mis = @(x)obj.nodal_power_balance_fcn(x, nm);
            hess_mis = @(x, lam)obj.nodal_power_balance_hess(x, lam, nm);
            obj.add_nln_constraint({'Pmis', 'Qmis'}, [nn;nn], 1, fcn_mis, hess_mis);
        end

        function [lam_p, lam_q] = node_power_balance_prices(obj, nm)
            %% shadow prices on node power balance
            nne = obj.get_idx('nle');
            lambda = obj.soln.lambda;
            lam_p = lambda.eqnonlin(nne.i1.Pmis:nne.iN.Pmis);
            lam_q = lambda.eqnonlin(nne.i1.Qmis:nne.iN.Qmis);
        end
    end     %% methods
end         %% classdef


function y=multimidfilter(x,m)
a=x;
for k=1 : m
    b=medfilt1(a, 5);
    a=b;
end
y=b;


function rez = learnAndSolve8b_old(rez)
% This is the main optimization. Takes the longest time and uses the GPU heavily.

ops = rez.ops;
ops.fig = getOr(ops, 'fig', 1); % whether to show plots every N batches

NrankPC = 6; % this one is the rank of the PCs, used to detect spikes with threshold crossings
Nrank = 3; % this one is the rank of the templates
rng('default'); rng(1);

% we need PC waveforms, as well as template waveforms
[wTEMP, wPCA]    = extractTemplatesfromSnippets(rez, NrankPC);

% move these to the GPU
wPCA = gpuArray(wPCA(:, 1:Nrank));
wTEMP = gpuArray(wTEMP);
wPCAd = double(wPCA); % convert to double for extra precision
ops.wPCA = gather(wPCA);
ops.wTEMP = gather(wTEMP);
nt0 = ops.nt0;
nt0min  = rez.ops.nt0min;
rez.ops = ops;
nBatches  = rez.temp.Nbatch;
NT  	= ops.NT;
Nfilt 	= ops.Nfilt;
Nchan 	= ops.Nchan;

% two variables for the same thing? number of nearest channels to each primary channel
NchanNear   = min(ops.Nchan, 32);
Nnearest    = min(ops.Nchan, 32);

% decay of gaussian spatial mask centered on a channel
sigmaMask  = ops.sigmaMask;

% spike threshold for finding missed spikes in residuals
ops.spkTh = -6; % why am I overwriting this here?

batchstart = 0:NT:NT*nBatches;

% find the closest NchanNear channels, and the masks for those channels
[iC, mask, C2C] = getClosestChannels(rez, sigmaMask, NchanNear);

% sorting order for the batches
isortbatches = rez.iorig(:);
nhalf = ceil(nBatches/2); % halfway point

% this batch order schedule goes through half of the data forward and backward during the model fitting
% and then goes through the data symmetrically-out from the center during the final pass
ischedule = [nhalf:nBatches nBatches:-1:nhalf];
i1 = [(nhalf-1):-1:1];
i2 = [nhalf:nBatches];

irounds = cat(2, ischedule, i1, i2);

niter   = numel(irounds);
if irounds(niter - nBatches)~=nhalf
    error('mismatch between number of batches'); % this check is in here in case I do somehting weird when I try different schedules
end

% these two flags are used to keep track of what stage of model fitting we're at
flag_final    =  0;
flag_resort   = 1;

% this is the absolute temporal offset in seconds corresponding to the start of the
% spike sorted time segment
t0 = ceil(rez.ops.trange(1) * ops.fs);

nInnerIter  = 60; % this is for SVD for the power iteration

% schedule of learning rates for the model fitting part
% starts small and goes high, it corresponds approximately to the number of spikes
% from the past that were averaged to give rise to the current template
pmi = exp(-1./linspace(ops.momentum(1), ops.momentum(2), niter-nBatches));

Nsum = min(Nchan,7); % how many channels to extend out the waveform in mexgetspikes
% lots of parameters passed into the CUDA scripts
Params     = double([NT Nfilt ops.Th(1) nInnerIter nt0 Nnearest ...
    Nrank ops.lam pmi(1) Nchan NchanNear ops.nt0min 1 Nsum NrankPC ops.Th(1)]);

% W0 has to be ordered like this
W0 = permute(double(wPCA), [1 3 2]);

% initialize the list of channels each template lives on
iList = int32(gpuArray(zeros(Nnearest, Nfilt)));

% initialize average number of spikes per batch for each template
nsp = gpuArray.zeros(0,1, 'double');

% this flag starts 0, is set to 1 later
Params(13) = 0;

% kernels for subsample alignment
[Ka, Kb] = getKernels(ops, 10, 1);

p1 = .95; % decay of nsp estimate in each batch

fprintf('Time %3.0fs. Optimizing templates ...\n', toc)

fid = fopen(ops.fproc, 'r');

ntot = 0;
ndrop = zeros(1,2); % this keeps track of dropped templates for debugging purposes

m0 = ops.minFR * ops.NT/ops.fs; % this is the minimum firing rate that all templates must maintain, or be dropped

for ibatch = 1:niter
    korder = irounds(ibatch); % korder is the index of the batch at this point in the schedule
    k = isortbatches(korder); % k is the index of the batch in absolute terms

    if ibatch>niter-nBatches && korder==nhalf
        % this is required to revert back to the template states in the middle of the batches
        [W, dWU] = revertW(rez);
        fprintf('reverted back to middle timepoint \n')
    end

    if ibatch<=niter-nBatches
        % obtained pm for this batch
        Params(9) = pmi(ibatch);
        pm = pmi(ibatch) * gpuArray.ones(Nfilt, 1, 'double');
    end

    % loading a single batch (same as everywhere)
    offset = 2 * ops.Nchan*batchstart(k);
    fseek(fid, offset, 'bof');
    dat = fread(fid, [NT ops.Nchan], '*int16');
    dataRAW = single(gpuArray(dat))/ ops.scaleproc;

    if ibatch==1
       % only on the first batch, we first get a new set of spikes from the residuals,
       % which in this case is the unmodified data because we start with no templates
        [dWU, cmap] = mexGetSpikes2(Params, dataRAW, wTEMP, iC-1); % CUDA function to get spatiotemporal clips from spike detections
        dWU = double(dWU);
        dWU = reshape(wPCAd * (wPCAd' * dWU(:,:)), size(dWU)); % project these into the wPCA waveforms

        W = W0(:,ones(1,size(dWU,3)),:); % initialize the low-rank decomposition with standard waves
        Nfilt = size(W,2); % update the number of filters/templates
        nsp(1:Nfilt) = m0; % initialize the number of spikes for new templates with the minimum allowed value, so it doesn't get thrown back out right away
        Params(2) = Nfilt; % update in the CUDA parameters
    end

    if flag_resort
        % this is a flag to resort the order of the templates according to best peak channel
        % this is important in order to have cohesive memory requests from the GPU RAM
        [~, iW] = max(abs(dWU(nt0min, :, :)), [], 2); % max channel (either positive or negative peak)
        iW = int32(squeeze(iW));

        [iW, isort] = sort(iW); % sort by max abs channel
        W = W(:,isort, :); % user ordering to resort all the other template variables
        dWU = dWU(:,:,isort);
        nsp = nsp(isort);
    end

    % decompose dWU by svd of time and space (via covariance matrix of 61 by 61 samples)
    % this uses a "warm start" by remembering the W from the previous iteration
    [W, U, mu] = mexSVDsmall2(Params, dWU, W, iC-1, iW-1, Ka, Kb);

    % UtU is the gram matrix of the spatial components of the low-rank SVDs
    % it tells us which pairs of templates are likely to "interfere" with each other
    % such as when we subtract off a template
    [UtU, maskU] = getMeUtU(iW, iC, mask, Nnearest, Nchan); % this needs to change (but I don't know why!)

    % main CUDA function in the whole codebase. does the iterative template matching
    % based on the current templates, gets features for these templates if requested (featW, featPC),
    % gets scores for the template fits to each spike (vexp), outputs the average of
    % waveforms assigned to each cluster (dWU0),
    % and probably a few more things I forget about
    [st0, id0, x0, featW, dWU0, drez, nsp0, featPC, vexp] = ...
        mexMPnu8(Params, dataRAW, single(U), single(W), single(mu), iC-1, iW-1, UtU, iList-1, ...
        wPCA);

    % Sometimes nsp can get transposed (think this has to do with it being
    % a single element in one iteration, to which elements are added
    % nsp, nsp0, and pm must all be row vectors (Nfilt x 1), so force nsp
    % to be a row vector.
    [nsprow, nspcol] = size(nsp);
    if nsprow<nspcol
        nsp = nsp';
    end

    % updates the templates as a running average weighted by recency
    % since some clusters have different number of spikes, we need to apply the
    % exp(pm) factor several times, and fexp is the resulting update factor
    % for each template
    fexp = exp(double(nsp0).*log(pm(1:Nfilt)));
    fexp = reshape(fexp, 1,1,[]);
    dWU = dWU .* fexp + (1-fexp) .* (dWU0./reshape(max(1, double(nsp0)), 1,1, []));

    % nsp just gets updated according to the fixed factor p1
    nsp = nsp * p1 + (1-p1) * double(nsp0);

    % \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

    if ibatch==niter-nBatches
        % if we reached this point, we need to disable secondary template updates
        % like dropping, and adding new templates. We need to memorize the state of the
        % templates at this timepoint, and set the processing mode to "extraction and tracking"

        flag_resort   = 0; % no need to resort templates by channel any more
        flag_final = 1; % this is the "final" pass

        % final clean up, triage templates one last time
        [W, U, dWU, mu, nsp, ndrop] = ...
            triageTemplates2(ops, iW, C2C, W, U, dWU, mu, nsp, ndrop);

        % final number of templates
        Nfilt = size(W,2);
        Params(2) = Nfilt;

        % final covariance matrix between all templates
        [WtW, iList] = getMeWtW(single(W), single(U), Nnearest);

        % iW is the final channel assigned to each template
        [~, iW] = max(abs(dWU(nt0min, :, :)), [], 2);
        iW = int32(squeeze(iW));

        % extract ALL features on the last pass
        Params(13) = 2; % this is a flag to output features (PC and template features)

        % different threshold on last pass?
        Params(3) = ops.Th(end); % usually the threshold is much lower on the last pass

        rez = memorizeW(rez, W, dWU, U, mu); % memorize the state of the templates
        fprintf('memorized middle timepoint \n')
    end

    if ibatch<niter-nBatches %-50
        % during the main "learning" phase of fitting a model
        if rem(ibatch, 5)==1
            % this drops templates based on spike rates and/or similarities to other templates
            [W, U, dWU, mu, nsp, ndrop] = ...
                triageTemplates2(ops, iW, C2C, W, U, dWU, mu, nsp, ndrop);
        end
        Nfilt = size(W,2); % update the number of filters
        Params(2) = Nfilt;

        % this adds new templates if they are detected in the residual
        [dWU0,cmap] = mexGetSpikes2(Params, drez, wTEMP, iC-1);

        if size(dWU0,3)>0
            % new templates need to be integrated into the same format as all templates
            dWU0 = double(dWU0);
            dWU0 = reshape(wPCAd * (wPCAd' * dWU0(:,:)), size(dWU0)); % apply PCA for smoothing purposes
            dWU = cat(3, dWU, dWU0);

            W(:,Nfilt + [1:size(dWU0,3)],:) = W0(:,ones(1,size(dWU0,3)),:); % initialize temporal components of waveforms

            nsp(Nfilt + [1:size(dWU0,3)]) = ops.minFR * NT/ops.fs; % initialize the number of spikes with the minimum allowed
            mu(Nfilt + [1:size(dWU0,3)])  = 10; % initialize the amplitude of this spike with a lowish number

            Nfilt = min(ops.Nfilt, size(W,2)); % if the number of filters exceed the maximum allowed, clip it
            Params(2) = Nfilt;

            W   = W(:, 1:Nfilt, :); % remove any new filters over the maximum allowed
            dWU = dWU(:, :, 1:Nfilt); % remove any new filters over the maximum allowed
            nsp = nsp(1:Nfilt); % remove any new filters over the maximum allowed
            mu  = mu(1:Nfilt); % remove any new filters over the maximum allowed
        end

    end

    if ibatch>niter-nBatches
        % during the final extraction pass, this keesp track of all spikes and features

        % we memorize the spatio-temporal decomposition of the waveforms at this batch
        % this is currently only used in the GUI to provide an accurate reconstruction
        % of the raw data at this time
        rez.WA(:,:,:,k) = gather(W);
        rez.UA(:,:,:,k) = gather(U);
        rez.muA(:,k) = gather(mu);

        % we carefully assign the correct absolute times to spikes found in this batch
        ioffset         = ops.ntbuff;
        if k==1
            ioffset         = 0; % the first batch is special (no pre-buffer)
        end
        toff = nt0min + t0 -ioffset + (NT-ops.ntbuff)*(k-1);
        st = toff + double(st0);

        irange = ntot + [1:numel(x0)]; % spikes and features go into these indices

        if ntot+numel(x0)>size(st3,1)
          % if we exceed the original allocated memory, double the allocated sizes
           fW(:, 2*size(st3,1))    = 0;
           fWpc(:,:,2*size(st3,1)) = 0;
           st3(2*size(st3,1), 1)   = 0;
        end

        st3(irange,1) = double(st); % spike times
        st3(irange,2) = double(id0+1); % spike clusters (1-indexing)
        st3(irange,3) = double(x0); % template amplitudes
        st3(irange,4) = double(vexp); % residual variance of this spike
        st3(irange,5) = korder; % batch from which this spike was found

        fW(:, irange) = gather(featW); % template features for this batch
        fWpc(:, :, irange) = gather(featPC); % PC features

        ntot = ntot + numel(x0); % keeps track of total number of spikes so far
    end

    if ibatch==niter-nBatches
        % allocate variables when switching to extraction phase
        st3 = zeros(1e7, 5); % this holds spike times, clusters and other info per spike

        % these next three store the low-d template decompositions
        rez.WA = zeros(nt0, Nfilt, Nrank,nBatches,  'single');
        rez.UA = zeros(Nchan, Nfilt, Nrank,nBatches,  'single');
        rez.muA = zeros(Nfilt, nBatches,  'single');

        % these ones store features per spike
        fW  = zeros(Nnearest, 1e7, 'single'); % Nnearest is the number of nearest templates to store features for
        fWpc = zeros(NchanNear, Nrank, 1e7, 'single'); % NchanNear is the number of nearest channels to take PC features from
    end

    if (rem(ibatch, 100)==1)
        % this is some of the relevant diagnostic information to be printed during training
        fprintf('%2.2f sec, %d / %d batches, %d units, nspks: %2.4f, mu: %2.4f, nst0: %d, merges: %2.4f, %2.4f \n', ...
            toc, ibatch, niter, Nfilt, sum(nsp), median(mu), numel(st0), ndrop)

        % these diagnostic figures should be mostly self-explanatory
        if ibatch==1
            figHand = figure;
        else
            figure(figHand);
        end

       if ops.fig
           make_fig(W, U, mu, nsp)
        end
    end
end
fclose(fid);
toc

% discards the unused portion of the arrays
st3 = st3(1:ntot, :);
fW = fW(:, 1:ntot);
fWpc = fWpc(:,:, 1:ntot);

% just display the total number of spikes
ntot

rez.st3 = st3;
rez.st2 = st3; % keep also an st2 copy, because st3 will be over-written by one of the post-processing steps

% the similarity score between templates is simply the correlation,
% taken as the max over several consecutive time delays
rez.simScore = gather(max(WtW, [], 3));

% the template features are stored in cProj, like in Kilosort1
rez.cProj    = fW';
% the neihboring templates idnices are stored in iNeigh
rez.iNeigh   = gather(iList);

rez.ops = ops; % update these (only rez comes out of this script)
rez.nsp = nsp;

%  permute the PC projections in the right order
rez.cProjPC     = permute(fWpc, [3 2 1]); %zeros(size(st3,1), 3, nNeighPC, 'single');
% iNeighPC keeps the indices of the channels corresponding to the PC features
rez.iNeighPC    = gather(iC(:, iW));

% this whole next block is just done to compress the compressed templates
% we separately svd the time components of each template, and the spatial components
% this also requires a careful decompression function, available somewhere in the GUI code
nKeep = min(Nchan*3,20); % how many PCs to keep
rez.W_a = zeros(nt0 * Nrank, nKeep, Nfilt, 'single');
rez.W_b = zeros(nBatches, nKeep, Nfilt, 'single');
rez.U_a = zeros(Nchan* Nrank, nKeep, Nfilt, 'single');
rez.U_b = zeros(nBatches, nKeep, Nfilt, 'single');
for j = 1:Nfilt
    % do this for every template separately
    WA = reshape(rez.WA(:, j, :, :), [], nBatches);
    WA = gpuArray(WA); % svd on the GPU was faster for this, but the Python randomized CPU version might be faster still
    [A, B, C] = svdecon(WA);
    % W_a times W_b results in a reconstruction of the time components
    rez.W_a(:,:,j) = gather(A(:, 1:nKeep) * B(1:nKeep, 1:nKeep));
    rez.W_b(:,:,j) = gather(C(:, 1:nKeep));

    UA = reshape(rez.UA(:, j, :, :), [], nBatches);
    UA = gpuArray(UA);
    [A, B, C] = svdecon(UA);
    % U_a times U_b results in a reconstruction of the time components
    rez.U_a(:,:,j) = gather(A(:, 1:nKeep) * B(1:nKeep, 1:nKeep));
    rez.U_b(:,:,j) = gather(C(:, 1:nKeep));
end

fprintf('Finished compressing time-varying templates \n')
%%


function ObjVal = FoxHoles(x,mydata)

[A,B] = size(x);
Top=double(0);
Top1=double(0);
C=[-32,-16,0,16,32,-32,-16,0,16,32,-32,-16,0,16,32,-32,-16,0,16,32,-32,-16,0,16,32;
    -32,-32,-32,-32,-32,-16,-16,-16,-16,-16,0,0,0,0,0,16,16,16,16,16,32,32,32,32,32];

for i=1:A
    for k=1:25
        for j=1:B
          Top1=Top1+power((double(x(i,j))-double(C(j,k))),6);
        end;
        Top=double(Top+(1/(Top1+k)));
        Top1=0;
     end;
ObjVal(i)= double(1/(0.002+Top));
Top=0;
end
ObjVal=ObjVal';

function y=power(x,a)
y=double(x^a);
  return


%-----------------------------------------------------------------------
% Job saved on 01-Apr-2016 11:17:08 by cfg_util (rev $Rev: 6134 $)
% spm SPM - SPM12 (6225)
% cfg_basicio BasicIO - Unknown
%-----------------------------------------------------------------------
matlabbatch{2}.spm.stats.fmri_est.spmmat = cfg_dep('fMRI model specification: SPM.mat File', substruct('.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1}), substruct('.','spmmat'));
matlabbatch{2}.spm.stats.fmri_est.write_residuals = 0;
matlabbatch{2}.spm.stats.fmri_est.method.Bayesian.space.volume.block_type = 'Slices';
matlabbatch{2}.spm.stats.fmri_est.method.Bayesian.signal = 'Uninformative';
matlabbatch{2}.spm.stats.fmri_est.method.Bayesian.ARP = 3;
matlabbatch{2}.spm.stats.fmri_est.method.Bayesian.noise.UGL = 1;
matlabbatch{2}.spm.stats.fmri_est.method.Bayesian.LogEv = 'Yes';
matlabbatch{2}.spm.stats.fmri_est.method.Bayesian.anova.first = 'No';
matlabbatch{2}.spm.stats.fmri_est.method.Bayesian.anova.second = 'Yes';
matlabbatch{2}.spm.stats.fmri_est.method.Bayesian.gcon(1).name = 'main positive';
matlabbatch{2}.spm.stats.fmri_est.method.Bayesian.gcon(1).convec = 1;
matlabbatch{2}.spm.stats.fmri_est.method.Bayesian.gcon(2).name = 'main negative';
matlabbatch{2}.spm.stats.fmri_est.method.Bayesian.gcon(2).convec = -1;


clc;
close all;
clearvars;

rng default;

A = mat_selector();

k  = 30;
spx_bdpro(A, k);


classdef SubMesher < handle

    properties (Access = public)
       subMesh
       localMesh
    end

    properties (Access = private)
        mesh
        lastNode
    end

    methods (Access = public)

        function obj = SubMesher(cParams)
            obj.init(cParams);
            obj.computeLocalMesh();
            obj.computeSubMesh();
        end

    end

    methods (Access = private)

        function init(obj,cParams)
            obj.mesh        = cParams.mesh;
            obj.lastNode    = cParams.lastNode;
        end

        function computeLocalMesh(obj)
            s.connec = [1 2 5;
                2 3 5;
                3 4 5;
                1 5 4];
            s.coord =  obj.computeCoordLocal();
            obj.localMesh = Mesh(s);
        end

        function xIsoCoord = computeCoordLocal(obj)
            xIsoQuad = obj.computeXisoQuad();
            xIsoCent = [0 0];
            xIsoCoord = [xIsoQuad;xIsoCent];
        end

        function computeSubMesh(obj)
            s.connec = obj.computeSubMeshConnec();
            s.coord  = obj.computeSubMeshCoord();
            obj.subMesh = Mesh(s);
        end

        function x = computeXisoQuad(obj)
            int = Interpolation.create(obj.mesh,'LINEAR');
            x = int.pos_nodes;
        end

        function newConnec = computeSubMeshConnec(obj)
            connecE = obj.computeExtendedConnectivities();
            nnodeN   = size(obj.localMesh.connec,2);
            nsubCells = size(obj.localMesh.connec,1);
            nelemB = obj.mesh.nelem;
            nelemN = nsubCells*nelemB;
            newConnec = zeros(nelemN,nnodeN);
            for isubcell = 1:nsubCells
                element = obj.computeGlobalElements(isubcell,nsubCells,nelemN);
                for inode = 1:nnodeN
                    node = obj.localMesh.connec(isubcell,inode);
                    newConnec(element,inode) = connecE(:,node);
                end
            end
        end

        function connecE = computeExtendedConnectivities(obj)
            oldConnec = obj.mesh.connec;
            nnode     = obj.mesh.nnodeElem;
            nnodeE    = nnode + 1;
            newNodes = obj.computeNewNodes();
            connecE(:,1:nnodeE) = [oldConnec newNodes];
        end

        function nNodes = computeNewNodes(obj)
            nelemOld = obj.mesh.nelem;
            nNodes(:,1) = (obj.lastNode+1):(obj.lastNode + nelemOld);
        end

        function newCoord = computeSubMeshCoord(obj)
            xC = obj.mesh.computeBaricenter();
            newCoord = [obj.mesh.coord; xC' ];
        end

    end

    methods (Access = private, Static)

        function gElement = computeGlobalElements(isub,nsubCells,nelem)
            gElement = isub:nsubCells:nelem ;
        end

    end

end


% POP_TIMEF - Returns estimates and plots of event-related (log) spectral
%           perturbation (ERSP) and inter-trial coherence (ITC) changes
%           timelocked to a set of input events in one data channel.
%
% Usage:
%   >> pop_timef(EEG, typeplot); % pop_up window
%   >> pop_timef(EEG, typeplot, lastcom); % pop_up window
%   >> pop_timef(EEG, typeplot, channel); % do not pop-up
%   >> pop_timef(EEG, typeproc, num, tlimits,cycles,
%                        'key1',value1,'key2',value2, ... );
%
% Inputs:
%   INEEG    - input EEG dataset
%   typeproc - type of processing. 1 process the raw
%              data and 0 the ICA components
%   num      - component or channel number
%   tlimits  - [mintime maxtime] (ms) sub-epoch time limits
%   cycles   -  >0 -> Number of cycles in each analysis wavelet
%               0 -> Use FFTs (with constant window length)
%
% Optional inputs:
%    See the TIMEF function.
%
% Outputs: same as TIMEF, no outputs are returned when a
%          window pops-up to ask for additional arguments
%
% Author: Arnaud Delorme, CNL / Salk Institute, 2001
%
% See also: TIMEF, EEGLAB

% Copyright (C) 2002 arno@salk.edu, Arnaud Delorme, CNL / Salk Institute
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. 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 HOLDER 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.

% 01-25-02 reformated help & license -ad
% 03-08-02 add eeglab option & optimize variable sizes -ad
% 03-10-02 change timef call -ad
% 03-18-02 added title -ad & sm
% 04-04-02 added outputs -ad & sm

function varargout = pop_timef(EEG, typeproc, num, tlimits, cycles, varargin );

varargout{1} = '';
% display help if not enough arguments
% ------------------------------------
if nargin < 2
	help pop_timef;
	return;
end;
lastcom = [];
if nargin < 3
	popup = 1;
else
	popup = ischar(num) | isempty(num);
	if ischar(num)
		lastcom = num;
	end
end

% pop up window
% -------------
if popup
	[txt vars] = gethelpvar('timef.m');

	geometry = { [1 0.5 0.5] [1 0.5 0.5] [1 0.5 0.5] [0.92 0.1 0.78] [1 0.5 0.5] [1 0.8 0.2] [1] [1 1]};
    uilist = { ...
                           { 'Style', 'text', 'string', fastif(typeproc, 'Channel number', 'Component number'), 'fontweight', 'bold'  } ...
			   { 'Style', 'edit', 'string', getkeyval(lastcom,3,[],'1') } {} ...
			   { 'Style', 'text', 'string', 'Epoch time range [min max] (msec)', 'fontweight', 'bold', ...
				 'tooltipstring', 'Sub epoch time limits' } ...
			   { 'Style', 'edit', 'string', getkeyval(lastcom,4,[],[ int2str(EEG.xmin*1000) ' ' int2str(EEG.xmax*1000) ]) } {} ...
			   { 'Style', 'text', 'string', 'Wavelet cycles (0->FFT, see >> help timef)', 'fontweight', 'bold', ...
				 'tooltipstring', context('cycles',vars,txt) } ...
			   { 'Style', 'edit', 'string', getkeyval(lastcom,5,[],'3 0.5') } {} ...
			   { 'Style', 'text', 'string',  '[set]->Linear coher / [unset]->Phase coher', 'fontweight', 'bold', ...
				 'tooltipstring', ['Compute linear inter-trial coherence (coher)' 10 ...
					'OR Amplitude-normalized inter-trial phase coherence (phasecoher)'] } ...
			   { 'Style', 'checkbox', 'value', ~getkeyval(lastcom,'phasecoher','present',1) } { } ...
			   { 'Style', 'text', 'string', 'Bootstrap significance level (Ex: 0.01 -> 1%)', 'fontweight', 'bold', ...
				 'tooltipstring', context('alpha',vars,txt) } ...
			   { 'Style', 'edit', 'string', getkeyval(lastcom,'alpha') } {} ...
			   { 'Style', 'text', 'string', 'Optional timef() arguments (see Help)', 'fontweight', 'bold', ...
				 'tooltipstring', 'See timef() help via the Help button on the right...' } ...
			   { 'Style', 'edit', 'string', '''padratio'', 4, ''plotphase'',''off''' } ...
			   { 'Style', 'pushbutton', 'string', 'Help', 'callback',  'pophelp(''timef'');' } ...
			   {} ...
			   { 'Style', 'checkbox', 'value', ~getkeyval(lastcom,'plotersp','present',0), 'string', ...
				 'Plot Event Related Spectral Power', 'tooltipstring', ...
				 'Plot log spectral perturbation image in the upper panel' } ...
			   { 'Style', 'checkbox', 'value', ~getkeyval(lastcom,'plotitc','present',0), 'string', ...
				 'Plot Inter Trial Coherence', 'tooltipstring', ...
				 'Plot the inter-trial coherence image in the lower panel' } ...
			 };
      % { 'Style', 'edit', 'string', '''padratio'', 4, ''plotphase'', ''off''' } ...
			   %{ 'Style', 'text', 'string',  '[set] -> Plot ITC phase sign', 'fontweight', 'bold', ...
			%	 'tooltipstring', ['Plot the sign (+/-) of inter-trial coherence phase' 10 ...
			%		'as red (+) or blue (-)'] } ...
			%   { 'Style', 'checkbox', 'value', ~getkeyval(lastcom,'plotphase','present',1) } { } ...

	result = inputgui( geometry, uilist, 'pophelp(''pop_timef'');', ...
					   fastif(typeproc, 'Plot channel time frequency -- pop_timef()', ...
							  'Plot component time frequency -- pop_timef()'));
	if length( result ) == 0 return; end

	num	     = eval( [ '[' result{1} ']' ] );
	tlimits	 = eval( [ '[' result{2} ']' ] );
	cycles	 = eval( [ '[' result{3} ']' ] );
    if result{4}
    	options = [ ',''type'', ''coher''' ];
    else
		options = [',''type'', ''phasecoher''' ];
    end;

    % add topoplot
    % ------------
    if isfield(EEG.chanlocs, 'theta')
        if ~isfield(EEG, 'chaninfo'), EEG.chaninfo = []; end
        if typeproc == 1
            options = [options ', ''topovec'', ' int2str(num) ...
                        ', ''elocs'', EEG.chanlocs, ''chaninfo'', EEG.chaninfo' ];
        else
            options = [options ', ''topovec'', EEG.icawinv(:,' int2str(num) ...
                       '), ''elocs'', EEG.chanlocs, ''chaninfo'', EEG.chaninfo' ];
        end
    end

    % add title
    % ---------
	if isempty( findstr(  '''title''', result{6}))
        if ~isempty(EEG.chanlocs) && typeproc
            chanlabel = EEG.chanlocs(num).labels;
        else
            chanlabel = int2str(num);
        end
	    switch lower(result{4})
	       case 'coher', options = [options ', ''title'',' fastif(typeproc, '''Channel ', '''Component ') chanlabel ...
	       ' power and inter-trial coherence' fastif(~ isempty(EEG.setname), [' (' EEG.setname ')''' ], '''') ];
	       otherwise, options = [options ', ''title'',' fastif(typeproc, '''Channel ', '''Component ') chanlabel ...
	       ' power and inter-trial phase coherence' fastif(~ isempty(EEG.setname), [' (' EEG.setname ')''' ], '''') ];
	    end
	end
	if ~isempty( result{5} )
		options      = [ options ', ''alpha'',' result{5} ];
	end
	if ~isempty( result{6} )
		  options = [ options ',' result{6} ];
	end
	if ~result{7}
		options = [ options ', ''plotersp'', ''off''' ];
	end
	if ~result{8}
		options = [ options ', ''plotitc'', ''off''' ];
	end
	figure; try, icadefs; set(gcf, 'color', BACKCOLOR); catch, end
else
    options = [ ',' vararg2str(varargin) ];
end

% compute epoch limits
% --------------------
if isempty(tlimits)
	tlimits = [EEG.xmin, EEG.xmax]*1000;
end;
pointrange1 = round(max((tlimits(1)/1000-EEG.xmin)*EEG.srate, 1));
pointrange2 = round(min((tlimits(2)/1000-EEG.xmin)*EEG.srate, EEG.pnts));
pointrange = [pointrange1:pointrange2];

% call function sample either on raw data or ICA data
% ---------------------------------------------------
if typeproc == 1
	tmpsig = EEG.data(num,pointrange,:);
else
	if ~isempty( EEG.icasphere )
        tmpsig = eeg_getdatact(EEG, 'component', num, 'samples', pointrange);
	else
		error('You must run ICA first');
	end;
end;

% outputs
% -------
outstr = '';
if ~popup
    for io = 1:nargout, outstr = [outstr 'varargout{' int2str(io) '},' ]; end
    if ~isempty(outstr), outstr = [ '[' outstr(1:end-1) '] =' ]; end
end

% plot the datas and generate output command
% --------------------------------------------
if length( options ) < 2
    options = '';
end
if nargin < 4
    varargout{1} = sprintf('figure; pop_timef( EEG, %d, %d, %s, %s %s);', typeproc, num, ...
                           vararg2str({tlimits}), vararg2str({cycles}), options);
end
com = sprintf('%s timef( tmpsig(:, :), length(pointrange), [tlimits(1) tlimits(2)], EEG.srate, cycles %s);', outstr, options);
eval(com)

return;

% get contextual help
% -------------------
function txt = context(var, allvars, alltext);
	loc = strmatch( var, allvars);
	if ~isempty(loc)
		txt= alltext{loc(1)};
	else
		disp([ 'warning: variable ''' var ''' not found']);
		txt = '';
	end


function out = isPeriodicTech(f)
%ISPERIODICTECH   Test if a CHEBFUN object is built upon a TECH of
%periodic functions.
%   out = ISPERIODICTECH(F) returns logical true if F has at least one FUN
%   which is made of a TECH of periodic functions and false otherwise.

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

% out = all(cellfun(@(f) isPeriodicTech(f), f.funs));

% Since all funs have the same technology, it is sufficient and faster to test
% only the first.
out = isPeriodicTech(f.funs{1});

end


function A = imresize3d_trans(V,scale,tsize,ntype,npad)
    A1 = imresize3d(V(:,:,:,1), scale, tsize, ntype, npad);
    A2 = imresize3d(V(:,:,:,2), scale, tsize, ntype, npad);
    A3 = imresize3d(V(:,:,:,3), scale, tsize, ntype, npad);
    A = cat(4, A1, A2, A3);
end