function [A,idxList]=quickSort(A,byCol,gtCompareFunc)
%%QUICKSORT Sort an array, a matrix, or a cell array in ascending order
%           using a non-recursive implementation of the quicksort
%           algorithm. The quicksort algorithm tends to have better average
%           performance than other techniques, being O(n*log(n)) averge and
%           best case, with a small multiplicative constant, but has O(n^2)
%           worst case performance, which is worse than heapsort.  A custom
%           comparison function can be used so that one can, for example,
%           sort strings or other things. Changing the direction of the
%           comparison function (from greater than to less than) changes
%           the sorting order from ascending to descending. Note that
%           quickSort is not a stable sorting algorithm, meaning that the
%           order of items having the same value might change.
%
%INPUTS: A  An array, 2D matrix, or linear cell array that is to be sorted.
%           When given a matrix, the comparison function gtCompareFunc must
%           be provided so that it is clear how the columns are compared
%           (or the rows if byCol is false).
%     byCol A boolean value indicating whether sorting should be performed
%           by row or by column. This must be specified when a matrix is
%           passed as as a linear array could be confused with a matrix
%           with just one row/column. The default if this parameter is
%           omitted and the input is 1-dimensional is whatever would sort
%           over the 1D array. If the input is 2D, then the default is
%           true. This parameter is not used when cell arrays are passed
%           (an empty matrix can be passed for this) as only linear cell
%           arrays are supported, so no ambiguity between 1D and 2D inputs
%           would exist.
%gtCompareFunc  A function handle that performs a greather-than comparison
%               of two entries in A. This lets one define custom comparison
%               operations. Providing a less-than comparison for this will
%               cause the list to be sorted in descending order rather than
%               ascending order. When sorting an array or matrix, the
%               the function handle takes inputs of the form
%               gtCompareFunc(A(:,i),A(:,j)) if byCol=true and with
%               reversed row and column indices if byCol=false. When
%               comparing cell arrays, it must handle inputs of the form
%               gtCompareFunc(A{i},A{j}). The default if this parameter is
%               omitted is @(x1,x2)(x1>x2);
%
%OUTPUTS: A The sorted array/ matrix/ cell array. If gtCompareFunc
%           performs a greater-than comparison, then it is in increasing
%           order. Otherwise it is in decreasing order.
%   idxList The indices of the original elements with respect to the sorted
%           order. For example, if the input A is an array, then
%           A(idxList) on the input A will give the sorted output A.
%
%The quicksort algorithm is based on the description given in Chapter 7 of
%[1]. However, it has been modified to eliminate the recursion.
%
%Note that sorting large matrices can be slow as each element (so an entire
%row/ column) is copied during the search. Thus, if one is just sorting
%according to a particular row, it makes sense ot get the idxList for that
%one row and then use it to sort everything else.
%
%REFERENCES:
%[1] T. H. Cormen, C. E. Leiserson, R. L. Rivest, and C. Stein,
%    Introduction to Algorithms, 2nd ed. Cambridge, MA: The MIT Press,
%    2001.
%
%December 2014 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

    %If an empty matrix is passed, return an empty matrix.
    if(isempty(A))
        idxList=[];
        return;
    end

    if(nargin<2||isempty(byCol))
        %If the input is 1-dimensional, then make the byCol parameter go
        %over whichever dimension would sort it. Otherwise, make it go over
        %columns.
        if(size(A,1)==1)
            byCol=true;
        elseif(size(A,2)==1)
            byCol=false;
        else
            byCol=true;
        end
    end

    if(nargin<3||isempty(gtCompareFunc))
        gtCompareFunc=@(x1,x2)(x1>x2);
    end

    isACellArray=isa(A,'cell');
    if(~isACellArray)
        %If A is supposed to be sorted by row.
        if(byCol==false)
            A=A';
        end

        numPoints=size(A,2);
    else
        numPoints=length(A);
    end

    %The index list is not used in the algorithm for sorting; it is just
    %computed in case the user wants it as a return variable.
    idxList=1:numPoints;

    %stack(:,i) holds the lower and upper bounds of the partiion being
    %sorted at the ith level. The upper bound on the stack space in
    %the worst-case scenario is where every single point visited
    %creates two partitions. However, since each time it splits, it
    %deletes itself, the limit on the memory is ceil(numPoints/2) and
    %not numPoints.
    stack=zeros(2,ceil(numPoints/2));

    p=1;
    r=numPoints;
    stackIdx=1;
    stack(:,stackIdx)=[p;r];
    while(stackIdx>0)
        %Pop the p and r values off of the stack.
        p=stack(1,stackIdx);
        r=stack(2,stackIdx);
        stackIdx=stackIdx-1;

        %Partition the array, getting the correct location of the pivor
        %element.
        if(~isACellArray)
            [q,A,idxList]=partition(A,idxList,p,r,gtCompareFunc);
        else
            [q,A,idxList]=partitionCell(A,idxList,p,r,gtCompareFunc);
        end

        %If there are elements on the left side, then push them onto
        %the stack.
        if(p<q-1)
            stackIdx=stackIdx+1;
            stack(:,stackIdx)=[p;q-1];
        end

        %If there are elements on the right side, then push them onto
        %the stack.
        if(q+1<r)
            stackIdx=stackIdx+1;
            stack(:,stackIdx)=[q+1;r];
        end
    end

    %Restore the orientation if it was supposed to be sorted by row.
    if(~isACellArray&&byCol==false)
        A=A';
    end
end

function [q,A,idxList]=partition(A,idxList,p,r,gtCompareFunc)
%Rearrange the subarray A(p:r) in place.
    x=A(:,r);
    i=p-1;
    for j=p:(r-1)
        if(~gtCompareFunc(A(:,j),x))
            i=i+1;
            %Swap A(:,i) and A(:,j)
            temp=A(:,i);
            A(:,i)=A(:,j);
            A(:,j)=temp;

            %Swap the indices in idxList to keep track of changes in the
            %ordering in A.
            temp=idxList(i);
            idxList(i)=idxList(j);
            idxList(j)=temp;
        end
    end

    %Swap A(:,i+1) and A(:,r)
    temp=A(:,i+1);
    A(:,i+1)=A(:,r);
    A(:,r)=temp;

    %Record the swap in the index list.
    temp=idxList(i+1);
    idxList(i+1)=idxList(r);
    idxList(r)=temp;

    %The new pivot point to return.
    q=i+1;
end

function [q,A,idxList]=partitionCell(A,idxList,p,r,gtCompareFunc)
%This is the same as the partition function, but has been modified to index
%cell arrays.
    x=A{r};
    i=p-1;
    for j=p:(r-1)
        if(~gtCompareFunc(A{j},x))
            i=i+1;
            %Swap A{i} and A{j}
            temp=A{i};
            A{i}=A{j};
            A{j}=temp;
            %Record the swap in the index list.
            temp=idxList(i);
            idxList(i)=idxList(j);
            idxList(j)=temp;
        end
    end

    %Swap A{i+1} and A{r}
    temp=A{i+1};
    A{i+1}=A{r};
    A{r}=temp;

    %Record the swap in the index list.
    temp=idxList(i+1);
    idxList(i+1)=idxList(r);
    idxList(r)=temp;

    %The new pivot point to return.
    q=i+1;
end

%LICENSE:
%
%The source code is in the public domain and not licensed or under
%copyright. The information and software may be used freely by the public.
%As required by 17 U.S.C. 403, third parties producing copyrighted works
%consisting predominantly of the material produced by U.S. government
%agencies must provide notice with such work(s) identifying the U.S.
%Government material incorporated and stating that such material is not
%subject to copyright protection.
%
%Derived works shall not identify themselves in a manner that implies an
%endorsement by or an affiliation with the Naval Research Laboratory.
%
%RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE
%SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY THE NAVAL
%RESEARCH LABORATORY FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE ACTIONS
%OF RECIPIENT IN THE USE OF THE SOFTWARE.


function [lin_restr,nonlin_restr,markov_chains]=create_restrictions_and_markov_chains0(markov_chains)
% create_restrictions_and_markov_chains0 -- creates restrictions for
% the constant-parameter SVAR model
%
% ::
%
%
%   [lin_restr,nonlin_restr,tpl]=create_restrictions_and_markov_chains0(tpl)
%
% Args:
%
%    - **markov_chains** [empty|struct]: structure of previously defined
%    markov chains
%
% Returns:
%    :
%
%    - **lin_restr** [cell]: cell array of restrictions (see below).
%
%    - **nonlin_restr** [cell]: cell array of inequality restrictions
%
%    - **markov_chains** [struct]: modified markov chains
%
% Note:
%
%    - The syntax to construct a restriction
%      --> ai(eqtn)
%      --> ai(eqtn,vbl)
%      --> ai(eqtn,vbl,chain_name,state)
%      --> a(eqtn)
%      --> a(eqtn,vbl)
%      --> a(eqtn,vbl,chain_name,state)
%      - **eqtn** [integer]: integer
%      - **vbl** [integer|char]: integer or variable name
%      - **i** [integer]: lag
%      - **chain_name** [char]: name of the markov chain
%      - **state** [integer]: state number
%
%    - The lag coefficients are labelled a0, a1, a2,...,ak, for a model with k
%    lags. Obviously, a0 denotes the contemporaneous coefficients.
%
%    - The constant terms labelled c_1_1, c_2_2,...,c_n_n, for a model with n
%    endogenous variables.
%
%    - The standard deviations labelled s_1_1, s_2_2,...,s_n_n, for a
%    model with n endogenous variables.
%
% Example:
%
%    See also:

if nargin==0||isempty(markov_chains)

    markov_chains=struct('name',{},...
    'states_expected_duration',{},...
    'controlled_parameters',{});

end

% syntax is coef(eqtn,vname,lag)
%-------------------------------
lin_restr={
    % first equation or "FFR" equation
    %----------------------------------
    'a1(1,pi)=0'
    'a2(1,pi)=0'
    'a1(1,ygap)=0'
    'a2(1,ygap)=0'
    'a2(1,FFR)=0'
    % second equation or "pi" equation
    %----------------------------------
    'a0(2,FFR)=0'
    'a1(2,FFR)=0'
    'a2(2,FFR)=0'
    'a1(2,ygap)=0'
    'a2(2,ygap)=0'
    % third equation or "ygap" equation
    %-----------------------------------
    'a1(3,FFR)=0'
    'a2(3,FFR)=0'
    'a1(3,pi)=0'
    'a2(3,pi)=0'
    'a0(3,pi)+a0(3,FFR)=0'
    };
nonlin_restr={
    'a0(3,FFR)>=0'
    'a1(1,FFR)>=0'
    'a1(1,FFR)<=1'
    };

end


classdef IDTLZ1 < PROBLEM
% <multi/many> <real> <large/none> <expensive/none>
% Inverted DTLZ1

%------------------------------- Reference --------------------------------
% H. Jain and K. Deb, An evolutionary many-objective optimization algorithm
% using reference-point based non-dominated sorting approach, part II:
% Handling constraints and extending to an adaptive approach, IEEE
% Transactions on Evolutionary Computation, 2014, 18(4): 602-622.
%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    methods
        %% Default settings of the problem
        function Setting(obj)
            if isempty(obj.M); obj.M = 3; end
            if isempty(obj.D); obj.D = obj.M+4; end
            obj.lower    = zeros(1,obj.D);
            obj.upper    = ones(1,obj.D);
            obj.encoding = ones(1,obj.D);
        end
        %% Calculate objective values
        function PopObj = CalObj(obj,PopDec)
            g      = 100*(obj.D-obj.M+1+sum((PopDec(:,obj.M:end)-0.5).^2-cos(20.*pi.*(PopDec(:,obj.M:end)-0.5)),2));
            PopObj = (1+repmat(g,1,obj.M))/2 - 0.5*repmat(1+g,1,obj.M).*fliplr(cumprod([ones(size(PopDec,1),1),PopDec(:,1:obj.M-1)],2)).*[ones(size(PopDec,1),1),1-PopDec(:,obj.M-1:-1:1)];
        end
        %% Generate points on the Pareto front
        function R = GetOptimum(obj,N)
            R = (1-UniformPoint(N,obj.M))/2;
        end
        %% Generate the image of Pareto front
        function R = GetPF(obj)
            if obj.M == 2
                R = obj.GetOptimum(100);
            elseif obj.M == 3
                a = linspace(0,1,10)';
                R = {(1-a*a')/2,(1-a*(1-a'))/2,(1-(1-a)*ones(size(a')))/2};
            else
                R = [];
            end
        end
    end
end


function I=wave_inv_transform(x,ld)
[m n]=size(x);
% [ld hd lr hr]=wfilters('sym8');
t=0:(length(ld)-1);
hd=ld; hd(end:-1:1)=cos(pi*t).*ld;
Wn=zeros(n);
Wm=zeros(m);
z=length(ld);
% l=ld;
% l(end:-1:1)=ld;
% ld=l;
j=1;
for i=1:n/2

        if j+z-1>n
            a=j+z-1-n;
            Wn(i,1:a)=ld(z-a+1:end);
            Wn(i,j:end)=ld(1:z-a);
        else
             Wn(i,j:j+z-1)=ld;
        end
        j=j+2;
end
j=1;
for i=n/2+1:n

        if j+z-1>n
            a=j+z-1-n;
            Wn(i,1:a)=hd(z-a+1:end);
            Wn(i,j:end)=hd(1:z-a);
        else
             Wn(i,j:j+z-1)=hd;
        end
        j=j+2;
end
Wn;
j=1;
for i=1:m/2

         if j+z-1>m
             a=j+z-1-m;
             Wm(i,1:a)=ld(z-a+1:end);
             Wm(i,j:end)=ld(1:z-a);
         else
              Wm(i,j:j+z-1)=ld;
         end
         j=j+2;
 end
 j=1;
 for i=m/2+1:m

         if j+z-1>m
             a=j+z-1-m;
             Wm(i,1:a)=hd(z-a+1:end);
             Wm(i,j:end)=hd(1:z-a);
         else
              Wm(i,j:j+z-1)=hd;
         end
         j=j+2;
 end
 Wm;
x=double(x);
 c=Wm'*x;
 I=c*Wn;
end


close all; clear all; clc

addpath('apm')

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Configuration
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% number of terms
ny = 2; % output coefficients
nu = 1; % input coefficients
% number of inputs
ni = 1;
% number of outputs
no = 1;
% load data and parse into columns
data = load('data_step_test.csv');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% generate time-series model
sysd = apm_id(data,ni,nu,ny);

% plt.figure(1)
% plt.subplot(2,1,1)
% plt.plot(data[:,0],ypred,'r-',LineWidth=2)
% plt.plot(data[:,0],data[:,2],'b--',LineWidth=2)
% plt.legend(['Predicted','Measured'],loc='best')
% plt.ylabel('Temp (K)')
%
% plt.subplot(2,1,2)
% plt.plot(data[:,0],data[:,1],'k-',LineWidth=2)
% plt.legend(['Heater'],loc='best')
% plt.ylabel('Heater')
% plt.show()


function net = cnnsetup(net, x, y)
    assert(~isOctave() || compare_versions(OCTAVE_VERSION, '3.8.0', '>='), ['Octave 3.8.0 or greater is required for CNNs as there is a bug in convolution in previous versions. See http://savannah.gnu.org/bugs/?39314. Your version is ' myOctaveVersion]);
    inputmaps = 1;
    mapsize = size(squeeze(x(:, :, 1)));

    for l = 1 : numel(net.layers)   %  layer
        if strcmp(net.layers{l}.type, 's')
            mapsize = mapsize / net.layers{l}.scale;
            assert(all(floor(mapsize)==mapsize), ['Layer ' num2str(l) ' size must be integer. Actual: ' num2str(mapsize)]);
            for j = 1 : inputmaps
                net.layers{l}.b{j} = 0;
            end
        end
        if strcmp(net.layers{l}.type, 'c')
            mapsize = mapsize - net.layers{l}.kernelsize + 1;
            fan_out = net.layers{l}.outputmaps * net.layers{l}.kernelsize ^ 2;
            for j = 1 : net.layers{l}.outputmaps  %  output map
                fan_in = inputmaps * net.layers{l}.kernelsize ^ 2;
                for i = 1 : inputmaps  %  input map
                    net.layers{l}.k{i}{j} = (rand(net.layers{l}.kernelsize) - 0.5) * 2 * sqrt(6 / (fan_in + fan_out));
                end
                net.layers{l}.b{j} = 0;
            end
            inputmaps = net.layers{l}.outputmaps;
        end
    end
    % 'onum' is the number of labels, that's why it is calculated using size(y, 1). If you have 20 labels so the output of the network will be 20 neurons.
    % 'fvnum' is the number of output neurons at the last layer, the layer just before the output layer.
    % 'ffb' is the biases of the output neurons.
    % 'ffW' is the weights between the last layer and the output neurons. Note that the last layer is fully connected to the output layer, that's why the size of the weights is (onum * fvnum)
    fvnum = prod(mapsize) * inputmaps;
    onum = size(y, 1);

    net.ffb = zeros(onum, 1);
    net.ffW = (rand(onum, fvnum) - 0.5) * 2 * sqrt(6 / (onum + fvnum));
end


function b_sorted = comp_b_sorted(R, bF)

[~,Rfp,~,Rpp] = seg_R(R);

% Optimized bP
bP_opt = -Rpp\Rfp'*bF;
b_sorted = [bF;bP_opt];

end


function kernel = calibrate2D(obj, AtA, nCha, coil)
% retrieve calibration kernel from 2D calibration region
%
% (c) Thomas Kuestner
% ---------------------------------------------------------------------

sampling = ones([obj.kernelSize,nCha],obj.measPara.precision);

dummyK = zeros(obj.kernelSize(1),obj.kernelSize(2),nCha,obj.measPara.precision);
dummyK((end+1)/2,(end+1)/2,coil) = 1;
idxY = find(dummyK);
sampling(idxY) = 0;
idxA = find(sampling);

Aty = AtA(:,idxY); Aty = Aty(idxA); % correlation values to target point, take complete neighbourhood and not just aquired ones
AtA = AtA(idxA,:); AtA =  AtA(:,idxA); % kick out the searched point

kernel = sampling*0;

lambda = norm(AtA,'fro')/size(AtA,1)*obj.calibTyk;

cnd = cond(AtA + eye(size(AtA))*lambda);
if(cnd == inf)
    rawkernel = pinv(AtA + eye(size(AtA))*lambda)*Aty; % grappa weighting values
else
    rawkernel = (AtA + eye(size(AtA))*lambda)\Aty; % grappa weighting values
end
kernel(idxA) = rawkernel;

end


% rovXYZ 3 x N vectors, inillh 3 x N vectors
% output 3 x N vectors
function dNED=posdiff_v001(rovXYZ, inillh)
% for blh2xyz, input N x 3, output N x 3;
startXYZ= blh2xyz(inillh');
startCen=llh2dcm_v000(inillh(1:2),[0,1]);
dXYZ = rovXYZ-startXYZ';
dNED = startCen*dXYZ;


report_this_filefun(mfilename('fullpath'));

l=storedcat(:,3) > mati+ 2.5/365 &  storedcat(:,3) <  mati+ 3/365 + 7/365;
b=storedcat.subset(l);

cd /home2/stefan/srisk/

load lat
load lon
lon = -lon;

le = length(lat);
Y0 = zeros(le,1);

for i = 1:length(b)
    di2 = deg2km((distance(lat,lon,repmat(b(i,2),le,1),repmat(b(i,1),le,1))));
    R = di2;
    r = sqrt(R.^2 + 5.57^2);
    M = b(i,6);
    Y = -0.136 + 0.229*(M-6) - 0.778 * log10(r) ;
    Y = 10.^Y;
    c = [Y , Y0];
    mapga = max(c');
    Y0 = mapga';
end

mapga = mapga';

cd /home2/stefan/srisk/

save hpga2 mapga -ascii

do = [' ! /home2/stefan/srisk/myriskobs2 ' num2str(max(mapga)/2.4,2)  '  ' num2str(max(mapga)/10,2) ]; eval(do)

% do = [' ! /home2/stefan/srisk/myriskobs 0.04 0.008' ]; eval(do)


% exampleTextureCalc1.m
%
% Example script for texture calculation
%
% APA, 05/23/2016

global planC

%% EXAMPLE 1: Patch-wise texture
scanNum     = 1;
structNum   = 3;
descript    = 'CTV texture';
patchUnit   = 'vox'; % or 'cm'
patchSizeV  = [1 1 1];
category    = 1; % Haralick texture
dirctn      = 1; % 1: 3d neighbors , 2: 2d neighbors
numGrLevels = 16; % 32, 64, 256 etc..
energyFlg = 1; % or 0
entropyFlg = 1; % or 0
sumAvgFlg = 1; % or 0
homogFlg = 1; % or 0
contrastFlg = 1; % or 0
corrFlg = 1; % or 0
clustShadFlg = 1; % or 0
clustPromFlg = 1; % or 0
haralCorrFlg = 1; % or 0
flagsV = [energyFlg, entropyFlg, sumAvgFlg, corrFlg, homogFlg, ...
    contrastFlg, clustShadFlg, clustPromFlg, haralCorrFlg];
planC = createTextureMaps(scanNum,structNum,descript,...
    patchUnit,patchSizeV,category,dirctn,numGrLevels,flagsV,planC);

%% EXAMPLE 2: Texture for the entire structure
global planC
indexS = planC{end};
scanNum     = 1;
structNum   = 4;
numGrLevels = 16;
dirctn      = 1; % 2: 2d neighbors
cooccurType = 1; % 2: build separate cooccurrence for each direction

% Quantize the volume of interest
[rasterSegments, planC, isError]    = getRasterSegments(structNum,planC);
[mask3M, uniqueSlices]              = rasterToMask(rasterSegments, scanNum, planC);
scanArray3M                         = getScanArray(planC{indexS.scan}(scanNum));
SUVvals3M                           = mask3M.*double(scanArray3M(:,:,uniqueSlices));
[minr, maxr, minc, maxc, mins, maxs]= compute_boundingbox(mask3M);
maskBoundingBox3M                   = mask3M(minr:maxr,minc:maxc,mins:maxs);
volToEval                           = SUVvals3M(minr:maxr,minc:maxc,mins:maxs);
volToEval(maskBoundingBox3M==0)     = NaN;
quantizedM = imquantize_cerr(volToEval,numGrLevels);

% Buiild cooccurrence matrix
offsetsM = getOffsets(dirctn);
cooccurM = calcCooccur(quantizedM, offsetsM, numGrLevels, cooccurType);

% Reduce cooccurrence matrix to scalar features
glcmFlagS.energy = 1;
glcmFlagS.jointEntropy = 1;
glcmFlagS.jointMax = 1;
glcmFlagS.jointAvg = 1;
glcmFlagS.jointVar = 1;
glcmFlagS.contrast = 1;
glcmFlagS.invDiffMoment = 1;
glcmFlagS.sumAvg = 1;
glcmFlagS.corr = 1;
glcmFlagS.clustShade = 1;
glcmFlagS.clustProm = 1;
glcmFlagS.haralickCorr = 1;
glcmFlagS.invDiffMomNorm = 1;
glcmFlagS.invDiff = 1;
glcmFlagS.invDiffNorm = 1;
glcmFlagS.invVar = 1;
glcmFlagS.dissimilarity = 1;
glcmFlagS.diffEntropy = 1;
glcmFlagS.diffVar = 1;
glcmFlagS.diffAvg = 1;
glcmFlagS.sumVar = 1;
glcmFlagS.sumEntropy = 1;
glcmFlagS.clustTendency = 1;
glcmFlagS.autoCorr = 1;
glcmFlagS.invDiffMomNorm = 1;
glcmFlagS.firstInfCorr = 1;
glcmFlagS.secondInfCorr = 1;

featureS = cooccurToScalarFeatures(cooccurM, glcmFlagS);

%% Dominant orientation
global planC
indexS = planC{end};

scanNum     = 1;
structNum   = 6;
patchSizeV  = [3 3 3];

[rasterSegments, planC, isError]    = getRasterSegments(structNum,planC);
[mask3M, uniqueSlices]              = rasterToMask(rasterSegments, scanNum, planC);
scanArray3M                         = getScanArray(planC{indexS.scan}(scanNum));

SUVvals3M                           = mask3M.*double(scanArray3M(:,:,uniqueSlices));
[minr, maxr, minc, maxc, mins, maxs]= compute_boundingbox(mask3M);
maskBoundingBox3M                   = mask3M(minr:maxr,minc:maxc,mins:maxs);
volToEval                           = SUVvals3M(minr:maxr,minc:maxc,mins:maxs);
volToEval(maskBoundingBox3M==0)     = NaN;

% volToEval = scanArray3M; % for ITK comparison

position = [400 400 300 50];
waitFig = figure('name','Creating Texture Maps','numbertitle','off',...
            'MenuBar','none','ToolBar','none','position',position);
waitAx = axes('parent',waitFig,'position',[0.1 0.3 0.8 0.4],...
    'nextplot','add','XTick',[],'YTick',[],'yLim',[0 1],'xLim',[0 1]);
waitH = patch([0 0 0 0], [0 1 1 0], [0.1 0.9 0.1],...
    'parent', waitAx);

domOrient3M = calcDominantOrientation(volToEval, patchSizeV, waitH);

vol3M = zeros(size(volToEval));
vol3M(:,30:60,5) = 1;
vol3M(30:62,:,5) = 1;
dom3M = calcDominantOrientation(vol3M, patchSizeV, waitH);

close(waitFig)

%% Law's texture
global planC
indexS = planC{end};

scanNum     = 1;
structNum   = 1;
patchSizeV  = [3 3 3];

[rasterSegments, planC, isError]    = getRasterSegments(structNum,planC);
[mask3M, uniqueSlices]              = rasterToMask(rasterSegments, scanNum, planC);
scanArray3M                         = getScanArray(planC{indexS.scan}(scanNum));

SUVvals3M                           = mask3M.*double(scanArray3M(:,:,uniqueSlices));
[minr, maxr, minc, maxc, mins, maxs]= compute_boundingbox(mask3M);
maskBoundingBox3M                   = mask3M(minr:maxr,minc:maxc,mins:maxs);
volToEval                           = SUVvals3M(minr:maxr,minc:maxc,mins:maxs);
%volToEval(maskBoundingBox3M==0)     = NaN;
volToEval(maskBoundingBox3M==0)     = nanmean(volToEval(:));
meanVol = nanmean(volToEval(:));
if exist('padarray.m','file')
    paddedVolM = padarray(volToEval,[5 5 5],meanVol,'both');
else
    paddedVolM = padarray_oct(volToEval,[5 5 5],meanVol,'both');
end
lawsMasksS = getLawsMasks();

fieldNamesC = fieldnames(lawsMasksS);
numFeatures = length(fieldNamesC);
featuresM = zeros(sum(maskBoundingBox3M(:)),numFeatures);
for i = 1:numFeatures
    disp(i)
    text3M = convn(paddedVolM,lawsMasksS.(fieldNamesC{i}),'same');
    text3M = text3M(6:end-5,6:end-5,6:end-5);
    featuresM(:,i) = text3M(maskBoundingBox3M);
end

% Haralick textures

featuresM = zeros(sum(maskBoundingBox3M(:)),0);
for patchSiz = 1:3

%patchSizeV  = [2 2 2];
patchSizeV  = [patchSiz patchSiz 0];

%numGrLevels = 16;
for numGrLevels = [8 16 32]
offsetsM = getOffsets(2);

[rasterSegments, planC, isError]    = getRasterSegments(structNum,planC);
[mask3M, uniqueSlices]              = rasterToMask(rasterSegments, scanNum, planC);
scanArray3M                         = getScanArray(planC{indexS.scan}(scanNum));

SUVvals3M                           = mask3M.*double(scanArray3M(:,:,uniqueSlices));
[minr, maxr, minc, maxc, mins, maxs]= compute_boundingbox(mask3M);
maskBoundingBox3M                   = mask3M(minr:maxr,minc:maxc,mins:maxs);
volToEval                           = SUVvals3M(minr:maxr,minc:maxc,mins:maxs);
volToEval(maskBoundingBox3M==0)     = NaN;

% Haralick texture
energyFlg = 1; % or 0
entropyFlg = 1; % or 0
sumAvgFlg = 1; % or 0
homogFlg = 1; % or 0
contrastFlg = 1; % or 0
corrFlg = 1; % or 0
clustShadFlg = 1; % or 0
clustPromFlg = 1; % or 0
haralCorrFlg = 1; % or 0
flagsV = [energyFlg, entropyFlg, sumAvgFlg, corrFlg, homogFlg, ...
    contrastFlg, clustShadFlg, clustPromFlg, haralCorrFlg];
waitH = NaN;
[energy3M,entropy3M,sumAvg3M,corr3M,invDiffMom3M,contrast3M, ...
    clustShade3M,clustPromin3M,haralCorr3M] = textureByPatchCombineCooccur(volToEval,...
    numGrLevels,patchSizeV,offsetsM,flagsV,waitH);

featuresM(:,end+1) = energy3M(maskBoundingBox3M);
featuresM(:,end+1) = entropy3M(maskBoundingBox3M);
featuresM(:,end+1) = sumAvg3M(maskBoundingBox3M);
featuresM(:,end+1) = corr3M(maskBoundingBox3M);
featuresM(:,end+1) = invDiffMom3M(maskBoundingBox3M);
featuresM(:,end+1) = contrast3M(maskBoundingBox3M);
featuresM(:,end+1) = clustShade3M(maskBoundingBox3M);
featuresM(:,end+1) = clustPromin3M(maskBoundingBox3M);
featuresM(:,end+1) = haralCorr3M(maskBoundingBox3M);

end
end

[coeff,score,latVar] = pca(featuresM,'NumComponents',20);
figure, plot(cumsum(latVar)./sum(latVar)*100,'linewidth',2)
xlabel('Number of components','fontsize',20)
ylabel('Explained variance','fontsize',20)
set(gca,'fontsize',20)

figure,
for i = 1:4
    comp1M = zeros(size(maskBoundingBox3M));
    comp1M(maskBoundingBox3M) = score(:,3);
    comp1M = volToEval;
    subplot(2,2,i), imagesc(comp1M(:,:,i)), title(['slice: ',num2str(i)])
    axis equal, colormap('gray')
    axis off
end

comp1M = NaN*ones(size(maskBoundingBox3M));
comp1M(maskBoundingBox3M) = score(:,2);
figure, hist(comp1M(:),30)
title('Component 2','fontsize',20)

%% Neighborhood Gray Tone Difference Matrix (NGTDM)
global planC
indexS = planC{end};

% L:\Ziad\HUH_from_Maria\ASTRO_AAPM\Included_after_AAPM\mat_cropped\HUH2

scanNum     = 1;
structNum   = 27;
patchRadiusV  = [1 1 1];
numGrLevels = 16;

[rasterSegments, planC, isError]    = getRasterSegments(structNum,planC);
[mask3M, uniqueSlices]              = rasterToMask(rasterSegments, scanNum, planC);
scanArray3M                         = getScanArray(planC{indexS.scan}(scanNum));

SUVvals3M                           = mask3M.*double(scanArray3M(:,:,uniqueSlices));
[minr, maxr, minc, maxc, mins, maxs]= compute_boundingbox(mask3M);
maskBoundingBox3M                   = mask3M(minr:maxr,minc:maxc,mins:maxs);
volToEval                           = SUVvals3M(minr:maxr,minc:maxc,mins:maxs);
volToEval(maskBoundingBox3M==0)     = NaN;
quantizedM = imquantize_cerr(volToEval,numGrLevels);

hWait = NaN;
[s,p] = calcNGTDM(quantizedM,patchRadiusV,numGrLevels,hWait);

if exist('padarray.m','file')
    paddedM = padarray(quantizedM,[1 1 1],0,'both');
    paddedMaskM = padarray(maskBoundingBox3M,[1 1 1],0,'both');
else
    paddedM = padarray_oct(quantizedM,[1 1 1],0,'both');
    paddedMaskM = padarray_oct(maskBoundingBox3M,[1 1 1],0,'both');
end
[rV,cV,sV] = find3d(paddedMaskM);
mask_rcs = [rV(:),cV(:),sV(:)];
[NGTDM,vox_occurances_NGD26] = compute_3D_NGTDM_full_vol(paddedM,numGrLevels,mask_rcs);


function[] = Param_Space(Cat)

rdc= ReasenbergDeclusterClass(Cat, ....
    'AutoShowPlots',false,'DelayProcessing',true,'InteractiveMode',false);

lTaumin     = 1;
lTaumax     = 10;
lP          = .95;
lXk         = .4;
lXmeff      = 3;
lRfact      = 10;
lErr        = 2;
lDerr       = 5;

rdc.taumin  = lTaumin;
rdc.taumax  = lTaumax;
rdc.P       = lP;
rdc.xk      = lXk;
rdc.xmeff   = lXmeff;
rdc.rfact   = lRfact;
rdc.err     = lErr;
rdc.derr    = lDerr;

%% loop for P

resFileOut = 'decResP';
parmFileOut = 'decParmP';
P_Sim = .8:.01:1;
numSim = length(P_Sim);

for simNum = 1:numSim
    rdc.P = P_sim(simNum);
    [declusCat] = rdc.ReasenbergDeclus();
    decResult(simNum) = {declusCat};
    save(resFileOut,'decResult');

    monteParms(simNum) = {[rdc.taumin;rdc.taumax;rdc.P;rdc.xk;rdc.xmeff;rdc.rfact;rdc.err;rdc.derr]};
    save(parmFileOut,'monteParms');
    disp(num2str(simNum));
end

rdc.P = lTauP;

%% loop for Taumin

resFileOut = 'decResTmin';
parmFileOut = 'decParmTmin';
T_Sim = .2:.1:5;
numSim = length(T_Sim);

for simNum = 1:numSim
    rdc.taumin = T_Sim(simNum);
    [declusCat] = rdc.ReasenbergDeclus();
    decResult(simNum) = {declusCat};
    save(resFileOut,'decResult');

    monteParms(simNum) = {[rdc.taumin;rdc.taumax;rdc.P;rdc.xk;rdc.xmeff;rdc.rfact;rdc.err;rdc.derr]};
    save(parmFileOut,'monteParms');
    disp(num2str(simNum));
end

rdc.taumin = lTaumin;

%% loop for Taumax

resFileOut = 'decResTmax';
parmFileOut = 'decParmTmax';
T_Sim = 1:1:20;
numSim = length(T_Sim);

for simNum = 1:numSim
    rdc.taumax = T_Sim(simNum);
    [declusCat] = rdc.ReasenbergDeclus();
    decResult(simNum) = {declusCat};
    save(resFileOut,'decResult');

    monteParms(simNum) = {[rdc.taumin;rdc.taumax;rdc.P;rdc.xk;rdc.xmeff;rdc.rfact;rdc.err;rdc.derr]};
    save(parmFileOut,'monteParms');
    disp(num2str(simNum));
end
rdc.taumax  = lTaumax;

%% loop for rFact

resFileOut = 'decRes_rFact';
parmFileOut = 'decParm_rFact';
R_Sim = 0:1:40;
numSim = length(R_Sim);

for simNum = 1:numSim
    rdc.rfact = R_Sim(simNum);
    [declusCat] = rdc.ReasenbergDeclus();
    decResult(simNum) = {declusCat};
    save(resFileOut,'decResult');

    monteParms(simNum) = {[rdc.taumin;rdc.taumax;rdc.P;rdc.xk;rdc.xmeff;rdc.rfact;rdc.err;rdc.derr]};
    save(parmFileOut,'monteParms');
    disp(num2str(simNum));
end

%% loop for xK

resFileOut = 'decRes_xk';
parmFileOut = 'decParm_xk';
Xk_Sim = 0:.1:1;
numSim = length(Xk_Sim);

for simNum = 1:numSim
    rdc.xk = Xk_Sim(simNum);
    [declusCat] = rdc.ReasenbergDeclus();
    decResult(simNum) = {declusCat};
    save(resFileOut,'decResult');

    monteParms(simNum) = {[rdc.taumin;rdc.taumax;rdc.P;rdc.xk;rdc.xmeff;rdc.rfact;rdc.err;rdc.derr]};
    save(parmFileOut,'monteParms');
    disp(num2str(simNum));
end


%% faceToVertexMeasure
% Below is a demonstration of the features of the |patchPathAngles| function

%%
clear; close all; clc;

%% Syntax
% |[indAngles]=faceToVertexMeasure(F,V,ind,isClosedLoop);|

%% Description
% The |faceToVertexMeasure| function converts data for faces to data on
% vertices through averaging.

%% Examples

%%
% Plot settings
markerSize=150;

%% Example 1: Convert face data to vertex data
[F,V]=geoSphere(2,1);
VF=patchCentre(F,V);
CF=VF(:,1);
[CV]=faceToVertexMeasure(F,V,CF);

%%

cFigure;
subplot(1,2,1); hold on;
title('Color data on faces')
gpatch(F,V,CF);
scatterV(VF,markerSize,CF,'filled');
colormap gjet; colorbar;
axisGeom;
camlight headlight;

subplot(1,2,2); hold on;
title('Converted data on vertices')
hp=gpatch(F,V,CV);
hp.FaceColor='Interp';
scatterV(V,markerSize,CV,'filled');
colormap gjet; colorbar;
axisGeom;
camlight headlight;

drawnow;

%% Example 2: Convert face data on a mixed mesh to vertex data

%%
% Create an example of a mixed mesh consisting of triangles and
% quadrilateral faces.

% Create a triangular mesh
[F,V]=geoSphere(2,1);

% Converting to a quadrilateral mesh
optionStruct.maxAngleDeviation=45*(pi/180);
optionStruct.selectionMethod='best';
optionStruct.triangleConvert=0;
optionStruct.fourConnectConvert=0;
[F,V]=tri2quadGroupSplit(F,V,optionStruct);

VF=patchCentre(F,V);
CF=VF;
for q=1:1:numel(VF)
    CF{q}=VF{q}(:,1);
end
[CV]=faceToVertexMeasure(F,V,CF);

%%

cFigure;
subplot(1,2,1); hold on;
title('Color data on faces')
gpatch(F,V,CF);
for q=1:1:numel(VF)
    scatterV(VF{q},markerSize,CF{q},'filled');
end
colormap gjet; colorbar;
axisGeom;
camlight headlight;

subplot(1,2,2); hold on;
title('Converted data on vertices')
hp=gpatch(F,V,CV);
% hp.FaceColor='Interp';
scatterV(V,markerSize,CV,'filled');
colormap gjet; colorbar;
axisGeom;
camlight headlight;
drawnow;

%% Example 3: Convert multi-dimensional face data (e.g. on a mixed mesh) to vertex data

N=patchNormal(F,V); %get face normals
NV=faceToVertexMeasure(F,V,N); %Convert to vertex normals

%%

VF=patchCentre(F,V); %Get face centres for plotting

cFigure;
subplot(1,2,1); hold on;
title('Vector data on faces')
gpatch(F,V,CF);
for q=1:1:numel(F)
    quiverVec(VF{q},N{q},0.25,'k');
end
colormap gjet; colorbar;
axisGeom;
camlight headlight;

subplot(1,2,2); hold on;
title('Converted data on vertices')
gpatch(F,V,CV);
quiverVec(V,NV,0.25,'k');
colormap gjet; colorbar;
axisGeom;
camlight headlight;
drawnow;

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

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


%LAMBDA2RGB RGB chromaticity coordinates
%
% RGB = LAMBDA2RG(LAMBDA) is the rg-chromaticity coordinate (1x2) for
% illumination at the specific wavelength LAMBDA [m]. If LAMBDA is a
% vector (Nx1), then P (Nx2) is a vector whose elements are the chromaticity
% coordinates at the corresponding elements of LAMBDA.
%
% RGB = LAMBDA2RG(LAMBDA, E) is the rg-chromaticity coordinate (1x2) for an
% illumination spectrum E (Nx1) defined at corresponding wavelengths
% LAMBDA (Nx1).
%
% References::
%  - Robotics, Vision & Control, Section 10.2,
%    P. Corke, Springer 2011.
%
% See also CMFRGB, LAMBDA2XY.

% Copyright (C) 1993-2011, by Peter I. Corke
%
% This file is part of The Machine Vision Toolbox for Matlab (MVTB).
%
% MVTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% MVTB 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with MVTB.  If not, see <http://www.gnu.org/licenses/>.
function [r,g] = lambda2rg(lambda, e)
    if nargin == 1,
        RGB = cmfrgb(lambda);
    elseif nargin == 2,
        RGB = cmfrgb(lambda, e);
    end
    cc = tristim2cc(RGB);

    if nargout == 1
        r = cc;
    elseif nargout == 2
        r = cc(:,1);
        g = cc(:,2);
    end


function [y, extra, invhess] = glmevfwd(net, x, t, x_test, invhess)
%GLMEVFWD Forward propagation with evidence for GLM
%
%	Description
%	Y = GLMEVFWD(NET, X, T, X_TEST) takes a network data structure  NET
%	together with the input X and target T training data and input test
%	data X_TEST. It returns the normal forward propagation through the
%	network Y together with a matrix EXTRA which consists of error bars
%	(variance) for a regression problem or moderated outputs for a
%	classification problem.
%
%	The optional argument (and return value)  INVHESS is the inverse of
%	the network Hessian computed on the training data inputs and targets.
%	Passing it in avoids recomputing it, which can be a significant
%	saving for large training sets.
%
%	See also
%	FEVBAYES
%

%	Copyright (c) Ian T Nabney (1996-2001)

[y, a] = glmfwd(net, x_test);
if nargin == 4
  [extra, invhess] = fevbayes(net, y, a, x, t, x_test);
else
  [extra, invhess] = fevbayes(net, y, a, x, t, x_test, invhess);
end


function [spectogram_y_lims, s, f] = cutSpectogramFrequency(s,f, handles)

    upper_freq = find(f>=handles.data.settings.HighFreq*1000,1);
    if isempty(upper_freq)
        upper_freq = length(f);
    end
    lower_freq = find(f>=handles.data.settings.LowFreq*1000,1);

    % Extract the region within the frequency range
    f = f(lower_freq:upper_freq,:);
    s = s(lower_freq:upper_freq,:);
    spectogram_y_lims = [ min(f), max(f)];
end


function [IDX, maxIdxArray] = Cluster(data, MinPts, epsilon, PtsNumThr, IS_SHOW)
if size(data, 2) ~= 2
    data = data';
end
if size(data, 2) ~= 2
    error('Input for Cluster() is wrong!');
end
IDX = [];
maxIdxArray = [];
if nargin == 4
    IS_SHOW = 0;
end
if size(data, 1) < PtsNumThr   %%%%%% too few points!
    return;
end
[ IDX, isNoise] =DBSCAN(data,epsilon,MinPts);
if IS_SHOW
    figure;
    hold on;
    box on;
    xlabel('X(meter)');
    ylabel('Y(meter)');
    PlotClusterinResult(data, IDX);
    title(['DBSCAN Clustering (\epsilon = ' num2str(epsilon) ', MinPts = ' num2str(MinPts) ')']);
end
ScanData = CalScanData(IDX);
if isempty(ScanData)
    IDX = [];
    maxIdxArray = [];
    return;
end
[maxVal, idxOrder]= max(ScanData(2, :));
if maxVal < PtsNumThr
    return;
end
maxIdxArray = find(IDX == ScanData(1, idxOrder));
end


function F = coeffs2spherefunv( X, Y, Z )
%COEFFS2SPHEREFUNV   Convert componentwise matrices of 2D Fourier
%   coefficients to a spherefunv.
%
%   F = coeffs2spherefunv( X, Y, Z ) returns a spherefunv object F that has
%   matrices of 2D Fourier coefficients X, Y, and Z for each component.
%
% See also SPHEREFUN/COEFFS2SPHEREFUN

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

U = spherefun.coeffs2spherefun(X);
V = spherefun.coeffs2spherefun(Y);
W = spherefun.coeffs2spherefun(Z);
F = spherefunv(U, V, W);
end


function [xyTV,xyLV,xyBV,xyRV] = dividePolygon(xV,yV,xc,yc)
% function [xyTV,xyLV,xyBV,xyRV] = dividePolygon(xV,yV,xc,yc)
%
% This function divides the passed polygon into Top, Left, Bottom and Right
% parts.
%
% APA, 08/23/2012

%xV = planC{indexS.structures}(2).contour(71).segments.points(:,1);
%yV = planC{indexS.structures}(2).contour(71).segments.points(:,2);

if nargin < 3
    xc = mean(xV);
    yc = mean(yV);
end
theta1 = 45*pi/180;
x1 = xc+100*cos(theta1);
y1 = yc+100*sin(theta1);
theta2 = 135*pi/180;
x2 = xc+100*cos(theta2);
y2 = yc+100*sin(theta2);

% Get 45 degree cut
xyTLV = cutpolygon([xV(:) yV(:)], [[xc; x1],[yc;y1]], 'B');
xyBRV = cutpolygon([xV(:) yV(:)], [[xc; x1],[yc;y1]], 'T');

% Top part
xyTV = cutpolygon([xyTLV(:,1) xyTLV(:,2)], [[xc; x2],[yc;y2]], 'B');

% Left part
xyLV = cutpolygon([xyTLV(:,1) xyTLV(:,2)], [[xc; x2],[yc;y2]], 'T');

% Bottom part
xyBV = cutpolygon([xyBRV(:,1) xyBRV(:,2)], [[xc; x2],[yc;y2]], 'T');

% Right part
xyRV = cutpolygon([xyBRV(:,1) xyBRV(:,2)], [[xc; x2],[yc;y2]], 'B');


function cCell = cqtSparse2Cell(cSparse,M,cDC,cNyq)

bins = size(M,1)/2 - 1;
cCell = cell(1,bins+2);
cCell{bins+2} = cNyq;

M = M(1:bins+1);
step = 1;
cSparse = full(cSparse);
distinctHops = log2(M(bins+1)/M(2))+1;
curNumCoef = M(bins+1);

for ii=1:distinctHops
   idx = (M == curNumCoef);
   temp = cSparse(idx,1:step:end).';
   temp = num2cell(temp,1);
   cCell(idx) = temp;
   step = step*2;
   curNumCoef = curNumCoef / 2;
end

cCell{1} = cDC;


function [lf] = eeg_halfspace_medium_leadfield(rd, elc, vol)

% HALFSPACE_MEDIUM_LEADFIELD calculate the halfspace medium leadfield
% on positions pnt for a dipole at position rd and conductivity cond
% The halfspace solution requires a plane dividing a conductive zone of
% conductivity cond, from a non coductive zone (cond = 0)
%
% [lf] = halfspace_medium_leadfield(rd, elc, cond)

% Copyright (C) 2011, Cristiano Micheli and Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.ru.nl/neuroimaging/fieldtrip
% for the documentation and details.
%
%    FieldTrip 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.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id: eeg_halfspace_medium_leadfield.m 2781 2011-02-03 10:48:53Z roboos $

siz = size(rd);
if any(siz==1)
  % positions are specified as a single vector
  Ndipoles = prod(siz)/3;
  rd = rd(:)'; % ensure that it is a row vector
elseif siz(2)==3
  % positions are specified as a Nx3 matrix -> reformat to a single vector
  Ndipoles = siz(1);
  rd = rd';
  rd = rd(:)'; % ensure that it is a row vector
else
  error('incorrect specification of dipole locations');
end

Nelc     = size(elc,1);
lf       = zeros(Nelc,3*Ndipoles);

for i=1:Ndipoles
  % this is the position of dipole "i"
  dip1 = rd((1:3) + 3*(i-1));

  % distances electrodes - dipole
  r1 = elc - ones(Nelc,1) * dip1;

  % Method of mirror dipoles:
  % Defines the position of mirror dipoles being symmetric to the plane
  dip2 = get_mirror_pos(dip1,vol);

  % distances electrodes - mirror dipole
  r2 = elc - ones(Nelc,1) * dip2;

  % denominator
  R1 =  (4*pi*vol.cond) * (sum(r1' .^2 ) .^ 1.5)';
  % denominator, mirror term
  R2 = -(4*pi*vol.cond) * (sum(r2' .^2 ) .^ 1.5)';

  % condition of dipoles falling in the non conductive halfspace
  invacuum = acos(dot(vol.ori,(dip1-vol.pnt)./norm(dip1-vol.pnt))) < pi/2;

  if invacuum
    warning('dipole lies on the vacuum side of the plane');
    lf(:,(1:3) + 3*(i-1)) = NaN(Nelc,3);
  elseif any(R1)==0
    warning('dipole coincides with one of the electrodes');
    lf(:,(1:3) + 3*(i-1)) = NaN(Nelc,3);
  else
    lf(:,(1:3) + 3*(i-1)) = (r1 ./ [R1 R1 R1]) + (r2 ./ [R2 R2 R2]);
  end
end


function g = orderedNoiseGradientParam(noise, mu, varsigma, y)

% ORDEREDNOISEGRADIENTPARAM Gradient of ORDERED noise's parameters.
% FORMAT
% DESC computes the gradient of the log Z of the ordered categorical noise model with respect to the of functions with respect to the
% ordered categorical
% noise's parameters.
% ARG noise : the noise structure for which the gradients are being
% computed.
% ARG mu : the input means for which the gradients are being computed.
% ARG varSigma : the input variances for which the gradients are being computed.
% ARG y : the target values for the noise model.
% RETURN g : gradients of the log Z with respect to
% the noise parameters. The ordering of the vector should match
% that provided by the function noiseExtractParam.
%
%
% SEEALSO orderedNoiseParamInit, orderednoiseGradVals, noiseGradientParam
%
% COPYRIGHT : Neil D. Lawrence, 2004, 2005

% NOISE

D = size(y, 2);
c = 1./sqrt(noise.variance + varsigma);
gnoise.bias = zeros(1, D);
gnoise.widths = zeros(noise.C-2, 1);
for j = 1:D
  % Do lowest category first
  index = find(y(:, j)==0);
  if ~isempty(index)
    mu(index, j) = mu(index, j) + noise.bias(j) ;
    mu(index, j) = mu(index, j).*c(index, j);
    gnoise.bias(j) = gnoise.bias(j) - sum(c(index, j).*gradLogCumGaussian(-mu(index, j)));
  end

  % Intermediate categories
  index = find(y(:, j)>0 & y(:, j) <noise.C-1);
  if ~isempty(index)
    for i = index'
      mu(i, j) = mu(i, j) + noise.bias(j) - sum(noise.widths(1:y(i, j)-1));
    end
    u = mu(index, j).*c(index, j);
    uprime = (mu(index, j) - noise.widths(y(index, j))).*c(index, j);
    B1 = gaussOverDiffCumGaussian(u, uprime, 1);
    B2 = gaussOverDiffCumGaussian(u, uprime, 2);
    gnoise.bias(j) = gnoise.bias(j) + sum(c(index, j).*(B1 - B2));
    for cat = 1:noise.C-2

      subIndex = find(y(index, j) == cat);
      if ~isempty(subIndex)
        addpart = sum(c(index(subIndex), j)...
                      .*B2(subIndex));
        gnoise.widths(1:cat) = gnoise.widths(1:cat) ...
            + repmat(addpart, cat, 1);
        if(cat > 1)
          addpart = sum(c(index(subIndex), j)...
                        .*B1(subIndex));
          gnoise.widths(1:cat-1) = gnoise.widths(1:cat-1) ...
              - repmat(addpart, cat-1, 1);
        end
      end
    end
  end

  % Highest category
  index = find(y(:, j) == noise.C-1);
  if ~isempty(index)
    for i = index'
      mu(i, j) = mu(i, j) + noise.bias(j) - sum(noise.widths(1:y(i, j)-1));
    end
    mu(index, j) = mu(index, j).*c(index, j);
    addpart = sum(c(index, j).*gradLogCumGaussian(mu(index, j)));
    gnoise.bias(j) = gnoise.bias(j) + addpart;
    if length(noise.widths > 0)
      gnoise.widths = gnoise.widths ...
          - repmat(addpart, noise.C-2, 1);
    end
  end
end
if length(noise.widths>0)
  g = [gnoise.bias gnoise.widths(:)'];
else
  g = gnoise.bias;
end


%% DEMO_febio_0037_lattice_test_octet_truss_01
% Below is a demonstration for:
%
% * Building the geometry for the octet truss lattive 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
% * compression, tension, compressive, tensile
% * displacement control, displacement boundary condition
% * hexahedral elements, hex8
% * cube, box, rectangular
% * Lattice
% * 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;
markerSize2=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;
elementType='hex8'; %'hex8'
strutThickness=0.5;

%Define applied displacement
appliedStrain=0.3; %Linear strain (Only used to compute applied stretch)
loadingOption='compression'; % or 'tension'
switch loadingOption
    case 'compression'
        stretchLoad=1-appliedStrain; %The applied stretch for uniaxial loading
    case 'tension'
        stretchLoad=1+appliedStrain; %The applied stretch for uniaxial loading
end
displacementMagnitude=(stretchLoad*sampleSize)-sampleSize; %The displacement magnitude

%Material parameter set
E_youngs1=0.1; %Material Young's modulus
nu1=0.4; %Material Poisson's ratio

% FEA control settings
numTimeSteps=20; %Number of time steps desired
max_refs=50; %Max reforms
max_ups=0; %Set to zero to use full-Newton iterations
opt_iter=15; %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'; %'internal' or 'external'

%%

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

shrinkFactor=strutThickness./((sampleSize./n).*(sqrt(2)./2));

%% Create lattice

switch latticeType
    case 1 %Octet truss
        [E,V,C,F,CF]=rhombicDodecahedronMesh(r,nCopies);
        V=V./(n-1);
        V=V*sampleSize;

        [indBoundary]=tesBoundary(F);
        cPar.shrinkFactor=shrinkFactor; %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=1;
        cPar.latticeSide=2; %1=side 1 the edge lattice, 2=side 2 the dual lattice to the edge lattice
        [Es,Vs,Cs]=element2lattice(E,V,cPar); %Get lattice structure

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

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

        Es=Es(logicKeepEs,:);
        Cs=Cs(logicKeepEs,:);
        [Es,Vs,indFix]=patchCleanUnused(Es,Vs);

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

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

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

        [indBoundary]=tesBoundary(F);
        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=3;
        cPar.latticeSide=1; %1=side 1 the edge lattice, 2=side 2 the dual lattice to the edge lattice
        [Es,Vs,Cs]=element2lattice(E,V,cPar); %Get lattice structure

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

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

        Es=Es(logicKeepEs,:);
        Cs=Cs(logicKeepEs,:);
        [Es,Vs,indFix]=patchCleanUnused(Es,Vs);

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

        %Get new boundary set
        indB=tesBoundary(Fs);
        Fb=Fs(indB,:);
end

if strcmp(elementType,'hex20')
    [Es,Vs,~,Fb]=hex8_hex20(Es,Vs,{},Fb);
end
%%
% Visualizing input mesh and lattic structures

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

% Fst=[Fs(:,[1 2 3]); Fs(:,[3 4 1]);];
% indB=tesBoundary(Fst,Vs);
% Fbt=Fst(indB,:);

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

drawnow;

%% DEFINE BC's

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

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

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

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

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;

%%

%Prescribed displacement nodes
bcPrescribeList=find(logicTop);
bcSupportList=find(logicBottom);

%%
% Visualizing input mesh and lattice structures

cFigure;
hs=subplot(1,2,1);
title('The input mesh','fontSize',fontSize)
hold on;
gpatch(F,V,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,Vs,'bw');
% patchNormPlot(Fs,Vs);
axisGeom(gca,fontSize);
camlight headlight; lighting flat;

drawnow;

%%
% Visualize BC's

hf=cFigure; hold on;
title('Boundary conditions model','FontSize',fontSize);
gpatch(Fb,Vs,'w','none',0.5);
hl2(1)=plotV(Vs(bcPrescribeList,:),'r.','MarkerSize',markerSize2);
hl2(2)=plotV(Vs(bcSupportList,:),'b.','MarkerSize',markerSize2);
legend(hl2,{'BC prescribe','BC support'});
axisGeom(gca,fontSize);
camlight headlight;
drawnow;

%% Check porosity
% Note it may be better to use the convex hull volume rather than the cube
% for the octet truss
vol_lattice=sum(hexVol(Es,Vs)); %Volume of hexahedra
porosity_lattice=vol_lattice./sampleSize.^3; %Porosity

%% 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.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='neo-Hookean';
febio_spec.Material.material{1}.ATTR.id=1;
febio_spec.Material.material{1}.E=E_youngs1;
febio_spec.Material.material{1}.v=nu1;

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

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

% -> NodeSets
nodeSetName1='bcSupportList';
febio_spec.Mesh.NodeSet{1}.ATTR.name=nodeSetName1;
febio_spec.Mesh.NodeSet{1}.node.ATTR.id=bcSupportList(:);

nodeSetName2='bcPrescribeList';
febio_spec.Mesh.NodeSet{2}.ATTR.name=nodeSetName2;
febio_spec.Mesh.NodeSet{2}.node.ATTR.id=bcPrescribeList(:);

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

%Boundary condition section
% -> Fix boundary conditions
febio_spec.Boundary.bc{1}.ATTR.type='fix';
febio_spec.Boundary.bc{1}.ATTR.node_set=nodeSetName1;
febio_spec.Boundary.bc{1}.dofs='x,y,z';

febio_spec.Boundary.bc{2}.ATTR.type='fix';
febio_spec.Boundary.bc{2}.ATTR.node_set=nodeSetName2;
febio_spec.Boundary.bc{2}.dofs='x,y';

febio_spec.Boundary.bc{3}.ATTR.type='prescribe';
febio_spec.Boundary.bc{3}.ATTR.node_set=nodeSetName2;
febio_spec.Boundary.bc{3}.dof='z';
febio_spec.Boundary.bc{3}.scale.ATTR.lc=1;
febio_spec.Boundary.bc{3}.scale.VAL=displacementMagnitude;
febio_spec.Boundary.bc{3}.relative=0;

%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=',';
% febio_spec.Output.logfile.element_data{1}.VAL=1:size(Es,1);

%% 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

%% 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; %Run in external or in matlab terminal

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

%% Import FEBio results

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

    % Importing nodal displacements from a log file
    [timeVec, N_disp_mat,~]=importFEBio_logfile(fullfile(savePath,febioLogFileName_disp)); %Nodal displacements
    timeVec=[0; timeVec(:)]; %Time

    N_disp_mat=N_disp_mat(:,2:end,:);
    sizImport=size(N_disp_mat);
    sizImport(3)=sizImport(3)+1;
    N_disp_mat_n=zeros(sizImport);
    N_disp_mat_n(:,:,2:end)=N_disp_mat;
    N_disp_mat=N_disp_mat_n;
    DN=N_disp_mat(:,:,end);
    DN_magnitude=sqrt(sum(DN(:,3).^2,2));
    Vs_def=Vs+DN;

    %     % Importing element stress from a log file
    %     [time_mat, E_stress_mat,~]=importFEBio_logfile(fullfile(savePath,febioLogFileName_stress)); %Nodal forces
    %     time_mat=[0; time_mat(:)]; %Time
    %     stress_cauchy_sim=[0; mean(squeeze(E_stress_mat(:,end,:)),1)'];
    %%
    % Importing nodal forces from a log file

    [dataStruct]=importFEBio_logfile(fullfile(savePath,febioLogFileName_force),1,1); %Nodal forces

    %Access data
    timeVec=dataStruct.time;
    f_sum_x=squeeze(sum(dataStruct.data(bcPrescribeList,1,:),1));
    f_sum_y=squeeze(sum(dataStruct.data(bcPrescribeList,2,:),1));
    f_sum_z=squeeze(sum(dataStruct.data(bcPrescribeList,3,:),1));

    %%
    % Visualize force data

    displacementApplied=timeVec.*displacementMagnitude;

    cFigure; hold on;
    xlabel('$u$ [mm]','Interpreter','Latex');
    ylabel('$F_z$ [N]','Interpreter','Latex');
    hp=plot(displacementApplied(:),f_sum_z(:),'b-','LineWidth',3);
    grid on; box on; axis square; axis tight;
    set(gca,'FontSize',fontSize);
    drawnow;

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

    % Create basic view and store graphics handle to initiate animation
    hf=cFigure; %Open figure
    gtitle([febioFebFileNamePart,': Press play to animate']);
    hp=gpatch(Fb,Vs_def,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;
    clim([0 max(DN_magnitude)]);
    axis([min([Vs_def(:,1);Vs(:,1)]) max([Vs_def(:,1);Vs(:,1)])...
        min([Vs_def(:,2);Vs(:,2)]) max([Vs_def(:,2);Vs(:,2)])...
        min([Vs_def(:,3);Vs(:,3)]) max([Vs_def(:,3);Vs(:,3)]) ]); %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
        Vs_def=Vs+DN; %Current nodal coordinates

        %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}={Vs_def,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 F = fit_metric_field(DiffDir, arange,brange, Q)

% fit_metric_field - fit a field of tensor
%
%    F = fit_metric_field(DiffDir, arange,brange, Q);
%
%   F is a (Q,Q,2,2) field of 2x2 SDP matrices.
%   DiffDir(x,h) is the directional value of the metric at x in direction h.
%
%   Copyright (c) 2014 Gabriel Peyre

F = zeros(Q,Q,2,2);
alist = linspace(arange(1), arange(2), Q);
blist = linspace(brange(1), brange(2), Q);
for i=1:Q
    % progressbar(i,Q);
    for j=1:Q
        ab = [alist(i) blist(j)];
        M = fit_metric(@(h)DiffDir(ab,h));
        F(i,j,:,:) = reshape(M, [1 1 2 2]);
    end
end

end


function out = riverplot_line(x, y, color, thickness, steepness, varargin)
% out = riverplot_line(x, y, color, thickness, steepness, varargin)
%
% Draw sigmoidal line from 2-coord point x to 2-coord point y
% x = [xcoord ycoord] for left-hand point
% y = [xcoord ycoord] for right-hand point
%
% x = rect1.topright
% y = rect2.topleft

% Programmers' notes:
% 8/21/2017 Stephan Geuter
% changed steepnes treatment computation. Steepness coefficient is now used
% in sigmoid function to control steepnes and curvature at tangets (box
% edges). shift in xstartpoints is removed. Makes ribbons smoother.
%
%

% x, y inputs can be [x,y,z] coordinate triplets or clusters.
if isstruct(x), x = x.mm_center(1:2); end
if isstruct(y), y = y.mm_center(1:2); end

% make middle points with sigmoid function

xdiff = y(1) - x(1);  % difference in x position
ydiff = y(2) - x(2);

% xstartpoints = [x(1) + xdiff * steepness(1) y(1) - xdiff * steepness(1)]';
xstartpoints = [x(1) y(1)]';

% sigmoid reference curve
% sigmoid = inline('p(1) .* ( 1 ./ (1 + p(2)*exp(-p(3)*x)) )','p','x');
sigmoid = @(p,x) (p(1) .* ( 1 ./ (1 + p(2)*exp(-p(3)*x)) ));
xx = linspace(-5, 5, 50); % generate 50 points with standard sigmoid
%                         % Range determines steepness bounds, larger range
%                         = more steep
yy = sigmoid([1 1 1+steepness(1)], xx)'; % add steepness coefficient to have ribbons meet the box edges

xmidpoints = linspace(xstartpoints(1), xstartpoints(end), 50)';
ymidpoints = x(2) + yy * ydiff;

xcoords = [x(1); xstartpoints(1); xmidpoints; xstartpoints(end); y(1)];
ycoords = [x(2); x(2); ymidpoints; y(2); y(2)];

%     % make x, y bend percents
%     if length(steepness) == 1
%         steepness = repmat(steepness, 1, 2);
%     end
%
%     % make 4 coords, adding 2 middle points, so we can bend
%     xdiff = y(1) - x(1);  % difference in x position
%     xmidpoints = [x(1) + xdiff * steepness(1) x(1) + xdiff * .5  y(1) - xdiff * steepness(1)]';
%
%     xcoords = [x(1); xmidpoints; y(1)];
%
%     ydiff = (y(2) - x(2)) ./ 2;
%     ycoords = [x(2); x(2); x(2) + ydiff; y(2); y(2)];

%     plot(xcoords, ycoords, 'go');
%
%      if any(steepness)
%
%     %[p,sse,fit] = nonlin_fit(ycoords, xcoords - mean(xcoords), 'start',[1 1 1]);
%
% sigmoid = inline('p(1) .* ( 1 ./ (1 + p(2)*exp(-p(3)*x)) )','p','x');
% xcoords2 = linspace(xcoords(1), xcoords(end), 100);
%
% ycoords2 = sigmoid([1 1 1], xcoords2 - mean(xcoords2));
% ycoords2 = ycoords(1) + ydiff * ycoords2;
%
% plot(xcoords2, ycoords2, 'rx');

%         % bow out: curved line
%         n = length(xcoords);
%
%         nsamples = [];
%         if length(varargin) > 0
%             nsamples = varargin{1};
%         end
%
%         if isempty(nsamples)
%             nsamples = 10 * n;
%         end
%
%         t = 1:n;
%         ts = 1:((n-1)/(nsamples-1)):n;          % spline grid
%
%         xcoords = spline(t, xcoords, ts);
%         ycoords = spline(t, ycoords, ts);
%
%     end

    h = plot(xcoords, ycoords,'Color',color,'LineWidth',thickness);

    out.h = h;
    out.xcoords = xcoords;
    out.ycoords = ycoords;

end % function


%COREG_INV invert coreg translations for coefficients
%
%    Andy Hooper, Aug 2005
%
%   ======================================================================
%   04/2008 AH: Updated for compatibility with matlab 2008a
%   11/2008 AH: Deltaline/pixel added for Doris 3.96 compatibility
%   ======================================================================

cpmname=dir('CPM_Data.*');

load coreg_parms
Lrange=coreg_parms(1)-1
Prange=coreg_parms(2)-1
N=coreg_parms(3)^2
%osf=coreg_parms(4)
osf=1
n_ifg=coreg_parms(5)

G=sparse(0,n_ifg*12);
d=zeros(0,1);

for i=1:length(cpmname);

    thisname=cpmname(i).name;
    CPM_Data=load(thisname);

    posL1=((CPM_Data(:,2)-1)*4/Lrange)-2;
    posP1=((CPM_Data(:,3)-1)*4/Prange)-2;
    offL=CPM_Data(:,4);
    offP=CPM_Data(:,5);
    posL2=((CPM_Data(:,2)+offL-1)*4/Lrange)-2;
    posP2=((CPM_Data(:,3)+offP-1)*4/Prange)-2;
    n_pos=size(posL2,1);
    corrf=CPM_Data(:,6);
    stdev=sqrt(3/2/N).*sqrt(1-corrf.^2)/pi./corrf*osf^(3/2);
    weighting=1./stdev;
    ifgs=sscanf(thisname,'CPM_Data.%d.%d');
    ifg1=ifgs(1);
    ifg2=ifgs(2);

    Gblock1=[ones(size(posL1)),posL1,posP1,posL1.^2,posL1.*posP1,posP1.^2];
    Gblock1=Gblock1.*repmat(weighting,1,6);
    Gblock2=[ones(size(posL2)),posL2,posP2,posL2.^2,posL2.*posP2,posP2.^2];
    Gblock2=Gblock2.*repmat(weighting,1,6);
    Gnew=sparse(n_pos*2,n_ifg*12);
    if ifg1~=0
       Gnew(1:n_pos,(ifg1-1)*12+1:(ifg1-1)*12+6)=Gblock1;
       Gnew(n_pos+1:n_pos*2,(ifg1-1)*12+7:ifg1*12)=Gblock1;
    end
    Gnew(1:n_pos,(ifg2-1)*12+1:(ifg2-1)*12+6)=-Gblock2;
    Gnew(n_pos+1:n_pos*2,(ifg2-1)*12+7:ifg2*12)=-Gblock2;

    G=[G;Gnew];
    d=[d;weighting.*offL;weighting.*offP];
    %d=[d;offL;offP];
end

% coeff_s gives mapping of slave to master w.r.t. slave position
coeff_s=G\d;

load slave_corners.txt
deltaL=zeros(4,size(slave_corners,1));
deltaP=zeros(4,size(slave_corners,1));
for i = 1:size(slave_corners,1)
    posL1=((slave_corners(i,1:2))*4/Lrange)-2;
    posL1=[posL1(1);posL1(1);posL1(2);posL1(2)];
    posP1=((slave_corners(i,3:4))*4/Prange)-2;
    posP1=[posP1(1);posP1(2);posP1(1);posP1(2)];
    G=[ones(4,1),posL1,posP1,posL1.^2,posL1.*posP1,posP1.^2];
    deltaL(:,i)=G*coeff_s((i-1)*12+1:(i-1)*12+6);
    deltaP(:,i)=G*coeff_s((i-1)*12+7:(i)*12);
end
corner_offsets=[deltaL(:)';deltaP(:)'];
corner_offsets=corner_offsets(:);
save('corner_offsets.txt','-ascii','corner_offsets')

% we want mapping of slave to master w.r.t. master position
l=[-2:0.05:2];
p=l;
[Ls,Ps]=meshgrid(l,p);
Ls=Ls(:);
Ps=Ps(:);
nsynth=length(Ls);

Gblock=[ones(nsynth,1),Ls,Ps,Ls.^2,Ls.*Ps,Ps.^2];
Gsynth=sparse(2*nsynth,12);
Gsynth(1:nsynth,1:6)=Gblock;
Gsynth(nsynth+1:end,7:12)=Gblock;
coeff_m=zeros(size(coeff_s));

for i=1:n_ifg
    ifg_coeff_s=coeff_s((i-1)*12+1:i*12);
    dsynth=Gsynth*ifg_coeff_s;
    Lm=Ls+dsynth(1:nsynth)*4/Lrange;
    Pm=Ps+dsynth(nsynth+1:end)*4/Prange;
    Gblock=[ones(nsynth,1),Lm,Pm,Lm.^2,Lm.*Pm,Pm.^2];
    Gsynth(1:nsynth,1:6)=Gblock;
    Gsynth(nsynth+1:end,7:12)=Gblock;
    coeff_m((i-1)*12+1:i*12)=Gsynth\-dsynth;
end

save('coreg_coeffs.txt','-ascii','coeff_m')


function EUI_data=riceVST_EUI(Efz_data,sigma_data,VST_ABC)
% Applies exact unbiased inverse of the variance-stabilizing transformation f
% --------------------------------------------------------------------------------------------
%
% SYNTAX
% ------
% EUI_data = riceVST_EUI ( Efz_data , sigma_data , VST_ABC )
%
%
% OUTPUT
% ------
% EUI_data    :  exact unbiased inverse of the input Efz_data
%
%
% INPUTS
% ------
% Efz_data    :  Filtered variance-stabilized data (e.g, output of the denoising filter)
% sigma_data  :  standard-deviation parameter of the Rice distribution;  the method assumes
%                that the data z_data before stabilization is distributed according to
%                z_data ~ Rice(nu,sigma_data), nu being some unknown noise-free signal.
%                EUI_data should coincide with nu if the denoising of fz_data is perfect.
% VST_ABC     :  file-selector for the variance-stabilizing transformation  (default = 'A')
%
%
% --------------------------------------------------------------------------------------------
%
% The software implements the method published in the paper:
%
%  A. Foi, "Noise Estimation and Removal in MR Imaging: the Variance-Stabilization Approach",
%  in Proc. 2011 IEEE Int. Sym. Biomedical Imaging, ISBI 2011, Chicago (IL), USA, April 2011.
%  doi:10.1109/ISBI.2011.5872758
%
% --------------------------------------------------------------------------------------------
%
%
% author:                Alessandro Foi
%
% web page:              http://www.cs.tut.fi/~foi/RiceOptVST
%
% contact:               firstname.lastname@tut.fi
%
% --------------------------------------------------------------------------------------------
% Copyright (c) 2010-2012 Tampere University of Technology.
% All rights reserved.
% This work should be used for nonprofit purposes only.
% --------------------------------------------------------------------------------------------
%
% Disclaimer
% ----------
%
% Any unauthorized use of these routines for industrial or profit-oriented activities is
% expressively prohibited. By downloading and/or using any of these files, you implicitly
% agree to all the terms of the TUT limited license (included in the file Legal_Notice.txt).
% --------------------------------------------------------------------------------------------
%

%% Defaults
if nargin<2
    sigma_data=1;
end
if isempty(sigma_data)
    sigma_data=1;
end

if nargin<3
    VST_ABC='A';
end
if isempty(VST_ABC)
    VST_ABC='A';
end

if ischar(VST_ABC)
    if numel(VST_ABC)==1
        Rice_VST_matFile=['Rice_VST_',VST_ABC];
    else
        Rice_VST_matFile=VST_ABC;
    end
end

%% load variance-stabilizing transformation and its exact unbiased inverse from file
load(Rice_VST_matFile,'Efz','nu','z','f')

%% scale data before applying exact unbiased inverse of the variance-stabilizing transformation (see riceVST.m)
sigma_data_scaling=sigma_data;
a=f(end)-sqrt(sigma_data_scaling^2*max(z)^2/sigma_data^2-1/2);
nu=nu*sigma_data_scaling;
%% apply exact unbiased inverse of the variance-stabilizing transformation
EUI_data=interp1(Efz,nu,Efz_data,'linear','extrap');
%% small values (see Equation 11 in the ISBI2011 paper)
EUI_data(Efz_data<=min(Efz))=min(nu);
%% apply asymptotical exact unbiased inverse of the variance-stabilizing transformation (used only for large values)
maxEfz=max(Efz);
if 0
    EUI_data(Efz_data>maxEfz)=sigma_data*sqrt((Efz_data(Efz_data>maxEfz)-a).^2+0.5);  %% this is the asymptotic inversion to Ez (identical to the above theta_or_Ez==1 case)
    EUI_data(Efz_data>maxEfz)=EUI_data(Efz_data>maxEfz).*(1-0.5*(sigma_data./EUI_data(Efz_data>maxEfz)).^2);  %% this is the asymptotic correction between nu and Ez
else
    EUI_data(Efz_data>maxEfz)=sigma_data*((Efz_data(Efz_data>maxEfz)-a).^2)./sqrt((Efz_data(Efz_data>maxEfz)-a).^2+0.5);   %% this is the result of the two lines above
end


function boolVal=isPermutation(possiblePerm,startIdx)
%%ISPERMUTATION Given an array, determine whether it is a valid
%        permutation of the values startIdx:(startIdx+permLength-1).
%
%INPUTS: possiblePerm A length permLength vector to test for being a
%                     permutation.
%            startIdx The starting index of the permutation values to
%                     consider. If this input is omitted or an empty matrix
%                     is passed, then the default of 1 is used.
%
%OUTPUTS: boolVal This is true if possiblePerm is a permutation vector and
%                 false otherwise. Empty matrices are considered
%                 permutation vectors.
%
%After initial checks, the function just allocates a vector having the
%length of possiblePerm and adds 1 to each index given in possiblePerm. If
%any index is repeated. Afterwards, it checks whether all of the indices
%contain a "1".
%
%EXAMPLE:
% boolVal1=isPermutation([1;4;3;5])
% boolVal2=isPermutation([1;4;3;2;5])
% boolVal3=isPermutation([13;16;15;17;14],13)
%One will find boolVal1=false, boolVal2=true, boolVal3=true.
%
%September 2020 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

if(nargin<2||isempty(startIdx))
    startIdx=1;
end

possiblePerm=possiblePerm(:);

if(~isnumeric(possiblePerm)||~isreal(possiblePerm)||any(~isfinite(possiblePerm))||any(possiblePerm~=fix(possiblePerm)))
    boolVal=false;
    return;
end

numEls=length(possiblePerm);

possiblePerm=possiblePerm-startIdx+1;
if(any(possiblePerm>numEls)||any(possiblePerm<1))
    boolVal=false;
    return;
end

numValsPresent=zeros(numEls,1);
for k=1:numEls
    idx=possiblePerm(k);
    numValsPresent(idx)=numValsPresent(idx)+1;
end

boolVal=all(numValsPresent==1);

end

%LICENSE:
%
%The source code is in the public domain and not licensed or under
%copyright. The information and software may be used freely by the public.
%As required by 17 U.S.C. 403, third parties producing copyrighted works
%consisting predominantly of the material produced by U.S. government
%agencies must provide notice with such work(s) identifying the U.S.
%Government material incorporated and stating that such material is not
%subject to copyright protection.
%
%Derived works shall not identify themselves in a manner that implies an
%endorsement by or an affiliation with the Naval Research Laboratory.
%
%RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE
%SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY THE NAVAL
%RESEARCH LABORATORY FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE ACTIONS
%OF RECIPIENT IN THE USE OF THE SOFTWARE.


function output=SSMultibandKamath02(signal,fs,IS)

% OUTPUT=SSMULTIBANDKAMATH02(S,FS,IS)
% Multi-band Spectral subtraction [Kamath2002]
% subtraction with adjusting subtraction factor. the adjustment is
% according to local a postriori SNR and the frequency band.
% S is the noisy signal, FS is the sampling frequency and IS is the initial
% silence (noise only) length in seconds (default value is .25 sec)
%
% April-04
% Esfandiar Zavarehei

if (nargin<3 | isstruct(IS))
    IS=.25; %seconds
end
W=fix(.025*fs); %Window length is 25 ms
nfft=W;
SP=.4; %Shift percentage is 40% (10ms) %Overlap-Add method works good with this value(.4)
wnd=hamming(W);

% IGNORE THIS SECTION FOR CAMPATIBALITY WITH ANOTHER PROGRAM FROM HERE.....
if (nargin>=3 & isstruct(IS))%This option is for compatibility with another programme
    W=IS.windowsize
    SP=IS.shiftsize/W;
    nfft=IS.nfft;
    wnd=IS.window;
    if isfield(IS,'IS')
        IS=IS.IS;
    else
        IS=.25;
    end
end
% .......IGNORE THIS SECTION FOR CAMPATIBALITY WITH ANOTHER PROGRAM T0 HERE

NIS=fix((IS*fs-W)/(SP*W) +1);%number of initial silence segments
Gamma=2;%Magnitude Power (1 for magnitude spectral subtraction 2 for power spectrum subtraction)

y=segment(signal,W,SP,wnd);
Y=fft(y,nfft);
YPhase=angle(Y(1:fix(end/2)+1,:)); %Noisy Speech Phase
Y=abs(Y(1:fix(end/2)+1,:)).^Gamma;%Specrogram
numberOfFrames=size(Y,2);
FreqResol=size(Y,1);

N=mean(Y(:,1:NIS)')'; %initial Noise Power Spectrum mean

NoiseCounter=0;
NoiseLength=9;%This is a smoothing factor for the noise updating

Beta=.03;
minalpha=1;
maxalpha=5;
minSNR=-5;
maxSNR=20;
alphaSlope=(minalpha-maxalpha)/(maxSNR-minSNR);
alphaShift=maxalpha-alphaSlope*minSNR;

BN=Beta*N;

%Delta is a frequency dependent coefficient
Delta=1.5*ones(size(BN));
Delta(1:fix((-2000+fs/2)*FreqResol*2/fs))=2.5; %if the frequency is lower than FS/2 - 2KHz
Delta(1:fix(1000*FreqResol*2/fs))=1; %if the frequency is lower than 1KHz

for i=1:numberOfFrames
    [NoiseFlag, SpeechFlag, NoiseCounter, Dist]=vad(Y(:,i).^(1/Gamma),N.^(1/Gamma),NoiseCounter); %Magnitude Spectrum Distance VAD
    if SpeechFlag==0
        N=(NoiseLength*N+Y(:,i))/(NoiseLength+1); %Update and smooth noise
        BN=Beta*N;
    end

    SNR=10*log(Y(:,i)./N);
    alpha=alphaSlope*SNR+alphaShift;
    alpha=max(min(alpha,maxalpha),minalpha);

    D=Y(:,i)-(Delta.*alpha.*N); %Nonlinear (Non-uniform) Power Specrum Subtraction

    X(:,i)=max(D,BN); %if BY>D X=BY else X=D which sets very small values of subtraction result to an attenuated
                      %version of the input power spectrum.
end

output=OverlapAdd2(X.^(1/Gamma),YPhase,W,SP*W);

function ReconstructedSignal=OverlapAdd2(XNEW,yphase,windowLen,ShiftLen);

%Y=OverlapAdd(X,A,W,S);
%Y is the signal reconstructed signal from its spectrogram. X is a matrix
%with each column being the fft of a segment of signal. A is the phase
%angle of the spectrum which should have the same dimension as X. if it is
%not given the phase angle of X is used which in the case of real values is
%zero (assuming that its the magnitude). W is the window length of time
%domain segments if not given the length is assumed to be twice as long as
%fft window length. S is the shift length of the segmentation process ( for
%example in the case of non overlapping signals it is equal to W and in the
%case of %50 overlap is equal to W/2. if not givven W/2 is used. Y is the
%reconstructed time domain signal.
%Sep-04
%Esfandiar Zavarehei

if nargin<2
    yphase=angle(XNEW);
end
if nargin<3
    windowLen=size(XNEW,1)*2;
end
if nargin<4
    ShiftLen=windowLen/2;
end
if fix(ShiftLen)~=ShiftLen
    ShiftLen=fix(ShiftLen);
    disp('The shift length have to be an integer as it is the number of samples.')
    disp(['shift length is fixed to ' num2str(ShiftLen)])
end

[FreqRes FrameNum]=size(XNEW);

Spec=XNEW.*exp(j*yphase);

if mod(windowLen,2) %if FreqResol is odd
    Spec=[Spec;flipud(conj(Spec(2:end,:)))];
else
    Spec=[Spec;flipud(conj(Spec(2:end-1,:)))];
end
sig=zeros((FrameNum-1)*ShiftLen+windowLen,1);
weight=sig;
for i=1:FrameNum
    start=(i-1)*ShiftLen+1;
    spec=Spec(:,i);
    sig(start:start+windowLen-1)=sig(start:start+windowLen-1)+real(ifft(spec,windowLen));
end
ReconstructedSignal=sig;

function [NoiseFlag, SpeechFlag, NoiseCounter, Dist]=vad(signal,noise,NoiseCounter,NoiseMargin,Hangover)

%[NOISEFLAG, SPEECHFLAG, NOISECOUNTER, DIST]=vad(SIGNAL,NOISE,NOISECOUNTER,NOISEMARGIN,HANGOVER)
%Spectral Distance Voice Activity Detector
%SIGNAL is the the current frames magnitude spectrum which is to labeld as
%noise or speech, NOISE is noise magnitude spectrum template (estimation),
%NOISECOUNTER is the number of imediate previous noise frames, NOISEMARGIN
%(default 3)is the spectral distance threshold. HANGOVER ( default 8 )is
%the number of noise segments after which the SPEECHFLAG is reset (goes to
%zero). NOISEFLAG is set to one if the the segment is labeld as noise
%NOISECOUNTER returns the number of previous noise segments, this value is
%reset (to zero) whenever a speech segment is detected. DIST is the
%spectral distance.
%Saeed Vaseghi
%edited by Esfandiar Zavarehei
%Sep-04

if nargin<4
    NoiseMargin=3;
end
if nargin<5
    Hangover=8;
end
if nargin<3
    NoiseCounter=0;
end

FreqResol=length(signal);

SpectralDist= 20*(log10(signal)-log10(noise));
SpectralDist(find(SpectralDist<0))=0;

Dist=mean(SpectralDist);
if (Dist < NoiseMargin)
    NoiseFlag=1;
    NoiseCounter=NoiseCounter+1;
else
    NoiseFlag=0;
    NoiseCounter=0;
end

% Detect noise only periods and attenuate the signal
if (NoiseCounter > Hangover)
    SpeechFlag=0;
else
    SpeechFlag=1;
end

function Seg=segment(signal,W,SP,Window)

% SEGMENT chops a signal to overlapping windowed segments
% A= SEGMENT(X,W,SP,WIN) returns a matrix which its columns are segmented
% and windowed frames of the input one dimentional signal, X. W is the
% number of samples per window, default value W=256. SP is the shift
% percentage, default value SP=0.4. WIN is the window that is multiplied by
% each segment and its length should be W. the default window is hamming
% window.
% 06-Sep-04
% Esfandiar Zavarehei

if nargin<3
    SP=.4;
end
if nargin<2
    W=256;
end
if nargin<4
    Window=hamming(W);
end
Window=Window(:); %make it a column vector

L=length(signal);
SP=fix(W.*SP);
N=fix((L-W)/SP +1); %number of segments

Index=(repmat(1:W,N,1)+repmat((0:(N-1))'*SP,1,W))';
hw=repmat(Window,1,N);
Seg=signal(Index).*hw;


% NTF | bcuNCP | Non-negative CP Decomposition by block-coordinate update (Xu and Yin, 2012)
% process_video('NTF', 'bcuNCP', 'dataset/demo.avi', 'output/bcuNCP.avi');

% Compute a simple NTF model of 10 components
A = double(T);
R = 10; % tensor rank
opts.maxit = 1000; % max number of iterations
opts.tol = 1e-4; % stopping tolerance
M = ncp(T,R,opts);
L = double(full(M));
S = (A - L);


function plotValdata(valdata, fignum)

cthresh = (0.001:0.001:0.5);
err = zeros(size(cthresh));
nregions = zeros(size(cthresh));
for f = 1:numel(valdata)
    for k = 1:numel(cthresh)
        [tmp, minind] = min(abs(valdata(f).mergeCost-cthresh(k)));
        err(k) = err(k) + valdata(f).segError(minind)/numel(valdata);
        nregions(k) = nregions(k) + valdata(f).nregions(minind)/numel(valdata);
    end
end
figure(fignum), subplot(2,2,1), hold off, plot(cthresh, err), title('bias vs. err')
figure(fignum), subplot(2,2,2), plot(err, nregions), title('conf: err vs. nregions')

rthresh = (5:5:1000);
err = zeros(size(rthresh));
nregions = zeros(size(rthresh));
for f = 1:numel(valdata)
    for k = 1:numel(rthresh)
        [tmp, minind] = min(abs(valdata(f).nregions-rthresh(k)));
        err(k) = err(k) + valdata(f).segError(minind)/numel(valdata);
        nregions(k) = nregions(k) + valdata(f).nregions(minind)/numel(valdata);
    end
end
figure(fignum), subplot(2,2,3), plot(rthresh, err),  title('minregion vs. err')
figure(fignum), subplot(2,2,4), plot(err, nregions), title('minreg: err vs. nregions')


function [fhat,xhat,fcount,retcode] = csminit(fcn,x0,f0,g0,badg,H0,varargin)
% [fhat,xhat,fcount,retcode] = csminit(fcn,x0,f0,g0,badg,H0,...
%                                       P1,P2,P3,P4,P5,P6,P7,P8)
% retcodes: 0, normal step.  5, largest step still improves too fast.
% 4,2 back and forth adjustment of stepsize didn't finish.  3, smallest
% stepsize still improves too slow.  6, no improvement found.  1, zero
% gradient.
%---------------------
% Modified 7/22/96 to omit variable-length P list, for efficiency and compilation.
% Places where the number of P's need to be altered or the code could be returned to
% its old form are marked with ARGLIST comments.
%
% Fixed 7/17/93 to use inverse-hessian instead of hessian itself in bfgs
% update.
%
% Fixed 7/19/93 to flip eigenvalues of H to get better performance when
% it's not psd.
%
%tailstr = ')';
%for i=nargin-6:-1:1
%   tailstr=[ ',P' num2str(i)  tailstr];
%end
%ANGLE = .03;
ANGLE = .005;
%THETA = .03;
THETA = .3; %(0<THETA<.5) THETA near .5 makes long line searches, possibly fewer iterations.
FCHANGE = 1000;
MINLAMB = 1e-9;
% fixed 7/15/94
% MINDX = .0001;
% MINDX = 1e-6;
MINDFAC = .01;
fcount=0;
lambda=1;
xhat=x0;
f=f0;
fhat=f0;
g = g0;
gnorm = norm(g);
%
if (gnorm < 1.e-12) & ~badg % put ~badg 8/4/94
   retcode =1;
   dxnorm=0;
   % gradient convergence
else
   % with badg true, we don't try to match rate of improvement to directional
   % derivative.  We're satisfied just to get some improvement in f.
   %
   %if(badg)
   %   dx = -g*FCHANGE/(gnorm*gnorm);
   %  dxnorm = norm(dx);
   %  if dxnorm > 1e12
   %     disp('Bad, small gradient problem.')
   %     dx = dx*FCHANGE/dxnorm;
   %   end
   %else
   % Gauss-Newton step;
   %---------- Start of 7/19/93 mod ---------------
   %[v d] = eig(H0);
   %toc
   %d=max(1e-10,abs(diag(d)));
   %d=abs(diag(d));
   %dx = -(v.*(ones(size(v,1),1)*d'))*(v'*g);
%      toc
   dx = -H0*g;
%      toc
   dxnorm = norm(dx);
   if dxnorm > 1e12
      disp('Near-singular H problem.')
      dx = dx*FCHANGE/dxnorm;
   end
   dfhat = dx'*g0;
   %end
   %
   %
   if ~badg
      % test for alignment of dx with gradient and fix if necessary
      a = -dfhat/(gnorm*dxnorm);
      if a<ANGLE
         dx = dx - (ANGLE*dxnorm/gnorm+dfhat/(gnorm*gnorm))*g;
         % suggested alternate code:  ---------------------
         dx = dx*dxnorm/norm(dx)    % This keeps scale invariant to the angle correction
         % ------------------------------------------------
         dfhat = dx'*g;
         % dxnorm = norm(dx);  % this line unnecessary with modification that keeps scale invariant
         disp(sprintf('Correct for low angle: %g',a))
      end
   end
   disp(sprintf('Predicted improvement: %18.9f',-dfhat/2))
   %
   % Have OK dx, now adjust length of step (lambda) until min and
   % max improvement rate criteria are met.
   done=0;
   factor=3;
   shrink=1;
   lambdaMin=0;
   lambdaMax=inf;
   lambdaPeak=0;
   fPeak=f0;
   lambdahat=0;
   while ~done
      if size(x0,2)>1
         dxtest=x0+dx'*lambda;
      else
         dxtest=x0+dx*lambda;
      end
      % home
      f = feval(fcn,dxtest,varargin{:});
      %ARGLIST
      %f = feval(fcn,dxtest,P1,P2,P3,P4,P5,P6,P7,P8,P9,P10,P11,P12,P13);
      % f = feval(fcn,x0+dx*lambda,P1,P2,P3,P4,P5,P6,P7,P8);
      disp(sprintf('lambda = %10.5g; f = %20.7f',lambda,f ))
      %debug
      %disp(sprintf('Improvement too great? f0-f: %g, criterion: %g',f0-f,-(1-THETA)*dfhat*lambda))
      if f<fhat
         fhat=f;
         xhat=dxtest;
         lambdahat = lambda;
      end
      fcount=fcount+1;
      shrinkSignal = (~badg & (f0-f < max([-THETA*dfhat*lambda 0]))) | (badg & (f0-f) < 0) ;
      growSignal = ~badg & ( (lambda > 0)  &  (f0-f > -(1-THETA)*dfhat*lambda) );
      if  shrinkSignal  &   ( (lambda>lambdaPeak) | (lambda<0) )
         if (lambda>0) & ((~shrink) | (lambda/factor <= lambdaPeak))
            shrink=1;
            factor=factor^.6;
            while lambda/factor <= lambdaPeak
               factor=factor^.6;
            end
            %if (abs(lambda)*(factor-1)*dxnorm < MINDX) | (abs(lambda)*(factor-1) < MINLAMB)
            if abs(factor-1)<MINDFAC
               if abs(lambda)<4
                  retcode=2;
               else
                  retcode=7;
               end
               done=1;
            end
         end
         if (lambda<lambdaMax) & (lambda>lambdaPeak)
            lambdaMax=lambda;
         end
         lambda=lambda/factor;
         if abs(lambda) < MINLAMB
            if (lambda > 0) & (f0 <= fhat)
               % try going against gradient, which may be inaccurate
               lambda = -lambda*factor^6
            else
               if lambda < 0
                  retcode = 6;
               else
                  retcode = 3;
               end
               done = 1;
            end
         end
      elseif  (growSignal & lambda>0) |  (shrinkSignal & ((lambda <= lambdaPeak) & (lambda>0)))
         if shrink
            shrink=0;
            factor = factor^.6;
            %if ( abs(lambda)*(factor-1)*dxnorm< MINDX ) | ( abs(lambda)*(factor-1)< MINLAMB)
            if abs(factor-1)<MINDFAC
               if abs(lambda)<4
                  retcode=4;
               else
                  retcode=7;
               end
               done=1;
            end
         end
         if ( f<fPeak ) & (lambda>0)
            fPeak=f;
            lambdaPeak=lambda;
            if lambdaMax<=lambdaPeak
               lambdaMax=lambdaPeak*factor*factor;
            end
         end
         lambda=lambda*factor;
         if abs(lambda) > 1e20;
            retcode = 5;
            done =1;
         end
      else
         done=1;
         if factor < 1.2
            retcode=7;
         else
            retcode=0;
         end
      end
   end
end
disp(sprintf('Norm of dx %10.5g', dxnorm))


function SE = functionPowerOptimization_maxmin(signal,interference,Pmax,prelogFactor)
%Compute DL power allocation that solves the max-min fairness problem,
%using the algorithm in Theorem 7.1.
%
%This function require additional software packages to be used, which
%need to be downloaded and installed separately. These packages are
%developed independently and are delivered with separate licenses.
%The implementation uses CVX (http://cvxr.com/cvx) and has been tested
%using CVX version 2.1. We recommend the use of the Mosek solver (we
%have tested using version 7.1.0.12).
%
%INPUT:
%signal       = K x L matrix where element (k,j) is a_jk in (7.2)
%interference = K x L x K x L matrix where (l,i,j,k) is b_lijk in (7.3)
%Pmax         = Maximum transmit power per BS
%prelogFactor = Prelog factor
%
%OUTPUT:
%SE = K x L matrix where element (k,j) is the downlink SE of UE k in cell j
%     using the max-min power allocation solution
%
%
%This Matlab function was developed to generate simulation results to:
%
%Emil Bjornson, Jakob Hoydis and Luca Sanguinetti (2017),
%"Massive MIMO Networks: Spectral, Energy, and Hardware Efficiency",
%Foundations and Trends in Signal Processing: Vol. 11, No. 3-4,
%pp. 154-655. DOI: 10.1561/2000000093.
%
%For further information, visit: https://www.massivemimobook.com
%
%This is version 1.01 (Last edited: 2019-03-16)
%
%License: This code is licensed under the GPLv2 license. If you in any way
%use this code for research that results in publications, please cite our
%monograph as described above.

%Extract number of UEs
K = size(signal,1);

%Extract number of cells
L = size(signal,2);

%Check which UEs that have non-zero channels, because these ones are
%excluded (they are considered inactive)
nonzero = reshape(signal,[K*L 1]);
nonzero = nonzero(nonzero>0);

%Initalize the gamma-variables in Algorithm 1
rateLower = 0;
rateUpper = log2(1+Pmax*min(nonzero));

%Set the accuracy of the bisection
delta = 0.01;

%Prepare to save the power solution
rhoBest = zeros(K,L);

%Solve the max-min problem by bisection - iterate until the difference
%between the lower and upper points in the interval is smaller than delta
while norm(rateUpper - rateLower) > delta

    %Compute the midpoint of the line. Note that we are performing the
    %bisection in the SE domain instead of the SINR domain as in Algorithm
    %1, since we can then specify delta as the SE difference
    rateCandidate = (rateLower+rateUpper)/2;

    %Transform the midpoints into SINR requirements
    gammaCandidate = 2.^(rateCandidate)-1;

    %Solve the feasibility problem using CVX
    [feasible,rhoSolution] = functionFeasibilityProblem_cvx(signal,interference,Pmax,K,L,gammaCandidate);

    %If the problem was feasible, then replace rateLower with
    %gammaCandidate and store rhoSolution as the new best solution.
    if feasible
        rateLower = rateCandidate;
        rhoBest = rhoSolution;
    else
        %If the problem was not feasible, then replace ratePoint with
        %gammaCandidate
        rateUpper = rateCandidate;
    end

end

%Compute the SEs using Theorem 4.6
SE = functionComputeSE_DL_poweralloc(rhoBest,signal,interference,prelogFactor);

function [feasible,rhoSolution] = functionFeasibilityProblem_cvx(signal,interference,Pmax,K,L,SINR)
%Solve the linear feasibility problem in Algorithm 1 using CVX, by adding
%an extra variable so that it becomes a minimization problem with better
%properties.

cvx_begin
cvx_quiet(true); % This suppresses screen output from the solver

variable rho(K,L);  %Variable for the K x L power allocation matrix
variable scaling    %Scaling parameter for power constraints

minimize scaling %Minimize the power indirectly by scaling the power constraints

subject to

for j = 1:L

    for k = 1:K

        if signal(k,j)>0

            %SINR constraints
            SINR*(sum(sum(rho.*interference(:,:,k,j))) + 1) - (rho(k,j)*signal(k,j)) <= 0

        end

        rho(k,j)>=0

    end

    sum(rho(:,j)) <= scaling*Pmax;

end

scaling >= 0; %Power constraints must be positive

cvx_end

%% Analyze the CVX output and prepare the output variables
if isempty(strfind(cvx_status,'Solved')) %Both the power minimization problem and the feasibility problem are infeasible
    feasible = false;
    rhoSolution = [];
elseif scaling>1 %Only the power minimization problem is feasible
    feasible = false;
    rhoSolution = rho;
else %Both the power minimization problem and feasibility problem are feasible
    feasible = true;
    rhoSolution = rho;
end