function dumpMPS2( model )

% 12 Nov 2015: dumpMPS2 (derived from dumpMPS) creates a linear program
%              in MPS format from data in the structure "model",
%              where model is one of 83 structures created by
%              Ali Ebrahim (UCSD) on 8 Nov 2015 using the notebook
% https://github.com/opencobra/m_model_collection/blob/master/load_models.ipynb.
%              The models in question have no osense.  We assume that the
%              objective c'*x should be maximized.  We add "-c" as the last
%              row of S and assume that LP solvers will treat it as the
%              objective row to be MINIMIZED (since this is the default for
%              other MPS files).
%
% 13 Nov 2015: Some of the bounds lb and ub are -1000 and +1000 respectively.
%              Ali says this:
% Most of the variables won't reach those bounds. Some variables representing
% fluxes in loops will however.
% There are also some cases where the bounds for the constraining exchanges
% are set to 1000. This I guess is the equivalent of unbounded. This is not
% a biologically relevant result, and comes from setting an unrealistic bound
% on uptake... The cells can't take it up that quickly.
%
% Generally though the number 1000 is generally used to mean "large flux" -
% it's just that it's much easier to deal with than infinity.
%
% 13 Nov 2015: The input parameter "model" is a structure.
%              name = model.description usually gives the name of the
%              structure, but not always.


name   = model.description;
lname  = length(name);
mname  = name(1:min( 8,lname));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Exceptions.
% For most models, name = model.description is the name of the structure.
% Fix any that are different.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if strcmp(mname,'SimPheny'), name = 'iRS605_fixed'; mname = name(1:8); end
if strcmp(mname,'model'),    name = 'iZM363';       mname = name;      end
if strcmp(mname,'Lactobac'), name = 'iBT721_fixed'; mname = name(1:8); end
if strcmp(mname,'Sc_therm'), name = 'iMP429_fixed'; mname = name(1:8); end
if strcmp(mname,'iTY425'),   name = 'iTY425_fixed'; mname = name(1:8); end
lname  = length(name);
fname  = name(1:min(8,lname));

S      = model.S;
b      = model.b;
c      = model.c;
xl     = model.lb;
xu     = model.ub;

[m,n]   = size(S);
if isfield(model,'csense')
    csense  = model.csense;          % E or L or G
    [mc,nc] = size(csense);
    if mc<nc, csense = csense'; end  % for Ali's structure
else
    csense(1:m,1) = 'E';
end

if isfield(model,'osense')
    osense = model.osense;      % 1=min   (-1=max)
else
    osense = -1;                % 
end

% 06 Aug 2012: Include c as an additional free *last* row of Ax = b
%              so that SQOPT will treat the problem as an LP, not a QP.


S     = [      S            % Luckily we only have to do it once
         osense*sparse(c)'];
b     = [b; 0];
csense(m+1,1) = 'N';

[m,n]  = size(S);
bigbnd = 1e+20;                % MINOS and SQOPT's "infinite" bound

%nzS     = nnz(S)
%[I,J,V] = find(S);          % Sij indices and values

% Generate dummy row name and column names

rname(1:m,1:8) = ' ';
rname(1:m,1)   = 'r';
for i=1:m
   rname(i,2:8) = sprintf('%7g', i);
end

cname(1:n,1:8) = ' ';
cname(1:n,1)   = 'x';
for j=1:n
   cname(j,2:8) = sprintf('%7g', j);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create MPS file.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fname = [fname '.mps'];
fid = fopen(fname,'w');          % Open file for writing
fprintf(fid,'NAME          %c%c%c%c%c%c%c%c', mname);
fprintf(fid,'\n');   % Has to be separate from previous line

fprintf(fid,'ROWS\n');
for i=1:m
    fprintf(fid,'  %c %c%c%c%c%c%c%c%c\n', csense(i),rname(i,:));
end

fprintf(fid,'COLUMNS\n');
for j=1:n
   c = S(:,j);
   [I,J,V] = find(c);
   for k=1:length(I);
      i = I(k);
      fprintf(fid,'    %c%c%c%c%c%c%c%c  %c%c%c%c%c%c%c%c  %12.5e\n', ...
                        cname(j,:),        rname(i,:),        V(k));
   end
end

fprintf(fid,'RHS\n');
[I,J,V] = find(b);
for k=1:length(I)
   i = I(k);
   fprintf(fid, '    RHS       %c%c%c%c%c%c%c%c  %12.5e\n', ...
                               rname(i,:),         b(i));
end

fprintf(fid,'BOUNDS\n');
for j=1:n
  if xl(j) ~= 0.0
     fprintf(fid, ' LO BND       %c%c%c%c%c%c%c%c  %12.5e\n', ...
                                 cname(j,:),         xl(j));
  end
  if xu(j) < bigbnd
     fprintf(fid, ' UP BND       %c%c%c%c%c%c%c%c  %12.5e\n', ...
                                 cname(j,:),         xu(j));
  end
end

fprintf(fid,'ENDATA\n');
fclose(fid);
%disp([num2str(m) '  ' num2str(n) '  ' fname])
char16 = '                ';
lname  = length(fname);
char16(1:lname) = fname;
fprintf('%8i%8i  %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n', m,n,char16)

pause(1)   % to make the timestamp order match the dumpMPS2(...) order.

