Program Listing for File generateC.m¶
↰ Return to documentation for file (matlab/@amimodel/generateC.m
)
function generateC(this)
% generateC generates the c files which will be used in the compilation.
%
% Return values:
% void
% different signatures for cvodes / idas
if(strcmp(this.wtype,'iw'))
dxvec = 'dx,';
rtcj = 'cj,';
else
dxvec = 'NULL,';
rtcj = '0.0,';
end
% write fun ccode
for ifun = this.funs
cppFunctionName = strrep(ifun{1}, 'sigma_', 'sigma');
if(isfield(this.fun,ifun{1}))
bodyNotEmpty = any(this.fun.(ifun{1}).sym(:)~=0);
if(strcmp(ifun{1},'JSparse'))
bodyNotEmpty = any(this.fun.J.sym(:)~=0);
end
if(bodyNotEmpty)
fprintf([ifun{1} ' | ']);
fid = fopen(fullfile(this.wrap_path,'models',this.modelname,[this.modelname '_' cppFunctionName '.cpp']),'w');
fprintf(fid,'\n');
fprintf(fid,'#include "amici/symbolic_functions.h"\n');
fprintf(fid,'#include "amici/defines.h" //realtype definition\n');
if(ismember(ifun{1},{'JSparse'}))
fprintf(fid,'#include <sunmatrix/sunmatrix_sparse.h> //SUNMatrixContent_Sparse definition\n');
end
fprintf(fid,'typedef amici::realtype realtype;\n');
fprintf(fid,'#include <cmath> \n');
fprintf(fid,'\n');
fprintf(fid,'using namespace amici;\n');
fprintf(fid,'\n');
fprintf(fid,'namespace amici {\n\n');
fprintf(fid,['namespace model_' this.modelname '{\n\n']);
% function definition
fprintf(fid,['void ' cppFunctionName '_' this.modelname '' this.fun.(ifun{1}).argstr ' {\n']);
if(strcmp(ifun{1},'JSparse'))
for i = 1:length(this.rowvals)
fprintf(fid,[' JSparse->indexvals[' num2str(i-1) '] = ' num2str(this.rowvals(i)) ';\n']);
end
for i = 1:length(this.colptrs)
fprintf(fid,[' JSparse->indexptrs[' num2str(i-1) '] = ' num2str(this.colptrs(i)) ';\n']);
end
end
if(strcmp(ifun{1},'JBand'))
fprintf(fid,['return(J_' this.modelname removeTypes(this.fun.J.argstr) ');']);
elseif(strcmp(ifun{1},'JBandB'))
fprintf(fid,['return(JB_' this.modelname removeTypes(this.fun.JB.argstr) ');']);
else
if( strcmp(ifun{1},'qBdot') )
fprintf(fid,'switch (ip) {\n');
this.fun.(ifun{1}).writeCcode_sensi(this,fid);
fprintf(fid,'}\n');
elseif(this.fun.(ifun{1}).sensiflag)
fprintf(fid,'switch (ip) {\n');
this.fun.(ifun{1}).writeCcode_sensi(this,fid);
fprintf(fid,'}\n');
else
this.fun.(ifun{1}).writeCcode(this,fid);
end
end
fprintf(fid,'}\n');
fprintf(fid,'\n');
fprintf(fid,['} // namespace model_' this.modelname '\n\n']);
fprintf(fid,'} // namespace amici\n\n');
fclose(fid);
end
end
end
% wrapfunctions.h
fid = fopen(fullfile(this.wrap_path,'models',this.modelname,'wrapfunctions.h'),'w');
fprintf(fid,'#ifndef _amici_wrapfunctions_h\n');
fprintf(fid,'#define _amici_wrapfunctions_h\n');
fprintf(fid,'\n');
fprintf(fid,['#include "' this.modelname '.h"\n']);
fprintf(fid,'\n');
fprintf(fid,'namespace amici {\n\n');
fprintf(fid,'namespace generic_model {\n\n');
fprintf(fid,'std::unique_ptr<amici::Model> getModel();\n');
fprintf(fid,'\n');
fprintf(fid,'} // namespace generic_model\n\n');
fprintf(fid,'} // namespace amici \n\n');
fprintf(fid,'#endif /* _amici_wrapfunctions_h */\n');
fclose(fid);
%
%----------------------------------------------------------------
% modelname.h
% model specific function declarations
%----------------------------------------------------------------
%
matVer = ver('MATLAB');
fid = fopen(fullfile(this.wrap_path,'models',this.modelname,[this.modelname '.h']),'w');
fprintf(fid,['#ifndef _amici_' this.modelname '_h\n']);
fprintf(fid,['#define _amici_' this.modelname '_h\n']);
fprintf(fid,['/* Generated by amiwrap ' matVer.Release ' ' getCommitHash(fileparts(fileparts(mfilename('fullpath')))) ' */\n']);
fprintf(fid,'#include <cmath>\n');
fprintf(fid,'#include <memory>\n');
fprintf(fid,'#include "amici/defines.h"\n');
fprintf(fid,'#include <sunmatrix/sunmatrix_sparse.h> //SUNMatrixContent_Sparse definition\n');
if(~strcmp(this.wtype,'iw'))
fprintf(fid,'#include "amici/solver_cvodes.h"\n');
fprintf(fid,'#include "amici/model_ode.h"\n');
else
fprintf(fid,'#include "amici/solver_idas.h"\n');
fprintf(fid,'#include "amici/model_dae.h"\n');
end
fprintf(fid,'\n');
fprintf(fid,'namespace amici {\n\n');
fprintf(fid,'class Solver;\n\n');
fprintf(fid,['namespace model_' this.modelname '{\n\n']);
for ifun = this.funs
if(~isfield(this.fun,ifun{1}))
this.fun(1).(ifun{1}) = amifun(ifun{1},this); % don't use getfun here
% as we do not want symbolics to be generated, we only want to be able
% access argstr
end
if(checkIfFunctionBodyIsNonEmpty(this,ifun{1}))
cppFunctionName = strrep(ifun{1}, 'sigma_', 'sigma');
fprintf(fid,['extern void ' cppFunctionName '_' this.modelname this.fun.(ifun{1}).argstr ';\n']);
end
end
% Subclass Model
fprintf(fid,'\n');
if(strcmp(this.wtype,'iw'))
baseclass = 'Model_DAE';
else
baseclass = 'Model_ODE';
end
fprintf(fid,['class Model_' this.modelname ' : public amici::' baseclass ' {\n']);
fprintf(fid,'public:\n');
fprintf(fid,[' Model_' this.modelname '()\n']);
fprintf(fid,[' : amici::' baseclass '(\n']);
fprintf(fid,[' amici::ModelDimensions(\n']);
fprintf(fid,[' ' num2str(this.nx) ',\n']);
fprintf(fid,[' ' num2str(this.nxtrue) ',\n']);
fprintf(fid,[' ' num2str(this.nx) ',\n']);
fprintf(fid,[' ' num2str(this.nxtrue) ',\n']);
fprintf(fid,[' 0,\n']);
fprintf(fid,[' ' num2str(this.np) ',\n']);
fprintf(fid,[' ' num2str(this.nk) ',\n']);
fprintf(fid,[' ' num2str(this.ny) ',\n']);
fprintf(fid,[' ' num2str(this.nytrue) ',\n']);
fprintf(fid,[' ' num2str(this.nz) ',\n']);
fprintf(fid,[' ' num2str(this.nztrue) ',\n']);
fprintf(fid,[' ' num2str(this.nevent) ',\n']);
fprintf(fid,[' ' num2str(this.ng) ',\n']);
fprintf(fid,[' ' num2str(this.nw) ',\n']);
fprintf(fid,[' ' num2str(this.ndwdx) ',\n']);
fprintf(fid,[' ' num2str(this.ndwdp) ',\n']);
fprintf(fid,[' 0,\n']);
fprintf(fid,[' 0,\n']);
fprintf(fid,[' {},\n']);
fprintf(fid,[' ' num2str(this.nnz) ',\n']);
fprintf(fid,[' ' num2str(this.ubw) ',\n']);
fprintf(fid,[' ' num2str(this.lbw) '\n']);
fprintf(fid,[' ),\n']);
fprintf(fid,[' amici::SimulationParameters(\n']);
fprintf(fid,[' std::vector<realtype>(' num2str(this.nk) ', 1.0),\n']);
fprintf(fid,[' std::vector<realtype>(' num2str(this.np) ', 1.0)\n']);
fprintf(fid,[' ),\n']);
switch(this.o2flag)
case 1
fprintf(fid,' amici::SecondOrderMode::full,\n');
case 2
fprintf(fid,' amici::SecondOrderMode::directional,\n');
otherwise
fprintf(fid,' amici::SecondOrderMode::none,\n');
end
initstr = num2str(this.id, '%d, ');
fprintf(fid,[' std::vector<realtype>{' initstr(1:end-1) '},\n']);
initstr = num2str(transpose(this.z2event), '%d, ');
fprintf(fid,[' std::vector<int>{' initstr(1:end-1) '})\n']);
fprintf(fid,[' {};\n\n']);
fprintf(fid,[' amici::Model* clone() const override { return new Model_' this.modelname '(*this); };\n\n']);
fprintf(fid,[' std::string getAmiciCommit() const override { return "' getCommitHash(fileparts(fileparts(mfilename('fullpath')))) '"; };\n\n']);
for ifun = this.funs
cppFunctionName = strrep(ifun{1}, 'sigma_', 'sigma');
fprintf(fid,[' void f' cppFunctionName this.fun.(ifun{1}).argstr ' override {\n']);
if(checkIfFunctionBodyIsNonEmpty(this,ifun{1}))
fprintf(fid,[' ' cppFunctionName '_' this.modelname '' removeTypes(this.fun.(ifun{1}).argstr) ';\n']);
end
fprintf(fid,' }\n\n');
end
fprintf(fid,'};\n\n');
fprintf(fid,['} // namespace model_' this.modelname '\n\n']);
fprintf(fid,'} // namespace amici \n\n');
fprintf(fid,['#endif /* _amici_' this.modelname '_h */\n']);
fclose(fid);
% wrapfunctions.cpp
fid = fopen(fullfile(this.wrap_path,'models',this.modelname,'wrapfunctions.cpp'),'w');
fprintf(fid,'#include "amici/model.h"\n');
fprintf(fid,'#include "wrapfunctions.h"\n\n');
fprintf(fid,'namespace amici {\n\n');
fprintf(fid,'namespace generic_model {\n\n');
fprintf(fid,'std::unique_ptr<amici::Model> getModel() {\n');
fprintf(fid,' return std::unique_ptr<amici::Model>(\n');
fprintf(fid,[' new amici::model_' this.modelname '::Model_' this.modelname '());\n']);
fprintf(fid,'}\n\n');
fprintf(fid,'} // namespace generic_model\n\n');
fprintf(fid,'} // namespace amici \n\n');
fclose(fid);
fprintf('CMakeLists | ');
generateCMakeFile(this);
fprintf('swig | ');
generateSwigInterfaceFiles(this)
fprintf('main | ');
generateMainC(this);
fprintf('\r')
end
function argstr = removeTypes(argstr)
% removeTypes transforms an argument string from a string with variable
% types (for function definition) to a string without variable types
% (for function calling)
%
% Parameters:
% argstr: function definition argument string @type *char
%
% Return values:
% argstr: function call argument string @type *char
argstr = strrep(argstr,'realtype','');
argstr = strrep(argstr,'int','');
argstr = strrep(argstr,'const','');
argstr = strrep(argstr,'double','');
argstr = strrep(argstr,'SUNMatrixContent_Sparse','');
argstr = strrep(argstr,'*','');
argstr = strrep(argstr,' ','');
argstr = strrep(argstr,',',', ');
end
function generateCMakeFile(this)
sourceStr = '';
for j=1:length(this.funs)
funcName = this.funs{j};
if(checkIfFunctionBodyIsNonEmpty(this,funcName))
cppFunctionName = strrep(funcName, 'sigma_', 'sigma');
sourceStr = [ sourceStr, sprintf('${MODEL_DIR}/%s_%s.cpp\n', this.modelname, cppFunctionName) ];
end
end
t = template();
t.add('TPL_MODELNAME', this.modelname);
t.add('TPL_SOURCES', sourceStr);
t.add('TPL_AMICI_VERSION', '');
CMakeFileName = fullfile(this.wrap_path,'models',this.modelname,'CMakeLists.txt');
CMakeTemplateFileName = fullfile(fileparts(fileparts(fileparts(mfilename('fullpath')))), 'src' , 'CMakeLists.template.cmake');
t.replace(CMakeTemplateFileName, CMakeFileName);
end
function generateSwigInterfaceFiles(this)
modelSwigDir = fullfile(this.wrap_path,'models',this.modelname,'swig');
amiciSwigDir = fullfile(fileparts(fileparts(fileparts(mfilename('fullpath')))),'swig');
if(~exist(modelSwigDir,'dir'))
mkdir(modelSwigDir)
end
%interface file
t = template();
t.add('TPL_MODELNAME', this.modelname);
SwigInterfaceFile = fullfile(modelSwigDir,[this.modelname '.i']);
SwigInterfaceTemplateFileName = fullfile(amiciSwigDir, 'modelname.template.i');
t.replace(SwigInterfaceTemplateFileName, SwigInterfaceFile);
%CMakeLists.txt
if(~exist(fullfile(this.wrap_path,'models',this.modelname,'swig'),'dir'))
mkdir(fullfile(this.wrap_path,'models',this.modelname),'swig');
end
copyfile(fullfile(amiciSwigDir,'CMakeLists_model.cmake'),fullfile(modelSwigDir,'CMakeLists.txt'));
end
function generateMainC(this)
mainFileSource = fullfile(fileparts(fileparts(fileparts(mfilename('fullpath')))), 'src/main.template.cpp');
mainFileDestination = fullfile(this.wrap_path,'models',this.modelname,'main.cpp');
copyfile(mainFileSource, mainFileDestination);
end
function nonempty = checkIfFunctionBodyIsNonEmpty(this,ifun)
% if we don't have symbolic variables, it might have been generated before and symbolic expressions were simply not
% regenerated. any() for empty (no generated) variables is always false.
cppFunctionName = strrep(ifun, 'sigma_', 'sigma');
nonempty = or(exist(fullfile(this.wrap_path,'models',this.modelname,[this.modelname '_' cppFunctionName '.cpp']),'file'),any(this.fun.(ifun).sym(:)~=0));
end