% DEMSILHOUETTEPLOT

% GP

% Show prediction for test data.
yPred = modelOut(model, XTest);
xyzankurAnimCompare(yPred, yTest, 96);

yDiff = (yPred - yTest);
rmsError = sqrt(sum(sum(yDiff.*yDiff))/numel(yDiff));

counter = 0;
if printDiagram
  ind = 1:27:size(yPred, 1);
  for i = ind
    counter = counter + 1;
    figure
    handle = xyzankurVisualise(yPred(i,:), 1);
    printPlot([fileBaseName '_' num2str(counter)], '../tex/diagrams', '../html')
  end
end


function a = le( x, y )

b = newcnstr( evalin( 'caller', 'cvx_problem', '[]' ), x, y, '<=' );
if nargout, a = b; end

% Copyright 2005-2016 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function varargout=gaussmixm(varargin)
%
% For calling details please see v_gaussmixm.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_gaussmixm.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: gaussmixm.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_gaussmixm(varargin{:});
else
    v_gaussmixm(varargin{:});
end


function Tr = loadCalibrationRigid(filename)

% open file
fid = fopen(filename,'r');

if fid<0
  error(['ERROR: Could not load: ' filename]);
end

% read calibration
R  = readVariable(fid,'R',3,3);
T  = readVariable(fid,'T',3,1);
Tr = [R T;0 0 0 1];

% close file
fclose(fid);

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

function A = readVariable(fid,name,M,N)

% rewind
fseek(fid,0,'bof');

% search for variable identifier
success = 1;
while success>0
  [str,success] = fscanf(fid,'%s',1);
  if strcmp(str,[name ':'])
    break;
  end
end

% return if variable identifier not found
if ~success
  A = [];
  return;
end

% fill matrix
A = zeros(M,N);
for m=1:M
  for n=1:N
    [val,success] = fscanf(fid,'%f',1);
    if success
      A(m,n) = val;
    else
      A = [];
      return;
    end
  end
end


function [acc pred softpred] = testbisvm(model, X, labels, params)
vecstest = sparse(params.dictsize, length(X));
pred = zeros(1, length(X));
for i = 1:length(X)
    nbsentraw = X{i};
    nbsentraw=nbsentraw(nbsentraw>0);
    updates = unique(nbsentraw);
    vecstest(updates,i) = 1;
end

[pred, acc, softpred] = predict(double(labels'), vecstest', model);
%[predicted_labelf, accuracyf, decision_valuesf] = svmpredict(double(labels'), vecstest', modelf, '-t 2');
pred = pred';
softpred = softpred';


function s=dUbox(pred,gt)
dX=dXbox(pred);
dI=dIbox(pred,gt);
s.dt=dX.dt-dI.dt;
s.db=dX.db-dI.db;
s.dl=dX.dl-dI.dl;
s.dr=dX.dr-dI.dr;


function [signal, accept, typeeeg, rt, response, chan_names, pnts, nsweeps, rate, xmin, xmax]=loadeeg( FILENAME, chanlist, TrialList, typerange, acceptype, rtrange, responsetype)
% eeg_load_scan_eeg - Load Neuroscan .EEG format
%
% Usage: [signal, accept, typeeeg, rt, response, chan_names, pnts, nsweeps, rate, xmin, xmax]=loadeeg( FILENAME, chanlist, TrialList, typerange, acceptype, rtrange, responsetype)
%
%      FILENAME     input Neuroscan .avg file
%      signal	    output signal
%      variance     variance of the signal
%      chan_names   array that represent the name of the electrodes
%
%      i.e.
%	  [signal] = loadeeg( 'test.eeg' );     % load data into the array named 'signal'
%         plot( signal(1,:) );	  		% plot the signal for the first electrode of the first sweep
%
%      data are organised into an array of Number_of_electrode x (Number_of_points_per_trial*Number_of_sweeps)
%      for a file with 32 electrodes, 700 points per trial and 300 sweeps, the resulting array is
%      of 32 collumn and 700*300 rows (300 consecutive blocs of 700 points)
%

% $Revision: 1.1 $ $Date: 2009-04-28 22:13:52 $

% Licence:  GNU GPL, no implied or express warranty
% History:  01/2001, arno_delorme@salk.edu
%	1062001		0.0		primitive version
%	1102001		1.0		fully working version
%	1112001		1.1		more parameters
%	1152001		1.2		fix bugs
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if nargin<1
	fprintf('Not enought arguments\n');
	help loadeeg
	return;
end;
if nargin<2 CHAN='all'; end;
if nargin<3 TrialList='all'; end;
if nargin<4 typerange='all'; end;
if nargin<5 acceptype='all'; end;
if nargin<6 rtrange  ='all'; end;
if nargin<7 responsetype='all'; end;

% open file for reading
% ---------------------
fid=fopen(FILENAME,'r','ieee-le');
if fid<0
	fprintf(2,['Error LOADEEG: File ' FILENAME ' not found\n']);
	return;
end;

% read general part of the erp header and set variables
% -----------------------------------------------------
erp = fread(fid, 362, 'uchar');	% skip the firsts 368 bytes
nsweeps = fread(fid, 1, 'ushort');	% number of sweeps
erp = fread(fid, 4, 'uchar'); 	% skip 4 bytes
pnts= fread(fid, 1, 'ushort');	% number of point per waveform
chan= fread(fid, 1, 'ushort');  % number of channels
erp = fread(fid, 4, 'uchar'); 	% skip 4 bytes
rate= fread(fid, 1, 'ushort');  % sample rate (Hz)
erp = fread(fid, 127, 'uchar');	% skip 125 bytes
xmin= fread(fid, 1, 'float32'); % in s
xmax= fread(fid, 1, 'float32'); % in s
erp = fread(fid, 387, 'uchar');	% skip 387 bytes

fprintf('number of channels         : %d\n', chan);
fprintf('number of points per trial : %d\n', pnts);
fprintf('sampling rate (Hz)         : %f\n', rate);
fprintf('xmin (s)                   : %f\n', xmin);
fprintf('xmax (s)                   : %f\n', xmax);

% read electrode configuration
% ----------------------------
fprintf('Electrode configuration\n');
for elec = 1:chan
   	channel_label_tmp = fread(fid, 10, 'uchar');
	chan_names(elec,:) = channel_label_tmp';
	for index = 2:9 if chan_names(elec,index) == 0 chan_names(elec,index)=' '; end; end;
	erp = fread(fid, 47-10, 'uchar');
	baseline(elec) = fread(fid, 1, 'ushort');
	erp = fread(fid, 10, 'uchar');
	sensitivity(elec) = fread(fid, 1, 'float32');
	erp = fread(fid, 8, 'uchar');
	calib(elec) = fread(fid, 1, 'float32');
	fprintf('%s: baseline: %d\tsensitivity: %f\tcalibration: %f\n', chan_names(elec,1:4), baseline(elec), sensitivity(elec), calib(elec));
	factor(elec) = calib(elec) * sensitivity(elec) / 204.8;
end;
%fprintf('Electrode configuration\n');
%for elec = 1:chan
%	erp = fread(fid, 47, 'uchar');
%	baseline(elec) = fread(fid, 1, 'ushort');
%	erp = fread(fid, 10, 'uchar');
%	sensitivity(elec) = fread(fid, 1, 'float32');
%	erp = fread(fid, 8, 'uchar');
%	calib(elec) = fread(fid, 1, 'float32');
%	fprintf('baseline: %d\tsensitivity: %f\tcalibration: %f\n', baseline(elec), sensitivity(elec), calib(elec));
%	factor(elec) = calib(elec) * sensitivity(elec) / 204.8;
%end;

xsize    = chan * pnts;
buf_size = chan * pnts ;			% size in shorts

% set tags for conditions
% -----------------------
if size(chanlist)  == size('all')	chanlist = [1:chan]; end;
if size(TrialList) == size('all')	trialtagI     = 1; else trialtagI     = 0; end;
if size(acceptype) == size('all')	acceptagI     = 1; else acceptagI     = 0; end;
if size(typerange) == size('all')	typetagI      = 1; else typetagI      = 0; end;
if size(responsetype) == size('all')	responsetagI  = 1; else responsetagI  = 0; end;
if size(rtrange)      == size('all')	rttagI        = 1; else rttagI        = 0; end;

count_selected = 1;
fprintf('Reserving array (can take some time)\n');
signal = zeros( chan, pnts*nsweeps);
fprintf('Array reserved, scanning file\n');

for sweep = 1:nsweeps

	% read sweeps header
	% ------------------
	s_accept   = fread(fid, 1, 'uchar');
	s_type     = fread(fid, 1, 'ushort');
	s_correct  = fread(fid, 1, 'ushort');
	s_rt       = fread(fid, 1, 'float32');
	s_response = fread(fid, 1, 'ushort');
	s_reserved = fread(fid, 1, 'ushort');

	unreaded_buf = 1;

	% store the sweep or reject the sweep
	% -----------------------------------
	if trialtagI trialtag = 1;        else trialtag = ismember(sweep, TrialList); end;
	if acceptagI acceptag = 1;        else acceptag =  ismember(s_accept, acceptype); end;
	if typetagI  typetag  = 1; 	  else typetag  =  ismember(s_type, typerange); end;
	if responsetagI responsetag  = 1; else responsetag  = ismember(s_response, responsetype); end;
	if rttagI       rttag  = 1; 	  else rttag  =  ismember(s_rt, rtrange); end;

	if typetag
		if trialtag
			if acceptag
				if responsetag
					if rttag

						buf = fread(fid, [chan pnts], 'short');
						unreaded_buf = 0;

						% copy information to array
						% -------------------------
						accept(count_selected)   = s_accept;
						typeeeg(count_selected)  = s_type;
						rt(count_selected)       = s_rt;
						response(count_selected) = s_response;

						% demultiplex the data buffer and convert to microvolts
						% -----------------------------------------------------
						for elec = 1:chan
							buf(elec, :) = (buf(elec, :)-baseline(elec)-0.0)*factor(elec);
						end;
						signal(:,[((count_selected-1)*pnts+1):count_selected*pnts]) = buf;
						count_selected = count_selected + 1;
						if not(mod(count_selected,10)) fprintf('%d sweeps selected out of %d\n', count_selected-1, sweep); end;
					end;
				end;
			end;
		end;
	end;

	if unreaded_buf fseek(fid, buf_size*2, 'cof'); end;
end;
nsweeps = count_selected-1;
fclose(fid);

% restrincting array
% ---------------------------------------
fprintf('rereservation of variables\n');
signal = signal(chanlist, 1:(count_selected-1)*pnts);
chan_names = chan_names(chanlist,:);

return;

% Frequency domain EEG File format
%
% The frequency domain epoched EEG format has
% the same header as that  described in the appendix
% of the SCAN manual (see the file sethead.h on the
% download page). For each sweep of data, there is a
% sweep header that is identical to that described
% on page Headers-5.
%
% At this point there is a difference.  After the sweep
% header, the frequency domain data for each sweep has
% the following format:
%
% for each channel (erp.nchannels):
%
% for each frequency bin (erp.pnts):
%
% real value of the FFT stored as a 4-byte float;
%
% for each frequency bin (erp.pnts):
%
% imaginary value of the FFT stored as a 4-byte float;
%
% The data have been scaled to microvolts prior to the FFT,
% and it is these results which are stored to the file.


function test_suite=SimTest_amico_test
try % assignment of 'localfunctions' is necessary in Matlab >= 2016
test_functions=localfunctions();
catch % no problem; early Matlab versions can use initTestSuite fine
end
initTestSuite;

function TestSetup
setenv('ISDISPLAY','0') % go faster! Fit only 2 voxels in FitData.m
setenv('ISCITEST','1')

function test_Sim
disp('===========================================')
disp('Running simulation test for amico');
disp('testing Simulation Single Voxel Curve...');

Model = str2func('amico'); Model = Model();
savedModel_fname = fullfile(fileparts(which('qMRLab')),'Test','MoxUnitCompatible','static_savedModelsforRetrocompatibility',['amico.qmrlab.mat']);
if ~exist(savedModel_fname,'file')
Model.saveObj(savedModel_fname);
else
Model = Model.loadObj(savedModel_fname);
end

disp(class(Model))
try Opt = button2opts(Model.Sim_Single_Voxel_Curve_buttons,1); end
try st = Model.st; catch, try st = mean([Model.lb(:),Model.ub(:)],2); catch, st = ones(length(Model.xnames),1); end; end
if exist('Opt','var') && length(Opt)>1
[Opt(:).SNR] = deal(1000);
else
Opt.SNR=1000;
end
for iopt=1:length(Opt) % Test all simulation options
disp(['Testing ' class(Model) ' simulation option:'])
disp(Opt(iopt))
FitResults = Model.Sim_Single_Voxel_Curve(st,Opt(iopt));
% Compare inputs and outputs
fnm=fieldnames(FitResults);
FitResults = rmfield(FitResults,fnm(~ismember(fnm,Model.xnames))); fnm=fieldnames(FitResults);
[~,FitResults,GroundTruth]=comp_struct(FitResults,mat2struct(st,Model.xnames),[],[],.30);
assertTrue(isempty(FitResults) & isempty(GroundTruth),evalc('FitResults, GroundTruth'))
end
disp ..ok

function TestTeardown
setenv('ISDISPLAY','') % go faster! Fit only 2 voxels in FitData.m
setenv('ISCITEST','')


%==============================================================================
% This code is part of the Matlab-based toolbox
% FAIR - Flexible Algorithms for Image Registration.
% For details see
% - https://github.com/C4IR and
% - http://www.siam.org/books/fa06/
%==============================================================================
% This is a testing environment for the files in the folder kernel/matrixfree
% 1. Based on data/contents, a list of required files is generated and it
%    is verified, that all files are present; additional files are listed.
% 2. All c-files are compiled.
% 3. All files are executed.
%==============================================================================

FAIRcheckFiles(mfilename);
testEnd;
%==============================================================================


function groupExperiments_STS(pathWORK,fSetNameType,freedomMat,maxOrder)
% -------------------------------------------------------------------------
% function groupExperiments_STS(pathWORK,fSetNameType,freedomMat,maxOrder)
% -------------------------------------------------------------------------
% DESCRIPTION:
% This function finds the best combination of model order and texture
% extraction parameter degree of freedom in terms of [AUC]0.632+ for all
% experiments performed for a given feature set. See ref. [1] for more
% details.
% -------------------------------------------------------------------------
% REFERENCE:
% [1] Vallieres, M. et al. (2015). A radiomics model from joint FDG-PET and
%     MRI texture features for the prediction of lung metastases in soft-tissue
%     sarcomas of the extremities. Physics in Medicine and Biology, 60(14),
%     5471-5496. doi:10.1088/0031-9155/60/14/5471
% -------------------------------------------------------------------------
% INPUTS:
% - pathWORK: Full path to the STS WORKSPACE directory.
% - fSetNameType: String specifying the name of the type of feature set
%                 (e.g., 'PET', 'SEPARATE', 'FUSED', etc.)
% - freedomMat:  Matrix of row vectors of 1's and 0's to specify the degree
%                of freedom on texture extraction parameters for all
%                experiments. For example, for an ith experiment where
%                extraction parameters 1, 2 and 4 in paramAll are allowed
%                to vary, use freedomMat(i,:) = [1,1,0,1].
% - maxOrder: Integer specifying the maximal model order to construct.
% -------------------------------------------------------------------------
% OUTPUTS: The optimal prediction performance results for every model order
%          (in terms of etexture extraction parameter degree of freedom)
%          are saved in a folder named 'RESULTS' in the STS WORKSPACE.
% -------------------------------------------------------------------------
% AUTHOR(S): Martin Vallieres <mart.vallieres@gmail.com>
% -------------------------------------------------------------------------
% HISTORY:
% - Creation: May 2015
%--------------------------------------------------------------------------
% STATEMENT:
% This file is part of <https://github.com/mvallieres/radiomics/>,
% a package providing MATLAB programming tools for radiomics analysis.
% --> Copyright (C) 2015  Martin Vallieres
%
%    This package 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 package 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 package.  If not, see <http://www.gnu.org/licenses/>.
% -------------------------------------------------------------------------

startpath = pwd;
cd([pathWORK,'/RESULTS'])

% LOADING ALL RESULTS FOR THE DIFFERENT EXPERIMENTS
nFreedom = size(freedomMat,1);
nParamType = size(freedomMat,2);
cellResults = cell(1,nFreedom);
for i = 1:nFreedom
    nameOpen = ['RESULTS_',fSetNameType,'_'];
    for j = 1:nParamType
        nameOpen = [nameOpen,num2str(freedomMat(i,j))];
    end
    temp = load(nameOpen); temp = struct2cell(temp); temp = temp{1};
    cellResults{i} = temp;
end

% FINDING THE BEST COMBINATIONS (model order/degree of freedom)
results = struct;
for i = 1:maxOrder
    orderName = ['Order',num2str(i)];
    auc = zeros(nFreedom,1);
    for j = 1:nFreedom
        auc(j) = cellResults{j}.(orderName).AUC632;
    end
    [~,indMax] = max(auc);
    results.(orderName) = cellResults{indMax}.(orderName);
    results.(orderName).freedom = freedomMat(indMax,:);
end

% SAVING RESULTS
save(['RESULTS_',fSetNameType,'_BEST'],'results')

cd(startpath)
end


% pop_rejkurt() - rejection of artifact in a dataset using kurtosis
%                 of activity (i.e. to detect peaky distribution of
%                 activity).
%
% Usage:
%   >> pop_rejkurt( INEEG, typerej) % pop-up interative window mode
%   >> [OUTEEG, locthresh, globthresh, nrej] = ...
%		= pop_rejkurt( INEEG, typerej, elec_comp, ...
%                   locthresh, globthresh, superpose, reject, vistype);
%
% Graphical interface:
%   "Electrode" - [edit box] electrodes or components (number) to take into
%                 consideration for rejection. Same as the 'elec_comp'
%                 parameter from the command line.
%   "Single-channel limit" - [edit box] pkurtosis limit in terms of
%                 standard-dev. Same as 'locthresh' command line
%                 parameter.
%   "All-channel limit" - [edit box] kurtosis limit in terms of
%                 standard-dev (all channel regrouped). Same as
%                 'globthresh' command line parameter.
%   "Display with previous rejection" - [edit box] can be either YES or
%                 NO. This edit box corresponds to the command line input
%                 option 'superpose'.
%   "Reject marked trials" - [edit box] can be either YES or NO. This edit
%                 box corresponds to the command line input option 'reject'.
%   "visualization type" - [edit box] can be either REJECTRIALS or EEGPLOT.
%                 This edit box corresponds to the command line input
%                 option 'vistype'.
%
% Inputs:
%   INEEG      - input dataset
%   typerej    - type of rejection (0 = independent components; 1 = eeg
%              data). Default is 1. For independent components, before
%              thresholding, the activity is normalized for each
%              component.
%   elec_comp  - [e1 e2 ...] electrodes (number) to take into
%              consideration for rejection
%   locthresh  - activity kurtosis limit in terms of standard-dev.
%   globthresh - global limit (for all channel). Same unit as above.
%   superpose  - 0=do not superpose pre-labelling with previous
%              pre-labelling (stored in the dataset). 1=consider both
%              pre-labelling (using different colors). Default is 0.
%   reject     - 0=do not reject labelled trials (but still store the
%              labels. 1=reject labelled trials. Default is 1.
%   vistype    - visualization type. 0 calls rejstatepoch() and 1 calls eegplot()
%              default is 0.
%
% Outputs:
%   OUTEEG     - output dataset with updated kurtosis array
%   locthresh  - electrodes probability of activity thresholds in terms
%              of standard-dev.
%   globthresh - global threshold (where all electrode activity are
%              regrouped).
%   nrej       - number of rejected sweeps
%
% Author: Arnaud Delorme, CNL / Salk Institute, 2001
%
% See also: rejkurt(), rejstatepoch(), pop_rejepoch(), eegplot(), eeglab()

% Copyright (C) 2001 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

% 01-25-02 reformated help & license -ad
% 03-07-02 added srate argument to eegplot call -ad
% 03-08-02 add eeglab options -ad

function [EEG, locthresh, globthresh, nrej, com] = pop_rejkurt( EEG, icacomp, elecrange, ...
                       		locthresh, globthresh, superpose, reject, vistype, topcommand);
com = '';
if nargin < 1
   help pop_rejkurt;
   return;
end;
if nargin < 2
   icacomp = 1;
end;
if exist('reject') ~= 1
    reject = 1;
end;
if icacomp == 0
	if isempty( EEG.icasphere )
	    ButtonName=questdlg( 'Do you want to run ICA now ?', ...
                         'Confirmation', 'NO', 'YES', 'YES');
    	switch ButtonName,
        	case 'NO', disp('Operation cancelled'); return;
        	case 'YES', [ EEG com ] = pop_runica(EEG);
    	end % switch
	end;
end;

if nargin < 3

	% which set to save
	% -----------------
	promptstr   = { [ fastif(icacomp, 'Electrode', 'Component') ' (number(s); Ex: 2 4 5):' ], ...
					[ fastif(icacomp, 'Single-channel', 'Single-component') ' limit(s) (std. dev(s).: Ex: 2 2 2.5):'], ...
					[ fastif(icacomp, 'All-channel', 'All-component') ' limit (std. dev(s).: Ex: 2.1 2 2):'], ...
               		'Display with previously marked rejections? (YES or NO)', ...
         			'Reject marked trial(s)? (YES or NO)', ...
         			'Visualization mode (REJECTTRIALS or EEGPLOT)' };
	inistr      = { fastif(icacomp, ['1:' int2str(EEG.nbchan)], ['1:' int2str(size(EEG.icaweights,1))])...
					fastif(icacomp, '3', '5'),  ...
					fastif(icacomp, '3', '5'), ...
               		'YES', ...
            		'NO', ...
            		'REJECTTRIALS' };

	result       = inputdlg2( promptstr, fastif(~icacomp, 'Trial rejection using comp. kurtosis -- pop_rejkurt()', 'Trial rejection using data kurtosis -- pop_rejkurt()'), 1,  inistr, 'pop_rejkurt');
	size_result  = size( result );
	if size_result(1) == 0 return; end;
	elecrange    = result{1};
	locthresh    = result{2};
	globthresh   = result{3};
	switch lower(result{4}), case 'yes', superpose=1; otherwise, superpose=0; end;
	switch lower(result{5}), case 'yes', reject=1; otherwise, reject=0; end;
	switch lower(result{6}), case 'rejecttrials', vistype=0; otherwise, vistype=1; end;
end;

if ~exist('vistype') vistype = 0; end;
if ~exist('reject') reject = 0; end;
if ~exist('superpose') superpose = 1; end;

if isstr(elecrange) % convert arguments if they are in text format
	calldisp = 1;
	elecrange = eval( [ '[' elecrange ']' ]  );
	locthresh = eval( [ '[' locthresh ']' ]  );
	globthresh = eval( [ '[' globthresh ']' ]  );
else
	calldisp = 0;
end;

if isempty(elecrange)
	error('No electrode selectionned');
end;

% compute the joint probability
% -----------------------------
if icacomp == 1
	fprintf('Computing kurtosis for channels...\n');
    if isempty(EEG.stats.kurtE )
		[ EEG.stats.kurtE rejE ] = rejkurt( EEG.data, locthresh, EEG.stats.kurtE, 1);
	end;
	[ tmp rejEtmp ] = rejkurt( EEG.data(elecrange, :,:), locthresh, EEG.stats.kurtE(elecrange, :), 1);
    rejE    = zeros(EEG.nbchan, size(rejEtmp,2));
	rejE(elecrange,:) = rejEtmp;

	fprintf('Computing all-channel kurtosis...\n');
	tmpdata = permute(EEG.data, [3 1 2]);
	tmpdata = reshape(tmpdata, size(tmpdata,1), size(tmpdata,2)*size(tmpdata,3));
	[ EEG.stats.kurt rej ] = rejkurt( tmpdata, globthresh, EEG.stats.kurt, 1);
else
	fprintf('Computing joint probability for components...\n');
    % test if ICA was computed
    % ------------------------
    icaacttmp = eeg_getica(EEG);
    if isempty(EEG.stats.icakurtE )
		[ EEG.stats.icakurtE rejE ] = rejkurt( icaacttmp, locthresh, EEG.stats.icakurtE, 1);
	end;
	[ tmp rejEtmp ] = rejkurt( icaacttmp(elecrange, :,:), locthresh, EEG.stats.icakurtE(elecrange, :), 1);
	rejE    = zeros(size(icaacttmp,1), size(rejEtmp,2));
	rejE(elecrange,:) = rejEtmp;

	fprintf('Computing global joint probability...\n');
	tmpdata = permute(icaacttmp, [3 1 2]);
	tmpdata = reshape(tmpdata, size(tmpdata,1), size(tmpdata,2)*size(tmpdata,3));
	[ EEG.stats.icakurt rej] = rejkurt( tmpdata, globthresh, EEG.stats.icakurt, 1);
end;
rej = rej' | max(rejE, [], 1);
fprintf('%d/%d trials marked for rejection\n', sum(rej), EEG.trials);

if calldisp
	if vistype == 1 % EEGPLOT -------------------------
	    if icacomp == 1 macrorej  = 'EEG.reject.rejkurt';
	        			macrorejE = 'EEG.reject.rejkurtE';
	    else			macrorej  = 'EEG.reject.icarejkurt';
	        			macrorejE = 'EEG.reject.icarejkurtE';
	    end;

		colrej = EEG.reject.rejkurtcol;
		eeg_rejmacro; % script macro for generating command and old rejection arrays

	    if icacomp == 1
	        eegplot( EEG.data(elecrange,:,:), 'srate', ...
		      EEG.srate, 'limits', [EEG.xmin EEG.xmax]*1000 , 'command', command, eegplotoptions{:});
	    else
	        eegplot( icaacttmp(elecrange,:,:), 'srate', ...
		      EEG.srate, 'limits', [EEG.xmin EEG.xmax]*1000 , 'command', command, eegplotoptions{:});
	    end;
    else % REJECTRIALS -------------------------
	  	if icacomp	== 1
			[ rej, rejE, n, locthresh, globthresh] = ...
				rejstatepoch( EEG.data, EEG.stats.kurtE(elecrange,:), 'global', 'on', 'rejglob', EEG.stats.kurt, ...
						'threshold', locthresh, 'thresholdg', globthresh, 'normalize', 'off'  );
		else
			[ rej, rejE, n, locthresh, globthresh] = ...
				rejstatepoch( icaacttmp, EEG.stats.icakurtE(elecrange,:), 'global', 'on', 'rejglob', EEG.stats.icakurt, ...
						'threshold', locthresh, 'thresholdg', globthresh, 'normalize', 'off' );
		end;
		nrej = n;
	end;
else
	% compute rejection locally
	rejtmp = max(rejE(elecrange,:),[],1);
	rej = rejtmp | rej;
	nrej =  sum(rej);
	fprintf('%d trials marked for rejection\n', nrej);
end;
if ~isempty(rej)
	if icacomp	== 1
		EEG.reject.rejkurt = rej;
		EEG.reject.rejkurtE = rejE;
	else
		EEG.reject.icarejkurt = rej;
		EEG.reject.icarejkurtE = rejE;
	end;
    if reject
        EEG = pop_rejepoch(EEG, rej, 0);
    end;
end;
nrej = sum(rej);

com = [ com sprintf('%s = pop_rejkurt(%s,%s);', inputname(1), ...
		inputname(1), vararg2str({icacomp,elecrange,locthresh,globthresh,superpose,reject})) ];
if nargin < 3 & nargout == 2
	locthresh = com;
end;

return;


% The COBRAToolbox: testAddLopLawConstraints.m
%
% Purpose:
%     - test OptForce (according to the tutorial)
%
% Authors:
%     - Thomas Pfau Oct 2017
%

global CBTDIR

solverPkgs = prepareTest('requireOneSolverOf', {'ibm_cplex','gurobi'});

originalDir = pwd;

pathTutorial = which('testOptForce.m');
pathstr = fileparts(pathTutorial);
cd(pathstr)

%Init paralell pool, if possible
try
    minWorkers = 2;
    myCluster = parcluster(parallel.defaultClusterProfile);

    if myCluster.NumWorkers >= minWorkers
        poolobj = gcp('nocreate');  % if no pool, do not create new one.
        if isempty(poolobj)
            parpool(minWorkers);  % launch minWorkers workers
        end
        parPoolCreated = true;
    end
catch
    parPoolCreated = false;
end

model = getDistributedModel('AntCore.mat');
model.c(strcmp(model.rxns, 'R75')) = 1;
model = changeRxnBounds(model, 'EX_gluc', -100, 'l');
model = changeRxnBounds(model, 'EX_o2', -100, 'l');
model = changeRxnBounds(model, 'EX_so4', -100, 'l');
model = changeRxnBounds(model, 'EX_nh3', -100, 'l');
model = changeRxnBounds(model, 'EX_cit', -100, 'l');
model = changeRxnBounds(model, 'EX_glyc', -100, 'l');

origmodel = model;

%set up the xlwrite command for xls io. We do this before the loop, as
%changeCobraSolver will correct the globals which are reset on 2014b by a
%javaaddpath.
setupxlwrite();

for k = 1:length(solverPkgs)
    solverLPOK = changeCobraSolver(solverPkgs.LP{k}, 'LP');
    solverMILPOK = changeCobraSolver(solverPkgs.MILP{k}, 'MILP');

    if solverLPOK && solverMILPOK
        %get max growth rate
        model = origmodel;
        growthRate = optimizeCbModel(model);
        %get max succinate production
        model = changeObjective(model, 'EX_suc');
        maxSucc = optimizeCbModel(model);
        %Set a high Biomass production constraint
        constrWT = struct('rxnList', {{'R75'}}, 'rxnValues', 14, 'rxnBoundType', 'b');
        constrMT = struct('rxnList', {{'R75', 'EX_suc'}}, 'rxnValues', [0, 155.55], ...
                  'rxnBoundType', 'bb');
        succExPos = ismember(model.rxns,'EX_suc');
        biomassPos = ismember(model.rxns,'R75');
        [minFluxesW, maxFluxesW, minFluxesM, maxFluxesM, ~, ~] = FVAOptForce(model, ...
                                                                     constrWT, constrMT);
        %Assert, that the constraints are met.
        assert(minFluxesW(biomassPos) == 14);
        assert(maxFluxesW(biomassPos) == 14);
        assert(minFluxesM(succExPos) == 155.55);
        assert(maxFluxesM(succExPos) == 155.55);
        assert(minFluxesM(biomassPos) == 0);
        assert(maxFluxesM(biomassPos) == 0);
        runID = 'TestOptForceM';

        %Get Must Sets
        fprintf('Building Must sets...\n')
        constrOpt = struct('rxnList', {{'EX_gluc', 'R75', 'EX_suc'}}, 'values', [-100, 0, 155.5]');
        [mustLSet, pos_mustL] = findMustL(model, minFluxesW, maxFluxesW, 'constrOpt', constrOpt, ...
                                  'runID', runID, 'printLevel', 0);
        [mustUSet, pos_mustU] = findMustU(model, minFluxesW, maxFluxesW, 'constrOpt', constrOpt, ...
                                  'runID', runID, 'printLevel', 0);

        %constrOpt = struct('rxnList', {{'EX_gluc', 'R75', 'EX_suc'}}, 'values', [-100, 0, 155.5]');
        exchangeRxns = model.rxns(cellfun(@isempty, strfind(model.rxns, 'EX_')) == 0);
        excludedRxns = unique([mustUSet; mustLSet; exchangeRxns]);
        [mustUU, pos_mustUU, mustUU_linear, pos_mustUU_linear] = ...
                findMustUU(model, minFluxesW, maxFluxesW, 'constrOpt', constrOpt, ...
                           'excludedRxns', excludedRxns,'runID', runID, ...
                           'printLevel', 0);

        [mustLL, pos_mustLL, mustLL_linear, pos_mustLL_linear] = ...
                findMustLL(model, minFluxesW, maxFluxesW, 'constrOpt', constrOpt, ...
                           'excludedRxns', excludedRxns,'runID', runID, ...
                           'printLevel', 0);
        [mustUL, pos_mustUL, mustUL_linear, pos_mustUL_linear] = ...
                findMustUL(model, minFluxesW, maxFluxesW, 'constrOpt', constrOpt, ...
                          'excludedRxns', excludedRxns,'runID', runID, ...
                          'printLevel', 0);
        mustU = unique(union(mustUSet, mustUU));
        mustL = unique(union(mustLSet, mustLL));
        targetRxn = 'EX_suc';
        biomassRxn = 'R75';
        nSets = 1;
        constrOpt = struct('rxnList', {{'EX_gluc','R75'}}, 'values', [-100, 0]);
        fprintf('Running OptForce with k = 1\n')
        [optForceSets, posOptForceSets, typeRegOptForceSets, flux_optForceSets] = ...
                optForce(model, targetRxn, biomassRxn, mustU, mustL, ...
                         minFluxesW, maxFluxesW, minFluxesM, maxFluxesM, ...
                         'k', 1, 'nSets', nSets, 'constrOpt', constrOpt, ...
                         'runID', runID);
        assert(validateOptForceSol(origmodel,posOptForceSets,typeRegOptForceSets,'EX_suc'));
        %clean up
        rmdir(runID,'s')
        fprintf('Running Optforce with k = 2\n')
        nSets = 20;
        runID = 'TestOptForceM2';
        excludedRxns = struct('rxnList', {{'SUCt'}}, 'typeReg','U');
        [optForceSets, posOptForceSets, typeRegOptForceSets, flux_optForceSets] = ...
            optForce(model, targetRxn, biomassRxn, mustU, mustL, ...
             minFluxesW, maxFluxesW, minFluxesM, maxFluxesM, ...
             'k', 2, 'nSets', nSets, 'constrOpt', constrOpt, ...
             'excludedRxns', excludedRxns, ...
             'runID', runID);
        assert(validateOptForceSol(origmodel,posOptForceSets,typeRegOptForceSets,'EX_suc'));
        %clean up
        rmdir(runID,'s');
    end
end

cd(originalDir);


function varargout = edgesEvalDL( model, varargin )
% Run and evaluate structured edge detector with deep contour features on BSDS500.
% The code is modified from Structured Edge Detection Toolbox

% get default parameters
dfs={'dataType','test', 'name','', 'opts',{}, 'show',0, ...
  'pDistr',{{'type','parfor'}}, 'cleanup',0, 'thrs',99, 'maxDist',.0075};
p=getPrmDflt(varargin,dfs,1);

% load model and update model.opts acoording to opts
if( ischar(model) ), model=load(model); model=model.model; end
for i=1:length(p.opts)/2, model.opts.(p.opts{i*2-1})=p.opts{i*2}; end
rgbd=model.opts.rgbd; model.opts.nms=1;

% get list of relevant directories (image, depth, gt, results)
name = [model.opts.modelFnm,p.name];
imgDir = fullfile(model.opts.bsdsDir,'images',p.dataType);
depDir = fullfile(model.opts.bsdsDir,'depth',p.dataType);
resDir = fullfile(model.opts.modelDir,p.dataType,name);

gtDir  = fullfile(model.opts.bsdsDir,'groundTruth',p.dataType);
evaDir = resDir;

assert(exist(imgDir,'dir')==7); assert(exist(gtDir,'dir')==7);
% run edgesDetect() on every image in imgDir and store in resDir
if( ~exist(fullfile([evaDir '-eval'],'eval_bdry.txt'),'file') )
  if(~exist(resDir,'dir')), mkdir(resDir); end
  ids=dir(imgDir); ids=ids([ids.bytes]>0); ids={ids.name}; n=length(ids);
  ext=ids{1}(end-2:end); for i=1:n, ids{i}=ids{i}(1:end-4); end
  res=cell(1,n); for i=1:n, res{i}=fullfile(resDir,[ids{i} '.png']); end
  do=false(1,n); for i=1:n, do(i)=~exist(res{i},'file'); end
  ids=ids(do); res=res(do); m=length(ids);
  for i=1:m, id=ids{i};
    I = imread(fullfile(imgDir,[id '.' ext])); D=[];
    if(rgbd), D=single(imread(fullfile(depDir,[id '.png'])))/1e4; end
    if(rgbd==1), I=D; elseif(rgbd==2), I=cat(3,single(I)/255,D); end
    model.imgId = id;
    tic;
    E=edgesDetectDL(I,model); imwrite(uint8(E*255),res{i});
    toc;
  end
end

% perform actual evaluation using edgesEvalDir
varargout=cell(1,max(1,nargout));
[varargout{:}] = edgesEvalDir('resDir',resDir,'gtDir',gtDir,...
  'pDistr',p.pDistr,'cleanup',p.cleanup,'thrs',p.thrs,'maxDist',p.maxDist);
if( p.show ), figure(p.show); edgesEvalPlot(evaDir,name); end

end


function f = or(f, g)
%|   CHEBTECH logical OR.
%   F | G performs a logical OR of the CHEBTECH objects F and G and returns a
%   CHEBTECH containing elements set to either logical 1 (TRUE) or logical 0
%   (FALSE).  An element of the output CHEBTECH is set to 1 if either input
%   CHEBTECH contains a non-zero element at that point, otherwise it is set to
%   0.  F and G must either be identically zero or have roots in their domains.
%   If this is not the case, garbage is returned with no warning.

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

arbitraryPoint = 0.1273881594;
f.coeffs = feval(f, arbitraryPoint) | feval(g, arbitraryPoint);

end


classdef WrapperMshResFiles < handle

    properties (Access = public)
        dataRes
        mesh
    end

    properties (Access = private)
        dataMesh
    end

    properties (Access = private)
        fileName
        folderPath
    end

    methods (Access = public)

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

        function compute(obj)
            obj.wrapGiDMshData();
            obj.createMesh();
            obj.wrapGiDResData();
        end

    end

    methods (Access = private)

        function init(obj,cParams)
            obj.fileName   = cParams.fileName;
            obj.folderPath = cParams.folderPath;
        end

        function wrapGiDMshData(obj)
            fM = [obj.fileName,'.flavia.msh'];
            s.filePath = fullfile(obj.folderPath,fM);
            wM = WrapperMshFile(s);
            wM.read();
            obj.dataMesh = wM.getDataBase();
        end

        function createMesh(obj)
            s.connec = obj.dataMesh.connec;
            s.coord  = obj.dataMesh.coord;
            obj.mesh = Mesh(s);
        end

        function wrapGiDResData(obj)
            fR = [obj.fileName,'.flavia.res'];
            s.filePath = fullfile(obj.folderPath,fR);
            s.nElem     = obj.mesh.nelem;
            s.nNodes    = obj.mesh.nnodes;
            s.dimension = obj.mesh.ndim;
            wR = WrapperResFile(s);
            wR.read();
            obj.dataRes = wR.getDataBase();
        end

    end

end


function kern = rbfinfwhiteKernExpandParam(kern, params)

% RBFINFWHITEKERNEXPANDPARAM Create kernel structure from RBF-WHITE kernel's
% parameters (with integration limits between minus infinity and infinity).
% FORMAT
% DESC returns a RBF-WHITE kernel structure filled with the parameters in
% the given vector. This is used as a helper function to enable parameters
% to be optimised in, for example, the NETLAB optimisation functions.
% ARG kern : the kernel structure in which the parameters are to be
% placed.
% ARG param : vector of parameters which are to be placed in the
% kernel structure.
% RETURN kern : kernel structure with the given parameters in the
% relevant locations.
%
% SEEALSO : rbfinfwhiteKernParamInit, rbfinfwhiteKernExtractParam, kernExpandParam
%
% COPYRIGHT : David Luengo, 2009

% KERN

kern.inverseWidth = params(1);
kern.variance = params(2);


function manoptADhelp()
% Automatic differentation (AD) in Manopt requires the following:
%   Matlab version R2021a or later.
%   Deep Learning Toolbox version 14.2 or later.
%
% First, read the documentation of manoptAD by typing:
%
%   help manoptAD
%
% Examples using AD can be found in the folder:
%
%   /manopt/autodiff/basic_examples_AD
%
% More sophisticated examples can also be found in
%
%   /examples
%
% by reading the comments inside the scripts.
%
% The comments here provide further information about how to use AD. These
% comments are necessary because of certain limitations both of the AD
% capabilities of the Deep Learning Toolbox and of Manopt's ability to
% handle certain delicate geometries, e.g., fixed-rank matrices, with AD.
%
% The basic usage of AD in Manopt goes as follows:
%
%   problem.M = ...; %call a factory to get a manifold structure
%   problem.cost = @(x) ...; % implement your cost function
%   problem = manoptAD(problem); % ask AD to figure out gradient + Hessian
%   ...; % call a solver on problem, e.g., x = trustregions(problem);
%
% The current implementation of AD is based on Matlab's Deep Learning
% Toolbox. The latter relies on dlarray to represent data (arrays).
% While this works very well, unfortunately, there are a few limitations.
% For example, certain functions do not support dlarray.
% See the following official website for a list of compatbile functions:
%
%   https://ch.mathworks.com/help/deeplearning/ug/list-of-functions-with-dlarray-support.html.
%
% Moreover, dlarray only supports complex variables starting with
% Matlab R2021b.
%
% To handle complex numbers in R2021a and earlier, and also to handle
% functions that are not supported by dlarray at this moment, Manopt
% provides a limited collection of backup functions which are compatible
% with AD. Explicitly, the left column below lists commonly used functions
% which are not supported by dlarray at this time, and the right column
% lists corresponding replacement functions that can be used:
%
%     trace                 ctrace
%     diag                  cdiag
%     triu                  ctriu
%     tril                  ctril
%     norm(..., 'fro')      cnormfro
%     norm(..., 'fro')^2    cnormsqfro
%     multiscale            cmultiscale
%
% All the other multi*** functions in Manopt support AD.
%
% Moreover, bsxfun is not supported. The user may have to translate it
% into repmat and point-wise expressions.
% Concatenating arrays along the third or higher dimension such as in
% cat(A, B, 3+) is not supported for AD.
% The matrix functions sqrtm, logm, expm, eig, svd, det, cumsum,  movsum,
% cumprod, \, inv, mod, rem, vecnorm, bandwidth are not supported.
%
% For Matlab R2021a or earlier, in addition to the functions mentioned
% above, dot is not supported.
% Element-wise multiplication can be replaced by cdottimes.
%
% To deal with complex variables in R2021a and earlier, Manopt converts
% complex arrays into a structure with fields real and imag.
% See mat2dl_complex and dl2mat_complex for more details. In this case,
% the user should try using the basic functions in the folder
%
%   /manopt/autodiff/functions_AD
%
% when defining the cost function. An alternative way is to define one's
% own basic functions. These functions should accept both numeric arrays
% and structures with fields real and imag.
% See cprod and complex_example_AD as examples.
%
% See also: manoptAD complex_example_AD

% This file is part of Manopt: www.manopt.org.
% Original author: Xiaowen Jiang, Aug. 31, 2021.
% Contributors: Nicolas Boumal
% Change log:

    fprintf('The file manoptADhelp is just for documentation: run ''help manoptADhelp''.\n');

end


function  data = datasaver(varargin)

persistent saved

if nargin > 3
    saved.savedfunctiondata = varargin{1};
    saved.savedfunctionGradientdata = varargin{2};
    saved.savedfunctionHessiandata = varargin{3};
    saved.savedconstraintdata = varargin{4};
    saved.savedconstraintGradientdata = varargin{5};
    saved.savedconstraintHessiandata = varargin{6};
    saved.m = size(saved.savedconstraintdata.F_struc,1);
    saved.n = length(saved.savedfunctiondata.linearindicies);
    saved.monomials = [];
    saved.x = randn(saved.n,1);
    return
end

x = varargin{2};
if ~isequal(x,saved.x)
    % Recompute the monomial terms for new x
    saved.monomials=ones(1,size(saved.savedfunctiondata.monomtable,2));
    saved.monomials(saved.savedfunctiondata.linearindicies) = x(:)';
   % changed = find(x-saved.x);
   % changed = saved.savedfunctiondata.linearindicies(changed);
   % changedmonomials = find(any(saved.savedfunctiondata.monomtable(saved.savedfunctiondata.nonlinearindicies,changed),2));

    for i = 1:length(saved.savedfunctiondata.nonlinearindicies)
        saved.monomials(saved.savedfunctiondata.nonlinearindicies(i)) = prod(saved.monomials.^saved.savedfunctiondata.monomtable(saved.savedfunctiondata.nonlinearindicies(i),:));
    end
    saved.x = x;
end

switch varargin{1}
    case 1
        F = saved.savedfunctiondata.F_struc;
        x = varargin{2};
    case 2
        F = saved.savedfunctionGradientdata.F_struc;
    case 3
        F = saved.savedfunctionHessiandata.F_struc;
    case 4
        if nargin == 2
            % ipopt call
            F = saved.savedconstraintdata.F_struc;
        else
            % pennlp call
            F = saved.savedconstraintdata.F_struc(1+varargin{3},:);
        end
    case 5
        F = saved.savedconstraintGradientdata.F_struc;
        start = 1+(varargin{3}-1)*saved.n;
        F = F(varargin{3}:saved.m:end,:);
    case 6
        F = saved.savedconstraintHessiandata.F_struc;
        F = full(F((varargin{3}-1)+(1:saved.m:saved.m*saved.n^2),:));
    otherwise
end

data = (F*[1;saved.monomials(:)]);


function BuildBCMaps3D()

% function BuildBCMaps3D
% Purpose: Build specialized nodal maps for various types of boundary conditions,
%           specified in BCType.

Globals3D;

% create label of face nodes with boundary types from BCType
bct    = BCType';
bnodes = ones(Nfp, 1)*bct(:)'; bnodes = bnodes(:);

% find location of boundary nodes in face and volume node lists
mapI = find(bnodes==In);           vmapI = vmapM(mapI);
mapO = find(bnodes==Out);	   vmapO = vmapM(mapO);
mapW = find(bnodes==Wall);         vmapW = vmapM(mapW);
mapF = find(bnodes==Far);          vmapF = vmapM(mapF);
mapC = find(bnodes==Cyl);          vmapC = vmapM(mapC);
mapD = find(bnodes==Dirichlet);    vmapD = vmapM(mapD);
mapN = find(bnodes==Neuman);       vmapN = vmapM(mapN);
mapS = find(bnodes==Slip);         vmapS = vmapM(mapS);
return;


function openCalcParamWindowGK(obj)
		%Here a window for the calculation parameters should be created
		%I suggest using the inputsdlg function

		Title = 'Gardner-Knopoff Decluster ';
		Prompt={'Window Method:', 'GK_Method';...
			'Force MainShock:', 'GK_SetMain'};

		LabelList2 =  {	'Gardener & Knopoff (table), 1974';...
				'Gardener & Knopoff (formula), 1974'; ...
				'Gruenthal pers. communication'; ...
				'Urhammer, 1986'};

		%Method
		Formats(1,1).type='list';
		Formats(1,1).style='popupmenu';
		Formats(1,1).items=LabelList2;

		%SetMain
		Formats(2,1).type='check';

		%%%% SETTING DIALOG OPTIONS
		Options.WindowStyle = 'modal';
		Options.Resize = 'on';
		Options.Interpreter = 'tex';
		Options.ApplyButton = 'off';

		%open the dialog window
		[NewParameter,Canceled] = inputsdlg(Prompt,Title,Formats,obj.CalcParameter,Options);

		obj.CalcParameter=NewParameter;

		if Canceled==1
			obj.StartCalc=false;
		else
			obj.StartCalc=true;
		end

end


function [oldvariable,sqrList] = expandforindex(sqrList,candidates,nonconvindex);
%EXPANDFORINDEX Internal function for organizing nonlinear variables

% Expand the incoming variables

if 1
z = sqrList(:,1);

x1_list = find(z==candidates(2));
if candidates(2)==candidates(1)
    x2_list = x1_list;
else
    x2_list = find(z==candidates(1));
end

temp = [];
if isempty(x1_list)
    temp = candidates(2);
else
    temp = sqrList(x1_list,2:end);
end
if isempty(x2_list)
    temp = [temp candidates(1)];
else
    temp = [temp sqrList(x2_list,2:end)];
end
temp = sort(temp(find(any(temp,1))));

oldsqrList = sqrList;
if length(temp)>size(sqrList,2)-1
    % This one cannot already exist
    index = [];

    %sqrList = [sqrList zeros(size(sqrList,1),1+size(sqrList,2)-length(temp));nonconvindex temp(end:-1:1)];
    sqrList = [sqrList zeros(size(sqrList,1),1+length(temp)-size(sqrList,2));nonconvindex temp(end:-1:1)];
else
%    sqrList = [sqrList;nonconvindex temp(end:-1:1) zeros(1,size(sqrList,2)-length(temp)-1)];
%    searchfor = sqrList(end,2:end);

    searchfor = [temp(end:-1:1) zeros(1,size(sqrList,2)-length(temp)-1)];
    searchin = sqrList(:,2:end);

    % Simple Hash
    key = sum(searchfor);
    tbl = sum(searchin,2);

    possible = find(tbl==key);

    index = findrows(searchin(possible,:),searchfor);
    if isempty(index)
         sqrList = [sqrList;nonconvindex temp(end:-1:1) zeros(1,size(sqrList,2)-length(temp)-1)];
    else
         index = possible(index);
    end
end

%searchfor = sqrList(end,2:end);
%index = findrows(sqrList(1:end-1,2:end),searchfor);

if length(index)>1
    index
end

if ~isempty(index)
    oldvariable = sqrList(index,1);
    sqrList = oldsqrList;
else
    oldvariable = [];
end

else

% Expand the list to begin with
if isempty(sqrList)
    sqrList = [nonconvindex candidates];
else
    sqrList = [sqrList; nonconvindex candidates(2) candidates(1) zeros(1,size(sqrList,2)-3)];
end
bottom = size(sqrList,1);

%%FIXz = sqrList(1:bottom,1);
z = sqrList(:,1);

x1_list = find(z==candidates(2));
if candidates(2)==candidates(1)
    x2_list = x1_list;
else
    x2_list = find(z==candidates(1));
end

temp = [];
if isempty(x1_list)
    temp = sqrList(bottom,2);
else
    temp = sqrList(x1_list,2:end);
end
if isempty(x2_list)
    temp = [temp sqrList(bottom,3)];
else
    temp = [temp sqrList(x2_list,2:end)];
end
temp = sort(temp(find(any(temp,1))));
sqrList(bottom,2:2+length(temp)-1)=temp(end:-1:1);%fliplr(sort(temp));

bottom = bottom+1;

searchfor = sqrList(end,2:end);
index = findrows(sqrList(1:end-1,2:end),searchfor);

if ~isempty(index)
    oldvariable = sqrList(index,1);
    sqrList = sqrList(1:end-1,:);
else
    oldvariable = [];
end

end


function slimgsetprep(srcfolder, dstpath, matsize, maxsec)
%SLIMGSETPREP organizes the images in a MATLAB friendly way
%
% $ Syntax $
%   - slimgsetprep(srcfolder, dstpath, matsize, maxsec)
%
% $ Argument $
%   - srcfolder:        the source file folder
%   - dstpath:          the destination file (without extension name)
%   - matsize:          the matrix size (row vector): [nrows, ncols]
%   - maxsec:           the maximum section size
%
% $ Description $
%   - slimgsetprep(srcfolder, dstpath, imgsiz, maxsec) prepares the matlab
%     files in destination for a set of images. The requirement is
%       1) In source folder: there are all the images and a DSDML
%          description file named dataset.xml
%       2) For destination, say abc, then there would be a core file named
%          abc.xml. And if the actual data is separately stored, there are
%          a series of files named abc.arr.<begin index>-<last index>. For
%          example, abc.arr.0001-2000, means that the 1st t0 2000th samples
%          are stored in the array file.
%       3) maxsec is the number of samples in each section. If maxsec is
%          specified, the images are stored in separate array files. If
%          maxsec is not specified or empty, the images are stored in core
%          file.
%       4) The core file is a MAT file with following variables:
%           'desc':         the DSDML data object descriptor
%           'sections':     the starting and ending indices of all sections
%           'matsize':      the row vector describing the size of images
%           'data':         the image array
%                           if imgs is numeric, it is the actual image
%                           array.
%                           if imgs is a cell array, it is the set of
%                           array filenames.
%
% $ History $
%   - Created by Dahua Lin, on Jul 26th, 2006
%

%% Parse and verify input arguments

if nargin < 3
    raise_lackinput('slimgsetprep', 3);
end

isseparate = false;
if nargin >= 4
    isseparate = ~isempty(maxsec);
end

matsize = matsize(:)';
if length(matsize) ~= 2
    error('sltoolbox:invalidarg', ...
        'imgsize should be a 2-element vector');
end

%% Read the dataset

descrfile = [srcfolder, '\dataset.xml'];
desc = dataset(descrfile);

N = desc.numsamples;
fns = desc.filenames;

%% Process data

if ~isseparate

    datasiz = [matsize, N];
    data = zeros(datasiz);

    for i = 1 : N
        img = imread([srcfolder, '\', fns{i}]);
        img = slimg2mat(img);
        data(:,:,i) = img;
    end

else

    sections = slpartition(N, 'maxblksize', maxsec);
    nsecs = length(sections.sinds);

    data = cell(nsecs, 1);

    % process filenames
    dstdir = fileparts(dstpath);
    numlen = length(num2str(N));
    if isempty(dstdir)  % local dst
        dstfnpat = [dstpath, sprintf('.arr.%%0%dd-%%0%dd', numlen, numlen)];
        dstfppre = [];
    else
        dstfnpat = [dstpath(length(dstdir)+2:end), sprintf('.arr.%%0%dd-%%0%dd', numlen, numlen)];
        dstfppre = [dstdir, '\'];
    end

    for i = 1 : nsecs
        si = sections.sinds(i);
        ei = sections.einds(i);

        curfn = sprintf(dstfnpat, si, ei);
        curfp = [dstfppre, curfn];
        data{i} = curfn;

        curN = ei - si + 1;
        arr = zeros([matsize, curN]);

        for j = 1 : curN
            curidx = si + j - 1;
            img = imread([srcfolder, '\', fns{curidx}]);
            img = slimg2mat(img);
            arr(:,:,j) = img;
        end

        slwritearray(arr, curfp);
    end

end

%% Output core

corefile = [dstpath, '.mat'];
save(corefile, 'desc', 'sections', 'matsize', 'data', '-v6');


function [x,fval,exitflag,info] = opti_lbfgsb(fun,grad,lb,ub,x0,opts)
%OPTI_LBFGSB Solve a bounded NLP using L-BFGS-B (Nocedal & Zhu)
%
%   min f(x)       subject to:   lb <= x <= ub
%    x
%
%   x = opti_lbfgsb(fun,grad,lb,ub,x0) solves a NLP where fun is the
%   objective function and grad is the gradient of the objective. lb and ub
%   are the decision variable bounds (required) and x0 is a starting guess.
%   Avoid Infinite bounds.
%
%   x = opti_lbfgsb(fun,...,x0,opts) uses opts to pass optiset options to
%   the solver.
%
%   [x,fval,exitflag,info] = opti_lbfgsb(...) returns the objective value
%   at the solution, together with the solver exitflag, and an information
%   structure.
%
%   THIS IS A WRAPPER FOR L-BFGS-B
%   See referenced BSD License

%   Copyright (C) 2012 Jonathan Currie (IPL)

if(nargin < 6), opts = optiset; end
if(nargin < 5), error('LBFGSB requires at least 5 arguments'); end

%Add in clpset settings
if(isfield(opts,'solverOpts') && ~isempty(opts.solverOpts))
    popts = lbfgsbset(opts.solverOpts);
else
    popts = lbfgsbset;
end
%Add in options from optiset
popts.maxiter = opts.maxiter;
popts.maxtime = opts.maxtime;
popts.maxfeval = opts.maxfeval;
popts.tolrfun = opts.tolrfun;
popts.iterfun = opts.iterfun;
popts.optiver = optiver;
%Setup display level
popts.display = dispLevel(opts.display);

%Ensure we have bounds
if(isempty(lb) || isempty(ub))
    error('L-BFGS-B only solves bounded NLPs - You must supply lb and ub to this function');
end
%Ensure we have a gradient
if(isempty(grad))
    error('L-BFGS-B requires a gradient function');
end

%Check we have a valid x0
if(isempty(x0) || any(isnan(x0)))
    error('L-BFGS-B requires an initial guess, x0!');
end

t = tic;
% Run L-BFGS-B
[x, fval, status, iter, feval] = lbfgsb(fun,grad,lb,ub,x0,popts);

%Collect Results
info.Iterations = iter;
info.FuncEvals = feval;
info.Time = toc(t);
info.Algorithm = 'L-BFGS-B: Limited Memory BFGS Bounded Optimization';

switch(status)
    case 0
        info.Status = 'Success';
        exitflag = 1;
    case 1
        info.Status = 'Abnormal Termination';
        exitflag = -2;
    case 2
        info.Status = 'Error On Input';
        exitflag = -3;
    case 3
        info.Status = 'Exceeded Iterations';
        exitflag = 0;
    case 4
        info.Status = 'Exceeded Maximum Fevals';
        exitflag = 0;
    case 5
        info.Status = 'Exceeded Maximum Time';
        exitflag = 0;
    case 6
        info.Status = 'User Exited';
        exitflag = -5;
    otherwise
        info.Status = 'L-BFGS-B Error';
        exitflag = -3;
end


function [fc_requested, fc_programmed, fs_requested, fs_programmed] = read_header_from_bin_fid(fid)

fc_requested = inf;
fc_programmed = inf;
fs_requested = inf;
fs_programmed = inf;

% fid = fopen(bin_filename);
%
% if fid==-1
%     disp('read_header_from_bin: Can not open file for read!');
%     return;
% end

magic1 = fread(fid, 1, 'double');
tmp1 = fread(fid, 1, 'uint64');

magic2 = fread(fid, 1, 'double');
tmp2 = fread(fid, 1, 'uint64');

magic3 = fread(fid, 1, 'double');
tmp3 = fread(fid, 1, 'uint64');

magic4 = fread(fid, 1, 'double');
tmp4 = fread(fid, 1, 'uint64');

magic5 = fread(fid, 1, 'double');
fread(fid, 1, 'uint64');

magic6 = fread(fid, 1, 'double');
fread(fid, 1, 'uint64');

magic7 = fread(fid, 1, 'double');
fread(fid, 1, 'uint64');

magic8 = fread(fid, 1, 'double');
fread(fid, 1, 'uint64');

% fclose(fid);

fc_requested_magic = 73492.215;
fc_programmed_magic = -0.7923597;
fs_requested_magic = -189978508;
fs_programmed_magic = 93.126712;

reserve1_magic = -53243.129;
reserve2_magic = 0.0008123898;
reserve3_magic = -6.0098321;
reserve4_magic = 237.09983;

if magic1 == fc_requested_magic && ...
   magic2 == fc_programmed_magic && ...
   magic3 == fs_requested_magic && ...
   magic4 == fs_programmed_magic && ...
   magic5 == reserve1_magic && ...
   magic6 == reserve2_magic && ...
   magic7 == reserve3_magic && ...
   magic8 == reserve4_magic

    fc_requested = tmp1;
    fc_programmed = tmp2;
    fs_requested = tmp3;
    fs_programmed = tmp4;
end


function aux_radius(params, hParentFigure)
% function aux_FMD(params, hParentFigure);
%-------------------------------------------
%
% Incoming variables:
% params        : all variables
% hParentFigure : Handle of the parent figure
%
% Thomas van Stiphout, thomas@sed.ethz.ch
% last update: 7.9.2005

report_this_filefun(mfilename('fullpath'));

% Get the axes handle of the plotwindow
axes(sr_result('GetAxesHandle', hParentFigure, [], guidata(hParentFigure)));
hold on;
% Select a point in the plot window with the mouse
[fX, fY] = ginput(1);
disp(['X: ' num2str(fX) ' Y: ' num2str(fY)]);
% Plot a small circle at the chosen place
plot(fX,fY,'ok');

% Get closest gridnode for the chosen point on the map
[fXGridNode fYGridNode,  nNodeGridPoint] = calc_ClosestGridNode(params.mPolygon, fX, fY);
plot(fXGridNode, fYGridNode, '*r');

xx = -pi-0.1:0.1:pi;
if ~params.bMap
    plot(fXGridNode+cos(xx)*params.vResolution(nNodeGridPoint), fYGridNode+sin(xx)*params.vResolution(nNodeGridPoint),'-r')
else
    disp('WARNING: Radiusplot fuer mapview noch pruefen!! aux_radius.m')
    plot((fXGridNode+sin(xx)*params.vResolution(nNodeGridPoint)/(cos(pi/180*fYGridNode)*111))', (fYGridNode+sin(xx)*params.vResolution(nNodeGridPoint)/(cos(pi/180*fYGridNode)*111))','-k')
end
hold off;

% % call
% uiwait(dlboxb2p);               % way is now 'unif' or 'real'
% if cancquest=='yes'; return; end; clear cancquest;
%
% % call
% uiwait(beta2prob_dlbox1);       % NuRep is now defined
% if cancquest=='yes'; return; end; clear cancquest;
% NuRep=str2double(NuRep);

way = 'unif'
NuRep=100

% produce Big Catalog
if way=='unif'
    BigCatalog=sort(rand(100000,1));
else % if way=='real'
    whichs=ceil(length(newcat)*rand(100000,1)); % numbers in whichs from 1 to length(newcat)
    BigCatalog(100000,1)=0;
    for i=1:100000
        BigCatalog(i,1)=newcat(whichs(i),3);    % ith element of BigCatalog is random out of newcat
    end
    BigCatalog=sort(BigCatalog);
    BigCatalog=(BigCatalog-min(BigCatalog))/(max(BigCatalog)-min(BigCatalog));
end

% Transformation of synthetic catalog to probability
[ceil(params.fTminCat):params.fBinning:floor(params.fTmaxCat)-params.fBinning]';
NuBins=(floor(params.fTmaxCat)-ceil(params.fTminCat))/params.fBinning;

delta=params.fTwLength/params.fBinning/NuBins

for nto=1:NuRep
   disp(nto);

   which=ceil(100000*(rand(params.nNumberEvents,1)));
   for i=1:params.nNumberEvents
       rancata(i)=BigCatalog(which(i));
   end
   clear i which;
   mCatSyn_=(floor(params.fTminCat)+((floor(params.fTmaxCat)-ceil(params.fTminCat))*rancata))';
   % Histogram for whole period
   vR1Syn_=histogram(mCatSyn_(:),params.fTminCat:params.fTimeSteps/365:params.fTmaxCat);
   % Histogram for window length starting at fTimeCut
   tmp=[];
   tmp=histogram(mCatSyn_(:),params.fTimeCut-params.fTimeSteps/365:params.fTimeSteps/365:params.fTimeCut+params.fTwLength+params.fTimeSteps/365)';
   vR2Syn_=tmp(2:length(tmp)-1);

   mean1_= mean(vR1Syn_);
   mean2_= mean(vR2Syn_);
   var1_ = var(vR1Syn_);
   var2_ = var(vR2Syn_);

   clear rancata i;

   %FirstBin=ceil(rand(1)*(NuBins-params.fTwLength/params.fBinning+1));

   %zin=Bins(FirstBin:FirstBin+params.fTwLength/params.fBinning-1); zout=[Bins(1:FirstBin-1,1); Bins(FirstBin+params.fTwLength/params.fBinning:NuBins,1)];
   ToBeFitted(nto,1)=nto;
   % calculating beta
   %ToBeFitted(nto,2)=(sum(zin)-params.nNumberEvents*delta)/(sqrt(params.nNumberEvents*delta*(1-delta)));
   % calculating z
   ToBeFitted(nto,3)=(mean1_-mean2_)/sqrt(var1_/length(vR1Syn_)+var2_/(length(vR2Syn_)));
   clear mean1_ mean2_ var1_ var2_ Bins FirstBin zin zout;
end

clear BigCatalog nto;

[meanval, std] =normfit(ToBeFitted(:,2)); IsFitted(1,1)=meanval; IsFitted(1,2)=std;
[meanval, std] =normfit(ToBeFitted(:,3)); IsFitted(2,1)=meanval; IsFitted(2,2)=std;
clear meanval std;
clear ToBeFitted;

% Calculating rates changes for this node over time axes
% Selecting the date of the events from the sampling volume

vTimeSteps_=[params.fTminCat:params.fTimeSteps/365:params.fTimeCut];

for i=1:length(vTimeSteps_)
    i
    vR1Node_=histogram( params.mCatalog(params.caNodeIndices{nNodeGridPoint},3) ,params.fTminCat:params.fTimeSteps/365:params.fTmaxCat);
    tmp=[];
    tmp=histogram( params.mCatalog(params.caNodeIndices{nNodeGridPoint},3) ,vTimeSteps_(i):params.fTimeSteps/365:params.fTimeCut+params.fTwLength)';
    vR2Node_=tmp(2:length(tmp)-1);

    mean1_= mean(vR1Node_);
    mean2_= mean(vR2Node_);
    var1_ = var(vR1Node_);
    var2_ = var(vR2Node_);
    zValues(i)=(mean1_-mean2_)/sqrt((var1_/length(vR1Node_)+var2_/(length(vR2Node_))));
end

   j=0;
   for i=ceil(params.fTminCat):params.fBinning:floor(params.fTmaxCat)-params.fBinning
       l=sum(roundn(params.mCatalog(params.caNodeIndices{nNodeGridPoint},3),-1)==i);
       j=j+1 ;
       zBins(j,1)=sum(l);
       clear l;
   end

   for i=1:length(zBins)-params.fTwLength/params.fBinning
       zin=zBins(i:i+params.fTwLength/params.fBinning);
       zout=[zBins(1:i); zBins(i+params.fTwLength/params.fBinning:length(zBins))];

       betaValue(i)=(sum(zin)-params.nNumberEvents*delta)/(sqrt(params.nNumberEvents*delta*(1-delta)));
   end

% switch value2trans
% case 'beta'
%     Pbeta = normcdf(BetaValues,IsFitted(1,1),IsFitted(1,2));
%     l = Pbeta == 0; Pbeta(l) = nan;
% case 'z'
    Pbeta = normcdf(zValues,IsFitted(2,1),IsFitted(2,2));
    l = Pbeta == 0; Pbeta(l) = nan;
% end
% tmporaer=ceil(params.fTminCat):params.fBinning:floor(params.fTmaxCat-params.fTwLength)-params.fBinning % 1:1:length(zValues)
% plot the resuts
figure
pq = -log10(1-Pbeta); l = isinf(pq);pq(l) = 18 ;
pl1 = plot(vTimeSteps_,pq,'color',[0.0 0.5 0.9]);
hold on
l = pq < 1.3; pq(l) = nan;
pl3 = plot(vTimeSteps_,pq,'b','Linewidth',2);

pq = -log10(Pbeta);l = isinf(pq);pq(l) = 18 ;
pl2 = plot(vTimeSteps_,pq,'color',[0.8 0.6 0.8]);
l = pq < 1.3; pq(l) = nan;
pl4 = plot(vTimeSteps_,pq,'r','Linewidth',2);

maxd = [get(pl1,'Ydata') get(pl2,'ydata') ]; maxd(isinf(maxd)) = []; maxd = max(maxd);
if maxd < 5 ; maxd = 5; end
if isnan(maxd) == 1 ; maxd = 10; end

legend([pl3 pl4],'Rate increases','Rate decreases');
set(gca,'Ylim',[0 maxd+1])
set(gca,'YTick',[1.3 2 3 4 5])
set(gca,'YTickLabel',[ '    5%' ; '    1%' ;  '  0.1%' ;  ' 0.01%' ; '0.001%'])
set(gca,'TickDir','out','Ticklength',[0.02 0.02],'pos',[0.2 0.2 0.7 0.7]);
xlabel('Time [years]')
ylabel('Significance level');
set(gcf,'color','w')
grid


function [im,regions,gt] = os_get_gt_regions(imdb, imageId)
% Get the image and GT regions for imageId

% read the image
ii = find(imdb.images.id == imageId) ;
im = imread(fullfile(imdb.imageDir, imdb.images.name{ii})) ;

if size(im,3) == 1, im = repmat(im, [1 1 3]) ; end
height = size(im,1) ;
width = size(im,2) ;

% read all corresponding segments
sel = find(imdb.segments.imageId == imdb.images.id(ii)) ;
area = zeros(1, numel(sel)) ;
support = cell(1, numel(sel)) ;
for j = 1:numel(sel)
  if isfield(imdb.segments, 'mask') && ...
      exist(fullfile(imdb.maskDir, imdb.segments.mask{sel(j)}), 'file')
    mask = logical(imread(fullfile(imdb.maskDir, imdb.segments.mask{sel(j)}))) ;
  else
    mask = true(height, width);
  end

  if size(mask,3) > 1, mask = mask(:,:,1) ; end
  area(j) = sum(mask(:)) ;
  support{j} = mask ;
end

% subtract smaller regions from larger ones, in case they overlap
occupied = false(height, width) ;
[~,perm] = sort(area) ;
for i = 1:numel(perm)
  j = perm(i) ;
  support{j} = support{j} & ~occupied ;
  occupied = occupied | support{j} ;
end

% create region structure
regions.basis = zeros(height, width) ;
regions.labels = cell(1, numel(support)) ;
regions.area = zeros(1, numel(support)) ;
regions.segmentIndex = zeros(1, numel(support)) ;
for j = 1:numel(support)
  regions.basis(support{j}) = j ;
  regions.labels(j) = {j} ;
  regions.area(j) = sum(support{j}(:)) ;
  regions.segmentIndex(j) = sel(j) ;
end

% drop empty regions (very uncommon but crashes the code)
ok = false(1, numel(regions.labels)) ;
for r = 1:numel(regions.labels)
  ok(r) = any(ismember(regions.basis(:), regions.labels{r})) ;
end
if ~all(ok)
  warning('Dropping some empty gt regions') ;
end
regions.labels = regions.labels(ok) ;

% now create a segmentation mask with class labels for the regions
if (size(imdb.segments.label, 1) == 1)
    gt = zeros(height, width) ;
    for r = 1:numel(regions.labels)
      mask = ismember(regions.basis, regions.labels{r}) ;
      gt(mask) = imdb.segments.label(regions.segmentIndex(r)) ;
    end
else
    numLabels = size(imdb.segments.label, 1);

    gt = zeros(numLabels, height, width) ;
    for ll = 1 : numLabels
        tmp = zeros(height, width);
        for r = 1:numel(regions.labels)
            mask = ismember(regions.basis, regions.labels{r}) ;
            tmp(mask) = (imdb.segments.label(ll, regions.segmentIndex(r)) == 1);
            gt(ll, :, :) = tmp;
        end
    end
end

if 0
  figure(3) ; clf ;
  [~,gt_] = ismember(gt, find(imdb.meta.inUse)) ;
  subplot(1,2,1) ; imagesc(im) ; title(imdb.images.name{ii}) ;
  subplot(1,2,2) ; image(gt_ + 1);
  colormap([ [1,1,1]; distinguishable_colors(sum(imdb.meta.inUse))]) ;
end

end


%{
 * Copyright (C) 2020-2030, The Regents of The University of Michigan.
 * All rights reserved.
 * This software was developed in the Biped Lab (https://www.biped.solutions/)
 * under the direction of Jessy Grizzle, grizzle@umich.edu. This software may
 * be available under alternative licensing terms; contact the address above.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * The views and conclusions contained in the software and documentation are those
 * of the authors and should not be interpreted as representing official policies,
 * either expressed or implied, of the Regents of The University of Michigan.
 *
 * AUTHOR: Bruce JK Huang (bjhuang[at]umich.edu)
 * WEBSITE: https://www.brucerobot.com/
%}

function [H_LC, P, min_cost, final_result, results] = optimizeIoU(opt, X, Y, intrinsic, display)
    % prepare for random initilization (not use for now)
    for i = 1:1
        theta_x = optimvar('theta_x', 1, 1,'LowerBound',-180,'UpperBound',180); % 1x1
        theta_y = optimvar('theta_y', 1, 1,'LowerBound',-180,'UpperBound',180); % 1x1
        theta_z = optimvar('theta_z', 1, 1,'LowerBound',-180,'UpperBound',180); % 1x1
        T = optimvar('T', 1, 3,'LowerBound',-0.5,'UpperBound',0.5);
%         theta_x = 0;
%         theta_y = 10;
%         theta_z = 20;
%         T = [ 1 2 3];  % 1x3
%         costIoU(theta_x, theta_y, theta_z, T, X, Y, intrinsic);

        prob = optimproblem;
        f = fcn2optimexpr(@costIoU, theta_x, theta_y, theta_z, T, X, Y, intrinsic);
        prob.Objective = f;

        noise = (rand([1,6]) - 0.5) * 2; % -1 to 1
        if i==1
            x0.theta_x = opt(1);
            x0.theta_y = opt(2) ;
            x0.theta_z = opt(3);
            x0.T = [0 0 0];
        elseif i==2
            x0.theta_x = 82.0122;
            x0.theta_y = -0.0192 ;
            x0.theta_z = 87.7953;
            x0.T = [0.0228
                   -0.2070
                   -0.0783];
        else
            x0.theta_x = opt(1) + noise(1) * 10;
            x0.theta_y = opt(2) + noise(2) * 10;
            x0.theta_z = opt(3) + noise(3) * 10;
            x0.T = [0 0 0] + noise(4:6) * 0.1;
        end

    %             options = optimoptions('fmincon', 'MaxIter',5e2,'Display','iter', 'TolX', 1e-12, 'FunctionTolerance', 1e-8, 'MaxFunctionEvaluations', 3e4);
        options = optimoptions('fmincon', 'MaxIter',5e2, 'TolX', 1e-12, 'Display','off', 'FunctionTolerance', 1e-8, 'MaxFunctionEvaluations', 3e4);
        % options.UseParallel = true;
        % showproblem(prob);
        % [sol, fval, exitflag, output] = solve(prob, x0, 'Options',options);
        [sol, fval, ~, ~] = solve(prob, x0, 'Options', options);
        R_final = rotx(sol.theta_x) * roty(sol.theta_y) * rotz(sol.theta_z);
        H_LC = eye(4);
        H_LC(1:3, 1:3) = R_final;
        H_LC(1:3, 4) = sol.T';

    %             disp('H_LC: ')
    %             disp('     R:')
    %             disp(H_LC(1:3, 1:3))
    %             disp('     T:')
    %             disp(-inv(H_LC(1:3, 1:3))*H_LC(1:3, 4))
        P = intrinsic * [eye(3) zeros(3,1)] * H_LC;
        results(i).total_cost = fval;
        results(i).RMSE = sqrt(fval/size(Y,2));
        results(i).H = H_LC;
        results(i).P = P;
        if display
            disp('-- H_LC: ')
            disp('------- R:')
            disp(H_LC(1:3, 1:3))
            disp('------- T:')
            disp(-inv(H_LC(1:3, 1:3))*H_LC(1:3, 4))
            disp('-- cost:')
            disp(results(i).total_cost)
            disp('-- RMSE:')
            disp(results(i).RMSE)
        end
    end

    [min_cost, k] = min([results(:).total_cost]);
    [max_cost, ~] = max([results(:).total_cost]);
    [min_RMSE, ~] = min([results(:).RMSE]);
    final_result.RMSE = min_RMSE;
    final_result.std = std([results(:).total_cost]);
    final_result.min_cost = min_cost;
    final_result.max_cost = max_cost;
    final_H = results(k).H;
    final_P = results(k).P;
    final_result.H = final_H;
    final_result.P = final_P;
    if display
%         disp("std:")
%         disp(final_result.std)
%         disp("minimum cost:")
%         disp(min_cost)
%         disp('H_LC: ')
%         disp(' R:')
%         disp(results(k).H(1:3, 1:3))
%         disp(' RPY (XYZ):')
%         disp(rad2deg(rotm2eul(results(k).H(1:3, 1:3), "XYZ")))
%         disp(' T:')
%         disp(-inv(results(k).H(1:3, 1:3))*results(k).H(1:3, 4))
%         disp("max cost:")
%         disp(max_cost)
%         disp('H_LC: ')
%         disp(' R:')
%         disp(results(j).H(1:3, 1:3))
%         disp(' RPY (XYZ):')
%         disp(rad2deg(rotm2eul(results(j).H(1:3, 1:3), "XYZ")))
%         disp(' T:')
%         disp(-inv(results(j).H(1:3, 1:3))*results(j).H(1:3, 4))
    end
end


function computeAllFinalRF_Aerts_Old(pathRF,nBoot,seed)

startpath = pwd;

cd(pathRF), load('training')
nameOutcomes = {'DeathSign'}; nOutcomes = numel(nameOutcomes);
fSetNames = {'CT'}; nFset = numel(fSetNames);

for o = 1:nOutcomes
    if strcmp(nameOutcomes{o},'DeathSign')
        outcome = training.outcomes.Death;
    else
        outcome = training.outcomes.(nameOutcomes{o});
    end
    for f = 1:nFset
        text = training.textures.(nameOutcomes{o}).(fSetNames{f}); nText = size(text,2);
        indClinic = training.clinical.bestAdd.(nameOutcomes{o}).(fSetNames{f});
        cost = training.cost.(nameOutcomes{o}).(fSetNames{f});
        tableTrain = [text,training.clinical.table(:,indClinic)];
        cat = logical([zeros(1,nText),training.clinical.categories(indClinic)]);
        rng(seed), [RF] = trainRF_table(tableTrain,outcome,cat,nBoot,cost);
        RF = compact(RF); % Compact version
        save(['RF_',fSetNames{f},'_',nameOutcomes{o}],'RF')
    end
end

cd(startpath)
end


% EPOCH = DATENUM2EPOCH(TIME) translates Matlab numeric
% date format into Unix epoch date format.

% Author: Michael West. Modified Glenn Thompson.
% $Date$
% $Revision$

function epoch = datenum2epoch(time)

epoch = zeros(size(time));

if admin.antelope_exists()
    for n = 1:numel(time)
        epoch(n) = str2epoch(datestr(time(n),'mm/dd/yyyy HH:MM:SS.FFF'));
    end
else
    % Does not account for leap seconds.
    for n = 1:numel(time)
        epoch(n) = (time - datenum(1970,1,1,0,0,0))*86400;
    end
end


function m = mesh_load_gmsh4( varargin )
% load a Gmsh mesh file (binary or ASCII)
%
% USAGE:
% m=mesh_load_gmsh4(fn);
%
% fn: filename
% m:  mesh-structure with
%       nodes
%       triangles: indices into the nodes, starting at 1
%       triangle_regions: region numbers (gmsh "physical groups")
%       tetrahedra
%       tetrahedron_regions
%
%       node_data{idx}.name: string
%       node_data{idx}.data: vector or matrix
%
%       element_data{idx}.name
%       element_data{idx}.tridata: vector or matrix (triangle data)
%       element_data{idx}.tetdata: vector or matrix (tetrahedra data)
%
%       element_node_data{idx}.name
%       element_node_data{idx}.data: vector or matrix (only tetrahedra data)
%
%
% Note: This function was written for the meshes created by SimNIBS 2.1 and
% does not support all features of Gmsh meshes:
% * only triangles and tetrahedra are supported element types
% * other elements will be skipped; if this occurs, reading of element-data
%   will skipped as well
% * loading binary meshes directly produced by gmsh and SimNIBS versions
%   prior to 2.1 will be very slow
% * node numbers have to be a continuous list of indexes starting at 1
% * triangles are stored prior to tetrahedra
% * element_node_data works only for binary meshes and assumes that
%   only tetrahedral data is stored
%
% See http://www.geuz.org/gmsh/doc/texinfo/gmsh-full.html#SEC56 for
% documentation of the file format.
%
% Andre Antunes 07 Apr 2015
% AT 27-Feb-2018: simplified code, added checks for mesh format

%    This program is part of the SimNIBS package.
%    Please check on www.simnibs.org how to cite our work in publications.
%
%    Copyright (C) 2013-2018 Axel Thielscher, Andre Antunes
%
%    This program is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    any later version.
%
%    This program is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with this program.  If not, see <http://www.gnu.org/licenses/>.

%%
tic

if nargin<1
   [fname, pname]= uigetfile('*.msh');
   if isequal(fname,0) || isequal(pname,0); return; end;
   fn = [pname fname];
else
    fn = varargin{1};
end

if ~ischar(fn)
    error(['invalid filename:' fn]);
end

if ~exist(fn, 'file')
    error(['file does not exist:' fn]);
end

m.node_data = {};
m.element_data = {};

fid=fopen(fn);

tline = fgetl(fid);
if ~strcmp('$MeshFormat', tline)
    error('Start tag $MeshFormat expected');
end

% parse 2nd line: version.minor_version is_binary byte_size
tline = fgetl(fid);
version = sscanf(tline, '%f %d %d');
v = int32(version(1));
if v ~= 2 && v ~= 4
    error(['Cant read mesh version ' num2str(version(1))]);
end
if version(3) ~= 8
    error(['expected to read 8 byte precision, but encountered: ' num2str(version(4))]);
end

is_binary = version(2);
if is_binary
    disp('reading binary')
    endianess = fread(fid, 1, 'int');
    if (endianess ~= 1)
        error('Endianess in binary file is different than 1. I cant procceed..\n Was this file created in windows?');
    end
    a = fread(fid, 1, 'char'); % read end of line ( should be ascii 010)
    if a ~= 10; error(['Expected LF (new line), but I read ASCII:' a]); end
end

tline = fgetl(fid);
if ~strcmp('$EndMeshFormat', tline)
    error('End tag $EndMeshFormat expected');
end

%% read nodes
line = fgetl(fid);
while ~strcmp('$Nodes', line)
    line = fgetl(fid);
end

if is_binary
   if v == 2
       m = read_nodes_binary(m, fid);
   else
       m = read_nodes_binary4(m, fid);
   end
else
   if v == 2
       m = read_nodes(m, fid);
   else
       m = read_nodes4(m, fid);
   end
end

%% read elements
line = fgetl(fid);
while ~strcmp('$Elements', line)
    line = fgetl(fid);
end

if is_binary
    if v == 2
        [m, continous_elm_numbers] = read_elements_binary(m, fid);
    else
        [m, continous_elm_numbers] = read_elements_binary4(m, fid);
    end
else
    if v == 2
        [m, continous_elm_numbers] = read_elements(m, fid);
    else
        [m, continous_elm_numbers] = read_elements4(m, fid);
    end
end

%% read data ($NodeData, $ElementData, $ElementNodeData)
tline = fgetl(fid);
while ~feof(fid)
    if strcmp('$NodeData', tline)
        m.node_data{end+1} = read_node_data(fid, size(m.nodes,1), is_binary);
    elseif strcmp('$ElementData', tline)
        m.element_data{end+1} = read_element_data(fid, size(m.triangles,1), size(m.tetrahedra,1), continous_elm_numbers, is_binary);
    elseif strcmp('$ElementNodeData', tline)
        if is_binary
            m.element_node_data = {};
            [data, name, ~] = read_data_binary(fid, tline);
            m.element_node_data{end+1}.data = data;
            m.element_node_data{end}.name = name;
            warning('reading of element_node_data is not tested. Good luck.');
        else
            error('$ElementNodeData is not supported for ASCII meshes.');
        end;
    else
        error(['Unsupported field:' tline]);
    end
    tline = fgetl(fid);
end

m.node_data = m.node_data';
m.element_data = m.element_data';
if isfield(m,'element_node_data')
    m.element_node_data = m.element_node_data';
end;

fprintf('Number of Nodes              : %d\n', size(m.nodes,1));
fprintf('Number of Triangles          : %d\n', size(m.triangles,1));
fprintf('Number of Triangle Regions   : %d\n', size(unique(m.triangle_regions),1));
fprintf('Number of Tetrahedra         : %d\n', size(m.tetrahedra,1));
fprintf('Number of Tetrahedron Regions: %d\n', size(unique(m.tetrahedron_regions),1));

toc

function m = read_nodes_binary(m, fid)
    % get number of nodes (this line is in ascii)
    tline = fgetl(fid);
    number_of_nodes = sscanf(tline,'%d');
    if ~isnumeric( number_of_nodes )
        error('number of nodes is not a number');
    end

    % get number of first node
    node_number(1) = fread(fid, 1 , 'int');

    % read 3 double columns, skipping 4 bytes after each read
    m.nodes = fread(fid, [3 number_of_nodes], '3*double',4)';

    % get number of last node
    fseek(fid, -(2*4+3*8), 'cof');
    node_number(2) = fread(fid, 1 , 'int', 3*8);

    if (node_number(1) < 1) || ...
       (node_number(2) > number_of_nodes) || ...
       (size(m.nodes,1) ~= number_of_nodes)
        error('node numbers have to be a continuous list of indexes starting at 1');
    end

    % sometimes there is an end of line after $Nodes, sometimes there is
    % not... handle that
    read_LF(fid);

    % confirm last line
    tline = fgetl(fid);
    if ~strcmp('$EndNodes', tline)
        error('End tag $EndNodes expected');
    end

function m = read_nodes(m, fid)
    % get number of nodes
    tline = fgetl(fid);
    number_of_nodes = sscanf(tline,'%d');
    if ~isnumeric( number_of_nodes )
        error(['number of nodes is not a number']);
    end

    pts = textscan(fid, '%d %f %f %f\n');
    node_numbers=pts{1};
    m.nodes = [pts{2} pts{3} pts{4}];

    if (min(node_numbers) < 1) || ...
       (max(node_numbers)> number_of_nodes) || ...
       (length(node_numbers) ~= number_of_nodes)
        error('node numbers have to be a continuous list of indexes starting at 1');
    end

    % read end line
    tline = fgetl(fid);
    if ~strcmp('$EndNodes', tline)
        error('End tag $EndNodes expected');
    end

function m = read_nodes_binary4(m, fid)
    n_blocks = fread(fid,1, 'uint64');
    number_of_nodes = fread(fid,1, 'uint64');
    if ~isnumeric(number_of_nodes)
        error('number of nodes is not a number');
    end
    node_numbers = [];%zeros(number_of_nodes, 0, 'int32');
    m.nodes = [];%zeros(number_of_nodes, 3);
    for b = 1:n_blocks
        fread(fid,2, 'int');
        if fread(fid,1, 'int')
            error('Cant read parametric nodes')
        end
        n_in_block = fread(fid,1, 'uint64');
        node_numbers = [node_numbers; fread(fid, n_in_block, 'int', 3*8)];
        fseek(fid, -n_in_block*(4+3*8)+4, 'cof');
        m.nodes = [m.nodes; fread(fid, [3, n_in_block], '3*double', 4)'];
        fseek(fid, -4, 'cof');
    end
    [node_numbers, order] = sort(node_numbers);
    m.nodes = m.nodes(order, :);
    if (min(node_numbers) < 1) || ...
       (max(node_numbers)> number_of_nodes) || ...
       (length(node_numbers) ~= number_of_nodes)
        error('node numbers have to be a continuous list of indexes starting at 1');
    end
    % sometimes there is an end of line after $Nodes, sometimes there is
    % not... handle that
    read_LF(fid);

    % confirm last line
    tline = fgetl(fid);
    if ~strcmp('$EndNodes', tline)
        error('End tag $EndNodes expected');
    end

function m = read_nodes4(m, fid)
    % get number of nodes
    tline = fgetl(fid);
    l = sscanf(tline,'%d %d');
    n_blocks = l(1);
    number_of_nodes = l(2);
    if ~isnumeric(number_of_nodes)
        error('number of nodes is not a number');
    end
    node_numbers = [];%zeros(number_of_nodes, 0, 'int32');
    m.nodes = [];%zeros(number_of_nodes, 3);
    for b = 1:n_blocks
        l = sscanf(fgetl(fid),'%d %d %d %d');
        if l(3)
            error('Cant read parametric nodes')
        end
        pts = textscan(fid, '%d %f %f %f\n', l(4));
        node_numbers = [node_numbers; pts{1}];
        m.nodes = [m.nodes; [pts{2} pts{3} pts{4}]];
    end
    [node_numbers, order] = sort(node_numbers);
    m.nodes = m.nodes(order, :);
    if (min(node_numbers) < 1) || ...
       (max(node_numbers)> number_of_nodes) || ...
       (length(node_numbers) ~= number_of_nodes)
        error('node numbers have to be a continuous list of indexes starting at 1');
    end

    % read end line
    tline = fgetl(fid);
    if ~strcmp('$EndNodes', tline)
        error('End tag $EndNodes expected');
    end

function [m, continous_elm_numbers] = read_elements_binary(m, fid)
    % get number of elements
    tline = fgetl(fid);
    number_of_elements = sscanf(tline,'%d');
    if ~isnumeric( number_of_elements )
        error('number of elements is not a number');
    end

    % loop to read in all elements

    m.triangles = [];
    m.triangle_regions = [];
    m.tetrahedra = [];
    m.tetrahedron_regions = [];

    elm_remaining = number_of_elements;
    element_numbers=[];
    element_types = [];
    continous_elm_numbers=true;
    while elm_remaining > 0

        type = fread(fid, 1, '*int32');
        nr_elm_follow = fread(fid, 1, '*int32');
        nr_tags = fread(fid, 1, '*int32');
        if (nr_tags ~= 2)
            error('nr_tags must be equal to 2');
        end

        elm_remaining = elm_remaining - nr_elm_follow;
        % read all the elements in one go
        % idx, tag1, tag2, node1, node2, node3, ... up to nr_nodes_in_element nodes
        buff = fread(fid, [nr_nodes_in_element(type)+3, nr_elm_follow], '*int32'); % +3 is for idx, tag1, tag2

        element_numbers = [element_numbers; buff(1,:)'];
        element_types = [element_types; type];
        switch type
            case 2
                if ~isempty(buff)
                    m.triangles = [m.triangles; buff(4:end,:)'];
                    m.triangle_regions = [m.triangle_regions; buff(2,:)']; % this is tag1
                end;

            case 4
                if ~isempty(buff)
                    m.tetrahedra = [m.tetrahedra; buff(4:end,:)'];
                    m.tetrahedron_regions = [m.tetrahedron_regions; buff(2,:)']; % this is tag1
                end;

            otherwise
                continous_elm_numbers=false;
                warning(['found element type ' num2str(type) '; skipped during reading! Only reading triangles and tetrahedra, not reading element data']);
        end
    end

    if (min(element_numbers) < 1) || ...
       (max(element_numbers) > number_of_elements)

       continous_elm_numbers=false;
       warning('only reading tetrahedra and triangles, not reading element_data')
    end

    if any(element_types==2) && any(element_types==4) && ...
       find(element_types==2, 1, 'last')>find(element_types==4, 1)

       continous_elm_numbers=false;
       warning('only reading tetrahedra and triangles, not reading element_data')
    end;

    % sometimes there is an end of line after $Elements, sometimes there is
    % not... handle that
    read_LF(fid);

    % read end line
    tline = fgetl(fid);
    if ~strcmp('$EndElements', tline)
        error(['End tag $EndElements expected, but I read: ' tline]);
    end

function [m, continous_elm_numbers] = read_elements_binary4(m, fid)
    n_blocks = fread(fid,1, 'uint64');
    number_of_elements = fread(fid,1, 'uint64');

    m.triangles = [];
    m.triangle_regions = [];
    m.tetrahedra = [];
    m.tetrahedron_regions = [];
    tr_numbers = [];
    th_numbers = [];
    for b = 1:n_blocks
        tag = fread(fid,1, 'int');
        fread(fid,1, 'int');
        type = fread(fid,1, 'int');
        n_in_block = fread(fid,1, 'uint64');
        buff = fread(fid, [nr_nodes_in_element(type)+1, n_in_block], '*int')';
        switch type
            case 2
                if ~isempty(buff)
                    tr_numbers = [tr_numbers; buff(:, 1)];
                    m.triangles = [m.triangles; buff(:, 2:end)];
                    m.triangle_regions = [m.triangle_regions; tag*ones(n_in_block,1, 'int32')];
                end
            case 4
                if ~isempty(buff)
                    th_numbers = [th_numbers; buff(:, 1)];
                    m.tetrahedra = [m.tetrahedra; buff(:, 2:end)];
                    m.tetrahedron_regions = [m.tetrahedron_regions; tag*ones(n_in_block,1, 'int32')];
                end
            otherwise
                continous_elm_numbers=false;
                warning(['found element type ' num2str(type) '; skipped during reading! Only reading triangles and tetrahedra, not reading element data']);
        end
    end
    [tr_numbers, order] = sort(tr_numbers);
    m.triangles = m.triangles(order, :);
    m.triangle_regions = m.triangle_regions(order);
    [th_numbers, order] = sort(th_numbers);
    m.tetrahedra = m.tetrahedra(order, :);
    m.tetrahedron_regions = m.tetrahedron_regions(order);
    element_numbers = [tr_numbers; th_numbers];
    if (min(element_numbers) < 1) || ...
       (max(element_numbers) > number_of_elements)

       continous_elm_numbers=false;
       warning('only reading tetrahedra and triangles, not reading element_data')
    end

    % sometimes there is an end of line after $Elements, sometimes there is
    % not... handle that
    read_LF(fid);

    % read end line
    tline = fgetl(fid);
    if ~strcmp('$EndElements', tline)
        error(['End tag $EndElements expected, but I read: ' tline]);
    end

function [m, continous_elm_numbers] = read_elements(m, fid)
    % get number of elements
    tline = fgetl(fid);
    number_of_elements = sscanf(tline,'%d');
    if ~isnumeric( number_of_elements )
        error('number of elements is not a number');
    end

    c = textscan(fid,'%d %d %d %d %*d %d %d %d %d\n');
    element_numbers=c{1};
    number_of_tags=c{3};

    if length(element_numbers) ~= number_of_elements
        error('wrong number of elements found');
    end;

    if any(number_of_tags ~= 2)
        error('two tag numbers are expected');
    end;

    continous_elm_numbers=true;
    if (min(element_numbers) < 1) || ...
       (max(element_numbers)> number_of_elements) || ...
       any(~((c{2} == 2)|(c{2} ==4)))

       continous_elm_numbers=false;
       warning('only reading tetrahedra and triangles, not reading element_data')
    end

    if any(c{2}==2) && any(c{2}==4) && ...
       find(c{2}==2, 1, 'last')>find(c{2}==4, 1)

       continous_elm_numbers=false;
       warning('only reading tetrahedra and triangles, not reading element_data')
    end;

	% Separate triangles from tetrahedra, throw away rest
    tri = c{2}==2;
    tetr = c{2}==4;
    m.triangles = [c{5}(tri) c{6}(tri) c{7}(tri)];
    m.tetrahedra = [c{5}(tetr) c{6}(tetr) c{7}(tetr) c{8}(tetr)];
    m.triangle_regions = c{4}(tri);
    m.tetrahedron_regions = c{4}(tetr);

    % read end line
    tline = fgetl(fid);
    if ~strcmp('$EndElements', tline)
        error(['End tag $EndElements expected, but I read: ' tline]);
    end

function [m, continous_elm_numbers] = read_elements4(m, fid)
    % get number of elements
    tline = fgetl(fid);
    l = sscanf(tline,'%d %d');
    n_blocks = l(1);
    number_of_elements = l(2);
    if ~isnumeric( number_of_elements )
        error('number of elements is not a number');
    end

    m.triangles = [];
    m.tetrahedra = [];
    m.triangle_regions = [];
    m.tetrahedron_regions = [];
    tr_numbers = [];
    th_numbers = [];
    for b = 1:n_blocks
        l = sscanf(fgetl(fid),'%d %d %d %d');
        if l(3) == 2
            c = textscan(fid,'%d %d %d %d\n', l(4));
            tr_numbers=[tr_numbers; c{1}];
            m.triangles = [m.triangles; [c{2} c{3} c{4}]];
            m.triangle_regions = [m.triangle_regions; l(1)*ones(l(4),1, 'int32')];
        elseif l(3) == 4
            c = textscan(fid,'%d %d %d %d %d\n', l(4));
            th_numbers=[th_numbers; c{1}];
            m.tetrahedra = [m.tetrahedra; [c{2} c{3} c{4} c{5}]];
            m.tetrahedron_regions = [m.tetrahedron_regions; l(1)*ones(l(4),1, 'int32')];
        else
            warning('only reading tetrahedra and triangles, not reading element_data')
            c = textscan(fid,'%d %*d %d\n', l(4));
            continue
        end
    end
    [tr_numbers, order] = sort(tr_numbers);
    m.triangles = m.triangles(order, :);
    m.triangle_regions = m.triangle_regions(order);
    [th_numbers, order] = sort(th_numbers);
    m.tetrahedra = m.tetrahedra(order, :);
    m.tetrahedron_regions = m.tetrahedron_regions(order);
    element_numbers = [tr_numbers; th_numbers];
    continous_elm_numbers=true;
    if (min(element_numbers) < 1) || ...
       (max(element_numbers)> number_of_elements) || ...
       any(~((c{2} == 2)|(c{2} ==4)))

       continous_elm_numbers=false;
       warning('only reading tetrahedra and triangles, not reading element_data')
    end

    if any(c{2}==2) && any(c{2}==4) && ...
       find(c{2}==2, 1, 'last')>find(c{2}==4, 1)

       continous_elm_numbers=false;
       warning('only reading tetrahedra and triangles, not reading element_data')
    end

    % read end line
    tline = fgetl(fid);
    if ~strcmp('$EndElements', tline)
        error(['End tag $EndElements expected, but I read: ' tline]);
    end

function data = read_node_data(fid, number_of_nodes, isbinary)

    if isbinary
        [dataIn, name, node_element_numbers]= read_data_binary(fid, '$NodeData');
    else
        [dataIn, name, node_element_numbers]= read_data(fid, '$NodeData');
    end;

    if (node_element_numbers(1) < 1) || ...
       (node_element_numbers(2) > number_of_nodes) || ...
       (size(dataIn,1) ~= number_of_nodes)
        error('node data has to contain exactly one data point for each node');
    end

    % sort data into struct
    data.name = name;
    data.data = dataIn;

function data = read_element_data(fid, number_of_triangles, number_of_tetrahedra, continous_elm_numbers, isbinary)

    % still reading element_data also for non-continous element number to
    % move file position indicator
    if isbinary
        [dataIn, name, node_element_numbers]= read_data_binary(fid, '$ElementData');
    else
        [dataIn, name, node_element_numbers]= read_data(fid, '$ElementData');
    end

    if continous_elm_numbers
        % sort data into struct
        data.name = name;

        if (node_element_numbers(1) == 1) && ...
           (node_element_numbers(2) == number_of_triangles)

            if size(dataIn,1) ~= number_of_triangles
                error('element data has to contain one data point for each triangle');
            end;

            data.tridata = dataIn;
            data.tetdata = [];
        elseif (node_element_numbers(1) == 1) && ...
               (node_element_numbers(2) == number_of_triangles+number_of_tetrahedra)

            if size(dataIn,1) ~= number_of_triangles+number_of_tetrahedra
                error('element data has to contain one data point for each element');
            end;

            data.tridata = dataIn(1:number_of_triangles,:);
            data.tetdata = dataIn(number_of_triangles+1:end,:);
        elseif (node_element_numbers(1) == number_of_triangles+1) && ...
               (node_element_numbers(2) == number_of_triangles+number_of_tetrahedra)

            if size(dataIn,1) ~= number_of_tetrahedra
                error('element data has to contain one data point for each tetrahedron');
            end;

            data.tridata = [];
            data.tetdata = dataIn;
        else
           error('reading element data did not succeed');
        end;
    end;

function [data, name, node_element_numbers] = read_data_binary(fid, data_type)

    % read string tags (including name)
    tline = fgetl(fid);
    if sscanf(tline,'%d') ~= 1; error('nr_string_tags should always be 1'); end
    name = fgetl(fid);

    % read real tags
    tline = fgetl(fid);
    if sscanf(tline,'%d') ~= 1; error('nr_real_tags should always be 1'); end
    tline = fgetl(fid);

    % read integer tags (size of data)
    tline = fgetl(fid);
    nlines = sscanf(tline,'%d');
    if nlines ~= 3 && nlines ~= 4
        error('nr_int_tags should always be 3 or 4');
    end

    for i=1:nlines
        tline = fgetl(fid);
        int_tags(i) = sscanf(tline, '%d');
    end;

    % nr of field components (1, 3, 9) for scalar, vector, tensor
    comp = int_tags(2);
    nr_data = int_tags(3);

    % read float data
    node_element_numbers = [0 0]; % node or element numbers of first and last data line
    if strcmp(data_type, '$ElementNodeData')
        % for $ElementNodeData, it is written as:
        % elm-number number-of-nodes-per-element value
        % where value has comp*number_of_nodes_per_element value
        % since we only write to tetrahedra, I will assume there are no triangles
        % with $ElementNodeData

        % read first two columns
        fread(fid, 2, '*uint32');
        data = fread(fid, [4*comp nr_data], [num2str(4*comp) '*double'], 8)';
        fseek(fid, -8, 'cof');
    elseif strcmp(data_type, '$NodeData') || strcmp(data_type, '$ElementData')
        % read the node or element number of the first data line
        node_element_numbers(1) = fread(fid, 1 , 'int');

        % read data
        data = fread(fid, [comp nr_data], [num2str(comp) '*double'], 4)';

        % read the node or element number of the last data line
        fseek(fid, -(2*4+comp*8), 'cof');
        node_element_numbers(2) = fread(fid, 1 , 'int', comp*8);
    else
        error('still need to code other data types');
    end

    % update name
    if length(name) > 2
        name = name(2:end-1);
    else
        name = '';
    end

    % read last line
    tline = fgetl(fid);
    if ~strcmp(['$End' data_type(2:end)], tline)
        error(['End tag $End' data_type ' expected']);
    end

function [data, name, node_element_numbers]= read_data(fid, data_type)

    % read string tags (including name)
    tline = fgetl(fid);
    if sscanf(tline,'%d') ~= 1; error('nr_string_tags should always be 1'); end
    name = fgetl(fid);

    % read real tags
    tline = fgetl(fid);
    if sscanf(tline,'%d') ~= 1; error('nr_real_tags should always be 1'); end
    tline = fgetl(fid);

    % read integer tags (size of data)
    tline = fgetl(fid);
    nlines = sscanf(tline,'%d');
    if nlines ~= 3 && nlines ~= 4
        error('nr_int_tags should always be 3 or 4');
    end

    for i=1:nlines
        tline = fgetl(fid);
        int_tags(i) = sscanf(tline, '%d');
    end;

    comp = int_tags(2);

    % read data
    t_str = repmat(' %f', 1, comp);
    c = textscan(fid, ['%d' t_str '\n']);
    if size(c{1},1) ~= int_tags(3)
        error(['number of data lines read does not correspond to ' num2str(int_tags(3))]);
    end

    if length(name) > 2
        name = name(2:end-1);
    else
        name = '';
    end

    node_element_numbers(1)=c{1}(1);
    node_element_numbers(2)=c{1}(end);

    data = [];
    for i=1:comp
        data = [data c{i+1}];
    end

    % read last line
    tline = fgetl(fid);
    if ~strcmp(['$End' data_type(2:end)], tline)
        error(['End tag $End' data_type ' expected']);
    end

function read_LF(fid)
    a = fread(fid, 1, 'char');
    if a == 10
        disp('LF found, but I should be able to handle it');
    elseif a == 36
        % go back 1 byte, I'm reading a "$" character
        fseek(fid, -1, 'cof');
    else
        error(['Dont know what to do with this: ' a]);
    end

function n = nr_nodes_in_element(t)
    nne = ...
     [ 2,  3,  4,  4,  8,  6,  5,  3,  6,  9, ...
      10, 27, 18, 14,  1,  8, 20, 15, 13,  9, ...
      10, 12, 15, 15, 21,  4,  5,  6, 20, 35, ...
      56,  0,  0,  0,  0,  0,  0,  0,  0,  0, ...
       0,  0,  0,  0,  0,  0,  0,  0,  0,  0, ...
       0,  0,  0,  0,  0,  0,  0,  0,  0,  0, ...
       0,  0,  0,  0,  0,  0,  0,  0,  0,  0, ...
       0,  0,  0,  0,  0,  0,  0,  0,  0,  0, ...
       0,  0,  0,  0,  0,  0,  0,  0,  0,  0, ...
       0, 64,125];
   n = nne(t);