def add_reaction_data(f, reaction_number, reaction, rev=False): for (m_id, st) in get_reactants(reaction, True): if m_id in m_id2i: f.write("%d,%d,%d\n" % (m_id2i[m_id], reaction_number, st if rev else -st)) for (m_id, st) in get_products(reaction, True): if m_id in m_id2i: f.write("%d,%d,%d\n" % (m_id2i[m_id], reaction_number, -st if rev else st))
def get_full_id2mask(r_id2mask, model): id2mask = defaultdict(lambda: 0) for r_id, mask in r_id2mask.items(): r = model.getReaction(r_id) if r: id2mask[r_id] |= mask id2mask.update({c_id: id2mask[c_id] | mask for c_id in get_r_comps(r_id, model)}) id2mask.update({s_id: id2mask[s_id] | mask for s_id in get_reactants(r)}) id2mask.update({s_id: id2mask[s_id] | mask for s_id in get_products(r)}) return id2mask
def model2stoichiometric_matrix(model, s_id2i, r_id2i): rows, cols, data = [], [], [] for r in model.getListOfReactions(): cols.extend([r_id2i[r.getId()]] * (r.getNumReactants() + r.getNumProducts())) for s_id, st in get_reactants(r, stoichiometry=True): rows.append(s_id2i[s_id]) data.append(-st) for s_id, st in get_products(r, stoichiometry=True): rows.append(s_id2i[s_id]) data.append(st) return csr_matrix((np.array(data), (np.array(rows), np.array(cols))), shape=(len(s_id2i), len(r_id2i))).toarray()
def get_exchange_reactions(model): result = [] for r in model.getListOfReactions(): rs, ps = set(get_reactants(r)), set(get_products(r)) boundary_s_ids = {s_id for s_id in rs if model.getSpecies(s_id).getBoundaryCondition()} if boundary_s_ids or not rs: result.append(r.getId()) continue boundary_s_ids = {s_id for s_id in ps if model.getSpecies(s_id).getBoundaryCondition()} if boundary_s_ids or not ps: result.append(r.getId()) return result
def is_reactant(model, t_id, r, s_id2clu, s_id2term_id, ubiquitous_chebi_ids): ubiquitous_reactants, ubiquitous_products, specific_reactant_classes, specific_product_classes = \ get_key_elements(model, r, s_id2clu, s_id2term_id, ubiquitous_chebi_ids) if r.getReversible() and need_to_reverse( ubiquitous_reactants, ubiquitous_products, specific_reactant_classes, specific_product_classes): return t_id in { s_id2term_id[s_id] if s_id in s_id2term_id else s_id for s_id in get_products(r) } else: return t_id in { s_id2term_id[s_id] if s_id in s_id2term_id else s_id for s_id in get_reactants(r) }
def constraint_exchange_reactions(model, forsed_r_id2rev, prohibited_r_id2rev=None, cofactors=None, min_flux=0.01): logging.info("Constraining input reactions...") for r in model.getListOfReactions(): r_id = r.getId() r_l, r_u = get_bounds(r) if forsed_r_id2rev and r_id in forsed_r_id2rev: rev = forsed_r_id2rev[r_id] if rev: # reverse the reaction and set positive bounds, # as if both bounds are negative, the glp solver produces an error reverse_reaction(r) set_bounds(r, max(min_flux, -r_u), max(min_flux, -r_l)) forsed_r_id2rev[r_id] = not rev else: set_bounds(r, max(min_flux, r_l), max(min_flux, r_u)) r.setReversible(False) continue if prohibited_r_id2rev and r_id in prohibited_r_id2rev: rev = prohibited_r_id2rev[r_id] if not rev: reverse_reaction(r) set_bounds(r, 0, max(0, -r_l)) prohibited_r_id2rev[r_id] = not rev else: set_bounds(r, 0, max(0, r_u)) r.setReversible(False) continue if not cofactors: continue rs, ps = set(get_reactants(r)), set(get_products(r)) boundary_s_ids = {s_id for s_id in rs if model.getSpecies(s_id).getBoundaryCondition()} if boundary_s_ids or not rs: if ps - cofactors: reverse_reaction(r) set_bounds(r, 0, max(-r_l, 0)) r.setReversible(False) continue boundary_s_ids = {s_id for s_id in ps if model.getSpecies(s_id).getBoundaryCondition()} if boundary_s_ids or not ps: if rs - cofactors: set_bounds(r, 0, max(r_u, 0)) r.setReversible(False)
def get_key_elements(model, r, s_id2clu, s_id2term_id, ubiquitous_chebi_ids, ignore_ch_ids=get_proton_ch_ids()): """ Gets elements that compose a reaction key: ubiquitous_reactants, ubiquitous_products, specific_reactant_classes, specific_product_classes :param model: libsbml.Model :param r: libsbml.Reaction reaction of interest :param s_id2clu: dict {metabolite_id: (compartment_id, cluster)} :param s_id2term_id: dict {metabolite_id: ChEBI_term_id} :param ubiquitous_chebi_ids: set of ubiquitous ChEBI_ids :param ignore_ch_ids: set of ChEBI_ids to be excluded from the result (by default protons) if there is anything else in the result :return: tuple (ubiquitous_reactants, ubiquitous_products, specific_reactant_classes, specific_product_classes) """ def classify(s_ids): specific, ubiquitous, ignored_ubs = [], [], [] for s_id in s_ids: c_id = model.getSpecies(s_id).getCompartment() if ubiquitous_chebi_ids and s_id in s_id2term_id and s_id2term_id[ s_id] in ubiquitous_chebi_ids: if s_id2term_id[s_id] in ignore_ch_ids: ignored_ubs.append((s_id2term_id[s_id], c_id)) else: ubiquitous.append((s_id2term_id[s_id], c_id)) else: specific.append((s_id2clu[s_id][1] if s_id in s_id2clu else (( s_id2term_id[s_id] if s_id in s_id2term_id else s_id), ), c_id)) transform = lambda collection: tuple(sorted(collection)) return transform(specific), transform(ubiquitous), transform( ignored_ubs) specific_reactant_classes, ubiquitous_reactants, ignored_reactants = classify( get_reactants(r)) specific_product_classes, ubiquitous_products, ignored_products = classify( get_products(r)) if not ubiquitous_reactants and not ubiquitous_products \ and not specific_reactant_classes and not specific_product_classes: ubiquitous_reactants, ubiquitous_products = ignored_reactants, ignored_products return ubiquitous_reactants, ubiquitous_products, specific_reactant_classes, specific_product_classes
def get_key_elements(model, r, s_id2clu, s_id2term_id, ubiquitous_chebi_ids, ignore_ch_ids=get_proton_ch_ids()): """ Gets elements that compose a reaction key: ubiquitous_reactants, ubiquitous_products, specific_reactant_classes, specific_product_classes :param model: libsbml.Model :param r: libsbml.Reaction reaction of interest :param s_id2clu: dict {metabolite_id: (compartment_id, cluster)} :param s_id2term_id: dict {metabolite_id: ChEBI_term_id} :param ubiquitous_chebi_ids: set of ubiquitous ChEBI_ids :param ignore_ch_ids: set of ChEBI_ids to be excluded from the result (by default protons) if there is anything else in the result :return: tuple (ubiquitous_reactants, ubiquitous_products, specific_reactant_classes, specific_product_classes) """ def classify(s_ids): specific, ubiquitous, ignored_ubs = [], [], [] for s_id in s_ids: c_id = model.getSpecies(s_id).getCompartment() if ubiquitous_chebi_ids and s_id in s_id2term_id and s_id2term_id[s_id] in ubiquitous_chebi_ids: if s_id2term_id[s_id] in ignore_ch_ids: ignored_ubs.append((s_id2term_id[s_id], c_id)) else: ubiquitous.append((s_id2term_id[s_id], c_id)) else: specific.append((s_id2clu[s_id][1] if s_id in s_id2clu else ((s_id2term_id[s_id] if s_id in s_id2term_id else s_id), ), c_id)) transform = lambda collection: tuple(sorted(collection)) return transform(specific), transform(ubiquitous), transform(ignored_ubs) specific_reactant_classes, ubiquitous_reactants, ignored_reactants = classify(get_reactants(r)) specific_product_classes, ubiquitous_products, ignored_products = classify(get_products(r)) if not ubiquitous_reactants and not ubiquitous_products \ and not specific_reactant_classes and not specific_product_classes: ubiquitous_reactants, ubiquitous_products = ignored_reactants, ignored_products return ubiquitous_reactants, ubiquitous_products, specific_reactant_classes, specific_product_classes
def is_reactant(model, t_id, r, s_id2clu, s_id2term_id, ubiquitous_chebi_ids): ubiquitous_reactants, ubiquitous_products, specific_reactant_classes, specific_product_classes = \ get_key_elements(model, r, s_id2clu, s_id2term_id, ubiquitous_chebi_ids) if r.getReversible() and need_to_reverse( ubiquitous_reactants, ubiquitous_products, specific_reactant_classes, specific_product_classes): return t_id in {s_id2term_id[s_id] if s_id in s_id2term_id else s_id for s_id in get_products(r)} else: return t_id in {s_id2term_id[s_id] if s_id in s_id2term_id else s_id for s_id in get_reactants(r)}
def save_as_cytoscape_json(n2lo, model, out_json, ub_sp_ids): """ Converts a model with the given node and edge layout to a json file readable by Cytoscape. :param ub_sp_ids: collection of ubiquitous species ids :param n2lo: node layout as a dictionary {node_id: ((x, y), (w, h)) if node is not ubiquitous else node_id : {r_ids: ((x, y), (w, h)) for r_ids of reactions using each duplicated metabolite}} :param model: SBML model :param out_json: path where to save the resulting json file. """ # let's scale the map so that a minimal node has a width == 16 (so that the labels fit) h_min, (x_shift, y_shift), _ = get_layout_characteristics(n2lo) scale_factor = MARGIN * 1.0 / h_min if h_min else 1 (x_shift, y_shift) = shift(scale((x_shift, y_shift), scale_factor), MARGIN, MARGIN) nodes, edges = [], [] for comp in model.getListOfCompartments(): c_id = comp.getId() c_name = get_name(comp) if c_id in n2lo: (x, y), (w, h) = transform(n2lo[c_id], x_shift, y_shift, scale_factor) nodes.append(get_node(x=x + w / 2, y=y + h / 2, z=-1, **{NAME: c_name, ID: c_id, WEIGHT: w, HEIGHT: h, TYPE: TYPE_COMPARTMENT})) for species in model.getListOfSpecies(): s_id = species.getId() s_name = get_name(species) glyph_type = UNSPECIFIED_ENTITY sbo_term = species.getSBOTermID() if sbo_term: sbo_term = sbo_term.upper().strip() if sbo_term in SBO_2_GLYPH_TYPE: glyph_type = SBO_2_GLYPH_TYPE[sbo_term] if s_id in n2lo: if isinstance(n2lo[s_id], dict): elements = n2lo[s_id].items() else: elements = [('', n2lo[s_id])] for r_ids, coords in elements: if not r_ids or next((it for it in (model.getReaction(r_id) for r_id in r_ids) if it), False): (x, y), (w, h) = transform(coords, x_shift, y_shift, scale_factor) nodes.append( get_node(x=x + w / 2, y=y + h / 2, z=1, **{GLYPH_TYPE: glyph_type, ID: "%s_%s" % (s_id, '_'.join(r_ids)) if r_ids else s_id, COMPARTMENT: species.getCompartment(), NAME: s_name, WEIGHT: w, HEIGHT: h, TYPE: TYPE_SPECIES, UBIQUITOUS: s_id in ub_sp_ids, 'ChEBI': get_chebi_id(species)})) def get_sref_id(s_id): if isinstance(n2lo[s_id], dict): for r_ids in n2lo[s_id].keys(): if r_id in r_ids: return "%s_%s" % (s_id, '_'.join(r_ids)) return s_id for reaction in model.getListOfReactions(): r_id = reaction.getId() r_name = get_name(reaction) ga = get_gene_association(reaction) if r_id in n2lo: (x, y), (w, h) = transform(n2lo[r_id], x_shift, y_shift, scale_factor) nodes.append(get_node(x=x + w / 2, y=y + h / 2, z=1, **{ID: r_id, NAME: ga, WEIGHT: w, HEIGHT: h, TYPE: TYPE_REACTION, REVERSIBLE: reaction.getReversible(), UBIQUITOUS: next((False for s_id in chain(get_reactants(reaction), get_products(reaction)) if s_id not in ub_sp_ids), True), 'genes': ga, 'r_name': r_name})) for s_id in get_reactants(reaction): edges.append(get_edge(**{ID: "%s_%s" % (r_id, s_id), SOURCE: r_id, TARGET: get_sref_id(s_id), NAME: '%s is a substrate of %s' % (get_name(model.getSpecies(s_id)), r_name), UBIQUITOUS: s_id in ub_sp_ids, INTERACTION: SUBSTRATE})) for s_id in get_products(reaction): edges.append(get_edge(**{ID: "%s_%s" % (r_id, s_id), SOURCE: r_id, TARGET: get_sref_id(s_id), NAME: '%s is a product of %s' % (get_name(model.getSpecies(s_id)), r_name), UBIQUITOUS: s_id in ub_sp_ids, INTERACTION: PRODUCT})) save_cyjson(nodes, edges, out_json)
def save_as_comp_generalized_sbml(input_model, out_sbml, groups_sbml, r_id2clu, clu2s_ids, ub_sps, onto): logging.info("serializing generalization") s_id_increment, r_id_increment = 0, 0 if groups_sbml: doc = convert_to_lev3_v1(input_model) groups_model = doc.getModel() groups_plugin = groups_model.getPlugin("groups") if groups_plugin: logging.info(" saving ubiquitous species annotations") s_group = groups_plugin.createGroup() s_group.setId("g_ubiquitous_sps") s_group.setKind(libsbml.GROUP_KIND_COLLECTION) s_group.setSBOTerm(SBO_CHEMICAL_MACROMOLECULE) s_group.setName("ubiquitous species") for s_id in ub_sps: member = s_group.createMember() member.setIdRef(s_id) add_annotation(s_group, libsbml.BQB_IS_DESCRIBED_BY, GROUP_TYPE_UBIQUITOUS) if out_sbml: # generalized model generalized_doc = libsbml.SBMLDocument(input_model.getSBMLNamespaces()) generalized_model = generalized_doc.createModel() copy_elements(input_model, generalized_model) r_id2g_eq, s_id2gr_id = {}, {} if not clu2s_ids: logging.info(" nothing to serialize") else: clu2r_ids = invert_map(r_id2clu) logging.info(" creating species groups") for ((c_id, t), s_ids) in clu2s_ids.items(): comp = input_model.getCompartment(c_id) if len(s_ids) > 1: t = onto.get_term(t) t_name, t_id = (t.get_name(), t.get_id()) if t \ else (' or '.join(input_model.getSpecies(s_id).getName() for s_id in s_ids), None) if not t_id: t = t_name if out_sbml: new_species = create_species(model=generalized_model, compartment_id=comp.getId(), type_id=None, name="{0} ({1}) [{2}]".format(t_name, len(s_ids), comp.getName())) add_annotation(new_species, libsbml.BQB_IS, t_id, CHEBI_PREFIX) new_s_id = new_species.getId() else: s_id_increment += 1 new_s_id = generate_unique_id(input_model, "s_g_", s_id_increment) for s_id in s_ids: s_id2gr_id[s_id] = new_s_id, t if groups_sbml and groups_plugin: # save as a group s_group = groups_plugin.createGroup() s_group.setId(new_s_id) s_group.setKind(libsbml.GROUP_KIND_CLASSIFICATION) s_group.setSBOTerm(SBO_CHEMICAL_MACROMOLECULE) g_name = "{0} [{1}]".format(t_name, comp.getName()) s_group.setName(g_name) # logging.info("%s: %d" % (g_name, len(s_ids))) if t_id: add_annotation(s_group, libsbml.BQB_IS, t_id, CHEBI_PREFIX) for s_id in s_ids: member = s_group.createMember() member.setIdRef(s_id) add_annotation(s_group, libsbml.BQB_IS_DESCRIBED_BY, GROUP_TYPE_EQUIV) generalize_species = lambda species_id: s_id2gr_id[species_id][0] if (species_id in s_id2gr_id) else species_id s_id_to_generalize = set(s_id2gr_id.keys()) logging.info(" creating reaction groups") for clu, r_ids in clu2r_ids.items(): representative = input_model.getReaction(list(r_ids)[0]) r_name = "generalized %s" % representative.getName() if out_sbml: reactants = dict(get_reactants(representative, stoichiometry=True)) products = dict(get_products(representative, stoichiometry=True)) if (len(r_ids) == 1) and \ not ((set(reactants.keys()) | set(products.keys())) & s_id_to_generalize): generalized_model.addReaction(representative) continue r_id2st = {generalize_species(it): st for (it, st) in reactants.items()} p_id2st = {generalize_species(it): st for (it, st) in products.items()} reversible = next((False for r_id in r_ids if not input_model.getReaction(r_id).getReversible()), True) new_r_id = create_reaction(generalized_model, r_id2st, p_id2st, name=r_name, reversible=reversible, id_=representative.getId() if len(r_ids) == 1 else None).getId() elif len(r_ids) > 1: r_id_increment += 1 new_r_id = generate_unique_id(input_model, "r_g_", r_id_increment) if len(r_ids) > 1: for r_id in r_ids: r_id2g_eq[r_id] = new_r_id, r_name if groups_sbml and groups_plugin: # save as a group r_group = groups_plugin.createGroup() r_group.setId(new_r_id) r_group.setKind(libsbml.GROUP_KIND_COLLECTION) r_group.setSBOTerm(SBO_BIOCHEMICAL_REACTION) r_group.setName(r_name) for r_id in r_ids: member = r_group.createMember() member.setIdRef(r_id) add_annotation(r_group, libsbml.BQB_IS_DESCRIBED_BY, GROUP_TYPE_EQUIV) if out_sbml: remove_unused_elements(generalized_model) save_as_sbml(generalized_model, out_sbml) if groups_sbml and groups_model: save_as_sbml(groups_model, groups_sbml) logging.info("serialized to " + groups_sbml) return r_id2g_eq, s_id2gr_id
def save_as_comp_generalized_sbml(input_model, out_sbml, groups_sbml, r_id2clu, clu2s_ids, ub_sps, onto): logging.info("serializing generalization") s_id_increment, r_id_increment = 0, 0 if groups_sbml: doc = convert_to_lev3_v1(input_model) groups_model = doc.getModel() groups_plugin = groups_model.getPlugin("groups") if groups_plugin: logging.info(" saving ubiquitous species annotations") s_group = groups_plugin.createGroup() s_group.setId("g_ubiquitous_sps") s_group.setKind(libsbml.GROUP_KIND_COLLECTION) s_group.setSBOTerm(SBO_CHEMICAL_MACROMOLECULE) s_group.setName("ubiquitous species") for s_id in ub_sps: member = s_group.createMember() member.setIdRef(s_id) add_annotation(s_group, libsbml.BQB_IS_DESCRIBED_BY, GROUP_TYPE_UBIQUITOUS) if out_sbml: # generalized model generalized_doc = convert_to_lev3_v1(input_model) generalized_model = generalized_doc.getModel() for _ in range(0, generalized_model.getNumReactions()): generalized_model.removeReaction(0) r_id2g_eq, s_id2gr_id = {}, {} if not clu2s_ids: logging.info(" nothing to serialize") else: clu2r_ids = invert_map(r_id2clu) logging.info(" creating species groups") for ((c_id, t), s_ids) in clu2s_ids.items(): comp = input_model.getCompartment(c_id) if len(s_ids) > 1: t = onto.get_term(t) t_name, t_id = (t.get_name(), t.get_id()) if t \ else (' or '.join(input_model.getSpecies(s_id).getName() for s_id in s_ids), None) if not t_id: t = t_name if out_sbml: new_species = create_species(model=generalized_model, compartment_id=comp.getId(), type_id=None, name="{0} ({1}) [{2}]".format(t_name, len(s_ids), comp.getName())) add_annotation(new_species, libsbml.BQB_IS, t_id, CHEBI_PREFIX) new_s_id = new_species.getId() else: s_id_increment += 1 new_s_id = generate_unique_id(input_model, "s_g_", s_id_increment) for s_id in s_ids: s_id2gr_id[s_id] = new_s_id, t if groups_sbml and groups_plugin: # save as a group s_group = groups_plugin.createGroup() s_group.setId(new_s_id) s_group.setKind(libsbml.GROUP_KIND_CLASSIFICATION) s_group.setSBOTerm(SBO_CHEMICAL_MACROMOLECULE) g_name = "{0} [{1}]".format(t_name, comp.getName()) s_group.setName(g_name) # logging.info("%s: %d" % (g_name, len(s_ids))) if t_id: add_annotation(s_group, libsbml.BQB_IS, t_id, CHEBI_PREFIX) for s_id in s_ids: member = s_group.createMember() member.setIdRef(s_id) add_annotation(s_group, libsbml.BQB_IS_DESCRIBED_BY, GROUP_TYPE_EQUIV) generalize_species = lambda species_id: s_id2gr_id[species_id][0] if (species_id in s_id2gr_id) else species_id s_id_to_generalize = set(s_id2gr_id.keys()) logging.info(" creating reaction groups") for clu, r_ids in clu2r_ids.items(): representative = input_model.getReaction(list(r_ids)[0]) r_name = "generalized %s" % representative.getName() if out_sbml: reactants = dict(get_reactants(representative, stoichiometry=True)) products = dict(get_products(representative, stoichiometry=True)) if (len(r_ids) == 1) and \ not ((set(reactants.keys()) | set(products.keys())) & s_id_to_generalize): create_reaction(generalized_model, reactants, products, name=representative.getName(), reversible=representative.getReversible(), id_=representative.getId()) continue r_id2st = {generalize_species(it): st for (it, st) in reactants.items()} p_id2st = {generalize_species(it): st for (it, st) in products.items()} reversible = next((False for r_id in r_ids if not input_model.getReaction(r_id).getReversible()), True) new_r_id = create_reaction(generalized_model, r_id2st, p_id2st, name=r_name, reversible=reversible, id_=representative.getId() if len(r_ids) == 1 else None).getId() elif len(r_ids) > 1: r_id_increment += 1 new_r_id = generate_unique_id(input_model, "r_g_", r_id_increment) if len(r_ids) > 1: for r_id in r_ids: r_id2g_eq[r_id] = new_r_id, r_name if groups_sbml and groups_plugin: # save as a group r_group = groups_plugin.createGroup() r_group.setId(new_r_id) r_group.setKind(libsbml.GROUP_KIND_COLLECTION) r_group.setSBOTerm(SBO_BIOCHEMICAL_REACTION) r_group.setName(r_name) for r_id in r_ids: member = r_group.createMember() member.setIdRef(r_id) add_annotation(r_group, libsbml.BQB_IS_DESCRIBED_BY, GROUP_TYPE_EQUIV) if out_sbml: remove_unused_elements(generalized_model) save_as_sbml(generalized_model, out_sbml) if groups_sbml and groups_model: save_as_sbml(groups_model, groups_sbml) logging.info("serialized to " + groups_sbml) return r_id2g_eq, s_id2gr_id