%
%  write a Dakota .in input file.
%
%  []=dakota_in_write(method,dvar,dresp,params,filei,varargin)
%  []=dakota_in_write(dmeth ,dvar,dresp,params,filei,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)
%    filei         (character, name of .in file)
%
%  the method and filei will be prompted if empty.  params
%  may be empty, in which case defaults will be used.
%
%  the optional varargin are not yet used.
%
%  this function writes a dakota .in input file to be used
%  by dakota.  this file is independent of 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.  (J. Schiermeier, 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_in_write(method,dvar,dresp,params,filei,varargin)

if ~nargin
    help dakota_in_write
    return
end

%  process the input parameters

if ~exist('method','var') || isempty(method)
    method=input('Method?  ','s');
end
if     ischar(method)
    dmeth=dakota_method(method);
elseif isa(method,'dakota_method')
    dmeth=method;
else
    error(['Method ''' inputname(1) ''' is unrecognized class ''' class(method) '''.']);
end

if ~exist('filei' ,'var') || isempty(filei)
    filei=input('Dakota input file to write?  ','s');
end
[pathstr,name,ext] = fileparts(filei);
if isempty(ext)
% fileparts only considers '.in' to be the extension, not '.qmu.in'
    ext='.qmu.in';
end
filei2=fullfile(pathstr,[name ext]);

display(sprintf('Opening Dakota input file ''%s''.',filei2));
fidi=fopen(sprintf('%s',filei2),'w');
if (fidi < 0)
    error('''%s'' could not be opened.',filei2);
end

if ~exist('params','var')
    params=struct();
end
params=dakota_in_params(params);

%  write the strategy section

if IssmConfig('_DAKOTA_VERSION_') < 6,
	strategy_write(fidi,params);
else
	environment_write(fidi,params);
end

%  write the method section

method_write(fidi,dmeth,dresp,params);

%  write the model section

model_write(fidi);

%  write the variables section

variables_write(fidi,dmeth,dvar);

%  write the interface section

interface_write(fidi,params);

%  write the responses section

responses_write(fidi,dmeth,dresp,params);

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

end

%%  function to write the strategy section of the file

function []=strategy_write(fidi,params)

display('Writing strategy section of Dakota input file.');

fprintf(fidi,'strategy,\n');
fprintf(fidi,'\tsingle_method\n\n');
param_write(fidi,'\t  ','graphics','','\n',params);
param_write(fidi,'\t  ','tabular_graphics_data','','\n',params);
param_write(fidi,'\t  ','tabular_graphics_file',' ''','''\n',params);
fprintf(fidi,'\n');

end

%%  function to write the environment section of the file

function []=environment_write(fidi,params)

	display('Writing environment section of Dakota input file.');

	fprintf(fidi,'environment,\n');
	param_write(fidi,'\t  ','graphics','','\n',params);
	param_write(fidi,'\t  ','tabular_graphics_data','','\n',params);
	param_write(fidi,'\t  ','tabular_graphics_file',' ''','''\n',params);
	fprintf(fidi,'\n');

end

%%  function to write the method section of the file

function []=method_write(fidi,dmeth,dresp,params)

display('Writing method section of Dakota input file.');

fprintf(fidi,'method,\n');
fprintf(fidi,'\t%s\n',dmeth.method);

dmeth_params_write(dmeth,fidi);

%  write response levels

if strcmp(dmeth.type,'nond')
    for i=1:length(dmeth.responses)
        fhresp=str2func([dmeth.responses{i} '.dakota_rlev_write']);
        fhresp(fidi,dresp,params);
    end
end
fprintf(fidi,'\n');

end

%%  function to write the model section of the file

function []=model_write(fidi)

display('Writing model section of Dakota input file.');

fprintf(fidi,'model,\n');
fprintf(fidi,'\t%s\n\n','single');

end

%%  function to write the variables section of the file

function []=variables_write(fidi,dmeth,dvar)

display('Writing variables section of Dakota input file.');

fprintf(fidi,'variables,\n');

%  variables vary by method

for i=1:length(dmeth.variables)
    fhvar=str2func([dmeth.variables{i} '.dakota_write']);
    fhvar(fidi,dvar);
end

%  linear constraints vary by method

for i=1:length(dmeth.lcspec)
    fhvar=str2func([dmeth.lcspec{i}    '.dakota_write']);
    fhvar(fidi,dvar);
end

fprintf(fidi,'\n');

end

%%  function to write the interface section of the file

function []=interface_write(fidi,params)

display('Writing interface section of Dakota input file.');

fprintf(fidi,'interface,\n');

if     ~params.system && ~params.fork && ~params.direct
    params.fork=true;
elseif (params.system+params.fork+params.direct > 1)
    error('Too many interfaces selected.')
end

if     params.system || params.fork
    param_write(fidi,'\t','asynchronous','','\n',params);
    param_write(fidi,'\t  ','evaluation_concurrency',' = ','\n',params);
    param_write(fidi,'\t  ','analysis_concurrency','   = ','\n',params);
    param_write(fidi,'\t  ','evaluation_servers','     = ','\n',params);
    param_write(fidi,'\t  ','evaluation_self_scheduling','','\n',params);
    param_write(fidi,'\t  ','evaluation_static_scheduling','','\n',params);
    param_write(fidi,'\t  ','analysis_servers','       = ','\n',params);
    param_write(fidi,'\t  ','analysis_self_scheduling','','\n',params);
    param_write(fidi,'\t  ','analysis_static_scheduling','','\n',params);
    param_write(fidi,'\t','algebraic_mappings',' = ','\n',params);
    param_write(fidi,'\t','system','','\n',params);
    param_write(fidi,'\t','fork','','\n',params);
    param_write(fidi,'\t  ','analysis_driver',' = ''','''\n',params);
    if ~isempty(params.input_filter)
        param_write(fidi,'\t  ','input_filter','    = ''','''\n',params);
    end
    if ~isempty(params.output_filter)
        param_write(fidi,'\t  ','output_filter','   = ''','''\n',params);
    end
    param_write(fidi,'\t  ','failure_capture','   ','\n',params);
    param_write(fidi,'\t  ','deactivate','        ','\n',params);
    param_write(fidi,'\t  ','parameters_file',' = ''','''\n',params);
    param_write(fidi,'\t  ','results_file','    = ''','''\n',params);
    param_write(fidi,'\t  ','verbatim', '','\n',params);
    param_write(fidi,'\t  ','aprepro', '','\n',params);
    param_write(fidi,'\t  ','file_tag', '','\n',params);
    param_write(fidi,'\t  ','file_save','','\n',params);
elseif params.direct
%  Error: asynchronous capability not yet supported in direct interfaces.
%  Update: it is now possible to run in parallel in direct interfaces.
    param_write(fidi,'\t','algebraic_mappings',' = ','\n',params);
    param_write(fidi,'\t','direct','','\n',params);
    param_write(fidi,'\t  ','analysis_driver','     = ''','''\n',params);
    if IssmConfig('_DAKOTA_VERSION_') < 6,
		param_write(fidi,'\t  ','evaluation_static_scheduling','','\n',params);
	else
		param_write(fidi,'\t  ','evaluation_scheduling',' ','\n',params);
		param_write(fidi,'\t  ','processors_per_evaluation',' = ','\n',params);
	end
    if ~isempty(params.analysis_components)
        [pathstr,name,ext] = fileparts(params.analysis_components);
        if isempty(ext)
            ext='.m';
        end
        params.analysis_components=fullfile(pathstr,[name ext]);
        param_write(fidi,'\t  ','analysis_components',' = ''','''\n',params);
    end
    if ~isempty(params.input_filter)
        param_write(fidi,'\t  ','input_filter','    = ''','''\n',params);
    end
    if ~isempty(params.output_filter)
        param_write(fidi,'\t  ','output_filter','   = ''','''\n',params);
    end
    param_write(fidi,'\t  ','failure_capture','   ','\n',params);
    param_write(fidi,'\t  ','deactivate','        ','\n',params);
    param_write(fidi,'\t  ','processors_per_analysis',' = ''','''\n',params);
end

fprintf(fidi,'\n');

end

%%  function to write the responses section of the file

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

display('Writing responses section of Dakota input file.');

fprintf(fidi,'responses,\n');

%  functions, gradients, and hessians vary by method

rdesc={};

for i=1:length(dmeth.responses)
    fhresp=str2func([dmeth.responses{i} '.dakota_write']);
    [rdesc]=fhresp(fidi,dresp,rdesc);
end

%  write accumulated response descriptors for all response classes

if ~isempty(rdesc)
    fprintf(fidi,'\tresponse_descriptors =\n');
    vector_write(fidi,sprintf('\t  '),rdesc,6,76);
end

ghspec_write(fidi,params,dmeth.ghspec);

fprintf(fidi,'\n');

end

%%  function to write gradient and hessian specifications

function []=ghspec_write(fidi,params,ghspec)

%  gradients

if ismember('grad',ghspec)
    if     ~params.numerical_gradients && ~params.analytic_gradients
        params.numerical_gradients=true;
    elseif (params.numerical_gradients+params.analytic_gradients > 1)
        error('Too many gradients selected.')
    end

    if     params.numerical_gradients
        param_write(fidi,'\t','numerical_gradients','','\n',params);
        param_write(fidi,'\t  ','method_source',' ','\n',params);
        param_write(fidi,'\t  ','interval_type',' ','\n',params);
        param_write(fidi,'\t  ','fd_gradient_step_size',' = ','\n',params);
    elseif params.analytic_gradients
        param_write(fidi,'\t','analytic_gradients','','\n',params);
%     elseif params.mixed_gradients
    end
else
    fprintf(fidi,'\tno_gradients\n');
end

%  hessians (no implemented methods use them yet)

if ismember('hess',ghspec)
    error('Hessians needed by method but not provided.');
else
    fprintf(fidi,'\tno_hessians\n');
end

end
