Source code for pysb.export.sbml

"""
Module containing a class for exporting a PySB model to SBML.

For information on how to use the model exporters, see the documentation
for :py:mod:`pysb.export`.
"""

# FIXME this should use libsbml if available

import pysb
import pysb.bng
from pysb.export import Exporter, ExpressionsNotSupported, \
    CompartmentsNotSupported
from sympy.printing.mathml import MathMLPrinter
import itertools
import textwrap
try:
    from cStringIO import StringIO
except ImportError:
    from io import StringIO

[docs]def indent(text, n=0): """Re-indent a multi-line string, stripping leading newlines and trailing spaces.""" text = text.lstrip('\n') text = textwrap.dedent(text) lines = text.split('\n') lines = [' '*n + l for l in lines] text = '\n'.join(lines) text = text.rstrip(' ') return text
class MathMLContentPrinter(MathMLPrinter): """Prints an expression to MathML without presentation markup.""" def _print_Symbol(self, sym): ci = self.dom.createElement(self.mathml_tag(sym)) ci.appendChild(self.dom.createTextNode(sym.name)) return ci def print_mathml(expr, **settings): return MathMLContentPrinter(settings).doprint(expr) def format_single_annotation(annotation): return '''<rdf:li rdf:resource="%s" />''' % annotation.object def get_annotation_preamble(meta_id): return indent(''' <annotation> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/"> <rdf:Description rdf:about="#%s"> ''' % meta_id) def get_annotation_postamble(): return indent(''' </rdf:Description> </rdf:RDF> </annotation> ''') def get_species_annotation(meta_id, cp): output = get_annotation_preamble(meta_id) model = cp.monomer_patterns[0].monomer.model() if len(cp.monomer_patterns) == 1: # single monomer all_annotations = model.get_annotations(cp.monomer_patterns[0].monomer) groups = itertools.groupby(all_annotations, lambda a: a.predicate) for predicate, annotations in groups: qualifier = 'bqbiol:%s' % predicate output += indent('<%s>\n <rdf:Bag>\n' % qualifier, 12) for a in annotations: output += indent(format_single_annotation(a) + '\n', 20) output += indent(' </rdf:Bag>\n</%s>\n' % qualifier, 12) else: # complex monomers = set(mp.monomer for mp in cp.monomer_patterns) annotations = [a for m in monomers for a in model.get_annotations(m) if a.predicate in ('is', 'hasPart')] qualifier = 'bqbiol:hasPart' output += indent('<%s>\n <rdf:Bag>\n' % qualifier, 12) for a in annotations: output += indent(format_single_annotation(a) + '\n', 20) output += indent(' </rdf:Bag>\n</%s>\n' % qualifier, 12) output += get_annotation_postamble() return indent(output, 16)
[docs]class SbmlExporter(Exporter): """A class for returning the SBML for a given PySB model. Inherits from :py:class:`pysb.export.Exporter`, which implements basic functionality for all exporters. """
[docs] def export(self): """Export the SBML for the PySB model associated with the exporter. Returns ------- string String containing the SBML output. """ if self.model.expressions: raise ExpressionsNotSupported() if self.model.compartments: raise CompartmentsNotSupported() output = StringIO() pysb.bng.generate_equations(self.model) output.write( """<?xml version="1.0" encoding="UTF-8"?> <sbml xmlns="http://www.sbml.org/sbml/level2" level="2" version="1"> <model name="%s">""" % self.model.name) if self.docstring: notes_str = """ <notes> <body xmlns="http://www.w3.org/1999/xhtml"> <p>%s</p> </body> </notes>""" % self.docstring.replace("\n", "<br />\n"+" "*20) output.write(notes_str) output.write(""" <listOfCompartments> <compartment id="default" name="default" spatialDimensions="3" size="1"/> </listOfCompartments> """) # complexpattern, initial value ics = [[s, 0] for s in self.model.species] for cp, ic_param in self.model.initial_conditions: ics[self.model.get_species_index(cp)][1] = ic_param.value output.write(" <listOfSpecies>\n") for i, (cp, value) in enumerate(ics): id = '__s%d' % i metaid = 'metaid_%d' % i name = str(cp).replace('% ', '._br_') # CellDesigner does something weird with % in names output.write(' <species id="%s" metaid="%s" name="%s" compartment="default" initialAmount="%.17g">\n' % (id, metaid, name, value)); output.write(get_species_annotation(metaid, cp)) output.write(' </species>\n') output.write(" </listOfSpecies>\n") output.write(" <listOfParameters>\n") for i, param in enumerate(self.model.parameters_rules()): output.write(' <parameter id="%s" metaid="metaid_%s" name="%s" value="%.17g"/>\n' % (param.name, param.name, param.name, param.value)); output.write(" </listOfParameters>\n") output.write(" <listOfReactions>\n") for i, reaction in enumerate(self.model.reactions_bidirectional): reversible = str(reaction['reversible']).lower() output.write(' <reaction id="r%d" metaid="metaid_r%d" name="r%d" reversible="%s">\n' % (i, i, i, reversible)); output.write(' <listOfReactants>\n'); for species in reaction['reactants']: output.write(' <speciesReference species="__s%d"/>\n' % species) output.write(' </listOfReactants>\n'); output.write(' <listOfProducts>\n'); for species in reaction['products']: output.write(' <speciesReference species="__s%d"/>\n' % species) output.write(' </listOfProducts>\n'); mathml = '<math xmlns="http://www.w3.org/1998/Math/MathML">' \ + print_mathml(reaction['rate']) + '</math>' output.write(' <kineticLaw>' + mathml + '</kineticLaw>\n'); output.write(' </reaction>\n'); output.write(" </listOfReactions>\n") output.write(" </model>\n</sbml>\n") return output.getvalue()