function obj = tidal_data_to_ob(obj,tidal_database,const)
% obj = tidal_data_to_ob(obj,tidal_database,const)
% Input a msh class obj with open boundary locations and tidal
% constituents, and interpolate the tidal database constituents onto it.
% Put the result into the f15 struct of the msh obj.
%
% Requires: m_map for projection
%
% Created by William Pringle March 15 2018
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% check entry
% if we are using wildcard for each constituent in list of files
cidx = strfind(tidal_database,'**') ;
if ~isempty(cidx)
    tidal_database(cidx:cidx+1) = lower(const{1});
end
if ~exist(tidal_database,'file')
   error(['tidal database file does not exist: ' tidal_database])
end
if isempty(obj.op)
   error('No open boundaries in the mesh to put BCs on')
end

% Select desired projection (using m_map)
proj = 'Mercator';

% Specify limits of grid
lat_min = min(obj.p(:,2)) - 1; lat_max = max(obj.p(:,2)) + 1;
lon_min = min(obj.p(:,1)) - 1; lon_max = max(obj.p(:,1)) + 1;

% doing the projection
m_proj(proj,'lon',[ lon_min lon_max],...
            'lat',[ lat_min lat_max])

%% Get boundary info
opedat = obj.op;
b_lon = zeros(opedat.neta,1);
b_lat = zeros(opedat.neta,1);
node_num = zeros(opedat.neta,1);
ns = 1; ne = 0;
for n = 1:opedat.nope
    ne = ne + opedat.nvdll(n);
    node_num(ns:ne) = opedat.nbdv(1:opedat.nvdll(n),n);
    b_lon(ns:ne)    = obj.p(node_num(ns:ne),1);
    b_lat(ns:ne)    = obj.p(node_num(ns:ne),2);
    ns = ne + 1;
end

% Do projection
[b_x,b_y] = m_ll2xy(b_lon,b_lat);

%% Load tide data and make vectors
lon = ncread(tidal_database,'lon_z');
lat = ncread(tidal_database,'lat_z');
const_t = ncread(tidal_database,'con');
if min(size(lon)) == 1
    [lon,lat] = meshgrid(lon,lat);
end
if max(obj.p(:,1)) <= 180
    % change to -180 to 180 format if msh is in that format
    lon(lon > 180) = lon(lon > 180) - 360;
end
lon_x = reshape(lon,[],1);
lat_y = reshape(lat,[],1);

% Delete uncessecary portions
% First delete by square
I = find(lon_x < lon_min | lon_x > lon_max | ...
         lat_y < lat_min | lat_y > lat_max);
lon_x(I) = []; lat_y(I) = [];

% Get 20 nearest neighbours
Kd = ourKNNsearch([lon_x,lat_y]',[b_lon, b_lat]',20);
Kd = unique(Kd);

% The new lon and lat vectors of data
lon_x = lon_x(Kd); lat_y = lat_y(Kd);

% Do the projection
[x,y] = m_ll2xy(lon_x,lat_y);

%% Now interpolate into f15 struct
keep = true(obj.f15.nbfr,1);
for j = 1:obj.f15.nbfr
    % Read the current consituent
    if ~isempty(cidx)
        tidal_database(cidx:cidx+1) = lower(const{j});
        if exist(tidal_database,'file')
            const_t = ncread(tidal_database,'con');
        end
    end
    k = find(startsWith(string(const_t'),lower(const{j})));
    if isempty(k)
        disp(['No tidal data in file for constituent ' const{j}])
        obj.f15.opealpha(j).name = const{j};
        obj.f15.opealpha(j).val = 0*[b_x b_x];
        continue
    end
        % For real part
    if min(size(const_t)) > 1
        Re_now = ncread(tidal_database,'hRe',[1 1 k],[size(lon) 1]);
    else
        Re_now = double(ncread(tidal_database,'hRe'))/1000;
    end
    % reshape to vector
    Re_now = reshape(Re_now,[],1);
    % For imaginary part
    if min(size(const_t)) > 1
        Im_now = ncread(tidal_database,'hIm',[1 1 k],[size(lon) 1]);
    else
        Im_now = double(ncread(tidal_database,'hIm'))/1000;
    end
    % reshape to vector
    Im_now = reshape(Im_now,[],1);
    % Eliminate regions outside of search area and on land
    % Linear extrapolation of ocean values will be conducted where
    % boundary nodes fall inside a land cell of the tidal data.
    Re_now(I) = []; Re_now = Re_now(Kd);
    K = find(Re_now == 0); Re_now(K) = [];
    Im_now(I) = []; Im_now = Im_now(Kd); Im_now(K) = [];
    xx = x; yy = y; xx(K) = []; yy(K) = [];
    % Make into complex number
    Z = Re_now - Im_now*1i;
    % Do the scattered Interpolation
    F = scatteredInterpolant(xx,yy,Z,'natural');
    BZ = F(b_x,b_y);
        %
    % Convert real and imaginary parts to amplitude and phase
    amp_b = abs(BZ);
    phs_b = rad2deg(angle(BZ));
    % Convert to 0 to 360;
    % phs_b that is positive 0 - 180 stays same.
    % phs_b that is negative -180 - 0 becomes 180 - 360
    phs_b(phs_b < 0) = phs_b(phs_b < 0) + 360;

    obj.f15.opealpha(j).name = const{j};
    obj.f15.opealpha(j).val = [amp_b phs_b];

end
obj.f15.nbfr = length(find(keep));
obj.f15.opealpha = obj.f15.opealpha(keep);
obj.f15.bountag = obj.f15.bountag(keep);
%EOF
end


function []=save_optimal_network(meth_Net,BrainNet,label,result_dir,varargin)
% Generate one of the output, i.e., the group averaged network for each group generated by the optimized parameters.
switch meth_Net
    case {'PC','tHOFC','aHOFC'}
        opt_BrainNet=BrainNet;
    case {'SR','SLR','SGR','GSR','WSR','WSGR','SSGSR','dHOFC'}
        Acc_para=varargin{1};
        [~,B]=max(Acc_para);
        opt_BrainNet=BrainNet{B(1)};
end

label_negative=find(label==-1);
label_positive=find(label==1);
BrainNet_negative_mean=mean(opt_BrainNet(:,:,label_negative),3);
BrainNet_positive_mean=mean(opt_BrainNet(:,:,label_positive),3);

%figure;
figure('visible','off');
subplot(1,2,1);
imagesc(BrainNet_negative_mean);
colormap jet
colorbar
axis square
xlabel('ROI');
ylabel('ROI');
title('label = -1');

subplot(1,2,2);
imagesc(BrainNet_positive_mean);
colormap jet
colorbar
axis square
xlabel('ROI');
ylabel('ROI');
title('label = 1');
print(gcf,'-r1000','-dtiff',char(strcat(result_dir,'/Mean_optimal_network.tiff')));
save (char(strcat(result_dir,'/Mean_optimal_negativeLabel_network.mat')),'BrainNet_negative_mean');
save (char(strcat(result_dir,'/Mean_optimal_positiveLabel_network.mat')),'BrainNet_positive_mean');


function [dimMismatch, isTranspose] = VerifyTiedLayers(tiedLayers)

for j=1:length(tiedLayers)
    dim(:,j) = tiedLayers{j}.dim;
end
dimMismatch = [];
isTranspose = [];
for j=2:length(tiedLayers)
    if sum(abs(dim(:,j)-dim(:,1)))
        if sum(abs(dim(end:-1:1,j)-dim(:,1)))
            dimMismatch(j) = 1;
            fprintf('Error: dimension mismatch between layers that share the same weight matrix\n');
        else
            isTranspose(j) = 1;
        end
    else
        isTranspose(j) = 0;
    end
end

end


function A00 = synA00Qmin(A11, sizeA00, cmax)
%-----------------------------------------------------------------------------
%
% For each point of colour 00 this function assigns the minimum value at the
% neighbouring gridpoints of colour 11.
%
% Design and implementation by:
% Dr. Paul M. de Zeeuw <Paul.de.Zeeuw@cwi.nl>  http://homepages.cwi.nl/~pauldz/
% Last Revision: December 12, 2001.
% (c) 1998-2002 Stichting CWI, Amsterdam
%-----------------------------------------------------------------------------
[n11, m11]=size(A11);
if nargin == 3
  o=[0 0];
  if ~all(size(o) == size(sizeA00))
    error(' synA00Qmin - unexpected dimensions of sizeA00 ')
  else
    clear o;
    n00=sizeA00(1);
    m00=sizeA00(2);
  end
elseif nargin == 2
  n00=n11+1;
  m00=m11+1;
else
  error(' synA00Qmin - number of arguments should be either 2 or 3 ')
end
%[n00, m00]=size(A00);
if m00 == m11+1
  if n00 == n11+1
    S = min(extL(A11, cmax), extR(A11, cmax));
    A00=min(extD(S, cmax), extU(S, cmax));
  elseif n00 == n11
    S = min(extL(A11, cmax), extR(A11, cmax));
    A00=min(S, stripD(extU(S, cmax)));
  else
    disp([' size A11 = ' int2str(size(A11)) ' size A00 = ' int2str([n00 m00])]);
    error(' synA00Qmin - A11 and target A00 do not match ');
  end
elseif m00 == m11
  if n00 == n11+1
    S = min(stripR(extL(A11, cmax)), A11);
    A00=min(extD(S, cmax), extU(S, cmax));
  elseif n00 == n11
    S = min(stripR(extL(A11, cmax)), A11);
    A00=min(S, stripD(extU(S, cmax)));
  else
    disp([' size A11 = ' int2str(size(A11)) ' size A00 = ' int2str([n00 m00])]);
    error(' synA00Qmin - A11 and target A00 do not match ');
  end
else
  disp([' size A11 = ' int2str(size(A11)) ' size A00 = ' int2str([n00 m00])]);
  error(' synA00Qmin - A11 and target A00 do not match ');
end
%------------------------------------------------------------------------------


% The COBRAToolbox: testDetermineSignMatrix.m
%
% Purpose:
%     - test the function to determine the binary version of the stoichiometric matrix S
%
% Authors:
%     - Laurent Heirendt, November 2018
%

% save the current path and initialize the test
currentDir = fileparts(which(mfilename));

% load the model
model = createToyModelForLifting(false);

% load reference test data
load([currentDir filesep 'refData_determineBinaryMatrix.mat']);

% run the function with full output
[test_Shat, test_Shatabs, test_mconnect, test_nconnect, test_mconnectin, test_mconnectout] = determineSignMatrix(model.S);

assert(isequal(test_Shat, Shat))
assert(isequal(test_Shatabs, Shatabs))
assert(isequal(test_mconnect, mconnect))
assert(isequal(test_nconnect, nconnect))
assert(isequal(test_mconnectin, mconnectin))
assert(isequal(test_mconnectout, mconnectout))

% run the function with partial output
[test_Shat, test_Shatabs, test_mconnect, test_nconnect] = determineSignMatrix(model.S);

assert(isequal(test_Shat, Shat))
assert(isequal(test_Shatabs, Shatabs))
assert(isequal(test_mconnect, mconnect))
assert(isequal(test_nconnect, nconnect))

% run the function with minimal output
[test_Shat, test_Shatabs, test_mconnect, test_nconnect] = determineSignMatrix(model.S);

assert(isequal(test_Shat, Shat))
assert(isequal(test_Shatabs, Shatabs))

% test the sorted flag
[test_Shat, test_Shatabs, test_mconnect, test_nconnect] = determineSignMatrix(model.S, true);

assert(isequal(test_mconnect, sort(mconnect, 'descend')));
assert(isequal(test_nconnect, sort(nconnect, 'descend')));

% change the directory
cd(currentDir)


function gibbsKernDisplay(kern, spaceNum)

% GIBBSKERNDISPLAY Display parameters of the GIBBS kernel.
% FORMAT
% DESC displays the parameters of the Mark Gibbs's non-stationary
% kernel and the kernel type to the console.
% ARG kern : the kernel to display.
%
% FORMAT does the same as above, but indents the display according
% to the amount specified.
% ARG kern : the kernel to display.
% ARG spacing : how many spaces to indent the display of the kernel by.
%
% SEEALSO : gibbsKernParamInit, modelDisplay, kernDisplay
%
% COPYRIGHT : Neil D. Lawrence, 2006

% KERN

if nargin > 1
else
  spaceNum = 0;
end
spacing = repmat(32, 1, spaceNum);
spacing = char(spacing);
fprintf(spacing);
fprintf('GIBBS variance: %2.4f\n', kern.variance)
fprintf(spacing);
fprintf('GIBBS length scale function: \n')
modelDisplay(kern.lengthScaleFunc, length(spacing) + 2);


function [Q_gppca, Q_vbpca] = mohsst5_experiment_periodic(data, D, maxiter, ...
                                                  densityW, densityX, ...
                                                  updatepseudow, updatepseudox, ...
                                                  vbinit, covfuncset)

seed = ceil(sum(clock))
randn('state', seed)
rand('state', seed)

if nargin < 1
  maxiter = 10;
end
if nargin < 6
  updatepseudow = true;
end
if nargin < 7
  updatepseudox = true;
end
if nargin < 8
  vbinit = false;
end
if nargin < 9
  covfuncset = 3;
end

[M,N] = size(data.observations);

% Divide data into test and train sets
testsize = 20; % testset size in percents
Itest = load(sprintf('/share/bayes/data/jaakko/mohsst5/ind%dtest.mat',testsize));
Itrain = load(sprintf('/share/bayes/data/jaakko/mohsst5/ind%dtrain.mat',testsize));
Ytest = data.observations;
Ytest(Itrain.Itrain) = nan;
Yobs = data.observations;
Yobs(Itest.Itest) = nan;

datestring = datestr(now, 'yyyymmdd');

% Weight observations!
weights = sqrt(cosd(data.coordinates(2,:)));
Yobsw = bsxfun(@times, weights(:), Yobs);
Ytestw = bsxfun(@times, weights(:), Ytest);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

init = [];
switch vbinit
 case 0
  vbinitstring = '';
 case 1
  Qvb = pca_full(Yobsw,D,'maxiters',10,'rotate2pca',true, 'algorithm','vb');
  init.W = zeros(M,D);
  init.X = randn(D,N);
  init.W(:,1:10) = Qvb.A(:,1:10);
  init.X(1:10,:) = Qvb.S(1:10,:);
  vbinitstring = '_vbinit';
 case 2
  Qvb = pca_full(Yobsw,D,'maxiters',10,'rotate2pca',true, 'algorithm','vb');

  init.W = zeros(M,D);
  init.X = randn(D,N);

  samplerate = 1/30; % one sample in month

  % 3 very slow components
  lowpass = 1 ./ (10*365);
  [Af,Sf,S] = dss(Qvb.A, Qvb.S, Qvb.Sv, 2 * lowpass/samplerate, 3);
  init.W(:,1:3) = Af;
  init.X(1:3,:) = S;

  % 5 slow components
  lowpass = 1 ./ [10*365, 2*365];
  [Af,Sf,S] = dss(Qvb.A, Qvb.S, Qvb.Sv, 2 * lowpass/samplerate, 5);
  init.W(:,4:8) = Af;
  init.X(4:8,:) = S;

  % 2 periodical components
  bandpass = 1 ./ [2*365, 0.5*365];
  [Af,Sf,S] = dss(Qvb.A, Qvb.S, Qvb.Sv, 2 * bandpass/samplerate, 2);
  init.W(:,9:10) = Af;
  init.X(9:10,:) = S;

% $$$   % DEBUGGING STUFF
% $$$   Q_gppca = Af;%init.W;
% $$$   Q_vbpca.Xf = Sf;
% $$$   Q_vbpca.X = S;
% $$$   return
% $$$
  vbinitstring = '_vbdssinit';

end

% Covariance functions
% W distances in kilometers
for d=1:D
  switch 1 % select covariance functions
   case 1
    gpcovW = {@gpcovScale, @(logtheta,x1,x2) gpcov(logtheta,x1,x2,@ ...
                                                   sqdistEarth)};
    logthetaW = [log(2); log(1e3)];
    Wcov = 'se';
  end
  initthetaW{d} = logthetaW;
  covfunW{d} = gpcovW;
end

% X distances in days
for d=1:D
  switch covfuncset % select covariance functions
   case 1
    % 80 pediodical
    if d==1
      disp('Using 80 periodical');
    end
    gpcovX = {@gpcovProduct, @gpcov, @gpcovPeriodic};
    logthetaX = log([1e5, 0.5, 365*(D-d+3)]);
    Xcov = 'per';
   case 2
    % 80 piecewise polynomial
    if d==1
      disp('Using 80 piecewise polynomial');
    end
    gpcovX = @gpcovPP;
    logthetaX = log(30*(5+40*rand));
    Xcov = 'cs';
   case 3
    % 5 trend SE + 5 slow SE + 5 periodical + rest faster piecewise
    % polynomial
    if d==1
      disp(['Using 5 trends + 5 slow + 5 periodical + rest faster ' ...
            'piecewise polynomial']);
    end
    if d <= 5
      gpcovX = @gpcov;
      logthetaX = log(365*(10+10*rand)); % 10-20 years
      densityX(d) = 0.05;
    elseif d <= 10
      gpcovX = @gpcov;
      logthetaX = log(365*(2+8*rand)); % 2-10 years
      densityX(d) = 0.2;
    elseif d <= 15
      gpcovX = {@gpcovProduct, @gpcov, @gpcovPeriodic};
      logthetaX = log([200*365, 0.5, 365*(0.5+1.5*rand)]); % 0.5-2 years
      densityX(d) = 0.2;
    else
      gpcovX = @gpcovPP;
      logthetaX = log(30*(6+6*rand)); % 0.5-1 years
      densityX(d) = 1;
    end
    Xcov = 'se-per-cs';
   case 4
    % 3 slow piecewise polynomial + 5 middle + 2 periodical + rest faster
    % piecewise polynomial
    if d==1
      disp(['Using 3 trends + 5 slow + 2 periodical + rest faster ' ...
            'piecewise polynomial']);
    end
    if d <= 3
      gpcovX = @gpcov;
      logthetaX = log(365*(10+10*rand)); % 10-20 years
      densityX(d) = 0.05;
    elseif d <= 8
      gpcovX = @gpcov;
      logthetaX = log(365*(2+8*rand)); % 2-10 years
      densityX(d) = 0.2;
    elseif d <= 10
      gpcovX = {@gpcovProduct, @gpcov, @gpcovPeriodic};
      logthetaX = log([80*365, 0.5, 365*(0.5+1.5*rand)]); % 0.5-2 years
      densityX(d) = 0.2;
    else
      gpcovX = @gpcovPP;
      logthetaX = log(30*(6+6*rand)); % 0.5-1 years
      densityX(d) = 1;
    end
    Xcov = 'se-per-cs';
  end
  initthetaX{d} = logthetaX;
  covfunX{d} = gpcovX;
end

filename = sprintf(['/share/bayes/data/jaakko/mohsst5/' ...
                    'mohsst5_weighted%s_testsize=%d_D=%d_Wcov=%s_Wden=' ...
                    '%d_Xcov=%s_Xden=%d_iter=%d_date=%s'], vbinitstring, ...
                   testsize, D, Wcov, ceil(100*min(densityW)), Xcov, ...
                   ceil(100*min(densityX)), maxiter, datestring)

disp('-- Run GP PCA --')
Q_gppca = vbgppcamv(Yobsw, D,...
                    data.coordinates, data.time,...
                    covfunW, initthetaW,...
                    covfunX,initthetaX, ...
                    'maxiter',maxiter, ...
                    'pseudodensityx', densityX, ...
                    'pseudodensityw', densityW, ...
                    'loglikelihood', true, ...
                    'updatehyper', [1 6 21 51 101 201 501], ...
                    'updatepseudox', updatepseudox, ...
                    'updatepseudow', updatepseudow, ...
                    'maxsearchx', 3, ...
                    'maxsearchw', 3, ...
                    'checkgradx', false, ...
                    'checkgradw', false, ...
                    'init', init, ...
                    'autosavetime', 3600, ...
                    'autosavefile', filename);

% Error measures (using weights!)
Yh_gppca = Q_gppca.W * Q_gppca.X;
trainrmse_gppca = rmse(Yobsw, Yh_gppca)
testrmse_gppca = rmse(Ytestw, Yh_gppca)

% Huuuuuge matrices... Don't save them..
Q_gppca.CovXp = [];
Q_gppca.CovWp = [];

% INVERSE WEIGHTS!!!
Q_gppca.W = bsxfun(@rdivide, Q_gppca.W, weights(:));
Q_gppca.varW = bsxfun(@rdivide, Q_gppca.varW, weights(:).^2);
for d=1:D
  lat = Q_gppca.pseudoW{d}(2,:);
  Q_gppca.Wp{d} = Q_gppca.Wp{d} ./ sqrt(abs(cosd(lat(:))));
end

% Save
Q_gppca.filename = filename;
Q_gppca.seed = seed;
save(filename, '-struct', 'Q_gppca');
fprintf('Saved results in %s\n', filename);

% $$$ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% $$$ disp('-- Run PCA --')
% $$$
% $$$ % Alexander's vbpca
% $$$ disp('version by Alex')
% $$$ Q_vbpca = pca_full(Yobs,D,'maxiters',maxiter,'rotate2pca',true,
%'algorithm','vb');
% $$$ Yh_vbpca = Q_vbpca.A * Q_vbpca.S + repmat(Q_vbpca.Mu,1,N);
% $$$ vb_filename = sprintf(['/share/bayes/data/jaakko/mohsst5/' ...
% $$$
%'mohsst5_VBPCA_testsize=%d_D=%d_iter=%d_date=%s'], ...
% $$$                       testsize, D, maxiter, datestring);
% $$$ save(vb_filename, '-struct', 'Q_vbpca');
% $$$
% $$$ % My vbpca
% $$$ %disp('version by Jaakko')
% $$$ %Q_vbpca = vbpcamv(Yobs,D,'maxiters',maxiter);
% $$$ %Yh_vbpca = Q_vbpca.W * Q_vbpca.X + repmat(Q_vbpca.mu,1,N);
% $$$
% $$$ trainrmse_vbpca = rmse(Yobs, Yh_vbpca)
% $$$ testrmse_vbpca = rmse(Ytest, Yh_vbpca)


function K = k00(x, xp, hyp, Ubar, Ubarp, dt, i)

ubar = Ubar(:,1);
vbar = Ubar(:,2);

ubarp = Ubarp(:,1);
vbarp = Ubarp(:,2);

Ku0u0 = k00.ku0u0(x, xp, hyp, ubar, vbar, ubarp, vbarp, dt, i);
Ku0v0 = k00.ku0v0(x, xp, hyp, ubar, vbar, ubarp, vbarp, dt, i);
Kv0u0 = Ku0v0';
Kv0v0 = k00.kv0v0(x, xp, hyp, ubar, vbar, ubarp, vbarp, dt, i);

K = [Ku0u0 Ku0v0;
     Kv0u0 Kv0v0];

end


function [modelFile, model] = trainSceneModel(imSet, paths, typ, classMapping, sceneMapping, objectDir),

	train = imSet{1};
	val = imSet{2};

	pt = getMetadata(sceneMapping);
	numScene = length(pt.sceneName);
	sceneName = pt.sceneName;

	pt = getMetadata(classMapping);
	numObjectClass = length(pt.className);

	imSet = {train, val}; useVal = 1;
	imList{1} = getImageSet(imSet{1});
	imList{2} = getImageSet(imSet{2});
	trainingParam.fileSuffix = sprintf('tr-%s_val-%s_useVal-%d', imSet{1}, imSet{2}, useVal);

	trainingParam.featureParam = getSceneParams(typ, struct('dirName', objectDir, 'numObjectClass', numObjectClass));

	trainingParam.classifierParam = getClassifierParam('svm-scene', struct('useVal', useVal, 'numClass', numScene));
	trainingParam.gtParam = struct('sceneMapping', sceneMapping);

	% Load the features.
	for i = 1:2,
		clear f;
		parfor j = 1:length(imList{i}),
			f{j} = getSceneFeatures(imList{i}{j}, paths, trainingParam.featureParam);
		end
		F{i} = cat(2, f{:});
		gt{i} = getGroundTruth(imList{i}, 'scene', '', sceneMapping);
	end

	for i = 1:2,
		X{i} = F{i};
		Y{i} = gt{i};
		W{i} = ones(size(Y{i}));
	end

	svmParam = trainingParam.classifierParam;

	model = svmMulticlassTrain(X, Y, W, svmParam);
	modelFile = fullfile(paths.modelDir, strcat(sprintf('scene-%s_%s', trainingParam.featureParam.featureStr, trainingParam.fileSuffix), '.mat'))

	% Write the scene model!
	save(modelFile, 'model', 'trainingParam', 'F', 'gt');
end


function [obX,obY,newlp,choice] = mrSelInplane(numofanats,obXM,obYM,lp,prevChoice)
%NAME:   [obX,obY,newlp,choice] = mrSelInplane(numofanats,obXM,obYM,lp,prevChoice)
%AUTHOR:  Poirson
%DATE:	  08.04.96
%PURPOSE: One of a set of routines that allows user
%         to set and select a set of oblique planes in saggital slice.
%         Returns the choice of inplane.
%	  The routines are mrTransInplanes.m, mrRotInplanes.m,
%	  mrClipInplanes.m, mrSelInplane.m, mrSetupInplanes.m,
%         mrSpreadInplanes.m
%HISTORY: Started with mrGetOblPlane from G. Boynton 4/6/96
%NOTES:   Modified 2/25/97 by SPG to return the inplane number so
%         that can use inplane angle as a degree of freedom in the rotation
%         control window

global sagwin
figure(sagwin)

newlp = lp;

% One more pair of points for the perpendicular line
nPtPairs = numofanats + 1;

% See if the user has already been working on some inPlanes
if size(obXM,1) == 0
	disp('You must first create a candidate set of Inplanes');
	disp('Choose Set_Up_Inplanes first');
	return
end

%prevChoice = -99;

xlim=get(gca,'XLim');
ylim=get(gca,'YLim');
xt = diff(xlim)*(-1.0) * 0.8;
yt=ylim(1)+diff(xlim)*[0.05,0.125,0.20,0.275];
msg(1) = text(xt,yt(1),'Select Inplane:');
msg(2) = text(xt,yt(2),'Left = Select Line');
msg(3) = text(xt,yt(3),'Right= Show Selection');

button = 0;
while(button~=3)
	[tempx,tempy,button]=mrGinput(1,'arrow');
	if (button~=3)
		%find the closest line and give it a different color
		for i=1:numofanats
			% p(1) = slope, p(2) = offset
			p = polyfit(obXM(i,:),obYM(i,:),1);
			d(i) = abs((p(1)*tempx)+(-1*tempy)+p(2))/((p(1)^2 + 1)^0.5);
		end
		%find the minimum distance
		choice = find(d == min(d));
		% remove previous choice
		if prevChoice > 0
			% delete(lp(prevChoice))
			newlp(prevChoice)=line(obXM(prevChoice,:),obYM(prevChoice,:),'Color',[0 0 1]);
		end
		% re-draw choice in red
		% delete(lp(choice));
		newlp(choice)=line(obXM(choice,:),obYM(choice,:),'Color',[1 0 0]);
	end
end

% Return this choice
obX = obXM(choice,:);
obY = obYM(choice,:);

for i=1:3
	delete(msg(i));
end

return;


function amps = mv_amps(mv,runs);
%
% amps = mv_amps(mv,[runs]);
%
% Return a 2D matrix of format
% voxels x conditions containing
% response amplitudes, evaluated
% according to the 'ampType' parameter
% set in the params struct. Does not compute amps
% for the null (0) condition.
%
% ras, 05/05.

if notDefined('mv')
    mv = get(gcf,'UserData');
end

allRuns = unique(mv.trials.run);

if notDefined('runs')
    runs = allRuns;
end

% check that we have an amplitude type defined
if ~checkfields(mv,'params','ampType')
    % set up a dialog, get it
    ui.string = 'Method to Calculate Amplitudes?';
    ui.fieldName = 'ampType';
    ui.list = {'Peak-Bsl Difference', 'GLM Betas', ...
        'Dot-product Relative Amps' 'raw'};
    ui.style = 'popup';
    ui.value = ui.list{1};

    resp = generalDialog(ui,'Select Amplitude Type');
    ampInd = cellfind(ui.list,resp.ampType);
    opts = {'difference' 'betas' 'relamps' 'raw'};
    mv.params.ampType = opts{ampInd};
end

nConds = sum(mv.trials.condNums > 0);

switch mv.params.ampType
    case 'difference',
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        % peak-bsl difference              %
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        [tSeries, trials] = er_dataSubset(mv, runs);
        voxData = er_voxDataMatrix(tSeries, trials, mv.params);

        voxAmps = er_voxAmpsMatrix(voxData, mv.params);
        amps = permute(nanmeanDims(voxAmps,1), [2 3 1]);

    case 'betas',
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        % apply a GLM and get beta values  %
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        % Get data from selected runs only
        [tSeries, trials] = er_dataSubset(mv, runs);

        % Build a design matrix, apply the glm, grab betas
        [X, nh, hrf] = glm_createDesMtx(trials, mv.params, tSeries, 0);

        model = glm(double(tSeries), X, mv.params.framePeriod, nh);
        amps = permute(model.betas(1,1:nConds,:), [3 2 1]);

%         % also add dc components to each beta value, to ensure the shift is
%         % not lost
%         dc = permute( model.betas(1,nConds+1:end,:), [3 2 1]);
%         amps = amps + repmat(mean(dc,2), [1 nConds]);

    case 'trialbetas'
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        % apply a GLM and get beta values for each trial %
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        [tSeries, trials] = er_dataSubset(mv, runs);
        nConds = sum(trials.cond > 0);
        counter = 0;
        for i = 1:length(trials.cond)
            if (trials.cond(i))
                counter = counter + 1;
                trials.cond(i) = counter;
            end
        end

        [X, nh, hrf] = glm_createDesMtx(trials, mv.params, tSeries, 0);

        model = glm(double(tSeries), X, mv.params.framePeriod, nh);
        amps = permute(model.betas(1,1:nConds,:), [3 2 1]);
        return;

    case 'raw',
		[tSeries, trials] = er_dataSubset(mv, runs);
		mv.params.normBsl=0;
		mv.params.ampType='raw'
		mv.voxData = er_voxDataMatrix(tSeries,mv.trials,mv.params);
		mv.mvAmps=er_voxAmpsMatrix(mv.voxData, mv.params);
		amps = permute(nanmeanDims(mv.voxAmps(runs,:,:),1), [2 3 1]);
    case 'zscore',
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        % Mean peak-bsl / std. deviation   %
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        tmp = mv;
        tmp.params.ampType = 'difference';
        mu = mv_amps(tmp, runs);
        sigma = mv_stdev(tmp, runs);
        amps = mu ./ sigma;
        return      % already chose selected conditions

    case 'relamps',
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        % dot-product relative amplitudes: %
        % * not currently implemented *    %
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        amps = er_relamps(mv.voxData(:,runs,:,:));
        amps = squeeze(nanmean(amps));

        % return amplitudes for selected conditions only
        sel = find(tc_selectedConds(mv));
        amps = amps(:,sel-1);

    case 'deconvolved',
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        % Amplitudes of deconvolved time courses %
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        % Get data from selected runs only
        [tSeries, trials] = er_dataSubset(mv, runs);

        % set up and run a GLM
        params = mv.params;
        params.glmHRF = 0;
        TR = mv.params.framePeriod;
        [X nh] = glm_createDesMtx(trials, params, tSeries);
        model = glm(tSeries, X, TR, nh);

        % get peak-bsl amplitudes from the deconvolved time courses
        frameWindow = unique(round(mv.params.timeWindow./TR));
        prestim = -1 * frameWindow(1);
        peakFrames = unique(round(mv.params.peakPeriod./TR));
        bslFrames = unique(round(mv.params.bslPeriod./TR));
        peakFrames = find(ismember(frameWindow,peakFrames));
        bslFrames = find(ismember(frameWindow,bslFrames));

        nConds = size(model.betas, 2);

        if mv.params.normBsl==1
            offset = mean(model.betas(bslFrames,:,:), 1);
            offset = repmat(offset, [length(frameWindow) 1 1]);
            model.betas = model.betas - offset;
        end

        for i = 1:nConds
            bsl = model.betas(bslFrames, i, :);
            peak = model.betas(peakFrames, i, :);
            amps(:,i) = squeeze(nanmean(peak) - nanmean(bsl))';
		end
	otherwise
		fprintf(1,'error ampType %s does not exist \n', mv.params.ampType);
end

% return amplitudes for selected conditions only
sel = find(tc_selectedConds(mv));
amps = amps(:,sel-1);

return


classdef AMICO_ACTIVEAX

properties
    id, name                % id and name of the model
    dPar                    % parallel diffusivity of the tensors [units of mm^2/s]
    dIso                    % isotropic diffusivity [units of mm^2/s]
    IC_Rs                   % radii of the axons [units of 1E-6 (micrometers)]
    IC_VFs                  % volume fractions of the axons
    OUTPUT_names            % suffix of the output maps
    OUTPUT_descriptions     % description of the output maps
end

methods

    % =================================
    % Setup the parameters of the model
    % =================================
    function obj = AMICO_ACTIVEAX()
        global CONFIG

        % set the parameters of the model
        obj.id        = 'ACTIVEAX';
        obj.name      = 'ActiveAx';
        obj.dPar      = 0.6 * 1E-3;
        obj.dIso      = 2.0 * 1E-3;
        obj.IC_Rs     = [0.01 linspace(0.5,10,20)];
        obj.IC_VFs    = [0.3:0.1:0.9];

        obj.OUTPUT_names        = { 'v', 'a', 'd' };
        obj.OUTPUT_descriptions = {'Intra-cellular volume fraction', 'Mean axonal diameter', 'Axonal density'};

        % set the parameters to fit it
        CONFIG.OPTIMIZATION.SPAMS_param.mode    = 2;
        CONFIG.OPTIMIZATION.SPAMS_param.pos     = true;
        CONFIG.OPTIMIZATION.SPAMS_param.lambda  = 0.25; % l1 regularization
        CONFIG.OPTIMIZATION.SPAMS_param.lambda2 = 4;    % l2 regularization
    end

    % ==================================================================
    % Generate high-resolution kernels and rotate them in harmonic space
    % ==================================================================
    function GenerateKernels( obj, ATOMS_path, schemeHR, AUX, idx_IN, idx_OUT )
        global CONFIG AMICO_data_path CAMINO_path

        % check if high-resolution scheme has been created
        schemeHrFilename = fullfile(ATOMS_path,'protocol_HR.scheme');
        if ~exist( schemeHrFilename, 'file' )
            error( '[AMICO_GenerateKernels_ACTIVEAX] File "protocol_HR.scheme" not found in folder "%s"', ATOMS_path )
        end

        filenameHr = [tempname '.Bfloat'];
        progress = ProgressBar( numel(obj.IC_Rs) + numel(obj.IC_VFs) + 1 );

        % Restricted
        % ==========
        for R = obj.IC_Rs
            % generate
            if exist( filenameHr, 'file' ), delete( filenameHr ); end
            CMD = sprintf( '%s/datasynth -synthmodel compartment 1 CYLINDERGPD %E 0 0 %E -schemefile %s -voxels 1 -outputfile %s 2> /dev/null', CAMINO_path, obj.dPar*1e-6, R*1e-6, schemeHrFilename, filenameHr );
            [status result] = system( CMD );
            if status>0
                disp(result)
                error( '[AMICO_ACTIVEAX.GenerateKernels] Problems generating the signal with datasynth' );
            end

            % rotate and save
            fid = fopen( filenameHr, 'r', 'b' );
            signal = fread(fid,'float');
            fclose(fid);
            delete( filenameHr );
            lm = AMICO_RotateKernel( signal, AUX, idx_IN, idx_OUT, false );
            save( fullfile( ATOMS_path, sprintf('A_%03d.mat',progress.i) ), '-v6', 'lm' )
            progress.update();
        end

        % Hindered
        % ========
        for ICVF = obj.IC_VFs
            % generate
            d_perp = obj.dPar * ( 1.0 - ICVF );
            if exist( filenameHr, 'file' ), delete( filenameHr ); end
            CMD = sprintf( '%s/datasynth -synthmodel compartment 1 ZEPPELIN %E 0 0 %E -schemefile %s -voxels 1 -outputfile %s 2> /dev/null', CAMINO_path, obj.dPar*1e-6, d_perp*1e-6, schemeHrFilename, filenameHr );
            [status result] = system( CMD );
            if status>0
                disp(result)
                error( '[AMICO_ACTIVEAX.GenerateKernels] problems generating the signal' );
            end

            % rotate and save
            fid = fopen( filenameHr, 'r', 'b' );
            signal = fread(fid,'float');
            fclose(fid);
            delete( filenameHr );
            lm = AMICO_RotateKernel( signal, AUX, idx_IN, idx_OUT, false );
            save( fullfile( ATOMS_path, sprintf('A_%03d.mat',progress.i) ), '-v6', 'lm' )

            progress.update();
        end

        % Isotropic
        % =========
        % generate
        if exist( filenameHr, 'file' ), delete( filenameHr ); end
        CMD = sprintf( '%s/datasynth -synthmodel compartment 1 BALL %E -schemefile %s -voxels 1 -outputfile %s 2> /dev/null', CAMINO_path, obj.dIso*1e-6, schemeHrFilename, filenameHr );
        [status result] = system( CMD );
        if status>0
            disp(result)
            error( '[AMICO_ACTIVEAX.GenerateKernels] problems generating the signal' );
        end

        % resample and save
        fid = fopen( filenameHr, 'r', 'b' );
        signal = fread(fid,'float');
        fclose(fid);
        delete( filenameHr );
        lm = AMICO_RotateKernel( signal, AUX, idx_IN, idx_OUT, true );
        save( fullfile( ATOMS_path, sprintf('A_%03d.mat',progress.i) ), '-v6', 'lm' )
        progress.update();

        progress.close();
    end

    % ==============================================
    % Project kernels from harmonic to subject space
    % ==============================================
    function ResampleKernels( obj, ATOMS_path, idx_OUT, Ylm_OUT )
        global CONFIG AMICO_data_path KERNELS

        % Setup the KERNELS structure
        % ===========================
        nIC = numel(obj.IC_Rs);
        nEC = numel(obj.IC_VFs);

        KERNELS = {};
        KERNELS.model    = 'ACTIVEAX';
        KERNELS.nS       = CONFIG.scheme.nS;
        KERNELS.nA       = nIC + nEC + 1; % number of atoms

        KERNELS.dPar     = obj.dPar;

        KERNELS.Aic      = zeros( [KERNELS.nS nIC 181 181], 'single' );
        KERNELS.Aic_R    = zeros( 1, nIC, 'single' );

        KERNELS.Aec      = zeros( [KERNELS.nS nEC 181 181], 'single' );
        KERNELS.Aec_icvf = zeros( 1, nEC, 'single' );

        KERNELS.Aiso     = zeros( [KERNELS.nS 1], 'single' );
        KERNELS.Aiso_d   = NaN;

        progress = ProgressBar( KERNELS.nA );

        % Restricted
        % ==========
        for i = 1:nIC
            load( fullfile( ATOMS_path, sprintf('A_%03d.mat',progress.i) ), 'lm' );
            KERNELS.Aic(:,i,:,:) = AMICO_ResampleKernel( lm, idx_OUT, Ylm_OUT, false );
            KERNELS.Aic_R(i)     = obj.IC_Rs(i);
            progress.update();
        end

        % Hindered
        % ========
        for i = 1:nEC
            load( fullfile( ATOMS_path, sprintf('A_%03d.mat',progress.i) ), 'lm' );
            KERNELS.Aec(:,i,:,:) = AMICO_ResampleKernel( lm, idx_OUT, Ylm_OUT, false );
            KERNELS.Aec_icvf(i)  = obj.IC_VFs(i);
            progress.update();
        end

        % Isotropic
        % =========
        load( fullfile( ATOMS_path, sprintf('A_%03d.mat',progress.i) ), 'lm' );
        KERNELS.Aiso   = AMICO_ResampleKernel( lm, idx_OUT, Ylm_OUT, true );
        KERNELS.Aiso_d = obj.dIso;
        progress.update();

        progress.close();
    end

    % ===========================
    % Fit the model to each voxel
    % ===========================
    function [ MAPs ] = Fit( obj, y, i1, i2 )
        global CONFIG KERNELS

        % prepare SIGNAL and DICTIONARY
        if numel(KERNELS.Aiso_d) > 0
            A = double( [ KERNELS.Aic(CONFIG.scheme.dwi_idx,:,i1,i2) KERNELS.Aec(CONFIG.scheme.dwi_idx,:,i1,i2) KERNELS.Aiso(CONFIG.scheme.dwi_idx) ] );
        else
            A = double( [ KERNELS.Aic(CONFIG.scheme.dwi_idx,:,i1,i2) KERNELS.Aec(CONFIG.scheme.dwi_idx,:,i1,i2) ] );
        end
        AA = [ ones(1,KERNELS.nA) ; A ];
        yy = [ 1 ; y(CONFIG.scheme.dwi_idx) ];

        % estimate coefficients
        x = full( mexLasso( yy, AA, CONFIG.OPTIMIZATION.SPAMS_param ) );

        % compute MAPS
        nIC = numel(obj.IC_Rs);
        nEC = numel(obj.IC_VFs);
        f1 = sum( x( 1:nIC ) );
        f2 = sum( x( (nIC+1):(nIC+nEC) ) );
        MAPs(1) = f1 / ( f1 + f2 + eps );                           % intra-cellular volume fraction (v)
        MAPs(2) = 2 * KERNELS.Aic_R * x(1:nIC) / ( f1 + eps );      % mean axonal diameter
        MAPs(3) = (4*MAPs(1)) / ( pi*MAPs(2)^2 + eps );             % axonal density
    end

end

end


function model = assignQuantDir(model)
% Quantitatively assigns reaction directionality based on estimated bounds
% on transformed reaction Gibbs energies
%
% USAGE:
%
%    model = assignQuantDir(model)
%
% INPUT:
%    model:    structure with fields:
%
%                * .SIntRxnBool - `n x 1` boolean of internal reactions
%                * .DrGtMin - `n x 1` array of estimated lower bounds on
%                  transformed reaction Gibbs energies.
%                * .DrGtMax - `n x 1` array of estimated upper bounds on
%                  transformed reaction Gibbs energies.
%
% OUTPUT:
%    model:    structure with fields:
%
%                * .quantDir - `n x 1` array indicating quantitatively assigned
%                  reaction directionality. 1 for reactions that are
%                  irreversible in the forward direction, -1 for
%                  reactions that are irreversible in the reverse
%                  direction, and 0 for reversible reactions.
%
% .. Author: - Hulda SH, Nov. 2012

model.NaNdfG0MetBool=isnan(model.DfGt0);
model.NaNd0GRxnBool = isnan(model.DrGt0);

DrGtMin=model.DrGtMin;
DrGtMax=model.DrGtMax;

[nMet,nRxn]=size(model.S);

% model.quantDir = zeros(size(DrGtMin));
% model.quantDir(DrGtMax < 0) = 1;
% model.quantDir(DrGtMin > 0) = -1;

nEqualDrGt=nnz(DrGtMin==DrGtMax & DrGtMin~=0);
if any(nEqualDrGt)
    fprintf('%s\n',[num2str(nEqualDrGt) '/' num2str(length(DrGtMin)) ' reactions with DrGtMin=DrGtMax~=0' ]);
end

nZeroDrGt=nnz(DrGtMin==0 & DrGtMax==0);
if any(nZeroDrGt)
    fprintf('%s\n',[num2str(nZeroDrGt) '/' num2str(length(DrGtMin)) ' reactions with DrGtMin=DrGtMax=0' ]);
end

if any(model.NaNd0GRxnBool)
    warning('Some DfGt0 are NaN');
end

if any(DrGtMin>DrGtMax)
    error('DrGtMin greater than DrGtMax');
end

%reaction directionality
%keep exchange bounds the same as for the recostruction
model.lb_reconThermo=model.lb;
model.ub_reconThermo=model.ub;

%now set internal reaction directions
for n=1:nRxn
    if model.SIntRxnBool(n)
        if model.NaNd0GRxnBool(n)
            %for the reactions that involve a NaN metabolite standard Gibbs energy of
            %formation, use the directions given by the reconstruction
            if model.lb(n)<0 && model.ub(n)>0
                model.lb_reconThermo(n)=-Inf;
                model.ub_reconThermo(n)=Inf;
            end
            %forward
            if model.lb(n)>=0 && model.ub(n)>0
                model.lb_reconThermo(n)=0;
                model.ub_reconThermo(n)=Inf;
            end
            %reverse
            if model.lb(n)<0 && model.ub(n)<=0
                model.lb_reconThermo(n)=-Inf;
                model.ub_reconThermo(n)=0;
            end
            if model.lb(n)==0 && model.ub(n)==0
                error(['Reaction ' model.rxns{n} ' bounds set to zero'])
            end
            %note that there is no thermodynamic directionality assignment
            %for this reaction
            model.directionalityThermo{n}=NaN;
        else
            if DrGtMax(n)<0
                model.directionalityThermo{n}='forward';
                model.lb_reconThermo(n)=0;
                model.ub_reconThermo(n)=Inf;
            end
            if DrGtMin(n)>0
                model.directionalityThermo{n}='reverse';
                model.lb_reconThermo(n)=-Inf;
                model.ub_reconThermo(n)=0;
            end
            if DrGtMin(n)<0 && DrGtMax(n)>0
                model.directionalityThermo{n}='reversible';
                model.lb_reconThermo(n)=-Inf;
                model.ub_reconThermo(n)=Inf;
            end
            if DrGtMin(n)==DrGtMax(n)
                model.directionalityThermo{n}='equilibrium';
            end
            if model.lb(n)==0 && model.ub(n)==0
                error(['Reaction ' model.rxns{n} ' bounds set to zero'])
            end
        end
    end
end


function fractOverlap = getSurfaceAttachment(structNum1,structNum2,margin,planC)
%function min_dist = getSurfaceAttachment(structNum1,structNum2,margin,planC)
%
%This function calculates fractional overlap between the masks of structNum2
% and structNum2 contracted by margin. planC is an optional input argument.
%
%APA, 11/25/2019
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR 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.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

if ~exist('planC','var')
    global planC
end

indexS = planC{end};

% Create Union of the two structure structNum1 (lung) and structNum2 (gtv)
planC = createUnionStructure(structNum1,structNum2,planC);

unionStrNum = length(planC{indexS.structures});

% Get surface mask of contracted unionStrNum
xyDownsampleIndex = 1; % no downsampling
contractedStr1M = getSurfaceContract(unionStrNum,margin,xyDownsampleIndex,planC);

% Remove unionStrNum
maskUnionM = getUniformStr(unionStrNum,planC);
ringMaskM = maskUnionM - contractedStr1M;
planC = deleteStructure(planC,unionStrNum);

% Get mask of structNum2 (gtv)
mask2M = getUniformStr(structNum2,planC);

% Get overlapping fraction of structNum2
overlapM = ringMaskM & mask2M;
fractOverlap = sum(overlapM(:)) / sum(mask2M(:));


function G = bst_meg_sph(L, Channel, Param)
% BST_MEG_SPH: Calculate the (overlapping) sphere models for MEG
%
% USAGE:  G = bst_meg_sph(L, Channel, Param);
%
% INPUT:
%    - L        : a 3 x nL array, each column a source location (x y z coordinates); nL sources
%    - Channel  : a Brainstorm channel structure
%    - Param[]  : array of structures (one per channel)
%        |- Center  : a vector of the x, y, z locations for the sphere model
%        |            (assume the same center for every sphere for the classical spherical head model)
%
% OUTPUT:
%    - G  : the gain matrix: each column is the forward field of each source

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@

%% ===== PARSE INPUTS =====
% Sources locations should be 3 x m
if(size(L,1)~=3)
    error('Matrix not given as 3 x n. Correct calling code');
end
% Check that the number of coils is the same for all the channels
chanCoils = cellfun(@(c)size(c,2), {Channel.Loc});
grpCoils = unique(chanCoils);
% If there are multiple sensor sensor types (different numbres of coils)
if (length(grpCoils) > 1)
    % This function can only accept calls to groups of sensors with the same number of coils
    % => Group the sensors by number of coils and call os_meg as many times as needed
    G = NaN * zeros(length(Channel), 3 * size(L,2));
    for iGrp = 1:length(grpCoils)
        % Get all the sensors with this amount of coils
        iMegGrp = find(chanCoils == grpCoils(iGrp));
        % Compute (os_meg)
        G(iMegGrp,:) = bst_meg_sph(L, Channel(iMegGrp), Param(iMegGrp));
    end
    return;
end
% Number of coils for this call
NumCoils = chanCoils(1);

%% ===== COMPUTATION =====
% Get locations
AllLocs = [Channel.Loc];
AllLocs = reshape(AllLocs, NumCoils*3, size(AllLocs,2)/NumCoils);
% Get orientations
AllOrient = [Channel.Orient];
AllOrient = AllOrient * bst_inorcol(AllOrient);
AllOrient = reshape(AllOrient, NumCoils*3, size(AllOrient,2)/NumCoils);
% Get weights
AllWeight = [Channel.Weight];
AllWeight = reshape(AllWeight(:), NumCoils, length(AllWeight(:))/NumCoils);

% Process each group of coils
G = 0;
for j = 1:NumCoils
    % P.sensor is 3 x nR,each column a sensor location
    % P.orient is 3 x nR, the sensor orientation
    % P.center is 3 x nR, the sphere center for each sensor
    P.sensor = AllLocs((-2:0) + j*3, :);
    P.orient = AllOrient((-2:0) + j*3, :);
    P.weight = AllWeight(j,:);
    P.center = [Param.Center];
    % Local call below
    G = G + sarvas(L, P);
end

%% %%%%%%%%%%%%%%%%%%%%%%%%%%%  Local Sarvas functions %%%%%%%%%%%%%%%%%%%%%%%%
function G = sarvas(L, P)
% Bronzan Sarvas forward model, spherical head
% P.sensor is 3 x nR,each column a sensor location
% P.orient is 3 x nR, the sensor orientation
% P.center is 3 x nR, the sphere center for each sensor

if(~isfield(P,'center')), % user did not provide
   P.center = []; % initialize to null
end
if(isempty(P.center)), % user gave as null
   P.center = zeros(size(P.sensor));  % set to coordinate origin
end

P.sensor = P.sensor - P.center; % shift sensor coordinates

iMag = find(sum(P.sensor.^2,1) == 0); % Indices of channels located at P.center.
if ~isempty(iMag)
    P.sensor(:,iMag) = repmat([1 1 1]',1,length(iMag)); % Move them away (arbitrary location).
end

nR = size(P.sensor,2); % number of sensors
nL = size(L,2);  % number of source points

Rn2 = sum(P.sensor.^2,1); % distance to sensor squared
Rn = sqrt(Rn2); % distance

if (nR >= nL), % more sensors than dipoles
   G = zeros(nR,3*nL);  % gain matrix
   for Li = 1:nL,
      Lmat = L(:,Li+zeros(1,nR)); % matrix of location repeated
      Lmat = Lmat - P.center; % each center shifted relative to its center
      D = P.sensor - Lmat;  % distance from souce to sensors
      Dn2 = sum(D.^2,1); % distance squared
      Dn = sqrt(Dn2);  % distance
      R_dot_D = sum(P.sensor .* D);  % dot product of sensor and distance
      R_dot_Dhat = R_dot_D ./ Dn;  % dot product of sensor and distance

      F = Dn2 .* Rn + Dn .* R_dot_D;  % Sarvas' function F

      GF_dot_o = Dn2 .* sum(P.sensor.*P.orient) ./ Rn + ...
         (2 * Rn + R_dot_Dhat) .* sum(D.*P.orient) + ...
         Dn .* sum((D+P.sensor).*P.orient);

      tempF = GF_dot_o ./ F.^2;

      temp = bst_cross(Lmat,P.orient) ./ F([1 1 1],:) - ...
             bst_cross(Lmat,P.sensor) .* tempF([1 1 1],:);
      G(:,Li*3+[-2 -1 0]) = temp';

   end

else  % more dipoles than sensors nL > nR
   G = zeros(3*nL,nR);  % gain matrix transposed

   for Ri = 1:nR,
      Rmat = P.sensor(:,Ri+zeros(1,nL)); % matrix of sensor repeated
      Omat = P.orient(:,Ri+zeros(1,nL)); % orientations
      Lmat = L - P.center(:,Ri+zeros(1,nL)); % shift centers to this coordinate

      D = Rmat - Lmat;
      Dn2 = sum(D.^2,1); % distance squared
      Dn = sqrt(Dn2);  % distance
      R_dot_D = sum(Rmat .* D);  % dot product of sensor and distance
      R_dot_Dhat = R_dot_D ./ Dn;  % dot product of sensor and distance

      F = Dn2 * Rn(Ri) + Dn .* R_dot_D;  % Sarvas' function F

      GF_dot_o = Dn2 * sum(P.sensor(:,Ri).*P.orient(:,Ri)) / Rn(Ri) + ...
         (2 * Rn(Ri) + R_dot_D ./ Dn) .* sum(D.*Omat) + ...
         Dn .* sum((D+Rmat).*Omat);

      tempF = GF_dot_o ./ F.^2;

      temp = bst_cross(Lmat,Omat) ./ F([1 1 1],:) - ...
             bst_cross(Lmat,Rmat) .* tempF([1 1 1],:);

      G(:,Ri) = temp(:);
   end

   G = G';
end

if(isfield(P,'weight')),
   Weights = P.weight(:); %make sure column
   % scale each row by its appropriate weight
   G = Weights(:,ones(1,size(G,2))) .* G;
end

G = G * 1e-7; % mu_o over 4 pi


function [transform, coordsys] = ft_headcoordinates(fid1, fid2, fid3, fid4, coordsys)

% FT_HEADCOORDINATES returns the homogeneous coordinate transformation matrix
% that converts the specified fiducials in any coordinate system (e.g. MRI)
% into the rotated and translated headcoordinate system.
%
% Use as
%   [transform, coordsys] = ft_headcoordinates(fid1, fid2, fid3, coordsys)
% or
%   [transform, coordsys] = ft_headcoordinates(fid1, fid2, fid3, fid4, coordsys)
%
% Depending on the desired coordinate system, the order of the fiducials is
% interpreted as follows
%
%   fid1 = nas
%   fid2 = lpa
%   fid3 = rpa
%   fid4 = extra point (optional)
%
%   fid1 = ac
%   fid2 = pc
%   fid3 = midsagittal
%   fid4 = extra point (optional)
%
%   fid1 = pt1
%   fid2 = pt2
%   fid3 = pt3
%   fid4 = extra point (optional)
%
%   fid1 = bregma
%   fid2 = lambda
%   fid3 = midsagittal
%   fid4 = extra point (optional)
%
% The fourth argument fid4 is optional and can be specified as an an extra point
% which is assumed to have a positive Z-coordinate. It will be used to ensure correct
% orientation of the Z-axis (ctf, 4d, bti, eeglab, yokogawa, neuromag, itab) or
% X-axis (acpc, spm, mni, tal). The specification of this extra point may result in
% the handedness of the transformation to be changed, but ensures consistency with
% the handedness of the input coordinate system.
%
% The coordsys input argument is a string that determines how the location of the
% origin and the direction of the axis is to be defined relative to the fiducials:
%   according to CTF conventions:             coordsys = 'ctf'
%   according to 4D conventions:              coordsys = '4d' or 'bti'
%   according to EEGLAB conventions:          coordsys = 'eeglab'
%   according to NEUROMAG conventions:        coordsys = 'itab'
%   according to ITAB conventions:            coordsys = 'neuromag'
%   according to YOKOGAWA conventions:        coordsys = 'yokogawa'
%   according to ASA conventions:             coordsys = 'asa'
%   according to FTG conventions:             coordsys = 'ftg'
%   according to ACPC conventions:            coordsys = 'acpc'
%   according to SPM conventions:             coordsys = 'spm'
%   according to MNI conventions:             coordsys = 'mni'
%   according to Talairach conventions:       coordsys = 'tal'
%   according to PAXINOS conventions:         coordsys = 'paxinos'
% If the coordsys input argument is not specified, it will default to 'ctf'.
%
% The CTF, 4D, YOKOGAWA and EEGLAB coordinate systems are defined as follows:
%   the origin is exactly between lpa and rpa
%   the X-axis goes towards nas
%   the Y-axis goes approximately towards lpa, orthogonal to X and in the plane spanned by the fiducials
%   the Z-axis goes approximately towards the vertex, orthogonal to X and Y
%
% The TALAIRACH, SPM and ACPC coordinate systems are defined as:
%   the origin corresponds with the anterior commissure
%   the Y-axis is along the line from the posterior commissure to the anterior commissure
%   the Z-axis is towards the vertex, in between the hemispheres
%   the X-axis is orthogonal to the midsagittal-plane, positive to the right
%
% The NEUROMAG and ITAB coordinate systems are defined as follows:
%   the X-axis is from the origin towards the RPA point (exactly through)
%   the Y-axis is from the origin towards the nasion (exactly through)
%   the Z-axis is from the origin upwards orthogonal to the XY-plane
%   the origin is the intersection of the line through LPA and RPA and a line orthogonal to L passing through the nasion
%
% The ASA coordinate system is defined as follows:
%   the origin is at the orthogonal intersection of the line from rpa-lpa and the line trough nas
%   the X-axis goes towards nas
%   the Y-axis goes through rpa and lpa
%   the Z-axis goes approximately towards the vertex, orthogonal to X and Y
%
% The FTG coordinate system is defined as:
%   the origin corresponds with pt1
%   the x-axis is along the line from pt1 to pt2
%   the z-axis is orthogonal to the plane spanned by pt1, pt2 and pt3
%
% The PAXINOS coordinate system is defined as:
%   the origin is at bregma
%   the x-axis extends along the Medial-Lateral direction, with positive towards the right
%   the y-axis points from dorsal to ventral, i.e. from inferior to superior
%   the z-axis passes through bregma and lambda and points from cranial to caudal, i.e. from anterior to posterior
%
% See also FT_ELECTRODEREALIGN, FT_VOLUMEREALIGN, FT_INTERACTIVEREALIGN, FT_AFFINECOORDINATES, COORDSYS2LABEL

% Copyright (C) 2003-2022, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% 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$

% figure out the input arguments
if nargin==3
  coordsys = 'ctf'; % default
  fid4     = [];
elseif nargin==4 && ischar(fid4)
  coordsys = fid4;
  fid4     = [];
elseif nargin==4 && isnumeric(fid4)
  coordsys = 'ctf'; % default
elseif nargin==5
  % do nothing
else
  ft_error('incorrect specification of input parameters');
end

if isnumeric(coordsys)
  % these are for backward compatibility, but should preferably not be used any more
  if coordsys==0
    coordsys = 'ctf';
  elseif coordsys==1
    coordsys = 'asa';
  elseif coordsys==2
    coordsys = 'ftg';
  else
    ft_error('if coordsys is numeric, it should assume one of the values 0/1/2');
  end
end

% ensure that they are row vectors
fid1 = fid1(:)';
fid2 = fid2(:)';
fid3 = fid3(:)';
fid4 = fid4(:)';

assert(numel(fid1)==3, 'incorrect specification of fiducial 1');
assert(numel(fid2)==3, 'incorrect specification of fiducial 2');
assert(numel(fid3)==3, 'incorrect specification of fiducial 3');
assert(isempty(fid4) || numel(fid4)==3, 'incorrect specification of fiducial 4');

% ensure that it is lower case
coordsys = lower(coordsys);

% compute the origin and direction of the coordinate axes in MRI coordinates
switch coordsys
  case {'ctf' '4d' 'bti' 'eeglab' 'yokogawa'}
    % rename the marker points for convenience
    nas = fid1; lpa = fid2; rpa = fid3; extrapoint = fid4; clear fid*
    origin = (lpa+rpa)/2;
    dirx = nas-origin;
    dirz = cross(dirx,lpa-rpa);
    diry = cross(dirz,dirx);
    dirx = dirx/norm(dirx);
    diry = diry/norm(diry);
    dirz = dirz/norm(dirz);
  case {'asa'}
    % rename the marker points for convenience
    nas = fid1; lpa = fid2; rpa = fid3; extrapoint = fid4; clear fid*
    dirz = cross(nas-rpa, lpa-rpa);
    diry = lpa-rpa;
    dirx = cross(diry,dirz);
    dirx = dirx/norm(dirx);
    diry = diry/norm(diry);
    dirz = dirz/norm(dirz);
    origin = rpa + dot(nas-rpa,diry)*diry;
  case {'neuromag' 'itab'}
    % rename the fiducials
    nas = fid1; lpa = fid2; rpa = fid3; extrapoint = fid4; clear fid*
    dirz = cross(rpa-lpa,nas-lpa);
    dirx = rpa-lpa;
    diry = cross(dirz,dirx);
    dirx = dirx/norm(dirx);
    diry = diry/norm(diry);
    dirz = dirz/norm(dirz);
    origin = lpa + dot(nas-lpa,dirx)*dirx;
  case 'ftg'
    % rename the marker points for convenience
    pt1 = fid1; pt2 = fid2; pt3 = fid3; extrapoint = fid4; clear fid*
    origin = pt1;
    dirx = pt2-origin;
    diry = pt3-origin;
    dirz = cross(dirx,diry);
    diry = cross(dirz,dirx);
    dirx = dirx/norm(dirx);
    diry = diry/norm(diry);
    dirz = dirz/norm(dirz);
  case {'acpc' 'spm' 'mni' 'tal'}
    % rename the marker points for convenience
    ac = fid1; pc = fid2; midsagittal = fid3; extrapoint = fid4; clear fid*
    origin = ac;
    diry   = ac-pc;
    dirz   = midsagittal-ac;
    dirx   = cross(diry,dirz);
    dirz   = cross(dirx,diry);
    dirx   = dirx/norm(dirx);
    diry   = diry/norm(diry);
    dirz   = dirz/norm(dirz);
  case 'paxinos'
    bregma = fid1; lambda = fid2; midsagittal = fid3; extrapoint = fid4; clear fid*
    origin = bregma;           % bregma is slightly above the brain
    dirz = lambda-bregma;      % lambda is slightly above the brain
    diry = bregma-midsagittal; % midsagittal should be somewhere in the middle of the brain
    dirx = cross(diry,dirz);   % compute the positive x-direction, i.e. towards the right
    diry = cross(dirz,dirx);   % update the y-direction
    dirx = dirx/norm(dirx);
    diry = diry/norm(diry);
    dirz = dirz/norm(dirz);
  otherwise
    ft_error('unrecognized headcoordinate system "%s"', coordsys);
end

% use the extra point to validate that it is a right-handed coordinate system
if ~isempty(extrapoint)
  dirq = extrapoint-origin;
  dirq = dirq/norm(dirq);
  if any(strcmp(coordsys, {'ctf' '4d' 'bti' 'eeglab' 'yokogawa' 'neuromag' 'itab'}))
    phi = dirq(:)'*dirz(:);
    if sign(phi)<0
      ft_warning('the input coordinate system seems left-handed, flipping z-axis to keep the transformation matrix consistent');
      dirz = -dirz;
    end
  elseif any(strcmp(coordsys, {'acpc' 'spm' 'mni' 'tal'}))
    phi = dirq(:)'*dirx(:);
    if sign(phi)<0
      ft_warning('the input coordinate system seems left-handed, flipping x-axis to keep the transformation matrix consistent');
      dirx = -dirx;
    end
  else
    ft_warning('the extra input coordinate is not used with coordsys "%s"', coordsys);
  end
end

% compute the rotation matrix
rot = eye(4);
rot(1:3,1:3) = inv(eye(3) / [dirx; diry; dirz]);
% compute the translation matrix
tra = eye(4);
tra(1:4,4)   = [-origin(:); 1];
% combine these to compute the full homogeneous transformation matrix
transform = rot * tra;


function x = p19_root ( i )

%*****************************************************************************80
%
%% P19_ROOT returns a root for problem 19.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    15 January 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer I, the index of the requested root.
%
%    Output, real X, the value of the root.
%
  if ( i == 1 )
    x = 0.33186603357456253747;
  else
    fprintf ( 1, '\n' );
    fprintf ( 1, 'P19_ROOT - Fatal error!\n' );
    fprintf ( 1, '  Illegal root index = %d\n', i );
    error ( 'P19_ROOT - Fatal error!' );
  end

  return
end


%%
 %  Copyright (c) 2014, Facebook, Inc.
 %  All rights reserved.
 %
 %  This source code is licensed under the BSD-style license found in the
 %  LICENSE file in the root directory of this source tree. An additional grant
 %  of patent rights can be found in the PATENTS file in the same directory.
 %
 %%
function level2_model=train_level2_cnn(train_labels, train_features, ...
    train_gfeatures, config)

level2_features_val = generate_level2_features_cnn(train_features,train_gfeatures,config);
clear train_features

tic;
fprintf('Training attribute classifier');
for attr_id = 1:size(train_labels,2)
    fprintf('%s ',config.ATTR_NAME{attr_id});
    %ignore those with labels = 0
    idx  = find(train_labels(:,attr_id) ~= 0);
    labels = (train_labels(idx,attr_id)>0)*2-1;
    level2_model{attr_id}.svm_weights = liblinear_do_train(labels,level2_features_val(idx,:));
end
fprintf('\n');
toc;
end


classdef specimenSymmetry < symmetry
% defines a specimen symmetry
%
% usually specimen symmetry is either
% triclinic or orthorhombic
%

properties
  axes = [xvector,yvector,zvector];
  plotOptions = {}
end

  methods

    function s = specimenSymmetry(varargin)
      % defines a specimen symmetry
      %
      % usually specimen symmetry is either triclinic or orthorhombic
      %

      axes = getClass(varargin,'vector3d',[xvector,yvector,zvector]);

      if nargin == 0

        id = 1;
        rot = rotation.id;

      elseif isa(varargin{1},'quaternion') % define the symmetry just by rotations

        rot = varargin{1};

        if check_option(varargin,'pointId')
          id = get_option(varargin,'pointId');
        else
          id = symmetry.rot2pointId(rot,axes);
        end

      else

        id = symmetry.extractPointId(varargin{:});
        rot = symmetry.calcQuat(id,axes);

      end

      s = s@symmetry(id,rot);
      s.axes = axes;

    end

    function display(s)
      disp(' ');
      disp([inputname(1) ' = ' char(s.lattice) ' ' doclink(s) ' ' docmethods(inputname(1))]);
      disp(' ');
    end

  end

  methods (Static = true)

    function cs = loadobj(s)
      % called by Matlab when an object is loaded from an .mat file
      % this overloaded method ensures compatibility with older MTEX
      % versions

       % maybe there is nothing to do
      if isa(s,'specimenSymmetry'), cs = s; return; end

      if isfield(s,'rot')
        rot = s.rot;
      else
        rot = rotation(s.a,s.b,s.c,s.d,s.i);
      end

      if isfield(s,'axes')
        axes = s.axes;
      else
        axes = [];
      end

      if isfield(s,'id')
        id = {'pointId',s.id};
      else
        id = {};
      end

      cs = specimenSymmetry(rot,id{:},axes);

      if isfield(s,'opt'), cs.opt = s.opt; end
      if isfield(s,'plotOptions'), cs.plotOptions = s.plotOptions; end

    end

  end

end


function DetectRedCells(db, ops0)

ops = build_ops3(db, ops0);
redcells = [];
for i = 1:length(ops.planesToProcess)
    iplane  = ops.planesToProcess(i);
    try
        try
            fname = sprintf('%s/F_%s_%s_plane%d.mat', ops.ResultsSavePath, ops.mouse_name, ops.date, iplane);
            dat = load(fname);
            while isfield(dat, 'dat')
                dat = dat.dat;
            end
        catch
            fname = sprintf('%s/F_%s_%s_plane%d_Nk%d_proc.mat', ops.ResultsSavePath, ops.mouse_name, ops.date, iplane, ops.Nk);
            dat = load(fname);
            while isfield(dat, 'dat')
                dat = dat.dat;
            end
        end
    catch
        fname = sprintf('%s/F_%s_%s_plane%d_Nk%d.mat', ops.ResultsSavePath, ops.mouse_name, ops.date, iplane, ops.Nk);
        dat = load(fname);
        while isfield(dat, 'dat')
            dat = dat.dat;
        end
    end

    % subtract bleedthrough of green into red channel
    % if there's a specific green channel (from a red+green short session)
    if isfield(dat.ops,'mimgGREEN')
        mimgG = dat.ops.mimgGREEN;
    else
        mimgG = dat.ops.mimg;
    end
    mimgR = dat.ops.mimgRED;

    % subsample mimgR and mimgG
    mimgR = mimgR(dat.ops.yrange,dat.ops.xrange);
    mimgG = mimgG(dat.ops.yrange,dat.ops.xrange);
    [nY nX] = size(mimgR);
    %
    % pixels with ROIs
    iscell = [dat.stat.mrs]./[dat.stat.mrs0]<1.2 & [dat.stat.npix]<150 & [dat.stat.npix]>20;
    icell  = find(iscell);
    cellpix = false(numel(mimgR),1);
    for j = icell
        cellpix(dat.stat(j).ipix) = 1;
    end

    nonrig = 1;
    if nonrig
        % non-rigid linear regression
        nblks               = 3;
        yB                  = round(linspace(1,nY,nblks+1));
        xB                  = round(linspace(1,nX,nblks+1));
        [yBL,xBL,numBlocks] = MakeQuadrants(yB,xB);
        msk                 = zeros(nY,nX,length(yB));
        for j = 1:length(yBL)
            xg              = mimgG(yBL{j},xBL{j});
            xr              = mimgR(yBL{j},xBL{j});
            A               = polyfit(xg,xr,1);
            msk(:,:,j)      = QuadrantMask(yBL,xBL,nY,nX,j);
            gw(j)           = A(1);
        end
        msk                 = bsxfun(@times,msk,1./sum(msk,3));
        pixweight           = zeros(nY,nX);
        for j = 1:length(yBL)
            pixweight = pixweight + msk(:,:,j)*gw(j);
        end
        mimgR0              = mimgR - pixweight.*mimgG;
    else
        % fit to non-ROI pixels
        mimgGn              = mimgG;
        mimgGn(cellpix)     = 0;
        mimgRn              = mimgR;
        mimgRn(cellpix)     = 0;

        xg                  = mimgGn;%my_conv2(mimgGn,[1 1],[1 2]);
        xr                  = mimgRn;%my_conv2(mimgRn,[1 1],[1 2]);
        A                   = polyfit(xg(:),xr(:),1);
        plot(xg(1:100:end)*A(1)+A(2),xr(1:100:end),'.')
        mimgR0              = mimgR - (A(1)*mimgG);
    end
    dat.ops.mimgREDcorrected = mimgR0;

    %%
    mimgR0 = normalize_image(mimgR0);
    %%%%% compute overlap with pixel map
    % (exclude pixels from other cells (cellpix))

    redpix = zeros(length(dat.stat),2);
    [xx,yy] = meshgrid([1:size(mimgR0,1)],[1:size(mimgR0,2)]);
    xx=xx(:); yy=yy(:);
    xy2 = xx.^2+yy.^2;

    for j = 1:numel(dat.stat)
        ipix                 = dat.stat(j).ipix;
        imgpix               = false(size(mimgR0));
        imgpix(ipix)         = 1;
        rpix                 = mimgR0(ipix);%.*(dat.stat(j).lambda'/sum(dat.stat(j).lambda));
        [ix,iy]              = ind2sub(size(mimgR0),ipix);
        params               = FitCircle(ix,iy);
        cellradius           = params.ra;
        yc                   = params.xc;
        xc                   = params.yc;
        icircle              = (xy2 - 2*xc*xx - 2*yc*yy + xc^2 + yc^2) < (cellradius+15)^2;
        extpix               = icircle & ~imgpix(:) & ~cellpix;
        ext_rpix             = mimgR0(extpix);%/length(extpix);
        redpix(j,:)          = [mean(rpix) mean(ext_rpix)];
    end
    redpix = redpix - min(redpix(:));
%     redpix(~dat.cl.isroi,:) = NaN;

    % set threshold for redpix
    if isfield(ops,'redthres')
        redthres = ops.redthres;
    else
        redthres = 1.5;
    end
    if isfield(ops,'redmax')
        redmax = ops.redmax;
    else
        redmax = 1;
    end
    rrat = redpix(:,1)./(redpix(:,2)+redpix(:,1));
    redcell  = rrat > nanmean(rrat)+redthres*nanstd(rrat);
    notred   = rrat <= nanmean(rrat) + redmax*nanstd(rrat);
    %%
    fprintf('plane %d  reds %d\n',iplane,sum(redcell(:)&iscell(:)));

%     dat.cl.redcell = redcell(:);
%     dat.cl.notred  = notred(:);

    for j = 1:length(dat.stat)
        dat.stat(j).redcell = redcell(j);
        dat.stat(j).redprob = rrat(j);
    end

    save(fname, '-struct', 'dat')
end


function data = detrenddata(data,T)

for n=1:length(T)
    ind = sum(T(1:n-1))+ (1:T(n));
    if isstruct(data)
        data.X(ind,:) = detrend(data.X(ind,:));
    else
        data(ind,:) = detrend(data(ind,:));
    end
end

end


%ISCOLOR Test for color image
%
% ISCOLOR(IM) is true (1) if IM is a color image, that is, it its third
% dimension is equal to three.

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

function s = iscolor(im)
    % WxH is mono
    % WxHx3 is color
    % WxHxN is mono sequence
    % WxHx3xN is color sequence
    s = isnumeric(im) && size(im,1) > 1 && size(im,2) > 1 && size(im,3) == 3;


function varargout = drawPolygon (px, varargin)
%DRAWPOLYGON Draw a polygon specified by a list of points.
%
%   drawPolygon(POLY);
%   Packs coordinates in a single N-by-2 array, with N the vertex number.
%
%   drawPolygon(PX, PY);
%   Specifies coordinates in separate arrays. Both array must be N-by-1,
%   with N the number of vertices.
%
%   drawPolygon(POLYS)
%   Packs coordinate of several polygons in a cell array. Each element of
%   the array is a Ni-by-2 double array.
%
%   drawPolygon(..., NAME, VALUE);
%   Specifies drawing options by using one or several parameter name-value
%   pairs, see the doc of plot function for details.
%
%   drawPolygon(AX, ...)
%   Specifies the axis to draw the polygon on.
%
%   H = drawPolygon(...);
%   Also return a handle to the list of line objects.
%
%   Example
%     % draw a red rectangle
%     poly = [10 10;40 10;40 30;10 30];
%     figure; drawPolygon(poly, 'r');
%     axis equal; axis([0 50 0 50]);
%
%     % Draw two squares
%     px = [10 20 20 10 NaN 30 40 40 30]';
%     py = [10 10 20 20 NaN 10 10 20 20]';
%     figure;
%     drawPolygon([px py], 'lineWidth', 2);
%     axis equal; axis([0 50 0 50]);
%
%   See also
%   polygons2d, drawPolyline

% ------
% Author: David Legland
% E-mail: david.legland@inrae.fr
% Created: 2004-05-05
% Copyright 2004-2022 INRA - TPV URPOI - BIA IMASTE

% Store hold state
state = ishold(gca);
hold on;

%% Check input
if nargin < 1
    error ('should specify at least one argument');
end

% check for empty polygons
if isempty (px)
    return
end

% extract handle of axis to draw on
ax = gca;
if isAxisHandle(px)
    ax          = px;
    px          = varargin{1};
    varargin(1) = [];
end

%% Manage cell arrays of polygons

% case of a set of polygons stored in a cell array
if iscell(px)
    h   = cellfun(@(x) drawPolygon(ax, x, varargin{:}), px, 'UniformOutput', 0);
    h   = horzcat(h{:});

else
    % Check size vs number of arguments
    if size(px, 2) == 2
        % Case of polygon specified as a N-by-2 array (most standard case)
        py = px(:, 2);
        px = px(:, 1);

    elseif size(px, 2) == 1
        % Case of polygon specified as two N-by-1 arrays with same length
        if nargin < 2 || nargin == 2 && ~isnumeric(varargin{1})
            error('Matgeom:invalid_input_arg', ...
                'Should specify either a N-by-2 array, or 2 N-by-1 vectors');
        end

        % Extract coordinates of polygon vertices
        py          = varargin{1};
        varargin(1) = [];

        if length(py) ~= length(px)
            error('Matgeom:invalid_input_arg', ...
                'X and Y coordinate arrays should have same lengths (%d,%d)', ...
                length(px), length(py))
        end

    else
        error('Matgeom:invalid_input_arg', 'Should specify a N-by-2 array');
    end

    % set default line format
    if isempty (varargin)
        varargin = {'b-'};
    end

    % Check case of polygons with holes
    if any (isnan (px(:)) )
        polygons = splitPolygons ([px py]);
        h        = drawPolygon (ax, polygons, varargin{:});

    else
        % ensure last point is the same as the first one
        px(end+1, :) = px(1,:);
        py(end+1, :) = py(1,:);

        % draw the polygon outline
        h = plot(ax, px, py, varargin{:});

    end % whether there where holes

end % whether input arg was a cell

if ~state
    hold off
end

% avoid returning argument if not required
if nargout > 0
    varargout = {h};
end


function []=panel3disp(n,N,m,p,k,T,Yi,Xi,Units,endo,exo,const,beta_gibbs,beta_median,beta_std,beta_lbound,beta_ubound,sigma_gibbs,sigma_median,D_estimates,gamma_estimates,lambda1,startdate,enddate,forecast_record,forecast_estimates,Fcperiods,stringdates3,Fstartdate,Fcenddate,Feval,Fcomp,data_endo_c,data_endo_c_lags,data_exo_c,It,Bu,IRF,IRFt,pref,names)

% start displaying and saving the general results

% preliminary task: create and open the txt file used to save the results

filelocation=fullfile(pref.results_path, [pref.results_sub '.txt']);
fid=fopen(filelocation,'wt');

% print toolbox header

fprintf('%s\n','');
fprintf(fid,'%s\n','');

% print the list of contributors
bear.printcontributors(fid);

% print then estimation results

fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');

toolboxinfo='BEAR toolbox estimates';
fprintf('%s\n',toolboxinfo);
fprintf(fid,'%s\n',toolboxinfo);

time=clock;
datestring=datestr(time);
dateinfo=['Date: ' datestring(1,1:11) '   Time: ' datestring(1,13:17)];
fprintf('%s\n',dateinfo);
fprintf(fid,'%s\n',dateinfo);

fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');

VARtypeinfo='Panel VAR: random effect model (Zellner and Hong)';
fprintf('%s\n',VARtypeinfo);
fprintf(fid,'%s\n',VARtypeinfo);

if IRFt==1
SVARinfo='structural decomposition: none';
fprintf('%s\n',SVARinfo);
fprintf(fid,'%s\n',SVARinfo);
elseif IRFt==2
SVARinfo='structural decomposition: choleski factorisation';
fprintf('%s\n',SVARinfo);
fprintf(fid,'%s\n',SVARinfo);
elseif IRFt==3
SVARinfo='structural decomposition: triangular factorisation';
fprintf('%s\n',SVARinfo);
fprintf(fid,'%s\n',SVARinfo);
end

temp='units: ';
for ii=1:N
temp=[temp ' ' Units{ii,1} ' '];
end
unitinfo=temp;
fprintf('%s\n',unitinfo);
fprintf(fid,'%s\n',unitinfo);

temp='endogenous variables: ';
for ii=1:n
temp=[temp ' ' endo{ii,1} ' '];
end
endoinfo=temp;
fprintf('%s\n',endoinfo);
fprintf(fid,'%s\n',endoinfo);

temp='exogenous variables: ';
if const==0 && m==0
temp=[temp ' none'];
elseif const==1 && m==1
temp=[temp ' constant '];
elseif const==0 && m>0
   for ii=1:m-1
   temp=[temp ' ' exo{ii,1} ' '];
   end
elseif const==1 && m>1
temp=[temp ' constant '];
   for ii=1:m-1
   temp=[temp ' ' exo{ii,1} ' '];
   end
end
exoinfo=temp;
fprintf('%s\n',exoinfo);
fprintf(fid,'%s\n',exoinfo);

sampledateinfo=['estimation sample: ' startdate '-' enddate];
fprintf('%s\n',sampledateinfo);
fprintf(fid,'%s\n',sampledateinfo);

samplelengthinfo=['sample size (omitting initial conditions): ' num2str(T)];
fprintf('%s\n',samplelengthinfo);
fprintf(fid,'%s\n',samplelengthinfo);

laginfo=['number of lags included in regression: ' num2str(p)];
fprintf('%s\n',laginfo);
fprintf(fid,'%s\n',laginfo);

hyperparam1='hyperparameters:';
fprintf('%s\n',hyperparam1);
fprintf(fid,'%s\n',hyperparam1);

hyperparam2=['overall tightness (lambda1):              ' num2str(lambda1)];
fprintf('%s\n',hyperparam2);
fprintf(fid,'%s\n',hyperparam2);

fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');

% everything else is then unit-specific, hence loop over units
for hh=1:N

% first estimate the in-sample evaluation criteria
% obtain predicted values
B_median(:,:,hh)=reshape(beta_median(:,:,hh),k,n);
Yp(:,:,hh)=Xi(:,:,hh)*B_median(:,:,hh);
% then produce the corresponding residuals, using (1.9.4)
EPS(:,:,hh)=Yi(:,:,hh)-Yp(:,:,hh);

% Compute then the sum of squared residuals
% compute first the RSS matrix, defined in (1.9.5)
RSS(:,:,hh)=EPS(:,:,hh)'*EPS(:,:,hh);
% retain only the diagonal elements to get the vector of RSSi values
rss(:,:,hh)=diag(RSS(:,:,hh));

% Go on calculating R2
% generate Mbar
Mbar=eye(T)-ones(T,T)/T;
% then compute the TSS matrix, defined in (1.9.8)
TSS(:,:,hh)=Yi(:,:,hh)'*Mbar*Yi(:,:,hh);
% generate the R2 matrix in (1.9.9)
R2(:,:,hh)=eye(n)-RSS(:,:,hh)./TSS(:,:,hh);
% retain only the diagonal elements to get the vector of R2 values
r2(:,:,hh)=diag(R2(:,:,hh));

% then calculate the adjusted R2, using (1.9.11)
R2bar(:,:,hh)=eye(n)-((T-1)/(T-k))*(eye(n)-R2(:,:,hh));
% retain only the diagonal elements to get the vector of R2bar values
r2bar(:,:,hh)=diag(R2bar(:,:,hh));

% now start the display phase: start with the name of the unit

unitinfo=['Unit: ' Units{hh,1}];
fprintf('%s\n',unitinfo);
fprintf(fid,'%s\n',unitinfo);

fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');

% display coefficient estimates
coeffinfo=['VAR coefficients:'];
fprintf('%s\n',coeffinfo);
fprintf(fid,'%s\n',coeffinfo);

% loop over the equations(that is, endogenous variables) of the model
for ii=1:n
fprintf('%s\n','');
fprintf(fid,'%s\n','');

endoinfo=['Endogenous: ' endo{ii,1}];
fprintf('%s\n',endoinfo);
fprintf(fid,'%s\n',endoinfo);

coeffheader=fprintf('%25s %15s %15s %15s %15s\n','','Median','St.dev','Low.bound','Upp.bound');
coeffheader=fprintf(fid,'%25s %15s %15s %15s %15s\n','','Median','St.dev','Low.bound','Upp.bound');

% handle the endogenous
   for jj=1:n
      for kk=1:p
      values=[beta_median((ii-1)*k+n*(kk-1)+jj,1,hh) beta_std((ii-1)*k+n*(kk-1)+jj,1,hh) beta_lbound((ii-1)*k+n*(kk-1)+jj,1,hh) beta_ubound((ii-1)*k+n*(kk-1)+jj,1,hh)];
      fprintf('%25s %15.3f %15.3f %15.3f %15.3f\n',strcat(endo{jj,1},'(-',int2str(kk),')'),values);
      fprintf(fid,'%25s %15.3f %15.3f %15.3f %15.3f\n',strcat(endo{jj,1},'(-',int2str(kk),')'),values);
      end
   end

% handle the exogenous
   % if there is no constant:
   if const==0
      % if there is no exogenous at all, obvioulsy, don't display anything
      if m==0
      % if there is no constant but some other exogenous, display them
      else
         for jj=1:m
         values=[beta_median(ii*k-m+jj,1,hh) beta_std(ii*k-m+jj,1,hh) beta_lbound(ii*k-m+jj,1,hh) beta_ubound(ii*k-m+jj,1,hh)];
         fprintf('%25s %15.3f %15.3f %15.3f %15.3f\n',exo{jj,1},values);
         fprintf(fid,'%25s %15.3f %15.3f %15.3f %15.3f\n',exo{jj,1},values);
         end
      end
   % if there is a constant
   else
   % display the results related to the constant
         values=[beta_median(ii*k-m+1,1,hh) beta_std(ii*k-m+1,1,hh) beta_lbound(ii*k-m+1,1,hh) beta_ubound(ii*k-m+1,1,hh)];
         fprintf('%25s %15.3f %15.3f %15.3f %15.3f\n','Constant',values);
         fprintf(fid,'%25s %15.3f %15.3f %15.3f %15.3f\n','Constant',values);
      % if there is no other exogenous, stop here
      if m==1
      % if there are other exogenous, display their results
      else
         for jj=1:m-1
         values=[beta_median(ii*k-m+jj+1,1,hh) beta_std(ii*k-m+jj+1,1,hh) beta_lbound(ii*k-m+jj+1,1,hh) beta_ubound(ii*k-m+jj+1,1,hh)];
         fprintf('%25s %15.3f %15.3f %15.3f %15.3f\n',exo{jj,1},values);
         fprintf(fid,'%25s %15.3f %15.3f %15.3f %15.3f\n',exo{jj,1},values);
         end
      end
   end

fprintf('%s\n','');
fprintf(fid,'%s\n','');

% display evaluation measures

rssinfo=['Sum of squared residuals: ' num2str(rss(ii,1,hh),'%.2f')];
fprintf('%s\n',rssinfo);
fprintf(fid,'%s\n',rssinfo);

r2info=['R-squared: ' num2str(r2(ii,1,hh),'%.3f')];
fprintf('%s\n',r2info);
fprintf(fid,'%s\n',r2info);

adjr2info=['adj. R-squared: ' num2str(r2bar(ii,1,hh),'%.3f')];
fprintf('%s\n',adjr2info);
fprintf(fid,'%s\n',adjr2info);

end

fprintf('%s\n','');
fprintf(fid,'%s\n','');

% display VAR stability results

% check whether the model is stationary
[stationary eigmodulus]=bear.checkstable(beta_median(:,:,hh),n,p,k);
eigmodulus=reshape(eigmodulus,p,n);
stabilityinfo1=['Roots of the characteristic polynomial (modulus):'];
fprintf('%s\n',stabilityinfo1);
fprintf(fid,'%s\n',stabilityinfo1);
for jj=1:p
temp=num2str(eigmodulus(jj,1),'%.3f');
   for kk=2:n
   temp=[temp,'  ',num2str(eigmodulus(jj,kk),'%.3f')];
   end
fprintf('%s\n',temp);
fprintf(fid,'%s\n',temp);
end
if stationary==1;
stabilityinfo2=['No root lies outside the unit circle.'];
stabilityinfo3=['The estimated VAR model satisfies the stability condition'];
fprintf('%s\n',stabilityinfo2);
fprintf(fid,'%s\n',stabilityinfo2);
fprintf('%s\n',stabilityinfo3);
fprintf(fid,'%s\n',stabilityinfo3);
else
stabilityinfo2=['Warning: at leat one root lies on or outside the unit circle.'];
fprintf('%s\n',stabilityinfo2);
fprintf(fid,'%s\n',stabilityinfo2);
stabilityinfo3=['The estimated VAR model will not be stable'];
fprintf('%s\n',stabilityinfo3);
fprintf(fid,'%s\n',stabilityinfo3);
end

fprintf('%s\n','');
fprintf(fid,'%s\n','');

% display posterior for sigma
sigmainfo=['sigma (residual covariance matrix): posterior estimates'];
fprintf('%s\n',sigmainfo);
fprintf(fid,'%s\n',sigmainfo);
% calculate the (integer) length of the largest number in sigma, for formatting purpose
width=length(sprintf('%d',floor(max(abs(bear.vec(sigma_median))))));
% add a separator, a potential minus sign, and three digits (total=5) to obtain the total space for each entry in the matrix
width=width+5;
for ii=1:n
temp=[];
   for jj=1:n
   % convert matrix entry into string
   number=num2str(sigma_median(ii,jj),'% .3f');
      % pad potential missing blanks
      while numel(number)<width
      number=[' ' number];
      end
   number=[number '  '];
   temp=[temp number];
   end
fprintf('%s\n',temp);
fprintf(fid,'%s\n',temp);
end

fprintf('%s\n','');
fprintf(fid,'%s\n','');

% then display the results for D and gamma, if a structural decomposition was selected

if IRF==1 && IRFt~=1
svarinfo1=['D (structural decomposition matrix): posterior estimates'];
fprintf('%s\n',svarinfo1);
fprintf(fid,'%s\n',svarinfo1);

% recover D
D=reshape(D_estimates(:,:,hh),n,n);
% calculate the (integer) length of the largest number in D, for formatting purpose
width=length(sprintf('%d',floor(max(abs(bear.vec(D))))));
% add a separator, a potential minus sign and three digits (total=5) to obtain the total space for each entry in the matrix
width=width+5;
for ii=1:n
temp=[];
   for jj=1:n
   % convert matrix entry into string
   number=num2str(D(ii,jj),'% .3f');
      % pad potential missing blanks
      while numel(number)<width
      number=[' ' number];
      end
   number=[number '  '];
   temp=[temp number];
   end
fprintf('%s\n',temp);
fprintf(fid,'%s\n',temp);
end

fprintf('%s\n','');
fprintf(fid,'%s\n','');

svarinfo2=['gamma (structural disturbances covariance matrix): posterior estimates'];
fprintf('%s\n',svarinfo2);
fprintf(fid,'%s\n',svarinfo2);

% recover gamma
gamma=reshape(gamma_estimates(:,:,hh),n,n);
% calculate the (integer) length of the largest number in D, for formatting purpose
width=length(sprintf('%d',floor(max(abs(bear.vec(gamma))))));
% add a separator, a potential minus sign and three digits (total=5) to obtain the total space for each entry in the matrix
width=width+5;
for ii=1:n
temp=[];
   for jj=1:n
   % convert matrix entry into string
   number=num2str(gamma(ii,jj),'% .3f');
      % pad potential missing blanks
      while numel(number)<width
      number=[' ' number];
      end
   number=[number '  '];
   temp=[temp number];
   end
fprintf('%s\n',temp);
fprintf(fid,'%s\n',temp);
end

end

fprintf('%s\n','');
fprintf(fid,'%s\n','');

% finally, estimate and print the forecast evaluation criteria
% first note that forecast evaluation can only be conducted if it is activated, and if there is some observable data after the beginning of the forecast
if Feval==1 && Fcomp==1

% compute forecast evaluation
[RMSE MAE MAPE Ustat CRPS_estimates S1_estimates S2_estimates]=bear.panelfeval(n,p,k,beta_gibbs(:,:,hh),sigma_gibbs(:,:,hh),forecast_record(:,:,hh),forecast_estimates(:,:,hh),Fcperiods,data_endo_c(:,:,hh),data_endo_c_lags(:,:,hh),data_exo_c,const,It,Bu);
% then display and save the results
bear.panelfprint(n,endo,RMSE,MAE,MAPE,Ustat,CRPS_estimates,S1_estimates,S2_estimates,stringdates3,Fstartdate,Fcenddate,Fcperiods,fid);

% if forecast evaluation is activated but not possible, return a message to signal it
elseif Feval==1 && Fcomp==0

finfo1=['Forecast evaluation cannot be conducted.'];
fprintf('%s\n',finfo1);
fprintf(fid,'%s\n',finfo1);
finfo2=['Forecasts start in ' Fstartdate ', while observable data is available only until ' names{end,1} '.'];
fprintf('%s\n',finfo2);
fprintf(fid,'%s\n',finfo2);
finfo3=['To obtain forecast evaluation, the forecast start date must be anterior to the end of the data set.'];
fprintf('%s\n',finfo3);
fprintf(fid,'%s\n',finfo3);

% if forecast evaluation is not activated altogether, do not do anything
end

fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');
fprintf('%s\n','');
fprintf(fid,'%s\n','');

end

fclose(fid);


function [z] = griddata_version_control(gridX,gridY,gridZ,x,y,method,matlab_version)
% This function just computes the gridded data set, but its input is
% modified to work with matlab version newer than 2012.
% By David Bekaert - December 2012

if matlab_version>=2012
    z=griddata(gridX,gridY,gridZ,x,y,method);
else
    z=griddata(gridX,gridY,gridZ,x,y,method,{'QJ'});
end


function f = compose(f, op, g, data, pref)
%COMPOSE   Composition of UNBNDFUN objects.
%   H = COMPOSE(F, OP) returns a UNBNDFUN representing OP(F) where F is also a
%   UNBNDFUN object, and OP is a function handle.
%
%   H = COMPOSE(F, OP, G) returns OP(F, G) where F and G are UNBNDFUN objects,
%   and OP is a function handle. Note that F and G are assumed to have the same
%   domain. No warning will be given/error thrown if that is not the case, but
%   the output of the method will not be useful.
%
%   H = COMPOSE(F, G) returns a FUN representing G(F), where at least one of F
%   and G is an UNBNDFUN object. If the range of F is not included in the domain
%   of G, an error is thrown. Note that the domain of H will be the same as the
%   domain of F.
%
%   H = COMPOSE(F, OP, G, DATA, PREF) or H = COMPOSE(F, OP, [], DATA, PREF),
%   where F (and G) are UNBNDFUN objects, and OP is a function handle, uses the
%   constructor data in the structure DATA and the options passed by the
%   CHEBFUNPREF or preferences structure PREF to build the returned UNBNDFUN.
%   In particular, if the underlying tech class supports it, one can use PREF
%   to alter the constructor's behavior to take advantage of the fact that F
%   (and possibly OP or G) has additional structure beyond just being an
%   UNBNDFUN object.

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

% Parse inputs:
if ( nargin == 2 )

    if ( isa(op, 'unbndfun') )
        % Composition of two UNBNDFUN objects ( out = g(f) ):

        % OP is a UNBNDFUN! Rename it to g for clarity:
        g = op;

        % For composition to work with two FUN objects, the range of F must be
        % within the domain of G. However, we allow this method to assume that
        % it is the case.

        % When we compose F and G, we need to find the appropriate part of the
        % domain of G on which the range of F lies. Since we then want to work
        % with the ONEFUN of G, we apply the inverse map for the domain of G to
        % find the (sub)interval on [-1, 1] on which the range of F (and hence
        % its ONEFUN) lives.
        fMapped = g.mapping.Inv(f.onefun);

        % Try to do the composition, will only work if the range of F lies in
        % the domain of G.
        f.onefun = compose(fMapped, g.onefun);

    else
        % Standard composition ( out = OP(F) )

        % OP is an operator!
        f.onefun = compose(f.onefun, op);
    end

else
    % out = OP(F,G).

    if ( nargin < 5 )
        pref = chebfunpref();
    else
        pref = chebfunpref(pref);
    end

    if ( nargin < 4 )
        data = struct();
    end

    % Call ONEFUN/COMPOSE():
    if ( isempty(g) )
        f.onefun = compose(f.onefun, op, g, data, pref);
    else
        f.onefun = compose(f.onefun, op, g.onefun, data, pref);
    end

end

end


%% Copyright (C) 2014-2022 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy 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 software 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 software; see the file COPYING.
%% If not, see <http://www.gnu.org/licenses/>.

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defmethod @@sym acoth (@var{x})
%% Symbolic acoth function.
%%
%% Example:
%% @example
%% @group
%% syms x
%% y = acoth (x)
%%   @result{} y = (sym) acoth(x)
%% @end group
%% @end example
%%
%% Note: this file is autogenerated: if you want to edit it, you might
%% want to make changes to 'generate_functions.py' instead.
%%
%% @end defmethod

function y = acoth(x)
  if (nargin ~= 1)
    print_usage ();
  end
  y = elementwise_op ('acoth', x);
end

%!error acoth (sym(1), 2)
%!assert (isequaln (acoth (sym(nan)), sym(nan)))

%!shared x, d
%! d = 2;
%! x = sym('2');

%!test
%! f1 = acoth(x);
%! f2 = acoth(d);
%! assert( abs(double(f1) - f2) < 1e-15 )

%!test
%! D = [d d; d d];
%! A = [x x; x x];
%! f1 = acoth(A);
%! f2 = acoth(D);
%! assert( all(all( abs(double(f1) - f2) < 1e-15 )))

%!test
%! % round trip
%! y = sym('y');
%! A = acoth (d);
%! f = acoth (y);
%! h = function_handle (f);
%! B = h (d);
%! assert (A, B, -eps)


function y = ivmOut(model, x);

% IVMOUT Evaluate the output of an IVM model.
% FORMAT
% DESC evaluates the output of a given IVM model.
% ARG model : the model for which the output is being evaluated.
% ARG x : the input position for which the output is required.
% RETURN y : the output of the GP model. The function checks if
% there is a noise model associated with the GP, if there is, it is
% used, otherwise the mean of gpPosteriorMeanVar is returned.
%
% SEEALSO : ivmCreate, ivmPosteriorMeanVar, noiseOut
%
% COPYRIGHT : Neil D. Lawrence, 2003, 2005

% IVM

if nargin < 2
  % This implies evaluate for the training data.
  mu = model.mu;
  varsigma = model.varSigma;
else
  [mu, varsigma] = ivmPosteriorMeanVar(model, x);
end

y = noiseOut(model.noise, mu, varsigma);


% Correlation map post processing in PIVlab
function [u_out,v_out] = PIVlab_correlation_filter (u,v,corr2_thresh,corr2_value)
u(corr2_value<corr2_thresh)=nan;
v(corr2_value<corr2_thresh)=nan;
u_out=u;
v_out=v;


%IM2OBJ Convert Matlab images or datafile to dataset object
%
%  B = IM2OBJ(IM,A)
%  B = IM2OBJ(IM,FEATSIZE)
%
% INPUT
%  IM        X*Y image, X*Y*C image, X*Y*K array of K images,
%            X*Y*C*K array of color images, or cell-array of images
%            The images may be given as a datafile.
%  A         Input dataset
%  FEATSIZE  Vector with desired feature sizes to solve ambiguities
%
% OUTPUT
%  B   Dataset with IM added
%
% DESCRIPTION
% Add standard Matlab images, as objects, to an existing dataset A. If A is
% not given, a new dataset is created. Images of type 'uint8' are converted
% to 'double' and divided by 256. The resulting feature size is X*Y or
% X*Y*C. The set of images IM may be given as a datafile.
%
% SEE ALSO (PRTools Guide)
% DATASETS, DATAFILES, IM2FEAT, FEATIM

% Copyright: R.P.W. Duin, r.p.w.duin@37steps.com
% Faculty EWI, Delft University of Technology
% P.O. Box 5031, 2600 GA Delft, The Netherlands

% $Id: im2obj.m,v 1.5 2008/07/28 08:59:47 duin Exp $

function a = im2obj (im,a)

	if iscell(im)
		imsize = size(im{1});
	else
		imsize = size(im);
	end

	nodataset = 0;
	if (nargin > 1)
		if (~isdataset(a)) & size(a,1) ~= 1
			error('second argument should be a dataset or a size vector');
		end
		if isdataset(a)
			featsize = getfeatsize(a);
		else
			featsize = a;
			nodataset = 1;
		end
	else % no information on feature size, assume most simple solution
		nodataset = 1;
		if length(imsize) == 2
			featsize = imsize;
		else
			featsize = imsize(1:end-1);
		end
	end
	if length(featsize) == length(imsize)
		nobj = 1;
	elseif length(featsize) == (length(imsize)-1)
		nobj = imsize(end);
	elseif length(featsize) == (length(imsize)-2) & imsize(3) == 1
		nobj = imsize(end);
	else
		wrongfeatsize;
	end

	if any(featsize ~= imsize(1:length(featsize)))
		wrongfeatsize;
	end

	if (isa(im,'cell'))

		% If IM is a cell array of images, unpack it and recursively call IM2OBJ
		% to add each image.

		im = im(:);																	% Reshape to 1D cell array.
		for i = 1:length(im)
			b = feval(mfilename,im{i});
			if ~isempty(a) & any(a.featsize ~= b.featsize)
				error('Images should have equal sizes')
			end
			a = [a; b];
		end

  elseif isdatafile(im)

		if (nargin < 2)
			a = prdataset([]);
		end
    testdatasize(im);
    a = [a; feval(mfilename,data2im(im))];

	else

		% If IM is an image or array of images, reshape it and add it in one go.

		% Convert to double, if necessary
		if (isa(im,'uint8'))
			im = double(im)/256;
		else
			im = double(im);
		end

		% ready for the real work, at last!

		if nobj == 1
			im = im(:)';
		else
			im = shiftdim(im,ndims(im)-1);
			im = reshape(im,nobj,prod(featsize));
		end

		if nodataset
			a = prdataset(im);
			a = setfeatsize(a,featsize);
		else
			a = [a; im];
		end

	end

return

function wrongfeatsize
	error('Desired feature size and size of supplied image array are inconsistent')
return


%% Copyright (C) 2014-2017 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy 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 software 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 software; see the file COPYING.
%% If not, see <http://www.gnu.org/licenses/>.

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defmethod  @@sym ezplot (@var{f})
%% @defmethodx @@sym ezplot (@var{f1}, @var{f2})
%% @defmethodx @@sym ezplot (@var{f}, @var{dom})
%% @defmethodx @@sym ezplot (@var{f1}, @var{f2}, @var{dom})
%% @defmethodx @@sym ezplot (@dots{}, @var{N})
%% Simple plotting of symbolic expressions.
%%
%% Example parametric plot of a Lissajous Curve:
%% @example
%% @group
%% syms t
%% x = cos(3*t), y = sin(2*t)
%%   @result{} x = (sym) cos(3⋅t)
%%   @result{} y = (sym) sin(2⋅t)
%%
%% ezplot(x, y)                                 % doctest: +SKIP
%% @end group
%% @end example
%%
%% Example plotting the zero level curve of a function of two
%% variables:
%% @example
%% @group
%% syms x y
%% f = x^2 + y^2 - 1;
%% ezplot (f)                                   % doctest: +SKIP
%% @end group
%% @end example
%% Here the curve is defined implicitly by @code{f(x, y) == 0},
%% but we do not enter the @code{== 0} part.
%%
%% See help for the (non-symbolic) @code{ezplot}, which this
%% routine calls after trying to convert sym inputs to
%% anonymous functions.
%%
%% Using sym arguments for @var{dom} and @var{n} can lead to
%% ambiguity where OctSymPy cannot tell if you are specifying @var{n}
%% or @var{f2}.  For example:
%% @example
%% @group
%% syms t
%% f = sin(t);
%% N = sym(50);
%%
%% % parametric plot of f(t), N(t)
%% ezplot(f, N)                                 % doctest: +SKIP
%%
%% % plot f vs t using 50 pts
%% ezplot(f, double(N))                         % doctest: +SKIP
%% @end group
%% @end example
%%
%% The solution, as shown in the example, is to convert the sym to
%% a double.
%%
%% @seealso{ezplot, @@sym/ezplot3, @@sym/ezsurf, @@sym/function_handle}
%% @end defmethod

function varargout = ezplot(varargin)

  % first input is handle, shift
  if (ishandle(varargin{1}))
    fshift = 1;
  else
    fshift = 0;
  end

  firstsym = [];

  for i = (1+fshift):nargin
    if (isa(varargin{i}, 'sym'))
      if ( (i == 1 + fshift) || ...
           (i == 2 + fshift && isscalar(varargin{i})) ...
         )
        % This is one of the fcns to plot, so convert to handle fcn
        % The "i == 2" issscalar cond is to supports ezplot(f, sym([0 1]))

        % Each is function of one var, and its the same var for all
        % (or could be a single function of two variables)
        thissym = symvar(varargin{i});
        assert(length(thissym) <= 2, ...
          'ezplot: plotting curves: functions should have at most two inputs');
        if (isempty(thissym))
          % a number, create a constant function in a dummy variable
          % (0*t works around some Octave oddity on 3.8 and hg Dec 2014)
          thisf = inline(sprintf('%g + 0*t', double(varargin{i})), 't');
          %thisf = @(t) 0*t + double(varargin{i});  % no
        else
          % check variables match (sanity check)
          if (isempty(firstsym))
            firstsym = thissym;
          else
            assert (all (logical (thissym == firstsym)), ...
              'ezplot: all functions must be in terms of the same variables');
          end
          thisf = function_handle(varargin{i});
        end

        varargin{i} = thisf;

      else
        % plot ranges, etc, convert syms to doubles
        varargin{i} = double(varargin{i});
      end
    end
  end

  h = ezplot(varargin{:});

  if (nargout)
    varargout{1} = h;
  end

end

%%!shared hf
%%! % offscreen rendering currently (2016-06) causing crashes:
%%! % e.g., https://savannah.gnu.org/bugs/?44478
%%! hf = figure ('visible', 'off');

%!test
%! % simple
%! syms x
%! f = cos(x);
%! h = ezplot(f);
%! xx = get(h, 'xdata');
%! yy = get(h, 'ydata');
%! assert (abs(yy(end) - cos(xx(end))) <= 2*eps)
%! if (exist ('OCTAVE_VERSION', 'builtin'))
%! % matlab misses endpoint with nodisplay
%! assert (abs(xx(end) - 2*pi) <= 4*eps)
%! assert (abs(yy(end) - cos(2*pi)) <= 4*eps)
%! end

%!test
%! % parametric
%! syms t
%! x = cos(t);
%! y = sin(t);
%! h = ezplot(x, y);
%! xx = get(h, 'xdata');
%! assert (abs(xx(end) - cos(2*pi)) <= 4*eps)

%!error <all functions must be in terms of the same variables>
%! syms x t
%! ezplot(t, x)

%!error
%! syms x t
%! ezplot(t, t*x)

%!test
%! % implicit plot of f(x,y) == 0
%! syms x y
%! f = sqrt(x*x + y*y) - 1;
%! h = ezplot(f);
%! if (exist ('OCTAVE_VERSION', 'builtin'))
%!   xx = get (h, 'xdata');
%!   yy = get (h, 'ydata');
%! else
%!   if (isempty (get (h, 'zdata')))
%!     xx = get (h, 'xdata');
%!     yy = get (h, 'ydata');
%!   else
%!     cm = get (h, 'ContourMatrix');
%!     xx = cm(1, 2:end);
%!     yy = cm(2, 2:end);
%!     assert (cm(1, 1) == 0)
%!     assert (cm(2, 1) == length (xx))
%!   end
%! end
%! assert (abs (max (xx) - 1) <= 0.02)
%! assert (abs (max (yy) - 1) <= 0.02)

%!error
%! % implicit plot supports single function
%! syms x y
%! f = sqrt(x*x + y*y) - 1;
%! g = sqrt(x*x + y*y) - 4;
%! h = ezplot(f, g);

%!test
%! % bounds etc as syms
%! if (exist ('OCTAVE_VERSION', 'builtin'))
%! % this number-of-points option not supported on matlab
%! syms x
%! f = cos(x);
%! h = ezplot(f, [0 2*sym(pi)], sym(42));
%! y = get(h, 'ydata');
%! assert (length(y) == 42)
%! assert (abs(y(end) - cos(4*pi)) <= 4*eps)
%! end

%!test
%! close all

%%!test
%%! close (hf);