function mesh_write_fs_overlay(p)

% mesh_write_fs_overlay - Save mesh CData to FreeSurfer overlay file
%
% USEAGE: mesh_write_fs_overlay(p)
%
% Write a binary overlay file (*.w) for each mesh in p.mesh.data.
% If any cells of p.mesh.data.meshtype are empty, they are skipped.
%
% This function outputs an *.w overlay file from the
% vertex scalar data contained in p.mesh.data.Cdata - if it
% contains a timeseries, the output values are taken from
% the column specified in p.mesh.samplePoint.
%
% All output is handled by fs_write_wfile.
%
% See the FreeSurfer website at http://surfer.nmr.mgh.harvard.edu/
% for more information.
%

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

% Licence:  GNU GPL, no implied or express warranties
% History:  10/2002, Darren.Weber_at_radiology.ucsf.edu
%           01/2003, Darren.Weber_at_radiology.ucsf.edu
%                    now using fs_write_surf and fs_write_wfile
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

fprintf('\nMESH_WRITE_FS_OVERLAY...\n');

if ~exist('p','var'),
    error('...no input p struct.\n');
elseif isempty(p),
    error('...input p struct is empty.\n');
elseif isempty(p.mesh.data),
    error('...input p struct has no mesh data.\n');
end

[path,name,ext] = fileparts(strcat(p.mesh.path,filesep,p.mesh.file));
file = fullfile(path,[name ext]);

fprintf('...writing FreeSurfer overlays to:\n\t%s\n',path);

tic;

Meshes = p.mesh.data.meshtype;

[path,name,ext] = fileparts(file);

for i=1:size(Meshes,2),

    if Meshes{i},

        % check for mesh Cdata
        if size(p.mesh.data.Cdata,2) >= i,
            if ~isempty(p.mesh.data.Cdata{i}),
                if size(p.mesh.data.Cdata{i},2) > 1,
                    % Obtain the Cdata at the selected time point
                    w = p.mesh.data.Cdata{i}(:,p.mesh.samplePoint);
                else
                    w = p.mesh.data.Cdata{i};
                end

                outputExt = [ext, '.w'];
                outputName = strcat(name,'.',Meshes{i});
                outputFile = fullfile(path,[outputName outputExt]);

                fprintf('...writing overlay: %s\n',[outputName outputExt]);
                fs_write_wfile(outputFile,w);
            else
                msg = sprintf('\np.mesh.data.Cdata{%d} is empty\n',i);
                warning(msg);
            end
        else
            msg = sprintf('\nno p.mesh.data.Cdata{%d}\n',i);
            warning(msg);
        end
    end
end

t=toc; fprintf('...done (%5.2f sec).\n\n',t);

return


function varargout = particleinB_E_gui(varargin)
% PARTICLEINB_E_GUI M-file for particleinB_E_gui.fig
%      PARTICLEINB_E_GUI, by itself, creates a new PARTICLEINB_E_GUI or raises the existing
%      singleton*.
%
%      H = PARTICLEINB_E_GUI returns the handle to a new PARTICLEINB_E_GUI or the handle to
%      the existing singleton*.
%
%      PARTICLEINB_E_GUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in PARTICLEINB_E_GUI.M with the given input arguments.
%
%      PARTICLEINB_E_GUI('Property','Value',...) creates a new PARTICLEINB_E_GUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before particleinB_E_gui_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to particleinB_E_gui_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 particleinB_E_gui

% Last Modified by GUIDE v2.5 17-Jun-2011 05:04:25

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @particleinB_E_gui_OpeningFcn, ...
                   'gui_OutputFcn',  @particleinB_E_gui_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 particleinB_E_gui is made visible.
function particleinB_E_gui_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 particleinB_E_gui (see VARARGIN)

% Choose default command line output for particleinB_E_gui
handles.output = hObject;

%close all;
%clear all;
clc;

set(handles.vx,'Value',0);
set(handles.vy,'Value',0);
set(handles.vz,'Value',0);

set(handles.x,'Value',-10);
set(handles.y,'Value',0);
set(handles.z,'Value',0);

set(handles.Bx,'Value',0);
set(handles.By,'Value',-6);
set(handles.Bz,'Value',0);
set(handles.Ex,'Value',0)
set(handles.Ey,'Value',0)
set(handles.Ez,'Value',2)

set(handles.q,'Value',1);
set(handles.m,'Value',5);

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes particleinB_E_gui wait for user response (see UIRESUME)
% uiwait(handles.figure1);

% --- Outputs from this function are returned to the command line.
function varargout = particleinB_E_gui_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 start.
function start_Callback(hObject, eventdata, handles)
% hObject    handle to start (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
set(handles.stop,'String','Stop!!');
guidata(hObject, handles);

v0 = [get(handles.vx,'Value'), get(handles.vy,'Value'), get(handles.vz,'Value') ]';   %initial velocity
B = [get(handles.Bx,'Value'), get(handles.By,'Value'), get(handles.Bz,'Value') ]';                                                %magnitude of B
E = [get(handles.Ex,'Value'), get(handles.Ey,'Value'), get(handles.Ez,'Value') ]';                                                %magnitude of B
m = get(handles.m,'Value');                                                        % mass
q = get(handles.q,'Value');                                                         % charge on particle
r0 = [get(handles.x,'Value'), get(handles.y,'Value'), get(handles.z,'Value') ]';    % initial position of particle
tspan = [0 70];

%to show B's direction
[x_q,y_q] = meshgrid(-15:12:15,-15:12:15);
z_q=10*ones(size(x_q));

u_q=B(1)*ones(size(x_q));
v_q=B(2)*ones(size(x_q));
w_q=B(3)*ones(size(x_q));
quiver3(x_q,y_q,z_q,u_q,v_q,w_q);
hold all;

% TO show electric field lines
z_q=-10*ones(size(x_q));

u_q=E(1)*ones(size(x_q));
v_q=E(2)*ones(size(x_q));
w_q=E(3)*ones(size(x_q));
quiver3(x_q,y_q,z_q,u_q,v_q,w_q);

legend('B','E');

% To draw axis and all
a_a = -15:0.1:15;
z_a = zeros(size(a_a));
plot3(a_a,z_a,z_a,'k','LineWidth',2);
plot3(z_a,a_a,z_a,'k','LineWidth',2);
plot3(z_a,z_a,a_a,'k','LineWidth',2);

% To set axis limits
%xlim([-15 15]);
%ylim([-15 15]);
%zlim([-15 15])

xlabel ('x axis');
ylabel ('y axis');
zlabel ('z axis');
title ('Particle in a magnetic field');

rotate3d(handles.axes,'on');

plot3(r0(1),r0(2),r0(3),'*m','MarkerSize',9,'LineWidth',2);

y0 = [r0; v0];
f = @(t,y) [y(4:6); (q/m)*cross(y(4:6),B)+E];
[t,y] = ode23t(f,tspan,y0);

%To show animation
for n=1:length(y)
    plot3(y(n,1),y(n,2),y(n,3),'--.r');
    pause(0.00001);

    z_z = get(handles.stop,'String');
    if z_z == 'Stoped'
        break;
    end

end

guidata(hObject, handles);

% --- Executes on slider movement.
function B_Callback(hObject, eventdata, handles)
% hObject    handle to B (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider

% --- Executes during object creation, after setting all properties.
function B_CreateFcn(hObject, eventdata, handles)
% hObject    handle to B (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function m_Callback(hObject, eventdata, handles)
% hObject    handle to m (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.m,'Value');
set(handles.m_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function m_CreateFcn(hObject, eventdata, handles)
% hObject    handle to m (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function q_Callback(hObject, eventdata, handles)
% hObject    handle to q (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.q,'Value');
set(handles.q_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function q_CreateFcn(hObject, eventdata, handles)
% hObject    handle to q (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

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

% --- Executes on button press in stop.
function stop_Callback(hObject, eventdata, handles)
% hObject    handle to stop (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
set(handles.stop,'String','Stoped');
guidata(hObject, handles);

% --- Executes on slider movement.
function x_Callback(hObject, eventdata, handles)
% hObject    handle to x (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.x,'Value');
set(handles.x_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function x_CreateFcn(hObject, eventdata, handles)
% hObject    handle to x (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function y_Callback(hObject, eventdata, handles)
% hObject    handle to y (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.y,'Value');
set(handles.y_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function y_CreateFcn(hObject, eventdata, handles)
% hObject    handle to y (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function z_Callback(hObject, eventdata, handles)
% hObject    handle to z (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.z,'Value');
set(handles.z_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function z_CreateFcn(hObject, eventdata, handles)
% hObject    handle to z (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function vx_Callback(hObject, eventdata, handles)
% hObject    handle to vx (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.vx,'Value');
set(handles.vx_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function vx_CreateFcn(hObject, eventdata, handles)
% hObject    handle to vx (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function vy_Callback(hObject, eventdata, handles)
% hObject    handle to vy (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.vy,'Value');
set(handles.vy_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function vy_CreateFcn(hObject, eventdata, handles)
% hObject    handle to vy (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function vz_Callback(hObject, eventdata, handles)
% hObject    handle to vz (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.vz,'Value');
set(handles.vz_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function vz_CreateFcn(hObject, eventdata, handles)
% hObject    handle to vz (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function E_Callback(hObject, eventdata, handles)
% hObject    handle to E (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider

% --- Executes during object creation, after setting all properties.
function E_CreateFcn(hObject, eventdata, handles)
% hObject    handle to E (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function Ex_Callback(hObject, eventdata, handles)
% hObject    handle to Ex (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.Ex,'Value');
set(handles.Ex_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function Ex_CreateFcn(hObject, eventdata, handles)
% hObject    handle to Ex (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function Ey_Callback(hObject, eventdata, handles)
% hObject    handle to Ey (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.Ey,'Value');
set(handles.Ey_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function Ey_CreateFcn(hObject, eventdata, handles)
% hObject    handle to Ey (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function Ez_Callback(hObject, eventdata, handles)
% hObject    handle to Ez (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.Ez,'Value');
set(handles.Ez_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function Ez_CreateFcn(hObject, eventdata, handles)
% hObject    handle to Ez (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function Bx_Callback(hObject, eventdata, handles)
% hObject    handle to Bx (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.Bx,'Value');
set(handles.Bx_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function Bx_CreateFcn(hObject, eventdata, handles)
% hObject    handle to Bx (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function By_Callback(hObject, eventdata, handles)
% hObject    handle to By (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.By,'Value');
set(handles.By_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function By_CreateFcn(hObject, eventdata, handles)
% hObject    handle to By (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function Bz_Callback(hObject, eventdata, handles)
% hObject    handle to Bz (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider
a = get (handles.Bz,'Value');
set(handles.Bz_text,'String',num2str(a));
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function Bz_CreateFcn(hObject, eventdata, handles)
% hObject    handle to Bz (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end


function tf = isfield2( S, fs, isinit )
% Similar to isfield but also test whether fields are initialized.
%
% A more comprehensive test of what fields are present [and optionally
% initialized] in a stuct S.  fs is either a single field name or a cell
% array of field names.  The presence of all fields in fs are tested for in
% S, tf is true iif all fs are present. Additionally, if isinit==1, then tf
% is true iff every field fs of every element of S is nonempty (test done
% using isempty).
%
% USAGE
%  tf = isfield2( S, fs, [isinit] )
%
% INPUTS
%  S        - struct array
%  fs       - cell of string name or string
%  isinit   - [0] if true additionally test if all fields are initialized
%
% OUTPUTS
%  tf      - true or false, depending on results of above tests
%
% EXAMPLE
%  isfield2( struct('a',1,'b',2), {'a','b'}, 1 )
%
% See also ISFIELD
%
% Piotr's Computer Vision Matlab Toolbox      Version 2.10
% Copyright 2014 Piotr Dollar.  [pdollar-at-gmail.com]
% Licensed under the Simplified BSD License [see external/bsd.txt]

tf = all( isfield(S,fs) );
if( ~tf || nargin<3 || ~isinit ); return; end

% now optionally check if fields are initialized
if( iscell(fs) )
  for i=1:length(fs)
    for j=1:numel(S)
      if( isempty(S(j).(fs{i})) ); tf=false; return; end;
    end;
  end;
else
  for j=1:numel(S)
    if( isempty(S(j).(fs)) ); tf=false; return; end;
  end;
end


function y = anyCones(K)

y = any(K.q) || any(K.e) || any(K.p) || any(K.s);


function q = uminus(q)
% overload unitary minus

q.a = -q.a;
q.b = -q.b;
q.c = -q.c;
q.d = -q.d;


function h = plotVectors(Y, varargin);
% Plot a matrix of amplitude vectors in a series of subplots.
%
% h = plotVectors(Y);
%
% Each column in Y is plotted in a separate subplot.
%
% If you enter additional input arguments, e.g.:
%
% h = plotVectors(X, Y, Z);
%
% where X, Y, and Z are all the same size, corresponding columns of each
% input will be plotted in the same subplot.
%
% ras, 12/2007.
if length(varargin) >= 1
	% check for additional data vectors
	try
		for n = 1:length(varargin)
			Y(:,:,n+1) = varargin{n};
		end
	catch
		size(Y)
		for n = 1:length(varargin)
			size(varargin{n})
		end
		error('Additional input vectors must be the same size.')
	end
end

% get color order for figure
co = plotVectors_colorOrder(size(Y, 3));

% open the figure
h(1) = figure('Color', 'w', 'Position', [100 100 600 500]);

N = size(Y, 2);
nrows = ceil( sqrt(N) );
ncols = ceil( N / nrows );

% want the position of the lower left-hand subplot,
% which is the only one that will have visible axes
lowerLeft = (nrows-1) * ncols + 1;

for n = 1:N
	h(n+1) = subplot(nrows, ncols, n);
	hold on

	for z = 1:size(Y, 3)
		plot(Y(:,n,z), 'LineWidth', 1);
	end

	axis tight
	set(gca, 'Box', 'off', 'TickDir', 'out');

	if n ~= lowerLeft
		axis off
	end

	setLineColors(co);
end

normAxes(h(2:end));

return
% /----------------------------------------------------------/ %

% /----------------------------------------------------------/ %
function co = plotVectors_colorOrder(N);
% create a nice color order for plotAmps (the default one isn't
% so great).

co = [0 0 0; ...
	  1 0 0; ...
	  0 0 1; ...
	  .5 .5 0; ...
	  0 .5 .5; ...
	  .4 .4 .4; ...
	  0 .6 0; ...
	  0 1 1; ...
	  1 0 1];

while size(co, 1) < N
	co = [co; co];
end

co = co(1:N,:);

return


function [TorF, vstr, rdate] = have_feature_e4st()
%HAVE_FEATURE_E4ST  Detect availability/version info for E4ST
%
%   Feature detection function implementing 'e4st' tag for HAVE_FEATURE
%   to detect availability/version of E4ST, the Engineering, Economic, and
%   Environmental Electricity Simulation Tool (https://e4st.com).
%
%   See also HAVE_FEATURE.

%   MATPOWER
%   Copyright (c) 2004-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://matpower.org for more info.

TorF = exist('e4st_ver', 'file') == 2;
if TorF
    v = e4st_ver('all');
    vstr = v.Version;
    rdate = v.Date;
else
    vstr = '';
    rdate = '';
end


function pink_noise_test ( )

%*****************************************************************************80
%
%% PINK_NOISE_TEST tests the PINK_NOISE library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    31 May 2010
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'PINK_NOISE_TEST:\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the PINK_NOISE library.\n' );

  pink_noise_test01 ( );
  pink_noise_test02 ( );
  pink_noise_test03 ( );
  pink_noise_test04 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'PINK_NOISE_TEST:\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


% Bundles submission data for sRGB denoising

% submission_folder Folder where denoised images reside

% Output is written to <submission_folder>/bundled/. Please submit
% the content of this folder.
%
% Author: Tobias Plötz, TU Darmstadt (tobias.ploetz@visinf.tu-darmstadt.de)
%
% This file is part of the implementation as described in the CVPR 2017 paper:
% Tobias Plötz and Stefan Roth, Benchmarking Denoising Algorithms with Real Photographs.
% Please see the file LICENSE.txt for the license governing this code.

function bundle_submission_srgb( submission_folder, para)

if nargin < 2
    out_folder = fullfile(submission_folder, 'bundled/');
else
    out_folder = [submission_folder, 'bundled' num2str(para) '/'];
end
mkdir(out_folder);

israw = false;
eval_version = '1.0';

for i=1:50
    Idenoised = cell(1,20);
    parfor b=1:20
        filename = sprintf('%04d_%02d.mat', i,b);
        s = load(fullfile(submission_folder, filename));

        Idenoised{b} = s.Idenoised_crop;
    end
    filename = sprintf('%04d.mat', i);
    save(fullfile(out_folder, filename), 'Idenoised', 'israw', 'eval_version', '-v7.3');
end
end


function varargout = process_opposite( varargin )
% PROCESS_OPPOSITE: Opposite values.

% @=============================================================================
% 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, 2010

eval(macro_method);
end

%% ===== GET DESCRIPTION =====
function sProcess = GetDescription() %#ok<DEFNU>
    % Description the process
    sProcess.Comment     = 'Opposite values';
    sProcess.FileTag     = 'opposite';
    sProcess.Category    = 'Filter';
    sProcess.SubGroup    = 'Pre-process';
    sProcess.Index       = 74;
    sProcess.Description = '';
    % Definition of the input accepted by this process
    sProcess.InputTypes  = {'data', 'results', 'timefreq', 'raw', 'matrix'};
    sProcess.OutputTypes = {'data', 'results', 'timefreq', 'raw', 'matrix'};
    sProcess.nInputs     = 1;
    sProcess.nMinFiles   = 1;
    % Default values for some options
    sProcess.processDim  = 2;    % Process time by time
    % === Sensor types
    sProcess.options.sensortypes.Comment = 'Sensor types or names (empty=all): ';
    sProcess.options.sensortypes.Type    = 'text';
    sProcess.options.sensortypes.Value   = 'MEG, EEG';
    sProcess.options.sensortypes.InputTypes = {'data', 'raw'};
end

%% ===== FORMAT COMMENT =====
function Comment = FormatComment(sProcess) %#ok<DEFNU>
    Comment = sProcess.Comment;
end

%% ===== RUN =====
function sInput = Run(sProcess, sInput) %#ok<DEFNU>
    % Opposite values
    sInput.A = -sInput.A;
end


classdef MapFeature < handle
    %MapFeature used to track and plot features on a map (works in 3d)
    %
    %   sample usage:
    %       load_fn = @get_earthquakes;
    %       save_fn = [];
    %       plot_defaults = struct('Tag','important_feature',...
    %            'DisplayName','importantFeature',...
    %            'LineWidth', 3.0,...
    %            'Color',[.1 .2 .5]);
    %
    %       f = MapFeature('feature', load_fn, save_fn, plot_defaults);
    %       ax = axes; % create new axes
    %       f.plot(ax);
    %
    %       % .. do something here that might change the axes limits or something
    %
    %       f.refreshPlot();
    %
    %
    %
    % lakes = ZG.features('lakes')
    %
    % % COMPARING PLOT and PLOTM in same figure
    % fig=figure;
    %
    % % PLOT FEATURE ON "NORMAL" PLOT AXES
    % % - SET UP THE AXES
    % ax1=subplot(1,2,1);
    % ylim(ax1,bounds2(ZG.primeCatalog.Y));
    % xlim(ax1,bounds2(ZG.primeCatalog.X));
    % title(ax1,'normal plot')
    %
    % % PLOT FEATURE ON "MAP" PLOT AXES
    % % - SET UP THE AXES
    % ax2=subplot(1,2,2);
    % ax2m=axesm('lambert','MapLatLimit',bounds2(ZG.primeCatalog.Latitude),...
    %  'MapLonLimit',bounds2(ZG.primeCatalog.Longitude));
    % setm(ax2m,'MLineLocation',.25, 'PLineLocation',.25); % degrees for grid lines
    % setm(ax2m,'Grid','on')
    % setm(ax2m,'MeridianLabel','on','ParallelLabel','on')
    % setm(ax2m,'PLabelLocation',.5,'MLabelLocation',.5)  % degrees for labeling
    % setm(ax2m,'LabelFormat','signed','LabelUnits','dms') % display as +7˚ 00' 00"
    % title(ax2m,'lambert plot')
    %
    % lakes.plot(ax2m) % plot into map
    % lakes.plot(ax1) % plot onto "normal" axes

    properties(Transient, Hidden)
        Loadfn function_handle = @do_nothing % used to load/import this feature's data
        Savefn function_handle = @do_nothing % used to save/export this feature's data
    end
    properties
        Name (1,:) char        % name of this feature
        PlottingDefaults struct  % properties used on this layer
        Value struct           % raw values to plot, as struct, class, or Table containing a "Longitude" and "Latitude" field
        ParentAxis matlab.graphics.axis.Axes % handle to a parent axis. assigned when this is plotted
        MenuToggle matlab.ui.container.Menu % handle to the uimenu used to show/hide this layer
        WasLoaded logical = false;
    end
    properties(Dependent)
        Handle              % handle to this layer
        Longitude           % vector of Longitudes [deg] (to be plotted on X)
        Latitude            % vector of Latitudes [deg] (to be plotted on Y)
        Depth               % vector of Depths [km] (to be plotted on -Z)
        Names
    end

    methods
        function obj= MapFeature(name, load_fn, save_fn, plot_defaults)
            % create a MapFeature
            % obj= MAPFEATURE(name, load_fn, save_fn, plot_defaults)

            assert(isfield(plot_defaults,'Tag'));
            obj.Name = name;
            if ~isempty(load_fn)
                obj.Loadfn = load_fn;
            end

            if ~isempty(save_fn)
                obj.Savefn = save_fn;
            end

            obj.PlottingDefaults = plot_defaults;
        end

        function obj=copyobj(orig,AX)
            % COPYOBJ copies a feature into a specified axes
            % feature.COPYOBJ(AX) where AX is the destination axes
            %
            % obj=feature.COPYOBJ(...) returns a handle to the copied Mapfeature.
            %
            % see also copyobj
            obj=MapFeature(orig.Name, orig.Loadfn, orig.Savefn, orig.PlottingDefaults);
            obj.Value=orig.Value;
            obj.WasLoaded=orig.WasLoaded;
            obj.plot(AX);
        end

        function h =get.Handle(obj)
            % get.HANDLE get the handle to this feature's layer
            % if this layer hasn't been plotted yet, or has been deleted, then
            % this returns []

            % make sure Parent Axis is still valid
            if ~isempty(obj.ParentAxis) && ~isvalid(obj.ParentAxis)
                obj.ParentAxis = [];
            end

            if ~isempty(obj.ParentAxis)
                h = findobj(obj.ParentAxis, 'Tag', obj.PlottingDefaults.Tag);
            else
                h=[];
                %error('This feature %s is not associated with a valid parent',obj.Name);
                % h = findobj(groot, 'Tag', obj.PlottingDefaults.Tag);
            end
        end

        function lons = get.Longitude(obj)
            lons = obj.Value.Longitude;
        end
        function lats = get.Latitude(obj)
            lats = obj.Value.Latitude;
        end
        function depths = get.Depth(obj)
            depths = obj.Value.Depth;
        end

        function names = get.Names(obj)
            try
                names = obj.Value.Names;
            catch ME
                names = {'no name'};
            end
        end

        function layer=plot(obj,ax)
            % plot this layer
            % will delete layer if it exists
            % note features will only plot the subset of features within the
            % currently visible axes
            %
            % see also refreshPlot

            assert(obj.WasLoaded,'load before plotting!')

            if ~exist('ax','var')
                ax = obj.ParentAxis;
            else
                obj.ParentAxis = ax;
            end

            if isempty(ax) || ~isvalid(ax)
                error('Feature "%s" ->plot has no associated axis',obj.Name);
            end

            if has_toolbox('Mapping Toolbox') && ismap(ax)
                obj.plotm(ax);
                return
            end
            % clear the existing layer
            h = obj.Handle;
            if ~isempty(h)
                delete(h);
            end
            if isempty(obj.Value)
                return % nothing to plot
            end

            holdstatus = ishold(ax); ax.NextPlot='add';

            val = obj.getTrimmedData();
            layer=line(ax,'XData',val.Longitude, 'YData',val.Latitude,'ZData',val.Depth');
            ax.ZDir='reverse';
            %stackorder_menu(layer)

            if ~holdstatus; ax.NextPlot='replace'; end

            % set properties for this layer
            set(layer, obj.PlottingDefaults);
        end

        function layer=plotm(obj,ax)
            % plot this layer onto a map (Requires mapping toolbox)
            % will delete layer if it exists
            % note features will only plot the subset of features within the
            % currently visible axes
            %
            % see also refreshPlot

            if ~exist('ax','var')
                ax = obj.ParentAxis;
            else
                obj.ParentAxis = ax;
            end

            if isempty(ax) || ~isvalid(ax)
                error('Feature "%s" ->plot has no associated axis',obj.Name);
            end

            % clear the existing layer
            h = obj.Handle;
            if ~isempty(h)
                delete(h);
            end

            if isempty(obj.Value)
                return % nothing to plot
            end

            holdstatus = ishold(ax); ax.NextPlot='add';

            val = obj.getTrimmedData();
            layer=plotm(val.Latitude, val.Longitude); %not allowed to specify axes
            zdatam(layer, reshape(val.Depth,1,[]));
            daspectm('km');
            if ~holdstatus; ax.NextPlot='replace'; end

            % set properties for this layer
            set(layer, obj.PlottingDefaults);
        end

        function refreshPlot(obj)
            % refreshPlot updates the X,Y,Z values without deleting the layer
            %
            % refreshPlot useful for when the axis limits have changed or
            % when the values have changed.  The plotted data will be trimmed, which reduces
            % the plotting overhead.
            %
            % see also plot

            %find this layer
            layer=obj.Handle;
            if isempty(layer)
                disp([obj.Name,' plot did not exist']);
            end
            val = obj.getTrimmedData();
            % set properties for this layer
            layer.XData=val.Longitude;
            layer.YData=val.Latitude;
            layer.ZData=val.Depth;
            set(layer,obj.PlottingDefaults);
        end

        function load(obj,varargin)
            % load this feature
            % uses the Loadfn provided during Feature Construction
            % loadFunction is expected to return a table or struct containing fields for
            % 'Latitude', 'Longitude', and 'Depth' (things with ELEVATION would have negative depth)
            item = obj.Loadfn(varargin{:});
            obj.Value = toValueStruct(item);
            obj.WasLoaded = true;
        end

        function save(obj)
            % save this feature
            % uses the Savefn provided during Feature construction
            obj.Savefn(obj)
        end

        function changeDefaults(obj, propname_struct)
            %changeDefaults changes this layer's properties and applies the change
            obj.PlottingDefaults = copyfields(obj.PlottingDefaults, propname_struct);
            %{
            fn=fieldnames(propname_struct);
            for i=1:numel(fn)
                obj.PlottingDefaults.(fn{i}) = propname_struct.(fn{i});
            end
            %}
            set(obj.Handle,obj.PlottingDefaults);
        end

        function addToggleMenu(obj, parentH, ax)
            % addToggleMenu add menu that hides/shows this Feature
            % addToggleMenu(parent) adds a toggle menu subordinate to the parent uimenu

            if ~isempty(obj.MenuToggle) && isvalid(obj.MenuToggle)
                error('ToggleMenu for Feature "%s" already exists.',obj.Name);
            end

            obj.MenuToggle = uimenu(parentH,...
                'Label',['Hide ' obj.Name],...
                'MenuSelectedFcn', @(s,~)obj.toggle_showhide_menu(s, ax));
        end
        function toggle_showhide_menu(obj, src, ax, contingencyFunction)
            % switch the show/hide menu between the "Show" and "Hide" stat
            % obj.toggle_showhide_menu(src, contingencyFunction
            %   this is intended to be the Callback for the addToggleMenu.
            %
            % if the plot this toggles no longer exists, then
            % the user-provided contingencyFunction will be run, which might be able to get things
            % back on track.
            h=obj.Handle;
            watchon
            drawnow;
            if isempty(h)
                if exist('contingencyFunction','var')
                    contingencyFunction();
                end
                h=findobj(ax,'Tag', obj.PlottingDefaults.Tag);
                errordlg('missing a layer %s', obj.PlottingDefaults.Tag);
            end
            axis(obj.ParentAxis,'manual')
            washeld = ishold(obj.ParentAxis); hold(obj.ParentAxis,'on');
            if startsWith(src.Label,'Hide ')
                src.Label = ['Show ' obj.Name];
                h.Visible = 'off';
            else % assume it starts with 'Show '
                src.Label = ['Hide ' obj.Name];
                h.Visible = 'on';
            end
            if ~washeld, hold(obj.ParentAxis,'off');end
            watchoff
            drawnow;
        end
    end % methods

    methods(Access=protected)
        function val = getTrimmedData(obj)
            % trim data to parent axis limits
            % obj.getTrimmedData()
            %
            % gaps where data was removed are replaced with a single "nan" value
            % this reduces the data size, and keeps segments from connecting when
            % they shouldn't.

            ax = obj.ParentAxis;
            if ismap(ax)
                trimLat=getm(ax,'maplatlimit');
                trimLon=getm(ax,'maplonlimit');
            else
                trimLat=ylim(ax);
                trimLon=xlim(ax);
            end
            idx  = obj.Value.Longitude >= trimLon(1) & obj.Value.Longitude <= trimLon(2);
            idx = idx & obj.Value.Latitude >= trimLat(1) & obj.Value.Latitude <= trimLat(2);

            val=obj.Value;

            % index used to delete any nan's after the first (per gap)
            todel = [false; ~idx(1:end-1)] & [false; ~idx(2:end)];
            if ~isfield(val,'Depth')
                val.Depth=zeros(size(val.Latitude));
            end
            % replace out-of-bounds values with NaN
            val.Longitude(~idx) = nan;
            val.Latitude(~idx) = nan;
            val.Depth(~idx)=nan;

            % reduce dataset by removing all nan's EXCEPT for one (per gap)
            val.Longitude(todel) = [];
            val.Latitude(todel) = [];
            val.Depth(todel)=[];
        end

    end %protected methods

    methods(Static)
        function foreach(features,funcname,varargin)
            %FOREACH run a function on a Map or array full of MapFeature
            % FOREACH(features) where features is either a map or array of MapFeature
            % FOREACH(features,arg1,...) arguments to pass to the function
            if isa(features,'containers.Map')
                k=features.keys;
                for i=1:numel(k)
                    ftr=features(k{i});
                    ftr.(funcname)(varargin{:});
                end
            else
                % treat as an array
                for i=1:numel(features)
                    ftr=features(i);
                    ftr.(funcname)(varargin{:});
                end
            end
        end

        function foreach_waitbar(features,funcname,varargin)
            %FOREACH run a function on a Map or array full of MapFeature
            % FOREACH(features) where features is either a map or array of MapFeature
            % FOREACH(features,arg1,...) arguments to pass to the function

            h=waitbar(0,'Calculating features for map...');
            if isa(features,'containers.Map')
                k=features.keys;
                for i=1:numel(k)
                    h.Name=[funcname ' : ', k{i}];
                    ftr=features(k{i});
                    ftr.(funcname)(varargin{:});
                    waitbar(i/numel(k),h);
                end
            else
                % treat as an array
                k = numel(features);
                for i=1:k
                    h.Name=[funcname ' : ', features(i).Name];
                    ftr=features(i);
                    ftr.(funcname)(varargin{:});
                    waitbar(i/k,h);
                end
            end
            delete(h)
        end

    end %static methods
end

function [finder, namer] = how_to_deal_with(item)
    switch class(item)
        case 'table'
            xx = item.Properties.VariableNames;
            finder = @(item, fn) startsWith(item.Properties.VariableNames, fn,'IgnoreCase',true);
            namer = @(idx) xx{idx};
            %accessor = @(item,fn) item.(fn)(:);
        case 'struct'
            xx = fieldnames(item);
            finder = @(item, fn) startsWith(xx, fn, 'IgnoreCase',true);
            fidx = fieldnameFromIndex(xx);
            namer = @(idx) fidx(idx);% fieldnameFromIndex(fieldnames(item));
            %accessor = @(item,fn) item.(fn)(:);
        otherwise
            xx=properties(item);
            assert(~isempty(xx),'item is not a table, struct, or class');
            finder = @(item, fn) startsWith(xx, fn, 'IgnoreCase',true);

            fidx = fieldnameFromIndex(xx);
            namer = @(idx) fidx(idx);% fieldnameFromIndex(fieldnames(item));
            %accessor = @(item,fn) item.(fn)(:);
    end
    function fn=fieldnameFromIndex(flds)
        fn = @(idx) flds{idx};
    end
end

function value = toValueStruct(data)
    % set.Value does the painful work of importing data form a variety of data types
    % result will have Latitude, Longitude, probably Depth, and possibly Names

    value=struct('Longitude',[],'Latitude',[],'Depth',[],'Names','');

    if isnumeric(data)
        % do number crunching

        if isempty(data)
            return
        end

        if size(data,2)>3 || size(data,2) < 2
            error('Feature "%s" expected 2-3 columns of data, or something with Latitude and Longitude fields',obj.Name); %#ok<MCSUP>
        end

        % assume longitude in first column
        if max(abs(data(:,2))) > 90.000001
            error('Feature "%s" expected latitudes in range of -90 to 90 in second column',obj.Name); %#ok<MCSUP>
        end

        if max(abs(data(:,1))) > 180.000001
            error('Feature "%s" expected longitudes in -180 to 180 range [%f]',obj.Name, max(abs(data(:,1)))); %#ok<MCSUP>
        end

        value.Longitude = data(:,1);
        value.Latitude = data(:,2);

        if size(data,2)==3
            value.Depth = data(:,3);
        else
            value.Depth = zeros(size(value.Longitude));
        end

        return
    end

    % data is in a class, struct, or table

    [searchFor, nameFromIdx] = how_to_deal_with(data);
    x = searchFor(data,'Longitude');
    y = searchFor(data,'Latitude');

    % assume parallel structure between x & y, so check x only and treat y accordingly

    if sum(x)==1
        % all is ok
    elseif ~any(x)
        x=searchFor(data,'Lon');
        y=searchFor(data,'Lat');
    end

    if ~any(x) || ~any(y)
        error('Feature %s Looking for data with a "Longitude" and "Latitude" fields', obj.Name); %#ok<MCSUP>
    elseif sum(x)>1 || sum(y)>1
        error('Feature %s Found too many "Longitude"-ish and "Latitude"-ish fields', obj.Name); %#ok<MCSUP>
    end

    lon_field = nameFromIdx(x);
    lat_field = nameFromIdx(y);

    d = searchFor(data,'Depth');
    el = searchFor(data,'Elev');

    if any(d)
        dep_field = nameFromIdx(d);
        value.Longitude = [data.(lon_field)];
        value.Latitude = [data.(lat_field)];
        value.Depth = [data.(dep_field)];
    elseif any(el)
        dep_field = nameFromIdx(el);
        value.Longitude = [data.(lon_field)];
        value.Latitude = [data.(lat_field)];
        value.Depth = -[data.(dep_field)];
    else
        value.Longitude = [data.(lon_field)];
        value.Latitude = [data.(lat_field)];
        value.Depth = zeros(size(value.Latitude));
    end

    value.Longitude = value.Longitude(:);
    value.Latitude = value.Latitude(:);
    value.Depth = value.Depth(:);

    nm = searchFor(data,'Name');
    if any(nm)
        value.Names = data.(nameFromIdx(nm));
    end

end


function gp = gp_unpak(gp, w, param)
%GP_UNPAK  Set GP parameters from vector to structure
%
%  Description
%    GP = GP_UNPAK(GP, W, PARAM) takes an Gaussian Process data
%    structure GP and a parameter vector W, and returns a Gaussian
%    Process structure identical to the input, except that the
%    parameters has been set to the ones in W. PARAM defines which
%    parameters are present in the W vector. If PARAM is not given
%    the function unpacks all parameters.
%
%    Each of the following strings in PARAM defines one group of
%    parameters to unpack:
%      covariance  - unpack parameters of covariance function
%      likelihood  - unpack parameters of likelihood
%      inducing    - unpack inducing inputs (in sparse approximations):
%                    W = gp.X_u(:)
%
%    By combining the strings one can unpack more than one group of
%    parameters. For example:
%      covariance+inducing   - unpack covariance function parameters
%                              and inducing inputs
%      covariance+likelihood - unpack covariance function parameters
%                              and likelihood parameters
%
%    Inside each group (such as covariance functions) the
%    parameters to be unpacked is defined by the existence of a
%    prior structure. For example, if GP has two covariance
%    functions but only the first one has prior for its parameters
%    then only the parameters of the first one are unpacked. Thus,
%    also inducing inputs require prior if they are to be
%    optimized.
%
%    GP_PAK and GP_UNPAK functions are used, e.g., when GP
%    parameters are optimized with GP_OPTIM or sampled with GP_MC.
%    See GP_SET and option 'infer_params'.
%
%  See also
%    GP_PAK, GP_SET
%
% Copyright (c) 2007-2010 Jarno Vanhatalo

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

if isempty(w)
  return
end

if nargin < 3
  param = gp.infer_params;
end

if size(w,1) > 1
  error(' The vector to be packed has to be row vector! \n')
end

% Unpack SVI variational parameters
if isfield(gp, 'latent_method') && isequal(gp.latent_method, 'SVI') ...
    && isfield(gp, 't1')
  w=w(:);
  gp.t1=w(1:length(gp.t1));
  w(1:length(gp.t1))=[];
  t2=reshape(w(1:numel(gp.t2)), length(gp.t1), length(gp.t1));
  [V,D]=eig(t2);
  gp.t2=t2;
  w(1:numel(gp.t2))=[];
  dtmp=-0.5./diag(D);
%   if any(dtmp<eps)
%     % Force positive definite covariance matrix
%     fprintf(['Variational covariance not positive definite. ' ...
%       'Forcing positive definitiness.\n']);
%     dtmp(dtmp<eps)=eps;
%     %gp.t2=-0.5.*(V*diag(1./dtmp))/V;
%   end
  dtmp=diag(dtmp);
  gp.S=(V*dtmp)/V;
  gp.m=gp.S*gp.t1;
  w=w';
end

% Unpack the parameters of covariance functions
if ~isempty(strfind(param, 'covariance'))
  ncf = length(gp.cf);

  for i=1:ncf
    gpcf = gp.cf{i};
    [gpcf, w] = gpcf.fh.unpak(gpcf, w);
    gp.cf{i} = gpcf;
  end

end

% Unpack the parameters of likelihood function
if ~isempty(strfind(param, 'likelihood'))
  [gp.lik, w] = gp.lik.fh.unpak(gp.lik, w);
  if isfield(gp, 'latent_method') && isequal(gp.latent_method, 'SVI') ...
      && ~isequal(gp.lik.type, 'Gaussian') && ~isempty(gp.lik.p.sigma2)
    gp.lik.sigma2=exp(w(1));
    w(1)=[];
  end
  % Unpack the parameters of the second likelihood function (monotonicity)
  if isfield(gp, 'lik_mono')
    [gp.lik_mono, w] = gp.lik_mono.fh.unpak(gp.lik_mono, w);
    if isfield(gp, 'latent_method') && isequal(gp.latent_method, 'SVI') ...
         && ~isempty(gp.lik_mono.p.sigma2)
      gp.lik_mono.sigma2=exp(w(1));
      w(1)=[];
    end
  end
end

% Unpack the inducing inputs
if ~isempty(strfind(param, 'inducing'))
  if isfield(gp,'p') && isfield(gp.p, 'X_u') && ~isempty(gp.p.X_u)
    if ~iscell(gp.p.X_u)
      % One prior for all inducing inputs
      lu = length(gp.X_u(:));
      gp.X_u = reshape(w(1:lu), size(gp.X_u'))';
      if lu < length(w)
        w = w(lu+1:end);
      end
      [gp.p.X_u, w]=gp.p.X_u.fh.unpak(gp.p.X_u, w);
    else
      % Own prior for each inducing input
      d=numel(gp.X_u(1,:));
      for i=1:size(gp.X_u)
        gp.X_u(i,:) = reshape(w(1:d), size(gp.X_u(1,:)));
        w(1:d)=[];
        [gp.p.X_u{i}, w] = gp.p.X_u{i}.fh.unpak(gp.p.X_u{i}, w);
      end
    end
  end
end

% Unpack the covariance function parameters
if ~isempty(strfind(param, 'mean'))
  nmf = length(gp.meanf);

  for i=1:nmf
    gpmf = gp.meanf{i};
    [gpmf, w] = gpmf.fh.unpak(gpmf, w);
    gp.meanf{i} = gpmf;
  end

end


function han = plot_vertical_line(x,color)
% ..
%    Edited by Tor, Feb 08, to plot multiple lines
% ..

if nargin < 2, color = 'k'; end

ylim = get(gca,'YLim');

for i = 1:length(x)
    han = plot([x(i) x(i)], ylim, color);

end

end


function tests = test_metaImageRead
% Test suite for the file metaImageRead.
%
%   Test suite for the file metaImageRead
%
%   Example
%   test_metaImageRead
%
%   See also
%     metaImageRead

% ------
% Author: David Legland
% e-mail: david.legland@inrae.fr
% Created: 2021-05-14,    using Matlab 9.8.0.1323502 (R2020a)
% Copyright 2021 INRAE - BIA-BIBS.

tests = functiontests(localfunctions);

function test_UInt8_2D(testCase)

fileName = 'img_UInt8_rampXY_20x10.mhd';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 2);
assertEqual(testCase, size(res), [10 20]);

function test_UInt8_2D_NoExtension(testCase)

fileName = 'img_UInt8_rampXY_20x10';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 2);
assertEqual(testCase, size(res), [10 20]);

function test_RGB8_2D_peppers(testCase)

fileName = 'img_RGB8_peppers.mhd';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 3);
assertEqual(testCase, size(res), [384 512 3]);

function test_UInt8_3D_RampXYZ(testCase)

fileName = 'img_UInt8_rampXYZ_6x5x4.mhd';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 3);
assertEqual(testCase, size(res), [5 6 4]);

assertEqual(testCase, res(1,1,1), uint8(0));
assertEqual(testCase, res(1,end,1), uint8(5));
assertEqual(testCase, res(end,1,1), uint8(40));
assertEqual(testCase, res(end,end,1), uint8(45));
assertEqual(testCase, res(end,end,end), uint8(255));

function test_read_slice_list(testCase)

filename = 'BRNOR39e5p1List.mhd';
img = metaImageRead(fullfile('ratBrainMriSlices', filename));

exp = [96 96 96];
assertEqual(testCase, size(img), exp, 'image does not have the right size');

assertTrue(max(img(:))>0);

function test_read_slices_pattern(testCase)

filename = 'BRNOR39e5p1Pattern.mhd';
img = metaImageRead(fullfile('ratBrainMriSlices', filename));

exp = [96 96 96];
assertEqual(testCase, size(img), exp, 'image does not have the right size');

assertTrue(max(img(:))>0);

function test_UInt16_3D_RampXYZ_msb(testCase)

fileName = 'img_UInt16_rampXYZ_6x5x4_msb.mhd';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 3);
assertEqual(testCase, size(res), [5 6 4]);

assertEqual(testCase, res(1, 1, 1), uint16(0));
assertEqual(testCase, res(1, 6, 1), uint16(5));
assertEqual(testCase, res(5, 1, 1), uint16(40));
assertEqual(testCase, res(5, 6, 1), uint16(45));
assertEqual(testCase, res(1, 1, 4), uint16(300));
assertEqual(testCase, res(1, 6, 4), uint16(305));
assertEqual(testCase, res(5, 1, 4), uint16(340));
assertEqual(testCase, res(5, 6, 4), uint16(345));

function test_UInt16_3D_RampXYZ_lsb(testCase)

fileName = 'img_UInt16_rampXYZ_6x5x4_lsb.mhd';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 3);
assertEqual(testCase, size(res), [5 6 4]);

assertEqual(testCase, res(1, 1, 1), uint16(0));
assertEqual(testCase, res(1, 6, 1), uint16(5));
assertEqual(testCase, res(5, 1, 1), uint16(40));
assertEqual(testCase, res(5, 6, 1), uint16(45));
assertEqual(testCase, res(1, 1, 4), uint16(300));
assertEqual(testCase, res(1, 6, 4), uint16(305));
assertEqual(testCase, res(5, 1, 4), uint16(340));
assertEqual(testCase, res(5, 6, 4), uint16(345));

function test_Int16_3D_RampXYZ_msb(testCase)

fileName = 'img_Int16_rampXYZ_6x5x4_msb.mhd';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 3);
assertEqual(testCase, size(res), [5 6 4]);

assertEqual(testCase, res(1, 1, 1), int16(0));
assertEqual(testCase, res(1, 6, 1), int16(5));
assertEqual(testCase, res(5, 1, 1), int16(40));
assertEqual(testCase, res(5, 6, 1), int16(45));
assertEqual(testCase, res(1, 1, 4), int16(300));
assertEqual(testCase, res(1, 6, 4), int16(305));
assertEqual(testCase, res(5, 1, 4), int16(340));
assertEqual(testCase, res(5, 6, 4), int16(345));

function test_Int16_3D_RampXYZ_lsb(testCase)

fileName = 'img_Int16_rampXYZ_6x5x4_lsb.mhd';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 3);
assertEqual(testCase, size(res), [5 6 4]);

assertEqual(testCase, res(1, 1, 1), int16(0));
assertEqual(testCase, res(1, 6, 1), int16(5));
assertEqual(testCase, res(5, 1, 1), int16(40));
assertEqual(testCase, res(5, 6, 1), int16(45));
assertEqual(testCase, res(1, 1, 4), int16(300));
assertEqual(testCase, res(1, 6, 4), int16(305));
assertEqual(testCase, res(5, 1, 4), int16(340));
assertEqual(testCase, res(5, 6, 4), int16(345));

function test_Int32_3D_RampXYZ_msb(testCase)

fileName = 'img_Int32_rampXYZ_6x5x4_msb.mhd';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 3);
assertEqual(testCase, size(res), [5 6 4]);

assertEqual(testCase, res(1, 1, 1), int32(0));
assertEqual(testCase, res(1, 6, 1), int32(5));
assertEqual(testCase, res(5, 1, 1), int32(40));
assertEqual(testCase, res(5, 6, 1), int32(45));
assertEqual(testCase, res(1, 1, 4), int32(300));
assertEqual(testCase, res(1, 6, 4), int32(305));
assertEqual(testCase, res(5, 1, 4), int32(340));
assertEqual(testCase, res(5, 6, 4), int32(345));

function test_Int32_3D_RampXYZ_lsb(testCase)

fileName = 'img_Int32_rampXYZ_6x5x4_lsb.mhd';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 3);
assertEqual(testCase, size(res), [5 6 4]);

assertEqual(testCase, res(1, 1, 1), int32(0));
assertEqual(testCase, res(1, 6, 1), int32(5));
assertEqual(testCase, res(5, 1, 1), int32(40));
assertEqual(testCase, res(5, 6, 1), int32(45));
assertEqual(testCase, res(1, 1, 4), int32(300));
assertEqual(testCase, res(1, 6, 4), int32(305));
assertEqual(testCase, res(5, 1, 4), int32(340));
assertEqual(testCase, res(5, 6, 4), int32(345));

function test_Float32_3D_RampXYZ_msb(testCase)

fileName = 'img_Float32_rampXYZ_6x5x4_msb.mhd';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 3);
assertEqual(testCase, size(res), [5 6 4]);

assertEqual(testCase, res(1, 1, 1), single(0));
assertEqual(testCase, res(1, 6, 1), single(5));
assertEqual(testCase, res(5, 1, 1), single(40));
assertEqual(testCase, res(5, 6, 1), single(45));
assertEqual(testCase, res(1, 1, 4), single(300));
assertEqual(testCase, res(1, 6, 4), single(305));
assertEqual(testCase, res(5, 1, 4), single(340));
assertEqual(testCase, res(5, 6, 4), single(345));

function test_Float32_3D_RampXYZ_lsb(testCase)

fileName = 'img_Float32_rampXYZ_6x5x4_lsb.mhd';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 3);
assertEqual(testCase, size(res), [5 6 4]);

assertEqual(testCase, res(1, 1, 1), single(0));
assertEqual(testCase, res(1, 6, 1), single(5));
assertEqual(testCase, res(5, 1, 1), single(40));
assertEqual(testCase, res(5, 6, 1), single(45));
assertEqual(testCase, res(1, 1, 4), single(300));
assertEqual(testCase, res(1, 6, 4), single(305));
assertEqual(testCase, res(5, 1, 4), single(340));
assertEqual(testCase, res(5, 6, 4), single(345));

function test_Float64_3D_RampXYZ_msb(testCase)

fileName = 'img_Float64_rampXYZ_6x5x4_msb.mhd';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 3);
assertEqual(testCase, size(res), [5 6 4]);

assertEqual(testCase, res(1, 1, 1), 0);
assertEqual(testCase, res(1, 6, 1), 5);
assertEqual(testCase, res(5, 1, 1), 40);
assertEqual(testCase, res(5, 6, 1), 45);
assertEqual(testCase, res(1, 1, 4), 300);
assertEqual(testCase, res(1, 6, 4), 305);
assertEqual(testCase, res(5, 1, 4), 340);
assertEqual(testCase, res(5, 6, 4), 345);

function test_Float64_3D_RampXYZ_lsb(testCase)

fileName = 'img_Float64_rampXYZ_6x5x4_lsb.mhd';

res = metaImageRead(fullfile('mhd_images', fileName));

assertEqual(testCase, ndims(res), 3);
assertEqual(testCase, size(res), [5 6 4]);

assertEqual(testCase, res(1, 1, 1), 0);
assertEqual(testCase, res(1, 6, 1), 5);
assertEqual(testCase, res(5, 1, 1), 40);
assertEqual(testCase, res(5, 6, 1), 45);
assertEqual(testCase, res(1, 1, 4), 300);
assertEqual(testCase, res(1, 6, 4), 305);
assertEqual(testCase, res(5, 1, 4), 340);
assertEqual(testCase, res(5, 6, 4), 345);


function [ pwIdxsAllrel ] = build_joint_pairs( p )

pidxs = p.pidxs;

if p.person_part
    pidxs = [pidxs pidxs(end)+1];
end

pwIdxsAllrel = cell(1, 1);
n = 0;
for i = 1:length(pidxs)-1
    for j = i+1:length(pidxs)
        n = n + 1;
        pwIdxsAllrel{n} = [i j];
    end
end


% [INPUT]
% ds = A structure representing the dataset.
% category = A string representing the type of validation to perform (optional, default='').
%
% [OUTPUT]
% ds = A structure containing the validated dataset.

function ds = validate_dataset(varargin)

    persistent categories;

    if (isempty(categories))
        categories = {
            'BubblesDetection' 'Comparison' 'Component' 'Connectedness' 'CrossEntropy' 'CrossQuantilogram' ...
            'CrossSectional' 'Default' 'Liquidity' 'RegimeSwitching' 'Spillover' 'TailDependence'
        };
    end

    persistent ip;

    if (isempty(ip))
        ip = inputParser();
        ip.addRequired('ds',@(x)validateattributes(x,{'struct'},{'nonempty'}));
        ip.addOptional('category','',@(x)any(validatestring(x,categories)));
    end

    ip.parse(varargin{:});

    ipr = ip.Results;
    ds = ipr.ds;
    category = ipr.category;

    nargoutchk(1,1);

    ds = validate_dataset_internal(ds,category,categories);

end

function ds = validate_dataset_internal(ds,category,categories)

    validate_field(ds,'File',{'char'},{'nonempty' 'size' [1 NaN]});
    validate_field(ds,'Version',{'char'},{'nonempty' 'size' [1 NaN]});
    creation_date = validate_field(ds,'CreationDate',{'double'},{'real' 'finite' '>=' datenum(2014,1,1) 'scalar'}); %#ok<DATNM>

    result = validate_field(ds,'Result',{'char'},{'optional' 'nonempty' 'size' [1 NaN]});
    result_date = validate_field(ds,'ResultDate',{'double'},{'optional' 'real' 'finite' '>=' datenum(2014,1,1) 'scalar'}); %#ok<DATNM>
    result_analysis = validate_field(ds,'ResultAnalysis',{'function_handle'},{'optional' 'scalar'});
    result_serial = validate_field(ds,'ResultSerial',{'char'},{'optional' 'nonempty' 'size' [1 NaN]});

    if (isempty(result))
        if (~isempty(result_date))
            error(['The dataset field ''ResultDate'' is invalid.' new_line() 'Expected value to be empty.']);
        end

        if (~isempty(result_analysis))
            error(['The dataset field ''ResultAnalysis'' is invalid.' new_line() 'Expected value to be empty.']);
        end

        if (~isempty(result_serial))
            error(['The dataset field ''ResultSerial'' is invalid.' new_line() 'Expected value to be empty.']);
        end
    else
        if (~ismember(result,categories))
            error(['The dataset field ''Result'' is invalid.' new_line() 'Expected value to be a string containing a valid result category.']);
        end

        if (isempty(result_date) || (result_date < creation_date))
            error(['The dataset field ''ResultDate'' is invalid.' new_line() 'Expected value to be a numeric date greater than or equal to ' datestr(creation_date,'dd/mm/yyyy') '.']); %#ok<DATST>
        end

        if (isempty(result_analysis))
            error(['The dataset field ''ResultAnalysis'' is invalid.' new_line() 'Expected value to be a function handle.']);
        end

        if (isempty(result_serial))
            error(['The dataset field ''ResultSerial'' is invalid.' new_line() 'Expected value to be a function handle.']);
        end
    end

    validate_field(ds,'TimeSeries',{'cellstr'},{'nonempty' 'size' [1 8]});

    n = validate_field(ds,'N',{'double'},{'real' 'finite' 'integer' '>=' 3 'scalar'});
    t = validate_field(ds,'T',{'double'},{'real' 'finite' 'integer' '>=' 252 'scalar'});

    validate_field(ds,'DatesNum',{'double'},{'real' 'finite' 'integer' '>' 0 'nonempty' 'size' [t 1]});
    validate_field(ds,'DatesStr',{'cellstr'},{'nonempty' 'size' [t 1]});
    validate_field(ds,'MonthlyTicks',{'logical'},{'scalar'});

    validate_field(ds,'IndexName',{'char'},{'nonempty' 'size' [1 NaN]});
    validate_field(ds,'FirmNames',{'cellstr'},{'nonempty' 'size' [1 n]});

    validate_field(ds,'Index',{'double'},{'real' 'finite' 'nonempty' 'size' [t 1]});
    validate_field(ds,'Returns',{'double'},{'real' 'nanfinite' 'nonempty' 'size' [t n]});

    validate_field(ds,'Prices',{'double'},{'optional' 'real' 'nanfinite' 'nonnegative' 'nonempty' 'size' [t n]});
    validate_field(ds,'Volumes',{'double'},{'optional' 'real' 'nanfinite' 'nonnegative' 'nonempty' 'size' [t n]});
    validate_field(ds,'Capitalizations',{'double'},{'optional' 'real' 'nanfinite' 'nonnegative' 'nonempty' 'size' [t n]});

    validate_field(ds,'RiskFreeRate',{'double'},{'optional' 'real' 'finite' 'nonempty' 'size' [t 1]});
    validate_field(ds,'CDS',{'double'},{'optional' 'real' 'nanfinite' 'nonnegative' 'nonempty' 'size' [t n]});

    validate_field(ds,'Assets',{'double'},{'optional' 'real' 'nanfinite' 'nonnegative' 'nonempty' 'size' [t n]});
    validate_field(ds,'Equity',{'double'},{'optional' 'real' 'nanfinite' 'nonempty' 'size' [t n]});
    validate_field(ds,'Liabilities',{'double'},{'optional' 'real' 'nanfinite' 'nonnegative' 'nonempty' 'size' [t n]});
    validate_field(ds,'SeparateAccounts',{'double'},{'optional' 'real' 'nanfinite' 'nonnegative' 'nonempty' 'size' [t n]});

    state_variables = validate_field(ds,'StateVariables',{'double'},{'optional' 'real' 'finite' 'nonempty' 'size' [t NaN]});
    validate_field(ds,'StateVariablesNames',{'cellstr'},{'optional' 'nonempty' 'size' [1 size(state_variables,2)]});

    groups = validate_field(ds,'Groups',{'double'},{'real' 'finite' 'integer' '>=' 0 'scalar'});

    if (groups == 0)
        validate_field(ds,'GroupDelimiters',{'double'},{'size' [0 0]});
        validate_field(ds,'GroupNames',{'double'},{'size' [0 0]});
        validate_field(ds,'GroupShortNames',{'double'},{'size' [0 0]});
    else
        validate_field(ds,'GroupDelimiters',{'double'},{'real' 'finite' 'integer' 'positive' 'increasing' 'nonempty' 'size' [(groups - 1) 1]});
        validate_field(ds,'GroupNames',{'cellstr'},{'nonempty' 'size' [groups 1]});
        validate_field(ds,'GroupShortNames',{'cellstr'},{'nonempty' 'size' [groups 1]});
    end

    crises = validate_field(ds,'Crises',{'double'},{'real' 'finite' 'integer' '>=' 0 'scalar'});
    crises_type = validate_field(ds,'CrisesType',{'char'},{'nonempty' 'size' [1 1]});

    if (~strcmp(crises_type,'E') && ~strcmp(crises_type,'R'))
        error(['The dataset field ''CrisesType'' is invalid.' new_line() 'Expected value to be either ''E'' or ''R''.']);
    end

    if (crises == 0)
        validate_field(ds,'CrisesDummy',{'double'},{'size' [0 0]});
        validate_field(ds,'CrisisDates',{'double'},{'size' [0 0]});
        validate_field(ds,'CrisisDummies',{'double'},{'size' [0 0]});
        validate_field(ds,'CrisisNames',{'double'},{'size' [0 0]});
    else
        validate_field(ds,'CrisesDummy',{'double'},{'real' 'finite' 'integer' '>=' 0 '<=' 1 'nonempty' 'size' [t 1]});

        if (strcmp(crises_type,'E'))
            validate_field(ds,'CrisisDates',{'double'},{'real' 'finite' 'integer' '>' 0 'nonempty' 'size' [crises 1]});
            validate_field(ds,'CrisisDummies',{'double'},{'size' [0 0]});
        else
            validate_field(ds,'CrisisDates',{'double'},{'real' 'finite' 'integer' '>' 0 'nonempty' 'size' [crises 2]});
            validate_field(ds,'CrisisDummies',{'double'},{'real' 'finite' 'integer' '>=' 0 '<=' 1 'nonempty' 'size' [t crises]});
        end

        validate_field(ds,'CrisisNames',{'cellstr'},{'nonempty' 'size' [crises 1]});
    end

    validate_field(ds,'Defaults',{'double'},{'real' 'nonempty' 'offset' 'size' [1 n]});
    validate_field(ds,'Insolvencies',{'double'},{'real' 'nonempty' 'offset' 'size' [1 n]});

    validate_field(ds,'SupportsComponent',{'logical'},{'scalar'});
    validate_field(ds,'SupportsConnectedness',{'logical'},{'scalar'});
    validate_field(ds,'SupportsCrossEntropy',{'logical'},{'scalar'});
    validate_field(ds,'SupportsCrossSectional',{'logical'},{'scalar'});
    validate_field(ds,'SupportsDefault',{'logical'},{'scalar'});
    validate_field(ds,'SupportsLiquidity',{'logical'},{'scalar'});
    validate_field(ds,'SupportsRegimeSwitching',{'logical'},{'scalar'});
    validate_field(ds,'SupportsSpillover',{'logical'},{'scalar'});
    validate_field(ds,'SupportsTailDependence',{'logical'},{'scalar'});
    validate_field(ds,'SupportsComparison',{'logical'},{'scalar'});

    if (~isempty(category))
        if (strcmp(category,'Comparison'))
            if (~ds.SupportsComparison)
                error('The dataset cannot be used to compare systemic risk measures.');
            end
        else
            supports = ['Supports' category];

            if (~ds.(supports))
                category_e = category;
                indices = find(isstrprop(category,'upper'));

                for i = 1:numel(indices)
                    index = indices(i);

                    if (index == 1)
                        category_e(i) = lower(category(index));
                    else
                        category_e = [category_e(1:index-1) '-' lower(category_e(index)) category_e(index+1:end)];
                        indices(i+1:end) = indices(i+1:end) + 1;
                    end
                end

                error(['The dataset cannot be used to calculate ''' category_e ''' measures.']);
            end
        end
    end

end

function value = validate_field(ds,field_name,field_type,field_validator)

    if (~isfield(ds,field_name))
        error(['The dataset does not contain the field ''' field_name '''.']);
    end

    value = ds.(field_name);
    value_iscellstr = (numel(field_type) == 1) && strcmp(field_type{1},'cellstr');
    value_isfinite = any(strcmp(field_validator,'nanfinite'));
    value_isoffset = any(strcmp(field_validator,'offset'));
    value_isoptional = strcmp(field_validator{1},'optional');

    if (value_isoptional)
        empty = false;

        try
            validateattributes(value,{'double'},{'size' [0 0]});
            empty = true;
        catch
        end

        if (empty)
            return;
        end

        field_validator = field_validator(2:end);
    end

    if (value_iscellstr)
        if (~iscellstr(value) || any(cellfun(@length,value) == 0) || any(cellfun(@(x)size(x,1),value) ~= 1)) %#ok<ISCLSTR>
            error(['The dataset field ''' field_name ''' is invalid.' new_line() 'Expected value to be a cell array of non-empty character vectors.']);
        end

        field_type{1} = 'cell';
    else
        if (value_isfinite)
            index = strcmp(field_validator,'nanfinite');
            field_validator(index) = [];
        end

        if (value_isoffset)
            index = strcmp(field_validator,'offset');
            field_validator(index) = [];
        end
    end

    try
        validateattributes(value,field_type,field_validator);
    catch e
        error(['The dataset field ''' field_name ''' is invalid.' new_line() strrep(e.message,'Expected input','Expected value')]);
    end

    if (value_isfinite)
        value_check = value;
        value_check(isnan(value_check)) = 0;

        try
            validateattributes(value_check,field_type,{'finite'});
        catch
            error(['The dataset field ''' field_name ''' is invalid.' new_line() 'Expected value to be finite.']);
        end
    end

    if (value_isoffset)
        value_check = value;
        value_check(isnan(value_check)) = 2;

        try
            validateattributes(value_check,field_type,{'>',1});
        catch
            error(['The dataset field ''' field_name ''' is invalid.' new_line() 'Expected value to contain all the finite values > 1.']);
        end
    end

end


function [indBoundary]=tesBoundary(varargin)

% function [indBoundary]=tesBoundary(F)
% ------------------------------------------------------------------------
%
% Change log:
% 2009
% 2019/04/24 Added varargin support since V can be skipped
% 2019/04/24 Started working on cell (e.g. mixed mesh) support, not
% completed yet
% 2020/07/09 Added mixed mesh support, works for pentahedra, needs work for
% general case
% 2021/10/08 Simplified
% 2021/10/08 No longer needs vertices as input
% ------------------------------------------------------------------------

%% Parse input

switch nargin
    case 1
        F=varargin{1};
    case 2
        F=varargin{1};
        warning('Second input (vertices) no longer required. Update code to avoid future error.');
end

%%

if isa(F,'cell')
    indBoundary=cell(size(F));
    for q=1:1:numel(F)
        indBoundary{q}=getBoundary(F{q});
    end
else
    [indBoundary]=getBoundary(F);
end

end

%%

function [indBoundary]=getBoundary(F)

Fs=sort(F,2); %Sort so faces with same nodes have the same rows
[~,~,~,F_count]=cunique(Fs,'rows'); %get indices for unique faces
indBoundary=find(F_count==1);

% Old method
%     Fbs=sort(F,2);
%     sizVirt=numPoints*ones(1,size(Fbs,2));
%     ind_F = sub2indn(sizVirt,Fbs);
%     [~,indUni1,~]=unique(Fbs,'rows'); %Get indices for unique faces
%     ind_F_uni=ind_F(indUni1,:);
%     ind=1:1:size(Fbs,1);
%     ind=ind(~ismember(ind,indUni1));
%     ind_Fb_cut=ind_F(ind,:);
%     L_uni=~ismember(ind_F_uni,ind_Fb_cut);
%     indBoundary=indUni1(L_uni,:);
end

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


function header = read_spmeeg_header(filename)

% read_spmeeg_header() - import SPM5 and SPM8 meeg datasets
%
% Usage:
%   >> header = read_spmeeg_header(filename);
%
% Inputs:
%   filename - [string] file name
%
% Outputs:
%   header   - FILEIO toolbox type structure
% _______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging
% Vladimir Litvak

if nargin < 1
  help read_spmeeg_header;
  return;
end

try
    D = load(filename, 'D');
    D = D.D;
catch
    ft_error('File not found or wrong format.');
end

header = [];

if isfield(D, 'Radc') % SPM5
    header.Fs          = D.Radc;
    header.nChans      = D.Nchannels;
    header.nSamples    = D.Nsamples;

    if isfield(D, 'events') && isfield(D.events, 'start')
        header.nSamplesPre = D.events.start;
    else
        header.nSamplesPre = 0;
    end

    header.nTrials     = D.Nevents;
    header.label       = D.channels.name';

elseif all(isfield(D, {'type', 'Nsamples', 'Fsample', 'timeOnset'})) % SPM8

    header.Fs          = D.Fsample;
    header.nChans      = numel(D.channels);
    header.nSamples    = D.Nsamples;
    header.nSamplesPre = -D.timeOnset*D.Fsample;
    header.nTrials     = numel(D.trials);
    header.label       = {D.channels.label}';
    header.chantype    = lower({D.channels.type}');
    header.chanunit    = {D.channels.units}';

    if isfield(D.sensors, 'eeg') && ~isempty(D.sensors.eeg)
        header.elec = D.sensors.eeg;
    end

    if isfield(D.sensors, 'meg') && ~isempty(D.sensors.meg)
        header.grad = D.sensors.meg;
    end

else
    ft_error('Cannot recognize an SPM EEG header format');
end

header.orig = D;


function i4mat_write ( output_filename, m, n, table )

%*****************************************************************************80
%
%% I4MAT_WRITE writes an I4MAT file.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    20 July 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string OUTPUT_FILENAME, the output filename.
%
%    Input, integer M, the spatial dimension.
%
%    Input, integer N, the number of points.
%
%    Input, integer TABLE(M,N), the points.
%
%    Input, logical HEADER, is TRUE if the header is to be included.
%

%
%  Open the file.
%
  output_unit = fopen ( output_filename, 'wt' );

  if ( output_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'I4MAT_WRITE - Error!\n' );
    fprintf ( 1, '  Could not open the output file.\n' );
    error ( 'I4MAT_WRITE0 - Error!' );
  end
%
%  Write the data.
%
  for j = 1 : n
    for i = 1 : m
      fprintf ( output_unit, '  %12d', round ( table(i,j) ) );
    end
    fprintf ( output_unit, '\n' );
  end
%
%  Close the file.
%
  fclose ( output_unit );

  return
end


classdef TestMergeDebevec
    %TestMergeDebevec

    methods (Static)
        function test_1
            N = 3; % use first N images only
            fpath = fullfile(mexopencv.root(),'test');
            files = dir(fullfile(fpath,'memorial*.png'));
            files = files(1:N);
            imgs = cell(1,numel(files));
            for i=1:numel(files)
                imgs{i} = cv.imread(fullfile(fpath,files(i).name), 'ReduceScale',2);
            end
            etimes = 2.^(5:-1:-10);
            etimes = etimes(1:N);
            assert(numel(imgs) == numel(etimes));

            obj = cv.MergeDebevec();
            hdr = obj.process(imgs, etimes);
            validateattributes(hdr, {'single'}, ...
                {'size',size(imgs{1}), 'nonnegative'});

            calibrate = cv.CalibrateDebevec();
            response = calibrate.process(imgs, etimes);
            hdr = obj.process(imgs, etimes, response);
            validateattributes(hdr, {'single'}, ...
                {'size',size(imgs{1}), 'nonnegative'});
        end
    end

end


function gtdata = breakGts(gtdata)
% normalize IDs
[~, ~, ic] = unique(gtdata(:,2));
gtdata(:,2) = ic;
% break the groundtruth trajetory with multiple object categories
tracks = unique(ic);
newtrack_id = max(tracks) + 1;
for i = 1:numel(tracks)
    idx = gtdata(:, 2) == tracks(i);
    cls = gtdata(idx, 8);
    allcls = unique(cls);
    if(numel(allcls) > 1)
        for j = 2:numel(allcls)
            idxCls = idx & gtdata(:, 8) == allcls(j);
            gtdata(idxCls, 2) = newtrack_id;
            newtrack_id = newtrack_id + 1;
        end
    end
end


function test_model = testNRSFM(data, train_model)

globals;
params = get_params();

fprintf('Testing NRSfM model\n');

% Generate test set
[~,test] = prep_data(data.test,0,0);

% Take full train labels and test on test set. Just reorder.
test = normalize_test(test, train_model);
nTest = size(test.points,1)/2;
nTestIters = params.nrsfm.test_em_iters;

% Fit NRSFM parameters parallely to instances
p =  TimedProgressBar( nTest, 30, ...
'Testing NRSfM ', ', completed ', 'Testing NRSfM concluded in ' );
parfor i=1:nTest
    test_model_arr(i) = em_single_instance(train_model,test,i,nTestIters);
    p.progress();
end
p.stop();

% Merge test models into a single test_model
test_model = merge_model_arr(test_model_arr);
if(isfield(test,'subtype'))
    test_model.subtype = test.subtype;
end
if(isfield(test,'rotP3d'))
    test_model.rotP3d = test.rotP3d;
end
if(isfield(test,'rotationPred'))
    test_model.rotationPred = test.rotationPred;
end
if(isfield(test,'subtypePred'))
    test_model.subtypePred = test.subtypePred;
end

end


function pf = mtimes(arg1,arg2)
% scaling of PoleFigures, implements pf1 * b and a * pf2
%
% overload the * operator, i.e. one can now write x * pf in order to
% scale the @PoleFigure pf by the factor x
%
% See also
% PoleFigure/PoleFigure PoleFigure/plus PoleFigure/minus

pf = arg1 .* arg2;


function Fmem = PQinitFMem (Nc, PCinit)
% Initialize the filter memories

% P. Kabal $Revision: 1.1 $  $Date: 2003/12/07 13:34:10 $

Fmem.TDS.Ef(1:2,1:Nc) = 0;
Fmem.Adap.P(1:2,1:Nc) = 0;
Fmem.Adap.Rn(1:Nc) = 0;
Fmem.Adap.Rd(1:Nc) = 0;
Fmem.Adap.PC(1:2,1:Nc) = PCinit;
Fmem.Env.Ese(1:2,1:Nc) = 0;
Fmem.Env.DE(1:2,1:Nc) = 0;
Fmem.Env.Eavg(1:2,1:Nc) = 0;


%ISDATAIM Returns true if a dataset contains image objects or image features
%
% 	N = ISDATAIM(A)
%
% INPUT
%		A 	Dataset
%
% OUTPUT
%		N	  Scalar: 1 if A contains images as objects or features, otherwise 0
%
% DESCRIPTION
% If no output argument is given, the function will produce an error if A does
% not contain image objects or features (i.e. it will act as an assertion).
%
% SEE ALSO (PRTools Guide)
% ISOBJIM, ISFEATIM

% $Id: isdataim.m,v 1.2 2006/03/08 22:06:58 duin Exp $

function n = isdataim (a)

		if (nargin < 1)
		error('Insufficient number of arguments.');
	end

	% The FEATSIZE and OBJSIZE fields of a dataset indicate whether it contains
	% images.

	n = (isa(a,'prdataset')) & ((length(a.featsize) > 1) | (length(a.objsize) > 1)) ;

	% Generate and error if the input is not a dataset with image data and
	% no output is requested (assertion).

	if (nargout == 0) & (n == 0)
		error('Dataset with images expected.')
	end

return


function exportImg(file_name, data_map, c_map)
% Save on a file a matrix provided in "data"
%
% SYNTAX:
%   exportImg(file_name, data_map, <col_map>)

%--- * --. --- --. .--. ... * ---------------------------------------------
%               ___ ___ ___
%     __ _ ___ / __| _ | __|
%    / _` / _ \ (_ |  _|__ \
%    \__, \___/\___|_| |___/
%    |___/                    v 1.0RC1
%
%--------------------------------------------------------------------------
%  Copyright (C) 2021 Geomatics Research & Development srl (GReD)
%  Written by:       Andrea Gatti
%  Contributors:     Andrea Gatti ...
%  A list of all the historical goGPS contributors is in CREDITS.nfo
%--------------------------------------------------------------------------
%
%   This program is free software: you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation, either version 3 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You should have received a copy of the GNU General Public License
%   along with this program.  If not, see <http://www.gnu.org/licenses/>.
%
%--------------------------------------------------------------------------
% 01100111 01101111 01000111 01010000 01010011
%--------------------------------------------------------------------------

    narginchk(2,3);

    if islogical(data_map)
        imwrite(data_map, file_name);
    else
        if nargin < 3
            c_map = jet(256);
        end

        % Normalize data
        im_alpha = isnan(data_map);
        data_map = data_map - min(data_map(:));
        data_map = max(2, ceil(data_map ./ max(data_map(:)) .* (size(c_map, 1) -1)) + 1);
        data_map(im_alpha) = 1;
        c_map = [[0, 0, 0]; c_map];

        im = reshape([c_map(data_map(:), 1); c_map(data_map(:), 2); c_map(data_map(:), 3)], size(data_map, 1), size(data_map, 2), 3);
        imwrite(im, file_name, 'Alpha', 1-im_alpha);
    end
end


%%
%% Run this script in Matlab command window
%%

   function Installmex
   curdir = pwd;
   fprintf(' current directory is:  %s\n',curdir);
   fsp = filesep;
%%
%%
%%
   src = [curdir,fsp,'Solver',fsp,'Mexfun'];
   eval(['cd ','Solver',fsp,'Mexfun']);
   fprintf ('\n Now compiling the mexFunctions in:\n');
   fprintf (' %s\n',src);

   fname{1} = 'mexProd2';
   fname{2} = 'mexProd2nz';
   fname{3} = 'mexinprod';
   fname{4} = 'mexmat';
   fname{5} = 'mexsmat';
   fname{6} = 'mexsvec';
   fname{7} = 'mexschur';
   fname{8} = 'mexqops';
   fname{9} = 'mexexpand';
   fname{10} = 'mexskron';
   fname{11} = 'mexnnz';
   fname{12} = 'mexschurfun';
   fname{13} = 'mexMatvec';
   fname{14} = 'mextriang';
   fname{15} = 'mextriangsp';

   if exist('OCTAVE_VERSION'),
      mexcmd = 'mex ';
   else
      mexcmd = 'mex  -O -largeArrayDims  ';
   end
   for k = 1:length(fname)
       cmd = [mexcmd,fname{k},'.c'];
       disp( cmd );
       eval( cmd );
   end
   cd ..
   cd ..


function res = bf_write_gifti(BF, S)
% Writes out beamformer results as GIfTI meshes
% Copyright (C) 2013 Wellcome Trust Centre for Neuroimaging

% Vladimir Litvak
% $Id: bf_write_gifti.m 7703 2019-11-22 12:06:29Z guillaume $

%--------------------------------------------------------------------------
if nargin == 0
    normalise         = cfg_menu;
    normalise.tag     = 'normalise';
    normalise.name    = 'Global normalisation';
    normalise.help    = {'Normalise image values by the mean'};
    normalise.labels  = {
        'No'
        'Each image separately'
        'Across images'
        }';
    normalise.values  = {
        'no'
        'separate'
        'all'
        }';
    normalise.val = {'no'};

    space         = cfg_menu;
    space.tag     = 'space';
    space.name    = 'Image space';
    space.help    = {'Specify image space'};
    space.labels  = {
        'MNI'
        'Native'
        'MNI-aligned'
        }';
    space.values  = {
        'mni'
        'native'
        'aligned'
        }';
    space.val = {'mni'};

    visualise = cfg_menu;
    visualise.tag = 'visualise';
    visualise.name = 'Visualise the outputs';
    visualise.help = {'Visualise the outputs in the graphics window.'};
    visualise.labels = {'inflated', 'yes', 'no'};
    visualise.values = {2, 1, 0};
    visualise.val = {0};

    res      = cfg_branch;
    res.tag  = 'gifti';
    res.name = 'GIfTI';
    res.val  = {normalise, space, visualise};

    return
elseif nargin < 2
    error('Two input arguments are required');
end

if ~isfield(BF.sources, 'mesh')
    error('Only mesh source space is supported');
end

scale = ones(1, numel(BF.output.image));
switch S.normalise
    case  'separate'
        for i = 1:numel(BF.output.image)
            val = BF.output.image(i).val;
            scale(i) = 1./mean(abs(val(~isnan(val))));
        end
    case  'all'
        val = spm_vec({BF.output.image(:).val});
        scale = scale./mean(abs(val(~isnan(val))));
end

switch S.space
    case 'mni'
        source = BF.sources.mesh.canonical;
    case 'aligned'
        source = BF.sources.mesh.individual;
        source.vert =  spm_eeg_inv_transform_points(BF.data.transforms.toMNI_aligned, source.vert);
    case 'native'
        source = BF.sources.mesh.individual;
        source.vert =  spm_eeg_inv_transform_points(BF.data.transforms.toNative, source.vert);
end

save(gifti(source), [BF.data.D.fname '.surf.gii']);

nimages = numel(BF.output.image);

spm('Pointer', 'Watch');drawnow;
spm_progress_bar('Init', nimages , 'Writing out images'); drawnow;
if nimages  > 100, Ibar = floor(linspace(1, nimages ,100));
else Ibar = 1:nimages; end

for i = 1:nimages
    fname = fullfile(pwd, [BF.output.image(i).label '.gii']);

    G = gifti;
    G.private.metadata(1).name = 'SurfaceID';
    G.private.metadata(1).value = [BF.data.D.fname '.surf.gii'];

    G.cdata = scale(i)*BF.output.image(i).val;

    G.cdata = G.cdata(:);

    save(G, fname, 'ExternalFileBinary');

    res.files{i, 1} = fname;

    if S.visualise
        Fgraph  = spm_figure('GetWin', fname); figure(Fgraph); clf
        a = axes;
        if S.visualise == 2
            H = spm_mesh_render('Disp', spm_mesh_inflate(gifti([BF.data.D.fname '.surf.gii'])), 'Parent', a);
            H = spm_mesh_render('Overlay', H, gifti(fname));
        else
            H = spm_mesh_render('Disp',gifti([BF.data.D.fname '.surf.gii']), 'Parent', a);
            H = spm_mesh_render('Overlay', H, gifti(fname));
        end
         spm_mesh_render('Colormap', H, jet(256));
    end

    if ismember(i, Ibar)
        spm_progress_bar('Set', i); drawnow;
    end
end

spm_progress_bar('Clear');


function [compartmentMetabolites] = findMetFromCompartment(model, compartment)
% Finds all the metabolites and their identifiers in
% a compartment of interest.
%
% USAGE:
%
%    [compartmentMetabolites] = findMetFromCompartment(model,Compartment)
%
% INPUTS:
%    model:                     COBRA model strcture
%    compartment:               compartment of interest (e.g.: '[m]', '[n]', '[e]', etc.)
%
% OUTPUT:
%    compartmentMetabolites:    List of metabolites in the compartment of interest
%
% .. Authors:
%       - written by Diana El Assal 27/10/15

[metabolites]=[model.mets]; % Form a matrix with the metabolites and its identifiers
%Find the metabolites in the compartment of interest (e.g. '[m], '[n]')
compartmentMets=strfind(model.mets, compartment);
index=find(~cellfun(@isempty, compartmentMets));
compartmentMets=model.mets(index);

%Find all metabolite identifiers
for i=1:size(compartmentMets,1);
    num=find(ismember(metabolites(:,1),compartmentMets{i,1}));
    if ~isempty(num);
        compartmentMetabolites(i,:)=metabolites(num,:);
    end
end