Exemple #1
0
def _unique_gras(gra_lst):
    """ Determine all of the unique gras deals with gras with multiple components
    """

    uni_gras = tuple()
    if gra_lst:

        # Initialize list with first element
        uni_gras += (gra_lst[0], )

        # Test if the del_gra is isomorphic to any of the uni_del_gras
        for gra in gra_lst[1:]:
            new_uni = True
            for uni_gra in uni_gras:
                if len(gra) == 1:
                    isodct = full_isomorphism(gra[0], uni_gra[0])
                else:
                    isodct = full_isomorphism(union(*gra), union(*uni_gra))
                if isodct:
                    new_uni = False
                    break

            # Add graph and idx to lst if del gra is unique
            if new_uni:
                uni_gras += (gra, )

    return uni_gras
def chem_unique_atoms_of_type(gra, asymb):
    """ For the given atom type, determine the idxs of all the
         chemically unique atoms.
    """

    # Get the indices for the atom type
    symb_idx_dct = atom_symbol_idxs(gra)
    atom_idxs = symb_idx_dct[asymb]

    # Loop over each idx
    uni_idxs = tuple()
    uni_del_gras = []
    for idx in atom_idxs:

        # Remove the atom from the graph
        del_gra = remove_atoms(gra, [idx])

        # Test if the del_gra is isomorphic to any of the uni_del_gras
        new_uni = True
        for uni_del_gra in uni_del_gras:
            iso_dct = full_isomorphism(del_gra, uni_del_gra)
            if iso_dct:
                new_uni = False
                break

        # Add graph and idx to lst if del gra is unique
        if new_uni:
            uni_del_gras.append(del_gra)
            uni_idxs += (idx,)

    return uni_idxs
Exemple #3
0
def _radical_graph_isomorphisms(gra):
    """ Generate a set of graphs where the radical has been migrated to a
        new atom and then calculate the isomorphism between the input
        graph and all of the new graphs generated by moving the radical
    """

    # Determine useful keys
    symbols = atom_symbols(gra)
    unsat_keys = unsaturated_atom_keys(gra)
    unsat_key = next(iter(unsat_keys))
    h_atm_key = max(symbols.keys()) + 1

    new_gras, isomorphisms = [], []
    for aidx, symbol in enumerate(symbols.values()):

        # Loop over saturated (non-radical) heavy atoms
        if symbol != 'H' and aidx != unsat_key:

            # Add hydrogen atom to radical atom
            new_graph = add_atom_explicit_hydrogen_keys(
                gra, {unsat_key: [h_atm_key]})

            # Remove hydrogen from saturated atom
            neighbors = atoms_neighbor_atom_keys(new_graph)
            for neigh in neighbors[aidx]:
                if symbols[neigh] == 'H':
                    aneighbor = neigh
                    break
            new_graph = remove_atoms(new_graph, [aneighbor])

            # Build lists to return
            new_gras.append(new_graph)
            isomorphisms.append(full_isomorphism(gra, new_graph))

    return tuple(zip(new_gras, isomorphisms))
Exemple #4
0
def isomorphic_radical_graphs(gra):
    """ Generate a set of graphs that are isomorphic to a graph
        of a radical species
    """

    # Determine useful keys
    symbols = atom_symbols(gra)
    unsat_keys = unsaturated_atom_keys(gra)
    unsat_key = next(iter(unsat_keys))
    h_atm_key = max(symbols.keys()) + 1

    iso_gras = []
    for aidx, symbol in enumerate(symbols.values()):
        # Loop over saturated (non-radical) heavy atoms
        if symbol != 'H' and aidx != unsat_key:

            # Add hydrogen atom to radical atom
            new_graph = add_atom_explicit_hydrogen_keys(
                gra, {unsat_key: [h_atm_key]})

            # Remove hydrogen from saturated atom
            neighbors = atom_neighbor_keys(new_graph)
            for neigh in neighbors[aidx]:
                if symbols[neigh] == 'H':
                    aneighbor = neigh
                    break
            new_graph = remove_atoms(new_graph, [aneighbor])

            # Test to see if new radical species is the same as the original
            inv_atm_key_dct = full_isomorphism(gra, new_graph)
            if inv_atm_key_dct:
                iso_gras.append(new_graph)

    return iso_gras
Exemple #5
0
def is_stereo_compatible(tra, sgr1, sgr2):
    """ is this transformation compatible with the reactant/product stereo
    assignments?
    """
    cgr1 = without_stereo_parities(sgr1)
    cgr2 = without_stereo_parities(sgr2)
    atm_key_dct = full_isomorphism(apply(tra, cgr1), cgr2)

    # determine the stereo centers which are preserved in the transformation
    sgr1 = _relabel(sgr1, atm_key_dct)
    atm_keys = sorted(atom_stereo_keys(sgr1) & atom_stereo_keys(sgr2))
    bnd_keys = sorted(bond_stereo_keys(sgr1) & bond_stereo_keys(sgr2))

    atm_pars1 = dict_.values_by_key(atom_stereo_parities(sgr1), atm_keys)
    atm_pars2 = dict_.values_by_key(atom_stereo_parities(sgr2), atm_keys)
    bnd_pars1 = dict_.values_by_key(bond_stereo_parities(sgr1), bnd_keys)
    bnd_pars2 = dict_.values_by_key(bond_stereo_parities(sgr2), bnd_keys)

    atm_ngb_keys_dct1 = atom_neighbor_keys(sgr1)
    atm_ngb_keys_dct2 = atom_neighbor_keys(sgr2)

    ret = True

    for atm_key, par1, par2 in zip(atm_keys, atm_pars1, atm_pars2):
        atm_ngb_keys1 = stereo_sorted_atom_neighbor_keys(
            sgr1, atm_key, atm_ngb_keys_dct1[atm_key])
        atm_ngb_keys2 = stereo_sorted_atom_neighbor_keys(
            sgr2, atm_key, atm_ngb_keys_dct2[atm_key])

        if _permutation_parity(atm_ngb_keys1, atm_ngb_keys2):
            ret &= (par1 == par2)
        else:
            ret &= (par1 != par2)

    for bnd_key, par1, par2 in zip(bnd_keys, bnd_pars1, bnd_pars2):
        atm1_key, atm2_key = bnd_key

        atm1_ngb_key1 = stereo_sorted_atom_neighbor_keys(
            sgr1, atm1_key, atm_ngb_keys_dct1[atm1_key] - {atm2_key})[0]
        atm2_ngb_key1 = stereo_sorted_atom_neighbor_keys(
            sgr1, atm2_key, atm_ngb_keys_dct1[atm2_key] - {atm1_key})[0]
        atm1_ngb_key2 = stereo_sorted_atom_neighbor_keys(
            sgr2, atm1_key, atm_ngb_keys_dct2[atm1_key] - {atm2_key})[0]
        atm2_ngb_key2 = stereo_sorted_atom_neighbor_keys(
            sgr2, atm2_key, atm_ngb_keys_dct2[atm2_key] - {atm1_key})[0]

        if not ((atm1_ngb_key1 != atm1_ngb_key2) ^
                (atm2_ngb_key1 != atm2_ngb_key2)):
            ret &= (par1 == par2)
        else:
            ret &= (par1 != par2)

    return ret
Exemple #6
0
def ring_forming_scission(rct_gras, prd_gras):
    """ find a ring forming reaction that eliminates a radical group
    """
    _assert_is_valid_reagent_graph_list(rct_gras)
    _assert_is_valid_reagent_graph_list(prd_gras)

    tras = []
    rct_idxs = None
    prd_idxs = None

    is_triv = is_trivial_reaction(rct_gras, prd_gras)

    if len(rct_gras) == 1 and len(prd_gras) == 2 and not is_triv:
        rgra, = rct_gras
        pgra1, pgra2 = prd_gras
        pgra = automol.graph.union(pgra1, pgra2)
        rad_atm_keys = unsaturated_atom_keys(rgra)
        atms, bnds = rgra
        ngb_atms = automol.graph.atom_neighbor_keys(rgra)

        for rad_atm in rad_atm_keys:
            for xatm in atms:
                if (xatm != rad_atm and atms[xatm][1] != 'H'
                        and xatm not in ngb_atms[rad_atm] and not tras):
                    for natm in ngb_atms[xatm]:
                        if natm != rad_atm:
                            xgra = atms.copy(), bnds.copy()
                            xgra = add_bonds(xgra,
                                             [frozenset({rad_atm, xatm})])
                            xgra = remove_bonds(xgra,
                                                [frozenset({xatm, natm})])
                            atm_key_dct = full_isomorphism(xgra, pgra)
                            if atm_key_dct:
                                tra = trans.from_data(
                                    rxn_class=(
                                        par.REACTION_CLASS.RING_FORM_SCISSION),
                                    frm_bnd_keys=[{rad_atm, xatm}],
                                    brk_bnd_keys=[
                                        {xatm, natm},
                                    ])
                                tras.append(tra)
                                break

                # sort the reactants so that the largest species is first
        rct_idxs = (0, )
        prd_idxs = _argsort_reactants(prd_gras)
        tras = tuple(tras)

    return tras, rct_idxs, prd_idxs
Exemple #7
0
def _partial_hydrogen_abstraction(qh_gra, q_gra):
    rets = []

    h_atm_key = max(atom_keys(q_gra)) + 1
    uns_atm_keys = unsaturated_atom_keys(q_gra)
    for atm_key in uns_atm_keys:
        q_gra_h = add_atom_explicit_hydrogen_keys(q_gra,
                                                  {atm_key: [h_atm_key]})
        inv_atm_key_dct = full_isomorphism(q_gra_h, qh_gra)
        if inv_atm_key_dct:
            qh_q_atm_key = inv_atm_key_dct[atm_key]
            qh_h_atm_key = inv_atm_key_dct[h_atm_key]
            q_q_atm_key = atm_key
            rets.append((qh_q_atm_key, qh_h_atm_key, q_q_atm_key))

    return rets
Exemple #8
0
def hydrogen_migration(rct_gras, prd_gras):
    """ find a hydrogen migration transformation

    Hydrogen migrations are identified by adding a hydrogen to an unsaturated
    site of the reactant and adding a hydrogen to an unsaturated site of the
    product and seeing if they match up. If so, we have a hydrogen migration
    between these two sites.
    """
    _assert_is_valid_reagent_graph_list(rct_gras)
    _assert_is_valid_reagent_graph_list(prd_gras)

    tras = []
    rct_idxs = None
    prd_idxs = None

    is_triv = is_trivial_reaction(rct_gras, prd_gras)

    if len(rct_gras) == 1 and len(prd_gras) == 1 and not is_triv:
        gra1, = rct_gras
        gra2, = prd_gras
        h_atm_key1 = max(atom_keys(gra1)) + 1
        h_atm_key2 = max(atom_keys(gra2)) + 1

        atm_keys1 = unsaturated_atom_keys(gra1)
        atm_keys2 = unsaturated_atom_keys(gra2)
        for atm_key1, atm_key2 in itertools.product(atm_keys1, atm_keys2):
            gra1_h = add_atom_explicit_hydrogen_keys(gra1,
                                                     {atm_key1: [h_atm_key1]})
            gra2_h = add_atom_explicit_hydrogen_keys(gra2,
                                                     {atm_key2: [h_atm_key2]})

            inv_atm_key_dct = full_isomorphism(gra2_h, gra1_h)
            if inv_atm_key_dct:
                tra = trans.from_data(
                    rxn_class=par.REACTION_CLASS.HYDROGEN_MIGRATION,
                    frm_bnd_keys=[{atm_key1, inv_atm_key_dct[h_atm_key2]}],
                    brk_bnd_keys=[{
                        inv_atm_key_dct[atm_key2], inv_atm_key_dct[h_atm_key2]
                    }])
                tras.append(tra)

                rct_idxs = (0, )
                prd_idxs = (0, )

    tras = tuple(tras)

    return tras, rct_idxs, prd_idxs
Exemple #9
0
def trivial_reaction(rct_gras, prd_gras):
    """ is this a trivial reaction, with the same reactants and products?
    """
    _assert_is_valid_reagent_graph_list(rct_gras)
    _assert_is_valid_reagent_graph_list(prd_gras)

    tras = []
    rct_idxs = None
    prd_idxs = None

    if len(rct_gras) == len(prd_gras):
        prd_gras = list(prd_gras)

        num = len(rct_gras)
        rct_idxs = tuple(range(num))
        prd_idxs = [0] * num

        # cycle through reactants and check for matching products
        for rct_idx, rct_gra in enumerate(rct_gras):
            prd_idx = next((idx for idx, prd_gra in enumerate(prd_gras)
                            if full_isomorphism(rct_gra, prd_gra)), None)

            # if the reactant has a matching product, remove it from the
            # products list
            if prd_idx is not None:
                prd_idxs[rct_idx] = prd_idx
                prd_gras.pop(prd_idx)
            # if the reactant has no matching product, this is not a
            # trivial reaction
            else:
                tras = []
                rct_idxs = prd_idxs = None
                break

    if rct_idxs is not None:
        tra = trans.from_data(rxn_class=par.REACTION_CLASS.TRIVIAL,
                              frm_bnd_keys=[],
                              brk_bnd_keys=[])
        tras = (tra, )
        rct_idxs = tuple(rct_idxs)
        prd_idxs = tuple(prd_idxs)

    tras = tuple(tras)

    return tras, rct_idxs, prd_idxs
Exemple #10
0
def radical_dissociation_prods(gra, pgra1):
    """ given a dissociation product, determine the other product
    """
    gra = without_fractional_bonds(gra)

    pgra2 = None
    rads = sing_res_dom_radical_atom_keys(gra)
    adj_atms = atoms_neighbor_atom_keys(gra)
    # adj_idxs = tuple(adj_atms[rad] for rad in rads)
    for rad in rads:
        for adj in adj_atms[rad]:
            for group in atom_groups(gra, adj):
                if full_isomorphism(explicit(group), explicit(pgra1)):
                    pgra2 = remove_atoms(gra, atom_keys(group))
                    # pgra2 = remove_bonds(pgra2, bond_keys(group))
                    if bond_keys(group) in pgra2:
                        pgra2 = remove_bonds(pgra2, bond_keys(group))
    return (pgra1, pgra2)
Exemple #11
0
def substitution(rct_gras, prd_gras):
    """ find an substitution transformation

    Substitutions are identified by breaking one bond in the reactants and one
    bond from the products and checking for isomorphism.
    """
    _assert_is_valid_reagent_graph_list(rct_gras)
    _assert_is_valid_reagent_graph_list(prd_gras)

    tras = []
    rct_idxs = None
    prd_idxs = None

    is_triv = is_trivial_reaction(rct_gras, prd_gras)

    if len(rct_gras) == 2 and len(prd_gras) == 2 and not is_triv:
        rct_gra = union_from_sequence(rct_gras)
        prd_gra = union_from_sequence(prd_gras)

        rct_bnd_keys = bond_keys(rct_gra)
        prd_bnd_keys = bond_keys(prd_gra)
        for rct_bnd_key, prd_bnd_key in itertools.product(
                rct_bnd_keys, prd_bnd_keys):
            rct_gra_ = remove_bonds(rct_gra, [rct_bnd_key])
            prd_gra_ = remove_bonds(prd_gra, [prd_bnd_key])

            inv_atm_key_dct = full_isomorphism(prd_gra_, rct_gra_)
            if inv_atm_key_dct:
                brk_bnd_key = rct_bnd_key
                frm_bnd_key = frozenset(
                    map(inv_atm_key_dct.__getitem__, prd_bnd_key))

                tra = trans.from_data(
                    rxn_class=par.REACTION_CLASS.SUBSTITUTION,
                    frm_bnd_keys=[frm_bnd_key],
                    brk_bnd_keys=[brk_bnd_key])
                tras.append(tra)

                rct_idxs = _argsort_reactants(rct_gras)
                prd_idxs = _argsort_reactants(prd_gras)

    tras = tuple(set(tras))
    return tras, rct_idxs, prd_idxs
Exemple #12
0
def reverse(tra, xgr1, xgr2):
    """ reverse a transformation to get the one taking products into reactants
    """
    rxn_class = reaction_class(tra)
    frm_bnd_keys = formed_bond_keys(tra)
    brk_bnd_keys = broken_bond_keys(tra)
    atm_key_dct = full_isomorphism(apply(tra, xgr1), xgr2)

    rev_rxn_class = reverse_class(rxn_class)
    rev_frm_bnd_keys = [
        frozenset(map(atm_key_dct.__getitem__, bnd_key))
        for bnd_key in brk_bnd_keys
    ]
    rev_brk_bnd_keys = [
        frozenset(map(atm_key_dct.__getitem__, bnd_key))
        for bnd_key in frm_bnd_keys
    ]
    rev_tra = from_data(rxn_class=rev_rxn_class,
                        frm_bnd_keys=rev_frm_bnd_keys,
                        brk_bnd_keys=rev_brk_bnd_keys)
    return rev_tra
Exemple #13
0
def addition(rct_gras, prd_gras):
    """ find an addition transformation

    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)

    tras = []
    rct_idxs = None
    prd_idxs = None

    is_triv = is_trivial_reaction(rct_gras, prd_gras)

    if len(rct_gras) == 2 and len(prd_gras) == 1 and not is_triv:
        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)

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

            atm_key_dct = full_isomorphism(xy_gra, prd_gra)
            if atm_key_dct:
                tra = trans.from_data(rxn_class=par.REACTION_CLASS.ADDITION,
                                      frm_bnd_keys=[{x_atm_key, y_atm_key}],
                                      brk_bnd_keys=[])
                tras.append(tra)

                # sort the reactants so that the largest species is first
                rct_idxs = _argsort_reactants(rct_gras)
                prd_idxs = (0, )

    tras = tuple(tras)
    return tras, rct_idxs, prd_idxs
Exemple #14
0
def prod_hydrogen_migration(gra):
    """ products of hydrogen migration
    """

    prod_gras = tuple()

    keys = atom_keys(gra)

    num_keys = len(keys)
    if num_keys > 2:
        rad_idxs = resonance_dominant_radical_atom_keys(gra)
        uni_h_idxs = chem_unique_atoms_of_type(gra, 'H')

        h_atm_key = max(keys) + 1

        for h_idx in uni_h_idxs:
            for rad_idx in rad_idxs:
                gra2 = remove_atoms(gra, [h_idx])
                gra2_h = add_atom_explicit_hydrogen_keys(
                    gra2, {rad_idx: [h_atm_key]})
                if not full_isomorphism(gra, gra2_h):
                    prod_gras += ((gra2_h, ), )

    return _unique_gras(prod_gras)
Exemple #15
0
def elimination(rct_gras, prd_gras):
    """ find an elimination transformation

    Eliminations are identified by breaking two bonds from the reactant,
    forming three fragments. This will form one "central fragment" with two
    break sites and two "end fragments" with one break site each. If the
    central fragment plus the two end fragments, joined at their break sites,
    matches the products, this is an elimination reaction.
    """
    _assert_is_valid_reagent_graph_list(rct_gras)
    _assert_is_valid_reagent_graph_list(prd_gras)

    tras = []
    rct_idxs = None
    prd_idxs = None

    is_triv = is_trivial_reaction(rct_gras, prd_gras)

    if len(rct_gras) == 1 and len(prd_gras) == 2 and not is_triv:
        rct_gra, = rct_gras
        rct_bnd_keys = bond_keys(rct_gra)
        # Loop over pairs of bonds and break them. Then, if this forms three
        # fragments, join the two end fragments and compare the result to the
        # products.
        for brk_bnd_key1, brk_bnd_key2 in itertools.combinations(rct_bnd_keys,
                                                                 r=2):
            rct_gra_ = remove_bonds(rct_gra, [brk_bnd_key1, brk_bnd_key2])

            # Find the central fragment, which is the one connected to both
            # break sites. If there's a loop there may not be a central
            # fragment, in which case this function will return None.
            cent_frag_atm_keys = _central_fragment_atom_keys(
                rct_gra_, brk_bnd_key1, brk_bnd_key2)
            if cent_frag_atm_keys is not None:
                atm1_key, = brk_bnd_key1 - cent_frag_atm_keys
                atm2_key, = brk_bnd_key2 - cent_frag_atm_keys
                frm_bnd_key = frozenset({atm1_key, atm2_key})
                rct_gra_ = add_bonds(rct_gra_, [frm_bnd_key])

                prd_gra = union_from_sequence(prd_gras)
                atm_key_dct = full_isomorphism(rct_gra_, prd_gra)
                if atm_key_dct:
                    tra = trans.from_data(
                        rxn_class=par.REACTION_CLASS.ELIMINATION,
                        frm_bnd_keys=[frm_bnd_key],
                        brk_bnd_keys=[brk_bnd_key1, brk_bnd_key2])
                    tras.append(tra)

                    rct_idxs = (0, )

                    cent_prd_atm_keys = frozenset(
                        map(atm_key_dct.__getitem__, cent_frag_atm_keys))

                    if cent_prd_atm_keys <= atom_keys(prd_gras[0]):
                        prd_idxs = (0, 1)
                    else:
                        assert cent_prd_atm_keys <= atom_keys(prd_gras[1])
                        prd_idxs = (1, 0)

    tras = tuple(tras)
    return tras, rct_idxs, prd_idxs