Example #1
0
def _decompose_ring_system_atom_keys(rsy):
    """ decompose a ring system into a ring and a series of arcs
    """
    # sort from smallest to largest
    rngs_pool = sorted(rings(rsy),
                       key=lambda x: atom_count(x, with_implicit=False))

    decomp = ()
    decomp_bnd_keys = set({})

    rng = rngs_pool.pop(0)
    bnd_keys = bond_keys(rng)
    atm_keys = sorted_ring_atom_keys_from_bond_keys(bnd_keys)

    decomp += (atm_keys, )
    decomp_bnd_keys.update(bnd_keys)

    while rngs_pool:
        decomp_rsy = bond_induced_subgraph(rsy, decomp_bnd_keys)
        for idx, rng in enumerate(rngs_pool):
            arcs = ring_arc_complement_atom_keys(decomp_rsy, rng)
            if arcs:
                rngs_pool.pop(idx)
                decomp += arcs
                decomp_bnd_keys.update(bond_keys(rng))

    return decomp
Example #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 = atoms(xgra)
        atmsb = atoms(xgrb)
        neighsa = atom_neighbor_keys(xgra)
        neighsb = atom_neighbor_keys(xgrb)
        bndsa = bond_keys(xgra)
        bndsb = 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 = atoms(xgra)
        neighsa = atom_neighbor_keys(xgra)
        bndsa = bond_keys(xgra)
        tra = _insertion(atmsa, neighsa, bndsa, atmsa, neighsa, xgr1, xgr2)
    return tra, idxs
Example #3
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)

    print('len xgrs test:', len(xgrs1), len(xgrs2))
    print('xgrs test:', xgrs1, xgrs2)

    if len(xgrs1) == 2 and len(xgrs2) == 2:
        xgra, xgrb = xgrs1
        xgrc, xgrd = xgrs2
        atmsa = atoms(xgra)
        neighsa = atom_neighbor_keys(xgra)
        bndsa = bond_keys(xgra)
        atmsb = atoms(xgrb)
        neighsb = atom_neighbor_keys(xgrb)
        bndsb = bond_keys(xgrb)
        atmsc = atoms(xgrc)
        neighsc = atom_neighbor_keys(xgrc)
        bndsc = bond_keys(xgrc)
        atmsd = atoms(xgrd)
        neighsd = atom_neighbor_keys(xgrd)
        bndsd = bond_keys(xgrd)
        tra = _substitution(atmsa, neighsa, bndsa, atmsb, xgr1, xgr2)
        # tra = _substitution(
        # atmsa, neighsa, bndsa, atmsb, neighsb, xgr1, xgr2)
        idxs = [[0, 1], [0, 1]]
        if not tra:
            tra = _substitution(atmsb, neighsb, bndsb, atmsa, xgr1, xgr2)
            # atmsb, neighsb, bndsb, atmsa, neighsa, xgr1, xgr2)
            idxs = [[0, 1], [1, 0]]
            if not tra:
                tra = _substitution(atmsc, neighsc, bndsc, atmsd, xgr2, xgr1)
                # atmsc, neighsc, bndsc, atmsd, neighsd, xgr2, xgr1)
                idxs = [[1, 0], [0, 1]]
                if not tra:
                    tra = _substitution(atmsd, neighsd, bndsd, atmsc, xgr2,
                                        xgr1)
                    # 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 = _unsaturated_atom_keys(xgra)
        # print('unsat test:', tra[0][0], unsat_atm_keys)
        tra_list = list(tra[0])
        for key in unsat_atm_keys:
            if key in tra_list[0]:
                pass
                # tra = None
                # commented out the tra = None and added pass to run CO + HO2

    return tra, idxs
Example #4
0
def bond_symmetry_numbers(gra, frm_bnd_key=None, brk_bnd_key=None):
    """ symmetry numbers, by bond

    the (approximate) symmetry number of the torsional potential for this bond,
    based on the hydrogen counts for each atom
    It is reduced to 1 if one of the H atoms in the torsional bond is a
    neighbor to the special bonding atom (the atom that is being transferred)
    """
    imp_gra = implicit(gra)
    atm_imp_hyd_vlc_dct = atom_implicit_hydrogen_valences(imp_gra)

    bnd_keys = bond_keys(imp_gra)

    tfr_atm = None
    if frm_bnd_key and brk_bnd_key:
        for atm_f in list(frm_bnd_key):
            for atm_b in list(brk_bnd_key):
                if atm_f == atm_b:
                    tfr_atm = atm_f

        if tfr_atm:
            neighbor_dct = atoms_neighbor_atom_keys(gra)
            nei_tfr = neighbor_dct[tfr_atm]

            atms = gra[0]
            all_hyds = []
            for atm in atms:
                if atms[atm][0] == 'H':
                    all_hyds.append(atm)
        else:
            nei_tfr = {}

    bnd_symb_num_dct = {}
    bnd_symb_nums = []
    for bnd_key in bnd_keys:
        bnd_sym = 1
        vlc = max(map(atm_imp_hyd_vlc_dct.__getitem__, bnd_key))
        if vlc == 3:
            bnd_sym = 3
            if tfr_atm:
                for atm in nei_tfr:
                    nei_s = neighbor_dct[atm]
                    h_nei = 0
                    for nei in nei_s:
                        if nei in all_hyds:
                            h_nei += 1
                    if h_nei == 3:
                        bnd_sym = 1
        bnd_symb_nums.append(bnd_sym)

    bnd_symb_num_dct = dict(zip(bnd_keys, bnd_symb_nums))

    # fill in the rest of the bonds for completeness
    bnd_symb_num_dct = dict_.by_key(bnd_symb_num_dct,
                                    bond_keys(gra),
                                    fill_val=1)

    return bnd_symb_num_dct
Example #5
0
def closest_unbonded_atoms(geo, gra=None):
    """ Determine which pair of unbonded atoms in a molecular geometry
        are closest together.

        :param geo: molecular geometry
        :type geo: automol geometry data structure
        :param gra: the graph describing connectivity; if None, a connectivity
            graph will be generated using default distance thresholds
        :type gra: automol graph data structure
        :rtype: (frozenset(int), float)
    """

    gra = _connectivity_graph(geo) if gra is None else gra
    atm_keys = atom_keys(gra)
    bnd_keys = bond_keys(gra)
    poss_bnd_keys = set(map(frozenset, itertools.combinations(atm_keys, r=2)))

    # The set of candidates includes all unbonded pairs of atoms
    cand_bnd_keys = poss_bnd_keys - bnd_keys

    min_bnd_key = None
    min_dist_val = 1000.
    for bnd_key in cand_bnd_keys:
        dist_val = distance(geo, *bnd_key)
        if dist_val < min_dist_val:
            min_dist_val = dist_val
            min_bnd_key = bnd_key

    return min_bnd_key, min_dist_val
Example #6
0
def ring_system_decomposed_atom_keys(rsy, rng_keys=None, check=True):
    """ decomposed atom keys for a polycyclic ring system in a graph

    The ring system is decomposed into a ring and a series of arcs that can
    be used to successively construct the system

    :param rsy: the ring system
    :param rng_keys: keys for the first ring in the decomposition; if None, the
        smallest ring in the system will be chosen
    """
    if rng_keys is None:
        rng = sorted(rings(rsy), key=atom_count)[0]
        rng_keys = sorted_ring_atom_keys(rng)

    # check the arguments, if requested
    if check:
        # check that the graph is connected
        assert is_connected(rsy), "Ring system can't be disconnected."

        # check that the graph is actually a ring system
        assert is_ring_system(rsy), (
            "This is not a ring system graph:\n{:s}".format(string(rsy)))

        # check that rng is a subgraph of rsy
        assert set(rng_keys) <= atom_keys(rsy), (
            "{}\n^ Rings system doesn't contain ring as subgraph:\n{}".format(
                string(rsy, one_indexed=False), str(rng_keys)))

    bnd_keys = list(mit.windowed(rng_keys + rng_keys[:1], 2))

    # Remove bonds for the ring
    rsy = remove_bonds(rsy, bnd_keys)
    keys_lst = [rng_keys]
    done_keys = set(rng_keys)

    while bond_keys(rsy):

        # Determine shortest paths for the graph with one more ring/arc deleted
        sp_dct = atom_shortest_paths(rsy)

        # The shortest path will be the next shortest arc in the system
        arc_keys = min((sp_dct[i][j]
                        for i, j in itertools.combinations(done_keys, 2)
                        if j in sp_dct[i]),
                       key=len)

        # Add this arc to the list
        keys_lst.append(arc_keys)

        # Add these keys to the list of done keys
        done_keys |= set(arc_keys)

        # Delete tbond keys for the new arc and continue to the next iteration
        bnd_keys = list(map(frozenset, mit.windowed(arc_keys, 2)))
        rsy = remove_bonds(rsy, bnd_keys)

    keys_lst = tuple(map(tuple, keys_lst))
    return keys_lst
Example #7
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)
Example #8
0
def rotational_bond_keys(gra, lin_keys=None, with_h_rotors=True):
    """ get all rotational bonds for a graph

    :param gra: the graph
    :param lin_keys: keys to linear atoms in the graph
    """
    gra = explicit(gra)
    sym_dct = atom_symbols(gra)
    ngb_keys_dct = atoms_neighbor_atom_keys(gra)
    bnd_ord_dct = resonance_dominant_bond_orders(gra)
    rng_bnd_keys = list(itertools.chain(*rings_bond_keys(gra)))

    def _is_rotational_bond(bnd_key):
        ngb_keys_lst = [ngb_keys_dct[k] - bnd_key for k in bnd_key]

        is_single = max(bnd_ord_dct[bnd_key]) <= 1
        has_neighbors = all(ngb_keys_lst)
        not_in_ring = bnd_key not in rng_bnd_keys

        is_h_rotor = any(
            set(map(sym_dct.__getitem__, ks)) == {'H'} for ks in ngb_keys_lst)

        return is_single and has_neighbors and not_in_ring and (
            not is_h_rotor or with_h_rotors)

    rot_bnd_keys = frozenset(filter(_is_rotational_bond, bond_keys(gra)))

    lin_keys_lst = linear_segments_atom_keys(gra, lin_keys=lin_keys)
    dum_keys = tuple(atom_keys(gra, sym='X'))
    for keys in lin_keys_lst:
        bnd_keys = sorted((k for k in rot_bnd_keys if k & set(keys)),
                          key=sorted)

        # Check whether there are neighboring atoms on either side of the
        # linear segment
        excl_keys = set(keys) | set(dum_keys)

        end_key1 = atom_neighbor_atom_key(gra,
                                          keys[0],
                                          excl_atm_keys=excl_keys)

        excl_keys |= {end_key1}
        end_key2 = atom_neighbor_atom_key(gra,
                                          keys[-1],
                                          excl_atm_keys=excl_keys)

        end_keys = {end_key1, end_key2}
        ngb_keys_lst = [ngb_keys_dct[k] - excl_keys for k in end_keys]
        has_neighbors = all(ngb_keys_lst)

        if not has_neighbors:
            rot_bnd_keys -= set(bnd_keys)
        else:
            rot_bnd_keys -= set(bnd_keys[:-1])

    return rot_bnd_keys
Example #9
0
def rings_bond_keys(gra):
    """ bond keys for each ring in the graph (minimal basis)
    """
    bnd_keys = bond_keys(gra)

    def _ring_bond_keys(rng_atm_keys):
        return frozenset(filter(lambda x: x <= rng_atm_keys, bnd_keys))

    nxg = _networkx.from_graph(gra)
    rng_atm_keys_lst = _networkx.minimum_cycle_basis(nxg)
    rng_bnd_keys_lst = frozenset(map(_ring_bond_keys, rng_atm_keys_lst))
    return rng_bnd_keys_lst
Example #10
0
def ring_arc_complement_atom_keys(gra, rng):
    """ non-intersecting arcs from a ring that shares segments with a graph
    """
    gra_atm_bnd_dct = atoms_bond_keys(gra)
    rng_atm_bnd_dct = atoms_bond_keys(rng)

    # 1. find divergence points, given by the atom at which the divergence
    # occurs and the bond followed by the ring as it diverges
    div_dct = {}

    for atm_key in atom_keys(gra) & atom_keys(rng):
        div = rng_atm_bnd_dct[atm_key] - gra_atm_bnd_dct[atm_key]
        if div:
            bnd_key, = div
            div_dct[atm_key] = bnd_key

    # 2. cycle through the ring atoms; if you meet a starting divergence, start
    # an arc; extend the arc until you meet an ending divergence; repeat until
    # all divergences are accounted for
    atm_keys = sorted_ring_atom_keys_from_bond_keys(bond_keys(rng))

    arcs = []
    arc = []
    for atm_key, next_atm_key in mit.windowed(itertools.cycle(atm_keys), 2):
        bnd_key = frozenset({atm_key, next_atm_key})

        # if we haven't started an arc, see if we are at a starting divergence;
        # if so, start the arc now and cross the divergence from our list
        if not arc:
            if atm_key in div_dct and div_dct[atm_key] == bnd_key:
                div_dct.pop(atm_key)

                arc.append(atm_key)
        # if we've started an arc, extend it; then, check if we are at an
        # ending divergence; if so, end the arc and cross the divergence from
        # our list; add it to our list of arcs
        else:
            arc.append(atm_key)

            if next_atm_key in div_dct and div_dct[next_atm_key] == bnd_key:
                div_dct.pop(next_atm_key)

                arc.append(next_atm_key)
                arcs.append(arc)
                arc = []

        # if no divergences are left, break out of the loop
        if not div_dct:
            break

    arcs = tuple(map(tuple, arcs))
    return arcs
Example #11
0
def one_resonance_dominant_bond_orders(rgr):
    """ resonance-dominant bond orders, by bond
    """
    rgr = without_fractional_bonds(rgr)
    bnd_keys = list(bond_keys(rgr))
    bnd_ords_by_res = [
        dict_.values_by_key(bond_orders(dom_rgr), bnd_keys)
        for dom_rgr in dominant_resonances(rgr)
    ]
    first_bnd_ords = [bnd_ords_by_res[0]]
    bnd_ords_lst = list(map(frozenset, zip(*first_bnd_ords)))
    bnd_dom_res_ords_dct = dict(zip(bnd_keys, bnd_ords_lst))
    return bnd_dom_res_ords_dct
Example #12
0
def equivalent_bonds(gra, bnd_key, stereo=True, dummy=True):
    """ Identify sets of isomorphically equivalent bonds

    Two bonds are equivalent if they transform into each other under an
    automorphism

    :param gra: A graph
    :param bnd_key: An bond key for the graph, which may be sorted or unsorted
    :param backbone_only: Compare backbone atoms only?
    :type stereo: bool
    :param dummy: Consider dummy atoms?
    :type dummy: bool
    :returns: Keys to equivalent bonds
    :rtype: frozenset
    """
    bnd_key = tuple(bnd_key)
    bnd_keys = list(map(tuple, map(sorted, bond_keys(gra))))
    bnd_keys += list(map(tuple, map(reversed, bnd_keys)))
    assert bnd_key in bnd_keys, "{} not in {}".format(bnd_key, bnd_keys)

    atm_symb_dct = atom_symbols(gra)
    atm_ngbs_dct = atoms_neighbor_atom_keys(gra)

    def _symbols(bnd_key):
        return list(map(atm_symb_dct.__getitem__, bnd_key))

    def _neighbor_symbols(bnd_key):
        key1, key2 = bnd_key
        nsymbs1 = sorted(map(atm_symb_dct.__getitem__, atm_ngbs_dct[key1]))
        nsymbs2 = sorted(map(atm_symb_dct.__getitem__, atm_ngbs_dct[key2]))
        return nsymbs1, nsymbs2

    # 1. Find bonds with the same atom types
    bnd_symbs = _symbols(bnd_key)
    cand_keys = [k for k in bnd_keys if _symbols(k) == bnd_symbs]

    # 2. Of those, find bonds with the same neighboring atom types
    bnd_ngb_symbs = _neighbor_symbols(bnd_key)
    cand_keys = [k for k in cand_keys if _neighbor_symbols(k) == bnd_ngb_symbs]

    # 3. Find the equivalent bonds from the list of candidates.
    # Strategy: Change the atom symbols to 'Lv' and 'Ts' and check for
    # isomorphism.  Assumes none of the compounds have element 116 or 117.
    ref_gra = set_atom_symbols(gra, {bnd_key[0]: 'Lv', bnd_key[1]: 'Ts'})
    bnd_keys = []
    for key in cand_keys:
        comp_gra = set_atom_symbols(gra, {key[0]: 'Lv', key[1]: 'Ts'})
        if isomorphism(ref_gra, comp_gra, stereo=stereo, dummy=dummy):
            bnd_keys.append(key)

    return frozenset(bnd_keys)
Example #13
0
def resonance_avg_bond_orders(rgr):
    """ resonance-dominant bond orders, by bond
    """
    rgr = without_fractional_bonds(rgr)
    bnd_keys = list(bond_keys(rgr))
    bnd_ords_by_res = [
        dict_.values_by_key(bond_orders(dom_rgr), bnd_keys)
        for dom_rgr in dominant_resonances(rgr)
    ]
    nres = len(bnd_ords_by_res)
    bnd_ords_lst = zip(*bnd_ords_by_res)
    avg_bnd_ord_lst = [sum(bnd_ords) / nres for bnd_ords in bnd_ords_lst]
    avg_bnd_ord_dct = dict(zip(bnd_keys, avg_bnd_ord_lst))
    return avg_bnd_ord_dct
Example #14
0
def from_graph(gra):
    """ networkx graph object from a molecular graph
    """
    nxg = networkx.Graph()
    nxg.add_nodes_from(atom_keys(gra))
    nxg.add_edges_from(bond_keys(gra))
    networkx.set_node_attributes(nxg, atom_symbols(gra), 'symbol')
    networkx.set_node_attributes(nxg, atom_implicit_hydrogen_valences(gra),
                                 'implicit_hydrogen_valence')
    networkx.set_node_attributes(nxg, atom_stereo_parities(gra),
                                 'stereo_parity')
    networkx.set_edge_attributes(nxg, bond_orders(gra), 'order')
    networkx.set_edge_attributes(nxg, bond_stereo_parities(gra),
                                 'stereo_parity')

    return nxg
Example #15
0
def angle_keys(gra):
    """ triples of keys for pairs of adjacent bonds, with the central atom in
    the middle
    """
    bnd_keys = bond_keys(gra)

    ang_keys = []
    for bnd_key1, bnd_key2 in itertools.combinations(bnd_keys, r=2):
        if bnd_key1 != bnd_key2 and bnd_key1 & bnd_key2:
            atm2_key, = bnd_key1 & bnd_key2
            atm1_key, = bnd_key1 - {atm2_key}
            atm3_key, = bnd_key2 - {atm2_key}
            ang_keys.append((atm1_key, atm2_key, atm3_key))
            ang_keys.append((atm3_key, atm2_key, atm1_key))

    return tuple(ang_keys)
Example #16
0
def frozen(gra):
    """ hashable, sortable, immutable container of graph data
    """
    atm_keys = sorted(atom_keys(gra))
    bnd_keys = sorted(bond_keys(gra), key=sorted)

    # make it sortable by replacing Nones with -infinity
    atm_vals = numpy.array(dict_.values_by_key(atoms(gra), atm_keys),
                           dtype=numpy.object)
    bnd_vals = numpy.array(dict_.values_by_key(bonds(gra), bnd_keys),
                           dtype=numpy.object)
    atm_vals[numpy.equal(atm_vals, None)] = -numpy.inf
    bnd_vals[numpy.equal(bnd_vals, None)] = -numpy.inf

    frz_atms = tuple(zip(atm_keys, map(tuple, atm_vals)))
    frz_bnds = tuple(zip(bnd_keys, map(tuple, bnd_vals)))
    return (frz_atms, frz_bnds)
Example #17
0
def inchi_with_sort_from_geometry(gra, geo=None, geo_idx_dct=None):
    """ Generate an InChI string from a molecular graph.
        If coordinates are passed in, they are used to determine stereo.

        :param gra: molecular graph
        :type gra: automol graph data structure
        :param geo: molecular geometry
        :type geo: automol geometry data structure
        :param geo_idx_dct:
        :type geo_idx_dct: dict[:]
        :rtype: (str, tuple(int))
    """
    gra = without_dummy_atoms(gra)
    gra = dominant_resonance(gra)
    atm_keys = sorted(atom_keys(gra))
    bnd_keys = list(bond_keys(gra))
    atm_syms = dict_.values_by_key(atom_symbols(gra), atm_keys)
    atm_bnd_vlcs = dict_.values_by_key(atom_bond_valences(gra), atm_keys)
    atm_rad_vlcs = dict_.values_by_key(atom_unsaturated_valences(gra),
                                       atm_keys)
    bnd_ords = dict_.values_by_key(bond_orders(gra), bnd_keys)

    if geo is not None:
        assert geo_idx_dct is not None
        atm_xyzs = coordinates(geo)
        atm_xyzs = [
            atm_xyzs[geo_idx_dct[atm_key]] if atm_key in geo_idx_dct else
            (0., 0., 0.) for atm_key in atm_keys
        ]
    else:
        atm_xyzs = None

    mlf, key_map_inv = _molfile.from_data(atm_keys,
                                          bnd_keys,
                                          atm_syms,
                                          atm_bnd_vlcs,
                                          atm_rad_vlcs,
                                          bnd_ords,
                                          atm_xyzs=atm_xyzs)
    rdm = _rdkit.from_molfile(mlf)
    ich, aux_info = _rdkit.to_inchi(rdm, with_aux_info=True)
    nums = _parse_sort_order_from_aux_info(aux_info)
    nums = tuple(map(key_map_inv.__getitem__, nums))

    return ich, nums
Example #18
0
def rotational_groups(gra, key1, key2, dummy=False):
    """ get the rotational groups for a given rotational axis

    :param gra: the graph
    :param key1: the first atom key
    :param key2: the second atom key
    """

    if not dummy:
        gra = without_dummy_atoms(gra)

    bnd_key = frozenset({key1, key2})
    assert bnd_key in bond_keys(gra)
    grp1 = branch_atom_keys(gra, key2, bnd_key) - {key1}
    grp2 = branch_atom_keys(gra, key1, bnd_key) - {key2}
    grp1 = tuple(sorted(grp1))
    grp2 = tuple(sorted(grp2))
    return grp1, grp2
Example #19
0
def qualitative_convergence_checker_(gra, keys, rqq_bond_max=1.8,
                                     rqh_bond_max=1.3, rhh_bond_max=1.1,
                                     bond_nobond_diff=0.3):
    """ a convergence checker for error minimization, checking that the
    geometry is qualitatively correct (correct connectivity and stereo)
    """
    symb_dct = atom_symbols(gra)
    pairs = set(map(frozenset, itertools.combinations(keys, 2)))

    bnd_keys = pairs & bond_keys(gra)
    nob_keys = pairs - bond_keys(gra)

    nob_symbs = tuple(tuple(map(symb_dct.__getitem__, nob_key))
                      for nob_key in nob_keys)
    bnd_symbs = tuple(tuple(map(symb_dct.__getitem__, bnd_key))
                      for bnd_key in bnd_keys)
    nob_idxs = tuple(tuple(map(keys.index, nob_key)) for nob_key in nob_keys)
    bnd_idxs = tuple(tuple(map(keys.index, bnd_key)) for bnd_key in bnd_keys)

    bnd_udists = tuple((rqq_bond_max if 'H' not in symb else
                        rhh_bond_max if set(symb) == {'H'} else
                        rqh_bond_max) for symb in bnd_symbs)

    diff = bond_nobond_diff
    nob_ldists = tuple((rqq_bond_max+diff if 'H' not in symb else
                        rhh_bond_max+diff if set(symb) == {'H'} else
                        rqh_bond_max+diff) for symb in nob_symbs)

    bnd_idxs += tuple(map(tuple, map(reversed, bnd_idxs)))
    bnd_idx_vecs = tuple(map(list, zip(*bnd_idxs)))
    bnd_udists *= 2

    nob_idxs += tuple(map(tuple, map(reversed, nob_idxs)))
    nob_idx_vecs = tuple(map(list, zip(*nob_idxs)))
    nob_ldists *= 2

    symbs = tuple(map(symb_dct.__getitem__, keys))
    geo_idx_dct = dict(map(reversed, enumerate(keys)))
    atm_ste_keys = atom_stereo_keys(gra) & set(keys)
    bnd_ste_keys = bond_stereo_keys(gra) & bnd_keys
    atm_ste_par_dct = atom_stereo_parities(gra)
    bnd_ste_par_dct = bond_stereo_parities(gra)

    def _is_converged(xmat, err, grad):
        assert err and numpy.any(grad)
        xyzs = xmat[:, :3]
        dmat = embed.distance_matrix_from_coordinates(xyzs)

        # check for correct connectivity
        connectivity_check = (
            (numpy.all(dmat[bnd_idx_vecs] < bnd_udists)
             if bnd_udists else True) and
            (numpy.all(dmat[nob_idx_vecs] > nob_ldists)
             if nob_ldists else True))

        # check for correct stereo parities
        geo = _create.geom.from_data(symbs, xyzs, angstrom=True)
        atom_stereo_check = all(
            (_atom_stereo_parity_from_geometry(gra, atm_key, geo, geo_idx_dct)
             == atm_ste_par_dct[atm_key])
            for atm_key in atm_ste_keys)

        bond_stereo_check = all(
            (_bond_stereo_parity_from_geometry(gra, bnd_key, geo, geo_idx_dct)
             == bnd_ste_par_dct[bnd_key])
            for bnd_key in bnd_ste_keys)

        return connectivity_check and atom_stereo_check and bond_stereo_check

    return _is_converged
Example #20
0
def sorted_ring_atom_keys(rng):
    """ get a ring's atom keys, sorted in order of connectivity
    """
    return sorted_ring_atom_keys_from_bond_keys(bond_keys(rng))
Example #21
0
 def _neighbor_keys(bnd_key, bnd_nbh):
     bnd_keys = bond_keys(bnd_nbh)
     bnd_keys -= {bnd_key}
     bnd_keys = frozenset(key for key in bnd_keys if key & bnd_key)
     return bnd_keys
Example #22
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 = atoms(xgr1)
        neighs = atom_neighbor_keys(xgr1)
        bnds = bond_keys(xgr1)
        radicals = _resonance_dominant_radical_atom_keys(xgr1)
        lonepairs = 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 = remove_bonds(xgr1, [bnd_break_key_ij])
                new_xgrs = _connected_components(new_xgr)
                if len(new_xgrs) == 2:
                    xgra, xgrb = new_xgrs
                    atmsa = atoms(xgra)
                    if atmi not in atmsa.keys():
                        xgrb, xgra = xgra, xgrb
                        atmsa = atoms(xgra)
                    neighsa = atom_neighbor_keys(xgra)
                    atmsb = atoms(xgrb)
                    neighs_i = neighsa[atmi]
                    for atmk in atmsb:
                        if atmk in radicals:
                            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 = remove_bonds(
                                        new_xgr, [bnd_break_key_il])
                                    newnew_xgr = 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 = remove_bonds(
                                            new_xgr, [bnd_break_key_lm])
                                        newnew_xgr = 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
                                                         ]])
        for atmi in atms:
            i_neighs = neighs[atmi]
            print('atmi test:', atmi)
            print('i_neighs test:', i_neighs)
            for atmj in i_neighs:
                bnd_break_key_ij = _get_bnd_key(atmi, atmj, bnds)
                new_xgr = remove_bonds(xgr1, [bnd_break_key_ij])
                new_xgrs = _connected_components(new_xgr)
                if len(new_xgrs) == 2:
                    xgra, xgrb = new_xgrs
                    atmsa = atoms(xgra)
                    if atmi not in atmsa.keys():
                        xgrb, xgra = xgra, xgrb
                        atmsa = atoms(xgra)
                    neighsa = atom_neighbor_keys(xgra)
                    atmsb = atoms(xgrb)
                    neighs_i = neighsa[atmi]
                    print('len atmsb test:', len(atmsb))
                    for atmk in atmsb:
                        if lonepairs[atmk] > 0 or len(atmsb) == 1:
                            # 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 = remove_bonds(
                                        new_xgr, [bnd_break_key_il])
                                    newnew_xgr = 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 = remove_bonds(
                                            new_xgr, [bnd_break_key_lm])
                                        newnew_xgr = 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