function tests = test_ft_preproc_padding

% MEM 1gb
% WALLTIME 00:10:00
% DEPENDENCY ft_preproc_padding

if nargout
  % assume that this is called by RUNTESTS
  tests = functiontests(localfunctions);
else
  % assume that this is called from the command line
  fn = localfunctions;
  for i=1:numel(fn)
    feval(fn{i});
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function testOptions(testCase)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

nchan   = 8;
nsample = 1000;
dat     = randn(nchan, nsample) + 1;

result = [];
result{end+1} = ft_preproc_padding(dat, 'zero',      10);
result{end+1} = ft_preproc_padding(dat, 'mean',      10);
result{end+1} = ft_preproc_padding(dat, 'localmean', 10);
result{end+1} = ft_preproc_padding(dat, 'edge',      10);
result{end+1} = ft_preproc_padding(dat, 'mirror',    10);
result{end+1} = ft_preproc_padding(dat, 'nan',       10);
result{end+1} = ft_preproc_padding(dat, 'remove',    10);
result{end+1} = ft_preproc_padding(dat, 'zero',      20);
result{end+1} = ft_preproc_padding(dat, 'mean',      20);
result{end+1} = ft_preproc_padding(dat, 'localmean', 20);
result{end+1} = ft_preproc_padding(dat, 'edge',      20);
result{end+1} = ft_preproc_padding(dat, 'mirror',    20);
result{end+1} = ft_preproc_padding(dat, 'nan',       20);
result{end+1} = ft_preproc_padding(dat, 'remove',    20);
result{end+1} = ft_preproc_padding(dat, 'zero',      10, 20);
result{end+1} = ft_preproc_padding(dat, 'mean',      10, 20);
result{end+1} = ft_preproc_padding(dat, 'localmean', 10, 20);
result{end+1} = ft_preproc_padding(dat, 'edge',      10, 20);
result{end+1} = ft_preproc_padding(dat, 'mirror',    10, 20);
result{end+1} = ft_preproc_padding(dat, 'nan',       10, 20);
result{end+1} = ft_preproc_padding(dat, 'remove',    10, 20);

for i=1:numel(result)
  % the number of samples should be larger, or smaller upon 'remove'
  assert(size(result{i},2)~=nsample);
end

% all iterations were done with (slightly) different options, hence the results should not be equal
for i=1:numel(result)
  for j=(i+1):numel(result)
    assert(~isequal(result{i}, result{j}), 'the results %d and %d should not be equal', i, j);
  end
end


function x = sample_vector(p,col)
%SAMPLE_VECTOR    Sample from multiple categorical distributions.
% X = SAMPLE_VECTOR(P) returns a row vector of cols(P) integers, where
% X(I) = SAMPLE(P(:,I)).
%
% X = SAMPLE_VECTOR(P,COL) returns a row vector of length(COL) integers, where
% X(I) = SAMPLE(P(:,COL(I))).
% This is equivalent to SAMPLE_VECTOR(P(:,COL)), but faster.

% Written by Tom Minka
% (c) Microsoft Corporation. All rights reserved.

cdf = cumsum(p);
if nargin >= 2
  cdf = cdf(:,col);
end
if any(cdf(end,:) <= 0)
  error('distribution is all zeros');
end
u = rand(1,cols(cdf)).*cdf(end,:);
x = col_sum(cdf < repmat(u,rows(cdf),1)) + 1;


function [x,y]=simulate(a,b,c,d,x0,T)
%Simulation of dynamical system
x(1)=x0;
for t=2:T
x(t)=random('normal',mx(a,x(t-1)),vx(b,x(t-1)));
y(t)=random('normal',my(c,x(t)),vy(d,x(t-1)));
end


function c = tapas_hgf_binary_mab_config
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Contains the configuration for the Hierarchical Gaussian Filter (HGF) in a multi-armded bandit
% situation for binary inputs in the absence of perceptual uncertainty.
%
% The HGF is the model introduced in
%
% Mathys C, Daunizeau J, Friston, KJ, and Stephan KE. (2011). A Bayesian foundation
% for individual learning under uncertainty. Frontiers in Human Neuroscience, 5:39.
%
% The binary HGF model has since been augmented with a positive factor kappa1 which
% scales the second level with respect to the first, i.e., the relation between the
% first and second level is
%
% p(x1=1|x2) = s(kappa1*x2), where s(.) is the logistic sigmoid.
%
% By default, kappa1 is fixed to 1, leading exactly to the model introduced in
% Mathys et al. (2011).
%
% This file refers to BINARY inputs (Eqs 1-3 in Mathys et al., (2011));
% for continuous inputs, refer to tapas_hgf_config.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% The HGF configuration consists of the priors of parameters and initial values. All priors are
% Gaussian in the space where the quantity they refer to is estimated. They are specified by their
% sufficient statistics: mean and variance (NOT standard deviation).
%
% Quantities are estimated in their native space if they are unbounded (e.g., the omegas). They are
% estimated in log-space if they have a natural lower bound at zero (e.g., the sigmas).
%
% Parameters can be fixed (i.e., set to a fixed value) by setting the variance of their prior to
% zero. Aside from being useful for model comparison, the need for this arises whenever the scale
% and origin at the j-th level are arbitrary. This is the case if the observation model does not
% contain the representations mu_j and sigma_j. A choice of scale and origin is then implied by
% fixing the initial value mu_j_0 of mu_j and either kappa_j-1 or omega_j-1.
%
% Fitted trajectories can be plotted by using the command
%
% >> tapas_hgf_binary_mab_plotTraj(est)
%
% where est is the stucture returned by tapas_fitModel. This structure contains the estimated
% perceptual parameters in est.p_prc and the estimated trajectories of the agent's
% representations (cf. Mathys et al., 2011). Their meanings are:
%
%         est.p_prc.mu_0       row vector of initial values of mu (in ascending order of levels)
%         est.p_prc.sa_0       row vector of initial values of sigma (in ascending order of levels)
%         est.p_prc.rho        row vector of rhos (representing drift; in ascending order of levels)
%         est.p_prc.ka         row vector of kappas (in ascending order of levels)
%         est.p_prc.om         row vector of omegas (in ascending order of levels)
%
% Note that the first entry in all of the row vectors will be NaN because, at the first level,
% these parameters are either determined by the second level (mu_0 and sa_0) or undefined (rho,
% kappa, and omega).
%
%         est.traj.mu          mu (rows: trials, columns: levels, 3rd dim: bandits)
%         est.traj.sa          sigma (rows: trials, columns: levels, 3rd dim: bandits)
%         est.traj.muhat       prediction of mu (rows: trials, columns: levels, 3rd dim: bandits)
%         est.traj.sahat       precisions of predictions (rows: trials, columns: levels, 3rd dim: bandits)
%         est.traj.v           inferred variance of random walk (rows: trials, columns: levels)
%         est.traj.w           weighting factors (rows: trials, columns: levels)
%         est.traj.da          volatility prediction errors  (rows: trials, columns: levels)
%         est.traj.ud          updates with respect to prediction  (rows: trials, columns: levels)
%         est.traj.psi         precision weights on prediction errors  (rows: trials, columns: levels)
%         est.traj.epsi        precision-weighted prediction errors  (rows: trials, columns: levels)
%         est.traj.wt          full weights on prediction errors (at the first level,
%                                  this is the learning rate) (rows: trials, columns: levels)
%
% Note that in the absence of sensory uncertainty (which is the assumption here), the first
% column of mu, corresponding to the first level, will be equal to the inputs. Likewise, the
% first column of sa will be 0 always.
%
% Tips:
% - When analyzing a new dataset, take your inputs u and use
%
%   >> est = tapas_fitModel([], u, 'tapas_hgf_binary_mab_config', 'tapas_bayes_optimal_binary_config');
%
%   to determine the Bayes optimal perceptual parameters (given your current priors as defined in
%   this file here, so choose them wide and loose to let the inputs influence the result). You can
%   then use the optimal parameters as your new prior means for the perceptual parameters.
%
% - If you get an error saying that the prior means are in a region where model assumptions are
%   violated, lower the prior means of the omegas, starting with the highest level and proceeding
%   downwards.
%
% - Alternatives are lowering the prior means of the kappas, if they are not fixed, or adjusting
%   the values of the kappas or omegas, if any of them are fixed.
%
% - If the log-model evidence cannot be calculated because the Hessian poses problems, look at
%   est.optim.H and fix the parameters that lead to NaNs.
%
% - Your guide to all these adjustments is the log-model evidence (LME). Whenever the LME increases
%   by at least 3 across datasets, the adjustment was a good idea and can be justified by just this:
%   the LME increased, so you had a better model.
%
% --------------------------------------------------------------------------------------------------
% Copyright (C) 2013-2017 Christoph Mathys, TNU, UZH & ETHZ
%
% This file is part of the HGF toolbox, which is released under the terms of the GNU General Public
% Licence (GPL), version 3. You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version). For further details, see the file
% COPYING or <http://www.gnu.org/licenses/>.

% Config structure
c = struct;

% Model name
c.model = 'hgf_binary_mab';

% Number of levels (minimum: 3)
c.n_levels = 3;

% Number of bandits
c.n_bandits = 3;

% Coupling
% This may only be set to true if c.n_bandits is set to 2 above. If
% true, it means that the two bandits' winning probabilities are
% coupled in the sense that they add to 1 and are both updated on
% each trial even though only the outcome for one of them is observed.
c.coupled = false;

% Input intervals
% If input intervals are irregular, the last column of the input
% matrix u has to contain the interval between inputs k-1 and k
% in the k-th row, and this flag has to be set to true
c.irregular_intervals = false;

% Sufficient statistics of Gaussian parameter priors

% Initial mus and sigmas
% Format: row vectors of length n_levels
% For all but the first two levels, this is usually best
% kept fixed to 1 (determines origin on x_i-scale). The
% first level is NaN because it is determined by the second,
% and the second implies neutrality between outcomes when it
% is centered at 0.
c.mu_0mu = [NaN, 0, 1];
c.mu_0sa = [NaN, 0, 0];

c.logsa_0mu = [NaN,   log(0.1), log(1)];
c.logsa_0sa = [NaN,          0,      0];

% Rhos
% Format: row vector of length n_levels.
% Undefined (therefore NaN) at the first level.
% Fix this to zero to turn off drift.
c.rhomu = [NaN, 0, 0];
c.rhosa = [NaN, 0, 0];

% Kappas
% Format: row vector of length n_levels-1.
% Fixing log(kappa1) to log(1) leads to the original HGF model.
% Higher log(kappas) should be fixed (preferably to log(1)) if the
% observation model does not use mu_i+1 (kappa then determines the
% scaling of x_i+1).
c.logkamu = [log(1), log(1)];
c.logkasa = [     0,      0];

% Omegas
% Format: row vector of length n_levels.
% Undefined (therefore NaN) at the first level.
c.ommu = [NaN,  -2,  -6];
c.omsa = [NaN, 4^2, 4^2];

% Gather prior settings in vectors
c.priormus = [
    c.mu_0mu,...
    c.logsa_0mu,...
    c.rhomu,...
    c.logkamu,...
    c.ommu,...
         ];

c.priorsas = [
    c.mu_0sa,...
    c.logsa_0sa,...
    c.rhosa,...
    c.logkasa,...
    c.omsa,...
         ];

% Check whether we have the right number of priors
expectedLength = 3*c.n_levels+2*(c.n_levels-1)+1;
if length([c.priormus, c.priorsas]) ~= 2*expectedLength;
    error('tapas:hgf:PriorDefNotMatchingLevels', 'Prior definition does not match number of levels.')
end

% Model function handle
c.prc_fun = @tapas_hgf_binary_mab;

% Handle to function that transforms perceptual parameters to their native space
% from the space they are estimated in
c.transp_prc_fun = @tapas_hgf_binary_mab_transp;

return;


function sc = patchCorr(imId,pix,ptch,method)

% PATCHCORR  Correlation score of a patch in an image
%   PATCHCORR(IMID,PIX,PATCH,METHOD) computes the correlation score
%   between PATCH and the corresponding patch centered at pixel
%   PIX in the _global_ image Image{IMID}, using METHOD.
%
%   PATCH is a structure containing:
%     I:   Matrix with pixellic values of the patch
%     SI:  Sum of all pixellic values
%     SII: Sum of all squared pixellic values
%
%   METHOD is one of the following strings 'zncc', 'ssd', 'census'
%
%   See also ZNCC, SSD, CENSUS

%   (c) 2005 Joan Sola

% patch size
pSze = size(ptch.I);

% pixel centered image patch
iPatch = pix2patch(imId,pix,pSze(2),pSze(1));

if nargin<4
    method = 'zncc';
end

switch lower(method)
    case 'zncc'
        sc = zncc(...
            ptch.I,iPatch.I,...
            ptch.SI,ptch.SII,...
            iPatch.SI,iPatch.SII);
    case 'ssd'
        sc = ssd(ptch,iPatch);
    case 'census'
        sc = census(ptch,iPatch);
    otherwise
        error('Unknown correlation method.')
end

% ========== End of function - Start GPL license ==========

%   # START GPL LICENSE

%---------------------------------------------------------------------
%
%   This file is part of SLAMTB, a SLAM toolbox for Matlab.
%
%   SLAMTB is free software: you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation, either version 3 of the License, or
%   (at your option) any later version.
%
%   SLAMTB is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You should have received a copy of the GNU General Public License
%   along with SLAMTB.  If not, see <http://www.gnu.org/licenses/>.
%
%---------------------------------------------------------------------

%   SLAMTB is Copyright:
%   Copyright (c) 2008-2010, Joan Sola @ LAAS-CNRS,
%   Copyright (c) 2010-2013, Joan Sola,
%   Copyright (c) 2014-2015, Joan Sola @ IRI-UPC-CSIC,
%   SLAMTB is Copyright 2009
%   by Joan Sola, Teresa Vidal-Calleja, David Marquez and Jean Marie Codol
%   @ LAAS-CNRS.
%   See on top of this file for its particular copyright.

%   # END GPL LICENSE


%% DEMO_febio_0054_lattice_hydrostatic_01
% Below is a demonstration for:
%
% * Building geometry for a cube with hexahedral elements
% * Defining the boundary conditions
% * Coding the febio structure
% * Running the model
% * Importing and visualizing the displacement and stress results

%% Keywords
%
% * febio_spec version 3.0
% * febio, FEBio
% * uniaxial loading
% * compression, tension, compressive, tensile
% * displacement control, displacement boundary condition
% * hexahedral elements, hex8
% * cube, box, rectangular
% * static, solid
% * hyperelastic, Ogden
% * displacement logfile
% * stress logfile

%%

clear; close all; clc;

%% Plot settings
% Plot settings
fontSize=15;
faceAlpha1=0.8;
faceAlpha2=1;
edgeColor=0.25*ones(1,3);
edgeWidth=1.5;
markerSize=25;
cMap=gjet(4);

%% Control parameters

% Path names
defaultFolder = fileparts(fileparts(mfilename('fullpath')));
savePath=fullfile(defaultFolder,'data','temp');

% Defining file names
febioFebFileNamePart='tempModel';
febioFebFileName=fullfile(savePath,[febioFebFileNamePart,'.feb']); %FEB file name
febioLogFileName=fullfile(savePath,[febioFebFileNamePart,'.txt']); %FEBio log file name
febioLogFileName_disp=[febioFebFileNamePart,'_disp_out.txt']; %Log file name for exporting displacement
febioLogFileName_force=[febioFebFileNamePart,'_force_out.txt']; %Log file name for exporting force
febioLogFileName_stress=[febioFebFileNamePart,'_stress_out.txt']; %Log file name for exporting stress
febioLogFileName_stiffness=[febioFebFileNamePart,'_stiffness_out.txt']; %Log file name for exporting stiffness

%Specifying dimensions and number of elements
sampleSize=10;
latticeType=1;

%Define applied displacement
J_final=0.7; %Final Jacobian or volume ration
lambdaFinal=J_final^(1/3); %Stretch values in all directions
displacementMagnitude=((lambdaFinal*sampleSize)-sampleSize)/2; %The displacement magnitude

%Material parameter set
c1=1; %Shear-modulus-like parameter
m1=2;
k=50*c1;

% FEA control settings
numTimeSteps=50; %Number of time steps desired
max_refs=50; %Max reforms
max_ups=0; %Set to zero to use full-Newton iterations
opt_iter=25; %Optimum number of iterations
max_retries=5; %Maximum number of retires
dtmin=(1/numTimeSteps)/100; %Minimum time step size
dtmax=(1/numTimeSteps); %Maximum time step size
min_residual=1e-20;
symmetric_stiffness=0;
runMode='external';

%%

%Specifying dimensions and number of elements
r=0.5; %Radii, results in a width of 1
n=4;
nCopies=n*ones(1,3); %Number of offset copies
d=2*r; %Diameter
w=(n-1)*d; %sampleSize

%% Create lattice

switch latticeType
    case 1 %Octet truss
        [Er,Vr,Cr,Fr,CFr]=rhombicDodecahedronMesh(r,nCopies);
        Vr=Vr./(n-1);
        Vr=Vr*sampleSize;

        [indBoundary]=tesBoundary(Fr,Vr);
        cPar.shrinkFactor=0.15; %Strut sides are formed by shrinking the input mesh faces by this factor
        cPar.meshType='hex'; %desired output mesh type
        cPar.indBoundary=indBoundary; %indices of the boundary faces
        cPar.hexSplit=2;
        cPar.latticeSide=2; %1=side 1 the edge lattice, 2=side 2 the dual lattice to the edge lattice
        [E,V,C]=element2lattice(Er,Vr,cPar); %Get lattice structure

        logicKeep1=~(V(:,1)<=-1e-3);
        logicKeep2=~(V(:,2)<=-1e-3);
        logicKeep3=~(V(:,3)<=-1e-3);
        logicKeep4=~(V(:,1)>=sampleSize+1e-3);
        logicKeep5=~(V(:,2)>=sampleSize+1e-3);
        logicKeep6=~(V(:,3)>=sampleSize+1e-3);

        logicKeepEs=sum(logicKeep1(E),2)>=4 &...
            sum(logicKeep2(E),2)>=4 &...
            sum(logicKeep3(E),2)>=4 &...
            sum(logicKeep4(E),2)>=4 &...
            sum(logicKeep5(E),2)>=4 &...
            sum(logicKeep6(E),2)>=4;

        E=E(logicKeepEs,:);
        C=C(logicKeepEs,:);
        [E,V,indFix]=patchCleanUnused(E,V);

        % [Es,Vs,~,~]=subHex(Es,Vs,1,1);
        % Cs=repmat(Cs,8,1);

        % Create patch Data for visualization
        [Fs,CsF]=element2patch(E,C); %Patch data for plotting

        %Get new boundary set
        indB=tesBoundary(Fs,V);
        Fb=Fs(indB,:);
    case 2 %Rhombic dodecahedron mesh ("dual" of octet truss lattice)
        [Er,Vr,Cr,Fr,CFr]=rhombicDodecahedronMesh(r,nCopies);
        Vr=Vr./(n-1);
        Vr=Vr*sampleSize;

        [indBoundary]=tesBoundary(Fr,Vr);
        cPar.shrinkFactor=0.15; %Strut sides are formed by shrinking the input mesh faces by this factor
        cPar.meshType='hex'; %desired output mesh type
        cPar.indBoundary=indBoundary; %indices of the boundary faces
        cPar.hexSplit=2;
        cPar.latticeSide=1; %1=side 1 the edge lattice, 2=side 2 the dual lattice to the edge lattice
        [E,V,C]=element2lattice(Er,Vr,cPar); %Get lattice structure

        logicKeep1=~(V(:,1)<=-1e-3);
        logicKeep2=~(V(:,2)<=-1e-3);
        logicKeep3=~(V(:,3)<=-1e-3);
        logicKeep4=~(V(:,1)>=sampleSize+1e-3);
        logicKeep5=~(V(:,2)>=sampleSize+1e-3);
        logicKeep6=~(V(:,3)>=sampleSize+1e-3);

        logicKeepEs=sum(logicKeep1(E),2)>=4 &...
            sum(logicKeep2(E),2)>=4 &...
            sum(logicKeep3(E),2)>=4 &...
            sum(logicKeep4(E),2)>=4 &...
            sum(logicKeep5(E),2)>=4 &...
            sum(logicKeep6(E),2)>=4;

        E=E(logicKeepEs,:);
        C=C(logicKeepEs,:);
        [E,V,indFix]=patchCleanUnused(E,V);

        % [Es,Vs,~,~]=subHex(Es,Vs,1,1);
        % Cs=repmat(Cs,8,1);

        % Create patch Data for visualization
        [Fs,CsF]=element2patch(E,C); %Patch data for plotting

        %Get new boundary set
        indB=tesBoundary(Fs,V);
        Fb=Fs(indB,:);
    case 3
        boxDim=sampleSize*[1 1 1];
        boxEl=[2 2 2];
        [meshStruct]=hexMeshBox(boxDim,boxEl);
        Er=meshStruct.E;
        Vr=meshStruct.V;
        minV=min(Vr,[],1); %Get lower left front corner
        Vr=Vr-minV(ones(size(Vr,1),1),:); %Set corner as origin
        [Er,Vr,~]=hex2tet(Er,Vr,[],1); %Convert to tetrahedral elements
        [Fr,Cr]=element2patch(Er,[]); %Patch data for plotting
        [indBoundary]=tesBoundary(Fr,Vr);

        % Create lattice structure
        controlParameter.latticeSide=1;
        controlParameter.numDigitKeep=5; %used for merging nodes
        controlParameter.indBoundary=indBoundary; %indices of the boundary faces
        controlParameter.shrinkFactor=0.15;
        controlParameter.meshType='hex';
        controlParameter.hexSplit=2;

        [E,V,C]=element2lattice(Er,Vr,controlParameter); %Get lattice structure

        % Create patch Data for visualization
        [Fs,CsF]=element2patch(E,C); %Patch data for plotting

        indB=tesBoundary(Fs,V);
        Fb=Fs(indB,:);
end
%%
% Visualizing input mesh and lattic structures

cFigure;
hs=subplot(1,2,1);
title('The input mesh','fontSize',fontSize)
hold on;
gpatch(Fr,Vr,0.5*ones(1,3),'k',0.5);
axisGeom(gca,fontSize);
camlight headlight; lighting flat;

subplot(1,2,2);
title('Lattice side 1','fontSize',fontSize)
hold on;
gpatch(Fb,V,'bw','k',1);
% patchNormPlot(Fs,Vs);
axisGeom(gca,fontSize);
camlight headlight; lighting flat;

drawnow;

%% DEFINE BC's

% Define node set logics
indAll=(1:1:size(V,1))';
logicBoundary=ismember(indAll,Fb);

Z=V(:,3);
logicTop=Z>=(sampleSize-eps(sampleSize))& logicBoundary;
logicBottom=Z<=eps(sampleSize) & logicBoundary;

X=V(:,1);
logicSide1=X>=(sampleSize-eps(sampleSize))& logicBoundary;
logicSide2=X<=eps(sampleSize)& logicBoundary;

Y=V(:,2);
logicSide3=Y>=(sampleSize-eps(sampleSize))& logicBoundary;
logicSide4=Y<=eps(sampleSize)& logicBoundary;

%Prescribed force nodes
bcPrescribeListCell{1}=find(logicSide1)';
bcPrescribeListCell{2}=find(logicSide2)';
bcPrescribeListCell{3}=find(logicSide3)';
bcPrescribeListCell{4}=find(logicSide4)';
bcPrescribeListCell{5}=find(logicTop)';
bcPrescribeListCell{6}=find(logicBottom)';

%% Smoothing lattice

% indKeep=unique([bcPrescribeListCell{:}]);
% [Fb_clean,Vb_clean,indFix]=patchCleanUnused(Fb,Vs);
%
% cPar.Method='HC';
% cPar.n=6;
%
% cPar.RigidConstraints=indFix(indKeep);
% % cPar.RigidConstraints=cPar.RigidConstraints(cPar.RigidConstraints>0);
%
% [Vb_clean]=tesSmooth(Fb_clean,Vb_clean,[],cPar);
% ind=Fb(:);
% ind=unique(ind(:));
% Vs(ind,:)=Vb_clean;

% cFigure; hold on;
% gpatch(Fb,Vs,'bw','k',1);
% % patchNormPlot(Fs,Vs);
% % plotV(Vs(indKeep,:),'k.','MarkerSize',25)
% axisGeom(gca,fontSize);
% camlight headlight; lighting flat;
% drawnow;

%%
% Visualizing input mesh and lattic structures

cFigure;
hs=subplot(1,2,1);
title('The input mesh','fontSize',fontSize)
hold on;
gpatch(Fr,Vr,0.5*ones(1,3),'k',0.5);
axisGeom(gca,fontSize);
camlight headlight; lighting flat;

subplot(1,2,2);
title('Lattice side 1','fontSize',fontSize)
hold on;
gpatch(Fb,V,'bw');
% patchNormPlot(Fs,Vs);
axisGeom(gca,fontSize);
camlight headlight; lighting flat;

drawnow;

%%
% Visualize BC's

cFigure; hold on;
title('Boundary conditions','FontSize',fontSize);
gpatch(Fb,V,'kw','none',0.4);
hl=gobjects(1,6);
plotColors=gjet(6);
for q=1:1:numel(bcPrescribeListCell)
    hl(q)=plotV(V(bcPrescribeListCell{q},:),'k.','MarkerSize',markerSize);
    hl(q).Color=plotColors(q,:);
end

legend(hl,{'BC 1','BC 2','BC 3','BC 4','BC 5','BC 6'});
axisGeom;
camlight headlight;
set(gca,'FontSize',fontSize);
drawnow;

%% Defining the FEBio input structure
% See also |febioStructTemplate| and |febioStruct2xml| and the FEBio user
% manual.

%Get a template with default settings
[febio_spec]=febioStructTemplate;

%febio_spec version
febio_spec.ATTR.version='3.0';

%Module section
febio_spec.Module.ATTR.type='solid';

%Control section
febio_spec.Control.analysis='STATIC';
febio_spec.Control.time_steps=numTimeSteps;
febio_spec.Control.step_size=1/numTimeSteps;
febio_spec.Control.solver.max_refs=max_refs;
febio_spec.Control.solver.max_ups=max_ups;
febio_spec.Control.solver.symmetric_stiffness=symmetric_stiffness;
febio_spec.Control.time_stepper.dtmin=dtmin;
febio_spec.Control.time_stepper.dtmax=dtmax;
febio_spec.Control.time_stepper.max_retries=max_retries;
febio_spec.Control.time_stepper.opt_iter=opt_iter;

%Material section
materialName1='Material1';
febio_spec.Material.material{1}.ATTR.name=materialName1;
febio_spec.Material.material{1}.ATTR.type='Ogden';
febio_spec.Material.material{1}.ATTR.id=1;
febio_spec.Material.material{1}.c1=c1;
febio_spec.Material.material{1}.m1=m1;
% febio_spec.Material.material{1}.c2=c1;
% febio_spec.Material.material{1}.m2=-m1;
febio_spec.Material.material{1}.k=k;

% Mesh section
% -> Nodes
febio_spec.Mesh.Nodes{1}.ATTR.name='Object1_lattice'; %The node set name
febio_spec.Mesh.Nodes{1}.node.ATTR.id=(1:size(V,1))'; %The node id's
febio_spec.Mesh.Nodes{1}.node.VAL=V; %The nodel coordinates

% -> Elements
partName1='Part1_lattice';
febio_spec.Mesh.Elements{1}.ATTR.name=partName1; %Name of this part
febio_spec.Mesh.Elements{1}.ATTR.type='hex8'; %Element type
febio_spec.Mesh.Elements{1}.elem.ATTR.id=(1:1:size(E,1))'; %Element id's
febio_spec.Mesh.Elements{1}.elem.VAL=E; %The element matrix

% -> NodeSets
for q=1:1:numel(bcPrescribeListCell)
    febio_spec.Mesh.NodeSet{q}.ATTR.name=['bcPrescribeList_',num2str(q)];
    febio_spec.Mesh.NodeSet{q}.node.ATTR.id=bcPrescribeListCell{q}';
end

%MeshDomains section
febio_spec.MeshDomains.SolidDomain.ATTR.name=partName1;
febio_spec.MeshDomains.SolidDomain.ATTR.mat=materialName1;

%Boundary condition section

% -> Prescribe boundary conditions
directionStringSet={'x','x','y','y','z','z'};
displacementMagnitudeDir=[1 -1 1 -1 1 -1];
for q=1:1:numel(bcPrescribeListCell)
    nodeSetName=febio_spec.Mesh.NodeSet{q}.ATTR.name;
    febio_spec.Boundary.bc{q}.ATTR.type='prescribe';
    febio_spec.Boundary.bc{q}.ATTR.node_set=nodeSetName;
    febio_spec.Boundary.bc{q}.dof=directionStringSet{q};
    febio_spec.Boundary.bc{q}.scale.ATTR.lc=1;
    febio_spec.Boundary.bc{q}.scale.VAL=displacementMagnitudeDir(q).*displacementMagnitude;
    febio_spec.Boundary.bc{q}.relative=0;
end

%LoadData section
% -> load_controller
febio_spec.LoadData.load_controller{1}.ATTR.id=1;
febio_spec.LoadData.load_controller{1}.ATTR.type='loadcurve';
febio_spec.LoadData.load_controller{1}.interpolate='LINEAR';
febio_spec.LoadData.load_controller{1}.points.point.VAL=[0 0; 1 1];

%Output section
% -> log file
febio_spec.Output.logfile.ATTR.file=febioLogFileName;

febio_spec.Output.logfile.node_data{1}.ATTR.file=febioLogFileName_disp;
febio_spec.Output.logfile.node_data{1}.ATTR.data='ux;uy;uz';
febio_spec.Output.logfile.node_data{1}.ATTR.delim=',';

febio_spec.Output.logfile.node_data{2}.ATTR.file=febioLogFileName_force;
febio_spec.Output.logfile.node_data{2}.ATTR.data='Rx;Ry;Rz';
febio_spec.Output.logfile.node_data{2}.ATTR.delim=',';

febio_spec.Output.logfile.element_data{1}.ATTR.file=febioLogFileName_stress;
febio_spec.Output.logfile.element_data{1}.ATTR.data='sz';
febio_spec.Output.logfile.element_data{1}.ATTR.delim=',';

%% Quick viewing of the FEBio input file structure
% The |febView| function can be used to view the xml structure in a MATLAB
% figure window.

%%
% |febView(febio_spec); %Viewing the febio file|

%% Exporting the FEBio input file
% Exporting the febio_spec structure to an FEBio input file is done using
% the |febioStruct2xml| function.

febioStruct2xml(febio_spec,febioFebFileName); %Exporting to file and domNode
%system(['gedit ',febioFebFileName,' &']);

%% Running the FEBio analysis
% To run the analysis defined by the created FEBio input file the
% |runMonitorFEBio| function is used. The input for this function is a
% structure defining job settings e.g. the FEBio input file name. The
% optional output runFlag informs the user if the analysis was run
% succesfully.

febioAnalysis.run_filename=febioFebFileName; %The input file name
febioAnalysis.run_logname=febioLogFileName; %The name for the log file
febioAnalysis.disp_on=1; %Display information on the command window
febioAnalysis.runMode=runMode;
febioAnalysis.maxLogCheckTime=10; %Max log file checking time

[runFlag]=runMonitorFEBio(febioAnalysis);%START FEBio NOW!!!!!!!!

%% Import FEBio results

if runFlag==1 %i.e. a succesful run

    %%

    % Importing nodal displacements from a log file
    dataStruct=importFEBio_logfile(fullfile(savePath,febioLogFileName_disp),1,1);

    %Access data
    N_disp_mat=dataStruct.data; %Displacement
    timeVec=dataStruct.time; %Time

    %Create deformed coordinate set
    V_DEF=N_disp_mat+repmat(V,[1 1 size(N_disp_mat,3)]);

    %%

    % Importing nodal forces
    dataStruct=importFEBio_logfile(fullfile(savePath,febioLogFileName_force),1,1);
    N_force_mat=dataStruct.data;

    indicesSide=bcPrescribeListCell{1};
    areaSide=sampleSize.^2;

    stressVal=mean(squeeze(N_force_mat(indicesSide,1,:))./areaSide,1);
    J_Val=1-((1-J_final).*timeVec(:));

    %%

    cFigure; hold on;
    xlabel('$J$','Interpreter','Latex'); ylabel('$\sigma^*$','Interpreter','Latex');
    plot(J_Val(:),stressVal(:),'r.-','LineWidth',3,'MarkerSize',15);
    axis square; axis tight; grid on; box on;
    set(gca,'FontSize',fontSize);
    drawnow;

    %%
    % Plotting the simulated results using |anim8| to visualize and animate
    % deformations

    DN_magnitude=sqrt(sum(N_disp_mat(:,:,end).^2,2)); %Current displacement magnitude

    % Create basic view and store graphics handle to initiate animation
    hf=cFigure; %Open figure
    gtitle([febioFebFileNamePart,': Press play to animate']);
    hp=gpatch(Fb,V_DEF(:,:,end),DN_magnitude,'k',1); %Add graphics object to animate
    %     gpatch(Fb,Vs,'kw','none',0.25); %A static graphics object
    hp.FaceColor='interp';

    axisGeom(gca,fontSize);
    colormap(gjet(250)); colorbar;
    caxis([0 max(DN_magnitude)]);
    axis(axisLim(V_DEF)); %Set axis limits statically
    %     view(130,25); %Set view direction
    camlight headlight;

    % Set up animation features
    animStruct.Time=timeVec; %The time vector
    for qt=1:1:size(N_disp_mat,3) %Loop over time increments
        DN=N_disp_mat(:,:,qt); %Current displacement
        DN_magnitude=sqrt(sum(DN.^2,2)); %Current displacement magnitude

        %Set entries in animation structure
        animStruct.Handles{qt}=[hp hp]; %Handles of objects to animate
        animStruct.Props{qt}={'Vertices','CData'}; %Properties of objects to animate
        animStruct.Set{qt}={V_DEF(:,:,qt),DN_magnitude}; %Property values for to set in order to animate
    end
    anim8(hf,animStruct); %Initiate animation feature
    drawnow;

end

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

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


function fx = p00_fun ( problem, n, x )

%*****************************************************************************80
%
%% P00_FUN evaluates the integrand for any problem.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 September 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer PROBLEM, the problem index.
%
%    Input, integer N, the number of evaluation points.
%
%    Input, real X(2,N), the evaluation points.
%
%    Output, real FX(N,1), the integrand values.
%
  fx = zeros ( n, 1 );

  if ( problem == 1 )
    fx = p01_fun ( n, x );
  elseif ( problem == 2 )
    fx = p02_fun ( n, x );
  elseif ( problem == 3 )
    fx = p03_fun ( n, x );
  elseif ( problem == 4 )
    fx = p04_fun ( n, x );
  elseif ( problem == 5 )
    fx = p05_fun ( n, x );
  elseif ( problem == 6 )
    fx = p06_fun ( n, x );
  elseif ( problem == 7 )
    fx = p07_fun ( n, x );
  elseif ( problem == 8 )
    fx = p08_fun ( n, x );
  else
    fprintf ( 1, '\n' );
    fprintf ( 1, 'P00_FUN - Fatal error!\n' );
    fprintf ( 1, '  Illegal problem index = %d\n', problem );
    error ( 'P00_FUN - Fatal error!\n' );
  end

  return
end


function g = restrict(f, s)
%RESTRICT Restrict an UNBNDFUN to a subinterval.
%   RESCTRICT(F, S) returns a FUN object that is restricted to the subinterval
%   [S(1), S(2)] of the domain of F.
%
%   If length(S) > 2, i.e., S = [S1, S2, ..., Sn], then RESCTRICT(F, S) returns
%   an array of FUN objects, where the cells contain F restricted to each of
%   the subintervals defined by S. If there is only one FUN to be returned,
%   that is, if length(S) == 2, then the FUN object g is returned. This
%   facilitates the use of the result by other functions, e.g. plot etc.

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

% Deal with empty case:
if ( isempty(f) )
    g = f;
    return
end

% Check if the argument s is actually a subinterval:
if ( s(1) < f.domain(1) || s(end) > f.domain(2) || any(diff(s) <= 0) )
    error('CHEBFUN:UNBNDFUN:restrict:badInterval', 'Not a valid interval.')
elseif ( numel(s) == 2 && all(s == f.domain) )
    % Nothing to do here!
    g = f;
    return
end

% Number of subdomains:
numSubDom = numel(s) - 1;

% Preallocate the output cell:
g = cell(1, numSubDom);

% Any exponents?
exps = [];

if ( issing(f) )

    % Grab the exponents:
    exps = get(f, 'exponents');

    % If there is a non-trivial exponent:
    if ( any(exps) )

        % Interior exponents:
        interiorExps = zeros(1, numSubDom-1);

        % Insert the interior exponents:
        exps = [exps(1) interiorExps exps(2)];

        % Negate the exponents for infinite endpoint, since the exponents stored
        % in SINGFUN are the negated values of those supplied to the UNBNDFUN
        % constructor:

        if ( s(1) == -Inf )
            exps(1) = -exps(1);
        elseif ( f.domain(1) == -Inf )
            exps(1) = 0;
        end

        if ( s(end) == Inf )
            exps(end) = -exps(end);
        elseif ( f.domain(end) == Inf )
            exps(end) = 0;
        end

    end

end

% Grab the vscale:
vscale = get(f, 'vscale');

% Loop over each subdomain:
for k = 1:numSubDom

    % Initialize preferences:
    pref = chebfunpref();

    % Pass the information about exponents through preference:
    if ( ~isempty(exps) && any(exps(k:k+1)) )
        data.exponents = exps(k:k+1);

        if ( (k == 1) || (k == numSubDom) )
            pref.techPrefs.extrapolate = 1;
        end
    else
        data.exponents = [];
    end

    data.domain = s(k:k+1);
    data.vscale = vscale;
    g{k} = classicfun.constructor(@(x) feval(f, x), data, pref);
end

% When there is only one cell, return the UNBNDFUN instead:
if ( numSubDom == 1 )
    g = g{1};
end

end


function y = Fault_decision_system(u)
global st14

% Using model defined by the structure st14 to make decision about system fault

u(3)=1e-10*u(3).*(u(end).^6);u=u(1:3);
sker=st14.x2sup+(abs(u))'*abs(u)*ones(st14.Nlsup,1)-2*st14.xsup*abs(u);
y=(st14.w)'*exp(-sker./(2*(st14.sigma).^2))+st14.b;

if y>=0.8
    y=1;
else
    y=0;
end
end


function model = yalmip2scs(interfacedata);

model.data.A = -interfacedata.F_struc(:,2:end);
model.data.b = full(interfacedata.F_struc(:,1));
model.data.c =  interfacedata.c;
model.cones = interfacedata.K;
model.param = interfacedata.options.scs;


function [pvec, pstruct] = tapas_hgf_binary_mab_transp(r, ptrans)
% --------------------------------------------------------------------------------------------------
% Copyright (C) 2013 Christoph Mathys, TNU, UZH & ETHZ
%
% This file is part of the HGF toolbox, which is released under the terms of the GNU General Public
% Licence (GPL), version 3. You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version). For further details, see the file
% COPYING or <http://www.gnu.org/licenses/>.

pvec    = NaN(1,length(ptrans));
pstruct = struct;

l = r.c_prc.n_levels;

pvec(1:l)         = ptrans(1:l);                                 % mu_0
pstruct.mu_0      = pvec(1:l);
pvec(l+1:2*l)     = exp(ptrans(l+1:2*l));                        % sa_0
pstruct.sa_0      = pvec(l+1:2*l);
pvec(2*l+1:3*l)   = ptrans(2*l+1:3*l);                           % rho
pstruct.rho       = pvec(2*l+1:3*l);
pvec(3*l+1:4*l-1) = exp(ptrans(3*l+1:4*l-1));                    % ka
pstruct.ka        = pvec(3*l+1:4*l-1);
pvec(4*l:5*l-1)   = ptrans(4*l:5*l-1);                           % om
pstruct.om        = pvec(4*l:5*l-1);

return;


function im_scale = prep_im_for_blob_size(im_size, target_size, max_size)

    im_size_min = min(im_size(1:2));
    im_size_max = max(im_size(1:2));
    im_scale = double(target_size) / im_size_min;

    % Prevent the biggest axis from being more than MAX_SIZE
    if round(im_scale * im_size_max) > max_size
        im_scale = double(max_size) / double(im_size_max);
    end
end


function distMat = BagDistMat(data,bagModels)

distMat = zeros(size(data,1),length(bagModels)*length(bagModels{1}),'single');
count = 1;
for mno = 1:length(bagModels)
  curModel = bagModels{mno};
  for j = 1:length(curModel)
    curWk = curModel(j);
    dd = data(:,curWk.dim)*curWk.dir;
    tt = curWk.tr*curWk.dir;
    distMat(:,count) = sign( (dd>tt)-0.5)*curWk.alpha;
    count = count+1;
  end
end


function drawCameraPly(PLYfilename,Rt,scale,w,h,f)

if ~exist('w','var')
    w = 640;
end
if ~exist('h','var')
    h = 480;
end
if ~exist('f','var')
    f = 570.3422090067766703214147128164768218994140625;
end
if ~exist('scale','var')
    scale = 0.01;
end

camera=[...
0 -w/2 +w/2 +w/2 -w/2
0 -h/2 -h/2 +h/2 +h/2
0   f    f    f    f];

camera = camera * scale;
camera = Rt(:,1:3) * camera + repmat(Rt(:,4),1,5);
edges = [1 2; 1 3; 1 4; 1 5; 2 3;3 4;4 5;5 2]';

graph2ply(PLYfilename, camera, edges);

%{
plot3(camera(1,[2 3 4 5 2]),camera(2,[2 3 4 5 2]),camera(3,[2 3 4 5 2]),'-k'); hold on;
for i=2:5
    plot3(camera(1,[1 i]),camera(2,[1 i]),camera(3,[1 i]),'-k'); hold on;
end
axis equal
xlabel('x');
ylabel('y');
zlabel('z');
%}


function  [c1, lmin1, lmax1, as, pm, sig8] = cmbaccur(van, omt, bmark, one_percent, lmax, stfname)
% cmbaccur.m :
% this program calculates the radiation and matter spectra to an accuracy of 1% or 0.1% for the open, flat and
% closed Friedman-Robertson-Walker universe.
% The radiation spectra include the temperature- polarisation and cross-polarisation spectra.
% We follow the method of Uros Seljak amd Matias Zaldarriaga in 'A line-of-sight integration approach
% to Cosmic microwave background anisotropies', ApJ, nr 469, 437-444 (1996), see also :
% Ma and Bertschinger, ApJ nr 455, 7-25 (1995) and Zaldarriaga, Seljak, Bertschinger
% ApJ nr 494, 491 (1998) and Zaldarriaga and Seljak, ApJ nr129, 431 (2000) and W Hu e.a, 'A complete treatment
% of CMB anisotropies in a FRW universe', Phys Rev D57, 3290-3301 (1998), for reionisation see N Sugiyama,
% ApJ nr 419 L1-L4 (1993) and ApjS nr 100, 281 (1995)
%
% input : the "vanilla-set" of Cosmological parameters, omt, the curvature of the universe,
%   bmark : a benchmark (file) to compare with (see remarks), one_percent: the accuracy
%   is 1% resp 0.1% for ~one_percent==0 resp one_percent==0, the default is 1%, lmax, the maximum
%   multipoint number, the default lmax value is lmax=1500 (lmax must be <= 1500. otherwise a special
%   la-vector has to be defined), name of the startfile for the ultra-spherical function.
% no inputs : if no inputs are given the functions takes the default values (see remarks),
% if 5th argument (lmax) is missing, the default value lmax=1500 is taken
%
% output :the normalisation constant (asc), the positions of the peaks (minima and maxima)
% in the temperature anisotropy spectrum (lmin & lmax), as: the temperature anisotropy spectrum, as.ctt
% the E-polarisation spectrum, as.cee and the cross-correlation spectrum, as.cte, pm: the matter spectrum

% D Vangheluwe 29 jun 2005 finished 4 july 2005
% remark 1: the vanilla-set is (As, omega_lambda, omega_d, omega_b, ns, tau), which are : the amplitude correction
% at l=10, dark energy density, dark matter density, baryon density, scalar spectral index, optical depth.
% The vanilla-set is converted internally to the parameters (c1, om, omt, omb, h, nprimtilt, zri), which are:
% the amplitude correction at l=10, dark matter omega, total omega, baryon omega, Hubble factor, scalar spectral index,
% reionisation redshift, see below for the default values. For example: omt = omega_lambda + omega_b + omega_d
% remark 1 this is a compilation of the programs cmbacc1.m and ambacc2.m for resp open (K<=0) and closed space (K>0)
% remark 2 the discrete values of la for closed space are chosen different from the ones for open space : reason that
%  for closed space the peaks in the spectrum shift to lower la and we need more points there : therefore the
%  step change in la is chosen at la =100 resp la = 250 for open/flat resp closed space.
% remark 3 :the lamda content of the universe is automatically : omt - omr -om, for example with omt = 1.1,
%  om = 0.27, h = 0.72 and omr = omp/(1 - fv)= 8.01e-5, we have oml = 0.83, we have chosen here not to
%  specify the lamda energy content of primordial space. For the Vanilla parameters see ambaccur(.)
% remark 4: the different path taken for closed resp open/flat space can be seen at the if (K>0) statements.
%  for K>0 we take a different set of k1 values to solve the Bolzamn equations and a different set of k2
%  (also 'beta' in the literature) values for the calculation of the anistropy spectrum
% remark 6: the connections with the input of cmbfast and our input is a bit difficult : we give the connection
%  for resp omega of the vacuum (omegav), cold dark matter (omegac) and baryons (omegab) :
%  omegav = omt - om, omegac = om - omb, omegab = omb (om is the omega for all matter, baryons+dark matter and omt
%  is the total omega)
% remark 7: try the vanilla-lite model from Tegmark et al. astro-ph/0310723, 15jan 2004:
%   van = [0.89, 0.72, 0.12, 0.024, 1, 0.17] and omt =1, it is the best fit to WMAP2003 +SDSS assuming ns==1 and tensor field zero.
%   or the old cdm model, a universe without dark energy : van = [1, 0.954, 0.0, 0.0115, 1, 0] and omt =1.
% remark 5 (4 aug 2005): if the spectrum needs only to be calculated for a multipole range smaller than the
%  default lmax0=1500, specify this value <1500 as the last argument, the accuracy is
%  kept in line with this choice (several changes are necessary such as : smaller nkst, extended k1max etc.)
%  The calculation time is proportional to sqrt(lmax), not with lmax!

global GL_dt_table   GL_pp_dtau;
global  GL_cmb_c  GL_cmb_h0   GL_cmb_t0   GL_cmb_T0   GL_cmb_rv   GL_cmb_fv   GL_cmb_kg1   GL_cmb_ka1   ...
  GL_cmb_yp   GL_cmb_ncr   GL_cmb_cr   GL_cmb_pcm   GL_cmb_dha;
% give the global physical constants a value
cmbglobl;

% tolerance
tol = 1e-6;
trace = [];

%cosmological parameters : (As, omega_lambda, omega_d, omega_b, ns, zri) and omt for spacial curvature
if nargin == 0  %take the default vanilla-set (which gives the best fit to wmap2003)
% the default set is : c10=1, om=0.27, omb=0.046, h=0.72, ns=0.99, zri= 17.28
    van = [1, 0.73, 0.1161216, 0.0238464, 0.99, 0.17295];
    omt = 1;
    lmax = 1500;
% the default accuracy is : one_percent == 1, for an of accuracy 1%, the accuracy = 0.1% only for one_percent == 0.
    one_percent = 1
% benchmark calculations to compare : available are cmbfast for h=0.72: 'h72', 'h72i' for reionisation with zri = 17.3
%  'h72o1' for h = 0.72 open universe with omt=1.1, 'h72c1' for h = 0.72 closed universe with omt=0.9,
% 'cdm', for the CDM model (flat space) (see for more info cmbdata3.m)
    bmark = 'h72i';
else
   if nargin == 1, error('the benchmark must be defined'), return; end
   if nargin == 2, error('the accuracy must be defined'), return; end
   if nargin == 4, lmax = 1500; end
end
if  ~(one_percent == 0), one_percent = 1; end;

% the hubble factor h
%h = 0.71
%h = 0.72
if (omt - van(2) > 0)
   h = sqrt((van(3) + van(4))/(omt - van(2)))
else
   error('omt < van(2) not allowed');
   return
end

% baryon content of the universe
%omb = 0.0444
%omb = 0.046
omb = van(4)/h^2

% matter content of the universe
%om = 0.27
%om = 0.27
om = (van(3) + van(4))/h^2

% redshift for reionisation
%zri = 0
%zri = 17.28   % tauri = 0.170
%zri = 0
zri = 92*(0.03 * h * van(6)/van(4))^(2/3) * om^(1/3)

% primordial tilt : the exponent of the power spectrum of matter
%nprimtilt = 0.99;
%nprimtilt = 0.99;
nprimtilt = van(5)

% normalisation of the anisotropy spectrum
%c10 = 1.00;
c10 = van(1);

% the cmb temperature
%cmbtemp = 2.725;
cmbtemp = GL_cmb_t0;
% velocity of light in m/s
%c = 2.998e8;
c = GL_cmb_c;
% the hubble constant at present in h Mpc^-1, see my notes p71
%h0 = 1e5/c;
h0 = GL_cmb_h0;
% the ratio of neutrino to total radiation density fv, assuming three massless neutrinos
%rv = (21/8) * (4/11)^(4/3);
%fv = rv/(1 + rv);
fv = GL_cmb_fv;
% amplitude of the primordial density perturbation at the horizon, see Dodelson (8.76)
%dha = 4.6e-5;
dha = GL_cmb_dha;
dha2 = dha^2;
% the ratio of the radiation density and the critical density, see Dodelson (omega_gamma)
%kg1 = 2.47e-5;
kg1 = GL_cmb_kg1;
%ka1 = kg1/(1 - fv);
ka1 = GL_cmb_ka1;

aeq = ka1/(om * h^2);
keq = h0 * h * sqrt(om*2/aeq);
% omega of radiation and neutrinos separately
omp = kg1/h^2;
omr = omp/(1 - fv);
omn = omp * fv/(1 - fv);
% the constant K for curvature energy content from the Friedman equation
K = (omt - 1) * (h0 * h)^2;

if  nargin < 6
  if K > 0, stfname = 'stfile1';
  else, stfname = 'stfile';
  end
end

tol_ode23 = 1e-5;
if one_percent == 1
  tol_ode23 = 2e-4;  % default 2e-4
end

% find the recombination curve and the inverse optical depth, dtau in Mpc^-1,
% tau and the visibility function (vsb1) :
dt = recomb(om, omb, omt, h, zri);
%sdata = load('cmbxe');
%dt = sdata.dt;
GL_dt_table = dt.dt_table;
%tauri = dt.tauri;
tauri = van(6);

zdec = dt.zdec;
sizetable = size(GL_dt_table, 2)
at1 = GL_dt_table(1,:);
dtau1 = GL_dt_table(3,:);
%tau1 = GL_dt_table(4,:);
%vsb1 = GL_dt_table(5,:);
% make a spline of dtau
GL_pp_dtau = spline(GL_dt_table(1,:), GL_dt_table(3,:));

% calculate the current conformal time :ctc0 and ctime at reionisation and at decoupling
ctc0 = quadl(@conftim1, 0, 1, tol, trace, om, omr, omt, h);
ctad = quadl(@conftim1, 0, 1/(zdec + 1), tol, trace, om, omr, omt, h);
ctri = quadl(@conftim1, 0, 1/(zri + 1), tol, trace, om, omr, omt, h);

% if the spectrum has become isotropic for K > 0 (all photons are coming from one point) break off:
if (K > 0)
    ct4sym = 0.5 * pi/sqrt(K);
    if  (2*ct4sym < ctc0),  message('the spectrum is isotropic, return'); return; end
    if sqrt(K) * ctc0 > 2, message('curvature K * ctc0 > 2'); end
end

% define the range of l (angle number)
%lmax = 1500;
lmin = 2;

% the wavenumber kw in Mpc^1 (range : 0.2 < kw < 2e-4)
% define the k-range
if one_percent == 1
%  nkst = 44
  nkst = 30 + 10*(lmax - 900)/600;   % adapt the k1step for lmax~1500
else
  nkst = 88
end

% find the maximum multipole number in the startfile for K>0 (lmax0 =default 1500)
stv1 = load(stfname);
lmax0 = stv1.ust.la(end);
if (K > 0)
    k1min = 3*sqrt(K);
%    k1int = 4e-3;
    k1int = 8e-3;
% if K*ctc0 > 2, it is necessary to increase k1max : important change for K>0!!
% and extend the range of k1 in case lmax < maximum of the startfile (lmax0 is default 1500)
    k1max = max(2*sqrt(lmax*lmax0)/ctc0, 1.5*sqrt(lmax*lmax0)*sqrt(K));
    k1step = (k1int - k1min)/8;
    k1step2 = (k1max - k1int)/nkst;
    k1 = [[k1min : k1step : (k1int - k1step)], [k1int : k1step2 : k1max]];
else
    k1min = 1e-5;
    k1int = 8e-3;
% extend the range of k1 in case lmax < maximum of the startfile (lmax0 is default 1500)
    k1max = 2*sqrt(lmax*lmax0)/ctc0;
    k1step = 0.0012;
    k1step2 = (k1max - k1int)/nkst;
    k1 = [k1min, 4e-5, 8e-5, 2e-4, 4e-4, 6e-4, 8e-4 : k1step : k1int, k1int+k1step2 : k1step2 : k1max];
end  %define k1 range
lk1 = size(k1, 2)

% take smaller steps in the same range of the conformal time now ct2:
step0 = ctc0/7000;
if one_percent == 1
  ct2step = step0;
else
  ct2step = step0/2;
end
ct2min = 0.5;
ct2max = ctc0;
ct2 = ct2min : ct2step : ct2max;
lct2 = size(ct2, 2);

%555555555555555555
% solve the Bolzman equations :
[table_srt, table_srp, deltam, a2] = ...
        bolzmslv(ct2, k1, tol_ode23, om, omb, omt, h, ctc0, ctad, zri, ctri, K, one_percent);

% find the conformal time at recombination :
vsb2 = spline(GL_dt_table(1,:), GL_dt_table(5,:), a2);
[vsbm irm] = max(vsb2);
etar = ct2(irm);
% calculate the thickness of the recombination surface in conformal time
ids = find(vsb2 >= 0.5* vsbm);
% half width ct2 points are:
hw1 = ct2(ids(1));
hw2 = ct2(ids(end));
trs = hw2 - hw1;
% number of points over the half width of the visibility function :
nphw = length(ids)
% find an accurate value for the decoupling time (recombination)
ct3 = hw1:0.01:hw2;
vsb3 = spline(ct2, vsb2, ct3);
[vsbm irm] = max(vsb3);
ctad1 = ct3(irm);

% define a k2 range:
if (K > 0)
% define a k-range with more points ->k2  :where kb = 1/3..
    logstep = 0;
    nn2min = fix(k1min/sqrt(K));
    nn2max = fix(k1max/sqrt(K));
    nksteps = 1.5* sqrt(lmax * lmax0);
    nn2step = max(1, round((nn2max - nn2min)/nksteps));
    nn2step = min(2, nn2step);   % limit to nn2step==2
    nn2 = nn2min : nn2step : nn2max;
    k2 = nn2 * sqrt(K);
else

    logstep = 1;
    k2min = k1min;
    k2max = k1max;
    if one_percent == 1
       ek2step = 0.002;
    else
       ek2step = 0.0015;
    end
    ek2 = log(k2min)/log(10) : ek2step : log(k2max)/log(10);
    k2 = 10 .^ ek2;
end % define k2 range
lk2 = size(k2, 2);
ik2 = floor(lk2/2);
ik4 = floor(lk2/4);

% calculate the anisotropy- and polariation spectrum for l > 2 in 2 steps: step1 :l<100 and step2 :l>100
% for l > 100 :select the interval in the conformal time range ct2 where the source is none zero
% for l < 100 :the source extends over a rather large cf time range of 200-ctc0 and we found that
% the ctime integration range must be extended in order to achieve 0.1% accuracy for l < 100
% With reionisation (zri > 0) for 1% accuracy, integration should be extended over the total ct time range.

%##anisotropy spectrum, step1 : l < 100  (2 and lct2-1 to stay within interpolation limits)
ict4min = 2;
%ict4max = lct2 - 1;
ict4max = lct2;
if one_percent == 1
   ict4step = 2;
else
   ict4step = 1;
end
ict4 = ict4min : ict4step : ict4max;
ct4 = ct2(ict4);
lct4 = size(ict4, 2);

% take as much splines ready for k2 interpolations as there are cftime points in ct4 :
% for each time we have one spline (the splines are in a column vector)
% this steps needs a lot of memory : if short of memory use srcpint.m with pp4, pp5 as argument : this
% is the case for one_percent ~= 1
pp4 = spline(k1, table_srt(:, ict4)');
pp5 = spline(k1, table_srp(:, ict4)');
if one_percent == 1
   src4 = [ppval(pp4, k2(1:ik2)), ppval(pp4, k2(ik2+1:end))];
   src5 = [ppval(pp5, k2(1:ik2)), ppval(pp5, k2(ik2+1:end))];
end

% calculate the anisotropy spectrum for l <= 100
if (one_percent == 1)  &  (K > 0 )
   lstep = 20;
else
   lstep = 10;
end
%la1 = 2;
if (K > 0)
   la1 = [2,6,10, 20:lstep:220];
   lla1 = size(la1,2);
   if one_percent == 1
      [cct1, ta1, te1] = srcintf1(la1, nn2, ct4, src4, src5, ctc0, ctad, nprimtilt, lmax, K, stfname);
   else
      [cct1, ta1, ta2] = srcint1(la1, nn2, ct4, pp4, pp5, ctc0, ctad, nprimtilt, lmax, K, stfname);
   end

else
   la1 = [2,6,10,20:lstep:90];
   lla1 = size(la1,2);
   if one_percent == 1
      [cct1, ta1, te1] = srcintf(la1, k2, ct4, src4, src5, ctc0, nprimtilt, lmax, K, stfname, logstep);
   else
      [cct1, ta1, ta2] = srcint(la1, k2, ct4, pp4, pp5, ctc0, nprimtilt, lmax, K, stfname, logstep);
   end

end

% change the stepsize in the k2 vector
if (K > 0)
   nksteps = 0.75* sqrt(lmax * lmax0);
% take care that in case the peak in the source region is splitup by the symmetry point, we take all
% modes (even and uneven nn2(i)) in the summation for the anistropy spectrum and nn2min==3
   if  ( (ctc0 - ct4sym) > 0 &  (ctc0 - ct4sym) < (ctad + 100) )
      nn2step = 1;
   else
      nn2step = max(1, round((nn2max - nn2min)/nksteps));
      nn2step = min(2, nn2step);   % limit to nn2step==2
   end
   nn2 = nn2min : nn2step : nn2max;
   k2 = nn2 * sqrt(K);
else

   clear('k2')
   logstep = 0;
   if one_percent == 1
     nksteps = 1.5*sqrt(lmax *lmax0);
   else
     nksteps = 2*sqrt(lmax *lmax0);
   end
   k2step = (k2max - k2min)/nksteps;
   k2 = k2min : k2step : k2max;
end % define k2 range
lk2 = size(k2, 2);
ik2 = floor(lk2/2);
ik4 = floor(lk2/4);

%##anisotropy spectrum, step 2 :l > 100, note that the cftime extends to the full range, ict4max= lt2-1
if one_percent == 1
   ict4step = 2;
else
   ict4step = 1;
end
ict4 = ict4min : ict4step : ict4max;
ct4 = ct2(ict4);
lct4 = size(ict4, 2);

% take the splines for all k2 interpolations within the conformal time interval ict4
% for each time we have one spline (the splines are in a column vector)
% this steps needs a lot of memory : if short of memory use srcpint.m with pp4, pp5 as argument
pp4 = spline(k1, table_srt(:, ict4)');
pp5 = spline(k1, table_srp(:, ict4)');
if one_percent == 1
   src4 = [ppval(pp4, k2(1:ik2)), ppval(pp4, k2(ik2+1:end))];
   src5 = [ppval(pp5, k2(1:ik2)), ppval(pp5, k2(ik2+1:end))];
end

% calculate the anisotropy spectrum for l > 100
if one_percent == 1
   lstep = 50;
else
   lstep = 25;
end
%la2 = 500
if (K > 0)
   la2 = 250:lstep:lmax;
   lla2 = size(la2,2);
   if  one_percent == 1
      [cct2, ta1] = srcintf1(la2, nn2, ct4, src4, src5, ctc0, ctad, nprimtilt, lmax, K,stfname);
   else
      [cct2, ta1] = srcint1(la2, nn2, ct4, pp4, pp5, ctc0, ctad, nprimtilt, lmax, K,stfname);
   end
else
   la2 = 100:lstep:lmax;
   lla2 = size(la2,2);
   if one_percent == 1
      [cct2, ta1] = srcintf(la2, k2, ct4, src4, src5, ctc0, nprimtilt, lmax, K, stfname, logstep);
   else
      [cct2, ta1] = srcint(la2, k2, ct4, pp4, pp5, ctc0, nprimtilt, lmax, K, stfname, logstep);
   end
end

% collect the results and go to the final step
la = [la1, la2];
ctth = [cct1.ctt, cct2.ctt];
ceeh = [cct1.cee, cct2.cee];
cteh = [cct1.cte, cct2.cte];

% calculate the amplitude of the anistropy spectrum in terms of the cmb temperature cmbtemp as
% cmbtemp^2*l*(l+1)*C1/(2*pi) in units of Kelvin^2 (including the effect of primordial tilt of the
% power spectrum)
% calculate the present (a==1) grow factor D1 by integration (see Dodelson 7.77)
D1 = 2.5 * om * quadl(@cmd3, 0, 1.0, tol, trace, om, omt);
% calculate the proportionality factor of the temperature spectrum, see Sachs and Wolfe and
% Dodelson (8.74) :
cswl1 = (50/9) * cmbtemp^2* (h*h0)^(1-nprimtilt) * (om/D1)^2;

% calculate the power spectrum of matter psm in units (Mpc/h)^3 as a function of kh = k1/h in h/Mpc.
kh = k1/h;
% use deltam(k) = delta(k)/psi, see Dodelson formulas (6.100) and (7.9) and delta is the mass overdensity.
psm1 =(50 *pi^2/9) .* (h./k1) .^3 .* (k1/(h*h0)) .^ (nprimtilt-1) .* (deltam .^2) * (om/D1)^2;
deltam(1)

% find psm at k1=0.05/Mpc and normalise the spectra with the density fluctuation at horizon crossing (dha)
% the c10 normalisation for the temperature spectrum is taken at l=10 :
% the best fit value for wmap2003 is 727 microKelvin^2, which gives C10 = 5.59e-12 and sqrt(C10) = 2.36e-6.
% the density fluctuation at the horizon for the best fit (dha) is in the global file of constants (cmbglobl.m)
% we use it to normalise both temperature and matter spectra.
kfid = 0.05
% normalise the temperature and matter spectra:
psm = psm1 * dha2;
cswl = cswl1 * dha2;

% calculate sigma8, the extended rms mass overdensity, sampled with a sphere of radius of radius 8 Mpc/h
% extend the matter power spectrum from k1 into small scales with k3 > 0.2 Mpc^-1,
k3step = 0.01;
k3max = 1.0;
k3 = (k1max+k3step) : k3step : k3max;
%for the extension use the asymptotic expansion of delta, see Dodelson formula (7.9) with the transfer function of (7.69)
% as psm is in units (Mpc/h)^3, we have to include the Hubble factor^3 in the Bolzman part of psm
psm2 = psm/h^3;
psm3 = psm2(end) * (k1(end) ./ k3) .^(4-nprimtilt) .* (log(k3/(8*keq))/log(k1(end)/(8*keq))) .^2;
k4 = [k1, k3];
psm4 = [psm2, psm3];
sig8h = (0.5/pi^2) * quadl(@sigma_8, k4(1), k4(end), tol, trace, k4, psm4, h);
sig8 = sqrt(sig8h);
% plot both psm from Bolzman calculation and the extension from formula (7.69)
figure(1)
loglog(k4, psm4)
%semilogy(k4, psm4)
title(['full range mass power spectrum: omt=', num2str(omt), ' h=', num2str(h), ',om=', num2str(om), ...
   ',omb=', num2str(omb), ',ns=', num2str(nprimtilt), ',tauri=', num2str(tauri)])
ylabel('P(k) in (Mpc/h)^3')
xlabel('log of the wavenumber in h/Mpc')

% compare with wmap results and find the normalisation constant c10
fn = 'cmbansp';
pm.k = kh;
pm.psm = psm;
as.la = la;
as.ctt = ctth * cswl;
as.cee = ceeh * cswl;
as.cte = cteh * cswl;
% c1==1 gives a model with a perfect fit

[c1, lmin1, lmax1] = cmbdata1(as, pm, h, omt, om, omb, nprimtilt, tauri, bmark);
% sigma* has to be corrected with sqrt of the amplitude correction ,sqrt(c1) :standard case sig8 =0.915
sig8 = sig8 * sqrt(c1);

% save the anisotropy spectra (as/pm) and matter spectrum (pm) and make plots
%save cmbansp as pm
% bring the cosmological parameters and other data that have been used in the routine to the output:
fid = 1;
fprintf(fid, '\n');
fprintf(fid, 'the redshift at decoupling (maximum of the visibility function) = %g\n', dt.zdec);
fprintf(fid, 'the thickness of the decoupling surface (half width of vsb in redshift) = %g\n', dt.tds);
fprintf(fid, 'the age of the universe at decoupling = %g kyear\n', dt.tdec);
fprintf(fid, 'the age of the universe at reionisation = %g kyear\n', dt.tri);
fprintf(fid, 'the current age of the universe = %g Gyear\n', dt.trc);
fprintf(fid, '\n');
fprintf(fid, 'the conformal distance at decoupling = %g Mpc\n', dt.etadec);
fprintf(fid, 'the thickness of the decoupling surface (half width of vsb in redshift) = %g Mpc\n', trs);
fprintf(fid, 'the number of time integration points over the thickness of the decoupling surface = %g\n', 2*nphw);
fprintf(fid, '\n');
fprintf(fid, 'the cosmological parameter values used in the routine are :\n');
fprintf(fid, 'the density fluctuation at the horizon = %g\n', dha);
fprintf(fid, 'the amplitude correction (at l=10) = %g\n', c1);
fprintf(fid, 'total omega (omt) = %g\n', omt);
fprintf(fid, 'dark matter omega = %g\n', om);
fprintf(fid, 'baryon omega = %g\n', omb);
fprintf(fid, 'Hubble factor = %g\n', h);
fprintf(fid, 'spectral density index = %g\n', nprimtilt);
fprintf(fid, 'optical depth at reionisation = %g\n', tauri);
fprintf(fid, 'sigma8, rms mass overdensity sampled with a sphere of 8 Mpc/h = %g\n', sig8);
fprintf(fid, ['in the figures we compare the results with ', bmark, '\n'])
fprintf(fid, 'the minima in the temperature spectrum are at: ')
fprintf(fid, '%g,  ', lmin1)
fprintf(fid, '\n')
fprintf(fid, 'the maxima in the temperature spectrum are at: ')
fprintf(fid, '%g,  ', lmax1)
fprintf(fid, '\n')


classdef MLSSolver < pf2odfSolver
%
% The class MLSSolver implements the modified least squares solver for
% reconstructing an ODF from arbitrarily scattered pole figure intensities.
% The resulting ODF is represented as a weighted sum of unimodal
% components. The shape and the number of component centers can be
% specified. The algorithm is explained in detail in *A novel pole figure
% inversion method: specification of the MTEX algorithm*, Hielscher,
% Schaeben: J. of Appl. Cryst., 41(6), 2008.
%
% Syntax
%
%   solver = MLSSolver(pf,'resolution',5*degree,'halfwidth',7.5*degree);
%   [odf,alpha] = solver.calcODF;
%
% Class Properties
%  psi     - @SO3Kernel describing the shape of the unimodal components
%  S3G     - the centers of the unimodal components as @SO3Grid in orientation space
%  c       - weighting coefficients to the unimodal components
%  weights -
%  zrm     - @zeroRangeMethod
%  ghostCorrection - whether to use ghost correction
%  iterMax - max number of iterations
%  iterMin - min number of iterations
%
% Dependent Class Properties
%  odf - @SO3Fun the reconstructed ODF
%
% See also
% PoleFigureTutorial PoleFigure2ODFAmbiguity PoleFigure2ODFGhostCorrection

  properties
    psi     % SO3Kernel function
    S3G     % SO3Grid
    c       % current coefficients
    c0      % constant portion
    weights % cell
    zrm     % zero range method
    ghostCorrection = 1
    iterMax = 10; % max number of iterations
    iterMin = 5;  % max number of iterations
    lambda = 0;   % regularisation parameter
    RM = [];      % regularization matrix
  end

  properties (Access = private)
    nfft_gh  % list of nfft plans
    nfft_r   % list of nfft plans
    A        % legendre coefficients of the kernel function
    refl     % cell
    u
    a
    alpha
  end

  properties (Dependent = true)
    odf % the reconstructed @SO3Fun
  end

  methods
    function solver = MLSSolver(pf,varargin)
      % constructor

      if nargin == 0, return; end

      % ensure intensities are non negative
      %solver.pf = unique(max(pf,0));
      solver.pf = max(pf,0);

      % normalize very different polefigures
      mm = max(pf.intensities(:));

      for i = 1:pf.numPF
        if mm > 5*max(pf.allI{i}(:))
          pf.allI{i} = pf.allI{i} * mm/5/max(pf.allI{i}(:));
        end
      end

      % generate discretization of orientation space
      solver.S3G = getClass(varargin,'SO3Grid');
      if isempty(solver.S3G)
        if pf.allR{1}.isOption('resolution')
          res = pf.allR{1}.resolution;
        else
          res = 5*degree;
        end
        res = get_option(varargin,'resolution',res);
        solver.S3G = equispacedSO3Grid(solver.pf.CS,solver.pf.SS,'resolution',res);
      end

      % zero range method
      if check_option(varargin,{'ZR','zero_range','zeroRange'})
        solver.zrm = zeroRangeMethod(solver.pf);
      end

      % get kernel
      psi = SO3DeLaValleePoussinKernel('halfwidth',...
        get_option(varargin,{'HALFWIDTH','KERNELWIDTH'},solver.S3G.resolution,'double'));
      solver.psi = getClass(varargin,'SO3Kernel',psi);

      % get other options
      solver.iterMin = get_option(varargin,'iterMin',solver.iterMin);
      solver.iterMax = get_option(varargin,'iterMax',solver.iterMax);

      % start vector
      solver.c = get_option(varargin,'C0',[]);

      % ghost correction
      solver.ghostCorrection = ~check_option(varargin,'noGhostCorrection');

      % compute quadrature weights
      if numProper(solver.SS) == 1
        solver.weights = cellfun(@(r) calcQuadratureWeights(r),solver.pf.allR,'UniformOutput',false);
      else
        solver.weights = num2cell(1./length(pf,[]));
      end

      % regularisation
      solver.lambda = get_option(varargin,'regularisation',0);

    end

    function delete(solver)
      % destructor

      % free all nfft plans
      for i = 1:length(solver.nfft_gh)
        nfsftmex('finalize',solver.nfft_gh(i));
      end

      for i = 1:length(solver.nfft_r)
        nfsftmex('finalize',solver.nfft_r(i));
      end

    end

    function odf = get.odf(solver)
      if solver.c0 > 0.99
        odf = SO3FunHarmonic(1,solver.CS, solver.SS);
      else
        odf = SO3FunRBF(solver.S3G,solver.psi,...
          (1-solver.c0)*solver.c./sum(solver.c), solver.c0);
      end
    end

  end

  methods (Static = true)

    function check

      cs = crystalSymmetry('222');
      odf = unimodalODF(orientation.id(cs));
      r = equispacedS2Grid('upper','antipodal','resolution',5*degree);
      h = Miller({1,0,0},{1,1,1},{1,1,0},cs);
      pf = calcPoleFigure(odf,h,r);
      odf = calcODF(pf)

      plotPDF(odf,h)
      plotFibre(odf,fibre.alpha(cs))

      mtexdata dubna
      tic
      solver = MLSSolver;
      solver.pf = pf;
      solver.S3G = equispacedSO3Grid(pf.CS,'resolution',2.5*degree);
      solver.psi = SO3DeLaValleePoussinKernel('halfwidth',2.5*degree);
      solver.weights = repcell(1,numPF(pf),1);
      solver.c = ones(length(solver.S3G),1) ./ length(solver.S3G);

      solver.init
      odf = solver.calcODF;
      delete(solver);
      toc

    end

  end

end


function bvalfit()
    % bvalfit Calculates Freq-Mag functions (b-value) for two time-segments
    %
    %   Calculates Freq-Mag functions (b-value) for two time-segments
    %   finds best fit to the foreground for a modified background
    %   assuming a change in time of the following types:
    %   Mnew = Mold + d     , i.e. Simple magnitude shift
    %   Mnew = c*Mold + d   , i.e. Mag stretch plus shift
    %   Nnew = fac*Nold     , i.e. Rate change (N = number of events)
    %                                      R. Zuniga IGF-UNAM/GI-UAF  6/94
    %                                      Rev. 4/2001

    ZG=ZmapGlobal.Data; % used by get_zmap_globals

    %TODO DELETE THIS -> Z TOOL REMOVE COMPARE TWO RATES(FIT)

    global p

    report_this_filefun();

    % This is the info window text
    %
    ttlStr='Comparing Seismicity rates ';
    hlpStr1map= ...
        ['                                                '
        ' To be Implemented                              '
        '                                                '];

    if ic == 0
        format short;
        fac = 1.0;

        bvfig = figure;
        set(bvfig,'Units','normalized','NumberTitle','off','Name','b-value curves');
        set(bvfig,'pos',[ 0.435  0.3 0.5 0.5])

        if isempty(ZG.newcat)
            ZG.newcat = a;
        end
        maxmag = max(ZG.newcat.Magnitude);
        mima = min(ZG.newcat.Magnitude);
        if mima > 0
            mima = 0 ;
        end
        [t0b, teb] = bounds(ZG.newcat.Date) ;
        n = ZG.newcat.Count;
        tdiff = round(teb - t0b);

        % number of mag units
        nmagu = (maxmag-mima*10)+1;

        td12 = t2p(1) - t1p(1);
        td34 = t4p(1) - t3p(1);

        l = ZG.newcat.Date > t1p(1) & ZG.newcat.Date < t2p(1) ;
        backg =  ZG.newcat.subset(l);
        [bval,xt2] = hist(backg(:,6),(mima:0.1:maxmag));
        bval = bval/td12;                      % normalization
        bvalsum = cumsum(bval);                        % N for M <=
        bvalsum3 = cumsum(bval(end:-1:1));    % N for M >= (counted backwards)
        magsteps_desc = (maxmag:-0.1:mima);
        [cumux, xt] = hist(ZG.newcat.Date(l),t1p(1):days(ZG.bin_dur):t2p(1));

        l = ZG.newcat.Date > t3p(1) & ZG.newcat.Date < t4p(1) ;
        foreg = ZG.newcat.subset(l);
        bval2 = histogram(foreg(:,6),(mima:0.1:maxmag));
        bval2 = bval2/td34;                     % normallization
        bvalsum2 = cumsum(bval2);
        bvalsum4 = cumsum(bval2(end:-1:1));
        [cumux2, xt] = hist(ZG.newcat.Date(l),t3p(1):days(ZG.bin_dur):t4p(1));
        mean1 = mean(cumux);
        mean2 = mean(cumux2);
        var1 = cov(cumux);
        var2 = cov(cumux2);
        zscore = (mean1 - mean2)/(sqrt(var1/length(cumux)+var2/length(cumux2)));

        backg_be = log10(bvalsum);
        backg_ab = log10(bvalsum3);
        foreg_be = log10(bvalsum2);
        foreg_ab = log10(bvalsum4);

        orient landscape
        rect = [0.2,  0.2, 0.70, 0.70];           % plot Freq-Mag curves
        axes('position',rect)
        semilogy(magsteps_desc,bvalsum3,'om')
        set(gca,'NextPlot','add')
        semilogy(magsteps_desc,bvalsum4,'xb')

        te1 = max([bvalsum  bvalsum2 bvalsum4 bvalsum3]);
        te1 = te1 - 0.2*te1;
        title([file1 '   o: ' num2str(t1p(1)) ' - ' num2str(t2p(1)) '     x: ' num2str(t3p(1)) ' - '  num2str(t4p(1)) ],'FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','bold')

        xlabel('Magnitude','FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','bold')
        ylabel('Cum. Number -normalized','FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','bold')
        %  find b-values;
        set(gca,'box','on',...
            'SortMethod','childorder','TickDir','out','FontWeight',...
            'bold','FontSize',ZmapGlobal.Data.fontsz.s,'Linewidth',1.2)

        figure(mess);
        clf;
        cla;
        set(gcf,'Name','Magnitude selection ');
        set(gca,'visible','off');
        txt5 = text('Position',[.01 0.99 0 ],...
            'FontSize',ZmapGlobal.Data.fontsz.m ,...
            'FontWeight','bold',...
            'String','Please select two magnitudes to be used');
        txt1 = text('Position',[.01 0.84 0 ],...
            'FontSize',ZmapGlobal.Data.fontsz.m ,...
            'FontWeight','bold',...
            'String','in the calculation of straight line fit i.e.');
        txt2 = text('Position',[.01 0.66 0 ],...
            'FontSize',ZmapGlobal.Data.fontsz.m ,...
            'FontWeight','bold',...
            'String','b value of BACKGROUND (o)');

        figure(bvfig);
        seti = uicontrol(...
            'Units','normal','Position',[.4 .01 .2 .05],...
            'String','Select Mag1 ');

        pause(1)

        M1b = ginput(1);
        tx1 = text( M1b(1),M1b(2),['M1'] );
        set(seti,'String','Select Mag2');

        pause(0.1)

        M2b = ginput(1);
        tx2 = text( M2b(1),M2b(2),['M2'] );

        pause(0.1)
        delete(seti)

        ll = magsteps_desc > M1b(1) & magsteps_desc < M2b(1);
        x = magsteps_desc(ll);
        y = backg_ab(ll);
        p  = polyfit(x,y,1);                  % fit a line to background
        f = polyval(p,x);
        f = 10.^f;
        set(gca,'NextPlot','add')
        semilogy(x,f,'r')                         % plot linear fit to backg
        r = corrcoef(x,y);
        r = r(1,2);
        std_backg = std(y - polyval(p,x));      % standard deviation of fit

        figure(mess);
        clf;
        cla;
        set(gcf,'Name','Magnitude selection ');
        set(gca,'visible','off');
        txt5 = text(...
            'Position',[.01 0.99 0 ],...
            'FontSize',ZmapGlobal.Data.fontsz.m ,...
            'FontWeight','bold',...
            'String','Please select two magnitudes to be used');
        txt1 = text('Position',[.01 0.84 0 ],...
            'FontSize',ZmapGlobal.Data.fontsz.m ,...
            'FontWeight','bold',...
            'String','in the calculation of straight line fit i.e.');
        txt2 = text(...
            'Position',[.01 0.66 0 ],...
            'FontSize',ZmapGlobal.Data.fontsz.m ,...
            'FontWeight','bold',...
            'String','b value of FOREGROUND (x)');

        figure(bvfig);
        seti = uicontrol('Units','normal',...
            'Position',[.4 .01 .2 .05],'String','Select Mag1 ');

        pause(1)

        M1f = [];
        M1f = ginput(1);
        tx3 = text( M1f(1),M1f(2),['M1'] )
        set(seti','String','Select Mag2');

        pause(0.1)

        M2f = [];
        M2f = ginput(1);
        tx4 = text( M2f(1),M2f(2),['M2'] )

        pause(0.1)
        delete(seti)

        l = magsteps_desc > M1f(1) & magsteps_desc < M2f(1);
        x = magsteps_desc(l);
        y = foreg_ab(l);
        pp = polyfit(x,y,1);
        % fit a line to foreground
        f = polyval(pp,x);
        f = 10.^f;
        semilogy(x,f,'r')                   % plot fit to foreg
        rr = corrcoef(x,y);
        rr = rr(1,2);
        std_foreg = std(y - polyval(pp,x));      % standard deviation of fit

        figure(mess);
        clf
        set(gca,'visible','off')
        set(gcf,'Units','normalized','pos',[ 0.03  0.1 0.4 0.7])
        set(gcf,'Name','Compare Results');
        orient tall
        te = text(0.,0.99, ['   Catalogue : ' file1]) ;
        set(te,'FontSize',ZmapGlobal.Data.fontsz.s);
        stri = [ 'Background (o):   ' num2str(t1p(1)) '  to  ' num2str(t2p(1)) ];
        te = text(0.01,0.93, stri) ;
        set(te,'FontSize',ZmapGlobal.Data.fontsz.s);
        aa_ = p(2) *1000.0;
        aa_ = round(aa_);
        aa_ = aa_/1000.0;
        bb = p(1) *1000.0;
        bb = round(bb);
        bb = bb/1000.0;          % round to 0.001
        stri = [' Log N = ' num2str(aa_)  num2str(bb) '*M ' ];
        te = text(0.01,0.88, stri) ;
        set(te,'FontSize',ZmapGlobal.Data.fontsz.s);
        stri = [ 'Foreground (x):   ' num2str(t3p(1)) '  to  ' num2str(t4p(1)) ];
        te = text(0.01,0.83, stri) ;
        set(te,'FontSize',ZmapGlobal.Data.fontsz.s);
        aa_ = pp(2) *1000.0;
        aa_ = round(aa_);
        aa_ = aa_/1000.0;
        bb = pp(1) *1000.0;
        bb = round(bb);
        bb = bb/1000.0;          % round to 0.001
        stri = [' Log N = ' num2str(aa_) num2str(bb) '*M '];
        te = text(0.01,0.78, stri) ;
        set(te,'FontSize',ZmapGlobal.Data.fontsz.s);
        disp([' Correlation coefficient for background = ', num2str(r) ]);
        disp([' Correlation coefficient for foreground = ', num2str(rr) ]);
        %  find simple shift
        % first find Mmin ( M for which the background relation
        % departs from straight line by more than std )
        ld = abs(backg_ab - polyval(p,magsteps_desc)) <= std_backg;
        [min_backg, ldb] = min(magsteps_desc(ld));        % Mmin of background
        n1 = backg_ab(ld);
        n1 = n1(ldb);                           % Cum number for Mmin background
        magi = (n1 - pp(2))/pp(1)  % magi is intercept of n1 with foreground linear fit
        dM = magi - min_backg;        % magnitude shift
        ld = abs(foreg_ab - polyval(pp,magsteps_desc)) <= std_foreg;
        [min_foreg, ldf] = min(magsteps_desc(ld));        % min_foreg is Mmin of foreground
        disp([' Mmin for background = ', num2str(min_backg) ]);
        disp([' Mmin for foreground = ', num2str(min_foreg) ]);
        stri = [ 'Minimum magnitude for Background = ' num2str(min_backg) ];
        te = text(0.01,0.73, stri) ;
        set(te,'FontSize',ZmapGlobal.Data.fontsz.s);
        stri = [ 'Minimum magnitude for Foreground = ' num2str(min_foreg) ];
        te = text(0.01,0.68, stri) ;
        set(te,'FontSize',ZmapGlobal.Data.fontsz.s);
        stri = ['Z score between both rates: '];
        te = text(0.01,0.63, stri) ;
        set(te,'FontSize',ZmapGlobal.Data.fontsz.s);
        stri = [' Z = ' num2str(zscore) ];
        te = text(0.01,0.58, stri) ;
        set(te,'FontSize',ZmapGlobal.Data.fontsz.s);
        dM = (round(dM *10.0))/10;     % round to 0.1
        backg_new = [backg(:,1:5), backg(:,6)+dM, backg(:,7)];    %  add shift

        [bvalN,xt2] = hist(backg_new(:,6),(mima:0.1:maxmag));
        bvalN = bvalN/td12;                               % normalize
        bvalsumN = cumsum(bvalN);
        bvalsum3N = cumsum(bvalN(end:-1:1));
        backg_beN = log10(bvalsumN);
        backg_abN = log10(bvalsum3N);

        res =  (sum((bvalN - bval2).^2)/length(bval2))^0.5 ; % residual in histograms
        %%disp(['Average residual of simple shift = ', num2str(res)]);

        figure(mess);
        stri = [ 'Suggested single magnitude shift (d):']
        te = text(0.01,0.50, stri) ;
        set(te,'FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','bold');
        stri = ['Mx = Mo + (', num2str(dM),')']
        te = text(0.01,0.45, stri) ;
        set(te,'FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','bold');
        %  compute magnitude stretch and shift
        pause(0.1)

        mf = p(1)/pp(1);            % factor is calculated from ratio of b values
        mf = (round(mf *100.0))/100.0;    % round to 0.01
        dM = -mf*(pp(2) - p(2))/p(1);   %  find shift by diff of zero ordinates
        dM = (round(dM *100.0))/100.0;    % round to 0.01
        stri = [ 'Linear Mag correction (stretch, c, and shift, d):' ];
        te = text(0.01,0.38, stri) ;
        set(te,'FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','bold');
        stri = [ 'Mx = ',num2str(mf), '* Mo + (', num2str(dM),')' ];
        te = text(0.01,0.33, stri) ;
        set(te,'FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','bold');
        set(gca,'NextPlot','add')
    end   % if ic

    if ic == 0 | ic == 2

        figure(bvfig);
        if ic == 2, clf, end
        bvalsumN = [ ];
        bvalsum3N = [ ];
        % Modify Magnitudes
        backg_new = [backg(:,1:5), (mf*backg(:,6))+dM, backg(:,7)];

        [bvalN,xt2] = hist(backg_new(:,6),(mima:0.1:maxmag));
        bvalN = bvalN/td12;                              % normalize
        bvalsumN = cumsum(bvalN);
        bvalsum3N = cumsum(bvalN(end:-1:1));
        backg_beN = log10(bvalsumN);
        backg_abN = log10(bvalsum3N);

        % residual in histograms
        res =  (sum((bvalN - bval2).^2)/length(bval2))^0.5 ;

        % find rate increase_decrease
        if ic ==0 |ic ==1
            rat = [ ];
            rat = bval2/bvalN;            % by mean of ratios
            l = 1 - (isnan(rat) + isinf(rat));
            fac1 = mean(rat(l));
            fac1 = fac1 *100.0;
            fac1 = round(fac1);
            fac1 = fac1/100.0;               % round to 0.01
            fac = fac1;
        end     % if ic

        ind = 0;                      %  find minimum magnitude for the rate change
        resm = [ ];
        if ic ==0
            fac = 1.0 ;
        end
        bvalN = bvalN*fac ;    % apply rate to all data

        bvalsumN = cumsum(bvalN);
        bvalsum3N = cumsum(bvalN(end:-1:1));
        backg_beN = log10(bvalsumN);
        backg_abN = log10(bvalsum3N);

        magi = magi *10.0;
        magi = round(magi);
        magi = magi/10.0;               % round to 0.1
        % residual in histograms
        res =  (sum((bvalN - bval2).^2)/length(bval2))^0.5 ;

        figure(mess);
        if ic == 0 | ic == 1
            stri = [ 'Suggested rate change (Nx = fac*No): \newline fac = ' num2str(fac1) ];
            te = text(0.01,0.27, stri) ;
            set(te,'FontSize',ZmapGlobal.Data.fontsz.s,'Visible','on');
        end   % if ic
        magis = maxmag;

        uicontrol('Units','normal','Position',[.88 .9 .11 .06],'String','Print  ', 'callback',@callbackfun_001)
        uicontrol('Units','normal','Position',[.88 .80 .11 .06],'String','Close  ', 'callback',@callbackfun_002)

        freq_field1=uicontrol('Style','edit',...
            'Position',[.30 .16 .13 .07],...
            'Units','normalized','String',num2str(dM),...
            'callback',@callbackfun_003);

        freq_field2=uicontrol('Style','edit',...
            'Position',[.75 .16 .13 .07],...
            'Units','normalized','String',num2str(mf),...
            'callback',@callbackfun_004);

        freq_field3=uicontrol('Style','edit',...
            'Position',[.30 .05 .13 .07],...
            'Units','normalized','String',num2str(fac),...
            'callback',@callbackfun_005);

        txt1 = text(...
            'Color',[0 0 0 ],...
            'Position',[.01 0.11 0 ],...
            'FontSize',ZmapGlobal.Data.fontsz.s ,...
            'String','Shift (d)');

        txt2 = text(...
            'Color',[0 0 0 ],...
            'Position',[.44 0.11 0 ],...
            'FontSize',ZmapGlobal.Data.fontsz.s ,...
            'String','  Stretch factor (c)');

        txt3 = text(...
            'Color',[0 0 0 ],...
            'Position',[.01 0.0 0 ],...
            'FontSize',ZmapGlobal.Data.fontsz.s ,...
            'String','Rate factor');

        go_button=uicontrol('Style','Pushbutton',...
            'Position',[.52 .01 .10 .07 ],...
            'Units','normalized',...
            'callback',@callbackfun_006,...
            'String','Go');
        res = bval2 - bvalN ;

        close(bvfig)
        % Find out if figure already exists and plot results of fit
        %
        bvfig=findobj('Type','Figure','-and','Name','Compare and fit two rates');

        ms3 = 5;

        %if isempty(bvfig)
        bvfig= figure_w_normalized_uicontrolunits( ...
            'Name','Compare and fit two rates',...
            'NumberTitle','off', ...
            'backingstore','on',...
            'Visible','on', ...
            'Position',position_in_current_monitor(ZG.map_len(1), ZG.map_len(2)+200));

        uicontrol('Units','normal',...
            'Position',[.0 .93 .08 .06],'String','Print ',...
            'callback',@callbackfun_007)

        uicontrol('Units','normal',...
            'Position',[.0 .75 .08 .06],'String','Close ',...
            'callback',@callbackfun_008)

        uicontrol('Units','normal',...
            'Position',[.0 .85 .08 .06],'String','Info ',...
            'callback',@callbackfun_009)
        axis off
        %end % if figure exits

        %%figure(bvfig);
        delete(findobj(bvfig,'Type','axes'));
        % plot b-value plot
        %
        orient tall
        set(gcf,'PaperPosition',[2 1 5.5 7.5])
        rect = [0.20,  0.7, 0.70, 0.25];           % plot Freq-Mag curves
        axes('position',rect)
        set(gca,'NextPlot','add')
        figure(bvfig);
        set(gca,'NextPlot','add')
        pl = semilogy(magsteps_desc,bvalsum4,'xb');
        set(gca,'Yscale','log')
        set(gca,'NextPlot','add')
        set(pl,'MarkerSize',ms3)
        semilogy(magsteps_desc,bvalsum4,'-.b')
        pl = semilogy(magsteps_desc,bvalsum3N,'om');
        set(pl,'MarkerSize',ms3)
        semilogy(magsteps_desc,bvalsum3N,'m')
        te1 = max([bvalsum  bvalsum2 bvalsum4 bvalsum3]);
        te1 = te1 - 0.2*te1;

        ylabel('Cum. rate/year','FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','bold')
        str = [ '   o: ' num2str(t1p(1),6) ' - ' num2str(t2p(1),4) '     x: ' num2str(t3p(1),6) ' - '  num2str(t4p(1),6) ];

        title(str,'FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','bold')
        %  find b-values;
        set(gca,'box','on',...
            'SortMethod','childorder','TickDir','out','FontWeight',...
            'bold','FontSize',ZmapGlobal.Data.fontsz.s,'Linewidth',1.0)
        p1 = gca;

        % Plot histogram
        %

        rect = [0.20,  0.40 0.70, 0.25];
        axes('position',rect)
        pl = plot(xt2,bvalN,'om');
        set(pl,'MarkerSize',ms3,'LineWidth',1.0)
        set(gca,'NextPlot','add')
        pl = plot(xt2,bval2,'xb');
        set(pl,'MarkerSize',ms3,'LineWidth',1.0)
        pl = plot(xt2,bval2,'-.b');
        set(pl,'MarkerSize',ms3,'LineWidth',1.0)
        pl = plot(xt2,bvalN,'m');
        set(pl,'MarkerSize',ms3,'LineWidth',1.0)
        disp([' Summation: ' num2str(sum(bval-bval2))])
        v = axis;
        xlabel('Magnitude ','FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','bold')
        ylabel('rate/year','FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','bold')
        set(gca,'box','on',...
            'SortMethod','childorder','TickDir','out','FontWeight',...
            'bold','FontSize',ZmapGlobal.Data.fontsz.s,'Linewidth',1.0)

        uic = uicontrol('Units','normal','Position',[.35 .15 .30 .07],'String','Magnitude Signature? ', 'callback',@callbackfun_010);

    end   % if ic

    clear rat bvalNN mean1 mean2 ld l ll txt1 txt2 txt3 txt4 M1b M2b M1f M2f tx1 tx2 tx3 tx4;
    ic = 0;
    format;

    function callbackfun_001(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        printdlg;
    end

    function callbackfun_002(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));

    end

    function callbackfun_003(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        dM=str2double(freq_field1.String);
        freq_field1.String=num2str(dM);
    end

    function callbackfun_004(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        mf=str2double(freq_field2.String);
        freq_field2.String=num2str(mf);
    end

    function callbackfun_005(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        fac=str2double(freq_field3.String);
        freq_field3.String=num2str(fac);
    end

    function callbackfun_006(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        ic = 2;
        bvalfit;
    end

    function callbackfun_007(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        printdlg;
    end

    function callbackfun_008(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        f1=gcf;
        f2=gpf;
        set(f1,'Visible','off');
    end

    function callbackfun_009(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        zmaphelp(ttlStr,hlpStr1map,hlpStr2map,hlpStr3map);
    end

    function callbackfun_010(mysrc,myevt)

        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        delete(uic);
        synsig;
    end

end


function s = getBehAssociation(Gamma,y,T,synch)
% Returns, for each time point, how well the state time courses predict
% the variable y across trials, which must have dimension (trials by 1)
%
% Author: Diego Vidaurre, OHBA, University of Oxford (2018)

if ~all(T(1)==T)
    error('Synchronisity can only be measured if trials have the same length');
end
N = length(T);
ttrial = size(Gamma,1)/N;
if nargin<4, synch = zeros(1,T(1)); end
K = size(Gamma,2);
Gamma = permute(reshape(Gamma,[ttrial N K]),[2 3 1]);
s = zeros(1,ttrial);
these = ~isnan(y);
y = y(these);
N = length(y);
y = zscore(y);
for t = 1:ttrial
   if synch(t)==1, continue; end
   x = [ones(N,1) Gamma(these,1:K-1,t)];
   beta = (x' * x + 1e-8 * eye(K) ) \ (x' *  y);
   s(t) = 1 - sum((y - x * beta).^2) / sum(y.^2);
end

end


function [f,g,H] = taylorModel(d,f,g,H,T)

p = length(d);

fd3 = 0;
gd2 = zeros(p,1);
Hd = zeros(p);
for t1 = 1:p
    for t2 = 1:p
        for t3 = 1:p
            fd3 = fd3 + T(t1,t2,t3)*d(t1)*d(t2)*d(t3);

            if nargout > 1
                gd2(t3) = gd2(t3) + T(t1,t2,t3)*d(t1)*d(t2);
            end

            if nargout > 2
                Hd(t2,t3) = Hd(t2,t3) + T(t1,t2,t3)*d(t1);
            end
        end

    end
end

f = f + g'*d + (1/2)*d'*H*d + (1/6)*fd3;

if nargout > 1
    g = g + H*d + (1/2)*gd2;
end

if nargout > 2
    H = H + Hd;
end

if any(abs(d) > 1e5)
    % We want the optimizer to stop if the solution is unbounded
    g = zeros(p,1);
end


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

%% Syntax
% |[Fq,Vq,Fc,Vc]=dualClad(F,V,shrinkFactor,cladMethod);|

%% Description
% This function creates patch data defining a cladding on a surface. The
% cladding is obtained by shrinking the input faces around their mean and
% by connecting the face sides to form new faces. The output faces cover
% the edges of the dual of the input surface (hence the name). The output
% is the set of shrunk faces (same type as input) and a set of new
% quadrilateral faces connecting the shrunk faces.
% The shrink factor, which can be a constant or a spatially varying metric
% on the nodes or faces, defines the face and edge shrink used. The
% clad method determines whether the output mesh is connected:
% 1: From shrunk face to shrunk face
% 2: From shrunk face to shrunk edge to shrunk face
% 3: From shrunk face to shrunk face through edge (computes intersection at
% edge which may not be the centre of edge. This method avoids potential
% "kinks" seen for method 2.

%% Examples
clear; close all; clc;

%%
% Plot settings

figStruct.ColorDef='black';
figStruct.Color='k';

%%
% Specify test surface. Alter settings to test for different geometries and
% surface types.

%Testing settings
testCase=2; %1= sphere, 2=bunny, 3=dino
meshType=1; %1=triangles, 2=quadrilaterials
cutMesh=0; %0=not cut, 1=cut in half

switch testCase
    case 1
        [F,V,~]=geoSphere(2,1); % Building a geodesic dome surface model
        shrinkFactor=0.25;
    case 2
        [F,V]=stanford_bunny('g'); %Bunny
        V_mean=mean(V,1);
        V=V-V_mean(ones(size(V,1),1),:);
        shrinkFactor=0.25;
    case 3
        [F,V]=parasaurolophus; %dino
        V_mean=mean(V,1);
        V=V-V_mean(ones(size(V,1),1),:);
        shrinkFactor=0.25;
    case 4
        defaultFolder = fileparts(fileparts(mfilename('fullpath')));
        pathName=fullfile(defaultFolder,'data','libSurf');

        dataStruct=load(fullfile(pathName,'sprocket.mat'));
        F=dataStruct.F;
        V=dataStruct.V;
        shrinkFactor=0.5;
    case 5
        defaultFolder = fileparts(fileparts(mfilename('fullpath')));
        pathName=fullfile(defaultFolder,'data','libSurf');

        dataStruct=load(fullfile(pathName,'enginePart_p1.mat'));
        F=dataStruct.F;
        V=dataStruct.V;
        shrinkFactor=0.5;
end

if meshType==2
    [F,V]=tri2quad(F,V);
end

if cutMesh==1
    logicKeep=V(:,1)<mean(V(:,1));
    logicKeep=all(logicKeep(F),2);
    F=F(logicKeep,:);
    [F,V]=patchCleanUnused(F,V);
end

%% Example 1: Explaining the clad method

%%
% Define |dualClad| settings, i.e. the cladMethod and the shrink factor.
cladMethods=[1 2 3]; %1= fact-to-face connections, 2=

%%
% Visualize results

cFigure;

for q=1:1:numel(cladMethods)

    [Fq,Vq,Fc,Vc]=dualClad(F,V,shrinkFactor,cladMethods(q));

    subplot(1,3,q); hold on;
    title(['Clad method: ',num2str(cladMethods(q))]);
    h(1)=gpatch(F,V,'kw','k',0.25);
    h(2)=gpatch(Fc,Vc,'gw','g',1);
    h(3)=gpatch(Fq,Vq,'rw','r',1);
    h(4)=plotV([Vc;Vq],'b.','MarkerSize',15);
    axisGeom;
    camlight headlight;
    view(2);
    hl=legend(h,{'Input','Shrunk faces','Quads','Output vertices'});
    hl.Location='SouthOutside';
end

drawnow;

%% Example 2: Explaining the shrink factor

%%
% Define |dualClad| settings, i.e. the cladMethod and the shrink factor.
cladMethod=3; %1= fact-to-face connections, 2=

shrinkFactors=linspace(0.1,0.75,3); %A range of shrink factors

%%
% Visualize results

cFigure;
subplot(2,2,1); hold on;
title('Input surface');
gpatch(F,V,'gw','g',1);

axisGeom;
camlight headlight;
view(2);

for q=1:1:numel(shrinkFactors)

    [Fq,Vq,Fc,Vc]=dualClad(F,V,shrinkFactors(q),cladMethod);

    subplot(2,2,q+1); hold on;
    title(['Shrink factor: ',num2str(shrinkFactors(q))]);
    gpatch(Fc,Vc,'rw','r',1);
    gpatch(Fq,Vq,'rw','r',1);
    gpatch(F,V,'kw','none',0.25);
    axisGeom;
    camlight headlight;
    view(2);
end

drawnow;

%% Example 3: Spatially varying shrink factors
% An animation will be created to show effect of a spatially varying shrink
% factor

cladMethod=3;

% Define spatially varying shrink factor
shrinkFactor=-V(:,1);
shrinkFactor=mean(shrinkFactor(F),2);
shrinkFactor=shrinkFactor-min(shrinkFactor(:));
shrinkFactor=shrinkFactor./max(shrinkFactor(:));
shrinkFactor=shrinkFactor*1.2;
shrinkFactor=shrinkFactor+0.05;
shrinkFactor(shrinkFactor>1)=1;

[Fq,Vq,Fc,Vc]=dualClad(F,V,shrinkFactor,cladMethod);

%%
% Animating the effect of the shrink factor

%%
% Initialize scene
hf=cFigure(figStruct);
hold on;

hp1=gpatch(Fc,Vc,shrinkFactor,'k',1);
hp2=gpatch(Fq,Vq,'r','none',1);

axisGeom;
camlight headlight;
colormap(viridis(250));
clim([0 1]);
drawnow;
axis off
axis manual;

%%
% Animate scene

nSteps=40; %Number of animation steps
animStruct.Time=linspace(0,1,nSteps); %Create the time vector

t=linspace(0,2,nSteps);
shrinkFactor=-V(:,1);
shrinkFactor=mean(shrinkFactor(F),2);
shrinkFactor=shrinkFactor-min(shrinkFactor(:));
shrinkFactor=shrinkFactor./max(shrinkFactor(:));
shrinkFactor=shrinkFactor+1;
minLevel=0.05;

for q=1:1:nSteps

      shrinkFactorNow=shrinkFactor;
      shrinkFactorNow=shrinkFactorNow-t(q);
      shrinkFactorNow(shrinkFactorNow<minLevel)=minLevel;
      shrinkFactorNow(shrinkFactorNow>1)=1;

    [Fq,Vq,Fc,Vc]=dualClad(F,V,shrinkFactorNow,cladMethod);

    %Set entries in animation structure
    animStruct.Handles{q}=[hp1 hp2 hp1]; %Handles of objects to animate
    animStruct.Props{q}={'Vertices','Vertices','CData'}; %Properties of objects to animate
    animStruct.Set{q}={Vc,Vq,shrinkFactorNow}; %Property values for to set in order to animate
end

anim8(hf,animStruct); %Initiate animation

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

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


clear all; close all;
I=imread('circles.png');
J=bwmorph(I, 'remove');
figure;
subplot(121);  imshow(I);
subplot(122);  imshow(J);


function varargout = slice(f)
%SLICE   Plots slices (cross sections) of a BALLFUN.
%   SLICE(F) creates a slice plot of the BALLFUN at x = 0, y = 0 and z = 0.
%
% See also BALLFUN/PLOT.

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

% Check if the function is empty
if isempty(f)
    error('CHEBFUN:BALLFUN:slice:isempty','Function is empty.');
end

% Add a warning of the function is not real
if (f.isReal == 0)
    warning('CHEBFUN:BALLFUN:slice:isReal','Function is not real, plotting the real part.');
end

% Is the plot currently being held?
plotOnHold = ishold;
% Default plotting options
defaultOpts = {'facecolor', 'interp','edgecolor', 'none'};

% Define the size of f:
[m,n,p] = size(f);

% m >= 25 and n, p >= 28
m = 25*(m < 25) + m*(m >= 25);
n = 28*(n < 28) + n*(n>=28);
p = 28*(p < 28) + p*(p>=28);

% Impose m = 1 [6] and n, p = 0 [4] to avoid errors in the plot
m = m + mod(1-mod(m,6),6);
n = n + mod(4-mod(n,4),4);
p = p + mod(4-mod(p,4),4);

% Discretization points
r = chebpts(m); r = r(floor(m/2)+1:end);
lam = linspace(-pi,pi,n);
th = linspace(0,pi,p);

% Evaluate the function at x = 0, y < 0
ff = permute(fevalm(f,r,-pi/2,th),[1 3 2]);
ff = real(ff);
% Plot the result
h = surf(zeros(length(r),length(th)),-r*sin(th),r*cos(th),ff,defaultOpts{:});

hold on

% Evaluate the function at x = 0, y > 0
ff = permute(fevalm(f,r,pi/2,th),[1 3 2]);
ff = real(ff);
% Plot the result
surf(zeros(length(r),length(th)),r*sin(th),r*cos(th),ff,defaultOpts{:})

% Evaluate the function at y = 0, x < 0
ff = permute(fevalm(f,r,pi,th),[1 3 2]);
ff = real(ff);
% Plot the result
surf(-r*sin(th),zeros(length(r),length(th)),r*cos(th),ff,defaultOpts{:})
% Evaluate the function at y = 0, x > 0
ff = permute(fevalm(f,r,0,th),[1 3 2]);
ff = real(ff);
% Plot the result
surf(r*sin(th),zeros(length(r),length(th)),r*cos(th),ff,defaultOpts{:})

% Evaluate the function at z = 0
ff = fevalm(f,r,lam,pi/2);
ff = real(ff);
% Plot the result
surf(r*cos(lam),r*sin(lam),zeros(length(r),length(lam)),ff,defaultOpts{:})

if ~plotOnHold
    hold off;
end

camlight('headlight');
lighting phong;
material dull;

axis([-1 1 -1 1 -1 1])
daspect([1 1 1])

if ( nargout > 0 )
    varargout = { h };
end
end


format compact
addpath('src_release');
addpath('build');
test_OMP
test_OMPMask
test_Lasso
test_LassoMask
test_LassoWeighted
test_CD
test_RidgeRegression
test_SparseProject
test_SOMP
test_L1L2BCD
test_TrainDL
test_TrainDL_Memory
test_StructTrainDL
test_nmf
test_ProximalFlat
test_ProximalTree
test_ProximalGraph
test_ProximalPathCoding
test_EvalPathCoding
test_FistaFlat
test_FistaTree
test_FistaGraph
test_FistaPathCoding
test_CalcAAt
test_CalcXAt
test_CalcXY
test_CalcXYt
test_CalcXtY
test_ConjGrad
test_InvSym
test_Normalize
test_Sort
test_CountConnexComponents
test_CountPathsDAG
test_RemoveCyclesGraph