Example #1
0
    def __init__(self, symbol, configuration = None, xc = LDA, 
                 maxiter = 200, mixing = 0.4, tol = 1e-6, output = None, 
                 write = None):
        """
        DFT atomic calculation.

        Parameters:
        symbol          chemical symbol
        configuration   '[He] 2s2 2p2', overrides default from table
        xc              XC functional (LDA default)
        """
        # store parameters
        self.element = Element(symbol)
        if configuration == None:
            self.configuration = self.element.get_configuration()
        else:
            self.configuration = configuration
        self.xc = xc
        self.maxiter = maxiter
        self.mixing = mixing
        self.tol = tol
        self.write = write
        self.set_output(output)

        # initialize grid, orbitals, energies
        self.grid = RadialGrid(self.element.get_atomic_number())
        self.setup_orbitals()
        
        # print header
        self.print_header()
Example #2
0
def inertia(atoms, xyz):
    ## This function calculate principal axis

    xyz = np.array([i for i in xyz])  # copy the array to avoid changing it
    mass = []
    for i in atoms:
        m = Element(i).getMass()
        mass.append(m)
    mass = np.array(mass)
    xyz -= np.average(xyz, weights=mass, axis=0)
    xx = 0.0
    yy = 0.0
    zz = 0.0
    xy = 0.0
    xz = 0.0
    yz = 0.0
    for n, i in enumerate(xyz):
        xx += mass[n] * (i[1]**2 + i[2]**2)
        yy += mass[n] * (i[0]**2 + i[2]**2)
        zz += mass[n] * (i[0]**2 + i[1]**2)
        xy += -mass[n] * i[0] * i[1]
        xz += -mass[n] * i[0] * i[2]
        yz += -mass[n] * i[1] * i[2]

    I = np.array([[xx, xy, xz], [xy, yy, yz], [xz, yz, zz]])
    eigval, eigvec = np.linalg.eig(I)

    return eigvec[np.argmax(eigval)]
Example #3
0
 def _read_coord(self, xyz):
     xyz = np.array(xyz)
     natom = len(xyz)
     T = xyz[:, 0]
     R = xyz[:, 1:].astype(float)
     M = np.array([Element(x).getMass() * 1822.8852
                   for x in T]).reshape([-1, 1])
     return T, R, M
Example #4
0
def Readinitcond(trvm):
    ## This function read coordinates from sampled initial condition
    ## This function return coordinates in a numpy array
    ## The elements are presented by the nuclear number
    ## This function also return a list of atomic mass in amu
    ## 1 g/mol = 1822.8852 amu
    natom = len(trvm)
    xyz = []
    velo = np.zeros((natom, 3))
    mass = np.zeros((natom, 1))
    for i, line in enumerate(trvm):
        e, x, y, z, vx, vy, vz, m, chrg = line
        xyz.append([e, x, y, z])
        m = Element(e).getMass()
        velo[i, 0:3] = float(vx), float(vy), float(vz)
        mass[i, 0:1] = float(m) * 1822.8852

    return xyz, mass, velo
Example #5
0
def Readcoord(title):
    ## This function read coordinates from a xyz file
    ## This function return coordinates in a numpy array
    ## The elements are presented by the nuclear number
    ## This function also return a list of atomic mass in amu
    ## 1 g/mol = 1822.8852 amu

    file = open('%s.xyz' % (title)).read().splitlines()
    natom = int(file[0])
    xyz = []
    mass = np.zeros((natom, 1))
    for i, line in enumerate(file[2:2 + natom]):
        e, x, y, z = line.split()
        xyz.append([e, x, y, z])
        m = Element(e).getMass()
        mass[i, 0:1] = m * 1822.8852

    return xyz, mass
Example #6
0
class DFTAtom:
    def __init__(self, symbol, configuration = None, xc = LDA, 
                 maxiter = 200, mixing = 0.4, tol = 1e-6, output = None, 
                 write = None):
        """
        DFT atomic calculation.

        Parameters:
        symbol          chemical symbol
        configuration   '[He] 2s2 2p2', overrides default from table
        xc              XC functional (LDA default)
        """
        # store parameters
        self.element = Element(symbol)
        if configuration == None:
            self.configuration = self.element.get_configuration()
        else:
            self.configuration = configuration
        self.xc = xc
        self.maxiter = maxiter
        self.mixing = mixing
        self.tol = tol
        self.write = write
        self.set_output(output)

        # initialize grid, orbitals, energies
        self.grid = RadialGrid(self.element.get_atomic_number())
        self.setup_orbitals()
        
        # print header
        self.print_header()


    def setup_orbitals(self):
        """Initialize atomic orbitals"""
        self.config_tuple = parse_configuration(self.configuration)
        self.orbitals = []
        self.nelec = 0.0
        for orb in self.config_tuple:
            self.orbitals.append(Orbital(orb[0], orb[1], orb[2], self.grid.npoints))
            self.nelec += orb[2]

         
    def set_output(self, output):
        """Open output file"""
        if output == None:
            self.out = open(os.devnull, 'w')
        elif output == '-':
            self.out = sys.stdout
        else:
            self.out = open(output, 'a')



    def print_header(self):
        """Print header information"""
        print >> self.out, '='*78
        print >> self.out, "DFT atomic calculation: Z = %i, name = %s" % (self.element.get_atomic_number(), self.element.get_name())
        print >> self.out, '='*78
        print >> self.out, "Radial grid          : rmin = %f, rmax = %f, npoints = %i" % (self.grid.rmin, self.grid.rmax, self.grid.npoints)
        print >> self.out, "Atomic configuration :", tuple_to_configuration(self.config_tuple)
        print >> self.out, "Number of electrons  :", self.nelec
        print >> self.out, "Exchange-correlation :", self.xc.full_name
        print >> self.out, "SCF                  : maxiter = %i, mixing = %f, tol = %f" % (self.maxiter, self.mixing, self.tol)
        print >> self.out, ""



    def print_eigenvalues(self):
        """Print eigenvalues and occupations"""
        print >> self.out, "Eigenvalues:"
        print >> self.out, "    n l occ    energy (Ha)  energy (eV)"
        for orb in self.orbitals:
             print >> self.out, "    %i %s %-6g %12.6f %12.6f" % (orb.n, orb.l, orb.occ, orb.ene, orb.ene*27.211383)
        print >> self.out, ""


    
    def print_energies(self):
        """Print final energies"""
        print >> self.out, "Total energy    : %12.4f Ha" % (self.e_tot)
        print >> self.out, "Kinetic energy  : %12.4f Ha" % (self.e_kin)
        print >> self.out, "Ionic energy    : %12.4f Ha" % (self.e_ion)
        print >> self.out, "Hartree energy  : %12.4f Ha" % (self.e_h)
        print >> self.out, "XC energy       : %12.4f Ha" % (self.e_xc)



    def run_scf(self):
        """Run the SCF calculation"""
        # initialize potential (pure coulomb)
        npoints = self.grid.npoints
        self.v_ion = -self.grid.zeta/self.grid.r
        self.v_pot = self.v_ion.copy()

        # start SCF iteration
        rho_old = numpy.zeros(npoints)
        e_old = 0.0
        for it in xrange(1, self.maxiter):
            # solve hydrogenoic problem for every orbital
            for orb in self.orbitals:
                 ene, psi = solve_atom(self.grid, orb.n, orb.l, vpot = self.v_pot, maxiter = 50, tol = self.tol)
                 if ene != None:
                      orb.ene = ene
                      orb.psi = psi.copy()

            # rho mixing
            self.calculate_rho()
            if it > 1:
                self.rho = self.mixing*self.rho + (1.0 - self.mixing)*self.rho_old
            self.rho_old = self.rho.copy()

            # calculate potential
            self.calculate_v_of_rho()
            self.v_pot = self.v_ion + self.v_h + self.v_xc

            # calculate energy
            self.e_band = 0.0
            for orb in self.orbitals:
                self.e_band += orb.occ * orb.ene
            self.e_tot = self.e_band - self.e_h + self.e_xc - self.e_vxc
            self.e_kin = self.e_tot - self.e_ion - self.e_h - self.e_xc
            de_tot = self.e_tot - e_old
            e_old = self.e_tot

            if it == 1:
                print >> self.out, "Iteration     Total energy  Delta Energy"
            print >> self.out, "%6i        %12.6f  %12.4e" % (it, self.e_tot, de_tot)

            # check convergence and exit
            if abs(de_tot) < self.tol:
                break

        # end of SCF, print energy and eigenvalues
        print >> self.out, ""
        self.print_energies()
        self.print_eigenvalues()



    def calculate_rho(self):
        """Calculate the charge density"""
        self.rho = numpy.zeros(self.grid.npoints)
        for orb in self.orbitals:
             self.rho += orb.occ * (orb.psi*orb.psi) / self.grid.r2
        nelec = self.grid.integrate_two(self.rho, self.grid.r2)
        if abs(nelec - self.nelec) > 1e-4:
             print >> self.out, "integrated charge (%f) different from number of electrons (%f)" % (nelec, self.nelec)
	self.rho /= (4.0*math.pi)


    
    def calculate_hartree(self, rho):
        """Calculate the Hartree potential from a given density"""
        npoints = self.grid.npoints
        r, r2, dr, dx = self.grid.r, self.grid.r2, self.grid.dr, self.grid.dx

        # running charge
        q = numpy.zeros(npoints)
        for i in xrange(1,npoints):
	    q[i] = q[i-1] + 4.0*math.pi*r2[i] * dx*dr[i] * rho[i]

        # hartree
        v_h = numpy.zeros(npoints)
        v_h[-1] = q[-1]/r[-1]
        for i in xrange(npoints-1,0,-1):
	    v_h[i-1] = v_h[i] + dx * q[i]*self.grid.dr[i]/self.grid.r2[i]
        e_h = 0.5*self.grid.integrate_two(v_h, rho * r2) * 4.0*math.pi
        return e_h, v_h



    def calculate_xc(self, rho):
        """Calculate the XC potential from a given density"""
        npoints = self.grid.npoints
        r, r2, dr, dx = self.grid.r, self.grid.r2, self.grid.dr, self.grid.dx

        e_x = numpy.zeros(npoints)
        v_x = numpy.zeros(npoints)
        e_c = numpy.zeros(npoints)
        v_c = numpy.zeros(npoints)

        for i in xrange(len(rho)):
            (e_x[i], v_x[i]), (e_c[i], v_c[i]) = self.xc.xc(rho[i])

        v_xc = v_x + v_c            
        e_xc = self.grid.integrate_two(e_x + e_c, rho * r2) * 4.0*math.pi
        e_vxc = self.grid.integrate_two(v_xc, rho * r2) * 4.0*math.pi
        return e_xc, v_xc, e_vxc



    def calculate_v_of_rho(self):
        """Calculate Hartree and XC, potential and energy"""
        self.e_h, self.v_h = self.calculate_hartree(self.rho)
        self.e_ion = self.grid.integrate_two(self.v_ion, self.rho*self.grid.r2) * 4.0*math.pi
        self.e_xc, self.v_xc, self.e_vxc = self.calculate_xc(self.rho)


    def __getstate__(self):
	"""In order to implement pickle"""
	odict = self.__dict__.copy()
	del odict['out']
	return odict