def linear_atoms(geo, gra=None, tol=5.): """ find linear atoms in a geometry (atoms with 180 degree bond angle) :param geo: the 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 :param tol: the tolerance threshold for linearity, in degrees :type tol: float :rtype: tuple(int) """ gra = connectivity_graph(geo) if gra is None else gra ngb_idxs_dct = atoms_neighbor_atom_keys(gra) lin_idxs = [] for idx in range(count(geo)): nidxs = ngb_idxs_dct[idx] if len(nidxs) >= 2: for nidx1, nidx2 in itertools.combinations(nidxs, 2): ang = central_angle(geo, nidx1, idx, nidx2, degree=True) if numpy.abs(ang - 180.) < tol: lin_idxs.append(idx) lin_idxs = tuple(lin_idxs) return lin_idxs
def inchi_with_sort(geo, stereo=True): """ Generate an InChI string from a molecular geometry. (Sort?) :param geo: molecular geometry :type geo: automol geometry data structure :param stereo: parameter to include stereochemistry information :type stereo: bool :rtype: str """ ich = object_to_hardcoded_inchi_by_key('geom', geo, comp=_compare) nums = None if ich is None: gra = connectivity_graph(geo) if not stereo: geo = None geo_idx_dct = None else: geo_idx_dct = dict(enumerate(range(count(geo)))) ich, nums = inchi_with_sort_from_geometry(gra=gra, geo=geo, geo_idx_dct=geo_idx_dct) return ich, nums
def insert_dummies_on_linear_atoms(geo, lin_idxs=None, gra=None, dist=1., tol=5.): """ Insert dummy atoms over linear atoms in the geometry. :param geo: the geometry :type geo: automol molecular geometry data structure :param lin_idxs: the indices of the linear atoms; if None, indices are automatically determined from the geometry based on the graph :type lin_idxs: tuple(int) :param gra: the graph describing connectivity; if None, a connectivity graph will be generated using default distance thresholds :type gra: automol molecular graph data structure :param dist: distance of dummy atom from the linear atom, in angstroms :type dist: float :param tol: the tolerance threshold for linearity, in degrees :type tol: float :returns: geometry with dummy atoms inserted, along with a dictionary mapping the linear atoms onto their associated dummy atoms :rtype: automol molecular geometry data structure """ lin_idxs = linear_atoms(geo) if lin_idxs is None else lin_idxs gra = connectivity_graph(geo) if gra is None else gra dummy_ngb_idxs = set(dummy_atoms_neighbor_atom_key(gra).values()) assert not dummy_ngb_idxs & set(lin_idxs), ( "Attempting to add dummy atoms on atoms that already have them: {}". format(dummy_ngb_idxs & set(lin_idxs))) ngb_idxs_dct = atoms_sorted_neighbor_atom_keys(gra) xyzs = coordinates(geo, angstrom=True) def _perpendicular_direction(idxs): """ find a nice perpendicular direction for a series of linear atoms """ triplets = [] for idx in idxs: for n1idx in ngb_idxs_dct[idx]: for n2idx in ngb_idxs_dct[n1idx]: if n2idx != idx: ang = central_angle(geo, idx, n1idx, n2idx, degree=True) if numpy.abs(ang - 180.) > tol: triplets.append((idx, n1idx, n2idx)) if triplets: idx1, idx2, idx3 = min(triplets, key=lambda x: x[1:]) xyz1, xyz2, xyz3 = map(xyzs.__getitem__, (idx1, idx2, idx3)) r12 = util.vec.unit_direction(xyz1, xyz2) r23 = util.vec.unit_direction(xyz2, xyz3) direc = util.vec.orthogonalize(r12, r23, normalize=True) else: if len(idxs) > 1: idx1, idx2 = idxs[:2] else: idx1, = idxs idx2, = ngb_idxs_dct[idx1] xyz1, xyz2 = map(xyzs.__getitem__, (idx1, idx2)) r12 = util.vec.unit_direction(xyz1, xyz2) for i in range(3): disp = numpy.zeros((3, )) disp[i] = -1. alt = numpy.add(r12, disp) direc = util.vec.unit_perpendicular(r12, alt) if numpy.linalg.norm(direc) > 1e-2: break return direc # partition the linear atoms into adjacent groups, to be handled together lin_idxs_lst = sorted( map( sorted, util.equivalence_partition(lin_idxs, lambda x, y: x in ngb_idxs_dct[y]))) dummy_key_dct = {} for idxs in lin_idxs_lst: direc = _perpendicular_direction(idxs) for idx in idxs: xyz = numpy.add(xyzs[idx], numpy.multiply(dist, direc)) dummy_key_dct[idx] = count(geo) geo = insert(geo, 'X', xyz, angstrom=True) return geo, dummy_key_dct