Beispiel #1
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
Beispiel #2
0
def longest_chain(xgr):
    """ longest chain in the graph
    """
    atm_keys = _atom_keys(xgr)

    max_chain = max((_longest_chain(xgr, atm_key) for atm_key in atm_keys),
                    key=len)
    return max_chain
Beispiel #3
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
Beispiel #4
0
def _correct_bond_stereo_coordinates(xgr, bnd_ste_par_dct, atm_xyz_dct):
    atm_ngb_keys_dct = _atom_neighbor_keys(xgr)

    bnd_keys = list(bnd_ste_par_dct.keys())
    for bnd_key in bnd_keys:
        par = bnd_ste_par_dct[bnd_key]
        curr_par = _bond_stereo_parity_from_coordinates(
            xgr, bnd_key, atm_xyz_dct)

        if curr_par != par:
            atm1_key, atm2_key = bnd_key
            atm1_xyz = atm_xyz_dct[atm1_key]
            atm2_xyz = atm_xyz_dct[atm2_key]

            atm1_ngb_keys = atm_ngb_keys_dct[atm1_key] - {atm2_key}
            atm2_ngb_keys = atm_ngb_keys_dct[atm2_key] - {atm1_key}
            atm1_ngb_keys = stereo_sorted_atom_neighbor_keys(
                xgr, atm1_key, atm1_ngb_keys)
            atm2_ngb_keys = stereo_sorted_atom_neighbor_keys(
                xgr, atm2_key, atm2_ngb_keys)

            rot_axis = numpy.subtract(atm2_xyz, atm1_xyz)
            rot_ = cart.vec.rotate_(rot_axis, numpy.pi, orig_xyz=atm1_xyz)

            rot_atm_keys = _atom_keys(
                _branch(xgr, atm2_key, {atm2_key, atm2_ngb_keys[0]}))

            if len(atm2_ngb_keys) > 1:
                assert len(atm2_ngb_keys) == 2
                rot_atm_keys |= _atom_keys(
                    _branch(xgr, atm2_key, {atm2_key, atm2_ngb_keys[1]}))

            rot_atm_keys = list(rot_atm_keys)

            rot_atm_xyzs = list(
                map(rot_, map(atm_xyz_dct.__getitem__, rot_atm_keys)))

            atm_xyz_dct.update(dict(zip(rot_atm_keys, rot_atm_xyzs)))

        assert _bond_stereo_parity_from_coordinates(xgr, bnd_key,
                                                    atm_xyz_dct) == par
        xgr = _set_bond_stereo_parities(xgr, {bnd_key: par})

    return xgr, atm_xyz_dct
Beispiel #5
0
def resonance_dominant_atom_hybridizations(rgr):
    """ resonance-dominant atom hybridizations, by atom
    """
    atm_keys = list(_atom_keys(rgr))
    atm_hybs_by_res = [
        dict_.values_by_key(atom_hybridizations(dom_rgr), atm_keys)
        for dom_rgr in dominant_resonances(rgr)]
    atm_hybs = [min(hybs) for hybs in zip(*atm_hybs_by_res)]
    atm_hyb_dct = dict(zip(atm_keys, atm_hybs))
    return atm_hyb_dct
Beispiel #6
0
def atom_longest_chains(xgr):
    """ longest chains, by atom
    """
    atm_keys = _atom_keys(xgr)

    long_chain_dct = {
        atm_key: _longest_chain(xgr, atm_key)
        for atm_key in atm_keys
    }
    return long_chain_dct
Beispiel #7
0
def _correct_atom_stereo_coordinates(xgr, atm_ste_par_dct, atm_xyz_dct):
    ring_atm_keys = set(itertools.chain(*_rings_sorted_atom_keys(xgr)))
    atm_ngb_keys_dct = _atom_neighbor_keys(xgr)

    atm_keys = list(atm_ste_par_dct.keys())
    for atm_key in atm_keys:
        par = atm_ste_par_dct[atm_key]
        curr_par = _atom_stereo_parity_from_coordinates(
            xgr, atm_key, atm_xyz_dct)
        atm_ngb_keys = atm_ngb_keys_dct[atm_key]

        if curr_par != par:
            # for now, we simply exclude rings from the pivot keys
            # (will not work for stereo atom at the intersection of two rings)
            atm_piv_keys = list(atm_ngb_keys - ring_atm_keys)[:2]
            assert len(atm_piv_keys) == 2
            atm3_key, atm4_key = atm_piv_keys
            atm_xyz = atm_xyz_dct[atm_key]
            atm3_xyz = atm_xyz_dct[atm3_key]
            atm4_xyz = atm_xyz_dct[atm4_key]
            rot_axis = cart.vec.unit_bisector(atm3_xyz,
                                              atm4_xyz,
                                              orig_xyz=atm_xyz)
            rot_ = cart.vec.rotate_(rot_axis, numpy.pi, orig_xyz=atm_xyz)

            rot_atm_keys = list(
                _atom_keys(_branch(xgr, atm_key, {atm_key, atm3_key}))
                | _atom_keys(_branch(xgr, atm_key, {atm_key, atm4_key})))

            rot_atm_xyzs = list(
                map(rot_, map(atm_xyz_dct.__getitem__, rot_atm_keys)))

            atm_xyz_dct.update(dict(zip(rot_atm_keys, rot_atm_xyzs)))

        new_par = _atom_stereo_parity_from_coordinates(xgr, atm_key,
                                                       atm_xyz_dct)

        assert new_par == par
        xgr = _set_atom_stereo_parities(xgr, {atm_key: par})

    return xgr, atm_xyz_dct
Beispiel #8
0
def sing_res_dom_radical_atom_keys(rgr):
    """ resonance-dominant radical atom keys,for one resonance
    """
    atm_keys = list(_atom_keys(rgr))
    atm_rad_vlcs_by_res = [
        dict_.values_by_key(_atom_unsaturated_valences(dom_rgr), atm_keys)
        for dom_rgr in dominant_resonances(rgr)]
    first_atm_rad_val = [atm_rad_vlcs_by_res[0]]
    atm_rad_vlcs = [max(rad_vlcs) for rad_vlcs in zip(*first_atm_rad_val)]
    atm_rad_keys = frozenset(atm_key for atm_key, atm_rad_vlc
                             in zip(atm_keys, atm_rad_vlcs) if atm_rad_vlc)
    return atm_rad_keys
Beispiel #9
0
def resonance_dominant_radical_atom_keys(rgr):
    """ resonance-dominant radical atom keys

    (keys of resonance-dominant radical sites)
    """
    atm_keys = list(_atom_keys(rgr))
    atm_rad_vlcs_by_res = [
        dict_.values_by_key(_atom_unsaturated_valences(dom_rgr), atm_keys)
        for dom_rgr in dominant_resonances(rgr)]
    atm_rad_vlcs = [max(rad_vlcs) for rad_vlcs in zip(*atm_rad_vlcs_by_res)]
    atm_rad_keys = frozenset(atm_key for atm_key, atm_rad_vlc
                             in zip(atm_keys, atm_rad_vlcs) if atm_rad_vlc)
    return atm_rad_keys
Beispiel #10
0
def atom_hybridizations(rgr):
    """ atom hybridizations, by atom
    """
    atm_keys = list(_atom_keys(rgr))
    atm_unsat_vlc_dct = _atom_unsaturated_valences(rgr, bond_order=True)
    atm_bnd_vlc_dct = _atom_bond_valences(rgr, bond_order=False)     # note!!
    atm_unsat_vlcs = numpy.array(
        dict_.values_by_key(atm_unsat_vlc_dct, atm_keys))
    atm_bnd_vlcs = numpy.array(dict_.values_by_key(atm_bnd_vlc_dct, atm_keys))
    atm_lpcs = numpy.array(
        dict_.values_by_key(_atom_lone_pair_counts(rgr), atm_keys))
    atm_hybs = atm_unsat_vlcs + atm_bnd_vlcs + atm_lpcs - 1
    atm_hyb_dct = dict_.transform_values(
        dict(zip(atm_keys, atm_hybs)), int)
    return atm_hyb_dct
Beispiel #11
0
def _partial_hydrogen_abstraction(qh_xgr, q_xgr):
    tra = None
    h_atm_key = max(_atom_keys(q_xgr)) + 1
    #rad_atm_keys = _resonance_dominant_radical_atom_keys(q_xgr)
    uns_atm_keys = automol.graph.unsaturated_atom_keys(q_xgr)
    for atm_key in uns_atm_keys:
        #for atm_key in rad_atm_keys:
        q_xgr_h = _add_atom_explicit_hydrogen_keys(q_xgr,
                                                   {atm_key: [h_atm_key]})
        inv_atm_key_dct = _full_isomorphism(q_xgr_h, qh_xgr)
        if inv_atm_key_dct:
            brk_bnd_keys = [
                frozenset(
                    {inv_atm_key_dct[atm_key], inv_atm_key_dct[h_atm_key]})
            ]
            tra = from_data(frm_bnd_keys=[], brk_bnd_keys=brk_bnd_keys)

    return tra
Beispiel #12
0
def subresonances(rgr):
    """ this connected graph and its lower-spin (more pi-bonded) resonances
    """
    def _inc_range(bnd_cap):
        return tuple(range(0, bnd_cap+1))

    add_pi_bonds_ = functools.partial(_add_pi_bonds, rgr)

    atm_keys = list(_atom_keys(rgr))
    bnd_keys = list(_bond_keys(rgr))
    atm_unsat_vlcs = dict_.values_by_key(
        _atom_unsaturated_valences(rgr), atm_keys)
    atm_bnd_keys_lst = dict_.values_by_key(_atom_bond_keys(rgr), atm_keys)
    bnd_caps = dict_.values_by_key(_bond_capacities(rgr), bnd_keys)
    bnd_ord_dct = _bond_orders(rgr)

    def _is_valid(bnd_ord_inc_dct):
        # check if pi bonds exceed unsaturated valences
        def __tally(atm_bnd_keys):
            return sum(dict_.values_by_key(bnd_ord_inc_dct, atm_bnd_keys))
        atm_unsat_vlc_decs = tuple(map(__tally, atm_bnd_keys_lst))
        enough_elecs = numpy.all(
            numpy.less_equal(atm_unsat_vlc_decs, atm_unsat_vlcs))
        # check if all bond orders are less than 4 (should only affect C2)
        bnd_inc_keys = bnd_ord_inc_dct.keys()
        bnd_incs = dict_.values_by_key(bnd_ord_inc_dct, bnd_inc_keys)
        bnd_ords = dict_.values_by_key(bnd_ord_dct, bnd_inc_keys)
        new_bnd_ords = numpy.add(bnd_ords, bnd_incs)
        not_too_many = numpy.all(numpy.less(new_bnd_ords, 4))
        return enough_elecs and not_too_many

    def _bond_value_dictionary(bnd_vals):
        return dict(zip(bnd_keys, bnd_vals))

    bnd_ord_incs_itr = itertools.product(*map(_inc_range, bnd_caps))
    bnd_ord_inc_dct_itr = map(_bond_value_dictionary, bnd_ord_incs_itr)
    bnd_ord_inc_dct_itr = filter(_is_valid, bnd_ord_inc_dct_itr)
    rgrs = tuple(sorted(map(add_pi_bonds_, bnd_ord_inc_dct_itr), key=_frozen))
    return rgrs
Beispiel #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