Working with CellML models using Python

Working with CellML models using Python

Setting up cgrspy

The CellML API comes with a module called CGRS (the CellML Generics and Reflection Service). A module called cgrspy allows you to call API services from Python through the CGRS.

Firstly, make sure the CellML SDK is in your dynamic linker library path and include paths, as discussed on the Getting Started page. Then you can run something like:

sudo pip install cgrspy

Getting started with the API in Python

The only Python module you need to import to use the CellML API is cgrspy.bootstrap.

The CellML API is divided up into services. Each service has a CGRS module which needs to be loaded before you can have any interaction with that part of the API. You load a CGRS module by calling cgrspy.botostrap.loadGenericModule("nameOfModuleHere"). The CGRS module should be in the dynamic library loader path. For example, this program simply loads the CGRS module for the core CellML API:

import cgrspy.bootstrap
cgrspy.bootstrap.loadGenericModule('cgrs_cellml')

The CellML API is object-orientated, and you generally obtain objects from other objects. However, to get started, you need to obtain a special object called a bootstrap object (there is typically only one bootstrap object per API service). You can use cgrspy.bootstrap.fetch to fetch a CellML API bootstrap. For example, to obtain the CellML Bootstrap:

import cgrspy.bootstrap
cgrspy.bootstrap.loadGenericModule('cgrs_cellml')
cellmlBootstrap = cgrspy.bootstrap.fetch('CreateCellMLBootstrap')

The Python object cellmlBootstrap is of Python type cgrspy.Object, as all objects obtained from cgrspy are. In the CellML API, one object can implement multiple interfaces; you can access attributes and methods on any of those interfaces directly from a Python object that supports them. You can see the list of interfaces that are supported by an object using the XPCOM::IObject::supported_interfaces attribute:

>>> cgrspy.bootstrap.loadGenericModule('cgrs_xpcom')
>>> cellmlBootstrap.supported_interfaces
['XPCOM::IObject', 'cellml_api::CellMLBootstrap']

All attributes defined on the API can be accessed directly as a Python attribute. Operations defined on the CellML API become methods in Python; `in' parameters are Python parameters, and the return value and any `out' parameters get put together as a Python tuple in the return value.

For example, the below example uses cellml_api::CellMLBootstrap::createModel, cellml_api::CellMLBootstrap::createComponent, cellml_api::NamedCellMLElement::name, cellml_api::CellMLElement::addElement, cellml_api::CellMLBootstrap::createCellMLVariable, cellml_services::TeLICeMService::parseMaths, cellml_api::CellMLDOMElement::domElement, dom::Document::ownerDocument, cellml_services::TeLICeMMathResult::mathResult, cellml_api::MathContainer::addMath and cellml_api::Model::serialisedText to create a simple document. Referring to the documentation for each of these operations will help you understand the Python code and how it relates to the API documentation.

import cgrspy.bootstrap
cgrspy.bootstrap.loadGenericModule('cgrs_cellml')
cgrspy.bootstrap.loadGenericModule('cgrs_telicems')
cellmlBootstrap = cgrspy.bootstrap.fetch('CreateCellMLBootstrap')
telicemService = cgrspy.bootstrap.fetch('CreateTeLICeMService')
model = cellmlBootstrap.createModel("1.0")
c = model.createComponent()
c.name = "maincomponent"
model.addElement(c)
xvar = model.createCellMLVariable()
xvar.name = "x"
xvar.unitsName = "dimensionless"
yvar = model.createCellMLVariable()
yvar.name = "y"
yvar.unitsName = "dimensionless"
tvar = model.createCellMLVariable()
tvar.name = "t"
tvar.unitsName = "dimensionless"
xvar.initialValue = "1.0"
yvar.initialValue = "1.0"
c.addElement(xvar)
c.addElement(yvar)
c.addElement(tvar)
doc = model.domElement.ownerDocument
c.addMath(telicemService.parseMaths(doc, "d(y)/d(t) = x").mathResult)
c.addMath(telicemService.parseMaths(doc, 'd(x)/d(t) = x - power(y, 2{units="dimensionless"})').mathResult)
model.serialisedText

One feature of the Python bindings is that you can use iterators conveniently using the Python iterator protocol to write code that looks more natural. The Python binding can be used anywhere where an interface defines an iterate function, and the return value defines a next function. For example, you can use it to iterate through all components in a model:

import cgrspy.bootstrap
cgrspy.bootstrap.loadGenericModule('cgrs_cellml')
cellmlBootstrap = cgrspy.bootstrap.fetch('CreateCellMLBootstrap')
model = cellmlBootstrap.modelLoader.loadFromURL("http://models.cellml.org/workspace/beeler_reuter_1977/@@rawfile/afb6088af6518dbe9c3b7564d9514f54356335d9/beeler_reuter_1977.cellml")
for c in model.allComponents:
print("Component: %s" % c.name)
Back to Top