Esempio n. 1
0
def hydrogen_abstraction(xgr1, xgr2):
    """ find an addition transformation
    """
    assert xgr1 == _explicit(xgr1) and xgr2 == _explicit(xgr2)

    tra = None
    xgrs1 = _connected_components(xgr1)
    xgrs2 = _connected_components(xgr2)

    ret = formula.reac.argsort_hydrogen_abstraction(
        list(map(automol.convert.graph.formula, xgrs1)),
        list(map(automol.convert.graph.formula, xgrs2)))
    if ret is not None:
        idxs1, idxs2 = ret
        q1h_xgr, q2_xgr = list(map(xgrs1.__getitem__, idxs1))
        q1_xgr, q2h_xgr = list(map(xgrs2.__getitem__, idxs2))
        q1_tra = _partial_hydrogen_abstraction(q1h_xgr, q1_xgr)
        q2_rev_tra = _partial_hydrogen_abstraction(q2h_xgr, q2_xgr)
        if q1_tra and q2_rev_tra:
            xgr1_ = _union(apply(q1_tra, q1h_xgr), q2_xgr)
            xgr2_ = _union(q1_xgr, q2h_xgr)

            q2_tra = _reverse(q2_rev_tra, xgr2_, xgr1_)
            tra = from_data(frm_bnd_keys=formed_bond_keys(q2_tra),
                            brk_bnd_keys=broken_bond_keys(q1_tra))

    return tra
Esempio n. 2
0
def insertion(xgr1, xgr2):
    """ find an insertion transformation
    """
    assert xgr1 == _explicit(xgr1) and xgr2 == _explicit(xgr2)

    tra = None
    idxs = None
    xgrs1 = _connected_components(xgr1)
    xgrs2 = _connected_components(xgr2)
    if len(xgrs1) == 2 and len(xgrs2) == 1:
        xgrA, xgrB = xgrs1
        atmsA = automol.graph.atoms(xgrA)
        atmsB = automol.graph.atoms(xgrB)
        neighsA = automol.graph.atom_neighbor_keys(xgrA)
        neighsB = automol.graph.atom_neighbor_keys(xgrB)
        bndsA = automol.graph.bond_keys(xgrA)
        bndsB = automol.graph.bond_keys(xgrB)
        tra = _insertion(atmsA, neighsA, bndsA, atmsB, neighsB, xgr1, xgr2)
        idxs = [0, 1]
        if not tra:
            tra = _insertion(atmsB, neighsB, bndsB, atmsA, neighsA, xgr1, xgr2)
            if tra:
                idxs = [1, 0]
            else:
                idxs = None
    elif len(xgrs1) == 1 and len(xgrs2) == 1:
        xgrA = xgr1
        idxs = [0]
        atmsA = automol.graph.atoms(xgrA)
        neighsA = automol.graph.atom_neighbor_keys(xgrA)
        bndsA = automol.graph.bond_keys(xgrA)
        tra = _insertion(atmsA, neighsA, bndsA, atmsA, neighsA, xgr1, xgr2)
    return tra, idxs
Esempio n. 3
0
def addition(xgr1, xgr2):
    """ find an addition transformation
    """
    assert xgr1 == _explicit(xgr1) and xgr2 == _explicit(xgr2)

    tra = None
    xgrs1 = _connected_components(xgr1)
    xgrs2 = _connected_components(xgr2)

    if len(xgrs1) == 2 and len(xgrs2) == 1:
        x_xgr, y_xgr = xgrs1
        xgr2, = xgrs2
        x_atm_keys = _unsaturated_atom_keys(x_xgr)
        y_atm_keys = _unsaturated_atom_keys(y_xgr)
        xgeo = automol.graph.geometry(xgr2)
        for x_atm_key, y_atm_key in itertools.product(x_atm_keys, y_atm_keys):
            xy_xgr = _add_bonds(_union(x_xgr, y_xgr), [{x_atm_key, y_atm_key}])

            xgeo = automol.graph.geometry(xy_xgr)
            atm_key_dct = _full_isomorphism(xy_xgr, xgr2)
            if atm_key_dct:
                tra = from_data(frm_bnd_keys=[{x_atm_key, y_atm_key}],
                                brk_bnd_keys=[])

    return tra
Esempio n. 4
0
def proton_migration(xgr1, xgr2):
    """ find a proton migration transformation
    """
    assert xgr1 == _explicit(xgr1) and xgr2 == _explicit(xgr2)

    tras = []
    xgrs1 = _connected_components(xgr1)
    xgrs2 = _connected_components(xgr2)

    h_atm_key1 = max(_atom_keys(xgr1)) + 1
    h_atm_key2 = max(_atom_keys(xgr2)) + 1

    if len(xgrs1) == 1 and len(xgrs2) == 1:
        xgr1, = xgrs1
        xgr2, = xgrs2
        atm_keys1 = _unsaturated_atom_keys(xgr1)
        atm_keys2 = _unsaturated_atom_keys(xgr2)
        for atm_key1, atm_key2 in itertools.product(atm_keys1, atm_keys2):
            xgr1_h = _add_atom_explicit_hydrogen_keys(xgr1,
                                                      {atm_key1: [h_atm_key1]})
            xgr2_h = _add_atom_explicit_hydrogen_keys(xgr2,
                                                      {atm_key2: [h_atm_key2]})

            inv_atm_key_dct = _full_isomorphism(xgr2_h, xgr1_h)
            if inv_atm_key_dct:
                tras.append(
                    from_data(
                        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]
                        }]))
    if len(tras) < 1:
        tras = None
    return tras
Esempio n. 5
0
def substitution(xgr1, xgr2):
    """identifies substitution reactions
    """
    assert xgr1 == _explicit(xgr1) and xgr2 == _explicit(xgr2)

    tra = None
    idxs = None
    xgrs1 = _connected_components(xgr1)
    xgrs2 = _connected_components(xgr2)

    if len(xgrs1) == 2 and len(xgrs2) == 2:
        xgrA, xgrB = xgrs1
        xgrC, xgrD = xgrs2
        atmsA = automol.graph.atoms(xgrA)
        neighsA = automol.graph.atom_neighbor_keys(xgrA)
        bndsA = automol.graph.bond_keys(xgrA)
        atmsB = automol.graph.atoms(xgrB)
        neighsB = automol.graph.atom_neighbor_keys(xgrB)
        bndsB = automol.graph.bond_keys(xgrB)
        atmsC = automol.graph.atoms(xgrC)
        neighsC = automol.graph.atom_neighbor_keys(xgrC)
        bndsC = automol.graph.bond_keys(xgrC)
        atmsD = automol.graph.atoms(xgrD)
        neighsD = automol.graph.atom_neighbor_keys(xgrD)
        bndsD = automol.graph.bond_keys(xgrD)
        tra = _substitution(atmsA, neighsA, bndsA, atmsB, neighsB, xgr1, xgr2)
        idxs = [[0, 1], [0, 1]]
        if not tra:
            tra = _substitution(atmsB, neighsB, bndsB, atmsA, neighsA, xgr1,
                                xgr2)
            idxs = [[0, 1], [1, 0]]
            if not tra:
                tra = _substitution(atmsC, neighsC, bndsC, atmsD, neighsD,
                                    xgr2, xgr1)
                idxs = [[1, 0], [0, 1]]
                if not tra:
                    tra = _substitution(atmsD, neighsD, bndsD, atmsC, neighsC,
                                        xgr2, xgr1)
                    idxs = [[1, 0], [1, 0]]
                    if not tra:
                        idxs = None

        # return not substitution for radical + unsaturated reactions
        unsat_atm_keys = automol.graph.unsaturated_atom_keys(xgrB)
        for key in unsat_atm_keys:
            if key in tra[0]:
                tra = None

    return tra, idxs
Esempio n. 6
0
def atom_stereo_coordinates(sgr):
    """ stereo-specific coordinates for this molecular graph
    """
    assert sgr == _explicit(sgr)
    last_xgr = None
    xgr = _without_stereo_parities(sgr)

    # first, get a set of non-stereo-specific coordinates for the graph
    atm_xyz_dct = _atom_coordinates(xgr)

    if has_stereo(sgr):
        full_atm_ste_par_dct = _atom_stereo_parities(sgr)
        full_bnd_ste_par_dct = _bond_stereo_parities(sgr)

        atm_keys = set()
        bnd_keys = set()

        while last_xgr != xgr:
            last_xgr = xgr
            atm_keys.update(stereogenic_atom_keys(xgr))
            bnd_keys.update(stereogenic_bond_keys(xgr))
            atm_ste_par_dct = {
                atm_key: full_atm_ste_par_dct[atm_key]
                for atm_key in atm_keys
            }
            bnd_ste_par_dct = {
                bnd_key: full_bnd_ste_par_dct[bnd_key]
                for bnd_key in bnd_keys
            }
            xgr, atm_xyz_dct = _correct_atom_stereo_coordinates(
                xgr, atm_ste_par_dct, atm_xyz_dct)
            xgr, atm_xyz_dct = _correct_bond_stereo_coordinates(
                xgr, bnd_ste_par_dct, atm_xyz_dct)

    return atm_xyz_dct
Esempio n. 7
0
def heuristic_geometry(xgr):
    """ heuristic geometry for this molecular graph
    """
    xgr = _explicit(xgr)
    atm_keys = sorted(_atom_keys(xgr))
    syms = dict_.values_by_key(_atom_symbols(xgr), atm_keys)
    xyzs = dict_.values_by_key(atom_stereo_coordinates(xgr), atm_keys)
    geo = automol.create.geom.from_data(syms, xyzs)
    return geo
Esempio n. 8
0
def _set_bond_stereo_from_coordinates(xgr, bnd_keys, atm_xyz_dct):
    assert xgr == _explicit(xgr)

    bnd_pars = [
        _bond_stereo_parity_from_coordinates(xgr, bnd_key, atm_xyz_dct)
        for bnd_key in bnd_keys
    ]
    xgr = _set_bond_stereo_parities(xgr, dict(zip(bnd_keys, bnd_pars)))
    return xgr
Esempio n. 9
0
def _set_atom_stereo_from_coordinates(xgr, atm_keys, atm_xyz_dct):
    assert xgr == _explicit(xgr)

    atm_pars = [
        _atom_stereo_parity_from_coordinates(xgr, atm_key, atm_xyz_dct)
        for atm_key in atm_keys
    ]
    xgr = _set_atom_stereo_parities(xgr, dict(zip(atm_keys, atm_pars)))
    return xgr
Esempio n. 10
0
def stereogenic_bond_keys(xgr):
    """ (unassigned) stereogenic bonds in this graph
    """
    xgr = _without_bond_orders(xgr)
    xgr = _explicit(xgr)  # for simplicity, add the explicit hydrogens back in
    bnd_keys = dict_.keys_by_value(_resonance_dominant_bond_orders(xgr),
                                   lambda x: 2 in x)

    # make sure both ends are sp^2 (excludes cumulenes)
    atm_hyb_dct = _resonance_dominant_atom_hybridizations(xgr)
    sp2_atm_keys = dict_.keys_by_value(atm_hyb_dct, lambda x: x == 2)
    bnd_keys = frozenset(
        {bnd_key
         for bnd_key in bnd_keys if bnd_key <= sp2_atm_keys})

    bnd_keys -= bond_stereo_keys(xgr)
    bnd_keys -= functools.reduce(  # remove double bonds in small rings
        frozenset.union, filter(lambda x: len(x) < 8, _rings_bond_keys(xgr)),
        frozenset())

    atm_ngb_keys_dct = _atom_neighbor_keys(xgr)

    def _is_stereogenic(bnd_key):
        atm1_key, atm2_key = bnd_key

        def _is_symmetric_on_bond(atm_key, atm_ngb_key):
            atm_ngb_keys = list(atm_ngb_keys_dct[atm_key] - {atm_ngb_key})

            if not atm_ngb_keys:  # C=:O:
                ret = True
            elif len(atm_ngb_keys) == 1:  # C=N:-X
                ret = False
            else:
                assert len(atm_ngb_keys) == 2  # C=C(-X)-Y
                ret = (stereo_priority_vector(
                    xgr, atm_key, atm_ngb_keys[0]) == stereo_priority_vector(
                        xgr, atm_key, atm_ngb_keys[1]))

            return ret

        return not (_is_symmetric_on_bond(atm1_key, atm2_key)
                    or _is_symmetric_on_bond(atm2_key, atm1_key))

    ste_gen_bnd_keys = frozenset(filter(_is_stereogenic, bnd_keys))
    return ste_gen_bnd_keys
Esempio n. 11
0
def stereogenic_atom_keys(xgr):
    """ (unassigned) stereogenic atoms in this graph
    """
    xgr = _without_bond_orders(xgr)
    xgr = _explicit(xgr)  # for simplicity, add the explicit hydrogens back in
    atm_keys = dict_.keys_by_value(_atom_bond_valences(xgr), lambda x: x == 4)
    atm_keys -= atom_stereo_keys(xgr)

    atm_ngb_keys_dct = _atom_neighbor_keys(xgr)

    def _is_stereogenic(atm_key):
        atm_ngb_keys = list(atm_ngb_keys_dct[atm_key])
        pri_vecs = [
            stereo_priority_vector(xgr, atm_key, atm_ngb_key)
            for atm_ngb_key in atm_ngb_keys
        ]
        return not any(pv1 == pv2
                       for pv1, pv2 in itertools.combinations(pri_vecs, r=2))

    ste_gen_atm_keys = frozenset(filter(_is_stereogenic, atm_keys))
    return ste_gen_atm_keys
Esempio n. 12
0
def rotational_bond_keys(xgr, with_h_rotors=True):
    """ determine rotational bonds in this molecular graph
    """
    xgr = _explicit(xgr)
    atm_bnd_vlc_dct = _atom_bond_valences(xgr, bond_order=False)
    atm_exp_hyd_vlc_dct = _atom_explicit_hydrogen_valences(xgr)
    res_dom_bnd_ords_dct = resonance_dominant_bond_orders(xgr)

    bnd_keys = []
    for bnd_key, bnd_ords in res_dom_bnd_ords_dct.items():
        if all(bnd_ord <= 1 for bnd_ord in bnd_ords):
            atm_keys = list(bnd_key)
            bnd_ord = min(bnd_ords)
            rot_vlcs = numpy.array(
                list(map(atm_bnd_vlc_dct.__getitem__, atm_keys)))
            rot_vlcs -= bnd_ord
            if not with_h_rotors:
                atm_exp_hyd_vlcs = numpy.array(list(
                    map(atm_exp_hyd_vlc_dct.__getitem__, atm_keys)))
                rot_vlcs -= atm_exp_hyd_vlcs
            if all(rot_vlcs):
                bnd_keys.append(bnd_key)

    return frozenset(bnd_keys)
Esempio n. 13
0
def _connected_graph_atom_coordinates(sgr):
    """ non-stereo-specific coordinates for a connected molecular graph

    (currently assumes a with at most one ring -- fix that)
    """
    assert sgr == _explicit(sgr)

    atm_keys = _atom_keys(sgr)
    rng_atm_keys_lst = _rings_sorted_atom_keys(sgr)

    if len(atm_keys) == 1:
        atm1_key, = atm_keys
        atm_xyz_dct = {}
        atm_xyz_dct[atm1_key] = (0., 0., 0.)
    elif len(atm_keys) == 2:
        atm1_key, atm2_key = atm_keys

        atm1_xyz = (0., 0., 0.)

        dist = _bond_distance(sgr, atm2_key, atm1_key)
        atm2_xyz = cart.vec.from_internals(dist=dist, xyz1=atm1_xyz)
        atm_xyz_dct = {}
        atm_xyz_dct[atm1_key] = tuple(atm1_xyz)
        atm_xyz_dct[atm2_key] = tuple(atm2_xyz)
    elif not rng_atm_keys_lst:
        atm_ngb_keys_dct = _atom_neighbor_keys(sgr)

        # start assigning coordinates along the longest chain
        max_chain = longest_chain(sgr)
        atm2_key, atm3_key = max_chain[:2]

        # add a dummy atom to start the chain
        atm1_key = max(atm_keys) + 1
        sgr = _add_atoms(sgr, {atm1_key: 'X'})

        atm1_xyz = (0., 0., -5.)
        atm2_xyz = (0., 0., 0.)

        dist = _bond_distance(sgr, atm3_key, atm2_key)
        ang = numpy.pi / 2.
        atm3_xyz = cart.vec.from_internals(dist=dist,
                                           xyz1=atm2_xyz,
                                           ang=ang,
                                           xyz2=atm1_xyz)

        atm_xyz_dct = {}
        atm_xyz_dct[atm1_key] = tuple(atm1_xyz)
        atm_xyz_dct[atm2_key] = tuple(atm2_xyz)
        atm_xyz_dct[atm3_key] = tuple(atm3_xyz)

        atm_xyz_dct = _extend_atom_coordinates(sgr, atm1_key, atm2_key,
                                               atm3_key, atm_xyz_dct)

        atm_ngb_keys_dct = _atom_neighbor_keys(sgr)
        atm4_keys = sorted(atm_ngb_keys_dct[atm3_key] - {atm2_key})
        for atm4_key in atm4_keys:
            atm_xyz_dct = _extend_atom_coordinates(sgr, atm4_key, atm3_key,
                                                   atm2_key, atm_xyz_dct)

        # we don't actually need to remove it from sgr, but fwiw
        sgr = _remove_atoms(sgr, {atm1_key})
        atm_xyz_dct.pop(atm1_key)
    elif len(rng_atm_keys_lst) == 1:
        # for now, we'll assume only one ring
        rng_atm_keys, = rng_atm_keys_lst
        rng_atm_xyzs = _polygon_coordinates(num=len(rng_atm_keys))

        atm_xyz_dct = dict(zip(rng_atm_keys, rng_atm_xyzs))

        assert len(rng_atm_keys) >= 3
        trip_iter = mit.windowed(rng_atm_keys[-2:] + rng_atm_keys, 3)
        for atm1_key, atm2_key, atm3_key in trip_iter:
            atm_xyz_dct = _extend_atom_coordinates(sgr, atm1_key, atm2_key,
                                                   atm3_key, atm_xyz_dct)
    else:
        raise NotImplementedError("This algorithm is currently not implemented"
                                  "for more than one ring.")

    return atm_xyz_dct
Esempio n. 14
0
def elimination(xgr1, xgr2):
    """identifies elimination reactions
    """
    assert xgr1 == _explicit(xgr1) and xgr2 == _explicit(xgr2)
    tra = None
    xgrs1 = _connected_components(xgr1)
    xgrs2 = _connected_components(xgr2)
    tras = []
    if len(xgrs1) == 1 and len(xgrs2) == 2:
        atms = automol.graph.atoms(xgr1)
        neighs = automol.graph.atom_neighbor_keys(xgr1)
        bnds = automol.graph.bond_keys(xgr1)
        lonepairs = automol.graph.atom_lone_pair_counts(xgr1)
        for atmi in atms:
            i_neighs = neighs[atmi]
            for atmj in i_neighs:
                bnd_break_key_ij = _get_bnd_key(atmi, atmj, bnds)
                new_xgr = automol.graph.remove_bonds(xgr1, [bnd_break_key_ij])
                new_xgrs = _connected_components(new_xgr)
                if len(new_xgrs) == 2:
                    xgrA, xgrB = new_xgrs
                    atmsA = automol.graph.atoms(xgrA)
                    if atmi not in atmsA.keys():
                        xgrB, xgrA = xgrA, xgrB
                        atmsA = automol.graph.atoms(xgrA)
                    neighsA = automol.graph.atom_neighbor_keys(xgrA)
                    atmsB = automol.graph.atoms(xgrB)
                    neighs_i = neighsA[atmi]
                    for atmk in atmsB:
                        if lonepairs[atmk] > 0:
                            for atml in neighs_i:
                                neighs_l = neighsA[atml]
                                if atml != atmj:
                                    bnd_break_key_il = _get_bnd_key(
                                        atmi, atml, bnds)
                                    bnd_form_key_kl = frozenset({atmk, atml})
                                    newnew_xgr = automol.graph.remove_bonds(
                                        new_xgr, [bnd_break_key_il])
                                    newnew_xgr = automol.graph.add_bonds(
                                        newnew_xgr, [bnd_form_key_kl])
                                    atm_key_dct = _full_isomorphism(
                                        newnew_xgr, xgr2)
                                    if atm_key_dct:
                                        tra = [[bnd_form_key_kl],
                                               [
                                                   bnd_break_key_ij,
                                                   bnd_break_key_il
                                               ]]
                                        return tra
                                for atmm in neighs_l:
                                    if atmm != atmi:
                                        bnd_break_key_lm = _get_bnd_key(
                                            atml, atmm, bnds)
                                        bnd_form_key_km = frozenset(
                                            {atmk, atmm})
                                        newnew_xgr = automol.graph.remove_bonds(
                                            new_xgr, [bnd_break_key_lm])
                                        newnew_xgr = automol.graph.add_bonds(
                                            newnew_xgr, [bnd_form_key_km])
                                        atm_key_dct = _full_isomorphism(
                                            newnew_xgr, xgr2)
                                        if atm_key_dct:
                                            tras.append([[bnd_form_key_km],
                                                         [
                                                             bnd_break_key_ij,
                                                             bnd_break_key_lm
                                                         ]])
    if len(tras) < 1:
        tras = None
    return tras