示例#1
0
def fromSBMLString(sbmlStr, id=None, duplicate_rxn_params=False):
    r = libsbml.SBMLReader()
    d = r.readSBMLFromString(sbmlStr)
    if d.getNumErrors():
        message = 'libSBML reported errors in SBML file. Try running file '\
                'through the online validator: '\
                'http://www.sbml.org/Facilities/Validator . Specific errors '\
                'noted are: '
        errors = []
        for ii in range(d.getNumErrors()):
            pm = d.getError(ii)
            errors.append(pm.getMessage())
        print(message + '; '.join(errors))

    m = d.getModel()

    modelId = m.getId()
    if (id is None) and (modelId == ''):
        raise ValueError('Network id not specified in SBML or passed in.')
    elif id is not None:
        modelId = id

    rn = Network_mod.Network(id=modelId, name=m.getName())

    for f in m.getListOfFunctionDefinitions():
        id, name = f.getId(), f.getName()
        math = f.getMath()
        variables = []
        for ii in range(math.getNumChildren() - 1):
            variables.append(formula_to_py(math.getChild(ii)))

        math = formula_to_py(math.getRightChild())

        rn.addFunctionDefinition(id, variables, math)

    for c in m.getListOfCompartments():
        id, name = c.getId(), c.getName()
        size = c.getSize()
        isConstant = c.getConstant()

        rn.addCompartment(id=id, size=size, isConstant=isConstant, name=name)

    for s in m.getListOfSpecies():
        id, name = s.getId(), s.getName()
        compartment = s.getCompartment()
        if s.isSetInitialConcentration():
            iC = s.getInitialConcentration()
        elif s.isSetInitialAmount():
            iC = s.getInitialAmount()
        else:
            iC = 1
        isBC, isConstant = s.getBoundaryCondition(), s.getConstant()

        xml_text = s.toSBML()
        uniprot_ids = set([
            entry[1:].split('"')[0] for entry in xml_text.split('uniprot')[1:]
        ])

        rn.addSpecies(id=id,
                      compartment=compartment,
                      initialConcentration=iC,
                      isConstant=isConstant,
                      is_boundary_condition=isBC,
                      name=name,
                      uniprot_ids=uniprot_ids)

    for p in m.getListOfParameters():
        parameter = createNetworkParameter(p)
        rn.addVariable(parameter)

    for rxn in m.getListOfReactions():
        id, name = rxn.getId(), rxn.getName()
        kL = rxn.getKineticLaw()
        kLFormula = kL.getFormula()

        substitution_dict = {}
        # Deal with parameters defined within reactions
        for p in kL.getListOfParameters():
            parameter = createNetworkParameter(p)
            # If a parameter with this name already exists, **and it has a
            # different value than this parameter** we rename this parameter
            # instance by prefixing it with the rxn name so there isn't a
            # clash.
            if parameter.id in rn.variables.keys():
                logger.warn('Parameter %s appears in two different reactions '
                            'in SBML file.' % parameter.id)
                if parameter.value != rn.variables.get(parameter.id).value or\
                   duplicate_rxn_params:
                    oldId = parameter.id
                    parameter.id = id + '_' + parameter.id
                    substitution_dict[oldId] = parameter.id
                    logger.warn('It has different values in the two positions '
                                'so we are creating a new parameter %s.' %
                                (parameter.id))
                else:
                    logger.warn('It has the same value in the two positions '
                                'so we are only defining one parameter %s. '
                                'This behavior can be changed with the option '
                                'duplicate_rxn_params = True' % (parameter.id))

            if parameter.id not in rn.variables.keys():
                rn.addVariable(parameter)
        kLFormula = ExprManip.sub_for_vars(kLFormula, substitution_dict)

        # Assemble the stoichiometry. SBML has the annoying trait that
        #  species can appear as both products and reactants and 'cancel out'
        # For each species appearing in the reaction, we build up a string
        # representing the stoichiometry. Then we'll simplify that string and
        # see whether we ended up with a float value in the end.
        stoichiometry = {}
        reactant_stoichiometry = {}
        product_stoichiometry = {}
        for reactant in rxn.getListOfReactants():
            species = reactant.getSpecies()
            stoichiometry.setdefault(species, '0')
            stoich = reactant.getStoichiometryMath()
            stoich = stoichToString(reactant, stoich)
            stoichiometry[species] += '-(%s)' % stoich
            if species in reactant_stoichiometry:
                reactant_stoichiometry[species].append(stoich)
            else:
                reactant_stoichiometry[species] = [stoich]

        for product in rxn.getListOfProducts():
            species = product.getSpecies()
            stoichiometry.setdefault(species, '0')
            stoich = product.getStoichiometryMath()
            stoich = stoichToString(product, stoich)
            stoichiometry[species] += '+(%s)' % stoich
            if species in product_stoichiometry:
                product_stoichiometry[species].append(stoich)
            else:
                product_stoichiometry[species] = [stoich]

        for species, stoich in stoichiometry.items():
            stoich = ExprManip.simplify_expr(stoich)
            try:
                # Try converting the string to a float.
                stoich = float(stoich)
            except ValueError:
                pass
            stoichiometry[species] = stoich

        for modifier in rxn.getListOfModifiers():
            stoichiometry.setdefault(modifier.getSpecies(), 0)

        rn.addReaction(id=id,
                       stoichiometry=stoichiometry,
                       kineticLaw=kLFormula,
                       reactant_stoichiometry=reactant_stoichiometry,
                       product_stoichiometry=product_stoichiometry)

    for ii, r in enumerate(m.getListOfRules()):
        if r.getTypeCode() == libsbml.SBML_ALGEBRAIC_RULE:
            math = formula_to_py(r.getMath())
            rn.add_algebraic_rule(math)
        else:
            variable = r.getVariable()
            math = formula_to_py(r.getMath())
            if r.getTypeCode() == libsbml.SBML_ASSIGNMENT_RULE:
                rn.addAssignmentRule(variable, math)
            elif r.getTypeCode() == libsbml.SBML_RATE_RULE:
                rn.addRateRule(variable, math)

    for ii, e in enumerate(m.getListOfEvents()):
        id, name = e.getId(), e.getName()

        if id == '':
            id = 'event%i' % ii

        try:
            # For libSBML 3.0
            trigger_math = e.getTrigger().getMath()
        except AttributeError:
            # For older versions
            trigger_math = e.getTrigger()
        trigger = formula_to_py(trigger_math)

        if e.getDelay() is not None:
            try:
                # For libSBML 3.0
                delay_math = e.getDelay().getMath()
            except AttributeError:
                # For older versions
                delay_math = e.getDelay()
            delay = formula_to_py(delay_math)
        else:
            delay = 0

        timeUnits = e.getTimeUnits()
        eaDict = KeyedList()
        for ea in e.getListOfEventAssignments():
            ea_formula = formula_to_py(ea.getMath())
            ea_formula = ea_formula.replace('or(', 'or_func(')
            ea_formula = ea_formula.replace('and(', 'and_func(')
            eaDict.set(ea.getVariable(), ea_formula)

        rn.addEvent(id=id,
                    trigger=trigger,
                    eventAssignments=eaDict,
                    delay=delay,
                    name=name)

    for ii, con in enumerate(m.getListOfConstraints()):
        id, name = con.getId(), con.getName()
        if id == '':
            id = 'constraint%i' % ii

        trigger_math = con.getMath()

        trigger = formula_to_py(trigger_math)

        if con.isSetMessage():
            message = con.getMessage()
        else:
            message = None

        rn.addConstraint(id=id, trigger=trigger, message=message, name=name)

    return rn