%
%  write a Matlab .m function file to be called by Dakota for
%  the Matlab direct or external driver.
%
%  []=dakota_m_write(method,dmeth,dvar,dresp,params,filem,package,varargin)
%
%  where the required input is:
%    method        (character, dakota method name)
%    dmeth         (dakota_method, method class object)
%    dvar          (structure array, variable class objects)
%    dresp         (structure array, response class objects)
%    params        (structure array, method-independent parameters)
%    filem         (character, name of .m file)
%    package       (character, analysis package)
%
%  the method, dmeth, and filem will be prompted if empty.
%  params may be empty, in which case defaults will be used.
%
%  the optional varargin are passed directly through to the
%  QmuUpdateFunctions brancher to be used by the analysis
%  package.  for example, this could be model information.
%
%  this function writes a matlab .m function file to be called
%  by dakota for the matlab direct or external driver.  for
%  the direct driver, dakota is linked with matlab and
%  automatically starts a matlab session, passing the variables
%  and responses through the function; for the external driver,
%  dakota calls a shell script to start the matlab session,
%  passing the variables and responses through text files.
%  this function must be tailored to the particular analysis
%  package.
%
%  this data would typically be generated by a matlab script
%  for a specific model, using the method, variable, and
%  response class objects.  this function may be called by
%  dakota_in_data.
%
%  "Copyright 2009, by the California Institute of Technology.
%  ALL RIGHTS RESERVED. United States Government Sponsorship
%  acknowledged. Any commercial use must be negotiated with
%  the Office of Technology Transfer at the California Institute
%  of Technology.  (NTR 47078)
%
%  This software may be subject to U.S. export control laws.
%  By accepting this  software, the user agrees to comply with
%  all applicable U.S. export laws and regulations. User has the
%  responsibility to obtain export licenses, or other export
%  authority as may be required before exporting such information
%  to foreign countries or providing access to foreign persons."
%
function []=dakota_m_write(method,dmeth,dvar,dresp,params,filem,package,varargin)

if ~nargin
    help dakota_m_write
    return
end

%  process the input parameters

if ~exist('method','var') || isempty(method)
    method=input('Method?  ','s');
end

if ~exist('dmeth' ,'var') || isempty(dmeth)
    dmeth=dakota_method(method);
end

if ~exist('params','var')
    params=[];
end

if ~exist('filem' ,'var') || isempty(filem)
    filem=input('Matlab m-file to write?  ','s');
end
[pathstr,name,ext,versn] = fileparts(filem);
if isempty(ext)
    ext='.m';
end
filem2=fullfile(pathstr,[name ext versn]);

display(sprintf('Opening Matlab m-file ''%s''.',filem2));
fidm=fopen(sprintf('%s',filem2),'w');
if (fidm < 0)
    error('''%s'' could not be opened.',filem2);
end

%  write beginning of the Matlab m-file

begin_write(fidm,name,params);

%  write variables into the Matlab m-file

variables_write(fidm,dmeth,dvar,params,varargin{:});

%  write solution into the Matlab m-file

solution_write(fidm,package);

%  write responses into the Matlab m-file

responses_write(fidm,dmeth,params,dresp);

%  write end of the Matlab m-file

end_write(fidm,name,params);

fclose(fidm);
display('End of file successfully written.');

end

%%  function to write beginning of the Matlab m-file

function []=begin_write(fidm,name,params)

display('Writing beginning of Matlab m-file.');

fprintf(fidm,'%%\n');
if strcmpi(params.analysis_driver,'matlab')
    fprintf(fidm,'%%  Run the specified input variables and return the output responses.\n');
    fprintf(fidm,'%%\n');
    fprintf(fidm,'function Dakota=%s(Dakota)\n\n',name);
    fprintf(fidm,'clk=clock;\n');
    fprintf(fidm,'cpu=cputime;\n\n');
    fprintf(fidm,'%% Dakota\n\n');
    fprintf(fidm,'infile=''%s'';\n','Qmu.model');
else
    fprintf(fidm,'%%  Run the specified input file and return the output file.\n');
    fprintf(fidm,'%%\n');
    fprintf(fidm,'function %s(infile,outfile)\n\n',name);
    fprintf(fidm,'clk=clock;\n');
    fprintf(fidm,'cpu=cputime;\n\n');
end
fprintf(fidm,'try\n');
fprintf(fidm,'\tloadmodel(infile);\n\n');

if strcmpi(params.analysis_driver,'matlab')
	fprintf(fidm,'\tmd=qmuname(md,Dakota.fnEvalId);\n\n');
else
	fprintf(fidm,'\tmd=qmuname(md);\n\n');
end

end

%%  function to write variables into the Matlab m-file

function []=variables_write(fidm,dmeth,dvar,params,varargin)

display('Writing variables for Matlab m-file.');

fprintf(fidm,'%%  Apply the variables.\n\n');
ixc=0;

%  variables vary by method

ixc=vsets_write(fidm,ixc,dvar,dmeth.variables,params,varargin{:});

end

%%  function to write variable sets into the Matlab m-file

function [ixc]=vsets_write(fidm,ixc,dvar,variables,params,varargin)

for i=1:length(variables)
    if isfield(dvar,variables{i})
        ixc=vlist_write(fidm,ixc,variables{i},dvar.(variables{i}),params,varargin{:});
    end
end

end

%%  function to write variable list into the Matlab m-file

function [ixc]=vlist_write(fidm,ixc,vtype,dvar,params,varargin)

disp(sprintf('  Writing %d %s variables.',length(dvar),class(dvar)));

for i=1:length(dvar)

	%first find descriptor, without sample number on it.
	descriptor=discardnum(dvar(i).descriptor);

	%is there a lock on this variable? We don't want to update the variable twice!
	if exist([descriptor '_lock'],'var'),
		%lock is in place, do not update! continue;
		continue;
	else
		%first things first, put lock in place
		eval([descriptor '_lock=1;']);

		%now, we need a string to put in the matlab file, which will update all the variables 
		%for  this descriptor.
		[string,ixc]=QmuUpdateFunctions(ixc,descriptor,dvar,params,i,varargin{:});

		%dump this string in the matlab file.
        fprintf(fidm,'%s',string);
	end
end

end

%%  function to write solution into the Matlab m-file

function []=solution_write(fidm,package)

display('Writing solution for Matlab m-file.');
fprintf(fidm,'%%  Run the solution.\n\n');

fprintf(fidm,['\tmd=solve(md,''diagnostic'',''' package ''');\n\n']);

end

%%  function to write responses into the Matlab m-file

function []=responses_write(fidm,dmeth,params,dresp)

display('Writing responses for Matlab m-file.');

fprintf(fidm,'%%  Calculate the responses.\n\n');
ifnvals=0;

if ~strcmpi(params.analysis_driver,'matlab')
    fprintf(fidm,'\tfid=fopen(outfile,''w'');\n\n');
end

%  responses vary by method

ifnvals=rsets_write(fidm,ifnvals,params,dresp,dmeth.responses);

fprintf(fidm,'\n');
if ~strcmpi(params.analysis_driver,'matlab')
    fprintf(fidm,'\tstatus=fclose(fid);\n\n');
end

end

%%  function to write response sets into the Matlab m-file

function [ifnvals]=rsets_write(fidm,ifnvals,params,dresp,responses)

for i=1:length(responses)
    if isfield(dresp,responses{i})
        ifnvals=rlist_write(fidm,ifnvals,params,responses{i},dresp.(responses{i}));
    end
end

end

%%  function to write response list into the Matlab m-file

function [ifnvals]=rlist_write(fidm,ifnvals,params,rtype,dresp)

disp(sprintf('  Writing %d %s responses.',length(dresp),class(dresp)));
for i=1:length(dresp)
    ifnvals=ifnvals+1;
    if strcmpi(params.analysis_driver,'matlab')
        fprintf(fidm,'\tDakota.fnVals(%d)=QmuResponseValue(md,''%s'');\n',ifnvals,dresp(i).descriptor);
    else
        fprintf(fidm,'\tfprintf(fid,''%%f\\n'',QmuResponseValue(md,''%s''));\n',dresp(i).descriptor);
    end
end

end

%%  function to write end of the Matlab m-file

function []=end_write(fidm,name,params)

display('Writing end of Matlab m-file.');

fprintf(fidm,'%%  Error condition.\n\n');

fprintf(fidm,'catch ME\n');
fprintf(fidm,'\tME\n');
fprintf(fidm,'\tfor i=1:length(ME.stack)\n');
fprintf(fidm,'\t\tdisplay(sprintf(''    file(%%d): %%s'',  i,ME.stack(i).file));\n');
fprintf(fidm,'\t\tdisplay(sprintf(''    name(%%d): %%s'',  i,ME.stack(i).name));\n');
fprintf(fidm,'\t\tdisplay(sprintf(''    line(%%d): %%d\\n'',i,ME.stack(i).line));\n');
fprintf(fidm,'\tend\n');
if strcmpi(params.analysis_driver,'matlab')
    fprintf(fidm,'\tDakota.failure=1;\n');
else
    fprintf(fidm,'\tif exist(''fid'',''var'')\n');
    fprintf(fidm,'\t\tstatus=fclose(fid);\n');
    fprintf(fidm,'\tend\n');
    fprintf(fidm,'\tfid=fopen(outfile,''w'');\n');
    fprintf(fidm,'\tfprintf(fid,''fail\\n'');\n');
    fprintf(fidm,'\tstatus=fclose(fid);\n');
end
fprintf(fidm,'end\n\n');

fprintf(fidm,'disp(sprintf(''%s -- %%f CPU seconds; %%f clock seconds\\n'',...\n',name);
fprintf(fidm,'    cputime-cpu,etime(clock,clk)))\n\n');
fprintf(fidm,'end\n\n');

end
