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
def continue_ring_system(gra, keys_lst, vma, zma_keys): """ continue constructing a v-matrix for a ring system Exactly one atom in the ring system must already be in the v-matrix, and this atom must be in the starting ring of the decomposed ring system key list. """ # First, get the ring keys keys_lst = list(keys_lst) keys = keys_lst.pop(0) # Break the bonds joining the last pair of atoms in each arc gra = remove_bonds(gra, [(k[-1], k[-2]) for k in keys_lst]) # Start by constructing the v-matrix for the first ring vma, zma_keys = continue_ring(gra, keys, vma, zma_keys) # Now, complete the ring system by continuing the v-matrix along each arc for keys in keys_lst: # Note that the atoms on each end of the arc are already in the # v-matrix, so we ignore those vma, zma_keys = continue_chain(gra, keys[1:-1], vma, zma_keys, term_hydrogens=False) return vma, zma_keys
def ring_system(gra, keys_lst): """ generate a v-matrix for a ring system :param gra: the graph :param keys_lst: the first entry contains keys for a ring and each next one contains keys for an arc that starts and ends on atoms in the preceding entries """ # First, get the ring keys keys_lst = list(keys_lst) keys = keys_lst.pop(0) # Break the bonds joining the last pair of atoms in each arc gra = remove_bonds(gra, [(k[-1], k[-2]) for k in keys_lst]) # Start by constructing the v-matrix for the first ring vma, zma_keys = ring(gra, keys) # Now, complete the ring system by continuing the v-matrix along each arc for keys in keys_lst: # Note that the atoms on each end of the arc are already in the # v-matrix, so we ignore those vma, zma_keys = continue_chain(gra, keys[1:-1], vma, zma_keys) return vma, zma_keys
def reactants_graph(tsg): """ get a graph of the reactants from a transition state graph """ frm_bnd_keys = forming_bond_keys(tsg) ord_dct = dict_.transform_values(bond_orders(tsg), func=round) gra = set_bond_orders(tsg, ord_dct) gra = remove_bonds(gra, frm_bnd_keys) return gra
def apply(tra, xgr): """ apply this transformation to a graph """ brk_bnd_keys = broken_bond_keys(tra) frm_bnd_keys = formed_bond_keys(tra) # in case some bonds are broken *and* formed, we subtract the other set xgr = remove_bonds(xgr, brk_bnd_keys - frm_bnd_keys) xgr = add_bonds(xgr, frm_bnd_keys - brk_bnd_keys) return xgr
def atom_groups(gra, atm): """ return a list of groups off of one atom """ adj_atms = atoms_neighbor_atom_keys(gra) keys = [] for atmi in adj_atms[atm]: key = [atm, atmi] key.sort() key = frozenset(key) keys.append(key) gras = remove_bonds(gra, keys) return connected_components(gras)
def atom_groups(gra, atm, stereo=False): """ return a list of groups off of one atom """ if not stereo: gra = without_stereo_parities(gra) adj_atms = atoms_neighbor_atom_keys(gra) keys = [] for atmi in adj_atms[atm]: key = [atm, atmi] key.sort() key = frozenset(key) keys.append(key) gras = remove_bonds(gra, keys) return connected_components(gras)
def ring(gra, keys): """ generate a v-matrix for a ring All neighboring atoms along the ring will be included :param gra: the graph :param keys: ring keys, in the order they should appear in the z-matrix """ # Break the bond between the first and last atoms to make this a chain gra = remove_bonds(gra, [(keys[0], keys[-1])]) # Now, construct a v-matrix for the chain vma, zma_keys = chain(gra, keys, term_hydrogens=True) return vma, zma_keys
def _substitution(atmsa, neighsa, bndsa, atmsb, xgr1, xgr2): ret_tra = None for atmi in atmsa: if _is_heavy(atmi, atmsa): i_neighs = neighsa[atmi] for atmj in i_neighs: bnd_break_key_ij = _get_bnd_key(atmi, atmj, bndsa) new_xgr = remove_bonds(xgr1, [bnd_break_key_ij]) for atmk in atmsb: if atmk not in (atmi, atmj): bnd_form_key_ik = frozenset({atmi, atmk}) newnew_xgr = add_bonds(new_xgr, [bnd_form_key_ik]) atm_key_dct = _full_isomorphism(newnew_xgr, xgr2) if atm_key_dct: tra = [[bnd_form_key_ik], [bnd_break_key_ij]] ret_tra = tra return ret_tra
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)
def continue_ring(gra, keys, vma, zma_keys): """ continue constructing a v-matrix around a ring All neighboring atoms along the ring will be included Exactly one atom in the ring must already be in the v-matrix. """ # Find the connecting key key = next((k for k in keys if k in zma_keys), None) assert key is not None, ( "There must be a ring atom already in the v-matrix") # Cycle the connecting key to the front of the ring keys = cycle_ring_atom_key_to_front(keys, key) # Break the bond between the first and last atoms to make this a chain gra = remove_bonds(gra, [(keys[0], keys[-1])]) # Now, construct a v-matrix for the chain vma, zma_keys = continue_chain(gra, keys, vma, zma_keys) return vma, zma_keys
def _insertion(atmsa, neighsa, bndsa, atmsb, neighsb, xgr1, xgr2): """Do the insertion for an order of reactants """ ret_tra = None for i in atmsa: if _is_heavy(i, atmsa): i_neighs = neighsa[i] for j in i_neighs: bnd_break_key_ij = _get_bnd_key(i, j, bndsa) new_xgr = remove_bonds(xgr1, [bnd_break_key_ij]) for k in atmsb: if _is_heavy(k, atmsb) and (k != i and k != j and i not in neighsb[k] and j not in neighsb[k]): bnd_form_key_ik = {i, k} bnd_form_key_jk = {j, k} newnew_xgr = add_bonds( new_xgr, [bnd_form_key_ik, bnd_form_key_jk]) atm_key_dct = _full_isomorphism(newnew_xgr, xgr2) if atm_key_dct: tra = [[bnd_form_key_ik, bnd_form_key_jk], [bnd_break_key_ij]] ret_tra = tra return ret_tra
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