function varargout=shadedErrorBar(x,y,errBar,varargin)
% generate continuous error bar area around a line plot
%
% function H=shadedErrorBar(x,y,errBar, ...)
%
% Purpose
% Makes a 2-d line plot with a pretty shaded error bar made
% using patch. Error bar color is chosen automatically.
%
%
% Inputs (required)
% x - vector of x values [optional, can be left empty]
% y - vector of y values or a matrix of n observations by m cases
%     where m has length(x);
% errBar - if a vector we draw symmetric errorbars. If it has a size
%          of [2,length(x)] then we draw asymmetric error bars with
%          row 1 being the upper bar and row 2 being the lower bar
%          (with respect to y). ** alternatively ** errBar can be a
%          cellArray of two function handles. The first defines which
%          statistic the line should be and the second defines the
%          error bar.
%
% Inputs (optional, param/value pairs)
% 'lineProps' - ['-k' by default] defines the properties of
%             the data line. e.g.:
%             'or-', or {'-or','markerfacecolor',[1,0.2,0.2]}
% 'transparent' - [true  by default] if true, the shaded error
%               bar is made transparent. However, for a transparent
%               vector image you will need to save as PDF, not EPS,
%               and set the figure renderer to "painters". An EPS
%               will only be transparent if you set the renderer
%               to OpenGL, however this makes a raster image.
% 'patchSaturation'- [0.2 by default] The saturation of the patch color.
%
%
%
% Outputs
% H - a structure of handles to the generated plot objects.
%
%
% Examples:
% y=randn(30,80);
% x=1:size(y,2);
%
% 1)
% shadedErrorBar(x,mean(y,1),std(y),'lineprops','g');
%
% 2)
% shadedErrorBar(x,y,{@median,@std},'lineprops',{'r-o','markerfacecolor','r'});
%
% 3)
% shadedErrorBar([],y,{@median,@(x) std(x)*1.96},'lineprops',{'r-o','markerfacecolor','k'});
%
% 4)
% Overlay two transparent lines:
% clf
% y=randn(30,80)*10;
% x=(1:size(y,2))-40;
% shadedErrorBar(x,y,{@mean,@std},'lineprops','-r','transparent',1);
% hold on
% y=ones(30,1)*x; y=y+0.06*y.^2+randn(size(y))*10;
% shadedErrorBar(x,y,{@mean,@std},'lineprops','-b','transparent',1);
% hold off
%
%
% Rob Campbell - November 2009

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Parse input arguments
narginchk(3,inf)

params = inputParser;
params.CaseSensitive = false;
params.addParameter('lineProps', '-k', @(x) ischar(x) | iscell(x));
params.addParameter('transparent', true, @(x) islogical(x) || x==0 || x==1);
params.addParameter('patchSaturation', 0.2, @(x) isnumeric(x) && x>=0 && x<=1);

params.parse(varargin{:});

%Extract values from the inputParser
lineProps =  params.Results.lineProps;
transparent =  params.Results.transparent;
patchSaturation = params.Results.patchSaturation;

if ~iscell(lineProps), lineProps={lineProps}; end

%Process y using function handles if needed to make the error bar dynamically
if iscell(errBar)
    fun1=errBar{1};
    fun2=errBar{2};
    errBar=fun2(y);
    y=fun1(y);
else
    y=y(:).';
end

if isempty(x)
    x=1:length(y);
else
    x=x(:).';
end

%Make upper and lower error bars if only one was specified
if length(errBar)==length(errBar(:))
    errBar=repmat(errBar(:)',2,1);
else
    s=size(errBar);
    f=find(s==2);
    if isempty(f), error('errBar has the wrong size'), end
    if f==2, errBar=errBar'; end
end

if length(x) ~= length(errBar)
    error('length(x) must equal length(errBar)')
end

%Log the hold status so we don't change
initialHoldStatus=ishold;
if ~initialHoldStatus, hold on,  end

H = makePlot(x,y,errBar,lineProps,transparent,patchSaturation);

if ~initialHoldStatus, hold off, end

if nargout==1
    varargout{1}=H;
end

function H = makePlot(x,y,errBar,lineProps,transparent,patchSaturation)

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Plot to get the parameters of the line
    H.mainLine=plot(x,y,lineProps{:});

    % Work out the color of the shaded region and associated lines.
    % Here we have the option of choosing alpha or a de-saturated
    % solid colour for the patch surface.
    mainLineColor=get(H.mainLine,'color');
    edgeColor=mainLineColor+(1-mainLineColor)*0.55;

    if transparent
        faceAlpha=patchSaturation;
        patchColor=mainLineColor;
    else
        faceAlpha=1;
        patchColor=mainLineColor+(1-mainLineColor)*(1-patchSaturation);
    end

    %Calculate the error bars
    uE=y-errBar(1,:);
    lE=y+errBar(2,:);

    %Add the patch error bar

    %Make the patch
    yP=[lE,fliplr(uE)];
    xP=[x,fliplr(x)];

    %remove nans otherwise patch won't work
    xP(isnan(yP))=[];
    yP(isnan(yP))=[];

    H.patch=patch(xP,yP,1,'facecolor',patchColor, ...
                  'edgecolor','none', ...
                  'facealpha',faceAlpha);

    %Make pretty edges around the patch.
    H.edge(1)=plot(x,lE,'-','color',edgeColor);
    H.edge(2)=plot(x,uE,'-','color',edgeColor);

    uistack(H.mainLine,'top') % Bring the main line to the top


function dataset = vl_svmdataset(x, varargin)
% VL_SVMDATASET  Construct advanced SVM dataset structure
%   DATASET = VL_SVMDATASET(X) wraps the matrix X into a dataset
%   structure. All the formats supported by VL_SVMTRAIN() are
%   suppported here as well.
%
%   DATASET = VL_SVMDATASET(X, 'homkermap', HOM) where HOM is a
%   structure with zero or more of the following fields: HOM.kernel,
%   HOM.order, HOM.window, HOM.gamma, HOM.period, See VL_HOMKERMAP()
%   for a discussion of these parameters. The effect is to use the
%   homogeneous kernel map to expand the data on the fly. This is
%   equivalent (albeit somewhat slower) to running VL_HOMKERMAP()
%   prior to learning. The main advantage is the significant memory
%   saving as the expanded data needs not to be stored in memory.
%
%   See:: VL_SVMTRAIN(), VL_HOMKERMAP(), VL_HELP().

% Author: Daniele Perrone and Andrea Vedaldi

opts.homkermap = [] ;
opts = vl_argparse(opts, varargin) ;

if issparse(x)
  error('X is a sparse matrix (sparse data will support be added in a future version.)') ;
end

if ~isa(x,'single') && ~isa(x,'double')
  error('X is neither SINGLE nor DOUBLE.') ;
end

sz = size(x) ;
if numel(sz) > 2
  error('X has more than two dimensions.') ;
end

dataset.data = x ;

if isstruct(opts.homkermap)
  if numel(opts.homkermap) ~= 1
    error('HOMKERMAP is not a singleton.') ;
  end
  ok = all(ismember(fieldnames(opts.homkermap), ...
                    {'kernel', 'order', 'window', 'gamma', 'period'})) ;
  if ~ok
    error('HOMKERMAP contains an unsupported field name.') ;
  end
  dataset.homkermap = opts.homkermap ;
elseif ~isempty(opts.homkermap)
    error('HOMKERMAP is not a structure nor []') ;
end


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

%% Keywords
%
% * febio_spec version 3.0
% * febio, FEBio
% * beam, gravity, body load
% * surface pressure boundary condition
% * hexahedral elements, hex8
% * beam, rectangular
% * static, solid
% * hyperelastic, Ogden
% * displacement logfile

%%

clear; close all; clc;

%% Plot settings
fontSize=20;
faceAlpha1=0.8;
markerSize=40;
markerSize2=20;
lineWidth=3;

%% 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=[febioFebFileNamePart,'.txt']; %FEBio log file name
febioLogFileName_disp=[febioFebFileNamePart,'_disp_out.txt']; %Log file name for exporting displacements

%Specifying dimensions and number of elements
beamWidth=0.1;
sampleWidth=beamWidth; %Width
sampleLength=6*beamWidth; %Thickness
sampleHeight=beamWidth; %Height
pointSpacings=0.025*ones(1,3); %Desired point spacing between nodes
numElementsWidth=round(sampleWidth/pointSpacings(1)); %Number of elemens in dir 1
numElementsThickness=round(sampleLength/pointSpacings(2)); %Number of elemens in dir 2
numElementsHeight=round(sampleHeight/pointSpacings(3)); %Number of elemens in dir 3

%Material parameter set
c1=1000; %Shear-modulus-like parameter
m1=8; %Material parameter setting degree of non-linearity
k_factor=1e2; %Bulk modulus factor
k=c1*k_factor; %Bulk modulus

%Determine load
sampleVolume=sampleWidth.*sampleLength.*sampleHeight;
sampleWeight=(sampleVolume.*1000);
gravityVector=[0 0 9.81.*sampleWeight];

% FEA control settings
numTimeSteps=10; %Number of time steps desired
max_refs=25; %Max reforms
max_ups=0; %Set to zero to use full-Newton iterations
opt_iter=6; %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-40;

%% Creating model geometry and mesh
% A box is created with tri-linear hexahedral (hex8) elements using the
% |hexMeshBox| function. The function offers the boundary faces with
% seperate labels for the top, bottom, left, right, front, and back sides.
% As such these can be used to define boundary conditions on the exterior.

% Create a box with hexahedral elements
beamDimensions=[sampleWidth sampleLength sampleHeight]; %Dimensions
beamElementNumbers=[numElementsWidth numElementsThickness numElementsHeight]; %Number of elements
outputStructType=2; %A structure compatible with mesh view
[meshStruct]=hexMeshBox(beamDimensions,beamElementNumbers,outputStructType);

%Access elements, nodes, and faces from the structure
E=meshStruct.elements; %The elements
V=meshStruct.nodes; %The nodes (vertices)
Fb=meshStruct.facesBoundary; %The boundary faces
Cb=meshStruct.boundaryMarker; %The "colors" or labels for the boundary faces
elementMaterialIndices=ones(size(E,1),1); %Element material indices

%%
% Plotting model boundary surfaces and a cut view

hFig=cFigure;

subplot(1,2,1); hold on;
title('Model boundary surfaces and labels','FontSize',fontSize);
gpatch(Fb,V,Cb,'k',faceAlpha1);
colormap(gjet(6)); icolorbar;
axisGeom(gca,fontSize);

hs=subplot(1,2,2); hold on;
title('Cut view of solid mesh','FontSize',fontSize);
optionStruct.hFig=[hFig hs];
meshView(meshStruct,optionStruct);
axisGeom(gca,fontSize);

drawnow;

%% Defining the boundary conditions
% The visualization of the model boundary shows colors for each side of the
% cube. These labels can be used to define boundary conditions.

%Define supported node set
logicFace=Cb==4; %Logic for current face set
Fr=Fb(logicFace,:); %The current face set
bcSupportList=unique(Fr(:)); %Node set part of selected face

%%
% Visualizing boundary conditions. Markers plotted on the semi-transparent
% model denote the nodes in the various boundary condition lists.

hf=cFigure;
title('Boundary conditions','FontSize',fontSize);
xlabel('X','FontSize',fontSize); ylabel('Y','FontSize',fontSize); zlabel('Z','FontSize',fontSize);
hold on;

gpatch(Fb,V,'kw','k',0.5);

hl(1)=plotV(V(bcSupportList,:),'k.','MarkerSize',markerSize);

legend(hl,{'BC support'});

axisGeom(gca,fontSize);
camlight headlight;
drawnow;

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

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

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

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

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

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

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

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

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

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

%Loads section
% -> Body load
febio_spec.Loads.body_load{1}.ATTR.type='const';
febio_spec.Loads.body_load{1}.x.ATTR.lc=1;
febio_spec.Loads.body_load{1}.x.VAL=gravityVector(1);
febio_spec.Loads.body_load{1}.y.ATTR.lc=1;
febio_spec.Loads.body_load{1}.y.VAL=gravityVector(2);
febio_spec.Loads.body_load{1}.z.ATTR.lc=1;
febio_spec.Loads.body_load{1}.z.VAL=gravityVector(3);

%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=',';

%% 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='external';%'internal';

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

%% Import FEBio results

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

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

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

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

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

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

    % Create basic view and store graphics handle to initiate animation
    hf=cFigure; %Open figure
    gtitle([febioFebFileNamePart,': Press play to animate']);
    title('Displacement magnitude [mm]','Interpreter','Latex')
    hp=gpatch(Fb,V_DEF(:,:,end),DN_magnitude,'k',1); %Add graphics object to animate
    hp.Marker='.';
    hp.MarkerSize=markerSize2;
    hp.FaceColor='interp';
    gpatch(Fb,V,0.5*ones(1,3),'k',0.25); %A static graphics object

    axisGeom(gca,fontSize);
    colormap(gjet(250)); colorbar;
    caxis([0 max(DN_magnitude)]);
    axis(axisLim(V_DEF)); %Set axis limits statically
    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_magnitude=sqrt(sum(N_disp_mat(:,:,qt).^2,2)); %Current displacement magnitude

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

end

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

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


function OUT = xcorr_multisubject(data, varargin)
% Cross-correlation and partial correlation matrices for 3-D data, i.e., a cell array of subject data matrices
%
% :Usage:
% ::
%
%     OUT = xcorr_multisubject(data, [optional inputs])
%
% ..
%     Author and copyright information:
%     -------------------------------------------------------------------------
%     Copyright (C) 2009 Tor Wager
%
%     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/>.
% ..
%
% :Inputs:
%
%   **data:**
%        A cell array, one cell per subject/replicate, of n x k
%        data to be inter-correlated.
%
% :Optional Inputs:
%
%   **'partialr':**
%        Use partial correlations obtained via ridge regression (k = 1 fixed)
%
%   **'shift_by':**
%        Followed by integer value for max number of time points to shift
%
% :Output:
%
%   **OUT:**
%        A structure containing subject correlation matrices, the mean
%        matrix, and raw and FDR-thresholded group matrix
%
% :Examples:
% ::
%
%    % cl cell structure:
%    for i = 1:length(clpos_data), data{i} = cat(2, clpos_data{i}.timeseries); end
%
%    % cl structure:
%    for i = 1:size(cl(1).all_data, 2), for c = 1:length(cl), data{i}(:,c) = cl(c).all_data(:, i); end, end
%
%    % parcel_cl_avgs or clpos_data2 structure:
%    for i = 1:length(parcel_cl_avgs), for j = 1:N, data{j}(:,i) = parcel_cl_avgs(i).timeseries{j}; end, end
%
%    create_figure('Xcorr', 1, 3);
%    imagesc(OUT.stats.mean);
%    subplot(1, 3, 2);
%    imagesc(OUT.stats.sig);
%    subplot(1, 3, 3);
%    imagesc(OUT.stats.fdrsig);
%    colormap gray
%
% Example of MDS and plotting total (not decomposed) relationships:
% ::
%
%    OUT.stats.D = (1 - OUT.stats.mean) ./ 2;
%    [OUT.stats_mds.GroupSpace,OUT.stats_mds.obs,OUT.stats_mds.implied_dissim] = shepardplot(OUT.stats.D,[]);
%    OUT.stats_mds = nmdsfig_tools('cluster_solution',OUT.stats_mds, OUT.stats_mds.GroupSpace, 2:5, 1000, []);
%    nmdsfig(OUT.stats_mds.GroupSpace,'classes',OUT.stats_mds.ClusterSolution.classes,'names',OUT.stats_mds.names,'sig',OUT.stats.fdrsig);
%
% Example of MDS and plotting direct relationships:
% ::
%
%    OUT.ridge = matrix_direct_effects_ridge(data);
%    D = OUT.ridge.mean; D(find(eye(size(D)))) = 1;
%    D = (D' + D) ./ 2;
%    OUT.ridge.D = (1 - D) ./ 2;
%    [OUT.stats_mds.GroupSpace,OUT.stats_mds.obs,OUT.stats_mds.implied_dissim] = shepardplot(OUT.ridge.D,[]);
%    OUT.stats_mds = nmdsfig_tools('cluster_solution',OUT.stats_mds, OUT.stats_mds.GroupSpace, 2:10, 1000, []);
%    nmdsfig(OUT.stats_mds.GroupSpace,'classes',OUT.stats_mds.ClusterSolution.classes,'names',OUT.stats_mds.names,'sig',OUT.ridge.fdrsig);
%    hh = nmdsfig_fill(OUT.stats_mds);
%    axis image, axis equal
%
%    OUT.stats_mds = nmdsfig_tools('cluster_solution',OUT.stats_mds, OUT.stats_mds.GroupSpace, 2:5, 1000, []);
%
%    % data is cell, one cell per subject
%    [OUT.stats_mds.GroupSpace,OUT.stats_mds.obs,OUT.stats_mds.implied_dissim] = shepardplot(OUT.stats.D,[]);
%    OUT.stats_mds = nmdsfig_tools('cluster_solution',OUT.stats_mds, OUT.stats_mds.GroupSpace, 2:5, 1000, []);
%
% See also:
% ttest3d, plot_correlation_matrix -- for more compact ways of estimating
% and plotting correlation matrices. See also cellfun and canlab_mat2cell
% for conversion options.

% ..
%    Defaults
% ..
shift_by = 0;   % currently, if shift_by = 1, runs cross-correls and returns betas
robustflag = 0; % used if shift_by > 0, can do robust correlations
dopartialr = 0; % partial correlations
betaflag = 1;   % used if shift_by > 0, return betas instead of correlation
nconditions = 1; % fixed at 1 now

% optional inputs with default values
% -----------------------------------

for i = 1:length(varargin)
    if ischar(varargin{i})
        switch varargin{i}

            case 'partialr', dopartialr = 1;
            case 'shift_by', shift_by = varargin{i+1}; varargin{i+1} = [];

                %case 'basistype', basistype = varargin{i+1}; varargin{i+1} = [];

                %otherwise, warning(['Unknown input string option:' varargin{i}]);
        end
    end
end

fprintf(1,'Multi-subject cross correlation\n')

if shift_by
    fprintf(1,'Estimating time-shifted (cross-lagged) correlations\n')

elseif dopartialr
    fprintf(1,'Estimating partial correlations\n')
end

fprintf('\t   ')

warning off     % for robustfit iteration limit

numsub = length(data);

for i = 1:numsub            %size(DATA.dat,3);

    subjdat = data{i};
    m = size(subjdat, 2);

    fprintf(1,'\b\b\b%03d', i);

    warning off

    for n=1:nconditions

        if shift_by > 0

            if betaflag
                betastr = 'max_cross_lagged_beta'; % or corr
            else
                betastr = 'max_cross_lagged_correlation';
            end

            for j = 1:m - 1
                for k = j + 1 : m
                    % now can handle shift by 0 in shift_correl

                    [sval,myc, mylat, myxc] = shift_correl(subjdat(:,j), subjdat(:,k), shift_by, robustflag, betaflag);

                    if isempty(mylat), mylat = NaN; end

                    nxl(j,k) = mylat;
                    nxc(j,k) = myxc;
                end
            end
        elseif dopartialr
            betastr = 'partial_correlation';
            nxc = calc_partial_r(subjdat);
            nxl = [];

        else % %if there's no shift by; fastest
            betastr = 'correlation';
            nxc = corr(subjdat);
            nxl = [];
        end

        warning on

        if shift_by > 0
            % adjust matrices
            nxc(end+1,:) = 0;
            nxc=nxc + nxc' + eye(size(nxc,1));

            nxl(end+1,:) = 0;
            nxl=nxl+nxl';

        end

        OUT.metric_returned = betastr;
        OUT.shift_by = shift_by;
        OUT.shift_explanation = '0 for no latency est., n for cross-correlations shifting up to n time points forward/back';

        OUT.pairwise_assoc{n}(:,:,i) = nxc;
        clear nxc;

        OUT.latency{n}(:,:,i)  = nxl;
        clear nxl;

    end         % condition loop

end             % subject loop

fprintf('\n');

fprintf('stats...')
[mxc,t,sig,OUT.stats] = ttest3d(OUT.pairwise_assoc{1});

t = OUT.stats.t .* abs(OUT.stats.fdrsig);
t = (t + t') ./ 2;
OUT.stats.fdr_thresholded_tvalues = t;

fprintf('\n');

end % Main function

function [b p] = calc_partial_r(X)

X = zscore(X);

p = [];

for i = 1:size(X, 2)
    y = X(:, i);
    xx = X;
    xx(:, i) = 1;  % intercept; need it, and also placeholder

    % ols version
    b(:, i) = xx \ y;
    b(i, i) = 1;        % use 1 for self, not intercept

    % ridge version
    % note: we have double intercept...
    b(:, i) = ridge(y, xx, 1);
    b(i, i) = 1;        % use 1 for self, not intercept

    %create_figure; plot(b(:, i)); hold on; plot(b1, 'r'); drawnow; pause(.05)

end

end % function


function nframe=eyematch(frame,thresh,template);

[face_a,skin_region]=face(frame);

im1 = double(rgb2gray(face_a));
img=im1-mean(mean(im1));
template=template-mean(mean(template));

C=normxcorr2(template,img);
Csub = C((size(template,1)-1)/2+1:size(img,1)-1,(size(template,2)-1)/2+1:size(img,2)-1);
figure;
% imshow(Csub, []), pixval;

BW = Csub;
BW(find(BW<thresh))=0;
BW(find(BW>thresh))=1;
% figure, imshow(BW);

[L,n] = bwlabel(BW);
stats = regionprops(L, 'centroid');
% Draw an asterisk

figure(1);imshow(frame);
centroids = cat(1, stats.Centroid);
hold on
plot(centroids(:,1), centroids(:,2), 'r*');
hold off


function drawPolyFromVertices(c, color, varargin)

if isempty(c)
  return
end

k = convhull(c(1,:), c(2,:), c(3,:));
X = reshape(c(1,k'), size(k'));
Y = reshape(c(2,k'), size(k'));
Z = reshape(c(3,k'), size(k'));
plot3(X,Y,Z,color)
fill3(X,Y,Z,color, 'FaceAlpha', 0.5, varargin{:})


function [indic, xlevels] = condf2indic(X, varargin)
% Create N x k indicator matrix of ones/zeros from N x 1 list of numeric
% values (X)
%
% :Usage:
% ::
%
%     [indic, xlevels] = condf2indic(X, ['integers'])
%
% :Inputs:
%
%   **'integers':**
%       Treat X as integer vector. Check that all are integers, and return
%       one column per integer in order, excluding zeros. Insert NaNs in
%       columns whose corresponding integers are missing.  Returns an n x k
%       matrix indic, where n is size(X, 1) and k is max(X).
%
%       'integers' may be followed by another variable specifying the
%       number of columns to use. this is useful because integers at the
%       end of a list in X may be missing; this will append columns for
%       those.
%
% :Outputs:
%
%   **indic:**
%        is returned as single precision type, because it can then be
%        used as a design matrix in a GLM
%
%   **xlevels:**
%        are the values of X corresponding to columns of indic
%
% :Examples:
% condf = [1 1 1 2 2 2 4 4 4 6 6 1 1 1 8 8]';
% [indic, xlevels] = condf2indic(condf); indic, xlevels
% [indic, xlevels] = condf2indic(condf, 'integers'); indic, xlevels
% [indic, xlevels] = condf2indic(condf, 'integers', 10); indic, xlevels

% ..
%    tor wager, nov 2007. Edited Feb 2018 to expand functionality to
%    'integers' case, for use with atlas object.
%    Aug 2018: fixed some inconsistencies in 'integers' option.
% ..

% PRELIM CALCULATIONS

X = double(X); % for objects/special types

[xlevels, ~, indx] = unique(X);

max_integers = length(xlevels);

% if X contains only zero values, return
if ~any(X)
    indic=[];
    return;
end

% INPUTS

dointegers = false;

if any(strcmp(varargin, 'integers'))

    dointegers = true;

    wh_input = strcmp(varargin, 'integers');

    if length(varargin) > find(wh_input)      % we have entered max integers

        max_integers = varargin{wh_input + 1};

    else

        max_integers = max(xlevels);

    end

end

% INITIALIZE - cols equal to num unique entries, or all integers

indic = single(false(length(indx), max_integers));

if dointegers

    % Check integers
    u = unique(X);
    if ~all(u == round(u))
        warning('Some condition function values are not integers.');
    end

    % Remove zero-valued integer
    wh = find(xlevels == 0);
    if ~isempty(wh)
        xlevels(wh) = [];
        indic(:, wh) = [];
        badIndx = indx(find(indx == wh, 1, 'first'));
        indx(indx == wh) = 0;
        indx(indx > badIndx) = indx(indx > badIndx) - 1;
    end

    for i = 1:length(xlevels)
        indic(indx == i, xlevels(i)) = 1;
    end

    xlevels = (1:max_integers)';
%
%     % if codes are 1...n, xlevels is index values...but if there are
%     % missing integers, need to insert into indic
%
%     is_missing = true(max(X), 1);
%     is_missing(xlevels) = false;
%
%     % Insert NaNs for any missing index values.
%
%     indic = naninsert(is_missing, indic')';

else
    % no integers, do not preserve empty columns

    for i = 1:length(xlevels)
        indic(indx == i, i) = 1;
    end

end % integers

end % main function


% SP_EVAL: Compute the value or the derivatives of a function, given by its degrees of freedom, at a given set of points.
%
%   [eu, F] = sp_eval (u, space, geometry, pts, [options]);
%   [eu, F] = sp_eval (u, space, geometry, npts, [options]);
%
% INPUT:
%
%     u:           vector of dof weights
%     space:       object defining the discrete space (see sp_scalar)
%     geometry:    geometry structure (see geo_load)
%     pts:         cell array with coordinates of points along each parametric direction
%     npts:        number of points along each parametric direction
%     options:     cell array with the fields to plot
%                   accepted options are 'value' (default), 'gradient' and 'laplacian'
%
% OUTPUT:
%
%     eu: cell-array with the fields evaluated at the given points
%     F:  grid points in the physical domain, that is, the mapped points
%
% Copyright (C) 2009, 2010 Carlo de Falco
% Copyright (C) 2011, 2012, 2014, 2015, 2018 Rafael Vazquez
%
%    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 [eu, F] = sp_eval (u, space, geometry, npts, options)

  if (numel (u) ~= space.ndof)
    error ('The number of degrees of freedom of the vector and the space do not match')
  end

  if (nargin < 5)
    options = {'value'};
  end
  if (~iscell (options))
    options = {options};
  end
  nopts = numel (options);

  ndim = numel (space.knots);

  endpoints = zeros (2, ndim);
  if (isfield (geometry, 'nurbs'))
    nurbs = geometry.nurbs;
    if (ndim == 1)
      nurbs.knots = {nurbs.knots};
    end
    for idim=1:ndim
      endpoints(:,idim) = nurbs.knots{idim}([nurbs.order(idim), end-nurbs.order(idim)+1]);
    end
    clear nurbs
  elseif (isfield (struct(space), 'knots'))
    degree = space.degree;
    for idim=1:ndim
      endpoints(:,idim) = space.knots{idim}([degree(idim)+1, end-degree(idim)]);
    end
  else
    endpoints(2,:) = 1;
  end

  if (iscell (npts))
    pts = npts;
    npts = cellfun (@numel, pts);
  elseif (isvector (npts))
    if (numel (npts) == 1)
      npts = npts * ones (1,ndim);
    end
    for idim = 1:ndim
      pts{idim} = linspace (endpoints(1,idim), endpoints(2,idim), npts(idim));
    end
  end

  for jj = 1:ndim
    pts{jj} = pts{jj}(:)';
    if (numel (pts{jj}) > 1)
      brk{jj} = [endpoints(1,jj), pts{jj}(1:end-1) + diff(pts{jj})/2, endpoints(2,jj)];
    else
      brk{jj} = endpoints(:,jj).';
    end
  end

  msh = msh_cartesian (brk, pts, [], geometry, 'boundary', false);
  sp  = space.constructor (msh);

  value = false; grad = false; laplacian = false; hessian = false;

  for iopt = 1:nopts
    switch (lower (options{iopt}))
      case 'value'
        eu{iopt} = zeros (msh.nqn, msh.nel);
        eunum{iopt} = {1:msh.nqn};
        eusize{iopt} = npts;
        value = true;

      case 'gradient'
        eu{iopt} = zeros (msh.rdim, msh.nqn, msh.nel);
        eunum{iopt} = {1:msh.rdim, 1:msh.nqn};
        eusize{iopt} = [msh.rdim, npts];
        grad = true;

      case 'laplacian'
        eu{iopt} = zeros (msh.nqn, msh.nel);
        eunum{iopt} = {1:msh.nqn};
        eusize{iopt} = npts;
        laplacian = true;

      case 'hessian'
        eu{iopt} = zeros (msh.rdim, msh.rdim, msh.nqn, msh.nel);
        eunum{iopt} = {1:msh.rdim, 1:msh.rdim, 1:msh.nqn};
        eusize{iopt} = [msh.rdim, msh.rdim, npts];
        hessian = true;
    end
  end

  F = zeros (msh.rdim, msh.nqn, msh.nel);

  for iel = 1:msh.nel_dir(1)
    msh_col = msh_evaluate_col (msh, iel);
    sp_col  = sp_evaluate_col (sp, msh_col, 'value', value, 'gradient', grad, ...
          'laplacian', laplacian, 'hessian', hessian);

    eu_aux = sp_eval_msh (u, sp_col, msh_col, options);

    F(:,:,msh_col.elem_list) = msh_col.geo_map;
    for iopt = 1:nopts
      eu{iopt}(eunum{iopt}{:},msh_col.elem_list) = eu_aux{iopt};
    end
  end

  F = reshape (F, [msh.rdim, npts]);
  for iopt = 1:nopts
    eu{iopt} = reshape (eu{iopt}, [eusize{iopt}, 1]); % The extra 1 makes things work also in 1D
  end

  if (nopts == 1)
    eu = eu{1};
  end
end


function imageOut = rescaleImage(image,scale)
%rescales an image

    s = size(image);
    s2 = round(s*scale);

    if min(s == s2) == 1

        imageOut = image;

    else

        if scale > 1

            startIdx = floor((s2 - s)/2);
            imageOut = imresize(image,s2);
            imageOut = imageOut((1:s(1))+startIdx(1),(1:s(2))+startIdx(2));

        else

            startIdx = floor((s - s2)/2);
            image2 = imresize(image,s2);
            imageOut = uint8(zeros(s));
            imageOut((1:s2(1)) + startIdx(1),(1:s2(2)) + startIdx(2)) = image2;

        end

    end


function [favar]=favar_fevdols(gamma_record,It,Bu,n,IRFperiods,FEVDband,favar)

% function [fevd_estimates]=bear.olsfevd(irf_estimates,IRFperiods,gamma,n,endo,datapath)
% computes and displays fevd values for the OLS VAR model
% inputs:  - cell 'irf_estimates': lower bound, point estimates, and upper bound for the IRFs
%          - integer 'IRFperiods': number of periods for IRFs
%          - matrix 'gamma': structural disturbance variance-covariance matrix (defined p 48 of technical guide)
%          - integer 'n': number of endogenous variables in the BVAR model (defined p 7 of technical guide)
%          - cell 'endo': list of endogenous variables of the model
%          - string 'datapath': user-supplied path to excel data spreadsheet
% outputs: - cell 'fevd_estimates': lower bound, point estimates, and upper bound for the FEVD

% preliminary tasks
npltX=favar.npltX;
npltXshck=favar.IRF.npltXshck;

%relevant loadings of restricted information variables
L=favar.L(favar.plotX_index,favar.IRF.plotXshock_index);
% gamma=gamma(:,favar.FEVD.plotXshock_index);
% % scale gamma, irf estimates are already scaled
%         for ii=1:npltX
%             for ll=1:npltXshck
%                 favar_gamma{ii}(:,ll)=L(ii,ll)*gamma(:,ll);
%             end
%         end

% create the first cell
temp=cell(npltX,npltXshck+1);

% start by filling the first column of every Tij matrix in the cell
% loop over rows of temp
for jj=1:npltX
   % loop over columns of temp
   for ii=1:npltXshck
   % square each element
   temp{jj,ii}(:,1)=favar.IRF.favar_irf_estimates{jj,ii}(:,1).^2;
   end
end
% fill all the other entries of the Tij matrices
% loop over rows of temp
for jj=1:npltX
   % loop over columns of temp
   for ii=1:npltXshck
      % loop over remaining columns
      for kk=2:IRFperiods
      % define the column as the square of the corresponding column in orthogonalised_irf_record
      % additioned to the value of the preceeding columns, which creates the cumulation
      temp{jj,ii}(:,kk)=favar.IRF.favar_irf_estimates{jj,ii}(:,kk).^2+temp{jj,ii}(:,kk-1);
      end
   end
end

% multiply each matrix in the cell by the variance of the structural shocks
% to do so, loop over simulations (rows of the Tij matrices)
for kk=1:It-Bu
% recover the covariance matrix of structural shocks gamma for this iteration
gamma=reshape(gamma_record(:,kk),n,n);

gamma=gamma(:,favar.IRF.plotXshock_index);
% scale gamma, irf estimates are already scaled
        for ii=1:npltX
            for ll=1:npltXshck
                favar_gamma{ii}(:,ll)=L(ii,ll)*gamma(:,ll);
            end
        end

% loop over rows of temp
for ii=1:npltX
% loop over columns of temp
   for jj=1:npltXshck
   % multiply column jj of the matrix by the variance of the structural shock
   temp{ii,jj}(1,:)=temp{ii,jj}(1,:)*favar_gamma{ii}(jj,jj);
   end
end
end

% obtain now the values for Ti, the (n+1)th matrix of each row
% loop over rows of temp
for ii=1:npltX
% start the summation over Tij matrices
temp{ii,npltXshck+1}=temp{ii,1};
   % sum over remaining columns
   for jj=2:npltXshck
   temp{ii,npltXshck+1}=temp{ii,npltXshck+1}+temp{ii,jj};
   end
end

% create the output cell fevd_record
favar_fevd_record=cell(npltX,npltXshck);
% fill the cell
% loop over rows of fevd_estimates
for ii=1:npltX
   % loop over columns of fevd_estimates
   for jj=1:npltXshck
   % define the matrix Vfij as the division (pairwise entry) of Tfij by Tfj
   favar_fevd_record{ii,jj}=temp{ii,jj}./temp{ii,npltXshck+1};
   end
end

%% create the FEVD estimates output
% create first the cell that will contain the estimates
favar_fevd_estimates=cell(npltX,npltXshck);

% for each variable and each variable contribution along with each period, compute the median, lower and upper bound from the Gibbs sampler records
% consider variables in turn
for ii=1:npltX
   % consider contributions in turn
   for jj=1:npltXshck
      % consider periods in turn
      for kk=1:IRFperiods
      % compute first the lower bound
      favar_fevd_estimates{ii,jj}(1,kk)=quantile(favar_fevd_record{ii,jj}(:,kk),(1-FEVDband)/2);
      % then compute the median
      favar_fevd_estimates{ii,jj}(2,kk)=quantile(favar_fevd_record{ii,jj}(:,kk),0.5);
      % finally compute the upper bound
      favar_fevd_estimates{ii,jj}(3,kk)=quantile(favar_fevd_record{ii,jj}(:,kk),1-(1-FEVDband)/2);
      end
   end
end

%save output
favar.FEVD.favar_fevd_estimates=favar_fevd_estimates;

% % % % finally, save on excel
% % % if pref.results==1
% % % % create the cell that will be saved on excel
% % % fevd_estimates=fevd_estimates';
% % % fevdcell={};
% % % % build preliminary elements: space between the tables
% % % horzspace=repmat({''},2,3*n);
% % % vertspace=repmat({''},IRFperiods+3,1);
% % % % loop over variables (vertical dimension)
% % % for ii=1:n
% % % tempcell={};
% % %    % loop over shocks (horizontal dimension)
% % %    for jj=1:n
% % %    % create cell of fevd record for variable ii in response to shock jj
% % %    temp=['part of ' endo{ii,1} ' fluctuation due to ' endo{jj,1} ' shocks'];
% % %    fevd_ij=[temp {''};{''} {''};{''} {'median'};num2cell((1:IRFperiods)') num2cell((fevd_estimates{ii,jj})')];
% % %    tempcell=[tempcell fevd_ij vertspace];
% % %    end
% % % fevdcell=[fevdcell;horzspace;tempcell];
% % % end
% % % % trim
% % % fevdcell=fevdcell(3:end,1:end-1);
% % % % write in excel
% % %     xlswrite(fullfile(pref.results_path, [pref.results_sub '.xlsx']),fevdcell,'FEVD','B2');
% % % end


function [ events ] = getEventsFromPlugData(dataset, household, appliance_id, evaluation_days, granularity, filter)

    % get ground truth from plug-level data
    events = [];

    p_edgeThreshold = filter.p_edgeThreshold;
    p_filtering = filter.p_filtering;
    p_filtLength = filter.p_filtLength;

    % detect events in plug data
    appliance_consumption = read_plug_data(dataset, household, appliance_id, evaluation_days, granularity);
    function_handle = str2func(p_filtering);
    appliance_consumption_filtered = function_handle(appliance_consumption, p_filtLength);
    diff_consumption = diff(appliance_consumption_filtered);
    edges = abs(diff_consumption) > p_edgeThreshold;
    events_start_time = find(diff(edges) == 1) + 1;
    events_end_time = find(diff(edges) == -1) + 1;

%     % skip appliance if the number of events is too low
%     if length(events_start_time) < 2 || length(events_end_time) < 2
%         continue;
%     end

    % make sure that the events' end and start time are correct
    if events_end_time(1) < events_start_time(1)
        events_end_time = events_end_time(2:end);
    end
    if events_end_time(end) < events_start_time(end)
        events_start_time = events_start_time(1:end-1);
    end

    % only slect significant events
    idx_siginificant_events = find(events_start_time(2:end) - events_end_time(1:end-1) > 2);
    events_start_time = events_start_time([1, 1+idx_siginificant_events]);
    events_end_time = events_end_time([idx_siginificant_events, end]);

    % compute change in power caused by events
    power_change = appliance_consumption_filtered(1, events_end_time) - appliance_consumption_filtered(1, events_start_time);

    % ignore events that last too long ( > 60 seconds)
    idx_valid_events = events_end_time - events_start_time < 60;

    % store the ground truth (events in plug data)
    events = [events; events_start_time(idx_valid_events)', events_end_time(idx_valid_events)', power_change(idx_valid_events)'];
end


%drawCrackPattern : dessine un motif de fissures
%
%
%   ---------
%
%   author : David Legland
%   INRA - TPV URPOI - BIA IMASTE
%   created the 15/08/2005.

%% Initialisations

% size of window
window = [0 100 0 100];

% box as polygon
box = [0 0;100 0;100 100;0 100];

% points density
lambda = .005;

%% compute diagram

% number of points
Np = round((window(2)-window(1))*(window(4)-window(3)) * lambda);

% points coordinate
x = rand(Np, 1)*(window(2)-window(1)) + window(1);
y = rand(Np, 1)*(window(4)-window(3)) + window(3);
points = [x y];

% random angles
angles = rand(Np, 1)*pi;

% compute crack pattern
edges = crackPattern(box, points, angles);

%% Draw Result

% create figure
figure(1); clf;
axis(window);hold on;

% draw diagram
drawEdge(edges);
drawPoint(points, 'bo');

% clean up window
set(gca, 'box', 'on');
set(gca, 'xtick', []);
set(gca, 'ytick', []);


report_this_filefun(mfilename('fullpath'));

clf
[X,Y,Z] = meshgrid(gx,gy,gz);
v = [];
main = [ -174.83 51.412 33];
i = 0.05
ii = 0.05
for i3 = z0:1*dz:z1
    l = loc(3,:) == i3;
    re3 = reshape(as(l),length(gy),length(gx));
    r = reshape(loc(4,l),length(gy),length(gx));
    l = r > tresh;
    re3(l) = zeros(1,length(find(l)))*nan;
    rect = [i ii 0.15 0.15];
    i = i+0.20;
    if i > 0.9 ; i = 0.05 ; ii = ii + 0.20; end
    axes('position',rect)
    pcolor(gx,gy,re3)
    caxis([min(as) max(as)])
    colormap(jet)
    title([ 'Depth ' num2str(i3) ' km'], 'FontSize',8)
    set(gca,'FontSize',8')

    hold on
    l = a.Depth > i3-dz/2 & a.Depth < i3+dz/2;
    plot3(a(l,1),a(l,2),a(l,7)*0,'k.')
    shading interp
    % axis('off')
    pl =plot3(main(:,1),main(:,2),main(:,3)*0,'xk');
    set(pl,'LineWidth',2)
    hold on

end


function [mResult, mResult2]=calc_pwtime(a,fMinTime, fMaxTime, fTstep, timef,bootloops,maepi, nMod)
% function [mResult] = calc_pwtime(a,fMinTime, fMaxTime, fTstep, timef,bootloops,maepi, nMod);
% -------------------------------------------------------------------------
% Calculate and plot p,c,k-value evolution with time
%
% Input variables:
% a         : earthquake catalog
% fMinTime  : Starting time after mainshock to calculate Omori-parameters
%             in days
% fMaxTime  : End time after mainshock to calculate Omori-parameters
%             in days
% fTstep    : Time step length fMinTime:fTstep:fMaxTime [days]
% timef     : dummy for forecast period, usually =1
% bootloops : Number of bootstraps
% maepi     : mainshock
% nMod      : Models to fit aftershock sequence
%
% j.woessner@sed.ethz.ch
% last update: 29.09.2004

% Surpress warnings from fmincon
warning off;

% Initialize
mResult = [];
mResult2 = [];

% Time loop
for time = fMinTime:fTstep:fMaxTime
    %[m_main, main] = max(a.Magnitude);
    date_matlab = datenum(a.Date.Year,a.Date.Month,a.Date.Day,a.Date.Hour,a.Date.Minute,zeros(size(a,1),1));
    date_main = datenum(floor(maepi(3)),maepi(4),maepi(5),maepi(8),maepi(9),0);
    time_aftershock = date_matlab-date_main;
    % Select biggest aftershock earliest in time, but more than 1 day after mainshock
    fDay = 1;
    ft_c=fDay/365; % Time not considered to find biggest aftershock
    vSel = (a.Date > maepi(:,3)+ft_c & a.Date<= maepi(:,3)+time/365);
    mCat = a.subset(vSel);
    vSel = mCat(:,6) == max(mCat(:,6));
    vBigAf = mCat(vSel,:);
    if length(mCat(:,1)) > 1
        vSel = vBigAf(:,3) == min(vBigAf(:,3));
        vBigAf = vBigAf(vSel,:);
    end

    date_biga = datenum(floor(vBigAf(3)),vBigAf(4),vBigAf(5),vBigAf(8),vBigAf(9),0);
    fT1 = date_biga - date_main; % Time of big aftershock

    % Aftershock times
    l = time_aftershock(:) > 0;
    tas = time_aftershock(l);
    eqcatalogue = a.subset(l);

    % time_as: Learning period
    l = tas <= time;
    time_as=tas(l);
    if length(time_as) > 50

        % Times up to the forecast time
        lf = tas <= time+timef ;
        time_asf= [tas(lf) ];
        time_asf=sort(time_asf);

        % Calculate uncertainty and mean values of p,c,and k
        [mMedModF, mStdL, loopout] = brutebootloglike_a2(time_as, time_asf, bootloops,fT1,nMod);
        pmed1 = mMedModF(1,1);
        pstd1 = mMedModF(1,2);
        pmed2 = mMedModF(1,3);
        pstd2 = mMedModF(1,4);
        cmed1 = mMedModF(1,5);
        cstd1 = mMedModF(1,6);
        cmed2 = mMedModF(1,7);
        cstd2 = mMedModF(1,8);
        kmed1 = mMedModF(1,9);
        kstd1 = mMedModF(1,10);
        kmed2 = mMedModF(1,11);
        kstd2 = mMedModF(1,12);

        % Compute model according to model choice
        if nMod == 1
            [pval1, pval2, cval1, cval2, kval1, kval2, fAIC, fL] = bruteforceloglike_a2(time_as,fT1,nMod);
        elseif nMod == 2
            [pval1, pval2, cval1, cval2, kval1, kval2, fAIC, fL] = bruteforceloglike_a2(time_as,fT1,nMod);
        elseif nMod == 3
            [pval1, pval2, cval1, cval2, kval1, kval2 , fAIC, fL] = bruteforceloglike_a2(time_as,fT1,nMod);
        else
            [pval1, pval2, cval1, cval2, kval1, kval2, fAIC, fL] = bruteforceloglike_a2(time_as,fT1,nMod);
        end

        % Calculate aftershock sequence ...
        cumnrf = (1:length(time_as))';
        cumnr_modelf = [];
        if nMod == 1
            for i=1:length(time_as)
                if pval1 ~= 1
                    cm = kval1/(pval1-1)*(cval1^(1-pval1)-(time_as(i)+cval1)^(1-pval1));
                else
                    cm = kval1*log(time_as(i)/cval1+1);
                end
                cumnr_modelf = [cumnr_modelf; cm];
            end % END of FOR on length(time_as)
        else
            for i=1:length(time_as)
                if time_as(i) <= fT1
                    if pval1 ~= 1
                        cm = kval1/(pval1-1)*(cval1^(1-pval1)-(time_as(i)+cval1)^(1-pval1));
                    else
                        cm = kval1*log(time_as(i)/cval1+1);
                    end
                    cumnr_modelf = [cumnr_modelf; cm];
                else
                    if (pval1 ~= 1 & pval2 ~= 1)
                        cm = kval1/(pval1-1)*(cval1^(1-pval1)-(time_as(i)+cval1)^(1-pval1))+ kval2/(pval2-1)*(cval2^(1-pval2)-(time_as(i)-fT1+cval2)^(1-pval2));
                    else
                        cm = kval1*log(time_as(i)/cval1+1) + kval2*log((time_as(i)-fT1)/cval2+1);
                    end
                    cumnr_modelf = [cumnr_modelf; cm];
                end; %END of IF on fT1
            end; % End of FOR length(time_as)
        end; % End of if on nMod
        time_as=sort(time_as);
        cumnr_modelf=sort(cumnr_modelf);

        % Calculate KSTEST2 as a measure of the goodness of fit
        [H,P,KSSTAT] = kstest2(cumnr_modelf,cumnrf);

        % Calculate RMS
        i=(1:1:length(time_as))';
        fRMS = (sum((i-cumnr_modelf).^2)/length(i))^0.5;

        % Result matrix
        mResult = [mResult; time pval1 pval2 cval1 cval2 kval1 kval2 fAIC fL H P KSSTAT fRMS];
        mResult2 = [mResult2; pmed1 pstd1 pmed2 pstd2 cmed1 cstd1 cmed2 cstd2 kmed1 kstd1 kmed2 kstd2];
    else
        mResult = [mResult; NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN];
        mResult2 = [mResult2; NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ];
    end % ENDIF on length(time_as)
end % FOR time

%save Result_pwtime.mat mResult mResult2;

% figure_w_normalized_uicontrolunits('tag','p-value time series', 'visible','on')
% hPplot4 = plot(mResult(:,1),mResult2(:,1));
% hold on
% hPplot=plot(mResult(:,1),mResult(:,2),'-k','Linewidth',2)
% hPplot2 = plot(mResult(:,1),mResult2(:,1)+mResult2(:,2));
% hPplot3 = plot(mResult(:,1),mResult2(:,1)-mResult2(:,2));
% set(hPplot2,'Linestyle','--','Linewidth',2,'Color',[0.5 0.5 0.5]);
% set(hPplot3,'Linestyle','--','Linewidth',2,'Color',[0.5 0.5 0.5]);
% set(hPplot4,'Linestyle','--','Linewidth',2,'Color',[0.5 0.5 0.5]);
% set(hPplot,'Linewidth',2)
% xlabel('Time after mainshock [days]','Fontweight','bold','FontSize',12)
% ylabel('p-value','Fontweight','bold','FontSize',12)
% set(gca,'Fontweight','bold','FontSize',12,'Box','on','Tickdir','out')

% Smoothing the plot
nWindowSize = 5;
figure_w_normalized_uicontrolunits('tag','p-value time series smooth', 'visible','on')
mPmean = filter(ones(1,nWindowSize)/nWindowSize,1,mResult2(:,1));
mPmean(1:nWindowSize,1)=mResult2(1:nWindowSize,1);
mPstd1 = filter(ones(1,nWindowSize)/nWindowSize,1,mResult2(:,2));
mPstd1(1:nWindowSize,1)=mResult2(1:nWindowSize,2);

mP = filter(ones(1,nWindowSize)/nWindowSize,1,mResult(:,2));
mP(1:nWindowSize,1)=mResult(1:nWindowSize,2);
% Plotting
hp1=plot(mResult(:,1),mPmean,'--','Linewidth',2,'Color',[0.3 0.3 0.3]);
hold on;
hp2=plot(mResult(:,1),mPmean-mPstd1,'-.','Linewidth',2,'Color',[0.5 0.5 0.5]);
plot(mResult(:,1),mPmean+mPstd1,'-.','Linewidth',2,'Color',[0.5 0.5 0.5]);
hPplot=plot(mResult(:,1),mResult(:,2),'-k','Linewidth',2)
ylabel('p-value','Fontweight','bold','FontSize',12)
% xlim([(min(mResult(:,1))) (max(mResult(:,1)))])
% ylim([floor(min(mP(:,1))) ceil(max(mP(:,1)))])
xlabel('Time / [days after main shock]','Fontweight','bold','FontSize',12)
l1=legend([hp1 hp2 hPplot],'p-value (mean)','\sigma p','p-value');
set(l1,'Fontweight','bold')
set(gca,'Fontweight','bold','FontSize',10,'Linewidth',2,'Tickdir','out')


% Demo for phase-space reduction (cf. Centre-Manifold theory): In this
% example we show that Generalised filtering can be used to approximate the
% dynamics on the Centre-Manifold of a chaotic system. This example uses a
% nominal polynomial for the reduced dynamics (cf, order parameters) and
% exploits parameter optimisation to learn their coefficients. The approach
% appeals to Centre Manifold Theory and the enslaving principle by assuming
% that stable modes collapse sufficiently quickly to be treated as random
% fluctuations. This means that the unstable (slow modes or patterns)
% dynamics are sufficient to characterise the emergent order (e.g. pattern
% formation) and can be accessed using a generative model that tries to
% explain observed motion in terms of a few hidden states (i.e. order
% parameters) that implicitly enslave random fluctuations.
%
% THIS DEMO IS UNDER CONSTRUCTION

% non-hierarchical non-linear generative model (dynamic & chaotic)
%==========================================================================
spm_figure('GetWin','Figure 1');

% get model parameters and initial states
%--------------------------------------------------------------------------
x      = [4 4 28]';
P.A    = [-10  10  0;
           32 -1   0;
           0   0  -8/3];
P.B{1} = [ 0  0  0;
           0  0 -1;
           0  1  0];
P.B{2} = [ 0  0  0;
           0  0  0;
           0  0  0];
P.B{3} = [ 0  0  0;
           0  0  0;
           0  0  0];
P.C    = {};

V.A    = [ 1  1  1;
           1  1  1;
           1  1  1];
V.B{1} = [ 1  1  1;
           1  1  1;
           1  1  1];
V.B{2} = [ 0  1  1;
           0  1  1;
           0  1  1];
V.B{3} = [ 0  0  1;
           0  0  1;
           0  0  1];
V.C    = {};
pE     = spm_unvec(spm_vec(P)/2,P);
pC     = diag(spm_vec(V));

% level 1
%--------------------------------------------------------------------------
M(1).f  = inline('spm_fx_poly(x,v,P)/32','x','v','P');
M(1).g  = inline('x','x','v','P');
M(1).x  = x;
M(1).pE = P;
M(1).V  = exp(8);
M(1).W  = exp(8);

% level 2
%--------------------------------------------------------------------------
M(2).v  = 0;
M(2).V  = exp(16);

% create data
%==========================================================================

% create innovations & add causes
%--------------------------------------------------------------------------
N       = 128;
U       = sparse(1,N);
DEM     = spm_DEM_generate(M,U);
spm_DEM_qU(DEM.pU)

% DEM estimation
%==========================================================================
DEM.M(1).E.n  = 4;
DEM.M(1).E.s  = 1/8;
DEM.M(1).pE   = pE;
DEM.M(1).pC   = pC*exp(0);
DEM           = spm_DEM(DEM);

M(1).pE = DEM.qP.P{1};
SIM     = spm_DEM_generate(M,U);

% graphics
%--------------------------------------------------------------------------
spm_figure('GetWin','Figure 1');
spm_DEM_qU(SIM.pU)

subplot(2,2,3)
x      = DEM.pU.x{1};
plot(x(1,:),x(2,:))
title('true manifold dynamics')
xlabel('time')
axis square

subplot(2,2,4)
x      = SIM.pU.x{1};
plot(x(1,:),x(2,:))
title('estimated dynamics')
xlabel('time')
axis square

return

% Notes for creation of a globally coupled map
%==========================================================================

% Demo of synchronization manifold using coupled Lorenz attractors
%--------------------------------------------------------------------------
W    = 2;                            % amplitude of random fluctuations
N    = 16;                           % number of (Lorenz) oscillators
T    = 512;                          % number of time bins
dt   = 1/32;                         % time interval

% parameters (set s.d. P.t to 1/4 to see oscillator death)
%--------------------------------------------------------------------------
P.t  = randn(N,1)/16;                 % variations in log-rate constants
P.k  = 2;                            % global coupling parameter

% states
%--------------------------------------------------------------------------
x      = randn(3,N)*8;               % microstates
x(1,:) = x(1,:) + 0;
x(2,:) = x(2,:) + 0;
x(3,:) = x(3,:) + 28;
v      = 0;

% integrate
%--------------------------------------------------------------------------
for i = 1:T

    [dfdx f]  = spm_diff('spm_lorenz_k',x,v,P,1);
    f         = f + randn(N*3,1)*W;
    dx        = spm_dx(dfdx,f,dt);
    x         = x + spm_unvec(dx,x);
    y(:,i)    = x(:);               % microstates
    X(:,i)    = mean(x,2);          % macrostates

end

% plot
%--------------------------------------------------------------------------
subplot(2,1,1)
plot(y',':'), hold on
plot(X','k'), hold off
axis tight

t = T/4:T;
subplot(2,1,2)
plot(X(1,t),X(2,t),'k')
axis square
axis([-16 16 -16 16])

return

% plot synchronisation manifold
%--------------------------------------------------------------------------
clf
subplot(2,1,1)
for i = 1:12
    plot(y(i*3 - 2,t),y(i*3 + 1,t),'.','Color',[1 1/2 1/2]),hold on
end
plot(X(1,t),X(1,t),'.k'),hold off
axis square
axis([-16 16 -16 16])


function model = L1APG_initialize(img, id, x1, y1, x2, y2)

init_pos = [y1, y2, y1; x1 x1 x2];
sz_T = [12 15];
% sz_T = [24 12];

% parameters setting for tracking
para.lambda = [0.2, 0.001, 10]; % lambda 1, lambda 2 for a_T and a_I respectively, lambda 3 for the L2 norm parameter
% set para.lambda = [a,a,0]; then this the old model
para.angle_threshold = 40;
para.Lip = 8;
para.Maxit = 5;
para.nT = 10; % number of templates for the sparse representation
% para.rel_std_afnv = [0.03,0.0005,0.0005,0.03,1,1]; % diviation of the sampling of particle filter
para.rel_std_afnv = [0.003, 0.0005, 0.0005, 0.003, 1, 1];
para.n_sample = 300;		% number of particles
para.sz_T = sz_T;
para.init_pos = init_pos;
para.bDebug = 1;		% debugging indicator

% generate the initial templates for the 1st frame
[T, T_norm, T_mean, T_std] = InitTemplates(sz_T, para.nT, img, init_pos);
norms = T_norm .* T_std; % template norms

% get affine transformation parameters from the corner points in the first frame
aff_obj = corners2affine(init_pos, sz_T);
map_aff = aff_obj.afnv;

dim_T = size(T,1);	% number of elements in one template, sz_T(1)*sz_T(2)=12x15 = 180
A = [T eye(dim_T)]; % data matrix is composed of T, positive trivial T.
% fixT = T(:,1)/para.nT; % first template is used as a fixed template
%Temaplate Matrix
Temp = A;
Dict = Temp'*Temp;
Temp1 = T*pinv(T);

% build model
model.T = T;
model.T_mean = T_mean;
model.norms = norms;
model.occlusionNf = 0;
model.map_aff = map_aff;
model.A = A;
model.Temp = Temp;
model.Dict = Dict;
model.Temp1 = Temp1;
model.Lambda = para.lambda;
model.para = para;
model.id = id;
model.lost = 0;
model.aff_samples = ones(para.n_sample,1)*map_aff;


function hedge = acqhedge_vbmc(action,hedge,stats,options)
%ACQPORTFOLIO Evaluate and update portfolio of acquisition functions.

switch lower(action(1:3))
    case 'acq'
        % Choose acquisition function based on hedge strategy

        if isempty(hedge)
            % Initialize hedge struct
            hedge.g = zeros(1,numel(options.SearchAcqFcn));
            hedge.n = numel(options.SearchAcqFcn);
            hedge.count = 0;
            hedge.lambda = 0.2;     % Lapse rate - random choice
            hedge.beta = 1;
            hedge.decay = options.AcqHedgeDecay^(options.FunEvalsPerIter);
        end

        hedge.count = hedge.count + 1;
        hedge.p = exp(hedge.beta*(hedge.g - max(hedge.g)))./sum(exp(hedge.beta*(hedge.g - max(hedge.g))));
        hedge.p = hedge.p*(1-hedge.lambda) + hedge.lambda/hedge.n;

        hedge.chosen = find(rand() < cumsum(hedge.p),1);
        hedge.phat = Inf(size(hedge.p));
        hedge.phat(hedge.chosen) = hedge.p(hedge.chosen);

    case 'upd'
        % Update value of hedge portfolio based on uncertainty reduction

        HedgeCutoff = 5;

        if ~isempty(hedge)
            iter = stats.iter(end);
            min_iter = max(1,iter-options.AcqHedgeIterWindow);

            min_sd = min(stats.elbo_sd(min_iter:iter-1));
            er_sd = max(0, log(min_sd / stats.elbo_sd(iter)));

            elcbo = stats.elbo - options.ELCBOImproWeight*stats.elbo_sd;
            max_elcbo = max(elcbo(min_iter:iter-1));
            er_elcbo = max(0,elcbo(iter) - max_elcbo)/options.TolImprovement;
            if er_elcbo > 1; er_elcbo = 1 + log(er_elcbo); end

            min_r = min(stats.rindex(min_iter:iter-1));
            er_r = max(0, log(min_r / stats.rindex(iter)));

            % er = 0.5*er_sd + 0.5*er_elcbo;  % Reward
            er = er_r;

            for iHedge = 1:hedge.n
                hedge.g(iHedge) = hedge.decay*hedge.g(iHedge) + er/hedge.phat(iHedge);
            end

            % Apply cutoff value on hedge
            hedge.g = min(hedge.g,HedgeCutoff);
            hedge.g
        end

end


function g = wangPriorGradient(prior, x)

% WANGPRIORGRADIENT Gradient wrt x of the Wang prior.

% PRIOR

% Compute gradient of prior
g = -prior.M./x;


function [ bdry ]  = seg2bdry(seg, fmt)
if nargin<2, fmt = 'doubleSize'; end;

if ~strcmp(fmt,'imageSize') && ~strcmp(fmt,'doubleSize'),
    error('possible values for fmt are: imageSize and doubleSize');
end

[tx, ty, nch] = size(seg);

if nch ~=1,
    error('seg must be a scalar image');
end

bdry = zeros(2*tx+1, 2*ty+1);

edgels_v = ( seg(1:end-1, :) ~= seg(2:end, :) );
edgels_v(end+1, :) = 0;
edgels_h = ( seg(:, 1:end-1) ~= seg(:, 2:end) );
edgels_h(:, end+1) = 0;

bdry(3:2:end, 2:2:end) = edgels_v;
bdry(2:2:end, 3:2:end) = edgels_h;
bdry(3:2:end-1, 3:2:end-1)= max ( max(edgels_h(1:end-1, 1:end-1), edgels_h(2:end, 1:end-1)), max(edgels_v(1:end-1,1:end-1), edgels_v(1:end-1,2:end)) );

bdry(1, :) = bdry(2, :);
bdry(:, 1) = bdry(:, 2);
bdry(end, :) = bdry(end-1, :);
bdry(:, end) = bdry(:, end-1);

if strcmp(fmt,'imageSize'),
    bdry = bdry(3:2:end, 3:2:end);
end


function [X, optinf] = cbpdnms(D, S, lambda, opt)

% cbpdnms -- Convolutional Basis Pursuit DeNoising (Mask Simulation)
%
%         argmin_{x_k} (1/2)||W (\sum_k d_k * x_k - s)||_2^2 +
%                           lambda \sum_k ||x_k||_1
%
%         The solution is computed using an ADMM approach (see
%         boyd-2010-distributed) with efficient solution of the main
%         linear systems (see wohlberg-2016-efficient and
%         wohlberg-2016-boundary).
%
% Usage:
%       [X, optinf] = cbpdnms(D, S, lambda, opt)
%
% Input:
%       D           Dictionary filter set (3D array)
%       S           Input image
%       lambda      Regularization parameter
%       opt         Algorithm parameters structure
%
% Output:
%       X           Dictionary coefficient map set (3D array)
%       optinf      Details of optimisation
%
%
% Options structure fields:
%   Verbose          Flag determining whether iteration status is displayed.
%                    Fields are iteration number, functional value,
%                    data fidelity term, l1 regularisation term, and
%                    primal and dual residuals (see Sec. 3.3 of
%                    boyd-2010-distributed). The value of rho is also
%                    displayed if options request that it is automatically
%                    adjusted.
%   MaxMainIter      Maximum main iterations
%   AbsStopTol       Absolute convergence tolerance (see Sec. 3.3.1 of
%                    boyd-2010-distributed)
%   RelStopTol       Relative convergence tolerance (see Sec. 3.3.1 of
%                    boyd-2010-distributed)
%   L1Weight         Weighting array for coefficients in l1 norm of X
%   Y0               Initial value for Y
%   U0               Initial value for U
%   rho              ADMM penalty parameter
%   AutoRho          Flag determining whether rho is automatically updated
%                    (see Sec. 3.4.1 of boyd-2010-distributed)
%   AutoRhoPeriod    Iteration period on which rho is updated
%   RhoRsdlRatio     Primal/dual residual ratio in rho update test
%   RhoScaling       Multiplier applied to rho when updated
%   AutoRhoScaling   Flag determining whether RhoScaling value is
%                    adaptively determined (see wohlberg-2015-adaptive). If
%                    enabled, RhoScaling specifies a maximum allowed
%                    multiplier instead of a fixed multiplier.
%   RhoRsdlTarget    Residual ratio targeted by auto rho update policy.
%   StdResiduals     Flag determining whether standard residual definitions
%                    (see Sec 3.3 of boyd-2010-distributed) are used instead
%                    of normalised residuals (see wohlberg-2015-adaptive)
%   RelaxParam       Relaxation parameter (see Sec. 3.4.3 of
%                    boyd-2010-distributed)
%   NoBndryCross     Flag indicating whether all solution coefficients
%                    corresponding to filters crossing the image boundary
%                    should be forced to zero.
%   AuxVarObj        Flag determining whether objective function is computed
%                    using the auxiliary (split) variable
%   HighMemSolve     Use more memory for a slightly faster solution
%   W                Synthesis spatial weighting matrix
%
%
% Author: Brendt Wohlberg <brendt@lanl.gov>  Modified: 2016-05-10
%
% This file is part of the SPORCO library. Details of the copyright
% and user license can be found in the 'License' file distributed with
% the library.

if nargin < 4,
  opt = [];
end
checkopt(opt, defaultopts([]));
opt = defaultopts(opt);

% Set up status display for verbose operation
hstr = 'Itn   Fnc       DFid      l1        r         s      ';
sfms = '%4d %9.2e %9.2e %9.2e %9.2e %9.2e';
nsep = 54;
if opt.AutoRho,
  hstr = [hstr '   rho  '];
  sfms = [sfms ' %9.2e'];
  nsep = nsep + 10;
end
if opt.Verbose && opt.MaxMainIter > 0,
  disp(hstr);
  disp(char('-' * ones(1,nsep)));
end

% Start timer
tstart = tic;

% Insert impulse filter into dictionary
imp = zeros(size(D,1), size(D,2), 1);
imp(1,1,1) = 1.0;
Di = cat(3, D, imp);

% Collapsing of trailing singleton dimensions greatly complicates
% handling of both SMV and MMV cases. The simplest approach would be
% if s could always be reshaped to 4d, with dimensions consisting of
% image rows, image cols, a single dimensional placeholder for number
% of filters, and number of measurements, but in the single
% measurement case the third dimension is collapsed so that the array
% is only 3d.
if size(S,3) > 1 && size(S,4) == 1,
  xsz = [size(S,1) size(S,2) size(Di,3) size(S,3)];
  % Insert singleton 3rd dimension (for number of filters) so that
  % 4th dimension is number of images in input s volume
  S = reshape(S, [size(S,1) size(S,2) 1 size(S,3)]);
  if ~isscalar(opt.W) & ndims(opt.W) > 2,
    opt.W = reshape(opt.W, [size(opt.W,1) size(opt.W,2) 1 size(opt.W,3)]);
  end
else
  xsz = [size(S,1) size(S,2) size(Di,3) size(S,4)];
end
IYW = 1.0 - opt.W;

% Compute filters in DFT domain
Df = fft2(Di, size(S,1), size(S,2));
% Convolve-sum and its Hermitian transpose
Dop = @(x) sum(bsxfun(@times, Df, x), 3);
DHop = @(x) bsxfun(@times, conj(Df), x);
% Compute signal in DFT domain
Sf = fft2(S);
% S convolved with all filters in DFT domain
DSf = DHop(Sf);

% Default lambda is 1/10 times the lambda value beyond which the
% solution is a zero vector
if nargin < 3 | isempty(lambda),
  b = ifft2(DHop(Sf), 'symmetric');
  lambda = 0.1*max(vec(abs(b)));
end

% Set up algorithm parameters and initialise variables
rho = opt.rho;
if isempty(rho), rho = 50*lambda+1; end;
if isempty(opt.RhoRsdlTarget),
  if opt.StdResiduals,
    opt.RhoRsdlTarget = 1;
  else
    opt.RhoRsdlTarget = 1 + (18.3).^(log10(lambda) + 1);
  end
end
if opt.HighMemSolve,
  C = bsxfun(@rdivide, Df, sum(Df.*conj(Df), 3) + rho);
else
  C = [];
end
Nx = prod(xsz);
optinf = struct('itstat', [], 'opt', opt);
r = Inf;
s = Inf;
epri = 0;
edua = 0;

% Initialise main working variables
X = [];
if isempty(opt.Y0),
  Y = zeros(xsz);
else
  Y = opt.Y0;
end
Yprv = Y;
if isempty(opt.U0),
  if isempty(opt.Y0),
    U = zeros(xsz);
  else
    U = (lambda/rho)*sign(Y);
  end
else
  U = opt.U0;
end

% Main loop
k = 1;
while k <= opt.MaxMainIter && (r > epri | s > edua),

  % Solve X subproblem
  Xf = solvedbi_sm(Df, rho, DSf + rho*fft2(Y - U), C);
  X = ifft2(Xf, 'symmetric');

  % See pg. 21 of boyd-2010-distributed
  if opt.RelaxParam == 1,
    Xr = X;
  else
    Xr = opt.RelaxParam*X + (1-opt.RelaxParam)*Y;
  end

  % Solve Y subproblem
  Y(:,:,1:(end-1),:) = shrink(Xr(:,:,1:(end-1),:) + U(:,:,1:(end-1),:), ...
                              (lambda/rho)*opt.L1Weight);
  Y(:,:,end,:) = bsxfun(@times, IYW, Xr(:,:,end,:) + U(:,:,end,:));
  if opt.NoBndryCross,
    Y((end-size(D,1)+2):end,:,1:(end-1),:) = 0;
    Y(:,(end-size(D,2)+2):end,1:(end-1),:) = 0;
  end

  % Update dual variable
  U = U + Xr - Y;

  % Compute data fidelity term in Fourier domain (note normalisation)
  if opt.AuxVarObj,
    Yf = fft2(Y); % This represents unnecessary computational cost
    Jdf = sum(vec(abs(sum(bsxfun(@times,Df,Yf),3)-Sf).^2))/(2*xsz(1)*xsz(2));
    Jl1 = sum(abs(vec(bsxfun(@times, opt.L1Weight, Y(:,:,1:(end-1),:)))));
  else
    Jdf = sum(vec(abs(sum(bsxfun(@times,Df,Xf),3)-Sf).^2))/(2*xsz(1)*xsz(2));
    Jl1 = sum(abs(vec(bsxfun(@times, opt.L1Weight, X(:,:,1:(end-1),:)))));
  end
  Jfn = Jdf + lambda*Jl1;

  nX = norm(X(:)); nY = norm(Y(:)); nU = norm(U(:));
  if opt.StdResiduals,
    % See pp. 19-20 of boyd-2010-distributed
    r = norm(vec(X - Y));
    s = norm(vec(rho*(Yprv - Y)));
    epri = sqrt(Nx)*opt.AbsStopTol+max(nX,nY)*opt.RelStopTol;
    edua = sqrt(Nx)*opt.AbsStopTol+rho*nU*opt.RelStopTol;
  else
    % See wohlberg-2015-adaptive
    r = norm(vec(X - Y))/max(nX,nY);
    s = norm(vec(Yprv - Y))/nU;
    epri = sqrt(Nx)*opt.AbsStopTol/max(nX,nY)+opt.RelStopTol;
    edua = sqrt(Nx)*opt.AbsStopTol/(rho*nU)+opt.RelStopTol;
  end

  % Record and display iteration details
  tk = toc(tstart);
  optinf.itstat = [optinf.itstat; [k Jfn Jdf Jl1 r s epri edua rho tk]];
  if opt.Verbose,
    if opt.AutoRho,
      disp(sprintf(sfms, k, Jfn, Jdf, Jl1, r, s, rho));
    else
      disp(sprintf(sfms, k, Jfn, Jdf, Jl1, r, s));
    end
  end

  % See wohlberg-2015-adaptive and pp. 20-21 of boyd-2010-distributed
  if opt.AutoRho,
    if k ~= 1 && mod(k, opt.AutoRhoPeriod) == 0,
      if opt.AutoRhoScaling,
        rhomlt = sqrt(r/(s*opt.RhoRsdlTarget));
        if rhomlt < 1, rhomlt = 1/rhomlt; end
        if rhomlt > opt.RhoScaling, rhomlt = opt.RhoScaling; end
      else
        rhomlt = opt.RhoScaling;
      end
      rsf = 1;
      if r > opt.RhoRsdlTarget*opt.RhoRsdlRatio*s, rsf = rhomlt; end
      if s > (opt.RhoRsdlRatio/opt.RhoRsdlTarget)*r, rsf = 1/rhomlt; end
      rho = rsf*rho;
      U = U/rsf;
      if opt.HighMemSolve && rsf ~= 1,
        C = bsxfun(@rdivide, Df, sum(Df.*conj(Df), 3) + rho);
      end
    end
  end

  Yprv = Y;
  k = k + 1;

end

% Record run time and working variables
optinf.runtime = toc(tstart);
optinf.X = X;
optinf.Xf = Xf;
optinf.Y = Y;
optinf.U = U;
optinf.lambda = lambda;
optinf.rho = rho;

if opt.Verbose && opt.MaxMainIter > 0,
  disp(char('-' * ones(1,nsep)));
end

% Remove coefficient map for impulse filter
X = X(:,:,1:(end-1), :);

return

function u = vec(v)

  u = v(:);

return

function u = shrink(v, lambda)

  if isscalar(lambda),
    u = sign(v).*max(0, abs(v) - lambda);
  else
    u = sign(v).*max(0, bsxfun(@minus, abs(v), lambda));
  end

return

function opt = defaultopts(opt)

  if ~isfield(opt,'Verbose'),
    opt.Verbose = 0;
  end
  if ~isfield(opt,'MaxMainIter'),
    opt.MaxMainIter = 1000;
  end
  if ~isfield(opt,'AbsStopTol'),
    opt.AbsStopTol = 0;
  end
  if ~isfield(opt,'RelStopTol'),
    opt.RelStopTol = 1e-4;
  end
  if ~isfield(opt,'L1Weight'),
   opt.L1Weight = 1;
  end
  if ~isfield(opt,'Y0'),
    opt.Y0 = [];
  end
  if ~isfield(opt,'U0'),
    opt.U0 = [];
  end
  if ~isfield(opt,'rho'),
    opt.rho = [];
  end
  if ~isfield(opt,'AutoRho'),
    opt.AutoRho = 1;
  end
  if ~isfield(opt,'AutoRhoPeriod'),
    opt.AutoRhoPeriod = 1;
  end
  if ~isfield(opt,'RhoRsdlRatio'),
    opt.RhoRsdlRatio = 1.2;
  end
  if ~isfield(opt,'RhoScaling'),
    opt.RhoScaling = 100;
  end
  if ~isfield(opt,'AutoRhoScaling'),
    opt.AutoRhoScaling = 1;
  end
  if ~isfield(opt,'RhoRsdlTarget'),
    opt.RhoRsdlTarget = [];
  end
  if ~isfield(opt,'StdResiduals'),
    opt.StdResiduals = 1;
  end
  if ~isfield(opt,'RelaxParam'),
    opt.RelaxParam = 1.8;
  end
  if ~isfield(opt,'NoBndryCross'),
    opt.NoBndryCross = 0;
  end
  if ~isfield(opt,'AuxVarObj'),
    opt.AuxVarObj = 0;
  end
  if ~isfield(opt,'HighMemSolve'),
    opt.HighMemSolve = 0;
  end
  if ~isfield(opt,'W'),
    opt.W = 1.0;
  end

return