gpac stands for "General-Purpose Analog Computer". This package makes it easy to specify ordinary differential equations (ODEs) and view their solutions.
Project description
gpac Python package
Table of contents
Overview
This will eventually be a package for simulating General-Purpose Analog Computers as defined and studied by Claude Shannon. So far it's just a front-end to scipy and sympy making it easier to numerically integrate systems of ODEs and plot their solutions.
API
The API for the package is here: https://gpac.readthedocs.io/
Installation
Python 3.7 or above is required.
-
Install the dependencies by typing
pip install numpy scipy matplotlib sympy
at the command line.
-
Clone this repo by typing
git clone https://github.com/UC-Davis-molecular-computing/gpac.git
at the command line. You may need to install
git
first: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git -
Add the directory into which you cloned it to your PYTHONPATH environment variable. See https://www.geeksforgeeks.org/pythonpath-environment-variable-in-python/ for example if you don't know how to do this. After doing this you should be able to import the gpac package in your Python scripts/Jupyter notebooks with
import gpac
. Try testing this out in the Python interpreter:$ python Python 3.9.12 (main, Apr 4 2022, 05:22:27) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import gpac >>>
Examples
See more examples in the Jupyter notebook notebook.ipynb.
Plotting ODEs
The following is an example of what can be done currently, which is simply to numerically integrate and plot a system of ODEs (ordinary differential equations).
The ODEs are specified by creating sympy symbols and expressions (or if you like, Python strings), represented as a Python dict odes
mapping each variable---a single sympy symbol or Python string---to an expression representing its time derivative, represented as a sympy expression composed of sympy symbols (or for convenience you can also use Python strings, or if the derivative is constant, a Python int
or float
).
Every symbol that appears in any of the expressions must also be a key in this dict.
The initial values are specified as a Python dict initial_values
mapping variables (again, sympy symbols or strings) to their initial values (floats). If you leave out a symbol as a key to initial_values
, it is assumed to have initial value 0.
Finally, you can specify the times at which to solve for the ODEs as an iterable of floats t_eval
. (This is optional; if not specified it uses the time values 0.0, 0.01, 0.02, 0.03, ..., 0.98, 0.99, 1.0)
Remaining parameters are optional (see below for examples of them). See docstrings of functions
integrate_odes
and plot
in the source code file gpac.py for more details.
import sympy
import gpac
import numpy as np
a,b,c = sympy.symbols('a b c')
# ODEs specified as dict mapping each variable to expression describing its derivative.
# key representing variable can be a sympy Symbol or string.
# value representing derivative can be a sympy Expr, string, or (if constant) int or float.
odes = {
a: -a*b + c*a,
b: -b*c + a*b,
'c': '-c*a + b*c',
}
initial_values = {
a: 10,
b: 1,
c: 1,
}
t_eval = np.linspace(0, 3, 200)
gpac.plot(odes, initial_values, t_eval=t_eval, figure_size=(20,4), symbols_to_plot=[a,c])
Getting trajectory data of ODEs
If you want the data itself from the ODE numerical integration (without plotting it), you can call gpac.integrate_odes
(replace the call to plot
above with the following code).
t_eval = np.linspace(0, 1, 5)
solution = gpac.integrate_odes(odes, initial_values, t_eval=t_eval)
print(f'times = {solution.t}')
print(f'a = {solution.y[0]}')
print(f'b = {solution.y[1]}')
print(f'c = {solution.y[2]}')
which prints
times = [0. 0.25 0.5 0.75 1. ]
a = [10. 4.84701622 0.58753815 0.38765743 3.07392998]
b = [1. 6.84903338 9.63512628 3.03634559 0.38421121]
c = [1. 0.3039504 1.77733557 8.57599698 8.54185881]
The value solution
returned by gpac.integrate_odes
is the same object returned from scipy.integrate.solve_ivp
.
Chemical reaction networks
There are also functions integrate_crn_odes
and plot_crn
, which take as input a description of a set of chemical reactions, derives their ODEs, then integrates/plots them. They both use the function crn_to_odes
, which converts chemical reactions into ODEs.
See notebook.ipynb for examples.
Reactions are constructed using operations on Specie
objects:
# plot solution to ODEs of this CRN that computes f(x) = x^2, using the gpac.crn module
# 2X -> 2X+Y
# Y -> nothing
x,y = gpac.species('X Y')
rxns = [
x+x >> x+x+y,
y >> gpac.empty,
]
initial_values = {x:5}
t_eval = np.linspace(0, 5, 100)
# plot trajectory of concentrations
gpac.plot_crn(rxns, initial_values, t_eval=t_eval, figure_size=(20,4))
Although they appear similar, a Specie
object (such as x
and y
returned from gpac.species
above) is different from a sympy.Symbol
object. The Specie
object is intended to help specify reactions using the notation above with the symbols +
, >>
, and |
(as well as the k
and r
functions for specifying non-unit rate constants, see example notebook). However, any of the following objects can be a key in the initial_values
parameter to plot_crn
and integrate_crn_odes
: Specie
, sympy.Symbol
, or str
. They will be normalized to sympy.Symbol
objects in the ODEs.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.