Esempio n. 1
0
    def calc_E_kin_bound(orbs):
        """
        Computes the kinetic energy contribution from the bound electrons

        Inputs:
        - orbs (object)        : the orbitals object
        Returns:
        - E_kin_bound (float)  : kinetic energy
        """

        # compute the grad^2 component
        grad2_orbs = mathtools.laplace(orbs.eigfuncs, orbs._xgrid)

        # compute the (l+1/2)^2 component
        l_arr = np.array([(l + 0.5)**2.0 for l in range(config.lmax)])
        lhalf_orbs = np.einsum("j,ijkl->ijkl", l_arr, orbs.eigfuncs)

        # add together and multiply by eigfuncs*exp(-3x)
        prefac = np.exp(-3.0 * orbs._xgrid) * orbs.eigfuncs
        kin_orbs = prefac * (grad2_orbs - lhalf_orbs)

        # multiply and sum over occupation numbers
        e_kin_dens = np.einsum("ijk,ijkl->l", orbs.occnums, kin_orbs)

        # integrate over sphere
        E_kin_bound = -0.5 * mathtools.int_sphere(e_kin_dens, orbs._xgrid)

        return E_kin_bound
Esempio n. 2
0
def E_xc(density, xgrid, xfunc, cfunc):
    """
    Wrapper function which computes the exchange and correlation energies
    """

    # initialize the _E_xc dict (leading underscore to distinguish from function name)
    _E_xc = {}

    # get the total density
    dens_tot = np.sum(density, axis=0)

    # compute the exchange energy
    ex_libxc = calc_xc(density, xgrid, xfunc, "e_xc")
    _E_xc["x"] = mathtools.int_sphere(ex_libxc * dens_tot, xgrid)

    # compute the correlation energy
    ec_libxc = calc_xc(density, xgrid, cfunc, "e_xc")
    _E_xc["c"] = mathtools.int_sphere(ec_libxc * dens_tot, xgrid)

    # sum to get the total xc potential
    _E_xc["xc"] = _E_xc["x"] + _E_xc["c"]

    return _E_xc
Esempio n. 3
0
    def calc_E_en(density, xgrid):
        """
        Computes the electron-nuclear energy
        E_en = \int dr v_en(r) n(r)

        Inputs:
        - density (np array) : density
        """

        # sum the density over the spin axes to get the total density
        dens_tot = np.sum(density, axis=0)

        # compute the integral
        v_en = Potential.calc_v_en(xgrid)
        E_en = mathtools.int_sphere(dens_tot * v_en, xgrid)

        return E_en
Esempio n. 4
0
    def calc_E_ha(density, xgrid):
        """
        Computes the Hartree energy
        E_ha = 1/2 \int dr \int dr' n(r)n(r')/|r-r'|
        Uses the pre-computed hartree potential
        E_ha = 1/2 /int dr n(r) v_ha(r)

        Inputs:
        - density (np array)    : the density object
        - pot  (object)         : the potential object
        Returns:
        - E_ha (float)       : the hartree energy
        """

        # sum density over spins to get total density
        dens_tot = np.sum(density, axis=0)

        # compute the integral
        v_ha = Potential.calc_v_ha(density, xgrid)
        E_ha = 0.5 * mathtools.int_sphere(dens_tot * v_ha, xgrid)

        return E_ha
Esempio n. 5
0
    def check_conv(self, E_free, pot, dens, iscf):
        """
        Computes the changes in energy, integrated density and integrated potential
        and checks if they satisfy the proscribed convergence parameters

        Parameters
        ----------
        E_free : float
            the total free energy
        v_s : ndarray
            the KS potential
        dens : ndarray
            the electronic density
        iscf : int
            the iteration number

        Returns
        -------
        conv_vals : dict
            Dictionary of convergence parameters as follows:
            {'conv_energy' : float, 'conv_rho' : ndarray,
             'conv_pot' : ndarray, 'complete' : bool}

        """

        conv_vals = {}

        # first update the energy, potential and density attributes
        self._energy[0] = E_free
        self._potential[0] = pot
        self._density[0] = dens

        # compute the change in energy
        conv_vals["dE"] = abs(
            (self._energy[0] - self._energy[1]) / self._energy[0])

        # compute the change in potential
        dv = np.abs(self._potential[0] - self._potential[1])
        # compute the norm
        norm_v = mathtools.int_sphere(np.abs(self._potential[0]), self._xgrid)
        conv_vals["dpot"] = mathtools.int_sphere(dv, self._xgrid) / norm_v

        # compute the change in density
        dn = np.abs(self._density[0] - self._density[1])
        # integrate over sphere to return a number
        # note we add a small constant to avoid errors if there are no electrons in one spin channel
        conv_vals["drho"] = mathtools.int_sphere(
            dn, self._xgrid) / (config.nele + 1e-3)

        # reset the energy, potential and density attributes
        self._energy[1] = E_free
        self._potential[1] = pot
        self._density[1] = dens

        # see if the convergence criteria are satisfied
        conv_energy = False
        conv_rho = False
        conv_pot = False
        conv_vals["complete"] = False

        if iscf > 3:
            if conv_vals["dE"] < config.conv_params["econv"]:
                conv_energy = True
            if np.all(conv_vals["drho"] < config.conv_params["nconv"]):
                conv_rho = True
            if np.all(conv_vals["dpot"] < config.conv_params["vconv"]):
                conv_pot = True
            if conv_energy and conv_rho and conv_pot:
                conv_vals["complete"] = True

        return conv_vals