예제 #1
0
def homolytic_scissions(rct_gras, viable_only=False):
    """ find all possible homolytic scission reactions for these reactants

    :param rct_gras: graphs for the reactants, without stereo and without
        overlapping keys
    :param viable_only: Filter out reactions with non-viable products?
    :type viable_only: bool
    :returns: a list of Reaction objects
    :rtype: tuple[Reaction]

    Homolytic scissions are enumerated by identifying all pure single bonds
    (single bonds with no resonances), and looping over the results of
    breaking each of them. If this gives rise to two distinct
    fragments, the reaction is added to the list.
    """
    assert_is_valid_reagent_graph_list(rct_gras)

    rxns = []

    if len(rct_gras) == 1:
        rct_gra, = rct_gras

        # Identify all pure single bonds involving radical site neighbor
        avg_bnd_ord_dct = resonance_avg_bond_orders(rct_gra)
        brk_bnd_keys = dict_.keys_by_value(avg_bnd_ord_dct, lambda x: x == 1)

        for brk_bnd_key in brk_bnd_keys:
            prds_gra = remove_bonds(rct_gra, [brk_bnd_key])
            prd_gras = connected_components(prds_gra)

            if len(prd_gras) == 2:
                prd_gras = sort_reagents(prd_gras)

                forw_tsg = ts.graph(rct_gra,
                                    frm_bnd_keys=[],
                                    brk_bnd_keys=[brk_bnd_key])
                back_tsg = ts.graph(prds_gra,
                                    frm_bnd_keys=[brk_bnd_key],
                                    brk_bnd_keys=[])

                # Create the reaction object
                rxns.append(
                    Reaction(
                        rxn_cls=par.ReactionClass.Typ.HOMOLYT_SCISSION,
                        forw_tsg=forw_tsg,
                        back_tsg=back_tsg,
                        rcts_keys=list(map(atom_keys, rct_gras)),
                        prds_keys=list(map(atom_keys, prd_gras)),
                    ))

    # Dummy line to fix linting checks
    assert viable_only or not viable_only
    # filter removes all reactions
    # if viable_only:
    #    rxns = filter_viable_reactions(rxns)

    return ts_unique(rxns)
예제 #2
0
def additions(rct_gras, prd_gras):
    """ find additions consistent with these reactants and products

    :param rct_gras: reactant graphs (must have non-overlapping keys)
    :param prd_gras: product graphs (must have non-overlapping keys)

    Additions are identified by joining an unsaturated site on one reactant to
    an unsaturated site on the other. If the result matches the products, this
    is an addition reaction.
    """

    assert_is_valid_reagent_graph_list(rct_gras)
    assert_is_valid_reagent_graph_list(prd_gras)

    rxns = []

    if len(rct_gras) == 2 and len(prd_gras) == 1:
        rct_gras = sort_reagents(rct_gras)
        x_gra, y_gra = rct_gras
        prd_gra, = prd_gras
        x_atm_keys = unsaturated_atom_keys(x_gra)
        y_atm_keys = unsaturated_atom_keys(y_gra)

        frm_bnd_pairs = tuple(itertools.product(x_atm_keys, y_atm_keys))
        for x_atm_key, y_atm_key in frm_bnd_pairs:
            xy_gra = add_bonds(union(x_gra, y_gra), [{x_atm_key, y_atm_key}])

            iso_dct = isomorphism(xy_gra, prd_gra)
            if iso_dct:
                rcts_gra = union_from_sequence(rct_gras)
                prds_gra = prd_gra
                f_frm_bnd_key = (x_atm_key, y_atm_key)
                b_brk_bnd_key = (iso_dct[x_atm_key], iso_dct[y_atm_key])
                forw_tsg = ts.graph(rcts_gra,
                                    frm_bnd_keys=[f_frm_bnd_key],
                                    brk_bnd_keys=[])
                back_tsg = ts.graph(prds_gra,
                                    frm_bnd_keys=[],
                                    brk_bnd_keys=[b_brk_bnd_key])

                # Create the reaction object
                rxns.append(
                    Reaction(
                        rxn_cls=ReactionClass.Typ.ADDITION,
                        forw_tsg=forw_tsg,
                        back_tsg=back_tsg,
                        rcts_keys=list(map(atom_keys, rct_gras)),
                        prds_keys=list(map(atom_keys, prd_gras)),
                    ))

    return ts_unique(rxns)
예제 #3
0
def additions(rct_gras, viable_only=True):
    """ find all possible addition reactions for these reactants

    :param rct_gras: graphs for the reactants, without stereo and without
        overlapping keys
    :param viable_only: Filter out reactions with non-viable products?
    :type viable_only: bool
    :returns: a list of Reaction objects
    :rtype: tuple[Reaction]

    Additions are enumerated by joining an unsaturated site on one reactant to
    an unsaturated site on the other.
    """
    assert_is_valid_reagent_graph_list(rct_gras)

    rxns = []

    if len(rct_gras) == 2:
        rct_gras = sort_reagents(rct_gras)
        rct1_gra, rct2_gra = rct_gras

        rct1_atm_keys = unsaturated_atom_keys(rct1_gra)
        rct2_atm_keys = unsaturated_atom_keys(rct2_gra)

        for frm_bnd_key in itertools.product(rct1_atm_keys, rct2_atm_keys):
            rcts_gra = union(rct1_gra, rct2_gra)
            prd_gra = add_bonds(rcts_gra, [frm_bnd_key])
            prd_gras = [prd_gra]

            forw_tsg = ts.graph(rcts_gra,
                                frm_bnd_keys=[frm_bnd_key],
                                brk_bnd_keys=[])
            back_tsg = ts.graph(prd_gra,
                                frm_bnd_keys=[],
                                brk_bnd_keys=[frm_bnd_key])

            # Create the reaction object
            rxns.append(
                Reaction(
                    rxn_cls=par.ReactionClass.Typ.ADDITION,
                    forw_tsg=forw_tsg,
                    back_tsg=back_tsg,
                    rcts_keys=list(map(atom_keys, rct_gras)),
                    prds_keys=list(map(atom_keys, prd_gras)),
                ))

    if viable_only:
        rxns = filter_viable_reactions(rxns)

    return ts_unique(rxns)
예제 #4
0
def ring_forming_scissions(rct_gras, viable_only=True):
    """ find all possible ring-forming scission reactions for these reactants

    :param rct_gras: graphs for the reactants, without stereo and without
        overlapping keys
    :param viable_only: Filter out reactions with non-viable products?
    :type viable_only: bool
    :returns: a list of Reaction objects
    :rtype: tuple[Reaction]

    Right now it takes the lazy, chemically specific approach of finding
    C-O-O-H groups and forming a bond between the O of the C-O bond
    and radical sites of the species, while breaking the O-O bond.
    """

    assert_is_valid_reagent_graph_list(rct_gras)

    rxns = []

    if len(rct_gras) == 1:
        rct_gra, = rct_gras

        # Identify the radical sites and COOH groups
        rad_keys = radical_atom_keys(rct_gra)
        cooh_grps = hydroperoxy_groups(rct_gra)

        # Get the bnd keys for filtering
        bnd_keys = bond_keys(rct_gra)

        # Set the forming and breaking bonds by looping over COOH groups
        rxn_bnd_keys = ()
        for cooh_grp in cooh_grps:
            brk_bnd_key = frozenset(cooh_grp[1:3])
            for rad_key in rad_keys:
                frm_bnd_key = frozenset({rad_key, cooh_grp[1]})
                # Only includ frm bnd if it does not exist
                # e.g., CC[C]OO already has frm bnd -> no rxn possible
                if frm_bnd_key not in bnd_keys:
                    rxn_bnd_keys += ((frm_bnd_key, brk_bnd_key), )

        # Form reactions with all combinations of frm and brk bnds
        for frm_bnd_key, brk_bnd_key in rxn_bnd_keys:
            prds_gra = rct_gra
            prds_gra = add_bonds(prds_gra, [frm_bnd_key])
            prds_gra = remove_bonds(prds_gra, [brk_bnd_key])
            prd_gras = connected_components(prds_gra)

            if len(prd_gras) == 2:
                prd_gras = sort_reagents(prd_gras)

                forw_tsg = ts.graph(rct_gra,
                                    frm_bnd_keys=[frm_bnd_key],
                                    brk_bnd_keys=[brk_bnd_key])
                back_tsg = ts.graph(prds_gra,
                                    frm_bnd_keys=[brk_bnd_key],
                                    brk_bnd_keys=[frm_bnd_key])
                # Create the reaction object
                rxns.append(
                    Reaction(
                        rxn_cls=par.ReactionClass.Typ.RING_FORM_SCISSION,
                        forw_tsg=forw_tsg,
                        back_tsg=back_tsg,
                        rcts_keys=list(map(atom_keys, rct_gras)),
                        prds_keys=list(map(atom_keys, prd_gras)),
                    ))

    if viable_only:
        rxns = filter_viable_reactions(rxns)

    return ts_unique(rxns)
예제 #5
0
def beta_scissions(rct_gras, viable_only=True):
    """ find all possible beta scission reactions for these reactants

    :param rct_gras: graphs for the reactants, without stereo and without
        overlapping keys
    :param viable_only: Filter out reactions with non-viable products?
    :type viable_only: bool
    :returns: a list of Reaction objects
    :rtype: tuple[Reaction]

    FIX DESCRIPTION:
    Beta scissions are enumerated by identifying all pure single bonds (single
    bonds with no resonances), and looping over the results of breaking each of
    them. If this gives rise to two distinct fragments, the reaction is added
    to the list.
    """
    assert_is_valid_reagent_graph_list(rct_gras)

    rxns = []

    if len(rct_gras) == 1:
        rct_gra, = rct_gras

        # Identify all atom keys that neighbor radical sites
        rad_neighs = frozenset({})
        neigh_dct = atoms_neighbor_atom_keys(rct_gra)
        for rad_key in radical_atom_keys(rct_gra):
            rad_neighs = rad_neighs | neigh_dct[rad_key]

        # Identify all pure single bonds involving radical site neighbor
        avg_bnd_ord_dct = resonance_avg_bond_orders(rct_gra)
        brk_bnd_keys = dict_.keys_by_value(avg_bnd_ord_dct, lambda x: x == 1)

        beta_bnd_keys = ()
        for brk_bnd_key in brk_bnd_keys:
            if brk_bnd_key & rad_neighs:
                beta_bnd_keys += (brk_bnd_key, )

        for brk_bnd_key in beta_bnd_keys:
            prds_gra = remove_bonds(rct_gra, [brk_bnd_key])
            prd_gras = connected_components(prds_gra)

            if len(prd_gras) == 2:
                prd_gras = sort_reagents(prd_gras)

                forw_tsg = ts.graph(rct_gra,
                                    frm_bnd_keys=[],
                                    brk_bnd_keys=[brk_bnd_key])
                back_tsg = ts.graph(prds_gra,
                                    frm_bnd_keys=[brk_bnd_key],
                                    brk_bnd_keys=[])

                # Create the reaction object
                rxns.append(
                    Reaction(
                        rxn_cls=par.ReactionClass.Typ.BETA_SCISSION,
                        forw_tsg=forw_tsg,
                        back_tsg=back_tsg,
                        rcts_keys=list(map(atom_keys, rct_gras)),
                        prds_keys=list(map(atom_keys, prd_gras)),
                    ))

    if viable_only:
        rxns = filter_viable_reactions(rxns)

    return ts_unique(rxns)
예제 #6
0
def two_bond_additions(rct_gras, prd_gras):
    """ two bond additions
    """
    assert_is_valid_reagent_graph_list(rct_gras)
    assert_is_valid_reagent_graph_list(prd_gras)

    rxns = []

    if len(rct_gras) == 2 and len(prd_gras) == 1:
        rct_gras = sort_reagents(rct_gras)
        x_gra, y_gra = rct_gras
        prd_gra, = prd_gras
        x_atm_keys = frozenset().union(unsaturated_atom_keys(x_gra),
                                       lone_pair_atom_keys(x_gra))
        y_atm_keys = frozenset().union(unsaturated_atom_keys(y_gra),
                                       lone_pair_atom_keys(y_gra))
        print('x,y keys', x_atm_keys, y_atm_keys)

        # Generate pairs of forming bonds, where each is a pair of idxs
        # describing the atoms making up the forming bond:
        # (frm1, frm2) = ((idx1, idx2), (idx1, idx2))
        frm_bnd_pairs = tuple(itertools.product(x_atm_keys, y_atm_keys))
        frm_bnds_lst = ()
        for pair in itertools.product(frm_bnd_pairs, frm_bnd_pairs):
            # Preclude pairs with same idxs (formind same bond twice)
            if pair[0] != pair[1]:
                # Preclude multiple bonds formed to same atom X---A---Y
                if pair[0][0] != pair[1][0] and pair[0][1] != pair[1][1]:
                    # Preclude the reverse
                    if pair[::-1] not in frm_bnds_lst:
                        frm_bnds_lst += (pair, )

        for frm_bnd_keys in frm_bnds_lst:
            xy_gra = add_bonds(union(x_gra, y_gra),
                               [set(frm_bnd_keys[0]),
                                set(frm_bnd_keys[1])])

            iso_dct = isomorphism(xy_gra, prd_gra)
            if iso_dct:
                rcts_gra = union_from_sequence(rct_gras)
                prds_gra = prd_gra
                b_brk_bnd_keys = [[
                    iso_dct[frm_bnd_keys[0][0]], iso_dct[frm_bnd_keys[0][1]]
                ], [iso_dct[frm_bnd_keys[1][0]], iso_dct[frm_bnd_keys[1][1]]]]
                forw_tsg = ts.graph(rcts_gra,
                                    frm_bnd_keys=frm_bnd_keys,
                                    brk_bnd_keys=[])
                back_tsg = ts.graph(prds_gra,
                                    frm_bnd_keys=[],
                                    brk_bnd_keys=b_brk_bnd_keys)

                # Create the reaction object
                rxns.append(
                    Reaction(
                        rxn_cls=ReactionClass.Typ.ADDITION,
                        forw_tsg=forw_tsg,
                        back_tsg=back_tsg,
                        rcts_keys=list(map(atom_keys, rct_gras)),
                        prds_keys=list(map(atom_keys, prd_gras)),
                    ))

    return ts_unique(rxns)