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 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)]
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
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
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
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