Program Listing for File amimodel.m

Return to documentation for file (matlab/@amimodel/amimodel.m)

%
% @file amimodel
% @brief definition of amimodel class
%
classdef amimodel < handle
    % AMIMODEL carries all model definitions including functions and events

    properties ( GetAccess = 'public', SetAccess = 'private' )
        % symbolic definition struct @type struct
        sym = struct.empty();
        % struct which stores information for which functions c code needs to be generated @type struct
        fun = struct.empty();
        % struct which stores information for which functions c code needs
        % to be generated @type amievent
        event = amievent.empty();
        % name of the model @type string
        modelname = char.empty();
        % struct that contains hash values for the symbolic model definitions @type struct
        HTable = struct.empty();
        % flag indicating whether debugging symbols should be compiled @type bool
        debug = false;
        % flag indicating whether adjoint sensitivities should be enabled @type bool
        adjoint = true;
        % flag indicating whether forward sensitivities should be enabled @type bool
        forward = true;
        % default initial time @type double
        t0 = 0;
        % type of wrapper (cvodes/idas) @type string
        wtype = char.empty();
        % number of states @type int
        nx = double.empty();
        % number of original states for second order sensitivities @type int
        nxtrue = double.empty();
        % number of observables @type int
        ny = double.empty();
        % number of original observables for second order sensitivities @type int
        nytrue = double.empty();
        % number of parameters @type int
        np = double.empty();
        % number of constants @type int
        nk = double.empty();
        % number of objective functions @type int
        ng = double.empty();
        % number of events @type int
        nevent = double.empty();
        % number of event outputs @type int
        nz = double.empty();
        % number of original event outputs for second order sensitivities @type int
        nztrue = double.empty();
        % flag for DAEs @type *int
        id = double.empty();
        % upper Jacobian bandwidth @type int
        ubw = double.empty();
        % lower Jacobian bandwidth @type int
        lbw = double.empty();
        % number of nonzero entries in Jacobian @type int
        nnz = double.empty();
        % dataindexes of sparse Jacobian @type *int
        sparseidx = double.empty();
        % rowindexes of sparse Jacobian @type *int
        rowvals = double.empty();
        % columnindexes of sparse Jacobian @type *int
        colptrs = double.empty();
        % dataindexes of sparse Jacobian @type *int
        sparseidxB = double.empty();
        % rowindexes of sparse Jacobian @type *int
        rowvalsB = double.empty();
        % columnindexes of sparse Jacobian @type *int
        colptrsB = double.empty();
        % cell array of functions to be compiled @type *cell
        funs = cell.empty();
        % cell array of matlab functions to be compiled @type *cell
        mfuns = cell.empty();
        % optimisation flag for compilation @type string
        coptim = '-O3';
        % default parametrisation @type string
        param = 'lin';
        % path to wrapper
        wrap_path = char.empty();
        % flag to enforce recompilation of the model
        recompile = false;
        % storage for flags determining recompilation of individual
        % functions
        cfun = struct.empty();
        % flag which identifies augmented models
        %  0 indicates no augmentation
        %  1 indicates augmentation by first order sensitivities (yields
        %  second order sensitivities)
        %  2 indicates augmentation by one linear combination of first
        %  order sensitivities (yields hessian-vector product)
        o2flag = 0;
    end

    properties ( GetAccess = 'public', SetAccess = 'public' )
        % vector that maps outputs to events
        z2event = double.empty();
        % flag indicating whether the model contains spline functions
        splineflag = false;
        % flag indicating whether the model contains min functions
        minflag = false;
        % flag indicating whether the model contains max functions
        maxflag = false;
        % number of derived variables w, w is used for code optimization to reduce the number of frequently occuring
        % expressions @type int
        nw = 0;
        % number of derivatives of derived variables w, dwdx @type int
        ndwdx = 0;
        % number of derivatives of derived variables w, dwdp @type int
        ndwdp = 0;
    end

    methods
        function AM = amimodel(symfun,modelname)
            % amimodel initializes the model object based on the provided
            % symfun and modelname
            %
            % Parameters:
            %  symfun: this is the string to the function which generates
            %  the modelstruct. You can also directly pass the struct here @type string
            %  modelname: name of the model @type string
            %
            % Return values:
            %  AM: model definition object
            if(isa(symfun,'amimodel'))
                AM = symfun;
            else
                if(isa(symfun,'char'))
                    if(exist(symfun,'file')==2)
                        fun = str2func(symfun);
                        model = fun();
                    else
                        error(['"' symfun '" must be the name of a matlab function in a matlab file, with the corresponding name, in the matlab path. Please check whether the folder containing "' symfun '" is in the matlab path. AMICI currently does not support absolute or relative paths in its input arguments.'])
                    end
                elseif(isa(symfun,'struct'))
                    model = symfun;
                elseif(isa(symfun,'function_handle'))
                    model = symfun();
                else
                    error('invalid input symfun')
                end

                if(isfield(model,'sym'))
                    AM.sym = model.sym;
                else
                    error('symbolic definitions missing in struct returned by symfun')
                end



                props = fields(model);

                for j = 1:length(props)
                    if(~strcmp(props{j},'sym')) % we already checked for the sym field
                        if(isfield(model,props{j}))
                            try
                                AM.(props{j}) = model.(props{j});
                            catch
                                error(['The provided model struct or the struct created by the provided model function has the field ' props{j} ' which is not a valid property of ' ...
                                    'the amimodel class. Please check your model definition.']);
                            end
                        end
                    else
                        AM.makeSyms();
                        AM.nx = length(AM.sym.x);
                        if(isempty(AM.nxtrue)) % if its not empty we are dealing with an augmented model
                            AM.nxtrue = AM.nx;
                        end
                        AM.ng = size(AM.sym.Jy,2);
                        AM.np = length(AM.sym.p);
                        AM.nk = length(AM.sym.k);
                        AM.ny = length(AM.sym.y);
                        if(isempty(AM.nytrue)) % if its not empty we are dealing with an augmented model
                            AM.nytrue = AM.ny;
                        end
                    end
                end

                AM.modelname = modelname;
                % set path and create folder
                AM.wrap_path=fileparts(fileparts(fileparts(mfilename('fullpath'))));
                if(~exist(fullfile(AM.wrap_path,'models'),'dir'))
                    mkdir(fullfile(AM.wrap_path,'models'));
                    mkdir(fullfile(AM.wrap_path,'models',AM.modelname));
                else
                    if(~exist(fullfile(AM.wrap_path,'models',AM.modelname),'dir'))
                        mkdir(fullfile(AM.wrap_path,'models',AM.modelname))
                    end
                end
                AM.makeEvents();
                AM.nz = length([AM.event.z]);
                if(isempty(AM.nztrue))
                    AM.nztrue = AM.nz;
                end
                AM.nevent = length(AM.event);

                % check whether we have a DAE or ODE
                if(isfield(AM.sym,'M'))
                    AM.wtype = 'iw'; % DAE
                else
                    AM.wtype = 'cw'; % ODE
                end
            end
        end

        function updateRHS(this,xdot)
            % updateRHS updates the private fun property .fun.xdot.sym
            % (right hand side of the differential equation)
            %
            % Parameters:
            %  xdot: new right hand side of the differential equation
            %
            % Return values:
            %  void
            this.fun.xdot.sym_noopt = this.fun.xdot.sym;
            this.fun.xdot.sym = xdot;
        end

        function updateModelName(this,modelname)
            % updateModelName updates the modelname
            %
            % Parameters:
            %  modelname: new modelname
            %
            % Return values:
            %  void
            this.modelname = modelname;
        end

        function updateWrapPath(this,wrap_path)
            % updateModelName updates the modelname
            %
            % Parameters:
            %  wrap_path: new wrap_path
            %
            % Return values:
            %  void
            this.wrap_path = wrap_path;
        end

        parseModel(this)

        generateC(this)

        generateRebuildM(this)

        compileC(this)

        generateM(this,amimodelo2)

        getFun(this,HTable,funstr)

        makeEvents(this)

        makeSyms(this)

        cflag = checkDeps(this,HTable,deps)

        HTable = loadOldHashes(this)

        modelo2 = augmento2(this)

        modelo2vec = augmento2vec(this)

    end

    methods(Static)
        compileAndLinkModel(modelname, modelSourceFolder, coptim, debug, funs, cfun)

        generateMatlabWrapper(nx, ny, np, nk, nz, o2flag, amimodelo2, wrapperFilename, modelname, pscale, forward, adjoint)
    end

end