def test__ring_puckering(): smi = 'CC1CCCCC1' ich = smiles.inchi(smi) geo = inchi.geometry(ich) zma = geom.zmatrix(geo) gra = zmat.graph(zma) rings_atoms = graph.rings_atom_keys(gra) val_dct = zmat.value_dictionary(zma) coos = zmat.coordinates(zma) geo = zmat.geometry(zma) da_names = zmat.dihedral_angle_names(zma) for ring_atoms in rings_atoms: rotate_hyds = [] ngbs = graph.atom_sorted_neighbor_atom_keys(gra, ring_atoms[0]) symbs = geom.symbols(geo) for ngb in ngbs: if symbs[ngb] == 'H': rotate_hyds.append(ngb) ring_value_dct = {} for da_name in da_names: da_idxs = list(coos[da_name])[0] if len(list(set(da_idxs) & set(ring_atoms))) == 4: print(da_name, da_idxs) ring_value_dct[da_name] = val_dct[da_name] dist_value_dct = {} for i, _ in enumerate(ring_atoms): dist_value_dct[i] = zmat.distance(zma, ring_atoms[i - 1], ring_atoms[i]) samp_range_dct = {} for key, value in ring_value_dct.items(): samp_range_dct[key] = (value - numpy.pi / 4, value + numpy.pi / 4) print(zmat.samples(zma, 5, samp_range_dct))
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)
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)
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)