class SumK_LDA_tools(SumK_LDA): """Extends the SumK_LDA class with some tools for analysing the data.""" def __init__(self, HDFfile, mu=0.0, hfield=0.0, UseLDABlocs=False, LDAdata='SumK_LDA', Symmcorrdata='SymmCorr', ParProjdata='SumK_LDA_ParProj', Symmpardata='SymmPar', Bandsdata='SumK_LDA_Bands'): self.Gupf_refreq = None SumK_LDA.__init__(self, HDFfile=HDFfile, mu=mu, hfield=hfield, UseLDABlocs=UseLDABlocs, LDAdata=LDAdata, Symmcorrdata=Symmcorrdata, ParProjdata=ParProjdata, Symmpardata=Symmpardata, Bandsdata=Bandsdata) def downfold_pc(self, ik, ir, ish, sig, gf_to_downfold, gf_inp): """Downfolding a block of the Greens function""" gf_downfolded = gf_inp.copy() isp = self.names_to_ind[self.SO][ sig] # get spin index for proj. matrices gf_downfolded.from_L_G_R(self.Proj_Mat_pc[ik][isp][ish][ir], gf_to_downfold, self.Proj_Mat_pc[ik][isp][ish] [ir].conjugate().transpose()) # downfolding G return gf_downfolded def rotloc_all(self, ish, gf_to_rotate, direction): """Local <-> Global rotation of a GF block. direction: 'toLocal' / 'toGlobal' """ assert ((direction == 'toLocal') or (direction == 'toGlobal') ), "Give direction 'toLocal' or 'toGlobal' in rotloc!" #gf_rotated = gf_to_rotate.copy() #if (direction=='toGlobal'): # gf_rotated.from_L_G_R(self.rotmat_all[ish],gf_to_rotate,self.rotmat_all[ish].conjugate().transpose()) #elif (direction=='toLocal'): # gf_rotated.from_L_G_R(self.rotmat_all[ish].conjugate().transpose(),gf_to_rotate,self.rotmat_all[ish]) gf_rotated = gf_to_rotate.copy() if (direction == 'toGlobal'): #if (self.rotmat_timeinv[ish]==1): gf_rotated <<= gf_rotated.transpose() #gf_rotated.from_L_G_R(self.rotmat[ish].transpose(),gf_rotated,self.rotmat[ish].conjugate()) if ((self.rotmat_all_timeinv[ish] == 1) and (self.SO)): gf_rotated <<= gf_rotated.transpose() gf_rotated.from_L_G_R(self.rotmat_all[ish].conjugate(), gf_rotated, self.rotmat_all[ish].transpose()) else: gf_rotated.from_L_G_R( self.rotmat_all[ish], gf_rotated, self.rotmat_all[ish].conjugate().transpose()) elif (direction == 'toLocal'): if ((self.rotmat_all_timeinv[ish] == 1) and (self.SO)): gf_rotated <<= gf_rotated.transpose() gf_rotated.from_L_G_R(self.rotmat_all[ish].transpose(), gf_rotated, self.rotmat_all[ish].conjugate()) else: gf_rotated.from_L_G_R( self.rotmat_all[ish].conjugate().transpose(), gf_rotated, self.rotmat_all[ish]) return gf_rotated def latticeGF_realfreq(self, ik, mu, broadening, Mesh=None, Beta=40, withSigma=True): """Calculates the lattice Green function on the real frequency axis. If self energy is present and withSigma=True, the mesh is taken from Sigma. Otherwise, the mesh has to be given.""" ntoi = self.names_to_ind[self.SO] bln = self.blocnames[self.SO] if (not hasattr(self, "Sigmaimp")): withSigma = False if (withSigma): assert self.Sigmaimp[ 0].Note == 'ReFreq', "Real frequency Sigma needed for latticeGF_realfreq!" Beta = self.Sigmaimp[0].Beta stmp = self.add_DC() else: assert (not (Mesh is None) ), "Without Sigma, give the mesh for latticeGF_realfreq!" if (self.Gupf_refreq is None): # first setting up of Gupf_refreq BS = [range(self.N_Orbitals[ik][ntoi[ib]]) for ib in bln] GFStruct = [(bln[ib], BS[ib]) for ib in range(self.NspinblocsGF[self.SO])] a_list = [a for a, al in GFStruct] if (withSigma): glist = lambda: [ GFBloc_ReFreq(Indices=al, Mesh=self.Sigmaimp[0].mesh) for a, al in GFStruct ] else: glist = lambda: [ GFBloc_ReFreq(Indices=al, Beta=Beta, MeshArray=Mesh) for a, al in GFStruct ] self.Gupf_refreq = GF(NameList=a_list, BlockList=glist(), Copy=False) self.Gupf_refreq.zero() GFsize = [gf.N1 for sig, gf in self.Gupf_refreq] unchangedsize = all([ self.N_Orbitals[ik][ntoi[bln[ib]]] == GFsize[ib] for ib in range(self.NspinblocsGF[self.SO]) ]) if (not unchangedsize): BS = [range(self.N_Orbitals[ik][ntoi[ib]]) for ib in bln] GFStruct = [(bln[ib], BS[ib]) for ib in range(self.NspinblocsGF[self.SO])] a_list = [a for a, al in GFStruct] if (withSigma): glist = lambda: [ GFBloc_ReFreq(Indices=al, Mesh=self.Sigmaimp[0].mesh) for a, al in GFStruct ] else: glist = lambda: [ GFBloc_ReFreq(Indices=al, Beta=Beta, MeshArray=Mesh) for a, al in GFStruct ] self.Gupf_refreq = GF(NameList=a_list, BlockList=glist(), Copy=False) self.Gupf_refreq.zero() idmat = [ numpy.identity(self.N_Orbitals[ik][ntoi[bl]], numpy.complex_) for bl in bln ] self.Gupf_refreq <<= GF_Initializers.A_Omega_Plus_B(A=1, B=1j * broadening) M = copy.deepcopy(idmat) for ibl in range(self.NspinblocsGF[self.SO]): ind = ntoi[bln[ibl]] M[ibl] = self.Hopping[ik][ind] - (idmat[ibl] * mu) - (idmat[ibl] * self.hfield * (1 - 2 * ibl)) self.Gupf_refreq -= M if (withSigma): tmp = self.Gupf_refreq.copy() # init temporary storage for icrsh in xrange(self.N_corr_shells): for sig, gf in tmp: tmp[sig] <<= self.upfold(ik, icrsh, sig, stmp[icrsh][sig], gf) self.Gupf_refreq -= tmp # adding to the upfolded GF self.Gupf_refreq.invert() return self.Gupf_refreq def check_inputDOS(self, ommin, ommax, N_om, Beta=10, broadening=0.01): delta_om = (ommax - ommin) / (N_om - 1) Mesh = numpy.zeros([N_om], numpy.float_) DOS = {} for bn in self.blocnames[self.SO]: DOS[bn] = numpy.zeros([N_om], numpy.float_) DOSproj = [{} for icrsh in range(self.N_inequiv_corr_shells)] DOSproj_orb = [{} for icrsh in range(self.N_inequiv_corr_shells)] for icrsh in range(self.N_inequiv_corr_shells): for bn in self.blocnames[self.corr_shells[self.invshellmap[icrsh]] [4]]: dl = self.corr_shells[self.invshellmap[icrsh]][3] DOSproj[icrsh][bn] = numpy.zeros([N_om], numpy.float_) DOSproj_orb[icrsh][bn] = numpy.zeros([dl, dl, N_om], numpy.float_) for i in range(N_om): Mesh[i] = ommin + delta_om * i # init: Gloc = [] for icrsh in range(self.N_corr_shells): b_list = [a for a, al in self.GFStruct_corr[icrsh]] glist = lambda: [ GFBloc_ReFreq(Indices=al, Beta=Beta, MeshArray=Mesh) for a, al in self.GFStruct_corr[icrsh] ] Gloc.append(GF(NameList=b_list, BlockList=glist(), Copy=False)) for icrsh in xrange(self.N_corr_shells): Gloc[icrsh].zero() # initialize to zero for ik in xrange(self.Nk): Gupf = self.latticeGF_realfreq(ik=ik, mu=self.Chemical_Potential, broadening=broadening, Beta=Beta, Mesh=Mesh, withSigma=False) Gupf *= self.BZ_weights[ik] # non-projected DOS for iom in range(N_om): for sig, gf in Gupf: asd = gf._data.array[:, :, iom].imag.trace() / (-3.1415926535) DOS[sig][iom] += asd for icrsh in xrange(self.N_corr_shells): tmp = Gloc[icrsh].copy() for sig, gf in tmp: tmp[sig] <<= self.downfold(ik, icrsh, sig, Gupf[sig], gf) # downfolding G Gloc[icrsh] += tmp if (self.symm_op != 0): Gloc = self.Symm_corr.symmetrise(Gloc) if (self.use_rotations): for icrsh in xrange(self.N_corr_shells): for sig, gf in Gloc[icrsh]: Gloc[icrsh][sig] <<= self.rotloc(icrsh, gf, direction='toLocal') # Gloc can now also be used to look at orbitally resolved quantities for ish in range(self.N_inequiv_corr_shells): for sig, gf in Gloc[self.invshellmap[ish]]: # loop over spins for iom in range(N_om): DOSproj[ish][sig][ iom] += gf._data.array[:, :, iom].imag.trace() / ( -3.1415926535) DOSproj_orb[ish][ sig][:, :, :] += gf._data.array[:, :, :].imag / ( -3.1415926535) # output: if (MPI.IS_MASTER_NODE()): for bn in self.blocnames[self.SO]: f = open('DOS%s.dat' % bn, 'w') for i in range(N_om): f.write("%s %s\n" % (Mesh[i], DOS[bn][i])) f.close() for ish in range(self.N_inequiv_corr_shells): f = open('DOS%s_proj%s.dat' % (bn, ish), 'w') for i in range(N_om): f.write("%s %s\n" % (Mesh[i], DOSproj[ish][bn][i])) f.close() for i in range(self.corr_shells[self.invshellmap[ish]][3]): for j in range( i, self.corr_shells[self.invshellmap[ish]][3]): Fname = 'DOS' + bn + '_proj' + str( ish) + '_' + str(i) + '_' + str(j) + '.dat' f = open(Fname, 'w') for iom in range(N_om): f.write("%s %s\n" % (Mesh[iom], DOSproj_orb[ish][bn][i, j, iom])) f.close() def read_ParProj_input_from_HDF(self): """ Reads the data for the partial projectors from the HDF file """ thingstoread = [ 'Dens_Mat_below', 'N_parproj', 'Proj_Mat_pc', 'rotmat_all', 'rotmat_all_timeinv' ] retval = self.read_input_from_HDF(SubGrp=self.ParProjdata, thingstoread=thingstoread) return retval def DOSpartial(self, broadening=0.01): """calculates the orbitally-resolved DOS""" assert hasattr(self, "Sigmaimp"), "Set Sigma First!!" #thingstoread = ['Dens_Mat_below','N_parproj','Proj_Mat_pc','rotmat_all'] #retval = self.read_input_from_HDF(SubGrp=self.ParProjdata, thingstoread=thingstoread) retval = self.read_ParProj_input_from_HDF() if not retval: return retval if self.symm_op: self.Symm_par = Symmetry(self.HDFfile, subgroup=self.Symmpardata) mu = self.Chemical_Potential GFStruct_proj = [[(al, range(self.shells[i][3])) for al in self.blocnames[self.SO]] for i in xrange(self.N_shells)] Gproj = [ GF(Name_Block_Generator=[ (a, GFBloc_ReFreq(Indices=al, Mesh=self.Sigmaimp[0].mesh)) for a, al in GFStruct_proj[ish] ], Copy=False) for ish in xrange(self.N_shells) ] for ish in range(self.N_shells): Gproj[ish].zero() Msh = [x for x in self.Sigmaimp[0].mesh] N_om = len(Msh) DOS = {} for bn in self.blocnames[self.SO]: DOS[bn] = numpy.zeros([N_om], numpy.float_) DOSproj = [{} for ish in range(self.N_shells)] DOSproj_orb = [{} for ish in range(self.N_shells)] for ish in range(self.N_shells): for bn in self.blocnames[self.SO]: dl = self.shells[ish][3] DOSproj[ish][bn] = numpy.zeros([N_om], numpy.float_) DOSproj_orb[ish][bn] = numpy.zeros([dl, dl, N_om], numpy.float_) ikarray = numpy.array(range(self.Nk)) for ik in MPI.slice_array(ikarray): S = self.latticeGF_realfreq(ik=ik, mu=mu, broadening=broadening) S *= self.BZ_weights[ik] # non-projected DOS for iom in range(N_om): for sig, gf in S: DOS[sig][iom] += gf._data.array[:, :, iom].imag.trace() / ( -3.1415926535) #projected DOS: for ish in xrange(self.N_shells): tmp = Gproj[ish].copy() for ir in xrange(self.N_parproj[ish]): for sig, gf in tmp: tmp[sig] <<= self.downfold_pc(ik, ir, ish, sig, S[sig], gf) Gproj[ish] += tmp # collect data from MPI: for sig in DOS: DOS[sig] = MPI.all_reduce(MPI.world, DOS[sig], lambda x, y: x + y) for ish in xrange(self.N_shells): Gproj[ish] <<= MPI.all_reduce(MPI.world, Gproj[ish], lambda x, y: x + y) MPI.barrier() if (self.symm_op != 0): Gproj = self.Symm_par.symmetrise(Gproj) # rotation to local coord. system: if (self.use_rotations): for ish in xrange(self.N_shells): for sig, gf in Gproj[ish]: Gproj[ish][sig] <<= self.rotloc_all(ish, gf, direction='toLocal') for ish in range(self.N_shells): for sig, gf in Gproj[ish]: for iom in range(N_om): DOSproj[ish][sig][ iom] += gf._data.array[:, :, iom].imag.trace() / ( -3.1415926535) DOSproj_orb[ish][ sig][:, :, :] += gf._data.array[:, :, :].imag / ( -3.1415926535) if (MPI.IS_MASTER_NODE()): # output to files for bn in self.blocnames[self.SO]: f = open('./DOScorr%s.dat' % bn, 'w') for i in range(N_om): f.write("%s %s\n" % (Msh[i], DOS[bn][i])) f.close() # partial for ish in range(self.N_shells): f = open('DOScorr%s_proj%s.dat' % (bn, ish), 'w') for i in range(N_om): f.write("%s %s\n" % (Msh[i], DOSproj[ish][bn][i])) f.close() for i in range(self.shells[ish][3]): for j in range(i, self.shells[ish][3]): Fname = './DOScorr' + bn + '_proj' + str( ish) + '_' + str(i) + '_' + str(j) + '.dat' f = open(Fname, 'w') for iom in range(N_om): f.write("%s %s\n" % (Msh[iom], DOSproj_orb[ish][bn][i, j, iom])) f.close() def spaghettis(self, broadening, shift=0.0, plotrange=None, ishell=None, invertAkw=False, Fermisurface=False): """ Calculates the correlated band structure with a real-frequency self energy. ATTENTION: Many things from the original input file are are overwritten!!!""" assert hasattr(self, "Sigmaimp"), "Set Sigma First!!" thingstoread = [ 'Nk', 'N_Orbitals', 'Proj_Mat', 'Hopping', 'N_parproj', 'Proj_Mat_pc' ] retval = self.read_input_from_HDF(SubGrp=self.Bandsdata, thingstoread=thingstoread) if not retval: return retval if Fermisurface: ishell = None # print hamiltonian for checks: if ((self.SP == 1) and (self.SO == 0)): f1 = open('hamup.dat', 'w') f2 = open('hamdn.dat', 'w') for ik in xrange(self.Nk): for i in xrange(self.N_Orbitals[ik][0]): f1.write('%s %s\n' % (ik, self.Hopping[ik][0][i, i].real)) for i in xrange(self.N_Orbitals[ik][1]): f2.write('%s %s\n' % (ik, self.Hopping[ik][1][i, i].real)) f1.write('\n') f2.write('\n') f1.close() f2.close() else: f = open('ham.dat', 'w') for ik in xrange(self.Nk): for i in xrange(self.N_Orbitals[ik][0]): f.write('%s %s\n' % (ik, self.Hopping[ik][0][i, i].real)) f.write('\n') f.close() #========================================= # calculate A(k,w): mu = self.Chemical_Potential bln = self.blocnames[self.SO] # init DOS: M = [x for x in self.Sigmaimp[0].mesh] N_om = len(M) if plotrange is None: omminplot = M[0] - 0.001 ommaxplot = M[N_om - 1] + 0.001 else: omminplot = plotrange[0] ommaxplot = plotrange[1] if (ishell is None): Akw = {} for ibn in bln: Akw[ibn] = numpy.zeros([self.Nk, N_om], numpy.float_) else: Akw = {} for ibn in bln: Akw[ibn] = numpy.zeros([self.shells[ishell][3], self.Nk, N_om], numpy.float_) if Fermisurface: omminplot = -2.0 * broadening ommaxplot = 2.0 * broadening Akw = {} for ibn in bln: Akw[ibn] = numpy.zeros([self.Nk, 1], numpy.float_) if not (ishell is None): GFStruct_proj = [(al, range(self.shells[ishell][3])) for al in bln] Gproj = GF(Name_Block_Generator=[ (a, GFBloc_ReFreq(Indices=al, Mesh=self.Sigmaimp[0].mesh)) for a, al in GFStruct_proj ], Copy=False) Gproj.zero() for ik in xrange(self.Nk): S = self.latticeGF_realfreq(ik=ik, mu=mu, broadening=broadening) if (ishell is None): # non-projected A(k,w) for iom in range(N_om): if (M[iom] > omminplot) and (M[iom] < ommaxplot): if Fermisurface: for sig, gf in S: Akw[sig][ ik, 0] += gf._data.array[:, :, iom].imag.trace( ) / (-3.1415926535) * (M[1] - M[0]) else: for sig, gf in S: Akw[sig][ ik, iom] += gf._data.array[:, :, iom].imag.trace( ) / (-3.1415926535) Akw[sig][ ik, iom] += ik * shift # shift Akw for plotting in xmgrace else: # projected A(k,w): Gproj.zero() tmp = Gproj.copy() for ir in xrange(self.N_parproj[ishell]): for sig, gf in tmp: tmp[sig] <<= self.downfold_pc(ik, ir, ishell, sig, S[sig], gf) Gproj += tmp # TO BE FIXED: # rotate to local frame #if (self.use_rotations): # for sig,gf in Gproj: Gproj[sig] <<= self.rotloc(0,gf,direction='toLocal') for iom in range(N_om): if (M[iom] > omminplot) and (M[iom] < ommaxplot): for ish in range(self.shells[ishell][3]): for ibn in bln: Akw[ibn][ish, ik, iom] = Gproj[ibn]._data.array[ ish, ish, iom].imag / (-3.1415926535) # END k-LOOP if (MPI.IS_MASTER_NODE()): if (ishell is None): for ibn in bln: # loop over GF blocs: if (invertAkw): maxAkw = Akw[ibn].max() minAkw = Akw[ibn].min() # open file for storage: if Fermisurface: f = open('FS_' + ibn + '.dat', 'w') else: f = open('Akw_' + ibn + '.dat', 'w') for ik in range(self.Nk): if Fermisurface: if (invertAkw): Akw[ibn][ik, 0] = 1.0 / (minAkw - maxAkw) * ( Akw[ibn][ik, iom] - maxAkw) f.write('%s %s\n' % (ik, Akw[ibn][ik, 0])) else: for iom in range(N_om): if (M[iom] > omminplot) and (M[iom] < ommaxplot): if (invertAkw): Akw[ibn][ ik, iom] = 1.0 / (minAkw - maxAkw) * ( Akw[ibn][ik, iom] - maxAkw) if (shift > 0.0001): f.write('%s %s\n' % (M[iom], Akw[ibn][ik, iom])) else: f.write( '%s %s %s\n' % (ik, M[iom], Akw[ibn][ik, iom])) f.write('\n') f.close() else: for ibn in bln: for ish in range(self.shells[ishell][3]): if (invertAkw): maxAkw = Akw[ibn][ish, :, :].max() minAkw = Akw[ibn][ish, :, :].min() f = open('Akw_' + ibn + '_proj' + str(ish) + '.dat', 'w') for ik in range(self.Nk): for iom in range(N_om): if (M[iom] > omminplot) and (M[iom] < ommaxplot): if (invertAkw): Akw[ibn][ish, ik, iom] = 1.0 / ( minAkw - maxAkw ) * (Akw[ibn][ish, ik, iom] - maxAkw) if (shift > 0.0001): f.write( '%s %s\n' % (M[iom], Akw[ibn][ish, ik, iom])) else: f.write('%s %s %s\n' % (ik, M[iom], Akw[ibn][ish, ik, iom])) f.write('\n') f.close() def constr_Sigma_ME(self, Filename, Beta, N_om, orb=0): """Uses Data from files to construct a GF object on the real axis.""" #first get the mesh out of one of the files: if (len(self.GFStruct_Solver[orb][0][1]) == 1): Fname = Filename + '_' + self.GFStruct_Solver[orb][0][0] + '.dat' else: Fname = Filename + '_' + self.GFStruct_Solver[orb][0][ 0] + '/' + str(self.GFStruct_Solver[orb][0][1][0]) + '_' + str( self.GFStruct_Solver[orb][0][1][0]) + '.dat' R = Read_Fortran_File(Fname) mesh = numpy.zeros([N_om], numpy.float_) try: for i in xrange(N_om): mesh[i] = R.next() sk = R.next() sk = R.next() except StopIteration: # a more explicit error if the file is corrupted. raise "SumK_LDA.read_Sigma_ME : reading file failed!" R.close() # now initialize the GF with the mesh a_list = [a for a, al in self.GFStruct_Solver[orb]] glist = lambda: [ GFBloc_ReFreq(Indices=al, Beta=Beta, MeshArray=mesh) for a, al in self.GFStruct_Solver[orb] ] SigmaME = GF(NameList=a_list, BlockList=glist(), Copy=False) SigmaME.load(Filename) SigmaME.Note = 'ReFreq' # This is important for the put_Sigma routine!!! return SigmaME def partial_charges(self): """Calculates the orbitally-resolved density matrix for all the orbitals considered in the input. The theta-projectors are used, hence case.parproj data is necessary""" #thingstoread = ['Dens_Mat_below','N_parproj','Proj_Mat_pc','rotmat_all'] #retval = self.read_input_from_HDF(SubGrp=self.ParProjdata,thingstoread=thingstoread) retval = self.read_ParProj_input_from_HDF() if not retval: return retval if self.symm_op: self.Symm_par = Symmetry(self.HDFfile, subgroup=self.Symmpardata) # Density matrix in the window bln = self.blocnames[self.SO] ntoi = self.names_to_ind[self.SO] self.Dens_Mat_window = [[ numpy.zeros([self.shells[ish][3], self.shells[ish][3]], numpy.complex_) for ish in range(self.N_shells) ] for isp in range(len(bln))] # init the density matrix mu = self.Chemical_Potential GFStruct_proj = [[(al, range(self.shells[i][3])) for al in bln] for i in xrange(self.N_shells)] if hasattr(self, "Sigmaimp"): Gproj = [ GF(Name_Block_Generator=[ (a, GFBloc_ImFreq(Indices=al, Mesh=self.Sigmaimp[0].mesh)) for a, al in GFStruct_proj[ish] ], Copy=False) for ish in xrange(self.N_shells) ] else: Gproj = [ GF(Name_Block_Generator=[(a, GFBloc_ImFreq(Indices=al, Beta=40)) for a, al in GFStruct_proj[ish]], Copy=False) for ish in xrange(self.N_shells) ] for ish in xrange(self.N_shells): Gproj[ish].zero() ikarray = numpy.array(range(self.Nk)) #print MPI.rank, MPI.slice_array(ikarray) #print "K-Sum starts on node",MPI.rank," at ",datetime.now() for ik in MPI.slice_array(ikarray): #print MPI.rank, ik, datetime.now() S = self.latticeGF_Matsubara(ik=ik, mu=mu) S *= self.BZ_weights[ik] for ish in xrange(self.N_shells): tmp = Gproj[ish].copy() for ir in xrange(self.N_parproj[ish]): for sig, gf in tmp: tmp[sig] <<= self.downfold_pc(ik, ir, ish, sig, S[sig], gf) Gproj[ish] += tmp #print "K-Sum done on node",MPI.rank," at ",datetime.now() #collect data from MPI: for ish in xrange(self.N_shells): Gproj[ish] <<= MPI.all_reduce(MPI.world, Gproj[ish], lambda x, y: x + y) MPI.barrier() #print "Data collected on node",MPI.rank," at ",datetime.now() # Symmetrisation: if (self.symm_op != 0): Gproj = self.Symm_par.symmetrise(Gproj) #print "Symmetrisation done on node",MPI.rank," at ",datetime.now() for ish in xrange(self.N_shells): # Rotation to local: if (self.use_rotations): for sig, gf in Gproj[ish]: Gproj[ish][sig] <<= self.rotloc_all(ish, gf, direction='toLocal') isp = 0 for sig, gf in Gproj[ish]: #dmg.append(Gproj[ish].density()[sig]) self.Dens_Mat_window[isp][ish] = Gproj[ish].density()[sig] isp += 1 # add Density matrices to get the total: Dens_Mat = [[ self.Dens_Mat_below[ntoi[bln[isp]]][ish] + self.Dens_Mat_window[isp][ish] for ish in range(self.N_shells) ] for isp in range(len(bln))] return Dens_Mat
def spaghettis(self, broadening, shift=0.0, plotrange=None, ishell=None, invertAkw=False, Fermisurface=False): """ Calculates the correlated band structure with a real-frequency self energy. ATTENTION: Many things from the original input file are are overwritten!!!""" assert hasattr(self, "Sigmaimp"), "Set Sigma First!!" thingstoread = [ 'Nk', 'N_Orbitals', 'Proj_Mat', 'Hopping', 'N_parproj', 'Proj_Mat_pc' ] retval = self.read_input_from_HDF(SubGrp=self.Bandsdata, thingstoread=thingstoread) if not retval: return retval if Fermisurface: ishell = None # print hamiltonian for checks: if ((self.SP == 1) and (self.SO == 0)): f1 = open('hamup.dat', 'w') f2 = open('hamdn.dat', 'w') for ik in xrange(self.Nk): for i in xrange(self.N_Orbitals[ik][0]): f1.write('%s %s\n' % (ik, self.Hopping[ik][0][i, i].real)) for i in xrange(self.N_Orbitals[ik][1]): f2.write('%s %s\n' % (ik, self.Hopping[ik][1][i, i].real)) f1.write('\n') f2.write('\n') f1.close() f2.close() else: f = open('ham.dat', 'w') for ik in xrange(self.Nk): for i in xrange(self.N_Orbitals[ik][0]): f.write('%s %s\n' % (ik, self.Hopping[ik][0][i, i].real)) f.write('\n') f.close() #========================================= # calculate A(k,w): mu = self.Chemical_Potential bln = self.blocnames[self.SO] # init DOS: M = [x for x in self.Sigmaimp[0].mesh] N_om = len(M) if plotrange is None: omminplot = M[0] - 0.001 ommaxplot = M[N_om - 1] + 0.001 else: omminplot = plotrange[0] ommaxplot = plotrange[1] if (ishell is None): Akw = {} for ibn in bln: Akw[ibn] = numpy.zeros([self.Nk, N_om], numpy.float_) else: Akw = {} for ibn in bln: Akw[ibn] = numpy.zeros([self.shells[ishell][3], self.Nk, N_om], numpy.float_) if Fermisurface: omminplot = -2.0 * broadening ommaxplot = 2.0 * broadening Akw = {} for ibn in bln: Akw[ibn] = numpy.zeros([self.Nk, 1], numpy.float_) if not (ishell is None): GFStruct_proj = [(al, range(self.shells[ishell][3])) for al in bln] Gproj = GF(Name_Block_Generator=[ (a, GFBloc_ReFreq(Indices=al, Mesh=self.Sigmaimp[0].mesh)) for a, al in GFStruct_proj ], Copy=False) Gproj.zero() for ik in xrange(self.Nk): S = self.latticeGF_realfreq(ik=ik, mu=mu, broadening=broadening) if (ishell is None): # non-projected A(k,w) for iom in range(N_om): if (M[iom] > omminplot) and (M[iom] < ommaxplot): if Fermisurface: for sig, gf in S: Akw[sig][ ik, 0] += gf._data.array[:, :, iom].imag.trace( ) / (-3.1415926535) * (M[1] - M[0]) else: for sig, gf in S: Akw[sig][ ik, iom] += gf._data.array[:, :, iom].imag.trace( ) / (-3.1415926535) Akw[sig][ ik, iom] += ik * shift # shift Akw for plotting in xmgrace else: # projected A(k,w): Gproj.zero() tmp = Gproj.copy() for ir in xrange(self.N_parproj[ishell]): for sig, gf in tmp: tmp[sig] <<= self.downfold_pc(ik, ir, ishell, sig, S[sig], gf) Gproj += tmp # TO BE FIXED: # rotate to local frame #if (self.use_rotations): # for sig,gf in Gproj: Gproj[sig] <<= self.rotloc(0,gf,direction='toLocal') for iom in range(N_om): if (M[iom] > omminplot) and (M[iom] < ommaxplot): for ish in range(self.shells[ishell][3]): for ibn in bln: Akw[ibn][ish, ik, iom] = Gproj[ibn]._data.array[ ish, ish, iom].imag / (-3.1415926535) # END k-LOOP if (MPI.IS_MASTER_NODE()): if (ishell is None): for ibn in bln: # loop over GF blocs: if (invertAkw): maxAkw = Akw[ibn].max() minAkw = Akw[ibn].min() # open file for storage: if Fermisurface: f = open('FS_' + ibn + '.dat', 'w') else: f = open('Akw_' + ibn + '.dat', 'w') for ik in range(self.Nk): if Fermisurface: if (invertAkw): Akw[ibn][ik, 0] = 1.0 / (minAkw - maxAkw) * ( Akw[ibn][ik, iom] - maxAkw) f.write('%s %s\n' % (ik, Akw[ibn][ik, 0])) else: for iom in range(N_om): if (M[iom] > omminplot) and (M[iom] < ommaxplot): if (invertAkw): Akw[ibn][ ik, iom] = 1.0 / (minAkw - maxAkw) * ( Akw[ibn][ik, iom] - maxAkw) if (shift > 0.0001): f.write('%s %s\n' % (M[iom], Akw[ibn][ik, iom])) else: f.write( '%s %s %s\n' % (ik, M[iom], Akw[ibn][ik, iom])) f.write('\n') f.close() else: for ibn in bln: for ish in range(self.shells[ishell][3]): if (invertAkw): maxAkw = Akw[ibn][ish, :, :].max() minAkw = Akw[ibn][ish, :, :].min() f = open('Akw_' + ibn + '_proj' + str(ish) + '.dat', 'w') for ik in range(self.Nk): for iom in range(N_om): if (M[iom] > omminplot) and (M[iom] < ommaxplot): if (invertAkw): Akw[ibn][ish, ik, iom] = 1.0 / ( minAkw - maxAkw ) * (Akw[ibn][ish, ik, iom] - maxAkw) if (shift > 0.0001): f.write( '%s %s\n' % (M[iom], Akw[ibn][ish, ik, iom])) else: f.write('%s %s %s\n' % (ik, M[iom], Akw[ibn][ish, ik, iom])) f.write('\n') f.close()
class SumK_LDA_tools(SumK_LDA): """Extends the SumK_LDA class with some tools for analysing the data.""" def __init__(self, HDFfile, mu = 0.0, hfield = 0.0, UseLDABlocs = False, LDAdata = 'SumK_LDA', Symmcorrdata = 'SymmCorr', ParProjdata = 'SumK_LDA_ParProj', Symmpardata = 'SymmPar', Bandsdata = 'SumK_LDA_Bands'): self.Gupf_refreq = None SumK_LDA.__init__(self,HDFfile=HDFfile,mu=mu,hfield=hfield,UseLDABlocs=UseLDABlocs,LDAdata=LDAdata, Symmcorrdata=Symmcorrdata,ParProjdata=ParProjdata,Symmpardata=Symmpardata, Bandsdata=Bandsdata) def downfold_pc(self,ik,ir,ish,sig,gf_to_downfold,gf_inp): """Downfolding a block of the Greens function""" gf_downfolded = gf_inp.copy() isp = self.names_to_ind[self.SO][sig] # get spin index for proj. matrices gf_downfolded.from_L_G_R(self.Proj_Mat_pc[ik][isp][ish][ir],gf_to_downfold,self.Proj_Mat_pc[ik][isp][ish][ir].conjugate().transpose()) # downfolding G return gf_downfolded def rotloc_all(self,ish,gf_to_rotate,direction): """Local <-> Global rotation of a GF block. direction: 'toLocal' / 'toGlobal' """ assert ((direction=='toLocal')or(direction=='toGlobal')),"Give direction 'toLocal' or 'toGlobal' in rotloc!" #gf_rotated = gf_to_rotate.copy() #if (direction=='toGlobal'): # gf_rotated.from_L_G_R(self.rotmat_all[ish],gf_to_rotate,self.rotmat_all[ish].conjugate().transpose()) #elif (direction=='toLocal'): # gf_rotated.from_L_G_R(self.rotmat_all[ish].conjugate().transpose(),gf_to_rotate,self.rotmat_all[ish]) gf_rotated = gf_to_rotate.copy() if (direction=='toGlobal'): #if (self.rotmat_timeinv[ish]==1): gf_rotated <<= gf_rotated.transpose() #gf_rotated.from_L_G_R(self.rotmat[ish].transpose(),gf_rotated,self.rotmat[ish].conjugate()) if ((self.rotmat_all_timeinv[ish]==1) and (self.SO)): gf_rotated <<= gf_rotated.transpose() gf_rotated.from_L_G_R(self.rotmat_all[ish].conjugate(),gf_rotated,self.rotmat_all[ish].transpose()) else: gf_rotated.from_L_G_R(self.rotmat_all[ish],gf_rotated,self.rotmat_all[ish].conjugate().transpose()) elif (direction=='toLocal'): if ((self.rotmat_all_timeinv[ish]==1)and(self.SO)): gf_rotated <<= gf_rotated.transpose() gf_rotated.from_L_G_R(self.rotmat_all[ish].transpose(),gf_rotated,self.rotmat_all[ish].conjugate()) else: gf_rotated.from_L_G_R(self.rotmat_all[ish].conjugate().transpose(),gf_rotated,self.rotmat_all[ish]) return gf_rotated def latticeGF_realfreq(self, ik, mu, broadening, Mesh=None, Beta=40, withSigma=True): """Calculates the lattice Green function on the real frequency axis. If self energy is present and withSigma=True, the mesh is taken from Sigma. Otherwise, the mesh has to be given.""" ntoi = self.names_to_ind[self.SO] bln = self.blocnames[self.SO] if (not hasattr(self,"Sigmaimp")): withSigma=False if (withSigma): assert self.Sigmaimp[0].Note=='ReFreq',"Real frequency Sigma needed for latticeGF_realfreq!" Beta = self.Sigmaimp[0].Beta stmp = self.add_DC() else: assert (not (Mesh is None)),"Without Sigma, give the mesh for latticeGF_realfreq!" if (self.Gupf_refreq is None): # first setting up of Gupf_refreq BS = [ range(self.N_Orbitals[ik][ntoi[ib]]) for ib in bln ] GFStruct = [ (bln[ib], BS[ib]) for ib in range(self.NspinblocsGF[self.SO]) ] a_list = [a for a,al in GFStruct] if (withSigma): glist = lambda : [ GFBloc_ReFreq(Indices = al, Mesh=self.Sigmaimp[0].mesh) for a,al in GFStruct] else: glist = lambda : [ GFBloc_ReFreq(Indices = al, Beta = Beta, MeshArray = Mesh) for a,al in GFStruct] self.Gupf_refreq = GF(NameList = a_list, BlockList = glist(),Copy=False) self.Gupf_refreq.zero() GFsize = [ gf.N1 for sig,gf in self.Gupf_refreq] unchangedsize = all( [ self.N_Orbitals[ik][ntoi[bln[ib]]]==GFsize[ib] for ib in range(self.NspinblocsGF[self.SO]) ] ) if (not unchangedsize): BS = [ range(self.N_Orbitals[ik][ntoi[ib]]) for ib in bln ] GFStruct = [ (bln[ib], BS[ib]) for ib in range(self.NspinblocsGF[self.SO]) ] a_list = [a for a,al in GFStruct] if (withSigma): glist = lambda : [ GFBloc_ReFreq(Indices = al, Mesh=self.Sigmaimp[0].mesh) for a,al in GFStruct] else: glist = lambda : [ GFBloc_ReFreq(Indices = al, Beta = Beta, MeshArray = Mesh) for a,al in GFStruct] self.Gupf_refreq = GF(NameList = a_list, BlockList = glist(),Copy=False) self.Gupf_refreq.zero() idmat = [numpy.identity(self.N_Orbitals[ik][ntoi[bl]],numpy.complex_) for bl in bln] self.Gupf_refreq <<= GF_Initializers.A_Omega_Plus_B(A=1,B=1j*broadening) M = copy.deepcopy(idmat) for ibl in range(self.NspinblocsGF[self.SO]): ind = ntoi[bln[ibl]] M[ibl] = self.Hopping[ik][ind] - (idmat[ibl]*mu) - (idmat[ibl] * self.hfield * (1-2*ibl)) self.Gupf_refreq -= M if (withSigma): tmp = self.Gupf_refreq.copy() # init temporary storage for icrsh in xrange(self.N_corr_shells): for sig,gf in tmp: tmp[sig] <<= self.upfold(ik,icrsh,sig,stmp[icrsh][sig],gf) self.Gupf_refreq -= tmp # adding to the upfolded GF self.Gupf_refreq.invert() return self.Gupf_refreq def check_inputDOS(self, ommin, ommax, N_om, Beta=10, broadening=0.01): delta_om = (ommax-ommin)/(N_om-1) Mesh = numpy.zeros([N_om],numpy.float_) DOS = {} for bn in self.blocnames[self.SO]: DOS[bn] = numpy.zeros([N_om],numpy.float_) DOSproj = [ {} for icrsh in range(self.N_inequiv_corr_shells) ] DOSproj_orb = [ {} for icrsh in range(self.N_inequiv_corr_shells) ] for icrsh in range(self.N_inequiv_corr_shells): for bn in self.blocnames[self.corr_shells[self.invshellmap[icrsh]][4]]: dl = self.corr_shells[self.invshellmap[icrsh]][3] DOSproj[icrsh][bn] = numpy.zeros([N_om],numpy.float_) DOSproj_orb[icrsh][bn] = numpy.zeros([dl,dl,N_om],numpy.float_) for i in range(N_om): Mesh[i] = ommin + delta_om * i # init: Gloc = [] for icrsh in range(self.N_corr_shells): b_list = [a for a,al in self.GFStruct_corr[icrsh]] glist = lambda : [ GFBloc_ReFreq(Indices = al, Beta = Beta, MeshArray = Mesh) for a,al in self.GFStruct_corr[icrsh]] Gloc.append(GF(NameList = b_list, BlockList = glist(),Copy=False)) for icrsh in xrange(self.N_corr_shells): Gloc[icrsh].zero() # initialize to zero for ik in xrange(self.Nk): Gupf=self.latticeGF_realfreq(ik=ik,mu=self.Chemical_Potential,broadening=broadening,Beta=Beta,Mesh=Mesh,withSigma=False) Gupf *= self.BZ_weights[ik] # non-projected DOS for iom in range(N_om): for sig,gf in Gupf: asd = gf._data.array[:,:,iom].imag.trace()/(-3.1415926535) DOS[sig][iom] += asd for icrsh in xrange(self.N_corr_shells): tmp = Gloc[icrsh].copy() for sig,gf in tmp: tmp[sig] <<= self.downfold(ik,icrsh,sig,Gupf[sig],gf) # downfolding G Gloc[icrsh] += tmp if (self.symm_op!=0): Gloc = self.Symm_corr.symmetrise(Gloc) if (self.use_rotations): for icrsh in xrange(self.N_corr_shells): for sig,gf in Gloc[icrsh]: Gloc[icrsh][sig] <<= self.rotloc(icrsh,gf,direction='toLocal') # Gloc can now also be used to look at orbitally resolved quantities for ish in range(self.N_inequiv_corr_shells): for sig,gf in Gloc[self.invshellmap[ish]]: # loop over spins for iom in range(N_om): DOSproj[ish][sig][iom] += gf._data.array[:,:,iom].imag.trace()/(-3.1415926535) DOSproj_orb[ish][sig][:,:,:] += gf._data.array[:,:,:].imag/(-3.1415926535) # output: if (MPI.IS_MASTER_NODE()): for bn in self.blocnames[self.SO]: f=open('DOS%s.dat'%bn, 'w') for i in range(N_om): f.write("%s %s\n"%(Mesh[i],DOS[bn][i])) f.close() for ish in range(self.N_inequiv_corr_shells): f=open('DOS%s_proj%s.dat'%(bn,ish),'w') for i in range(N_om): f.write("%s %s\n"%(Mesh[i],DOSproj[ish][bn][i])) f.close() for i in range(self.corr_shells[self.invshellmap[ish]][3]): for j in range(i,self.corr_shells[self.invshellmap[ish]][3]): Fname = 'DOS'+bn+'_proj'+str(ish)+'_'+str(i)+'_'+str(j)+'.dat' f=open(Fname,'w') for iom in range(N_om): f.write("%s %s\n"%(Mesh[iom],DOSproj_orb[ish][bn][i,j,iom])) f.close() def read_ParProj_input_from_HDF(self): """ Reads the data for the partial projectors from the HDF file """ thingstoread = ['Dens_Mat_below','N_parproj','Proj_Mat_pc','rotmat_all','rotmat_all_timeinv'] retval = self.read_input_from_HDF(SubGrp=self.ParProjdata,thingstoread = thingstoread) return retval def DOSpartial(self,broadening=0.01): """calculates the orbitally-resolved DOS""" assert hasattr(self,"Sigmaimp"), "Set Sigma First!!" #thingstoread = ['Dens_Mat_below','N_parproj','Proj_Mat_pc','rotmat_all'] #retval = self.read_input_from_HDF(SubGrp=self.ParProjdata, thingstoread=thingstoread) retval = self.read_ParProj_input_from_HDF() if not retval: return retval if self.symm_op: self.Symm_par = Symmetry(self.HDFfile,subgroup=self.Symmpardata) mu = self.Chemical_Potential GFStruct_proj = [ [ (al, range(self.shells[i][3])) for al in self.blocnames[self.SO] ] for i in xrange(self.N_shells) ] Gproj = [GF(Name_Block_Generator = [ (a,GFBloc_ReFreq(Indices = al, Mesh = self.Sigmaimp[0].mesh)) for a,al in GFStruct_proj[ish] ], Copy = False ) for ish in xrange(self.N_shells)] for ish in range(self.N_shells): Gproj[ish].zero() Msh = [x for x in self.Sigmaimp[0].mesh] N_om = len(Msh) DOS = {} for bn in self.blocnames[self.SO]: DOS[bn] = numpy.zeros([N_om],numpy.float_) DOSproj = [ {} for ish in range(self.N_shells) ] DOSproj_orb = [ {} for ish in range(self.N_shells) ] for ish in range(self.N_shells): for bn in self.blocnames[self.SO]: dl = self.shells[ish][3] DOSproj[ish][bn] = numpy.zeros([N_om],numpy.float_) DOSproj_orb[ish][bn] = numpy.zeros([dl,dl,N_om],numpy.float_) ikarray=numpy.array(range(self.Nk)) for ik in MPI.slice_array(ikarray): S = self.latticeGF_realfreq(ik=ik,mu=mu,broadening=broadening) S *= self.BZ_weights[ik] # non-projected DOS for iom in range(N_om): for sig,gf in S: DOS[sig][iom] += gf._data.array[:,:,iom].imag.trace()/(-3.1415926535) #projected DOS: for ish in xrange(self.N_shells): tmp = Gproj[ish].copy() for ir in xrange(self.N_parproj[ish]): for sig,gf in tmp: tmp[sig] <<= self.downfold_pc(ik,ir,ish,sig,S[sig],gf) Gproj[ish] += tmp # collect data from MPI: for sig in DOS: DOS[sig] = MPI.all_reduce(MPI.world,DOS[sig],lambda x,y : x+y) for ish in xrange(self.N_shells): Gproj[ish] <<= MPI.all_reduce(MPI.world,Gproj[ish],lambda x,y : x+y) MPI.barrier() if (self.symm_op!=0): Gproj = self.Symm_par.symmetrise(Gproj) # rotation to local coord. system: if (self.use_rotations): for ish in xrange(self.N_shells): for sig,gf in Gproj[ish]: Gproj[ish][sig] <<= self.rotloc_all(ish,gf,direction='toLocal') for ish in range(self.N_shells): for sig,gf in Gproj[ish]: for iom in range(N_om): DOSproj[ish][sig][iom] += gf._data.array[:,:,iom].imag.trace()/(-3.1415926535) DOSproj_orb[ish][sig][:,:,:] += gf._data.array[:,:,:].imag / (-3.1415926535) if (MPI.IS_MASTER_NODE()): # output to files for bn in self.blocnames[self.SO]: f=open('./DOScorr%s.dat'%bn, 'w') for i in range(N_om): f.write("%s %s\n"%(Msh[i],DOS[bn][i])) f.close() # partial for ish in range(self.N_shells): f=open('DOScorr%s_proj%s.dat'%(bn,ish),'w') for i in range(N_om): f.write("%s %s\n"%(Msh[i],DOSproj[ish][bn][i])) f.close() for i in range(self.shells[ish][3]): for j in range(i,self.shells[ish][3]): Fname = './DOScorr'+bn+'_proj'+str(ish)+'_'+str(i)+'_'+str(j)+'.dat' f=open(Fname,'w') for iom in range(N_om): f.write("%s %s\n"%(Msh[iom],DOSproj_orb[ish][bn][i,j,iom])) f.close() def spaghettis(self,broadening,shift=0.0,plotrange=None, ishell=None, invertAkw=False, Fermisurface=False): """ Calculates the correlated band structure with a real-frequency self energy. ATTENTION: Many things from the original input file are are overwritten!!!""" assert hasattr(self,"Sigmaimp"), "Set Sigma First!!" thingstoread = ['Nk','N_Orbitals','Proj_Mat','Hopping','N_parproj','Proj_Mat_pc'] retval = self.read_input_from_HDF(SubGrp=self.Bandsdata,thingstoread=thingstoread) if not retval: return retval if Fermisurface: ishell=None # print hamiltonian for checks: if ((self.SP==1)and(self.SO==0)): f1=open('hamup.dat','w') f2=open('hamdn.dat','w') for ik in xrange(self.Nk): for i in xrange(self.N_Orbitals[ik][0]): f1.write('%s %s\n'%(ik,self.Hopping[ik][0][i,i].real)) for i in xrange(self.N_Orbitals[ik][1]): f2.write('%s %s\n'%(ik,self.Hopping[ik][1][i,i].real)) f1.write('\n') f2.write('\n') f1.close() f2.close() else: f=open('ham.dat','w') for ik in xrange(self.Nk): for i in xrange(self.N_Orbitals[ik][0]): f.write('%s %s\n'%(ik,self.Hopping[ik][0][i,i].real)) f.write('\n') f.close() #========================================= # calculate A(k,w): mu = self.Chemical_Potential bln = self.blocnames[self.SO] # init DOS: M = [x for x in self.Sigmaimp[0].mesh] N_om = len(M) if plotrange is None: omminplot = M[0]-0.001 ommaxplot = M[N_om-1] + 0.001 else: omminplot = plotrange[0] ommaxplot = plotrange[1] if (ishell is None): Akw = {} for ibn in bln: Akw[ibn] = numpy.zeros([self.Nk, N_om ],numpy.float_) else: Akw = {} for ibn in bln: Akw[ibn] = numpy.zeros([self.shells[ishell][3],self.Nk, N_om ],numpy.float_) if Fermisurface: omminplot = -2.0*broadening ommaxplot = 2.0*broadening Akw = {} for ibn in bln: Akw[ibn] = numpy.zeros([self.Nk,1],numpy.float_) if not (ishell is None): GFStruct_proj = [ (al, range(self.shells[ishell][3])) for al in bln ] Gproj = GF(Name_Block_Generator = [ (a,GFBloc_ReFreq(Indices = al, Mesh = self.Sigmaimp[0].mesh)) for a,al in GFStruct_proj ], Copy = False) Gproj.zero() for ik in xrange(self.Nk): S = self.latticeGF_realfreq(ik=ik,mu=mu,broadening=broadening) if (ishell is None): # non-projected A(k,w) for iom in range(N_om): if (M[iom]>omminplot) and (M[iom]<ommaxplot): if Fermisurface: for sig,gf in S: Akw[sig][ik,0] += gf._data.array[:,:,iom].imag.trace()/(-3.1415926535) * (M[1]-M[0]) else: for sig,gf in S: Akw[sig][ik,iom] += gf._data.array[:,:,iom].imag.trace()/(-3.1415926535) Akw[sig][ik,iom] += ik*shift # shift Akw for plotting in xmgrace else: # projected A(k,w): Gproj.zero() tmp = Gproj.copy() for ir in xrange(self.N_parproj[ishell]): for sig,gf in tmp: tmp[sig] <<= self.downfold_pc(ik,ir,ishell,sig,S[sig],gf) Gproj += tmp # TO BE FIXED: # rotate to local frame #if (self.use_rotations): # for sig,gf in Gproj: Gproj[sig] <<= self.rotloc(0,gf,direction='toLocal') for iom in range(N_om): if (M[iom]>omminplot) and (M[iom]<ommaxplot): for ish in range(self.shells[ishell][3]): for ibn in bln: Akw[ibn][ish,ik,iom] = Gproj[ibn]._data.array[ish,ish,iom].imag/(-3.1415926535) # END k-LOOP if (MPI.IS_MASTER_NODE()): if (ishell is None): for ibn in bln: # loop over GF blocs: if (invertAkw): maxAkw=Akw[ibn].max() minAkw=Akw[ibn].min() # open file for storage: if Fermisurface: f=open('FS_'+ibn+'.dat','w') else: f=open('Akw_'+ibn+'.dat','w') for ik in range(self.Nk): if Fermisurface: if (invertAkw): Akw[ibn][ik,0] = 1.0/(minAkw-maxAkw)*(Akw[ibn][ik,iom] - maxAkw) f.write('%s %s\n'%(ik,Akw[ibn][ik,0])) else: for iom in range(N_om): if (M[iom]>omminplot) and (M[iom]<ommaxplot): if (invertAkw): Akw[ibn][ik,iom] = 1.0/(minAkw-maxAkw)*(Akw[ibn][ik,iom] - maxAkw) if (shift>0.0001): f.write('%s %s\n'%(M[iom],Akw[ibn][ik,iom])) else: f.write('%s %s %s\n'%(ik,M[iom],Akw[ibn][ik,iom])) f.write('\n') f.close() else: for ibn in bln: for ish in range(self.shells[ishell][3]): if (invertAkw): maxAkw=Akw[ibn][ish,:,:].max() minAkw=Akw[ibn][ish,:,:].min() f=open('Akw_'+ibn+'_proj'+str(ish)+'.dat','w') for ik in range(self.Nk): for iom in range(N_om): if (M[iom]>omminplot) and (M[iom]<ommaxplot): if (invertAkw): Akw[ibn][ish,ik,iom] = 1.0/(minAkw-maxAkw)*(Akw[ibn][ish,ik,iom] - maxAkw) if (shift>0.0001): f.write('%s %s\n'%(M[iom],Akw[ibn][ish,ik,iom])) else: f.write('%s %s %s\n'%(ik,M[iom],Akw[ibn][ish,ik,iom])) f.write('\n') f.close() def constr_Sigma_ME(self,Filename, Beta, N_om, orb = 0): """Uses Data from files to construct a GF object on the real axis.""" #first get the mesh out of one of the files: if (len(self.GFStruct_Solver[orb][0][1])==1): Fname = Filename+'_'+self.GFStruct_Solver[orb][0][0]+'.dat' else: Fname = Filename+'_'+self.GFStruct_Solver[orb][0][0]+'/'+str(self.GFStruct_Solver[orb][0][1][0])+'_'+str(self.GFStruct_Solver[orb][0][1][0])+'.dat' R = Read_Fortran_File(Fname) mesh = numpy.zeros([N_om],numpy.float_) try: for i in xrange(N_om): mesh[i] = R.next() sk = R.next() sk = R.next() except StopIteration : # a more explicit error if the file is corrupted. raise "SumK_LDA.read_Sigma_ME : reading file failed!" R.close() # now initialize the GF with the mesh a_list = [a for a,al in self.GFStruct_Solver[orb]] glist = lambda : [ GFBloc_ReFreq(Indices = al, Beta = Beta, MeshArray = mesh) for a,al in self.GFStruct_Solver[orb] ] SigmaME = GF(NameList = a_list, BlockList = glist(),Copy=False) SigmaME.load(Filename) SigmaME.Note='ReFreq' # This is important for the put_Sigma routine!!! return SigmaME def partial_charges(self): """Calculates the orbitally-resolved density matrix for all the orbitals considered in the input. The theta-projectors are used, hence case.parproj data is necessary""" #thingstoread = ['Dens_Mat_below','N_parproj','Proj_Mat_pc','rotmat_all'] #retval = self.read_input_from_HDF(SubGrp=self.ParProjdata,thingstoread=thingstoread) retval = self.read_ParProj_input_from_HDF() if not retval: return retval if self.symm_op: self.Symm_par = Symmetry(self.HDFfile,subgroup=self.Symmpardata) # Density matrix in the window bln = self.blocnames[self.SO] ntoi = self.names_to_ind[self.SO] self.Dens_Mat_window = [ [numpy.zeros([self.shells[ish][3],self.shells[ish][3]],numpy.complex_) for ish in range(self.N_shells)] for isp in range(len(bln)) ] # init the density matrix mu = self.Chemical_Potential GFStruct_proj = [ [ (al, range(self.shells[i][3])) for al in bln ] for i in xrange(self.N_shells) ] if hasattr(self,"Sigmaimp"): Gproj = [GF(Name_Block_Generator = [ (a,GFBloc_ImFreq(Indices = al, Mesh = self.Sigmaimp[0].mesh)) for a,al in GFStruct_proj[ish] ], Copy = False) for ish in xrange(self.N_shells)] else: Gproj = [GF(Name_Block_Generator = [ (a,GFBloc_ImFreq(Indices = al, Beta = 40)) for a,al in GFStruct_proj[ish] ], Copy = False) for ish in xrange(self.N_shells)] for ish in xrange(self.N_shells): Gproj[ish].zero() ikarray=numpy.array(range(self.Nk)) #print MPI.rank, MPI.slice_array(ikarray) #print "K-Sum starts on node",MPI.rank," at ",datetime.now() for ik in MPI.slice_array(ikarray): #print MPI.rank, ik, datetime.now() S = self.latticeGF_Matsubara(ik=ik,mu=mu) S *= self.BZ_weights[ik] for ish in xrange(self.N_shells): tmp = Gproj[ish].copy() for ir in xrange(self.N_parproj[ish]): for sig,gf in tmp: tmp[sig] <<= self.downfold_pc(ik,ir,ish,sig,S[sig],gf) Gproj[ish] += tmp #print "K-Sum done on node",MPI.rank," at ",datetime.now() #collect data from MPI: for ish in xrange(self.N_shells): Gproj[ish] <<= MPI.all_reduce(MPI.world,Gproj[ish],lambda x,y : x+y) MPI.barrier() #print "Data collected on node",MPI.rank," at ",datetime.now() # Symmetrisation: if (self.symm_op!=0): Gproj = self.Symm_par.symmetrise(Gproj) #print "Symmetrisation done on node",MPI.rank," at ",datetime.now() for ish in xrange(self.N_shells): # Rotation to local: if (self.use_rotations): for sig,gf in Gproj[ish]: Gproj[ish][sig] <<= self.rotloc_all(ish,gf,direction='toLocal') isp = 0 for sig,gf in Gproj[ish]: #dmg.append(Gproj[ish].density()[sig]) self.Dens_Mat_window[isp][ish] = Gproj[ish].density()[sig] isp+=1 # add Density matrices to get the total: Dens_Mat = [ [ self.Dens_Mat_below[ntoi[bln[isp]]][ish]+self.Dens_Mat_window[isp][ish] for ish in range(self.N_shells)] for isp in range(len(bln)) ] return Dens_Mat
def spaghettis(self,broadening,shift=0.0,plotrange=None, ishell=None, invertAkw=False, Fermisurface=False): """ Calculates the correlated band structure with a real-frequency self energy. ATTENTION: Many things from the original input file are are overwritten!!!""" assert hasattr(self,"Sigmaimp"), "Set Sigma First!!" thingstoread = ['Nk','N_Orbitals','Proj_Mat','Hopping','N_parproj','Proj_Mat_pc'] retval = self.read_input_from_HDF(SubGrp=self.Bandsdata,thingstoread=thingstoread) if not retval: return retval if Fermisurface: ishell=None # print hamiltonian for checks: if ((self.SP==1)and(self.SO==0)): f1=open('hamup.dat','w') f2=open('hamdn.dat','w') for ik in xrange(self.Nk): for i in xrange(self.N_Orbitals[ik][0]): f1.write('%s %s\n'%(ik,self.Hopping[ik][0][i,i].real)) for i in xrange(self.N_Orbitals[ik][1]): f2.write('%s %s\n'%(ik,self.Hopping[ik][1][i,i].real)) f1.write('\n') f2.write('\n') f1.close() f2.close() else: f=open('ham.dat','w') for ik in xrange(self.Nk): for i in xrange(self.N_Orbitals[ik][0]): f.write('%s %s\n'%(ik,self.Hopping[ik][0][i,i].real)) f.write('\n') f.close() #========================================= # calculate A(k,w): mu = self.Chemical_Potential bln = self.blocnames[self.SO] # init DOS: M = [x for x in self.Sigmaimp[0].mesh] N_om = len(M) if plotrange is None: omminplot = M[0]-0.001 ommaxplot = M[N_om-1] + 0.001 else: omminplot = plotrange[0] ommaxplot = plotrange[1] if (ishell is None): Akw = {} for ibn in bln: Akw[ibn] = numpy.zeros([self.Nk, N_om ],numpy.float_) else: Akw = {} for ibn in bln: Akw[ibn] = numpy.zeros([self.shells[ishell][3],self.Nk, N_om ],numpy.float_) if Fermisurface: omminplot = -2.0*broadening ommaxplot = 2.0*broadening Akw = {} for ibn in bln: Akw[ibn] = numpy.zeros([self.Nk,1],numpy.float_) if not (ishell is None): GFStruct_proj = [ (al, range(self.shells[ishell][3])) for al in bln ] Gproj = GF(Name_Block_Generator = [ (a,GFBloc_ReFreq(Indices = al, Mesh = self.Sigmaimp[0].mesh)) for a,al in GFStruct_proj ], Copy = False) Gproj.zero() for ik in xrange(self.Nk): S = self.latticeGF_realfreq(ik=ik,mu=mu,broadening=broadening) if (ishell is None): # non-projected A(k,w) for iom in range(N_om): if (M[iom]>omminplot) and (M[iom]<ommaxplot): if Fermisurface: for sig,gf in S: Akw[sig][ik,0] += gf._data.array[:,:,iom].imag.trace()/(-3.1415926535) * (M[1]-M[0]) else: for sig,gf in S: Akw[sig][ik,iom] += gf._data.array[:,:,iom].imag.trace()/(-3.1415926535) Akw[sig][ik,iom] += ik*shift # shift Akw for plotting in xmgrace else: # projected A(k,w): Gproj.zero() tmp = Gproj.copy() for ir in xrange(self.N_parproj[ishell]): for sig,gf in tmp: tmp[sig] <<= self.downfold_pc(ik,ir,ishell,sig,S[sig],gf) Gproj += tmp # TO BE FIXED: # rotate to local frame #if (self.use_rotations): # for sig,gf in Gproj: Gproj[sig] <<= self.rotloc(0,gf,direction='toLocal') for iom in range(N_om): if (M[iom]>omminplot) and (M[iom]<ommaxplot): for ish in range(self.shells[ishell][3]): for ibn in bln: Akw[ibn][ish,ik,iom] = Gproj[ibn]._data.array[ish,ish,iom].imag/(-3.1415926535) # END k-LOOP if (MPI.IS_MASTER_NODE()): if (ishell is None): for ibn in bln: # loop over GF blocs: if (invertAkw): maxAkw=Akw[ibn].max() minAkw=Akw[ibn].min() # open file for storage: if Fermisurface: f=open('FS_'+ibn+'.dat','w') else: f=open('Akw_'+ibn+'.dat','w') for ik in range(self.Nk): if Fermisurface: if (invertAkw): Akw[ibn][ik,0] = 1.0/(minAkw-maxAkw)*(Akw[ibn][ik,iom] - maxAkw) f.write('%s %s\n'%(ik,Akw[ibn][ik,0])) else: for iom in range(N_om): if (M[iom]>omminplot) and (M[iom]<ommaxplot): if (invertAkw): Akw[ibn][ik,iom] = 1.0/(minAkw-maxAkw)*(Akw[ibn][ik,iom] - maxAkw) if (shift>0.0001): f.write('%s %s\n'%(M[iom],Akw[ibn][ik,iom])) else: f.write('%s %s %s\n'%(ik,M[iom],Akw[ibn][ik,iom])) f.write('\n') f.close() else: for ibn in bln: for ish in range(self.shells[ishell][3]): if (invertAkw): maxAkw=Akw[ibn][ish,:,:].max() minAkw=Akw[ibn][ish,:,:].min() f=open('Akw_'+ibn+'_proj'+str(ish)+'.dat','w') for ik in range(self.Nk): for iom in range(N_om): if (M[iom]>omminplot) and (M[iom]<ommaxplot): if (invertAkw): Akw[ibn][ish,ik,iom] = 1.0/(minAkw-maxAkw)*(Akw[ibn][ish,ik,iom] - maxAkw) if (shift>0.0001): f.write('%s %s\n'%(M[iom],Akw[ibn][ish,ik,iom])) else: f.write('%s %s %s\n'%(ik,M[iom],Akw[ibn][ish,ik,iom])) f.write('\n') f.close()
class SumK_LDA: """This class provides a general SumK method for combining ab-initio code and pytriqs.""" def __init__( self, HDFfile, mu=0.0, hfield=0.0, UseLDABlocs=False, LDAdata="SumK_LDA", Symmcorrdata="SymmCorr", ParProjdata="SumK_LDA_ParProj", Symmpardata="SymmPar", Bandsdata="SumK_LDA_Bands", ): """ Initialises the class from data previously stored into an HDF5 """ if not (type(HDFfile) == StringType): MPI.report("Give a string for the HDF5 filename to read the input!") else: self.HDFfile = HDFfile self.LDAdata = LDAdata self.ParProjdata = ParProjdata self.Bandsdata = Bandsdata self.Symmpardata = Symmpardata self.Symmcorrdata = Symmcorrdata self.blocnames = [["up", "down"], ["ud"]] self.NspinblocsGF = [2, 1] self.Gupf = None self.hfield = hfield # read input from HDF: thingstoread = [ "EnergyUnit", "Nk", "k_dep_projection", "SP", "SO", "charge_below", "Density_Required", "symm_op", "N_shells", "shells", "N_corr_shells", "corr_shells", "use_rotations", "rotmat", "rotmat_timeinv", "Nreps", "dim_reps", "T", "N_Orbitals", "Proj_Mat", "BZ_weights", "Hopping", ] optionalthings = [ "GFStruct_Solver", "mapinv", "map", "Chemical_Potential", "dc_imp", "DCenerg", "deg_shells", ] # ar=HDF_Archive(self.HDFfile,'a') # del ar self.retval = self.read_input_from_HDF( SubGrp=self.LDAdata, thingstoread=thingstoread, optionalthings=optionalthings ) # ar=HDF_Archive(self.HDFfile,'a') # del ar if (self.SO) and (abs(self.hfield) > 0.000001): self.hfield = 0.0 MPI.report("For SO, the external magnetic field is not implemented, setting it to 0!!") self.inequiv_shells(self.corr_shells) # determine the number of inequivalent correlated shells # field to convert blocnames to indices self.names_to_ind = [{}, {}] for ibl in range(2): for inm in range(self.NspinblocsGF[ibl]): self.names_to_ind[ibl][self.blocnames[ibl][inm]] = inm * self.SP # (self.Nspinblocs-1) # GF structure used for the local things in the k sums self.GFStruct_corr = [ [(al, range(self.corr_shells[i][3])) for al in self.blocnames[self.corr_shells[i][4]]] for i in xrange(self.N_corr_shells) ] if not (self.retval["GFStruct_Solver"]): # No GFStruct was stored in HDF, so first set a standard one: self.GFStruct_Solver = [ [ (al, range(self.corr_shells[self.invshellmap[i]][3])) for al in self.blocnames[self.corr_shells[self.invshellmap[i]][4]] ] for i in xrange(self.N_inequiv_corr_shells) ] self.map = [{} for i in xrange(self.N_inequiv_corr_shells)] self.mapinv = [{} for i in xrange(self.N_inequiv_corr_shells)] for i in xrange(self.N_inequiv_corr_shells): for al in self.blocnames[self.corr_shells[self.invshellmap[i]][4]]: self.map[i][al] = [al for j in range(self.corr_shells[self.invshellmap[i]][3])] self.mapinv[i][al] = al if not (self.retval["dc_imp"]): # init the double counting: self.__initDC() if not (self.retval["Chemical_Potential"]): self.Chemical_Potential = mu if not (self.retval["deg_shells"]): self.deg_shells = [[] for i in range(self.N_inequiv_corr_shells)] if self.symm_op: # MPI.report("Do the init for symm:") self.Symm_corr = Symmetry(HDFfile, subgroup=self.Symmcorrdata) # determine the smallest blocs, if wanted: if UseLDABlocs: dm = self.analyse_BS() # now save things again to HDF5: if MPI.IS_MASTER_NODE(): ar = HDF_Archive(self.HDFfile, "a") ar[self.LDAdata]["hfield"] = self.hfield del ar self.save() def read_input_from_HDF(self, SubGrp, thingstoread, optionalthings=[]): """ Reads data from the HDF file """ retval = True # init variables on all nodes: for it in thingstoread: exec "self.%s = 0" % it for it in optionalthings: exec "self.%s = 0" % it if MPI.IS_MASTER_NODE(): ar = HDF_Archive(self.HDFfile, "a") if SubGrp in ar: # first read the necessary things: for it in thingstoread: if it in ar[SubGrp]: exec "self.%s = ar['%s']['%s']" % (it, SubGrp, it) else: MPI.report("Loading %s failed!" % it) retval = False if (retval) and (len(optionalthings) > 0): # if necessary things worked, now read optional things: retval = {} for it in optionalthings: if it in ar[SubGrp]: exec "self.%s = ar['%s']['%s']" % (it, SubGrp, it) retval["%s" % it] = True else: retval["%s" % it] = False else: MPI.report("Loading failed: No %s subgroup in HDF5!" % SubGrp) retval = False del ar # now do the broadcasting: for it in thingstoread: exec "self.%s = MPI.bcast(self.%s)" % (it, it) for it in optionalthings: exec "self.%s = MPI.bcast(self.%s)" % (it, it) retval = MPI.bcast(retval) return retval def save(self): """Saves some quantities into an HDF5 arxiv""" if not (MPI.IS_MASTER_NODE()): return # do nothing on nodes ar = HDF_Archive(self.HDFfile, "a") ar[self.LDAdata]["Chemical_Potential"] = self.Chemical_Potential ar[self.LDAdata]["DCenerg"] = self.DCenerg ar[self.LDAdata]["dc_imp"] = self.dc_imp del ar def load(self): """Loads some quantities from an HDF5 arxiv""" thingstoread = ["Chemical_Potential", "dc_imp", "DCenerg"] retval = self.read_input_from_HDF(SubGrp=self.LDAdata, thingstoread=thingstoread) return retval def downfold(self, ik, icrsh, sig, gf_to_downfold, gf_inp): """Downfolding a block of the Greens function""" gf_downfolded = gf_inp.copy() isp = self.names_to_ind[self.SO][sig] # get spin index for proj. matrices gf_downfolded.from_L_G_R( self.Proj_Mat[ik][isp][icrsh], gf_to_downfold, self.Proj_Mat[ik][isp][icrsh].conjugate().transpose() ) # downfolding G return gf_downfolded def upfold(self, ik, icrsh, sig, gf_to_upfold, gf_inp): """Upfolding a block of the Greens function""" gf_upfolded = gf_inp.copy() isp = self.names_to_ind[self.SO][sig] # get spin index for proj. matrices gf_upfolded.from_L_G_R( self.Proj_Mat[ik][isp][icrsh].conjugate().transpose(), gf_to_upfold, self.Proj_Mat[ik][isp][icrsh] ) return gf_upfolded def rotloc(self, icrsh, gf_to_rotate, direction): """Local <-> Global rotation of a GF block. direction: 'toLocal' / 'toGlobal' """ assert (direction == "toLocal") or ( direction == "toGlobal" ), "Give direction 'toLocal' or 'toGlobal' in rotloc!" gf_rotated = gf_to_rotate.copy() if direction == "toGlobal": # if (self.rotmat_timeinv[icrsh]==1): gf_rotated <<= gf_rotated.transpose() # gf_rotated.from_L_G_R(self.rotmat[icrsh].transpose(),gf_rotated,self.rotmat[icrsh].conjugate()) if (self.rotmat_timeinv[icrsh] == 1) and (self.SO): gf_rotated <<= gf_rotated.transpose() gf_rotated.from_L_G_R(self.rotmat[icrsh].conjugate(), gf_rotated, self.rotmat[icrsh].transpose()) else: gf_rotated.from_L_G_R(self.rotmat[icrsh], gf_rotated, self.rotmat[icrsh].conjugate().transpose()) elif direction == "toLocal": if (self.rotmat_timeinv[icrsh] == 1) and (self.SO): gf_rotated <<= gf_rotated.transpose() gf_rotated.from_L_G_R(self.rotmat[icrsh].transpose(), gf_rotated, self.rotmat[icrsh].conjugate()) else: gf_rotated.from_L_G_R(self.rotmat[icrsh].conjugate().transpose(), gf_rotated, self.rotmat[icrsh]) return gf_rotated def latticeGF_Matsubara(self, ik, mu, Beta=40, withSigma=True): """Calculates the lattice Green function from the LDA hopping and the self energy at k-point number ik and chemical potential mu.""" ntoi = self.names_to_ind[self.SO] bln = self.blocnames[self.SO] if not hasattr(self, "Sigmaimp"): withSigma = False if withSigma: stmp = self.add_DC() Beta = self.Sigmaimp[0].Beta # override Beta if Sigma is present if self.Gupf is None: # first setting up of Gupf BS = [range(self.N_Orbitals[ik][ntoi[ib]]) for ib in bln] GFStruct = [(bln[ib], BS[ib]) for ib in range(self.NspinblocsGF[self.SO])] a_list = [a for a, al in GFStruct] glist = lambda: [GFBloc_ImFreq(Indices=al, Beta=Beta) for a, al in GFStruct] self.Gupf = GF(NameList=a_list, BlockList=glist(), Copy=False) self.Gupf.zero() GFsize = [gf.N1 for sig, gf in self.Gupf] unchangedsize = all( [self.N_Orbitals[ik][ntoi[bln[ib]]] == GFsize[ib] for ib in range(self.NspinblocsGF[self.SO])] ) if not unchangedsize: BS = [range(self.N_Orbitals[ik][ntoi[ib]]) for ib in bln] GFStruct = [(bln[ib], BS[ib]) for ib in range(self.NspinblocsGF[self.SO])] a_list = [a for a, al in GFStruct] glist = lambda: [GFBloc_ImFreq(Indices=al, Beta=Beta) for a, al in GFStruct] self.Gupf = GF(NameList=a_list, BlockList=glist(), Copy=False) self.Gupf.zero() idmat = [numpy.identity(self.N_Orbitals[ik][ntoi[bl]], numpy.complex_) for bl in bln] # for ibl in range(self.NspinblocsGF[self.SO]): mupat[ibl] *= mu self.Gupf <<= GF_Initializers.A_Omega_Plus_B(A=1, B=0) M = copy.deepcopy(idmat) for ibl in range(self.NspinblocsGF[self.SO]): ind = ntoi[bln[ibl]] M[ibl] = self.Hopping[ik][ind] - (idmat[ibl] * mu) - (idmat[ibl] * self.hfield * (1 - 2 * ibl)) self.Gupf -= M if withSigma: tmp = self.Gupf.copy() # init temporary storage for icrsh in xrange(self.N_corr_shells): for sig, gf in tmp: tmp[sig] <<= self.upfold(ik, icrsh, sig, stmp[icrsh][sig], gf) self.Gupf -= tmp # adding to the upfolded GF self.Gupf.invert() return self.Gupf def check_projectors(self): densmat = [ numpy.zeros([self.corr_shells[ish][3], self.corr_shells[ish][3]], numpy.complex_) for ish in range(self.N_corr_shells) ] for ik in range(self.Nk): for ish in range(self.N_corr_shells): Norb = self.corr_shells[ish][3] densmat[ish][:, :] += ( numpy.dot(self.Proj_Mat[ik][0][ish], self.Proj_Mat[ik][0][ish].transpose().conjugate()) * self.BZ_weights[ik] ) if self.symm_op != 0: densmat = self.Symm_corr.symmetrise(densmat) # Rotate to local coordinate system: if self.use_rotations: for icrsh in xrange(self.N_corr_shells): if self.rotmat_timeinv[icrsh] == 1: densmat[icrsh] = densmat[icrsh].conjugate() densmat[icrsh] = numpy.dot( numpy.dot(self.rotmat[icrsh].conjugate().transpose(), densmat[icrsh]), self.rotmat[icrsh] ) return densmat def simplepointdensmat(self): ntoi = self.names_to_ind[self.SO] bln = self.blocnames[self.SO] MMat = [numpy.zeros([self.N_Orbitals[0][ntoi[bl]], self.N_Orbitals[0][ntoi[bl]]], numpy.complex_) for bl in bln] densmat = [{} for icrsh in xrange(self.N_corr_shells)] for icrsh in xrange(self.N_corr_shells): for bl in self.blocnames[self.corr_shells[icrsh][4]]: densmat[icrsh][bl] = numpy.zeros( [self.corr_shells[icrsh][3], self.corr_shells[icrsh][3]], numpy.complex_ ) ikarray = numpy.array(range(self.Nk)) for ik in MPI.slice_array(ikarray): unchangedsize = all( [self.N_Orbitals[ik][ntoi[bln[ib]]] == len(MMat[ib]) for ib in range(self.NspinblocsGF[self.SO])] ) if not unchangedsize: MMat = [ numpy.zeros([self.N_Orbitals[ik][ntoi[bl]], self.N_Orbitals[ik][ntoi[bl]]], numpy.complex_) for bl in bln ] for ibl, bl in enumerate(bln): ind = ntoi[bl] for inu in range(self.N_Orbitals[ik][ind]): if (self.Hopping[ik][ind][inu, inu] - self.hfield * (1 - 2 * ibl)) < 0.0: MMat[ibl][inu, inu] = 1.0 else: MMat[ibl][inu, inu] = 0.0 for icrsh in range(self.N_corr_shells): for ibn, bn in enumerate(self.blocnames[self.corr_shells[icrsh][4]]): isp = self.names_to_ind[self.corr_shells[icrsh][4]][bn] # print ik, bn, isp densmat[icrsh][bn] += self.BZ_weights[ik] * numpy.dot( numpy.dot(self.Proj_Mat[ik][isp][icrsh], MMat[ibn]), self.Proj_Mat[ik][isp][icrsh].transpose().conjugate(), ) # get data from nodes: for icrsh in range(self.N_corr_shells): for sig in densmat[icrsh]: densmat[icrsh][sig] = MPI.all_reduce(MPI.world, densmat[icrsh][sig], lambda x, y: x + y) MPI.barrier() if self.symm_op != 0: densmat = self.Symm_corr.symmetrise(densmat) # Rotate to local coordinate system: if self.use_rotations: for icrsh in xrange(self.N_corr_shells): for bn in densmat[icrsh]: if self.rotmat_timeinv[icrsh] == 1: densmat[icrsh][bn] = densmat[icrsh][bn].conjugate() densmat[icrsh][bn] = numpy.dot( numpy.dot(self.rotmat[icrsh].conjugate().transpose(), densmat[icrsh][bn]), self.rotmat[icrsh] ) return densmat def density_gf(self, Beta=40): """Calculates the density without setting up Gloc. It is useful for Hubbard I, and very fast.""" densmat = [{} for icrsh in xrange(self.N_corr_shells)] for icrsh in xrange(self.N_corr_shells): for bl in self.blocnames[self.corr_shells[icrsh][4]]: densmat[icrsh][bl] = numpy.zeros( [self.corr_shells[icrsh][3], self.corr_shells[icrsh][3]], numpy.complex_ ) ikarray = numpy.array(range(self.Nk)) for ik in MPI.slice_array(ikarray): Gupf = self.latticeGF_Matsubara(ik=ik, mu=self.Chemical_Potential) Gupf *= self.BZ_weights[ik] dm = Gupf.density() MMat = [dm[bl] for bl in self.blocnames[self.SO]] for icrsh in range(self.N_corr_shells): for ibn, bn in enumerate(self.blocnames[self.corr_shells[icrsh][4]]): isp = self.names_to_ind[self.corr_shells[icrsh][4]][bn] # print ik, bn, isp densmat[icrsh][bn] += numpy.dot( numpy.dot(self.Proj_Mat[ik][isp][icrsh], MMat[ibn]), self.Proj_Mat[ik][isp][icrsh].transpose().conjugate(), ) # get data from nodes: for icrsh in range(self.N_corr_shells): for sig in densmat[icrsh]: densmat[icrsh][sig] = MPI.all_reduce(MPI.world, densmat[icrsh][sig], lambda x, y: x + y) MPI.barrier() if self.symm_op != 0: densmat = self.Symm_corr.symmetrise(densmat) # Rotate to local coordinate system: if self.use_rotations: for icrsh in xrange(self.N_corr_shells): for bn in densmat[icrsh]: if self.rotmat_timeinv[icrsh] == 1: densmat[icrsh][bn] = densmat[icrsh][bn].conjugate() densmat[icrsh][bn] = numpy.dot( numpy.dot(self.rotmat[icrsh].conjugate().transpose(), densmat[icrsh][bn]), self.rotmat[icrsh] ) return densmat def analyse_BS(self, threshold=0.00001, includeshells=None): """ Determines the Greens function block structure from the simple point integration""" dm = self.simplepointdensmat() densmat = [dm[self.invshellmap[ish]] for ish in xrange(self.N_inequiv_corr_shells)] if includeshells is None: includeshells = range(self.N_inequiv_corr_shells) for ish in includeshells: # self.GFStruct_Solver.append([]) self.GFStruct_Solver[ish] = [] a_list = [a for a, al in self.GFStruct_corr[self.invshellmap[ish]]] for a in a_list: dm = densmat[ish][a] dmbool = abs(dm) > threshold # gives an index list of entries larger that threshold offdiag = [] for i in xrange(len(dmbool)): for j in xrange(i, len(dmbool)): if (dmbool[i, j]) & (i != j): offdiag.append([i, j]) NBlocs = len(dmbool) blocs = [[i] for i in range(NBlocs)] for i in range(len(offdiag)): if offdiag[i][0] != offdiag[i][1]: for j in range(len(blocs[offdiag[i][1]])): blocs[offdiag[i][0]].append(blocs[offdiag[i][1]][j]) del blocs[offdiag[i][1]] for j in range(i + 1, len(offdiag)): if offdiag[j][0] == offdiag[i][1]: offdiag[j][0] = offdiag[i][0] if offdiag[j][1] == offdiag[i][1]: offdiag[j][1] = offdiag[i][0] if offdiag[j][0] > offdiag[i][1]: offdiag[j][0] -= 1 if offdiag[j][1] > offdiag[i][1]: offdiag[j][1] -= 1 offdiag[j].sort() NBlocs -= 1 for i in range(NBlocs): blocs[i].sort() self.GFStruct_Solver[ish].append(("%s%s" % (a, i), blocs[i])) # map is the mapping of the blocs from the SK blocs to the CTQMC blocs: self.map[ish][a] = range(len(dmbool)) for ibl in range(NBlocs): for j in range(len(blocs[ibl])): self.map[ish][a][blocs[ibl][j]] = "%s%s" % (a, ibl) self.mapinv[ish]["%s%s" % (a, ibl)] = a # now calculate degeneracies of orbitals: dm = {} for bl in self.GFStruct_Solver[ish]: bln = bl[0] ind = bl[1] # get dm for the blocks: dm[bln] = numpy.zeros([len(ind), len(ind)], numpy.complex_) for i in range(len(ind)): for j in range(len(ind)): dm[bln][i, j] = densmat[ish][self.mapinv[ish][bln]][ind[i], ind[j]] for bl in self.GFStruct_Solver[ish]: for bl2 in self.GFStruct_Solver[ish]: if dm[bl[0]].shape == dm[bl2[0]].shape: if ((abs(dm[bl[0]] - dm[bl2[0]]) < threshold).all()) and (bl[0] != bl2[0]): # check if it was already there: ind1 = -1 ind2 = -2 for n, ind in enumerate(self.deg_shells[ish]): if bl[0] in ind: ind1 = n if bl2[0] in ind: ind2 = n if (ind1 < 0) and (ind2 >= 0): self.deg_shells[ish][ind2].append(bl[0]) elif (ind1 >= 0) and (ind2 < 0): self.deg_shells[ish][ind1].append(bl2[0]) elif (ind1 < 0) and (ind2 < 0): self.deg_shells[ish].append([bl[0], bl2[0]]) if MPI.IS_MASTER_NODE(): ar = HDF_Archive(self.HDFfile, "a") ar[self.LDAdata]["GFStruct_Solver"] = self.GFStruct_Solver ar[self.LDAdata]["map"] = self.map ar[self.LDAdata]["mapinv"] = self.mapinv try: ar[self.LDAdata]["deg_shells"] = self.deg_shells except: MPI.report("deg_shells not stored, degeneracies not found") del ar return densmat def symm_deg_GF(self, gftosymm, orb): """Symmetrises a GF for the given degenerate shells self.deg_shells""" for degsh in self.deg_shells[orb]: # loop over degenerate shells: ss = gftosymm[degsh[0]].copy() ss.zero() Ndeg = len(degsh) for bl in degsh: ss += gftosymm[bl] / (1.0 * Ndeg) for bl in degsh: gftosymm[bl] <<= ss def eff_atomic_levels(self): """Calculates the effective atomic levels needed as input for the Hubbard I Solver.""" # define matrices for inequivalent shells: eff_atlevels = [{} for ish in range(self.N_inequiv_corr_shells)] for ish in range(self.N_inequiv_corr_shells): for bn in self.blocnames[self.corr_shells[self.invshellmap[ish]][4]]: eff_atlevels[ish][bn] = numpy.identity(self.corr_shells[self.invshellmap[ish]][3], numpy.complex_) # Chemical Potential: for ish in xrange(self.N_inequiv_corr_shells): for ii in eff_atlevels[ish]: eff_atlevels[ish][ii] *= -self.Chemical_Potential # double counting term: # if hasattr(self,"dc_imp"): for ish in xrange(self.N_inequiv_corr_shells): for ii in eff_atlevels[ish]: eff_atlevels[ish][ii] -= self.dc_imp[self.invshellmap[ish]][ii] # sum over k: if not hasattr(self, "Hsumk"): # calculate the sum over k. Does not depend on mu, so do it only once: self.Hsumk = [{} for ish in range(self.N_corr_shells)] for icrsh in range(self.N_corr_shells): for bn in self.blocnames[self.corr_shells[icrsh][4]]: dim = self.corr_shells[icrsh][3] # *(1+self.corr_shells[icrsh][4]) self.Hsumk[icrsh][bn] = numpy.zeros([dim, dim], numpy.complex_) for icrsh in range(self.N_corr_shells): for ibn, bn in enumerate(self.blocnames[self.corr_shells[icrsh][4]]): isp = self.names_to_ind[self.corr_shells[icrsh][4]][bn] for ik in xrange(self.Nk): MMat = numpy.identity(self.N_Orbitals[ik][isp], numpy.complex_) MMat = self.Hopping[ik][isp] - (1 - 2 * ibn) * self.hfield * MMat self.Hsumk[icrsh][bn] += self.BZ_weights[ik] * numpy.dot( numpy.dot(self.Proj_Mat[ik][isp][icrsh], MMat), # self.Hopping[ik][isp]) , self.Proj_Mat[ik][isp][icrsh].conjugate().transpose(), ) # symmetrisation: if self.symm_op != 0: self.Hsumk = self.Symm_corr.symmetrise(self.Hsumk) # Rotate to local coordinate system: if self.use_rotations: for icrsh in xrange(self.N_corr_shells): for bn in self.Hsumk[icrsh]: if self.rotmat_timeinv[icrsh] == 1: self.Hsumk[icrsh][bn] = self.Hsumk[icrsh][bn].conjugate() # if (self.corr_shells[icrsh][4]==0): self.Hsumk[icrsh][bn] = self.Hsumk[icrsh][bn].conjugate() self.Hsumk[icrsh][bn] = numpy.dot( numpy.dot(self.rotmat[icrsh].conjugate().transpose(), self.Hsumk[icrsh][bn]), self.rotmat[icrsh], ) # add to matrix: for ish in xrange(self.N_inequiv_corr_shells): for bn in eff_atlevels[ish]: eff_atlevels[ish][bn] += self.Hsumk[self.invshellmap[ish]][bn] return eff_atlevels def __initDC(self): # construct the density matrix dm_imp and double counting arrays # self.dm_imp = [ {} for i in xrange(self.N_corr_shells)] self.dc_imp = [{} for i in xrange(self.N_corr_shells)] for i in xrange(self.N_corr_shells): l = self.corr_shells[i][3] for j in xrange(len(self.GFStruct_corr[i])): self.dc_imp[i]["%s" % self.GFStruct_corr[i][j][0]] = numpy.zeros([l, l], numpy.float_) self.DCenerg = [0.0 for i in xrange(self.N_corr_shells)] def SetDC_Lichtenstein(self, sigimp): """Sets a double counting term according to Lichtenstein et al. PRL2001""" assert isinstance( sigimp, list ), "sigimp has to be a list of impurity self energies for the correlated shells, even if it is of length 1!" assert len(sigimp) == self.N_inequiv_corr_shells, "give exactly one Sigma for each inequivalent corr. shell!" for i in xrange(self.N_corr_shells): l = (self.corr_shells[i][4] + 1) * self.corr_shells[i][3] for j in xrange(len(self.GFStruct_corr[i])): self.dc_imp[i]["%s" % self.GFStruct_corr[i][j][0]] = numpy.identity(l, numpy.float_) # transform the CTQMC blocks to the full matrix: for icrsh in xrange(self.N_corr_shells): s = self.shellmap[icrsh] # s is the index of the inequivalent shell corresponding to icrsh for ibl in range(len(self.GFStruct_Solver[s])): for i in range(len(self.GFStruct_Solver[s][ibl][1])): for j in range(len(self.GFStruct_Solver[s][ibl][1])): bl = self.GFStruct_Solver[s][ibl][0] ind1 = self.GFStruct_Solver[s][ibl][1][i] ind2 = self.GFStruct_Solver[s][ibl][1][j] self.dm_imp[icrsh][self.mapinv[s][bl]][ind1, ind2] = sigimp[s][bl]._data.array[i, j, 0].real # self energy at smallest matsubara, could be done better for icrsh in xrange(self.N_corr_shells): # trace: Sigtr = 0.0 a_list = [a for a, al in self.GFStruct_corr[icrsh]] for bl in a_list: Sigtr += self.dm_imp[icrsh][bl].trace() for bl in a_list: self.dc_imp[icrsh][bl] *= Sigtr / (self.corr_shells[icrsh][3] * 2.0) # self.dc_imp[icrsh]['up'][:,:] += self.dc_imp[icrsh]['down'][:,:] # self.dc_imp[icrsh]['up'][:,:] /= 2.0 # self.dc_imp[icrsh]['down'][:,:] = self.dc_imp[icrsh]['up'][:,:] def SetDoubleCounting(self, densmat, U_interact, J_Hund, orb=0, useDCformula=0, useval=None): """Sets the double counting term for inequiv orbital orb useDCformula=0: LDA+U FLL double counting, useDCformula=1: Held's formula. useDCformula=2: AMF Be sure that you use the correct interaction Hamiltonian!""" # if (not hasattr(self,"dc_imp")): self.__initDC() dm = [{} for i in xrange(self.N_corr_shells)] for i in xrange(self.N_corr_shells): l = self.corr_shells[i][3] # *(1+self.corr_shells[i][4]) for j in xrange(len(self.GFStruct_corr[i])): dm[i]["%s" % self.GFStruct_corr[i][j][0]] = numpy.zeros([l, l], numpy.float_) for icrsh in xrange(self.N_corr_shells): iorb = self.shellmap[icrsh] # iorb is the index of the inequivalent shell corresponding to icrsh if iorb == orb: # do this orbital l = self.corr_shells[icrsh][3] # *(1+self.corr_shells[icrsh][4]) for j in xrange(len(self.GFStruct_corr[icrsh])): self.dc_imp[icrsh]["%s" % self.GFStruct_corr[icrsh][j][0]] = numpy.identity(l, numpy.float_) # transform the CTQMC blocks to the full matrix: for ibl in range(len(self.GFStruct_Solver[iorb])): for i in range(len(self.GFStruct_Solver[iorb][ibl][1])): for j in range(len(self.GFStruct_Solver[iorb][ibl][1])): bl = self.GFStruct_Solver[iorb][ibl][0] ind1 = self.GFStruct_Solver[iorb][ibl][1][i] ind2 = self.GFStruct_Solver[iorb][ibl][1][j] dm[icrsh][self.mapinv[iorb][bl]][ind1, ind2] = densmat[bl][ i, j ].real # only real part relevant for trace M = self.corr_shells[icrsh][3] Ncr = {} Ncrtot = 0.0 a_list = [a for a, al in self.GFStruct_corr[icrsh]] for bl in a_list: Ncr[bl] = dm[icrsh][bl].trace() Ncrtot += Ncr[bl] # average the densities if there is no SP: if self.SP == 0: for bl in a_list: Ncr[bl] = Ncrtot / len(a_list) # correction for SO: we have only one block in this case, but in DC we need N/2 elif self.SP == 1 and self.SO == 1: for bl in a_list: Ncr[bl] = Ncrtot / 2.0 if useval is None: if useDCformula == 0: self.DCenerg[icrsh] = U_interact / 2.0 * Ncrtot * (Ncrtot - 1.0) for bl in a_list: Uav = U_interact * (Ncrtot - 0.5) - J_Hund * (Ncr[bl] - 0.5) self.dc_imp[icrsh][bl] *= Uav self.DCenerg[icrsh] -= J_Hund / 2.0 * (Ncr[bl]) * (Ncr[bl] - 1.0) MPI.report("DC for shell %(icrsh)i and block %(bl)s = %(Uav)f" % locals()) elif useDCformula == 1: self.DCenerg[icrsh] = ( (U_interact + J_Hund * (2.0 - (M - 1)) / (2 * M - 1)) / 2.0 * Ncrtot * (Ncrtot - 1.0) ) for bl in a_list: # Held's formula, with U_interact the interorbital onsite interaction Uav = (U_interact + J_Hund * (2.0 - (M - 1)) / (2 * M - 1)) * (Ncrtot - 0.5) self.dc_imp[icrsh][bl] *= Uav MPI.report("DC for shell %(icrsh)i and block %(bl)s = %(Uav)f" % locals()) elif useDCformula == 2: self.DCenerg[icrsh] = 0.5 * U_interact * Ncrtot * Ncrtot for bl in a_list: # AMF Uav = U_interact * (Ncrtot - Ncr[bl] / M) - J_Hund * (Ncr[bl] - Ncr[bl] / M) self.dc_imp[icrsh][bl] *= Uav self.DCenerg[icrsh] -= (U_interact + (M - 1) * J_Hund) / M * 0.5 * Ncr[bl] * Ncr[bl] MPI.report("DC for shell %(icrsh)i and block %(bl)s = %(Uav)f" % locals()) # output: MPI.report("DC energy for shell %s = %s" % (icrsh, self.DCenerg[icrsh])) else: a_list = [a for a, al in self.GFStruct_corr[icrsh]] for bl in a_list: self.dc_imp[icrsh][bl] *= useval self.DCenerg[icrsh] = useval * Ncrtot # output: MPI.report("DC for shell %(icrsh)i = %(useval)f" % locals()) MPI.report("DC energy = %s" % self.DCenerg[icrsh]) def find_DC(self, orb, guess, densmat, densreq=None, precision=0.01): """searches for DC in order to fulfill charge neutrality. If densreq is given, then DC is set such that the LOCAL charge of orbital orb coincides with densreq.""" mu = self.Chemical_Potential def F(dc): self.SetDoubleCounting(densmat=densmat, U_interact=0, J_Hund=0, orb=orb, useval=dc) if densreq is None: return self.total_density(mu=mu) else: return self.extract_Gloc()[orb].total_density() if densreq is None: Dens_rel = self.Density_Required - self.charge_below else: Dens_rel = densreq dcnew = Dichotomy.Dichotomy( Function=F, xinit=guess, yvalue=Dens_rel, Precision_on_y=precision, Delta_x=0.5, MaxNbreLoop=100, xname="Double-Counting", yname="Total Density", verbosity=3, )[0] return dcnew def put_Sigma(self, Sigmaimp): """Puts the impurity self energies for inequivalent atoms into the class, respects the multiplicity of the atoms.""" assert isinstance( Sigmaimp, list ), "Sigmaimp has to be a list of Sigmas for the correlated shells, even if it is of length 1!" assert len(Sigmaimp) == self.N_inequiv_corr_shells, "give exactly one Sigma for each inequivalent corr. shell!" # init self.Sigmaimp: if Sigmaimp[0].Note == "ReFreq": # Real frequency Sigma: self.Sigmaimp = [ GF( Name_Block_Generator=[ (a, GFBloc_ReFreq(Indices=al, Mesh=Sigmaimp[0].mesh)) for a, al in self.GFStruct_corr[i] ], Copy=False, ) for i in xrange(self.N_corr_shells) ] self.Sigmaimp[0].Note = "ReFreq" else: # Imaginary frequency Sigma: self.Sigmaimp = [ GF( Name_Block_Generator=[ (a, GFBloc_ImFreq(Indices=al, Mesh=Sigmaimp[0].mesh)) for a, al in self.GFStruct_corr[i] ], Copy=False, ) for i in xrange(self.N_corr_shells) ] # transform the CTQMC blocks to the full matrix: for icrsh in xrange(self.N_corr_shells): s = self.shellmap[icrsh] # s is the index of the inequivalent shell corresponding to icrsh for ibl in range(len(self.GFStruct_Solver[s])): for i in range(len(self.GFStruct_Solver[s][ibl][1])): for j in range(len(self.GFStruct_Solver[s][ibl][1])): bl = self.GFStruct_Solver[s][ibl][0] ind1 = self.GFStruct_Solver[s][ibl][1][i] ind2 = self.GFStruct_Solver[s][ibl][1][j] self.Sigmaimp[icrsh][self.mapinv[s][bl]][ind1, ind2] <<= Sigmaimp[s][bl][ind1, ind2] # rotation from local to global coordinate system: if self.use_rotations: for icrsh in xrange(self.N_corr_shells): for sig, gf in self.Sigmaimp[icrsh]: self.Sigmaimp[icrsh][sig] <<= self.rotloc(icrsh, gf, direction="toGlobal") def add_DC(self): """Substracts the double counting term from the impurity self energy.""" # Be careful: Sigmaimp is already in the global coordinate system!! sres = [s.copy() for s in self.Sigmaimp] for icrsh in xrange(self.N_corr_shells): for bl, gf in sres[icrsh]: dccont = numpy.dot( self.rotmat[icrsh], numpy.dot(self.dc_imp[icrsh][bl], self.rotmat[icrsh].conjugate().transpose()) ) sres[icrsh][bl] -= dccont return sres def set_mu(self, mu): """Sets a new chemical potential""" self.Chemical_Potential = mu # print "Chemical potential in SumK set to ",mu def sorts_of_atoms(self, lst): """ This routine should determine the number of sorts in the double list lst """ sortlst = [lst[i][1] for i in xrange(len(lst))] sortlst.sort() sorts = 1 for i in xrange(len(sortlst) - 1): if sortlst[i + 1] > sortlst[i]: sorts += 1 return sorts def number_of_atoms(self, lst): """ This routine should determine the number of atoms in the double list lst """ atomlst = [lst[i][0] for i in xrange(len(lst))] atomlst.sort() atoms = 1 for i in xrange(len(atomlst) - 1): if atomlst[i + 1] > atomlst[i]: atoms += 1 return atoms def inequiv_shells(self, lst): """ The number of inequivalent shells is calculated from lst, and a mapping is given as map(i_corr_shells) = i_inequiv_corr_shells invmap(i_inequiv_corr_shells) = i_corr_shells in order to put the Self energies to all equivalent shells, and for extracting Gloc """ tmp = [] self.shellmap = [0 for i in range(len(lst))] self.invshellmap = [0] self.N_inequiv_corr_shells = 1 tmp.append(lst[0][1:3]) if len(lst) > 1: for i in range(len(lst) - 1): fnd = False for j in range(self.N_inequiv_corr_shells): if tmp[j] == lst[i + 1][1:3]: fnd = True self.shellmap[i + 1] = j if fnd == False: self.shellmap[i + 1] = self.N_inequiv_corr_shells self.N_inequiv_corr_shells += 1 tmp.append(lst[i + 1][1:3]) self.invshellmap.append(i + 1) def total_density(self, mu): """ Calculates the total charge for the energy window for a given mu. Since in general N_Orbitals depends on k, the calculation is done in the following order: G_aa'(k,iw) -> n(k) = Tr G_aa'(k,iw) -> sum_k n_k mu: chemical potential The calculation is done in the global coordinate system, if distinction is made between local/global! """ dens = 0.0 ikarray = numpy.array(range(self.Nk)) for ik in MPI.slice_array(ikarray): S = self.latticeGF_Matsubara(ik=ik, mu=mu) dens += self.BZ_weights[ik] * S.total_density() # collect data from MPI: dens = MPI.all_reduce(MPI.world, dens, lambda x, y: x + y) MPI.barrier() return dens def find_mu(self, precision=0.01): """Searches for mu in order to give the desired charge A desired precision can be specified in precision.""" F = lambda mu: self.total_density(mu=mu) Dens_rel = self.Density_Required - self.charge_below self.Chemical_Potential = Dichotomy.Dichotomy( Function=F, xinit=self.Chemical_Potential, yvalue=Dens_rel, Precision_on_y=precision, Delta_x=0.5, MaxNbreLoop=100, xname="Chemical_Potential", yname="Total Density", verbosity=3, )[0] return self.Chemical_Potential def find_mu_nonint(self, densreq, orb=None, Beta=40, precision=0.01): def F(mu): # gnonint = self.nonint_G(Beta=Beta,mu=mu) gnonint = self.extract_Gloc(mu=mu, withSigma=False) if orb is None: dens = 0.0 for ish in range(self.N_inequiv_corr_shells): dens += gnonint[ish].total_density() else: dens = gnonint[orb].total_density() return dens self.Chemical_Potential = Dichotomy.Dichotomy( Function=F, xinit=self.Chemical_Potential, yvalue=densreq, Precision_on_y=precision, Delta_x=0.5, MaxNbreLoop=100, xname="Chemical_Potential", yname="Local Density", verbosity=3, )[0] return self.Chemical_Potential def extract_Gloc(self, mu=None, withSigma=True): """ extracts the local downfolded Green function at the chemical potential of the class. At the end, the local G is rotated from the gloabl coordinate system to the local system. if withSigma = False: Sigma is not included => non-interacting local GF """ if mu is None: mu = self.Chemical_Potential Gloc = [self.Sigmaimp[icrsh].copy() for icrsh in xrange(self.N_corr_shells)] # this list will be returned for icrsh in xrange(self.N_corr_shells): Gloc[icrsh].zero() # initialize to zero ikarray = numpy.array(range(self.Nk)) for ik in MPI.slice_array(ikarray): S = self.latticeGF_Matsubara(ik=ik, mu=mu, withSigma=withSigma) S *= self.BZ_weights[ik] for icrsh in xrange(self.N_corr_shells): tmp = Gloc[icrsh].copy() # init temporary storage for sig, gf in tmp: tmp[sig] <<= self.downfold(ik, icrsh, sig, S[sig], gf) Gloc[icrsh] += tmp # collect data from MPI: for icrsh in xrange(self.N_corr_shells): Gloc[icrsh] <<= MPI.all_reduce(MPI.world, Gloc[icrsh], lambda x, y: x + y) MPI.barrier() # Gloc[:] is now the sum over k projected to the local orbitals. # here comes the symmetrisation, if needed: if self.symm_op != 0: Gloc = self.Symm_corr.symmetrise(Gloc) # Gloc is rotated to the local coordinate system: if self.use_rotations: for icrsh in xrange(self.N_corr_shells): for sig, gf in Gloc[icrsh]: Gloc[icrsh][sig] <<= self.rotloc(icrsh, gf, direction="toLocal") # transform to CTQMC blocks: Glocret = [ GF( Name_Block_Generator=[ (a, GFBloc_ImFreq(Indices=al, Mesh=Gloc[0].mesh)) for a, al in self.GFStruct_Solver[i] ], Copy=False, ) for i in xrange(self.N_inequiv_corr_shells) ] for ish in xrange(self.N_inequiv_corr_shells): for ibl in range(len(self.GFStruct_Solver[ish])): for i in range(len(self.GFStruct_Solver[ish][ibl][1])): for j in range(len(self.GFStruct_Solver[ish][ibl][1])): bl = self.GFStruct_Solver[ish][ibl][0] ind1 = self.GFStruct_Solver[ish][ibl][1][i] ind2 = self.GFStruct_Solver[ish][ibl][1][j] Glocret[ish][bl][ind1, ind2] <<= Gloc[self.invshellmap[ish]][self.mapinv[ish][bl]][ind1, ind2] # return only the inequivalent shells: return Glocret def calc_DensityCorrection(self, Filename="densmat.dat"): """ Calculates the density correction in order to feed it back to the DFT calculations.""" assert type(Filename) == StringType, "Filename has to be a string!" ntoi = self.names_to_ind[self.SO] bln = self.blocnames[self.SO] # Set up deltaN: deltaN = {} for ib in bln: deltaN[ib] = [ numpy.zeros([self.N_Orbitals[ik][ntoi[ib]], self.N_Orbitals[ik][ntoi[ib]]], numpy.complex_) for ik in range(self.Nk) ] ikarray = numpy.array(range(self.Nk)) dens = {} for ib in bln: dens[ib] = 0.0 for ik in MPI.slice_array(ikarray): S = self.latticeGF_Matsubara(ik=ik, mu=self.Chemical_Potential) for sig, g in S: deltaN[sig][ik] = S[sig].density() dens[sig] += self.BZ_weights[ik] * S[sig].total_density() # put MPI Barrier: for sig in deltaN: for ik in range(self.Nk): deltaN[sig][ik] = MPI.all_reduce(MPI.world, deltaN[sig][ik], lambda x, y: x + y) dens[sig] = MPI.all_reduce(MPI.world, dens[sig], lambda x, y: x + y) MPI.barrier() # now save to file: 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.EnergyUnit)) if self.SP != 0: f1.write("%.14f\n" % (self.Chemical_Potential / self.EnergyUnit)) # write beta in ryderg-1 f.write("%.14f\n" % (S.Beta * self.EnergyUnit)) if self.SP != 0: f1.write("%.14f\n" % (S.Beta * self.EnergyUnit)) if self.SP == 0: for ik in range(self.Nk): 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) and (self.SO == 0): for ik in range(self.Nk): 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]): f.write( "%.14f %.14f " % (deltaN["up"][ik][inu, imu].real, deltaN["up"][ik][inu, imu].imag) ) f.write("\n") f.write("\n") f.close() for ik in range(self.Nk): f1.write("%s\n" % self.N_Orbitals[ik][1]) for inu in range(self.N_Orbitals[ik][1]): for imu in range(self.N_Orbitals[ik][1]): f1.write( "%.14f %.14f " % (deltaN["down"][ik][inu, imu].real, deltaN["down"][ik][inu, imu].imag) ) f1.write("\n") f1.write("\n") f1.close() else: for ik in range(self.Nk): 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]): f.write( "%.14f %.14f " % (deltaN["ud"][ik][inu, imu].real, deltaN["ud"][ik][inu, imu].imag) ) f.write("\n") f.write("\n") f.close() for ik in range(self.Nk): f1.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]): f1.write( "%.14f %.14f " % (deltaN["ud"][ik][inu, imu].real, deltaN["ud"][ik][inu, imu].imag) ) f1.write("\n") f1.write("\n") f1.close() return deltaN, dens
class Solver_HubbardI_base(Solver_Base): """ Python interface to the fortran Hubbard-I Solver. """ Required = { "ur" : ("4-index interaction matrix",type(numpy.zeros([1]))), "umn" : ("2-index reduced matrix U(m,m',m,m')",type(numpy.zeros([1]))), "ujmn" : ("2-index reduced matrix U(m,m',m,m')-U(m,m',m',m)",type(numpy.zeros([1]))), #"zmsb" : ("Imaginary energy mesh",type(numpy.zeros([1]))), "Nlm" : ("Number of orbitals",IntType) } Optional = { "Nmsb" : ( "Number of frequencies of the Green's functions", 1025, IntType ), "Nspin" : ("Number of spin channels used",2,IntType), "Nmoments" : ("Number of high frequency moments to be computed",5,IntType), "UseSpinOrbit" : ("Use Spin-Orbit coupling?",False,BooleanType), "Verbosity" : ("Verbosity level of Fortran output",1,IntType) } # initialisation: def __init__(self,Beta,GFstruct,**param): self.Beta = float(Beta) Parameters.check_no_parameters_not_in_union_of_dicts (param,self.Required, self.Optional) #DataTestTools.EnsureAllParametersMakeSense(self,param) if 'Nmsb' not in param : param['Nmsb'] = 1025 if 'Nspin' not in param : param['Nspin'] = 2 Solver_Base.__init__(self,GFstruct,param) # construct Greens functions: self.a_list = [a for a,al in self.GFStruct] glist = lambda : [ GFBloc_ImFreq(Indices = al, Beta = self.Beta, NFreqMatsubara = self.Nmsb) for a,al in self.GFStruct] self.G = GF(NameList = self.a_list, BlockList = glist(),Copy=False) self.G_Old = self.G.copy() self.G0 = self.G.copy() self.Sigma = self.G.copy() self.Sigma_Old = self.G.copy() M = [x for x in self.G.mesh] self.zmsb = numpy.array([x for x in M],numpy.complex_) # for the tails: self.tailtempl={} for sig,g in self.G: self.tailtempl[sig] = copy.deepcopy(g._tail) for i in range(11): self.tailtempl[sig][i].array[:] *= 0.0 self.Name='' # effective atomic levels: if self.UseSpinOrbit: self.NSpin=2 self.ealmat = numpy.zeros([self.Nlm*self.Nspin,self.Nlm*self.Nspin],numpy.complex_) def Solve(self,Iteration_Number=1,Test_Convergence=0.0001): """Calculation of the impurity Greens function using Hubbard-I""" # Test all a parameters before solutions print Parameters.check(self.__dict__,self.Required,self.Optional) #Solver_Base.Solve(self,is_last_iteration,Iteration_Number,Test_Convergence) if self.Converged : MPI.report("Solver %(Name)s has already converted: SKIPPING"%self.__dict__) return self.__save_eal('eal.dat',Iteration_Number) MPI.report( "Starting Fortran solver %(Name)s"%self.__dict__) self.Sigma_Old <<= self.Sigma self.G_Old <<= self.G # call the fortran solver: temp = 1.0/self.Beta gf,tail,self.atocc,self.atmag = gf_hi_fullu(e0f=self.ealmat, ur=self.ur, umn=self.umn, ujmn=self.ujmn, zmsb=self.zmsb, nmom=self.Nmoments, ns=self.Nspin, temp=temp, verbosity = self.Verbosity) #self.sig = sigma_atomic_fullu(gf=self.gf,e0f=self.eal,zmsb=self.zmsb,ns=self.Nspin,nlm=self.Nlm) if (self.Verbosity==0): # No fortran output, so give basic results here MPI.report("Atomic occupancy in Hubbard I Solver : %s"%self.atocc) MPI.report("Atomic magn. mom. in Hubbard I Solver : %s"%self.atmag) # transfer the data to the GF class: if (self.UseSpinOrbit): nlmtot = self.Nlm*2 # only one block in this case! else: nlmtot = self.Nlm M={} isp=-1 for a,al in self.GFStruct: isp+=1 #M[a] = gf[isp*self.Nlm:(isp+1)*self.Nlm,isp*self.Nlm:(isp+1)*self.Nlm,:] M[a] = gf[isp*nlmtot:(isp+1)*nlmtot,isp*nlmtot:(isp+1)*nlmtot,:] for i in range(min(self.Nmoments,10)): self.tailtempl[a][i+1].array[:] = tail[i][isp*nlmtot:(isp+1)*nlmtot,isp*nlmtot:(isp+1)*nlmtot] glist = lambda : [ GFBloc_ImFreq(Indices = al, Beta = self.Beta, NFreqMatsubara = self.Nmsb, Data=M[a], Tail=self.tailtempl[a]) for a,al in self.GFStruct] self.G = GF(NameList = self.a_list, BlockList = glist(),Copy=False) # Self energy: self.G0 <<= GF_Initializers.A_Omega_Plus_B(A=1,B=0.0) M = [ self.ealmat[isp*nlmtot:(isp+1)*nlmtot,isp*nlmtot:(isp+1)*nlmtot] for isp in range((2*self.Nlm)/nlmtot) ] self.G0 -= M self.Sigma <<= self.G0 - inverse(self.G) # invert G0 self.G0.invert() def test_distance(G1,G2, dist) : def f(G1,G2) : print abs(G1._data.array - G2._data.array) dS = max(abs(G1._data.array - G2._data.array).flatten()) aS = max(abs(G1._data.array).flatten()) return dS <= aS*dist return reduce(lambda x,y : x and y, [f(g1,g2) for (i1,g1),(i2,g2) in izip(G1,G2)]) MPI.report("\nChecking Sigma for convergence...\nUsing tolerance %s"%Test_Convergence) self.Converged = test_distance(self.Sigma,self.Sigma_Old,Test_Convergence) if self.Converged : MPI.report("Solver HAS CONVERGED") else : MPI.report("Solver has not yet converged") def GF_realomega(self,ommin,ommax,N_om,broadening=0.01): """Calculates the GF and spectral function on the real axis.""" delta_om = (ommax-ommin)/(1.0*(N_om-1)) omega = numpy.zeros([N_om],numpy.complex_) Mesh = numpy.zeros([N_om],numpy.float_) for i in range(N_om): omega[i] = ommin + delta_om * i + 1j * broadening Mesh[i] = ommin + delta_om * i temp = 1.0/self.Beta gf,tail,self.atocc,self.atmag = gf_hi_fullu(e0f=self.ealmat, ur=self.ur, umn=self.umn, ujmn=self.ujmn, zmsb=omega, nmom=self.Nmoments, ns=self.Nspin, temp=temp, verbosity = self.Verbosity) for sig in self.a_list: for i in range(11): self.tailtempl[sig][i].array[:] *= 0.0 # transfer the data to the GF class: if (self.UseSpinOrbit): nlmtot = self.Nlm*2 # only one block in this case! else: nlmtot = self.Nlm M={} isp=-1 for a,al in self.GFStruct: isp+=1 #M[a] = gf[isp*self.Nlm:(isp+1)*self.Nlm,isp*self.Nlm:(isp+1)*self.Nlm,:] M[a] = gf[isp*nlmtot:(isp+1)*nlmtot,isp*nlmtot:(isp+1)*nlmtot,:] for i in range(min(self.Nmoments,10)): self.tailtempl[a][i+1].array[:] = tail[i][isp*nlmtot:(isp+1)*nlmtot,isp*nlmtot:(isp+1)*nlmtot] glist = lambda : [ GFBloc_ReFreq(Indices = al, Beta = self.Beta, MeshArray = Mesh, Data=M[a], Tail=self.tailtempl[a]) for a,al in self.GFStruct] # Indices for the upfolded G self.G = GF(NameList = self.a_list, BlockList = glist(),Copy=False) # Self energy: self.G0 = self.G.copy() self.Sigma = self.G.copy() self.G0 <<= GF_Initializers.A_Omega_Plus_B(A=1,B=1j*broadening) M = [ self.ealmat[isp*nlmtot:(isp+1)*nlmtot,isp*nlmtot:(isp+1)*nlmtot] for isp in range((2*self.Nlm)/nlmtot) ] self.G0 -= M self.Sigma <<= self.G0 - inverse(self.G) self.Sigma.Note='ReFreq' # This is important for the put_Sigma routine!!! #sigmamat = sigma_atomic_fullu(gf=gf,e0f=self.ealmat,zmsb=omega,nlm=self.Nlm,ns=self.Nspin) #return omega,gf,sigmamat def __save_eal(self,Filename,it): f=open(Filename,'a') f.write('\neff. atomic levels, Iteration %s\n'%it) for i in range(self.Nlm*self.Nspin): for j in range(self.Nlm*self.Nspin): f.write("%12.8f "%self.ealmat[i,j]) f.write("\n") f.close()