Exemplo n.º 1
0
def test__atoms_neighbor_atom_keys():
    """ test graph.atoms_neighbor_atom_keys
    """
    assert graph.atoms_neighbor_atom_keys(C8H13O_CGR) == {
        0: frozenset({3}),
        1: frozenset({4}),
        2: frozenset({6}),
        3: frozenset({0, 5}),
        4: frozenset({1, 6}),
        5: frozenset({3, 7}),
        6: frozenset({2, 4, 7}),
        7: frozenset({8, 5, 6}),
        8: frozenset({7})
    }
Exemplo n.º 2
0
def eliminations(rct_gras, viable_only=True):
    """ find all possible elimination 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]

    Eliminations are enumerated by forming a bond between an attacking heavy
    atom and another atom not initially bonded to it, forming a ring. The bond
    adjacent to the attacked atom is then broken, along with a second bond in
    the ring, downstream from the attacking heavy atom, away from the attacked
    atom.
    """
    assert_is_valid_reagent_graph_list(rct_gras)

    rxns = []

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

        ngb_keys_dct = atoms_neighbor_atom_keys(rct_gra)

        # frm1_keys = atom_keys(rct_gra, excl_syms=('H',))
        frm1_keys = unsaturated_atom_keys(rct_gra)
        rct_symbs = atom_symbols(rct_gra)
        frm1_keys_o = frozenset(key for key in frm1_keys
                                if rct_symbs[key] == 'O')
        frm2_keys = atom_keys(rct_gra)
        bnd_keys = bond_keys(rct_gra)

        frm_bnd_keys = [(frm1_key, frm2_key)
                        for frm1_key, frm2_key in itertools.product(
                            frm1_keys_o, frm2_keys) if frm1_key != frm2_key
                        and not frozenset({frm1_key, frm2_key}) in bnd_keys]

        for frm1_key, frm2_key in frm_bnd_keys:
            # Bond the radical atom to the hydrogen atom
            prds_gra = add_bonds(rct_gra, [(frm2_key, frm1_key)])

            # Get keys to the ring formed by this extra bond
            rng_keys = next((ks for ks in rings_atom_keys(prds_gra)
                             if frm2_key in ks and frm1_key in ks), None)
            # Eliminations (as far as I can tell) only happen through TSs with
            # 3- or 4-membered rings
            if rng_keys is not None and len(rng_keys) < 5:
                frm1_ngb_key, = ngb_keys_dct[frm1_key] & set(rng_keys)
                frm2_ngb_key, = ngb_keys_dct[frm2_key] & set(rng_keys)

                # Break the bonds on either side of the newly formed bond
                prds_gra = remove_bonds(prds_gra, [(frm1_key, frm1_ngb_key)])
                prds_gra = remove_bonds(prds_gra, [(frm2_key, frm2_ngb_key)])

                prd_gras = connected_components(prds_gra)

                if len(prd_gras) == 2:
                    forw_tsg = ts.graph(rct_gra,
                                        frm_bnd_keys=[(frm1_key, frm2_key)],
                                        brk_bnd_keys=[(frm1_key, frm1_ngb_key),
                                                      (frm2_key, frm2_ngb_key)
                                                      ])
                    back_tsg = ts.graph(prds_gra,
                                        frm_bnd_keys=[(frm1_key, frm1_ngb_key),
                                                      (frm2_key, frm2_ngb_key)
                                                      ],
                                        brk_bnd_keys=[(frm1_key, frm2_key)])

                    rcts_atm_keys = list(map(atom_keys, rct_gras))
                    prds_atm_keys = list(map(atom_keys, prd_gras))

                    if frm2_key not in prds_atm_keys[1]:
                        prds_atm_keys = list(reversed(prds_atm_keys))

                    # Create the reaction object
                    rxns.append(
                        Reaction(
                            rxn_cls=par.ReactionClass.Typ.ELIMINATION,
                            forw_tsg=forw_tsg,
                            back_tsg=back_tsg,
                            rcts_keys=rcts_atm_keys,
                            prds_keys=prds_atm_keys,
                        ))

    if viable_only:
        rxns = filter_viable_reactions(rxns)

    return ts_unique(rxns)
Exemplo n.º 3
0
def eliminations(rct_gras, prd_gras):
    """ find eliminations 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)

    Eliminations are identified by forming a bond between an attacking heavy
    atom and another atom not initially bonded to it, forming a ring. The bond
    adjacent to the attacked atom is then broken, along with a second bond in
    the ring, downstream of the attacking heavy atom, away from the attacked
    atom.
    """
    _assert_is_valid_reagent_graph_list(rct_gras)
    _assert_is_valid_reagent_graph_list(prd_gras)

    rxns = []

    if len(rct_gras) == 1 and len(prd_gras) == 2:
        rct_gra, = rct_gras
        prds_gra = union_from_sequence(prd_gras)

        ngb_keys_dct = atoms_neighbor_atom_keys(rct_gra)

        frm1_keys = atom_keys(rct_gra, excl_syms=('H', ))
        frm2_keys = atom_keys(rct_gra)
        bnd_keys = bond_keys(rct_gra)

        frm_bnd_keys = [
            (frm1_key, frm2_key)
            for frm1_key, frm2_key in itertools.product(frm1_keys, frm2_keys)
            if frm1_key != frm2_key
            and not frozenset({frm1_key, frm2_key}) in bnd_keys
        ]

        for frm1_key, frm2_key in frm_bnd_keys:
            # Bond the radical atom to the hydrogen atom
            gra_ = add_bonds(rct_gra, [(frm2_key, frm1_key)])

            # Get keys to the ring formed by this extra bond
            rng_keys = next((ks for ks in rings_atom_keys(gra_)
                             if frm2_key in ks and frm1_key in ks), None)
            # Eliminations (as far as I can tell) only happen through TSs with
            # 3- or 4-membered rings
            if rng_keys is not None and len(rng_keys) < 5:
                frm1_ngb_key, = ngb_keys_dct[frm1_key] & set(rng_keys)
                frm2_ngb_key, = ngb_keys_dct[frm2_key] & set(rng_keys)

                # Break the bonds on either side of the newly formed bond
                gra_ = remove_bonds(gra_, [(frm1_key, frm1_ngb_key)])
                gra_ = remove_bonds(gra_, [(frm2_key, frm2_ngb_key)])

                inv_dct = isomorphism(gra_, prds_gra)
                if inv_dct:
                    f_frm_bnd_key = (frm1_key, frm2_key)
                    f_brk_bnd_key1 = (frm1_key, frm1_ngb_key)
                    f_brk_bnd_key2 = (frm2_key, frm2_ngb_key)
                    inv_ = inv_dct.__getitem__
                    b_frm_bnd_key1 = tuple(map(inv_, f_brk_bnd_key1))
                    b_frm_bnd_key2 = tuple(map(inv_, f_brk_bnd_key2))
                    b_brk_bnd_key = tuple(map(inv_, f_frm_bnd_key))

                    forw_tsg = ts.graph(
                        rct_gra,
                        frm_bnd_keys=[f_frm_bnd_key],
                        brk_bnd_keys=[f_brk_bnd_key1, f_brk_bnd_key2])
                    back_tsg = ts.graph(
                        prds_gra,
                        frm_bnd_keys=[b_frm_bnd_key1, b_frm_bnd_key2],
                        brk_bnd_keys=[b_brk_bnd_key])

                    rcts_atm_keys = list(map(atom_keys, rct_gras))
                    prds_atm_keys = list(map(atom_keys, prd_gras))

                    if inv_dct[frm2_key] not in prds_atm_keys[1]:
                        prds_atm_keys = list(reversed(prds_atm_keys))

                    # Create the reaction object
                    rxns.append(
                        Reaction(
                            rxn_cls=par.ReactionClass.ELIMINATION,
                            forw_tsg=forw_tsg,
                            back_tsg=back_tsg,
                            rcts_keys=rcts_atm_keys,
                            prds_keys=prds_atm_keys,
                        ))

    return ts_unique(rxns)
Exemplo n.º 4
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)
Exemplo n.º 5
0
def _rotor_counts(gra, symbs):
    """ Count up various types of bonds for a structure.

        :param gra: molecular graph of species
        :type gra: automol graph data structure
        :param symbs: atomic symbols of species
        :type symbs: tuple(str)
        :rtype: tuple(float)
    """

    # Initialize the rotor counts
    n_pp, n_ps, n_pt, n_pq = 0, 0, 0, 0
    n_ss, n_st, n_sq = 0, 0, 0
    n_tt, n_tq = 0, 0
    n_qq = 0
    n_co, n_oo = 0, 0
    n_ss_ring, n_rings = 0, 0

    # Get the rings  and the number
    rings = _rings(gra)
    ring_keys = set(ring_idxs(_rings(gra)))
    n_rings = len(rings)

    # Loop over the bonds and count the number of atoms
    neighbors = atoms_neighbor_atom_keys(gra)
    for bnd in bond_keys(gra):
        key1, key2 = bnd
        spair = (symbs[key1], symbs[key2])
        if spair == ('C', 'C'):
            # Figure out which neighbors are not hydrogen and count the number
            atom1_neighbors = neighbors[key1]
            numc1 = 0
            for neighbor1 in atom1_neighbors:
                if symbs[neighbor1] != 'H':
                    numc1 += 1
            atom2_neighbors = neighbors[key2]
            numc2 = 0
            for neighbor2 in atom2_neighbors:
                if symbs[neighbor2] != 'H':
                    numc2 += 1
            # Determine appropriate term to increment
            npair = (numc1, numc2)
            if npair == (1, 1):
                n_pp += 1
            elif npair in ((1, 2), (2, 1)):
                n_ps += 1
            elif npair in ((1, 3), (3, 1)):
                n_pt += 1
            elif npair in ((1, 4), (4, 1)):
                n_pq += 1
            elif npair == (2, 2):
                if {key1, key2} <= ring_keys:
                    n_ss_ring += 1
                else:
                    n_ss += 1
            elif npair in ((2, 3), (3, 2)):
                n_st += 1
            elif npair in ((2, 4), (4, 2)):
                n_sq += 1
            elif npair == (3, 3):
                n_tt += 1
            elif npair in ((3, 4), (4, 3)):
                n_tq += 1
            elif npair == (4, 4):
                n_qq += 1
        elif spair in (('C', 'O'), ('O', 'C')):
            n_co += 1
        elif spair == ('O', 'O'):
            n_oo += 1

    # Compile counts into a tuple
    return (n_pp, n_ps, n_pt, n_pq, n_ss, n_st, n_sq, n_tt, n_tq, n_qq, n_co,
            n_oo, n_ss_ring, n_rings)