Example #1
0
    def export(self):
        """Export Python code for simulation of a model without PySB.

        Returns
        -------
        string
            String containing the standalone Python code.
        """
        if self.model.expressions:
            raise ExpressionsNotSupported()
        if self.model.compartments:
            raise CompartmentsNotSupported()

        output = StringIO()
        pysb.bng.generate_equations(self.model)

        # Note: This has a lot of duplication from pysb.integrate.
        # Can that be helped?

        code_eqs = '\n'.join([
            'ydot[%d] = %s;' % (i, sympy.ccode(self.model.odes[i]))
            for i in range(len(self.model.odes))
        ])
        code_eqs = re.sub(r'__s(\d+)', lambda m: 'y[%s]' % (int(m.group(1))),
                          code_eqs)
        for i, p in enumerate(self.model.parameters):
            code_eqs = re.sub(r'\b(%s)\b' % p.name, 'p[%d]' % i, code_eqs)

        if self.docstring:
            output.write('"""')
            output.write(self.docstring)
            output.write('"""\n\n')
        output.write("# exported from PySB model '%s'\n" % self.model.name)
        output.write(
            pad(r"""
            import numpy
            import scipy.integrate
            import collections
            import itertools
            import distutils.errors
            """))
        output.write(
            pad(r"""
            _use_cython = False
            # try to inline a C statement to see if Cython is functional
            try:
                import Cython
            except ImportError:
                Cython = None
            if Cython:
                from Cython.Compiler.Errors import CompileError
                try:
                    Cython.inline('x = 1', force=True, quiet=True)
                    _use_cython = True
                except (CompileError,
                        distutils.errors.CompileError,
                        ValueError):
                    pass

            Parameter = collections.namedtuple('Parameter', 'name value')
            Observable = collections.namedtuple('Observable', 'name species coefficients')
            Initial = collections.namedtuple('Initial', 'param_index species_index')
            """))
        output.write("\n")

        output.write("class Model(object):\n")
        init_data = {
            'num_species': len(self.model.species),
            'num_params': len(self.model.parameters),
            'num_observables': len(self.model.observables),
            'num_ics': len(self.model.initials),
        }
        output.write(
            pad(
                r"""
            def __init__(self):
                self.y = None
                self.yobs = None
                self.y0 = numpy.empty(%(num_species)d)
                self.ydot = numpy.empty(%(num_species)d)
                self.sim_param_values = numpy.empty(%(num_params)d)
                self.parameters = [None] * %(num_params)d
                self.observables = [None] * %(num_observables)d
                self.initials = [None] * %(num_ics)d
            """, 4) % init_data)
        for i, p in enumerate(self.model.parameters):
            p_data = (i, repr(p.name), p.value)
            output.write(" " * 8)
            output.write("self.parameters[%d] = Parameter(%s, %.17g)\n" %
                         p_data)
        output.write("\n")
        for i, obs in enumerate(self.model.observables):
            obs_data = (i, repr(obs.name), repr(obs.species),
                        repr(obs.coefficients))
            output.write(" " * 8)
            output.write("self.observables[%d] = Observable(%s, %s, %s)\n" %
                         obs_data)
        output.write("\n")
        for i, ic in enumerate(self.model.initials):
            ic_data = (i, self.model.parameters.index(ic.value),
                       self.model.get_species_index(ic.pattern))
            output.write(" " * 8)
            output.write("self.initials[%d] = Initial(%d, %d)\n" % ic_data)
        output.write("\n")

        output.write(" " * 8)
        if 'math.' in code_eqs:
            code_eqs = 'import math\n' + code_eqs
        output.write('code_eqs = \'\'\'\n%s\n\'\'\'\n' %
                     code_eqs.replace(';', ''))

        output.write(" " * 8)
        output.write("if _use_cython:\n")
        output.write(
            pad(
                r"""
            def ode_rhs(t, y, p):
                ydot = self.ydot
                Cython.inline(code_eqs, quiet=True)
                return ydot
            """, 12))
        output.write("        else:\n")
        output.write(
            pad(
                r"""
            def ode_rhs(t, y, p):
                ydot = self.ydot
                exec(code_eqs)
                return ydot
            """, 12))
        output.write(" " * 8)
        output.write('self.integrator = scipy.integrate.ode(ode_rhs)\n')
        output.write(" " * 8)
        output.write("self.integrator.set_integrator('vode', method='bdf', "
                     "with_jacobian=True)\n")

        # note the simulate method is fixed, i.e. it doesn't require any templating
        output.write(
            pad(
                r"""
            def simulate(self, tspan, param_values=None, view=False):
                if param_values is not None:
                    # accept vector of parameter values as an argument
                    if len(param_values) != len(self.parameters):
                        raise Exception("param_values must have length %d" %
                                        len(self.parameters))
                    self.sim_param_values[:] = param_values
                else:
                    # create parameter vector from the values in the model
                    self.sim_param_values[:] = [p.value for p in self.parameters]
                self.y0.fill(0)
                for ic in self.initials:
                    self.y0[ic.species_index] = self.sim_param_values[ic.param_index]
                if self.y is None or len(tspan) != len(self.y):
                    self.y = numpy.empty((len(tspan), len(self.y0)))
                    if len(self.observables):
                        self.yobs = numpy.ndarray(len(tspan),
                                        list(zip((obs.name for obs in self.observables),
                                            itertools.repeat(float))))
                    else:
                        self.yobs = numpy.ndarray((len(tspan), 0))
                    self.yobs_view = self.yobs.view(float).reshape(len(self.yobs),
                                                                   -1)
                # perform the actual integration
                self.integrator.set_initial_value(self.y0, tspan[0])
                self.integrator.set_f_params(self.sim_param_values)
                self.y[0] = self.y0
                t = 1
                while self.integrator.successful() and self.integrator.t < tspan[-1]:
                    self.y[t] = self.integrator.integrate(tspan[t])
                    t += 1
                for i, obs in enumerate(self.observables):
                    self.yobs_view[:, i] = \
                        (self.y[:, obs.species] * obs.coefficients).sum(1)
                if view:
                    y_out = self.y.view()
                    yobs_out = self.yobs.view()
                    for a in y_out, yobs_out:
                        a.flags.writeable = False
                else:
                    y_out = self.y.copy()
                    yobs_out = self.yobs.copy()
                return (y_out, yobs_out)
            """, 4))

        return output.getvalue()
Example #2
0
    def export(self):
        """Generate a MATLAB class definition containing the ODEs for the PySB
        model associated with the exporter.

        Returns
        -------
        string
            String containing the MATLAB code for an implementation of the
            model's ODEs.
        """
        output = StringIO()
        pysb.bng.generate_equations(self.model)

        docstring = ''
        if self.docstring:
            docstring += self.docstring.replace('\n', '\n    % ')

        # Substitute underscores for any dots in the model name
        model_name = self.model.name.replace('.', '_')

        # -- Parameters and Initial conditions -------
        # Declare the list of parameters as a struct
        params_str = 'self.parameters = struct( ...\n'+' '*16
        params_str_list = []
        for i, p in enumerate(self.model.parameters):
            # Add parameter to struct along with nominal value
            cur_p_str = "'%s', %.17g" % (_fix_underscores(p.name), p.value)
            # Decide whether to continue or terminate the struct declaration:
            if i == len(self.model.parameters) - 1:
                cur_p_str += ');'    # terminate
            else:
                cur_p_str += ', ...' # continue

            params_str_list.append(cur_p_str)

        # Format and indent the params struct declaration
        params_str += ('\n'+' '*16).join(params_str_list)

        # Fill in an array of the initial conditions based on the named
        # parameter values
        initial_values_str = ('initial_values = zeros(1,%d);\n'+' '*12) % \
                             len(self.model.species)
        initial_values_str += ('\n'+' '*12).join(
                ['initial_values(%d) = self.parameters.%s; %% %s' %
                 (i+1, _fix_underscores(ic[1].name), ic[0])
                 for i, ic in enumerate(self.model.initial_conditions)])

        # -- Build observables declaration --
        observables_str = 'self.observables = struct( ...\n'+' '*16
        observables_str_list = []
        for i, obs in enumerate(self.model.observables):
            # Associate species and coefficient lists with observable names,
            # changing from zero- to one-based indexing
            cur_obs_str = "'%s', [%s; %s]" % \
                          (_fix_underscores(obs.name),
                           ' '.join([str(sp+1) for sp in obs.species]),
                           ' '.join([str(c) for c in obs.coefficients]))
            # Decide whether to continue or terminate the struct declaration:
            if i == len(self.model.observables) - 1:
                cur_obs_str += ');'    # terminate
            else:
                cur_obs_str += ', ...' # continue

            observables_str_list.append(cur_obs_str)
        # Format and indent the observables struct declaration
        observables_str += ('\n'+' '*16).join(observables_str_list)

        # -- Build ODEs -------
        # Build a stringified list of species
        species_list = ['%% %s;' % s for i, s in enumerate(self.model.species)]
        # Build the ODEs as strings from the model.odes array
        odes_list = ['y(%d,1) = %s;' % (i+1, sympy.ccode(self.model.odes[i])) 
                     for i in range(len(self.model.odes))] 
        # Zip the ODEs and species string lists and then flatten them
        # (results in the interleaving of the two lists)
        odes_species_list = [item for sublist in zip(species_list, odes_list)
                                  for item in sublist]
        # Flatten to a string and add correct indentation
        odes_str = ('\n'+' '*12).join(odes_species_list)

        # Change species names from, e.g., '__s(0)' to 'y0(1)' (note change
        # from zero-based indexing to 1-based indexing)
        odes_str = re.sub(r'__s(\d+)', \
                          lambda m: 'y0(%s)' % (int(m.group(1))+1), odes_str)
        # Change C code 'pow' function to MATLAB 'power' function
        odes_str = re.sub(r'pow\(', 'power(', odes_str)
        # Prepend 'p.' to named parameters and fix any underscores
        for i, p in enumerate(self.model.parameters):
            odes_str = re.sub(r'\b(%s)\b' % p.name,
                              'p.%s' % _fix_underscores(p.name), odes_str)

        # -- Build final output --
        output.write(pad(r"""
            classdef %(model_name)s
                %% %(docstring)s
                %% A class implementing the ordinary differential equations
                %% for the %(model_name)s model.
                %%
                %% Save as %(model_name)s.m.
                %%
                %% Generated by pysb.export.matlab.MatlabExporter.
                %%
                %% Properties
                %% ----------
                %% observables : struct
                %%     A struct containing the names of the observables from the
                %%     PySB model as field names. Each field in the struct
                %%     maps the observable name to a matrix with two rows:
                %%     the first row specifies the indices of the species
                %%     associated with the observable, and the second row
                %%     specifies the coefficients associated with the species.
                %%     For any given timecourse of model species resulting from
                %%     integration, the timecourse for an observable can be
                %%     retrieved using the get_observable method, described
                %%     below.
                %%
                %% parameters : struct
                %%     A struct containing the names of the parameters from the
                %%     PySB model as field names. The nominal values are set by
                %%     the constructor and their values can be overriden
                %%     explicitly once an instance has been created.
                %%
                %% Methods
                %% -------
                %% %(model_name)s.odes(tspan, y0)
                %%     The right-hand side function for the ODEs of the model,
                %%     for use with MATLAB ODE solvers (see Examples).
                %%
                %% %(model_name)s.get_initial_values()
                %%     Returns a vector of initial values for all species,
                %%     specified in the order that they occur in the original
                %%     PySB model (i.e., in the order found in model.species).
                %%     Non-zero initial conditions are specified using the
                %%     named parameters included as properties of the instance.
                %%     Hence initial conditions other than the defaults can be
                %%     used by assigning a value to the named parameter and then
                %%     calling this method. The vector returned by the method
                %%     is used for integration by passing it to the MATLAB
                %%     solver as the y0 argument.
                %%
                %% %(model_name)s.get_observables(y)
                %%     Given a matrix of timecourses for all model species
                %%     (i.e., resulting from an integration of the model),
                %%     get the trajectories corresponding to the observables.
                %%     Timecourses are returned as a struct which can be
                %%     indexed by observable name.
                %%
                %% Examples
                %% --------
                %% Example integration using default initial and parameter
                %% values:
                %%
                %% >> m = %(model_name)s();
                %% >> tspan = [0 100];
                %% >> [t y] = ode15s(@m.odes, tspan, m.get_initial_values());
                %%
                %% Retrieving the observables:
                %%
                %% >> y_obs = m.get_observables(y)
                %%
                properties
                    observables
                    parameters
                end

                methods
                    function self = %(model_name)s()
                        %% Assign default parameter values
                        %(params_str)s

                        %% Define species indices (first row) and coefficients
                        %% (second row) of named observables
                        %(observables_str)s
                    end

                    function initial_values = get_initial_values(self)
                        %% Return the vector of initial conditions for all
                        %% species based on the values of the parameters
                        %% as currently defined in the instance.

                        %(initial_values_str)s
                    end

                    function y = odes(self, tspan, y0)
                        %% Right hand side function for the ODEs

                        %% Shorthand for the struct of model parameters
                        p = self.parameters;

                        %(odes_str)s
                    end

                    function y_obs = get_observables(self, y)
                        %% Retrieve the trajectories for the model observables
                        %% from a matrix of the trajectories of all model
                        %% species.

                        %% Initialize the struct of observable timecourses
                        %% that we will return
                        y_obs = struct();

                        %% Iterate over the observables;
                        observable_names = fieldnames(self.observables);
                        for i = 1:numel(observable_names)
                            obs_matrix = self.observables.(observable_names{i});
                            species = obs_matrix(1, :);
                            coefficients = obs_matrix(2, :);
                            y_obs.(observable_names{i}) = ...
                                            y(:, species) * coefficients';
                        end
                    end
                end
            end
            """, 0) %
            {'docstring': docstring,
             'model_name': model_name,
             'params_str':params_str,
             'initial_values_str': initial_values_str,
             'observables_str': observables_str,
             'params_str': params_str,
             'odes_str': odes_str})

        return output.getvalue()
Example #3
0
    def export(self):
        """Export STAN code for simulation of a model using STAN
        Returns
        -------
        string
            String containing the STAN code.
        """
        output = StringIO()
        pysb.bng.generate_equations(self.model)
        # Note: This has a lot of duplication from pysb.integrate.
        # Can that be helped?
        code_eqs = '\n'.join(['ydot[%d] = %s;' %
                                 (i+1, sympy.ccode(self.model.odes[i]))
                              for i in range(len(self.model.odes))])
        code_eqs = re.sub(r's(\d+)',
                          lambda m: 'y[%s]' % (int(m.group(1))+1), code_eqs)
						  
        for i, p in enumerate(self.model.parameters):
            code_eqs = re.sub(r'\b(%s)\b' % p.name, 'p[%s]' % str(i+1), code_eqs)
        init_data = {
            'num_species': len(self.model.species),
            'num_params': len(self.model.parameters),
            'num_observables': len(self.model.observables),
            'num_ics': len(self.model.initial_conditions),
            }            
        if self.docstring:
            output.write('"""')
            output.write(self.docstring)
            output.write('"""\n\n')
        output.write("// exported from PySB model '%s'\n" % self.model.name)
        # output independent STAN model and simulation code
        # first write the STAN code as a string
        
        #output.write('stan_code = r"""')
        output.write("functions{")
		# EDIT BY DUNCAN KIRBY: REMOVE '_' FROM code_eqs TO GET SIMULATIONS TO RUN 
        code_eqs = re.sub('_','',code_eqs)
        output.write(pad(r"""
        real[] ode_rhs(real t,
                        real[] y,
                        real[] p,
                        real[] x_r,
                        int[] x_i){
            real ydot[%d];""",4) % init_data['num_species'])
        output.write(r"""
        %s
        return ydot;
    }
}
            """ % pad('\n' + code_eqs, 8).strip())
			# note the simulate method is fixed, i.e. it doesn't require any templating
        output.write(r"""
data {
    int<lower=1> T;
    real t0;
    real ts[%d];
}
transformed data {
    real x_r[0];
    int x_i[0];
}
parameters{
}
transformed parameters {
    real y0[%d];
    real p[%d];
    
""" % (72,init_data['num_species'],init_data['num_params']))

        # initial conditions
        species_stringList = [str(el) for el in self.model.species]
        used_indices=[]
        for ic in self.model.initial_conditions:
            y_index = species_stringList.index(str(ic[0]))+1
            used_indices.append(y_index)
            output.write("    y0[%d] = %d;\n" % (y_index, ic[1].value))
        for i in range(1,init_data['num_species']+1):
            if i not in used_indices:
                output.write("    y0[%d] = 0;\n" % i)
        # model parameter vector
        for i, p in enumerate(self.model.parameters):
            p_data = (i+1, p.value, repr(p.name))
            output.write("    p[%d] = %.8g; // %s\n" % p_data)    

        output.write(r"""
}
model {
    real y[72,%d];
    real observables[72,%d];
    y = integrate_ode_rk45(ode_rhs, y0, t0, ts, p, x_r, x_i);
""" % (init_data['num_species'],init_data['num_observables']))
        #   observables
        output.write("""    for (t in 1:72) {""")
        output.write("\n")
        for i, obs in enumerate(self.model.observables):
            ycoords = [j for j in obs.species]
            for ind in range(len(ycoords)):# offset indices by 1
                ycoords[ind]+=1
            if ycoords == []:# pass 0 to observables which don't appear in ODE equations
                ycoords = 0
            obs_data = (i+1, str(ycoords).replace(", ","]+y[t,")[1:], repr(obs.name))
            output.write(" " * 8)
            if ycoords==0:
                output.write("observables[t,%d] =%s 0; // %s\n" % obs_data)
            else:
                output.write("observables[t,%d] = y[t,%s; // %s\n" % obs_data)         
        output.write("""    }
}""")
        #output.write('"""')
        
        # now write the simulation code
        output.write(r"""
# suggested python code:
/*
# Import the required libraries 
import pystan
import numpy as np
import scipy
import os
import pickle
from matplotlib import pyplot as plt
# Check to see if we can avoid compiling the model:
cwd=os.getcwd()
if os.path.isfile(cwd+'/STAN_alpha.pkl'):
    print('Model has been compiled')
    sm = pickle.load(open('STAN_alpha.pkl','rb'))
else:
    sm = pystan.StanModel(file='STAN_alpha.stan')
    # save the compiled model for later use
    with open('STAN_alpha.pkl','wb') as f:
        pickle.dump(sm,f)
# Simulate the model
deltaT = 50
t_end = 3600
t0 = -1
ts = np.arange(0,t_end*deltaT,deltaT)""")


        
        output.write(r"""
samples = sm.sampling(data={'T':t_end,'t0':t0,'ts':ts},
                        algorithm='Fixed_param',
                        seed=42,
                        chains=1,
                        iter=1)
                  
#samples.plot()
#plt.show()

# Plot TotalpSTAT
res = samples.extract("observables",permuted=False)['observables'][0][0]
plt.plot(range(0,t_end,deltaT),res[:,11])
plt.show()
*/""")
        
        return output.getvalue()
Example #4
0
    def export(self):
        """Generate a MATLAB class definition containing the ODEs for the PySB
        model associated with the exporter.

        Returns
        -------
        string
            String containing the MATLAB code for an implementation of the
            model's ODEs.
        """
        output = StringIO()
        pysb.bng.generate_equations(self.model)

        docstring = ''
        if self.docstring:
            docstring += self.docstring.replace('\n', '\n    % ')

        # Substitute underscores for any dots in the model name
        model_name = self.model.name.replace('.', '_')

        # -- Parameters and Initial conditions -------
        # Declare the list of parameters as a struct
        params_str = 'self.parameters = struct( ...\n' + ' ' * 16
        params_str_list = []
        for i, p in enumerate(self.model.parameters):
            # Add parameter to struct along with nominal value
            cur_p_str = "'%s', %.17g" % (_fix_underscores(p.name), p.value)
            # Decide whether to continue or terminate the struct declaration:
            if i == len(self.model.parameters) - 1:
                cur_p_str += ');'  # terminate
            else:
                cur_p_str += ', ...'  # continue

            params_str_list.append(cur_p_str)

        # Format and indent the params struct declaration
        params_str += ('\n' + ' ' * 16).join(params_str_list)

        # Fill in an array of the initial conditions based on the named
        # parameter values
        initial_values_str = ('initial_values = zeros(1,%d);\n'+' '*12) % \
                             len(self.model.species)
        initial_values_str += ('\n' + ' ' * 12).join([
            'initial_values(%d) = self.parameters.%s; %% %s' %
            (i + 1, _fix_underscores(ic[1].name), ic[0])
            for i, ic in enumerate(self.model.initial_conditions)
        ])

        # -- Build observables declaration --
        observables_str = 'self.observables = struct( ...\n' + ' ' * 16
        observables_str_list = []
        for i, obs in enumerate(self.model.observables):
            # Associate species and coefficient lists with observable names,
            # changing from zero- to one-based indexing
            cur_obs_str = "'%s', [%s; %s]" % \
                          (_fix_underscores(obs.name),
                           ' '.join([str(sp+1) for sp in obs.species]),
                           ' '.join([str(c) for c in obs.coefficients]))
            # Decide whether to continue or terminate the struct declaration:
            if i == len(self.model.observables) - 1:
                cur_obs_str += ');'  # terminate
            else:
                cur_obs_str += ', ...'  # continue

            observables_str_list.append(cur_obs_str)
        # Format and indent the observables struct declaration
        observables_str += ('\n' + ' ' * 16).join(observables_str_list)

        # -- Build ODEs -------
        # Build a stringified list of species
        species_list = ['%% %s;' % s for i, s in enumerate(self.model.species)]
        # Build the ODEs as strings from the model.odes array
        odes_list = [
            'y(%d,1) = %s;' % (i + 1, sympy.ccode(self.model.odes[i]))
            for i in range(len(self.model.odes))
        ]
        # Zip the ODEs and species string lists and then flatten them
        # (results in the interleaving of the two lists)
        odes_species_list = [
            item for sublist in zip(species_list, odes_list)
            for item in sublist
        ]
        # Flatten to a string and add correct indentation
        odes_str = ('\n' + ' ' * 12).join(odes_species_list)

        # Change species names from, e.g., '__s(0)' to 'y0(1)' (note change
        # from zero-based indexing to 1-based indexing)
        odes_str = re.sub(r'__s(\d+)', \
                          lambda m: 'y0(%s)' % (int(m.group(1))+1), odes_str)
        # Change C code 'pow' function to MATLAB 'power' function
        odes_str = re.sub(r'pow\(', 'power(', odes_str)
        # Prepend 'p.' to named parameters and fix any underscores
        for i, p in enumerate(self.model.parameters):
            odes_str = re.sub(r'\b(%s)\b' % p.name,
                              'p.%s' % _fix_underscores(p.name), odes_str)

        # -- Build final output --
        output.write(
            pad(
                r"""
            classdef %(model_name)s
                %% %(docstring)s
                %% A class implementing the ordinary differential equations
                %% for the %(model_name)s model.
                %%
                %% Save as %(model_name)s.m.
                %%
                %% Generated by pysb.export.matlab.MatlabExporter.
                %%
                %% Properties
                %% ----------
                %% observables : struct
                %%     A struct containing the names of the observables from the
                %%     PySB model as field names. Each field in the struct
                %%     maps the observable name to a matrix with two rows:
                %%     the first row specifies the indices of the species
                %%     associated with the observable, and the second row
                %%     specifies the coefficients associated with the species.
                %%     For any given timecourse of model species resulting from
                %%     integration, the timecourse for an observable can be
                %%     retrieved using the get_observable method, described
                %%     below.
                %%
                %% parameters : struct
                %%     A struct containing the names of the parameters from the
                %%     PySB model as field names. The nominal values are set by
                %%     the constructor and their values can be overriden
                %%     explicitly once an instance has been created.
                %%
                %% Methods
                %% -------
                %% %(model_name)s.odes(tspan, y0)
                %%     The right-hand side function for the ODEs of the model,
                %%     for use with MATLAB ODE solvers (see Examples).
                %%
                %% %(model_name)s.get_initial_values()
                %%     Returns a vector of initial values for all species,
                %%     specified in the order that they occur in the original
                %%     PySB model (i.e., in the order found in model.species).
                %%     Non-zero initial conditions are specified using the
                %%     named parameters included as properties of the instance.
                %%     Hence initial conditions other than the defaults can be
                %%     used by assigning a value to the named parameter and then
                %%     calling this method. The vector returned by the method
                %%     is used for integration by passing it to the MATLAB
                %%     solver as the y0 argument.
                %%
                %% %(model_name)s.get_observables(y)
                %%     Given a matrix of timecourses for all model species
                %%     (i.e., resulting from an integration of the model),
                %%     get the trajectories corresponding to the observables.
                %%     Timecourses are returned as a struct which can be
                %%     indexed by observable name.
                %%
                %% Examples
                %% --------
                %% Example integration using default initial and parameter
                %% values:
                %%
                %% >> m = %(model_name)s();
                %% >> tspan = [0 100];
                %% >> [t y] = ode15s(@m.odes, tspan, m.get_initial_values());
                %%
                %% Retrieving the observables:
                %%
                %% >> y_obs = m.get_observables(y)
                %%
                properties
                    observables
                    parameters
                end

                methods
                    function self = %(model_name)s()
                        %% Assign default parameter values
                        %(params_str)s

                        %% Define species indices (first row) and coefficients
                        %% (second row) of named observables
                        %(observables_str)s
                    end

                    function initial_values = get_initial_values(self)
                        %% Return the vector of initial conditions for all
                        %% species based on the values of the parameters
                        %% as currently defined in the instance.

                        %(initial_values_str)s
                    end

                    function y = odes(self, tspan, y0)
                        %% Right hand side function for the ODEs

                        %% Shorthand for the struct of model parameters
                        p = self.parameters;

                        %(odes_str)s
                    end

                    function y_obs = get_observables(self, y)
                        %% Retrieve the trajectories for the model observables
                        %% from a matrix of the trajectories of all model
                        %% species.

                        %% Initialize the struct of observable timecourses
                        %% that we will return
                        y_obs = struct();

                        %% Iterate over the observables;
                        observable_names = fieldnames(self.observables);
                        for i = 1:numel(observable_names)
                            obs_matrix = self.observables.(observable_names{i});
                            if isempty(obs_matrix)
                                y_obs.(observable_names{i}) = zeros(size(y, 1), 1);
                                continue
                            end
                            species = obs_matrix(1, :);
                            coefficients = obs_matrix(2, :);
                            y_obs.(observable_names{i}) = ...
                                            y(:, species) * coefficients';
                        end
                    end
                end
            end
            """, 0) % {
                    'docstring': docstring,
                    'model_name': model_name,
                    'params_str': params_str,
                    'initial_values_str': initial_values_str,
                    'observables_str': observables_str,
                    'params_str': params_str,
                    'odes_str': odes_str
                })

        return output.getvalue()
Example #5
0
    def export(self):
        """Export Python code for simulation of a model without PySB.

        Returns
        -------
        string
            String containing the standalone Python code.
        """

        output = StringIO()
        pysb.bng.generate_equations(self.model)

        # Note: This has a lot of duplication from pysb.integrate.
        # Can that be helped?

        code_eqs = '\n'.join(['ydot[%d] = %s;' %
                                 (i, sympy.ccode(self.model.odes[i]))
                              for i in range(len(self.model.odes))])
        code_eqs = re.sub(r's(\d+)',
                          lambda m: 'y[%s]' % (int(m.group(1))), code_eqs)
        for i, p in enumerate(self.model.parameters):
            code_eqs = re.sub(r'\b(%s)\b' % p.name, 'p[%d]' % i, code_eqs)

        if self.docstring:
            output.write('"""')
            output.write(self.docstring)
            output.write('"""\n\n')
        output.write("# exported from PySB model '%s'\n" % self.model.name)
        output.write(pad(r"""
            import numpy
            import scipy.weave, scipy.integrate
            import collections
            import itertools
            import distutils.errors
            """))
        output.write(pad(r"""
            _use_inline = False
            # try to inline a C statement to see if inline is functional
            try:
                scipy.weave.inline('int i;', force=1)
                _use_inline = True
            except distutils.errors.CompileError:
                pass

            Parameter = collections.namedtuple('Parameter', 'name value')
            Observable = collections.namedtuple('Observable', 'name species coefficients')
            Initial = collections.namedtuple('Initial', 'param_index species_index')
            """))
        output.write("\n")

        output.write("class Model(object):\n")
        init_data = {
            'num_species': len(self.model.species),
            'num_params': len(self.model.parameters),
            'num_observables': len(self.model.observables),
            'num_ics': len(self.model.initial_conditions),
            }
        output.write(pad(r"""
            def __init__(self):
                self.y = None
                self.yobs = None
                self.integrator = scipy.integrate.ode(self.ode_rhs)
                self.integrator.set_integrator('vode', method='bdf',
                                               with_jacobian=True)
                self.y0 = numpy.empty(%(num_species)d)
                self.ydot = numpy.empty(%(num_species)d)
                self.sim_param_values = numpy.empty(%(num_params)d)
                self.parameters = [None] * %(num_params)d
                self.observables = [None] * %(num_observables)d
                self.initial_conditions = [None] * %(num_ics)d
            """, 4) % init_data)
        for i, p in enumerate(self.model.parameters):
            p_data = (i, repr(p.name), p.value)
            output.write(" " * 8)
            output.write("self.parameters[%d] = Parameter(%s, %.17g)\n" % p_data)
        output.write("\n")
        for i, obs in enumerate(self.model.observables):
            obs_data = (i, repr(obs.name), repr(obs.species),
                        repr(obs.coefficients))
            output.write(" " * 8)
            output.write("self.observables[%d] = Observable(%s, %s, %s)\n" %
                         obs_data)
        output.write("\n")
        for i, (cp, param) in enumerate(self.model.initial_conditions):
            ic_data = (i, self.model.parameters.index(param),
                       self.model.get_species_index(cp))
            output.write(" " * 8)
            output.write("self.initial_conditions[%d] = Initial(%d, %d)\n" %
                         ic_data)
        output.write("\n")

        output.write("    if _use_inline:\n")
        output.write(pad(r"""
            def ode_rhs(self, t, y, p):
                ydot = self.ydot
                scipy.weave.inline(r'''%s''', ['ydot', 't', 'y', 'p'])
                return ydot
            """, 8) % (pad('\n' + code_eqs, 16) + ' ' * 16))
        output.write("    else:\n")
        output.write(pad(r"""
            def ode_rhs(self, t, y, p):
                ydot = self.ydot
                %s
                return ydot
            """, 8) % pad('\n' + code_eqs, 12).replace(';','').strip())

        # note the simulate method is fixed, i.e. it doesn't require any templating
        output.write(pad(r"""
            def simulate(self, tspan, param_values=None, view=False):
                if param_values is not None:
                    # accept vector of parameter values as an argument
                    if len(param_values) != len(self.parameters):
                        raise Exception("param_values must have length %d" %
                                        len(self.parameters))
                    self.sim_param_values[:] = param_values
                else:
                    # create parameter vector from the values in the model
                    self.sim_param_values[:] = [p.value for p in self.parameters]
                self.y0.fill(0)
                for ic in self.initial_conditions:
                    self.y0[ic.species_index] = self.sim_param_values[ic.param_index]
                if self.y is None or len(tspan) != len(self.y):
                    self.y = numpy.empty((len(tspan), len(self.y0)))
                    if len(self.observables):
                        self.yobs = numpy.ndarray(len(tspan),
                                        zip((obs.name for obs in self.observables),
                                            itertools.repeat(float)))
                    else:
                        self.yobs = numpy.ndarray((len(tspan), 0))
                    self.yobs_view = self.yobs.view(float).reshape(len(self.yobs),
                                                                   -1)
                # perform the actual integration
                self.integrator.set_initial_value(self.y0, tspan[0])
                self.integrator.set_f_params(self.sim_param_values)
                self.y[0] = self.y0
                t = 1
                while self.integrator.successful() and self.integrator.t < tspan[-1]:
                    self.y[t] = self.integrator.integrate(tspan[t])
                    t += 1
                for i, obs in enumerate(self.observables):
                    self.yobs_view[:, i] = \
                        (self.y[:, obs.species] * obs.coefficients).sum(1)
                if view:
                    y_out = self.y.view()
                    yobs_out = self.yobs.view()
                    for a in y_out, yobs_out:
                        a.flags.writeable = False
                else:
                    y_out = self.y.copy()
                    yobs_out = self.yobs.copy()
                return (y_out, yobs_out)
            """, 4))

        return output.getvalue()