Exemplo n.º 1
0
def _coulomb_matrix(geo):
    """ Calculate the Coulomb matrix wich describes the
        electrostatic interactions between nuclei:

        M[i,j] = 0.5Z_i^2.4 (i=j), Z_iZ_j/R_ij (i!=j

        :param geo: molecular geometry
        :type geo: automol molecular geometry data structure
        :rtype: tuple(tuple(float))
    """

    nums = numpy.array(list(map(ptab.to_number, geom_base.symbols(geo))))
    xyzs = numpy.array(geom_base.coordinates(geo))

    _ = numpy.newaxis
    natms = len(nums)
    diag_idxs = numpy.diag_indices(natms)
    tril_idxs = numpy.tril_indices(natms, -1)
    triu_idxs = numpy.triu_indices(natms, 1)

    zxz = numpy.outer(nums, nums)
    rmr = numpy.linalg.norm(xyzs[:, _, :] - xyzs[_, :, :], axis=2)

    mat = numpy.zeros((natms, natms))
    mat[diag_idxs] = nums**2.4 / 2.
    mat[tril_idxs] = zxz[tril_idxs] / rmr[tril_idxs]
    mat[triu_idxs] = zxz[triu_idxs] / rmr[triu_idxs]

    return mat
Exemplo n.º 2
0
def permutation(geo, ref_geo, thresh=1e-4):
    """ Determine the permutation of one geometry that reproduces another
        (if there isn't one -- the geometries are not aligned, return None).

        :param geo: molecular geometry
        :type geo: automol molecular geometry data structure
        :param ref_geo: molecular geometry
        :type ref_geo: automol molecular geometry data structure
        :param thresh: theshold for assessing if permutation exists
        :type thresh: float
        :rtype: tuple(int)
    """

    natms = geom_base.count(geo)
    symbs = geom_base.symbols(geo)
    xyzs = geom_base.coordinates(geo)

    perm_idxs = [None] * natms
    for idx, (symb, xyz) in enumerate(zip(symbs, xyzs)):
        # Loop over atoms in the reference geometry with the same symbol
        ref_idxs = geom_base.atom_indices(ref_geo, symb=symb)
        ref_xyzs = geom_base.coordinates(ref_geo, idxs=ref_idxs)
        perm_idx = next(
            (ref_idx for ref_idx, ref_xyz in zip(ref_idxs, ref_xyzs)
             if util.vec.distance(xyz, ref_xyz) < thresh), None)
        perm_idxs[idx] = perm_idx

    perm_idxs = tuple(perm_idxs)

    if any(perm_idx is None for perm_idx in perm_idxs):
        perm_idxs = None

    return perm_idxs
Exemplo n.º 3
0
def almost_equal(geo1, geo2, rtol=2e-3):
    """ Assess if the coordinates of two molecular geometries
        are numerically equal.

        :param geo1: molecular geometry 1
        :type geo1: automol molecular geometry data structure
        :param geo2: molecular geometry 2
        :type geo2: automol molecular geometry data structure
        :param rtol: Relative tolerance for the distances
        :type rtol: float
        :rtype: tuple(tuple(float))
    """

    ret = False
    if geom_base.symbols(geo1) == geom_base.symbols(geo2):
        ret = numpy.allclose(geom_base.coordinates(geo1),
                             geom_base.coordinates(geo2),
                             rtol=rtol)

    return ret
Exemplo n.º 4
0
def displace(geo, xyzs):
    """ Displace the coordinates of a geometry along a vector.

        :param geo: molecular geometry
        :type geo: automol molecular geometry data structure
        :param xyzs: vector to displace along
        :type xyzs: tuple(float)
        :rtype: automol molecular geometry data structure
    """

    symbs = geom_base.symbols(geo)
    orig_xyzs = geom_base.coordinates(geo)
    xyzs = numpy.add(orig_xyzs, xyzs)

    return automol.create.geom.from_data(symbs, xyzs)
Exemplo n.º 5
0
def transform_by_matrix(geo, mat):
    """ Transform the coordinates of a molecular geometry by multiplying
        it by some input transfomration matrix.

        :param geo: molecular geometry
        :type geo: automol molecular geometry data structure
        :param mat: transformation matrix
        :type mat: tuple(tuple(float))
        :rtype: automol moleculer geometry data structure
    """

    symbs = geom_base.symbols(geo)
    xyzs = geom_base.coordinates(geo)
    xyzs = numpy.dot(xyzs, numpy.transpose(mat))

    return automol.create.geom.from_data(symbs, xyzs)
Exemplo n.º 6
0
def move_atom(geo, idx1, idx2):
    """ Move an atom to a different position in the geometry

        :param geo: molecular geometry
        :type geo: automol molecular geometry data structure
        :param idx1: index of the atom to be moved
        :type idx1: int
        :param idx2: new position that the atom should be moved to
        :type idx2: int
        :returns: the transformed geometry
        :rtype: molecular geometry
    """
    symbs = list(geom_base.symbols(geo))
    xyzs = list(geom_base.coordinates(geo))
    symbs.insert(idx2, symbs.pop(idx1))
    xyzs.insert(idx2, xyzs.pop(idx1))
    return automol.create.geom.from_data(symbs, xyzs)
Exemplo n.º 7
0
def transform(geo, func, idxs=None):
    """ Transform the coordinates of a geometry by a function.
        A set of `idxs` can be supplied to transform a subset of coordinates.

        :param geo: molecular geometry
        :type geo: automol geometry data structure
        :param func: transformation function
        :type func: function object
        :param idxs: indices representing the subset of atoms
        :type idxs: tuple(int)
    """

    idxs = list(range(geom_base.count(geo))) if idxs is None else idxs
    symbs = geom_base.symbols(geo)
    xyzs = geom_base.coordinates(geo)
    xyzs = [func(xyz) if idx in idxs else xyz for idx, xyz in enumerate(xyzs)]

    return automol.create.geom.from_data(symbs, xyzs)
Exemplo n.º 8
0
def reorder_coordinates(geo, idx_dct):
    """ Reorder the atoms of a molecular geometry using
        the mapping of an input dictionary.

        :param geo: The geometry
        :param idx_dct: The new order of the atoms, by index
        :type idx_dct: dict
        :rtype: automol geometry data structure
    """

    symbs = geom_base.symbols(geo)
    xyzs = geom_base.coordinates(geo)

    idxs = [idx for idx, _ in sorted(idx_dct.items(), key=lambda x: x[1])]
    assert len(symbs) == len(xyzs) == len(idxs)

    symbs = [symbs[idx] for idx in idxs]
    xyzs = [xyzs[idx] for idx in idxs]

    return automol.create.geom.from_data(symbs, xyzs)
Exemplo n.º 9
0
def masses(geo, amu=True):
    """ Build a list of the atomic masses that corresponds to the list
        of atomic sybmols of a molecular geometry.

        :param geo: molecular geometry
        :type geo: automol geometry data structure
        :param amu: parameter to control electron mass -> amu conversion
        :type amu: bool
        :rtype: tuple(float)
    """

    symbs = geom_base.symbols(geo)
    amas = list(map(ptab.to_mass, symbs))

    if not amu:
        amas = numpy.multiply(amas, phycon.AMU2EMASS)

    amas = tuple(amas)

    return amas
Exemplo n.º 10
0
def is_linear(geo, tol=2.*phycon.DEG2RAD):
    """ Determine if the molecular geometry is linear.

        :param geo: molecular geometry
        :type geo: automol geometry data structure
        :param tol: tolerance of bond angle(s) for determing linearity
        :type tol: float
        :rtype: bool
    """

    ret = True

    if len(geo) == 1:
        ret = False
    elif len(geo) == 2:
        ret = True
    else:
        keys = range(len(geom_base.symbols(geo)))
        for key1, key2, key3 in mit.windowed(keys, 3):
            cangle = numpy.abs(geom_base.central_angle(geo, key1, key2, key3))
            if not (numpy.abs(cangle) < tol or
                    numpy.abs(cangle - numpy.pi) < tol):
                ret = False
    return ret
Exemplo n.º 11
0
def join(geo1,
         geo2,
         key2,
         key3,
         r23,
         a123=85.,
         a234=85.,
         d1234=85.,
         key1=None,
         key4=None,
         angstrom=True,
         degree=True):
    """ join two geometries based on four of their atoms, two on the first
    and two on the second

    Variables set the coordinates for 1-2...3-4 where 1-2 are bonded atoms in
    geo1 and 3-4 are bonded atoms in geo2.
    """
    key3 = key3 - geom_base.count(geo1)
    a123 *= phycon.DEG2RAD if degree else 1
    a234 *= phycon.DEG2RAD if degree else 1
    d1234 *= phycon.DEG2RAD if degree else 1

    gra1, gra2 = map(automol.convert.geom.connectivity_graph, (geo1, geo2))
    key1 = (automol.graph.atom_neighbor_atom_key(gra1, key2)
            if key1 is None else key1)
    key4 = (automol.graph.atom_neighbor_atom_key(gra2, key3)
            if key4 is None else key4)

    syms1 = geom_base.symbols(geo1)
    syms2 = geom_base.symbols(geo2)
    xyzs1 = geom_base.coordinates(geo1, angstrom=angstrom)
    xyzs2 = geom_base.coordinates(geo2, angstrom=angstrom)

    xyz1 = xyzs1[key1]
    xyz2 = xyzs1[key2]
    orig_xyz3 = xyzs2[key3]
    if key4 is not None:
        orig_xyz4 = xyzs2[key4]
    else:
        orig_xyz4 = [1., 1., 1.]

    r34 = vec.distance(orig_xyz3, orig_xyz4)

    # Place xyz3 as far away from the atoms in geo1 as possible by optimizing
    # the undetermined dihedral angle
    xyz0 = vec.arbitrary_unit_perpendicular(xyz2, orig_xyz=xyz1)

    def _distance_norm(dih):  # objective function for minimization
        xyz3 = vec.from_internals(dist=r23,
                                  xyz1=xyz2,
                                  ang=a123,
                                  xyz2=xyz1,
                                  dih=dih,
                                  xyz3=xyz0)
        dist_norm = numpy.linalg.norm(numpy.subtract(xyzs1, xyz3))
        # return the negative norm so that minimum value gives maximum distance
        return -dist_norm

    res = scipy.optimize.basinhopping(_distance_norm, 0.)
    dih = res.x[0]

    # Now, get the next position with the optimized dihedral angle
    xyz3 = vec.from_internals(dist=r23,
                              xyz1=xyz2,
                              ang=a123,
                              xyz2=xyz1,
                              dih=dih,
                              xyz3=xyz0)

    # Don't use the dihedral angle if 1-2-3 are linear
    if numpy.abs(a123 * phycon.RAD2DEG - 180.) > 5.:
        xyz4 = vec.from_internals(dist=r34,
                                  xyz1=xyz3,
                                  ang=a234,
                                  xyz2=xyz2,
                                  dih=d1234,
                                  xyz3=xyz1)
    else:
        xyz4 = vec.from_internals(dist=r34, xyz1=xyz3, ang=a234, xyz2=xyz2)

    align_ = vec.aligner(orig_xyz3, orig_xyz4, xyz3, xyz4)
    xyzs2 = tuple(map(align_, xyzs2))

    syms = syms1 + syms2
    xyzs = xyzs1 + xyzs2

    geo = automol.create.geom.from_data(syms, xyzs, angstrom=angstrom)
    return geo