Skip to content

Commit

Permalink
Fix ScipyOdeSimulator lambdify multiprocessing (#480)
Browse files Browse the repository at this point in the history
Fixes an error when using ScipyOdeSimulator with the num_processors
option >1 (i.e. use multiprocessing) together with compiler='python'.
  • Loading branch information
alubbock committed Jan 18, 2020
1 parent df184d0 commit 5dc1604
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 15 deletions.
25 changes: 11 additions & 14 deletions pysb/simulator/scipyode.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,26 +264,21 @@ def __init__(self, model, tspan=None, initials=None, param_values=None,
if theano is None:
raise ImportError('Theano library is not installed')

code_eqs_py = theano_function(
self._code_eqs = theano_function(
self._symbols,
[o if not o.is_zero else theano.tensor.zeros(1)
for o in ode_mat],
on_unused_input='ignore'
)
else:
code_eqs_py = sympy.lambdify(self._symbols,
sympy.flatten(ode_mat))

rhs = _get_rhs(self._compiler, code_eqs_py)
self._code_eqs = code_eqs_py
self._code_eqs = (self._symbols, sympy.flatten(ode_mat))
else:
raise ValueError('Unknown compiler_mode: %s' % self._compiler)

# JACOBIAN -----------------------------------------------
# We'll keep the code for putting together the matrix in Sympy
# in case we want to do manipulations of the matrix later (e.g., to
# put together the sensitivity matrix)
jac_fn = None
self._jac_eqs = None
if self._use_analytic_jacobian:
species_symbols = [sympy.Symbol('__s%d' % i)
Expand Down Expand Up @@ -356,11 +351,7 @@ def jac_fn(t, y, p):
jac_fn(0.0, self.initials[0], self.param_values[0])
self._jac_eqs = jac_eqs
else:
jac_eqs_py = sympy.lambdify(self._symbols, jac_matrix, "numpy")

jac_fn = _get_rhs(self._compiler, jac_eqs_py)

self._jac_eqs = jac_eqs_py
self._jac_eqs = (self._symbols, jac_matrix, "numpy")

# build integrator options list from our defaults and any kwargs
# passed to this function
Expand All @@ -375,7 +366,7 @@ def jac_fn(t, y, p):

if integrator != 'lsoda':
# Only used to check the user has selected a valid integrator
self.integrator = scipy.integrate.ode(rhs, jac=jac_fn)
self.integrator = scipy.integrate.ode(None)
with warnings.catch_warnings():
warnings.filterwarnings('error', 'No integrator name match')
self.integrator.set_integrator(integrator, **options)
Expand Down Expand Up @@ -649,12 +640,18 @@ def _integrator_process(code_eqs, jac_eqs, num_species, num_odes, initials,
tspan, param_values, integrator_name, compiler,
integrator_opts, compiler_directives):
""" Single integrator process, for parallel execution """
if compiler == 'python':
code_eqs = sympy.lambdify(*code_eqs)
if jac_eqs:
jac_eqs = sympy.lambdify(*jac_eqs)

rhs = _get_rhs(compiler, code_eqs, ydot=np.zeros(num_species),
compiler_directives=compiler_directives)

jac_fn = None
if jac_eqs:
jac_eqs = _get_rhs(compiler, jac_eqs,
jac_eqs = _get_rhs(compiler,
jac_eqs,
jac=np.zeros((num_odes, num_species)),
compiler_directives=compiler_directives)

Expand Down
11 changes: 10 additions & 1 deletion pysb/tests/test_simulator_scipy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import numpy as np
from pysb import Monomer, Parameter, Initial, Observable, Rule, Expression
from pysb.simulator import ScipyOdeSimulator
from pysb.examples import robertson, earm_1_0
from pysb.examples import robertson, earm_1_0, tyson_oscillator
import unittest
import pandas as pd

Expand Down Expand Up @@ -500,3 +500,12 @@ def test_unicode_exprname_nonascii():
sim = ScipyOdeSimulator(rob_copy)
simres = sim.run(tspan=t)


def test_multiprocessing_lambdify():
model = tyson_oscillator.model
pars = [p.value for p in model.parameters]
tspan = np.linspace(0, 100, 100)
ScipyOdeSimulator(
model, tspan=tspan, compiler='python',
use_analytic_jacobian=True
).run(param_values=[pars, pars], num_processors=2)

0 comments on commit 5dc1604

Please sign in to comment.