libSBML Python API  5.18.0
Tutorial: creating a simple model

The following is a short example of creating a complete model using the libSBML Python interface.

The model created is simple and not biologically relevant, but it does bring together many SBML components, including units of measurement on quantities. Another significant aspect of this example program is its checking of return values on all libSBML calls. This is an important aspect of using the libSBML Python API in practice, especially when building models dynamically (rather than the hardcoded static structure shown here); without checking return values from libSBML calls, there would be a danger of creating objects with invalid components or syntax.

We start by importing the libSBML Python library as well as the Python sys library.

1 import sys
2 from libsbml import *

Next, we define a simple function to check the return values of libSBML calls and report any errors encountered. This function uses a generic parameter for the value (the first argument), and tests the value against nulls as well as integer codes. This makes it suitable for testing the return values from any libSBML function, whether the function returns an object or an integer status codes. The benefit of this will become clear in the code further below.

1 def check(value, message):
2  """If 'value' is None, prints an error message constructed using
3  'message' and then exits with status code 1. If 'value' is an integer,
4  it assumes it is a libSBML return status code. If the code value is
5  LIBSBML_OPERATION_SUCCESS, returns without further action; if it is not,
6  prints an error message constructed using 'message' along with text from
7  libSBML explaining the meaning of the code, and exits with status code 1.
8  """
9  if value == None:
10  raise SystemExit('LibSBML returned a null value trying to ' + message + '.')
11  elif type(value) is int:
12  if value == LIBSBML_OPERATION_SUCCESS:
13  return
14  else:
15  err_msg = 'Error encountered trying to ' + message + '.' \
16  + 'LibSBML returned error code ' + str(value) + ': "' \
17  + OperationReturnValue_toString(value).strip() + '"'
18  raise SystemExit(err_msg)
19  else:
20  return

Now we get to the real business of building the model. Here we encapsulated the entire model in one function to make the example simpler, but in a real application, it would likely be more effective to decompose the function further. For example, an improvement would be to abstract away the construction of major pieces such as SBML species into functions that encapsulate repeated code for setting the component's attributes.

1 def create_model():
2  """Returns a simple but complete SBML Level 3 model for illustration."""
3 
4  # Create an empty SBMLDocument object. It's a good idea to check for
5  # possible errors. Even when the parameter values are hardwired like
6  # this, it is still possible for a failure to occur (e.g., if the
7  # operating system runs out of memory).
8 
9  try:
10  document = SBMLDocument(3, 1)
11  except ValueError:
12  raise SystemExit('Could not create SBMLDocumention object')
13 
14  # Create the basic Model object inside the SBMLDocument object. To
15  # produce a model with complete units for the reaction rates, we need
16  # to set the 'timeUnits' and 'extentUnits' attributes on Model. We
17  # set 'substanceUnits' too, for good measure, though it's not strictly
18  # necessary here because we also set the units for invididual species
19  # in their definitions.
20 
21  model = document.createModel()
22  check(model, 'create model')
23  check(model.setTimeUnits("second"), 'set model-wide time units')
24  check(model.setExtentUnits("mole"), 'set model units of extent')
25  check(model.setSubstanceUnits('mole'), 'set model substance units')
26 
27  # Create a unit definition we will need later. Note that SBML Unit
28  # objects must have all four attributes 'kind', 'exponent', 'scale'
29  # and 'multiplier' defined.
30 
31  per_second = model.createUnitDefinition()
32  check(per_second, 'create unit definition')
33  check(per_second.setId('per_second'), 'set unit definition id')
34  unit = per_second.createUnit()
35  check(unit, 'create unit on per_second')
36  check(unit.setKind(UNIT_KIND_SECOND), 'set unit kind')
37  check(unit.setExponent(-1), 'set unit exponent')
38  check(unit.setScale(0), 'set unit scale')
39  check(unit.setMultiplier(1), 'set unit multiplier')
40 
41  # Create a compartment inside this model, and set the required
42  # attributes for an SBML compartment in SBML Level 3.
43 
44  c1 = model.createCompartment()
45  check(c1, 'create compartment')
46  check(c1.setId('c1'), 'set compartment id')
47  check(c1.setConstant(True), 'set compartment "constant"')
48  check(c1.setSize(1), 'set compartment "size"')
49  check(c1.setSpatialDimensions(3), 'set compartment dimensions')
50  check(c1.setUnits('litre'), 'set compartment size units')
51 
52  # Create two species inside this model, set the required attributes
53  # for each species in SBML Level 3 (which are the 'id', 'compartment',
54  # 'constant', 'hasOnlySubstanceUnits', and 'boundaryCondition'
55  # attributes), and initialize the amount of the species along with the
56  # units of the amount.
57 
58  s1 = model.createSpecies()
59  check(s1, 'create species s1')
60  check(s1.setId('s1'), 'set species s1 id')
61  check(s1.setCompartment('c1'), 'set species s1 compartment')
62  check(s1.setConstant(False), 'set "constant" attribute on s1')
63  check(s1.setInitialAmount(5), 'set initial amount for s1')
64  check(s1.setSubstanceUnits('mole'), 'set substance units for s1')
65  check(s1.setBoundaryCondition(False), 'set "boundaryCondition" on s1')
66  check(s1.setHasOnlySubstanceUnits(False), 'set "hasOnlySubstanceUnits" on s1')
67 
68  s2 = model.createSpecies()
69  check(s2, 'create species s2')
70  check(s2.setId('s2'), 'set species s2 id')
71  check(s2.setCompartment('c1'), 'set species s2 compartment')
72  check(s2.setConstant(False), 'set "constant" attribute on s2')
73  check(s2.setInitialAmount(0), 'set initial amount for s2')
74  check(s2.setSubstanceUnits('mole'), 'set substance units for s2')
75  check(s2.setBoundaryCondition(False), 'set "boundaryCondition" on s2')
76  check(s2.setHasOnlySubstanceUnits(False), 'set "hasOnlySubstanceUnits" on s2')
77 
78  # Create a parameter object inside this model, set the required
79  # attributes 'id' and 'constant' for a parameter in SBML Level 3, and
80  # initialize the parameter with a value along with its units.
81 
82  k = model.createParameter()
83  check(k, 'create parameter k')
84  check(k.setId('k'), 'set parameter k id')
85  check(k.setConstant(True), 'set parameter k "constant"')
86  check(k.setValue(1), 'set parameter k value')
87  check(k.setUnits('per_second'), 'set parameter k units')
88 
89  # Create a reaction inside this model, set the reactants and products,
90  # and set the reaction rate expression (the SBML "kinetic law"). We
91  # set the minimum required attributes for all of these objects. The
92  # units of the reaction rate are determined from the 'timeUnits' and
93  # 'extentUnits' attributes on the Model object.
94 
95  r1 = model.createReaction()
96  check(r1, 'create reaction')
97  check(r1.setId('r1'), 'set reaction id')
98  check(r1.setReversible(False), 'set reaction reversibility flag')
99  check(r1.setFast(False), 'set reaction "fast" attribute')
100 
101  species_ref1 = r1.createReactant()
102  check(species_ref1, 'create reactant')
103  check(species_ref1.setSpecies('s1'), 'assign reactant species')
104  check(species_ref1.setConstant(True), 'set "constant" on species ref 1')
105 
106  species_ref2 = r1.createProduct()
107  check(species_ref2, 'create product')
108  check(species_ref2.setSpecies('s2'), 'assign product species')
109  check(species_ref2.setConstant(True), 'set "constant" on species ref 2')
110 
111  math_ast = parseL3Formula('k * s1 * c1')
112  check(math_ast, 'create AST for rate expression')
113 
114  kinetic_law = r1.createKineticLaw()
115  check(kinetic_law, 'create kinetic law')
116  check(kinetic_law.setMath(math_ast), 'set math on kinetic law')
117 
118  # And we're done creating the basic model.
119  # Now return a text string containing the model in XML format.
120 
121  return writeSBMLToString(document)

The function above is designed to return the SBML model as a string. The closing portion of code in this example is a main routine to invoke it:

1 if __name__ == '__main__':
2  print(create_model())

In Unix/Linux environments, we would put the code above into a file and execute it from a command line, redirecting the output to a file. The following is an example:

1 python createSimpleModel.py > output.xml

This tutorial has demonstrated one approach to creating models and their components; the libSBML API actually provides other means of accomplishing these goals, but for the purposes of this tutorial we focused only on one. Readers are invited to explore the rest of this API manual as well as the set of Python example files included with the libSBML distribution. (The complete text of this example program is included as the file createSimpleModel.py.)