function [studyinfo,options] = dsSetupStudy(base_model,varargin)
% dsSetupStudy - Initialize DynaSim studyinfo structure, prepare list of output file names, and create output directories
%
% TODO: break up this function into smaller functions
%
% See also: dsSimulate, dsUpdateStudy
%
% Author: Jason Sherfey, PhD <jssherfey@gmail.com>
% Copyright (C) 2016 Jason Sherfey, Boston University, USA
% Check inputs
opts=dsCheckOptions(varargin,{...
'modifications_set',[],[],... % search space
'simulator_options',[],[],... % options from dsSimulate
'mex_flag',0,{0,1},...
'cluster_flag',0,{0,1},...
'one_solve_file_flag',0,{0,1},...
'process_id',[],[],... % process identifier for loading studyinfo if necessary
},false);
if isempty(opts.simulator_options)
error('dsSetupStudy must be given a simulator_options structure from dsSimulate');
end
modifications_set = opts.modifications_set;
process_id = opts.process_id;
options = opts.simulator_options;
% Setup Study
if options.verbose_flag
fprintf('\nPREPARING STUDY:\n');
end
if options.save_data_flag || options.save_results_flag || options.parfor_flag
% If in parallel mode, need to calculate
% studyinfo regardless of whether or not
% are saving data.
% set default study_dir if necessary
if isempty(options.study_dir)
if ~options.auto_gen_test_data_flag && ~options.unit_test_flag
% format: <study_dir> = <project_dir>/<prefix>_<timestamp>
options.study_dir=fullfile(options.project_dir,[options.prefix '_' datestr(now,'yyyymmddHHMMSS')]);
else
options.study_dir=fullfile(options.project_dir,[options.prefix '_unitTest']);
end
end
% make sure we have the full path and access rights
options.study_dir = getAbsolutePath(options.study_dir);
% create study_dir if it doesn't exist
if ~isdir(options.study_dir)
if options.verbose_flag
fprintf('Creating study directory: %s\n',options.study_dir);
end
mkdir(options.study_dir);
end
% set solve_file name for this study
if isempty(options.solve_file)
% set default solve_file for this study
[~,fname] = fileparts(options.study_dir);
fname = ['solve_ode_' fname];
% replace non-word characters by underscores so that matlab can execute
% the file as a Matlab function:
fname = regexprep(fname,'[^\w]','_');
% add #sims to name if mex_flag and one_solve_file_flag since #sims coded
% into file
if options.mex_flag && options.one_solve_file_flag && options.cluster_flag
nSims = length(modifications_set);
fname = sprintf('%s_%isims', fname, nSims);
end
% store the solve file
options.solve_file = fullfile(options.study_dir,'solve',[fname '.m']);
end
% initialize studyinfo if not already initialized
if ischar(options.study_dir) && isdir(options.study_dir) && exist(fullfile(options.study_dir,'studyinfo.mat'),'file')
% studyinfo file already exists
studyinfo=dsCheckStudyinfo(options.study_dir,'process_id',process_id, varargin{:});
orig_studyinfo=studyinfo;
else
orig_studyinfo=[];
% studyinfo file does not exist; initialize new studyinfo structure
if ~isempty(base_model)
warning off; %warning('off','MATLAB:warn_r14_stucture_assignment')
studyinfo.simulations.sim_id = 1; % set up dummy simulations sub-structure
warning on;
else
studyinfo = [];
end
studyinfo=dsCheckStudyinfo(studyinfo,'process_id',process_id, varargin{:}); % auto-fill all fields
end
% set basic metadata for this study
studyinfo.study_dir = options.study_dir;
studyinfo.project_id = [];%options.project_id; % <-- placeholder for future feature
if isempty(studyinfo.base_model)
studyinfo.base_model = base_model;
end
if isempty(studyinfo.base_simulator_options)
studyinfo.base_simulator_options = options;
end
if isempty(studyinfo.base_solve_file)
studyinfo.base_solve_file = options.solve_file;
end
if isempty(studyinfo.base_data_files)
studyinfo.base_data_files = {};%options.base_data_files; % <-- placeholder for future feature (analysis stream)
end
% create study_dir if it doesn't exist
if ~isdir(options.study_dir)
if options.verbose_flag
fprintf('Creating study directory: %s\n',options.study_dir);
end
mkdir(options.study_dir);
end
% create models dir if it doesn't exist and saving model
% models_dir = fullfile(options.study_dir,'models');
% if ~isdir(models_dir)
% if options.verbose_flag
% fprintf('creating models directory: %s\n',models_dir);
% end
% mkdir(models_dir);
% end
% create data dir if it doesn't exist
data_dir = fullfile(options.study_dir,'data');
if ~isdir(data_dir)
if options.verbose_flag
fprintf('Creating data directory: %s\n',data_dir);
end
mkdir(data_dir);
end
% create results dir if it doesn't exist
results_dir = fullfile(options.study_dir,'results');
if ~isdir(results_dir)
if options.verbose_flag
fprintf('Creating results directory: %s\n',results_dir);
end
mkdir(results_dir);
end
% create figure dir if it doesn't exist and is needed
if ~isempty(options.plot_functions)
plot_dir = fullfile(options.study_dir,'plots');
if ~isdir(plot_dir)
if options.verbose_flag
fprintf('Creating plot directory: %s\n',plot_dir);
end
mkdir(plot_dir);
end
end
% set single-simulation metadata (studyinfo.simulation(k))
% create list of output file names (use modifications_set to loop sims)
for k = 1:length(modifications_set)
if length(studyinfo.simulations)<k || isempty(studyinfo.simulations(k).status)
studyinfo.simulations(k).sim_id=k;
studyinfo.simulations(k).modifications=modifications_set{k};
% set file names for data (in data_dir)
fname=[options.prefix '_sim' num2str(k) '_data.mat'];
studyinfo.simulations(k).data_file=fullfile(data_dir,fname);
fname=[options.prefix '_sim' num2str(k) '_model.mat'];
%studyinfo.simulations(k).modified_model_file=fullfile(models_dir,fname);
studyinfo.simulations(k).status='initialized';
% set file names for analysis results (in results_dir)
for kk = 1:length(options.analysis_functions)
studyinfo.simulations(k).result_functions{end+1} = options.analysis_functions{kk};
studyinfo.simulations(k).result_options{end+1} = options.analysis_options{kk};
% check for function-specific prefix
this_analysis_options = dsCheckOptions(options.analysis_options{kk}, {'prefix',options.prefix,[]},false);
prefix = this_analysis_options.prefix;
fname = [prefix '_sim' num2str(k) '_analysis' num2str(kk) '_' func2str(options.analysis_functions{kk}) '.mat'];
studyinfo.simulations(k).result_files{end+1} = fullfile(results_dir,fname);
end
% set files names for saved plots (in plot_dir)
for kk = 1:length(options.plot_functions)
studyinfo.simulations(k).result_functions{end+1}=options.plot_functions{kk};
studyinfo.simulations(k).result_options{end+1}=options.plot_options{kk};
% check for function-specific prefix
this_plot_options = dsCheckOptions(options.plot_options{kk}, {'prefix',options.prefix,[]},false);
prefix = this_plot_options.prefix;
fname=[prefix '_sim' num2str(k) '_plot' num2str(kk) '_' func2str(options.plot_functions{kk})];
% note: extension will depend on output format (jpg,png,eps,svg)
% and be set in dsAnalyze().
studyinfo.simulations(k).result_files{end+1}=fullfile(plot_dir,fname);
end
% TODO: add options.detailed_names_flag (see dsAnalyzeStudy())
% ...
end
end
% TODO: set single-analysis metadata (studyinfo.analysis(k))
% ...
% save studyinfo if it has changed
if ~isequal(orig_studyinfo,studyinfo)
% save studyinfo structure to disk
study_file=fullfile(options.study_dir,'studyinfo.mat');
dsStudyinfoIO(studyinfo,study_file,process_id,options.verbose_flag);
end
%% save run file
if options.copy_run_file_flag
stack = dbstack;
firstFile = stack(end).file;
if ~contains(firstFile, 'dsSimulate')
runFile = firstFile;
runFilePath = which(firstFile);
else
runFilePath = '';
end
solveDir = fullfile(options.study_dir, 'solve');
if ~isdir(solveDir)
mkdir(solveDir);
end
if ~isempty(runFilePath)
dsVprintf(options, 'Copying run file ''%s'' into ''study_dir/solve'': %s \n', runFile,solveDir);
copyPath = fullfile(solveDir, runFile);
copyfile(runFilePath, copyPath);
end
end
%% save mech files
if options.copy_mech_files_flag
% add pop mechs
mechFiles = horzcat(base_model.specification.populations.mechanism_list);
% add connection mechs
if ~isempty(base_model.specification.connections)
mechFiles = horzcat(mechFiles, base_model.specification.connections.mechanism_list);
end
if ~isempty(mechFiles)
dsVprintf(options, 'Copying mech files into ''study_dir/solve/mechs''... \n');
mechCopyDir = fullfile(options.study_dir, 'solve','mechs');
if ~isdir(mechCopyDir)
mkdir(mechCopyDir);
end
for iFile = 1:length(mechFiles)
try
thisFilePath = mechFiles{iFile};
thisFilePath = which(thisFilePath);
[~, fileName,ext] = fileparts(thisFilePath);
dsVprintf(options, ' %s \n', fileName);
thisCopyPath = fullfile(mechCopyDir, [fileName, ext]);
copyfile(thisFilePath, thisCopyPath);
end
end
end
end % options.copy_mech_files_flag
else
% set defaults for not saving anything
if isempty(options.study_dir)
% if not saving data, store solvers in current directory
options.study_dir = pwd; % this is where /solve/solve_ode.m will be created
end
if ~isdir(options.study_dir) % in case user provides different location to save solvers
if options.verbose_flag
fprintf('Creating study directory: %s\n',options.study_dir);
end
mkdir(options.study_dir);
end
studyinfo=[];
end