function defscommands = MPI_Run( m_file, n_proc, machines )
% MPI_Run  -  Run m_file on multiple processors.
%
%  defscommands = MPI_Run( m_file, n_proc, machines )
%
%    Runs n_proc copies of m_file on machines, where
%
%    machines = {};
%      Run on a local processor.
%
%    machines = {'machine1' 'machine2'}) );
%      Run on a multi processors.
%
%    machines = {'machine1:dir1' 'machine2:dir2'}) );
%      Run on a multi processors and communicate using via dir1 and dir2,
%      which must be visible to both machines.
%
%    If machine1 is the local cpu, then defscommands will contain
%    the commands that need to be run locally, via eval(defscommands).
%

  % Check if the directory 'MatMPI' exists
  if exist('MatMPI', 'dir') ~= 0
     error('MatMPI directory already exists: rename or remove with MatMPI_Delete_all');
  end

  % Create working directory.
  mkdir('MatMPI');

  % Get host.
  host = getenv('HOST');

  % Get number of machines to launch on.
  n_machines = size(machines,2);

  % Create generic comm.
  MPI_COMM_WORLD = MatMPI_Comm_init(n_proc,machines);

  % Set newline string.
  nl = sprintf('\n');
  % Get single quote character.
  q = strrep(' '' ',' ','');

  % Initialize unix command launch on all the different machines.
  unix_launch = '';

  % Get number of machines.
  n_m = MPI_COMM_WORLD.machine_db.n_machine;

  % Loop backwards over each machine.
  for i_m=n_m:-1:1

    % Get number of processes to launch on this machine.
    n_proc_i_m = MPI_COMM_WORLD.machine_db.n_proc(1,i_m);

    if (n_proc_i_m >= 1)

      % Get machine info.
      machine = MPI_COMM_WORLD.machine_db.machine{1,i_m};
      remote_launch = MPI_COMM_WORLD.machine_db.remote_launch{1,i_m};
      remote_flags = MPI_COMM_WORLD.machine_db.remote_flags{1,i_m};

      % Get starting and stopping rank.
      i_rank_start = MPI_COMM_WORLD.machine_db.id_start(1,i_m) - 1;
      i_rank_stop = MPI_COMM_WORLD.machine_db.id_stop(1,i_m) - 1;

      % Initialize unix command that will be run on each node.
      unix_matlab = '';

      % Loop backwards over number of processes.
      for i_rank=i_rank_stop:-1:i_rank_start

        % Build commands
        [defscommands, unix_matlab_i_rank] = ...
          MatMPI_Commands(m_file,i_rank,MPI_COMM_WORLD);
        unix_matlab = [unix_matlab unix_matlab_i_rank];

      end

      % Create a file name.
%      unix_matlab_file = ['MatMPI/Unix_Commands.' machine '.sh'];
      unix_matlab_file = ['MatMPI/Unix_Commands.' machine '.' num2str(i_rank_start) '.sh'];

      % Append delete command.
      unix_matlab = [unix_matlab ' rm ' unix_matlab_file ';' nl];

      % Put commands in a file.
      fid = fopen(unix_matlab_file,'wt');
      fwrite(fid,unix_matlab);
      fclose(fid);

      % Create unix commands to launch this file.
      if (strcmp(machine,host))
        unix_launch_i_m = ['/bin/sh ./' unix_matlab_file ' &' nl];
      else
        unix_launch_i_m = [remote_launch machine remote_flags ...
           q 'cd ' pwd '; /bin/sh ./' unix_matlab_file ' &' q ' &' nl];
      end

      unix_launch = [unix_launch unix_launch_i_m];
    end
  end

  % Execute all launches in a single unix call.
  unix_launch
%  unix(unix_launch);

  
  % Write commands unix commands to .sh text file
  % to fix Matlab's problem with very long commands sent to unix().
  unix_launch_file = 'MatMPI/Unix_Commands.sh';
  fid = fopen(unix_launch_file,'wt');
  fwrite(fid,unix_launch);
  fclose(fid);
  unix(['/bin/sh ' unix_launch_file]);
  delete(unix_launch_file);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MatlabMPI
% Dr. Jeremy Kepner
% MIT Lincoln Laboratory
% kepner@ll.mit.edu
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Copyright 2002 Massachusetts Institute of Technology
% 
% Permission is herby granted, without payment, to copy, modify, display
% and distribute this software and its documentation, if any, for any
% purpose, provided that the above copyright notices and the following
% three paragraphs appear in all copies of this software.  Use of this
% software constitutes acceptance of these terms and conditions.
%
% IN NO EVENT SHALL MIT BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
% SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
% THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF MIT HAS BEEN ADVISED OF THE
% POSSIBILITY OF SUCH DAMAGE.
% 
% MIT SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING,
% BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
% FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
%
% THIS SOFTWARE IS PROVIDED "AS IS," MIT HAS NO OBLIGATION TO PROVIDE
% MAINTENANCE, SUPPORT, UPDATE, ENHANCEMENTS, OR MODIFICATIONS.

