def main(args):
    """usage: convertFbcToCobra.py input-filename output-filename
    """
    if len(args) != 3:
        print(main.__doc__)
        sys.exit(1)

    infile = args[1]
    outfile = args[2]

    if not os.path.exists(infile):
        print("[Error] %s : No such file." % infile)
        sys.exit(1)

    reader = libsbml.SBMLReader()
    writer = libsbml.SBMLWriter()
    sbmldoc = reader.readSBML(infile)

    if sbmldoc.getNumErrors() > 0:
        if sbmldoc.getError(0).getErrorId() == libsbml.XMLFileUnreadable:
            # Handle case of unreadable file here.
            sbmldoc.printErrors()
        elif sbmldoc.getError(0).getErrorId() == libsbml.XMLFileOperationError:
            # Handle case of other file error here.
            sbmldoc.printErrors()
        else:
            # Handle other error cases here.
            sbmldoc.printErrors()

            # sys.exit(1)

    # strip non-FBC plugins
    for p_ in range(sbmldoc.getNumPlugins()):
        if sbmldoc.getPlugin(p_).getPackageName() != 'fbc':
            props = libsbml.ConversionProperties()
            props.addOption(
                "stripPackage", True,
                "Strip SBML Level 3 package constructs from the model")
            props.addOption("package",
                            sbmldoc.getPlugin(p_).getPackageName(),
                            "Name of the SBML Level 3 package to be stripped")
            if sbmldoc.convert(props) != libsbml.LIBSBML_OPERATION_SUCCESS:
                print("[Error] Failed to remove package: {}".format(
                    sbmldoc.getPlugin(p_).getPackageName()))

    # convert to L2
    props = libsbml.ConversionProperties()
    props.addOption("convert fbc to cobra", True,
                    "Convert FBC model to Cobra model")
    result = sbmldoc.convert(props)

    if result != libsbml.LIBSBML_OPERATION_SUCCESS:
        print("[Error] Conversion failed... (%d)" % result)
        sys.exit(1)

    writer.writeSBML(sbmldoc, outfile)
    print("[OK] converted file %s to %s" % (infile, outfile))
def main (args):
  """usage: flattenModel.py [-p] input-filename output-filename
      -p : list unused ports
  """
  if len(args) != 4 and len(args) != 3 :
    print(main.__doc__)
    sys.exit(1)

  leavePorts = False

  if len(args) == 3:
    infile  = args[1]
    outfile = args[2]
  elif len(args) == 4:
    if args[1] != "-p":
      print(main.__doc__)
      sys.exit(1)
    else:
      leavePorts = True
      infile  = args[2]
      outfile = args[3]



  if not os.path.exists(infile):
    print("[Error] %s : No such file." % (infile))
    sys.exit(1)

  reader  = libsbml.SBMLReader()
  writer  = libsbml.SBMLWriter()
  sbmldoc = reader.readSBML(infile)

  if sbmldoc.getNumErrors() > 0:
    if sbmldoc.getError(0).getErrorId() == libsbml.XMLFileUnreadable:
      # Handle case of unreadable file here.
      sbmldoc.printErrors()
    elif sbmldoc.getError(0).getErrorId() == libsbml.XMLFileOperationError:
      # Handle case of other file error here.
      sbmldoc.printErrors()
    else:
      # Handle other error cases here.
      sbmldoc.printErrors()

    sys.exit(1)

  # Create the converter options
  props = libsbml.ConversionProperties()
  props.addOption("flatten comp", True, "flatten comp")
  props.addOption("leavePorts", leavePorts, "unused ports should be listed in the flattened model")

  # do conversion
  result = sbmldoc.convert(props)
  if (result != libsbml.LIBSBML_OPERATION_SUCCESS):
    sbmldoc.printErrors()
    print("[Error] Conversion failed... ("+ str(result) + ")")
    sys.exit(1)

  writer.writeSBML(sbmldoc, outfile)
  print("Flat model written to %s" % (outfile))
Beispiel #3
0
def promote_params(model, document):
    """Change parameters to global, so that they are preserved
    when reactions change."""
    convProps = libsbml.ConversionProperties()
    convProps.addOption("promoteLocalParameters", True,
                        "Promotes all Local Parameters to Global ones")
    if (document.convert(convProps) != libsbml.LIBSBML_OPERATION_SUCCESS):
        raise SystemExit("Error promoting local parameters to global.")
Beispiel #4
0
def convert_functions(model, document):
    """Replace functions with formulas."""
    config = libsbml.ConversionProperties()
    if config != None:
        config.addOption('expandFunctionDefinitions')
    status = document.convert(config)
    if status != libsbml.LIBSBML_OPERATION_SUCCESS:
        print('Error: function conversion failed:')
        document.printErrors()
Beispiel #5
0
def main(args):
    """usage: stripPackage.py input-filename package-to-strip output-filename
  """
    if len(args) != 4:
        print(main.__doc__)
        sys.exit(1)

    infile = args[1]
    package = args[2]
    outfile = args[3]

    if not os.path.exists(infile):
        print("[Error] %s : No such file." % (infile))
        sys.exit(1)

    reader = libsbml.SBMLReader()
    writer = libsbml.SBMLWriter()
    sbmldoc = reader.readSBML(infile)

    if sbmldoc.getNumErrors() > 0:
        if sbmldoc.getError(0).getErrorId() == libsbml.XMLFileUnreadable:
            # Handle case of unreadable file here.
            sbmldoc.printErrors()
        elif sbmldoc.getError(0).getErrorId() == libsbml.XMLFileOperationError:
            # Handle case of other file error here.
            sbmldoc.printErrors()
        else:
            # Handle other error cases here.
            sbmldoc.printErrors()

        sys.exit(1)

    props = libsbml.ConversionProperties()
    props.addOption("stripPackage", True,
                    "Strip SBML Level 3 package constructs from the model")
    props.addOption("package", package,
                    "Name of the SBML Level 3 package to be stripped")
    if (sbmldoc.convert(props) != libsbml.LIBSBML_OPERATION_SUCCESS):
        print("[Error] Conversion failed...")
        sys.exit(1)

    writer.writeSBML(sbmldoc, outfile)
    print("[OK] stripped package '%s' from %s to %s" %
          (package, infile, outfile))
def main(args):
    """usage: flattenArrays.py input-filename output-filename
    """
    if len(args) != 3:
        print(main.__doc__)
        sys.exit(1)

    infile = args[1]
    outfile = args[2]

    if not os.path.exists(infile):
        print("[Error] {} : No such file.".format(infile))
        sys.exit(1)

    reader = libsbml.SBMLReader()
    writer = libsbml.SBMLWriter()
    sbmldoc = reader.readSBML(infile)

    if sbmldoc.getNumErrors() > 0:
        if sbmldoc.getError(0).getErrorId() == libsbml.XMLFileUnreadable:
            # Handle case of unreadable file here.
            sbmldoc.printErrors()
        elif sbmldoc.getError(0).getErrorId() == libsbml.XMLFileOperationError:
            # Handle case of other file error here.
            sbmldoc.printErrors()
        else:
            # Handle other error cases here.
            sbmldoc.printErrors()

        sys.exit(1)

    props = libsbml.ConversionProperties()
    props.addOption("flatten arrays", True, "flatten arrays")
    # Optional: validate flattened file ... may take some time
    # props.addOption("performValidation", True, "perform validation before and after trying to flatten")

    result = sbmldoc.convert(props)
    if (result != libsbml.LIBSBML_OPERATION_SUCCESS):
        print("[Error] Array flattening failed... ({})".format(result))
        sys.exit(1)

    writer.writeSBML(sbmldoc, outfile)
    print("[OK] Flattened arrays file {} to {}".format(infile, outfile))
Beispiel #7
0
def promote_local_variables(doc):
    """ Promotes local variables in SBMLDocument.

    :param doc:
    :return:
    """
    model = doc.getModel()
    mid = model.id
    mid = '{}_{}'.format(mid, 'promoted')
    model.setId(mid)

    # promote local parameters
    props = libsbml.ConversionProperties()
    props.addOption("promoteLocalParameters", True,
                    "Promotes all Local Parameters to Global ones")
    if doc.convert(props) != libsbml.LIBSBML_OPERATION_SUCCESS:
        warnings.warn("SBML Conversion failed...")
    else:
        print("SBML Conversion successful")
    return doc
def main(args):
    """usage: convertFbcToCobra.py input-filename output-filename
  """
    if len(args) != 3:
        print(main.__doc__)
        sys.exit(1)

    infile = args[1]
    outfile = args[2]

    if not os.path.exists(infile):
        print("[Error] %s : No such file." % (infile))
        sys.exit(1)

    reader = libsbml.SBMLReader()
    writer = libsbml.SBMLWriter()
    sbmldoc = reader.readSBML(infile)

    if sbmldoc.getNumErrors() > 0:
        if sbmldoc.getError(0).getErrorId() == libsbml.XMLFileUnreadable:
            # Handle case of unreadable file here.
            sbmldoc.printErrors()
        elif sbmldoc.getError(0).getErrorId() == libsbml.XMLFileOperationError:
            # Handle case of other file error here.
            sbmldoc.printErrors()
        else:
            # Handle other error cases here.
            sbmldoc.printErrors()

        #sys.exit(1)

    props = libsbml.ConversionProperties()
    props.addOption("convert fbc to cobra", True,
                    "Convert FBC model to Cobra model")
    result = sbmldoc.convert(props)
    if (result != libsbml.LIBSBML_OPERATION_SUCCESS):
        print("[Error] Conversion failed... (%d)" % (result))
        sys.exit(1)

    writer.writeSBML(sbmldoc, outfile)
    print("[OK] converted file %s to %s" % (infile, outfile))
Beispiel #9
0
def main(args):
    """usage: promoteParameters.py input-filename output-filename
  """
    if len(args) != 3:
        print(main.__doc__)
        sys.exit(1)

    infile = args[1]
    outfile = args[2]

    if not os.path.exists(infile):
        print("[Error] %s : No such file." % (infile))
        sys.exit(1)

    reader = libsbml.SBMLReader()
    writer = libsbml.SBMLWriter()
    sbmldoc = reader.readSBML(infile)

    if sbmldoc.getNumErrors() > 0:
        if sbmldoc.getError(0).getErrorId() == libsbml.XMLFileUnreadable:
            # Handle case of unreadable file here.
            sbmldoc.printErrors()
        elif sbmldoc.getError(0).getErrorId() == libsbml.XMLFileOperationError:
            # Handle case of other file error here.
            sbmldoc.printErrors()
        else:
            # Handle other error cases here.
            sbmldoc.printErrors()

        sys.exit(1)

    props = libsbml.ConversionProperties()
    props.addOption("promoteLocalParameters", True,
                    "Promotes all Local Parameters to Global ones")
    if (sbmldoc.convert(props) != libsbml.LIBSBML_OPERATION_SUCCESS):
        print("[Error] Conversion failed...")
        sys.exit(1)

    writer.writeSBML(sbmldoc, outfile)
    print("[OK] wrote %s" % (package, infile, outfile))
def main (args):
    """usage: inlineFunctionDefinitions.py input-filename output-filename
    """
    if len(args) != 3:
        print(main.__doc__)
        sys.exit(1)

    infile  = args[1]
    outfile = args[2]

    if not os.path.exists(infile):
        print("[Error] %s : No such file." % infile)
        sys.exit(1)

    reader  = libsbml.SBMLReader()
    writer  = libsbml.SBMLWriter()
    sbmldoc = reader.readSBML(infile)

    if sbmldoc.getNumErrors() > 0:
        if sbmldoc.getError(0).getErrorId() == libsbml.XMLFileUnreadable:
            # Handle case of unreadable file here.
            sbmldoc.printErrors()
        elif sbmldoc.getError(0).getErrorId() == libsbml.XMLFileOperationError:
            # Handle case of other file error here.
            sbmldoc.printErrors()
        else:
            # Handle other error cases here.
            sbmldoc.printErrors()

        sys.exit(1)

    props = libsbml.ConversionProperties()
    props.addOption("expandFunctionDefinitions", True)
    if sbmldoc.convert(props) != libsbml.LIBSBML_OPERATION_SUCCESS:
        print("[Error] Conversion failed...")
        sys.exit(1)

    writer.writeSBML(sbmldoc, outfile)
    print("[OK] wrote {}".format(outfile))
Beispiel #11
0
def promote_local_variables(doc: libsbml.SBMLDocument,
                            suffix: str = "_promoted") -> libsbml.SBMLDocument:
    """Promotes local variables in SBMLDocument.

    Manipulates SBMLDocument in place!

    :param doc: SBMLDocument
    :param suffix: str suffix for promoted SBML
    :return: SBMLDocument with promoted parameters
    """
    model: libsbml.Model = doc.getModel()
    model.setId(f"{model.id}{suffix}")

    # promote local parameters
    props = libsbml.ConversionProperties()
    props.addOption("promoteLocalParameters", True,
                    "Promotes all Local Parameters to Global ones")

    if doc.convert(props) != libsbml.LIBSBML_OPERATION_SUCCESS:
        logger.error(f"Promotion of local parameters failed: {doc}")
    else:
        logger.info(f"Promotion of local paramters successful: {doc}")
    return doc
Beispiel #12
0
def writeCode(doc):
    comp_template = 'model.addCompartment(vol=%s, comp_id=\'%s\');'
    species_template = 'model.addSpecies(species_id=\'%s\', amt=%s, comp=\'%s\');'
    param_template = 'model.addParameter(param_id=\'%s\', val=%s, units=\'%s\');'
    rxn_template = 'model.addReaction(reactants=%s, products=%s, expression=\'%s\', local_params=%s, rxn_id=\'%s\');'
    event_template = 'model.addEvent(trigger=\'%s\', assignments=%s, persistent=%s, initial_value=%s, priority=%s, delay=%s, event_id=\'%s\');'
    event_defaults = [True, False, '0', 0]
    assignrule_template = 'model.addAssignmentRule(var=\'%s\', math=\'%s\');'
    raterule_template = 'model.addRateRule(var=\'%s\', math=\'%s\');'
    initassign_template = 'model.addInitialAssignment(symbol=\'%s\', math=\'%s\')'
    init_template = 'import simplesbml\nmodel = simplesbml.sbmlModel(time_units=\'%s\', extent_units=\'%s\', sub_units=\'%s\', level=%s, version=%s);'
    init_defaults = ['second', 'mole', 'mole', 3, 1]
    command_list = []

    if doc.getLevel() == 1:
        print "Warning: SimpleSBML does not support Level 1 SBML models.  Before \
        running this code, set the model to level 2 or 3."

    props = libsbml.ConversionProperties()
    props.addOption('flatten comp', True)
    result = doc.convert(props)
    if (result != libsbml.LIBSBML_OPERATION_SUCCESS):
        raise SystemExit('Conversion failed: (' + str(result) + ')')

    mod = doc.getModel()
    comps = mod.getListOfCompartments()
    species = mod.getListOfSpecies()
    params = mod.getListOfParameters()
    rxns = mod.getListOfReactions()
    events = mod.getListOfEvents()
    rules = mod.getListOfRules()
    inits = []
    if doc.getLevel() == 3 or (doc.getLevel() == 2 and doc.getVersion() > 1):
        inits = mod.getListOfInitialAssignments()

    timeUnits = 'second'
    substanceUnits = 'mole'
    extentUnits = 'mole'
    if doc.getLevel() == 3:
        timeUnits = mod.getTimeUnits()
        extentUnits = mod.getExtentUnits()
        substanceUnits = mod.getSubstanceUnits()
    level = mod.getLevel()
    version = mod.getVersion()
    init_list = [timeUnits, extentUnits, substanceUnits, level, version]
    for i in range(0, 5):
        if init_list[i] == init_defaults[i]:
            init_list[i] = 'del'

    command_list.append(init_template % \
            (init_list[0], init_list[1], init_list[2], init_list[3], init_list[4]))

    for comp in comps:
        if comp.getId() != 'c1':
            if comp.getId()[0] == 'c' and comp.getId()[1:len(comp.getId()
                                                             )].isdigit():
                if comp.getSize() == 1e-15:
                    command_list.append(comp_template % ('del', 'del'))
                else:
                    command_list.append(comp_template %
                                        (comp.getSize(), 'del'))
            else:
                if comp.getSize() == 1e-15:
                    command_list.append(comp_template % ('del', comp.getId()))
                else:
                    command_list.append(comp_template %
                                        (comp.getSize(), comp.getId()))

    for s in species:
        conc = s.getInitialConcentration()
        amt = s.getInitialAmount()
        sid = s.getId()
        if s.getCompartment() == 'c1':
            comp = 'del'
        else:
            comp = s.getCompartment()
        bc = s.getBoundaryCondition()
        if bc:
            sid = "$" + sid
        if isnan(conc) or amt > conc:
            command_list.append(species_template % (sid, str(amt), comp))
        else:
            command_list.append(species_template %
                                ("[" + sid + "]", str(conc), comp))

    for p in params:
        val = p.getValue()
        pid = p.getId()
        if p.getUnits() == 'per_second':
            units = 'del'
        else:
            units = p.getUnits()
        isDelay = pid.find('Delay')
        if isDelay == -1:
            command_list.append(param_template % (pid, str(val), str(units)))

    for v in rxns:
        vid = v.getId()
        if vid[0] == 'v' and vid[1:len(vid)].isdigit():
            vid = 'del'
        reactants = []
        for r in v.getListOfReactants():
            reactants.append(
                (str(r.getStoichiometry()) + ' ' + r.getSpecies()).replace(
                    '1.0 ', ''))
        products = []
        for p in v.getListOfProducts():
            products.append(
                (str(p.getStoichiometry()) + ' ' + p.getSpecies()).replace(
                    '1.0 ', ''))
        expr = libsbml.formulaToString(v.getKineticLaw().getMath())
        local_params = {}
        local_ids = []
        local_values = []
        for k in v.getKineticLaw().getListOfParameters():
            local_ids.append(k.getId())
            local_values.append(k.getValue())
        local_params = dict(zip(local_ids, local_values))
        if len(local_params) == 0:
            local_params = 'del'
        command_list.append(rxn_template % (str(reactants), str(products), \
                    expr, str(local_params), vid))

    for e in events:
        persistent = True
        initialValue = False
        priority = '0'
        eid = e.getId()
        if len(eid) == 0 or (eid[0] == 'e' and eid[1:len(eid)].isdigit()):
            eid = 'del'
        if doc.getLevel() == 3:
            persistent = e.getTrigger().getPersistent()
            initialValue = e.getTrigger().getInitialValue()
            priority = e.getPriority()
            if type(priority) == libsbml.Priority:
                priority = libsbml.formulaToL3String(priority.getMath())
            else:
                priority = '0'
        tri = libsbml.formulaToL3String(e.getTrigger().getMath())
        did = e.getDelay()
        if type(did) == libsbml.Delay:
            delay = libsbml.formulaToL3String(did.getMath())
        else:
            delay = '0'
        assigns = e.getListOfEventAssignments()
        var = []
        values = []
        for assign in assigns:
            var.append(assign.getVariable())
            values.append(libsbml.formulaToL3String(assign.getMath()))
        assigns = dict(zip(var, values))

        event_list = [persistent, initialValue, priority, delay]
        for i in range(0, 4):
            if event_list[i] == event_defaults[i]:
                event_list[i] = 'del'

        command_list.append(event_template % (tri, str(assigns), \
                event_list[0], event_list[1], event_list[2], event_list[3], eid))

    for r in rules:
        sym = r.getVariable()
        math = libsbml.formulaToL3String(r.getMath())
        if r.getTypeCode() == libsbml.SBML_ASSIGNMENT_RULE:
            command_list.append(assignrule_template % (sym, math))
        elif r.getTypeCode() == libsbml.SBML_RATE_RULE:
            command_list.append(raterule_template % (sym, math))
        else:
            next

    for i in inits:
        sym = i.getSymbol()
        math = libsbml.formulaToL3String(i.getMath())
        command_list.append(initassign_template % (sym, math))

    commands = '\n'.join(command_list)
    commands = sub('\w+=\'?del\'?(?=[,)])', '', commands)
    commands = sub('\((, )+', '(', commands)
    commands = sub('(, )+\)', ')', commands)
    commands = sub('(, )+', ', ', commands)
    return commands
	def loadModelFile(self):
		
		# Get SBMLModelPath from user input
		self.SBMLModelPath = str(QtGui.QFileDialog.getOpenFileName(filter = '*.xml'))
		
		# Read in SBML model file into SBML Document variable
		SBMLDoc = libsbml.readSBMLFromFile( self.SBMLModelPath )
    
		# Check if any major errors in reading SBML model
		# e.g. Filepath does not exist
		if SBMLDoc.getNumErrors() > 0:
			self.ErrorLog.append('ERROR: File reading errors.\n')
			self.ErrorLog.append(SBMLDoc.getErrorLog().toString()+'\n')

		# Make all parameters of the model global parameters.
		# Enables all parameters to be vectorized.
		Properties = libsbml.ConversionProperties()
		Properties.addOption('promoteLocalParameters', True)
		if SBMLDoc.convert(Properties) != libsbml.LIBSBML_OPERATION_SUCCESS:
			self.ErrorLog.append('ERROR: Unable to convert parameters to global.\n')
			self.ErrorLog.append(SBMLDoc.getErrorLog().toString()+'\n')

		# Write out all reaction-specific function definitions.
		# Enables all variables in reactions to be swapped with vectorized
		# versions.
		Properties = libsbml.ConversionProperties()
		Properties.addOption('expandFunctionDefinitions', True)
		if SBMLDoc.convert(Properties) != libsbml.LIBSBML_OPERATION_SUCCESS:
			self.ErrorLog.append('ERROR: Unable to expand internal function usage.\n')
			self.ErrorLog.append(SBMLDoc.getErrorLog().toString()+'\n')
	
		# Write out all state variable and parameter initializations.
		# Enables this data to be placed into required SciPyModel object
		# places.
		Properties = libsbml.ConversionProperties()
		Properties.addOption('expandInitialAssignments', True)
		if SBMLDoc.convert(Properties) != libsbml.LIBSBML_OPERATION_SUCCESS:
			self.ErrorLog.append('ERROR: Unable to expand initial assignments.\n')
			self.ErrorLog.append(SBMLDoc.getErrorLog().toString()+'\n')
        
		# Extract SBML Model object from SBML Document object.
		self.SBMLModel = SBMLDoc.getModel()
    
		# Extract MetaData data from SBML model object
		self.lineEditModelName.setText(str(self.SBMLModel.getName()))
		self.lineEditVolumeUnits.setText(str(self.SBMLModel.getVolumeUnits()))
		self.lineEditQuantityUnits.setText(str(self.SBMLModel.getSubstanceUnits()))	
		self.lineEditTimeUnits.setText(str(self.SBMLModel.getTimeUnits()))
    
		# Extract Compartment data from SBML model
		self.tableCompartments.setRowCount(self.SBMLModel.getNumCompartments())
		for i in range(self.tableCompartments.rowCount()):
			CurCompartment = self.SBMLModel.getCompartment(i)
			self.tableCompartments.setItem(i, 0, QtGui.QTableWidgetItem('c['+str(i)+']'))
			
			if not str(CurCompartment.getName()):
				self.tableCompartments.setItem(i, 1, 
					QtGui.QTableWidgetItem('default'+str(i)))
				self.tableCompartments.item(i, 1).setBackground(QtGui.QColor(255,255,150))
			else:
				self.tableCompartments.setItem(i, 1, 
					QtGui.QTableWidgetItem(str(CurCompartment.getName())))
			
			self.tableCompartments.setItem(i, 2, QtGui.QTableWidgetItem(str(CurCompartment.volume)))
			self.tableCompartments.setItem(i, 3, QtGui.QTableWidgetItem(str(CurCompartment.volume)))
			# Add compartment to comboBox used by Species and Reactions 
			self.comboBoxCompartments.addItem(str(CurCompartment.getName()))
		self.tableCompartments.resizeColumnsToContents()
		
		# Extract Species data from SBML Model
		self.tableSpecies.setRowCount(self.SBMLModel.getNumSpecies())
		for i in range(self.tableSpecies.rowCount()):
			CurSpecies = self.SBMLModel.getSpecies(i)
			self.tableSpecies.setItem(i, 0, QtGui.QTableWidgetItem('s['+str(i)+']'))
			self.tableSpecies.setItem(i, 1, QtGui.QTableWidgetItem(str(CurSpecies.getName())))
			self.tableSpecies.setItem(i, 2, QtGui.QTableWidgetItem(str(CurSpecies.initial_amount)))
			self.tableSpecies.setItem(i, 3, QtGui.QTableWidgetItem(str(CurSpecies.initial_amount)))
			self.tableSpecies.setItem(i, 4, QtGui.QTableWidgetItem(str(CurSpecies.compartment)))
			FooBox = QtGui.QCheckBox(); FooBox.setChecked(CurSpecies.boundary_condition)
			self.tableSpecies.setCellWidget(i, 5, FooBox)
			self.tableSpecies.setItem(i, 6, QtGui.QTableWidgetItem(str(CurSpecies.getMetaId())))
		self.tableSpecies.resizeColumnsToContents()
		
		# Create a vector of Species names for later use
		ListOfSpecies = self.getTableData(self.tableSpecies, 1, 0, 1, 
								self.SBMLModel.getNumSpecies()).flatten()
		
		# Extract Parameter data from SBML Model
		# -- Quantity, Names, Value, VectorIndex
		self.tableParameters.setRowCount(self.SBMLModel.getNumParameters())
		for i in range(self.tableParameters.rowCount()):
			CurParameter = self.SBMLModel.getParameter(i)
			
			# Create vector index for parameter
			self.tableParameters.setItem(i, 0, QtGui.QTableWidgetItem('p['+str(i)+']'))
			
			# Port parameter name data from SBML model
			if not str(CurParameter.getName()):
				self.tableParameters.setItem(i, 1, 
					QtGui.QTableWidgetItem('default_prm'+str(i)))
			else:
				self.tableParameters.setItem(i, 1, 
					QtGui.QTableWidgetItem(str(CurParameter.getName())))
			
			# Get parameter value data from SBML model
			if not str(CurParameter.getValue()):
				self.tableParameters.setItem(i, 2, 
					QtGui.QTableWidgetItem('nan'))
			else:
				self.tableParameters.setItem(i, 2, 
					QtGui.QTableWidgetItem(str(CurParameter.getValue())))
			
			# Initialize parameter variable condtional
			self.tableParameters.setCellWidget(i, 3, QtGui.QCheckBox())
			
			# Get parameter metaid data from SBML model
			if not str(CurParameter.getMetaId()):
				self.tableParameters.setItem(i, 4, 
					QtGui.QTableWidgetItem('default_prmid'+str(i)))
			else:
				self.tableParameters.setItem(i, 4, 
					QtGui.QTableWidgetItem(str(CurParameter.getMetaId())))
					
			
			
		self.tableParameters.resizeColumnsToContents()
	
		# Extract Reaction data from SBML Model
		self.tableReactions.setRowCount(self.SBMLModel.getNumReactions())
		
		# Construct Stoichiometric Matrix from SBML Model
		# Expand Stoichiometric table to correct dimensions
		self.tableStoichMatrix.setRowCount(self.SBMLModel.getNumSpecies())
		self.tableStoichMatrix.setColumnCount(self.SBMLModel.getNumReactions())
		
		# Place Species names on vertical header for identification
		self.tableStoichMatrix.setVerticalHeaderLabels(ListOfSpecies)
		
		# Create empty numpy array of correct dimension for later use
		StoichMatrix = numpy.empty([self.SBMLModel.getNumSpecies(), 
										self.SBMLModel.getNumReactions()])
		
		for i in range(self.tableReactions.rowCount()):
			
			# Get current reaction from SBML model
			CurReaction = self.SBMLModel.getReaction(i)
			
			# Create reaction vector index
			self.tableReactions.setItem(i, 0, QtGui.QTableWidgetItem(str(i)))
			
			# Port name data from SBML model
			if not str(CurReaction.getName()):
				self.tableReactions.setItem(i, 1, 
					QtGui.QTableWidgetItem('default_rxn'+str(i)))
				self.tableReactions.item(i, 1).setBackground(QtGui.QColor(255,255,150))
			else:
				self.tableReactions.setItem(i, 1, 
					QtGui.QTableWidgetItem(str(CurReaction.getName())))
				
			# Get current reaction differential equation
			Formula = str(CurReaction.getKineticLaw().getFormula())
	
			# Replace compartment names with vector index in equation
			for j in reversed(range(self.tableCompartments.rowCount())):
				Formula = Formula.replace( str(self.tableCompartments.item(j,1).data(0).toString()), 
										   str(self.tableCompartments.item(j,0).data(0).toString()) )
		
			# Replace parameter names with vector index in equation
			for j in reversed(range(self.tableParameters.rowCount())):
				Formula = Formula.replace( str(self.tableParameters.item(j,1).data(0).toString()), 
										   str(self.tableParameters.item(j,0).data(0).toString()) )
				Formula = Formula.replace( str(self.tableParameters.item(j,4).data(0).toString()), 
										   str(self.tableParameters.item(j,0).data(0).toString()) )
										   
			# Replace species names with vector index in equation
			for j in reversed(range(self.tableSpecies.rowCount())):
				Formula = Formula.replace( str(self.tableSpecies.item(j,1).data(0).toString()), 
										   str(self.tableSpecies.item(j,0).data(0).toString()) )
				Formula = Formula.replace( str(self.tableSpecies.item(j,6).data(0).toString()), 
										   str(self.tableSpecies.item(j,0).data(0).toString()) )

			# Place differential equation into tableReactions
			self.tableReactions.setItem(i, 2, QtGui.QTableWidgetItem(Formula))
			
			# Assemeble stoichiometric matrix into a numpy array.
			for r in CurReaction.getListOfReactants():
				StoichMatrix[numpy.where(ListOfSpecies == r.getSpecies()), i] -= r.getStoichiometry()
			for p in CurReaction.getListOfProducts():
				StoichMatrix[numpy.where(ListOfSpecies == p.getSpecies()), i] += p.getStoichiometry()
	
			# Assemble list of reaction modifiers for clarity
			ListOfModifiers = []
			for m in CurReaction.getListOfModifiers():
				ListOfModifiers.append(str(m.getSpecies()))
			
			# Clean string for clarity and display in table
			ListOfModifiers = str(ListOfModifiers).replace('[', '').replace(']', '').replace('\'', '')
			self.tableReactions.setItem(i, 3, QtGui.QTableWidgetItem(ListOfModifiers))
			
			# Print compartment where reaction occurs
			self.tableReactions.setItem(i, 4, QtGui.QTableWidgetItem(CurReaction.getCompartment()))
			
		for i in range(self.tableStoichMatrix.rowCount()):
			for j in range(self.tableStoichMatrix.columnCount()):
				self.tableStoichMatrix.setItem(i,j,QtGui.QTableWidgetItem(str(StoichMatrix[i,j])))
	
		self.tableStoichMatrix.setHorizontalHeaderLabels(
				self.getTableData(self.tableReactions, 1, 0, 1, self.SBMLModel.getNumReactions()).flatten())
		
		# Update error log for user feedback on issues
		self.modelErrorLog.setPlainText(self.ErrorLog)
def importSBMLFile(SciPyModel):
    ''' 
        Reads an SBML model file and unpacks the
        SBML model into the provided SciPyModel object structure.
        User may specify SBML model file path within SciPyModel
        manually.
        
        To-Do
        -----
        1. Difficulty importing Copasi exported SBML models due to
           difference in name/meta_id fields. Specific issue with
           SBML models imported/exported through Copasi.
           
        2. Write code to inform user of required fields to be
           filled out. Should be in the form of:
           
           SciPyModel.errorLog()
           
           Which prints a list of potential issues in the model
           for the user to update.
           
        3. Implement conditional to reset SciPyModel to initial
           form if user passes in filled model.
    
        Parameters
        ----------
        SciPyModel : object instance
            
            Can be called on any SciPyModel object.
        
        Returns
        -------
        SciPyModel : object instance
            Initial SciPyModel object with relevant edits in
            structure as dictated by the SBML model file.
            
        See Also
        --------
        createSciPyModel
        
        Notes
        -----
        If no file path is provided or if the provided file
        encounters error, then the function returns an unmodified
        SciPyModel object.
    '''

    # Import required modules
    import libsbml, numpy, Tkinter, tkFileDialog

    # Conditional to check if FilePath was specified
    if SciPyModel.MetaData.FilePath == None:
        Tkinter.Tk().withdraw()
        SciPyModel.MetaData.FilePath = tkFileDialog.askopenfilename()
    else:
        pass

    # Read in SBML model file into SBML Document variable
    SBMLDoc = libsbml.readSBMLFromFile(SciPyModel.MetaData.FilePath)

    # Check if any major errors in reading SBML model
    # e.g. Filepath does not exist
    if SBMLDoc.getNumErrors() > 0:
        print('ERROR: File reading errors.')
        print(SBMLDoc.getErrorLog().toString())

    # Make all parameters of the model global parameters.
    # Enables all parameters to be vectorized.
    Properties = libsbml.ConversionProperties()
    Properties.addOption('promoteLocalParameters', True)
    if SBMLDoc.convert(Properties) != libsbml.LIBSBML_OPERATION_SUCCESS:
        print('ERROR: Unable to convert parameters to global.')
        print(SBMLDoc.getErrorLog().toString())

    # Write out all reaction-specific function definitions.
    # Enables all variables in reactions to be swapped with vectorized
    # versions.
    Properties = libsbml.ConversionProperties()
    Properties.addOption('expandFunctionDefinitions', True)
    if SBMLDoc.convert(Properties) != libsbml.LIBSBML_OPERATION_SUCCESS:
        print('ERROR: Unable to expand internal function usage.')
        print(SBMLDoc.getErrorLog().toString())

    # Write out all state variable and parameter initializations.
    # Enables this data to be placed into required SciPyModel object
    # places.
    Properties = libsbml.ConversionProperties()
    Properties.addOption('expandInitialAssignments', True)
    if SBMLDoc.convert(Properties) != libsbml.LIBSBML_OPERATION_SUCCESS:
        print('ERROR: Unable to expand initial assignments.')
        print(SBMLDoc.getErrorLog().toString())

    # Extract SBML Model object from SBML Document object.
    SBMLModel = SBMLDoc.getModel()

    # Extract MetaData
    # -- Name, VolumeUnits, SubstanceUnits, TimeUnits
    SciPyModel.MetaData.Name = SBMLModel.getName()
    SciPyModel.MetaData.VolumeUnits = SBMLModel.getVolumeUnits()
    SciPyModel.MetaData.SubstanceUnits = SBMLModel.getSubstanceUnits()
    SciPyModel.MetaData.TimeUnits = SBMLModel.getTimeUnits()

    # Extract Compartment Data
    # -- Quantity, Names, VectorIndex
    SciPyModel.Compartments.Quantity = SBMLModel.getNumCompartments()
    for i in range(SBMLModel.getNumCompartments()):
        current_compartment = SBMLModel.getCompartment(i)
        SciPyModel.Compartments.Names.append(current_compartment.name)
        SciPyModel.Compartments.VectorIndex.append(i)
        SciPyModel.Compartments.MetaID.append(current_compartment.meta_id)

    # Extract Species Data
    # -- Quanity, Names, Value, VectorIndex, BoundaryValue
    SciPyModel.Species.Quantity = SBMLModel.getNumSpecies()
    for i in range(SBMLModel.getNumSpecies()):
        current_species = SBMLModel.getSpecies(i)
        SciPyModel.Species.Names.append(current_species.name)
        SciPyModel.Species.Value.append(current_species.initial_amount)
        SciPyModel.Species.VectorIndex.append(i)
        SciPyModel.Species.BoundaryValue.append(
            current_species.boundary_condition)
        SciPyModel.Species.MetaID.append(current_species.meta_id)

    # Extract Parameter Data
    # -- Quantity, Names, Value, VectorIndex, MetaID, KineticFlag
    SciPyModel.Parameters.Quantity = SBMLModel.getNumParameters()
    for i in range(SBMLModel.getNumParameters()):
        current_parameter = SBMLModel.getParameter(i)
        SciPyModel.Parameters.Names.append(current_parameter.name)
        SciPyModel.Parameters.Value.append(current_parameter.value)
        SciPyModel.Parameters.VectorIndex.append(i)
        SciPyModel.Parameters.MetaID.append(current_parameter.meta_id)
    [
        SciPyModel.Parameters.KineticFlag.append(False)
        for i in range(SciPyModel.Parameters.Quantity)
    ]

    # Extract Reaction Data
    # -- Names, Formulas, Stoichiometry
    SciPyModel.Reactions.Stoichiometry = numpy.zeros(
        [SBMLModel.getNumSpecies(),
         SBMLModel.getNumReactions()])
    SciPyModel.Reactions.Quantity = SBMLModel.getNumReactions()
    for i in range(SBMLModel.getNumReactions()):
        current_reaction = SBMLModel.getReaction(i)
        SciPyModel.Reactions.Names.append(current_reaction.name)
        SciPyModel.Reactions.Formulas.append(
            current_reaction.getKineticLaw().getFormula())

        # Try-Except in order to see if Names or MetaID are used in the functions
        try:
            for r in current_reaction.getListOfReactants():
                SciPyModel.Reactions.Stoichiometry[
                    SciPyModel.Species.Names.index(r.getSpecies()),
                    i] -= r.getStoichiometry()
            for p in current_reaction.getListOfProducts():
                SciPyModel.Reactions.Stoichiometry[
                    SciPyModel.Species.Names.index(p.getSpecies()),
                    i] += p.getStoichiometry()
        except ValueError:
            for r in current_reaction.getListOfReactants():
                SciPyModel.Reactions.Stoichiometry[
                    SciPyModel.Species.MetaID.index(r.getSpecies()),
                    i] -= r.getStoichiometry()
            for p in current_reaction.getListOfProducts():
                SciPyModel.Reactions.Stoichiometry[
                    SciPyModel.Species.MetaID.index(p.getSpecies()),
                    i] += p.getStoichiometry()
        else:
            print 'ERROR: Unable to create Stoichiometric Matrix. Check species name/metaid.'

        # Remove Stoichiometry of Boundary State Variables
        for s in range(SciPyModel.Species.Quantity):
            if SciPyModel.Species.BoundaryValue[s]:
                SciPyModel.Reactions.Stoichiometry[s, :] = numpy.zeros(
                    (1, SciPyModel.Reactions.Quantity))

    # Vectorize Functions within SciPyModel object.
    for rxn_ix in range(SciPyModel.Reactions.Quantity):

        # Get information about the current reaction
        Formula = SciPyModel.Reactions.Formulas[rxn_ix]

        # Removes usage of compartments from reaction equations.
        for j in reversed(range(SciPyModel.Compartments.Quantity)):
            if SciPyModel.Compartments.Names[j] != '':  # If name isn't empty
                Formula = Formula.replace(
                    SciPyModel.Compartments.Names[j] + ' * ', '')
                Formula = Formula.replace(
                    ' * ' + SciPyModel.Compartments.Names[j], '')
                Formula = Formula.replace(
                    ' / ' + SciPyModel.Compartments.Names[j], '')

        # Replace parameter names with index of vectorized parameter array.
        # Iterates through parameter names sorted by length of name.
        for key in sorted(SciPyModel.Parameters.Names, key=len, reverse=True):
            if key != '':
                Formula = Formula.replace(
                    key,
                    'p[' + str(SciPyModel.Parameters.Names.index(key)) + ']')

        for key in sorted(SciPyModel.Parameters.MetaID, key=len, reverse=True):
            if key != '':
                Formula = Formula.replace(
                    key,
                    'p[' + str(SciPyModel.Parameters.MetaID.index(key)) + ']')

        # Replace species names with index of species parameter array.
        for key in sorted(SciPyModel.Species.Names, key=len, reverse=True):
            if key != '':
                Formula = Formula.replace(
                    key, 'y[' + str(SciPyModel.Species.Names.index(key)) + ']')

        for key in sorted(SciPyModel.Species.MetaID, key=len, reverse=True):
            if key != '':
                Formula = Formula.replace(
                    key,
                    'y[' + str(SciPyModel.Species.MetaID.index(key)) + ']')

        # Reset formula declaration in SciPyModel class
        SciPyModel.Reactions.Formulas[rxn_ix] = Formula

    # Grab indecies of kinetic rate constant parameters
    ReactionIndex = []
    for rxn_ix in range(SciPyModel.Reactions.Quantity):
        ReactionIndex.append(
            int(SciPyModel.Reactions.Formulas[rxn_ix].split(']')[0].split('[')
                [-1]))

    # Order the parameters and track the internal index ordering
    SortedIndex = [
        i[0] for i in sorted(enumerate(ReactionIndex), key=lambda x: x[1])
    ]

    # Apply the index ordering to order the formula vector
    SciPyModel.Reactions.Formulas = [
        SciPyModel.Reactions.Formulas[i] for i in SortedIndex
    ]

    # Apply the index ordering to order the stoichiometry matrix
    SciPyModel.Reactions.Stoichiometry = numpy.vstack([
        SciPyModel.Reactions.Stoichiometry[:, i] for i in SortedIndex
    ]).transpose()

    return SciPyModel
Beispiel #15
0
from __future__ import absolute_import, print_function

import libsbml
import time

model_paths = ["rbc_top.xml"]

for p in model_paths:

    t_start = time.time()
    print("\n*** {} ***".format(p))
    doc = libsbml.readSBMLFromFile(p)
    t_read = time.time()
    print('reading: {:5.3} [s]'.format(t_read - t_start))

    # converter options
    props = libsbml.ConversionProperties()
    props.addOption("flatten comp", True)  # Invokes CompFlatteningConverter
    props.addOption("leave_ports", True)  # Indicates whether to leave ports

    # convert
    result = doc.convert(props)
    if result != libsbml.LIBSBML_OPERATION_SUCCESS:
        doc.printErrors()
        print("model could not be flattended due to errors.")
    t_flat = time.time()
    print('flattening: {:5.3} [s]'.format(t_flat - t_start))
Beispiel #16
0
def convert_function_definitions(doc):
    props = libsbml.ConversionProperties()
    props.addOption("expandFunctionDefinitions", True)
    return doc.convert(props)
def sbml_to_ode(filename):
  # 
  # read the SBML from file 
  # 
  import libsbml as lb 
  import sys
  raise NotImplementedError

  doc = lb.readSBMLFromFile(filename)
  if doc.getNumErrors(lb.LIBSBML_SEV_FATAL):
    print('Encountered serious errors while reading file')
    print(doc.getErrorLog().toString())
    sys.exit(1)
     
  # clear errors
  doc.getErrorLog().clearLog()
   
  #
  # perform conversions
  #
  props = lb.ConversionProperties()
  props.addOption("promoteLocalParameters", True)
   
  if doc.convert(props) != lb.LIBSBML_OPERATION_SUCCESS: 
    print('The document could not be converted')
    print(doc.getErrorLog().toString())
     
  props = lb.ConversionProperties()
  props.addOption("expandInitialAssignments", True)
   
  if doc.convert(props) != lb.LIBSBML_OPERATION_SUCCESS: 
    print('The document could not be converted')
    print(doc.getErrorLog().toString())
     
  props = lb.ConversionProperties()
  props.addOption("expandFunctionDefinitions", True)
   
  if doc.convert(props) != lb.LIBSBML_OPERATION_SUCCESS: 
    print('The document could not be converted')
    print(doc.getErrorLog().toString())
     
  #
  # figure out which species are variable 
  #
  mod = doc.getModel()
  variables = {}
   
  for i in range(mod.getNumSpecies()): 
     species = mod.getSpecies(i)
     if species.getBoundaryCondition() == True or species.getId() in variables.keys():
       continue
     variables[species.getId()] = []
   
  #
  # start generating the code by appending to bytearray
  #
  generated_code = bytearray('')
  generated_code.extend('from numpy import *\n')
  generated_code.extend('from matplotlib.pylab import *\n')
  generated_code.extend('from matplotlib.pyplot import *\n')
  generated_code.extend('from scipy.integrate import odeint \n')
   
  generated_code.extend('\n')
  generated_code.extend('def simulateModel(t0, tend, numPoints):\n')
   
  # write out compartment values 
  generated_code.extend('  \n')
  generated_code.extend('  #compartments\n')
  for i in range(mod.getNumCompartments()):
    element = mod.getCompartment(i)
    generated_code.extend('  {0} = {1}\n'.format(element.getId(), element.getSize()))
   
  # write out parameter values 
  generated_code.extend('  \n')
  generated_code.extend('  #global parameters\n')
  for i in range(mod.getNumParameters()):
    element = mod.getParameter(i)
    generated_code.extend('  {0} = {1}\n'.format(element.getId(), element.getValue()))
   
  # write out boundary species 
  generated_code.extend('  \n')
  generated_code.extend('  #boundary species\n')
  for i in range(mod.getNumSpecies()):
    element = mod.getSpecies(i)
    if element.getBoundaryCondition() == False: 
      continue
    if element.isSetInitialConcentration(): 
      generated_code.extend('  {0} = {1}\n'.format(element.getId(), element.getInitialConcentration()))
    else:
      generated_code.extend('  {0} = {1}\n'.format(element.getId(), element.getInitialAmount()))  
   
  # write derive function
  generated_code.extend('  \n')
  generated_code.extend('  def ode_fun(__Y__, t):\n')
  for i in range(len(variables.keys())): 
    generated_code.extend('    {0} = __Y__[{1}]\n'.format(variables.keys()[i], i))
  generated_code.extend('\n')
   
  for i in range(mod.getNumReactions()): 
    reaction = mod.getReaction(i)
    kinetics = reaction.getKineticLaw()  
     
    generated_code.extend('    {0} = {1}\n'.format(reaction.getId(),  kinetics.getFormula()))
     
    for j in range(reaction.getNumReactants()): 
      ref = reaction.getReactant(j)
      species = mod.getSpecies(ref.getSpecies())
      if species.getBoundaryCondition() == True: 
        continue
      if ref.getStoichiometry() == 1.0: 
        variables[species.getId()].append('-{0}'.format(reaction.getId()))
      else:
        variables[species.getId()].append('-({0})*{1}'.format(ref.getStoichiometry(), reaction.getId()))
    for j in range(reaction.getNumProducts()): 
      ref = reaction.getProduct(j)
      species = mod.getSpecies(ref.getSpecies())
      if species.getBoundaryCondition() == True: 
        continue
      if ref.getStoichiometry() == 1.0: 
        variables[species.getId()].append('{0}'.format(reaction.getId()))
      else:
        variables[species.getId()].append('({0})*{1}'.format(ref.getStoichiometry(), reaction.getId()))
   
  generated_code.extend('\n')
     
  generated_code.extend('    return array([')
  for i in range(len(variables.keys())):
    for eqn in variables[variables.keys()[i]]:
      generated_code.extend(' + ({0})'.format(eqn))
    if i + 1 < len(variables.keys()):
      generated_code.extend(',\n      ')
  generated_code.extend('    ])\n')
  generated_code.extend('\n')
   
  generated_code.extend('  time = linspace(t0, tend, numPoints)\n')
   
  # 
  # write out initial concentrations 
  # 
  generated_code.extend('  yinit= array([')
  count = 0
  for key in variables.keys():
    # get initialValue 
    element = mod.getElementBySId(key)
    if element.getTypeCode() == lb.SBML_PARAMETER: 
      generated_code.extend('{0}'.format(element.getValue()))
    elif element.getTypeCode() == lb.SBML_SPECIES: 
      if element.isSetInitialConcentration(): 
        generated_code.extend('{0}'.format(element.getInitialConcentration()))
      else: 
        generated_code.extend('{0}'.format(element.getInitialAmount()))
    else: 
      generated_code.extend('{0}'.format(element.getSize()))
    count += 1
    if count < len(variables.keys()):
      generated_code.extend(', ')
  generated_code.extend('])\n')
  generated_code.extend('  \n')
   
  generated_code.extend('  y = odeint(ode_fun, yinit, time)\n')
  generated_code.extend('\n')
   
  generated_code.extend('  return time, y\n')
  generated_code.extend('\n')
  generated_code.extend('\n')
  generated_code.extend('time, result = simulateModel({0}, {1}, {2})\n'.format(t0, tEnd, numPoints))
  generated_code.extend('\n')
   
  #
  # write out plotting code 
  #
  generated_code.extend('fig = figure()\n')
  generated_code.extend('ax = subplot(111)\n')
   
  for i in range(len(variables.keys())): 
    generated_code.extend('plot(time,result[:,{0}], label="{1}", lw=1.5)\n'.format(i, variables.keys()[i]))
     
  generated_code.extend('box = ax.get_position()\n')
  generated_code.extend('ax.set_position([box.x0, box.y0, box.width * 0.7, box.height])\n')
  generated_code.extend('xlabel("time")\n')
  generated_code.extend('ylabel("concentration")\n')
  generated_code.extend('legend(loc="center left", bbox_to_anchor=(1, 0.5))\n')
  generated_code.extend('show()\n')
   
   
  # convert generated code to string 
  result = str(generated_code);
  return simulateModel 
   
Beispiel #18
0
def flattenSBMLDocument(doc, leave_ports=True, output_path=None, suffix='_flat'):
    """ Flatten the given SBMLDocument.

    Validation should be performed before the flattening and is not part
    of the flattening routine.

    :param doc: SBMLDocument to flatten.
    :type doc: SBMLDocument
    :return:
    :rtype: SBMLDocument
    """
    Nerrors = doc.getNumErrors()
    if Nerrors > 0:
        if doc.getError(0).getErrorId() == libsbml.XMLFileUnreadable:
            # Handle case of unreadable file here.
            logging.error("SBML error in doc: libsbml.XMLFileUnreadable")
        elif doc.getError(0).getErrorId() == libsbml.XMLFileOperationError:
            # Handle case of other file error here.
            logging.error("SBML error in doc: libsbml.XMLFileOperationError")
        else:
            # Handle other error cases here.
            logging.error("SBML errors in doc, see SBMLDocument error log.")

    # converter options
    props = libsbml.ConversionProperties()
    props.addOption("flatten comp", True)  # Invokes CompFlatteningConverter
    props.addOption("leave_ports", leave_ports)  # Indicates whether to leave ports

    # flatten
    current = time.clock()
    result = doc.convert(props)
    flattened_status = (result==libsbml.LIBSBML_OPERATION_SUCCESS)

    lines = [
        '',
        '-' * 120,
        str(doc),
        "{:<25}: {}".format("flattened", str(flattened_status).upper()),
        "{:<25}: {:.3f}".format("flatten time (ms)", time.clock() - current),
        '-' * 120,
    ]
    info = "\n".join(lines)

    if flattened_status:
        logging.info(info)
    else:
        logging.error(info)
        raise ValueError("SBML could not be flattend due to errors in the SBMLDocument.")

    if suffix is not None:
        model = doc.getModel()
        if model is not None:
            model.setId(model.getId() + suffix)
            if model.isSetName():
                model.setName(model.getName() + suffix)

    if output_path is not None:
        # Write the results to the output file.
        libsbml.writeSBMLToFile(doc, output_path)
        logging.info("Flattened model written to {}".format(output_path))

    return doc
Beispiel #19
0
def flatten_sbml_doc(doc: libsbml.SBMLDocument,
                     output_path: Path = None,
                     leave_ports: bool = True) -> libsbml.SBMLDocument:
    """Flatten SBMLDocument.

    Validation should be performed before the flattening and is not part
    of the flattening routine.
    If an output path is provided the file is written to the output path.

    :param doc: SBMLDocument to flatten.
    :param output_path: Path to write flattended SBMLDocument to
    :param leave_ports: flag to leave ports

    :return: SBMLDocument
    """
    error_count = doc.getNumErrors()
    if error_count > 0:
        if doc.getError(0).getErrorId() == libsbml.XMLFileUnreadable:
            # Handle case of unreadable file here.
            logger.error("SBML error in doc: libsbml.XMLFileUnreadable")
        elif doc.getError(0).getErrorId() == libsbml.XMLFileOperationError:
            # Handle case of other file error here.
            logger.error("SBML error in doc: libsbml.XMLFileOperationError")
        else:
            # Handle other error cases here.
            logger.error("SBML errors in doc, see SBMLDocument error log.")

    # converter options
    libsbml.CompFlatteningConverter
    props = libsbml.ConversionProperties()
    props.addOption("flatten comp", True)  # Invokes CompFlatteningConverter
    props.addOption("leave_ports",
                    leave_ports)  # Indicates whether to leave ports
    props.addOption("abortIfUnflattenable", "none")

    # flatten
    current = time.perf_counter()
    result = doc.convert(props)
    flattened_status = result == libsbml.LIBSBML_OPERATION_SUCCESS

    lines = [
        "",
        "-" * 120,
        str(doc),
        "{:<25}: {}".format("flattened",
                            str(flattened_status).upper()),
        "{:<25}: {:.3f}".format("flatten time (ms)",
                                time.perf_counter() - current),
        "-" * 120,
    ]
    info = bcolors.BOLD + "\n".join(lines) + bcolors.ENDC

    if flattened_status:
        logger.info(bcolors.OKGREEN + info + bcolors.ENDC)
    else:
        logger.error(bcolors.FAIL + info + bcolors.ENDC)
        raise ValueError(
            "SBML could not be flattend due to errors in the SBMLDocument.")

    if output_path is not None:
        write_sbml(doc, filepath=output_path)
        logger.info(f"Flattened model created: '{output_path}'")

    return doc
Beispiel #20
0
    def convert(self, level=(3, 2)):
        """
        Convert the PySB model to a libSBML document

        Requires the libsbml python package

        Parameters
        ----------
        level: (int, int)
            The SBML level and version to use. The default is SBML level 3, version 2. Conversion
            to other levels/versions may not be possible or may lose fidelity.

        Returns
        -------
        libsbml.SBMLDocument
            A libSBML document converted form the PySB model
        """
        doc = libsbml.SBMLDocument(3, 2)
        smodel = doc.createModel()
        _check(smodel)
        _check(smodel.setName(self.model.name))

        pysb.bng.generate_equations(self.model)

        # Docstring
        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)
            _check(smodel.setNotes(notes_str))

        # Compartments
        if self.model.compartments:
            for cpt in self.model.compartments:
                c = smodel.createCompartment()
                _check(c)
                _check(c.setId(cpt.name))
                _check(c.setSpatialDimensions(cpt.dimension))
                _check(c.setSize(cpt.size.value))
                _check(c.setConstant(True))
        else:
            c = smodel.createCompartment()
            _check(c)
            _check(c.setId('default'))
            _check(c.setSpatialDimensions(3))
            _check(c.setSize(1))
            _check(c.setConstant(True))

        # Expressions
        for i, expr in enumerate(self.model.expressions):
            # create an observable "parameter"
            e = smodel.createParameter()
            _check(e)
            _check(e.setId(expr.name))
            _check(e.setName(expr.name))
            _check(e.setConstant(False))

            # create an assignment rule which assigns the expression to the parameter
            expr_rule = smodel.createAssignmentRule()

            _check(expr_rule)
            _check(expr_rule.setVariable(e.getId()))

            expr_mathml = self._sympy_to_sbmlast(
                expr.expand_expr(expand_observables=True))
            _check(expr_rule.setMath(expr_mathml))

        # Initial values/assignments
        fixed_species_idx = set()
        initial_species_idx = set()
        for ic in self.model.initials:
            sp_idx = self.model.get_species_index(ic.pattern)
            ia = smodel.createInitialAssignment()
            _check(ia)
            _check(ia.setSymbol('__s{}'.format(sp_idx)))
            init_mathml = self._sympy_to_sbmlast(Symbol(ic.value.name))
            _check(ia.setMath(init_mathml))
            initial_species_idx.add(sp_idx)

            if ic.fixed:
                fixed_species_idx.add(sp_idx)

        # Species
        for i, s in enumerate(self.model.species):
            sp = smodel.createSpecies()
            _check(sp)
            _check(sp.setId('__s{}'.format(i)))
            if self.model.compartments:
                # Try to determine compartment, which must be unique for the species
                mon_cpt = set(mp.compartment for mp in s.monomer_patterns
                              if mp.compartment is not None)
                if len(mon_cpt) == 0 and s.compartment:
                    compartment_name = s.compartment_name
                elif len(mon_cpt) == 1:
                    mon_cpt = mon_cpt.pop()
                    if s.compartment is not None and mon_cpt != s.compartment:
                        raise ValueError(
                            'Species {} has different monomer and species compartments, '
                            'which is not supported in SBML'.format(s))
                    compartment_name = mon_cpt.name
                else:
                    raise ValueError(
                        'Species {} has more than one different monomer compartment, '
                        'which is not supported in SBML'.format(s))
            else:
                compartment_name = 'default'
            _check(sp.setCompartment(compartment_name))
            _check(sp.setName(str(s).replace('% ', '._br_')))
            _check(sp.setBoundaryCondition(i in fixed_species_idx))
            _check(sp.setConstant(False))
            _check(sp.setHasOnlySubstanceUnits(True))
            if i not in initial_species_idx:
                _check(sp.setInitialAmount(0.0))

        # Parameters

        for i, param in enumerate(self.model.parameters):
            p = smodel.createParameter()
            _check(p)
            _check(p.setId(param.name))
            _check(p.setName(param.name))
            _check(p.setValue(param.value))
            _check(p.setConstant(True))

        # Reactions
        for i, reaction in enumerate(self.model.reactions_bidirectional):
            rxn = smodel.createReaction()
            _check(rxn)
            _check(rxn.setId('r{}'.format(i)))
            _check(rxn.setName(' + '.join(reaction['rule'])))
            _check(rxn.setReversible(reaction['reversible']))

            for sp in reaction['reactants']:
                reac = rxn.createReactant()
                _check(reac)
                _check(reac.setSpecies('__s{}'.format(sp)))
                _check(reac.setConstant(True))

            for sp in reaction['products']:
                prd = rxn.createProduct()
                _check(prd)
                _check(prd.setSpecies('__s{}'.format(sp)))
                _check(prd.setConstant(True))

            for symbol in reaction['rate'].free_symbols:
                if isinstance(symbol, pysb.Expression):
                    expr = symbol.expand_expr(expand_observables=True)
                    for sym in expr.free_symbols:
                        if not isinstance(sym,
                                          (pysb.Parameter, pysb.Expression)):
                            # Species reference, needs to be specified as modifier
                            modifier = rxn.createModifier()
                            _check(modifier)
                            _check(modifier.setSpecies(str(sym)))

            rate = rxn.createKineticLaw()
            _check(rate)
            rate_mathml = self._sympy_to_sbmlast(reaction['rate'])
            _check(rate.setMath(rate_mathml))

        # Observables
        for i, observable in enumerate(self.model.observables):
            # create an observable "parameter"
            obs = smodel.createParameter()
            _check(obs)
            _check(obs.setId('__obs{}'.format(i)))
            _check(obs.setName(observable.name))
            _check(obs.setConstant(False))

            # create an assignment rule which assigns the observable expression to the parameter
            obs_rule = smodel.createAssignmentRule()

            _check(obs_rule)
            _check(obs_rule.setVariable(obs.getId()))

            obs_mathml = self._sympy_to_sbmlast(observable.expand_obs())
            _check(obs_rule.setMath(obs_mathml))

        # Apply any requested level/version conversion
        if level != (3, 2):
            prop = libsbml.ConversionProperties(libsbml.SBMLNamespaces(*level))
            prop.addOption('strict', False)
            prop.addOption('setLevelAndVersion', True)
            prop.addOption('ignorePackages', True)
            _check(doc.convert(prop))

        return doc
Beispiel #21
0
def read_sbml_ec_model(
    filename: str,
    number: float = float,
    # re.Pattern does not exist in py36 so this type hint cannot be added now
    f_replace=F_REPLACE,
    set_missing_bounds: bool = False,
    hardcoded_rev_reactions: bool = True,
    **kwargs,
) -> Model:
    """Create `geckopy.Model` from SBMLDocument.

    Parameters
    ----------
    filename: str
    number: data type of stoichiometry: {float, int}
        In which data type should the stoichiometry be parsed.
    f_replace : dict of replacement functions for id replacement
    set_missing_bounds : flag to set missing bounds
    hardcoded_rev_reactions: bool
        if reversible reaction to account for proteins being consumed on both
        directions are written explicitly for in the SBML

    Returns
    -------
    cobra.core.Model

    """
    try:
        fsanitized = str(filename) if isinstance(filename, Path) else filename
        doc = _get_doc_from_filename(fsanitized)
    except IOError as e:
        raise e
    except Exception as original_error:
        raise CobraSBMLError(
            "Something went wrong reading the SBML model. Most likely the SBML"
            " model is not valid. Please check that your model is valid using "
            "the `cobra.io.sbml.validate_sbml_model` function or via the "
            "online validator at http://sbml.org/validator .\n"
            "\t`(model, errors) = validate_sbml_model(filename)`"
            "\nIf the model is valid and cannot be read please open an issue "
            f"at https://github.com/opencobra/cobrapy/issues: {original_error}"
        )

    if f_replace is None:
        f_replace = {}

    # SBML model
    model: libsbml.Model = doc.getModel()
    if model is None:
        raise CobraSBMLError("No SBML model detected in file.")
    model_fbc: libsbml.FbcModelPlugin = model.getPlugin("fbc")

    if not model_fbc:
        LOGGER.warning("Model does not contain SBML fbc package information.")
    else:
        if not model_fbc.isSetStrict():
            LOGGER.warning('Loading SBML model without fbc:strict="true"')

        # fbc-v1 (legacy)
        doc_fbc = doc.getPlugin("fbc")  # type: libsbml.FbcSBMLDocumentPlugin
        fbc_version = doc_fbc.getPackageVersion()

        if fbc_version == 1:
            LOGGER.warning("Loading SBML with fbc-v1 (models should be encoded"
                           " using fbc-v2)")
            conversion_properties = libsbml.ConversionProperties()
            conversion_properties.addOption("convert fbc v1 to fbc v2", True,
                                            "Convert FBC-v1 model to FBC-v2")
            result = doc.convert(conversion_properties)
            if result != libsbml.LIBSBML_OPERATION_SUCCESS:
                raise Exception("Conversion of SBML fbc v1 to fbc v2 failed")

    # Model
    model_id = model.getIdAttribute()
    if not libsbml.SyntaxChecker.isValidSBMLSId(model_id):
        LOGGER.error("'%s' is not a valid SBML 'SId'." % model_id)
    geckopy_model = Model(model_id,
                          hardcoded_rev_reactions=hardcoded_rev_reactions)
    geckopy_model.name = model.getName()

    # meta information
    meta = {
        "model.id": model_id,
        "level": model.getLevel(),
        "version": model.getVersion(),
        "packages": [],
    }
    # History
    creators = []
    created = None
    if model.isSetModelHistory():
        history = model.getModelHistory()  # type: libsbml.ModelHistory

        if history.isSetCreatedDate():
            created = history.getCreatedDate()

        for c in history.getListCreators():  # type: libsbml.ModelCreator
            creators.append({
                "familyName":
                c.getFamilyName() if c.isSetFamilyName() else None,
                "givenName":
                c.getGivenName() if c.isSetGivenName() else None,
                "organisation":
                c.getOrganisation() if c.isSetOrganisation() else None,
                "email":
                c.getEmail() if c.isSetEmail() else None,
            })

    meta["creators"] = creators
    meta["created"] = created
    meta["notes"] = _parse_notes_dict(doc)
    meta["annotation"] = _parse_annotations(doc)

    info = "<{}> SBML L{}V{}".format(model_id, model.getLevel(),
                                     model.getVersion())
    packages = {}
    for k in range(doc.getNumPlugins()):
        plugin = doc.getPlugin(k)  # type:libsbml.SBasePlugin
        key, value = plugin.getPackageName(), plugin.getPackageVersion()
        packages[key] = value
        info += ", {}-v{}".format(key, value)
        if key not in ["fbc", "groups", "l3v2extendedmath"]:
            LOGGER.warning(
                "SBML package '%s' not supported by cobrapy, "
                "information is not parsed",
                key,
            )
    meta["info"] = info
    meta["packages"] = packages
    geckopy_model._sbml = meta

    # notes and annotations
    geckopy_model.notes = _parse_notes_dict(model)
    geckopy_model.annotation = _parse_annotations(model)

    # Compartments
    # FIXME: update with new compartments
    compartments = {}
    for (compartment) in model.getListOfCompartments(
    ):  # noqa: E501 type: libsbml.Compartment
        cid = _check_required(compartment, compartment.getIdAttribute(), "id")
        compartments[cid] = compartment.getName()
    geckopy_model.compartments = compartments

    # Species
    metabolites = []
    # proteins that rely on the naming convention "prot_UNIPROT_ID" will be
    # catched here. Those who are annotated by groups membership will be parsed
    # after the groups are processed.
    proteins = []
    boundary_metabolites = []
    if model.getNumSpecies() == 0:
        LOGGER.warning("No metabolites in model")

    for specie in model.getListOfSpecies():  # type: libsbml.Species
        sid = _check_required(specie, specie.getIdAttribute(), "id")
        if f_replace and F_SPECIE in f_replace:
            sid = f_replace[F_SPECIE](sid)

        met = Metabolite(sid)
        met.name = specie.getName()
        met.notes = _parse_notes_dict(specie)
        met.annotation = _parse_annotations(specie)
        met.compartment = specie.getCompartment()
        initial_amount = specie.getInitialAmount()

        specie_fbc = specie.getPlugin("fbc")  # type: libsbml.FbcSpeciesPlugin
        if specie_fbc:
            met.charge = specie_fbc.getCharge()
            met.formula = specie_fbc.getChemicalFormula()
        else:
            if specie.isSetCharge():
                LOGGER.warning(
                    "Use of the species charge attribute is "
                    "discouraged, use fbc:charge "
                    "instead: %s",
                    specie,
                )
                met.charge = specie.getCharge()
            else:
                if "CHARGE" in met.notes:
                    LOGGER.warning(
                        "Use of CHARGE in the notes element is "
                        "discouraged, use fbc:charge "
                        "instead: %s",
                        specie,
                    )
                    try:
                        met.charge = int(met.notes["CHARGE"])
                    except ValueError:
                        # handle nan, na, NA, ...
                        pass

            if "FORMULA" in met.notes:
                LOGGER.warning(
                    "Use of FORMULA in the notes element is "
                    "discouraged, use fbc:chemicalFormula "
                    "instead: %s",
                    specie,
                )
                met.formula = met.notes["FORMULA"]

        # Detect boundary metabolites
        if specie.getBoundaryCondition() is True:
            boundary_metabolites.append(met)

        if not PROT_PATTERN.match(met.id):
            metabolites.append(met)
        else:
            proteins.append(Protein(met, concentration=initial_amount))

    geckopy_model.add_metabolites(metabolites)
    geckopy_model.add_proteins(proteins)

    # Add exchange reactions for boundary metabolites
    ex_reactions = []
    for met in boundary_metabolites:
        ex_rid = "EX_{}".format(met.id)
        ex_reaction = Reaction(ex_rid)
        ex_reaction.name = ex_rid
        ex_reaction.annotation = {"sbo": SBO_EXCHANGE_REACTION}
        ex_reaction.lower_bound = config.lower_bound
        ex_reaction.upper_bound = config.upper_bound
        LOGGER.warning("Adding exchange reaction %s with default bounds "
                       "for boundary metabolite: %s." %
                       (ex_reaction.id, met.id))
        # species is reactant
        ex_reaction.add_metabolites({met: -1})
        ex_reactions.append(ex_reaction)
    geckopy_model.add_reactions(ex_reactions)

    # Genes
    if model_fbc:
        for (gp) in model_fbc.getListOfGeneProducts(
        ):  # noqa: E501 type: libsbml.GeneProduct
            gid = _check_required(gp, gp.getIdAttribute(), "id")
            if f_replace and F_GENE in f_replace:
                gid = f_replace[F_GENE](gid)
            cobra_gene = Gene(gid)
            cobra_gene.name = gp.getName()
            if cobra_gene.name is None:
                cobra_gene.name = gid
            cobra_gene.annotation = _parse_annotations(gp)
            cobra_gene.notes = _parse_notes_dict(gp)

            geckopy_model.genes.append(cobra_gene)
    else:
        for (cobra_reaction) in model.getListOfReactions(
        ):  # noqa: E501 type: libsbml.Reaction
            # fallback to notes information
            notes = _parse_notes_dict(cobra_reaction)
            if "GENE ASSOCIATION" in notes:
                gpr = notes["GENE ASSOCIATION"]
            elif "GENE_ASSOCIATION" in notes:
                gpr = notes["GENE_ASSOCIATION"]
            else:
                gpr = ""

            if len(gpr) > 0:
                gpr = gpr.replace("(", ";")
                gpr = gpr.replace(")", ";")
                gpr = gpr.replace("or", ";")
                gpr = gpr.replace("and", ";")
                # Interaction of the above replacements can lead to multiple
                # ;, which results in empty gids
                gids = [t.strip() for t in gpr.split(";")]
                gids = set(gids).difference({""})

                # create missing genes
                for gid in gids:
                    if f_replace and F_GENE in f_replace:
                        gid = f_replace[F_GENE](gid)

                    if gid not in geckopy_model.genes:
                        cobra_gene = Gene(gid)
                        cobra_gene.name = gid
                        geckopy_model.genes.append(cobra_gene)

    # GPR rules
    def process_association(ass):
        """Recursively convert gpr association to a gpr string.

        Defined as inline functions to not pass the replacement dict around.
        """
        if ass.isFbcOr():
            return " ".join([
                "(",
                " or ".join(
                    process_association(c)
                    for c in ass.getListOfAssociations()),
                ")",
            ])
        elif ass.isFbcAnd():
            return " ".join([
                "(",
                " and ".join(
                    process_association(c)
                    for c in ass.getListOfAssociations()),
                ")",
            ])
        elif ass.isGeneProductRef():
            gid = ass.getGeneProduct()
            if f_replace and F_GENE in f_replace:
                return f_replace[F_GENE](gid)
            else:
                return gid

    # Reactions
    missing_bounds = False
    reactions = []
    if model.getNumReactions() == 0:
        LOGGER.warning("No reactions in model")

    for reaction in model.getListOfReactions():  # type: libsbml.Reaction
        rid = _check_required(reaction, reaction.getIdAttribute(), "id")
        # proteins are parsed based on Species, prot exchanges are ignored
        if PROT_EX_PATTERN.search(rid):
            continue
        if f_replace and F_REACTION in f_replace:
            rid = f_replace[F_REACTION](rid)
        cobra_reaction = Reaction(rid)
        cobra_reaction.name = reaction.getName()
        cobra_reaction.annotation = _parse_annotations(reaction)
        cobra_reaction.notes = _parse_notes_dict(reaction)

        # set bounds
        p_ub, p_lb = None, None
        r_fbc = reaction.getPlugin("fbc")  # type: libsbml.FbcReactionPlugin
        if r_fbc:
            # bounds in fbc
            lb_id = r_fbc.getLowerFluxBound()
            if lb_id:
                p_lb = model.getParameter(lb_id)  # type: libsbml.Parameter
                if p_lb and p_lb.getConstant() and (p_lb.getValue()
                                                    is not None):
                    cobra_reaction.lower_bound = p_lb.getValue()
                else:
                    raise CobraSBMLError("No constant bound '%s' for "
                                         "reaction: %s" % (p_lb, reaction))

            ub_id = r_fbc.getUpperFluxBound()
            if ub_id:
                p_ub = model.getParameter(ub_id)  # type: libsbml.Parameter
                if p_ub and p_ub.getConstant() and (p_ub.getValue()
                                                    is not None):
                    cobra_reaction.upper_bound = p_ub.getValue()
                else:
                    raise CobraSBMLError("No constant bound '%s' for "
                                         "reaction: %s" % (p_ub, reaction))

        elif reaction.isSetKineticLaw():
            # some legacy models encode bounds in kinetic laws
            klaw = reaction.getKineticLaw()  # type: libsbml.KineticLaw
            p_lb = klaw.getParameter(
                "LOWER_BOUND")  # noqa: E501 type: libsbml.LocalParameter
            if p_lb:
                cobra_reaction.lower_bound = p_lb.getValue()
            p_ub = klaw.getParameter(
                "UPPER_BOUND")  # noqa: E501 type: libsbml.LocalParameter
            if p_ub:
                cobra_reaction.upper_bound = p_ub.getValue()

            if p_ub is not None or p_lb is not None:
                LOGGER.warning(
                    "Encoding LOWER_BOUND and UPPER_BOUND in "
                    "KineticLaw is discouraged, "
                    "use fbc:fluxBounds instead: %s",
                    reaction,
                )

        if p_lb is None:
            missing_bounds = True
            lower_bound = config.lower_bound
            cobra_reaction.lower_bound = lower_bound
            LOGGER.warning(
                "Missing lower flux bound set to '%s' for "
                " reaction: '%s'",
                lower_bound,
                reaction,
            )

        if p_ub is None:
            missing_bounds = True
            upper_bound = config.upper_bound
            cobra_reaction.upper_bound = upper_bound
            LOGGER.warning(
                "Missing upper flux bound set to '%s' for "
                " reaction: '%s'",
                upper_bound,
                reaction,
            )

        # add reaction
        reactions.append(cobra_reaction)

        # parse equation
        stoichiometry = defaultdict(lambda: 0)
        for (sref) in reaction.getListOfReactants(
        ):  # noqa: E501 type: libsbml.SpeciesReference
            sid = _check_required(sref, sref.getSpecies(), "species")

            if f_replace and F_SPECIE in f_replace:
                sid = f_replace[F_SPECIE](sid)
            stoichiometry[sid] -= number(
                _check_required(sref, sref.getStoichiometry(),
                                "stoichiometry"))

        for (sref) in reaction.getListOfProducts(
        ):  # noqa: E501 type: libsbml.SpeciesReference
            sid = _check_required(sref, sref.getSpecies(), "species")

            if f_replace and F_SPECIE in f_replace:
                sid = f_replace[F_SPECIE](sid)
            stoichiometry[sid] += number(
                _check_required(sref, sref.getStoichiometry(),
                                "stoichiometry"))

        # convert to metabolite objects
        object_stoichiometry = {}
        for met_id in stoichiometry:
            target_set = (geckopy_model.proteins
                          if met_id in geckopy_model.proteins else
                          geckopy_model.metabolites)
            metabolite = target_set.get_by_id(met_id)
            object_stoichiometry[metabolite] = stoichiometry[met_id]
        cobra_reaction.add_metabolites(object_stoichiometry)

        # GPR
        if r_fbc:
            gpr = ""
            gpa = (r_fbc.getGeneProductAssociation()
                   )  # noqa: E501 type: libsbml.GeneProductAssociation
            if gpa is not None:
                association = (gpa.getAssociation()
                               )  # noqa: E501 type: libsbml.FbcAssociation
                gpr = process_association(association)
        else:
            # fallback to notes information
            notes = cobra_reaction.notes
            if "GENE ASSOCIATION" in notes:
                gpr = notes["GENE ASSOCIATION"]
            elif "GENE_ASSOCIATION" in notes:
                gpr = notes["GENE_ASSOCIATION"]
            else:
                gpr = ""

            if len(gpr) > 0:
                LOGGER.warning(
                    "Use of GENE ASSOCIATION or GENE_ASSOCIATION "
                    "in the notes element is discouraged, use "
                    "fbc:gpr instead: %s",
                    reaction,
                )
                if f_replace and F_GENE in f_replace:
                    gpr = " ".join(f_replace[F_GENE](t)
                                   for t in gpr.split(" "))

        # remove outside parenthesis, if any
        if gpr.startswith("(") and gpr.endswith(")"):
            try:
                parse_gpr(gpr[1:-1].strip())
                gpr = gpr[1:-1].strip()
            except (SyntaxError, TypeError) as e:
                LOGGER.warning(
                    f"Removing parenthesis from gpr {gpr} leads to "
                    f"an error, so keeping parenthesis, error: {e}", )

        cobra_reaction.gene_reaction_rule = gpr

    geckopy_model.add_reactions(reactions)

    # Objective
    obj_direction = "max"
    coefficients = {}
    if model_fbc:
        obj_list = (model_fbc.getListOfObjectives()
                    )  # noqa: E501 type: libsbml.ListOfObjectives
        if obj_list is None:
            LOGGER.warning("listOfObjectives element not found")
        elif obj_list.size() == 0:
            LOGGER.warning("No objective in listOfObjectives")
        elif not obj_list.getActiveObjective():
            LOGGER.warning("No active objective in listOfObjectives")
        else:
            obj_id = obj_list.getActiveObjective()
            obj = model_fbc.getObjective(obj_id)  # type: libsbml.Objective
            obj_direction = LONG_SHORT_DIRECTION[obj.getType()]

            for (flux_obj) in (obj.getListOfFluxObjectives()
                               ):  # noqa: E501 type: libsbml.FluxObjective
                rid = flux_obj.getReaction()
                if f_replace and F_REACTION in f_replace:
                    rid = f_replace[F_REACTION](rid)
                try:
                    objective_reaction = geckopy_model.reactions.get_by_id(rid)
                except KeyError:
                    raise CobraSBMLError("Objective reaction '%s' "
                                         "not found" % rid)
                try:
                    coefficients[objective_reaction] = number(
                        flux_obj.getCoefficient())
                except ValueError as e:
                    LOGGER.warning(str(e))
    else:
        # some legacy models encode objective coefficients in kinetic laws
        for reaction in model.getListOfReactions():  # type: libsbml.Reaction
            if reaction.isSetKineticLaw():
                klaw = reaction.getKineticLaw()  # type: libsbml.KineticLaw
                p_oc = klaw.getParameter(
                    "OBJECTIVE_COEFFICIENT")  # type: libsbml.LocalParameter
                if p_oc:
                    rid = _check_required(reaction, reaction.getIdAttribute(),
                                          "id")
                    if f_replace and F_REACTION in f_replace:
                        rid = f_replace[F_REACTION](rid)
                    try:
                        objective_reaction = geckopy_model.reactions.get_by_id(
                            rid)
                    except KeyError:
                        raise CobraSBMLError(
                            "Objective reaction '%s' "
                            "not found", rid)
                    try:
                        coefficients[objective_reaction] = number(
                            p_oc.getValue())
                    except ValueError as e:
                        LOGGER.warning(str(e))

                    LOGGER.warning(
                        "Encoding OBJECTIVE_COEFFICIENT in "
                        "KineticLaw is discouraged, "
                        "use fbc:fluxObjective "
                        "instead: %s",
                        reaction,
                    )

    if len(coefficients) == 0:
        LOGGER.error("No objective coefficients in model. Unclear what should "
                     "be optimized")
    set_objective(geckopy_model, coefficients)
    geckopy_model.solver.objective.direction = obj_direction

    # parse groups
    model_groups = model.getPlugin("groups")  # type: libsbml.GroupsModelPlugin
    groups = []
    if model_groups:
        # calculate hashmaps to lookup objects in O(1)
        sid_map = {}
        metaid_map = {}
        for obj_list in [
                model.getListOfCompartments(),
                model.getListOfSpecies(),
                model.getListOfReactions(),
                model_groups.getListOfGroups(),
        ]:

            for sbase in obj_list:  # type: libsbml.SBase
                if sbase.isSetId():
                    sid_map[sbase.getIdAttribute()] = sbase
                if sbase.isSetMetaId():
                    metaid_map[sbase.getMetaId()] = sbase

        # create groups
        for group in model_groups.getListOfGroups():  # type: libsbml.Group
            gid = _check_required(group, group.getIdAttribute(), "id")
            if f_replace and F_GROUP in f_replace:
                gid = f_replace[F_GROUP](gid)
            cobra_group = Group(gid)
            cobra_group.name = group.getName()
            if group.isSetKind():
                cobra_group.kind = group.getKindAsString()
            cobra_group.annotation = _parse_annotations(group)
            cobra_group.notes = _parse_notes_dict(group)

            cobra_members = []
            for member in group.getListOfMembers():  # type: libsbml.Member
                if member.isSetIdRef():
                    obj = sid_map[member.getIdRef()]
                elif member.isSetMetaIdRef():
                    obj = metaid_map[member.getMetaIdRef()]

                typecode = obj.getTypeCode()
                obj_id = _check_required(obj, obj.getIdAttribute(), "id")

                # id replacements
                cobra_member = None
                if typecode == libsbml.SBML_SPECIES:
                    if f_replace and F_SPECIE in f_replace:
                        obj_id = f_replace[F_SPECIE](obj_id)
                    try:
                        cobra_member = geckopy_model.metabolites.get_by_id(
                            obj_id)
                    except KeyError:
                        cobra_member = geckopy_model.proteins.get_by_id(obj_id)
                elif typecode == libsbml.SBML_REACTION:
                    if f_replace and F_REACTION in f_replace:
                        obj_id = f_replace[F_REACTION](obj_id)
                    cobra_member = geckopy_model.reactions.get_by_id(obj_id)
                elif typecode == libsbml.SBML_FBC_GENEPRODUCT:
                    if f_replace and F_GENE in f_replace:
                        obj_id = f_replace[F_GENE](obj_id)
                    cobra_member = geckopy_model.genes.get_by_id(obj_id)
                else:
                    LOGGER.warning("Member %s could not be added to group %s."
                                   "unsupported type code: "
                                   "%s" % (member, group, typecode))

                if cobra_member:
                    cobra_members.append(cobra_member)

            cobra_group.add_members(cobra_members)
            groups.append(cobra_group)
    else:
        # parse deprecated subsystems on reactions
        groups_dict = {}
        for cobra_reaction in geckopy_model.reactions:
            if "SUBSYSTEM" in cobra_reaction.notes:
                g_name = cobra_reaction.notes["SUBSYSTEM"]
                if g_name in groups_dict:
                    groups_dict[g_name].append(cobra_reaction)
                else:
                    groups_dict[g_name] = [cobra_reaction]

        for gid, cobra_members in groups_dict.items():
            if f_replace and F_GROUP in f_replace:
                gid = f_replace[F_GROUP](gid)
            cobra_group = Group(gid, name=gid, kind="collection")
            cobra_group.add_members(cobra_members)
            groups.append(cobra_group)

    geckopy_model.add_groups(groups)

    # now add everything under group Proteins to model.proteins if it was not
    # already added based on naming conventions
    if geckopy_model.groups.query("Protein"):
        g_proteins = geckopy_model.groups.Protein.members.copy()
        g_proteins = {
            prot: {reac: reac.metabolites[prot]
                   for reac in prot.reactions}
            for prot in g_proteins if prot not in geckopy_model.proteins
        }

        if g_proteins:
            geckopy_model.remove_metabolites(g_proteins.keys())
            geckopy_model.add_proteins([Protein(prot) for prot in g_proteins])
            for prot, reactions in g_proteins.items():
                for reac, stoich in reactions.items():
                    # reverse the (negative) stoichiometry coefficient to kcat
                    # we expect that Proteins that are identified only by their
                    # group are respecting the specification and do form part
                    # of reactions
                    # TODO: provide options to tune this behvior
                    reac.add_protein(prot.id, -1 / (stoich * 3600))

    # general hint for missing flux bounds
    if missing_bounds:
        LOGGER.warning(
            "Missing flux bounds on reactions set to default bounds."
            "As best practise and to avoid confusion flux bounds "
            "should be set explicitly on all reactions.")

    return geckopy_model