%qsf() - submit a job to the Sun Grid Engine queue system,
% Revision 2.33 2006/08/15
%
% Usage:
% >> qsf( funcname, funcarg);
% >> status = qsf( funcname, funcarg, funcout, 'key', 'val' );
% >> status = qsf({{ funcname1, funcarg1, funcout1, 'key', 'val' ... } ...
% { funcname2, funcarg2, funcout2, 'key', 'val' ... }});
%
% Inputs:
% funcname - string for the function name. Can also be a cell array
% of cell arrays of calls to qsf() (see example).
% funcarg - cell array of the function arguments
% funcout - cell array of output variables in the global
% workspace (as strings). Default is [].
%
% Optional inputs:
% 'display' - ['on'|'off'] Send back display to original
% X window server. Default is 'on'./matlab/matlab
% 'mail' - ['on'|'off'] Send mail for job events (job beginning, ...
% end, abort, suspend). Default is 'off'.
% 'mailabort' - ['on'|'off'] Send mail only for job problems such as
% when the job is aborted or suspended. Default is 'on'.
% 'nice' - [integer] Renice the job. Default is 0.
% 'comsave' - [command] Instead of displaying the figure, the
% 'comsave' command is executed. Note that this can be
% use in conjunction with 'display'. By default, when
% the 'comsave' command is not empty, the 'display' is
% set to 'off', but you can force it to 'on' to save 'jpg'
% figures, for examppe, which requires the X-SERVER to be
% functional (though not required for printing '.eps' files
% or for using the hgsave() function).
% Ex: 'print -depsc /home/user/test.eps'
% 'hostname' - [string] Force hostname for display
% 'processes' - Cell array of other parallel function to launch. The
% syntax is the same as the qsf function. This is only
% useful if the called functions return some values
% (otherwise it is possible to launch all the commands
% sequentially).
% 'path' - [string] folder to store information for function calls.
% By default it is a directory named "qsub" in the home
% directory (folder is created if it does not exist). Use
% absolute paths.
% 'matlabpath' - [string] absolute path of Matlab on the cluster.
% 'jobname' - [string] Name of the job. Default is
% g.jobname = sprintf('%s_%06d', funcname, qsub_count) where
% qsub_count is a number that is stored in
% ['path' '_' funcname '_count.mat'] and is incremented by
% one for each call to qsf.m
%
% Outputs: status - [0|1] 0=fail, 1=suceeded to submit job
%
% Example:
%
% % Submit a single plotting job
% qsf('plot', { [0:10] });
%
% % Submit 4 plotting jobs and return
% >> qsf({{'plot', { [0:10] 'r' }}, { 'plot', { [10:20] 'm' } } ...
% { 'plot', { [20:30] 'g' } } { 'plot', { [30:40] 'y' } }} );
%
% % Submit 2 compute jobs and pop-up an editing window to enter commands
% % in the local workspace while the jobs are running
% >> qsf({ {'max', { [1:10,11:-1:1] }, { 'maxval' 'maxindex' }} ...
% {'min', { [1:10,11:-1:1] }, { 'minval' 'minindex' }}} );
% % The two jobs are strictly equivalent to the evaluation of the
% % following expression in the global workspace
% >> [maxval maxindex] = max([1:10,11:-1:1]);
% >> [minval minindex] = min([1:10,11:-1:1]);
%
% Note:
% qsf() will create a directory name "qsub" in your home direcoty,
% then create sub-folders in this directory (these folders may have to be
% removed manually).
% Recursive calls to qsf() from the qsf edit window are possible.
%
% Graphical interface:
% Execute a command: When jobs returns values to the global workspace,
% qsf() has to wait for them (to write a file) and an editing
% window pops-up for the user to enter local commands to execute. To
% execute a command, type in some text and press the "Execute button".
% Abort computation: it is also possible to abort the computation from the local
% Matlab session by pressing the abort button (Note: jobs sent to the
% grid are not automatically killed and have to be killed manually using
% the command 'qdel' under Unix).
% Close window: When computation is finished, the Abort button becomes
% inactivated and the "Ready to close" button becomes activated. The window
% does not close automatically, since the user might be editing some text.
%
% Troubleshooting:
% The function has been tested on Matlab 6.1 under Redhat Linux 2.4.19
% using Sun Grid Engine 5.2 and tcsh shell.
% 1) Problems may arise with use of bash.
% 2) Check that the nice command is accessible in /bin/nice otherwise
% edit the code and enter the location of the nice command (or simply
% "nice").
% 3) For any other problem, contact arno@salk.edu with a detailed
% description of the problem.
%
% Version:
% The latest version of this function is available at
% www.sccn.ucsd.edu/~arno/qsf/qsf.php
%
% Authors: Arnaud Delorme, CNL / Salk Institute, 11 Oct 2002
% (Joern Anemueller for the Unix qsub call syntax)
%
% See also: eeglab()
%123456789012345678901234567890123456789012345678901234567890123456789012
% Copyright (C) 2002 Arnaud Delorme & Jorn Anemuller, Salk Institute, arno@salk.edu
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
% $Log: qsf.m,v $
%
% Revision 2.33 2006/08/15 17:29:01 ag
% Fixed problem with funcout values not being returned
% due to using ischar instead of isstruct in line:
% if ~isstruct(pendingjobs) % abort
%
% Revision 2.32 2006/08/15 12:36:57 ag
% Removed xhost setting. This did not work
% as written, and I felt it better to set
% X outside of matlab.
%
% Revision 2.31 2006/05/30 12:17:57 Al Graham
% Changed default nice level to 0, ie. no niceing.
%
% Revision 2.30 2006/05/24 11:38:09 Al Graham
% Various minor changes and a bug fix. qsf now properly
% returns to original directory. Modified job counting file
% to be count_file = [g.path '_count.mat'].
%
% Revision 2.20 2006/05/15 13:28:55 Al Graham
% Modified random job naming to default
% '[funcname]_[qsub_count]' where qsub_count is a number
% that is stored in ~/matlab/qsub_count.mat and is
% incremented by one for each call to qsf.m.
% This aids job traceability and prevents random name collisions.
%
% Revision 2.10 2006/05/10 18:32:37 Al Graham
% Converted to using bash shell. Now a bash script and a
% matlab script are created and saved. The bash script
% submits a qmon job that runs matlab on the matlab script.
% Also changed name to qsf.m
%
% Revision 2.00 2006/05/10 18:32:37 Al Graham
% Ran mlint and fixed some issues.
%
% Revision 1.31 2005/03/22 17:28:16 arno
% debugging some calls
%
% Revision 1.30 2003/04/15 22:20:17 arno
% adding path option
%
% Revision 1.29 2003/04/15 22:04:05 arno
% adding csh command
%
% Revision 1.28 2003/03/15 20:42:46 scott
% header edit -sm
%
% Revision 1.27 2002/11/15 01:42:24 scott
% Can not -> cannot
%
% Revision 1.26 2002/11/01 19:51:52 arno
% putting back error fle check
%
% Revision 1.25 2002/11/01 18:35:33 arno
% removing .e and .o file checking -> appear at once
%
% Revision 1.24 2002/11/01 18:22:28 arno
% disble file deletion
%
% Revision 1.23 2002/11/01 18:09:26 arno
% dealing with qsub error messages
%
% Revision 1.22 2002/11/01 17:04:16 arno
% force hostname
%
% Revision 1.21 2002/11/01 00:58:23 arno
% go back to the original directory for writing
%
% Revision 1.20 2002/10/31 22:42:26 arno
% back to previous dir
%
% Revision 1.19 2002/10/25 16:41:51 arno
% add quesdlg2 and more doc
%
% Revision 1.18 2002/10/25 01:59:33 arno
% adding finputcheck code
%
% Revision 1.17 2002/10/25 01:55:47 arno
% including supergui in qsubfunc
%
% Revision 1.16 2002/10/25 00:41:34 arno
% nice update
%
% Revision 1.15 2002/10/25 00:35:14 arno
% debug command call
%
% Revision 1.14 2002/10/25 00:32:14 arno
% job index corrected
%
% Revision 1.13 2002/10/25 00:28:10 arno
% more debuging
%
% Revision 1.12 2002/10/25 00:20:43 arno
% update qsubfunc for real parallel processing
%
% Revision 1.11 2002/10/24 22:18:44 arno
% remove directory
%
% Revision 1.10 2002/10/24 20:13:40 arno
% remove comment
%
% Revision 1.9 2002/10/24 20:12:47 arno
% new qsubfunc mutiprocess
%
% Revision 1.8 2002/10/21 18:52:17 arno
% nice update
%
% Revision 1.7 2002/10/21 17:30:57 arno
% reset random generator
%
% Revision 1.6 2002/10/14 01:05:40 arno
% xhost +
%
% Revision 1.5 2002/10/13 23:26:17 arno
% putting path to the UNIX call
%
% Revision 1.4 2002/10/11 18:14:59 arno
% new options
%
% Revision 1.3 2002/10/11 17:26:37 arno
% debugging display
%
% Revision 1.2 2002/10/11 17:05:49 arno
% real intial revision
%
% note for how to return values
% I looked thrgh all the documentation, etc and there is 2 solutions
% 1 - write my own editor, so that the user is still able to evaluate expressions.
% I can make a simple edit box and scroll the text up dan down, while using
% the global workspace.
% 2 - start asynchronously mex commands
function status = qsf( funcname, funcarg, funcout, varargin )
% Explicit path to matlab executable on cluster to avoid automounting problems.
% matlab_path = '/usr/local/matlab71/bin/matlab';
matlab_path = '/usr/local/bin/matlab'; %'matlab';
local_path = '~/qsub';
status = 0;
if nargin < 1
help qsf;
return;
end;
if nargin < 2
funcarg = {};
end;
if nargin < 3
funcout = {};
end;
if iscell(funcname)
disp('If the function does not work, specify explicitely')
disp('the location of the Matlab executable on the cluster')
disp('and the location of the local temporary folder to store results');
disp(' ');
oldd = pwd;
if length(funcname{1}) == 2
qsf(funcname{1}{:}, {}, 'processes', funcname(2:end));
elseif length(funcname{1}) == 3
qsf(funcname{1}{:}, 'processes', funcname(2:end));
else
error('Wrong number of arguments for first function call');
end;
cd(oldd);
return;
end;
% check inputs
% ------------
g = finputcheck(varargin, { 'display' 'string' { 'on' 'off' } 'on'; ...
'jobname' 'string' [] ''; ...
'mail' 'string' { 'on' 'off' } 'off'; ...
'jobindex' 'integer' [] 1; ...
'hostname' 'string' [] ''; ...
'nice' 'integer' [] 0; ...
'path' 'string' [] local_path; ...
'matlabpath' 'string' [] matlab_path; ...
'mailabort' 'string' { 'on' 'off' } 'on'; ...
'processes' 'cell' [] {}; ...
'comsave' 'string' [] ''}, 'qsf');
if ischar(g), error(g); end;
if g.path(end) == '/', g.path = g.path(1:end-1); end;
count_file = [g.path '_count.mat'];
if exist(count_file)
load(count_file,'qsub_count')
qsub_count = qsub_count+1;
save(count_file,'qsub_count')
else
qsub_count = 1;
save(count_file,'qsub_count')
end
g.jobname = sprintf('%s_%06d', funcname, qsub_count);
if ~ischar(funcname)
disp('Error qsf arguments: funcname must be a string, call aborted');
return;
end;
if ~isempty(funcarg)
if ~iscell(funcout)
disp('Error qsf arguments: funcarg must be a cell array, call aborted');
return;
end;
end;
if ~isempty(funcout)
if ~iscell(funcout)
disp('Error qsf arguments: funcout must be a cell array, call aborted');
return;
else
for index = 1:length(funcout)
if ~ischar(funcout{index})
disp('Error qsf arguments: funcout must be a cell array of strings, call aborted');
return;
end;
end;
end;
end;
% copy param file to directory
% ----------------------------
oldd = pwd;
cd ~
[res tmp] = unix([ 'mkdir ' g.path ]);
cd(g.path)
fprintf('********************** Processing job %d ***********************\n', g.jobindex);
fprintf('All results for this process will be stored in folder ''%s'': ', [ g.path '/' g.jobname ]);
[res tmp] = mkdir(g.jobname);
if res ~= 1,
fprintf('error, cannot create folder\n');
cd(oldd);
return;
else
fprintf('OK (folder created)\n');
cd(g.jobname);
end;
save('funcarg.mat', '-mat', 'funcarg');
% prepare function outputs
% ------------------------
argsout = '';
saveout = '';
for index = 1:length(funcout)
argsout = [ argsout ' out' int2str(index) ];
saveout = [ saveout '''out' int2str(index) ''','];
end;
if ~isempty(argsout), argsout = [ '[' argsout '] =' ]; end;
% make and execute command
% ------------------------
matlabcom = [ 'cd(''' g.path '/' g.jobname ''');' ...
'load(''funcarg.mat''); ' ...
'lasterr(''''); ' ...
argsout funcname '(funcarg{:}); ' ];
if isempty(g.hostname)
[tmp g.hostname] = unix('hostname');
end;
matlabopt = '-nosplash -nodesktop';
if strcmpi(g.display, 'off')
matlabopt = [ matlabopt ' -nodisplay' ];
else
if isempty(g.comsave)
matlabcom =[matlabcom 'if ~isempty(get(0, ''currentfigure'')); waitfor(gcf); end;' ];
end;
end;
if ~isempty(argsout)
matlabcom = [ matlabcom 'cd ' g.path '/' g.jobname ';funcerr = lasterr; if isempty(funcerr), save(''funcout.mat'', ''-mat'',' saveout ' ''funcerr'');' ...
'else, save(''funcout.mat'', ''funcerr''); end;' ];
end;
matlabcom =[matlabcom g.comsave ' quit force' ];
cd(sprintf('%s/%s',g.path,g.jobname));
matlab_script = [ g.jobname '.m' ];
if exist(matlab_script)
delete(matlab_script);
end
fid = fopen(matlab_script,'w');
fprintf(fid,'%s\n',matlabcom);
fclose(fid);
unixcom = [ 'hostname; cd ' g.path '/' g.jobname ';' ...
'/bin/nice -n ' int2str(g.nice) ' ' g.matlabpath ' ' ...
matlabopt ' -r ' g.jobname ';'];
if isempty(funcout)
unixcom = [ unixcom 'cd ..;'];
end;
if strcmp(g.mail, 'on'), qsubopt = '-m beas';
elseif strcmp(g.mailabort, 'on'), qsubopt = '-m as';
else qsubopt ='';
end;
run_script = [ g.jobname '.bash' ];
if exist(run_script)
delete(run_script);
end
fid_run = fopen(run_script,'w');
fprintf(fid_run,'#! /bin/bash\n\n# Author: A. Delorme & Al Graham\n# Date: 060512\n\n%s\n',unixcom);
fclose(fid_run);
unix(sprintf('chmod +x %s',run_script));
strCmd = [ 'qsub ' qsubopt ' -N ' g.jobname ' -o ' g.path '/' g.jobname ' -e ' g.path '/' g.jobname ' ' run_script ];
qsub_script = [ g.jobname '.qsub' ];
if exist(qsub_script)
delete(qsub_script);
end
fid_qsub = fopen(qsub_script,'w');
fprintf(fid_qsub,'#! /bin/bash\n\n# Author: A. Delorme & Al Graham\n# Date: 060515\n\n%s\n',strCmd);
fclose(fid_qsub);
unix(sprintf('chmod +x %s', qsub_script));
fprintf('\nUnix command: \t%s\n', strCmd);
submit_jobs = true;
if submit_jobs
[ucstatus, message] = unix(qsub_script);
if (ucstatus == 0)
disp(' was sucessfully submitted to cluster.');
else
disp(['*** Unix command submission error message ' message ' ***']);
end
else
disp(' created but not submitted');
end
disp(' ');
% create editing window
% ---------------------
windowcreator = 0;
fig = findobj('tag', 'qsf');
if isempty(fig)
fig = figure('visible', 'off', 'tag', 'qsf', 'userdata', []);
abortcom = [ 'if strcmpi(questdlg2(''All pending data will be lost'', ''Cancel'', ''Ok'', ''Ok''), ''ok''),' ...
'set(gcbf, ''userdata'', -1); end;' ];
execcom = [ 'disp(get(findobj(gcbf, ''tag'', ''strcommand''), ''string''));' ...
'evalin(''base'', get(findobj(gcbf, ''tag'', ''strcommand''), ''string''), ''disp(lasterr);''); drawnow;'];
supergui( fig, [1 1 1 3], [1 4 1 1], {'style' 'text' 'string', 'Enter matlab command below ' }, ...
{'style' 'edit' 'string', '', 'tag', 'strcommand', 'HorizontalAlignment', 'left' }, ...
{'style' 'text' 'string', 'Job running (only includes job that have not returned yet): 1', 'tag', 'jobrun' }, ...
{'style' 'pushbutton' 'string', 'abort', 'tag', 'abort', 'callback', abortcom }, ...
{'style' 'pushbutton' 'string', 'Ready to close', 'tag', 'close', 'enable', 'off', 'callback', 'close(gcbf);' }, ...
{'style' 'pushbutton' 'string', 'Execute', 'callback', execcom } );
set(gcf, 'visible', 'off');
windowcreator = 1;
else
objjob = findobj(fig, 'tag', 'jobrun');
curjobs = get(fig, 'userdata');
if isempty(curjobs)
windowcreator = 1;
end;
end;
if ~isempty(funcout)
curjobs = get(fig, 'userdata');
curjobs(end+1).proc = g.jobindex;
curjobs(end).folder = g.jobname;
curjobs(end).funcout = funcout;
set(fig, 'userdata', curjobs);
objjob = findobj(fig, 'tag', 'jobrun');
set(objjob, 'string', ['Job running (only includes job returning outputs): ' , int2str(length(curjobs)) ] );
drawnow;
set(findobj(fig, 'tag', 'abort'), 'enable', 'on');
set(findobj(fig, 'tag', 'close'), 'enable', 'off'); % do not allow window to close
end;
% deal with other processes to launch
% -----------------------------------
if ~isempty(g.processes)
cd(oldd);
for index = 1:length(g.processes)
if length(g.processes{index}) == 2
qsf(g.processes{index}{:}, {}, 'jobindex', g.jobindex+index);
elseif length(g.processes{index}) == 3
qsf(g.processes{index}{:}, 'jobindex', g.jobindex+index);
else
error([ 'Wrong number of arguments for function in process ' int2str(index+1) ]);
end;
end;
end;
% waiting for outputs and processing them
% ---------------------------------------
if windowcreator
fig = findobj('tag', 'qsf');
pendingjobs = length(get(fig, 'userdata'));
if pendingjobs == 0
status = 1;
cleanup;
cd(oldd);
return;
else
set(fig, 'visible', 'on');
drawnow;
end;
cd(g.path);
while length(pendingjobs) > 0
pause(0.5);
pendingjobs = get(fig, 'userdata');
if ~isstruct(pendingjobs) % abort
close(fig);
disp('Warning: jobs might still be running on other machines');
pendingjobs = [];
end;
index = 1;
while index <= length(pendingjobs)
tmpdir = dir([ '~/' pendingjobs(index).folder '.e*']);
if (~isempty(tmpdir) && tmpdir(1).bytes ~= 0) || exist([ pendingjobs(index).folder '/funcout.mat' ])
% reading outputs to global workspace
% -----------------------------------
if exist([ pendingjobs(index).folder '/funcout.mat' ])
evalin('base', [ 'load(''' pendingjobs(index).folder '/funcout.mat'');' ]);
else
evalin('base', [ 'tmpfid = fopen(''~/' tmpdir(1).name ''', ''r'');' ...
'funcerr = '''';' ...
'while ~feof(tmpfid), funcerr = [ funcerr fgets(tmpfid) ]; end;' ...
'fclose(tmpfid);' ]);
end;
% cleaning up
% -----------
tmpdir = dir([ '~/' pendingjobs(index).folder '.*']);
%unix(['rm -f ~/' tmpdir(1).name ]);
%unix(['rm -f ~/' tmpdir(2).name ]);
%unix(['rm -f -r ' pendingjobs(index).folder ]);
if evalin('base', '~isempty(funcerr)')
evalin('base', 'funcerr = sprintf(''\nError while calling process using qsub:\n\n%s'', funcerr); disp(funcerr);');
else
funcout = pendingjobs(index).funcout;
fprintf('Process %d: Loading ''%s'' function return variables ''%s'' ...\n', pendingjobs(index).proc, funcname, funcout{1});
for indexout = 1:length(funcout)
evalin('base', [ funcout{indexout} ' = out' int2str(indexout) ';' ], 'disp(lasterr);');
evalin('base' , ['clear out' int2str(indexout) ]);
warning on;
end;
end;
evalin('base', 'clear funcerr;');
% update gui window
% -----------------
pendingjobs(index) = [];
set(fig, 'userdata', pendingjobs);
objjob = findobj(fig, 'tag', 'jobrun');
set(objjob, 'string', ['Jobs running (only includes jobs returning outputs): ' int2str(length(pendingjobs))] );
drawnow;
end;
index = index + 1;
end;
end; % end while
cleanup;
end;
cd(oldd);
status = 1;
return;
function cleanup
fig = findobj('tag', 'qsf');
if ~isempty(fig)
set(findobj(fig, 'tag', 'abort'), 'enable', 'off'); % allow window to close
set(findobj(fig, 'tag', 'close'), 'enable', 'on'); % allow window to close
end;
% questdlg2() - questdlg function clone with coloring and help for
% eeglab().
%
% Usage: same as questdlg()
%
% Warning:
% Case of button text and result might be changed by the function
%
%
% Author: Arnaud Delorme, CNL / Salk Institute, La Jolla, 11 August 2002
%
% See also: inputdlg2(), errordlg2(), supergui(), inputgui()
%123456789012345678901234567890123456789012345678901234567890123456789012
% Copyright (C) Arnaud Delorme, CNL / Salk Institute, arno@salk.edu
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
% $Log: qsubfunc.m,v $
% Revision 1.31 2005/03/22 17:28:16 arno
% debugging some calls
%
% Revision 1.30 2003/04/15 22:20:17 arno
% adding path option
%
% Revision 1.29 2003/04/15 22:04:05 arno
% adding csh command
%
% Revision 1.28 2003/03/15 20:42:46 scott
% header edit -sm
%
% Revision 1.27 2002/11/15 01:42:24 scott
% Can not -> cannot
%
% Revision 1.26 2002/11/01 19:51:52 arno
% putting back error fle check
%
% Revision 1.25 2002/11/01 18:35:33 arno
% removing .e and .o file checking -> appear at once
%
% Revision 1.24 2002/11/01 18:22:28 arno
% disble file deletion
%
% Revision 1.23 2002/11/01 18:09:26 arno
% dealing with qsub error messages
%
% Revision 1.22 2002/11/01 17:04:16 arno
% force hostname
%
% Revision 1.21 2002/11/01 00:58:23 arno
% go back to the original directory for writing
%
% Revision 1.20 2002/10/31 22:42:26 arno
% back to previous dir
%
% Revision 1.19 2002/10/25 16:41:51 arno
% add quesdlg2 and more doc
%
% Revision 1.11 2002/10/15 17:23:50 arno
% drawnow
%
% Revision 1.10 2002/10/15 16:54:09 arno
% add drawnow ofr windows
%
% Revision 1.9 2002/10/15 14:45:12 arno
% display warning
%
% Revision 1.8 2002/10/15 14:35:52 arno
% default case for buttons
%
% Revision 1.7 2002/08/14 18:17:00 arno
% new supergui arg
%
% Revision 1.6 2002/08/13 22:36:43 arno
% debug for error
%
% Revision 1.5 2002/08/13 17:29:35 arno
% new superguicall
%
% Revision 1.4 2002/08/12 18:49:20 arno
% header
%
% Revision 1.3 2002/08/12 18:24:29 arno
% debug
%
% Revision 1.2 2002/08/12 18:02:47 arno
% debug
%
% Revision 1.1 2002/08/12 18:01:34 arno
% Initial revision
%
function [result] = questdlg2(Prompt,Title,varargin)
result = varargin{end};
if nargin < 2
help questdlg2;
return;
end;
if Prompt(end) == 10, Prompt(end) = []; end;
if Prompt(end) == 10, Prompt(end) = []; end;
if Prompt(end) == 10, Prompt(end) = []; end;
if Prompt(end) == 10, Prompt(end) = []; end;
fig = figure('visible', 'off');
set(gcf, 'name', Title);
geometry = { 1 };
listui = {{ 'Style', 'text', 'string' Prompt }};
geometry = { geometry{:} ones(1,length(varargin)-1) };
for index = 1:length(varargin)-1 % ignoring default val
listui = {listui{:} { 'Style', 'pushbutton', 'string', varargin{index}, 'callback', ['set(gcbf, ''userdata'', ''' varargin{index} ''');'] } };
if strcmp(varargin{index}, varargin{end})
listui{end}{end+1} = 'fontweight';
listui{end}{end+1} = 'bold';
end;
end;
cr = length(find(Prompt == char(10)))+1;
if cr == 1
cr = size(Prompt,1);
end;
[tmp tmp2 allobj] = supergui( fig, geometry, [cr 1], listui{:} );
waitfor( fig, 'userdata');
try
result = get(fig, 'userdata');
close(fig);
drawnow;
catch
% Nothing
end;
% supergui() - a comprehensive gui automatic builder. This function help
% to create GUI very fast without bothering about the
% positions of the elements. After creating a geometry,
% elements just place themselves into the predefined
% locations. It is especially usefull for figure where you
% intend to put text button and descriptions.
%
% Usage:
% >> [handlers, width, height ] = ...
% supergui( geomx, geomy, { arguments1 }, { arguments2 }... );
%
% Inputs:
% figh - figure handler, if 0 create a new figure
% geomx - cell array describing the geometry of the elements
% in the figure. For instance, [2 3 2] means that the
% figures will have 3 rows, with 2 elements in the first
% and last row and 3 elements in the second row.
% An other syntax is { [2 8] [1 2 3] } which means
% that figures will have 2 rows, the first one with 2
% elements of relative width 2 and 8 (20% and 80%). The
% second row will have 3 elements of relative size 1, 2
% and 3.
% geomy - [array] describting geometry for the rows. For instance
% [1 2 1] means that the second row will be twice the height
% of the other ones. If [], all the lines have the same height.
% {argument} - GUI matlab element arguments. Ex { 'style',
% 'radiobutton', 'String', 'hello' }.
%
% Hint:
% use 'print -mfile filemane' to save a matlab file of the figure.
%
% Output:
% handlers - all the handler of the elements (in the same form as the
% geometry cell input.
% height - adviced widht for the figure (so the text look nice).
% height - adviced height for the figure (so the text look nice).
%
% Example:
% figure;
% supergui( [1 1], [], { 'style', 'radiobutton', 'string', 'radio' }, ...
% { 'style', 'pushbutton', 'string', 'push' });
%
% Author: Arnaud Delorme, CNL / Salk Institute, La Jolla, 2001
%
% See also: eeglab()
%123456789012345678901234567890123456789012345678901234567890123456789012
% Copyright (C) 2001 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
% $Log: qsubfunc.m,v $
% Revision 1.31 2005/03/22 17:28:16 arno
% debugging some calls
%
% Revision 1.30 2003/04/15 22:20:17 arno
% adding path option
%
% Revision 1.29 2003/04/15 22:04:05 arno
% adding csh command
%
% Revision 1.28 2003/03/15 20:42:46 scott
% header edit -sm
%
% Revision 1.27 2002/11/15 01:42:24 scott
% Can not -> cannot
%
% Revision 1.26 2002/11/01 19:51:52 arno
% putting back error fle check
%
% Revision 1.25 2002/11/01 18:35:33 arno
% removing .e and .o file checking -> appear at once
%
% Revision 1.24 2002/11/01 18:22:28 arno
% disble file deletion
%
% Revision 1.23 2002/11/01 18:09:26 arno
% dealing with qsub error messages
%
% Revision 1.22 2002/11/01 17:04:16 arno
% force hostname
%
% Revision 1.21 2002/11/01 00:58:23 arno
% go back to the original directory for writing
%
% Revision 1.20 2002/10/31 22:42:26 arno
% back to previous dir
%
% Revision 1.19 2002/10/25 16:41:51 arno
% add quesdlg2 and more doc
%
% Revision 1.18 2002/10/25 01:59:33 arno
% adding finputcheck code
%
% Revision 1.17 2002/10/25 01:55:47 arno
% including supergui in qsubfunc
%
% Revision 1.34 2002/10/23 15:06:40 arno
% isppc -> computer
%
% Revision 1.33 2002/10/15 16:25:15 arno
% magnify edit boxes windows
%
% Revision 1.32 2002/10/15 14:42:15 arno
% button text aspect
%
% Revision 1.31 2002/08/20 22:33:34 arno
% debug for Mac
%
% Revision 1.30 2002/08/19 19:12:16 arno
% debugging last
%
% Revision 1.29 2002/08/19 19:10:13 arno
% figure bigger for MAC
%
% Revision 1.28 2002/08/17 02:38:42 arno
% debugging
%
% Revision 1.27 2002/08/14 18:17:23 arno
% new supergui arg
%
% Revision 1.26 2002/08/14 18:07:20 arno
% changing default checkbox backcolor
%
% Revision 1.25 2002/08/14 16:32:37 arno
% yfact takes into account button now
%
% Revision 1.24 2002/08/13 23:04:51 arno
% debug pop_merge
%
% Revision 1.23 2002/08/13 18:59:49 arno
% update automatic INSETY
%
% Revision 1.22 2002/08/13 18:56:01 arno
% adjustments
%
% Revision 1.21 2002/08/13 18:50:54 arno
% same
%
% Revision 1.20 2002/08/13 18:50:31 arno
% vert align
%
% Revision 1.19 2002/08/13 17:40:41 arno
% same
%
% Revision 1.18 2002/08/13 17:38:13 arno
% ordinate adjustment
%
% Revision 1.17 2002/08/13 17:28:56 arno
% new geometry
%
% Revision 1.16 2002/08/13 00:20:42 arno
% same
%
% Revision 1.15 2002/08/13 00:20:22 arno
% update position
%
% Revision 1.14 2002/08/12 21:42:59 arno
% ignore pushbutton extent
%
% Revision 1.13 2002/08/12 16:00:57 arno
% same
%
% Revision 1.12 2002/08/12 16:00:13 arno
% do not adapt size for edit windows
%
% Revision 1.11 2002/08/12 15:57:04 arno
% size calculation
%
% Revision 1.10 2002/08/12 14:50:15 arno
% color
%
% Revision 1.9 2002/08/12 14:47:40 arno
% color
%
% Revision 1.8 2002/08/12 14:30:55 arno
% background
%
% Revision 1.7 2002/08/12 01:17:42 arno
% update colors
%
% Revision 1.6 2002/08/12 00:41:41 arno
% updating default colors
%
% Revision 1.5 2002/07/18 17:18:31 arno
% offscreen correction
%
% Revision 1.4 2002/07/18 17:13:05 arno
% same
%
% Revision 1.3 2002/07/18 17:11:19 arno
% correct out-of screen problem
%
% Revision 1.2 2002/07/18 17:07:40 arno
% no modif
%
% Revision 1.1 2002/04/05 17:39:45 jorn
% Initial revision
%
function [handlers, outheight, allhandlers] = supergui( fig, geomx, geomy, varargin)
% handlers cell format
% allhandlers linear format
INSETX = 0.05; % x border absolute (5% of width)
INSETY = 0.05/length(geomx); % y border relative (50% of heigth)
if nargin < 2
help supergui;
return;
end;
if fig == 0
figure('visible','off');
end;
% converting the geometry formats
% -------------------------------
if ~iscell( geomx )
oldgeom = geomx;
geomx = {};
for row = 1:length(oldgeom)
geomx = { geomx{:} ones(1, oldgeom(row)) };
end;
end;
if isempty(geomy)
geomy = ones(1, length(geomx));
end;
% setting relative width in percent
% ---------------------------------
for row = 1:length(geomx)
tmprow = geomx{row};
sumrow = sum(geomx{row});
geomx{row} = 1.05*geomx{row}/sumrow;
geomx{row} = geomx{row} - INSETX*(length(tmprow)-1)/length(tmprow);
end;
% setting relative height in percent
% ---------------------------------
sumcol = sum(geomy);
geomy = (1.03+0.003*sumcol)*geomy/sumcol;
geomy = geomy - INSETY*(length(geomy)-1)/length(geomy);
% get axis coordinates
% --------------------
set(gcf, 'menubar', 'none', 'numbertitle', 'off');
pos = get(gca,'position'); % plot relative to current axes
q = [pos(1) pos(2) 0 0];
s = [pos(3) pos(4) pos(3) pos(4)]; % allow to use normalized position [0 100] for x and y
axis('off');
% creating guis
% -------------
counter = 1; % count the elements
outwidth = 0;
outheight = 0;
%height = 1.05/(length(geomx)+1)*(1-INSETY);
%posy = 1 - height - 1/length(geomx)*INSETY;
factmultx = 0;
factmulty = 0; %zeros(length(geomx));
posy = 0.98+(0.003*sumcol)/2+INSETY;
for row = 1:length(geomx)
% init
posx = -0.05;
clear rowhandle;
tmprow = geomx{row};
height = geomy(row);
posy = posy - height - INSETY;
for column = 1:length(tmprow)
width = tmprow(column);
try
currentelem = varargin{ counter };
catch
fprintf('Warning: not all boxes were filled\n');
return;
end;
if ~isempty(currentelem)
rowhandle(column) = uicontrol( 'unit', 'normalized', 'position', ...
[posx posy width height].*s+q, currentelem{:});
% this simply compute a factor so that all uicontrol will be visible
% ------------------------------------------------------------------
style = get( rowhandle(column), 'style');
set( rowhandle(column), 'units', 'pixels');
curpos = get(rowhandle(column), 'position');
curext = get(rowhandle(column), 'extent');
if ~strcmp(style, 'edit') && ~strcmp(style, 'pushbutton')
factmultx = max(factmultx, curext(3)/curpos(3));
end;
factmulty = max(factmulty, curext(4)/curpos(4));
set( rowhandle(column), 'units', 'normalized');
% Uniformize button text aspect
% -----------------------------
if strcmp(style, 'pushbutton')
tmptext = lower(get(rowhandle(column), 'string'));
try tmptext(1) = upper(tmptext(1)); catch end;
set(rowhandle(column), 'string', tmptext);
end;
else
rowhandle(column) = 0;
end;
handlers{ row } = rowhandle;
allhandlers(counter) = rowhandle(column);
posx = posx + width + INSETX;
counter = counter+1;
end;
%posy = posy - height - 1/length(geomx)*INSETY; %compensate for inset
end;
% adjustments
% -----------
factmultx = factmultx+0.1; % because some text was still hidden
if factmultx < 0.3
factmultx = 0.3;
end;
% for MAC (magnify figures that have edit fields)
% -------
warning off;
try
if strcmp(computer, 'MAC')
hh = findobj(allhandlers, 'style', 'edit');
if ~isempty(hh)
factmulty = factmulty*1.4;
end;
elseif ~isunix % windows
hh = findobj(allhandlers, 'style', 'edit');
if ~isempty(hh)
factmulty = factmulty*1.15;
end;
end;
catch
% Nothing
end;
warning on;
% scale and replace the figure in the screen
% -----------------------------------------
pos = get(gcf, 'position');
if factmulty > 1
pos(2) = max(0,pos(2)+pos(4)-pos(4)*factmulty);
end;
pos(1) = pos(1)+pos(3)*(1-factmultx)/2;
pos(3) = pos(3)*factmultx;
pos(4) = pos(4)*factmulty;
set(gcf, 'position', pos);
% vertical alignment to bottom for text
% ---------------------------------------
for index = 1:length(allhandlers)
if allhandlers(index) ~= 0
if strcmp(get(allhandlers(index), 'style'), 'text')
curpos = get(allhandlers(index), 'position');
curext = get(allhandlers(index), 'extent');
set(allhandlers(index), 'position',[curpos(1) curpos(2) curpos(3) curext(4)]);
end;
end;
end;
% setting defaults colors
%------------------------
try
icadefs;
catch
GUIBACKCOLOR = [.8 .8 .8];
GUIPOPBUTTONCOLOR = [.8 .8 .8];
GUITEXTCOLOR = [0 0 0];
end;
hh = findobj(allhandlers, 'parent', gcf, 'style', 'text');
%set(hh, 'BackgroundColor', get(gcf, 'color'), 'horizontalalignment', 'left');
set(hh, 'Backgroundcolor', GUIBACKCOLOR);
set(hh, 'foregroundcolor', GUITEXTCOLOR);
set(gcf, 'color',GUIBACKCOLOR );
set(hh, 'horizontalalignment', 'left');
hh = findobj(allhandlers, 'style', 'edit');
set(hh, 'BackgroundColor', [1 1 1]); %, 'horizontalalignment', 'right');
hh =findobj(allhandlers, 'parent', gcf, 'style', 'pushbutton');
set(hh, 'backgroundcolor', GUIPOPBUTTONCOLOR);
set(hh, 'foregroundcolor', GUITEXTCOLOR);
hh =findobj(allhandlers, 'parent', gcf, 'style', 'checkbox');
if isunix
set(hh, 'backgroundcolor', GUIPOPBUTTONCOLOR);
set(hh, 'foregroundcolor', GUITEXTCOLOR);
else
set(hh, 'backgroundcolor', GUIBACKCOLOR);
set(hh, 'foregroundcolor', GUITEXTCOLOR);
end;
hh =findobj(allhandlers, 'parent', gcf, 'style', 'listbox');
set(hh, 'backgroundcolor', GUIPOPBUTTONCOLOR);
set(hh, 'foregroundcolor', GUITEXTCOLOR);
hh =findobj(allhandlers, 'parent', gcf, 'style', 'radio');
set(hh, 'foregroundcolor', GUITEXTCOLOR);
set(hh, 'backgroundcolor', GUIPOPBUTTONCOLOR);
set(gcf, 'visible', 'on');
return;
% finputcheck() - check matlab function { 'key', 'val' } inputs
%
% Usage: >> struct = finputcheck( varargin, fieldlist );
% >> [struct varargin] = finputcheck( varargin, fieldlist, ...
% callingfunc, mode );
%
% Input:
% varargin - varargin arguement from a function call with 'key', 'val'
% arguements.
% fieldlist - 3 or 4 columns cell array with one row per variable. The first
% column contain the variable name, the second one the type,
% the third the accepted value range and the fourth one the
% defaultvalue. Ex:
% { 'varanme1' { 'value1' 'value2' } 'defaultvaluevar1' }
% { 'varanme2' { int1 int2 } 'defaultvaluevar2' }
% etc...
% allowed types are 'boolean', 'integer', 'real', 'string',
% 'cell' or 'struct'
% the fifth column may contain the size (can be a cell array
% of size), but is optional.
% callingfunc - calling function name for error messages. Default is none.
% mode - ['ignore'|'error'] ignore keywords that are not specified in
% the fieldlist cell array or generate an error. Default is
% 'error'.
% Outputs:
% struct - checked structure
% varargin - residual varagin with non-recognized arguments
%
% Note: in case of error, a string is returned with the error message
% instead of a structure.
%
% Example:
% finputcheck(varargin,
% { 'title' 'string' [] '';
% 'percent' 'real' [0 1] 1 ;
% 'elecamp' 'integer' [1:10] [] });
% 'title' is a string with no default value
% 'percent' is a real number in between 0 and 1 and default value 1
% 'elecamp' is an integer that can tak value between 1 and 10
%
% Author: Arnaud Delorme, CNL / Salk Institute, 10 July 2002
%123456789012345678901234567890123456789012345678901234567890123456789012
% Copyright (C) Arnaud Delorme, CNL / Salk Institute, 10 July 2002, arno@salk.edu
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
% $Log: qsubfunc.m,v $
% Revision 1.31 2005/03/22 17:28:16 arno
% debugging some calls
%
% Revision 1.30 2003/04/15 22:20:17 arno
% adding path option
%
% Revision 1.29 2003/04/15 22:04:05 arno
% adding csh command
%
% Revision 1.28 2003/03/15 20:42:46 scott
% header edit -sm
%
% Revision 1.27 2002/11/15 01:42:24 scott
% Can not -> cannot
%
% Revision 1.26 2002/11/01 19:51:52 arno
% putting back error fle check
%
% Revision 1.25 2002/11/01 18:35:33 arno
% removing .e and .o file checking -> appear at once
%
% Revision 1.24 2002/11/01 18:22:28 arno
% disble file deletion
%
% Revision 1.23 2002/11/01 18:09:26 arno
% dealing with qsub error messages
%
% Revision 1.22 2002/11/01 17:04:16 arno
% force hostname
%
% Revision 1.21 2002/11/01 00:58:23 arno
% go back to the original directory for writing
%
% Revision 1.20 2002/10/31 22:42:26 arno
% back to previous dir
%
% Revision 1.19 2002/10/25 16:41:51 arno
% add quesdlg2 and more doc
%
% Revision 1.18 2002/10/25 01:59:33 arno
% adding finputcheck code
%
% Revision 1.11 2002/09/30 15:29:23 arno
% autorizing cell arrays for types
%
% Revision 1.10 2002/09/30 00:42:08 arno
% debug input arguments
%
% Revision 1.9 2002/07/29 18:00:53 arno
% debugging for NaN
%
% Revision 1.8 2002/07/29 17:24:22 arno
% header
%
% Revision 1.7 2002/07/20 19:10:41 arno
% debugging output
%
% Revision 1.6 2002/07/19 17:58:11 arno
% returning non-matched 'key' 'val' arguments
%
% Revision 1.5 2002/07/19 17:46:53 arno
% g empty if no varargin
%
% Revision 1.4 2002/07/19 16:27:14 arno
% adding ignore mode
%
% Revision 1.3 2002/07/10 02:18:32 arno
% header info
%
% Revision 1.2 2002/07/10 02:17:27 arno
% debugging error message passing
%
% Revision 1.1 2002/07/10 01:03:19 arno
% Initial revision
%
function [g, varargnew] = finputcheck( vararg, fieldlist, callfunc, mode )
if nargin < 2
help finputcheck;
return;
end;
if nargin < 3
callfunc = '';
else
callfunc = [callfunc ' ' ];
end;
if nargin < 4
mode = 'do not ignore';
end;
NAME = 1;
TYPE = 2;
VALS = 3;
DEF = 4;
SIZE = 5;
varargnew = {};
% create structure
% ----------------
if ~isempty(vararg)
for index=1:length(vararg)
if iscell(vararg{index})
vararg{index} = {vararg{index}};
end;
end;
try
g = struct(vararg{:});
catch
g = [ callfunc 'error: bad ''key'', ''val'' sequence' ]; return;
end;
else
g = [];
end;
for index = 1:size(fieldlist,NAME)
% check if present
% ----------------
if ~isfield(g, fieldlist{index, NAME})
g = setfield( g, fieldlist{index, NAME}, fieldlist{index, DEF});
end;
tmpval = getfield( g, {1}, fieldlist{index, NAME});
% check type
% ----------
if ~iscell( fieldlist{index, TYPE} )
res = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}, ...
fieldlist{index, VALS}, tmpval, callfunc );
if ischar(res), g = res; return; end;
else
testres = 0;
tmplist = fieldlist;
for it = 1:length( fieldlist{index, TYPE} )
res{it} = fieldtest( fieldlist{index, NAME}, fieldlist{index, TYPE}{it}, ...
fieldlist{index, VALS}, tmpval, callfunc );
if ~ischar(res{it}), testres = 1; end;
end;
if testres == 0, g = strvcat(res{:}); return; end;
end;
end;
% check if fields are defined
% ---------------------------
allfields = fieldnames(g);
for index=1:length(allfields)
if isempty(strncmp(allfields{index}, fieldlist(:, 1)', length(allfields{index})))
if ~strcmpi(mode, 'ignore')
g = [ callfunc 'error: undefined argument ''' allfields{index} '''']; return;
end;
varargnew{end+1} = allfields{index};
varargnew{end+1} = getfield(g, {1}, allfields{index});
end;
end;
function g = fieldtest( fieldname, fieldtype, fieldval, tmpval, callfunc )
NAME = 1;
TYPE = 2;
VALS = 3;
DEF = 4;
SIZE = 5;
g = [];
switch fieldtype
case { 'integer' 'real' 'boolean' },
if ~isnumeric(tmpval)
g = [ callfunc 'error: argument ''' fieldname ''' must be numeric' ]; return;
end;
if strcmp(fieldtype, 'boolean')
if tmpval ~=0 && tmpval ~= 1
g = [ callfunc 'error: argument ''' fieldname ''' must be 0 or 1' ]; return;
end;
else
if strcmp(fieldtype, 'integer')
if ~isempty(fieldval)
if (isnan(tmpval) && ~any(isnan(fieldval))) ...
&& (~ismember(tmpval, fieldval))
g = [ callfunc 'error: wrong value for argument ''' fieldname '''' ]; return;
end;
end;
else % real
if ~isempty(fieldval)
if tmpval < fieldval(1) || tmpval > fieldval(2)
g = [ callfunc 'error: value out of range for argument ''' fieldname '''' ]; return;
end;
end;
end;
end;
case 'string'
if ~ischar(tmpval)
g = [ callfunc 'error: argument ''' fieldname ''' must be a string' ]; return;
end;
if ~isempty(fieldval)
tmpval_lc = lower(tmpval);
if isempty(strncmp(tmpval_lc, fieldval, length(tmpval_lc)))
g = [ callfunc 'error: wrong value for argument''' fieldname '''' ]; return;
end;
end;
case 'cell'
if ~iscell(tmpval)
g = [ callfunc 'error: argument ''' fieldname ''' must be a cell array' ]; return;
end;
case 'struct'
if ~ischaruct(tmpval)
g = [ callfunc 'error: argument ''' fieldname ''' must be a structure' ]; return;
end;
case '';
otherwise, error([ 'finputcheck error: unrecognized type ''' fieldname '''' ]);
end;