function predictions = predictOneVsAll(all_theta, X)
    %% PREDICT Predict the label for a trained one-vs-all classifier. The labels
    %are in the range 1..K, where K = size(all_theta, 1).
    %  predictions = PREDICTONEVSALL(all_theta, X) will return a vector of predictions
    %  for each example in the matrix X. Note that X contains the examples in
    %  rows. all_theta is a matrix where the i-th row is a trained logistic
    %  regression theta vector for the i-th class. You should set p to a vector
    %  of values from 1..K (e.g., p = [1; 3; 1; 2] predicts classes 1, 3, 1, 2
    %  for 4 examples)

    % Add ones to the X data matrix
    n = size(X, 1);
    X = [ones(n, 1) X];

    % ====================== YOUR CODE HERE ======================
    % Instructions: Complete the following code to make predictions using
    %               your learned logistic regression parameters (one-vs-all).
    %               You should set p to a vector of predictions (from 1 to
    %               num_labels).
    %
    % Hint: This code can be done all vectorized using the max function.
    %       In particular, the max function can also return the index of the
    %       max element, for more information see 'help max'. If your examples
    %       are in rows, then, you can use max(A, [], 2) to obtain the max
    %       for each row.
    %

    % try every example against every classifier
    activations = sigmoid(X * all_theta');

    % return both probabilities, predictions
    % but throw away probabilities for now
    [~, predictions] = max(activations, [], 2);

end


function [X,rho,eta] = mr2(A,b,k,reorth)
%MR2 Solution of symmetric indefinite problems by the MR-II algorithm
%
% [X,rho,eta] = mr2(A,b,k,reorth)
%
% MR-II is a variant of the MINRES algorithm for symmetric indefinite linear
% systems A x = b, with starting vector A*b (instead of b as in MINRES).
% This function returns all k iterates, stored as the columns of the
% matrix X.  The solution norm and residual norm are returned in eta and
% rho, respectively.
%
% Reorthogonalization is controlled by means of reorth:
%    reorth = 0 : no reorthogonalization (default),
%    reorth = 1 : reorthogonalization by means of MGS.

% Reference: M. Hanke, "Conjugate Gradient Methods for Ill-Posed Problems",
% Longman Scientific and Technical, Essex, 1995.

% Per Christian Hansen, IMM, September 1, 2007.
% Based on the function mr2 from Restore Tools by James G. Nagy.

% Initialization.
if (k < 1), error('Number of steps k must be positive'), end
if (nargin==3), reorth = 0; end
[m,n] = size(A);
if (m ~= n || norm(A-A','fro')), error('The matrix must be symmetric'), end

% Allocate space.
X = zeros(n,k);
if reorth
  W = zeros(n,k);
  if (k>=n), error('No. of iterations must satisfy k < n'), end
end
if (nargout > 1)
  eta = zeros(k,1); rho = eta;
end

% Prepare for interation.
x = zeros(n,1); r = b;
vold = 0; v = A*r;
wold = 0; w = A*v;
beta = norm(w);
v = v./beta; w = w./beta;
if reorth, W(:,1) = w; end

% Perform k iterations.
for i=1:k

  rrho = r'*w;
  x = x + rrho*v;
  r = r - rrho*w;
  Aw = A*w;
  alpha = w'*Aw;
  vnew  =  w - alpha*v - beta*vold;
  wnew  = Aw - alpha*w - beta*wold;
  vold = v; wold = w; v = vnew; w = wnew;
  if reorth
    for j=1:i, w = w - (W(:,j)'*w)*W(:,j); end
  end;
  beta = norm(w);
  v = v./beta;	w = w./beta;
  if reorth, W(:,i+1) = w; end;

  X(:,i) = x;
  if (nargout>1), rho(i) = norm(r); end
  if (nargout>2), eta(i) = norm(x); end

end


%% Execute this file to collect training data for model identification

%% Parameters: Model
n = 5;
options = odeset('RelTol',1e-10,'AbsTol',1e-10*ones(1,n));
SIM_DURATION = 10;  % Physical time simulation is integrated before integrator is switched, adjust if necessary, depends on length of time series to be computed
dt = 1/12;       % time step of data

run_HIV_params

% Steady-state of model corresponding to progressive infection
xSTEADY1 = zeros(1,5);
xSTEADY1(2) = ((c2*(lambda1-d*q)-b2*alpha1) - ...
    sqrt((c2*(lambda1-d*q)-b2*alpha1)^2 - 4*alpha1*c2*q*d*b2))/(2*alpha1*c2*q);
xSTEADY1(1) = lambda1/(d+alpha1*xSTEADY1(2));
xSTEADY1(4) = 0;
xSTEADY1(5) = (xSTEADY1(2)*c2*(alpha1*q-a) + b2*alpha1)/(c2*p2*xSTEADY1(2));
xSTEADY1(3) = h*xSTEADY1(5)/(c2*q*xSTEADY1(2));

% Steady-state of model corresponding to successful immune response
xSTEADY2 = zeros(1,5);
xSTEADY2(1) = (lambda1*c1)/(d*c1 + b1*alpha1);
xSTEADY2(2) = b1/c1;
xSTEADY2(3) = 0;
xSTEADY2(4) = (alpha1*xSTEADY2(1)-a)/p1;
xSTEADY2(5) = 0;

xref = xSTEADY1; % recovered healthy steady state as reference, might be used in system identification
%% Collect data
if DATA_ENSEMBLE == 1

    Nic = 32; %568
    if exist(fullfile(datapath,['DATA_',SystemModel,'_TRAINING-ENSEMBLE_',InputSignalType,'_N',num2str(Nic),'.mat']))==2
        load(fullfile(datapath,['DATA_',SystemModel,'_TRAINING-ENSEMBLE_',InputSignalType,'_N',num2str(Nic),'.mat']))
    else
        tspan=[0:dt:20];
        Ntrain = (length(tspan)-1)/2+1;
        Nt = length(tspan);

        if strcmp(ModelName,'SINDYc')
            [x10, x20, x30, x40, x50] = ndgrid([1000],[0,10], [0,10], [0.1,1,10], [0.1,1,10]);
        elseif strcmp(ModelName,'NARX') || strcmp(ModelName,'DMDc')
            [x10, x20, x30, x40, x50] = ndgrid([10,10],[0.1,0.1], [0.1,0.1],[0.1,0.1], [0.1,0.1]);

        end
        [N1,N2,N3,N4,N5] = size(x10);
        x0_ensemble = [reshape(x10,[N1*N2*N3*N4*N5,1]), reshape(x20,[N1*N2*N3*N4*N5,1]), reshape(x30,[N1*N2*N3*N4*N5,1]), reshape(x40,[N1*N2*N3*N4*N5,1]), reshape(x50,[N1*N2*N3*N4*N5,1])];
        Nic = size(x0_ensemble,1)

        xensemble = zeros(Nt,n,Nic); % Init ensemble data
        switch InputSignalType

            case 'sine2'

                rng(1,'twister')
                Nrand = [1*rand(Nic,5)];
                A = 2;
                forcing = @(x,t) [(0.4*(sin(2*pi*0.2*t).*sin(2*pi*0.05*t)))+0.3];
                for iIC = 1:Nic
                    tic
                    try
                        forcing = @(x,t) [(Nrand(iIC,1)*A* (sin(Nrand(iIC,1)*0.7*t).*sin(Nrand(iIC,1)*.1*t).*sin(Nrand(iIC,1)*.2*t).*sin(Nrand(iIC,1)*.05*t)) ).^2]; %[(A*(sin(0.01*t)+sin(.1*t))).^2];
                        [t,x]=ode45(@(t,x) HIVsys_KWON(t,x,forcing(x,t)),tspan,x0_ensemble(iIC,:),options);
                        xensemble(:,:,iIC) = x;
                        for i = 1:length(tspan)
                            u(i,:,iIC) = forcing(0,tspan(i));
                        end
                    catch
                        disp(['ERROR: Simulation failed for i=',num2str(iIC)])
                        xensemble(:,:,iIC) = nan(Nt,n);
                        u(:,:,iIC) = zeros(Nt,length(A));
                    end
                    tend = toc;
                    disp(['Time for ',num2str(iIC), ' of ',num2str(Nic),': ', num2str(tend)])
                end
                figure,plot(t,xensemble(:,:,iIC))
                figure,plot(t,squeeze(xensemble(:,5,:)))

            case 'prbs'
                A = 1;
                taulim = [0.2 8];
                states = [0,0:0.25:1,0,0,0]
                Nswitch = 200;

                rng(1,'twister');
                seed = randi(Nic,Nic,1); % vary actuation in each trajectory
                forcing = @(x,t,seedval) [A(1)*prbs(taulim, Nswitch, states, t,0,seedval)];
                u = zeros(length(tspan),length(A),Nic);

                for iIC = 1:Nic
                    tic
                    try
                        % IF simulation takes longer than SIM_DURATION,
                        % stop simulation and switch solver
                        [t,x,isterminal] = integrateODE(tspan, x0_ensemble(iIC,:), 'ode45', SIM_DURATION,@(x,t) forcing(x,t,seed(iIC)));
                        if isterminal == 1 % try different solver
                            [t,x,isterminal] = integrateODE(tspan, x0_ensemble(iIC,:), 'ode15s', SIM_DURATION,@(x,t) forcing(x,t,seed(iIC)));
                        end
                        xensemble(:,:,iIC) = x;
                        for i = 1:length(tspan)
                            u(i,:,iIC) = forcing(0,tspan(i),seed(iIC));
                        end
                    catch
                        disp(['ERROR: Simulation failed for i=',num2str(iIC)])
                        xensemble(:,:,iIC) = nan(Nt,n);
                        u(:,:,iIC) = zeros(Nt,length(A));
                    end
                    tend = toc;
                    disp(['Time for ',num2str(iIC), ' of ',num2str(Nic),': ', num2str(tend)])
                end

        end

        %% Clean up data
        % from unstable simulations or which failed
        IXnaninf = zeros(Nic,1);
        for i = 1:Nic
            IXnan = isnan(squeeze((xensemble(:,:,i))));
            IXinf = isinf(squeeze(abs(xensemble(:,:,i))));
            if any(IXnan(:)==1) || any(IXinf(:)==1)
                IXnaninf(i) = 1;
            end
        end
        xensemble(:,:,logical(IXnaninf)) = [];
        u(:,:,logical(IXnaninf)) = [];
        Nic = size(xensemble,3);

        %% Split into training and validation data set
        Ntrain = ceil(length(tspan)/2);
        xv = xensemble(Ntrain+1:end,:,:);
        x = xensemble(1:Ntrain,:,:);

        uv = u(Ntrain+1:end,:,:);
        u = u(1:Ntrain,:,:);

        tv = t(Ntrain+1:end);
        t = t(1:Ntrain);

        tspanv = tspan(Ntrain+1:end);
        tspan = tspan(1:Ntrain);

        %% Show data

        figure;
        subplot(6,1,1)
        plot(tspan,squeeze(x(:,1,:)),'LineWidth',1.5)
        ylabel('x1')
        set(gca,'LineWidth',1, 'FontSize',14)

        subplot(6,1,2)
        plot(tspan,squeeze(x(:,2,:)),'LineWidth',1.5)
        ylabel('x2')
        set(gca,'LineWidth',1, 'FontSize',14)

        subplot(6,1,3)
        plot(tspan,squeeze(x(:,3,:)),'LineWidth',1.5)
        ylabel('x3')
        set(gca,'LineWidth',1, 'FontSize',14)

        subplot(6,1,4)
        plot(tspan,squeeze(x(:,4,:)),'LineWidth',1.5)
        ylabel('x4')
        set(gca,'LineWidth',1, 'FontSize',14)

        subplot(6,1,5)
        plot(tspan,squeeze(x(:,5,:)),'LineWidth',1.5)
        ylabel('x5')
        set(gca,'LineWidth',1, 'FontSize',14)

        subplot(6,1,6)
        plot(tspan,squeeze(u(:,1,:)),'LineWidth',1.5)
        ylabel('u')
        set(gca,'LineWidth',1, 'FontSize',14)
        %%
        T = length(tspan);
        N = length(tspan);
        save(fullfile(datapath,['DATA_',SystemModel,'_TRAINING-ENSEMBLE_',InputSignalType,'_N',num2str(Nic),'.mat']))
    end
elseif DATA_ENSEMBLE == 0
    rng(3,'twister')

    % Initial Condition
    x0 = [10, 0.1, 0.1, 1, 0.1];
    tspan=[0:dt:400];
    Ntrain = (length(tspan)-1)/2+1;

    switch InputSignalType
        case 'unforced'
            forcing = @(x,t) [0];
            [t,x]=ode45(@(t,x) HIVsys_ZURAKOWSKI(t,x,forcing(x,t)),tspan,x0,options);
            u = zeros(length(tspan),1);
            for i = 1:length(tspan)
                u(i,:) = forcing(0,tspan(i));
            end
        case 'sine2'
            A = 1.5;
            Nic = 1; iIC = 1;
            Nrand = [rand(Nic,1),rand(Nic,1),randn(Nic,1),rand(Nic,1),randn(Nic,1),rand(Nic,1),randn(Nic,1),rand(Nic,1),randn(Nic,1)];
            forcing = @(x,t) [mod((A* (sin(Nrand(iIC,2)*0.7*(t-Nrand(iIC,3))).* ...
                sin(Nrand(iIC,4)*.1*(t-Nrand(iIC,5))).*sin(Nrand(iIC,6)*.2*(t-Nrand(iIC,7))).*sin(Nrand(iIC,8)*.05*(t-Nrand(iIC,9)))) ).^2,1)];
            [t,x]=ode45(@(t,x) HIVsys_ZURAKOWSKI(t,x,forcing(x,t)),tspan,x0,options);
            u = forcing(0,tspan)';

        case 'prbs'
            A = 1; % PAPER
            taulim = [0.2 10];
            states = [0:0.25:1,0,0,0,0];
            Nswitch = 200;
            forcing = @(x,t) [A(1)*prbs(taulim, Nswitch, states, t,0)];

            [t,x]=ode45(@(t,x) HIVsys_ZURAKOWSKI(t,x,forcing(x,t)),tspan,x0,options);

            u = zeros(length(tspan),1);
            for i = 1:length(tspan)
                u(i,:) = forcing(0,tspan(i));
            end
            figure,plot(tspan,u)
            size(u)

    end

    %% Split into training and validation data set
    Ntrain = ceil(length(tspan)/2);
    xv = x(Ntrain+1:end,:);
    x = x(1:Ntrain,:);

    uv = u(Ntrain+1:end,:);
    u = u(1:Ntrain,:);

    tv = t(Ntrain+1:end);
    t = t(1:Ntrain);

    tspanv = tspan(Ntrain+1:end);
    tspan = tspan(1:Ntrain);

    %% Show results
    betta_eff = alpha1*(1-eta*u(1));
    betta_eff<c1*(c2*b1*(lambda1-q*d)-b2*c1*d)/(b1*(c2*b1*q+b2*c1))
    xSTEADY = xSTEADY1;
    figure;
    subplot(5,1,1),hold on
    % plot(t,xSTEADY(1)*ones(size(t)),'--k')
    plot(t,x(:,1),'LineWidth',1.5)
    ylabel('x1')
    set(gca,'LineWidth',1, 'FontSize',14)
    axis tight

    subplot(5,1,2),hold on
    % plot(t,xSTEADY(2)*ones(size(t)),'--k')
    plot(t,x(:,2),'LineWidth',1.5)
    ylabel('x2')
    set(gca,'LineWidth',1, 'FontSize',14)
    axis tight

    subplot(5,1,3),hold on
    % plot(t,xSTEADY(3)*ones(size(t)),'--k')
    plot(t,x(:,3),'LineWidth',1.5)
    ylabel('x3')
    set(gca,'LineWidth',1, 'FontSize',14)
    axis tight

    subplot(5,1,4),hold on
    % plot(t,xSTEADY(4)*ones(size(t)),'--k')
    plot(t,x(:,4),'LineWidth',1.5)
    ylabel('x4')
    set(gca,'LineWidth',1, 'FontSize',14)
    axis tight

    subplot(5,1,5),hold on
    % plot(t,xSTEADY(5)*ones(size(t)),'--k')
    plot(t,x(:,5),'LineWidth',1.5)
    ylabel('x5')
    set(gca,'LineWidth',1, 'FontSize',14)
    axis tight

    T = length(tspan);
    N = length(tspan);
end


function res = le(a,b)
%LE           Implements  a <= b  elementwise for intervals a and b
%
%  if true,  a  is definitely less than or equal to  b
%

% written  10/16/98     S.M. Rump
% modified 11/30/98     S.M. Rump
% modified 04/04/04     S.M. Rump  set round to nearest for safety
% modified 04/06/05     S.M. Rump  rounding unchanged
%

  if ~isa(a,'intval')
    a = intval(a);
  end
  if ~isa(b,'intval')
    b = intval(b);
  end

  if a.complex | b.complex
    res = real(sup(a)) <= real(inf(b)) & imag(sup(a)) <= imag(inf(b)) ;
  else
    res = sup(a) <= inf(b) ;
  end


% fbp_fan_arc_example.m
% example of how to use fbp_fan_arc.m
% Copyright Jeff Fessler, University of Michigan

if ~isvar('sino')
	down = 4;
	ig = image_geom('nx', 512, 'ny', 504, 'fov', 500, 'down', down);
	sg = sino_geom('fan', 'nb', 888, 'na', 984, 'ds', 1.0, ...
		'dsd', 949, 'dod', 408, 'offset_s', 0.25, ...
		'orbit', 360, ...
		'down', down);

	ell = [0 0 200 200 0 1; 0 0 10 10 0 1];
	ell = [0 0 200 200 0 0; 0 0 10 10 0 1];
	ell = [20 -15 225 150 30 10; 40 0 10 15 0 1];
%	ell = [100 100 ds/4 ds/4 0 1]; % point source

	sino = ellipse_sino(sg, ell, 'oversample', 2);

	xtrue = ellipse_im(ig, ell, 'oversample', 4);

	% system object
	G = Gtomo2_dscmex(sg, ig);

	im plc 2 3
	im(1, xtrue, 'x'), cbar
	im(4, sino, 'sino'), cbar
prompt
end

if 0 % examine recon of flat fan-beam sinogram
	sino = repmat(abs(sg.s) < 0.8 * max(sg.s), [1 sg.na]);
	im(sino)
end

% fan-beam reconstruction
if ~isvar('recon')
	recon = fbp_fan_arc(sino, G, 'ramp');
end

if 1 % compare to new fbp2() method
	tmat = fbp2(sg, ig, 'type', 'std:mat');
	rmat = fbp2(sino, tmat);
	max_percent_diff(rmat, recon)
prompt
end

if 0 % compare to new fbp2() method
	tmex = fbp2(sg, ig, 'type', 'std:mex');
	rmex = fbp2(sino, tmex);
	mmask = (rmat > 0);
	max_percent_diff(rmex .* mmask, recon .* mmask)
	im(2, rmat .* mmask, 'mat'), cbar
	im(3, rmex .* mmask, 'mex'), cbar
return
end

if 0 % examine "aliasing"
	clim = [9.5 10.5];
%	clim = [0.8 1.2];
%	clim = [-0.2 0.2];
	im clf, im(recon, clim), cbar
return
end

if im
	im(2, recon, 'FBP matlab'), cbar
	im(5, recon - xtrue, 'error'), cbar
	iy = ig.ny/2; ix = 1:ig.nx;
	subplot(133)
	plot(ix, xtrue(ix,iy), '-', ix, recon(ix,iy), '--')
	axis([1 ig.nx -0.5 10.5]), legend('true', 'recon', 4)
end

if has_aspire % check consistency with aspire
	dir = test_dir;
	f.sino = [dir 'sino.fld'];
	f.image = [dir 'image.fld'];
	f.dsc = [dir 't.dsc'];
	fld_write(f.sino, sino)

	char_array_write(f.dsc, G.arg.args)
	f.win = 'boxcar,1,0,1';
	com = sprintf('echo y | i fbp dsc %s %s %s %s', ...
		f.image, f.sino, f.dsc, f.win)
%	eval(['!' com])
	disp(os_run(com))

	if 0 % compare filters
		tmp = fld_read('fft_filt.fld');
		sum(tmp) / sum(test)
%		im clf, plot([tmp test])
		max_percent_diff(test, tmp)
	return
	end

	if 0 % compare filtered projections
		% seem to match except for slight shift??
		tmp = fld_read('proj_filt.fld');
		im clf, plot([tmp(:,1) test(:,1)])
		plot(tmp(:,1)-test(:,1))
		max_percent_diff(test, tmp)
		sum(tmp(:)) / sum(test(:))
		minmax(test)
		minmax(tmp)
		minmax(test-tmp)
	return
	end

	im_asp = fld_read(f.image);
	im(233, im_asp, 'aspire'), cbar
	good = recon ~= 0;
	diff = im_asp - recon;
	diff = diff .* good;
	im(236, diff, 'aspire-matlab'), cbar
	im(234, (im_asp ~= 0) - (recon ~= 0), 'aspire-matlab support'), cbar
	max_percent_diff(recon.*good, im_asp.*good)
end


%trotz SE(3) rotation about Z axis
%
% T = trotz(THETA) is a homogeneous transformation (4x4) representing a rotation
% of THETA radians about the z-axis.
%
% T = trotz(THETA, 'deg') as above but THETA is in degrees.
%
% Notes::
% - Translational component is zero.
%
% See also rotz, trotx, troty, trot2, SE3.Rz.

%## 3d homogeneous rotation

% Copyright (C) 1993-2019 Peter I. Corke
%
% This file is part of The Spatial Math Toolbox for MATLAB (SMTB).
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the "Software"), to deal
% in the Software without restriction, including without limitation the rights
% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
% of the Software, and to permit persons to whom the Software is furnished to do
% so, subject to the following conditions:
%
% The above copyright notice and this permission notice shall be included in all
% copies or substantial portions of the Software.
%
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
% FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
% COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
% IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
% CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
%
% https://github.com/petercorke/spatial-math

function T = trotz(t, varargin)
	T =    [rotz(t, varargin{:}) [0 0 0]'; 0 0 0 1];


function [ HessGrad ] = lbfgs_two_loop_recursion( grad, s_array, y_array )
% Two loop recursion algorithm for L-BFGS.
%
% Reference:
%       Jorge Nocedal and Stephen Wright,
%       "Numerical optimization,"
%       Springer Science & Business Media, 2006.
%
%       Algorithm 7.4 in Section 7.2.
%
% This file is part of GDLibrary and SGDLibrary.
%
% Created H.Kasai on Oct. 17, 2016

    if(size(s_array,2)==0)
        HessGrad = -grad;
    else
        q = grad;

        for i = size(s_array,2):-1:1
            rk(i) = 1/(y_array(:,i)'*s_array(:,i));
            a(i) = rk(i)*s_array(:,i)'*q;
            q = q - a(i)*y_array(:,i);
        end

        Hk0 = (s_array(:,end)'*y_array(:,end))/(y_array(:,end)'*y_array(:,end));
        R = Hk0.*q;

        for jj = 1:size(s_array,2)
            beta = rk(jj)*y_array(:,jj)'*R;
            R = R + s_array(:,jj)*(a(jj) - beta);
        end

        HessGrad = -R;
    end
end


function H=comp_warpedfreqresponse(wintype,fc,bw,fs,L,freqtoscale,scaletofreq,varargin)
%COMP_WARPEDFREQRESPONSE  Transfer function of warped filter
%   Usage: H=comp_warpedfreqresponse(wintype,fc,bw,fs,L,freqtoscale);
%          H=comp_warpedfreqresponse(wintype,fc,bw,fs,L,freqtoscale,normtype);
%
%   Input parameters:
%      wintype     : Type of window (from firwin)
%      fc          : Centre frequency, in scale units.
%      bw          : Bandwith, in scale units.
%      fs          : Sampling frequency in Hz.
%      L           : Transform length (in samples).
%      freqtoscale : Function to convert Hz into scale units.
%      scaletofreq : Function to convert scale units into Hz.
%      normtype    : Normalization flag to pass to |setnorm|.

definput.import={'setnorm'};
definput.flags.symmetry = {'nonsymmetric','symmetric'};
[flags,kv]=ltfatarghelper({},definput,varargin);

fcwasnegative = fc < 0;

if fcwasnegative && flags.do_symmetric
   fc = -fc;
end

fcscale = freqtoscale(fc);

if ~flags.do_symmetric
   % Compute the values in Aud of the channel frequencies of an FFT of
   % length L.
   bins_lo   = freqtoscale(modcent(fs*(0:L-1)/L,fs)).';
else
   bins_lo   = freqtoscale(fs*(0:L-1)/L).';
end

% This one is necessary to represent the highest frequency filters, which
% overlap into the negative frequencies.
nyquest2  = 2*freqtoscale(fs/2);
bins_hi   = nyquest2+bins_lo;

% firwin makes a window of width 1 centered around 0 on the scale, so we rescale the
% bins in order to pass the correct width to firwin and subtract fc
bins_lo=(bins_lo-fcscale)/bw;
bins_hi=(bins_hi-fcscale)/bw;

pos_lo=comp_warpedfoff(fc,bw,fs,L,freqtoscale,scaletofreq,flags.do_symmetric);
% The "floor" below often cuts away a non-zero sample, but it makes
% the support stay below the limit needed for the painless case. Same
% deal 4 lines below.
pos_hi=floor(scaletofreq(fcscale+.5*bw)/fs*L);

if pos_hi>L/2
    % Filter is high pass and spilling into the negative frequencies
    pos_hi=floor(scaletofreq(fcscale+.5*bw-nyquest2)/fs*L);
end;

win_lo=firwin(wintype,bins_lo);
win_hi=firwin(wintype,bins_hi);

H=win_lo+win_hi;
H(isnan(H)) = 0;

H=setnorm(H,flags.norm);

H=circshift(H,-pos_lo);
upidx=modcent(pos_hi-pos_lo,L);

% ------ Testing ---------------
if 0
    bb=circshift(bins_lo,-pos_lo);
    if bb(1)<-0.5
        % Adjust bin_lo
        error('Could do better here.');
    end;
    if (bb(upidx+1)<0.5) && (bb(upidx+1)>0)
        disp('Chopped non-zero sample.');
        bb(upidx+1)
    end;
end;

H=H(1:upidx);

if fcwasnegative && flags.do_symmetric
   H = H(end:-1:1);
end


function [y,dy] = div_gmc(dx,x,Mu_x,Mu_dx,Sigma_dxdx,Sigma_xx,Sigma_dxx,Sigma_xdx)
%GMC_DIV Derivative of the conditional Gaussian Mixture model P(dx|x)
%
%    sqrt((2*pi)^nbVar * (abs(det(Sigma))+realmin))
%   check the derivative of  log exp(- 0.5 * (dx - \Mu_{dx|x})'(\Sigma_{dx|x}^-1) (dx - \Mu_{dx|x})  )
%
%   input -----------------------------------------------------------------
%
%       o dx : (P x 1)
%
%       o x  : (Q x 1)
%
%       o Mu_dx : (P x 1), $\mu_{\dot{x}}$
%
%       o Mu_x  : (Q x 1), $\mu_x$
%
%           P + Q = D
%
%       o Sigma_dxdx   : (P x P), covariance between dx and dx
%
%       o Sigma_{dx,x} : (P x Q), covarariance between dx and x
%
%       o Sigma_{x,x}  : (Q x Q), covariance between x and x
%
%       o Sigma_{x,dx} : (Q x P),  covariance between x and dx
%
%

x   = x(:);
dx  = dx(:);
P   = size(Mu_dx,1);

% (P x 1) = (P x 1) + (P x Q)    (Q x Q)    *  (Q x 1) - (Q x 1)
% (P x 1) =           (P x 1)
invSig_xx   =  inv(Sigma_xx);
% (P x Q) = (P x Q) * (Q x Q)
A           = Sigma_dxx * invSig_xx;

% (P x 1)
Mu_dx_x = Mu_dx + A * (x - Mu_x);

% (P x P)
Sigma_dx_x = Sigma_dxdx - A * Sigma_xdx;

%  (P x N)
invSigma_dx_x = inv(Sigma_dx_x);
%norm_fac      = 0.9;%1/( (2*pi^(P/2)) * sqrt(det(Sigma_dx_x)));
%norm_fac      = -P/2 * log(pi) - 0.5*log(det(Sigma_dx_x));
denom         = sqrt((2*pi)^P * (abs(det(Sigma_dx_x))+realmin));
%norm_fac      = log(1/denom);
norm_fac      = -log(denom);
%norm_fac      = -log(sqrt((2*pi)^P) - log(abs(det(Sigma_dx_x))+realmin));

%y             =  norm_fac .* exp(-0.5 .* (dx - Mu_dx_x)' * (invSigma_dx_x *  (dx - Mu_dx_x)));
y             =   norm_fac + (-0.5 .* (dx - Mu_dx_x)' * (invSigma_dx_x *  (dx - Mu_dx_x)));

%
% (dx - Mu_dx_x)' * (invSigma_dx_x *  (dx - Mu_dx_x))
%
% (dx' * invSigma_dx_x - Mu_dx_x' * invSigma_dx_x) * (dx - Mu_dx_x)
% dx' * invSigma_dx_x * dx - Mu_dx_x' * invSigma_dx_x * dx - dx' * invSigma_dx_x * Mu_dx_x +  Mu_dx_x' * invSigma_dx_x * Mu_dx_x
%
% dx' * invSigma_dx_x * dx - 2 * Mu_dx_x' * invSigma_dx_x * dx  +  Mu_dx_x' * invSigma_dx_x * Mu_dx_x
%
% dx' * invSigma_dx_x * dx - 2 * (Mu_dx + A * (x - Mu_x))' * invSigma_dx_x * dx  +  (Mu_dx + A * (x - Mu_x))' * invSigma_dx_x * (Mu_dx + A * (x - Mu_x))
% 'here'
% tmp1  = (x - Mu_x)' * A' * invSigma_dx_x;
%
% part1 = dx' * invSigma_dx_x * dx  - 2 *Mu_dx' *invSigma_dx_x * dx  - 2 * tmp1 * dx;
%
% part1 + (Mu_dx' * invSigma_dx_x + tmp1) * (Mu_dx + A * (x - Mu_x))
%  'max expansion'
% part1 + Mu_dx' * invSigma_dx_x * Mu_dx + tmp1 * Mu_dx + Mu_dx' * invSigma_dx_x * (A * (x - Mu_x)) + tmp1 * (A * (x - Mu_x))
%
% part1 + Mu_dx' * invSigma_dx_x * Mu_dx + tmp1 * Mu_dx + tmp1 * Mu_dx + tmp1 * (A * (x - Mu_x))
%
%
% dx' * invSigma_dx_x * dx  - 2 *Mu_dx' *invSigma_dx_x * dx +  Mu_dx' * invSigma_dx_x * Mu_dx  - 2 * tmp1 * dx  + tmp1 * Mu_dx + tmp1 * Mu_dx + tmp1 * (A * (x - Mu_x))
%
% dx' * invSigma_dx_x * dx  - 2 *Mu_dx' *invSigma_dx_x * dx +  Mu_dx' * invSigma_dx_x * Mu_dx +  tmp1 * (- 2 * dx  + Mu_dx + Mu_dx + (A * (x - Mu_x)));

%fac = (x - Mu_x)' * A' * invSigma_dx_x;
% y2 = dx' * invSigma_dx_x * dx   -2 *Mu_dx' *invSigma_dx_x * dx +  Mu_dx' * invSigma_dx_x * Mu_dx + fac * (-2*dx + 2*Mu_dx + A * (x - Mu_x));
%
% y2 = exp(-0.5 .* y2);

if nargout > 1
    %
    %          -            (1 x P)          (1 x P)                      (1 x P)
%    dy = y .* ((dx' * invSigma_dx_x)' - (Mu_dx' * invSigma_dx_x)' - fac' );
 %   dy = ((dx' * invSigma_dx_x)' - (Mu_dx' * invSigma_dx_x)' - ( (x - Mu_x)' * A' * invSigma_dx_x)' );
    dy = invSigma_dx_x' * ( dx - Mu_dx  -  ((x - Mu_x)' * A')' );

end

end


% Data File LAN
% Free linear vibrations of a system
% with one degree of freedom
s     = 1; % degree of freedom
L     = '1/2*(a*qt1^2 - c*q1^2)'; % Lagrangian
QN{1} = '-b*qt1'; % generalized non potential force
qj0   = 'q0';     % initial coordinate
qtj0  = 'qt0';    % initial velocity
Tend  = 20;       % upper bound of integration
eps   = 1e-10;    % desirable accuracy
np    = 3;        % number of parameters
P{1}  = 'a';      % generalized coefficient of inertia
P{2}  = 'b';      % generalized coefficient of resistance
P{3}  = 'c';      % generalized coefficient of stiffness


function out = MD_hrv_classic(y)
% MD_hrv_classic    Classic heart rate variability (HRV) statistics.
%
% Typically assumes an NN/RR time series in units of seconds.
%
%---INPUTS:
% y, the input time series.
%
% Includes:
%  (i) pNNx
%  cf. "The pNNx files: re-examining a widely used heart rate variability
%           measure", J.E. Mietus et al., Heart 88(4) 378 (2002)
%
%  (ii) Power spectral density ratios in different frequency ranges
%   cf. "Heart rate variability: Standards of measurement, physiological
%       interpretation, and clinical use",
%       M. Malik et al., Eur. Heart J. 17(3) 354 (1996)
%
%  (iii) Triangular histogram index, and
%
%  (iv) Poincare plot measures
%  cf. "Do existing measures of Poincare plot geometry reflect nonlinear
%       features of heart rate variability?"
%       M. Brennan, et al., IEEE T. Bio.-Med. Eng. 48(11) 1342 (2001)
%
% Code is heavily derived from that provided by Max A. Little:
% http://www.maxlittle.net/

% ------------------------------------------------------------------------------
% Copyright (C) 2020, Ben D. Fulcher <ben.d.fulcher@gmail.com>,
% <http://www.benfulcher.com>
%
% If you use this code for your research, please cite the following two papers:
%
% (1) B.D. Fulcher and N.S. Jones, "hctsa: A Computational Framework for Automated
% Time-Series Phenotyping Using Massive Feature Extraction, Cell Systems 5: 527 (2017).
% DOI: 10.1016/j.cels.2017.10.001
%
% (2) B.D. Fulcher, M.A. Little, N.S. Jones, "Highly comparative time-series
% analysis: the empirical structure of time series and their methods",
% J. Roy. Soc. Interface 10(83) 20130048 (2013).
% DOI: 10.1098/rsif.2013.0048
%
% This function is free software: you can redistribute it and/or modify it under
% the terms of the GNU General Public License as published by the Free Software
% Foundation, either version 3 of the License, or (at your option) any later
% version.
%
% This program is distributed in the hope that it will be useful, but WITHOUT
% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
% FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
% details.
%
% You should have received a copy of the GNU General Public License along with
% this program. If not, see <http://www.gnu.org/licenses/>.
% ------------------------------------------------------------------------------

% Standard defaults
diffy = diff(y);
N = length(y); % time-series length

% ------------------------------------------------------------------------------
% Calculate pNNx percentage
% ------------------------------------------------------------------------------
% pNNx: recommendation as per Mietus et. al. 2002, "The pNNx files: ...", Heart
% strange to do this for a z-scored time series...

Dy = abs(diffy);

% Anonymous function to do the PNNx calcualtion:
% proportion of difference magnitudes greater than X*sigma
PNNxfn = @(x) mean(Dy > x/1000);

out.pnn5  = PNNxfn(5); % 0.005*sigma
out.pnn10 = PNNxfn(10); % 0.01*sigma
out.pnn20 = PNNxfn(20); % 0.02*sigma
out.pnn30 = PNNxfn(30); % 0.03*sigma
out.pnn40 = PNNxfn(40); % 0.04*sigma

% ------------------------------------------------------------------------------
% Calculate PSD
% ------------------------------------------------------------------------------
% [Pxx, F] = psd(series,1024,1,hanning(1024),512);
[Pxx, F] = periodogram(y,hann(N)); % periodogram with hanning window

% ------------------------------------------------------------------------------
% Calculate spectral measures such as subband spectral power percentage, LF/HF ratio etc.
% ------------------------------------------------------------------------------
% LF/HF: as per Malik et. al. 1996, "Heart Rate Variability"
LF_lo = 0.04; % /pi -- fraction of total power (max F is pi)
LF_hi = 0.15;
HF_lo = 0.15;
HF_hi = 0.4;

fbinsize = F(2) - F(1);
indl  = ((F >= LF_lo) & (F <= LF_hi));
indh  = ((F >= HF_lo) & (F <= HF_hi));
indv  = (F <= LF_lo);
lfp   = fbinsize * sum(Pxx(indl));
hfp   = fbinsize * sum(Pxx(indh));
vlfp  = fbinsize * sum(Pxx(indv));
out.lfhf  = lfp / hfp;
total     = fbinsize * sum(Pxx);
out.vlf   = vlfp/total * 100;
out.lf    = lfp/total * 100;
out.hf    = hfp/total * 100;

% ------------------------------------------------------------------------------
% Triangular histogram index
% ------------------------------------------------------------------------------
numBins = 10;
out.tri = length(y)/max(histcounts(y,numBins));

% ------------------------------------------------------------------------------
% Poincare plot measures:
% ------------------------------------------------------------------------------
% cf. "Do Existing Measures ... ", Brennan et. al. (2001), IEEE Trans Biomed Eng 48(11)
rmssd = std(diffy); % std of differenced series
sigma = std(y); % should be 1 for zscored time series
out.SD1 = 1/sqrt(2) * rmssd * 1000;
out.SD2 = sqrt(2 * sigma^2 - (1/2) * rmssd^2) * 1000;

end


%% Analyzing Neural Time Series Data
% Matlab code for Chapter 26
% Mike X Cohen
%
% This code accompanies the book, titled "Analyzing Neural Time Series Data"
% (MIT Press). Using the code without following the book may lead to confusion,
% incorrect data analyses, and misinterpretations of results.
% Mike X Cohen assumes no responsibility for inappropriate or incorrect use of this code.

%% Figure 26.1

% load sample EEG dataset
load sampleEEGdata

% names of the channels you want to synchronize
channel1 = 'p1';
channel2 = 'pz';

% create complex Morlet wavelet
center_freq = 5; % in Hz
time        = -1:1/EEG.srate:1; % time for wavelet
wavelet     = exp(2*1i*pi*center_freq.*time) .* exp(-time.^2./(2*(4/(2*pi*center_freq))^2))/center_freq;
half_of_wavelet_size = (length(time)-1)/2;

% FFT parameters
n_wavelet     = length(time);
n_data        = EEG.pnts;
n_convolution = n_wavelet+n_data-1;

% FFT of wavelet
fft_wavelet = fft(wavelet,n_convolution);

% initialize output time-frequency data
phase_data = zeros(2,EEG.pnts);
real_data  = zeros(2,EEG.pnts);

% find channel indices
chanidx = zeros(1,2); % always initialize!
chanidx(1) = find(strcmpi(channel1,{EEG.chanlocs.labels}));
chanidx(2) = find(strcmpi(channel2,{EEG.chanlocs.labels}));

% run convolution and extract filtered signal (real part) and phase
for chani=1:2
    fft_data = fft(squeeze(EEG.data(chanidx(chani),:,1)),n_convolution);
    convolution_result_fft = ifft(fft_wavelet.*fft_data,n_convolution) * sqrt(4/(2*pi*center_freq));
    convolution_result_fft = convolution_result_fft(half_of_wavelet_size+1:end-half_of_wavelet_size);

    % collect real and phase data
    phase_data(chani,:) = angle(convolution_result_fft);
    real_data(chani,:)  = real(convolution_result_fft);
end

% open and name figure
figure, set(gcf,'Name','Movie magic minimizes the mystery.','Number','off');

% draw the filtered signals
subplot(321)
filterplotH1 = plot(EEG.times(1),real_data(1,1),'b');
hold on
filterplotH2 = plot(EEG.times(1),real_data(2,1),'m');
set(gca,'xlim',[EEG.times(1) EEG.times(end)],'ylim',[min(real_data(:)) max(real_data(:))])
xlabel('Time (ms)')
ylabel('Voltage (\muV)')
title([ 'Filtered signal at ' num2str(center_freq) ' Hz' ])

% draw the phase angle time series
subplot(322)
phaseanglesH1 = plot(EEG.times(1),phase_data(1,1),'b');
hold on
phaseanglesH2 = plot(EEG.times(1),phase_data(2,1),'m');
set(gca,'xlim',[EEG.times(1) EEG.times(end)],'ylim',[-pi pi]*1.1,'ytick',-pi:pi/2:pi)
xlabel('Time (ms)')
ylabel('Phase angle (radian)')
title('Phase angle time series')

% draw phase angle differences in cartesian space
subplot(323)
filterplotDiffH1 = plot(EEG.times(1),real_data(1,1)-real_data(2,1),'b');
set(gca,'xlim',[EEG.times(1) EEG.times(end)],'ylim',[-10 10])
xlabel('Time (ms)')
ylabel('Voltage (\muV)')
title([ 'Filtered signal at ' num2str(center_freq) ' Hz' ])

% draw the phase angle time series
subplot(324)
phaseanglesDiffH1 = plot(EEG.times(1),phase_data(1,1)-phase_data(2,1),'b');
set(gca,'xlim',[EEG.times(1) EEG.times(end)],'ylim',[-pi pi]*2.2,'ytick',-2*pi:pi/2:pi*2)
xlabel('Time (ms)')
ylabel('Phase angle (radian)')
title('Phase angle time series')

% draw phase angles in polar space
subplot(325)
polar2chanH1 = polar([phase_data(1,1) phase_data(1,1)]',repmat([0 1],1,1)','b');
hold on
polar2chanH2 = polar([phase_data(1,1) phase_data(2,1)]',repmat([0 1],1,1)','m');
title('Phase angles from two channels')

% draw phase angle differences in polar space
subplot(326)
polarAngleDiffH = polar([zeros(1,1) phase_data(2,1)-phase_data(1,1)]',repmat([0 1],1,1)','k');
title('Phase angle differences from two channels')

% now update plots at each timestep
% Note: in/decrease skipping by 10 to speed up/down the movie
for ti=1:10:EEG.pnts

    % update filtered signals
    set(filterplotH1,'XData',EEG.times(1:ti),'YData',real_data(1,1:ti))
    set(filterplotH2,'XData',EEG.times(1:ti),'YData',real_data(2,1:ti))

    % update cartesian plot of phase angles
    set(phaseanglesH1,'XData',EEG.times(1:ti),'YData',phase_data(1,1:ti))
    set(phaseanglesH2,'XData',EEG.times(1:ti),'YData',phase_data(2,1:ti))

    % update cartesian plot of phase angles differences
    set(phaseanglesDiffH1,'XData',EEG.times(1:ti),'YData',phase_data(1,1:ti)-phase_data(2,1:ti))
    set(filterplotDiffH1,'XData',EEG.times(1:ti),'YData',real_data(1,1:ti)-real_data(2,1:ti))

    subplot(325)
    cla
    polar(repmat(phase_data(1,1:ti),1,2)',repmat([0 1],1,ti)','b');
    hold on
    polar(repmat(phase_data(2,1:ti),1,2)',repmat([0 1],1,ti)','m');

    subplot(326)
    cla
    polar(repmat(phase_data(2,1:ti)-phase_data(1,1:ti),1,2)',repmat([0 1],1,ti)','k');

    drawnow
end

%% Figure 26.2

figure
subplot(221)
polar(repmat(phase_data(2,:)-phase_data(1,:),1,2)',repmat([0 1],1,EEG.pnts)','k');
title([ 'Phase synchronization: ' num2str(abs(mean(exp(1i*(diff(phase_data,1)))))) ])

new_phase_data = phase_data;
for i=2:4
    subplot(2,2,i)

    % add random phase offset
    new_phase_data(1,:) = new_phase_data(1,:)+rand*pi;

    % plot again
    polar(repmat(new_phase_data(2,:)-new_phase_data(1,:)+pi/2,1,2)',repmat([0 1],1,EEG.pnts)','k');
    title([ 'Phase synchronization: ' num2str(abs(mean(exp(1i*(diff(new_phase_data,1)))))) ])
end

%% Figure 26.3

% note: see commented line "time_window_idx..." below for panels C and D

channel1 = 'fz';
channel2 = 'o1';

freqs2use  = logspace(log10(4),log10(30),15); % 4-30 Hz in 15 steps
times2save = -400:20:800;
timewindow = linspace(1.5,3,length(freqs2use)); % number of cycles on either end of the center point (1.5 means a total of 3 cycles))
baselinetm = [-400 -200];

% wavelet and FFT parameters
time          = -1:1/EEG.srate:1;
half_wavelet  = (length(time)-1)/2;
num_cycles    = logspace(log10(4),log10(8),length(freqs2use));
n_wavelet     = length(time);
n_data        = EEG.pnts*EEG.trials;
n_convolution = n_wavelet+n_data-1;

% time in indices
times2saveidx = dsearchn(EEG.times',times2save');
baselineidx   = dsearchn(times2save',baselinetm');

chanidx    = zeros(1,2); % always initialize!
chanidx(1) = find(strcmpi(channel1,{EEG.chanlocs.labels}));
chanidx(2) = find(strcmpi(channel2,{EEG.chanlocs.labels}));

% initialize
ispc = zeros(length(freqs2use),length(times2save));
ps   = zeros(length(freqs2use),length(times2save));

% data FFTs
data_fft1 = fft(reshape(EEG.data(chanidx(1),:,:),1,n_data),n_convolution);
data_fft2 = fft(reshape(EEG.data(chanidx(2),:,:),1,n_data),n_convolution);

for fi=1:length(freqs2use)

    % create wavelet and take FFT
    s = num_cycles(fi)/(2*pi*freqs2use(fi));
    wavelet_fft = fft( exp(2*1i*pi*freqs2use(fi).*time) .* exp(-time.^2./(2*(s^2))) ,n_convolution);

    % phase angles from channel 1 via convolution
    convolution_result_fft = ifft(wavelet_fft.*data_fft1,n_convolution);
    convolution_result_fft = convolution_result_fft(half_wavelet+1:end-half_wavelet);
    phase_sig1 = angle(reshape(convolution_result_fft,EEG.pnts,EEG.trials));

    % phase angles from channel 2 via convolution
    convolution_result_fft = ifft(wavelet_fft.*data_fft2,n_convolution);
    convolution_result_fft = convolution_result_fft(half_wavelet+1:end-half_wavelet);
    phase_sig2 = angle(reshape(convolution_result_fft,EEG.pnts,EEG.trials));

    % phase angle differences
    phase_diffs = phase_sig1-phase_sig2;

    % compute ICPS over trials
    ps(fi,:) = abs(mean(exp(1i*phase_diffs(times2saveidx,:)),2));

    % compute time window in indices for this frequency
    time_window_idx = round((1000/freqs2use(fi))*timewindow(fi)/(1000/EEG.srate));
%     time_window_idx = round(300/(1000/EEG.srate)); % set 300 to 100 for figure 3c/d

    for ti=1:length(times2save)

        % compute phase synchronization
        phasesynch = abs(mean(exp(1i*phase_diffs(times2saveidx(ti)-time_window_idx:times2saveidx(ti)+time_window_idx,:)),1));

        % average over trials
        ispc(fi,ti) = mean(phasesynch);
    end
end % end frequency loop

figure
contourf(times2save,freqs2use,ispc-repmat(mean(ispc(:,baselineidx(1):baselineidx(2)),2),1,size(ispc,2)),20,'linecolor','none')
set(gca,'clim',[-.08 .08],'yscale','log','ytick',round(logspace(log10(freqs2use(1)),log10(freqs2use(end)),8)))
xlabel('Time (ms)'), ylabel('Frequency (Hz)')

figure
plot(freqs2use,(1000./freqs2use).*timewindow*2,'o-','markerface','k')
hold on
plot(freqs2use,(1000./freqs2use).*timewindow(1)*2,'ro-','markerface','m')
ylabel('Window width (ms)'), xlabel('Frequency (Hz)')
legend({'variable windows';'fixed 3*f window'})

%% Figure 26.4

figure
for i=1:8
    subplot(8,1,i)
    plot(phase_sig1(1:200,i)-phase_sig2(1:200,i))
end

figure
subplot(121)
polar(repmat(phase_sig1(1:200,1)-phase_sig2(1:200,1),2,1),repmat([0 1]',200,1),'k');
title('Phase angle differences over time')

subplot(122)
polar(repmat(phase_sig1(100,1:i)-phase_sig2(100,1:i),2,1),repmat([0 1]',1,i),'k');
title('Phase angle differences over trials')

%% Figure 26.5

figure
contourf(times2save,freqs2use,bsxfun(@minus,ps,mean(ps(:,baselineidx(1):baselineidx(2)),2)),20,'linecolor','none')
set(gca,'clim',[-.2 .2],'yscale','log','ytick',round(logspace(log10(freqs2use(1)),log10(freqs2use(end)),8)),'xlim',[-300 800])
xlabel('Time (ms)'), ylabel('Frequency (Hz)')

%% figure 26.6

time2use = 300; % ms
niterations = 50; % you can decrease this to make the code a bit faster

% initialize
ispcByNandF = zeros(length(freqs2use),EEG.trials);
time2useidx = dsearchn(times2save',time2use);

% data FFTs
data_fft1 = fft(reshape(EEG.data(chanidx(1),:,:),1,n_data),n_convolution);
data_fft2 = fft(reshape(EEG.data(chanidx(2),:,:),1,n_data),n_convolution);

for fi=1:length(freqs2use)

    % create wavelet and take FFT
    s = num_cycles(fi)/(2*pi*freqs2use(fi));
    wavelet_fft = fft( exp(2*1i*pi*freqs2use(fi).*time) .* exp(-time.^2./(2*(s^2))) ,n_convolution);

    % phase angles from channel 1 via convolution
    convolution_result_fft = ifft(wavelet_fft.*data_fft1,n_convolution);
    convolution_result_fft = convolution_result_fft(half_wavelet+1:end-half_wavelet);
    phase_sig1 = angle(reshape(convolution_result_fft,EEG.pnts,EEG.trials));

    % phase angles from channel 2 via convolution
    convolution_result_fft = ifft(wavelet_fft.*data_fft2,n_convolution);
    convolution_result_fft = convolution_result_fft(half_wavelet+1:end-half_wavelet);
    phase_sig2 = angle(reshape(convolution_result_fft,EEG.pnts,EEG.trials));

    % phase angle differences
    phase_diffs = phase_sig1-phase_sig2;

    for n=1:EEG.trials
        % multiple iterations to select different random sets of trials
        for iteri=1:niterations
            trials2use = randsample(EEG.trials,n);
            ispcByNandF(fi,n) = ispcByNandF(fi,n) + mean(abs(mean(exp(1i*phase_diffs(times2saveidx(time2useidx)-time_window_idx:times2saveidx(time2useidx)+time_window_idx,trials2use)),2)),1);
        end
    end
end

figure
plot(1:EEG.trials,ispcByNandF/iteri)
xlabel('Trials')
ylabel('ICPS-trials')

%% Figure 26.7

% initialize
data4test  = zeros(2,EEG.pnts,EEG.trials);
data4power = zeros(2,EEG.pnts,EEG.trials);

amp_mod = 0.00001;

for triali=1:EEG.trials
    % each trial is a random channel and trial
    trialdata1 = EEG.data(chanidx(1),:,triali);
    trialdata2 = EEG.data(chanidx(2),:,triali);

    % Un/comment the next line of code for band-pass filtered data.
    % This uses the eegfilt function, which is part of the eeglab toolbox.
    % You can also replace this function with your preferred filter method (chapter 14).
    trialdata1 = eegfilt(double(trialdata1),EEG.srate,10,20);
    trialdata2 = eegfilt(double(trialdata2),EEG.srate,10,20);

    % phase angle differences, with and without amplitude dampening
    data4test(1,:,triali) = angle(hilbert(trialdata1)) - angle(hilbert(trialdata2));
    data4test(2,:,triali) = angle(hilbert(trialdata1)) - angle(hilbert(trialdata2*amp_mod));

    data4power(1,:,triali) = abs(hilbert(trialdata2)).^2;
    data4power(2,:,triali) = abs(hilbert(trialdata2*amp_mod)).^2;
end

% compute ITPC
ispc_nomod = abs(mean(exp(1i*data4test(1,:,:)),3));
ispc_mod   = abs(mean(exp(1i*data4test(2,:,:)),3));

% compute power
power = squeeze(mean(data4power,3));

% plot!
figure
subplot(311)
plot(EEG.times,trialdata2)
hold on
plot(EEG.times,trialdata2*amp_mod,'r')
title('Amplitude modulator')

subplot(312)
plot(EEG.times,data4test(1,:,10))
hold on
plot(EEG.times,data4test(2,:,10),'r')
axis tight
set(gca,'ytick',-2*pi:pi:2*pi)
title('Example trials')

subplot(313)
plot(EEG.times,ispc_mod,'ro')
hold on
h=plotyy(EEG.times,ispc_nomod,EEG.times,squeeze(mean(data4power(1,:,:),3)));
legend({'amplitude modulation';'no amp mod'})
set(h(2),'ylim',[12 36])
set(h(1),'ylim',[0 .4])
xlabel('Time (ms)'), ylabel('ICPS')
title('ICPS')

figure
subplot(121)
plot(power(1,:),ispc_nomod,'.')
axis square
xlabel('Power'), ylabel('ICPS')
title('non-modulated power')

subplot(122)
plot(power(2,:),ispc_mod,'.')
axis square
xlabel('Power'), ylabel('ICPS')
title('modulated power')

%% figure 26.8

% select channels
channel1 = 'fz';
channel2 = 'o1';

% wavelet and FFT parameters
time          = -1:1/EEG.srate:1;
half_wavelet  = (length(time)-1)/2;
n_wavelet     = length(time);
n_data        = EEG.pnts*EEG.trials;
n_convolution = n_wavelet+n_data-1;

chanidx    = zeros(1,2); % always initialize!
chanidx(1) = find(strcmpi(channel1,{EEG.chanlocs.labels}));
chanidx(2) = find(strcmpi(channel2,{EEG.chanlocs.labels}));

% data FFTs
data_fft1 = fft(reshape(EEG.data(chanidx(1),:,:),1,n_data),n_convolution);
data_fft2 = fft(reshape(EEG.data(chanidx(2),:,:),1,n_data),n_convolution);

% initialize
spectcoher = zeros(length(freqs2use),length(times2save));

for fi=1:length(freqs2use)

    % create wavelet and take FFT
    s = num_cycles(fi)/(2*pi*freqs2use(fi));
    wavelet_fft = fft( exp(2*1i*pi*freqs2use(fi).*time) .* exp(-time.^2./(2*(s^2))) ,n_convolution);

    % phase angles from channel 1 via convolution
    convolution_result_fft = ifft(wavelet_fft.*data_fft1,n_convolution);
    convolution_result_fft = convolution_result_fft(half_wavelet+1:end-half_wavelet);
    sig1 = reshape(convolution_result_fft,EEG.pnts,EEG.trials);

    % phase angles from channel 2 via convolution
    convolution_result_fft = ifft(wavelet_fft.*data_fft2,n_convolution);
    convolution_result_fft = convolution_result_fft(half_wavelet+1:end-half_wavelet);
    sig2 = reshape(convolution_result_fft,EEG.pnts,EEG.trials);

    % compute power and cross-spectral power
    spec1 = mean(sig1.*conj(sig1),2);
    spec2 = mean(sig2.*conj(sig2),2);
    specX = abs(mean(sig1.*conj(sig2),2)).^2;

    % alternative notation for the same procedure, using the Euler-like expression: Me^ik
    %spec1 = mean(abs(sig1).^2,2);
    %spec2 = mean(abs(sig2).^2,2);
    %specX = abs(mean( abs(sig1).*abs(sig2) .* exp(1i*(angle(sig1)-angle(sig2))) ,2)).^2;

    % compute spectral coherence, using only requested time points
    spectcoher(fi,:) = specX(times2saveidx)./(spec1(times2saveidx).*spec2(times2saveidx));

    % yet another equivalent notation, just FYI
    %spec1 = sum(sig1.*conj(sig1),2);
    %spec2 = sum(sig2.*conj(sig2),2);
    %specX = sum(sig1.*conj(sig2),2);
    %spectcoher(fi,:) = abs(specX(times2saveidx)./sqrt(spec1(times2saveidx).*spec2(times2saveidx))).^2;

    % imaginary coherence
    %spec1 = sum(sig1.*conj(sig1),2);
    %spec2 = sum(sig2.*conj(sig2),2);
    %specX = sum(sig1.*conj(sig2),2);
    % spectcoher(fi,:) = abs(imag(specX(times2saveidx)./sqrt(spec1(times2saveidx).*spec2(times2saveidx))));
end

figure
subplot(121)
contourf(times2save,freqs2use,spectcoher,20,'linecolor','none') %
set(gca,'clim',[0 .2],'yscale','log','ytick',round(logspace(log10(freqs2use(1)),log10(freqs2use(end)),8)),'xlim',[times2save(1) times2save(end)])
title('"Raw" spectral coherence')

subplot(122)
contourf(times2save,freqs2use,spectcoher-repmat(mean(spectcoher(:,baselineidx(1):baselineidx(2)),2),1,size(spectcoher,2)),20,'linecolor','none') %
set(gca,'clim',[-.1 .1],'yscale','log','ytick',round(logspace(log10(freqs2use(1)),log10(freqs2use(end)),8)),'xlim',[times2save(1) times2save(end)])
xlabel('Time (ms)'), ylabel('Frequency (Hz)')
title('Baseline-subtracted spectral coherence')

%% Figure 26.9

% number of "trials"
n = 100;

figure

subplot(221)
phases = rand(n,1)*pi;
polar([phases; phases],repmat([0 1]',n,1),'k');
pli  = abs(mean(sign(imag(exp(1i*phases)))));
ispc = abs(mean(exp(1i*phases)));
title([ 'PLI=' num2str(pli) ', ISPC=' num2str(ispc) ])

subplot(222)
phases = phases-pi/2;
polar([phases; phases],repmat([0 1]',n,1),'k');
pli  = abs(mean(sign(imag(exp(1i*phases)))));
ispc = abs(mean(exp(1i*phases)));
title([ 'PLI=' num2str(pli) ', ISPC=' num2str(ispc) ])

subplot(223)
phases = rand(n,1)/2+pi/3+.25;
polar([phases; phases],repmat([0 1]',n,1),'k');
pli  = abs(mean(sign(imag(exp(1i*phases)))));
ispc = abs(mean(exp(1i*phases)));
title([ 'PLI=' num2str(pli) ', ISPC=' num2str(ispc) ])

subplot(224)
phases = phases-pi/2;
polar([phases; phases],repmat([0 1]',n,1),'k');
pli  = abs(mean(sign(imag(exp(1i*phases)))));
ispc = abs(mean(exp(1i*phases)));
title([ 'PLI=' num2str(pli) ', ISPC=' num2str(ispc) ])

%% Figure 26.10

% select channels
channel1 = 'fz';
channel2 = 'o1';

% specify some time-frequency parameters
freqs2use  = logspace(log10(4),log10(30),15); % 4-30 Hz in 15 steps
times2save = -400:10:800;
timewindow = linspace(1.5,3,length(freqs2use)); % number of cycles on either end of the center point (1.5 means a total of 3 cycles))
baselinetm = [-400 -200];

% wavelet and FFT parameters
time          = -1:1/EEG.srate:1;
half_wavelet  = (length(time)-1)/2;
num_cycles    = logspace(log10(4),log10(8),length(freqs2use));
n_wavelet     = length(time);
n_data        = EEG.pnts*EEG.trials;
n_convolution = n_wavelet+n_data-1;

% time in indices
times2saveidx = dsearchn(EEG.times',times2save');
baselineidxF  = dsearchn(EEG.times',baselinetm');  % for the full temporal resolution data (thanks to Daniel Roberts for finding/reporting this bug here!)
baselineidx   = dsearchn(times2save',baselinetm'); % for the temporally downsampled data

chanidx = zeros(1,2); % always initialize!
chanidx(1) = find(strcmpi(channel1,{EEG.chanlocs.labels}));
chanidx(2) = find(strcmpi(channel2,{EEG.chanlocs.labels}));

% data FFTs
data_fft1 = fft(reshape(EEG.data(chanidx(1),:,:),1,n_data),n_convolution);
data_fft2 = fft(reshape(EEG.data(chanidx(2),:,:),1,n_data),n_convolution);

% initialize
ispc    = zeros(length(freqs2use),EEG.pnts);
pli     = zeros(length(freqs2use),EEG.pnts);
wpli    = zeros(length(freqs2use),EEG.pnts);
dwpli   = zeros(length(freqs2use),EEG.pnts);
dwpli_t = zeros(length(freqs2use),length(times2save));
ispc_t  = zeros(length(freqs2use),length(times2save));

for fi=1:length(freqs2use)

    % create wavelet and take FFT
    s = num_cycles(fi)/(2*pi*freqs2use(fi));
    wavelet_fft = fft( exp(2*1i*pi*freqs2use(fi).*time) .* exp(-time.^2./(2*(s^2))) ,n_convolution);

    % phase angles from channel 1 via convolution
    convolution_result_fft = ifft(wavelet_fft.*data_fft1,n_convolution);
    convolution_result_fft = convolution_result_fft(half_wavelet+1:end-half_wavelet);
    sig1 = reshape(convolution_result_fft,EEG.pnts,EEG.trials);

    % phase angles from channel 2 via convolution
    convolution_result_fft = ifft(wavelet_fft.*data_fft2,n_convolution);
    convolution_result_fft = convolution_result_fft(half_wavelet+1:end-half_wavelet);
    sig2 = reshape(convolution_result_fft,EEG.pnts,EEG.trials);

    % cross-spectral density
    cdd = sig1 .* conj(sig2);

    % ISPC
    ispc(fi,:) = abs(mean(exp(1i*angle(cdd)),2)); % note: equivalent to ispc(fi,:) = abs(mean(exp(1i*(angle(sig1)-angle(sig2))),2));

    % take imaginary part of signal only
    cdi = imag(cdd);

    % phase-lag index
    pli(fi,:)  = abs(mean(sign(imag(cdd)),2));

    % weighted phase-lag index (eq. 8 in Vink et al. NeuroImage 2011)
    wpli(fi,:) = abs( mean( abs(cdi).*sign(cdi) ,2) )./mean(abs(cdi),2);

    % debiased weighted phase-lag index (shortcut, as implemented in fieldtrip)
    imagsum      = sum(cdi,2);
    imagsumW     = sum(abs(cdi),2);
    debiasfactor = sum(cdi.^2,2);
    dwpli(fi,:)  = (imagsum.^2 - debiasfactor)./(imagsumW.^2 - debiasfactor);

    % compute time window in indices for this frequency
    time_window_idx = round((1000/freqs2use(fi))*timewindow(fi)/(1000/EEG.srate));

    for ti=1:length(times2save)
        imagsum        = sum(cdi(times2saveidx(ti)-time_window_idx:times2saveidx(ti)+time_window_idx,:),1);
        imagsumW       = sum(abs(cdi(times2saveidx(ti)-time_window_idx:times2saveidx(ti)+time_window_idx,:)),1);
        debiasfactor   = sum(cdi(times2saveidx(ti)-time_window_idx:times2saveidx(ti)+time_window_idx,:).^2,1);
        dwpli_t(fi,ti) = mean((imagsum.^2 - debiasfactor)./(imagsumW.^2 - debiasfactor));

        % compute phase synchronization
        phasesynch     = abs(mean(exp(1i*angle(cdd(times2saveidx(ti)-time_window_idx:times2saveidx(ti)+time_window_idx,:))),1));
        ispc_t(fi,ti)  = mean(phasesynch);
    end
end

% baseline subtraction from all measures
ispc    = bsxfun(@minus,ispc,mean(ispc(:,baselineidxF(1):baselineidxF(2)),2)); % not plotted in the book, but you can plot it for comparison with PLI
ispc_t  = bsxfun(@minus,ispc_t,mean(ispc_t(:,baselineidx(1):baselineidx(2)),2));
pli     = bsxfun(@minus,pli,mean(pli(:,baselineidxF(1):baselineidxF(2)),2));
dwpli   = bsxfun(@minus,dwpli,mean(dwpli(:,baselineidxF(1):baselineidxF(2)),2));
dwpli_t = bsxfun(@minus,dwpli_t,mean(dwpli_t(:,baselineidx(1):baselineidx(2)),2));

figure
subplot(221)
contourf(times2save,freqs2use,pli(:,times2saveidx),40,'linecolor','none')
set(gca,'clim',[-.3 .3],'yscale','log','ytick',round(logspace(log10(freqs2use(1)),log10(freqs2use(end)),8)))
title('PLI over trials')

subplot(222)
contourf(times2save,freqs2use,dwpli(:,times2saveidx),40,'linecolor','none')
set(gca,'clim',[-.2 .2],'yscale','log','ytick',round(logspace(log10(freqs2use(1)),log10(freqs2use(end)),8)))
title('dWPLI over trials')

subplot(223)
contourf(times2save,freqs2use,ispc_t,40,'linecolor','none')
set(gca,'clim',[-.1 .1],'yscale','log','ytick',round(logspace(log10(freqs2use(1)),log10(freqs2use(end)),8)))
title('ICPS over time')

subplot(224)
contourf(times2save,freqs2use,dwpli_t,40,'linecolor','none')
set(gca,'clim',[-.1 .1],'yscale','log','ytick',round(logspace(log10(freqs2use(1)),log10(freqs2use(end)),8)))
title('dWPLI over time')

%% Figure 26.11

trial2plot = 10; % any trial between 1 and 99 (book uses trial 10)
center_freq = 4.6; % Hz (book uses 4.6)

% create wavelet and take FFT
s = 4.5/(2*pi*center_freq);
wavelet_fft = fft( exp(2*1i*pi*center_freq.*time) .* exp(-time.^2./(2*(s^2))) ,n_convolution);
% phase angles from channel 1 via convolution
convolution_result_fft = ifft(wavelet_fft.*data_fft1,n_convolution);
convolution_result_fft = convolution_result_fft(half_wavelet+1:end-half_wavelet);
sig1 = reshape(convolution_result_fft,EEG.pnts,EEG.trials);
% phase angles from channel 2 via convolution
convolution_result_fft = ifft(wavelet_fft.*data_fft2,n_convolution);
convolution_result_fft = convolution_result_fft(half_wavelet+1:end-half_wavelet);
sig2 = reshape(convolution_result_fft,EEG.pnts,EEG.trials);
% cross-spectral density
xsd  = sig1 .* conj(sig2);
xsdi = imag(xsd);

dwpli = zeros(size(EEG.times));
ispc  = zeros(size(EEG.times));

[junk,animate_start] = min(abs(EEG.times-0));
[junk,animate_stop]  = min(abs(EEG.times-1000));

time_window_idx = round(100*timewindow(1)/(1000/EEG.srate));

figure
subplot(121)
hpol = polar(repmat(angle(xsd(animate_start:animate_start+time_window_idx-1,trial2plot)),1,2)',[zeros(time_window_idx,1) ones(time_window_idx,1)]','k-o');
subplot(122)
hplo2 = plot(EEG.times,0,'r');
hold on
hplo1 = plot(EEG.times,0,'b');

for idx=animate_start:animate_stop

    % update angles
    for i=1:length(hpol)
        set(hpol(i),'XData',[0; cos(angle(xsd(idx+i,trial2plot)))],'YData',[0; sin(angle(xsd(idx+i,trial2plot)))]);
    end
    title([ num2str(round(EEG.times(idx))) '-' num2str(round(EEG.times(idx+i))) ' ms' ])

    % compute ICPS and dwPLI
    ispc(idx) = abs(mean(exp(1i*angle(xsd(idx:idx+i,trial2plot))),1));

    imagsum        = sum(xsdi(idx:idx+i,trial2plot),1);
    imagsumW       = sum(abs(xsdi(idx:idx+i,trial2plot)),1);
    debiasfactor   = sum(xsdi(idx:idx+i,trial2plot).^2,1);
    dwpli(idx) = mean((imagsum.^2 - debiasfactor)./(imagsumW.^2 - debiasfactor));

    set(hplo1,'XData',EEG.times(1:idx),'YData',ispc(1:idx));
    set(hplo2,'XData',EEG.times(1:idx),'YData',dwpli(1:idx));
    set(gca,'xlim',EEG.times([animate_start animate_stop]),'ylim',[-.1 1.1])
    axis square

    pause(0.01)
end

%% Figure 26.12

% This figure is generated in the code below.

%% Figure 26.13

% generate inline functions (small functions that you define without being
% saved as general Matlab functions)
vtest  = inline('n.*icpcmag*cos(val).*sqrt(2./n)');
gvtest = inline('n.*(icpcmag*exp((-(val).^2)./(4.*pi./n)).*(sqrt(2./n)))');

% Since initially writing this code, Matlab decided to make the inline
% function obsolete in future versions. The following two lines produce
% the identical 'anonymous functions' as the previous two lines.
%vtest  = @(icpcmag,n,val) n.*icpcmag*cos(val).*sqrt(2./n);
%gvtest = @(icpcmag,n,val) n.*(icpcmag*exp((-(val).^2)./(4.*pi./n)).*(sqrt(2./n)));

% figure
clf
subplot(221)
n = 2:100;
plot(n,1-normcdf(vtest(.3,n,pi/10)))
hold on
plot(n,1-normcdf(gvtest(.3,n,pi/10)),'m')
legend({'v-test';'gv-test'})
xlabel('Number of points'), ylabel('P-value')
set(gca,'ylim',[0 .6])
title('angle = pi/10')

subplot(222)
plot(n,1-normcdf(vtest(.3,n,pi/3)))
hold on
plot(n,1-normcdf(gvtest(.3,n,pi/3)),'m')
legend({'v-test';'gv-test'})
xlabel('Number of points'), ylabel('P-value')
set(gca,'ylim',[0 .6])
title('angle = pi/3')

subplot(223)
x=linspace(-pi,pi,50);
n=15;
polar(x,1-normcdf(vtest(.3,n,x-0)))
hold on
polar(x,1-normcdf(gvtest(.3,n,x-0)),'m')
title([ 'N=' num2str(n) ])

subplot(224)
n=600;
polar(x,1-normcdf(vtest(.3,n,x-0)))
hold on
polar(x,1-normcdf(gvtest(.3,n,x-0)),'m')
set(gca,'xtick',round((-pi:pi/4:pi)*100)/100)
title([ 'N=' num2str(n) ])

% number of simulated data points
numUsims = 10000;

u = zeros(2,numUsims);

for i=1:numUsims

    % make some noise
    fake_phase_data = rand(2,EEG.pnts)*pi*2-pi;

    % compute ispc
    ispc_mag = abs  (mean(exp(1i*(diff(fake_phase_data,1)))));
    ispc_phs = angle(mean(exp(1i*(diff(fake_phase_data,1)))));

    % compute statistics
    u(1,i) = vtest (ispc_mag,EEG.pnts,ispc_phs-0);
    u(2,i) = gvtest(ispc_mag,EEG.pnts,ispc_phs-0);
end

% This figure is also figure 26.12 but with no log-scaling
figure
for i=1:2
    subplot(1,2,i)

    [y,x]=hist(u(i,:),100);
    h=bar(x,log10(y),'histc');
    set(h,'linestyle','none')

    title([ num2str(100*sum((1-normcdf(u(i,:)))<.05)/length(u)) '% false positive' ])
end

nrange    = 10:300; % here n is number of datapoints
ispcrange = .05:.01:.7;
pvalmat   = zeros(2,length(nrange),length(ispcrange));

for ni=1:length(nrange)
    for mi=1:length(ispcrange)

        n = nrange(ni);

        pvalmat(1,ni,mi) = 1-normcdf( vtest(ispcrange(mi),nrange(ni),pi/5));
        pvalmat(2,ni,mi) = 1-normcdf(gvtest(ispcrange(mi),nrange(ni),pi/5));
    end
end

figure
subplot(121)
imagesc(ispcrange,nrange,squeeze(pvalmat(1,:,:))), axis xy,
set(gca,'clim',[0 .5])
xlabel('ICPS strength'), ylabel('N')
title('v-test')

subplot(122)
imagesc(ispcrange,nrange,squeeze(pvalmat(2,:,:))), axis xy,
title('gv-test')
xlabel('ICPS strength'), ylabel('N')
set(gca,'clim',[0 .5])

%% end.


%% patchCurvature
% Below is a demonstration of the features of the |patchCurvature| function

%% Syntax
% |[Vd,Fd,Fds]=patchCurvature(V,F);|

%% Description
% Computes curvature metrics for the patch data defined by the faces F and
% the vertices V.

%% Examples

%%
clear; close all; clc;

%%
% Plot settings
cMap=warmcold(250);

%%

[F,V]=graphicsModels(9);
% [F,V]=stanford_bunny;
% [F,V]=tri2quad(F,V);

%% Compute curvature

[U_min,U_max,C_min,C_max,C_mean,C_gauss] = patchCurvature(F,V);

%% Visualize curvature on mesh

% Compute plot variables
C_min_V=faceToVertexMeasure(F,V,C_min); %Vertex data for interpolated shading
C_max_V=faceToVertexMeasure(F,V,C_max); %Vertex data for interpolated shading
VN=patchCentre(F,V); %Element centres used for vector origins
vecPlotSize=mean(patchEdgeLengths(F,V)); %Vector plotting size

% Visualize
cFigure;
subplot(1,2,1); hold on;
title('C_{min}');
hp=gpatch(F,V,C_min_V,'none',0.9);
hp.FaceColor='interp';
colormap(gca,cMap); colorbar;
quiverVec(VN,U_min,vecPlotSize,'k');
axisGeom;
c=max(abs(C_min(:)));
caxis(0.25*[-c c]);
camlight headlight;

subplot(1,2,2); hold on;
title('C_{max}');
hp=gpatch(F,V,C_max_V,'none',0.9);
hp.FaceColor='interp';
quiverVec(VN,U_max,vecPlotSize,'k');
colormap(gca,cMap); colorbar;
axisGeom;
c=max(abs(C_max(:)));
caxis(0.25*[-c c]);
camlight headlight;

drawnow;

%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


%GSP_DEMO Tutorial on the GSPBox
%
%   In this demo, we are going to show the basic operations of the GSPBox.
%   To lauch the toolbox, just go into the repository where the GSPBox was
%   extracted and type:
%
%           gsp_start;
%
%   A banner will popup telling you that everything happens correctly. To
%   speedup some processing, you might want to compile some mexfile. Refer
%   to |gsp_make| for more informations. However, if the compilation is not
%   working on your computer, keep quiet, everything should still work and
%   most of the routine are implemented only in matlab.
%
%   Most likely, the first thing you would like to do is to create a graph.
%   To do so, you only need the adjacendy or the weight matrix $W$. Once
%   you have it, you can construct a graph using::
%
%           G = gsp_graph(W);
%
%   This function will create a full structure ready to be used with the
%   toolbox. To know a bit more about what is in this structure, you can
%   refer to the help of the function |gsp_graph_default_parameters|.
%
%   The GSPBox contains also a list of graph generators. To see a full list
%   of these graphs, type:::
%
%           help graphs
%
%   For this demo, we will use the graph |gsp_logo|. You can load it
%   using:::
%
%           G = gsp_logo
%
%   Here observe the attribute of the structure *G*.
%
%   * *G.W*: Weight matrix
%   * *G.A*: Adacency matrix
%   * *G.N*: Number of nodes
%   * *G.type*: Type of graph
%   * *G.directed*: 1 if the graph is directed, 0 if not
%   * *G.lap_type*: Laplacian type
%   * *G.d*: Degree vector
%   * *G.Ne*: Number of edges
%   * *G.coords*: Coordinates of the vertices
%   * *G.plotting*: Plotting parameters
%
%   In the folder 'plotting', the GSPBox contains some plotting routine.
%   For instance, we can plot a graph using::
%
%           gsp_plot_graph(G);
%
%   .. figure::
%
%      GSP graph
%
%      This figure shows the result of the command 'gsp_plot_graph(G)'
%
%   Wonderful! Isn't it? Now, let us start to analyse this graph. To compute
%   graph Fourier transform or exact graph filtering, you need to
%   precompute the Fourier basis of the graph. This operation could be
%   relatively long since it involves a full diagonalization of the
%   Laplacian. Don't worry, you do not need to perform this operation to
%   filter signals on graph. The fourier basis is computed by::
%
%           G = gsp_compute_fourier_basis(G);
%
%   The function |gsp_compute_fourier_basis| add two new fields to the
%   structure *G*:
%
%   * *G.U*: The eigenvectors of the Fourier basis
%   * *G.e*: The eigenvalues
%
%   The fourier eigenvectors does look like a sinusoide on the graph. Let's
%   plot the second and the third ones. (The first one is constant!)::
%
%           gsp_plot_signal(G,G.U(:,2));
%           title('Second eigenvector')
%           subplot(212)
%           gsp_plot_signal(G,G.U(:,3));
%           title('Third eigenvector')
%
%   .. figure::
%
%      Eigenvectors
%
%
%
%   Now, we are going to show a basic filtering operation. Filters are usually
%   defined in the spectral domain. To define the following filter
%
%   ..   h(x) = 1/(1+tau*x),
%
%   .. math:: h(x) =\frac{1}{1+\tau x},
%
%   just write in Matlab::
%
%           tau = 1;
%           h = @(x) 1./(1+tau*x);
%
%   Hint: You can define filterbank using cell array!
%
%   Let's display this filter::
%
%           gsp_plot_filter(G,h);
%
%   .. figure::
%
%      Low pass filter $h$
%
%      The filter $h$ is plotted along all the spectrum of the graph.
%      The black cross are the eigenvalues of the Laplacian. They are the
%      points where the continuous filter will be evaluated to create a
%      discrete filter.
%
%   To apply the filter to a given signal, you only need to run a single
%   function::
%
%           % Create a signal
%           f = zeros(G.N,1);
%           f(G.info.idx_g) = -1;
%           f(G.info.idx_s) = 1;
%           f(G.info.idx_p) = -0.5;
%           f = f + 0.3*randn(G.N,1);
%           % Remove the noise
%           f2 = gsp_filter(G,h,f);
%
%   `gsp_filter` is actually a shortcut to |gsp_filter_analysis|.
%   `gsp_filter_analysis` performs the analysis operator associated to a
%   filterbank. See the |gsp_demo_wavelet| for more information.
%
%   Finnaly, we display the result of this low pass filtering on the graph::
%
%           figure;
%           subplot(211)
%           gsp_plot_signal(G,f);
%           title('Signal with noise')
%           subplot(212)
%           gsp_plot_signal(G,f2);
%           title('Signal denoised');
%
%   .. figure::
%
%      Result of filtering
%
%      The noise is largely removed thanks to the filter. However, some
%      energy is diffused between the letters. This is the typical
%      behaviour of a low pass filter.
%
%   Enjoy the GSPBOX !
%

% Author: Nathanael Perraudin
% Date : 14 August 2014

clear;
close all;

G = gsp_logo;

% display the graph
figure;
gsp_plot_graph(G);

%% Compute the Fourier basis

G = gsp_compute_fourier_basis(G);

% Display an eigenvector
figure;
subplot(211)
gsp_plot_signal(G,G.U(:,2));
title('Second eigenvector')
subplot(212)
gsp_plot_signal(G,G.U(:,3));
title('Third eigenvector')

%% Create a signal

f = zeros(G.N,1);
f(G.info.idx_g) = -1;
f(G.info.idx_s) = 1;
f(G.info.idx_p) = -0.5;
f = f + 0.3*randn(G.N,1);

%% Define a low pass filter
tau = 1;
h = @(x) 1./(1+tau*x);

figure
gsp_plot_filter(G,h);
title('Filter h')

%% Perform the filtering operation
f2 = gsp_filter(G,h,f);
% f2 = gsp_filter_analysis(G,h,f);

% Display the result
figure;
subplot(211)
gsp_plot_signal(G,f);
title('Signal with noise')
subplot(212)
gsp_plot_signal(G,f2);
title('Signal denoised');


function [dyc, dyt]=hamfilter(X,h,d,ck,fig,timeplot, nameplot)

% local projections (direct  forecast) to  perform detrending
% regressions
% y(t+h)= a*y(t)+b*y(t-1)+c*y(t-2)+...+d*y(t-d)+ e(t+h)
% cycle  is  e(t+h)
% trend  is  hat(a)*y(t)+hat(b)*y(t-1)+hat(c)*y(t-2)+...+hat(d)*y(t-d)

% h= horizon of  the  projection
% d= number  of  lags  used
% ck if=1 constant  if =0 no constant in  the projection

% dyc = estimated cycle
% dyt = estimated trend

[enddT,QQ]=size(X);
yc=zeros(enddT,QQ); yt=zeros(enddT,QQ);
R=[];
T = 1:1:enddT;
time = T;
if nargin > 5
    time =timeplot;
end
if nargin > 6
    titleplot = nameplot;
    if length(nameplot) ~= size(X,2)
        error('nameplot size shold be the same as the column of Y')
    end
else
    for v = 1 : size(X,2)
        eval(['titleplot{'   num2str(v) '} =  ''Var' num2str(v) ''';'])
    end
end

for qq=1:QQ
    yh=squeeze(X(d+h:enddT,qq)); %    independent  variable
    if  ck==1
        R=ones(enddT-d-h+1,1);     % constant
    end

    for  jj=1:d
        r=squeeze(X(d+1-jj:enddT-h+1-jj,qq));
        R=[R r];  % dependent  variables
    end

    yc(d+h:enddT,qq) = yh - R*((R'*R)\(R'*yh)); % cycle
    yt(d+h:enddT,qq) = R*((R'*R)\(R'*yh));        % trend

    if  fig==1
        subplot(2,1,1)
        %plot(time(d+h:enddT),yh(1:enddT-d-h,1),'r', 'linewidth',2);hold  on;
        plot(time(d+h:enddT),X(d+h:enddT,qq),'r', 'linewidth',2);hold  on;
        plot(time(d+h:enddT),yt(d+h:enddT,qq),'k--','linewidth',2);hold off; axis  tight;
        legend('data', 'Hamil trend')
        title(titleplot(qq))
        subplot(2,1,2)
        plot(time(d+h:enddT),yc(d+h:enddT,qq),'b', 'linewidth',2);
        legend('Hamil cycle')
        pause
    end
end
dyc=yc;
dyt=yt;
end


%% DEMO_stent_hexahedral_sweeping_02
% Below is a demonstration for:
%
% * Creating a hexahedral mesh for a vascular stent by sweeping allong a
% curve and copying over the segments.

%% Keywords
% * Sweeping, sweepLoft
% * Hexahedral mesh
% * stent, vascular
% * Exporting Abaqus, .inp

%%
clear; close all; clc;

%%
% plot settings

fontSize=25;
markerSize=10;
lineWidth=3;

%% Contol parameters

controlParameterSet.stentRadius=3; %The outer radius of the stent
controlParameterSet.numPeriodsWave=10; %The number of periods to use for a sinusoidal modulation
numStepsPeriod=100; %Number of sweeping steps allong a single period segment for sweeping
controlParameterSet.stentSectionHeight=0.1; %Height of the stent wire
controlParameterSet.stentSectionWidth=0.1; %Width of the stent wire
controlParameterSet.numStepsCircumference=(controlParameterSet.numPeriodsWave*numStepsPeriod)+1; %Number of sweeping steps across curve
controlParameterSet.overSampleFactorCurve=10; %Oversample factor curve
controlParameterSet.numSplitSteps_axial=1;
controlParameterSet.numSplitSteps_inward=1;
controlParameterSet.plotOn=0;
% controlParameterSet.waveAmplitude=0.9; %Amplitude of the sinusoidal modulation

sheetLayerThickness=0.025;
numStepsSheet=1;

%%

numSegments=8;
waveAmplitudes=0.6*ones(1,numSegments);
waveAmplitudes(2)=0.9;
offsetLevels=waveAmplitudes*2;

offSetTotal=0;

cFigure; hold on;
title('Stent hexahedral mesh','fontSize',fontSize);
colormap(gjet(4)); caxis([1 4]); icolorbar;
axisGeom;
camlight headlight;
drawnow;

E_stent_cell=cell(numSegments,1);
V_stent_cell=cell(numSegments,1);
E_sheet_cell=cell(numSegments,1);
V_sheet_cell=cell(numSegments,1);
for q=1:1:numSegments

    controlParameterSet.waveAmplitude=waveAmplitudes(q); %Amplitude of the sinusoidal modulation
    [E,V]=stentSegmentDesign(controlParameterSet);

    offSetTotal=offSetTotal+offsetLevels(q);
    V(:,3)=V(:,3)+offSetTotal;

    %%

    C=hexVol(E,V); %Get hexahedral element volumes

    [F,CF]=element2patch(E,C); %Create face data for plotting

    [indBoundary]=tesBoundary(F,V);
    faceMarker=ones(size(E,1),1)*(1:6); %The 6 face colors for the hexahedral faces
    faceMarker=faceMarker(:); %Force as a column
    Fb=F(indBoundary,:); %Select the boundary faces (which will exclude tops (1) and bottoms (2))
    faceBoundaryMarker=faceMarker(indBoundary,:)-2; %Get boundary colors and subtract 2 so they are 1-4

    %%
    gpatch(Fb,V,faceBoundaryMarker,'k',1);

    %%

    F_inner = Fb(faceBoundaryMarker==2,:);
    [edgesBoundaryInner]=patchBoundary(F_inner,V);

    edgesBottom=F_inner(:,[4 1]);
    edgesTop=F_inner(:,[2 3]);

    edgesBoundaryInnerTop=edgesBoundaryInner(all(ismember(edgesBoundaryInner,edgesTop),2),:);
    edgesBoundaryInnerBottom=edgesBoundaryInner(all(ismember(edgesBoundaryInner,edgesBottom),2),:);

    indCurveTop=edgeListToCurve(edgesBoundaryInnerTop);
    indCurveTop=flip(indCurveTop(1:end-1));
    indCurveBottom=edgeListToCurve(edgesBoundaryInnerBottom);
    indCurveBottom=indCurveBottom(1:end-1);

    plotV(V(indCurveTop(:),:),'r-','LineWidth',lineWidth);
    plotV(V(indCurveBottom(:),:),'b-','LineWidth',lineWidth);

    drawnow;

   %%
   if q==1
       [FQ,VQ]=patchCleanUnused(F_inner,V);
   else
       cPar.closeLoopOpt=1;
       cPar.patchType='quad';
       [Fq,Vq]=polyLoftLinear(V_curveTopPrevious,V(indCurveBottom(:),:),cPar);
%        gpatch(Fq,Vq,'rw','rw',1);
       [F_inner_clean,V_inner_clean]=patchCleanUnused(F_inner,V);
       [FQ,VQ]=joinElementSets({Fq,F_inner_clean},{Vq,V_inner_clean});
       [FQ,VQ]=mergeVertices(FQ,VQ);
%        gpatch(FQ,VQ,'rw','rw',1);
%        patchNormPlot(FQ,VQ);
   end

   [E_sheet,V_sheet,Fq1,Fq2]=quadThick(FQ,VQ,1,sheetLayerThickness,numStepsSheet);

   [F_sheet]=element2patch(E_sheet); %Create face data for plotting
   gpatch(F_sheet,V_sheet,'gw','gw',1);
   %        patchNormPlot(F_sheet,V_sheet);

   E_sheet_cell{q}=E_sheet;
   V_sheet_cell{q}=V_sheet;

   V_curveTopPrevious=V(indCurveTop(:),:);

   E_stent_cell{q}=E;
   V_stent_cell{q}=V;

end

%% Merge components

[E_stent,V_stent,C_stent]=joinElementSets(E_stent_cell,V_stent_cell);
[E_sheet,V_sheet,C_sheet]=joinElementSets(E_sheet_cell,V_sheet_cell);
[E,V,C]=joinElementSets({E_stent,E_sheet},{V_stent,V_sheet},{C_stent,C_sheet+max(C_stent)});
[E,V]=mergeVertices(E,V);

[F,CF]=element2patch(E,C); %Create face data for plotting

%%
cFigure; hold on;
title('Stent hexahedral mesh','fontSize',fontSize);
gpatch(F,V,CF,'none',1);
% patchNormPlot(F,V);
colormap gjet; icolorbar
axisGeom;
camlight headlight;
drawnow;

%% Export inp file
%
% elementStruct.E=E;
% elementStruct.E_ind=(1:size(E,1))';
% elementStruct.E_type='*ELEMENT, TYPE=C3D8, ELSET=PART-STENT';
% nodeStruct.N=V;
% nodeStruct.N_ind=(1:size(V,1))';
%
% pathName = fileparts(fileparts(mfilename('fullpath')));
% fileName=fullfile(pathName,'data','INP','stentMeshSheet.inp');
% export_INP(elementStruct,nodeStruct,fileName);

%% FUNCTIONS

function [E,V]=stentSegmentDesign(controlParameterSet)

%% parse input

stentRadius=controlParameterSet.stentRadius; %The outer radius of the stent
numPeriodsWave=controlParameterSet.numPeriodsWave; %The number of periods to use for a sinusoidal modulation
waveAmplitude=controlParameterSet.waveAmplitude; %Amplitude of the sinusoidal modulation
stentSectionHeight=controlParameterSet.stentSectionHeight; %Height of the stent wire
stentSectionWidth=controlParameterSet.stentSectionWidth; %Width of the stent wire
numStepsCircumference=controlParameterSet.numStepsCircumference; %Number of sweeping steps across curve
overSampleFactorCurve=controlParameterSet.overSampleFactorCurve; %Oversample factor curve
numSplitSteps_axial=controlParameterSet.numSplitSteps_axial;
numSplitSteps_inward=controlParameterSet.numSplitSteps_inward;
plotOn=controlParameterSet.plotOn;

%% plot settings
if plotOn==1
    fontSize=25;
    markerSize=10;
    lineWidth=1;
end

%% Build stent section
% The rectangular stent wire section is created here.

V_section=[-stentSectionWidth/2  stentSectionHeight/2 0; ...
    stentSectionWidth/2  stentSectionHeight/2 0; ...
    stentSectionWidth/2 -stentSectionHeight/2 0; ...
    -stentSectionWidth/2 -stentSectionHeight/2 0; ...
    ];

%%
% V=isualize stent section
if plotOn==1
    cFigure; hold on;
    title('Stent section','fontSize',fontSize);
    plotV(V_section,'b.-','lineWidth',lineWidth,'MarkerSize',markerSize);
    view(2); axis tight; axis equal; grid on; box on;
    set(gca,'fontSize',fontSize);
    drawnow;
end

%% Create guide curve
% The sweepLoft (see |HELP_sweepLoft|) is created here. First and angle
% based parameterization is created. Next this curve is evenly sample
% across the curve length (see |HELP_evenlySampleCurve|).
t=linspace(0,2*pi,numStepsCircumference*overSampleFactorCurve); %Angles
t=t(1:end-1); %Remove last point so it is not closed for resampling
x=stentRadius.*sin(t); %x-coordinates
y=stentRadius.*cos(t); %y-coordinates
z=waveAmplitude.*sin(numPeriodsWave*t); %z-coordinates
V_guide_curve=[x(:) y(:) z(:)]; %Collected curve nodes
[V_guide_curve] = evenlySampleCurve(V_guide_curve,numStepsCircumference-1,'pchip',1); %Resample curve evenly
V_guide_curve(end+1,:)=V_guide_curve(1,:); %Append start to end so it is a closed loop

%%
% Visualize guide curve
if plotOn==1
    cFigure; hold on;
    title('Stent guide curve','fontSize',fontSize);
    plotV(V_guide_curve,'k.-','lineWidth',lineWidth,'MarkerSize',markerSize);
    axisGeom;
    drawnow;
end

%% Position stent section at the start and end of the guide curve
% Next the section is translated and rotated so it is placed at the start
% of the guide curve such that the curve normal points allong the curve.

% Create rotation matrix
n3=vecnormalize(V_guide_curve(2,:)-V_guide_curve(1,:)); %Out of section normal direction z ish direction
[~,indMin]=min(dot(n3(ones(1,2),:),[1 0 0; 0 1 0],2)); %Get index most appropriate initial other axis
switch indMin
    case 1
        n1=[1 0 0]; %Initialized x direction
        n2=vecnormalize(cross(n3,n1)); %y ish direction
        n1=vecnormalize(cross(n2,n3)); %Proper x ish direction
        R=[n1; n2; n3]; %Rotation matrix
    case 2
        n2=[0 1 0]; %Initialized y direction
        n1=vecnormalize(cross(n2,n3)); %x ish direction
        n2=vecnormalize(cross(n3,n1)); %Proper y ish direction
        R=[n1; n2; n3]; %Rotation matrix
end

p1=V_guide_curve(1,:); %The start node
V_section=V_section*R; %Rotate the section
V_section=V_section+p1(ones(size(V_section,1),1),:); % Translate coordinate to start

%%
% Visualize guide curve

if plotOn==1
    cFigure; hold on;
    title('Stent section positioned on guide curve','fontSize',fontSize);
    plotV(V_guide_curve,'k-','lineWidth',1);
    plotV(V_section,'k.-','lineWidth',lineWidth,'MarkerSize',markerSize);
    quiverVec(p1,n1,1,'r');
    quiverVec(p1,n2,1,'g');
    quiverVec(p1,n3,1,'b');
    axisGeom;
    drawnow;
end

%% Sweeping section allong curve
% Normally |sweepLoft| produces patch data as an output (e.g. faces and
% vertices). However these outputs are supressed here and the coordinate
% mesh output is instead used to create a hexahedral mesh. See also |HELP_sweepLoft|

numTwist=0; %Number of additional twists of loft feature around guide curve
numStepsSweep=numStepsCircumference; %Number of steps for loft feature from sketch 1 to sketch 2
[~,~,~,S]=sweepLoft(V_section,V_section,n3,n3,V_guide_curve,numStepsSweep,numTwist,0);

%% Construct hexahedral mesh

X=S.X'; Y=S.Y'; Z=S.Z'; %Coordinate matrices
V=[X(:) Y(:) Z(:)]; %Create node list

F=reshape((1:1:size(V,1)),4,size(V,1)/4)'; %All top and bottom faces
E=[F(2:end,:) F(1:end-1,:)]; %The hexahedral elements
[E,V]=mergeVertices(E,V); %Merge nodes (start and end are not shared yet)

%% Refine mesh
% The swept mesh can be refined through slitting. The splitting can be
% homogeneous or only in a particular direction (see HELP_subHex|)
% Split method explanation:
% 1: Overall splitting in all directions
% 2: Split allong curve direction
% 3: Split axially
% 4: Splint inward

splitMethod=3;
nRefine=numSplitSteps_axial;
[E,V]=subHex(E,V,nRefine,splitMethod);

splitMethod=4;
nRefine=numSplitSteps_inward;
[E,V]=subHex(E,V,nRefine,splitMethod);

%%
% Visualize hexahedral mesh

if plotOn==1

    [F]=element2patch(E); %Create face data for plotting

    cFigure; hold on;
    title('Stent hexahedral mesh','fontSize',fontSize);
    plotV(V_guide_curve,'k-','lineWidth',3);
    gpatch(F,V,'gw','k',1);
    patchNormPlot(F,V);
    axisGeom;
    camlight headlight;
    drawnow;
end

%%

end
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


function ld = sn_ld(l, n_sensor, n_source, n_snapshot)
%SN_LD Sufficient statistic for source number detection in MDL/AIC.
%   This function is used internally.
%Syntax:
%   ld = SN_LD(l, n_sensor, n_source, n_snapshot);
%Inputs:
%   l - Eigenvalues of the covariance matrix in descending order.
%   n_sensor - Number of sensors used. Should match the length of l.
%   n_source - Number of sources.
%   n_snapshot - Number of snapshots.
%Outputs:
%   ld - Computed value.
%Reference:
%   H. L. Van Trees, Optimum array processing. New York: Wiley, 2002.

diff = n_sensor - n_source;
l = l(n_source+1:end);
ld = n_snapshot * diff * log(sum(l)/diff/(prod(l)^(1/diff)));

end


clear;
t0=0;
tf=10;
b0=[0.2 0.2];
[t,b]=ode45('dfun3',[t0, tf],b0);
plot(b(:,1),b(:,2));
hold on
b0=[0.1 0.1];
[t,b]=ode45('dfun3',[t0, tf],b0);
plot(b(:,1),b(:,2));
hold on
b0=[0.2 0.15];
[t,b]=ode45('dfun3',[t0, tf],b0);
plot(b(:,1),b(:,2));
hold on
xlabel('x1');
ylabel('x2');


function [ x, w ] = rule06 ( n )

%*****************************************************************************80
%
%% RULE06 returns the rule of degree 6.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    01 July 2014
%
%  Author:
%
%    Original FORTRAN77 version by Hong Xiao, Zydrunas Gimbutas.
%    This MATLAB version by John Burkardt.
%
%  Reference:
%
%    Hong Xiao, Zydrunas Gimbutas,
%    A numerical algorithm for the construction of efficient quadrature
%    rules in two and higher dimensions,
%    Computers and Mathematics with Applications,
%    Volume 59, 2010, pages 663-676.
%
%  Parameters:
%
%    Input, integer N, the number of nodes.
%
%    Output, real X(2,N), the coordinates of the nodes.
%
%    Output, real W(N), the weights.
%
  xs = [ ...
    0.4595981103653579E-16, ...
    0.9258200997725515E+00, ...
    0.6742045114073804E-16, ...
   -0.9258200997725515E+00, ...
   -0.3805544332083157E+00, ...
    0.3805544332083157E+00, ...
    0.3805544332083157E+00, ...
   -0.3805544332083157E+00, ...
   -0.8059797829185990E+00, ...
    0.8059797829185988E+00, ...
    0.8059797829185990E+00, ...
   -0.8059797829185988E+00 ];
  ys = [ ...
   -0.9258200997725515E+00, ...
   -0.1073032005210112E-16, ...
    0.9258200997725515E+00, ...
    0.1241105822293750E-15, ...
   -0.3805544332083157E+00, ...
   -0.3805544332083157E+00, ...
    0.3805544332083157E+00, ...
    0.3805544332083157E+00, ...
   -0.8059797829185988E+00, ...
   -0.8059797829185990E+00, ...
    0.8059797829185988E+00, ...
    0.8059797829185990E+00 ];
  ws = [ ...
    0.1711023816204485E+00, ...
    0.1711023816204485E+00, ...
    0.1711023816204485E+00, ...
    0.1711023816204485E+00, ...
    0.3681147816131979E+00, ...
    0.3681147816131979E+00, ...
    0.3681147816131979E+00, ...
    0.3681147816131979E+00, ...
    0.1678896179529011E+00, ...
    0.1678896179529011E+00, ...
    0.1678896179529011E+00, ...
    0.1678896179529011E+00 ];

  x(1,1:n) = xs(1:n);
  x(2,1:n) = ys(1:n);
  w(1:n) = ws(1:n);

  return
end


% This is a 2D separable low pass filter for constructing Gaussian and
% Laplacian pyramids, built from a 1D 5-tap low pass filter.
%
% tom.mertens@gmail.com, August 2007
% sam.hasinoff@gmail.com, March 2011  [imfilter faster with 2D filter]
%

function f = pyramid_filter()
f = [.05, .25, .4, .25, .05];  % original [Burt and Adelson, 1983]
%f = [.0625, .25, .375, .25, .0625];  % binom-5
f = f'*f;
end


function gray = grayFilter(img, varargin)
%GRAYFILTER Compute configuration map of a binary image
%
%   GRAY = grayFilter(IMG);
%   Returns a gray-scale image, with size dim(IMG)-1, containing values of
%   the 2x2 configuration of the original binary image.
%
%   Example:
%   img = [0 0 0 0 0;0 1 1 0 0;0 1 1 1 0;0 0 0 0 0];
%   grayFilter(img)
%   ans =
%      8    12     4     0
%     10    15    13     4
%      2     3     3     1
%
%   ---------
%
%   author : David Legland
%   INRA - TPV URPOI - BIA IMASTE
%   created the 22/10/2004.
%

%   HISTORY
%   03/11/2004 : add 3x3 2D case.

% pre-processing
img = img~=0;
dim = size(img);
nd = length(dim);

% size of neighborhood to consider
nu=1;

% extract input parameters
if ~isempty(varargin)
    var = varargin{1};
    if length(var)==1
        nu = var;
    else
        coef = var;
        % find size of filter from length of coefficients.
        nu = power(log(length(coef))/log(2), 1/nd);
    end
end

if length(dim)==2
    % 2 dimensions
    NY = dim(1)-nu;
    NX = dim(2)-nu;

    if nu==1
        gray=1*img(1:NY,    1:NX) + ...
             2*img(1:NY,    2:NX+1) + ...
             4*img(2:NY+1,  1:NX) + ...
             8*img(2:NY+1,  2:NX+1) ;
    elseif nu==2
        gray =  1*img(1:NY,     1:NX) + ...
                2*img(1:NY,     2:NX+1) + ...
                4*img(1:NY,     3:NX+2) + ...
                8*img(2:NY+1,   1:NX) + ...
               16*img(2:NY+1,   2:NX+1) + ...
               32*img(2:NY+1,   3:NX+2) + ...
               64*img(3:NY+2,   1:NX) + ...
              128*img(3:NY+2,   2:NX+1) + ...
              256*img(3:NY+2,   3:NX+2) ;
    end

else
    % 3 dimensions
    NY = dim(1)-nu;
    NX = dim(2)-nu;
    NZ = dim(3)-nu;

    gray=   img(1:NY,    1:NX,   1:NZ) + ...
          2*img(1:NY,    2:NX+1, 1:NZ) + ...
          4*img(2:NY+1,  1:NX,   1:NZ) + ...
          8*img(2:NY+1,  2:NX+1, 1:NZ) + ...
         16*img(1:NY,    1:NX,   2:NZ+1) + ...
         32*img(1:NY,    2:NX+1, 2:NZ+1) + ...
         64*img(2:NY+1,  1:NX,   2:NZ+1) + ...
        128*img(2:NY+1,  2:NX+1, 2:NZ+1);
end


classdef IMOP6 < PROBLEM
% <multi> <real> <expensive/none>
% Benchmark MOP with irregular Pareto front
% a1 --- 0.05 --- Parameter a1
% a2 ---   10 --- Parameter a2
% K  ---    5 --- Parameter K

%------------------------------- Reference --------------------------------
% Y. Tian, R. Cheng, X. Zhang, M. Li, and Y. Jin, Diversity assessment of
% multi-objective evolutionary algorithms: Performance metric and benchmark
% problems, IEEE Computational Intelligence Magazine, 2019, 14(3): 61-74.
%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    properties(Access = private)
        a1 = 0.05;  % Parameter a1
        a2 = 10;    % Parameter a2
        K  = 5;     % Parameter K
    end
    methods
        %% Default settings of the problem
        function Setting(obj)
            [obj.a1,obj.a2,obj.K] = obj.ParameterSet(0.05,10,5);
            obj.M = 3;
            if isempty(obj.D); obj.D = 10; end
            obj.lower    = zeros(1,obj.D);
            obj.upper    = ones(1,obj.D);
            obj.encoding = ones(1,obj.D);
        end
        %% Calculate objective values
        function PopObj = CalObj(obj,PopDec)
            y1 = mean(PopDec(:,1:2:obj.K),2).^obj.a1;
            y2 = mean(PopDec(:,2:2:obj.K),2).^obj.a2;
            g  = sum((PopDec(:,obj.K+1:end)-0.5).^2,2);
            r  = max(0,min(sin(3*pi*y1).^2,sin(3*pi*y2).^2)-0.05);
            PopObj(:,1) = (1+g).*y1 + ceil(r);
            PopObj(:,2) = (1+g).*y2 + ceil(r);
            PopObj(:,3) = (0.5+g).*(2-y1-y2) + ceil(r);
        end
        %% Generate points on the Pareto front
        function R = GetOptimum(obj,N)
            [x,y] = meshgrid(linspace(0,1,ceil(sqrt(N))));
            R = [x(:),y(:)];
            r = max(0,min(sin(3*pi*R(:,1)).^2,sin(3*pi*R(:,2)).^2)-0.05);
            R(:,3) = 1 - sum(R,2)/2;
            R = R + repmat(ceil(r),1,3);
            R = R(NDSort(R,1)==1,:);
        end
        %% Generate the image of Pareto front
        function R = GetPF(obj)
            [x,y] = meshgrid(linspace(0,1,50));
            z     = 1 - x/2 - y/2;
            R     = [x(:),y(:),z(:)];
            r     = max(0,min(sin(3*pi*R(:,1)).^2,sin(3*pi*R(:,2)).^2)-0.05);
            R     = R + repmat(ceil(r),1,3);
            fes   = NDSort(R,1) == 1;
            z(reshape(~fes,size(z))) = nan;
            R     = {x,y,z};
        end
    end
end


function chebcoeffs = chebvals2chebcoeffs(chebvals, kind)
%CHEBVALS2CHEBCOEFFS  Convert Chebyshev values to coefficients.
% 	CHEBCOEFFS = CHEBVALS2CHEBCOEFFS(CHEBVALS), converts the column vector
%   CHEBVALS of values on a second-kind Chebyshev grid (i.e, F(CHEBPTS(N)))
%   to a vector CHEBCOEFFS of the Chebyshev coefficients of the series
%       F(X) = C_CHEB(1)*T0(X) + ... + C_CHEB(N)*T{N-1}(X).
%
% 	CHEBVALS2CHEBCOEFFS(CHEBVALS, 1) is similar, but assumes the entries in
% 	CHEBVALS come from evaluating on a first-kind Chebyshev grid, i.e.,
%   F(CHEBPTS(N,1))).
%
% See also CHEBTECH2.VALS2COEFFS, CHEBPTS.

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

% Default to second-kind points
if ( nargin == 1 )
    kind = 2;
end

if ( kind == 1 )
    % This command is a wrapper for chebtech2/vals2coeffs.
    chebcoeffs = chebtech1.vals2coeffs(chebvals);
elseif ( kind == 2 )
    % This command is a wrapper for chebtech1/vals2coeffs.
    chebcoeffs = chebtech2.vals2coeffs(chebvals);
else
    error('CHEBFUN:chebvals2chebcoeffs:kind', ...
        'Invalid Chebyshev kind. Must be 1 or 2.')
end

end


% The OxyGEN proyect by Profoty.xyz
% Together against the Covid-19
% V4.0 rev.17/03/2020
%
% Website/blog: oxygen.protofy.xyz
% Contact: oxygen@protofy.xyz

%GEOMETRICAL PARAMETERS

clear;

%Length from the bearing to the hinge
l0 = 27.5;

%Length of the vertical wall that supports the hinge
h0 = 6.5;

%Lenght of the vertical support of the bearing
hb = 4.0;

%Bearing radius
br = 1.1;

%Array of different max and min positions of the bearing
h1a = [6.5, 7.1, 7.7, 8.3];
h2a = [20.5, 20.5, 20.5, 20.5];

%Number of cycles per cam turn (1 to 3).
nc = 1;

%Minimum radius of the camshaft
rmin = 5;

%BREATHING CYCLE PARAMETERS

%Duration of the inhale cycle / duration of the whole cycle
lambda1 = 0.500;
lambda2 = 0.060;

%Soft transition between inhale and exhale cycles
dpsi21 = 0.12;
dpsi12 = 0.15;

%Adjust parameters of the inhale curve
ga1 = pi;
gb1 = 1.2;
ff1 = 20;
sp1 = 1;

%Adjust parametes of the exhale curve
ga2 = 9;
gb2 = .5;
ff2 = 20;

%GENERATION OF THE CURVES AND THE CAMSHAFT

%Generation of the geometry

l = sqrt(l0^2+hb^2);

for i = 1:numel(h1a);

    ymin(i) = h1a(i);
    ymax(i) = h2a(i);

    alphamin(i) = acos((h0 - h1a(i)) / l);
    alphamax(i) = acos((h0 - h2a(i)) / l);

    xmin(i) = l*sin(alphamin(i));
    xmax(i) = l*sin(alphamax(i));

    d(i) = sqrt((xmin(i)-xmax(i))^2 + (ymin(i)-ymax(i))^2);

    alphatan(i) = (alphamin(i) + alphamax(i)) / 2;

    xtan(i) = l*sin(alphatan(i));
    ytan(i) = h0 - l*cos(alphatan(i));

    xsup(i) = xtan(i) + (d(i)/2)*cos(alphatan(i));
    xinf(i) = xtan(i) - (d(i)/2)*cos(alphatan(i));

    ysup(i) = ytan(i) + (d(i)/2)*sin(alphatan(i));
    yinf(i) = ytan(i) - (d(i)/2)*sin(alphatan(i));

    xcam(i) = xtan(i) + (d(i)/2 + rmin + br)*cos(alphatan(i));
    ycam(i) = ytan(i) + (d(i)/2 + rmin + br)*sin(alphatan(i));

end;

%Time increment
dt = 0.01;

%time coordinate during the whole cycle
theta = 0:dt:2*pi;

%Generation of the soft transition between inhale and exhale curves
psi1 = [];
psi2 = [];

for i = 1:numel(theta);

    if theta(i) < (lambda2-dpsi21/2)*2*pi;
        psi1(i) = 0;

    elseif theta(i) < (lambda2+dpsi21/2)*2*pi;
        psi1(i) = 0.5 + 0.5*cos((theta(i)-(lambda2+dpsi21/2)*2*pi)/(2*dpsi21));

    else theta(i) < (lambda1-dpsi12/2)*2*pi;
        psi1(i) = 1;

    end;

    psi2(i) = 1 - psi1(i);

end;

%Generation of the complete breathing cycle rho(theta)

rho = [];
rho1 = [];
rho2 = [];
rho2next = [];

rhomin = 1000;
rhomax = 0;

for i = 1:numel(theta);

    %Inhale curve
    rho1(i) = ff1*normpdf(sp1*theta(i), ga1, gb1);
    rho1next(i) = ff1*normpdf(sp1*theta(i)+sp1*2*pi, ga1, gb1);

    %Exhale curve
    rho2(i) = ff2*gampdf(theta(i), ga2, gb2);
    rho2next(i) = ff2*gampdf(theta(i)+2*pi, ga2, gb2);

    rho(i) = max(rho1(i), rho1next(i));

    %Capturing min and max in order to generate the normalized curve
    if rho(i) > rhomax
        rhomax = rho(i);
    end;

    if rho(i) < rhomin
        rhomin = rho(i);
    end;

end;

%Generation of a normalised curve and camshaft

rhonorm = [];
rhocam = [];

for i = 1:numel(theta);

    rhonorm(i) = (rho(i)-rhomin)/(rhomax-rhomin);

    for n = 1:numel(d)

        rhocam(n,i) = rmin + rhonorm(i)*d(n);

    end;

end;

%Generation of the first derivate of the camshaft geometry to analize and
%validate the design

drho = [];
drhonorm = [];
drhocam = [];

a = rmin;
b = 1/dt;

for i = 1 : numel(rho)-1;

    drho(i) = b*(rho(i+1)-rho(i));
    drhonorm(i) = b*(rhonorm(i+1)-rhonorm(i));
    drhocam(i) = b*(rhocam(i+1)-rhocam(i)) + a;

end;

drho(numel(rho)) = b*(rho(1)-rho(numel(rho)));
drhonorm(numel(rhonorm)) = b*(rhonorm(1)-rhonorm(numel(rhonorm)));
drhocam(numel(rhocam)) = b*(rhocam(1)-rhocam(numel(rhocam))) + a;

%X and Y coordinates during two cycles (for 2-cycle camshaft plot)

theta2 = [theta/2, (2*pi+theta)/2];

rhocam2 = [rhocam, rhocam];
drhocam2 = [drho, drho];

%X and Y coordinates during three cycles (for 3-cycle camshaft plot)

theta3 = [theta/3, (2*pi+theta)/3, (4*pi+theta)/3];

rhocam3 = [rhocam, rhocam, rhocam];
drhocam3 = [drho, drho, drho];

%GENERATION OF THE PLOTS

%Trying to print it out in real size (FAIL)
%set(gcf,'PaperUnits','centimeters');
%set(gcf,'PaperSize',[42 29.7]);

fpos = figure('Name', 'Dimensions', 'Units', 'centimeters', 'NumberTitle', 'off');
set(gcf,'PaperUnits','centimeters', 'PaperSize', [42/2 27.9/2]);
set(gcf, 'units', 'centimeters', 'position', [0, 0, 28, 20]);
fpos = gcf;
hold on

xlim([-5 35]);
ylim([0 30]);

for i = 1:numel(xmin)

    plot([0, xmin(i)], [h0, ymin(i)], '-x')
    plot([0, xmax(i)], [h0, ymax(i)], '-x')

    plot([0, xtan(i)], [h0, ytan(i)], '--xb')

    plot([xsup(i), xinf(i)], [ysup(i), yinf(i)], '--xr')
    scatter(xcam(i), ycam(i))

end;

hold off

%Plot of the breathing cycle interpolation by curves

fcycle = figure('Name', 'Breath Cycle curves', 'Units', 'centimeters', 'NumberTitle', 'off');

hold on
plot(theta, psi1, '-k')
plot(theta, psi2, '-k')
plot(theta, rho1, '-g')
plot(theta, rho1next, '-g')
plot(theta, rho2, '-g')
plot(theta, rho2next, '-g')
%plot(theta, drho, '-r')
plot(theta, rho, '-b')
hold off

set(gcf,'PaperUnits','centimeters', 'PaperSize', [42 27.9]);
set(gcf, 'units', 'centimeters', 'position', [0, 0, 27.9, 27.9]);
fcam3 = gcf;

%Plot of the normalized breathing cycle and first derivate

fnorm = figure('Name', 'Normalized Breath Cycle', 'Units', 'centimeters', 'NumberTitle', 'off');

hold on
%plot(theta, drhonorm, '-r')
plot(theta, rhonorm, '-b')
hold off

set(gcf,'PaperUnits','centimeters', 'PaperSize', [42/2 27.9/2]);
set(gcf, 'units', 'centimeters', 'position', [0, 0, 27.9, 27.9]);
fcam3 = gcf;

%Plot of a 1-cycle camshaft

for n = 1:numel(d)

    fcam1 = figure('Name', '1-Cycle Camshaft', 'Units', 'centimeters', 'NumberTitle', 'off');
    %hold on

    %polarplot(theta, drhocam, '-r')
    polar(theta, rhocam(n,:), '-b')

    %rlim([0 25]);
    hold off

    set(gcf,'PaperUnits','centimeters', 'PaperSize', [42 27.9]);
    set(gcf, 'units', 'centimeters', 'position', [0, 0, 27.9, 27.9]);
    fcam3 = gcf;

end

% %Plot of a 2-cycle camshaft
%
% fcam2 = figure('Name', '2-Cycle', 'Units', 'centimeters', 'NumberTitle', 'off');
%
% %hold on;
% %polar(theta, drhocam2, '-r')
% polar(theta2, rhocam2, '-b')
% %hold off;
%
% set(gcf,'PaperUnits','centimeters', 'PaperSize', [42 27.9]);
% set(gcf, 'units', 'centimeters', 'position', [0, 0, 27.9, 27.9]);
% fcam3 = gcf;
%
%
% %Plot of a 3-cycle camshaft
%
% fcam3 = figure('Name', '3-Cycle', 'Units', 'centimeters', 'NumberTitle', 'off');
%
% %hold on;
% %polar(theta,drhocam3)
% polar(theta3, rhocam3)
% %hold off;
%
% set(gcf,'PaperUnits','centimeters', 'PaperSize', [42 27.9]);
% set(gcf, 'units', 'centimeters', 'position', [0, 0, 27.9, 27.9]);
% fcam3 = gcf;

% The OxyGEN proyect by Profoty.xyz
% Together against the Covid-19
% V4.0 rev.17/03/2020
%
% Website/blog: oxygen.protofy.xyz
% Contact: oxygen@protofy.xyz


function value = p05_exact ( dim_num )

%*****************************************************************************80
%
%% P05_EXACT returns the exact integral for problem 05.
%
%  Discussion:
%
%    The exact value is given only for DIM_NUM = 1, 2, 3, 4 or 5.
%    For other cases, the value R8_HUGE is returned instead.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 March 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer DIM_NUM, the spatial dimension.
%
%    Output, real VALUE, the exact value of the integral,
%    or R8_HUGE if the exact value is not known.
%
  if ( dim_num == 1 )

    value = log ( 3.0 );

  elseif ( dim_num == 2 )

    value = 5.0 * log ( 5.0 ) - 6.0 * log ( 3.0 );

  elseif ( dim_num == 3 )

    value = 0.5 * ( 49.0 * log ( 7.0 ) ...
      - 75.0 * log ( 5.0 ) + 27.0 * log ( 3.0 ) );

  elseif ( dim_num == 4 )

    value = 225.0 * log ( 3.0 ) + 125.0 * log ( 5.0 ) ...
      - 686.0 * log ( 7.0 ) / 3.0;

  elseif ( dim_num == 5 )

    value = ( ...
      - 65205.0 * log ( 3.0 ) ...
      - 6250.0 * log ( 5.0 ) ...
      + 24010.0 * log ( 7.0 ) ...
      + 14641.0 * log ( 11.0 ) ) / 24.0;

  else

    value = r8_huge ( );

  end

  return
end


function  [yz, dy] = pzextr1(iest, xest, yest)
% pzextr.m  uses extrapolation to evaluate nv functions at x=0 by fitting a
% polynomial to a sequence of estimates with progressively smaller values x= xest(1..np), and
% corresponding function vectors yest(1..nv,1..np). This call is number iest in the sequence
% of calls, see also bsstep1.m and pzextr.m
%
% output : the extrapolated function values, yz(1..nv,1..np) and their estimated error, dy(1..nv,1..np).

% D Vangheluwe 8 mrt 2005

global x_bulirsch_stoer  d_bulirsch_stoer

[nv np] = size(yest);

if np > 1
  x_bulirsch_stoer(iest,:) = xest;
% save current independent variable
  yz = yest;
  dy = yz;

%  x_bulirsch_stoer
%  d_bulirsch_stoer

  if iest == 1
% store first estimate in first column
     d_bulirsch_stoer(:,:,1) = yest;
  else
     c = yest;
     for k1 = 1:iest-1
        delta = 1 ./ (x_bulirsch_stoer(iest-k1,:) - xest);
        f1 = xest .* delta;
        f2 = x_bulirsch_stoer(iest-k1,:) .* delta;
        q = d_bulirsch_stoer(:,:,k1);
        d_bulirsch_stoer(:,:,k1) = dy;
        deltay = c - q;
        dy = repmat(f1, nv, 1) .* deltay;
        c = repmat(f2, nv, 1) .* deltay;
        yz = yz + dy;
     end
     d_bulirsch_stoer(:,:,iest) = dy;
  end

else  %np == 1

  x_bulirsch_stoer(iest) = xest';
% save current independent variable
  yz = yest;
  dy = yz;

%  x_bulirsch_stoer
%  d_bulirsch_stoer
  if iest == 1
% store first estimate in first column
     d_bulirsch_stoer(:,1) = yest;
  else
     c = yest;
     for k1 = 1:iest-1
        delta = 1 ./ (x_bulirsch_stoer(iest-k1) - xest);
        f1 = xest .* delta;
        f2 = x_bulirsch_stoer(iest-k1) .* delta;
        q = d_bulirsch_stoer(:,k1);
        d_bulirsch_stoer(:,k1) = dy;
        deltay = c - q;
        dy = f1 .* deltay;
        c = f2 .* deltay;
        yz = yz + dy;
     end
     d_bulirsch_stoer(:,iest) = dy;
  end

end  %np > 1