% File: "qsuball.m"
% Author: Albert Law [bleuant@cim.mcgill.ca] (McGill University, Montreal, Quebec, Canada)
% Description: This is written for any linux cluster using PBS queueing
% execution.  It reads in an M-file, writes a bunch of M-files that
% replicate that initial M-file (such that the first #LINE lines are exact
% replicates but every line afterwards is only one line of test case
% execution), writes a PBS file for each new replicant M-file, and will
% automatically suhbmit each PBS file for the queue.
% Note #1: Must only be executed on the head node.
% Note #2: The entire point is to present ALL the test cases in a serial
% manner for the cluster to process.  So each test case must be
% self-contained and independant.
% Note #3: Not well documented as this was done as a fastish hack.
% Note #4: Beware the directory coding.  It gets a little confusing.
% Note #5: This script will pause until the system has none of your
% processs in the queue to prevent queue abuse.
% Note #6: Has been successfully used for CLUMEQ [www.clumeq.mcgill.ca] and
% WESTGRID GLACIER [www.westgrid.ca].  Should work with other WESTGRID
% facilities.
% Note #7: The first #LINES of the replicated M-file must not be longer
% than 256 cloumns (can be changed).  Change these settings on the line
% "headerM = repmat(' ', LINES, CHARACTER_WIDTH);"
% Note #8: The STDOUT and STDERR have been redirected to the directory
% "westgrid" or "clumeq" or "other" depending on which system you are
% using.  It is the same directory where all the fabricated scripts will
% be.


% the following are a bunch of parameters one must set for proper
% functionality of the M-file
filename = 'batch'; % base filename (ie: no file extension) of the file you wish to replicate
testfunction = 'go'; % the matlab function one used to execute a test case (the script will look for this test function)


% no need to set the following (done automatically)
systemchoice = 'default';
if (max(size(strfind(getenv('HOSTNAME'),'westgrid')))>0)
    systemchoice = 'westgrid'; % westgrid or clumeq
end;
if (max(size(strfind(getenv('HOSTNAME'),'clumeq')))>0)
    systemchoice = 'clumeq'; % westgrid or clumeq
end;
LINES = 30; % how many lines to skip
username = getenv('USER'); % the user name on the system currently being used
if strcmp(systemchoice, 'westgrid')
    script_dir = 'westgrid'; % name of directory where all your M-files will be created note: "cd .." will be inserted to the replicant scripts to "realign" the directory structure expected
elseif strcmp(systemchoice, 'clumeq')
	script_dir = 'clumeq'; % name of directory where all your M-files will be created note: "cd .." will be inserted to the replicant scripts to "realign" the directory structure expected
else % some other system (not important as it is just a directory name that may remain oblivious to the user)
    script_dir = 'other'; % name of directory where all your M-files will be created note: "cd .." will be inserted to the replicant scripts to "realign" the directory structure expected
end;
if ~isdir(script_dir)
    mkdir(script_dir); % make the script directory in sace it doesn't exist
end;
if strcmp(filesep, '/') % this part only works in NIX-like environments)
    [junk, matlab] = system ('which matlab'); % sets the full path of matlab
end;


% only proceed if all other queues have already been processed
if strcmp(filesep, '/') % this part only works in NIX-like environments)
[s, out] = system (['qstat | grep ', username]);
    while (sum(size(out)) > 0)
        disp(fix(clock));
        system('sleep 600');
        [s, out] = system (['qstat | grep ', username]);
    end;
end;

fid = fopen([filename, '.m']); % open "filename.m" for replication


% set the header information for the PBS file
headerPBS1 = '#PBS -l ncpus=1'; % not strictly needed
headerPBS2 = '#PBS -V'; % not strictly needed
headerPBS3 = '#PBS -l software=MATLAB'; % indicates that this PBS job needs a matlab license free
headerPBS4 = ['cd ', pwd, filesep, script_dir];
headerPBS5 = strcat (matlab, ' < ');
% all headerPBS1234 must have the same length
maxsize = max([size(headerPBS1,2), size(headerPBS2,2), size(headerPBS3,2), size(headerPBS4,2), size(headerPBS5,2)]);
headerPBS1 = [headerPBS1, repmat(' ', 1, (maxsize - size(headerPBS1,2)))];
headerPBS2 = [headerPBS2, repmat(' ', 1, (maxsize - size(headerPBS2,2)))];
headerPBS3 = [headerPBS3, repmat(' ', 1, (maxsize - size(headerPBS3,2)))];
headerPBS4 = [headerPBS4, repmat(' ', 1, (maxsize - size(headerPBS4,2)))];
headerPBS5 = [headerPBS5, repmat(' ', 1, (maxsize - size(headerPBS5,2)))];
% headers are different for different systems
if strcmp(systemchoice, 'westgrid')
    headerPBS = [headerPBS3; headerPBS4; headerPBS5;]; % this is the PBS header...
elseif strcmp(systemchoice, 'clumeq')
	headerPBS = [headerPBS1; headerPBS2; headerPBS3; headerPBS4; headerPBS5]; % this is the PBS header...
else % some other system (not important as it is just a directory name that may remain oblivious to the user)
    headerPBS = [headerPBS3; headerPBS4; headerPBS5]; % this is the PBS header...(probably won't work well with untested systems)
end;


% read the first #LINES of "filename.m" for M-file header information
headerM = repmat(' ', LINES, 256);
iter = 1;
while ((feof(fid) ~= 1) && (iter <= LINES))
    temp = fgets(fid);
    headerM(iter,1:size(temp,2)) = temp;
    iter = iter + 1;
end;

iterFOEF = 1;
while (feof(fid) ~= 1)
    temp = fgetl(fid);
    sizetestfunction = size(testfunction,2);
    if ((max(size(temp)) >= sizetestfunction) & (strcmpi (temp(1:sizetestfunction), testfunction))) % find the lines that contain a test function command
        % write the M-file
        temp_fid = fopen ([script_dir, filesep, filename, '_', num2str(iterFOEF), '.m'], 'w');
        fprintf(temp_fid, '%s\n', 'cd ..'); % to fix the directory call for the other functions
        iterH = 1;
        while (iterH <= size(headerM,1))
            fprintf(temp_fid, '%s\n', headerM(iterH,:));
            iterH = iterH + 1;
        end;
        fprintf(temp_fid, '\n%s\n', temp);
        fclose(temp_fid);
        
        % write the PBS file
        temp_fid = fopen ([script_dir, filesep, filename, '-', num2str(iterFOEF), '.pbs'], 'w');
        iterH = 1;
        while (iterH < size(headerPBS,1))
            fprintf(temp_fid, '%s\n', headerPBS(iterH,:));
            iterH = iterH + 1;
        end;
        fprintf(temp_fid, '%s\n', strcat(headerPBS(iterH,:), [' ', filename, '_', num2str(iterFOEF), '.m']));
        fclose(temp_fid);
        
        % submit the PBS file to the PBS queue
        if strcmp(filesep, '/') % this part only works in NIX-like environments)
           system(['qsub -e ', pwd, filesep, script_dir, filesep, ' -o ', pwd, filesep, script_dir, filesep, ' ', script_dir, filesep, filename, '-', num2str(iterFOEF), '.pbs']);
        end;
        
        iterFOEF = iterFOEF + 1;
    end;
end;

fclose(fid);
