Esempio n. 1
0
def test__from_data():
    """ test getters
    """
    cgr = automol.graph.from_data(
        atm_symb_dct=graph.atom_symbols(C8H13O_CGR),
        bnd_keys=graph.bond_keys(C8H13O_CGR),
        atm_imp_hyd_vlc_dct=(
            graph.atom_implicit_hydrogen_valences(C8H13O_CGR)),
    )
    assert cgr == C8H13O_CGR

    rgr = automol.graph.from_data(
        atm_symb_dct=graph.atom_symbols(C8H13O_RGR),
        bnd_keys=graph.bond_keys(C8H13O_RGR),
        atm_imp_hyd_vlc_dct=(
            graph.atom_implicit_hydrogen_valences(C8H13O_RGR)),
        bnd_ord_dct=graph.bond_orders(C8H13O_RGR),
    )
    assert rgr == C8H13O_RGR

    sgr = automol.graph.from_data(
        atm_symb_dct=graph.atom_symbols(C8H13O_SGR),
        bnd_keys=graph.bond_keys(C8H13O_SGR),
        atm_imp_hyd_vlc_dct=(
            graph.atom_implicit_hydrogen_valences(C8H13O_SGR)),
        atm_ste_par_dct=graph.atom_stereo_parities(C8H13O_SGR),
        bnd_ste_par_dct=graph.bond_stereo_parities(C8H13O_SGR))
    assert sgr == C8H13O_SGR
Esempio n. 2
0
def substitutions(rct_gras, prd_gras):
    """ find substitutions 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)

    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)

    rxns = []

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

        for rgra1, rgra2 in itertools.permutations(rct_gras):
            bnd_keys = bond_keys(rgra1)
            rad_keys = unsaturated_atom_keys(rgra2)

            for bnd_key, rad_key in itertools.product(bnd_keys, rad_keys):
                gra = remove_bonds(rct_gra, [bnd_key])

                for brk_key1 in bnd_key:
                    gra = add_bonds(gra, [(brk_key1, rad_key)])

                    inv_dct = isomorphism(gra, prd_gra)
                    if inv_dct:
                        brk_key2, = bnd_key - {brk_key1}
                        f_frm_bnd_key = (brk_key1, rad_key)
                        f_brk_bnd_key = (brk_key1, brk_key2)
                        b_frm_bnd_key = (inv_dct[brk_key1], inv_dct[brk_key2])
                        b_brk_bnd_key = (inv_dct[brk_key1], inv_dct[rad_key])

                        forw_tsg = ts.graph(rct_gra,
                                            frm_bnd_keys=[f_frm_bnd_key],
                                            brk_bnd_keys=[f_brk_bnd_key])
                        back_tsg = ts.graph(prd_gra,
                                            frm_bnd_keys=[b_frm_bnd_key],
                                            brk_bnd_keys=[b_brk_bnd_key])

                        rcts_atm_keys = [atom_keys(rgra1), atom_keys(rgra2)]

                        prds_atm_keys = list(map(atom_keys, prd_gras))
                        if inv_dct[rad_key] not in prds_atm_keys[0]:
                            prds_atm_keys = list(reversed(prds_atm_keys))

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

    return ts_unique(rxns)
Esempio n. 3
0
def test__set_atom_implicit_hydrogen_valences():
    """ test graph.set_atom_implicit_hydrogen_valences
    """
    atm_keys = graph.atom_keys(C8H13O_CGR)
    cgr = graph.set_atom_implicit_hydrogen_valences(
        C8H13O_CGR, {atm_key: 0
                     for atm_key in atm_keys})

    assert cgr == automol.graph.from_data(graph.atom_symbols(C8H13O_CGR),
                                          graph.bond_keys(C8H13O_CGR))
Esempio n. 4
0
def test__from_dictionaries():
    """ test graph.from_dictionaries
    """
    assert graph.from_dictionaries(
        graph.atom_symbols(CH2FH2H_CGR_EXP),
        graph.bond_keys(CH2FH2H_CGR_EXP)
    ) == CH2FH2H_CGR_EXP

    assert graph.from_dictionaries(
        graph.atom_symbols(C8H13O_RGRS[0]),
        graph.bond_keys(C8H13O_RGRS[0]),
        atm_imp_hyd_vlc_dct=graph.atom_implicit_hydrogen_valences(
            C8H13O_RGRS[0]),
        bnd_ord_dct=graph.bond_orders(C8H13O_RGRS[0])
    ) == C8H13O_RGRS[0]

    assert graph.from_dictionaries(
        graph.atom_symbols(C8H13O_SGRS[0]),
        graph.bond_keys(C8H13O_SGRS[0]),
        atm_imp_hyd_vlc_dct=graph.atom_implicit_hydrogen_valences(
            C8H13O_SGRS[0]),
        atm_ste_par_dct=graph.atom_stereo_parities(C8H13O_SGRS[0]),
        bnd_ste_par_dct=graph.bond_stereo_parities(C8H13O_SGRS[0])
    ) == C8H13O_SGRS[0]

    # a litte ridiculous, but make sure we get the keys right
    sgr_ref = C8H13O_SGRS[0]
    natms = len(graph.atoms(sgr_ref))
    for _ in range(10):
        pmt_dct = dict(enumerate(numpy.random.permutation(natms)))
        sgr = graph.relabel(sgr_ref, pmt_dct)
        assert graph.from_dictionaries(
            graph.atom_symbols(sgr),
            graph.bond_keys(sgr),
            atm_imp_hyd_vlc_dct=graph.atom_implicit_hydrogen_valences(sgr),
            atm_ste_par_dct=graph.atom_stereo_parities(sgr),
            bnd_ste_par_dct=graph.bond_stereo_parities(sgr)
        ) == sgr
Esempio n. 5
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)
Esempio n. 6
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)
Esempio n. 7
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)
Esempio n. 8
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)
Esempio n. 9
0
def substitutions(rct_gras, prd_gras):
    """ find substitutions 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)

    Substitutions are identified by breaking one bond in the reactants and one
    bond from the products and checking for isomorphism.

    Currently it assumes that one of the reactants has a radical site that
    can attack the other reactants, forming a bond and breaking another.

    From the perspective of breaking and forming breaking bonds, substitutions
    are equivalent with hydrogen abstractions. Hence, we remove all cases where
    the forming bond involves a hydrogen atom off the reactant in which a bond
    is breaking.
    """
    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) == 2:
        rct_gra = union_from_sequence(rct_gras)
        prd_gra = union_from_sequence(prd_gras)

        # Loop over both orders of reactants: A+B and B+A
        for rgra1, rgra2 in itertools.permutations(rct_gras):
            bnd_keys = bond_keys(rgra1)
            atom_symb_dct = automol.graph.atom_symbols(rgra1)
            rad_keys = unsaturated_atom_keys(rgra2)

            # Break all possible bonds in total reactant
            for bnd_key, rad_key in itertools.product(bnd_keys, rad_keys):
                gra = remove_bonds(rct_gra, [bnd_key])

                # Form all possible bonds between rad site and non-H atoms
                frm_keys = ()
                for key in bnd_key:
                    frm_symb = atom_symb_dct[key]
                    if frm_symb != 'H':
                        frm_keys += (key, )

                for frm_key in frm_keys:
                    gra = add_bonds(gra, [(frm_key, rad_key)])

                    inv_dct = isomorphism(gra, prd_gra)
                    if inv_dct:
                        brk_key2, = bnd_key - {frm_key}
                        f_frm_bnd_key = (frm_key, rad_key)
                        f_brk_bnd_key = (frm_key, brk_key2)
                        b_frm_bnd_key = (inv_dct[frm_key], inv_dct[brk_key2])
                        b_brk_bnd_key = (inv_dct[frm_key], inv_dct[rad_key])

                        forw_tsg = ts.graph(rct_gra,
                                            frm_bnd_keys=[f_frm_bnd_key],
                                            brk_bnd_keys=[f_brk_bnd_key])
                        back_tsg = ts.graph(prd_gra,
                                            frm_bnd_keys=[b_frm_bnd_key],
                                            brk_bnd_keys=[b_brk_bnd_key])

                        rcts_atm_keys = [atom_keys(rgra1), atom_keys(rgra2)]

                        prds_atm_keys = list(map(atom_keys, prd_gras))
                        if inv_dct[rad_key] not in prds_atm_keys[0]:
                            prds_atm_keys = list(reversed(prds_atm_keys))

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

    return ts_unique(rxns)
Esempio n. 10
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.
    """
    def _identify(frm1_keys, frm2_keys, bnd_keys):
        """ Try and identify elmination from some set of keys
        """

        _rxns = []

        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:

            prds_gra_ = add_bonds(rct_gra, [(frm2_key, frm1_key)])

            # Get keys of all bonds in the ring formed by this extra bond
            rng_bnd_keys = next((ks for ks in rings_bond_keys(prds_gra_)
                                 if frozenset({frm1_key, frm2_key}) in ks),
                                None)

            if rng_bnd_keys is not None:

                # Elims break two bonds of the ring formed by the forming bond
                # Loop over all ring bond-pairs, break bonds, see if prods form
                # Ensure to preclude the forming-bond from this set
                brk_bnds = tuple(
                    bond for bond in itertools.combinations(rng_bnd_keys, 2)
                    if frozenset({frm1_key, frm2_key}) not in bond)

                for brk_bnd_1, brk_bnd_2 in brk_bnds:
                    prds_gra_2_ = prds_gra_
                    prds_gra_2_ = remove_bonds(prds_gra_2_, [brk_bnd_1])
                    prds_gra_2_ = remove_bonds(prds_gra_2_, [brk_bnd_2])

                    inv_dct = isomorphism(prds_gra_2_, prds_gra)
                    if inv_dct:
                        f_frm_bnd_key = (frm1_key, frm2_key)

                        inv_ = inv_dct.__getitem__
                        b_frm_bnd_key1 = tuple(map(inv_, brk_bnd_1))
                        b_frm_bnd_key2 = tuple(map(inv_, brk_bnd_2))
                        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=[brk_bnd_1, brk_bnd_2])
                        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[frm1_key] not in prds_atm_keys[1]:
                            prds_atm_keys = list(reversed(prds_atm_keys))

                        assert inv_dct[frm1_key] in prds_atm_keys[1]
                        assert inv_dct[frm2_key] in prds_atm_keys[1]

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

        return _rxns

    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)

        # Generate keys all bonds and 1/2 the forming bond
        frm1_keys = atom_keys(rct_gra)
        bnd_keys = bond_keys(rct_gra)

        frm2_keys = unsaturated_atom_keys(rct_gra)
        rct_symbs = atom_symbols(rct_gra)
        frm2_keys_o = frozenset(key for key in frm2_keys
                                if rct_symbs[key] == 'O')
        rxns.extend(_identify(frm1_keys, frm2_keys_o, bnd_keys))

        # OLD WAY. More IDs but more mistakes
        # To make the function general, try to ID reaction
        # with different types of keys for the attacking atom
        # (1) unsaturated atom sites
        # frm2_keys = unsaturated_atom_keys(rct_gra)
        # rxns.extend(_identify(frm1_keys, frm2_keys, bnd_keys))
        # if not rxns:
        #     # (2) remaining saturated atom sites
        #     frm2_keys = atom_keys(rct_gra, excl_syms=('H',)) - frm2_keys
        #     rxns.extend(_identify(frm1_keys, frm2_keys, bnd_keys))
        #     # if not rxns:  # Ignoring H2 formation for now for speed
        #     #     # (3) H atoms
        #     #     frm1_keys = atom_keys(rct_gra, sym='H')
        #     #     rxns.extend(_identify(frm1_keys, frm2_keys, bnd_keys))

    return ts_unique(rxns)
Esempio n. 11
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:
        rgra, = rct_gras
        pgra = union_from_sequence(prd_gras)

        rngb_keys = atoms_sorted_neighbor_atom_keys(rgra)

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

        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
            rgra_ = add_bonds(rgra, [(frm2_key, frm1_key)])

            # Get keys to the ring formed by this extra bond
            rng_keys = next((ks for ks in rings_atom_keys(rgra_)
                             if frm2_key in ks and frm1_key in ks), None)
            if rng_keys is not None:
                for nfrm2_key in rngb_keys[frm2_key]:
                    # Break the bond between the attacked atom and its neighbor
                    rgra_ = remove_bonds(rgra_, [(frm2_key, nfrm2_key)])

                    # Sort the ring keys so that they start with the radical
                    # atom and end with the hydrogen atom
                    keys = cycle_ring_atom_key_to_front(rng_keys,
                                                        frm1_key,
                                                        end_key=frm2_key)

                    # Break one ring bond at a time, starting from the rind,
                    # and see what we get
                    for brk_key1, brk_key2 in mit.windowed(keys[:-1], 2):
                        gra = remove_bonds(rgra_, [(brk_key1, brk_key2)])

                        inv_dct = full_isomorphism(gra, pgra)
                        if inv_dct:
                            f_frm_bnd_key = (frm2_key, frm1_key)
                            f_brk_bnd_key1 = (frm2_key, nfrm2_key)
                            f_brk_bnd_key2 = (brk_key1, brk_key2)
                            b_frm_bnd_key1 = (inv_dct[frm2_key],
                                              inv_dct[nfrm2_key])
                            b_frm_bnd_key2 = (inv_dct[brk_key1],
                                              inv_dct[brk_key2])
                            b_brk_bnd_key = (inv_dct[frm2_key],
                                             inv_dct[frm1_key])
                            forw_tsg = ts.graph(
                                rgra,
                                frm_bnd_keys=[f_frm_bnd_key],
                                brk_bnd_keys=[f_brk_bnd_key1, f_brk_bnd_key2])
                            back_tsg = ts.graph(
                                pgra,
                                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 tuple(rxns)