示例#1
0
文件: _prop.py 项目: sjklipp/autochem
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
示例#2
0
文件: _comp.py 项目: sjklipp/autochem
def minimum_distance(geo1, geo2):
    """ get the minimum distance between atoms in geo1 and those in geo2

        :param geo1: molecular geometry 1
        :type geo1: automol molecular geometry data structure
        :param geo2: molecular geometry 2
        :type geo2: automol molecular geometry data structure
        :rtype: float
    """

    xyzs1 = geom_base.coordinates(geo1)
    xyzs2 = geom_base.coordinates(geo2)
    return min(
        util.vec.distance(xyz1, xyz2)
        for xyz1, xyz2 in itertools.product(xyzs1, xyzs2))
示例#3
0
文件: _comp.py 项目: sjklipp/autochem
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
示例#4
0
文件: _comp.py 项目: sjklipp/autochem
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
示例#5
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)
示例#6
0
文件: _prop.py 项目: sjklipp/autochem
def center_of_mass(geo):
    """ Determine the center-of-mass for a molecular geometry.

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

    xyzs = geom_base.coordinates(geo)
    amas = masses(geo)
    cm_xyz = tuple(
        sum(numpy.multiply(xyz, ama) for xyz, ama in zip(xyzs, amas)) /
        sum(amas))

    return cm_xyz
示例#7
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)
示例#8
0
def perturb(geo, atm_idx, pert_xyz):
    """ Perturb the position of one atom by
        changing the value of an xyz coord by some amount.
    """

    # Get the xyz coordinates of the atom to perturb
    atm_coords = list(geom_base.coordinates(geo)[atm_idx])

    # Get the perturbed set of atomic coordinates
    for idx, val in enumerate(pert_xyz):
        atm_coords[idx] += val
    pert_dct = {atm_idx: atm_coords}

    # Perturb the coordinates of the atom
    pert_geo = geom_base.set_coordinates(geo, pert_dct)

    return pert_geo
示例#9
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)
示例#10
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)
示例#11
0
文件: _prop.py 项目: sjklipp/autochem
def inertia_tensor(geo, amu=True):
    """ Build the moment-of-inertia tensor for 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(tuple(float))
    """

    geo = mass_centered(geo)
    amas = masses(geo, amu=amu)
    xyzs = geom_base.coordinates(geo)
    ine = tuple(map(tuple, sum(
        ama * (numpy.vdot(xyz, xyz) * numpy.eye(3) - numpy.outer(xyz, xyz))
        for ama, xyz in zip(amas, xyzs))))

    return ine
示例#12
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)
示例#13
0
def reflect_coordinates(geo, idxs, axes):
    """ Reflect a specified set of coordinates of a molecular geometry
        about some each of the requested axes.

        A set of `idxs` can be supplied to transform a subset of coordinates.

        :param geo: molecular geometry
        :type geo: automol geometry data structure
        :param idxs: indices of atoms whose coordinates are to be reflected
        :type idxs: tuple(int)
        :param axes: axes to reflect about
        :type axes: tuple(str)
        :rtype: automol geometry data structure
    """

    # check input
    assert all(idx < len(geo) for idx in idxs)
    assert all(axis in ('x', 'y', 'z') for axis in axes)

    # get coords
    coords = geom_base.coordinates(geo)

    # convert x,y,z to nums
    axes = [AXIS_DCT[axis] for axis in axes]

    # build set atom dct with relected coords
    reflect_dct = {}
    for idx in idxs:
        coord_lst = list(coords[idx])
        for axis in axes:
            coord_lst[axis] *= -1.0
        reflect_dct[idx] = coord_lst

    # Reflect coords with dct
    geo_reflected = geom_base.set_coordinates(geo, reflect_dct)

    return geo_reflected
示例#14
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