classdef Kernel
    % Kernel
    % Represents the kernel G(x)
    properties (SetAccess = protected, GetAccess = public)
        func, % anonymous function representing G(x)
        der, % anonymous function representing G'(x)
        scalFunc, % anonymous function,
        % scalFunc(a,b,rho) =2 \pi C(rho) \int_{a}^b rG'(r) J_0(\rho r)
        % where C(rho) is the normalization constant, si Cp.m in folder
        % radialQuad.
        normFunc,  % anonymous function,
        % normFunc(a,b) = \sqrt{2\pi \int_{a}^b r G'(r)^2 dr}
        startFreq = 0, % real number
        % frequency where the greatest Bessel coefficients are located.
        gamma_est, % Estimator used to predict the number of coefficients in
        % the Bessel series
        customRadialQuad = [],
        % If non-empty, contains the method to compute the radial
        % quadrature optimized for this kernel.
        singular = true;
        % Set to false if x G'(x)^2 is integrable near 0.
        lim0;
    end

    methods
        % Class constructor
        function[kernel] = Kernel(func,der)
            if nargin == 0
                func = @(x)(0*x);
                der = @(x)(0*x);
            end
            kernel.func = func;
            kernel.der = der;
            fun1 = @(rho)(@(x)((x.*der(x)).*...
                -rho(:)'.*Cp(rho(:)').*besselj(1,rho(:)'*x)));
            % H10 scalar product
            fun2 = @(x)(x.*der(x).^2);
            % H10 norm
            kernel.scalFunc = @(a,b,rho)(2*pi*integral(fun1(rho),...
                a,b,'ArrayValued',true)'); % -2\pi \int_{a}^b rf'(r)ep'(r)dr
            kernel.normFunc = @(a,b)(sqrt(2*pi*integral(fun2,a,b)));
            kernel.startFreq = 0; % We don't know a priori where the energy
            % is located in the spectrum.
            kernel.gamma_est = @(tol)deal(0,7); % No fine tuning of gamma
            kernel.customRadialQuad = [];
            if ~ or(isinf(func(0)),isnan(func(0)))
                kernel.singular = false;
                kernel.gamma_est = @(tol)deal(0,3); % No fine tuning of gamma
                kernel.lim0 = func(0);
            else
                kernel.lim0 = 0;
            end
        end
    end

    methods (Access = public)

        % Efficient Bessel Decomposition for the kernel.
        function[onlineEBD,rq,loc] = offlineEBD(this,X,Y,a,tol)

            % Rescaling
            rMax = rMaxCalc(X,Y); % diameter
            x = X/rMax; % in B(0,1)
            y = Y/rMax; % in B(0,1)
            k1 = this.dilatation(rMax); % k1 must be approximated on {a < r < 1}

            % Radial quadrature (Bessel decomposition in 1D)
            rq = k1.radialQuadKernel(a,tol);

            % Circular quadrature
            q2d = Quad2D(rq);

            % Local correction
            loc = localCorrections(x,y,a,k1,rq,tol,false);
            % We are ready to compute fast convolutions.
            onlineEBD = @(v)(q2d.conv(x,y,v) + loc*v);
        end
        function[MVx,MVy,rq,locx,locy] = offline_dEBD(this,X,Y,a,tol)

            % Rescaling
            rMax = rMaxCalc(X,Y); % diameter
            x = X/rMax; % in B(0,1)
            y = Y/rMax; % in B(0,1)
            k1 = this.dilatation(rMax); % k1 must be approximated on {a < r < 1}
            rq = k1.radialQuadKernel(a,tol*rMax,'grad',true);
            % the tolerance is set to tol*rMax because G'(rMax*u) = 1/rMax
            % k1'(u).
            q2d = Quad2D(rq);
            [q2dx,q2dy] = grad(q2d);
            loc = localCorrections(x,y,a,k1,rq,tol,true);
            locx = loc{1}; locy = loc{2};
            MVx = @(v)(-(q2dx.conv(x,y,v))/rMax + locx*v/rMax);
            MVy = @(v)(-(q2dy.conv(x,y,v))/rMax + locy*v/rMax);
        end

        % Display
        function[] = disp(this)
            fprintf('Kernel : function %s \n',func2str(this.func));
        end

        function[out] = eval(this,x)
            fun = this.func;
            out = fun(x);
            out(abs(x) < 1e-12) = this.lim0;
        end
        function[out] = evalDer(this,x)
            fun = this.der;
            out = fun(x);
            out(abs(x) < 1e-12) = 0;
        end
        % Setters
        function[this] = setScalFunc(this,f)
            this.scalFunc = f;
        end
        function[this] = setNormFunc(this,g)
            this.normFunc = g;
        end
        function[this] = setStartFreq(this,k)
            this.startFreq = k;
        end
        % Addition of two kernels
        function[C] = plus(k1,k2)
            C = Kernel(@(x)(k1.func(x) + k2.func(x)),@(x)(k1.der(x) + k2.der(x)));
            sf1 = k1.scalFunc;
            sf2 = k2.scalFunc;
            C.scalFunc =  @(a,b,rho)(sf1(a,b,rho) + sf2(a,b,rho));
            C.customRadialQuad = @(a,tol,varargin)(k1.radialQuadKernel(a,tol/2,varargin{:}) ...
                + k2.radialQuadKernel(a,tol/2,varargin{:}));
            C.singular = or(k1.singular,k2.singular);
            C.lim0 = k1.lim0 + k2.lim0;
        end
        % Multiplication by a constant
        function[c] = mtimes(lambda,this)
            if and(isa(lambda,'double'),isscalar(lambda))
                assert(isa(this,'Kernel'));
                c = this;
                c.func = @(x)(lambda*this.func(x));
                c.der = @(x)(lambda*this.der(x));
                c.scalFunc = @(a,b,rho)(lambda*this.scalFunc(a,b,rho));
                c.normFunc = @(a,b)(abs(lambda)*this.normFunc(a,b));
                c.lim0 = lambda*this.lim0;
                c.customRadialQuad = @(a,tol,varargin)(lambda*this.radialQuadKernel(a,tol/lambda,varargin{:}));
            else
                assert(and(isa(this,'double'),isscalar(this)))
                c = times(this,lambda);
            end
        end
    end
    methods (Access = public)
        % Wrapper
        function[rq] = radialQuadKernel(this,a,tol,varargin)
            if ~ isempty(this.customRadialQuad)
                rq = this.customRadialQuad(a,tol,varargin{:});
            else
                rq = RadialQuadrature(a,this,tol,varargin{:});
            end
        end
        % Dilatation of the kernel : G(x) -> G(R*x).
        function[this] = dilatation(old,lambda)
            oldFunc = old.func;
            oldDer = old.der;
            ffunc = @(x)(oldFunc(lambda*x));
            dder = @(x)(lambda*oldDer(lambda*x));
            this = Kernel(ffunc,dder);
            this = this.setStartFreq(lambda*old.startFreq);
            this.lim0 = old.lim0;
        end

    end
end


%Function of Circular Convolution for the Overlap Save Method.
function y=mycirconv(x,h)
lx=length(x);
lh=length(h);
l=max(lx,lh);
X=[x zeros(1,l-lx)];
H=zeros(l);
H(1:lh)=h;
for j=1:l-1
for i=1:l-1
H(i+1,j+1)=H(i,j);
end
H(1,j+1)=H(l,j);
end
y=H*X';


function [strikb,dipb,rakeb,dipdib,ierr] = focal_pl2pl(strika,dipa,rakea)

    % compute strike, dip and rake of a nodal plane from strike, dip and rake of the other one
    %
    %
    %     usage:
    %     call pl2pl(strika,dipa,rakea,strikb,dipb,rakeb,dipdib,ierr)
    %
    %     arguments:
    %     strika         strike angle in degrees of the first nodal plane (INPUT)
    %     dipa           dip angle in degrees of the first nodal plane (INPUT)
    %     rakea          rake angle in degrees of the first nodal plane (INPUT)
    %     strikb         strike angle in degrees of the second nodal plane (OUTPUT)
    %     dipb           dip angle in degrees of the second nodal plane (OUTPUT)
    %     rakeb          rake angle in degrees of the second nodal plane (OUTPUT)
    %     dipdib         dip direction in degrees of the second nodal plane (OUTPUT)
    %     ierr           error indicator (OUTPUT)
    %
    %     errors:
    %     1              input STRIKE angle out of range
    %     2              input DIP angle out of range
    %     4              input RAKE angle out of range
    %     3              1+2
    %     5              1+4
    %     7              1+2+4
    %     8              internal error
    %
    %      implicit none
    %-------------------------------------------------------------------------------
    %%       integer io
    %%       real amistr,amastr,amidip,amadip,amirak,amarak,amitre,amatre
    %%      1,amiplu,amaplu,orttol,ovrtol,tentol,dtor,c360,c90,c0,c1,c2,c3
    %%       common /fpscom/amistr,amastr,amidip,amadip,amirak,amarak,amitre
    %%      1,amatre,amiplu,amaplu,orttol,ovrtol,tentol,dtor,c360,c90,c0,c1,c2
    %%      2,c3,io
    %-------------------------------------------------------------------------------
    %%       real strika,dipa,rakea,anx,any,anz,dx,dy,dz,strikb,dipb,rakeb,
    %%      1dipdib
    %%       integer ierr
    %
    %%      call fpsset
    amistr=-360.;
    amastr=360.;
    amidip=0.;
    amadip=90.;
    amirak=-360.;
    amarak=360.;
    amitre=-360.;
    amatre=360.;
    amiplu=0.;
    amaplu=90.;
    orttol=2.;
    ovrtol=0.001;
    tentol=0.0001;
    dtor=0.017453292519943296;
    c360=360.;
    c90=90.;
    c0=0.;
    c1=1.;
    c2=2.;
    c3=3.;
    io=6;
    ifl=1;

    [anx,any,anz,dx,dy,dz,ierr] = focal_pl2nd(strika,dipa,rakea);
    if (ierr ~= 0)
        disp(['PL2PL: ierr = ' num2str(ierr)]);
        return;
    end
    [strikb,dipb,rakeb,dipdib,ierr] = focal_nd2pl(dx,dy,dz,anx,any,anz);
    if (ierr ~= 0)
        ierr = 8;
        disp(['PL2PL: ierr = ' num2str(ierr)]);
    end
end


function [gVarmeans gVarcovs gDynKern] = modelPriorReparamGrads(dynModel, gVarmeansLik, gVarcovsLik,gInd)
% MODELPRIORREPARAMGRADS Wrapper function for the gradients of the various types of the
% variational GPLVM bound when dynamics is used.
% FORMAT
% DESC provides a wrapper function for the variational GP-LVM, when there
% are dynamics. It takes a dynamics model structure and according to its type it
% calls the appropriate function to calculate the gradient for the
% variational bound. The gradients returned are w.r.t mu_bar and lambda, i.e. the parameters used by the optimiser
% (the ones introduced by the reparametrization), not the original ones (mu and S).
% These gradients are obtained in two steps: firstly, another funtion is used to calculate the
% gradients that correspond only to the likelihood part of the bound and
% are w.r.t the original parameters mu and S. These quantities are the arguments
% gVarmenasLik and gVarcovsLik and are calculated using the already
% implemented code for the static vargplvm, which assumes that the original
% parameters are not coupled.
% The current funtions receives these quantities and a) amends
% with partial derivatives because the variational parameters are coupled
% via Kt for the dyn. gplvm b) Computes the whole gradients for both parts
% of the bound, the one corresponding to the likelihood and the one
% corresponding to the prior. This must be done in a single function
% because the final formula contains both parts in a nonlinear form.
% c) Also the kernel hyperparameters for the dynamics kernel are being retured.
%
% See the dyn. vargplvm notes for more details.
%
% ARG dynModel : the dynamics model structure for which the gradients are
% to be computed.
% ARG gVarmeansLik, gVarcovsLik: the gradients for the VAR-GPLVM model computed
% for the original parameters and only for the likelihood term.
% ARG gInd: in case the inducing points are tied to the variational means
% this is the partial derivatives of the likelihood part of the variational
% bound w.r.t the inducing points X_u, otherwise it is just [].
% RETURN gVarmeans, gVarcovs : the gradients for the "reparametrized" means
% and covariances (the ones that are visible to the optimiser, not the
% original ones) for the VAR-GPLVM model.
% RETURN gDynKern: the gradient w.r.t the hyperparameters of the dynamics
% kernel
%
% SEEALSO : vargplvmLogLikeGradients vargpTimeDynamicsPriorReparamGrads
%
% COPYRIGHT : Michalis K. Titsias, 2010-2011
% COPYRIGHT : Neil D. Lawrence, 2010-2011
% COPYRIGHT : Andreas C. Damianou, 2010-2011

% VARGPLVM

fhandle = str2func([dynModel.type 'PriorReparamGrads']);
[gVarmeans gVarcovs gDynKern] = fhandle(dynModel, gVarmeansLik, gVarcovsLik, gInd);


function i4_uniform_ab_test ( )

%*****************************************************************************80
%
%% I4_UNIFORM_AB_TEST tests I4_UNIFORM_AB.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    27 October 2014
%
%  Author:
%
%    John Burkardt
%
  a = -100;
  b = 200;
  seed = 123456789;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'I4_UNIFORM_AB_TEST\n' );
  fprintf ( 1, '  I4_UNIFORM_AB computes pseudorandom values\n' );
  fprintf ( 1, '  in an interval [A,B].\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  The lower endpoint A = %f\n', a );
  fprintf ( 1, '  The upper endpoint B = %f\n', b );
  fprintf ( 1, '  The initial seed is %d\n', seed );
  fprintf ( 1, '\n' );

  for i = 1 : 20

    [ j, seed ] = i4_uniform_ab ( a, b, seed );

    fprintf ( 1,'  %8d  %8d\n', i, j );

  end

  return
end


function [output] = volumefillholes(input, along)

% VOLUMEFILLHOLES is a helper function for segmentations
%
% See also VOLUMETHRESHOLD, VOLUMESMOOTH

% ensure that SPM is available, needed for spm_bwlabel
ft_hastoolbox('spm8up', 3) || ft_hastoolbox('spm2', 1);

if nargin<2
  inflate = false(size(input)+2);                   % grow the edges along each dimension
  inflate(2:end-1, 2:end-1, 2:end-1) = (input~=0);  % insert the original volume
  [lab, num] = spm_bwlabel(double(~inflate), 18);   % note that 18 is consistent with imfill, 26 is not
  if num>1
    inflate(lab~=lab(1)) = true;
    output  = inflate(2:end-1, 2:end-1, 2:end-1);   % trim the edges
  else
    output = input;
  end

else
  output = input;
  dim    = size(input);
  switch along
    case 1
      for i=1:dim(1)
        slice = reshape(input(i,:,:),dim([2 3]));
        im = imfill(slice,8,'holes');
        output(i,:,:) = im;
      end

    case 2
      for i=1:dim(2)
        slice = reshape(input(:,i,:),dim([1 3]));
        im = imfill(slice,8,'holes');
        output(:,i,:) = im;
      end

    case 3
      for i=1:dim(3)
        slice = reshape(input(:,:,i),dim([1 2]));
        im = imfill(slice,8,'holes');
        output(:,:,i) = im;
      end

    otherwise
      ft_error('invalid dimension %d to slice the volume', along);
  end % switch along
end % if nargin


classdef TestContourFitting
    %TestContourFitting

    methods (Static)
        function test_contourSampling
            c = get_contour();

            % cell array
            c2 = cv.ContourFitting.contourSampling(c, 100);
            validateattributes(c2, {'cell'}, {'numel',100});

            % Nx2
            c = cat(1, c{:});
            c2 = cv.ContourFitting.contourSampling(c, 100);
            validateattributes(c2, {'numeric'}, {'size',[100 2]});

            % Nx1x2
            c = permute(c, [1 3 2]);
            c2 = cv.ContourFitting.contourSampling(c, 100);
            validateattributes(c2, {'numeric'}, {'size',[100 1 2]});
        end

        function test_fourierDescriptor
            c = get_contour();

            % cell array
            fd = cv.ContourFitting.fourierDescriptor(c, 'NumFD',30);
            validateattributes(fd, {'numeric'}, {});
            assert(length(fd)==30 && size(fd,3)==2);

            % Nx2
            c = cat(1, c{:});
            fd = cv.ContourFitting.fourierDescriptor(c, 'NumFD',30);
            validateattributes(fd, {'numeric'}, {});
            assert(length(fd)==30 && size(fd,3)==2);

            % Nx1x2
            c = permute(c, [1 3 2]);
            fd = cv.ContourFitting.fourierDescriptor(c, 'NumFD',30);
            validateattributes(fd, {'numeric'}, {});
            assert(length(fd)==30 && size(fd,3)==2);
        end

        function test_transformFD
            c = get_contour();
            t = [0 pi/2 1 10 20];  % [alpha, phi, s, Tx, Ty]

            % cell array
            c2 = cv.ContourFitting.transformFD(c, t, 'FD',false);
            validateattributes(c2, {'cell'}, {'nonempty'});

            % Nx2
            c = cat(1, c{:});
            c2 = cv.ContourFitting.transformFD(c, t, 'FD',false);
            validateattributes(c2, {'cell'}, {'nonempty'});

            % Nx1x2
            c = permute(c, [1 3 2]);
            c2 = cv.ContourFitting.transformFD(c, t, 'FD',false);
            validateattributes(c2, {'cell'}, {'nonempty'});
        end

        function test_transformFD_2
            c = get_contour();
            t = [0 pi/2 1 10 20];  % [alpha, phi, s, Tx, Ty]

            n = cv.getOptimalDFTSize(numel(c));
            cc = cv.ContourFitting.contourSampling(c, n);
            fd = cv.ContourFitting.fourierDescriptor(cc);

            fd2 = cv.ContourFitting.transformFD(fd, t, 'FD',true);
            validateattributes(fd2, {'numeric'}, {'nonempty'});
            assert(length(fd2)==length(fd) && size(fd2,3)==2);
        end

        function test_estimateTransformation
            c1 = get_contour();
            c2 = cellfun(@(pt) pt+[10 20], c1, 'UniformOutput',false);

            obj = cv.ContourFitting();
            [t, d] = obj.estimateTransformation(c1, c2, 'FD',false);
            validateattributes(t, {'double'}, {'vector', 'numel',5});
            validateattributes(d, {'numeric'}, {'scalar', 'nonnegative'});
        end

        function test_estimateTransformation_2
            c1 = get_contour();
            c2 = cellfun(@(pt) pt+[10 20], c1, 'UniformOutput',false);

            n = cv.getOptimalDFTSize(numel(c1));
            cc1 = cv.ContourFitting.contourSampling(c1, n);
            cc2 = cv.ContourFitting.contourSampling(c2, n);
            fd1 = cv.ContourFitting.fourierDescriptor(cc1);
            fd2 = cv.ContourFitting.fourierDescriptor(cc2);
            fd1 = reshape(fd1, [], 1, 2);
            fd2 = reshape(fd2, [], 1, 2);

            obj = cv.ContourFitting();
            [t, d] = obj.estimateTransformation(fd1, fd2, 'FD',true);
            validateattributes(t, {'double'}, {'vector', 'numel',5});
            validateattributes(d, {'numeric'}, {'scalar', 'nonnegative'});
        end
    end

end

function [c, img] = get_contour()
    im = fullfile(mexopencv.root(),'test','shape06.png');
    img = cv.imread(im, 'Grayscale',true);
    c = cv.findContours(img, 'Mode','List', 'Method','None');
    [~,idx] = max(cellfun(@numel,c));
    c = c{idx};
end


%+========================================================================+
%|                                                                        |
%|            This script uses the GYPSILAB toolbox for Matlab            |
%|                                                                        |
%| COPYRIGHT : Matthieu Aussal, Marc Bakry (c) 2017-2019.                 |
%| PROPERTY  : Centre de Mathematiques Appliquees, Ecole polytechnique,   |
%| route de Saclay, 91128 Palaiseau, France. All rights reserved.         |
%| LICENCE   : This program is free software, distributed in the hope that|
%| it will be useful, but WITHOUT ANY WARRANTY. Natively, you can use,    |
%| redistribute and/or modify it under the terms of the GNU General Public|
%| License, as published by the Free Software Foundation (version 3 or    |
%| later,  http://www.gnu.org/licenses). For private use, dual licencing  |
%| is available, please contact us to activate a "pay for remove" option. |
%| CONTACT   : matthieu.aussal@polytechnique.edu                          |
%|             marc.bakry@polytechnique.edu                               |
%| WEBSITE   : www.cmap.polytechnique.fr/~aussal/gypsilab                 |
%|                                                                        |
%| Please acknowledge the gypsilab toolbox in programs or publications in |
%| which you use it.                                                      |
%|________________________________________________________________________|
%|   '&`   |                                                              |
%|    #    |   FILE       : nrtHmxVibroSlab2d.m                           |
%|    #    |   VERSION    : 0.55                                          |
%|   _#_   |   AUTHOR(S)  : Matthieu Aussal & Marc Bakry                  |
%|  ( # )  |   CREATION   : 14.03.2019                                    |
%|  / 0 \  |   LAST MODIF :                                               |
%| ( === ) |   SYNOPSIS   :                                               |
%|  `---'  |                                                              |
%+========================================================================+

% Cleaning
clear all
close all
clc

% Gypsilab path
run('../../addpathGypsilab.m')

% Accuracy
tol = 1e-3

% Width of the slab
e = 0.5

% Frequency
f = 900:500:4000

% Incident direction (from bottom)
X0  = [0 1 0];

% Exterior domain (water)
rho0 = 1000;         % density      (kg.m3)
c0   = 1500;         % celerity     (m.s-1)
k0   = 2*pi/c0.*f;   % wave-number  (m-1)
lam0 = c0./f;        % wave-length  (m)

% Interior domain (different from water)
rhoS = 2*rho0;                                 % density                             (kg.m3)
cL   = 2*c0;                                   % celerity of longitudinal waves      (m.s-1)
kL   = 2*pi.*f./cL;                            % wave-number of longitudinal waves   (m-1)
lamL = real(cL)./f;                            % wavelength of longitudinal waves    (m)
cT   = 0;                                      % celerity of transverse waves        (m.s-1)
kT   = 2*pi.*f./cT;                            % wave-number of transverse waves     (m-1)
lamT = real(cT)./f;                            % wavelength of transverse waves      (m)

% Solution (pressure)
sol = zeros(2,length(f));

% Loop for each frequency
for i = 1:length(f)
    % Minimum wavelength
    tmp  = [lam0(i),lamL(i),lamT(i)];
    lmin = min(tmp(tmp>0));

    % Slab mesh
    L    = 60 * lmin;            % 60 wavelength to simulate infinite slab
    nx   = ceil(L/lmin * 6)+1;   % 6 node per wavelength for L
    ny   = ceil(e/lmin * 12)+1;  % 12 node per wavelength for e
    N    = nx * ny;              % Total number of nodes
    mesh = mshSquare(N,[L e])

    % Radiative mesh (fixed number of nodes)
    radiat = mshSquare(1e3,[L L]);

    % Boundary
    bound = swap(mesh.bnd)

    % Measurement points for trans and refl coeff (1 wavelenth from bound)
    Xmes = [0 -e/2-lmin 0 ; 0 e/2+lmin 0];

    % Cut-off function (50% full, 10% decrease)
    cutoff = vibsCutoff(1,L/5,L/10);

    % Green kernel function
    Gxy         = @(X,Y) femGreenKernel(X,Y,'[H0(kr)]',k0(i));
    gradyGxy{1} = @(X,Y) femGreenKernel(X,Y,'grady[H0(kr)]1',k0(i));
    gradyGxy{2} = @(X,Y) femGreenKernel(X,Y,'grady[H0(kr)]2',k0(i));
    gradyGxy{3} = @(X,Y) femGreenKernel(X,Y,'grady[H0(kr)]3',k0(i));

    % Plane wave function
    PW         = @(X) exp(1i*k0(i)*X*X0') .* cutoff(X);
    gradxPW{1} = @(X) 1i*k0(i)*X0(1) .* PW(X);
    gradxPW{2} = @(X) 1i*k0(i)*X0(2) .* PW(X);
    gradxPW{3} = @(X) 1i*k0(i)*X0(3) .* PW(X);

    % Coupling coeff for Brackage-Werner simulation
    beta = 1i*k0(i);

    % Quadrature and finite elements (volumn)
    omega = dom(mesh,3);
    U     = fem(mesh,'P1');

    % Quadrature and finite elements (boundary)
    sigma = dom(bound,3);
    u     = fem(bound,'P1');

    % Left-hand side
    tic
    [A,B,C,D] = vibsHmxBlockOperator(omega,U,sigma,u,cL,cT,rhoS,c0,rho0,f(i),tol);
    toc

    % Add dirichlet condition to x unknows (penalization)
    A(sub2ind(size(A),1:length(U),1:length(U))) = 1e15;

    % Right-hand side
    V    = cell(3,1);
    V{1} = - integral(sigma,ntimes(U,1),PW);
    V{2} = - integral(sigma,ntimes(U,2),PW);
    V{3} = integral(sigma,ntimes(u),gradxPW);

    % Resolution with Schur complement
    Fa     = decomposition(A);
    LHS    = @(V) D*V - C*(Fa \ (B.Ml*(B.Mr*V)) );
    RHS    = V{end} - C*(Fa \ cell2mat(V(1:end-1)) );
    mu     = mgcr(LHS,RHS,[],tol,100);
    lambda = beta*mu;

    % Measure of refexive and transmitted coeff
    tic
    Pmes = 1i/4 .* integral(Xmes,sigma,Gxy,u)*lambda - ...
        1i/4 .* integral(Xmes,sigma,gradyGxy,ntimes(u))*mu;
    Pmes(2) = Pmes(2) + PW(Xmes(2,:));
    toc

    % Save solution
    sol(:,i) = Pmes;
end

% Analytical solution
tic
c     = ones(length(f),1) * [c0 cL c0];
rho   = [rho0 rhoS rho0];
[R,T] = slabVibro(f,rho,c,e);
toc

% Comparison (db)
ref = 20*log10(abs([R ; T]));
sol = 20*log10(abs(sol));

norm(ref-sol)/norm(ref)

% Graphical representation
figure(100)
subplot(1,2,1)
plot(f,ref(1,:),'r',f,sol(1,:),'b+')
grid on
title('Reflexion coeffiscient')
legend({'Analytical','Numerical'})
xlabel('Frequency (Hz)')
ylabel('Amplitude (dB)')

subplot(1,2,2)
plot(f,ref(2,:),'r',f,sol(2,:),'b+')
grid on
title('Transmission coeffiscient')
legend({'Analytical','Numerical'})
xlabel('Frequency (Hz)')
ylabel('Amplitude (dB)')

disp('~~> Michto gypsilab !')


function varargout = spm_mesh_utils(action,varargin)
% A gateway function for surface mesh-related compiled algorithms
%
% FORMAT [N, D] = spm_mesh_utils('neighbours',A)
% Return an array of first-order neighbours given an adjacency matrix
%
% FORMAT Fi = spm_mesh_utils('neighbouringfaces',F,i)
% Return the indices of the neighbouring triangles of a given triangle
%
% FORMAT D = spm_mesh_utils('dijkstra',N,D,i,dmax)
% Compute geodesic distance on a triangular mesh using Dijkstra algorith
%
% FORMAT V = spm_mesh_utils('volume',M)
% Compute the volume of a closed surface mesh
%__________________________________________________________________________
% Copyright (C) 2010-2017 Wellcome Trust Centre for Neuroimaging

% Guillaume Flandin
% $Id: spm_mesh_utils.m 7240 2017-12-19 12:06:59Z guillaume $

%-This is merely the help file for the compiled routine
error('spm_mesh_utils.c not compiled - see Makefile')


%%**********************************************************************
%% HSDNTpred: Compute (dX,dy,dZ) for NT direction.
%%
%% compute SVD of Xchol*Zchol via eigenvalue decompostion of
%%     Zchol * X * Zchol' = V * diag(sv2) * V'.
%% compute W satisfying W*Z*W = X.
%%     W = G'*G,  where G = diag(sqrt(sv)) * (invZchol*V)'
%%
%% SDPT3: version 3.1
%% Copyright (c) 1997 by
%% K.C. Toh, M.J. Todd, R.H. Tutuncu
%% Last Modified: 16 Sep 2004
%%**********************************************************************

 function [par,dX,dy,dZ,coeff,L,hRd] = ...
           HSDNTpred(blk,At,par,rp,Rd,sigmu,X,Z,Zchol,invZchol);

    global schurfun schurfun_par
%%
%% compute NT scaling matrix
%%
    [par.W,par.G,par.sv,par.gamx,par.gamz,par.dd,par.ee,par.ff] = ...
     NTscaling(blk,X,Z,Zchol,invZchol);
%%
%% compute schur matrix
%%
    m = par.m;
    schur = sparse(m+2,m+2);
    UU = []; EE = [];
    dX = cell(size(blk,1),1); dy = []; dZ = cell(size(blk,1),1);
%%
    for p = 1:size(blk,1)
       pblk = blk(p,:);
       if strcmp(pblk{1},'l')
          [schur,UU,EE] = schurmat_lblk(blk,At,par,schur,UU,EE,p,par.dd);
       elseif strcmp(pblk{1},'q');
          [schur,UU,EE] = schurmat_qblk(blk,At,par,schur,UU,EE,p,par.dd,par.ee);
       elseif strcmp(pblk{1},'s')
          if isempty(schurfun{p})
             schur = schurmat_sblk(blk,At,par,schur,p,par.W);
          elseif isstr(schurfun{p})
             schurtmp = sparse(m,m);
             if ~isempty(par.permZ{p})
                Wp = par.W{p}(par.permZ{p},par.permZ{p});
             else
                Wp = par.W{p};
             end
             eval(['schurtmp = ',schurfun{p},'(Wp,Wp,schurfun_par(p,:));']);
             schur = schur + schurtmp;
          end
       end
    end
%%
%% compute rhs
%%
    [rhs,EinvRc,hRd] = HSDNTrhsfun(blk,At,par,X,Z,rp,Rd,sigmu);
%%
%% solve linear system
%%
    par.addschur   = par.kap/par.tau;
    schur(m+1,m+1) = schur(m+1,m+1) + par.kap/par.tau;
    schur(m+2,m+2) = schur(m+2,m+2) + par.addschur;
    [xx,coeff,L] = HSDlinsysolve(par,schur,UU,EE,par.Umat,rhs);
%%
%% compute (dX,dZ)
%%
    [par,dX,dy,dZ] = HSDNTdirfun(blk,At,par,Rd,EinvRc,xx);
%%**********************************************************************


%% Function List
%
%% ARMAX-GARCH Toolbox
%
% <matlab:web(fullfile('garch.m')) garch.m>, estimates the ARMAX-GARCH family of models
%
% Inputs: a data vector, the GARCH model to be estimated, the distribution, the order of AR, MA, ARCH and GARCH effects as well as a vector of factors for the mean and volatility process.
%
% Outputs: a vector of estimated parameters, standard errors estimated by the inverse Hessian, the Log-Likelihood value, a vector of conditional variances, a vector of residuals, and a summary of results which includes: model statistics, t-statistics, robust standard errors, scores among others.
%
% <matlab:web(fullfile('garchfind.m')) garchfind>, finds the combination of models and distributions that better fits the data based on a set of criteria (i.e. largest log likelihood value and the smallest AIC and BIC criteria).
%
% Inputs: a data vector, a model and distribution vectors, the order of AR, MA, ARCH and GARCH,
%
% Outputs: the best fit model
%
% % <matlab:web(fullfile('garchplot.m')) garchplot>, Plots the data,volatility and residuals
%
% <matlab:web(fullfile('garchfor.m')) garchfor> & <matlab:web(fullfile('garchfor2.m')) garchfor2>, estimates mean, volatility and kurtosis forecasts
%
% Inputs: a data vector, a vector of residuals, a vector of conditional variances, a set of parameters, the  model, the order of AR, MA, ARCH and GARCH and the number of forecasts
%
% Outputs: a vector of mean, and volatility forecasts as well as a vector of cumulative mean and volatility forecasts.
%
% <matlab:web(fullfile('garchsim.m')) garchsim>, simulates GARCH responses
%
% Inputs: estimated parameters, GARCH model, distribution, order of ARCH and GARCH, number of samples and number of paths. Additionally, a vector of time series of positive pre-sample conditional standard deviations may be provided, which the variance model will initialize.
%
% Outputs: a vector of simulated series and conditional standard deviations
%
% <matlab:web(fullfile('garchvar.m')) garchvar> & <matlab:web(fullfile('garchvar2.m')) garchvar2>, estimates  Value-at-Risk for a given confidence level and horizon period for both long and short positions
%
% Inputs: a data vector, a vector of residuals, a vector of conditional% variances, a set of parameters, the  model, the distribution, the order of AR, MA, ARCH and GARCH, the number of forecasts and confidence level
%
% Outputs: a vector of VaR forecasts
%
% <matlab:web(fullfile('garchvolfor.m')) garchvolfor>, an application in Volatility Forecasting & Value-at-Risk. It allows the comparison of volatility and Value-at-Risk estimates for a data vector and for a variety of GARCH models and distributions as specified in the model & distribution variables and at different forecast periods as well as sort the results according to only a sub-set of forecast periods.
%
% Inputs: a data vector, a vector of models and distributions, order of AR, MA, ARCH and GARCH, max forecasts, the forecasts of interest and a vector of a% VaR losses
%
% Outputs:  volatility and VaR back-testing results, vectors of forecasted estimated of volatility, VaR and returns
%
%% ARMAX-GARCH-K Toolbox
%
% <matlab:web(fullfile('garchk.m')) garchk>, estimates the ARMAX-GARCH-K family of models
%
% Inputs: a data vector, the GARCH model to be estimated, the order of AR, MA, ARCH and GARCH effects as well as a vector of factors for the mean and volatility process.
%
% Outputs: a vector of estimated parameters, standard errors estimated by the inverse Hessian, the Log-Likelihood value, a vector of conditional variances, a vector of conditional kurtosis, a vector of residuals, and a summary of results which includes: model statistics, t-statistics, robust standard errors, scores among others.
%
% <matlab:web(fullfile('garchkplot.m')) garchkplot>, Plots the data, conditional volatility, conditional kurtosis and residuals
%
% <matlab:web(fullfile('garchkfor.m')) garchkfor> & <matlab:web(fullfile('garchkfor2.m')) garchkfor2>, estimates mean, volatility and kurtosis forecasts
%
% Inputs: a data vector, a vector of residuals, a vector of conditional variances, a vector of conditional kurtosis, a set of parameters, the  model, the order of AR, MA, ARCH and GARCH and the number of forecasts
%
% Outputs: a vector of mean, volatility and kurtosis forecasts as well as a vector of cumulative mean and volatility forecasts.
%
% <matlab:web(fullfile('garchksim.m')) garchksim>, simulates volatility and kurtosis responses
%
% Inputs: estimated parameters, GARCH model, distribution, order of ARCH and GARCH, number of samples and number of paths. Additionally, a vector of time series of positive pre-sample conditional standard deviations may be provided, which the variance model will initialize.
%
% Outputs: a vector of simulated series, conditional standard deviations and conditional kurtosis
%
% <matlab:web(fullfile('garchkvar.m')) garchkvar> & <matlab:web(fullfile('garchkvar2.m')) garchkvar2>, estimates  Value-at-Risk for a given confidence level and horizon period for both long and short positions
%
% Inputs: a data vector, a vector of residuals, a vector of conditional variances, a set of parameters, the  model, the order of AR, MA, ARCH and GARCH, the number of forecasts and confidence level
%
% Outputs: a vector of VaR forecasts
%
% <..\readme\readme.html Return to Main>


function [datac,datafit,Amps,freqs]=rmlinesmovingwinc(data,movingwin,tau,params,p,plt,f0,fscanbw)
% fits significant sine waves to data (continuous data) using overlapping windows.
%
% Usage: [datac,datafit]=rmlinesmovingwinc(data,movingwin,tau,params,p,plt)
%
%  Inputs:
% Note that units of Fs, fpass have to be consistent.
%       data        (data in [N,C] i.e. time x channels/trials or as a single vector) - required.
%       movingwin         (in the form [window winstep] i.e length of moving
%                                                 window and step size)
%                                                 Note that units here have
%                                                 to be consistent with
%                                                 units of Fs - required
%       tau      parameter controlling degree of smoothing for the amplitudes - we use the
%       function 1-1/(1+exp(-tau*(x-Noverlap/2)/Noverlap) in the region of overlap to smooth
%       the sinewaves across the overlap region. Noverlap is the number of points
%       in the overlap region. Increasing tau leads to greater overlap smoothing,
%       typically specifying tau~10 or higher is reasonable. tau=1 gives an almost
%       linear smoothing function. tau=100 gives a very steep sigmoidal. The default is tau=10.
%       params      structure containing parameters - params has the
%       following fields: tapers, Fs, fpass, pad
%           tapers : precalculated tapers from dpss or in the one of the following
%                    forms:
%                   (1) A numeric vector [TW K] where TW is the
%                       time-bandwidth product and K is the number of
%                       tapers to be used (less than or equal to
%                       2TW-1).
%                   (2) A numeric vector [W T p] where W is the
%                       bandwidth, T is the duration of the data and p
%                       is an integer such that 2TW-p tapers are used. In
%                       this form there is no default i.e. to specify
%                       the bandwidth, you have to specify T and p as
%                       well. Note that the units of W and T have to be
%                       consistent: if W is in Hz, T must be in seconds
%                       and vice versa. Note that these units must also
%                       be consistent with the units of params.Fs: W can
%                       be in Hz if and only if params.Fs is in Hz.
%                       The default is to use form 1 with TW=3 and K=5
%                    Note that T has to be equal to movingwin(1).
%
%	        Fs 	        (sampling frequency) -- optional. Defaults to 1.
%               fpass       (frequency band to be used in the calculation in the form
%                                   [fmin fmax])- optional.
%                                   Default all frequencies between 0 and Fs/2
%	        pad		    (padding factor for the FFT) - optional (can take values -1,0,1,2...).
%                    -1 corresponds to no padding, 0 corresponds to padding
%                    to the next highest power of 2 etc.
%			      	 e.g. For N = 500, if PAD = -1, we do not pad; if PAD = 0, we pad the FFT
%			      	 to 512 points, if pad=1, we pad to 1024 points etc.
%			      	 Defaults to 0.
%	    p		    (P-value to calculate error bars for) - optional.
%	    Defaults to 0.05/Nwin where Nwin is length of window which
%	    corresponds to a false detect probability of approximately 0.05.
%       plt         (y/n for plot and no plot respectively) - default no
%                   plot.
%       f0          frequencies at which you want to remove the
%                   lines - if unspecified the program uses the f statistic
%                   to determine appropriate lines.
%
%  Outputs:
%       datafit        (fitted sine waves)
%       datac          (cleaned up data)
if nargin < 2; error('Need data and window parameters'); end;
if nargin < 4 || isempty(params); params=[]; end;
if nargin < 8, fscanbw = [];  end

if length(params.tapers)==3 & movingwin(1)~=params.tapers(2);
    error('Duration of data in params.tapers is inconsistent with movingwin(1), modify params.tapers(2) to proceed')
end

[tapers,pad,Fs,fpass,err,trialave,params]=getparams(params); % set defaults for params
clear err trialave
if nargin < 6; plt='n'; end;
%
% Window,overlap and frequency information
%
data=change_row_to_column(data);
[N,C]=size(data);
Nwin=round(Fs*movingwin(1)); % number of samples in window
Nstep=round(movingwin(2)*Fs); % number of samples to step through
Noverlap=Nwin-Nstep; % number of points in overlap
%
% Sigmoidal smoothing function
%
if nargin < 3 || isempty(tau); tau=10; end; % smoothing parameter for sigmoidal overlap function
x=(1:Noverlap)';
smooth=1./(1+exp(-tau.*(x-Noverlap/2)/Noverlap)); % sigmoidal function
smooth=repmat(smooth,[1 C]);
%
% Start the loop
%
if nargin < 5 || isempty(p); p=0.05/Nwin; end % default for p value
if nargin < 7 || isempty(f0); f0=[]; end; % empty set default for f0 - uses F statistics to determine the frequencies
params.tapers=dpsschk(tapers,Nwin,Fs); % check tapers
winstart=1:Nstep:N-Nwin+1;
nw=length(winstart);
datafit=zeros(winstart(nw)+Nwin-1,C);
Amps=cell(1,nw);
freqs=cell(1,nw);
for n=1:nw;
   indx=winstart(n):winstart(n)+Nwin-1;
   datawin=data(indx,:);
   [datafitwin,as,fs]=fitlinesc(datawin,params,p,'n',f0,fscanbw);
   Amps{n}=as;
   freqs{n}=fs;
   datafitwin0=datafitwin;
   if n>1; datafitwin(1:Noverlap,:)=smooth.*datafitwin(1:Noverlap,:)+(1-smooth).*datafitwin0(Nwin-Noverlap+1:Nwin,:);end;
   datafit(indx,:)=datafitwin;
end;
datac=data(1:size(datafit,1),:)-datafit;
if strcmp(plt,'y');
    [S,f]=mtspectrumsegc(data,movingwin(1),params);
    [Sc,fc]=mtspectrumsegc(datac,movingwin(1),params);
    plot(f,10*log10(S),fc,10*log10(Sc));
end;


function [val, pos] = min3(f)
%MIN3   Global minimum of a CHEBFUN3.
%   [VAL, POS] = MIN3(F) returns the global minimum VAL and the position
%   POS of the global minimum of a CHEBFUN3 object F.
%
% See also CHEBFUN3/MINANDMAX3.

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

% Call MINANDMAX3:
[val, pos] = minandmax3(f);

% Extract minimum:
val = val(1);
pos = pos(1, :);

end


function points2d
%POINTS2D  Description of functions operating on points
%
%   A point is defined by its two cartesian coordinate, put into a row
%   vector of 2 elements:
%   P = [x y];
%
%   Several points are stores in a matrix with two columns, one for the
%   x-coordinate, one for the y-coordinate.
%   PTS = [x1 y1 ; x2 y2 ; x3 y3];
%
%   Example
%   P = [5 6];
%
%   See also:
%   centroid, midPoint, boundingBox, polarPoint
%   distancePoints, minDistancePoints, nndist, circumCenter
%   isCounterClockwise, angle2Points, angle3Points, angleSort
%   transformPoint, clipPoints, drawPoint
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2008-10-13,    using Matlab 7.4.0.287 (R2007a)
% Copyright 2008 INRA - BIA PV Nantes - MIAJ Jouy-en-Josas.

help('points2d');


%%% ERROR_ANALYSIS
%%% This simulation helps coputing the acturacies of calibration
%%% Run it after the main calibration

N_runs = 200;

%N_ima_active = 4;

saving = 1;

if 1, %~exist('fc_list'), % initialization

   % Initialization:

   load Calib_Results;
   check_active_images;

	fc_list = [];
	cc_list = [];
	kc_list = [];
   active_images_list = [];

	for kk=1:n_ima,

   	eval(['omc_list_' num2str(kk) ' = [];']);
   	eval(['Tc_list_' num2str(kk) ' = [];']);

   end;

	%sx = median(abs(ex(1,:)))*1.4836;
	%sy = median(abs(ex(2,:)))*1.4836;

	sx = std(ex(1,:));
	sy = std(ex(2,:));

	% Saving the feature locations:

	for kk = 1:n_ima,

   	eval(['x_save_' num2str(kk) ' = x_' num2str(kk) ';']);
   	eval(['y_save_' num2str(kk) ' = y_' num2str(kk) ';']);

	end;

   active_images_save = active_images;
   ind_active_save = ind_active;

   fc_save = fc;
   cc_save = cc;
   kc_save = kc;
   KK_save = KK;

end;

%%% The main loop:

for ntrial = 1:N_runs,

   fprintf(1,'\nRun number: %d\n',ntrial);
   fprintf(1,  '----------\n');

   for kk = 1:n_ima,

      eval(['y_kk = y_save_' num2str(kk) ';'])

      if active_images(kk) & ~isnan(y_kk(1,1)),

         Nkk = size(y_kk,2);

         x_kk_new = y_kk + [sx * randn(1,Nkk);sy*randn(1,Nkk)];

         eval(['x_' num2str(kk) ' = x_kk_new;']);

      end;

   end;

   N_active = length(ind_active_save);
   junk = randn(1,N_active);
   [junk,junk2] = sort(junk);

   active_images = zeros(1,n_ima);
   active_images(ind_active_save(junk2(1:N_ima_active))) = ones(1,N_ima_active);

   fc = fc_save;
   cc = cc_save;
   kc = kc_save;
   KK = KK_save;

   go_calib_optim;

   fc_list = [fc_list fc];
   cc_list = [cc_list cc];
   kc_list = [kc_list kc];
   active_images_list = [active_images_list active_images'];

   for kk=1:n_ima,

   	eval(['omc_list_' num2str(kk) ' = [ omc_list_' num2str(kk) ' omc_' num2str(kk) ' ];']);
   	eval(['Tc_list_' num2str(kk) ' = [ Tc_list_' num2str(kk) ' Tc_' num2str(kk) ' ];']);

	end;

end;

if 0,

% Restoring the feature locations:

for kk = 1:n_ima,

   eval(['x_' num2str(kk) ' = x_save_' num2str(kk) ';']);

end;

fprintf(1,'\nFinal run (with the real data)\n');
fprintf(1,  '------------------------------\n');

active_images = active_images_save;
ind_active = ind_active_save;

go_calib_optim;

fc_list = [fc_list fc];
cc_list = [cc_list cc];
kc_list = [kc_list kc];
active_images_list = [active_images_list active_images'];

for kk=1:n_ima,

   eval(['omc_list_' num2str(kk) ' = [ omc_list_' num2str(kk) ' omc_' num2str(kk) ' ];']);
   eval(['Tc_list_' num2str(kk) ' = [ Tc_list_' num2str(kk) ' Tc_' num2str(kk) ' ];']);

end;

end;

if saving,

disp(['Save Calibration accuracy results under Calib_Accuracies_' num2str(N_ima_active) '.mat']);

string_save = ['save Calib_Accuracies_' num2str(N_ima_active) ' active_images n_ima N_ima_active N_runs active_images_list fc cc kc fc_list cc_list kc_list'];

for kk = 1:n_ima,
   string_save = [string_save ' Tc_list_' num2str(kk) ' omc_list_' num2str(kk)  ' Tc_' num2str(kk) ' omc_' num2str(kk) ];
end;

eval(string_save);

end;

return;

std(fc_list')

std(cc_list')

std(kc_list')

for kk = 1:n_ima,

   eval(['std(Tc_list_'  num2str(kk) ''')'])

end;


function p = prior_sqinvgamma(varargin)
%PRIOR_SQINVGAMMA  Gamma prior structure for square inverse of the parameter
%
%  Description
%    P = PRIOR_SQINVGAMMA('PARAM1', VALUE1, 'PARAM2', VALUE2, ...)
%    creates Gamma prior structure for square inverse of the
%    parameter in which the named parameters have the specified
%    values. Any unspecified parameters are set to default values.
%
%    P = PRIOR_SQINVGAMMA(P, 'PARAM1', VALUE1, 'PARAM2', VALUE2, ...)
%    modify a prior structure with the named parameters altered
%    with the specified values.
%
%    Parametrisation is done by Bayesian Data Analysis,
%    second edition, Gelman et.al. 2004.
%
%    Parameters for Gamma prior [default]
%      sh       - shape [4]
%      is       - inverse scale [1]
%      sh_prior - prior for sh [prior_fixed]
%      is_prior - prior for is [prior_fixed]
%
%  See also
%    PRIOR_*

% Copyright (c) 2000-2001,2010,2012 Aki Vehtari
% Copyright (c) 2010 Jaakko Riihim�ki

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

  ip=inputParser;
  ip.FunctionName = 'PRIOR_SQINVGAMMA';
  ip.addOptional('p', [], @isstruct);
  ip.addParamValue('sh',4, @(x) isscalar(x) && x>0);
  ip.addParamValue('sh_prior',[], @(x) isstruct(x) || isempty(x));
  ip.addParamValue('is',1, @(x) isscalar(x) && x>0);
  ip.addParamValue('is_prior',[], @(x) isstruct(x) || isempty(x));
  ip.parse(varargin{:});
  p=ip.Results.p;

  if isempty(p)
    init=true;
    p.type = 'SqInv-Gamma';
  else
    if ~isfield(p,'type') && ~isequal(p.type,'SqInv-Gamma')
      error('First argument does not seem to be a valid prior structure')
    end
    init=false;
  end

  % Initialize parameters
  if init || ~ismember('sh',ip.UsingDefaults)
    p.sh = ip.Results.sh;
  end
  if init || ~ismember('is',ip.UsingDefaults)
    p.is = ip.Results.is;
  end
  % Initialize prior structure
  if init
    p.p=[];
  end
  if init || ~ismember('sh_prior',ip.UsingDefaults)
    p.p.sh=ip.Results.sh_prior;
  end
  if init || ~ismember('is_prior',ip.UsingDefaults)
    p.p.is=ip.Results.is_prior;
  end

  if init
    % set functions
    p.fh.pak = @prior_sqinvgamma_pak;
    p.fh.unpak = @prior_sqinvgamma_unpak;
    p.fh.lp = @prior_sqinvgamma_lp;
    p.fh.lpg = @prior_sqinvgamma_lpg;
    p.fh.recappend = @prior_sqinvgamma_recappend;
  end

end

function [w, s] = prior_sqinvgamma_pak(p)

  w=[];
  s={};
  if ~isempty(p.p.sh)
    w = log(p.sh);
    s=[s; 'log(SqInv-Gamma.sh)'];
  end
  if ~isempty(p.p.is)
    w = [w log(p.is)];
    s=[s; 'log(SqInv-Gamma.is)'];
  end
end

function [p, w] = prior_sqinvgamma_unpak(p, w)

  if ~isempty(p.p.sh)
    i1=1;
    p.sh = exp(w(i1));
    w = w(i1+1:end);
  end
  if ~isempty(p.p.is)
    i1=1;
    p.is = exp(w(i1));
    w = w(i1+1:end);
  end
end

function lp = prior_sqinvgamma_lp(x, p)

  lJ = -log(x)*3 + log(2);  % log(-2/x^3) log(|J|) of transformation
  xt = x.^-2;               % transformation
  lp = sum(-p.is.*xt + (p.sh-1).*log(xt) +p.sh.*log(p.is)  -gammaln(p.sh) +lJ);

  if ~isempty(p.p.sh)
    lp = lp + p.p.sh.fh.lp(p.sh, p.p.sh) + log(p.sh);
  end
  if ~isempty(p.p.is)
    lp = lp + p.p.is.fh.lp(p.is, p.p.is) + log(p.is);
  end
end

function lpg = prior_sqinvgamma_lpg(x, p)

  lJg = -3./x;              % gradient of log(|J|) of transformation
  xt  = x.^-2;              % transformation
  xtg = -2/x.^3;            % derivative of transformation
  lpg = xtg.*((p.sh-1)./xt - p.is) + lJg;

  if ~isempty(p.p.sh)
    lpgsh = (sum(-digamma1(p.sh) + log(p.is) + log(x)) + p.p.sh.fh.lpg(p.sh, p.p.sh)).*p.sh + 1;
    lpg = [lpg lpgsh];
  end
  if ~isempty(p.p.is)
    lpgis = (sum(p.sh./p.is+x) + p.p.is.fh.lpg(p.is, p.p.is)).*p.is + 1;
    lpg = [lpg lpgis];
  end

end

function rec = prior_sqinvgamma_recappend(rec, ri, p)
% The parameters are not sampled in any case.
  rec = rec;
  if ~isempty(p.p.sh)
    rec.sh(ri,:) = p.sh;
  end
  if ~isempty(p.p.is)
    rec.is(ri,:) = p.is;
  end
end


% dtft_test.m
% test mex versions of DTFT by comparing to m-file versions

for1 = @(om, x) jf_mex('dtft,forward', om', x, int32(1));
adj1 = @(om, Xm, N) jf_mex('dtft,adjoint', om', Xm, int32(N), int32(1));

%
% 1d tests
%
if 1, printm '1d dtft for'
	N1 = 32;
	M = 10;
	om = 2*pi*[0:(M-1)]'/M; % test with uniform frequency locations
	x = [1:N1]';
	Xm = dtft1(x, om);
	Xc = for1(om, x);
	printm('1d forward real mpd = %g%%', max_percent_diff(Xm,Xc))

	X2 = for1([om 0*om], x); % trick: fake as 2d!
	if any(X2 ~= Xc), error bug, end

	x = x - 2i*flipud(x);
	Xm = dtft1(x, om);
	Xc = for1(om, x);
	printm('1d forward cplx mpd = %g%%', max_percent_diff(Xm,Xc))

	X2 = for1(om, [x x]); % L=2 reps
	if any(X2 ~= [Xc Xc]), error bug, end
end

if 1, printm '1d dtft adj'
	xm = dtft_adj(Xm, om, N1, [], 0);
	xc = adj1(om, Xm, N1);
	printm('1d adjoint cplx mpd = %g%%', max_percent_diff(xm,xc))

	x2 = dtft_adj([Xm Xm], om, N1, [], 0);
%	if any(x2 ~= [xm xm]), error bugxm2, end % strangely nonzero!
	x2 = adj1(om, [Xm Xm], N1);
	if any(x2 ~= [xc xc]), error bug, end
end

%
% 2d tests
%
if 1, printm '2d dtft for'
	N1 = 4; N2 = 6;
	x = [[1:N1]'*ones(1,3), ones(N1,N2-3)]; % test signal

	o1 = 2*pi*[0:(N1-1)]'/N1; % test with uniform frequency locations
	o2 = 2*pi*[0:(N2-1)]'/N2; % test with uniform frequency locations
	[o1 o2] = ndgrid(o1, o2);
	omega = [o1(:) o2(:)];
	omega = [omega; [2 7]];

	Xm = dtft2(x, omega, [], 1);
	Xc = for1(omega, x);
	printm('2d forward real mpd = %g%%', max_percent_diff(Xm,Xc))

	x = x - 2i * flipud(x); % complex
	Xm = dtft(x, omega, 'how', 'loop');
	Xc = for1(omega, x);
	printm('2d forward cplx mpd = %g%%', max_percent_diff(Xm,Xc))

	X2 = for1(omega, stackup(x,x));
	if any(X2 ~= [Xc Xc]), error bug, end
end

if 1, printm '2d dtft adj'
	xm = dtft2_adj(Xm, omega, N1, N2, [], 0);
	xc = adj1(omega, Xm, [N1 N2]);
	printm('2d adjoint cplx mpd = %g%%', max_percent_diff(xm,xc))

	if 1 % stack 2d adjoint
		X = [Xm Xm]; % L=2
		x2 = dtft_adj(X, omega, [N1 N2], [], 0);
	%	if any(x2 ~= stackup(xm, xm)), error bug, end % strangely nonzero!
		x2 = adj1(omega, X, [N1 N2]);
		if any(x2 ~= stackup(xc, xc)), error bug, end
	end

	if 0 % real 2d spectrum (not implemented, and probably not needed)
		X = real(Xm);
		xm = dtft2_adj(X, omega, N1, N2, [], 0);
		xc = adj1(omega, X, [N1 N2]);
		printm('2d adjoint real mpd = %g%%', max_percent_diff(xm,xc))
	end
end

%
% 3d tests
%
if 1, printm '3d dtft for'
	N1 = 4; N2 = 6; N3 = 5;
	rng(3)
	x = rand(N1,N2,N3);

	o1 = 2*pi*[0:(N1-1)]'/N1; % test with uniform frequency locations
	o2 = 2*pi*[0:(N2-1)]'/N2;
	o3 = 2*pi*[0:(N3-1)]'/N3;
	[o1 o2 o3] = ndgrid(o1, o2, o3);
	omega = [o1(:) o2(:) o3(:)];
	omega = [omega; [2 7 1]];

	Xm = dtft(x, omega, 'how', 'loop');
	Xc = for1(omega, x);
	printm('3d forward real mpd = %g%%', max_percent_diff(Xm,Xc))

	x = x - 2i * flipdim(x,3); % complex
	Xm = dtft(x, omega, 'how', 'loop');
	Xc = for1(omega, x);
	printm('3d forward cplx mpd = %g%%', max_percent_diff(Xm,Xc))

	X3 = for1(omega, stackup(x,x));
	if any(X3 ~= [Xc Xc]), error bug, end
end

if 1, printm '3d dtft adj'
	xm = dtft_adj(Xm, omega, [N1 N2 N3], [], 0);
	xc = adj1(omega, Xm, [N1 N2 N3]);
	printm('3d adjoint cplx mpd = %g%%', max_percent_diff(xm,xc))

	if 1 % stack 3d adjoint
		X = [Xm Xm]; % L=2
		x2 = dtft_adj(X, omega, [N1 N2 N3], [], 0);
	%	if any(x2 ~= stackup(xm, xm)), error bug, end % strangely nonzero!
		x2 = adj1(omega, X, [N1 N2 N3]);
		if any(x2 ~= stackup(xc, xc)), error bug, end
	end

	if 0 % real 3d spectrum (not implemented, and probably not needed)
		X = real(Xm);
		xm = dtft_adj(X, omega, [N1 N2 N3], [], 0);
		xc = adj1(omega, X, [N1 N2 N3]);
		printm('3d adjoint real mpd = %g%%', max_percent_diff(xm,xc))
	end
end

%
% now test thread speedup
%
if 1 % thread setup
	clear
	N1 = 2^6;
	N2 = 2^5;
	M = 2^12;
	rng(0)
	omega = rand(M, 2);
	s0 = rand(M,1) + 1i * rand(M,1);
	x0 = rand(N1,N2) + 1i * rand(N1,N2);
	nthread = int32(8);

	arg1 = {'dtft,forward', omega', x0};
	arg2 = {'dtft,adjoint', omega', s0, int32([N1 N2]')};
end

if 1, printm 'threads forw'
	tic
	s1 = jf_mex(arg1{:}, int32(1));
	t1 = toc;
	tic
	s2 = jf_mex(arg1{:}, int32(2));
	t2 = toc;

	if any(s1 ~= s2), error bug, end
	printm('thread for time %g %g, speedup = %g', t1, t2, t1 / t2)
	if 1 % vs exact
		se = dtft(x0, omega, 'how', 'loop');
		printm('2d forward exct mpd = %g%%', max_percent_diff(se,s1))
	end
end

if 1, printm 'threads adj'
	tic
	x1 = jf_mex(arg2{:}, int32(1));
	t1 = toc;
	tic
	x2 = jf_mex(arg2{:}, int32(2));
	t2 = toc;
%	printm('2d adjoint mpd2 = %g%%', max_percent_diff(xm,x2))

	if nrms(x2,x1) > 1e-11, warning 'bug-adj-thread'
		max_percent_diff(x2,x1), end
	printm('thread adj time %g %g, speedup = %g', t1, t2, t1 / t2)
	if 1 % vs exact
		xm = dtft2_adj(s0, omega, N1, N2, [], 0);
		printm('2d adjoint exct mpd = %g%%', max_percent_diff(xm,x1))
	end
end


function [Xs, delta, C, B, names] = get_session_X(obj, s)
% Get design matrix (predictors) for one session of fmri_model object, using
% basis functions defined in the object and onsets for one session (s).
%
% :Usage:
% ::
%
%     [Xs, delta, C, B, names] = get_session_X(obj, session number)
%

% ..
%    Define sessions and number of conditions
% ..

nsess = length(obj.Sess);

if s > nsess, error('Session %3.0f does not exist', s); end

TR = obj.xY.RT;

nconds = length(obj.Sess(s).U);

[ons, name] = deal(cell(1, nconds));

[ons{:}] = deal(obj.Sess(s).U(:).ons);
[name{:}] = deal(obj.Sess(s).U(:).name);

% make sure onsets are in TRs, not secs
switch obj.xBF(1).UNITS
    case 'secs'
        % onsets are in sec, convert
        for i = 1:nconds
            ons{i} = ons{i} ./ TR;
        end

    case {'tr', 'TR', 'trs'}
        % ok, do nothing
end

% ----------------------------------------------
% Predictors
% ----------------------------------------------

delta = onsets2delta(ons, obj.nscan(s));

% Of-interest part of design matrix
% time res is defined as TR / 16, so build and downsample by 16 to TR
% Allow for different basis sets for each condition.

Xs = cell(1, nconds);

for i = 1:nconds

    bf = obj.xBF(i).bf;

    Xs{i} = getPredictors(delta(:, i), bf, 16);
end

Xs = cat(2, Xs{:});

% covariate part of design matrix
C = [];
if ~isempty(obj.Sess(s).C) && isfield(obj.Sess(s).C, 'C')
    C = obj.Sess(s).C.C;
end

% baseline
% ----------------------------------------------

B = ones(obj.nscan(s), 1);

% ----------------------------------------------
% modulators
% ----------------------------------------------

Xs_pm = cell(1, nconds);

for i = 1:nconds
    is_pm = isfield(obj.Sess(s).U(i), 'P') && ~isempty(obj.Sess(s).U(i).P) && isfield(obj.Sess(s).U(i).P, 'P') && ~isempty(obj.Sess(s).U(i).P.P);

    if is_pm

        pm_vals = {obj.Sess(s).U(i).P.P};

        model = onsets2parametric_mod_X(ons(i), pm_vals, obj.nscan(s), obj.xBF(i).bf, 16);

        Xs_pm{i} = model;

    end

end

Xs_pm = cat(2, Xs_pm{:});

% add to Xs
Xs = [Xs Xs_pm];

% ----------------------------------------------
% get names for each BF
% Allow variable number of basis fcns for each condition
% ----------------------------------------------

names = {};

for i = 1:nconds

    nbf = size(obj.xBF(i).bf, 2);

    for j = 1:nbf
        myname = [name{i} ' BF' num2str(j)];
        myname = replaceblanks(myname);

        names{end+1} = myname;
    end
end

all_pmnames = {};

for i = 1:nconds
    is_pm = isfield(obj.Sess(s).U(i), 'P') && ~isempty(obj.Sess(s).U(i).P) && isfield(obj.Sess(s).U(i).P, 'P') && ~isempty(obj.Sess(s).U(i).P.P);

    if is_pm
        % Get param mod names
        % ------------------------------------------------
        pmnames = cell(1, nbf);

        for j = 1:nbf
            myname = [obj.Sess(s).U(i).P.name ' BF' num2str(j)];
            myname = replaceblanks(myname);

            pmnames{1, j} = myname;
        end

        all_pmnames = cat(2, all_pmnames, pmnames{:});

    end
end

names = names(:)';

names = [names all_pmnames];

end

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

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

function myname = replaceblanks(myname)

myname(myname == ' ') = '-';
% this works in 2010b but not a...
%tmp = diff(num2str(myname)) == 0;

tmp = diff(double(myname)) == 0;
myname([false tmp] & myname == '-') = [];

end


classdef HolonomicConstraint < handle
    % HolonomicConstraint: represents a group of holonomic constraints of a
    % dynamical systems.
    %
    % A holonomic constraint is defined as a function of state variables
    % that equals to constants, i.e.,
    %   h(x) == hd
    %
    % @author ayonga @date 2017-04-20
    %
    % Copyright (c) 2016-2017, AMBER Lab
    % All right reserved.
    %
    % Redistribution and use in source and binary forms, with or without
    % modification, are permitted only in compliance with the BSD 3-Clause
    % license, see
    % http://www.opensource.org/licenses/bsd-license.php

    % properties determined internally
    properties (SetAccess=protected, GetAccess=public)
       % The dimension of the virtual constraints
        %
        % @type integer
        Dimension

        % The symbolic representation of constant parameter value 'hd' that
        % the holonomic constraints associated wtih.
        %
        % @type SymVariable
        Param

        % The symbolic representation of the input variables associated
        % with the holonomic constraints
        %
        % @type SymVariable
        Input
    end

    % properties must be determined by the users
    properties (SetAccess=protected, GetAccess=public)
        % The name of the virtual constraints
        %
        % @type char
        Name

        % The label of the holonomic constraint
        %
        % @type char
        ConstrLabel

        % The highest order of derivatives to enforce the holonomic
        % constraints. This is the same as the relative degree of a virtual
        % constraint.
        %
        % @type integer
        DerivativeOrder

    end

    properties (Dependent)
        % The holonomic constraint expression
        %
        % @type SymFunction
        ConstrExpr

        % The Jacobian matrix of the holonomic constraitns
        %
        % @type SymFunction
        ConstrJac

         % The Jacobian matrix of the holonomic constraitns
        %
        % @type SymFunction
        ConstrJacDot

        % The name of the parameter variable 'hd' associated with the
        % holonomic constraints
        %
        % @type char
        ParamName

        % The name othe input variables (external forces, etc.) associated
        % with the holonomic constraints
        %
        % @type char
        InputName
    end

    %% GET methods
    methods
        function cstr = get.ConstrExpr(obj)
            cstr = obj.h_;
        end
        function jac = get.ConstrJac(obj)
            jac = obj.Jh_;
        end
        function jacdot = get.ConstrJacDot(obj)
            jacdot = obj.dJh_;
        end
        function name = get.ParamName(obj)
            name = ['p' obj.Name];
        end
        function name = get.InputName(obj)
            name = ['f' obj.Name];
        end
        function name = get.h_name(obj)
            name = ['h_' obj.Name '_' obj.Model.Name];
        end

        function name = get.Jh_name(obj)
            name = ['Jh_' obj.Name '_' obj.Model.Name];
        end

        function name = get.dJh_name(obj)
            name = ['dJh_' obj.Name '_' obj.Model.Name];
        end

        function name = get.dh_name(obj)
            name = ['dh_' obj.Name '_' obj.Model.Name];
        end

        function name = get.ddh_name(obj)
            name = ['ddh_' obj.Name '_' obj.Model.Name];
        end
    end

    properties (Dependent)

        h_name

        Jh_name

        dh_name

        dJh_name

        ddh_name
    end

    properties (Access = protected)
        % The dynamical system model
        %
        % @type DynamicalSystem
        Model

        % The holonomic constraint expression
        %
        % @type SymFunction
        h_

        % The Jacobian matrix of the holonomic constraint expression
        %
        % @type SymFunction
        Jh_

        % The first order derivative of the holonomic constraint expression
        %
        % @type SymFunction
        dh_
        % The first order derivative of the Jacobian matrix of the
        % holonomic constraint expression
        %
        %
        % @type SymFunction
        dJh_

        % The second order derivatives of the holonomic constraints
        % expression
        %
        % @type SymFunction
        ddh_
    end

    methods

        function obj = HolonomicConstraint(model, h, name, varargin)
            % The class constructor function
            %
            % Parameters:
            % model: the dynamical system model in which the virtual
            % constraints are defined @type DynamicalSystem
            % h: the symbolic expression of the constraints
            % name: the name of the virtual constraints @type char
            % @type SymExpression
            % varargin: optional parameters. In details
            %  ConstrLabel: labels for constraints @type cellstr
            %  Jacobian: the custom Jacobian matrix @type SymExpression
            %  DerivativeOrder: the degree of holonomic constraints
            %  @type integer

            if nargin == 0
                return;
            end

            % validate (model) argument
            validateattributes(model, {'ContinuousDynamics'},...
                {'scalar'},...
                'HolonomicConstraint','model');
            obj.Model = model;
            x = model.States.x;

            % validates (name) argument
            validateName(obj, name);
            obj.Name = name;

            % parse the input options
            args = struct(varargin{:});
            assert(isscalar(args),...
                'The values of optional properties are must be scalar data.');

            if ~isempty(h)
                % validate (ya) argument
                validateattributes(h,{'SymExpression'},...
                    {'nonempty','vector'},...
                    'HolonomicConstraint','h');
                if isrow(h) % convert to column vector if it is a row vector
                    h = vertcat(h(:));
                end
            elseif isfield(args, 'LoadPath') && ~isempty(args.LoadPath)
                h = SymExpression([]);
                h = load(h, args.LoadPath, obj.h_name);
            else
                error(['Unable to create the HolonomicConstraint object. ',...
                    'Either the expression is empty or the load path is not specified.'],...
                    'HolonomicConstraint');
            end

            if isfield(args, 'LoadPath') && ~isempty(args.LoadPath)
                is_loaded = true;
            else
                is_loaded = false;
            end

            dim = length(h);
            obj.Dimension = dim;

            hd = SymVariable(obj.ParamName, [dim,1]);
            obj.Param = hd;
            obj.Input = SymVariable(obj.InputName,[dim,1]);

            if is_loaded % the loaded expression is h:= h_a - h_d
                obj.h_ = SymFunction(obj.h_name, h, {x, hd});
            else
                obj.h_ = SymFunction(obj.h_name, h-hd, {x, hd});
            end

            % validate and assign the desired outputs
            if isfield(args, 'ConstrLabel')
                obj.setConstrLabel(args.ConstrLabel);
            end

            if is_loaded
                Jh = SymFunction(obj.Jh_name, [], {model.States.x});
                obj.Jh_ = load(Jh,args.LoadPath);
            else
                if isfield(args, 'Jacobian')
                    obj.setJacobian(args.Jacobian);
                end
            end

            if isfield(args, 'DerivativeOrder')
                obj.setDerivativeOrder(args.DerivativeOrder);
            end

            if is_loaded
                obj.configure(args.LoadPath);
            else
                obj.configure();
            end

        end

    end

    methods

        % configure and compile the holonomic constraints
        obj = configure(obj, load_path);

        % enforce as NLP constraints
        nlp = imposeNLPConstraint(obj, nlp);

        % calculate the Jacobian matrix of the holonomic constraints
        [Jh, dJh] = calcJacobian(obj, x, dx);

        h = calcConstraint(obj, x);

        % save the symbolic expressions
        saveExpression(obj, export_path, varargin);

    end

    % set functions
    methods

        function export(obj, export_path, varargin)
            % export the symbolic expressions of the constraints matrices and
            % vectors and compile as MEX files.
            %
            % Parameters:
            %  export_path: the path to export the file @type char
            %  varargin: variable input parameters @type varargin
            %   Vars: a list of symbolic variables @type SymVariable
            %   File: the (full) file name of exported file @type char
            %   ForceExport: force the export @type logical
            %   BuildMex: flag whether to MEX the exported file @type logical
            %   Namespace: the namespace of the function @type char

            export(obj.h_,export_path, varargin{:});
            export(obj.Jh_,export_path, varargin{:});

            if ~isempty(obj.dJh_)
                export(obj.dJh_,export_path, varargin{:});
            end

        end

        % Jacobian matrix
        function obj = setJacobian(obj, jac)
            % sets the Jacobian matrix of the holonomic constraints if it
            % is provided directly by the users
            %
            % Parameters:
            % jac: the jacobian matrix @type SymExpression

            model = obj.Model;
            if nargin > 1
                validateattributes(jac,{'SymExpression'},...
                    {'2d','size',[obj.Dimension,model.numState]},...
                    'HolonomicConstraint','Jacobian');
            else
                jac = jacobian(obj.h_, model.States.x);
            end
            obj.Jh_ = SymFunction(obj.Jh_name, jac, {model.States.x});
        end

        % RelativeDegree
        function obj = setDerivativeOrder(obj, degree)
            % sets the highest derivative order of holonomic constraints in
            % order to enforce as bilateral constraints of the system
            %
            % Parameters:
            % degree: derivative order @type integer

            if degree == 1
                error('Currently we do not support J(x)dx = 0 type of holonomic constraitns.')
            end

            validateattributes(degree, {'double'},...
                {'nonempty','scalar','positive','integer','>=',1,'<=',2},...
                'HolonomicConstraint','DerivativeOrder');
            obj.DerivativeOrder = degree;

        end

        % OutputLabel
        function obj = setConstrLabel(obj, label)
            % sets the naming labels of outputs
            %
            % Parameters:
            % label: the cell array of labels @type cellstr

            validateattributes(label,{'cell'},...
                {'nonempty','numel',obj.Dimension,'row'},...
                'HolonomicConstraint','ConstrLabel');
            cellfun( @(x) validateattributes(...
                x, {'char'},{}), label);

            obj.ConstrLabel = label;
        end

        % Name
        function name = validateName(~, name)
            validateattributes(name, {'char'},...
                {'nonempty','scalartext'},...
                'HolonomicConstraint','Name');

            assert(isempty(regexp(name, '\W', 'once')) || ~isempty(regexp(name, '\$', 'once')),...
                'HolonomicConstraint:invalidSymbol', ...
                'Invalid symbol string, can NOT contain special characters.');

            assert(isempty(regexp(name, '_', 'once')),...
                'HolonomicConstraint:invalidSymbol', ...
                'Invalid symbol string, can NOT contain ''_''.');

        end
    end
end


classdef H1Projector_toP1Discontinuous < Projector

    methods (Access = public)

        function obj = H1Projector_toP1Discontinuous(cParams)
            obj.init(cParams);
        end

        function xProj = project(obj, x)
            LHS = obj.computeLHS();
            RHS = obj.computeRHS(x);
            f = LHS\RHS;
            fVals = obj.reshapeFValues(f, x.ndimf);
            s.mesh    = obj.mesh;
            s.fValues = fVals;
            xProj = P1DiscontinuousFunction(s);
        end

    end

    methods (Access = private)

        function LHS = computeLHS(obj)
            LHSM    = obj.computeMassMatrix();
            LHSK    = obj.computeStiffnessMatrix();
            epsilon = obj.mesh.computeMeanCellSize();
            LHS     = LHSM + epsilon^2*LHSK;
        end

        function LHSM = computeMassMatrix(obj)
            s.fun  = P1DiscontinuousFunction.create(obj.mesh, 1);
            s.mesh = obj.mesh;
            s.type = 'MassMatrix';
            s.quadratureOrder = 'QUADRATIC';
            lhs = LHSintegrator.create(s);
            LHSM = lhs.compute();
        end

        function LHSK = computeStiffnessMatrix(obj)
            s.type  = 'StiffnessMatrix';
            s.mesh  = obj.mesh;
            s.fun   = P1DiscontinuousFunction.create(obj.mesh,1);
            s.quadratureOrder = 'CONSTANT';
            lhs = LHSintegrator.create(s);
            LHSK = lhs.compute();
        end

        function RHS = computeRHS(obj,fun)
            quad = obj.createRHSQuadrature(fun);
            xV = quad.posgp;
            dV = obj.mesh.computeDvolume(quad);
            obj.mesh.interpolation.computeShapeDeriv(xV);
            shapes = permute(obj.mesh.interpolation.shape,[1 3 2]);
            conne = obj.createDiscontinuousConnectivity();

            nGaus = quad.ngaus;
            nFlds = fun.ndimf;
            nElem = obj.mesh.nelem;
            nNode = size(conne,2);
            nDofs = nElem*nNode;

            fGaus = fun.evaluate(xV);
            f     = zeros(nDofs,nFlds);
            for iField = 1:nFlds
                for igaus = 1:nGaus
                    dVg(:,1) = dV(igaus, :);
                    fG = squeeze(fGaus(iField,igaus,:));
                    for inode = 1:nNode
                        dofs = conne(:,inode);
                        Ni = shapes(inode,igaus);
                        int = Ni.*fG.*dVg;
                        f(dofs,iField) = f(dofs,iField) + int;
                    end
                end
            end
            RHS = f;
        end

        function conn = createDiscontinuousConnectivity(obj)
            nElem   = obj.mesh.nelem;
            nNodeEl = obj.mesh.nnodeElem;
            nDofs   = nElem*nNodeEl;
            dofs = 1:nDofs;
            conn = reshape(dofs, [nNodeEl,nElem])';
        end

        function q = createRHSQuadrature(obj, fun)
            ord = obj.determineQuadratureOrder(fun);
            q = Quadrature.set(obj.mesh.type);
            q.computeQuadrature(ord);
        end

        function fVals = reshapeFValues(obj, x, nFlds)
            nElem = obj.mesh.nelem;
            nNode = obj.mesh.nnodeElem;
            fVals = reshape(x',nFlds, nNode, nElem);
        end

    end

end


function flowplot(qmethod,sol,By,Bx,A,xy,xyp,x,y,bound,spc,fig)
%flowplot   plots flow data on square-shaped domain
%   flowplot(qmethod,sol,By,Bx,A,xy,xyp,x,y,bound,spc,fig);
%   input
%          qmethod    mixed method
%          sol        flow solution vector
%          By         velocity  y-derivative matrix
%          Bx         velocity x-derivative matrix
%          A          vector diffusion matrix
%          xy         velocity nodal coordinate vector
%          xyp        pressure nodal coordinate vector
%          x          vector of x-axis interpolation points
%          y          vector of y-axis interpolation points
%          bound      boundary vertex vector
%          spc        uniform/nonuniform streamline switch
%          fig        figure number
%
%   IFISS function: DJS; 30 March 2005.
% Copyright (c) 2005 D.J. Silvester, H.C. Elman, A. Ramage
nvtx=length(xy); nu=2*nvtx; np=length(xyp);
Asv=A(1:nvtx,1:nvtx);
%
% compute auxilliary quantites
u=sol(1:nu);p=sol(nu+1:end);
f=[By,-Bx]*u;
[Asv,fsv] = nonzerobc(Asv,f,xy,bound);
phi=Asv\fsv;
%
%% plot pressure
if qmethod==2
   xx=x(1:2:end); yy=y(1:2:end);
elseif qmethod==3
   p=p(1:3:end); xx=x(1:end); yy=y(1:end);
else
   xx=x(1:end); yy=y(1:end);
end
% interpolate to a cartesian product mesh
[X,Y]=meshgrid(xx,yy);
xysol = griddata(xyp(:,1),xyp(:,2),p,X,Y);
figure(fig)
subplot(122), mesh(X,Y,xysol),axis('square')
title('pressure field')
%
%% plot velocity
[X,Y]=meshgrid(x,y);
xysol = griddata(xy(:,1),xy(:,2),phi,X,Y);
if spc==1,
   subplot(121),contour(X,Y,xysol,20),axis('square')
   title('Streamlines: uniform');
   if all([min(x),max(x),min(y),max(y)] == [-1,1,-1,1]), squarex, end
elseif spc==2,
   v=[-15:1.3:6]';v=exp(v); list=sort([-v;v]);
   subplot(121),contour(X,Y,xysol,list),axis('square')
   title('Streamlines: selected');
   if all([min(x),max(x),min(y),max(y)] == [-1,1,-1,1]), squarex, end
end
axis('off')
subplot(111)
return


function [dm] = directmethods(y,lags,options)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 'directmethods' generates local projeciton IRF and direct forecasts

% Core Inputs:
% - y, data columns variables
% - lags, lag order of the VAR

% Additonal Inputs collected options
% (...) see below
% See the Hitchhiker's guide for more details.
% https://github.com/naffe15/BVAR_/blob/master/HitchhikerGuide_.pdf

% Filippo Ferroni, 27/02/2020
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if nargin < 2
    error('the BVAR toolbox needs at least two inputs: data and number of lags');
end
if lags < 1
    error('lags cannot be zero or negative');
end
% number of observable variables
[T,ny]       = size(y);

%********************************************************
%* DEFAULT SETTINGS
%********************************************************
% Control random number generator
if isOctave == 0
    isMatlab = 1;
    rng('default');
    rng(999);
else
    isMatlab = 0;
    % pkg load optim
     pkg load statistics
    randn('state',999);
    rand('state',999);
end

hor          = 24;
conf_sig     = 0.9;
controls_    = 0;
robust_se_   = 1; % by default robust SE
proxy_       = 0;
noconstant   = 0;
ns           = 0;
Q            = eye(ny);
dummy        = 0;
K            = 5000;
max_prior_tau_ = 0;
lb             = -1e10;
ub             = 1e10;
clags         = 0;

%********************************************************
%* CUSTOMIZED SETTINGS
%********************************************************
if nargin>2
    %======================================================================
    % Various options
    %======================================================================
    if isfield(options,'hor') ==1 % horizon of IRF and Forecasts
        hor = options.hor;
    end
    if isfield(options,'conf_sig') ==1 % CI of OLS estimation of LP and DF
        conf_sig = options.conf_sig;
    end
    if isfield(options,'Q') == 1 % orthonormal matrix
        Q = options.Q;
    end
    if isfield(options,'K') == 1 % # of draws for the BLP
        K = options.K;
    end
    %======================================================================
    % options: adding controls
    %======================================================================
    if isfield(options,'controls') ==1
        controls_  = 1;
        controls   = options.controls;
        if T~=size(controls,1)
            error('Control variables and observables must have the same time length')
        end
        if isfield(options,'clags') ==1
            clags = options.clags;
        end
    end
    %======================================================================
    % options: adding proxy variable for identification
    %======================================================================
    if isfield(options,'proxy') ==1
        proxy_  = 1;
        proxy   = options.proxy;
        ns      = size(proxy,2);
        if T~=size(proxy,1)
            error('Shocks proxies and observables must have the same time length')
        end
    end
    %======================================================================
    % options: Compuing Robust Standard Errors
    %======================================================================
    if isfield(options,'robust_se_') == 1
        robust_se_ = options.robust_se_;
        % robust_se_ = 0    unadjusted SE
        % robust_se_ = 1    NW Robust SE:  Hamilton (1994), Ch 10 pag 282, eq (10.5.20)
        % robust_se_ = 5    Matlab HAC function: need Matlab Econ Toolbox
    end
    %======================================================================
    % Conjugate/Hierachical prior options
    %======================================================================
    if (isfield(options,'priors')==1 && strcmp(options.priors.name,'Conjugate')==1) || (isfield(options,'priors')==1 && strcmp(options.priors.name,'conjugate')==1) || ...
            (isfield(options,'prior')==1 && strcmp(options.prior.name,'Conjugate')==1) || (isfield(options,'prior')==1 && strcmp(options.prior.name,'conjugate')==1)

        dummy = 2;
        prior.name= 'Conjugate';
        % Priors for the AR parameters
        if isfield(options.priors,'Phi') == 1
            % mean
            if isfield(options.priors.Phi,'mean') == 1
                prior.Phi.mean  = options.priors.Phi.mean;
                if size(prior.Phi.mean) ~= [ny*lags+(1-noconstant)    ny]
                    error('Size mismatch')
                end
            else
                warning(['You did not provide a prior mean for the AR coeff. ' ...
                    'Assume zeros everywhere.'])
                prior.Phi.mean  = zeros(ny*lags+(1-noconstant) , ny);
            end
            % variance
            if isfield(options.priors.Phi,'cov') == 1
                prior.Phi.cov   = options.priors.Phi.cov;
                if length(prior.Phi.cov) ~= (ny*lags+(1-noconstant) ) || size(prior.Phi.cov,1 )~=size(prior.Phi.cov,2)
                    error('Size mismatch: Covariance Phi should be square, e.g. size(Phi.mean,1)x size(Phi.mean,1)x')
                end
            else
                warning(['You did not provide a Covariance for the AR coeff. ' ...
                    'Assume 10 times Identity Matrix.'])
                prior.Phi.cov  = 10 * eye((ny*lags+(1-noconstant) ));
            end
        else
            warning(['You did not provide prior mean and covariance for the AR coeff ' ...
                'Assume zeros everywhere with covariance 10 times Identity Matrix.'])
            %             prior.Phi.cov   = 10 * eye((ny*lags+(1-noconstant) +timetrend ) * ny);
            prior.Phi.cov   = 10 * eye((ny*lags+(1-noconstant)  ));
            prior.Phi.mean  = zeros(ny*lags+(1-noconstant) ,  ny);
        end
        % Priors for the Residual Covariance
        if isfield(options.priors,'Sigma') == 1
            % scale
            if isfield(options.priors.Sigma,'scale') == 1
                prior.Sigma.scale = options.priors.Sigma.scale;
                if size(prior.Sigma.scale) ~= [ny ny]
                    error('Size mismatch')
                end
            else
                warning(['You did not provide a prior mean for the Residual Covariance. ' ...
                    'Assume identity matrix.'])
                prior.Sigma.scale = eye(ny);
            end
            % degrees of freedom
            if isfield(options.priors.Sigma,'df') == 1
                prior.Sigma.df = options.priors.Sigma.df;
                if length(prior.Sigma.df) ~= 1
                    error('Size mismatch')
                end
                if prior.Sigma.df < ny
                    error('Too few degrees of freedom - prior on variance residuals')
                end
            else
                warning(['You did not provide the degrees of freedom for the Residual Covariance. ' ...
                    'Assume ny+1.'])
                prior.Sigma.df = ny + 1;
            end
        else
            warning(['You did not provide prior mean and variance for the Residual Covariance. ' ...
                'Assume an identity matrix matrix with N+1 degrees of freedom.'])
            prior.Sigma.scale = eye(ny);
            prior.Sigma.df    = ny + 1;
        end
        if isfield(options.priors,'tau') == 1 && isnumeric(options.priors.tau) == 1
            prior.tau = options.priors.tau;
            if length(options.priors.tau) ~= hor
                error('tau must be a vector of size hor')
            end
        elseif isfield(options.priors,'max_tau') == 1 && options.priors.max_tau ==1
            max_prior_tau_ = 1;
            max_compute    = 3;
            prior.tau = ones(hor,1);
        else
            prior.tau = ones(hor,1);
        end
    end
    % options for the maximization
    if isfield(options,'max_compute') == 1
        max_compute    = options.max_compute;
        max_prior_tau_ = 1;
    end
    if isfield(options,'ub') == 1
        ub    = options.ub;
        if length(ub) ~=  length(prior.tau)
            error('Mismatch between the size of upper bounds and the param vector');
        end
    end
    if isfield(options,'lb') == 1
        lb    = options.lb;
        if length(lb) ~=  length(prior.tau)
            error('Mismatch between the size of lower bounds and the param vector');
        end
    end
end

% Confidence Interval Points and Index for confidence serts
alpha  = 1 - conf_sig;
talpha = abs(tinv(alpha/2,T-ny-1));
sort_idx   = round((0.5 + [-conf_sig, conf_sig, 0]/2) * K);

%**************************************************
% Construct the RHS matrix
%**************************************************

X1 = lagX(y,1:lags);
positions_nylags = 1  : size(X1,2);
nylags           = length(positions_nylags);

% forecast launching point
fdata_initval            = lagX(y(end-lags+1:end, :),0:lags-1);
fdata_initval(1:end-1,:) = [];
% add controls if any
if controls_ == 1
    a  = size(X1,2) + 1;
    X1 = [X1 lagX(controls,0:clags)];
    b  = size(X1,2);
    position_controls = a:b;
    % forecast launching point
    %lastvalc = lagX(controls(end-lags+1:end, :),0:lags-1);
    fdata_initval  = [fdata_initval, controls(end,:)];

else
    position_controls = [];
end
% add proxy shocks if any
if proxy_ == 1
    a     = size(X1,2) + 1;
    X1    = [X1 proxy];
    b     = size(X1,2);
    position_proxy = a:b ;
    % forecast launching point (assume shocks are zero)
    fdata_initval  = [fdata_initval,  zeros(1,ns)];
else
    position_proxy = [];
end
X_ = X1;
if noconstant == 0
    X_ = [X1 ones(T,1)];
    position_constant = size(X_,2);
    % forecast launching point
    fdata_initval  = [fdata_initval, 1];
else
    position_constant = [];
end
nx           = 1 - noconstant;
% other checks
if (lags + hor) >= size(X_,1)
    error('More parameters than observations: consider reducing ''hor'' or ''lags''')
end

%**************************************************
% pre allocation
%**************************************************
Omegaproxy  = eye(ny);
Omega       = eye(ny);
ir_lp       = nan(ny,hor+1,ny,3);  % variable, horizon, shock and mean upper lower
irproxy_lp  = nan(ny,hor+1,1,3);
forecasts   = nan(hor,ny,3);
if dummy == 2
    ir_blp                  = nan(ny,hor+1,ny,K);
    irproxy_blp             = nan(ny,hor+1,1,K);
    bforecasts_no_shocks    = nan(hor,ny,K);
    bforecasts_with_shocks  = nan(hor,ny,K);
    log_dnsty               = nan(hor,1);
end

%**************************************************
%* Computing the LP and DF
%**************************************************
wb = waitbar(0, 'Direct Methods');
for hh = 0 : hor % iteration over horizon
    ytmp = lagX(y, -hh);
    % Reduced Form estimations
    if robust_se_ ~= 0 % Robust SE
        options.robust_se_ = robust_se_;
        options.L     = lags + hh + 1;
        olsreg_(hh+1) = ols_reg(ytmp, X_, options);
    else
        olsreg_(hh+1) = ols_reg(ytmp, X_);
    end
    % Proxy IV identifications
    if proxy_
        irproxy_lp(:, hh+1, :, 2) = olsreg_(hh+1).beta(position_proxy, :)'; % mean
        irproxy_lp(:, hh+1, :, 3) = irproxy_lp(:, hh+1, :, 2) + talpha * olsreg_(hh+1).se(position_proxy, :)'; % upper
        irproxy_lp(:, hh+1, :, 1) = irproxy_lp(:, hh+1, :, 2) - talpha * olsreg_(hh+1).se(position_proxy, :)'; % lower
        if hh == 0
            Omegaproxy(:,1) = olsreg_(hh+1).beta(position_proxy, :)';
            Omegasproxy(:,1,:) =  repmat(Omegaproxy(:,1), 1, 1, K) + ...
                olsreg_(hh+1).se(position_proxy, :)'.* randn(ny,1,K);
        end
    end
    % Choleski/Rotated identification
    if hh == 0
        try
            Omega = chol(olsreg_(hh+1).Serror,'Lower') * Q;
        catch
            warning('Covariance of the error term is almost singular')
            Omega = chol(cov(olsreg_(hh+1).error),'Lower') * Q;
        end
        % generate uncertainty on S (flat prior)
        Sbar = olsreg_(hh+1).error'*olsreg_(hh+1).error;
        df   = olsreg_(hh+1).N - olsreg_(hh+1).K;
        if df > 0
        [~, Omegas] = generateOmegas(Sbar,df,K,Q);
            Omegasort = sort(Omegas,3);
        else
            warning('not enought degrees of freedom - too many regressors')
            Omegasort = repmat(Omega,1,1,K);
        end
        ir_lp(:, hh+1, :, 2) = Omega; % mean
        ir_lp(:, hh+1, :, 3) = Omegasort(:,:,sort_idx(2)); % UPPER
        ir_lp(:, hh+1, :, 1) = Omegasort(:,:,sort_idx(1)); % LOWER
    else
        [ir] =  iresponse(olsreg_(hh).beta(positions_nylags, :), eye(ny) , 2, Omega);
        ir_lp(:, hh+1, :, 2) = ir(:, 2, :);  % mean
        [ir3] =  iresponse(olsreg_(hh).beta(positions_nylags, :) + talpha * olsreg_(hh).se(positions_nylags, :), eye(ny) , 2, Omega);
        ir_lp(:, hh+1, :, 3) = ir3(:, 2, :); % upper
        [ir1] =  iresponse(olsreg_(hh).beta(positions_nylags, :) - talpha * olsreg_(hh).se(positions_nylags, :), eye(ny) , 2, Omega);
        ir_lp(:, hh+1, :, 1) = ir1(:, 2, :); % lower
    end

    % forecast part
    forecasts(hh+1, :, 2) = (fdata_initval * olsreg_(hh+1).beta);
    forecasts(hh+1, :, 3) = forecasts(hh+1, :, 2) + talpha * diag(olsreg_(hh+1).Serror)' ;
    forecasts(hh+1, :, 1) = forecasts(hh+1, :, 2) - talpha * diag(olsreg_(hh+1).Serror)' ;

    %======================================================================
    % Baysian DM
    if dummy == 2 % activating Bayesian Direct methods.
        if hh == 0
            % cholesky IRF on impact
            ir_blp(:, hh+1, :, :)  = Omegas;
            % proxy IRF on impact
            if proxy_
                irproxy_blp(:, hh+1, :, :) = Omegasproxy;
            end
            % one-step ahead forecast
            bforecasts_no_shocks(hh+1, :, :)   = repmat(forecasts(hh+1, :, 2),1,1,K);
            fnoise = Omega * randn(ny,K);
            bforecasts_with_shocks(hh+1, :, :) = bforecasts_no_shocks(hh+1, :, :) + reshape(fnoise,1,ny,K);

            % computing the companion matrix
            F       = [prior.Phi.mean(1 : ny * lags, :)'; eye(ny*(lags-1), ny*lags)];
            % constant
            Fo        = [prior.Phi.mean(end, :)'; zeros(ny * (lags-1), 1)];
            % Shocks Companion
            G       = eye(ny * lags, ny);

        else % hh > 0
            %********************************************************
            % Conjugate Prior: MN-IW
            %********************************************************
            if max_prior_tau_ == 1 % Maximize the shrinkage on the VAR coefficients
                try
                    disp(['***********************************************'])
                    disp(['***********************************************'])
                    disp(['Optimization at horizon ' num2str(hh)])
                    x0   = log(prior.tau(hh));
                    switch max_compute
                        case 1
                            optim_options = optimset('display','iter','MaxFunEvals',100000,'TolFun',1e-8,'TolX',1e-6);
                            [xh,fh,~,~,~,~] = ...
                                fminunc('blp_opt_hyperpara',x0,optim_options,...
                                hh,prior,olsreg_(hh),F,G,Fo,positions_nylags,position_constant);
                            %=====================================================================
                        case 2 % constraint
                            % Set default optimization options for fmincon.
                            optim_options = optimset('display','iter', 'LargeScale','off', 'MaxFunEvals',100000, 'TolFun',1e-8, 'TolX',1e-6);
                            [xh,fh,~,~,~,~,~] = ...
                                fmincon('blp_opt_hyperpara',x0,[],[],[],[],lb(hh),ub(hh),[],optim_options,y,lags,options);
                            %=====================================================================
                        case 3 % Sims
                            crit = 10e-5;
                            nit  = 10e-4;
                            [fh, xh, ~, ~, ~, ~, ~] = ...
                                csminwel('blp_opt_hyperpara',x0,.1*eye(length(x0)),[],crit,nit,hh,prior,olsreg_(hh),F,G,Fo,positions_nylags,position_constant);
                            %=====================================================================
                        case 7 % Matlab's simplex (Optimization toolbox needed).
                            optim_options = optimset('display','iter','MaxFunEvals',30000,'MaxIter',10000,'TolFun',1e-3,'TolX',1e-3);
                            [xh,fh,~,~] = fminsearch('blp_opt_hyperpara',x0,optim_options,y,lags,options);
                    end
                    fprintf('%s = %0.5g\n','Hyper-parameter Mode ',exp(xh))
                    fprintf('%s = %0.5g\n','Marginal Likelihood ',-fh)
                catch
                    warning('Maximization NOT Successful')
                    disp('Using hyper parameter default values')
                    xh = x0;
                end
                prior.tau(hh) = exp(xh);
                disp(['***********************************************'])
            end
            % constructing the posterior moments given the (optimal) shrinkage
            [posterior_, ~]   = p2p(hh,prior.tau(hh),prior,olsreg_(hh),F,G,Fo,positions_nylags,position_constant);
            % computing the marginal likelihood
            log_dnsty(hh)     = blp_ml(prior.tau(hh),hh,prior,olsreg_(hh),F,G,Fo,positions_nylags,position_constant);
            % Second moments
            S_inv_upper_chol  = chol(inv(posterior_.S));
            XXi_lower_chol    = chol(posterior_.XXi)';
            % number of regressors
            nk = nylags + nx;
            %**************************************************
            %* Generating draws form the Posterior Distribution
            %**************************************************
            for  d =  1 : K %  Gibbs Sampler
                %======================================================================
                % Inferece: Drawing from the posterior distribution
                % Step 1: draw from the Covariance
                Sigma = rand_inverse_wishart(ny, posterior_.df, S_inv_upper_chol);

                % Step 2: given the Covariance Matrix, draw from the AR parameters
                Sigma_lower_chol = chol(Sigma)';
                Phi1 = randn(nk * ny, 1);
                Phi2 = kron(Sigma_lower_chol , XXi_lower_chol) * Phi1;
                Phi3 = reshape(Phi2, nk, ny);
                Phi  = Phi3 + posterior_.PhiHat;

                % Step 3: compute IRF
                blp  =  iresponse(Phi, eye(ny) , 2, Omega);
                ir_blp(:, hh+1, :, d) = blp(:, 2, :);  % mean
                if proxy_
                    blpproxy  =  iresponse(Phi, eye(ny) , 2, Omegaproxy);
                    irproxy_blp(:, hh+1, :, d) = blpproxy(:,2,1);
                end
                % Step 4: compute Forecasts
                bforecasts_no_shocks(hh+1, :, d) = (fdata_initval(1, [positions_nylags position_constant]) * Phi);
                bforecasts_with_shocks(hh+1, :, d) = (fdata_initval(1, [positions_nylags position_constant]) * Phi) + (Sigma_lower_chol * randn(ny,1))';
            end
        end
    end
    waitbar(hh/hor, wb);
end
close(wb);

%********************************************************
%* Storing the resutls
%*******************************************************
% dm.olsreg_     = olsreg_;
dm.forecasts   = forecasts;
dm.ir_lp       = ir_lp;
dm.irproxy_lp  = irproxy_lp;
if dummy == 2
    dm.ir_blp                 = ir_blp;
    dm.irproxy_blp            = irproxy_blp;
    dm.bforecasts.no_shocks   = bforecasts_no_shocks;         % trajectories of forecasts without shocks
    dm.bforecasts.with_shocks = bforecasts_with_shocks;       % trajectories of forecasts with shocks
    dm.logmlike               = log_dnsty;
    dm.prior                  = prior;
else
    dm.ir_blp                 = [];
    dm.irproxy_blp            = [];
    dm.bforecasts.no_shocks   = [];
    dm.bforecasts.with_shocks = [];
    dm.logmlike               = [];
    dm.prior                  = [];
end

%**************************************************************************
%**************************************************************************
%**************************************************************************
%**************************************************************************
function [S,Omegas] = generateOmegas(Sbar,df,K,Q)
% generate uncertainty on S
ny      = size(Sbar,1);
S       = nan(ny,ny,K);
Omegas  = nan(ny,ny,K);

S_inv_upper_chol = chol(inv(Sbar));

for  d = 1:K
    S(:,:,d)      = rand_inverse_wishart(ny, df, S_inv_upper_chol);
    Omegas(:,:,d) = chol(S(:,:,d),'Lower') * Q;
end


function [tow,prn,P1,Phi1,P2,Phi2,eof] = readGrilR
%READGRIL Reading a binary GRIL files.
%         The following message was sent to receiver:
%             em,,/msg/jps/{GT,SI,R1,P1,R2,P2}
%             dm

%Kai Borre November 12, 2007
%Copyright (c) by Kai Borre
%$Revision: 1.1 $  $Date: 2007/11/12 $

global fidr

% Constants
c = 299792458;  % vacuum speed of light, m/s
f1 = 154*10.23E6;			% L1 frequency Hz
f2 = 120*10.23E6;			% L2 frequency Hz
lambda1 = c/f1;	     % wavelength on L1:  .19029367  m
lambda2 = c/f2;	     % wavelength on L2:  .244210213 m
Pi = 3.1415926535898; % GPS value for pi
eof = 0;

% struct GPSEphemeris
et = fread(fidr,5,'uint8');
if isempty(et) == 1
    eof = 1;
    tow = 0;
    prn = [];
    P1 = [];
    Phi1 = [];
    P2 = P1;
    Phi2 = Phi1;
    return;
end

while strcmp(char(et(1:2)'), 'GE')
    %et2 = hex2dec(et1(3:end));
    sv = fread(fidr,1,'uint8');
    i = 1;% sv;
    eph(1,i) = sv;
    tow = fread(fidr,1,'uint32');
    flags = fread(fidr,1,'uint8');
    iodc = fread(fidr,1,'int16');
    eph(21,i) = fread(fidr,1,'int32'); % toc
    ura = fread(fidr,1,'int8');
    healthS = fread(fidr,1,'uint8');
    wn = fread(fidr,1,'int16');
    tgd = fread(fidr,1,'single');
    eph(2,i) = fread(fidr,1,'single'); % af2
    eph(20,i) = fread(fidr,1,'single'); %af1
    eph(19,i) = fread(fidr,1,'single'); %af0
    eph(18,i) = fread(fidr,1,'int32'); %toe
    iode = fread(fidr,1,'int16');
    eph(4,i) = fread(fidr,1,'double'); %rootA
    eph(6,i) = fread(fidr,1,'double'); %ecc
    eph(3,i) = fread(fidr,1,'double')*Pi; %m0
    eph(16,i) = fread(fidr,1,'double')*Pi; %Omega0
    eph(12,i) = fread(fidr,1,'double')*Pi; %i0
    eph(7,i) = fread(fidr,1,'double')*Pi; %omega
    eph(5,i) = fread(fidr,1,'single')*Pi; %deltan
    eph(17,i) = fread(fidr,1,'single')*Pi; %Omegadot
    eph(13,i) = fread(fidr,1,'single')*Pi; %idot
    eph(10,i) = fread(fidr,1,'single'); %crc
    eph(11,i) = fread(fidr,1,'single'); %crs
    eph(8,i) = fread(fidr,1,'single'); %cuc
    eph(9,i) = fread(fidr,1,'single'); %cus
    eph(14,i) = fread(fidr,1,'single'); %cic
    eph(15,i) = fread(fidr,1,'single'); %cis
    cs = fread(fidr,1,'uint8');
    dummy = fread(fidr,1,'uint8');
    et = fread(fidr,5,'char');
    if ~strcmp(char(et(1:2)'), 'GE'), break; end
end

% struct GPSTime
if ~strcmp(char(et(1:2)'), 'GT')
    gt = fread(fidr,5,'uint8=>char');
else
    gt = et;
end
gt1 = char(gt');
%gt2 = str2num(gt1(3:end));
tow = fread(fidr,1,'uint32')/1000; %211 588 seconds
wn = fread(fidr,1,'uint16'); % 347 correct
cs = fread(fidr,1,'uint8');
dummy = fread(fidr,1,'uint8');

% struct SatIndex
si = fread(fidr,5,'char');
si1 = char(si');
si2 = hex2dec(si1(3:end));
for i = 1:si2-1
    prn(i) = fread(fidr,1,'uint8');
end
cs = fread(fidr,1,'uint8');
dummy = fread(fidr,1,'uint8');
PRN = prn;

% struct PR_P1
pr = fread(fidr,5,'char');
pr1 = char(pr');
pr2 = hex2dec(pr1(3:end));
for i = 1:si2-1
    prange1(i) = fread(fidr,1,'double')*c;
end
cs = fread(fidr,1,'uint8');
dummy = fread(fidr,1,'uint8');
P1 = prange1;

% struct PhaseP1
ph = fread(fidr,5,'char');
ph1 = char(ph');
ph2 = hex2dec(ph1(3:end));
for i = 1:si2-1
    phase1(i) = fread(fidr,1,'double')*lambda1;
end
cs = fread(fidr,1,'uint8');
dummy = fread(fidr,1,'uint8');
Phi1 = phase1;

% struct PR_P2
pr = fread(fidr,5,'char');
pr1 = char(pr');
pr2 = hex2dec(pr1(3:end));
for i = 1:si2-1
    prange2(i) = fread(fidr,1,'double')*c;
end
cs = fread(fidr,1,'uint8');
dummy = fread(fidr,1,'uint8');
P2 = prange2;

% struct PhaseP2
ph = fread(fidr,5,'char');
ph1 = char(ph');
ph2 = hex2dec(ph1(3:end));
for i = 1:si2-1
    phase2(i) = fread(fidr,1,'double')*lambda2;
end
cs = fread(fidr,1,'uint8');
dummy = fread(fidr,1,'uint8');
Phi2 = phase2;
%%%%%%%%% end readGrilR.m %%%%%%%%%%%%%%%%%%%%%%%%


function [output] = volumefillholes(input, along)

% VOLUMEFILLHOLES is a helper function for segmentations
%
% See also VOLUMETHRESHOLD, VOLUMESMOOTH

% ensure that SPM is available, needed for spm_bwlabel
hasspm = ft_hastoolbox('spm8up', 3) || ft_hastoolbox('spm2', 1);

if nargin<2
  inflate = false(size(input)+2);                   % grow the edges along each dimension
  inflate(2:end-1, 2:end-1, 2:end-1) = (input~=0);  % insert the original volume
  [lab, num] = spm_bwlabel(double(~inflate), 18);   % note that 18 is consistent with imfill, 26 is not
  if num>1
    inflate(lab~=lab(1)) = true;
    output  = inflate(2:end-1, 2:end-1, 2:end-1);   % trim the edges
  else
    output = input;
  end

else
  output = input;
  dim    = size(input);
  switch along
    case 1
      for i=1:dim(1)
        slice=reshape(input(i,:,:),dim([2 3]));
        im = imfill(slice,8,'holes');
        output(i,:,:) = im;
      end

    case 2
      for i=1:dim(2)
        slice=reshape(input(:,i,:),dim([1 3]));
        im = imfill(slice,8,'holes');
        output(:,i,:) = im;
      end

    case 3
      for i=1:dim(3)
        slice=reshape(input(:,:,i),dim([1 2]));
        im = imfill(slice,8,'holes');
        output(:,:,i) = im;
      end

    otherwise
      ft_error('invalid dimension along which to slice the volume');
  end % switch
end % if nargin