def HT(Res) : # First compute the eps_hat array eps_hat = Epsilon_Hat(self.dos.eps) if Epsilon_Hat else numpy.array( [ x* numpy.identity (Sigma.N1) for x in self.dos.eps] ) assert eps_hat.shape[0] == self.dos.eps.shape[0],"Epsilon_Hat function behaves incorrectly" assert eps_hat.shape[1] == eps_hat.shape[2],"Epsilon_Hat function behaves incorrectly (result not a square matrix)" assert Sigma.N1 == eps_hat.shape[1], "Size of Sigma and of epsilon_hat mismatch" Res.zero() Sigma_fnt = callable(Sigma) if Sigma_fnt : assert len(inspect.getargspec(Sigma)[0]) ==1, "Sigma function is not of the correct type. See Documentation" # Perform the sum over eps[i] tmp,tmp2 = Res.copy(),Res.copy() tmp <<= GF_Initializers.A_Omega_Plus_B(1,mu + eta * 1j) if not(Sigma_fnt) : tmp -= Sigma if Field != None : tmp -= Field # I slice all the arrays on the node. Cf reduce operation below. for d,e_h,e in itertools.izip (*[MPI.slice_array(A) for A in [self.rho_for_sum,eps_hat,self.dos.eps]]): tmp2.copyFrom(tmp) tmp2 -= e_h if Sigma_fnt : tmp2 -= Sigma(e) tmp2.invert() tmp2 *= d Res += tmp2 # sum the Res GF of all nodes and returns the results on all nodes... # Cf Boost.mpi.python, collective communicator for documentation. # The point is that Res is pickable, hence can be transmitted between nodes without further code... Res <<= MPI.all_reduce(MPI.world,Res,lambda x,y : x+y) MPI.barrier()
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 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 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 HT(Res): # First compute the eps_hat array eps_hat = Epsilon_Hat( self.dos.eps) if Epsilon_Hat else numpy.array( [x * numpy.identity(Sigma.N1) for x in self.dos.eps]) assert eps_hat.shape[0] == self.dos.eps.shape[ 0], "Epsilon_Hat function behaves incorrectly" assert eps_hat.shape[1] == eps_hat.shape[ 2], "Epsilon_Hat function behaves incorrectly (result not a square matrix)" assert Sigma.N1 == eps_hat.shape[ 1], "Size of Sigma and of epsilon_hat mismatch" Res.zero() Sigma_fnt = callable(Sigma) if Sigma_fnt: assert len( inspect.getargspec(Sigma)[0] ) == 1, "Sigma function is not of the correct type. See Documentation" # Perform the sum over eps[i] tmp, tmp2 = Res.copy(), Res.copy() tmp <<= GF_Initializers.A_Omega_Plus_B(1, mu + eta * 1j) if not (Sigma_fnt): tmp -= Sigma if Field != None: tmp -= Field # I slice all the arrays on the node. Cf reduce operation below. for d, e_h, e in itertools.izip(*[ MPI.slice_array(A) for A in [self.rho_for_sum, eps_hat, self.dos.eps] ]): tmp2.copyFrom(tmp) tmp2 -= e_h if Sigma_fnt: tmp2 -= Sigma(e) tmp2.invert() tmp2 *= d Res += tmp2 # sum the Res GF of all nodes and returns the results on all nodes... # Cf Boost.mpi.python, collective communicator for documentation. # The point is that Res is pickable, hence can be transmitted between nodes without further code... Res <<= MPI.all_reduce(MPI.world, Res, lambda x, y: x + y) MPI.barrier()
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 __call__(self, Sigma, mu=0, eta=0, Field=None, Epsilon_Hat=None, Res=None, SelectedBlocks=()): """ - Computes : Res <- \[ \sum_k (\omega + \mu - Field - t(k) - Sigma(k,\omega)) \] if Res is None, it returns a new GF with the results. otherwise, Res must be a GF, in which the calculation is done, and which is then returned. (this allows chain calculation : SK(mu = mu,Sigma = Sigma, Res = G).total_density() which computes the sumK into G, and returns the density of G. - Sigma can be a X, or a function k-> X or a function k,eps ->X where : - k is expected to be a 1d-numpy array of size self.dim of float, containing the k vector in the basis of the RBZ (i.e. -0.5< k_i <0.5) - eps is t(k) - X is anything such that X[BlockName] can be added/subtracted to a GFBloc for BlockName in SelectedBlocks. e.g. X can be a GF (with at least the SelectedBlocks), or a dictionnary BlockName -> array if the array has the same dimension as the GF blocks (for example to add a static Sigma). - Field : Any k independant object to be added to the GF - Epsilon_Hat : a function of eps_k returning a matrix, the dimensions of Sigma - SelectedBlocks : The calculation is done with the SAME t(k) for all blocks. If this list is not None only the blocks in this list are calculated. e.g. G and Sigma have block indices 'up' and 'down'. if SelectedBlocks ==None : 'up' and 'down' are calculated if SelectedBlocks == ['up'] : only 'up' is calculated. 'down' is 0. """ S = Sigma.View_SelectedBlocks( SelectedBlocks) if SelectedBlocks else Sigma Gres = Res if Res else Sigma.copy() G = Gres.View_SelectedBlocks( SelectedBlocks) if SelectedBlocks else Gres # check input assert self.Orthogonal_Basis, "Local_G : must be orthogonal. non ortho cases not checked." assert isinstance(G, GF), "G must be a GF" assert len(list(set([g.N1 for i, g in G]))) == 1 assert self.BZ_weights.shape[0] == self.N_kpts(), "Internal Error" no = list(set([g.N1 for i, g in G]))[0] Sigma_Nargs = len( inspect.getargspec(Sigma)[0]) if callable(Sigma) else 0 assert Sigma_Nargs <= 2, "Sigma function is not of the correct type. See Documentation" # Initialize G.zero() tmp, tmp2 = G.copy(), G.copy() mupat = mu * numpy.identity(no, numpy.complex_) tmp <<= iOmega_n if Field != None: tmp -= Field if Sigma_Nargs == 0: tmp -= Sigma # substract Sigma once for all # Loop on k points... for w, k, eps_k in izip(*[ MPI.slice_array(A) for A in [self.BZ_weights, self.BZ_Points, self.Hopping] ]): eps_hat = Epsilon_Hat(eps_k) if Epsilon_Hat else eps_k tmp2 <<= tmp tmp2 -= tmp2.NBlocks * [eps_hat - mupat] if Sigma_Nargs == 1: tmp2 -= Sigma(k) elif Sigma_Nargs == 2: tmp2 -= Sigma(k, eps_k) tmp2.invert() tmp2 *= w G += tmp2 G <<= MPI.all_reduce(MPI.world, G, lambda x, y: x + y) MPI.barrier() return Gres
def __call__ (self, Sigma, mu=0, eta = 0, Field = None, Epsilon_Hat=None, Res = None, SelectedBlocks = ()): """ - Computes : Res <- \[ \sum_k (\omega + \mu - Field - t(k) - Sigma(k,\omega)) \] if Res is None, it returns a new GF with the results. otherwise, Res must be a GF, in which the calculation is done, and which is then returned. (this allows chain calculation : SK(mu = mu,Sigma = Sigma, Res = G).total_density() which computes the sumK into G, and returns the density of G. - Sigma can be a X, or a function k-> X or a function k,eps ->X where : - k is expected to be a 1d-numpy array of size self.dim of float, containing the k vector in the basis of the RBZ (i.e. -0.5< k_i <0.5) - eps is t(k) - X is anything such that X[BlockName] can be added/subtracted to a GFBloc for BlockName in SelectedBlocks. e.g. X can be a GF (with at least the SelectedBlocks), or a dictionnary BlockName -> array if the array has the same dimension as the GF blocks (for example to add a static Sigma). - Field : Any k independant object to be added to the GF - Epsilon_Hat : a function of eps_k returning a matrix, the dimensions of Sigma - SelectedBlocks : The calculation is done with the SAME t(k) for all blocks. If this list is not None only the blocks in this list are calculated. e.g. G and Sigma have block indices 'up' and 'down'. if SelectedBlocks ==None : 'up' and 'down' are calculated if SelectedBlocks == ['up'] : only 'up' is calculated. 'down' is 0. """ S = Sigma.View_SelectedBlocks(SelectedBlocks) if SelectedBlocks else Sigma Gres = Res if Res else Sigma.copy() G = Gres.View_SelectedBlocks(SelectedBlocks) if SelectedBlocks else Gres # check input assert self.Orthogonal_Basis, "Local_G : must be orthogonal. non ortho cases not checked." assert isinstance(G,GF), "G must be a GF" assert len(list(set([g.N1 for i,g in G]))) == 1 assert self.BZ_weights.shape[0] == self.N_kpts(), "Internal Error" no = list(set([g.N1 for i,g in G]))[0] Sigma_Nargs = len(inspect.getargspec(Sigma)[0]) if callable (Sigma) else 0 assert Sigma_Nargs <=2 , "Sigma function is not of the correct type. See Documentation" # Initialize G.zero() tmp,tmp2 = G.copy(),G.copy() mupat = mu * numpy.identity(no, numpy.complex_) tmp <<= iOmega_n if Field != None : tmp -= Field if Sigma_Nargs==0: tmp -= Sigma # substract Sigma once for all # Loop on k points... for w, k, eps_k in izip(*[MPI.slice_array(A) for A in [self.BZ_weights, self.BZ_Points, self.Hopping]]): eps_hat = Epsilon_Hat(eps_k) if Epsilon_Hat else eps_k tmp2 <<= tmp tmp2 -= tmp2.NBlocks * [eps_hat - mupat] if Sigma_Nargs == 1: tmp2 -= Sigma (k) elif Sigma_Nargs ==2: tmp2 -= Sigma (k,eps_k) tmp2.invert() tmp2 *= w G += tmp2 G <<= MPI.all_reduce(MPI.world,G,lambda x,y : x+y) MPI.barrier() return Gres
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 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 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 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 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
def __call__ (self, Sigma, mu=0, eta = 0, Field = None, Res = None, SelectedBlocks = () ): """ - Computes : Res <- \[ \sum_k (\omega + \mu - Field - t(k) - Sigma(k,\omega)) \] if Res is None, it returns a new GF with the results. otherwise, Res must be a GF, in which the calculation is done, and which is then returned. (this allows chain calculation : SK(mu = mu,Sigma = Sigma, Res = G).total_density() which computes the sumK into G, and returns the density of G. - Sigma can be a X, or a function k-> X or a function k,eps ->X where : - k is expected to be a 1d-numpy array of size self.dim of float, containing the k vector in the basis of the RBZ (i.e. -0.5< k_i <0.5) - eps is t(k) - X is anything such that X[BlockName] can be added/subtracted to a GFBloc for BlockName in SelectedBlocks. e.g. X can be a GF (with at least the SelectedBlocks), or a dictionnary BlockName -> array if the array has the same dimension as the GF blocks (for example to add a static Sigma). - Field : Any k independant Array_with_GF_Indices to be added to the GF - SelectedBlocks : The calculation is done with the SAME t(k) for all blocks. If this list is not None only the blocks in this list are calculated. e.g. G and Sigma have block indices 'up' and 'down'. if SelectedBlocks ==None : 'up' and 'down' are calculated if SelectedBlocks == ['up'] : only 'up' is calculated. 'down' is 0. """ if Field : assert isinstance(Field,Array_with_GF_Indices) , " Field must be a Array_with_GF_Indices object. Cf Example" S = Sigma.View_SelectedBlocks(SelectedBlocks) if SelectedBlocks else Sigma Gres = Res if Res else Sigma.copy() G = Gres.View_SelectedBlocks(SelectedBlocks) if SelectedBlocks else Gres # check input assert self.Orthogonal_Basis, "Local_G : must be orthogonal. non ortho cases not checked." assert isinstance(G,GF), "G must be a GF" assert list(set([ g.N1 for i,g in G])) == [self.Hopping.shape[1]],"G size and hopping size mismatch" assert self.BZ_weights.shape[0] == self.N_kpts(), "Internal Error" Sigma_Nargs = len(inspect.getargspec(Sigma)[0]) if callable (Sigma) else 0 assert Sigma_Nargs <=2 , "Sigma function is not of the correct type. See Documentation" #init G.zero() #tmp,tmp2 = GF(G),GF(G) tmp,tmp2 = G.copy(),G.copy() mupat = mu * self.Mu_Pattern tmp <<= GF_Initializers.A_Omega_Plus_B(A=1,B=0) #tmp.Set_Omega() ##tmp += tmp.Nblocks() * [ mupat ] if Field : tmp -= Field if Sigma_Nargs==0: tmp -= Sigma # substract Sigma once for all # Loop on k points... for w, k, eps_k in izip(*[MPI.slice_array(A) for A in [self.BZ_weights, self.BZ_Points, self.Hopping]]): tmp2 <<= tmp #tmp2.copy_from(tmp) tmp2 -= tmp2.NBlocks * [eps_k -mupat ] #tmp2.save("tmp2_w") #Sigma.save("S_w") if Sigma_Nargs == 1: tmp2 -= Sigma (k) elif Sigma_Nargs ==2: tmp2 -= Sigma (k,eps_k) tmp2.invert() tmp2 *= w G += tmp2 #G.save("GG1") #print mu,mupat,eps_k #assert 0 #print G['up'][1,1]._data G <<= MPI.all_reduce(MPI.world,G,lambda x,y : x+y) MPI.barrier() return Res