Site navigation:
Python is a high level, interpreted, language with powerful object orientation. PyDSTool is primarily a scripting environment for working with dynamical systems models. This is achieved through a set of Python classes for use within a regular, interactive, Python session. These classes themselves rely on several SciPy and NumPy classes, particularly the array class.
The user can build objects from the PyDSTool classes interactively, and can manipulate them using PyDSTool utility functions, or using scripts or modules that the user has written. Visualization tools are provided via Matplotlib to study the results of computations, in much the same way as is done in Matlab. Being built to work with common packages such as SciPy, the user benefits from being able to apply well-known algorithms from other packages to PyDSTool objects.
For a full introduction please see the page ProjectOverview and the first Tutorial.
As well as providing simulation and analysis routines of its own, PyDSTool is also intended to provide an environment for embedding numerical calculations within each other, in a hierarchical fashion (a.k.a. "nesting"). A design goal was to make the embedding as straightforward and as general-purpose as possible, with the least amount of effort required by the user. PyDSTool provides core Python classes from which a user can take existing numerical computation packages and apply them to high level objects. This is often done by "wrapping" the external packages, providing them with a common API for use within Python. The packages may take the form of simple executables, or as shared libraries that can be loaded into Python after they are wrapped (e.g. using SWIG). Embedding is also made more transparent through Python's dynamic typing system, whereby different classes can be treated in common ways by providing common interface methods.
The core elements of PyDSTool are the classes that represent or relate to trajectories of dynamical systems, which are discussed next.
From the bottom up:
Point (N-dimensional). Context-laden N x 1 array, always non-parameterized. May possess a text label. (See Pointsets)
Pointset (N-dimensional ordered set of points). Context-laden N x M arrays, where M is the variable length of a data array. A Pointset may be either parameterized or not. May also contain point labels. (See Pointsets)
Variable. 1-dimensional parameterized curve, in the form of a named scalar variable. Optional bounds and domain checks are built in to its access.
Trajectory (curve). N-dimensional curve, made up of Variable objects for each dimension, and may or may not be parameterized. (See section on solving for trajectories below.)
Note that in discrete spaces, a "curve" refers to an ordered set of discrete points (a "discretized curve").
A companion class is the Interval. This class is used like its mathematical equivalent, to indicate scalar intervals of real numbers or integers, depending on their desired type. See Intervals for details.
See the page Symbolic for more details.
From the bottom up:
str: PyDSTool symbolic expressions are built upon the in-built string class.
QuantSpec: The specification of a symbolic expression, from a string. Typically returned as the result of operations on Quantity classes.
Beyond the numerical classes are those that create them as part of solving systems of dynamical equations. Generator objects create Trajectories, for instance. A Model object allows one or more Generators to be combined into (possibly hybrid) dynamical systems models, also providing many additional user utilities for interacting with the model.
Generator class: This is a generic class to support the many ways in which trajectories (or, more generally, parameterized curves) may be generated. The class incorporates dynamical systems prescriptions for trajectories, and also explicit and implicit descriptions of trajectories using mathematical functions, or extrapolated from data sets. See below and the page on Generators.
Model class: This class supports more structured naming for variables and parameters, as well as hybrid and non-hybrid dynamical systems. See the Model, ModelSpec and HybridSystems pages.
Event class: This implements user-defined events for stopping generation of trajectories, e.g. for creating Poincare maps or as the basis for switching vector fields in hybrid systems.
PyCont class: This class provides continuation and bifurcation analysis functionality (including a programmatic interface to AUTO).
Toolbox classes: There are several of these, detailed on the page ToolboxDocumentation, and include classes for parameter estimation (also see ParamEst), neural dynamics, phase plane analysis, and data analysis.
Create a directory somewhere using the name of your project. Make sure the path to the PyDSTool package is in Python's path. In a new Python script that will execute your computations, an easy way to do this is to put
from PyDSTool import *
in the header. Any project-specific compilation of program components (e.g. using numerical integrators implemented in C) will require temporary files to be created. These will appear in automatically generated sub-directories of your project directory. If you are worried about "polluting your namespace" then just use
import PyDSTool as dst
(or a similar short abbreviation) for convenience. All commands will then be entered with the prefix dst.
It is recommended that, to the fullest possible extent, variables and parameters of the dynamical systems studied using PyDSTool are scaled so that they are "order 1" in magnitude. This helps the software accurately deal with occasional rounding errors in the resolution of intervals (see the section on Bounds and Constraints on this page).
The reading and writing of text-format data files is supported. This can be used to import or export trajectory data, for instance. The commands for these are importPointset and exportPointset. To export arrays more easily than using numpy.io, run exportPointset(arrayToPointset(a), {'fname.dat': []}) to save the array in text format to file 'fname.dat'.
It is also possible to load and save PyDSTool objects, as well as any numpy arrays, numeric values, lists, dictionaries, etc., for re-use in a different session. These functions are loadObjects and saveObjects. Multiple objects can be saved in a single file, and named objects (such as trajectories or generators) can be loaded individually from a file containing multiple objects. For instance, suppose a user wants to store a list of arrays, a Trajectory and a Generator for another session.
# supposed Generator g exists a = array([1, Inf]) traj = g.compute('test') saveObjects('mystuff.sav', [a, traj, g])
This last call stores ('serializes') those objects into the given filename. Any file extension can be used, as is your preference. This call will fail if the file already exists. To force the file to be overwritten regardless of whether it exists, append the argument force=True. To reload the objects in a different session:
a, traj, g = loadObjects('mystuff.sav')
If you only want some of the objects back, you can either specify an index or indices into the list returned from loadObjects, as in loadObjects('mystuff.sav')[1] or you can specify a list of string names as a second argument that match the 'name' attributes of any objects stored in the file which have that attribute, as in loadObjects('mystuff.sav', ['test']). Note that if you save a singleton object, e.g. saveObjects(a, 'mystuff.sav'), then it will actually be stored as a list of one element, requiring you to reload with a = loadObjects('mystuff.sav')[0] or by broadcasting with the syntax a, = loadObjects('mystuff.sav') (note the comma).
There are a few less commonly used classes defined in PyDSTool whose instances cannot be saved using these functions, and have to be recreated from their initialization arguments afresh in each session. Work is underway to ensure that all objects can be saved and loaded. For large Trajectories, this form of saving is actually not as memory efficient as recreating from a binary-stored file of the underlying array and metadata.
N.B. For Windows users, saving and loading PyDSTool objects may be a little slow. This is because there is a bug in Python's "pickler" in Windows implementations that concerns IEEE 754 special values such as Inf and NaN. As a result, the workaround is a non-binary data format which is less compact.
The regular Python command del can be used on any PyDSTool object in order to delete it from memory. The whole session can be cleared using the restart command (see below, under Memory Management).
The current PyDSTool session can be saved and reloaded using the commands saveSession and loadSession. By default, saving the session will only save objects that belong to PyDSTool classes. Setting the argument deepSearch=True in a call to saveSession will cause the system to search all top-level lists, dictionaries and tuples for PyDSTool objects, and save those top-level lists, etc. if there is a match. The list of classes searched for is given by the global list _pyDSToolTypes.
PyDSTool objects presently resident in memory can be identified using the who command. who can take an optional argument, either an individual type name or a list of type names, that filter the output to only include PyDSTool objects of those types.
A more specialized option is to add the returnlevel=N option, where N > 0. In the argument's absence, N defaults to 0. When N is 1, the call to who does not print anything to the screen. Instead, it returns a list of the objects found. This can be useful when you want to pass to a function all objects of a certain type that have been defined in the default namespace. N = 2 causes who to return a dictionary of object name keys mapping to the objects.
The default namespace for the search is the globals() dictionary of the calling scope. To specify an alternative namespace, add the option objdict=<scope_name_dictionary> to the call.
The optional argument deepSearch=True will search for PyDSTool objects contained up to one-level deep in lists, tuples and dictionaries defined in the supplied namespace objdict (defaults to the calling namespace's globals dictionary).
The current session can be restarted using the restart command. By default this merely clears the global registries of declared symbolic and ModelSpec names, but the additional argument delall=X where X=1 or 2 will delete all PyDSTool objects (X=2 causes a "deep search" to find them contained in lists, tuples, and dictionaries).
Important: At this time, restart cannot clear from memory any dynamically loaded C-based ODE integrators such as Dopri and Radau. This is a problem with the underlying behaviour of Python itself, and we hope to fix this in the future.
The larger data structures in PyDSTool generally contain several levels of objects, which themselves include arrays, IEEE754 Floating Point special values, and sometimes dynamically created method functions, etc. This includes classes such as Model, Generator, Trajectory, Variable, Pointset, and the symbolic and model specification classes QuantSpec, Quantity, ModelSpec, and so on.
The standard Python copy and deepcopy functions will both behave identically for all these major PyDSTool classes, and will always create full copies without references. This has been implemented for the sake of safety, as shallow copy-by-reference is rarely a desirable outcome for these large data structures.
Copying may however be a little slow for very large data structures, as the only typesafe way to deep copy complex classes is through a tweaked version of the standard Python "pickler". A web search will show that there are problems with using deepcopy on complex data types, and even the C pickler cannot be relied upon to deal with IEEE754 special values properly (at least not on Windows platforms). Hence, we use a patched version of the standard pickler, which on Windows platforms uses a non-binary data format and is therefore less efficient. This issue is discussed further, in relation to handling dynamically-created functions, on the TechDocumentation page.
Matplotlib is the graphics library currently recommended the most for 2D graphics, although no core PyDSTool functionality relies on any particular graphics library. The command interface of Matplotlib is intentionally similar to that of Matlab. For 3D plots, you are free to choose your own as there is no obvious standard yet, although MayaVi is a leading competitor. A 3D toolkit emerged for Matplotlib called mplot3D. See the Matplotlib web site for documentation and tutorials on plotting.
The most important thing to remember when plotting trajectories is that a sample of the trajectory must be extracted from the trajectory object. This is partly because trajectory objects hide their underlying time mesh, but also because the plotted mesh resolution often has to be chosen differently to the time mesh of the original data source anyway.
Matplotlib's pyplot plotting namespace is automatically imported when PyDSTool is imported (or ignored if it is not present) as plt. See the Tutorials for examples.
There are two routes to the specification of a dynamical system.
Directly supply all of the requisite information to a Generator class in creating an instance of that class. This is recommended for small systems. See page FunctionalSpec for details.
Create a hierarchy of model component objects, each containing symbolic definitions of variables, bounds, and so forth, using an abstract specification syntax. This hierarchy, once self-consistently defined, can be "flattened" and transformed into a target language specification (e.g., for Python, C, or Matlab-ADMC++ targets). See page ModelSpec for details.
In addition, you can import a vector field definition from VFGEN using an XML format, or from SloppyCell using an included conversion tool (demonstrated in this example script).
The Generator classes represent the basic simulation objects of PyDSTool, implementing ODE/DAE integration, and the computation of discrete maps. More generally, they are also sources of curves, which may or may not be interpreted as trajectories. For instance, explicit or implicit functions (including those that are parameterized) can be used to specify Generators.
In programming terms, Generators are class instances that produce Trajectory objects (also viewed as curves, especially if they are not parameterized) on demand (see description of Trajectory class below). They take many forms, and may or may not use user-specified parameters and initial condition specifications in order to determine the exact Trajectory object that they produce.
The abstract and target-language independent specification of dynamical systems described in Section 5 is converted into target simulation objects that perform trajectory computations on demand. The target class is Generator, and has many sub-types corresponding to the different types of dynamical system supported.
The trajectory class can represent continuous curves or discrete sets of ordered points. In the former case, it provides the illusion of dense output for trajectories that are defined only by an underlying discrete mesh. This is usually done by linear interpolation between mesh points. Trajectories defined by explicit functions (including Taylor series, which will be implemented at a later date), are intrinsically dense.
The Generator and Trajectory classes are discussed in detail on the page Generators. The implementation of Trajectory objects is described on the page TechDocumentation.
The PyDSTool Model class builds upon Generators and serves two purposes. The first is to generalize the forms of dynamical system that can be simulated in PyDSTool, by supporting hybrid dynamical systems (see the page HybridSystems). The second is to provide support for a "hierarchical naming" scheme used by ModelSpec, useful for building complex structured models. See the Models page for details.
PyDSTool supports the optional specification of bounds on variables and parameters. This is most useful when performing parameter and model estimation, but also provides a means to check the consistency of iterative processes as they run. Variable domains may be intervals or singleton values, but parameter domains must be an interval. At initialization or using the 'set' method, such bounds on variables are specified to a generator using the xdomain key, while those on parameters use the pdomain key. An example of using these bounds in hybrid models is the Single-leg Inverted Pendulum (SLIP) model in the /tests/ directory.
These issues are described further on the BoundsSafety page.
PyDSTool incorporates the sub-package PyCont, written by Drew Lamar as part of the PyDSTool group. PyCont provides a suite of continuation and bifurcation tools that can be applied to existing PyDSTool Model objects. Further information about the package can be found in the link above.
Various toolboxes are available for parameter estimation, phase plane analysis, model reduction, mechanical modeling, data analysis, and neural modeling. Details are given on the page ToolboxDocumentation.
Access to automatic differentiation via the older ODETools Matlab package is provided by creating a model as an instance of the ADMC_ODEsystem class of Generators.
PyDSTool provides access to a large subset of the Systems Biology Markup Language (SBML) through third-party packages (see this tutorial page), and to the NineML language's abstraction layer (see this tutorial page). Exporting functionality is in development.
Other helpful tools to translate between dynamical systems model descriptions are already provided by VFGEN.
PyDSTool source code is hosted by: