Exemple #1
0
    def __call__(self, x,y,z):
        """
        evaluate basis function on a grid

        Parameters
        ----------
        x,y,z      : np.1darray
                     coordinates of grid points. The cartesian position of the
                     i-th point is given by `x[i]`, `y[i]`, `z[i]`.

        Returns
        -------
        wfn        : np.1darray
                     wfn[i] is the atomic orbital at the point `(x[i],y[i],z[i])`

        """
        x0,y0,z0 = self.center
        r,th,ph = cartesian2spherical((x-x0,y-y0,z-z0))

        # radial part of Gaussian type orbital
        wfn_radial = 0*x
        for a,c,N in zip(self.exponents, self.coefficients, self.norms):
            wfn_radial += N*c*np.exp(-a*r**2)
        wfn_radial *= r**self.l

        # angular part of wavefunction, Y^(real)_{l,m}(th,ph)
        sph_it = spherical_harmonics_it(th,ph)
        for Ylm,ll,mm in sph_it:
            # This is very inefficient, since all spherical harmonics with ll<l, mm<m have
            # to be generate first. It is much better to group basis functions on the same
            # atom together and evaluate them in one go.
            if ll == self.l and mm == self.m:
                # real spherical harmonics
                if mm < 0:
                    Ylm_real = -np.sqrt(2.0) * Ylm.imag
                elif mm > 0:
                    Ylm_real =  np.sqrt(2.0) * (-1)**mm * Ylm.real
                else:
                    # mm == 0
                    Ylm_real = Ylm.real

                wfn_angular = Ylm_real
                break

        # combine radial and angular parts
        wfn = wfn_radial * wfn_angular

        return wfn
Exemple #2
0
    def __call__(self, x,y,z):
        """

        evaluate molecular orbital on a grid

        Parameters
        ----------
        x,y,z      : np.1darray
                     coordinates of grid points. The cartesian position of the
                     i-th point is given by `x[i]`, `y[i]`, `z[i]`.

        Returns
        -------
        wfn        : np.1darray
                     wfn[i] is the molecular orbital at the point `(x[i],y[i],z[i])`

        """
        wfn = 0.0*x

        # The following commented section is a slow and stupid way to evaluate the MO,
        # because many primitive Gaussians share the same spherical harmonics.
        # Below is a faster implementation that gives exactly the same result.
        #
        #for cgbf in self.basis:
        #    wfn += self.coefficients[cgbf.ifunc] * cgbf(x,y,z)
        #return wfn
        #

        # group basis functions by atomic center
        atom_group = itertools.groupby(self.basis, key=lambda cgbf: cgbf.iatom)
        for iatom, atomic_basis in atom_group:
            # spherical coordinates around atomic center
            x0, y0, z0 = self.atomlist[iatom][1]
            r,th,ph = cartesian2spherical((x-x0,y-y0,z-z0))
            # spherical harmonics can be shared by all basis functions having the same l,m
            sph_it = spherical_harmonics_it(th,ph)
            # group basis functions on atom by angular momentum quantum numbers (l,m)
            # in the same order in which the spherical harmonics are generated iteratively
            angmom_group = itertools.groupby(atomic_basis, key=lambda cgbf: (cgbf.l, abs(cgbf.m), (-1)*np.sign(cgbf.m)))
            for (l,abs_m,msign_m), shell_basis in angmom_group:
                m = (-1) * msign_m * abs_m

                Ylm,ll,mm = next(sph_it)
                assert ll == l and mm == m
                # real spherical harmonics
                if mm < 0:
                    Ylm_real = -np.sqrt(2.0) * Ylm.imag
                elif mm > 0:
                    Ylm_real =  np.sqrt(2.0) * (-1)**mm * Ylm.real
                else:
                    # mm == 0
                    Ylm_real = Ylm.real
                # radial part is the same for all basis functions in `shell_basis`
                wfn_angular = Ylm_real
                # radial parts differ
                for cgbf in shell_basis:
                    assert cgbf.l == l and cgbf.m == m
                    # radial part of Gaussian type orbital
                    wfn_radial = 0*x
                    for a,c,N in zip(cgbf.exponents, cgbf.coefficients, cgbf.norms):
                        wfn_radial += N*c*np.exp(-a*r**2)
                    wfn_radial *= r**l

                    wfn += self.coefficients[cgbf.ifunc] * wfn_radial * wfn_angular
        return wfn
Exemple #3
0
def Y(l, m, r):
    """spherical harmonic Ylm in cartesian coordinates, r=[x,y,z]"""
    assert (l >= abs(m))
    (x, y, z) = (r[0], r[1], r[2])
    rn, th, phi = cartesian2spherical((x, y, z))
    return special.sph_harm(m, l, phi, th)