Program Listing for File generateMatlabWrapper.m

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

function generateMatlabWrapper(nx, ny, np, nk, nz, o2flag, amimodelo2, wrapperFilename, modelname, ...
    pscale, forward, adjoint)
    % generateMatlabWrapper generates the matlab wrapper for the compiled C files.
    %
    % Parameters:
    %  nx: number of states
    %  ny: number of observables
    %  np: number of parameters
    %  nk: number of fixed parameters
    %  nz: number of events
    %  o2flag: o2flag
    %  amimodelo2: this struct must contain all necessary symbolic
    %  definitions for second order sensivities @type amimodel
    %  wrapperFilename: output filename
    %  modelname: name of the model
    %  pscale: default parameter scaling
    %  forward: has forward sensitivity equations
    %  adjoint: has adjoint sensitivity equations
    %
    % Return values:
    %  void
    amiciRootDir = fileparts(fileparts(fileparts(mfilename('fullpath'))));

    if(~isempty(amimodelo2))
        nztrue = amimodelo2.nztrue;
        nxtrue = amimodelo2.nxtrue;
        nytrue = amimodelo2.nytrue;
        o2flag = amimodelo2.o2flag;
    else
        nztrue = nz;
        nxtrue = nx;
        nytrue = ny;
        o2flag = o2flag;
    end

    [commit_hash,branch,url] = getCommitHash(amiciRootDir);
    if(isempty(commit_hash))
        commit_hash = '#';
    end

    if(o2flag)
        nxtrue = amimodelo2.nxtrue;
        nytrue = amimodelo2.nytrue;
    end


    %% Generation of the simulation file

    fid = fopen(wrapperFilename,'w');
    fprintf(fid,['%% simulate_' modelname '.m is the matlab interface to the cvodes mex\n'...
        '%%   which simulates the ordinary differential equation and respective\n'...
        '%%   sensitivities according to user specifications.\n'...
        '%%   this routine was generated using AMICI commit ' commit_hash ' in branch ' branch ' in repo ' url '.\n'...
        '%%\n'...
        '%% USAGE:\n'...
        '%% ======\n'...
        '%% [...] = simulate_' modelname '(tout,theta)\n'...
        '%% [...] = simulate_' modelname '(tout,theta,kappa,data,options)\n'...
        '%% [status,tout,x,y,sx,sy] = simulate_' modelname '(...)\n'...
        '%%\n'...
        '%% INPUTS:\n'...
        '%% =======\n'...
        '%% tout ... 1 dimensional vector of timepoints at which a solution to the ODE is desired\n'...
        '%% theta ... 1 dimensional parameter vector of parameters for which sensitivities are desired.\n'...
        '%%           this corresponds to the specification in model.sym.p\n'...
        '%% kappa ... 1 dimensional parameter vector of parameters for which sensitivities are not desired.\n'...
        '%%           this corresponds to the specification in model.sym.k\n'...
        '%% data ... struct containing the following fields:\n'...
        '%%     Y ... 2 dimensional matrix containing data.\n'...
        '%%           columns must correspond to observables and rows to time-points\n'...
        '%%     Sigma_Y ... 2 dimensional matrix containing standard deviation of data.\n'...
        '%%           columns must correspond to observables and rows to time-points\n'...
        '%%     T ... (optional) 2 dimensional matrix containing events.\n'...
        '%%           columns must correspond to event-types and rows to possible event-times\n'...
        '%%     Sigma_T ... (optional) 2 dimensional matrix containing standard deviation of events.\n'...
        '%%           columns must correspond to event-types and rows to possible event-times\n'...
        '%% options ... additional options to pass to the cvodes solver. Refer to the cvodes guide for more documentation.\n'...
        '%%    .atol ... absolute tolerance for the solver. default is specified in the user-provided syms function.\n'...
        '%%        default value is 1e-16\n'...
        '%%    .rtol ... relative tolerance for the solver. default is specified in the user-provided syms function.\n'...
        '%%        default value is 1e-8\n'...
        '%%    .maxsteps    ... maximal number of integration steps. default is specified in the user-provided syms function.\n'...
        '%%        default value is 1e4\n'...
        '%%    .tstart    ... start of integration. for all timepoints before this, values will be set to initial value.\n'...
        '%%        default value is 0\n'...
        '%%    .sens_ind ... 1 dimensional vector of indexes for which sensitivities must be computed.\n'...
        '%%        default value is 1:length(theta).\n'...
        '%%    .x0 ... user-provided state initialisation. This should be a vector of dimension [#states, 1].\n'...
        '%%        default is state initialisation based on the model definition.\n'...
        '%%    .sx0 ... user-provided sensitivity initialisation. this should be a matrix of dimension [#states x #parameters].\n'...
        '%%        default is sensitivity initialisation based on the derivative of the state initialisation.\n'...
        '%%    .lmm    ... linear multistep method for forward problem.\n'...
        '%%        1: Adams-Bashford\n'...
        '%%        2: BDF (DEFAULT)\n'...
        '%%    .iter    ... iteration method for linear multistep.\n'...
        '%%        1: Functional\n'...
        '%%        2: Newton (DEFAULT)\n'...
        '%%    .linsol   ... linear solver module.\n'...
        '%%        direct solvers:\n'...
        '%%        1: Dense\n'...
        '%%        2: Band (not implemented)\n'...
        '%%        3: LAPACK Dense (not implemented)\n'...
        '%%        4: LAPACK Band  (not implemented)\n'...
        '%%        5: Diag (not implemented)\n'...
        '%%        implicit krylov solvers:\n'...
        '%%        6: SPGMR\n'...
        '%%        7: SPBCG\n'...
        '%%        8: SPTFQMR\n'...
        '%%        sparse solvers:\n'...
        '%%        9: KLU (DEFAULT)\n'...
        '%%    .stldet   ... flag for stability limit detection. this should be turned on for stiff problems.\n'...
        '%%        0: OFF\n'...
        '%%        1: ON (DEFAULT)\n'...
        '%%    .sensi   ... sensitivity order.\n'...
        '%%        0: OFF (DEFAULT)\n'...
        '%%        1: first\n'...
        '%%        2: second\n'...
        '%%    .sensi_meth   ... method for sensitivity analysis.\n'...
        '%%        0: no sensitivity analysis\n'...
        '%%        1 or ''forward'': forward sensitivity analysis (DEFAULT)\n'...
        '%%        2 or ''adjoint'': adjoint sensitivity analysis \n'...
        '%%        3 or ''ss'': defined but not documented \n'...
        '%%    .adjoint   ... flag for adjoint sensitivity analysis.\n'...
        '%%        true: on \n'...
        '%%        false: off (DEFAULT)\n'...
        '%%        NO LONGER USED: Replaced by sensi_meth\n'...
        '%%    .ism   ... only available for sensi_meth == 1. Method for computation of forward sensitivities.\n'...
        '%%        1: Simultaneous (DEFAULT)\n'...
        '%%        2: Staggered\n'...
        '%%        3: Staggered1\n'...
        '%%    .Nd   ... only available for sensi_meth == 2. Number of Interpolation nodes for forward solution. \n'...
        '%%        default is 1000. \n'...
        '%%    .interpType   ... only available for sensi_meth == 2. Interpolation method for forward solution.\n'...
        '%%        1: Hermite (DEFAULT for problems without discontinuities)\n'...
        '%%        2: Polynomial (DEFAULT for problems with discontinuities)\n'...
        '%%    .ordering   ... online state reordering.\n'...
        '%%        0: AMD reordering (default)\n'...
        '%%        1: COLAMD reordering\n'...
        '%%        2: natural reordering\n'...
        '%%    .newton_maxsteps   ... maximum newton steps\n'...
        '%%        default value is 40\n'...
        '%%        a value of 0 will disable the newton solver\n'...
        '%%    .newton_maxlinsteps   ... maximum linear steps\n'...
        '%%        default value is 100\n'...
        '%%    .newton_preeq   ... preequilibration of system via newton solver\n'...
        '%%        default value is false\n'...
        '%%    .pscale   ... parameter scaling\n'...
        '%%        []: (DEFAULT) use value specified in the model (fallback: ''lin'')\n'...
        '%%        0 or ''lin'': linear\n'...
        '%%        1 or ''log'': natural log (base e)\n'...
        '%%        2 or ''log10'': log to the base 10\n'...
        '%%\n'...
        '%% Outputs:\n'...
        '%% ========\n'...
        '%% sol.status ... flag for status of integration. generally status<0 for failed integration\n'...
        '%% sol.t ... vector at which the solution was computed\n'...
        '%% sol.llh ... likelihood value\n'...
        '%% sol.chi2 ... chi2 value\n'...
        '%% sol.sllh ... gradient of likelihood\n'...
        '%% sol.s2llh ... hessian or hessian-vector-product of likelihood\n'...
        '%% sol.x ... time-resolved state vector\n'...
        '%% sol.y ... time-resolved output vector\n'...
        '%% sol.sx ... time-resolved state sensitivity vector\n'...
        '%% sol.sy ... time-resolved output sensitivity vector\n'...
        '%% sol.z ... event output\n'...
        '%% sol.sz ... sensitivity of event output\n'...
        ]);


    fprintf(fid,['function varargout = simulate_' modelname '(varargin)\n\n']);
    fprintf(fid,'%% DO NOT CHANGE ANYTHING IN THIS FILE UNLESS YOU ARE VERY SURE ABOUT WHAT YOU ARE DOING\n');
    fprintf(fid,'%% MANUAL CHANGES TO THIS FILE CAN RESULT IN WRONG SOLUTIONS AND CRASHING OF MATLAB\n');
    fprintf(fid,'if(nargin<2)\n');
    fprintf(fid,'    error(''Not enough input arguments.'');\n');
    fprintf(fid,'else\n');
    fprintf(fid,'    tout=varargin{1};\n');
    fprintf(fid,'    theta=varargin{2};\n');
    fprintf(fid,'end\n');

    fprintf(fid,'if(nargin>=3)\n');
    fprintf(fid,'    kappa=varargin{3};\n');
    fprintf(fid,'else\n');
    fprintf(fid,'    kappa=[];\n');
    fprintf(fid,'end\n');
    fprintf(fid,'\n');
    if(nk==0)
        fprintf(fid,'if(nargin==2)\n');
        fprintf(fid,'    kappa = [];\n');
        fprintf(fid,'end\n');
    end

    fprintf(fid,['if(length(theta)<' num2str(np) ')\n']);
    fprintf(fid,'    error(''provided parameter vector is too short'');\n');
    fprintf(fid,'end\n');
    fprintf(fid,'\n');

    fprintf(fid,'\n');
    fprintf(fid,'xscale = [];\n');
    fprintf(fid,'if(nargin>=5)\n');
    fprintf(fid,'    if(isa(varargin{5},''amioption''))\n');
    fprintf(fid,'        options_ami = varargin{5};\n');
    fprintf(fid,'    else\n');
    fprintf(fid,'        options_ami = amioption(varargin{5});\n');
    fprintf(fid,'    end\n');
    fprintf(fid,'else\n');
    fprintf(fid,'    options_ami = amioption();\n');
    fprintf(fid,'end\n');
    fprintf(fid,'if(isempty(options_ami.sens_ind))\n');
    fprintf(fid,['    options_ami.sens_ind = 1:' num2str(np) ';\n']);
    fprintf(fid,['end\n']);
    if(o2flag == 0)
        fprintf(fid,'if(options_ami.sensi>1)\n');
        fprintf(fid,'    error(''Second order sensitivities were requested but not computed'');\n');
        fprintf(fid,'end\n');
    end
    fprintf(fid,'\n');


    fprintf(fid,'if(isempty(options_ami.pscale))\n');
    fprintf(fid,['    options_ami.pscale = ''' pscale ''' ;\n']);
    fprintf(fid,'end\n');

    if(o2flag == 2)
        fprintf(fid,'if(nargin>=6)\n');
        fprintf(fid,'    chainRuleFactor = getChainRuleFactors(options_ami.pscale, theta, options_ami.sens_ind);\n');
        fprintf(fid,'    v = varargin{6};\n');
        fprintf(fid,'    v = v(:).*chainRuleFactor(:);\n');
        fprintf(fid,'else\n');
        fprintf(fid,'    if(options_ami.sensi==2)\n');
        fprintf(fid,'        error(''6th argument (multiplication vector is missing'');\n');
        fprintf(fid,'    end\n');
        fprintf(fid,'end\n');
    end

    if(o2flag)
        fprintf(fid,'if(nargout>1)\n');
        fprintf(fid,'    if(nargout>6)\n');
        fprintf(fid,'        options_ami.sensi = 2;\n');
        fprintf(fid,'        options_ami.sensi_meth = ''forward'';\n');
        fprintf(fid,'    elseif(nargout>4)\n');
        fprintf(fid,'        options_ami.sensi = 1;\n');
        fprintf(fid,'        options_ami.sensi_meth = ''forward'';\n');
        fprintf(fid,'    else\n');
        fprintf(fid,'        options_ami.sensi = 0;\n');
        fprintf(fid,'    end\n');
        fprintf(fid,'end\n');
    else
        fprintf(fid,'if(nargout>1)\n');
        fprintf(fid,'    if(nargout>4)\n');
        fprintf(fid,'        options_ami.sensi = 1;\n');
        fprintf(fid,'        options_ami.sensi_meth = ''forward'';\n');
        fprintf(fid,'    else\n');
        fprintf(fid,'        options_ami.sensi = 0;\n');
        fprintf(fid,'    end\n');
        fprintf(fid,'end\n');
    end
    if(~forward)
        fprintf(fid,'if(options_ami.sensi>0)\n');
        fprintf(fid,'    if(options_ami.sensi_meth == 1)\n');
        fprintf(fid,'        error(''forward sensitivities are disabled as necessary routines were not compiled'');\n');
        fprintf(fid,'    end\n');
        fprintf(fid,'end\n');
    end
    if(~adjoint)
        fprintf(fid,'if(options_ami.sensi>0)\n');
        fprintf(fid,'    if(options_ami.sensi_meth == 2)\n');
        fprintf(fid,'        error(''adjoint sensitivities are disabled as necessary routines were not compiled'');\n');
        fprintf(fid,'    end\n');
        fprintf(fid,'end\n');
    end
    fprintf(fid,['nplist = length(options_ami.sens_ind); %% MUST NOT CHANGE THIS VALUE\n']);
    fprintf(fid,['if(nplist == 0)\n']);
    fprintf(fid,['    options_ami.sensi = 0;\n']);
    fprintf(fid,['end\n']);
    if(o2flag)
        fprintf(fid,['if(options_ami.sensi > 1)\n']);
        fprintf(fid,['    nxfull = ' num2str(amimodelo2.nx) ';\n']);
        fprintf(fid,['else\n']);
        fprintf(fid,['    nxfull = ' num2str(nxtrue) ';\n']);
        fprintf(fid,['end\n']);
    else
        fprintf(fid,['nxfull = ' num2str(nx) ';\n']);
    end
    fprintf(fid,'plist = options_ami.sens_ind-1;\n');
    fprintf(fid,['if(nargin>=4)\n']);
    fprintf(fid,['    if(isempty(varargin{4}))\n']);
    fprintf(fid,['        data=[];\n']);
    fprintf(fid,['    else\n']);
    fprintf(fid,['        if(isa(varargin{4},''amidata''))\n']);
    fprintf(fid,['             data=varargin{4};\n']);
    fprintf(fid,['        else\n']);
    fprintf(fid,['            data=amidata(varargin{4});\n']);
    fprintf(fid,['        end\n']);
    fprintf(fid,['        if(data.ne>0)\n']);
    fprintf(fid,['            options_ami.nmaxevent = data.ne;\n']);
    fprintf(fid,['        else\n']);
    fprintf(fid,['            data.ne = options_ami.nmaxevent;\n']);
    fprintf(fid,['        end\n']);
    fprintf(fid,['        if(isempty(kappa))\n']);
    fprintf(fid,['            kappa = data.condition;\n']);
    fprintf(fid,['        end\n']);
    fprintf(fid,['        if(isempty(tout))\n']);
    fprintf(fid,['            tout = data.t;\n']);
    fprintf(fid,['        end\n']);
    fprintf(fid,['    end\n']);
    fprintf(fid,['else\n']);
    fprintf(fid,['    data=[];\n']);
    fprintf(fid,['end\n']);
    fprintf(fid,['if(~all(tout==sort(tout)))\n']);
    fprintf(fid,['    error(''Provided time vector is not monotonically increasing!'');\n']);
    fprintf(fid,['end\n']);
    fprintf(fid,['if(max(options_ami.sens_ind)>' num2str(np) ')\n']);
    fprintf(fid,['    error(''Sensitivity index exceeds parameter dimension!'')\n']);
    fprintf(fid,['end\n']);
    fprintf(fid,['if(length(kappa)<' num2str(nk) ')\n']);
    fprintf(fid,'    error(''provided condition vector is too short'');\n');
    fprintf(fid,'end\n');

    if(o2flag == 2)
        fprintf(fid,'if(nargin>=6)\n');
        fprintf(fid,'    kappa = [kappa(:);v(:)];\n');
        fprintf(fid,'end\n');
    end

    fprintf(fid,'init = struct();\n');
    fprintf(fid,'if(~isempty(options_ami.x0))\n');
    fprintf(fid,'    if(size(options_ami.x0,2)~=1)\n');
    fprintf(fid,'        error(''x0 field must be a column vector!'');\n');
    fprintf(fid,'    end\n');
    fprintf(fid,'    if(size(options_ami.x0,1)~=nxfull)\n');
    fprintf(fid,'        error(''Number of rows in x0 field does not agree with number of states!'');\n');
    fprintf(fid,'    end\n');
    fprintf(fid,'    init.x0 = options_ami.x0;\n');
    fprintf(fid,'end\n');
    fprintf(fid,'if(~isempty(options_ami.sx0))\n');
    fprintf(fid,'    if(size(options_ami.sx0,2)~=nplist)\n');
    fprintf(fid,'        error(''Number of columns in sx0 field does not agree with number of model parameters!'');\n');
    fprintf(fid,'    end\n');
    fprintf(fid,'    if(size(options_ami.sx0,1)~=nxfull)\n');
    fprintf(fid,'        error(''Number of rows in sx0 field does not agree with number of states!'');\n');
    fprintf(fid,'    end\n');
    fprintf(fid,'end\n');


    if(o2flag)
        fprintf(fid,'if(options_ami.sensi<2)\n');
        fprintf(fid,['    sol = ami_' modelname '(tout,theta(1:' num2str(np) '),kappa(1:' num2str(nk) '),options_ami,plist,xscale,init,data);\n']);
        fprintf(fid,'else\n');
        switch(o2flag)
            case 1
                fprintf(fid,['    sol = ami_' modelname '_o2(tout,theta(1:' num2str(np) '),kappa(1:' num2str(nk) '),options_ami,plist,xscale,init,data);\n']);
            case 2
                fprintf(fid,['    sol = ami_' modelname '_o2vec(tout,theta(1:' num2str(np) '),kappa(1:' num2str(amimodelo2.nk) '),options_ami,plist,xscale,init,data);\n']);
        end
        fprintf(fid,'end\n');
    else
        fprintf(fid,['sol = ami_' modelname '(tout,theta(1:' num2str(np) '),kappa(1:' num2str(nk) '),options_ami,plist,xscale,init,data);\n']);
    end

    if(o2flag)
        fprintf(fid,'if(options_ami.sensi == 2)\n');
        fprintf(fid, '    if(~(options_ami.sensi_meth==2))\n');

        fprintf(fid,['        sz = zeros(size(sol.z,1),' num2str(nztrue) ',length(theta(options_ami.sens_ind)));\n']);
        fprintf(fid,['        ssigmaz = zeros(size(sol.z,1),' num2str(nztrue) ',length(theta(options_ami.sens_ind)));\n']);
        fprintf(fid,['        srz = zeros(size(sol.z,1),' num2str(nztrue) ',length(theta(options_ami.sens_ind)));\n']);
        fprintf(fid,['        for iz = 1:' num2str(nztrue) '\n']);
        fprintf(fid,['            sz(:,iz,:) = sol.sz(:,2*iz-1,:);\n']);
        fprintf(fid,['            ssigmaz(:,iz,:) = sol.ssigmaz(:,2*iz-1,:);\n']);
        fprintf(fid,['            srz(:,iz,:) = sol.srz(:,2*iz-1,:);\n']);
        fprintf(fid,['        end\n']);
        switch(o2flag)
            case 1
                fprintf(fid,['        sol.s2x = reshape(sol.sx(:,' num2str(nxtrue+1) ':end,:),length(tout),' num2str(nxtrue) ',' num2str(np) ',length(options_ami.sens_ind));\n']);
                fprintf(fid,['        sol.s2y = reshape(sol.sy(:,' num2str(nytrue+1) ':end,:),length(tout),' num2str(nytrue) ',' num2str(np) ',length(options_ami.sens_ind));\n']);
                fprintf(fid,['        sol.s2sigmay = reshape(sol.ssigmay(:,' num2str(nytrue+1) ':end,:),length(tout),' num2str(nytrue) ',' num2str(np) ',length(options_ami.sens_ind));\n']);
            case 2
                fprintf(fid,['        sol.s2x = sol.sx(:,' num2str(nxtrue+1) ':end,:);\n']);
                fprintf(fid,['        sol.s2y = sol.sy(:,' num2str(nytrue+1) ':end,:);\n']);
                fprintf(fid,['        sol.s2sigmay = sol.ssigmay(:,' num2str(nytrue+1) ':end,:);\n']);
        end
        switch(o2flag)
            case 1
                fprintf(fid,['        s2z = zeros(size(sol.z,1),' num2str(nztrue) ',' num2str(np) ',length(options_ami.sens_ind));\n']);
                fprintf(fid,['        s2sigmaz = zeros(size(sol.z,1),' num2str(nztrue) ',' num2str(np) ',length(options_ami.sens_ind));\n']);
                fprintf(fid,['        s2rz = zeros(size(sol.z,1),' num2str(nztrue) ',' num2str(np) ',length(options_ami.sens_ind));\n']);
            case 2
                fprintf(fid,['        s2z = zeros(size(sol.z,1),' num2str(nztrue) ',length(theta(options_ami.sens_ind)));\n']);
                fprintf(fid,['        s2sigmaz = zeros(size(sol.z,1),' num2str(nztrue) ',length(theta(options_ami.sens_ind)));\n']);
                fprintf(fid,['        s2rz = zeros(size(sol.z,1),' num2str(nztrue) ',length(theta(options_ami.sens_ind)));\n']);
        end
        fprintf(fid,['        for iz = 1:' num2str(nztrue) '\n']);
        switch(o2flag)
            case 1
                fprintf(fid,['            sol.s2z(:,iz,:,:) = reshape(sol.sz(:,((iz-1)*(' num2str(np) '+1)+2):((iz-1)*(' num2str(np) '+1)+' num2str(np) '+1),:),options_ami.nmaxevent,1,' num2str(np) ',length(options_ami.sens_ind));\n']);
                fprintf(fid,['            sol.s2sigmaz(:,iz,:,:) = reshape(sol.ssigmaz(:,((iz-1)*(' num2str(np) '+1)+2):((iz-1)*(' num2str(np) '+1)+' num2str(np) '+1),:),options_ami.nmaxevent,1,' num2str(np) ',length(options_ami.sens_ind));\n']);
                fprintf(fid,['            sol.s2rz(:,iz,:,:) = reshape(sol.srz(:,((iz-1)*(' num2str(np) '+1)+2):((iz-1)*(' num2str(np) '+1)+' num2str(np) '+1),:),options_ami.nmaxevent,1,' num2str(np) ',length(options_ami.sens_ind));\n']);
            case 2
                fprintf(fid,['            sol.s2z(:,iz,:) = reshape(sol.sz(:,2*(iz-1)+2,:),options_ami.nmaxevent,1,length(theta(options_ami.sens_ind)));\n']);
                fprintf(fid,['            sol.s2sigmaz(:,iz,:) = reshape(sol.ssigmaz(:,2*(iz-1)+2,:),options_ami.nmaxevent,1,length(theta(options_ami.sens_ind)));\n']);
                fprintf(fid,['            sol.s2rz(:,iz,:) = reshape(sol.srz(:,2*(iz-1)+2,:),options_ami.nmaxevent,1,length(theta(options_ami.sens_ind)));\n']);
        end
        fprintf(fid,'        end\n');
        fprintf(fid,['        sol.sx = sol.sx(:,1:' num2str(nxtrue) ',:);\n']);
        fprintf(fid,['        sol.sy = sol.sy(:,1:' num2str(nytrue) ',:);\n']);
        fprintf(fid,['        sol.ssigmay = sol.ssigmay(:,1:' num2str(nytrue) ',:);\n']);
        fprintf(fid,['        if(iz>0)\n']);
        fprintf(fid,['            sol.sz = sz;\n']);
        fprintf(fid,['            sol.ssigmaz = ssigmaz;\n']);
        fprintf(fid,['            sol.srz = srz;\n']);
        fprintf(fid,'         end\n');
        fprintf(fid,'    end\n');
        fprintf(fid,['    sol.x = sol.x(:,1:' num2str(nxtrue) ');\n']);
        fprintf(fid,['    sol.y = sol.y(:,1:' num2str(nytrue) ');\n']);
        fprintf(fid,['    sol.sigmay = sol.sigmay(:,1:' num2str(nytrue) ');\n']);
        fprintf(fid,['    sol.z = sol.z(:,1:' num2str(nztrue) ');\n']);
        fprintf(fid,['    sol.rz = sol.rz(:,1:' num2str(nztrue) ');\n']);
        fprintf(fid,['    sol.sigmaz = sol.sigmaz(:,1:' num2str(nztrue) ');\n']);
        fprintf(fid,'end\n');
    end

    fprintf(fid,'if(nargout>1)\n');
    fprintf(fid,'    varargout{1} = sol.status;\n');
    fprintf(fid,'    varargout{2} = sol.t;\n');
    fprintf(fid,'    varargout{3} = sol.x;\n');
    fprintf(fid,'    varargout{4} = sol.y;\n');
    fprintf(fid,'    if(nargout>4)\n');
    fprintf(fid,'        varargout{5} = sol.sx;\n');
    fprintf(fid,'        varargout{6} = sol.sy;\n');
    if(o2flag)
        fprintf(fid,'        if(nargout>6)\n');
        fprintf(fid,'            varargout{7} = sol.s2x;\n');
        fprintf(fid,'            varargout{8} = sol.s2y;\n');
        fprintf(fid,'        end\n');
    end
    fprintf(fid,'    end\n');
    fprintf(fid,'else\n');
    fprintf(fid,'    varargout{1} = sol;\n');
    fprintf(fid,'end\n');

    fprintf(fid,'function chainRuleFactors = getChainRuleFactors(pscale, theta, sens_ind)\n');
    fprintf(fid,'    if(length(pscale) == 1 && length(sens_ind) ~= length(pscale))\n');
    fprintf(fid,'        chainRuleFactors = arrayfun(@(x, ip) getChainRuleFactor(x, theta(ip)), repmat(pscale, 1, length(sens_ind)), sens_ind);\n');
    fprintf(fid,'    else\n');
    fprintf(fid,'        chainRuleFactors = arrayfun(@(x, ip) getChainRuleFactor(x, theta(ip)), pscale, sens_ind);\n');
    fprintf(fid,'    end\n');
    fprintf(fid,'end\n');
    fprintf(fid,'\n');

    fprintf(fid,'function chainRuleFactor = getChainRuleFactor(pscale, parameterValue)\n');
    fprintf(fid,'    switch (pscale)\n');
    fprintf(fid,'        case 1\n');
    fprintf(fid,'            chainRuleFactor = exp(parameterValue);\n');
    fprintf(fid,'        case 2\n');
    fprintf(fid,'            chainRuleFactor = 10.^parameterValue*log(10);\n');
    fprintf(fid,'        otherwise\n');
    fprintf(fid,'            chainRuleFactor = 1.0;\n');
    fprintf(fid,'    end\n');
    fprintf(fid,'end\n');
    fprintf(fid,'\n');

    fprintf(fid,'end\n');

    fclose(fid);

end