% MatrixUser, a multi-dimensional matrix analysis software package
% https://sourceforge.net/projects/matrixuser/
%
% The MatrixUser is a matrix analysis software package developed under Matlab
% Graphical User Interface Developing Environment (GUIDE). It features
% functions that are designed and optimized for working with multi-dimensional
% matrix under Matlab. These functions typically includes functions for
% multi-dimensional matrix display, matrix (image stack) analysis and matrix
% processing.
%
% Author:
%   Fang Liu <leoliuf@gmail.com>
%   University of Wisconsin-Madison
%   Aug-30-2014

function varargout = MU_Matrix_Display_3Plane(varargin)
% MU_MATRIX_DISPLAY_3PLANE M-file for MU_Matrix_Display_3Plane.fig
%      MU_MATRIX_DISPLAY_3PLANE, by itself, creates a new MU_MATRIX_DISPLAY_3PLANE or raises the existing
%      singleton*.
%
%      H = MU_MATRIX_DISPLAY_3PLANE returns the handle to a new MU_MATRIX_DISPLAY_3PLANE or the handle to
%      the existing singleton*.
%
%      MU_MATRIX_DISPLAY_3PLANE('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in MU_MATRIX_DISPLAY_3PLANE.M with the given input arguments.
%
%      MU_MATRIX_DISPLAY_3PLANE('Property','Value',...) creates a new MU_MATRIX_DISPLAY_3PLANE or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before MU_Matrix_Display_3Plane_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to MU_Matrix_Display_3Plane_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help MU_Matrix_Display_3Plane

% Last Modified by GUIDE v2.5 20-Sep-2013 16:08:24

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @MU_Matrix_Display_3Plane_OpeningFcn, ...
                   'gui_OutputFcn',  @MU_Matrix_Display_3Plane_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before MU_Matrix_Display_3Plane is made visible.
function MU_Matrix_Display_3Plane_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to MU_Matrix_Display_3Plane (see VARARGIN)
global Figure_handles;

Figure_handles.MU_display2=hObject;
filepath=mfilename('fullpath');   % find current running m-file fullpath
sep=filesep;
k=strfind(filepath, sep);
path=filepath(1:k(end)-1);

MU_icon(handles.Sag2Main_pushbutton,[path sep '..' sep '..' sep 'Resource' sep 'Icon' sep 'Exchange.gif']);
MU_icon(handles.Cor2Main_pushbutton,[path sep '..' sep '..' sep 'Resource' sep 'Icon' sep 'Exchange.gif']);

% Choose default command line output for MU_Matrix_Display_3Plane
handles.Parent = Figure_handles.MU_display;
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes MU_Matrix_Display_3Plane wait for user response (see UIRESUME)
% uiwait(MU_display_handles.MU_matrix_display_3Plane);

% --- Outputs from this function are returned to the command line.
function varargout = MU_Matrix_Display_3Plane_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

% --- Executes on button press in SMatrix_pushbutton.
function SMatrix_pushbutton_Callback(hObject, eventdata, handles)
% hObject    handle to SMatrix_pushbutton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

MU_display_handles=guidata(handles.Parent);
if MU_display_handles.V.Localizer.Local_switch==0;
    MU_display_handles.V.Localizer.Local_switch=1;
    MU_display_handles=MU_update_image(MU_display_handles.Matrix_display_axes,{MU_display_handles.TMatrix,MU_display_handles.Mask},MU_display_handles,0);
else
    MU_display_handles.V.Localizer.Local_switch=0;
    delete(MU_display_handles.V.Localizer.Local_h1);
    delete(MU_display_handles.V.Localizer.Local_h2);
end
guidata(handles.Parent, MU_display_handles);

% --- Executes on button press in CMatrix_pushbutton.
function CMatrix_pushbutton_Callback(hObject, eventdata, handles)
% hObject    handle to CMatrix_pushbutton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

MU_display_handles=guidata(handles.Parent);
if MU_display_handles.V.Localizer.Local_switch==0;
    MU_display_handles.V.Localizer.Local_switch=1;
    MU_display_handles=MU_update_image(MU_display_handles.Matrix_display_axes,{MU_display_handles.TMatrix,MU_display_handles.Mask},MU_display_handles,0);
else
    MU_display_handles.V.Localizer.Local_switch=0;
    delete(MU_display_handles.V.Localizer.Local_h1);
    delete(MU_display_handles.V.Localizer.Local_h2);
end
guidata(handles.Parent, MU_display_handles);

% --- Executes on button press in Sag2Main_pushbutton.
function Sag2Main_pushbutton_Callback(hObject, eventdata, handles)
% hObject    handle to Sag2Main_pushbutton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

MU_display_handles=guidata(handles.Parent);

% initialize MU_display & more
MergeM=get(MU_display_handles.Matrix_name_edit,'String');
MU_display_new_handles=MU_display_initialize(MU_display_handles.MU_matrix_display, ...
                                             MU_display_handles,[MergeM '_s2m'], ...
                                             MU_display_handles.SMatrix);
if isempty(MU_display_new_handles)
    return;
end

MU_display_new_handles.Mask=permute(MU_display_handles.Mask,[3 1 2]);
MU_display_new_handles.SMatrix=permute(MU_display_handles.SMatrix,[3 1 2]); % Sagittal Matrix
MU_display_new_handles.CMatrix=permute(MU_display_handles.SMatrix,[3 2 1]); % Coronal Matrix
MU_display_new_handles.Slicer=1;
MU_display_new_handles.V.Localizer=MU_display_handles.V.Localizer;
MU_display_new_handles.V.Localizer.Local_point=[ceil(MU_display_new_handles.V.DimSize(2)/2) ...
                                                ceil(MU_display_new_handles.V.DimSize(1)/2)];

MU_display_new_handles=MU_update_image(MU_display_new_handles.Matrix_display_axes, ...
                                      {MU_display_new_handles.TMatrix,MU_display_new_handles.Mask},...
                                       MU_display_new_handles,0);
cla(handles.Matrix_display_axes2);
cla(handles.Matrix_display_axes3);
MU_update_ass_image({handles.Matrix_display_axes2,handles.Matrix_display_axes3}, ...
                    {MU_display_new_handles.SMatrix,MU_display_new_handles.CMatrix}, ...
                    MU_display_new_handles);

guidata(handles.Parent, MU_display_new_handles);

% --- Executes on button press in Cor2Main_pushbutton.
function Cor2Main_pushbutton_Callback(hObject, eventdata, handles)
% hObject    handle to Cor2Main_pushbutton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

MU_display_handles=guidata(handles.Parent);

% initialize MU_display & more
MergeM=get(MU_display_handles.Matrix_name_edit,'String');
MU_display_new_handles=MU_display_initialize(MU_display_handles.MU_matrix_display, ...
                                             MU_display_handles,[MergeM '_c2m'], ...
                                             MU_display_handles.CMatrix);
if isempty(MU_display_new_handles)
    return;
end

MU_display_new_handles.Mask=permute(MU_display_handles.Mask,[3 2 1]);
MU_display_new_handles.SMatrix=permute(MU_display_handles.CMatrix,[3 1 2]); % Sagittal Matrix
MU_display_new_handles.CMatrix=permute(MU_display_handles.CMatrix,[3 2 1]); % Coronal Matrix
MU_display_new_handles.Slicer=1;
MU_display_new_handles.V.Localizer=MU_display_handles.V.Localizer;
MU_display_new_handles.V.Localizer.Local_point=[ceil(MU_display_new_handles.V.DimSize(2)/2) ...
                                                ceil(MU_display_new_handles.V.DimSize(1)/2)];

MU_display_new_handles=MU_update_image(MU_display_new_handles.Matrix_display_axes, ...
                                      {MU_display_new_handles.TMatrix,MU_display_new_handles.Mask},...
                                       MU_display_new_handles,0);
cla(handles.Matrix_display_axes2);
cla(handles.Matrix_display_axes3);
MU_update_ass_image({handles.Matrix_display_axes2,handles.Matrix_display_axes3}, ...
                    {MU_display_new_handles.SMatrix,MU_display_new_handles.CMatrix}, ...
                    MU_display_new_handles);

guidata(handles.Parent, MU_display_new_handles);

% --- Executes when user attempts to close MU_matrix_display_3Plane.
function MU_matrix_display_3Plane_CloseRequestFcn(hObject, eventdata, handles)
% hObject    handle to MU_matrix_display_3Plane (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

global Figure_handles
Figure_handles=rmfield(Figure_handles,'MU_display2');

if ~ishandle(handles.Parent)
    delete(hObject);
    return;
end
MU_display_handles=guidata(handles.Parent);
MU_display_handles.V.Localizer.Local_switch=0;
MU_display_handles.Slicer=0;
MU_display_handles=rmfield(MU_display_handles,'SMatrix');
MU_display_handles=rmfield(MU_display_handles,'CMatrix');

try
    delete(MU_display_handles.V.Localizer.Local_h1);
    delete(MU_display_handles.V.Localizer.Local_h2);
catch me
end
set(MU_display_handles.MatrixCalc_pushbutton,'Enable','on'); % enable matrix calculation when slicer if off
guidata(handles.Parent, MU_display_handles);

% Hint: delete(hObject) closes the figure
delete(hObject);

% --- Executes on mouse motion over figure - except title and menu.
function MU_matrix_display_3Plane_WindowButtonMotionFcn(hObject, eventdata, handles)
% hObject    handle to MU_matrix_display_3Plane (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

if ~ishandle(handles.Parent)
    delete(hObject);
end

% --- Executes during object deletion, before destroying properties.
function MU_matrix_display_3Plane_DeleteFcn(hObject, eventdata, handles)
% hObject    handle to MU_matrix_display_3Plane (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)


function h = tc_sessionPlots(tcs, plotType, titleType);
% h = tc_sessionPlots(tcs, plotType, [titleType = 1]);
%
% produce a figure showing individual subjects time course or amplitude data
% each subject's data will be a subplot of the figure
% plotType (string):
% 'wholetc'         raw timecourse
% 'meanampsplustcs' left panel will show mean amps according to tc.params.ampType; right panel will show event-triggered average
% 'meantcs'         event trigerred averaging mean time course
% 'deconvolvedTcs'  deconvolved time courses
% 'amps'            Means amplitudes of each condition according to the
%                   value in the tc.params.ampType filed which can be
%                   one of the following: 'difference' 'betas' 'relamps' or 'deconvolved';
% 'meanamps'        estimated from the event-triggered average based on the
%                   baseline and peak periods
% 'betas'           one beta per condition (no beta for baseline)estimated
%                   from a glm on the tc
% 'relamps'         David Ress's method for amplitude estimatation
% 'deconvolvedamps' Etimate of the mean amps from the deconvolved time
%                   course based on the peak and baseline period
%
% titleType: 1 (default) uses tcs.sessionCode for chart titles (usually
% corresponds to the directory of the session); 2 uses tcs.description.
%
%
% ras, 02/2007.
% ras, 04/2007: was part of tc_acrossSessions, but broke off to be its own
% function, since it's pretty useful. Also allows cells of tc structs as
% inputs.
% remus 10/2007: added titleType flag.
% kgs 3/2008: added deconvolvedtc and deconvolvedamps options
%
h = [];

% set titleType parameters
if exist('titleType') & titleType == 2
    titleField = 'description';
else
    titleField = 'sessionCode';
end

% allow input to be a cell array
if iscell(tcs)
	% remove empty entries
	tcs = tcs( cellfind(tcs) );

	C = tcs;
	tcs = tcs{1};
	for i = 2:length(C)
		tcs(i) = mergeStructures(tcs(i-1), C{i});
	end
end

nSessions = length(tcs);
maxSubplotsPerFig = 16;  % if length(tcs)>this, make multiple figures
nFigs = ceil(nSessions / maxSubplotsPerFig);
subplotsPerFig = min(nSessions, maxSubplotsPerFig);

if nFigs > 1
    nRows = 5;
    nCols = 4;
else
    nRows = ceil( sqrt(subplotsPerFig) );
    nCols = ceil( subplotsPerFig / nRows );
end

% adjustment for plot types which display >1 axis per session
if isequal(lower(plotType), 'meanampsplustcs')
    nFigs = ceil(2 * nSessions / maxSubplotsPerFig); % 2 subplots per session
    subplotsPerFig = maxSubplotsPerFig / 2;
    nRows = nRows*2;
    nCols = nCols*2;
end

for s = 1:nSessions
    if mod(s, subplotsPerFig)==1
        h(end+1) = figure('Color', 'w', 'Position', [100 100 600 800], ...
                    'Name', sprintf('%s Session Plots', tcs(1).roi.name));
	end

	% get text for the title for this subplot
	titleText = tcs(s).params.(titleField);
	titleText( titleText=='_' ) = '-';  % TeX markup--avoid subscripts

    switch lower(plotType)
        case {'wholetc' 'wholetcs'}
            subplot(nRows, nCols, s);
            tc_plotWholeTc(tcs(s), gca);
            title(titleText, 'FontSize', 10);

        case 'meanampsplustcs'
            subplot(ceil(nRows/2), nCols, (2*s-1));
            tc_barMeanAmplitudes(tcs(s), gca, 0); % this will plot the event triggered average plots
            title(titleText, 'FontSize', 10);

            subplot(ceil(nRows/2), nCols, (2*s));
            tc_plotMeanTrials(tcs(s), gca);

			if isfield(tcs(s), 'SNR') & ~isempty(tcs(s), 'SNR')
				snrNums = tcs(s).condNums(tcs(s).params.snrConds);
				snrConds = sprintf('%i ', snrNums);
				title(sprintf('SNR: %3.2f (conds [%s])', tcs(s).SNR, snrConds));
			end

        case {'meantc' 'meantcs'}
            subplot(nRows, nCols, s);
            tc_plotMeanTrials(tcs(s), gca); % this will plot what is in the meantc field
            title(titleText, 'FontSize', 10);

        case {'deconvolved' 'deconvolvedTcs' 'deconvolvedtcs'}  % will plot the deconvolved time courses
                currTc=tcs(s);
     			currTc.params.glmHRF=0 % set glm flag for deconvolution
                % deconvolve
                 currTc = tc_applyGlm(currTc);
                 % add a blank condition at the beginning betas are zero
                % because this is the baseline to which the glm is
                 % estimated
                currTc.meanTcs = [zeros(currTc.glm.nh, 1) currTc.glm.betas];
                subplot(nRows, nCols, s);
                tc_plotMeanTrials(currTc, gca);
                title(titleText, 'FontSize', 10);

        case 'amps'
            subplot(nRows, nCols, s);
            %   0 - Use the value in the tc.params.ampType field.
            tc_barMeanAmplitudes(tcs(s), gca, 0);
            title(titleText, 'FontSize', 10);

        case 'meanamps'
            subplot(nRows, nCols, s);
            %  1 - Plot Peak/Baseline difference of event-triggered average
            tc_barMeanAmplitudes(tcs(s), gca, 1);
            title(titleText, 'FontSize', 10);

        case 'betas'
            subplot(nRows, nCols, s);
            %   2 - Plot GLM Beta values
            tc_barMeanAmplitudes(tcs(s), gca, 2);
            title(titleText, 'FontSize', 10);

        case {'relamps' 'dotproductamps' 'projamps'}
            subplot(nRows, nCols, s);
            %   3 - Plot Dot-Product Projection Amplitudes
            tc_barMeanAmplitudes(tcs(s), gca, 3);
            title(titleText, 'FontSize', 10);

        case { 'deconvolvedamps'  'deconvolvedAmps'}
            subplot(nRows, nCols, s);
            %   4 - Plot Peak/Baseline from deconvolved time courses
            tc_barMeanAmplitudes(tcs(s), gca, 4);
            title(titleText, 'FontSize', 10);

        otherwise, warning( sprintf('Unknown plot type %s', plotType) )
    end

end

return


%Author: Guosheng Lin

function do_forward_trn(obj, inputs)

%copy from  matconvnet/matlab/+dagnn/@DagNN/eval.m
% copy this function to matconvnet/matlab/+dagnn/@DagNN/

obj.computingDerivative = true;

% -------------------------------------------------------------------------
% Forward pass
% -------------------------------------------------------------------------

% set the input values
v = obj.getVarIndex(inputs(1:2:end)) ;
if any(isnan(v))
  broken = find(isnan(v)) ;
  error('No variable of name ''%s'' could be found in the DAG.', inputs{2*broken(1)-1}) ;
end
[obj.vars(v).value] = deal(inputs{2:2:end}) ;
inputs = [] ;

obj.numPendingVarRefs = [obj.vars.fanout] ;
for l = obj.executionOrder
  time = tic ;
  obj.layers(l).block.forwardAdvanced(obj.layers(l)) ;
  obj.layers(l).forwardTime = toc(time) ;
end

end


function [par] = readprocpar(fpath, ext)

% READPROCPAR reads in parameter used in FID acquisition
%
%   PAR = READPROCPAR(FPATH) reads the parameters in the the
%   procpar file in the FID directory FPATH
%
% see also WRITEPROCPAR, READFID, WRITEFID

% Written by L Martyn Klassen
% Copyright 2003 Robarts Research Institute

if nargin < 1
   error('CFMM:readprocpar','One input argument required.');
end

if nargin < 2
   ext = [];
end

[data,fpath] = readprocpar2(fpath, ext);

% Initialize outputs
par.path     = fpath;
par.dp       = [];
par.seqfil   = [];
par.nf       = [];
par.ni       = [];
par.sw       = [];
par.ns       = [];
par.ne1      = [];
par.ne2      = [];
par.rfspoil  = [];
par.rfphase  = [];
par.nt       = [];
par.np       = [];
par.nv       = [];
par.nv2      = [];
par.nv3      = [];
par.ne       = [];
par.polarity = [];
par.evenecho = [];
par.tr       = [];
par.te       = [];
par.esp      = [];
par.espincr  = [];
par.nprof    = [];
par.tproj    = [];
par.phi      = [];
par.psi      = [];
par.theta    = [];
par.vpsi     = [];
par.vphi     = [];
par.vtheta   = [];
par.array{1} = [];
par.arraydim = [];
par.seqcon   = [];
par.lro      = [];
par.lpe      = [];
par.lpe2     = [];
par.pro      = [];
par.ppe      = [];
par.ppe2     = [];
par.pss      = [];
par.thk      = [];
par.thk2     = [];
par.pos1     = [];
par.pos2     = [];
par.pos3     = [];
par.vox1     = [];
par.vox2     = [];
par.vox3     = [];
par.nD       = [];
par.cntr     = [];
par.gain     = [];
par.shimset  = [];
par.z1       = [];
par.z2       = [];
par.z3       = [];
par.z4       = [];
par.z5       = [];
par.z6       = [];
par.z7       = [];
par.z8       = [];
par.x1       = [];
par.y1       = [];
par.xz       = [];
par.yz       = [];
par.xy       = [];
par.x3       = [];
par.y3       = [];
par.x4       = [];
par.y4       = [];
par.z1c      = [];
par.z2c      = [];
par.z3c      = [];
par.z4c      = [];
par.xz2      = [];
par.yz2      = [];
par.xz2      = [];
par.yz2      = [];
par.zxy      = [];
par.z3x      = [];
par.z3y      = [];
par.zx3      = [];
par.zy3      = [];
par.z4x        = [];
par.z4y        = [];
par.z5x        = [];
par.z5y        = [];
par.x2y2       = [];
par.z2xy       = [];
par.z3xy       = [];
par.z2x3       = [];
par.z2y3       = [];
par.z3x3       = [];
par.z3y3       = [];
par.z4xy       = [];
par.zx2y2      = [];
par.z2x2y2     = [];
par.z3x2y2     = [];
par.z4x2y2     = [];
par.petable    = [];
par.nrcvrs     = [];
par.trise      = [];
par.at         = [];
par.gro        = [];
par.gmax       = [];
par.intlv      = [];
par.rcvrs      = [];
par.celem      = [];
par.arrayelemts = [];
par.contrast   = [];
par.tep        = [];
par.date       = [];
par.ti         = [];
par.gss2       = [];
par.gss        = [];
par.tpwri      = [];
par.tpwr1      = [];
par.tpwr2      = [];
par.orient     = [];
par.tof        = [];
par.resto      = [];
par.grox       = [];
par.groy       = [];
par.fov        = [];
par.res        = [];
par.npix       = [];
par.nseg       = [];
par.nzseg      = [];
par.waveform   = [];
par.SR         = [];
par.gradfrac   = [];
par.sfrq       = [];
par.B0         = [];
par.dtmap      = [];
par.nnav       = [];
par.tnav       = [];
par.fast       = [];
par.bt         = [];
par.nhomo      = [];
par.fpmult     = [];
par.d1         = [];
par.ss         = [];
par.ssc        = [];
par.r1         = [];
par.r2         = [];
par.ps_coils   = [];
par.coil_array = [];
par.nav        = [];
par.fliplist   = [];
par.varflip    = [];
par.nfreq      = [];
par.freq       = [];
par.flip       = [];
par.flip1      = [];
par.flipprep   = [];
par.seg        = [];
par.state      = [];
par.rfdelay    = [];
par.gro        = [];
par.gimp       = [];
par.SR         = [];
par.readaxis   = [];
par.timescale  = [];
par.etl        = [];
par.grof       = [];
par.Po         = [];
par.Psl        = [];
par.console    = [];
par.shimcoils  = [];
par.spiral_gmax      = [];
par.spiral_gamma     = [];
par.spiral_delay     = [];
par.spiral_tep       = [];
par.dtg              = [];
par.nturns           = [];
par.direction        = [];
par.ninterleave      = [];
par.tn               = [];
par.randomseed       = [];
par.interleave_order = [];
par.profile          = [];
par.image            = [];
par.spiral_version   = [];
par.spiral_filter    = [];
par.spiral_alpha     = [];
par.spiral_density   = [];
par.navigator        = [];
par.tfirst           = [];
par.tpe              = [];
par.ky_order         = [];
par.alternate        = [];
par.offlineAverages  = [];
par.threshold        = [];
par.cluster          = [];
par.weightfit        = [];
par.offlineAverage   = [];
par.bipolar          = [];
par.tpwr             = [];
par.tpwrf            = [];
par.dpwr             = [];
par.dpwrf            = [];
par.echoes           = [];
par.combinedAcq      = [];
par.reductionFactor  = [];
par.referenceUnits   = [];
par.referenceLines   = [];

names = fieldnames(par);
params = fieldnames(data);

for i = 1:length(params);
   par.(params{i}) = data.(params{i}).value;
end

% Make the returned values fully backwards compatible.
for i = 1:length(names)
   if isfield(data,names{i})
      field = data.(names{i});
      switch field.basictype
         case 1
            par.(names{i}) = field.value;
         case {0 2}
            par.(names{i}) = field.value{1};
      end
   end
end

if isfield(data, 'rcvrs')
   par.nrcvrs = data.rcvrs.number;
end

if isfield(data, 'array')
   par.array = data.array.loops;
end

if isfield(data, 'shimcoils')
   par.shimcoils = data.shimcoils.value;
end

if isfield(data, 'ps_coils')
   par.ps_coils = data.ps_coils.value;
end

if isfield(data, 'coil_array')
   par.coil_array = data.coil_array.value;
end

par.path = fpath;

return


function dtiMakeBrainMaskSafe(dtiDir,  dtiAlignedAvgFile)

%E.g., dtiMakeBrainSafeMask('dti06rt', 'dti_g712_b2000_aligned_trilin_avg.nii.gz')
%Take brainMask.nii.gz and remove the voxels that have a zero in the raw data (at
%least in one gradient directions)
%Input: directory with raw dti data
%Will overwrite your brainMask.nii.gz with a new safer one.

%ER 02/23/2009 pulled code out of mtrNotes to perform this operation
%ER 09/09 removed redundant code and changed input (dtiRawDir->dtiAlignedAvgFile)

dirPrev = pwd;
ni=niftiRead(dtiAlignedAvgFile);

% Update brain mask so that bad voxels are removed
cd([dtiDir filesep 'bin']);
bm = niftiRead('brainMask.nii.gz');
rawm = min(ni.data,[],4);
bm.data(rawm<1) = 0;

%bm.fname='brainMaskRawSafe.nii.gz';
writeFileNifti(bm);

cd(dirPrev);

return;


function option_num = p10_option_num ( )

%*****************************************************************************80
%
%% P10_OPTION_NUM returns the number of options for problem 10.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    03 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer OPTION_NUM, the number of options.
%
  option_num = 2;

  return
end


close all; clear all; clc;

audio = audioload();

file = 'text.txt';
fid  = fopen(file, 'r');
text = fread(fid,'*char')';
fclose(fid);

msg = echo_dec_ts(audio.data);
err = BER(text,msg);
nc  = NC(text, msg);

fprintf('Text: %s\n', msg);
fprintf('BER : %d\n', err);
fprintf('NC  : %d\n', nc);


 function axis_equal
%function axis_equal
%|
%| my version of "axis equal"

set(gca, 'DataAspectRatio', [1 1 1])


function h = figcopy(fc,fm)
% FIGCOPY - copies one figure into another figure and lets the
% users move and  resize the copied figure. This utility is great
% if you need a figure in a figure and still would like to use
% MATLAB's export function.
%
% h = FIGCOPY the user selects both figures by mouse clicks. Please
% follow the instructions in the command window. First activate the
% figure to be copied. Second activate the "master" figure and
% select the lower left and upper right corner, where the copied
% figure should appear in the "master" figure. Click on the copied
% figure to move or resize it. (Don't worry, the resize markers
% will not be printed!) h is the handle of the copied figure.
%
% h = FIGCOPY(fc) fc specifies the figure number (handle) to be
% copied. The master figure is selected by mouse click.
%
% h = FIGCOPY(fc,fm) specifies the figure number to be copied and
% the figure number of the master figure.

% Dirk Tenne
% CoDE (Control Dynamics and Estimation)
% web:      "http://code.eng.buffalo.edu"
% created:  "long time ago"
% modified: "December 12. 2002" updated the input handling
%           "November 27. 2007" copy only figure axes ignoring the new
%           uicontrols of Figures.
%

% input handling
  % is the figure number given or should it be clicked?
  if nargin < 3
    select_fc = 0;
    select_fm = 0;
    if nargin < 2
      select_fc = 0;
      select_fm = 1;
      if nargin < 1
	select_fc = 1;
	select_fm = 1;
      end
    end
  end

%activate the figure to copy

  if select_fc
    disp('Click on the figure which you''d like to copy!')
    waitforbuttonpress;
    fc = gcf;
    disp(' ')
    disp(['Figure ',num2str(gcf),' copied into the clipboard.'])
  end

  %hcfig = get(fc,'Children');
  % only look for axes handles as new versions also return uicontrols
  hcfig = findobj(1,'Type','axes');

  if select_fm
    disp('Activate master figure! (Try clicking the frame.)')
    waitforbuttonpress;
    fm = gcf;
  end

% specify the position of the figure
  figure(fm);
  disp(['Click to indicate the LOWER LEFT and UPPER RIGHT'])
  disp(['corners, where the copied figure should appear!'])
  [xi,yi] = ginput(2);

%normalizing x and y
   m_axis = axis;
   m_ax_pos = get(gca,'position');
   alphax = m_ax_pos(3); % rescaling the units
   alphay = m_ax_pos(4);
   x_max = diff(m_axis(1:2)); y_max = diff(m_axis(3:4));
   x = (xi-m_axis(1))/x_max*alphax;
   y = (yi-m_axis(3))/y_max*alphay;

   % placing the figure
   pos(1) = m_ax_pos(1) + x(1);
   pos(2) = m_ax_pos(2) + y(1);
   siz(1) = abs(x(1)-x(2));
   siz(2) = abs(y(1)-y(2));
   newhcfig = copyobj(hcfig,fm);
   for j = 1:length(newhcfig)
     set(newhcfig(j),'Position',[pos siz])
   end
   set(newhcfig(1),'ButtonDownFcn','selectmoveresize')
   %disable:set(gco,'ButtonDownFcn','','Selected','off')

% output handling
   if nargout > 0
     h = newhcfig;
   end


function [errorcode, rows, columns] = rndcheck(nargs,nparms,arg1,arg2,arg3,arg4,arg5)
    %RNDCHECK error checks the argument list for the random number generators.

    %	B.A. Jones  1-22-93
    %	Copyright (c) 1993 by The MathWorks, Inc.
    %	$Revision: 1399 $  $Date: 2006-08-11 11:19:27 +0200 (Fr, 11 Aug 2006) $

    report_this_filefun(mfilename('fullpath'));

    sizeinfo = nargs - nparms;
    errorcode = 0;

    if nparms == 3
        [r1, c1] = size(arg1);
        [r2, c2] = size(arg2);
        [r3, c3] = size(arg3);
    end

    if nparms == 2
        [r1, c1] = size(arg1);
        [r2, c2] = size(arg2);
    end

    if sizeinfo == 0
        if nparms == 1
            [rows, columns] = size(arg1);
        end

        if nparms == 2
            scalararg1 = isscalar(arg1);
            scalararg2 = isscalar(arg2);
            if ~scalararg1  &&  ~scalararg2
                if r1 ~= r2 | c1 ~= c2
                    errorcode = 1;
                    return;
                end
            end
            if ~scalararg1
                [rows, columns] = size(arg1);
            elseif ~scalararg2
                [rows, columns] = size(arg2);
            else
                [rows, columns] = size(arg1);
            end
        end

        if nparms == 3
            scalararg1 = isscalar(arg1);
            scalararg2 = isscalar(arg2);
            scalararg3 = isscalar(arg3);

            if ~scalararg1  &&  ~scalararg2
                if r1 ~= r2 | c1 ~= c2
                    errorcode = 1;
                    return;
                end
            end

            if ~scalararg1  &&  ~scalararg3
                if r1 ~= r3 | c1 ~= c3
                    errorcode = 1;
                    return;
                end
            end

            if ~scalararg3  &&  ~scalararg2
                if r3 ~= r2 | c3 ~= c2
                    errorcode = 1;
                    return;
                end
            end
            if ~scalararg1
                [rows, columns] = size(arg1);
            elseif ~scalararg2
                [rows, columns] = size(arg2);
            else
                [rows, columns] = size(arg3);
            end
        end
    end

    if sizeinfo == 1
        scalararg1 = isscalar(arg1);
        if nparms == 1
            if prod(size(arg2)) ~= 2
                errorcode = 2;
                return;
            end
           if  ~scalararg1  && arg2 ~= size(arg1)
                errorcode = 3;
                return;
            end
            if (arg2(1) < 0 | arg2(2) < 0 | arg2(1) ~= round(arg2(1)) | arg2(2) ~= round(arg2(2)))
                errorcode = 4;
                return;
            end
            rows    = arg2(1);
            columns = arg2(2);
        end

        if nparms == 2
            if prod(size(arg3)) ~= 2
                errorcode = 2;
                return;
            end
            scalararg2 = isscalar(arg2);
            if ~scalararg1  &&  ~scalararg2
                if r1 ~= r2 | c1 ~= c2
                    errorcode = 1;
                    return;
                end
            end
            if (arg3(1) < 0 | arg3(2) < 0 | arg3(1) ~= round(arg3(1)) | arg3(2) ~= round(arg3(2)))
                errorcode = 4;
                return;
            end
            if ~scalararg1
                if any(arg3 ~= size(arg1))
                    errorcode = 3;
                    return;
                end
                [rows, columns] = size(arg1);
            elseif ~scalararg2
                if any(arg3 ~= size(arg2))
                    errorcode = 3;
                    return;
                end
                [rows, columns] = size(arg2);
            else
                rows    = arg3(1);
                columns = arg3(2);
            end
        end

        if nparms == 3
            if prod(size(arg4)) ~= 2
                errorcode = 2;
                return;
            end
            scalararg1 = isscalar(arg1);
            scalararg2 = isscalar(arg2);
            scalararg3 = isscalar(arg3);

            if (arg4(1) < 0 | arg4(2) < 0 | arg4(1) ~= round(arg4(1)) | arg4(2) ~= round(arg4(2)))
                errorcode = 4;
                return;
            end

            if ~scalararg1  &&  ~scalararg2
                if r1 ~= r2 | c1 ~= c2
                    errorcode = 1;
                    return;
                end
            end

            if ~scalararg1  &&  ~scalararg3
                if r1 ~= r3 | c1 ~= c3
                    errorcode = 1;
                    return;
                end
            end

            if ~scalararg3  &&  ~scalararg2
                if r3 ~= r2 | c3 ~= c2
                    errorcode = 1;
                    return;
                end
            end
            if ~scalararg1
                if any(arg4 ~= size(arg1))
                    errorcode = 3;
                    return;
                end
                [rows, columns] = size(arg1);
            elseif ~scalararg2
                if any(arg4 ~= size(arg2))
                    errorcode = 3;
                    return;
                end
                [rows, columns] = size(arg2);
            elseif ~scalararg3
                if any(arg4 ~= size(arg3))
                    errorcode = 3;
                    return;
                end
                [rows, columns] = size(arg3);
            else
                rows    = arg4(1);
                columns = arg4(2);
            end
        end
    end

    if sizeinfo == 2
        if nparms == 1
            scalararg1 = isscalar(arg1);
            if ~scalararg1
                [rows, columns] = size(arg1);
                if rows ~= arg2 | columns ~= arg3
                    errorcode = 3;
                    return;
                end
            end
            if (arg2 < 0 | arg3 < 0 | arg2 ~= round(arg2) | arg3 ~= round(arg3))
                errorcode = 4;
                return;
            end
            rows = arg2;
            columns = arg3;
        end

        if nparms == 2
            scalararg1 = isscalar(arg1);
            scalararg2 = isscalar(arg2);
            if ~scalararg1  &&  ~scalararg2
                if r1 ~= r2 | c1 ~= c2
                    errorcode = 1;
                    return;
                end
            end
            if ~scalararg1
                [rows, columns] = size(arg1);
                if rows ~= arg3 | columns ~= arg4
                    errorcode = 3;
                    return;
                end
            elseif ~scalararg2
                [rows, columns] = size(arg2);
                if rows ~= arg3 | columns ~= arg4
                    errorcode = 3;
                    return;
                end
            else
                if (arg3 < 0 | arg4 < 0 | arg3 ~= round(arg3) | arg4 ~= round(arg4))
                    errorcode = 4;
                    return;
                end
                rows = arg3;
                columns = arg4;
            end
        end

        if nparms == 3
            scalararg1 = isscalar(arg1);
            scalararg2 = isscalar(arg2);
            scalararg3 = isscalar(arg3);

            if ~scalararg1  &&  ~scalararg2
                if r1 ~= r2 | c1 ~= c2
                    errorcode = 1;
                    return;
                end
            end

            if ~scalararg1  &&  ~scalararg3
                if r1 ~= r3 | c1 ~= c3
                    errorcode = 1;
                    return;
                end
            end

            if ~scalararg3  &&  ~scalararg2
                if r3 ~= r2 | c3 ~= c2
                    errorcode = 1;
                    return;
                end
            end

            if ~scalararg1
                [rows, columns] = size(arg1);
                if rows ~= arg4 | columns ~= arg5
                    errorcode = 3;
                    return;
                end
            elseif ~scalararg2
                [rows, columns] = size(arg2);
                if rows ~= arg4 | columns ~= arg5
                    errorcode = 3;
                    return;
                end
            elseif ~scalararg3
                [rows, columns] = size(arg3);
                if rows ~= arg4 | columns ~= arg5
                    errorcode = 3;
                    return;
                end
            else
                if (arg4 < 0 | arg5 < 0 | arg4 ~= round(arg4) | arg5 ~= round(arg5))
                    errorcode = 4;
                    return;
                end
                rows    = arg4;
                columns = arg5;
            end
        end
    end


function y = givensrot(gjc,g,x,K) %#ok
% y = givensrot(gjc,g,x,K)
%
% GIVENSROT
%
% **********  INTERNAL FUNCTION OF SEDUMI **********
%
% See also sedumi

% This file is part of SeDuMi 1.1 by Imre Polik and Oleksandr Romanko
% Copyright (C) 2005 McMaster University, Hamilton, CANADA  (since 1.1)
%
% Copyright (C) 2001 Jos F. Sturm (up to 1.05R5)
%   Dept. Econometrics & O.R., Tilburg University, the Netherlands.
%   Supported by the Netherlands Organization for Scientific Research (NWO).
%
% Affiliation SeDuMi 1.03 and 1.04Beta (2000):
%   Dept. Quantitative Economics, Maastricht University, the Netherlands.
%
% Affiliations up to SeDuMi 1.02 (AUG1998):
%   CRL, McMaster University, Canada.
%   Supported by the Netherlands Organization for Scientific Research (NWO).
%
% 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.,  51 Franklin Street, Fifth Floor, Boston, MA
% 02110-1301, USA

%Indicate to the user Matlab cannot find the SeDuMi binaries
sedumi_binary_error();


function Align = Find_Fiducials(q, r, s, Align, ecg, Param)
%OVERVIEW, Finds the lead with maximum QRS amplitude, takes a beat as QRS template and finds fiducial points such that
% aligned beats have maximum cross-correlation (over Q to S or S to T interval) in the chosen
% lead against the template.
%
% INPUTS            MANDATORY           OUTPUTS
%                   q                   q point locations
%
%                   r                   r point locations
%
%                   s                   s point locations
%
%                   Align               Alignment information for beats in
%                                       analysis window.
%
%                   ecg                 N by M array of ecg data. Contains M channels of ecg with N data points each.
%
%                   Param               Structure containing the parameters
%                                       used for evaluating TWAs.
%
% OUTPUTS
%                   Align               Alignment information used to
%                                       determine if current window is clean enough for
%                                       analysis.
%
%   REPO:
%       https://github.com/cliffordlab/PhysioNet-Cardiovascular-Signal-Toolbox
%   ORIGINAL SOURCE AND AUTHORS:
%       Written by Shamim Nemati,
%       editted by Ismail Sadiq on 10/26/2019.
%	COPYRIGHT (C) 2019
%   LICENSE:
%       This software is offered freely and without warranty under
%       the GNU (v3 or later) public license. See license file for
%       more information. The license may be found in
%       the Documents folder of the Physionet-Cardiovascular-Signal-Toolbox.

q = q(1:min(length(q), length(s)));
s = s(1:min(length(q), length(s)));

% Sort leads by amplitude.
leadSorted = Sort_Leads(q, s, Align.st, ecg, Param);

for ilead = 1:length(leadSorted)
    Align.lead = leadSorted(ilead);

    % Get the orientation of the QRS complex, max positive or max negative deflection.
    Align.orientation = MaxFrontOrientation(ecg(:, Align.lead), q, s);

    Align.fidBase = r;

    Align.f2s = floor(median(s - Align.fidBase) + Param.stAdjIntv);   % reserve to avoid including part of QRS in ST interval computations
    Align.q2f = min([floor(median(Align.fidBase - q)),Align.f2s-Param.stAdjIntv]);

    Align.fid = [];
    NFailed = 0;

    Align.template = 0;
    while isempty(Align.fid)
        Align.template = Align.template + 1;
        % Get alignment information
        Align = Adjust_e(Align, ecg, 1000, Param);
        if isempty(Align.fid)

            NFailed = NFailed + 1;
            if (NFailed > 0.1 * length(s))
                break
            end
        end
    end
    if (~isempty(Align.fid))
        for lead=1:size(ecg, 2)
            for i = 1:length(Align.fid)
                Align.amp(i, lead) = (max(ecg(q(i) : s(i), lead))+min(ecg(q(i) : s(i), lead)))/2;  % align to zero mean on QS segment
            end
        end
        % get correlation for each beat with template over Q-S and S-T
        % interval
        Align = CheckLead_Correlations(Align, ecg, Param);
        disp(['FindFiducials: Alignment in lead ' num2str(Align.lead)]);
        break;
    end;
    disp(['FindFiducials: lead ' num2str(Align.lead) ' is too noisy or ectopic..']);
end;
return;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function leads = Sort_Leads(q, s, st, ecg, Param)

NLead = size(ecg, 2);

%   QRS or T amplitudes in each lead
ptp = zeros(min(length(q), 8),NLead);
for i = 1:min(length(q), 8)
    for l = 1:NLead
        if strcmp(Param.Alignment, 'st')
            ptp(i, l) = max(ecg(s(i):s(i) + st, l)) - min(ecg(s(i):s(i) + st, l));
        else
            ptp(i, l) = max(ecg(q(i):s(i), l)) - min(ecg(q(i):s(i), l));
        end;
    end;
end;
ptpmed = zeros(1,NLead);
for i = 1:NLead
    ptpmed(i) = median(ptp(:, i));
end;

[sorted indices] = sort(ptpmed);
leads = indices(length(indices):-1:1);
return;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Align = Adjust_e(Align, ecg, freq, Param)
% OVERVIEW, This function determines which beats in analysis window for
% the lead given by Align.lead are valid for analysis, based on correlation
% with a QRS and S-T offset segment template.
Align.fidBase(Align.template);

len_ecg = size(ecg,1);
qs_templ = ecg(max(Align.fidBase(Align.template) - Align.q2f,1):min(Align.fidBase(Align.template) + Align.f2s,len_ecg), Align.lead);
st_templ = ecg(max(Align.fidBase(Align.template) + Align.f2s,1):min(Align.fidBase(Align.template) + Align.f2s + Align.st,len_ecg), Align.lead);

[a b c d] = Adjust_Fiducials(ecg, Align.fidBase, Align.q2f, Align.f2s, qs_templ, Align.st, st_templ, Param);
% fid a -> with respect to QRS alignment
% fid c -> with respect to ST alignment

if ~isempty(c)
    Align.fidQRS = a;
    Align.QRScorr(:, Align.lead) = b;
    Align.fid = c;
    Align.Tcorr(:, Align.lead) = d;
    amp = (max(qs_templ)+min(qs_templ))/2;
    Align.qs_templ(:, Align.lead) = qs_templ - amp;
    Align.st_templ(:, Align.lead) = st_templ - amp;

    for i = 1:length(Align.fid)
        Align.valid(i, Align.lead) = (Align.QRScorr(i, Align.lead) >= Param.corrQRS) && (Align.Tcorr(i, Align.lead) >= Param.corrT);
    end;
    Align.validleads(Align.lead) = true;
end;

return;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function orientation = MaxFrontOrientation(ecg, q, s)

NPos = 0;

for i = 1:min(20, length(s))
    [ma maI] = max(ecg(q(i):s(i)));
    [mi miI] = min(ecg(q(i):s(i)));

    NPos = NPos + (maI > miI);
end;

orientation = (NPos > 10);

return;


% The COBRAToolbox: testMergeTwoModels.m
%
% Purpose:
%     - testMergeTwoModels tests the mergeTwoModels function for
%     applicability to multiple different scenarios.
%
% Authors:
%     - Thomas Pfau 2018

% We will create 2 toy models
%model1
model1 = createModel();
model1 = addMultipleMetabolites(model1,{'A[c]','B[c]','C[c]','D[c]','E[c]'},'metKEGGID',{'C1','C2','C3','C4','C5'});
model1 = addGenes(model1,{'G1','G2','G3'},'geneNames',{'Gene1','Gene2','Gene3'});
model1 = addMultipleReactions(model1,{'R1','R2','R3'},model1.mets,rand(5,3),'grRules',{'G1','G2 and G3',''});

% Model2
model2 = createModel();
model2 = addMultipleMetabolites(model2,{'A2[c]','B2[c]','C2[c]','D2[c]','E2[c]'},'metKEGGID',{'C1','C2','C3','C4','C5'});
model2 = addGenes(model2,{'G21','G22','G23'},'geneNames',{'Gene1a','Gene2a','Gene3a'});
model2 = addMultipleReactions(model2,{'R21','R22','R23'},model2.mets,rand(5,3),'grRules',{'G21','G22 and G23',''});

%join the models (first, with genes)
modelJoint = mergeTwoModels(model1,model2);
%New S is of size 10 x 6
assert(size(modelJoint.S,1) == 10)
assert(size(modelJoint.S,2) == 6)
%Test, that the reactions are the same.
model2rxn = printRxnFormula(model2,'rxnAbbrList',model2.rxns(1),'printFlag',false);
modelJointRxn = printRxnFormula(modelJoint,'rxnAbbrList',model2.rxns(1),'printFlag',false);
assert(strcmp(model2rxn{1},modelJointRxn{1}));
model1rxn = printRxnFormula(model1,'rxnAbbrList',model1.rxns(2),'printFlag',false);
modelJointRxn = printRxnFormula(modelJoint,'rxnAbbrList',model1.rxns(2),'printFlag',false);
assert(strcmp(model1rxn{1},modelJointRxn{1}));

%Check, that the rules are correctly updated.
ruleR22 = modelJoint.rules{ismember(modelJoint.rxns,'R22')};
genePos = find(ismember(modelJoint.genes,{'G22','G23'}));
rule = strjoin(cellfun(@(x) ['x(' num2str(x) ')'], num2cell(genePos),'Uniform',0),' & ');
fp = FormulaParser();
modelRule = fp.parseFormula(ruleR22);
shouldBeRule = fp.parseFormula(rule);
assert(modelRule.isequal(shouldBeRule))

%Now, lets change G22 in model2 to G2 and introduce a common reaction
model2 = changeGeneAssociation(model2,'R22','G1 and G2');
model2 = addReaction(model2,'Rcommon','A[c] + B[c] -> C[c]');
model1 = addReaction(model1,'Rcommon','A[c] + B[c] -> C[c]');
model2.geneNames(end-1) = {'GeneFromModel2'};

%Assert that Model2 overrides model 1
modelJoint = mergeTwoModels(model1,model2);
assert(size(modelJoint.S,1) == 10)
assert(size(modelJoint.S,2) == 7)
geneWithName = model2.genes(end-1);
m2pos = ismember(model2.genes,geneWithName);
m1pos = ismember(model1.genes,geneWithName);
mjointPos = ismember(modelJoint.genes,geneWithName);
assert(strcmp(modelJoint.geneNames{mjointPos}, model1.geneNames{m1pos}))
model1rxn = printRxnFormula(model1,'rxnAbbrList','Rcommon','printFlag',false);
modelJointRxn = printRxnFormula(modelJoint,'rxnAbbrList','Rcommon','printFlag',false);
assert(strcmp(model1rxn{1},modelJointRxn{1}));

%Now also check that the objective is set correctly
model2.c(1) = 1;
model1.c(1) = 1;
modelJoint = mergeTwoModels(model1,model2,2);
assert(strcmp(modelJoint.rxns{find(modelJoint.c)},model2.rxns{1}));
modelJoint = mergeTwoModels(model1,model2,1);
assert(strcmp(modelJoint.rxns{find(modelJoint.c)},model1.rxns{1}));

%Finally, check that the merger is ok without merging genes
modelJoint = mergeTwoModels(model1,model2,2,false);
assert(~isfield(modelJoint,'geneNames'));
assert(isempty(modelJoint.genes));

%Test appropriate error if there are duplicate ids with distinct
%stoichiometries:
model2 = addReaction(model2,'Rcommon','A[c] -> C[c]');
assert(verifyCobraFunctionError('mergeTwoModels','outputArgCount',1,'inputs',{model1,model2},...
                         'testMessage','The following reactions were present in both models but had distinct stoichiometries:\nRcommon'));


classdef BRISK < handle
    %BRISK  Class implementing the BRISK keypoint detector and descriptor extractor
    %
    % As described in [LCS11].
    %
    % ## References
    % [LCS11]:
    % > Stefan Leutenegger, Margarita Chli, and Roland Yves Siegwart.
    % > "BRISK: Binary Robust Invariant Scalable Keypoints".
    % > In IEEE International Conference on Computer Vision (ICCV) 2011,
    % > pages 2548-2555. IEEE, 2011.
    %
    % See also: cv.BRISK.BRISK, cv.FeatureDetector, cv.DescriptorExtractor,
    %  detectBRISKFeatures, extractFeatures, BRISKPoints
    %

    properties (SetAccess = private)
        % Object ID
        id
    end

    methods
        function this = BRISK(varargin)
            %BRISK  The BRISK constructor
            %
            %     obj = cv.BRISK()
            %     obj = cv.BRISK(radiusList, numberList)
            %     obj = cv.BRISK(..., 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __radiusList__ defines the radii (in pixels) where the samples
            %   around a keypoint are taken (for keypoint scale 1).
            % * __numberList__ defines the number of sampling points on the
            %   sampling circle. Must be the same size as `radiusList`.
            %
            % ## Options
            % Options accepted by first variant:
            %
            % * __Threshold__ FAST/AGAST detection threshold score. default 30
            % * __Octaves__ detection octaves. Use 0 to do single scale.
            %   default 3
            % * __PatternScale__ apply this scale to the pattern used for
            %   sampling the neighbourhood of a keypoint. default 1.0
            %
            % Options accepted by second variant for a custom pattern:
            %
            % * __Threshold__ FAST/AGAST detection threshold score. default 20
            % * __Octaves__ detection octaves. Use 0 to do single scale.
            %   default 3
            % * __DMax__ threshold for the short pairings used for descriptor
            %   formation (in pixels for keypoint scale 1). default 5.85
            % * __DMin__ threshold for the long pairings used for orientation
            %   determination (in pixels for keypoint scale 1). default 8.2
            % * __IndexChange__ index remapping of the bits.
            %   default empty vector.
            %
            % See also: cv.BRISK.detectAndCompute
            %
            this.id = BRISK_(0, 'new', varargin{:});
        end

        function delete(this)
            %DELETE  Destructor
            %
            %     obj.delete()
            %
            % See also: cv.BRISK
            %
            if isempty(this.id), return; end
            BRISK_(this.id, 'delete');
        end

        function typename = typeid(this)
            %TYPEID  Name of the C++ type (RTTI)
            %
            %     typename = obj.typeid()
            %
            % ## Output
            % * __typename__ Name of C++ type
            %
            typename = BRISK_(this.id, 'typeid');
        end
    end

    %% Algorithm
    methods
        function clear(this)
            %CLEAR  Clears the algorithm state
            %
            %     obj.clear()
            %
            % See also: cv.BRISK.empty, cv.BRISK.load
            %
            BRISK_(this.id, 'clear');
        end

        function b = empty(this)
            %EMPTY  Checks if detector object is empty
            %
            %     b = obj.empty()
            %
            % ## Output
            % * __b__ Returns true if the detector object is empty (e.g in the
            %   very beginning or after unsuccessful read).
            %
            % See also: cv.BRISK.clear, cv.BRISK.load
            %
            b = BRISK_(this.id, 'empty');
        end

        function save(this, filename)
            %SAVE  Saves the algorithm parameters to a file
            %
            %     obj.save(filename)
            %
            % ## Input
            % * __filename__ Name of the file to save to.
            %
            % This method stores the algorithm parameters in the specified
            % XML or YAML file.
            %
            % See also: cv.BRISK.load
            %
            BRISK_(this.id, 'save', filename);
        end

        function load(this, fname_or_str, varargin)
            %LOAD  Loads algorithm from a file or a string
            %
            %     obj.load(fname)
            %     obj.load(str, 'FromString',true)
            %     obj.load(..., 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __fname__ Name of the file to read.
            % * __str__ String containing the serialized model you want to
            %   load.
            %
            % ## Options
            % * __ObjName__ The optional name of the node to read (if empty,
            %   the first top-level node will be used). default empty
            % * __FromString__ Logical flag to indicate whether the input is a
            %   filename or a string containing the serialized model.
            %   default false
            %
            % This method reads algorithm parameters from the specified XML or
            % YAML file (either from disk or serialized string). The previous
            % algorithm state is discarded.
            %
            % See also: cv.BRISK.save
            %
            BRISK_(this.id, 'load', fname_or_str, varargin{:});
        end

        function name = getDefaultName(this)
            %GETDEFAULTNAME  Returns the algorithm string identifier
            %
            %     name = obj.getDefaultName()
            %
            % ## Output
            % * __name__ This string is used as top level XML/YML node tag
            %   when the object is saved to a file or string.
            %
            % See also: cv.BRISK.save, cv.BRISK.load
            %
            name = BRISK_(this.id, 'getDefaultName');
        end
    end

    %% Features2D: FeatureDetector + DescriptorExtractor
    methods
        function ntype = defaultNorm(this)
            %DEFAULTNORM  Returns the default norm type
            %
            %     ntype = obj.defaultNorm()
            %
            % ## Output
            % * __ntype__ Norm type. One of `cv::NormTypes`:
            %   * __Inf__
            %   * __L1__
            %   * __L2__
            %   * __L2Sqr__
            %   * __Hamming__
            %   * __Hamming2__
            %
            % Always `Hamming` for BRISK.
            %
            % See also: cv.BRISK.compute, cv.DescriptorMatcher
            %
            ntype = BRISK_(this.id, 'defaultNorm');
        end

        function sz = descriptorSize(this)
            %DESCRIPTORSIZE  Returns the descriptor size in bytes
            %
            %     sz = obj.descriptorSize()
            %
            % ## Output
            % * __sz__ Descriptor size.
            %
            % See also: cv.BRISK.descriptorType, cv.BRISK.compute
            %
            sz = BRISK_(this.id, 'descriptorSize');
        end

        function dtype = descriptorType(this)
            %DESCRIPTORTYPE  Returns the descriptor type
            %
            %     dtype = obj.descriptorType()
            %
            % ## Output
            % * __dtype__ Descriptor type, one of numeric MATLAB class names.
            %
            % Always `uint8` for BRISK.
            %
            % See also: cv.BRISK.descriptorSize, cv.BRISK.compute
            %
            dtype = BRISK_(this.id, 'descriptorType');
        end

        function keypoints = detect(this, img, varargin)
            %DETECT  Detects keypoints in an image or image set
            %
            %     keypoints = obj.detect(img)
            %     keypoints = obj.detect(imgs)
            %     [...] = obj.detect(..., 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __img__ Image (first variant), 8-bit grayscale image.
            % * __imgs__ Image set (second variant), cell array of images.
            %
            % ## Output
            % * __keypoints__ The detected keypoints. In the first variant, a
            %   1-by-N structure array. In the second variant of the method,
            %   `keypoints{i}` is a set of keypoints detected in `imgs{i}`.
            %
            % ## Options
            % * __Mask__ A mask specifying where to look for keypoints
            %   (optional). It must be a logical or 8-bit integer matrix with
            %   non-zero values in the region of interest. In the second
            %   variant, it is a cell-array of masks for each input image,
            %   `masks{i}` is a mask for `imgs{i}`. Not set by default.
            %
            % See also: cv.BRISK.compute, cv.BRISK.detectAndCompute
            %
            keypoints = BRISK_(this.id, 'detect', img, varargin{:});
        end

        function [descriptors, keypoints] = compute(this, img, keypoints)
            %COMPUTE  Computes the descriptors for a set of keypoints detected in an image or image set
            %
            %     [descriptors, keypoints] = obj.compute(img, keypoints)
            %     [descriptors, keypoints] = obj.compute(imgs, keypoints)
            %
            % ## Input
            % * __img__ Image (first variant), 8-bit grayscale image.
            % * __imgs__ Image set (second variant), cell array of images.
            % * __keypoints__ Input collection of keypoints. Keypoints for
            %   which a descriptor cannot be computed are removed. Sometimes
            %   new keypoints can be added, for example: cv.SIFT duplicates
            %   keypoint with several dominant orientations (for each
            %   orientation). In the first variant, this is a struct-array of
            %   detected keypoints. In the second variant, it is a cell-array,
            %   where `keypoints{i}` is a set of keypoints detected in
            %   `imgs{i}` (a struct-array like before).
            %
            % ## Output
            % * __descriptors__ Computed descriptors. In the second variant of
            %   the method `descriptors{i}` are descriptors computed for a
            %   `keypoints{i}`. Row `j` in `descriptors` (or `descriptors{i}`)
            %   is the descriptor for `j`-th keypoint.
            % * __keypoints__ Optional output with possibly updated keypoints.
            %
            % See also: cv.BRISK.detect, cv.BRISK.detectAndCompute
            %
            [descriptors, keypoints] = BRISK_(this.id, 'compute', img, keypoints);
        end

        function [keypoints, descriptors] = detectAndCompute(this, img, varargin)
            %DETECTANDCOMPUTE  Detects keypoints and computes their descriptors
            %
            %     [keypoints, descriptors] = obj.detectAndCompute(img)
            %     [...] = obj.detectAndCompute(..., 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __img__ Image, input 8-bit grayscale image.
            %
            % ## Output
            % * __keypoints__ The detected keypoints. A 1-by-N structure array
            %   with the following fields:
            %   * __pt__ coordinates of the keypoint `[x,y]`
            %   * __size__ diameter of the meaningful keypoint neighborhood
            %   * __angle__ computed orientation of the keypoint (-1 if not
            %     applicable); it's in [0,360) degrees and measured relative
            %     to image coordinate system (y-axis is directed downward),
            %     i.e in clockwise.
            %   * __response__ the response by which the most strong keypoints
            %     have been selected. Can be used for further sorting or
            %     subsampling.
            %   * __octave__ octave (pyramid layer) from which the keypoint
            %     has been extracted.
            %   * **class_id** object class (if the keypoints need to be
            %     clustered by an object they belong to).
            % * __descriptors__ Computed descriptors. Output concatenated
            %   vectors of descriptors. Each descriptor is a vector of length
            %   cv.BRISK.descriptorSize, so the total size of descriptors will
            %   be `numel(keypoints) * obj.descriptorSize()`. A matrix of size
            %   N-by-sz of class `uint8`, one row per keypoint.
            %
            % ## Options
            % * __Mask__ optional mask specifying where to look for keypoints.
            %   Not set by default.
            % * __Keypoints__ If passed, then the method will use the provided
            %   vector of keypoints instead of detecting them, and the
            %   algorithm just computes their descriptors.
            %
            % See also: cv.BRISK.detect, cv.BRISK.compute
            %
            [keypoints, descriptors] = BRISK_(this.id, 'detectAndCompute', img, varargin{:});
        end
    end

end


% Map the numerical elements in the vector "v" onto the variables "s" which can
% be of any type. The number of numerical elements must match; on exit "v"
% should be empty. Non-numerical entries are just copied. See also unwrap2vec.m.

function [s v] = rewrap(s, v)

if isnumeric(s)
  if numel(v) < numel(s)
    error('The vector for conversion contains too few elements')
  end
  s = reshape(v(1:numel(s)), size(s));            % numeric values are reshaped
  v = v(numel(s)+1:end);                        % remaining arguments passed on
elseif isstruct(s)
  [s p] = orderfields(s); p(p) = 1:numel(p);      % alphabetize, store ordering
  [t v] = rewrap(struct2cell(s), v);                 % convert to cell, recurse
  s = orderfields(cell2struct(t,fieldnames(s),1),p);  % conv to struct, reorder
elseif iscell(s)
  for i = 1:numel(s)             % cell array elements are handled sequentially
    [s{i} v] = rewrap(s{i}, v);
  end
end                                             % other types are not processed


function tokens = get_tokens(string, delimiter)
% GET_TOKENS	To extract all tokens from a string even if a token is null.
%
% Description:	GET_TOKENS extract all tokens from a string even if one or
%		more tokens are null.  It is a replacement to iteratively calling the
%		builtin function 'strtok.m' because it did not output null tokens as
%		would be normally expected.  Note that if there are two adjacent
%		delimiters then an empty token would be output representing the token
%		that could have been present between the delimiters.
%
% Usage:	tokens = get_tokens(string, delimiter)
%
% Input:
%  string: a string from which to extract tokens.
%  delimiter:	a string containing one or more delimiters. The default
%    delimiters are whitespace characters (i.e. the ASCII codes for TAB,
%    LF, VT, FF, CR and space). Note that each delimiter is assumed to be
%    a single character; so if the delimiter string has three characters,
%    each of the three characters is considered a delimiter.
%
% Output:
%		tokens: An cell array of strings; the tokens retrieved from the input
%			character array.
%
% Example:
%
%		>> s = 'what a great , day';
%
%  Note that the variable 's' is a string that uses two delimiters, a space
%  and a comma.
%
%		>> get_tokens(s, ' ,')
%
%		ans =
%
%       'what'
%       'a'
%       'great'
%       ''
%       ''
%       'day'
%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   Copyright 2007  Jeff Jackson (Ocean Sciences, DFO Canada)
%   Creation Date: Oct. 20, 2006
%   Last Updated:  Jan. 22, 2008
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Check the input arguments before continuing.

% Check to see if no input arguments were supplied.  If this is the case,
% stop execution and output an error message to the user.
if nargin == 0
  error('MATLAB:get_tokens:NrInputArguments', 'No input arguments were supplied. At least one is expected.');
% Check to see if the only input argument is a cell array.  If it isn't
% then stop execution and output an error message to the user. Also set the
% DIM value since it was not supplied.
elseif nargin == 1
	% Check to see if the input is a string.  Output a message if the input
	% value is a not a character array, then exit the function.
	if ~ischar(string)
		error('MATLAB:get_tokens:InvalidInputArgument', 'The input string must be a valid character array.');
	end
	% Set the default delimiter value to whitespace characters.
	delimiter = [9:13 32];
elseif nargin == 2
	% Check to see if the two input arguments are character strings.  If
	% either check fails then stop execution and output an error message to
	% the user.
	if ~ischar(string)
		error('MATLAB:get_tokens:InvalidInputArgument', 'The first input variable must be a valid character array.');
	end
	if ~ischar(delimiter)
		error('MATLAB:get_tokens:InvalidInputArgument', 'The second input variable must be a valid character array.');
	end
elseif nargin > 2
	% Check to see if too many arguments were input.  If there were then exit
	% the function issuing a error message to the user.
	error('MATLAB:get_tokens:TooManyInputArguments', 'Too many input arguments were supplied.  The maximum permitted is two.');
end

%% If the input arguments are valid continue processing.

% Get the sizes of the input parameters.
string_size = size(string);
delim_size = size(delimiter);

% Check to see if the character array is vertical instead of horizontal. If
% it is then change it. Do the opposite for the delimiter array.
if string_size(1) > 1
	s = string';
else
	s = string;
end
if delim_size(1) > 1
	d = delimiter;
else
	d = delimiter';
end

% Get the array sizes.
if isempty(d)
   error('MATLAB:get_tokens:InputArguments', 'Delimiter is invalid.');
end

% Surround the delimiter string with square brackets so the regexprep
% function works correctly.
delimiter2 = ['[' delimiter ']'];

% Change all delimiters to the character value of the number 1.
s2 = regexprep(s,delimiter2,char(1));

% Extract all tokens from this updated string.
tokens = strread(s2,'%s','delimiter',char(1));

% Check to see if the last character in the input string is a delimiter. If
% it was then add a cell with an empty string to the end of the tokens cell
% array.
if strcmp(s2(end), char(1)) == 1
	tokens(end+1,1) = {''};
end


function y=add_CP(x,Ncp)
    y = [x(:,end-Ncp+1:end) x];
end


function [exchModel,unusedMets] = setExchangeBounds(model,mets,lb,ub,closeOthers,mediaOnly)
% setExchangeBounds
%   Define the exchange flux bounds for a given set of metabolites.
%
% Input:
%   model         a model structure
%   mets          a cell array of metabolite names (case insensitive) or
%                 metabolite IDs, or a vector of metabolite indices
%                 (opt, default all exchanged metabolites)
%   lb            lower bound of exchange flux. Can be either a vector of
%                 bounds corresponding to each of the provided metabolites,
%                 or a single value that will be applied to all.
%                 (opt, default to model.annotation.defaultLB if it exists,
%                 otherwise -1000)
%   ub            upper bound of exchange flux. Can be either a vector of
%                 bounds corresponding to each of the provided metabolites,
%                 or a single value that will be applied to all.
%                 (opt, default to model.annotation.defaultUB if it exists,
%                 otherwise 1000)
%   closeOthers   close exchange reactions for all other exchanged
%                 metabolites not present in the provided list. This will
%                 prevent IMPORT of the metabolites, but their EXPORT will
%                 not be modified.
%                 (opt, default true)
%   mediaOnly     only consider exchange reactions involving exchange to or
%                 from the extracellular (media) compartment. Reactions
%                 such as "sink" reactions that exchange metabolites
%                 directly with an intracellular compartment will therefore
%                 be ignored even though "getExchangeRxns" identifies such
%                 such reactions as exchange reactions.
%                 Note: The function will attempt to identify the
%                 extracellular compartment by the "compNames" field, and
%                 also requires the "metComps" field to be present,
%                 otherwise the mediaOnly flag will be ignored.
%                 (opt, default false)
%
% Output:
%   exchModel     a model structure with updated exchange flux bounds for
%                 the provided set of metabolites
%   unusedMets    metabolites provided by the user that were not used
%                 because they are not involved in any exchange reactions
%                 in the model
%
% NOTE: Exchange reactions involving more than one metabolite will be
% ignored.
%
% Usage: exchModel = setExchangeBounds(model,mets,lb,ub,closeOthers,mediaOnly);

% handle input arguments
if nargin < 2
    mets = [];
elseif ~islogical(mets) || ~isnumeric(mets)
    mets=convertCharArray(mets);
end

if nargin < 3 || isempty(lb)
    if isfield(model,'annotation') && isfield(model.annotation,'defaultLB')
        lb = model.annotation.defaultLB;
    else
        lb = -1000;
    end
end

if nargin < 4 || isempty(ub)
    if isfield(model,'annotation') && isfield(model.annotation,'defaultUB')
        ub = model.annotation.defaultUB;
    else
        ub = 1000;
    end
end

if nargin < 5 || isempty(closeOthers)
    closeOthers = true;
end

if nargin < 6
    mediaOnly = false;
elseif mediaOnly
    if ~all(isfield(model,{'compNames','metComps'}))
        error('mediaOnly option requires the "compNames" and "metComps" model fields.');
    end
end

% for models with an "unconstrained" field, generate a version of the model
% where all the unconstrained metabolites have stoichiometric coeffs set to
% zero, but remain in the model to avoid index changes
model_temp = model;
if isfield(model,'unconstrained')
    model_temp.S(model_temp.unconstrained == 1,:) = 0;
end

% find exchange rxns, ignoring those involving more than one metabolite
[~,exchRxnInd] = getExchangeRxns(model);
exchRxnInd(sum(model_temp.S(:,exchRxnInd) ~= 0,1) > 1) = [];

% find all exchanged metabolites
exchMetInd = find(any(model_temp.S(:,exchRxnInd) ~= 0,2));

if ( mediaOnly )
    % ignore exchanged metabolites in non-extracellular compartments and
    % any exchange reactions involving these metabolites
    [~,extCompInd] = ismember('extracellular',lower(model.compNames));
    if extCompInd > 0
        ignoreMet = (model.metComps(exchMetInd) ~= extCompInd);
    else
        error('Could not find any compartments named "extracellular".');
    end
    ignoreRxn = any(model.S(exchMetInd(ignoreMet),exchRxnInd) ~= 0,1);
    exchMetInd(ignoreMet) = [];
    exchRxnInd(ignoreRxn) = [];
end

% Check that all exchange reactions are formulated in the same direction.
% If not, this means that negative flux indicates import for some exchange
% reactions, but indicates export for others. Therefore, the LB and UB
% would need to be specified differently depending on the exchange reaction
% direction, which is error-prone.
if all(all(model.S(exchMetInd,exchRxnInd) <= 0))
    importDir = 'backward';
elseif all(all(model.S(exchMetInd,exchRxnInd) >= 0))
    importDir = 'forward';
else
    fprintf('WARNING: Some exchange reactions differ in direction, and therefore have opposite meanings of LB and UB.\n');
    if closeOthers
        fprintf('         Therefore, the "closeOthers" option will be set to FALSE.\n');
    end
    closeOthers = false;
end

% prepare exchanged metabolites and bounds
if ~isempty(mets)

    % prepare lb and ub variables
    if numel(lb) == 1
        lb = lb*ones(size(mets));
    elseif numel(lb) ~= numel(mets)
        error('lb must be a single value or a vector of equal length as mets');
    end
    if numel(ub) == 1
        ub = ub*ones(size(mets));
    elseif numel(ub) ~= numel(mets)
        error('ub must be a single value or a vector of equal length as mets');
    end

    % map provided mets to exchanged metabolites
    if isnumeric(mets)
        % mets are provided as indices
        [isExch,metInd] = ismember(mets,exchMetInd);
    elseif sum(ismember(lower(mets),lower(model.metNames))) > sum(ismember(mets,model.mets))
        % assume that mets are provided as names
        [isExch,metInd] = ismember(lower(mets),lower(model.metNames(exchMetInd)));
    else
        % assume that mets are provided as met IDs
        [isExch,metInd] = ismember(mets,model.mets(exchMetInd));
    end

    % get exchanged met indices and determine unused (non-exchanged) mets
    unusedMets = mets(~isExch);
    exchMetInd = exchMetInd(metInd(isExch));

    % update bound vectors
    lb = lb(isExch);
    ub = ub(isExch);

else
    % if no mets were provided, use all exchanged mets
    if numel(lb) > 1 || numel(ub) > 1
        error('Only one upper and one lower bound may be provide if metabolites are not specified.');
    else
        lb = lb*ones(size(exchMetInd));
        ub = ub*ones(size(exchMetInd));
    end
    unusedMets = {};
end

% check that at least one exchanged metabolite matches
if isempty(exchMetInd)
    fprintf('None of the provided metabolites were found in any exchange reactions.\n');
    exchModel = model;
    return
end

% determine which metabolite is exchanged in each exchange reaction
[metInd,rxnInd] = find(model_temp.S(exchMetInd,exchRxnInd) ~= 0);

% check for any metabolites that are exchanged in more than one reaction
[tbl,i,~] = unique(metInd,'first');
repeatedInds = find(not(ismember(1:numel(tbl),i)));
multiMetInd = exchMetInd(metInd(repeatedInds));
if ~isempty(multiMetInd)
    fprintf('WARNING: The following metabolites are involved in more than one exchange reaction:\n');
    fprintf('\t%s\n',model.metNames{multiMetInd(1:min(numel(multiMetInd),10))});
    if numel(multiMetInd) > 10
        fprintf('\t... and %u more.\n',numel(multiMetInd)-10);
    end
end

% set exchange reaction bounds
model = setParam(model,'lb',exchRxnInd(rxnInd),lb(metInd));
model = setParam(model,'ub',exchRxnInd(rxnInd),ub(metInd));

if closeOthers
    % constrain import of all other exchange reactions to zero
    constrainInd = setdiff(exchRxnInd,exchRxnInd(rxnInd));
    if strcmp(importDir,'backward')
        model = setParam(model,'lb',constrainInd,0);
    else
        model = setParam(model,'ub',constrainInd,0);
    end
end

% assign output model
exchModel = model;


function decomp = SFC_3D(path, obs, boundary)
    % Initialize MultipleSegments
	local_bbox = boundary; offset_x = 0;
    decomp = MultipleSegments(local_bbox);
    decomp.set_obs(obs);
    decomp.dilate(path, offset_x);
end


function amplitudes = GetSpikeAmplitudes(units,varargin)

%GetSpikeAmplitudes - Get spike amplitudes.
%
%  USAGE
%
%    amplitudes = GetSpikeAmplitudes(units,<options>)
%
%    units          list of [electrode group,cluster] pairs
%                   special conventions:
%                     cluster = -1   all clusters except artefacts and MUA
%                     cluster = -2   all clusters except artefacts
%                     cluster = -3   all clusters
%                   (artefacts are assumed to be in cluster 0, and MUA in 1)
%    <options>      optional list of property-value pairs (see table below)
%
%    =========================================================================
%     Properties    Values
%    -------------------------------------------------------------------------
%     'restrict'    list of time intervals to read from file
%    =========================================================================
%
%  SEE
%
%    See also GetSpikeTimes, GetSpikeWaveforms.

% Copyright (C) 2004-2013 by Michaël Zugaro
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 3 of the License, or
% (at your option) any later version.

global DATA;
if isempty(DATA),
	error('No session defined (did you forget to call SetCurrentSession? Type ''help Data'' for details).');
end

% Default values
intervals = [];

if nargin < 1,
	error('Incorrect number of parameters (type ''help GetSpikeAmplitudes'' for details).');
end

if ~isimatrix(units,'>=-3') || size(units,2) ~= 2,
	error('Incorrect unit list (type ''help GetSpikeAmplitudes'' for details).');
end

% Parse parameter list
for i = 1:2:length(varargin),
	if ~ischar(varargin{i}),
		error(['Parameter ' num2str(i+1) ' is not a property (type ''help GetSpikeAmplitudes'' for details).']);
	end
	switch(lower(varargin{i})),
		case 'restrict',
		intervals = varargin{i+1};
		if ~isdmatrix(intervals) || size(intervals,2) ~= 2,
			error('Incorrect value for property ''restrict'' (type ''help GetSpikeAmplitudes'' for details).');
		end
		otherwise,
		error(['Unknown property ''' num2str(varargin{i}) ''' (type ''help GetSpikeAmplitudes'' for details).']);
	end
end

groups = unique(units(:,1));

% Check for incompatible list items
for i = 1:length(groups),
	group = groups(i);
	clusters = units(units(:,1)==group,2);
	if	(ismember(-1,clusters) && ~all(clusters==-1)) || (ismember(-2,clusters) && ~all(clusters==-2)) || (ismember(-3,clusters) && ~all(clusters==-3)),
		error('Incompatible list items (type ''help GetSpikeAmplitudes'' for details).');
	end
end

amplitudes = [];
for i = 1:length(groups),

	% Clusters for this group
	group = groups(i);
	clusters = units(units(:,1)==group,2);

	% Load all waveforms for this group
	filename = [DATA.session.path '/' DATA.session.basename '.spk.' int2str(group)];
	nChannels = length(DATA.spikeGroups.groups{group});
	nSamplesPerWaveform = DATA.spikeGroups.nSamples(group);
	peak = DATA.spikeGroups.peakSamples(group);
	a = LoadSpikeAmplitudes(filename,nChannels,nSamplesPerWaveform,peak,DATA.rates.wideband);

	% Select appropriate clusters
	if ismember(-1,clusters),
		keep = a(:,3) ~= 0 & a(:,3) ~= 1;
	elseif ismember(-2,clusters),
		keep = a(:,3) ~= 0;
	elseif ismember(-3,clusters),
		keep = logical(ones(size(a,1),1));
	else
		keep = ismember(a(:,3),clusters);
	end
	a = a(keep,:);

	% Select timeframes
	if ~isempty(intervals),
		a = Restrict(a,intervals);
	end

	% Add to growing list
	amplitudes = [amplitudes;a];

end

% Sort list by time
amplitudes = sortrows(amplitudes);


function [hFig, iDS, iFig] = view_statcluster( StatFile, DisplayMode, Modality, hFig )
% VIEW_STATCLUSTER: Display the significant clusters in cluster-based stat file.
%
% USAGE: [hFig, iDS, iFig] = view_statcluster(StatFile, DisplayMode=[], Modality=[], hFig=[])
%
% INPUT:
%     - StatFile    : Relative path to stat file to visualize
%     - DisplayMode : {'clustindex_time', 'clustsize_time', 'longest'}
%     - hFig        : If defined, display file in existing figure
%
% OUTPUT :
%     - hFig : Matlab handle to the figure that was created or updated
%     - iDS  : DataSet index in the GlobalData variable
%     - iFig : Indice of returned figure in the GlobalData(iDS).Figure array

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

global GlobalData;

% ===== READ INPUTS =====
if (nargin < 4) || isempty(hFig)
    hFig = [];
end
if (nargin < 3) || isempty(Modality)
    Modality = [];
end
if (nargin < 2) || isempty(DisplayMode)
    DisplayMode = [];
end
iDS = [];
iFig = [];

% ===== LOAD DATA =====
FileType = file_gettype(StatFile);
switch (FileType)
    case 'pdata'
        % Load data file
        iDS = bst_memory('LoadDataFile', StatFile);
        if isempty(iDS)
            return;
        end
        bst_memory('LoadRecordingsMatrix', iDS);
        % Get clusters
        StatClusters = GlobalData.DataSet(iDS).Measures.StatClusters;
        % Row names = channel names
        RowNames = {GlobalData.DataSet(iDS).Channel.Name};
        nRows = length(RowNames);
        % Default display
        if isempty(DisplayMode)
            DisplayMode = 'clustindex_time';
        end
        FreqLabels = [];

    case 'presults'
        % Load results file
        [iDS, iRes] = bst_memory('LoadResultsFileFull', StatFile);
        if isempty(iDS)
            return;
        end
        % Get clusters
        StatClusters = GlobalData.DataSet(iDS).Results(iRes).StatClusters;
        nRows = size(GlobalData.DataSet(iDS).Results(iRes).ImageGridAmp,1);
        RowNames = 1:nRows;
        % Default display
        if isempty(DisplayMode)
            DisplayMode = 'clustsize_time';
        end
        FreqLabels = [];

    case 'ptimefreq'
        % Load timefreq file
        [iDS, iTf] = bst_memory('LoadTimefreqFile', StatFile);
        if isempty(iDS)
            return;
        end
        % Get clusters
        StatClusters = GlobalData.DataSet(iDS).Timefreq(iTf).StatClusters;
        RowNames     = GlobalData.DataSet(iDS).Timefreq(iTf).RowNames;
        nRows = length(RowNames);
        % Default display
        if isempty(DisplayMode)
            DisplayMode = 'clustsize_time';
        end
        FreqLabels = panel_freq('FormatFreqLabels', GlobalData.DataSet(iDS).Timefreq(iTf).Freqs);

    case 'pmatrix'
        % Load matrix file
        [iDS, iMat] = bst_memory('LoadMatrixFile', StatFile);
        if isempty(iDS)
            return;
        end
        % Get clusters
        StatClusters = GlobalData.DataSet(iDS).Matrix(iMat).StatClusters;
        RowNames     = GlobalData.DataSet(iDS).Matrix(iMat).Description;
        nRows = length(RowNames);
        % Default display
        if isempty(DisplayMode)
            DisplayMode = 'clustindex_time';
        end
        FreqLabels = [];

    otherwise
        error('Unsupported file type.');
end
% No clusters available
if isempty(StatClusters)
    error(['No cluster information available from this file:' StatFile]);
end
% Get time vector
Time = bst_memory('GetTimeVector', iDS);

% ===== THRESHOLD CLUSTER MAPS =====
% Get significant clusters
[sClusters, PosClust, NegClust] = panel_stat('GetSignificantClusters', StatClusters);
% Set all the values that are not is a signficant cluster to zero
if isempty(PosClust)
    StatClusters.posclusterslabelmat = zeros(nRows, length(Time));
else
    StatClusters.posclusterslabelmat(~ismember(StatClusters.posclusterslabelmat, [PosClust.ind])) = 0;
end
if isempty(NegClust)
    StatClusters.negclusterslabelmat = zeros(nRows, length(Time));
else
    StatClusters.negclusterslabelmat(~ismember(StatClusters.negclusterslabelmat, [NegClust.ind])) = 0;
end

% ===== BUILD CLUSTER IMAGE =====
% Switch display mode
switch lower(DisplayMode)
    case 'clustindex_time'
        % Combine the two maps into one
        ClusterMap = StatClusters.posclusterslabelmat - StatClusters.negclusterslabelmat;
        % Apply function to map cluster indices with colors in the same way as the panel Stat
        clustPos = ClusterMap(ClusterMap > 0);
        ClusterMap(ClusterMap > 0) = max(clustPos(:)) - clustPos + 1;
        clustNeg = abs(ClusterMap(ClusterMap < 0));
        ClusterMap(ClusterMap < 0) = -(max(clustNeg(:)) - clustNeg + 1);
        % Replace non-stat values with NaN
        ClusterMap(ClusterMap == 0) = NaN;
        % Create the labels
        Labels = cell(1,4);
        Labels{1} = RowNames;
        Labels{2} = [];
        Labels{3} = Time;
        Labels{4} = FreqLabels;
        % Create the image volume: [N1 x N2 x Ntime x Nfreq]
        M = reshape(ClusterMap, size(ClusterMap,1), 1, size(ClusterMap,2), size(ClusterMap,3));
        % Show the image
        [hFig, iDS, iFig] = view_image_reg(M, Labels, [1,3], {'Signals','Time (s)'}, StatFile, hFig, 'cluster', 1, '$freq');
        % Configure the colormap to show positive and negative values
        bst_colormaps('SetColormapAbsolute', 'Image', 0);

    case 'clustsize_time'
        % For each cluster, compute the number of channels/sources involved at each time point
        if ~isempty(sClusters)
            F = zeros(length(sClusters), length(Time));
            LinesColor = cell(length(sClusters), 1);
            LinesLabels = cell(length(sClusters), 1);
            for i = 1:length(sClusters)
                F(i,:) = sum(sum(double(sClusters(i).mask), 1), 3);
                LinesColor{i} = sClusters(i).color;
                LinesLabels{i} = sprintf('p=%1.5f, c=%d, s=%d', sClusters(i).prob, round(sClusters(i).clusterstat), sClusters(i).clustsize);
            end
        else
            F = zeros(1, length(Time));
            LinesColor{1} = [0 0 0];
            LinesLabels{1} = 'Empty';
        end
        % Display signals
        [hFig, iDS, iFig] = view_timeseries_matrix(StatFile, F, [], 'Clusters', 'Cluster size', LinesLabels, LinesColor, hFig, []);

    % Topography or source map with longest values for each cluster
    case 'longest'
        % Plot topography/source map
        switch (FileType)
            case 'pdata'
                % For each cluster, compute the number of significant time points for each channel/source
                if ~isempty(sClusters)
                    F = zeros(nRows, 1);
                    for i = 1:length(sClusters)
                        [lenMax, iRow] = max(sum(sClusters(i).mask,2));
                        F(iRow,:) = lenMax;
                    end
                else
                    F = zeros(nRows, 1);
                end

                % Get channels from selected modality
                iChannels = channel_find(GlobalData.DataSet(iDS).Channel, Modality);
                % Display topography
                [hFig, iDS, iFig] = view_topography(StatFile, Modality, '2DSensorCap', F(iChannels,:), 0, 'NewFigure', []);
                % Set colormap
                bst_colormaps('ConfigureColorbar', hFig, 'timefreq', 'samples', 'samples');
                ColormapInfo = getappdata(hFig, 'Colormap');
                ColormapInfo.Type = 'timefreq';
                ColormapInfo.AllTypes = {'timefreq'};
                ColormapInfo.DisplayUnits = 'samples';
                setappdata(hFig, 'Colormap', ColormapInfo);

            case 'presults'
                % Display surface
                [hFig, iDS, iFig] = view_surface_data(GlobalData.DataSet(iDS).Results(iRes).SurfaceFile, StatFile, [], hFig);
                % Get axes object
                hAxes = findobj(hFig, '-depth', 1, 'Tag', 'Axes3D');
                % Get surface in memory
                % sSurf = bst_memory('GetSurface', GlobalData.DataSet(iDS).Results(iRes).SurfaceFile);
                % Get displayed surface
                hPatch = findobj(hAxes, '-depth', 1, 'Tag', 'AnatSurface');
                Vertices = get(hPatch, 'Vertices');
                % Remove previous markers
                delete(findobj(hAxes, '-depth', 1, 'Tag', 'ptClusterMax'));
                % Search maximum duration for each cluster
                for i = 1:length(sClusters)
                    % Get maximum
                    [lenMax, iRow] = max(sum(sClusters(i).mask,2));
                    if (lenMax == 0)
                        continue;
                    end
                    % Get point coordinates
                    pt = Vertices(iRow,:);
                    % Mark new point
                    line(pt(1)*1.005, pt(2)*1.005, pt(3)*1.005, ...
                         'MarkerFaceColor', sClusters(i).color, ...
                         'MarkerEdgeColor', sClusters(i).color, ...
                         'Marker',          '+',  ...
                         'MarkerSize',      12, ...
                         'LineWidth',       2, ...
                         'Parent',          hAxes, ...
                         'Tag',             'ptClusterMax');
                end

            otherwise
                error('Not supported.');
        end
    otherwise
        error(['Invalid display mode: "' DisplayMode '"']);
end

% Add tag in the figure appdata
StatInfo.StatFile    = StatFile;
StatInfo.DisplayMode = DisplayMode;
setappdata(hFig, 'StatInfo', StatInfo);

% Show "stat" tab
gui_brainstorm('ShowToolTab', 'Stat');
% Update figure selection
bst_figures('SetCurrentFigure', hFig, '2D');

% Save reload call
ReloadCall = {'view_statcluster', StatFile, DisplayMode, Modality, hFig};
setappdata(hFig, 'ReloadCall', ReloadCall);

% Stat panel: reload clusters list
panel_stat('CurrentFigureChanged_Callback', hFig);

% Last update for topography
if strcmpi(DisplayMode, 'longest')
    if strcmpi(FileType, 'pdata')
        figure_topo('ColormapChangedCallback', iDS, iFig);
        figure_topo('CurrentTimeChangedCallback', iDS, iFig);
%     elseif strcmpi(FileType, 'presults')
%         panel_surface('UpdateSurfaceData', hFig, 1);
    end
end


function r = isequal_weak(a,b)
% Compare 2 values for equality under relaxed conditions.
% Equal = isequal_weak(A,B)
%
% In:
%   A : first value
%
%   B : second value
%
% Out:
%   Equal : whether the two values are weakly equal, ignoring:
%           * NaNs
%           * contents of Java objects
%           * variables accessible to anonymous functions that are not referenced in the code
%           * new-style classes that have the same struct() representation
%
% Examples:
%   % test two data sets for equivalence
%   isequal_weak(EEG1,EEG2)
%
% See also:
%   isequal, isequalwithequalnans
%
%                                Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                2011-02-19

% Copyright (C) Christian Kothe, SCCN, 2011, christian@sccn.ucsd.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

if isequal(a,b)
    r = true;
else
    ca = class(a);
    if ~strcmp(ca,class(b))
        r = false;
        % unequal class
        return;
    else
        % same class; check in detail
        switch ca
            case {'double','char','logical'}
                % common non-recursive data structure
                r = isequalwithequalnans(a,b);
            case 'cell'
                % recurse into cells
                if ~isequal(size(a),size(b))
                    r = false;
                else
                    for k=1:numel(a)
                        if ~isequal_weak(a{k},b{k})
                            r = false;
                            return;
                        end
                    end
                    r = true;
                end
            case 'struct'
                % recurse into structs
                if ~isequal(size(a),size(b)) || ~isequal(fieldnames(a),fieldnames(b))
                    r = false;
                else
                    r = isequal_weak(struct2cell(a),struct2cell(b));
                end
            case 'function_handle'
                if isequal(a,b)
                    r = true;
                else
                    % functions are considered different by isequal...
                    sa = char(a);
                    if strcmp(sa,char(b)) && sa(1) == '@'
                        % but are both anonymous functions with identical code:
                        fa = functions(a);
                        fb = functions(b);
                        % equality is determined by referenced variables
                        if ~isempty(fa.workspace) && ~isempty(fb.workspace)
                            r = isequal_weak(fa.workspace{1},fb.workspace{1});
                        elseif isempty(fa.workspace) && isempty(fb.workspace)
                            r = true;
                        elseif (isempty(fa.workspace) && isempty(fieldnames(fb.workspace{1}))) || (isempty(fb.workspace) && isempty(fieldnames(fa.workspace{1})))
                            r = true;
                        else
                            r = false;
                        end
                    else
                        r = false;
                    end
                end
            otherwise
                % misc class
                if isnumeric(a)
                    % misc number format
                    r = isequalwithequalnans(a,b);
                elseif isobject(a)
                    % MATLAB objects with same class: compare as structs
                    r = isequal_weak(struct(a),struct(b));
                elseif isjava(a)
                    % Java objects with same class: ignore contents
                    r = true;
                else
                    try
                        % new-style classes with the same class?
                        r = isequal_weak(struct(a),struct(b));
                    catch
                        % some unknown data type
                        r = isequalwithequalnans(a,b);
                    end
                end
        end
    end
end


function display(this)
%DISPLAY   Displays parameters of HS optical flow algorithm
%
%   This is a member function of the class 'hs_optical_flow'.

%   Author: Deqing Sun, Department of Computer Science, Brown University
%   Contact: dqsun@cs.brown.edu
%   $Date: 2007-11-30 $
%   $Revision: $
%
% Copyright 2007-2010, Brown University, Providence, RI. USA
%
%                          All Rights Reserved
%
% All commercial use of this software, whether direct or indirect, is
% strictly prohibited including, without limitation, incorporation into in
% a commercial product, use in a commercial service, or production of other
% artifacts for commercial purposes.
%
% Permission to use, copy, modify, and distribute this software and its
% documentation for research purposes is hereby granted without fee,
% provided that the above copyright notice appears in all copies and that
% both that copyright notice and this permission notice appear in
% supporting documentation, and that the name of the author and Brown
% University not be used in advertising or publicity pertaining to
% distribution of the software without specific, written prior permission.
%
% For commercial uses contact the Technology Venture Office of Brown University
%
% THE AUTHOR AND BROWN UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO
% THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
% FITNESS FOR ANY PARTICULAR PURPOSE.  IN NO EVENT SHALL THE AUTHOR OR
% BROWN UNIVERSITY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
% DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
% PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
% ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
% THIS SOFTWARE.

  disp(sprintf('Image sequence (size):          %s', ...
               mat2str(size(this.images))));
  disp(sprintf('Spatial term weighting:         %s', ...
               mat2str(this.lambda)));
  disp(sprintf('Linear solver:                  %s', ...
               this.solver));
  disp(sprintf('# of pyramid levels:            %d', ...
               this.pyramid_levels));
  disp(sprintf('Spacing of pyramid levels:      %d', ...
               this.pyramid_spacing));
  disp(sprintf('Max. # of iterations:           %d', ...
               this.max_iters));
  disp(sprintf('Limit flow updates              %d', ...
               this.limit_update));