def zmatrix(geo, ts_bnds=()): """ Generate a corresponding Z-Matrix for a molecular geometry using internal autochem procedures. :param geo: molecular geometry :type geo: automol geometry data structure :param ts_bnds: keys for the breaking/forming bonds in a TS :type ts_bnds: tuple(frozenset(int)) """ if ts_bnds: raise NotImplementedError if automol.geom.is_atom(geo): symbs = symbols(geo) key_mat = [[None, None, None]] val_mat = [[None, None, None]] zma = create.zmat.from_data(symbs, key_mat, val_mat) zma_keys = [0] dummy_key_dct = {} else: geo, dummy_key_dct = insert_dummies_on_linear_atoms(geo) gra = geom_connectivity_graph(geo) bnd_keys = tuple(dummy_key_dct.items()) ord_dct = {k: 0 for k in bnd_keys} gra = add_bonds(gra, bnd_keys, ord_dct=ord_dct) vma, zma_keys = automol.graph.vmat.vmatrix(gra) geo = from_subset(geo, zma_keys) zma = from_geometry(vma, geo) return zma, zma_keys, dummy_key_dct
def connectivity_graph(zma, dummy=False, rqq_bond_max=3.5, rqh_bond_max=2.6, rhh_bond_max=1.9): """ Convert a Z-Matrix to a molecular connectivitiy graph. :param zma: Z-Matrix :type zma: automol Z-Matrix data structure :param rqq_bond_max: maximum distance between heavy atoms :type rqq_bond_max: float :param rqh_bond_max: maximum distance between heavy atoms and hydrogens :type rqh_bond_max: float :param rhh_bond_max: maximum distance between hydrogens :type rhh_bond_max: float :param dummy: parameter to include dummy atoms :type dummy: bool :rtype: automol molecular graph data structure """ geo = geometry_with_dummy_atoms(zma) if not dummy: geo = geom_without_dummy_atoms(geo) gra = geom_connectivity_graph(geo, rqq_bond_max=rqq_bond_max, rqh_bond_max=rqh_bond_max, rhh_bond_max=rhh_bond_max) if dummy: bnd_keys = tuple(dummy_neighbor_keys(zma).items()) ord_dct = {k: 0 for k in bnd_keys} gra = add_bonds(gra, bnd_keys, ord_dct=ord_dct) 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 ring_forming_scission(rct_gras, prd_gras): """ find a ring forming reaction that eliminates a radical group """ _assert_is_valid_reagent_graph_list(rct_gras) _assert_is_valid_reagent_graph_list(prd_gras) tras = [] rct_idxs = None prd_idxs = None is_triv = is_trivial_reaction(rct_gras, prd_gras) if len(rct_gras) == 1 and len(prd_gras) == 2 and not is_triv: rgra, = rct_gras pgra1, pgra2 = prd_gras pgra = automol.graph.union(pgra1, pgra2) rad_atm_keys = unsaturated_atom_keys(rgra) atms, bnds = rgra ngb_atms = automol.graph.atom_neighbor_keys(rgra) for rad_atm in rad_atm_keys: for xatm in atms: if (xatm != rad_atm and atms[xatm][1] != 'H' and xatm not in ngb_atms[rad_atm] and not tras): for natm in ngb_atms[xatm]: if natm != rad_atm: xgra = atms.copy(), bnds.copy() xgra = add_bonds(xgra, [frozenset({rad_atm, xatm})]) xgra = remove_bonds(xgra, [frozenset({xatm, natm})]) atm_key_dct = full_isomorphism(xgra, pgra) if atm_key_dct: tra = trans.from_data( rxn_class=( par.REACTION_CLASS.RING_FORM_SCISSION), frm_bnd_keys=[{rad_atm, xatm}], brk_bnd_keys=[ {xatm, natm}, ]) tras.append(tra) break # sort the reactants so that the largest species is first rct_idxs = (0, ) prd_idxs = _argsort_reactants(prd_gras) tras = tuple(tras) return tras, rct_idxs, prd_idxs
def prod_addition(x_gra, y_gra): """ products of addition """ prod_gras = tuple() shift = len(automol.graph.atoms(x_gra)) y_gra = automol.graph.transform_keys(y_gra, lambda x: x + shift) x_keys = unsaturated_atom_keys(x_gra) y_keys = unsaturated_atom_keys(y_gra) for x_key, y_key in itertools.product(x_keys, y_keys): xy_gra = add_bonds(union(x_gra, y_gra), [{x_key, y_key}]) prod_gras += ((xy_gra, ), ) return _unique_gras(prod_gras)
def graph(zma, stereo=True, dummy=False): """ Convert a Z-Matrix to a molecular graph. :param zma: Z-Matrix :type zma: automol Z-Matrix data structure :param dummy: parameter to include dummy atoms :type dummy: bool :rtype: (automol molecular geometry data structure, dict[int, int]) """ geo = geometry_with_dummy_atoms(zma) if not dummy: geo = geom_without_dummy_atoms(geo) gra = geom_graph(geo, stereo=stereo) if dummy: bnd_keys = tuple(dummy_neighbor_keys(zma).items()) ord_dct = {k: 0 for k in bnd_keys} gra = add_bonds(gra, bnd_keys, ord_dct=ord_dct) return gra
def addition(rct_gras, prd_gras): """ find an addition transformation Additions are identified by joining an unsaturated site on one reactant to an unsaturated site on the other. If the result matches the products, this is an addition reaction. """ _assert_is_valid_reagent_graph_list(rct_gras) _assert_is_valid_reagent_graph_list(prd_gras) tras = [] rct_idxs = None prd_idxs = None is_triv = is_trivial_reaction(rct_gras, prd_gras) if len(rct_gras) == 2 and len(prd_gras) == 1 and not is_triv: x_gra, y_gra = rct_gras prd_gra, = prd_gras x_atm_keys = unsaturated_atom_keys(x_gra) y_atm_keys = unsaturated_atom_keys(y_gra) for x_atm_key, y_atm_key in itertools.product(x_atm_keys, y_atm_keys): xy_gra = add_bonds(union(x_gra, y_gra), [{x_atm_key, y_atm_key}]) atm_key_dct = full_isomorphism(xy_gra, prd_gra) if atm_key_dct: tra = trans.from_data(rxn_class=par.REACTION_CLASS.ADDITION, frm_bnd_keys=[{x_atm_key, y_atm_key}], brk_bnd_keys=[]) tras.append(tra) # sort the reactants so that the largest species is first rct_idxs = _argsort_reactants(rct_gras) prd_idxs = (0, ) tras = tuple(tras) return tras, rct_idxs, prd_idxs
def elimination(rct_gras, prd_gras): """ find an elimination transformation Eliminations are identified by breaking two bonds from the reactant, forming three fragments. This will form one "central fragment" with two break sites and two "end fragments" with one break site each. If the central fragment plus the two end fragments, joined at their break sites, matches the products, this is an elimination reaction. """ _assert_is_valid_reagent_graph_list(rct_gras) _assert_is_valid_reagent_graph_list(prd_gras) tras = [] rct_idxs = None prd_idxs = None is_triv = is_trivial_reaction(rct_gras, prd_gras) if len(rct_gras) == 1 and len(prd_gras) == 2 and not is_triv: rct_gra, = rct_gras rct_bnd_keys = bond_keys(rct_gra) # Loop over pairs of bonds and break them. Then, if this forms three # fragments, join the two end fragments and compare the result to the # products. for brk_bnd_key1, brk_bnd_key2 in itertools.combinations(rct_bnd_keys, r=2): rct_gra_ = remove_bonds(rct_gra, [brk_bnd_key1, brk_bnd_key2]) # Find the central fragment, which is the one connected to both # break sites. If there's a loop there may not be a central # fragment, in which case this function will return None. cent_frag_atm_keys = _central_fragment_atom_keys( rct_gra_, brk_bnd_key1, brk_bnd_key2) if cent_frag_atm_keys is not None: atm1_key, = brk_bnd_key1 - cent_frag_atm_keys atm2_key, = brk_bnd_key2 - cent_frag_atm_keys frm_bnd_key = frozenset({atm1_key, atm2_key}) rct_gra_ = add_bonds(rct_gra_, [frm_bnd_key]) prd_gra = union_from_sequence(prd_gras) atm_key_dct = full_isomorphism(rct_gra_, prd_gra) if atm_key_dct: tra = trans.from_data( rxn_class=par.REACTION_CLASS.ELIMINATION, frm_bnd_keys=[frm_bnd_key], brk_bnd_keys=[brk_bnd_key1, brk_bnd_key2]) tras.append(tra) rct_idxs = (0, ) cent_prd_atm_keys = frozenset( map(atm_key_dct.__getitem__, cent_frag_atm_keys)) if cent_prd_atm_keys <= atom_keys(prd_gras[0]): prd_idxs = (0, 1) else: assert cent_prd_atm_keys <= atom_keys(prd_gras[1]) prd_idxs = (1, 0) tras = tuple(tras) return tras, rct_idxs, prd_idxs