% batch run full-clustering on all fish

% f.pushbutton_autoclus_Callback

global VAR;

data_masterdir = GetCurrentDataDir();

% range_fish = [5,6,7];
% M_ClusGroup = [2,2,2,2];
% M_Cluster = [1,1,1,1];
range_fish = 2:2;
M_ClusGroup = 1;
M_Cluster = 1;
M_stim = [1];
% M_fish_set = [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2];

%%
M_param = 5:25:30%0.3:0.1:0.8;

ParamScores = cell(length(M_param),length(range_fish));
ParamScores_raw = cell(length(M_param),length(range_fish));

for k_param = 1:length(M_param),
    numK2 = M_param(k_param);
    %thres_split = M_param(k_param);
    setappdata(hfig,'thres_split',thres_split);

    for k_fish = 1:length(range_fish),
        i_fish = range_fish(k_fish);
        disp(i_fish);
        LoadFullFish(hfig,i_fish);
        absIX = getappdata(hfig,'absIX');

        %% partitions for CV
        timelists = getappdata(hfig,'timelists');
        timelists_names = getappdata(hfig,'timelists_names');
        periods = getappdata(hfig,'periods');
        if length(periods)>1,
            timelistsCV = cell(length(M_stim),2);
            for k_stim = 1:length(M_stim), % :3
                i_stim = M_stim(k_stim);
                TL = timelists{i_stim};
                period = periods(i_stim);
                nrep = size(TL,2)/periods(i_stim); % integer
                n = floor(nrep/2);
                timelistsCV{k_stim,1} = TL(1):TL(n*period);
                timelistsCV{k_stim,2} = TL(1+n*period):TL(2*n*period);
            end
        end

        %% CV loop: auto-clustering with the partitions
        Score = zeros(length(M_stim),2);

        for k_stim = 1:length(M_stim), % :3
            i_stim = M_stim(k_stim);
            NumClus = zeros(1,2);
            CIX = cell(1,2);
            GIX = cell(1,2);
            for k = 1:2,
                %% Cluster to start auto-clustering
                i_ClusGroup = M_ClusGroup(k_fish);
                i_Cluster = M_Cluster(k_fish);
                ClusGroup = VAR(i_fish).ClusGroup{i_ClusGroup};
                numK = ClusGroup(i_Cluster).numK;
                gIX = ClusGroup(i_Cluster).gIX;
                cIX_abs = ClusGroup(i_Cluster).cIX_abs; % convert absolute index to index used for this dataset
                [~,cIX] = ismember(cIX_abs,absIX);

                % ~UpdateTimeIndex
                tIX = timelistsCV{k_stim,k};
                M_0 = GetTimeIndexedData_Default_Direct(hfig,cIX,tIX,'isAllCells');

                isWkmeans = 1;
                [cIX,gIX] = AutoClustering(cIX,gIX,absIX,i_fish,M_0,isWkmeans,numK2);

                NumClus(k) = length(unique(gIX));
                CIX{k} = cIX;
                GIX{k} = gIX;
            end
            % plot cell-matching figure
            Score(k_stim,1) = HungarianCV(NumClus(1),NumClus(2),CIX{1},CIX{2},GIX{1},GIX{2},timelists_names{i_stim});
            Score(k_stim,2) = HungarianCV(NumClus(2),NumClus(1),CIX{2},CIX{1},GIX{2},GIX{1},timelists_names{i_stim});
        end

        ParamScores{k_param,k_fish} = mean(mean(Score));
        ParamScores_raw{k_param,k_fish} = Score;
    end

end


function [SPM,pKX] = spm_spm_local(SPM)
% [Re]ML Estimation of a General Linear Model
% FORMAT [SPM,pKX] = spm_spm_local(SPM)
%
% Michal and Brian spent a week comparing how SPM computes the beta values
% and comparing that with Rory's/mrVIsta's glm code.
%
% The structure sent in to spm_get_data() contains information that
% specifies how the data will be scaled upon return.  If you only send in
% the file name, the data are unscaled.  We did not determined, however,
% which entry of the structure causes spm_get_data() to scale the returned
% values.
%
% Given the same design matrix and data, the two calculations are
% identical. (We didn't check the covariance stuff, this is assuming no
% whitening).  This can be hard to see because of problems in reading the
% data with SPM.  The routine spm_get_data() apparently can scale the time
% series that it returns.  This has the consequence that the beta weights
% may differ by this scale factor.  But apart from this, the beta weights
% are the same in the two cases, when the design matrix is the same.
%
%         pKX is the pseudo-inverse of the and smoothed (by K) design
%         matrix.
%
% required fields of SPM:
%
% xY.VY - nScan x 1 struct array of mapped image volumes
%         Images must have the same orientation, voxel size and data type
%       - Any scaling should have already been applied via the image handle
%         scalefactors.
%
% xX    - Structure containing design matrix information
%       - Required fields are:
%         xX.X      - Design matrix (raw, not temporally smoothed)
%         xX.name   - cellstr of parameter names corresponding to columns
%                     of design matrix
%       - Optional fields are:
%         xX.K      - cell of session-specific structures (see spm_filter)
%                   - Design & data are pre-multiplied by K
%                     (K*Y = K*X*beta + K*e)
%                   - Note that K should not smooth across block boundaries
%                   - defaults to speye(size(xX.X,1))
%         xX.W      - Optional whitening/weighting matrix used to give
%                     weighted least squares estimates (WLS). If not specified
%                     spm_spm will set this to whiten the data and render
%                     the OLS estimtes maximum likelihood
%                     i.e. W*W' = inv(xVi.V).
%
% xVi   - structure describing intrinsic temporal non-sphericity
%       - required fields are:
%         xVi.Vi    - array of non-sphericity components
%                   - defaults to {speye(size(xX.X,1))} - i.i.d.
%                   - specifying a cell array of contraints (Qi)
%                     These contraints invoke spm_reml to estimate
%                     hyperparameters assuming V is constant over voxels.
%                     that provide a high precise estimate of xX.V
%       - Optional fields are:
%         xX.V      - Optional non-sphericity matrix.  Cov(e) = sigma^2*V
%                     If not specified spm_spm will compute this using
%                     a 1st pass to identify signifcant voxels over which
%                     to estimate V.  A 2nd pass is then used to re-estimate
%                     the parameters with WLS and save the ML estimates
%                     (unless xX.W is already specified)
%
% xM    - Structure containing masking information, or a simple column vector
%         of thresholds corresponding to the images in VY.
%       - If a structure, the required fields are:
%         xM.TH - nVar x nScan matrix of analysis thresholds, one per image
%         xM.I  - Implicit masking (0=>none, 1 => implicit zero/NaN mask)
%         xM.VM - struct array of mapped explicit mask image volumes
% 		- (empty if no explicit masks)
%               - Explicit mask images are >0 for valid voxels to assess.
%               - Mask images can have any orientation, voxel size or data
%                 type. They are interpolated using nearest neighbour
%                 interpolation to the voxel locations of the data Y.
%       - Note that voxels with constant data (i.e. the same value across
%         scans) are also automatically masked out.
%
%
% In addition, the global default UFp is used to set a critical
% F-threshold for selecting voxels over which the non-sphericity
% is estimated (if required)
%
%_______________________________________________________________________
%
% spm_spm is the heart of the SPM package. Given image files and a
% General Linear Model, it estimates the model parameters, variance
% hyerparameters, and smoothness of standardised residual fields, writing
% these out to disk in the current working directory for later
% interrogation in the results section. (NB: Existing analyses in the
% current working directory are overwritten).  This directory
% now becomes the working directory for this analysis and all saved
% images are relative to this directory.
%
% The model is expressed via the design matrix (xX.X). The basic model
% at each voxel is of the form is Y = X*B + e, for data Y, design
% matrix X, (unknown) parameters B, and residual errors e. The errors
% are assummed to have a normal distribution.
%
% Sometimes confounds (e.g. drift terms in fMRI) are necessary.  These
% can be specified directly in the design matrix or implicitly, in terms
% of a residual forming matrix K to give a generalised linear model
% K*Y = K*X*B + K*e.  In fact K can be any matrix (e.g. a convolution
% matrix).
%
% In some instances i.i.d. assumptions about errors do not hold.  For
% example, with serially correlated (fMRI) data or correlations among the
% levels of a factor in repeated measures designs.  This non-sphericity
% can be specified in terms of components (SPM.xVi.Vi{i}). If specified
% these covariance components will then be estimated with ReML (restricted
% maximum likelihood) hyperparameters.  This estimation assumes the same
% non-sphericity for voxels that exceed the global F-threshold. The ReML
% estimates can then used to whiten the data giving maximum likelihood (ML)
% or Gauss-Markov estimators.  This entails a second pass of the data
% with an augmented model K*W*Y = K*W*X*B + K*W*e where W*W' = inv(xVi.V).
% xVi.V is the non-sphericity based on the hyperparameter esimates.
% W is stored in xX.W and cov(K*W*e) in xX.V.  The covariance of the
% parameter estimates is then xX.Bcov = pinv(K*W*X)*xX.V*pinv(K*W*X)';
%
% If you do not want ML estimates but want to use ordinary least squares
% (OLS) then simply set SPM.xX.W to the identity matrix. Any non-sphericity
% V will still be estimated but will be used to adjust the degrees of freedom
% of the ensuing statistics using the Satterthwaite approximation (c.f.
% the Greenhouse-Giesser corrections)
%
% If [non-spherical] variance components Vi are not specified xVi.Vi and
% xVi.V default to the identity matrix (i.e. i.i.d). The parameters are
% then estimated by OLS.  In this instance the OLS and ML estimates are
% the same.
%
% Note that only a single voxel-specific hyperaprameter (i.e. variance
% component) is estimated, even if V is not i.i.d.  This means spm_spm
% always implements a fixed-effects model.
% Random effects models can be emulated using a multi-stage procedure:
% This entails summarising the data with contrasts such that the fixed
% effects in a second model on the summary data are those effects of
% interest (i.e. the population effects). This means contrasts are
% re-entered into spm_spm to make an inference (SPM) at the next
% level. At this higher hierarchial level the residual variance for the
% model contains the appropriate variance components from lower levels.
% See spm_RandFX.man for further details and below.
%
% Under the additional assumption that the standardised residual images
% are non-stationary standard Gaussian random fields, results from
% Random field theory can be applied to estimate the significance
% statistic images (SPM's) adjusting p values for the multiple tests
% at all voxels in the search volume. The parameters required for
% this random field correction are the volume, and Lambda, the covariance
% matrix of partial derivatives of the standardised error fields.
%
% spm_est_smoothness estimates the variances of the partial derivatives
% in the axis directions (the diagonal of Lambda). The covariances (off
% diagonal elements of Lambda) are assumed to be zero.
%
%                           ----------------
%
%
% The volume analsed is the intersection of the threshold masks,
% explicit masks and implicit masks. See spm_spm_ui for further details
% on masking options.
%
%
%-----------------------------------------------------------------------
%
% The output of spm_spm takes the form of an SPM.mat file of the analysis
% parameters, and 'float' flat-file images of the parameter and variance
% [hyperparameter] estimates. An 8bit zero-one mask image indicating the
% voxels assessed is also written out, with zero indicating voxels outside
% tha analysed volume.
%
%                           ----------------
%
% The following SPM.fields are set by spm_spm (unless specified)
%
%     xVi.V      - estimated non-sphericity trace(V) = rank(V)
%     xVi.h      - hyperparameters  xVi.V = xVi.h(1)*xVi.Vi{1} + ...
%     xVi.Cy     - spatially whitened <Y*Y'> (used by ReML to estimate h)
%     xVi.CY     - <(Y - <Y>)*(Y - <Y>)'>    (used by spm_spm_Bayes)
%
%                           ----------------
%
%     Vbeta     - struct array of beta image handles (relative)
%     VResMS    - file struct of ResMS image handle  (relative)
%     VM        - file struct of Mask  image handle  (relative)
%
%                           ----------------
%     xX.W      - if not specified W*W' = inv(x.Vi.V)
%     xX.V      - V matrix (K*W*Vi*W'*K') = correlations after K*W is applied
%     xX.xKXs   - space structure for K*W*X, the 'filtered and whitened'
%                 design matrix
%               - given as spm_sp('Set',xX.K*xX.W*xX.X) - see spm_sp
%     xX.pKX    - pseudoinverse of K*W*X, computed by spm_sp
%     xX.Bcov   - xX.pKX*xX.V*xX.pKX - variance-covariance matrix of
%                 parameter estimates
%		  (when multiplied by the voxel-specific hyperparameter ResMS)
%                 (of the parameter estimates. (ResSS/xX.trRV = ResMS)    )
%     xX.trRV   - trace of R*V, computed efficiently by spm_SpUtil
%     xX.trRVRV - trace of RVRV
%     xX.erdf   - effective residual degrees of freedom (trRV^2/trRVRV)
%     xX.nKX    - design matrix (xX.xKXs.X) scaled for display
%                 (see spm_DesMtx('sca',... for details)
%
%                           ----------------
%
%     xVol.M    - 4x4 voxel->mm transformation matrix
%     xVol.iM   - 4x4 mm->voxel transformation matrix
%     xVol.DIM  - image dimensions - column vector (in voxels)
%     xVol.XYZ  - 3 x S vector of in-mask voxel coordinates
%     xVol.S    - Lebesgue measure or volume       (in voxels)
%     xVol.R    - vector of resel counts           (in resels)
%     xVol.FWHM - Smoothness of components - FWHM, (in voxels)
%
%                           ----------------
%
% xCon  - See Christensen for details of F-contrasts.  These are specified
%         at the end of spm_spm after the non-sphericity V has been defined
%         or estimated. The fist contrast tests for all effects of interest
%         assuming xX.iB and xX.iG index confounding or nuisance effects.
%
%     xCon      - Contrast structure (created by spm_FcUtil.m)
%     xCon.name - Name of contrast
%     xCon.STAT - 'F', 'T' or 'P' - for F/T-contrast ('P' for PPMs)
%     xCon.c    - (F) Contrast weights
%     xCon.X0   - Reduced design matrix (spans design space under Ho)
%                 It is in the form of a matrix (spm99b) or the
%                 coordinates of this matrix in the orthogonal basis
%                 of xX.X defined in spm_sp.
%     xCon.iX0  - Indicates how contrast was specified:
%                 If by columns for reduced design matrix then iX0 contains the
%                 column indices. Otherwise, it's a string containing the
%                 spm_FcUtil 'Set' action: Usuall one of {'c','c+','X0'}
%                 (Usually this is the input argument F_iX0.)
%     xCon.X1o  - Remaining design space (orthogonal to X0).
%                 It is in the form of a matrix (spm99b) or the
%                 coordinates of this matrix in the orthogonal basis
%                 of xX.X defined in spm_sp.
%     xCon.eidf - Effective interest degrees of freedom (numerator df)
%     xCon.Vcon - ...for handle of contrast/ESS image (empty at this stage)
%     xCon.Vspm - ...for handle of SPM image (empty at this stage)
%
%                           ----------------
%
%
% The following images are written to file
%
% mask.{img,hdr}                                   - analysis mask image
% 8-bit (uint8) image of zero-s & one's indicating which voxels were
% included in the analysis. This mask image is the intersection of the
% explicit, implicit and threshold masks specified in the xM argument.
% The XYZ matrix contains the voxel coordinates of all voxels in the
% analysis mask. The mask image is included for reference, but is not
% explicitly used by the results section.
%
%                           ----------------
%
% beta_????.{img,hdr}                                 - parameter images
% These are 16-bit (float) images of the parameter estimates. The image
% files are numbered according to the corresponding column of the
% design matrix. Voxels outside the analysis mask (mask.img) are given
% value NaN.
%
%                           ----------------
%
% ResMS.{img,hdr}                    - estimated residual variance image
% This is a 32-bit (double) image of the residual variance estimate.
% Voxels outside the analysis mask are given value NaN.
%
%                           ----------------
%
% RVP.{img,hdr}                      - estimated resels per voxel image
% This is a 32-bit (double) image of the RESELs per voxel estimate.
% Voxels outside the analysis mask are given value 0.  These images
% reflect the nonstationary aspects the spatial autocorrelations.
%
%
%-----------------------------------------------------------------------
%
% References:
%
% Christensen R (1996) Plane Answers to Complex Questions
%       Springer Verlag
%
% Friston KJ, Holmes AP, Worsley KJ, Poline JP, Frith CD, Frackowiak RSJ (1995)
% ``Statistical Parametric Maps in Functional Imaging:
%   A General Linear Approach''
%       Human Brain Mapping 2:189-210
%
% Worsley KJ, Friston KJ (1995)
% ``Analysis of fMRI Time-Series Revisited - Again''
%       Neuroimage 2:173-181
%
%-----------------------------------------------------------------------
%
% For those interested, the analysis proceeds a "block" at a time,
% The block size conforms to maxMem that can be set as a global variable
% MAXMEM (in bytes) [default = 2^20]
%
%_______________________________________________________________________
% @(#)spm_spm.m	2.66 Andrew Holmes, Jean-Baptiste Poline, Karl Friston 03/03/27
SCCSid   = '2.66';

%-Say hello
%-----------------------------------------------------------------------
SPMid    = spm('FnBanner',mfilename,SCCSid);
Finter   = spm('FigName','Stats: estimation...'); spm('Pointer','Watch')

%-Get SPM.mat if necessary
%-----------------------------------------------------------------------
if nargin ==0
	swd     = spm_str_manip(spm_get(1,'SPM.mat','Select SPM.mat'),'H');
	load(fullfile(swd,'SPM.mat'));
	SPM.swd = swd;
end

%-Change to SPM.swd if specified
%-----------------------------------------------------------------------
try
	cd(SPM.swd);
end

%-Ensure data are assigned
%-----------------------------------------------------------------------
try
	SPM.xY.VY;
catch
	helpdlg({	'Please assign data to this design',...
			'Use fMRI under model specification'});
	spm('FigName','Stats: done',Finter); spm('Pointer','Arrow')
	return
end

%-Delete files from previous analyses
%-----------------------------------------------------------------------
if exist(fullfile('.','mask.img'),'file') == 2

	str   = {'Current directory contains SPM estimation files:',...
		 'pwd = ',pwd,...
		 'Existing results will be overwritten!'};

	abort = spm_input(str,1,'bd','stop|continue',[1,0],1);
	if abort
		spm('FigName','Stats: done',Finter); spm('Pointer','Arrow')
		return
	else
		str = sprintf('Overwriting old results\n\t (pwd = %s) ',pwd)
		warning(str)
		drawnow
	end
end

files = {	'mask.???','ResMS.???','RVP.???',...
		'beta_????.???','con_????.???','ResI_????.???',...
		'ess_????.???', 'spm?_????.???'};

for i=1:length(files)
	if any(files{i} == '*'|files{i} == '?' )
		[j,null] = spm_list_files(pwd,files{i});
		for i=1:size(j,1)
			spm_unlink(deblank(j(i,:)))
		end
	else
		spm_unlink(files{i})
	end
end

%=======================================================================
% - A N A L Y S I S   P R E L I M I N A R I E S
%=======================================================================

%-Initialise
%=======================================================================
fprintf('%-40s: %30s','Initialising parameters','...computing')    %-#
xX            = SPM.xX;
[nScan nBeta] = size(xX.X);

%-If xM is not a structure then assumme it's a vector of thresholds
%-----------------------------------------------------------------------
try
	xM = SPM.xM;
catch
	xM = -ones(nScan,1)/0;
end
if ~isstruct(xM)
	xM = struct(	'T',	[],...
			'TH',	xM,...
			'I',	0,...
			'VM',	{[]},...
			'xs',	struct('Masking','analysis threshold'));
end

%-Check confounds (xX.K) and non-sphericity (xVi)
%-----------------------------------------------------------------------
if ~isfield(xX,'K')
	xX.K  = 1;
end
try
	%-If covariance components are specified use them
	%---------------------------------------------------------------
	xVi   = SPM.xVi;
catch

	%-otherwise assume i.i.d.
	%---------------------------------------------------------------
	xVi   = struct(	'form',  'i.i.d.',...
			'V',	 speye(nScan,nScan));
end

%-Get non-sphericity V
%=======================================================================
try
	%-If xVi.V is specified proceed directly to parameter estimation
	%---------------------------------------------------------------
	V     = xVi.V;
	str   = 'parameter estimation';

catch
	% otherwise invoke ReML selecting voxels under i.i.d assumptions
	%---------------------------------------------------------------
	V     = speye(nScan,nScan);
	str   = '[hyper]parameter estimation';
end

%-Get whitening/Weighting matrix: If xX.W exists we will save WLS estimates
%-----------------------------------------------------------------------
try
	%-If W is specified, use it
	%-------------------------------------------------------
	W     = xX.W;   % imagesc(W); title('Whitening matrix')
catch
	if isfield(xVi,'V')

		% otherwise make W a whitening filter W*W' = inv(V)
		%-------------------------------------------------------
		[u s] = spm_svd(xVi.V);
		s     = spdiags(1./sqrt(diag(s)),0,nScan,nScan);
		W     = u*s*u';
		W     = W.*(abs(W) > 1e-6);
		xX.W  = sparse(W);
	else
		% unless xVi.V has not been estimated - requiring 2 passes
		%-------------------------------------------------------
		W     = speye(nScan,nScan);
		str   = 'hyperparameter estimation (1st pass)';
	end
end

%-Design space and projector matrix [pseudoinverse] for WLS
%=======================================================================

% The first 'Set' initializes the SVD of the design matrix properties. In
% our default analysis, W is the identity matrix. In our case, we set K so
% that it is an impulse.
xX.xKXs = spm_sp('Set',spm_filter(xX.K,W*xX.X));		% KWX

% Hence, it turns out the with our settings, KWX is just X
% figure(1); subplot(1,3,1), plot(spm_filter(xX.K,W*xX.X));
%            subplot(1,3,2), plot(W*xX.X)
%            subplot(1,3,3), plot(xX.xKXs.X)

% Compute the pseudo-inverse of xX.xKXs (from above)
xX.pKX  = spm_sp('x-',xX.xKXs);				% projector

% So, after all this nonsense, it is still the case that pKX remains
% the pseudoinverse of X.
% max(abs(xX.X(:) - xX.xKXs.X(:)))

%-If xVi.V is not defined compute Hsqr and F-threshold under i.i.d.
%-----------------------------------------------------------------------
if ~isfield(xVi,'V')
	Fcname = 'effects of interest';
	iX0    = [SPM.xX.iB SPM.xX.iG];
	xCon   = spm_FcUtil('Set',Fcname,'F','iX0',iX0,xX.xKXs);
	X1o    = spm_FcUtil('X1o', xCon(1),xX.xKXs);
	Hsqr   = spm_FcUtil('Hsqr',xCon(1),xX.xKXs);
	trRV   = spm_SpUtil('trRV',xX.xKXs);
	trMV   = spm_SpUtil('trMV',X1o);
	UFp    = spm('GetGlobal','UFp');
	UF     = spm_invFcdf(1 - UFp,[trMV,trRV]);
end

%-Image dimensions and data
%=======================================================================
VY       = SPM.xY.VY;
M        = VY(1).mat;
DIM      = VY(1).dim(1:3)';
xdim     = DIM(1); ydim = DIM(2); zdim = DIM(3);
YNaNrep  = spm_type(VY(1).dim(4),'nanrep');

%-Maximum number of residual images for smoothness estimation
%-----------------------------------------------------------------------
global     defaults
MAXRES   = defaults.stats.maxres;

%-maxMem is the maximum amount of data processed at a time (bytes)
%-----------------------------------------------------------------------
MAXMEM   = defaults.stats.maxmem;
nSres    = min(nScan,MAXRES);
blksz    = ceil(MAXMEM/8/nScan);				%-block size
nbch     = ceil(xdim*ydim/blksz);				%-# blocks
nbch = 1;
blksz    = ceil(MAXMEM);				%-block size

fprintf('%s%30s\n',sprintf('\b')*ones(1,30),'...done')               %-#

%-Initialise output images (unless this is a 1st pass for ReML)
%=======================================================================
if isfield(xX,'W')
fprintf('%-40s: %30s','Output images','...initialising')     %-#

%-Intialise the name of the new mask : current mask & conditions on voxels
%-----------------------------------------------------------------------
VM    = struct(		'fname',	'mask.img',...
			'dim',		[DIM',spm_type('uint8')],...
			'mat',		M,...
			'pinfo',	[1 0 0]',...
			'descrip',	'spm_spm:resultant analysis mask');
VM    = spm_create_vol(VM);

%-Intialise beta image files
%-----------------------------------------------------------------------
Vbeta(1:nBeta) = deal(struct(...
			'fname',	[],...
			'dim',		[DIM',spm_type('float')],...
			'mat',		M,...
			'pinfo',	[1 0 0]',...
			'descrip',	''));
for i = 1:nBeta
	Vbeta(i).fname   = sprintf('beta_%04d.img',i);
	Vbeta(i).descrip = sprintf('spm_spm:beta (%04d) - %s',i,xX.name{i});
	spm_unlink(Vbeta(i).fname)
end
Vbeta = spm_create_vol(Vbeta,'noopen');

%-Intialise residual sum of squares image file
%-----------------------------------------------------------------------
VResMS = struct(	'fname',	'ResMS.img',...
			'dim',		[DIM',spm_type('double')],...
			'mat',		M,...
			'pinfo',	[1 0 0]',...
			'descrip',	'spm_spm:Residual sum-of-squares');
VResMS = spm_create_vol(VResMS,'noopen');

%-Intialise residual images
%-----------------------------------------------------------------------
VResI(1:nSres) = deal(struct(...
			'fname',	[],...
			'dim',		[DIM',spm_type('double')],...
			'mat',		M,...
			'pinfo',	[1 0 0]',...
			'descrip',	'spm_spm:Residual image'));

for i = 1:nSres
	VResI(i).fname   = sprintf('ResI_%04d.img', i);
	VResI(i).descrip = sprintf('spm_spm:ResI (%04d)', i);
	spm_unlink(VResI(i).fname);
end
VResI = spm_create_vol(VResI);
end % (xX,'W')

fprintf('%s%30s\n',sprintf('\b')*ones(1,30),'...initialised')        %-#

%=======================================================================
% - F I T   M O D E L   &   W R I T E   P A R A M E T E R    I M A G E S
%=======================================================================

%-Intialise variables used in the loop
%=======================================================================
xords = [1:xdim]'*ones(1,ydim); xords = xords(:)';  % plane X coordinates
yords = ones(xdim,1)*[1:ydim];  yords = yords(:)';  % plane Y coordinates
S     = 0;                                          % Volume (voxels)
s     = 0;                                          % Volume (voxels > UF)
Cy    = 0;					    % <Y*Y'> spatially whitened
CY    = 0;					    % <Y*Y'> for ReML
EY    = 0;					    % <Y>    for ReML
i_res = round(linspace(1,nScan,nSres))';	    % Indices for residual

%-Initialise XYZ matrix of in-mask voxel co-ordinates (real space)
%-----------------------------------------------------------------------
XYZ   = zeros(3,xdim*ydim*zdim);

%-Cycle over bunches blocks within planes to avoid memory problems
%=======================================================================
% spm_progress_bar('Init',100,str,'');

totalVox = 0;
for z = 1:zdim				%-loop over planes (2D or 3D data)

    % current plane-specific parameters
    %-------------------------------------------------------------------
    zords   = z*ones(xdim*ydim,1)';	%-plane Z coordinates
    CrBl    = [];			%-parameter estimates
    CrResI  = [];			%-normalized residuals
    CrResSS = [];			%-residual sum of squares
    Q       = [];			%-in mask indices for this plane

    for bch = 1:nbch			%-loop over blocks

	%-# Print progress information in command window
	%---------------------------------------------------------------
	str   = sprintf('Plane %3d/%-3d, block %3d/%-3d',z,zdim,bch,nbch);
	fprintf('\r%-40s: %30s',str,' ')                                %-#

	%-construct list of voxels in this block
	%---------------------------------------------------------------
	I     = [1:blksz] + (bch - 1)*blksz;		%-voxel indices
	I     = I(I <= xdim*ydim);			%-truncate
	xyz   = [xords(I); yords(I); zords(I)];		%-voxel coordinates
	nVox  = size(xyz,2);				%-number of voxels

	%-Get data & construct analysis mask
	%===============================================================
	fprintf('%s%30s',sprintf('\b')*ones(1,30),'...read & mask data')%-#
	Cm    = logical(ones(1,nVox));			%-current mask

	%-Compute explicit mask
	% (note that these may not have same orientations)
	%---------------------------------------------------------------
	for i = 1:length(xM.VM)

		%-Coordinates in mask image
		%-------------------------------------------------------
		j      = xM.VM(i).mat\M*[xyz;ones(1,nVox)];

		%-Load mask image within current mask & update mask
		%-------------------------------------------------------
		Cm(Cm) = spm_get_data(xM.VM(i),j(:,Cm)) > 0;
	end

	%-Get the data in mask, compute threshold & implicit masks
	%---------------------------------------------------------------
	Y     = zeros(nScan,nVox);
	for i = 1:nScan

		%-Load data in mask
		%-------------------------------------------------------
		if ~any(Cm), break, end			%-Break if empty mask
		Y(i,Cm)  = spm_get_data(VY(i),xyz(:,Cm));

        % tmp = Y(i,Cm); hist(tmp(:));

		Cm(Cm)   = Y(i,Cm) > xM.TH(i);		%-Threshold (& NaN) mask
		if xM.I & ~YNaNrep & xM.TH(i) < 0	%-Use implicit mask
			Cm(Cm) = abs(Y(i,Cm)) > eps;
        end
        max(Y(:))
	end

	%-Mask out voxels where data is constant
	%---------------------------------------------------------------
	Cm(Cm) = any(diff(Y(:,Cm),1));
	Y      = Y(:,Cm);				%-Data within mask
	CrS    = sum(Cm);				%-# current voxels

    figure(1); plot(Y);
    totalVox = CrS + totalVox
    title(sprintf('Current voxels TS %.0f, total: ',CrS,totalVox));
    pause(.2)
    foo = analyzeRead(VY(i).fname);
    hist(foo(:),100)
    imtool(foo/max(foo(:)))
	%===============================================================
	%-Proceed with General Linear Model (if there are voxels)
	%===============================================================
	if CrS

		%-Whiten/Weight data and remove filter confounds
		%-------------------------------------------------------
		fprintf('%s%30s',sprintf('\b')*ones(1,30),'filtering')	%-#

        % For us, W is the identity.
        % figure(1); imagesc(W)
        % In this case, KWY is just Y, the data
        %     max(abs(KWY(:) - Y(:)))
		KWY   = spm_filter(xX.K,W*Y);

		%-General linear model: Weighted least squares estimation
		%------------------------------------------------------
		fprintf('%s%30s',sprintf('\b')*ones(1,30),' estimation') %-#

        % Wandell notes:
        %
        %  SPM computes the beta weights using the formula
        %
        %    KWY= KX*beta
        %
        %  Here, pKX is the pseudo-inverse of KX. X is the design matrix,
        %  and K is the term that introduces the convolution with the HRF
        %
        %  KWY is the whitened, filtered, time series. I don't underwstand
        %  why K is on both sides.  Maybe, therefore, I don't understand K.
        %
        %  The formula our glm computes is Y = X*beta
        %  So the differences are that we included the HRF into X and they
        %  assume we did not.  The W is the identity, so it doesn't matter.
        %  If we set up the SPM so that K is the impulse, we should get the
        %  same.  If we set up the SPM so that we pass it X prior to
        %  filtering with the HRF, then we should also get the same.

        % So,
		beta  = xX.pKX*KWY;			%-Parameter estimates
        pKX   = xX.pKX;             % Wandell added for return

		res   = spm_sp('r',xX.xKXs,KWY);	%-Residuals
		ResSS = sum(res.^2);			%-Residual SSQ
		clear KWY				%-Clear to save memory

		%-If ReML hyperparameters are needed for xVi.V
		%-------------------------------------------------------
		if ~isfield(xVi,'V')

			%-F-threshold & accumulate spatially whitened Y*Y'
			%-----------------------------------------------
			j   = sum((Hsqr*beta).^2,1)/trMV > UF*ResSS/trRV;
			j   = find(j);
			if length(j)
				q  = size(j,2);
				s  = s + q;
				q  = spdiags(sqrt(trRV./ResSS(j)'),0,q,q);
				Y  = Y(:,j)*q;
				Cy = Cy + Y*Y';
			end

		end % (xVi,'V')

		%-if we are saving the WLS parameters
		%-------------------------------------------------------
		if isfield(xX,'W')

			%-sample covariance and mean of Y (all voxels)
			%-----------------------------------------------
			CY         = CY + Y*Y';
			EY         = EY + sum(Y,2);

			%-Save betas etc. for current plane as we go along
			%-----------------------------------------------
			CrBl 	   = [CrBl,    beta];
			CrResI     = [CrResI,  res(i_res,:)];
			CrResSS    = [CrResSS, ResSS];

		end % (xX,'W')
		clear Y				%-Clear to save memory

	end % (CrS)

	%-Append new inmask voxel locations and volumes
	%---------------------------------------------------------------
	XYZ(:,S + [1:CrS]) = xyz(:,Cm);		%-InMask XYZ voxel coords
	Q                  = [Q I(Cm)];		%-InMask XYZ voxel indices
	S                  = S + CrS;		%-Volume analysed (voxels)

    end   % (bch)

    %-Plane complete, write plane to image files (unless 1st pass)
    %===================================================================
    if isfield(xX,'W')

    	fprintf('%s%30s',sprintf('\b')*ones(1,30),'...saving plane')	%-#

	%-Write Mask image
	%-------------------------------------------------------------------
	j   = sparse(xdim,ydim);
	if length(Q), j(Q) = 1; end
	VM    = spm_write_plane(VM, j, z);

	%-Write beta images
	%-------------------------------------------------------------------
	j   = NaN*ones(xdim,ydim);
	for i = 1:nBeta
		if length(Q), j(Q) = CrBl(i,:); end
		Vbeta(i) = spm_write_plane(Vbeta(i), j, z);
	end

	%-Write residual images
	%-------------------------------------------------------------------
	for i = 1:nSres
		if length(Q), j(Q) = CrResI(i,:); end
		VResI(i) = spm_write_plane(VResI(i), j, z);
   	end

	%-Write ResSS into ResMS (variance) image scaled by tr(RV) above
	%-------------------------------------------------------------------
	if length(Q), j(Q) = CrResSS;    end
	VResMS  = spm_write_plane(VResMS,j,z);

    end % (xX,'W')

    %-Report progress
    %-------------------------------------------------------------------
    fprintf('%s%30s',sprintf('\b')*ones(1,30),'...done')             %-#
    spm_progress_bar('Set',100*(bch + nbch*(z - 1))/(nbch*zdim));

end % (for z = 1:zdim)
fprintf('\n')                                                        %-#
spm_progress_bar('Clear')

%=======================================================================
% - P O S T   E S T I M A T I O N   C L E A N U P
%=======================================================================
if S == 0, warning('No inmask voxels - empty analysis!'), end

%-close written image files (unless 1st pass)
%=======================================================================
if isfield(xX,'W')

	fprintf('%s%30s\n',sprintf('\b')*ones(1,30),'...closing files')  %-#
	VM              = spm_close_vol(VM);
	Vbeta           = spm_close_vol(Vbeta);
	VResI           = spm_close_vol(VResI);
	VResMS          = spm_close_vol(VResMS);

end % (xVi,'V')

%-average sample covariance and mean of Y (over voxels)
%-----------------------------------------------------------------------
CY          = CY/S;
EY          = EY/S;
CY          = CY - EY*EY';

%-If not defined, compute non-sphericity V using ReML Hyperparameters
%=======================================================================
if ~isfield(xVi,'V')

	%-REML estimate of residual correlations through hyperparameters (h)
	%---------------------------------------------------------------
	str    = 'Temporal non-sphericity (over voxels)';
	fprintf('%-40s: %30s\n',str,'...REML estimation') %-#
	Cy            = Cy/s;

	% ReML for separable designs and covariance components
	%---------------------------------------------------------------
	if isstruct(xX.K)
		m     = length(xVi.Vi);
		h     = zeros(m,1);
		V     = sparse(nScan,nScan);
		for i = 1:length(xX.K)

			% extract blocks from bases
			%-----------------------------------------------
			q     = xX.K(i).row;
			p     = [];
			Qp    = {};
			for j = 1:m
				if nnz(xVi.Vi{j}(q,q))
					Qp{end + 1} = xVi.Vi{j}(q,q);
					p           = [p j];
				end
			end

			% design space for ReML (with confounds in filter)
			%-----------------------------------------------
			Xp         = xX.X(q,:);
			try
				Xp = [Xp xX.K(i).X0];
			end

			% ReML
			%-----------------------------------------------
			fprintf('%-30s- %i\n','  ReML Block',i);
			[Vp,hp]  = spm_reml(Cy(q,q),Xp,Qp);
			V(q,q)   = V(q,q) + Vp;
			h(p)     = hp;
		end
	else
		[V,h] = spm_reml(Cy,xX.X,xVi.Vi);
	end

	% normalize non-sphericity and save hyperparameters
	%---------------------------------------------------------------
	V           = V*nScan/trace(V);
	xVi.h       = h;
	xVi.V       = V;			% Save non-sphericity xVi.V
	xVi.Cy      = Cy;			%-spatially whitened <Y*Y'>
	SPM.xVi     = xVi;			% non-sphericity structure

	% If xX.W is not specified use W*W' = inv(V) to give ML estimators
	%---------------------------------------------------------------
	if ~isfield(xX,'W')
		save SPM SPM
		clear
		load SPM
		SPM = spm_spm(SPM);
		return
	end
end

%-Use non-sphericity xVi.V to compute [effective] degrees of freedom
%=======================================================================
xX.V            = spm_filter(xX.K,spm_filter(xX.K,W*V*W')');	% KWVW'K'
[trRV trRVRV]   = spm_SpUtil('trRV',xX.xKXs,xX.V);		% trRV (for X)
xX.trRV         = trRV;						% <R'*y'*y*R>
xX.trRVRV       = trRVRV;					%-Satterthwaite
xX.erdf         = trRV^2/trRVRV;				% approximation
xX.Bcov         = xX.pKX*xX.V*xX.pKX';				% Cov(beta)

%-Set VResMS scalefactor as 1/trRV (raw voxel data is ResSS)
%-----------------------------------------------------------------------
VResMS.pinfo(1) = 1/xX.trRV;
VResMS          = spm_create_vol(VResMS,'noopen');

%-Create 1st contrast for 'effects of interest' (all if not specified)
%=======================================================================
Fcname          = 'effects of interest';
try
	iX0     = [xX.iB xX.iG];
catch
	iX0     = [];
end
xCon            = spm_FcUtil('Set',Fcname,'F','iX0',iX0,xX.xKXs);

%-Append contrasts for fMRI - specified by SPM.Sess(s).Fc(i)
%-----------------------------------------------------------------------
if isfield(SPM,'Sess')
    for s = 1:length(SPM.Sess)
	for i = 1:length(SPM.Sess(s).Fc)
	    iX0           = 1:nBeta;
	    iX            = SPM.Sess(s).col(SPM.Sess(s).Fc(i).i);
	    iX0(iX)       = [];
	    Fcname        = sprintf('Sess(%d):%s',s,SPM.Sess(s).Fc(i).name);
	    xCon(end + 1) = spm_FcUtil('Set',Fcname,'F','iX0',iX0,xX.xKXs);
	end
    end
end

%-Smoothness estimates of component fields and RESEL counts for volume
%=======================================================================
try
	FWHM = SPM.xVol.FWHM;
	VRpv = SPM.xVol.VRpv;
	R    = SPM.xVol.R;
catch
	[FWHM,VRpv] = spm_est_smoothness(VResI,VM);
	R           = spm_resels_vol(VM,FWHM)';
end

%-Delete the residuals images
%=======================================================================
for  i = 1:nSres,
	spm_unlink([spm_str_manip(VResI(i).fname,'r') '.img']);
	spm_unlink([spm_str_manip(VResI(i).fname,'r') '.hdr']);
	spm_unlink([spm_str_manip(VResI(i).fname,'r') '.mat']);
end

%-Compute scaled design matrix for display purposes
%-----------------------------------------------------------------------
xX.nKX        = spm_DesMtx('sca',xX.xKXs.X,xX.name);

fprintf('%s%30s\n',sprintf('\b')*ones(1,30),'...done')               %-#

%-Save remaining results files and analysis parameters
%=======================================================================
fprintf('%-40s: %30s','Saving results','...writing')                 %-#

%-place fields in SPM
%-----------------------------------------------------------------------
SPM.xVol.XYZ   = XYZ(:,1:S);			%-InMask XYZ coords (voxels)
SPM.xVol.M     = M;				%-voxels -> mm
SPM.xVol.iM    = inv(M);			%-mm -> voxels
SPM.xVol.DIM   = DIM;				%-image dimensions
SPM.xVol.FWHM  = FWHM;				%-Smoothness data
SPM.xVol.R     = R;				%-Resel counts
SPM.xVol.S     = S;				%-Volume (voxels)
SPM.xVol.VRpv  = VRpv;				%-Filehandle - Resels per voxel

SPM.Vbeta      = Vbeta;				%-Filehandle - Beta
SPM.VResMS     = VResMS;			%-Filehandle - Hyperparameter
SPM.VM         = VM;				%-Filehandle - Mask

SPM.xVi        = xVi;				% non-sphericity structure
SPM.xVi.CY     = CY;				%-<(Y - <Y>)*(Y - <Y>)'>

SPM.xX         = xX;				%-design structure
SPM.xM         = xM;				%-mask structure

SPM.xCon       = xCon;				%-contrast structure

SPM.SPMid      = SPMid;
SPM.swd        = pwd;

%-Save analysis parameters in SPM.mat file
%-----------------------------------------------------------------------
save SPM SPM

%=======================================================================
%- E N D: Cleanup GUI
%=======================================================================
fprintf('%s%30s\n',sprintf('\b')*ones(1,30),'...done')               %-#
spm('FigName','Stats: done',Finter); spm('Pointer','Arrow')
fprintf('%-40s: %30s\n','Completed',spm('time'))                     %-#
fprintf('...use the results section for assessment\n\n')             %-#


function [val1,val2,val3,val4,val5,val6,val7] = dtiGetValFromTensors(dt6, coords, xform, valName, interpMethod)
% Interpolates dt6 tensor field and computes stats at each of the coords
%
%  [val1,val2,val3,val4,val5,val6,val7] = ...
%     dtiGetValFromTensors(dt6, coords, [xform], [valName], [interpMethod])
%
% This  also works for a scalar image in place of the dt6. In that case,
% 'valName' is ignored. (OK, but what does it do in that case? BW)
%
% Inputs:
%  xform: the transform that converts coords to dt6 indices. Default is
%    eye(4) (ie. no xform).  As an example,
%    dtiFiberGroupPropertyWeightedAverage sets the xform to
%    inv(dt.xformToAcpc).  This is the inverse of the transform from coords
%    to acpc, suggesting that the coords in there are acpc and the xform
%    maps from acpc to image space.
%  coords: Nx3 matrix of coords. The returned val will be of length N.  The
%    coords are often in ACPC space while the dt6 indices are in image
%    space.  So xform would move from ACPC to image, typically.
%  interpMethod: 'nearest', 'trilin' (default), 'spline'
%
% The values returned (val1, val2, etc.) differ depending on the string in
% valName.  The current valnaem options are:
%    - 'fa' (fractional anisotropy) (DEFAULT)
%    - 'md' (mean diffusivity)
%    - 'eigvals' (triplet of values for 1st, 2nd and 3rd eigenvalues)
%    - 'shapes' (triplet of values indicating linearity, planarity and
%              spherisity)
%    - 'dt6' (the full tensor in [Dxx Dyy Dzz Dxy Dxz Dyz] format
%    - 'pdd' (principal diffusion direction)
%    - 'linearity'
%    - 'fa md pdd', 'fa md ad rd', 'fa md pdd dt6'
%    - 'fa md ad rd shape'
%
% HISTORY:
% 2005.03.18 RFD (bob@white.stanford.edu) wrote it.
% 2006.08.07 RFD: we no longer set NaNs to 0. If there are missing
%   data, the caller should know about it and deal with as they wish.
% 2012.09 BW - Coments and consistency with other methods
%
% Bob (c) Stanford VISTA Team

%% Parameter initialization
if(~exist('xform','var') || isempty(xform)),  xform = eye(4); end
if(~exist('valName','var') || isempty(valName)),  valName = 'fa'; end
if(~exist('interpMethod','var') || isempty(interpMethod))
    interpMethod = 'trilin';
end
if(size(coords,2)~=3), coords = coords'; end
if(size(coords,2)~=3), error('coords must be an Nx3 array!'); end

% The coordinates are in YYY space. The data are in XXX space. We convert
% the coordinates from YYY space to XXX space. The parameter xfrom is the
% way to do the conversion, and this is sent in. Hence, this routine has no
% way to know what the coordinate frames are. Typically, the coordinates
% are in ACPC and we convert to image. A comment from someone who really
% knows would be nice (BW).
if(~all(all(xform==eye(4))))
    coords = mrAnatXformCoords(xform, coords);
end

%% Data volumetric interpolation
% We use the SPM interpolation interpolating the measurements to the
% sampling resolution of the coordinates.This requires some parameters that
% depend on the method.  Those parameters are set here.  A comment would be
% nice (BW).
switch lower(interpMethod)
    case 'nearest'
        interpParams = [0 0 0 0 0 0];
    case 'trilin'
        interpParams = [1 1 1 0 0 0];
    case 'spline'
        interpParams = [7 7 7 0 0 0];
    otherwise
        error(['Unknown interpMethod "' interpMethod '".']);
end
val_dt6 = zeros(size(coords,1), size(dt6,4));
for ii=1:size(dt6,4)
    bsplineCoefs  = spm_bsplinc(dt6(:,:,:,ii), interpParams);
    val_dt6(:,ii) = spm_bsplins(bsplineCoefs, coords(:,1), coords(:,2), coords(:,3), interpParams);
end
clear dt6 coords;

%% Initialize the returns.  Not all are used.
val1 = []; val2 = []; val3 = []; val4 = []; val5 = []; val6 = [];
if(size(val_dt6,2)~=6)
    % This might be the scalar case?  (BW)
    val1 = val_dt6(:,1);
    return;
end

% The user passes in with spaces and upper/lower variation.  We squeeze out
% the spaces and force to lower here.  That makes the switch easier.
valName = mrvParamFormat(valName);
switch lower(valName)
    case 'dt6'
        val1 = val_dt6(:,1);
        val2 = val_dt6(:,2);
        val3 = val_dt6(:,3);
        val4 = val_dt6(:,4);
        val5 = val_dt6(:,5);
        val6 = val_dt6(:,6);
    case 'eigvals'
        val_dt6 = reshape(val_dt6, [size(val_dt6,1) 1 1 6]);
        [nil, eigVal] = dtiSplitTensor(val_dt6);
        val1 = squeeze(eigVal(:,:,:,1));
        val2 = squeeze(eigVal(:,:,:,2));
        val3 = squeeze(eigVal(:,:,:,3));
    case 'fa'
        val_dt6 = reshape(val_dt6, [size(val_dt6,1) 1 1 6]);
        [nil, eigVal] = dtiSplitTensor(val_dt6);
        val1 = dtiComputeFA(eigVal);
        %val(isnan(val)) = 0;
    case 'md'
        % mean diffusivity: trace/3, where trace is the sum of the diagonal
        % elements (ie. the first three dt6 values)
        val1 = sum(val_dt6(:,1:3),2)./3;
    case {'shapes','linearity'}
        val_dt6 = reshape(val_dt6, [size(val_dt6,1) 1 1 6]);
        [eigVec, eigVal] = dtiSplitTensor(val_dt6);
        [val1, val2, val3] = dtiComputeWestinShapes(eigVal);
    case 'pdd'
        % principal diffusion direction
        val_dt6 = reshape(val_dt6, [size(val_dt6,1) 1 1 6]);
        [eigVec, eigVal] = dtiSplitTensor(val_dt6);
        val1 = squeeze(eigVec(:,:,:,[1 2 3],1)); % Should be [1 3 2]?
        %val(isnan(val)) = 0;
    case 'famdpdd'
        % FA, Mean diffusivity, PDD
        val_dt6 = reshape(val_dt6, [size(val_dt6,1) 1 1 6]);
        [eigVec, eigVal] = dtiSplitTensor(val_dt6);
        val1 = dtiComputeFA(eigVal);
        %val(isnan(val)) = 0;
        val2 = sum(val_dt6(:,1:3),2)./3;
        val3 = squeeze(eigVec(:,:,:,[1 2 3],1)); % Should be [1 3 2]?
        %val3(isnan(val3)) = 0;
    case 'famdadrd'
        % FA, mean diffusivity, axial diffusivity, radial diffusivity
        val_dt6 = reshape(val_dt6, [size(val_dt6,1) 1 1 6]);
        [eigVec, eigVal] = dtiSplitTensor(val_dt6);
        val1 = dtiComputeFA(eigVal);  % FA
        %val(isnan(val)) = 0;
        val2 = sum(val_dt6(:,1:3),2)./3;  % Mean diffusivity
        val3 = squeeze(eigVal(:,:,:,1));  % Axial diffusivity
        val4 = squeeze(eigVal(:,:,:,2)+eigVal(:,:,:,3))./2; % Radial
    case 'famdpdddt6'
        % FA MD PDD DT6
        val_dt6 = reshape(val_dt6, [size(val_dt6,1) 1 1 6]);
        [eigVec, eigVal] = dtiSplitTensor(val_dt6);
        val1 = dtiComputeFA(eigVal);
        %val(isnan(val)) = 0;
        val2 = sum(val_dt6(:,1:3),2)./3;
        val3 = squeeze(eigVec(:,:,:,[1 2 3],1)); % Should be [1 3 2]?
        %val3(isnan(val3)) = 0;
        val4 = val_dt6;
    case 'famdadrdshape'
        % FA MD AD RD shape
        val_dt6 = reshape(val_dt6, [size(val_dt6,1) 1 1 6]);
        [eigVec, eigVal] = dtiSplitTensor(val_dt6);
        val1 = dtiComputeFA(eigVal);
        %val(isnan(val)) = 0;
        val2 = sum(val_dt6(:,1:3),2)./3;
        val3 = squeeze(eigVal(:,:,:,1));
        val4 = squeeze(eigVal(:,:,:,2)+eigVal(:,:,:,3))./2;
        %val5=linearity (cp); val6=planarity (cp); val7=sphericity (cs)
        [val5, val6, val7] = dtiComputeWestinShapes(eigVal);

    otherwise
        error(['Unknown tensor value "' valName '".']);
end

return


function CPD = tree_CPD(varargin)
%DTREE_CPD Make a conditional prob. distrib. which is a decision/regression tree.
%
% CPD =dtree_CPD() will create an empty tree.

if nargin==0
  % This occurs if we are trying to load an object from a file.
  CPD = init_fields;
  clamp = 0;
  CPD = class(CPD, 'tree_CPD', discrete_CPD(clamp, []));
  return;
elseif isa(varargin{1}, 'tree_CPD')
  % This might occur if we are copying an object.
  CPD = varargin{1};
  return;
end

CPD = init_fields;

clamped = 0;
fam_sz = [];
CPD = class(CPD, 'tree_CPD', discrete_CPD(clamped, fam_sz));

%%%%%%%%%%%

function CPD = init_fields()
% This ensures we define the fields in the same order
% no matter whether we load an object from a file,
% or create it from scratch. (Matlab requires this.)

%init the decision tree set the root to null
CPD.tree.num_node = 0;
CPD.tree.root=1;
CPD.tree.nodes=[];


function wav = readAlaw(file_name)

FILE = fopen( file_name );
if FILE < 0
    fprintf('File open error: %s\n', file_name);
    return;
end

data = fread(FILE, 'uint8');
wav = pcma2lin(data);
% plot(wav); pause;
% clear binData;
% binChars = dec2bin(data);
% for i=1:8
%     binData(:,i) = str2num(binChars(:,i));
% end

fclose(FILE);


%CODEGENERATOR.GENMFUNFKINE Generate M-function for forward kinematics
%
% cGen.genmfunfkine() generates a robot-specific M-function to compute
% forward kinematics.
%
% Notes::
% - Is called by CodeGenerator.genfkine if cGen has active flag genmfun
% - Access to generated function is provided via subclass of SerialLink
%   whose class definition is stored in cGen.robjpath.
%
% Author::
%  Joern Malzahn, (joern.malzahn@tu-dortmund.de)
%
% See also CodeGenerator.CodeGenerator, CodeGenerator.genjacobian.

% Copyright (C) 2012-2014, by Joern Malzahn
%
% This file is part of The Robotics Toolbox for Matlab (RTB).
%
% RTB 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.
%
% RTB 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 RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com
%
% The code generation module emerged during the work on a project funded by
% the German Research Foundation (DFG, BE1569/7-1). The authors gratefully
% acknowledge the financial support.

function [] = genmfunfkine(CGen)

%% Does robot class exist?
if ~exist(fullfile(CGen.robjpath,[CGen.getrobfname,'.m']),'file')
    CGen.logmsg([datestr(now),'\tCreating ',CGen.getrobfname,' m-constructor ']);
    CGen.createmconstructor;
    CGen.logmsg('\t%s\n',' done!');
end

%% Forward kinematics up to tool center point
CGen.logmsg([datestr(now),'\tGenerating forward kinematics m-function up to the end-effector frame: ']);
symname = 'fkine';
fname = fullfile(CGen.sympath,[symname,'.mat']);

if exist(fname,'file')
    tmpStruct = load(fname);
else
    error ('genmfunfkine:SymbolicsNotFound','Save symbolic expressions to disk first!')
end

funfilename = fullfile(CGen.robjpath,[symname,'.m']);
q = CGen.rob.gencoords;

matlabFunction(tmpStruct.(symname).T,'file',funfilename,...              % generate function m-file
    'outputs', {symname},...
    'vars', {'rob',[q]});
hStruct = createHeaderStructFkine(CGen.rob,symname);                 % replace autogenerated function header
replaceheader(CGen,hStruct,funfilename);
CGen.logmsg('\t%s\n',' done!');

%% Individual joint forward kinematics
CGen.logmsg([datestr(now),'\tGenerating forward kinematics m-function up to joint: ']);
for iJoints=1:CGen.rob.n

    CGen.logmsg(' %i ',iJoints);
    symname = ['T0_',num2str(iJoints)];
    fname = fullfile(CGen.sympath,[symname,'.mat']);

    tmpStruct = struct;
    tmpStruct = load(fname);

    funfilename = fullfile(CGen.robjpath,[symname,'.m']);
    q = CGen.rob.gencoords;

    matlabFunction(tmpStruct.(symname).T,'file',funfilename,...              % generate function m-file
        'outputs', {symname},...
        'vars', {'rob',[q]});
    hStruct = createHeaderStruct(CGen.rob,iJoints,symname);                 % replace autogenerated function header
    CGen.replaceheader(hStruct,funfilename);
end
CGen.logmsg('\t%s\n',' done!');

end

%% Definition of the header contents for each generated file
function hStruct = createHeaderStruct(rob,curBody,fname)
[~,hStruct.funName] = fileparts(fname);
hStruct.shortDescription = ['Forward kinematics for the ',rob.name,' arm up to frame ',int2str(curBody),' of ',int2str(rob.n),'.'];
hStruct.calls = {['T = ',hStruct.funName,'(rob,q)'],...
    ['T = rob.',hStruct.funName,'(q)']};
hStruct.detailedDescription = {['Given a set of joint variables up to joint number ',int2str(curBody),' the function'],...
    'computes the pose belonging to that joint with respect to the base frame.'};
hStruct.inputs = {['q:  ',int2str(curBody),'-element vector of generalized coordinates.'],...
    'Angles have to be given in radians!'};
hStruct.outputs = {['T:  [4x4] Homogenous transformation matrix relating the pose of joint ',int2str(curBody),' of ',int2str(rob.n)],...
    '          for the given joint values to the base frame.'};
hStruct.references = {'1) Robot Modeling and Control - Spong, Hutchinson, Vidyasagar',...
    '2) Modelling and Control of Robot Manipulators - Sciavicco, Siciliano',...
    '3) Introduction to Robotics, Mechanics and Control - Craig',...
    '4) Modeling, Identification & Control of Robots - Khalil & Dombre'};
hStruct.authors = {'This is an autogenerated function!',...
    'Code generator written by:',...
    'Joern Malzahn',...
    '2012 RST, Technische Universitaet Dortmund, Germany',...
     'http://www.rst.e-technik.tu-dortmund.de'};
hStruct.seeAlso = {rob.name};
end

%% Definition of the header contents for each generated file
function hStruct = createHeaderStructFkine(rob,fname)
[~,hStruct.funName] = fileparts(fname);
hStruct.shortDescription = ['Forward kinematics solution including tool transformation for the ',rob.name,' arm.'];
hStruct.calls = {['T = ',hStruct.funName,'(rob,q)'],...
    ['T = rob.',hStruct.funName,'(q)']};
hStruct.detailedDescription = {['Given a full set of joint variables the function'],...
    'computes the pose belonging to that joint with respect to the base frame.'};
hStruct.inputs = { ['rob: robot object of ', rob.name, ' specific class'],...
                   ['q:  ',int2str(rob.n),'-element vector of generalized'],...
                   '     coordinates',...
                   'Angles have to be given in radians!'};
hStruct.outputs = {['T:  [4x4] Homogenous transformation matrix relating the pose of the tool'],...
    '          for the given joint values to the base frame.'};
hStruct.references = {'1) Robot Modeling and Control - Spong, Hutchinson, Vidyasagar',...
    '2) Modelling and Control of Robot Manipulators - Sciavicco, Siciliano',...
    '3) Introduction to Robotics, Mechanics and Control - Craig',...
    '4) Modeling, Identification & Control of Robots - Khalil & Dombre'};
hStruct.authors = {'This is an autogenerated function!',...
    'Code generator written by:',...
    'Joern Malzahn',...
    '2012 RST, Technische Universitaet Dortmund, Germany',...
     'http://www.rst.e-technik.tu-dortmund.de'};
hStruct.seeAlso = {'jacob0'};
end


classdef DensityPlotterForPerimeter < handle

    properties (Access = private)
        inputFile
        mesh
        scale
        density
        densityVariable
        plotter
    end

    methods (Access = public)

        function obj = DensityPlotterForPerimeter(cParams)
            obj.init(cParams)
        end

        function plot(obj)
            obj.createDesignVariable();
            obj.createPlotter();
            obj.plotter.refresh();
        end

    end

    methods (Access = private)

        function init(obj,cParams)
            obj.mesh       = cParams.mesh;
            obj.inputFile  = cParams.inputFile;
            obj.scale      = cParams.scale;
            obj.density    = cParams.density;
        end

        function createDesignVariable(obj)
            s.mesh      = obj.mesh;
            s.inputFile = obj.inputFile;
            s.scale     = obj.scale;
            s.type      = 'Density';
            d = DesignVariableCreatorSettings(s);
            s = d.create();
            obj.densityVariable       = DesignVariable.create(s);
            obj.densityVariable.update(obj.density);
            obj.densityVariable.rho   = obj.density;
        end

        function createPlotter(obj)
            sD.shallDisplay   = true;
            sD.showBC         = false;
            sD.bc             = false;
            sD.designVariable = obj.densityVariable;
            sD.optimizerNames = '';
            sD.dim            = '2D';
            sD.scale          = obj.scale;
            sD.mesh           = Mesh_Total(obj.mesh);
            f = DesignVarMonitorFactory;
            obj.plotter = f.create(sD);
        end

    end

end


function out = floor(in)

out = cellfun(@floor, in, 'uniformoutput', 0);


function cosmo_plot_slices(data, dim, slice_step, slice_start, slice_stop)
% Plots a set of slices from a dataset, nifti image, or 3D data array
%
% cosmo_plot_slices(data[, dim][, slice_step][, slice_start][, slice_stop])
%
% Inputs:
%  data         an fmri dataset (e.g., from cosmo_fmri_dataset), or a 3D
%               array with data. data should contain samples from a single
%               volume (sample) only.
%  dim          dimension according to which slices are plotted
%               (default: 3). Values between 1 and 3 allows using a
%               saggital, axial or coronal view; but the mapping between
%               the 3 numbers and 3 views depends on the particular
%               orientation of the data.
%  slice_step   step between slices (default: 1). If negative then
%               -slice_step indicates the number of slices
%  slice_start  the index of the first slice to plot (default: 1).
%  slice_stop   the index of the last slice to plot (default: the number of
%               slices in the dim-th dimension).
%
% Examples:
%    % plot an fMRI dataset struct with default options
%    cosmo_plot_slices(ds)
%
%    % plot an fMRI dataset struct along the second spatial dimension
%    cosmo_plot_slices(ds, 2)
%
%    % plot a random gaussian 3D array along the first dimension
%    cosmo_plot_slices(randn([40,50,20]),1)
%
%    % plot an fMRI dataset struct along the default spatial dimension
%    % every 5-th slice
%    cosmo_plot_slices(ds, [], 5)
%
%    % plot an fMRI dataset struct along the third spatial dimension
%    % with about 12 slices
%    cosmo_plot_slices(ds, 3, -12)
%
%    % plot an fMRI dataset struct along the third spatial dimension
%    % with about 12 slices, starting at slice 10 and stopping at slice 25
%    cosmo_plot_slices(ds, 3, -12, 10, 25)
%
% Notes:
%  - Using this function only really makes sense for fMRI-like data.
%  - This function does not provide a consistent orientation for slices,
%    as this depends on the voxel-to-world transformation matrix, which is
%    completely ignored in this function. Thus left-right and top-down
%    swaps can occur. Different datasets may provide different views, for
%    example dim=1 may give a saggital view if the dataset comes from one
%    program and an axial view if it comes from another program.
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #

    if nargin<2 || isempty(dim), dim=3; end
    if nargin<3 || isempty(slice_step), slice_step=-20; end
    if nargin<4 || isempty(slice_start), slice_start=1; end
    if nargin<5 || isempty(slice_stop), slice_stop=[]; end % set later

    data3D=get_data3D(data);

    % get min and max values across the entire volume
    data_lin=data3D(:);
    mn=min(data_lin);
    mx=max(data_lin);

    % shift it so that we can walk over the first dimension
    data_sh=shiftdim(data3D, dim-1);

    if isempty(slice_stop)
        slice_stop=size(data_sh,1);
    end

    if slice_step<0
        nslices=-slice_step;
        slice_step=ceil((slice_stop-slice_start+1)/nslices);
    end

    % determine which slices to show
    slice_idxs=slice_start:slice_step:slice_stop;
    nslices=numel(slice_idxs);

    plot_ratio=.8; % ratio between number of rows and colums
    nrows=ceil(sqrt(nslices)*plot_ratio);
    ncols=ceil(nslices/nrows);

    % use header depending on dim
    header_labels={'i','j','k'};

    % order of slices and whether the slice should be transposed
    xorder=[-1 -1 1];
    yorder=[-1 1 -1];
    do_transpose=[true false true];

    for k=1:nslices
        slice_idx=slice_idxs(k);
        slice=squeeze(data_sh(slice_idx,:,:));

        if xorder(dim)<0
            slice=slice(end:-1:1,:);
        end
        if yorder(dim)<0
            slice=slice(:,end:-1:1);
        end
        if do_transpose(dim)
            slice=slice';
        end

        subplot(nrows, ncols, k);
        imagesc(slice, [mn, mx]);
        title(sprintf('%s = %d', header_labels{dim}, slice_idx));
    end

function data3D=get_data3D(data)
    if isstruct(data)
        cosmo_check_dataset(data,'fmri');
        data4D=cosmo_unflatten(data);
        sz=size(data4D);
        if sz(1)>1
            error(['expected single volume data, but found %d '...
                    'volumes. To select a single volume, use '...
                    'cosmo_slice. For example, to show the %d-th '...
                    'volume from a dataset struct ds, use:\n\n   '...
                    'cosmo_plot_slices(cosmo_slice(ds,%d))\n'],...
                    sz(1),sz(1),sz(1));
        end

        if numel(sz)>4
            error('data must be 4D');
        end

        data3D=reshape(data4D, sz(2:end));
    elseif isnumeric(data) || islogical(data)
        ndim=numel(size(data));
        if ndim>3
            error('expected 3D image - did you select a single volume?');
        end
        data3D=data;
    else
        error('illegal input: expected dataset or 3D array');
    end


function output = deformation(input, displacementField, interpolation)
% DEFORMATION Deforms an image according to the given displacement field
%
% output = deformation(input, displacementField, interpolation)
%
% INPUT ARGUMENTS
% input                 - Data to deform
% displacementField     - Displacement field
% interpolation         - Interpolation method
%
% OPTIONAL INPUT ARGUMENTS
% N/A
%
% OUTPUT ARGUMENTS
% output                - Deformed data

% Copyright (c) 2012 Daniel Forsberg
% danne.forsberg@outlook.com
%
% 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/>.

if isempty(input)
    output = input;
    return;
end

dims = length(size(input));
sz = size(input);

if (dims == 2)
    [X,Y] = meshgrid(1:sz(2), 1:sz(1));
    output = ba_interp2(input, X+displacementField{1}, ...
        Y+displacementField{2}, interpolation);
elseif (dims == 3)
    [X,Y,Z] = meshgrid(1:sz(2), 1:sz(1), 1:sz(3));
    output = ba_interp3(input, X+displacementField{1}, ...
        Y+displacementField{2}, Z+displacementField{3}, ...
        interpolation);
end


function test_suite=test_mask_dim_intersect
% tests for test_mask_dim_intersect
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #
    try % assignment of 'localfunctions' is necessary in Matlab >= 2016
        test_functions=localfunctions();
    catch % no problem; early Matlab versions can use initTestSuite fine
    end
    initTestSuite;

function test_mask_dim_intersect_feature_dim()
    helper_test_mask_dim_intersect(2)

function test_mask_dim_intersect_sample_dim()
    helper_test_mask_dim_intersect(1)

function helper_test_mask_dim_intersect(dim)
    other_dim=3-dim;

    n_ds=ceil(rand()*2+2);
    keep_ratio=.8;

    ds_cell=cell(n_ds,1);
    for k=1:n_ds
        if dim==1
            % optimalization due to somewhat slow dim_transpose
            sz='small';
        else
            sz='big';
        end

        ds=cosmo_synthetic_dataset('size',sz,'seed',0,...
                                    'nchunks',1,'ntargets',1);
        n_features=size(ds.samples,2);
        ds.samples=1:n_features;

        rp=randperm(n_features);
        keep_indices=round(1:(keep_ratio*n_features));

        ds_keep=cosmo_slice(ds,rp(keep_indices),2);

        if dim==1
            ds_keep=cosmo_dim_transpose(ds_keep,ds.a.fdim.labels,1);
        end

        ds_indices=ds_keep;

        % fill with random data so that the function to test cannot
        % use the indices
        ds_data=ds_keep;
        ds_data.samples=randn(size(ds_keep.samples));

        % the first row has random data, and is used as input for %
        % cosmo_mask_dim_intersect; the second row has indices, and is
        % used to verify the proper contents of the datasets
        ds_cell{k}=cosmo_stack({ds_data,ds_indices},other_dim);
    end

    ds_data_cell=cellfun(@(x)cosmo_slice(x,1,other_dim),ds_cell,...
                            'UniformOutput',false);

    [indices,ds_intersect_cell]=cosmo_mask_dim_intersect(ds_data_cell,dim);

    if dim==2
        % must have same output using default second argument
        [indices2,ds_intersect_cell2]=cosmo_mask_dim_intersect(...
                                            ds_data_cell);

        assertEqual(indices,indices2);
        assertEqual(ds_intersect_cell,ds_intersect_cell2);
    end

    % verify ds_intersect_cell based on indices
    assert(iscell(ds_intersect_cell));
    assertEqual(size(ds_intersect_cell),size(ds_data_cell));
    for k=1:n_ds
        idx=indices{k};
        assert(all(idx>0));
        assert(all(isfinite(idx)));
        assertEqual(cosmo_slice(ds_data_cell{k},idx,dim),...
                                ds_intersect_cell{k})
    end

    ds_indices_cell=cellfun(@(x)cosmo_slice(x,2,other_dim),ds_cell,...
                            'UniformOutput',false);

    % see which indices are common across all datasets
    ds_keep_indices=1:n_features;
    for k=1:n_ds
        ds_idx=ds_indices_cell{k}.samples;
        assertEqual(sort(ds_idx),unique(ds_idx));
        ds_keep_indices=intersect(ds_keep_indices, ds_idx);
    end

    % verify that indices match across all datasets
    for k=1:n_ds
        % select indices
        idx=ds_indices_cell{k}.samples(indices{k});

        % indices must be unique
        if isempty(idx)
            assert(isempty(ds_keep_indices));
        else
            assertEqual(sort(idx(:)),sort(ds_keep_indices(:)));
        end

        % must return indices in the same order
        ds_sel=cosmo_slice(ds_indices_cell{k},indices{k},dim);
        if k==1
            first_ds_sel=ds_sel;
        else
            assertEqual(first_ds_sel,ds_sel)
        end
    end

function test_mask_dim_intersect_identity
    % after permuting the features, dataset should be identical following
    % unpermuting them

    types={'fmri','surface','source','timelock','timefreq'};

    for k=1:numel(types)
        type=types{k};
        ds=cosmo_synthetic_dataset('size','big','type',type,...
                                        'ntargets',1,'nchunks',1);

        switch type
            case 'source'
                args={'matrix_labels',{'pos'}};
            otherwise
                args={};
        end
        n_features=size(ds.samples,2);
        ds.samples(1,:)=1:n_features;

        rp=randperm(n_features);
        ds=cosmo_slice(ds,rp,2);

        [indices_cell,ds_cell]=cosmo_mask_dim_intersect({ds},2,args{:});
        assert(numel(indices_cell)==1);
        assert(numel(ds_cell)==1);

        idx=indices_cell{1};
        ds_perm=ds_cell{1};

        assertEqual(sort(idx),1:n_features);
        ds_reordered=cosmo_slice(ds,idx,2);
        assertEqual(ds_perm,ds_reordered);

        % indices must be sorted
        assertEqual(ds_perm.samples,1:n_features);

    end

function test_mask_dim_intersect_exceptions()
    aet=@(varargin)assertExceptionThrown(@()...
                        cosmo_mask_dim_intersect(varargin{:}),'');
    % cannot deal with empty
    aet(cosmo_synthetic_dataset());

    % input must be a cell with datasets
    aet(struct);
    aet('foo');
    aet({struct,struct});

    % repeated features not supported
    ds=cosmo_synthetic_dataset('size','big');
    ds2=cosmo_stack({ds,ds},2);
    aet({ds2});

    % not even a single feature duplicated is allowed
    col_index=ceil(rand()*size(ds.samples,2));
    ds_extra_col=cosmo_stack({ds,cosmo_slice(ds,col_index,2)},2);
    aet(ds_extra_col);

    % dim must be 1 or 2
    aet({ds},3);
    aet({ds},struct);
    aet({ds},[1 2]);

function test_mask_dim_intersect_missing_dim()
    ds1=cosmo_synthetic_dataset();
    ds2=ds1;
    ds2.fa=rmfield(ds2.fa,'k');

    assertEqual(ds1.samples,ds2.samples);
    assertExceptionThrown(@()cosmo_mask_dim_intersect({ds1,ds2}),'');

function test_mask_dim_intersect_nonmatching_dim()
    ds1=cosmo_synthetic_dataset();
    ds2=ds1;
    ds2=cosmo_dim_remove(ds2,'k');

    assertEqual(ds1.samples,ds2.samples);
    assertExceptionThrown(@()cosmo_mask_dim_intersect({ds1,ds2}),'');

function test_mask_dim_intersect_renamed_dim()
    ds1=cosmo_synthetic_dataset();
    ds2=ds1;
    ds2=cosmo_dim_rename(ds2,'k','kk');

    assertEqual(ds1.samples,ds2.samples);
    assertExceptionThrown(@()cosmo_mask_dim_intersect({ds1,ds2}),'');


function illustrate_ppp(ResultsAllCellLines,mets,path,samples,label,fonts,tol)
% This function generates and saves heatmaps for the results of the function
% performPPP for all sample models.
%
% USAGE:
%
%     illustrate_ppp(ResultsAllCellLines, mets, path, samples, label, fonts, tol)
%
% INPUTS:
%    ResultsAllCellLines:     Result structure
%    mets:                    Metabolites that were tested in the phase plane analysis
%    step_size:               Step size of each metabololite tested
%    path:                    Path where output is saved
%    samples:                 Names of conditions
%    label:                   Defining label of X-axis, y-axis and z-axis, e.g., {`Glucose uptake (fmol/cell/hr)`; `Oxygen uptake
%                             (fmol/cell/hr)`; `Growth rate (hr-1)`} The z-axis is the growth rate which is color coded
%    fonts:                   Font size for labels on heatmap
%    tol:                     Fluxes are considered zero if they are below the tol
%
% Individual pdf files showing the result of the PPP are being saved automatically for each condition.
%
% .. Author: - Maike K. Aurich 19/02/15

k=1;

for i=1:length(samples)

    for p=1:size(mets,2)
              if contains(mets{p,1},'[')
         name  = ['phasePlane_' strtok(mets{1,p}, '[') '_' strtok(mets{2,p}, '[')];
        else
        name  = ['phasePlane_' strtok(mets{1,p}, '(') '_' strtok(mets{2,p}, '(')];
              end
        %load condition specific performPPP result
        growthRates = ResultsAllCellLines.(samples{i}).(name).growthRates;
        bounds = ResultsAllCellLines.(samples{k}).(name).bounds;

        %chop off the additional entries in bounds
        ivalues=bounds(1:size(growthRates,1),1);
        jvalues=bounds(1:size(growthRates,2),2);

        % to mark the reaction bounds in the pruned model onto the phase plane
        modelPruned = eval(['ResultsAllCellLines.' samples{i} '.modelPruned']);
        lb = modelPruned.lb(find(ismember(modelPruned.rxns, mets{1,p})));
        ub = modelPruned.ub(find(ismember(modelPruned.rxns, mets{1,p})));
        clear modelPruned

        %make title
        name = regexprep(samples{i},'_','-');
        title_name = ['Objective values under variation of ' regexprep(mets{1,p},'_','-') ' and ' regexprep(mets{2,p},'_','-') ' in ' name];
       % define max of z-axis, which is the growth rate and color coded
%        zmax = eval(['ResultsAllCellLines.' samples{i} '.maxBiomass.f'])+ 0.001;
        zmax=eval(['ResultsAllCellLines.' samples{i} '.maxBiomass.f'])+ 0.001;;
        B = growthRates;
        % set values below tol as zero
        B(find(abs(B)<abs(tol)))=0;
        B(find(B==0))=nan; % remove zero as value

        % 3D plot
        figure1=figure;
        axes1 = axes('Parent',figure1);
        surf(ivalues',jvalues',B','Parent',axes1,'SpecularStrength',0.4,...
            'AmbientStrength',0.55,...
            'LineStyle','none');

        colorbar('peer',axes1);

        lowToHigh = [2 15];
        caxis(lowToHigh + [-1 1]*diff(lowToHigh));

        % set viewpoint
        az = 0;
        el = 90;
        view(az, el);

        %hold off
        hold on
        plot3([lb,lb],[0,-10],[zmax,zmax],'Color',[0 0 0],'LineWidth',1.2);

        hold on
        plot3([ub,ub],[-10,0],[zmax,zmax],'Color',[0 0 0],'LineWidth',1.2);

        hold off
        xlabel(label(1,1),'FontSize',fonts);
        ylabel(label(2,1),'FontSize',fonts);
        zlabel(label(3,1),'FontSize',fonts);
        title(title_name,'FontSize',fonts);
        axis tight %% seems to limit the axis, excludes white edge
              set(gcf, 'PaperUnits', 'inches');
        zlim([0 32]) % z-axis now from 0 to 10
        x_width=8 ;y_width=6;
        set(gcf, 'PaperPosition', [0 0 x_width y_width]); %
        name  = [ 'phasePlane_' samples{i} '_' strtok(mets{1,p}, '(') '_' strtok(mets{2,p}, '(')];
        saveas(gcf,[path filesep name '.pdf']);
        % saveas(gcf,[path filesep name '.png']);
        clear ivalues
        clear jvalues
    end

end
end


function candoit = canGetHessian(problem)
% Checks whether the Hessian can be computed for a problem structure.
%
% function candoit = canGetHessian(problem)
%
% Returns true if the Hessian of the cost function can be computed given
% the problem description, false otherwise.
%
% See also: canGetCost canGetDirectionalDerivative canGetGradient

% This file is part of Manopt: www.manopt.org.
% Original author: Nicolas Boumal, Dec. 30, 2012.
% Contributors:
% Change log:

    candoit = isfield(problem, 'hess') || ...
              (isfield(problem, 'ehess') && canGetEuclideanGradient(problem));

end


%% (Internal) Create a colormap for signal visualization
%
%   colors = my_colormap( cant_colors )
%
% Arguments:
%
%      + cant_colors: amount of colors required
%
% Output:
%
%      + colors: the colormap created
%
% Example:
%
% Author: Mariano Llamedo Soria llamedom@electron.frba.utn.edu.ar
% Version: 0.1 beta
% Last update: 14/5/2014
% Birthdate  : 21/4/2015
% Copyright 2008-2015
%
function colors = my_colormap( cant_colors )
colors = hsv(64);

%avoid yellowish colours
bAux = colors(:,1) > 200/255 & colors(:,2) > 200/255 & colors(:,3) == 0;
if( any(bAux) )
    colors( bAux,: ) = repmat([200 200 0]./255, sum(bAux),1 );
end

ncol = size(colors,1);

aux_idx = 1+rem(round(round(ncol/6)+linspace(0, (round(ncol/2)+1)*(ncol-1), ncol)), ncol);
if( cant_colors > 4 )
    colors = colors( aux_idx(round(linspace(1,64, cant_colors))) , :);
else
    colors = colors( aux_idx(1:cant_colors) , :);
end


function [d,dt]=formatts(d)
%
% Usage: [d,dt]=formatts(d)
%
% Helper function for CWT,XWT,WTC
%
% Brings a timeseries into a shape so that it has two columns: [time, value].
%
%
% (C) Aslak Grinsted 2002-2004
%

% -------------------------------------------------------------------------
%   Copyright (C) 2002-2004, Aslak Grinsted
%   This software may be used, copied, or redistributed as long as it is not
%   sold and this copyright notice is reproduced on each copy made.  This
%   routine is provided as is without any express or implied warranties
%   whatsoever.

if (ndims(d)>2)
    error('Input time series should be 2 dimensional.');
end
if (numel(d)==length(d))
    d=[(1:length(d))' d(:)];
end
if size(d,1)<size(d,2)
    d=d';
end
if (size(d,2)~=2)
    error('Time series must have 2 columns.')
end

if (d(2,1)-d(1,1)<0)
    d=flipud(d);
end

dt=diff(d(:,1));
if any(abs(dt-dt(1))>1e-1*dt(1))
    error('Time step must be constant.');
end
if (dt==0)
    error('Time step must be greater than zero.')
end

dt=dt(1);


function [RF] = trainRF_table(table,Y,categories,nBoot,cost)

[trainSets,~] = buildBootSet(Y,nBoot,'NoAdjust');

RF = applyEnsembleRF_table(table(trainSets(:,1),:),Y(trainSets(:,1)),categories,cost);
for n = 2:nBoot
   RFtemp = applyEnsembleRF_table(table(trainSets(:,n),:),Y(trainSets(:,n)),categories,cost);
   RF = append(RF,RFtemp);
end

end


function unit = ft_estimate_units(size)

% FT_ESTIMATE_UNITS tries to determine the units of a geometrical object by
% looking at its size and by relating this to the size of the human
% brain.
%
% Use as
%   unit = ft_estimate_units(size)
%
% This function will return one of the following strings
%   'm'
%   'dm'
%   'cm'
%   'mm'

% Copyright (C) 2009, 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: ft_estimate_units.m 2885 2011-02-16 09:41:58Z roboos $

% do some magic based on the size
unit = {'m', 'dm', 'cm', 'mm'};
indx = round(log10(size)+2-0.2);

if indx>length(unit)
  indx = length(unit);
  warning('assuming that the units are "%s"', unit{indx});
end

if indx<1
  indx = 1;
  warning('assuming that the units are "%s"', unit{indx});
end

unit = unit{indx};


function test_bug1775

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_sourceparcellate ft_checkdata ft_datatype_source ft_datatype_volume ft_datatype_parcellation ft_datatype_segmentation

%% create a set of sensors
[pnt, tri] = mesh_sphere(162);
pnt = pnt .* 10; % convert to cm
sel = find(pnt(:,3)>0);

grad.pnt = pnt(sel,:) .* 1.2;
grad.ori = pnt(sel,:);
grad.tra = eye(length(sel));
for i=1:length(sel)
  grad.ori(i,:) = grad.ori(i,:) ./ norm(grad.ori(i,:));
  grad.label{i} = sprintf('magnetometer%d', i);
end
grad.unit = 'cm';
grad.type = 'meg';

grad = ft_datatype_sens(grad);

%% create a volume conductor

vol = [];
vol.r     = 10;
vol.o     = [0 0 0];
vol.unit  = 'cm';

vol = ft_datatype_headmodel(vol);

%% create some precomputed leadfields

cfg = [];
cfg.grad            = grad;
cfg.headmodel       = vol;
cfg.resolution      = 2; % cm
cfg.channel         = 'all';
grid = ft_prepare_leadfield(cfg);

%% create an anatomical parcellation
parcellation = [];
parcellation.pos          = grid.pos;
parcellation.unit         = grid.unit;
parcellation.tissue       = zeros(size(grid.pos,1),1);
parcellation.tissuelabel  = {};
height = [3 4 5 6 7 8 9];
for i=1:length(height)
  sel = parcellation.pos(:,3)==height(i);
  parcellation.tissue(sel) = i;
  parcellation.tissuelabel{i} = sprintf('%d%s', height(i), parcellation.unit);
end
parcellation.cfg = 'manual'; % to check whether the provenance is correct

%% create simulated data
cfg = [];
cfg.grad = grad;
cfg.headmodel = vol;
cfg.dip.pos = [0 0 4];
data = ft_dipolesimulation(cfg);

cfg = [];
cfg.covariance = 'yes';
timelock = ft_timelockanalysis(cfg, data);

cfg = [];
cfg.method  = 'mtmfft';
cfg.taper   = 'hanning';
freq1 = ft_freqanalysis(cfg, data);

cfg = [];
cfg.method  = 'wavelet';
cfg.toi     = data.time{1};
freq2 = ft_freqanalysis(cfg, data);

cfg = [];
cfg.grad        = grad;
cfg.headmodel   = vol;
cfg.sourcemodel = grid;
cfg.method      = 'lcmv';
source1 = ft_sourceanalysis(cfg, timelock);

cfg = [];
cfg.grad        = grad;
cfg.headmodel   = vol;
cfg.sourcemodel = grid;
cfg.method      = 'mne';
cfg.mne.lambda  = 0;
source2 = ft_sourceanalysis(cfg, timelock);

%% make some parcellations
cfg = [];
gridp    = ft_sourceparcellate(cfg, grid, parcellation);
source1p = ft_sourceparcellate(cfg, source1, parcellation);
source2p = ft_sourceparcellate(cfg, source2, parcellation);

%% construct a more complex source structure
% note that this increases memory requirements
source3 = [];
source3.pos       = source2.pos;
source3.freq      = 1:5;
source3.coh       = randn(size(source2.pos,1), size(source2.pos,1), 5);
source3.cohdimord = 'pos_pos_freq';

cfg = [];
source3p = ft_sourceparcellate(cfg, source3, parcellation);

%%
% this increases memory requirements even more
source4 = [];
source4.pos       = source2.pos;
source4.freq      = 1:5;
source4.time      = 1:3;
source4.coh       = randn(size(source2.pos,1), size(source2.pos,1), 5, 3);
source4.cohdimord = 'pos_pos_freq_time';

cfg = [];
source4p = ft_sourceparcellate(cfg, source4, parcellation);

%%
source5 = [];
source5.pos       = source2.pos;
source5.inside    = source2.inside;
source5.freq      = 1:2;
source5.coh       = cell(size(source2.pos,1), size(source2.pos,1));
for i=find(source2.inside)'
  for j=find(source2.inside)'
    source5.coh{i,j} = randn(3, 2);
  end
end
source5.cohdimord = '{pos_pos}_ori_freq';

cfg = [];
cfg.method = 'mean';
source5p = ft_sourceparcellate(cfg, source5, parcellation);
cfg.method = 'min';
source5p = ft_sourceparcellate(cfg, source5, parcellation);
cfg.method = 'max';
source5p = ft_sourceparcellate(cfg, source5, parcellation);

%%
source6 = [];
source6.pos       = source2.pos;
source6.inside    = source2.inside;
source6.time      = 1:20;
source6.mom       = randn(size(source2.pos,1),20);
source6.momdimord = 'pos_time';

cfg = [];
cfg.method = 'mean';
source6p = ft_sourceparcellate(cfg, source6, parcellation);
cfg.method = 'min';
source6p = ft_sourceparcellate(cfg, source6, parcellation);
cfg.method = 'max';
source6p = ft_sourceparcellate(cfg, source6, parcellation);
cfg.method = 'eig';
source6p = ft_sourceparcellate(cfg, source6, parcellation);


function [zeitgeberTime relativeTime absTime] = bz_getZeitgeberTime(basename,downSampleFactor)
% assumes pwd is basepath for now

%% get timestamps for recording starts
parts = strsplit(basename, '_');
date = parts{end-1};

if strcmp(parts{end},'merge') % if multiple sessions are merged, find the start times of each
    fileList = dir('*');

    for f = 1:length(fileList)
        if fileList(f).isdir
        for p = 1:length(parts)
            if ~isempty(strfind(fileList(f).name,parts{p}))
               matches(f,p) = 1;
            else
               matches(f,p) = 0;
            end
        end
        end
    end
    idx = find(sum(matches')==length(parts)-1);  % exlude '_merge' string
    for ind = 1:length(idx)
        temp = strsplit(fileList(idx(ind)).name,'_');
        recordingStart{ind} = temp{end};
    end
else
    recordingStart{1} = parts{end};
end

for ind = 1:length(recordingStart)
timeSeconds(ind) = int32(str2num(recordingStart{ind}(1:2)) * 60 * 60 + ...
                   str2num(recordingStart{ind}(3:4)) * 60 + ...
                   str2num(recordingStart{ind}(5:6)));
end

%% now get relative time from time.dat file
fileinfo = dir('time.dat');
num_samples = fileinfo.bytes/4; % int32 = 4 bytes
fid = fopen('time.dat', 'r');
t = fread(fid, num_samples, 'int32=>int32')';
t = downsample(t,downSampleFactor);
fclose(fid);

[a b] = min(t);  %% fixes output for time.dat files that 'wrap' at the int32 limit
if a < 0
    t = double(t)./20000;
    for i=b:length(t)
    t(i) = t(i-1)+1;
    end
else
    t = single(t)./20000;
end
% t = t / 20000;

idx = find(t==0);
idx(length(idx)+1) = length(t); % add end ts

for ind = 1:length(idx)-1
    zeitgeberTime(idx(ind):idx(ind+1)) = single(t(idx(ind):idx(ind+1)))/20000 + single(timeSeconds(ind));
end

zeitgeberTime = single(wrap(double(zeitgeberTime)/86400*pi*2,2))/ (2*pi) * 86400; % wrap it up

relativeTime = t;  % recording time

% zeitgeberTime = downsample(zeitgeberTime,downSampleFactor);
% relativeTime = downsample(relativeTime,downSampleFactor

% below is error prone if gaps in relative time, but WAY faster
absTime = linspace(datenum(2000 + str2num(date(1:2)),str2num(date(3:4)),str2num(date(5:6)),...
        str2num(parts{end}(1:2)),str2num(parts{end}(3:4)),double(relativeTime(1))),...
        datenum(2000 + str2num(date(1:2)),str2num(date(3:4)),str2num(date(5:6)),...
        str2num(parts{end}(1:2)),str2num(parts{end}(3:4)),double(relativeTime(end))),length(relativeTime));

% switch to this for accuracy
% for ind = 1:length(relativeTime)
%     absTime(ind) = datenum(2000 + str2num(date(1:2)),str2num(date(3:4)),str2num(date(5:6)),...
%         str2num(parts{end}(1:2)),str2num(parts{end}(3:4)),double(relativeTime(ind)));
% end


% testWriteSegy : Script to test WriteSegy and WriteSegyStructure
%
n=200;
seisdata=peaks(n);
imagesc(seisdata);colorbar;
xlabel('Traces');
ylabel('Time')
title('The data that should be written to disk')

% use WriteSegy to write an IEEE Revision 1 formatted file
%
WriteSegy('test.segy',seisdata);

% Read the file we just created with all of its header values
%
[Data,SegyTraceHeaders,SegyHeader,HeaderInfo]=ReadSegy('test.segy');

% NOW WE CAN WRITE ALL THE FORMATS SUPPORTED BY SegyMAT :

% WRITE IBM FLOATING POINT REV 0
% THIS IS THE ONLY IMPLEMENTED FORMAT FOR REV 0
SegyHeader.SegyFormatRevisionNumber=0;
SegyHeader.DataSampleFormat=1;
WriteSegyStructure('data_IBM_REV0.segy',SegyHeader,SegyTraceHeaders,Data);

% WRITE IBM FLOATING POINT REV 1
SegyHeader.DataSampleFormat=1;
WriteSegyStructure('data_IBM_REV1.segy',SegyHeader,SegyTraceHeaders,Data);

% WRITE 4BYTE INT POINT REV 1
SegyHeader.DataSampleFormat=2;
WriteSegyStructure('data_4byteINT.segy',SegyHeader,SegyTraceHeaders,Data);

% WRITE 2BYTE INT POINT REV 1
SegyHeader.DataSampleFormat=3;
WriteSegyStructure('data_2byteINT.segy',SegyHeader,SegyTraceHeaders,Data);

% WRITE 1BYTE INT POINT REV 1
SegyHeader.DataSampleFormat=8;
WriteSegyStructure('data_1byteINT.segy',SegyHeader,SegyTraceHeaders,Data);

% WRITE IEEE POINT REV 1
SegyHeader.DataSampleFormat=5;
WriteSegyStructure('data_IEEE.segy',SegyHeader,SegyTraceHeaders,Data);


function train_id_net_vgg16(varargin)
% -------------------------------------------------------------------------
% Part 4.1: prepare the data
% -------------------------------------------------------------------------

imdb = load('./dataset/Flickr30k-prepare/url_data.mat');
imdb = imdb.imdb;
load('./dataset/Flickr30k-prepare/dense_feature_word2.1.mat');
imdb.charcnn = wordcnn;
%imdb.charmean = mean(imdb.charcnn(:,:,:,imdb.images.set==1),4);
% -------------------------------------------------------------------------
% Part 4.2: initialize a CNN architecture
% -------------------------------------------------------------------------
net = resnet52_new_hope_word_Rankloss();
net.conserveMemory = true;
im_mean = imdb.rgbMean;
net.meta.normalization.averageImage = im_mean;
%net.meta.normalization.charmean = imdb.charmean;
% -------------------------------------------------------------------------
% Part 4.3: train and evaluate the CNN

% -------------------------------------------------------------------------
opts.train.averageImage = net.meta.normalization.averageImage;
opts.train.batchSize = 32;
opts.train.continue = true;
opts.train.gpus = 3;
opts.train.prefetch = false ;
opts.train.nesterovUpdate = true ;
opts.train.expDir = './data/res52_batch32_Rankloss_2:1:0.1_margin0.5_img0.75_shift_hard_256_no_ranking';
opts.train.derOutputs = {'objective_f',0,'objective_img',1,'objective_txt',0.1} ;
opts.train.candidate = 256;
%opts.train.gamma = 0.9;
opts.train.momentum = 0.9;
%opts.train.constraint = 100;
opts.train.learningRate = [0.1*ones(1,40),0.01*ones(1,20)] ;
opts.train.weightDecay = 0.0001;
opts.train.numEpochs = numel(opts.train.learningRate) ;
[opts, ~] = vl_argparse(opts.train, varargin) ;
% Call training function in MatConvNet
[net,info] = cnn_train_dag_batchsize_net(net, imdb, @getBatch,opts) ;

% --------------------------------------------------------------------
function inputs = getBatch(imdb,batch,net,opts)
% --------------------------------------------------------------------
%-- img data
im_url = imdb.images.data(batch) ;
im = vl_imreadjpeg(im_url,'Pack','Resize',[224,224],'Flip',...
    'CropLocation','random','CropSize',[0.8,1],...
    'Interpolation', 'bicubic','NumThreads',16,... %'Brightness', double(0.1*imdb.rgbCovariance),...
    'SubtractAverage',imdb.rgbMean,...
    'CropAnisotropy',[3/4,4/3]);
oim = gpuArray(im{1});
label_img =  imdb.images.label(batch);

%----- first half img feature
net.mode = 'test' ;
%net.vars(net.getVarIndex('fc2bn_n')).value = [];
%net.vars(net.getVarIndex('data')).value = [];
%net.vars(net.getVarIndex('data2')).value = [];
%net.vars(net.getVarIndex('label_img')).value = [];
%net.vars(net.getVarIndex('label_txt')).value = [];
reset(net);
batchsize = numel(batch);
half = batchsize/2;
f_img = getFeature2(net,oim(:,:,:,1:half),[],'data','fc1bn_n');
f_img = reshape(f_img,[],half)';

%------ rand txt input
ind = imdb.images.set==1;  % training set
ind(batch) = 0;  % remove the same label
ind = find(ind==1);  % change 0-1 to real index
ind = (ind-1)*5 + randi(5,numel(ind),1); % img index to char index
rand_ind = ind(randi(numel(ind),opts.candidate,1)); % random select 256 sample

txt = single(imdb.charcnn(:,rand_ind));
txtinput_rand = zeros(1,32,20074,opts.candidate,'single');
for i=1:opts.candidate
    len = sum(txt(:,i)>0);
    location = randi(33-len);
    for j=1:len
        v = txt(j,i);
        txtinput_rand(1,location,v,i)=1;
        location = location+1;
    end
end

%---txt feature
net.vars(net.getVarIndex('fc1bn_n')).value = [];
f_txt = getFeature2(net,gpuArray(txtinput_rand),[],'data2','fc2bn_n');
size4 = size(f_txt,4);
f_txt = reshape(f_txt,[],size4)';

txt_branch = bsxfun(@times,(batch-1),5) + randi(5,batchsize,1); %correct sample
txt = single(imdb.charcnn(:,txt_branch));
txtinput = zeros(1,32,20074,batchsize,'single');
% correct half
for i=1:half
    len = sum(txt(:,i)>0);
    location = randi(33-len);
    for j=1:len
       v = txt(j,i);
       txtinput(1,location,v,i)=1;
       location = location+1;
    end
end
%--- select hard txt sample
for i= half+1:batchsize
    [~,max_ind] = max(f_img(i-half,:)*f_txt'); %1x2048 2048x256
    txt_branch(i) = rand_ind(max_ind);
    txtinput(:,:,:,i) = txtinput_rand(:,:,:,max_ind);
end
label_txt =  imdb.images.label(floor((txt_branch-1)/5)+1);

%----- reset net
net.vars(net.getVarIndex('fc1bn_n')).value = [];
net.vars(net.getVarIndex('fc2bn_n')).value = [];
net.mode = 'normal' ;

%--
inputs = {'data',oim,'data2',gpuArray(txtinput),'label_img',label_img,'label_txt',label_txt};


function [shape] = ft_transform_headshape(transform, shape)

% FT_TRANSFORM_HEADSHAPE applies a homogenous coordinate transformation to a
% structure with headshape and fiducial information.
%
% Use as
%   shape = ft_transform_headshape(transform, shape)
%
% See also FT_READ_HEADSHAPE

% Copyright (C) 2008, 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: ft_transform_headshape.m 946 2010-04-21 17:51:16Z roboos $

if any(transform(4,:) ~= [0 0 0 1])
  error('invalid transformation matrix');
end

if isfield(shape, 'pnt') && ~isempty(shape.pnt)
  % this also works if the structure describes electrode or gradiometer positions instead of a headshape
  shape.pnt = apply(transform, shape.pnt);
end

if isfield(shape, 'ori')
  % gradiometer coil orientations should only be rotated and not translated
  rotation = eye(4);
  rotation(1:3,1:3) = transform(1:3,1:3);
  if abs(det(rotation)-1)>10*eps
    error('only a rigid body transformation without rescaling is allowed for MEG sensors');
  end
  % apply the rotation to the coil orientations
  shape.ori = apply(rotation, sens.ori);
end

if isfield(shape, 'fid') && isfield(shape.fid, 'pnt')
  % apply the same transformation on the fiducials
  shape.fid.pnt = apply(transform, shape.fid.pnt);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION that applies the homogenous transformation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [new] = apply(transform, old)
old(:,4) = 1;
new = old * transform';
new = new(:,1:3);


function test_issue1568

% WALLTIME 00:10:00
% MEM 2gb
% DEPENDENCY ft_databrowser

global ft_default
ft_default.representation = 'table';

%%

ntrials = 10;
nchans = 16;
fsample = 1000;
trialgap = 0;

data = [];
for i=1:nchans
  data.label{i} = sprintf('chan%d', i);
end
for i=1:ntrials
  data.time{i} = (1:fsample)/fsample;
  data.trial{i} = randn(nchans, fsample);
  data.sampleinfo(i,1) = (i-1)*fsample + 1 + (i*trialgap); % create some gaps between the trials
  data.sampleinfo(i,2) = data.sampleinfo(i,1) + fsample - 1;
end

if strcmp(ft_default.representation, 'numeric')
  data.trialinfo = [1:ntrials]';
else
  trialnum = arrayfun(@num2str, 1:ntrials, 'UniformOutput', false)';
  data.trialinfo = table(trialnum);
end

% this is for visualising the provenance
data.cfg.version.name = 'a';
data.cfg.previous.version.name = 'b';
data.cfg.previous.previous.version.name = 'c';
data.cfg.previous.previous.previous.version.name = 'd';
data.cfg.previous.previous.previous.previous.version.name = 'e';

%%

close all

cfg = [];
cfg.ylim = [-6 6];
% cfg.viewmode = 'vertical';

tmp1.begsample = 101;
tmp1.endsample = 110;
tmp1.channel = 'chan1';

tmp2.begsample = 121;
tmp2.endsample = 130;
tmp2.channel = 'chan2';

tmp3.begsample = 141;
tmp3.endsample = 150;
tmp3.channel = 'chan3';

% let's use three different types of artifacts, just like visual, eog, muscle, clip, etc.
cfg.artfctdef.clip.artifact = struct2table(tmp1);
cfg.artfctdef.threshold.artifact = struct2table(tmp2);
cfg.artfctdef.other.artifact = struct2table(tmp3);
cfg.artfctdef.someoption = 'no';

event(1).type     = 'ttl1';
event(1).value    = 1;
event(1).sample   = 701;
event(1).duration = 1;
event(1).offset   = 0;

event(2).type     = 'ttl2';
event(2).value    = 2;
event(2).sample   = 721;
event(2).duration = 10;
event(2).offset   = 0;

event(3).type     = 'ttl3';
event(3).value    = 3;
event(3).sample   = 741;
event(3).duration = 10;
event(3).offset   = [];

cfg.event = event;

cfg.plotartifactlabels = 'type';
cfg.ploteventlabels = 'type=value';
ft_databrowser(cfg, data);


function [ complexdata ] = read_complex( fid, datasize, offset, ...
    datatype, complexbool, varargin )
%READ_COMPLEX Generic function for reading binary complex data.
%
%   Assumes i and q components interleaved (adjacent for a single pixel).
%   Uses regular fread functions to read in data.
%
%   complexdata = read_complex( fid, datasize, offset, datatype,...
%      complexbool, dim1range, dim2range, subsample, decimationfun )
%
%   INPUTS:
%      FID:           MATLAB file identifier.  Must refer to a file that is
%         open for reading.
%      DATASIZE:      1x2 array [number of elements in first dimension,
%         number of elements in the second dimension].  Total number of
%         elements in each dimension of the data, with dimension ordered as
%         there are written in the file.
%      OFFSET:        Index (in bytes) from the beginning of the file to
%         the beginning of the data.  Default is 0 (beginning of file).
%      DATATYPE:      MATLAB string for specifying binary data precision
%         ('uint8','float32',etc.) See FREAD documentation for full list.
%         Default is 'float32'.
%      COMPLEXBOOL:   Boolean whether data is complex (true) or real
%      DIM1RANGE:     1x2 array [first element, last element].  If reading
%         a subimage, this is the range of data to read, in the first
%         dimension (as written in the file).  Default is entire image
%         range.  Can also use an empty array ([]) to specify entire range.
%      DIM2RANGE:     1x2 array [first element, last element].   Default is
%         entire image range.  Can also use an empty array ([]) to specify
%         entire range.
%      SUBSAMPLE:     1x2 array [subsample rate in first dimension,
%         subsample rate in second dimension].  Default is [1 1] (no
%         subsampling).
%
%   OUTPUTS:
%      COMPLEXDATA:   Array of complex data values, of data type single
%         complex.  Is oriented so that the first dimension in the file
%         order matches the first dimension in MATLAB (vertical when
%         display in imshow, imagesc, etc.), so this may need to be
%         transposed for display for many image types.
%
% Author: Wade Schwartzkopf (NGA/IDT)
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

if complexbool
    complexdata=read_bip(fid, datasize, offset, datatype, 2, true, varargin{:});
    complexdata=complex(complexdata(:,:,1:2:end),complexdata(:,:,2:2:end));
else
    complexdata=read_bip(fid, datasize, offset, datatype, 1, true, varargin{:});
end

end

% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////