#from triqs_dft_tools.sumk_dft import * from sumk_dft import * #from triqs_dft_tools.converters.wien2k_converter import * from converters.vasp_converter import * #from pytriqs.applications.impurity_solvers.hubbard_I.hubbard_solver import Solver from hf_solver import Solver import shutil class TestSumkDFT(SumkDFT): # calculate and save occupancy matrix in the Bloch basis for VASP charge denity recalculation def calc_density_correction(self, filename='GAMMA', dm_type='wien2k'): r""" Calculates the charge density correction and stores it into a file. The charge density correction is needed for charge-self-consistent DFT+DMFT calculations. It represents a density matrix of the interacting system defined in Bloch basis and it is calculated from the sum over Matsubara frequecies of the full GF, ..math:: N_{\nu\nu'}(k) = \sum_{i\omega_{n}} G_{\nu\nu'}(k, i\omega_{n}) The density matrix for every `k`-point is stored into a file. Parameters ---------- filename : string Name of the file to store the charge density correction. Returns ------- (deltaN, dens) : tuple Returns a tuple containing the density matrix `deltaN` and the corresponing total charge `dens`. """ assert type(filename) == StringType, "calc_density_correction: filename has to be a string!" assert dm_type in ('vasp', 'wien2k'), "'type' must be either 'vasp' or 'wienk'" ntoi = self.spin_names_to_ind[self.SO] spn = self.spin_block_names[self.SO] dens = {sp: 0.0 for sp in spn} # Fetch Fermi weights and energy window band indices if dm_type == 'vasp': fermi_weights = 0 band_window = 0 if mpi.is_master_node(): with HDFArchive(self.hdf_file,'r') as ar: fermi_weights = ar['dft_misc_input']['dft_fermi_weights'] band_window = ar['dft_misc_input']['band_window'] fermi_weights = mpi.bcast(fermi_weights) band_window = mpi.bcast(band_window) # Convert Fermi weights to a density matrix dens_mat_dft = {} for sp in spn: dens_mat_dft[sp] = [fermi_weights[ik, ntoi[sp], :].astype(numpy.complex_) for ik in xrange(self.n_k)] # Set up deltaN: deltaN = {} for sp in spn: deltaN[sp] = [numpy.zeros([self.n_orbitals[ik,ntoi[sp]],self.n_orbitals[ik,ntoi[sp]]], numpy.complex_) for ik in range(self.n_k)] ikarray = numpy.array(range(self.n_k)) for ik in mpi.slice_array(ikarray): G_latt_iw = self.lattice_gf(ik = ik, mu = self.chemical_potential, iw_or_w = "iw") for bname,gf in G_latt_iw: deltaN[bname][ik][:, :] = G_latt_iw[bname].density() dens[bname] += self.bz_weights[ik] * G_latt_iw[bname].total_density() if dm_type == 'vasp': # In 'vasp'-mode subtract the DFT density matrix diag_inds = numpy.diag_indices(self.n_orbitals[ik, ntoi[bname]]) deltaN[bname][ik][diag_inds] -= dens_mat_dft[bname][ik] dens[bname] -= self.bz_weights[ik] * dens_mat_dft[bname][ik].sum().real # mpi reduce: for bname in deltaN: for ik in range(self.n_k): deltaN[bname][ik] = mpi.all_reduce(mpi.world, deltaN[bname][ik], lambda x,y : x+y) dens[bname] = mpi.all_reduce(mpi.world, dens[bname], lambda x,y : x+y) mpi.barrier() # now save to file: if dm_type == 'wien2k': if mpi.is_master_node(): if self.SP == 0: f = open(filename,'w') else: f = open(filename+'up','w') f1 = open(filename+'dn','w') # write chemical potential (in Rydberg): f.write("%.14f\n"%(self.chemical_potential/self.energy_unit)) if self.SP != 0: f1.write("%.14f\n"%(self.chemical_potential/self.energy_unit)) # write beta in rydberg-1 f.write("%.14f\n"%(G_latt_iw.mesh.beta*self.energy_unit)) if self.SP != 0: f1.write("%.14f\n"%(G_latt_iw.mesh.beta*self.energy_unit)) if self.SP == 0: # no spin-polarization for ik in range(self.n_k): f.write("%s\n"%self.n_orbitals[ik,0]) for inu in range(self.n_orbitals[ik,0]): for imu in range(self.n_orbitals[ik,0]): valre = (deltaN['up'][ik][inu,imu].real + deltaN['down'][ik][inu,imu].real) / 2.0 valim = (deltaN['up'][ik][inu,imu].imag + deltaN['down'][ik][inu,imu].imag) / 2.0 f.write("%.14f %.14f "%(valre,valim)) f.write("\n") f.write("\n") f.close() elif self.SP == 1: # with spin-polarization # dict of filename: (spin index, block_name) if self.SO == 0: to_write = {f: (0, 'up'), f1: (1, 'down')} if self.SO == 1: to_write = {f: (0, 'ud'), f1: (0, 'ud')} for fout in to_write.iterkeys(): isp, sp = to_write[fout] for ik in range(self.n_k): fout.write("%s\n"%self.n_orbitals[ik,isp]) for inu in range(self.n_orbitals[ik,isp]): for imu in range(self.n_orbitals[ik,isp]): fout.write("%.14f %.14f "%(deltaN[sp][ik][inu,imu].real,deltaN[sp][ik][inu,imu].imag)) fout.write("\n") fout.write("\n") fout.close() elif dm_type == 'vasp': # assert self.SP == 0, "Spin-polarized density matrix is not implemented" if mpi.is_master_node(): with open(filename, 'w') as f: f.write(" %i -1 ! Number of k-points, default number of bands\n"%(self.n_k)) for sp in spn: for ik in xrange(self.n_k): ib1 = band_window[0][ik, 0] ib2 = band_window[0][ik, 1] f.write(" %i %i %i\n"%(ik + 1, ib1, ib2)) for inu in xrange(self.n_orbitals[ik, 0]): for imu in xrange(self.n_orbitals[ik, 0]): if self.SP == 0: valre = (deltaN['up'][ik][inu, imu].real + deltaN['down'][ik][inu, imu].real) / 2.0 valim = (deltaN['up'][ik][inu, imu].imag + deltaN['down'][ik][inu, imu].imag) / 2.0 else: valre = deltaN[sp][ik][inu, imu].real valim = deltaN[sp][ik][inu, imu].imag f.write(" %.14f %.14f"%(valre, valim)) f.write("\n") else: raise NotImplementedError("Unknown density matrix type: '%s'"%(dm_type)) return deltaN, dens def calc_hamiltonian_correction(self, filename='GAMMA'): r""" Calculates the charge density correction and stores it into a file. The charge density correction is needed for charge-self-consistent DFT+DMFT calculations. It represents a density matrix of the interacting system defined in Bloch basis and it is calculated from the sum over Matsubara frequecies of the full GF, ..math:: N_{\nu\nu'}(k) = \sum_{i\omega_{n}} G_{\nu\nu'}(k, i\omega_{n}) The density matrix for every `k`-point is stored into a file. Parameters ---------- filename : string Name of the file to store the charge density correction. Returns ------- (deltaN, dens) : tuple Returns a tuple containing the density matrix `deltaN` and the corresponing total charge `dens`. """ assert type(filename) == StringType, "calc_density_correction: filename has to be a string!" ntoi = self.spin_names_to_ind[self.SO] spn = self.spin_block_names[self.SO] dens = {sp: 0.0 for sp in spn} # Fetch Fermi weights and energy window band indices fermi_weights = 0 band_window = 0 if mpi.is_master_node(): with HDFArchive(self.hdf_file,'r') as ar: fermi_weights = ar['dft_misc_input']['dft_fermi_weights'] band_window = ar['dft_misc_input']['band_window'] fermi_weights = mpi.bcast(fermi_weights) band_window = mpi.bcast(band_window) # Set up deltaH: deltaH = {} for sp in spn: deltaH[sp] = [numpy.zeros([self.n_orbitals[ik,ntoi[sp]],self.n_orbitals[ik,ntoi[sp]]], numpy.complex_) for ik in range(self.n_k)] ikarray = numpy.array(range(self.n_k)) for ik in mpi.slice_array(ikarray): sigma_minus_dc = [s.copy() for s in self.Sigma_imp_iw] sigma_minus_dc = self.add_dc('iw') beta = self.Sigma_imp_iw[0].mesh.beta # override beta if Sigma_iw is present n_iw = len(self.Sigma_imp_iw[0].mesh) block_structure = [ range(self.n_orbitals[ik,ntoi[sp]]) for sp in spn ] gf_struct = [ (spn[isp], block_structure[isp]) for isp in range(self.n_spin_blocks[self.SO]) ] block_ind_list = [block for block,inner in gf_struct] glist = lambda : [ GfImFreq(indices=inner,beta=beta,n_points=n_iw) for block,inner in gf_struct] G_latt = BlockGf(name_list = block_ind_list, block_list = glist(), make_copies = False) G_latt.zero() for icrsh in range(self.n_corr_shells): for bname, gf in G_latt: gf += self.upfold(ik,icrsh,bname,sigma_minus_dc[icrsh][bname],gf) for sp in spn: deltaH[sp][ik][:, :] = G_latt[sp](0) # Any Matsubara frequency will do # G_latt_iw = self.lattice_gf(ik = ik, mu = self.chemical_potential, iw_or_w = "iw") # for bname,gf in G_latt_iw: # deltaN[bname][ik][:, :] = G_latt_iw[bname].density() # dens[bname] += self.bz_weights[ik] * G_latt_iw[bname].total_density() # if dm_type == 'vasp': ## In 'vasp'-mode subtract the DFT density matrix # diag_inds = numpy.diag_indices(self.n_orbitals[ik, ntoi[bname]]) # deltaN[bname][ik][diag_inds] -= dens_mat_dft[bname][ik] # dens[bname] -= self.bz_weights[ik] * dens_mat_dft[bname][ik].sum().real # mpi reduce: for bname in deltaH: for ik in range(self.n_k): deltaH[bname][ik] = mpi.all_reduce(mpi.world, deltaH[bname][ik], lambda x,y : x+y) mpi.barrier() # now save to file: if mpi.is_master_node(): with open(filename, 'w') as f: f.write("H %i -1 ! Number of k-points, default number of bands\n"%(self.n_k)) for sp in spn: for ik in xrange(self.n_k): ib1 = band_window[0][ik, 0] ib2 = band_window[0][ik, 1] f.write(" %i %i %i\n"%(ik + 1, ib1, ib2)) for inu in xrange(self.n_orbitals[ik, 0]): for imu in xrange(self.n_orbitals[ik, 0]): if self.SP == 0: valre = (deltaH['up'][ik][inu, imu].real + deltaH['down'][ik][inu, imu].real) / 2.0 valim = (deltaH['up'][ik][inu, imu].imag + deltaH['down'][ik][inu, imu].imag) / 2.0 else: valre = deltaH[sp][ik][inu, imu].real valim = deltaH[sp][ik][inu, imu].imag f.write(" %.14f %.14f"%(valre, valim)) f.write("\n") return deltaH def dmft_cycle(): lda_filename = 'vasp' beta = 400 U_int = 4.00 J_hund = 0.70 Loops = 1 # Number of DMFT sc-loops Mix = 1.0 # Mixing factor in QMC DC_type = 0 # 0...FLL, 1...Held, 2... AMF, 3...Lichtenstein DC_Mix = 1.0 # 1.0 ... all from imp; 0.0 ... all from Gloc useBlocs = False # use bloc structure from LDA input useMatrix = True # use the U matrix calculated from Slater coefficients instead of (U+2J, U, U-J) chemical_potential_init=-0.0 # initial chemical potential use_dudarev = True HDFfilename = lda_filename+'.h5' # Convert DMFT input: # Can be commented after the first run Converter = VaspConverter(filename=lda_filename) Converter.convert_dft_input() #check if there are previous runs: previous_runs = 0 previous_present = False if mpi.is_master_node(): with HDFArchive(HDFfilename,'a') as ar: if 'iterations' in ar: previous_present = True previous_runs = ar['iterations'] else: previous_runs = 0 previous_present = False mpi.barrier() previous_runs = mpi.bcast(previous_runs) previous_present = mpi.bcast(previous_present) # Init the SumK class #SK=SumkDFT(hdf_file=lda_filename+'.h5',use_dft_blocks=False) SK=TestSumkDFT(hdf_file=lda_filename+'.h5',use_dft_blocks=False) Norb = SK.corr_shells[0]['dim'] l = SK.corr_shells[0]['l'] # Init the Hubbard-I solver: S = Solver(beta = beta, l = l, dudarev=use_dudarev) # DEBUG #SK.put_Sigma(Sigma_imp=[S.Sigma]) #dH = SK.calc_hamiltonian_correction(filename='GAMMA') # END DEBUG chemical_potential=chemical_potential_init # load previous data: old self-energy, chemical potential, DC correction if (previous_present): mpi.report("Using stored data for initialisation") if (mpi.is_master_node()): with HDFArchive(HDFfilename,'a') as ar: S.Sigma <<= ar['SigmaF'] things_to_load=['chemical_potential','dc_imp'] old_data=SK.load(things_to_load) chemical_potential=old_data[0] SK.dc_imp=old_data[1] S.Sigma = mpi.bcast(S.Sigma) chemical_potential=mpi.bcast(chemical_potential) SK.dc_imp=mpi.bcast(SK.dc_imp) # DMFT loop: for Iteration_Number in range(1,Loops+1): itn = Iteration_Number + previous_runs # put Sigma into the SumK class: S.Sigma.zero() # !!!! SK.put_Sigma(Sigma_imp = [ S.Sigma ]) # Compute the SumK, possibly fixing mu by dichotomy if SK.density_required and (Iteration_Number > 1): chemical_potential = SK.calc_mu( precision = 0.001 ) else: mpi.report("No adjustment of chemical potential\nTotal density = %.3f"%SK.total_density(mu=chemical_potential)) # Density: S.G <<= SK.extract_G_loc()[0] mpi.report("Total charge of Gloc : %.6f"%S.G.total_density()) # calculated DC at the first run to have reasonable initial non-interacting atomic level positions if ((Iteration_Number==1)and(previous_present==False)): if use_dudarev: dc_value_init = 0.0 else: dc_value_init=U_int/2.0 dm=S.G.density() SK.calc_dc( dm, U_interact = U_int, J_hund = J_hund, orb = 0, use_dc_formula = DC_type, use_dc_value=dc_value_init) # calculate non-interacting atomic level positions: # eal = SK.eff_atomic_levels()[0] # S.set_atomic_levels( eal = eal ) # solve it: corr_energy, dft_dc = S.solve(U_int = U_int, J_hund = J_hund, verbosity = 1) # Now mix Sigma and G: if ((itn>1)or(previous_present)): if (mpi.is_master_node()and (Mix<1.0)): with HDFArchive(HDFfilename,'r') as ar: mpi.report("Mixing Sigma and G with factor %s"%Mix) if ('SigmaF' in ar): S.Sigma <<= Mix * S.Sigma + (1.0-Mix) * ar['SigmaF'] if ('GF' in ar): S.G <<= Mix * S.G + (1.0-Mix) * ar['GF'] S.G = mpi.bcast(S.G) S.Sigma = mpi.bcast(S.Sigma) # after the Solver has finished, set new double counting: # dm = S.G.density() # if not use_dudarev: # SK.calc_dc( dm, U_interact = U_int, J_hund = J_hund, orb = 0, use_dc_formula = DC_type ) # correlation energy calculations: correnerg = 0.5 * (S.G * S.Sigma).total_density() mpi.report("Corr. energy = %s"%correnerg) # store the impurity self-energy, GF as well as correlation energy in h5 if (mpi.is_master_node()): with HDFArchive(HDFfilename,'a') as ar: ar['iterations'] = itn ar['chemical_cotential%s'%itn] = chemical_potential ar['SigmaF'] = S.Sigma ar['GF'] = S.G ar['correnerg%s'%itn] = correnerg ar['DCenerg%s'%itn] = SK.dc_energ #Save essential SumkDFT data: things_to_save=['chemical_potential','dc_energ','dc_imp'] SK.save(things_to_save) # print out occupancy matrix of Ce 4f # mpi.report("Orbital densities of impurity Green function:") # for s in dm: # mpi.report("Block %s: "%s) # for ii in range(len(dm[s])): # str = '' # for jj in range(len(dm[s])): # if (dm[s][ii,jj].real>0): # str += " %.4f"%(dm[s][ii,jj].real) # else: # str += " %.4f"%(dm[s][ii,jj].real) # mpi.report(str) mpi.report("Total charge of impurity problem : %.6f"%S.G.total_density()) # find exact chemical potential #if (SK.density_required): # SK.chemical_potential = SK.calc_mu( precision = 0.000001 ) # SK.chemical_potential = SK.calc_mu( precision = 0.01 ) #dN, d = SK.calc_density_correction(filename='GAMMA', dm_type='vasp') #mpi.report("Trace of Density Matrix: %s"%d) mpi.report("Storing Hamiltonian correction GAMMA...") SK.put_Sigma(Sigma_imp=[S.Sigma]) dH = SK.calc_hamiltonian_correction(filename='GAMMA') # shutil.copyfile('GAMMA', 'it%i.GAMMA'%(itn)) # store correlation energy contribution to be read by Wien2ki and then included to DFT+DMFT total energy if (mpi.is_master_node()): with HDFArchive(HDFfilename) as ar: itn = ar['iterations'] correnerg = ar['correnerg%s'%itn] DCenerg = ar['DCenerg%s'%itn] correnerg -= DCenerg[0] f=open(lda_filename+'.qdmft','a') f.write("%.16f\n"%correnerg) f.close() return corr_energy, dft_dc if __name__ == '__main__': dmft_cycle()