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))
Example #2
0
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
Example #5
0
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)
Example #7
0
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
Example #8
0
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
Example #9
0
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)}
Example #10
0
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)
Example #11
0
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
Example #12
0
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