def _gen3(ich): if has_stereo(ich): raise ValueError gra = graph(ich, stereo=False) gra = automol.graph.explicit(gra) geo = automol.graph.embed.geometry(gra) return geo
def hydrogen_bonded_idxs(geo, dist_thresh=5.3, angle_thresh=1.92, grxn=None): """ Compare bond lengths in structure to determine if there is a hydrogen bond. :param geo: geometry object :type geo: geo object (tuple of tuples) :param grxn: reaction object (geo indexing) :type grxn: automol.reac.Reaction object :param dist_thresh: cutoff value for hbond length (Bohr) :type dist_thresh: float :param angle_thresh: cutoff value for hbond angle (Radian) :type angle_thresh: float :rtype: tuple """ # Initialize the hydrogen bond list to None hydrogen_bond = None if count(geo) > 1: # Get the forming/breaking bond idxs if possible if grxn is not None: frm_bnd_keys = automol.graph.ts.forming_bond_keys( grxn.forward_ts_graph) brk_bnd_keys = automol.graph.ts.breaking_bond_keys( grxn.forward_ts_graph) rxn_keys = set() for key in frm_bnd_keys: rxn_keys = rxn_keys | key for key in brk_bnd_keys: rxn_keys = rxn_keys | key rxn_h_idxs = tuple(rxn_keys) else: rxn_h_idxs = () # Get all potential indices for HB interactions gra = graph(geo) dist_mat = distance_matrix(geo) adj_atm_dct = automol.graph.atoms_neighbor_atom_keys(gra) h_idxs = automol.graph.atom_keys(gra, sym='H') acceptor_idxs = list( automol.graph.resonance_dominant_radical_atom_keys(gra)) acceptor_idxs.extend(list(automol.graph.atom_keys(gra, sym='O'))) # Loop over indices, ignoring H-idxs in reacting bonds hb_idxs = tuple(idx for idx in h_idxs if idx not in rxn_h_idxs) for h_idx in hb_idxs: for acceptor_idx in acceptor_idxs: donor_idx = list(adj_atm_dct[h_idx])[0] if acceptor_idx in adj_atm_dct[donor_idx]: continue if dist_mat[h_idx][acceptor_idx] < dist_thresh: ang = central_angle(geo, donor_idx, h_idx, acceptor_idx) if ang > angle_thresh: hydrogen_bond = ( donor_idx, h_idx, acceptor_idx, ) dist_thresh = dist_mat[h_idx][acceptor_idx] return hydrogen_bond
def components_graph(geo, stereo=True): """ Generate a list of molecular graphs where each element is a graph that consists of fully connected (bonded) atoms. Stereochemistry is included if requested. :param geo: molecular geometry :type geo: automol geometry data structure :param stereo: parameter to include stereochemistry information :type stereo: bool :rtype: automol molecular graph data structure """ return automol.graph.connected_components(graph(geo, stereo=stereo))
def expand_stereo(ich): """ Obtain all possible stereoisomers compatible with an InChI string. :param ich: InChI string :type ich: str :rtype: list[str] """ gra = graph(ich) sgrs = automol.graph.stereomers(gra) ste_ichs = [automol.graph.stereo_inchi(sgr) for sgr in sgrs] return ste_ichs
def is_complete(ich): """ Determine if the InChI string is complete (has all stereo-centers assigned). Currently only checks species that does not have any resonance structures. :param ich: InChI string :type ich: str :rtype: bool """ gra = graph(ich, stereo=False) ste_atm_keys = automol.graph.stereogenic_atom_keys(gra) ste_bnd_keys = automol.graph.stereogenic_bond_keys(gra) graph_has_stereo = bool(ste_atm_keys or ste_bnd_keys) _complete = equivalent( ich, standard_form(ich)) and not (has_stereo(ich) ^ graph_has_stereo) return _complete
def torsional_symmetry_numbers(zma, tors_names, frm_bnd_key=None, brk_bnd_key=None): """ symmetry numbers for torsional dihedrals """ dih_edg_key_dct = _dihedral_edge_keys(zma) assert set(tors_names) <= set(dih_edg_key_dct.keys()) edg_keys = tuple(map(dih_edg_key_dct.__getitem__, tors_names)) gra = graph(zma, stereo=False) bnd_sym_num_dct = automol.graph.bond_symmetry_numbers( gra, frm_bnd_key, brk_bnd_key) tors_sym_nums = [] for edg_key in edg_keys: if edg_key in bnd_sym_num_dct.keys(): sym_num = bnd_sym_num_dct[edg_key] else: sym_num = 1 tors_sym_nums.append(sym_num) tors_sym_nums = tuple(tors_sym_nums) return tors_sym_nums
def torsion_leading_atom(zma, key1, key2, zgra=None): """ Obtain the leading atom for a torsion coordinate about a torsion axis. The leading atom is the atom whose dihedral defines the torsional coordinate, which must always be the first dihedral coordinate for this bond. A bond is properly decoupled if all other dihedrals along this bond depend on the leading atom. :param zma: the z-matrix :type zma: automol Z-Matrix data structure :param key1: the first key in the torsion axis (rotational bond) :type key1: int :param key2: the second key in the torsion axis (rotational bond) :type key2: int :param gra: an automol graph data structure, aligned to the z-matrix; used to check connectivity when necessary :rtype: int """ key_mat = key_matrix(zma) krs1 = [(key, row) for key, row in enumerate(key_mat) if row[:2] == (key1, key2)] krs2 = [(key, row) for key, row in enumerate(key_mat) if row[:2] == (key2, key1)] lead_key_candidates = [] for krs in (krs1, krs2): if krs: keys, rows = zip(*krs) start_key = keys[0] assert all(row[-1] == start_key for row in rows[1:]), ( "Torsion coordinate along bond {:d}-{:d} not decoupled:\n{}" .format(key1, key2, string(zma, one_indexed=False))) if rows[0][-1] is not None: lead_key_candidates.append(start_key) if not lead_key_candidates: lead_key = None elif len(lead_key_candidates) == 1: lead_key = lead_key_candidates[0] else: # If we get to this point, then the z-matrix includes dihedrals across # the key1-key2 bond in both directions and we have to choose which # dihedral to use. This mans there will be two lead_key_candidates. zgra = graph(zma) if zgra is None else zgra # Let key0 be the lead key and let (key1, key2, key3) be its key row in # the z-matrix. For the torsion coordinate, key0-key1-key2-key3 should # all be connected in a line. For subsidiary dihedral coordinates, key3 # will be connected to key1 instead of key2. # A simple solution is therefore to choose the lead key based on # whether or not key2 and key3 are connected, which is what this code # does. bnd_keys = automol.graph.bond_keys(zgra) lead_key = next((k for k in lead_key_candidates if frozenset(key_mat[k][-2:]) in bnd_keys), None) # If that fails, choose the key that appears earlier. It's possible # that it would be better to choose the later one, in which case we # would replace the min() here with a max(). if lead_key is None: lead_key = min(lead_key_candidates) return lead_key
def rot_permutated_geoms(geo, frm_bnd_keys=(), brk_bnd_keys=()): """ Convert an input geometry to a list of geometries corresponding to the rotational permuations of all the terminal groups. :param geo: molecular geometry :type geo: automol molecular geometry data structure :param frm_bnd_keys: keys denoting atoms forming bond in TS :type frm_bnd_keys: frozenset(int) :param brk_bnd_keys: keys denoting atoms breaking bond in TS :type brk_bnd_keys: frozenset(int) :rtype: tuple(automol geom data structure) """ # Set saddle based on frm and brk keys existing saddle = bool(frm_bnd_keys or brk_bnd_keys) gra = graph(geo, stereo=False) term_atms = {} all_hyds = [] neighbor_dct = automol.graph.atoms_neighbor_atom_keys(gra) ts_atms = [] for bnd_ in frm_bnd_keys: ts_atms.extend(list(bnd_)) for bnd_ in brk_bnd_keys: ts_atms.extend(list(bnd_)) # determine if atom is a part of a double bond unsat_atms = automol.graph.unsaturated_atom_keys(gra) if not saddle: rad_atms = automol.graph.sing_res_dom_radical_atom_keys(gra) res_rad_atms = automol.graph.resonance_dominant_radical_atom_keys(gra) rad_atms = [atm for atm in rad_atms if atm not in res_rad_atms] else: rad_atms = [] gra = gra[0] for atm in gra: if gra[atm][0] == 'H': all_hyds.append(atm) for atm in gra: if atm in unsat_atms and atm not in rad_atms: pass else: if atm not in ts_atms: nonh_neighs = [] h_neighs = [] neighs = neighbor_dct[atm] for nei in neighs: if nei in all_hyds: h_neighs.append(nei) else: nonh_neighs.append(nei) if len(nonh_neighs) < 2 and len(h_neighs) > 1: term_atms[atm] = h_neighs geo_final_lst = [geo] for hyds in term_atms.values(): geo_lst = [] for geom in geo_final_lst: geo_lst.extend(_swap_for_one(geom, hyds)) geo_final_lst = geo_lst return geo_final_lst
def end_group_symmetry_factor(geo, frm_bnd_keys=(), brk_bnd_keys=()): """ Determine sym factor for terminal groups in a geometry :param geo: molecular geometry :type geo: automol molecular geometry data structure :param frm_bnd_keys: keys denoting atoms forming bond in TS :type frm_bnd_keys: frozenset(int) :param brk_bnd_keys: keys denoting atoms breaking bond in TS :type brk_bnd_keys: frozenset(int) :rtype: (automol geom data structure, float) """ # Set saddle based on frm and brk keys existing saddle = bool(frm_bnd_keys or brk_bnd_keys) gra = graph(geo, stereo=False) term_atms = {} all_hyds = [] neighbor_dct = automol.graph.atoms_neighbor_atom_keys(gra) ts_atms = [] for bnd_ in frm_bnd_keys: ts_atms.extend(list(bnd_)) for bnd_ in brk_bnd_keys: ts_atms.extend(list(bnd_)) # determine if atom is a part of a double bond unsat_atms = automol.graph.unsaturated_atom_keys(gra) if not saddle: rad_atms = automol.graph.sing_res_dom_radical_atom_keys(gra) res_rad_atms = automol.raph.resonance_dominant_radical_atom_keys(gra) rad_atms = [atm for atm in rad_atms if atm not in res_rad_atms] else: rad_atms = [] gra = gra[0] for atm in gra: if gra[atm][0] == 'H': all_hyds.append(atm) for atm in gra: if atm in unsat_atms and atm not in rad_atms: pass else: if atm not in ts_atms: nonh_neighs = [] h_neighs = [] neighs = neighbor_dct[atm] for nei in neighs: if nei in all_hyds: h_neighs.append(nei) else: nonh_neighs.append(nei) if len(nonh_neighs) == 1 and len(h_neighs) > 1: term_atms[atm] = h_neighs print('terminal atom accepted:', atm, h_neighs) factor = 1. remove_atms = [] for atm in term_atms: hyds = term_atms[atm] if len(hyds) > 1: factor *= len(hyds) remove_atms.extend(hyds) geo = remove(geo, remove_atms) return geo, factor, remove_atms