コード例 #1
0
ファイル: hilbert_transform.py プロジェクト: TRIQS/triqs
        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 (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 N1 == eps_hat.shape[1], "Size of Sigma and of epsilon_hat mismatch"

            res.zero()

            # Perform the sum over eps[i]
            tmp, tmp2 = res.copy(), res.copy()
            tmp << iOmega_n + 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.copy_from(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()
コード例 #2
0
ファイル: observables.py プロジェクト: elam3/soliDMFT
def calc_bandcorr_man(general_parameters, SK, E_kin_dft):
    """
    Calculates the correlated kinetic energy from DMFT for target states
    and then determines the band correction energy

    Parameters
    ----------
    general_parameters : dict
        general parameters as a dict

    SK : SumK Object instances

    E_kin_dft: float
        kinetic energy from DFT


    __Returns:__
    E_bandcorr: float
        band energy correction E_kin_dmft - E_kin_dft

    """
    E_kin_dmft = 0.0 + 0.0j
    E_kin = 0.0 + 0.0j
    H_ks = SK.hopping
    num_kpts = SK.n_k

    # kinetic energy from dmft lattice Greens functions
    ikarray = np.array(range(SK.n_k))
    for ik in mpi.slice_array(ikarray):
        nb = int(SK.n_orbitals[ik])
        # calculate lattice greens function
        G_iw_lat = SK.lattice_gf(ik,
                                 beta=general_parameters['beta'],
                                 with_Sigma=True,
                                 with_dc=True).copy()
        # calculate G(beta) via the function density, which is the same as fourier trafo G(w) and taking G(b)
        G_iw_lat_beta = G_iw_lat.density()
        # Doing the formula
        E_kin += np.trace(
            np.dot(
                H_ks[ik, 0, :nb, :nb], G_iw_lat_beta['up'][:, :])) + np.trace(
                    np.dot(H_ks[ik, 0, :nb, :nb], G_iw_lat_beta['down'][:, :]))
    E_kin = float(E_kin.real)

    # collect data and put into E_kin_dmft
    E_kin_dmft = mpi.all_reduce(mpi.world, E_kin, lambda x, y: x + y)
    mpi.barrier()
    # E_kin should be divided by the number of k-points
    E_kin_dmft = E_kin_dmft / num_kpts

    if mpi.is_master_node():
        print 'Kinetic energy contribution dmft part: ' + str(E_kin_dmft)

    E_bandcorr = E_kin_dmft - E_kin_dft

    return E_bandcorr
コード例 #3
0
 def extract_Gloc(mu):
     ret = Gloc.copy()
     ret.zero()
     Gk = ret.copy()
     mu_mat = np.zeros((8, 8))
     for i in range(4):
         mu_mat[i, i] = mu
         mu_mat[i + 4, i + 4] = -mu
     nk = Hk_nambu.shape[0]
     ikarray = np.array(range(nk))
     for ik in mpi.slice_array(ikarray):
         Gk['nambu'] << inverse(iOmega_n - Hk_nambu[ik] + mu_mat -
                                Sigma_orig['nambu'])
         ret['nambu'] += Gk['nambu']
     mpi.barrier()
     ret['nambu'] << mpi.all_reduce(mpi.world, ret['nambu'],
                                    lambda x, y: x + y) / nk
     return ret
コード例 #4
0
ファイル: sumk_lda.py プロジェクト: boujnah-mourad/dft_tools
    def density_gf(self,beta):
        """Calculates the density without setting up Gloc. It is useful for Hubbard I, and very fast.""" 

        dens_mat = [ {} for icrsh in xrange(self.n_corr_shells)]
        for icrsh in xrange(self.n_corr_shells):
            for bl in self.block_names[self.corr_shells[icrsh][4]]:
                dens_mat[icrsh][bl] = numpy.zeros([self.corr_shells[icrsh][3],self.corr_shells[icrsh][3]], numpy.complex_)

        ikarray=numpy.array(range(self.n_k))

        for ik in mpi.slice_array(ikarray):
            
            Gupf = self.lattice_gf_matsubara(ik=ik, beta=beta, mu=self.chemical_potential)
            Gupf *= self.bz_weights[ik]
            dm = Gupf.density()
            MMat = [dm[bl] for bl in self.block_names[self.SO]]
            
            for icrsh in range(self.n_corr_shells):
                for ibn,bn in enumerate(self.block_names[self.corr_shells[icrsh][4]]):
                    isp = self.names_to_ind[self.corr_shells[icrsh][4]][bn]
                    dim = self.corr_shells[icrsh][3]
                    n_orb = self.n_orbitals[ik,isp]
                    #print ik, bn, isp
                    dens_mat[icrsh][bn] += numpy.dot( numpy.dot(self.proj_mat[ik,isp,icrsh,0:dim,0:n_orb],MMat[ibn]),
                                                      self.proj_mat[ik,isp,icrsh,0:dim,0:n_orb].transpose().conjugate() )

        # get data from nodes:
        for icrsh in range(self.n_corr_shells):
            for sig in dens_mat[icrsh]:
                dens_mat[icrsh][sig] = mpi.all_reduce(mpi.world,dens_mat[icrsh][sig],lambda x,y : x+y)
        mpi.barrier()


        if (self.symm_op!=0): dens_mat = self.Symm_corr.symmetrize(dens_mat)

        # Rotate to local coordinate system:
        if (self.use_rotations):
            for icrsh in xrange(self.n_corr_shells):
                for bn in dens_mat[icrsh]:
                    if (self.rot_mat_time_inv[icrsh]==1): dens_mat[icrsh][bn] = dens_mat[icrsh][bn].conjugate()
                    dens_mat[icrsh][bn] = numpy.dot( numpy.dot(self.rot_mat[icrsh].conjugate().transpose(),dens_mat[icrsh][bn]) , 
                                                    self.rot_mat[icrsh] )

        return dens_mat
コード例 #5
0
        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 <<= iOmega_n + 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.copy_from(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()
コード例 #6
0
ファイル: sumk_lda.py プロジェクト: boujnah-mourad/dft_tools
 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.n_k))
     
     for ik in mpi.slice_array(ikarray):
     
         S = self.lattice_gf_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
コード例 #7
0
ファイル: sumk_lda.py プロジェクト: boujnah-mourad/dft_tools
    def simple_point_dens_mat(self):


        ntoi = self.names_to_ind[self.SO]
        bln = self.block_names[self.SO]

        MMat = [numpy.zeros( [self.n_orbitals[0,ntoi[bl]],self.n_orbitals[0,ntoi[bl]]], numpy.complex_) for bl in bln] 

        dens_mat = [ {} for icrsh in xrange(self.n_corr_shells)]
        for icrsh in xrange(self.n_corr_shells):
            for bl in self.block_names[self.corr_shells[icrsh][4]]:
                dens_mat[icrsh][bl] = numpy.zeros([self.corr_shells[icrsh][3],self.corr_shells[icrsh][3]], numpy.complex_)

        ikarray=numpy.array(range(self.n_k))
          
        for ik in mpi.slice_array(ikarray):
            
            unchangedsize = all( [ self.n_orbitals[ik,ntoi[bln[ib]]]==len(MMat[ib]) 
                                   for ib in range(self.n_spin_blocks_gf[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.h_field*(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.block_names[self.corr_shells[icrsh][4]]):
                    isp = self.names_to_ind[self.corr_shells[icrsh][4]][bn]
                    dim = self.corr_shells[icrsh][3]
                    n_orb = self.n_orbitals[ik,isp]
                    
                    #print ik, bn, isp
                    dens_mat[icrsh][bn] += self.bz_weights[ik] * numpy.dot( numpy.dot(self.proj_mat[ik,isp,icrsh,0:dim,0:n_orb],MMat[ibn]) , 
                                                                           self.proj_mat[ik,isp,icrsh,0:dim,0:n_orb].transpose().conjugate() )

        # get data from nodes:
        for icrsh in range(self.n_corr_shells):
            for sig in dens_mat[icrsh]:
                dens_mat[icrsh][sig] = mpi.all_reduce(mpi.world,dens_mat[icrsh][sig],lambda x,y : x+y)
        mpi.barrier()

                    
        if (self.symm_op!=0): dens_mat = self.Symm_corr.symmetrize(dens_mat)

        # Rotate to local coordinate system:
        if (self.use_rotations):
            for icrsh in xrange(self.n_corr_shells):
                for bn in dens_mat[icrsh]:
                    if (self.rot_mat_time_inv[icrsh]==1): dens_mat[icrsh][bn] = dens_mat[icrsh][bn].conjugate()
                    dens_mat[icrsh][bn] = numpy.dot( numpy.dot(self.rot_mat[icrsh].conjugate().transpose(),dens_mat[icrsh][bn]) , 
                                                    self.rot_mat[icrsh])
                

        return dens_mat
コード例 #8
0
ファイル: sumk_lda.py プロジェクト: boujnah-mourad/dft_tools
    def calc_density_correction(self,filename = 'dens_mat.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.block_names[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.n_k)]

        ikarray=numpy.array(range(self.n_k))
        
        dens = {}
        for ib in bln:
            dens[ib] = 0.0
 
        for ik in mpi.slice_array(ikarray):
        
            S = self.lattice_gf_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.n_k):
                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.energy_unit))
            if (self.SP!=0): f1.write("%.14f\n"%(self.chemical_potential/self.energy_unit))
            # write beta in ryderg-1
            f.write("%.14f\n"%(S.mesh.beta*self.energy_unit))
            if (self.SP!=0): f1.write("%.14f\n"%(S.mesh.beta*self.energy_unit))
            if (self.SP==0):
                for ik in range(self.n_k):
                    f.write("%s\n"%self.n_orbitals[ik,0])
                    for inu in range(self.n_orbitals[ik,0]):
                        for imu in range(self.n_orbitals[ik,0]):
                            valre = (deltaN['up'][ik][inu,imu].real + deltaN['down'][ik][inu,imu].real) / 2.0
                            valim = (deltaN['up'][ik][inu,imu].imag + deltaN['down'][ik][inu,imu].imag) / 2.0
                            f.write("%.14f  %.14f "%(valre,valim))
                        f.write("\n")
                    f.write("\n")
                f.close()
            elif ((self.SP==1)and(self.SO==0)):
                for ik in range(self.n_k):
                    f.write("%s\n"%self.n_orbitals[ik,0])
                    for inu in range(self.n_orbitals[ik,0]):
                        for imu in range(self.n_orbitals[ik,0]):
                            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.n_k):
                    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.n_k):
                    f.write("%s\n"%self.n_orbitals[ik,0])
                    for inu in range(self.n_orbitals[ik,0]):
                        for imu in range(self.n_orbitals[ik,0]):
                            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.n_k):
                    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
コード例 #9
0
ファイル: sumk_dft_tools.py プロジェクト: krivenko/dft_tools
    def dos_wannier_basis(self, mu=None, broadening=None, mesh=None, with_Sigma=True, with_dc=True, save_to_file=True):
        """
        Calculates the density of states in the basis of the Wannier functions.

        Parameters
        ----------
        mu : double, optional
             Chemical potential, overrides the one stored in the hdf5 archive.
        broadening : double, optional
                     Lorentzian broadening of the spectra. If not given, standard value of lattice_gf is used.
        mesh : real frequency MeshType, optional
               Omega mesh for the real-frequency Green's function. Given as parameter to lattice_gf.
        with_Sigma : boolean, optional
                     If True, the self energy is used for the calculation. If false, the DOS is calculated without self energy.
        with_dc : boolean, optional
                  If True the double counting correction is used.
        save_to_file : boolean, optional
                       If True, text files with the calculated data will be created.

        Returns
        -------
        DOS : Dict of numpy arrays
              Contains the full density of states.
        DOSproj :  Dict of numpy arrays
                   DOS projected to atoms.
        DOSproj_orb : Dict of numpy arrays
                      DOS projected to atoms and resolved into orbital contributions.
        """

        if (mesh is None) and (not with_Sigma):
            raise ValueError, "lattice_gf: Give the mesh=(om_min,om_max,n_points) for the lattice GfReFreq."
        if mesh is None:
            om_mesh = [x.real for x in self.Sigma_imp_w[0].mesh]
            om_min = om_mesh[0]
            om_max = om_mesh[-1]
            n_om = len(om_mesh)
            mesh = (om_min, om_max, n_om)
        else:
            om_min, om_max, n_om = mesh
            om_mesh = numpy.linspace(om_min, om_max, n_om)

        G_loc = []
        for icrsh in range(self.n_corr_shells):
            spn = self.spin_block_names[self.corr_shells[icrsh]['SO']]
            glist = [GfReFreq(indices=inner, window=(om_min, om_max), n_points=n_om)
                     for block, inner in self.gf_struct_sumk[icrsh]]
            G_loc.append(
                BlockGf(name_list=spn, block_list=glist, make_copies=False))
        for icrsh in range(self.n_corr_shells):
            G_loc[icrsh].zero()

        DOS = {sp: numpy.zeros([n_om], numpy.float_)
               for sp in self.spin_block_names[self.SO]}
        DOSproj = [{} for ish in range(self.n_inequiv_shells)]
        DOSproj_orb = [{} for ish in range(self.n_inequiv_shells)]
        for ish in range(self.n_inequiv_shells):
            for sp in self.spin_block_names[self.corr_shells[self.inequiv_to_corr[ish]]['SO']]:
                dim = self.corr_shells[self.inequiv_to_corr[ish]]['dim']
                DOSproj[ish][sp] = numpy.zeros([n_om], numpy.float_)
                DOSproj_orb[ish][sp] = numpy.zeros(
                    [n_om, dim, dim], numpy.float_)

        ikarray = numpy.array(range(self.n_k))
        for ik in mpi.slice_array(ikarray):

            G_latt_w = self.lattice_gf(
                ik=ik, mu=mu, iw_or_w="w", broadening=broadening, mesh=mesh, with_Sigma=with_Sigma, with_dc=with_dc)
            G_latt_w *= self.bz_weights[ik]

            # Non-projected DOS
            for iom in range(n_om):
                for bname, gf in G_latt_w:
                    DOS[bname][iom] -= gf.data[iom, :, :].imag.trace() / \
                        numpy.pi

            # Projected DOS:
            for icrsh in range(self.n_corr_shells):
                tmp = G_loc[icrsh].copy()
                for bname, gf in tmp:
                    tmp[bname] << self.downfold(ik, icrsh, bname, G_latt_w[
                                                bname], gf)  # downfolding G
                G_loc[icrsh] += tmp

        # Collect data from mpi:
        for bname in DOS:
            DOS[bname] = mpi.all_reduce(
                mpi.world, DOS[bname], lambda x, y: x + y)
        for icrsh in range(self.n_corr_shells):
            G_loc[icrsh] << mpi.all_reduce(
                mpi.world, G_loc[icrsh], lambda x, y: x + y)
        mpi.barrier()

        # Symmetrize and rotate to local coord. system if needed:
        if self.symm_op != 0:
            G_loc = self.symmcorr.symmetrize(G_loc)
        if self.use_rotations:
            for icrsh in range(self.n_corr_shells):
                for bname, gf in G_loc[icrsh]:
                    G_loc[icrsh][bname] << self.rotloc(
                        icrsh, gf, direction='toLocal')

        # G_loc can now also be used to look at orbitally-resolved quantities
        for ish in range(self.n_inequiv_shells):
            for bname, gf in G_loc[self.inequiv_to_corr[ish]]:  # loop over spins
                for iom in range(n_om):
                    DOSproj[ish][bname][iom] -= gf.data[iom,
                                                        :, :].imag.trace() / numpy.pi
                DOSproj_orb[ish][bname][
                    :, :, :] -= gf.data[:, :, :].imag / numpy.pi

        # Write to files
        if save_to_file and mpi.is_master_node():
            for sp in self.spin_block_names[self.SO]:
                f = open('DOS_wann_%s.dat' % sp, 'w')
                for iom in range(n_om):
                    f.write("%s    %s\n" % (om_mesh[iom], DOS[sp][iom]))
                f.close()

                # Partial
                for ish in range(self.n_inequiv_shells):
                    f = open('DOS_wann_%s_proj%s.dat' % (sp, ish), 'w')
                    for iom in range(n_om):
                        f.write("%s    %s\n" %
                                (om_mesh[iom], DOSproj[ish][sp][iom]))
                    f.close()

                    # Orbitally-resolved
                    for i in range(self.corr_shells[self.inequiv_to_corr[ish]]['dim']):
                        for j in range(i, self.corr_shells[self.inequiv_to_corr[ish]]['dim']):
                            f = open('DOS_wann_' + sp + '_proj' + str(ish) +
                                     '_' + str(i) + '_' + str(j) + '.dat', 'w')
                            for iom in range(n_om):
                                f.write("%s    %s\n" % (
                                    om_mesh[iom], DOSproj_orb[ish][sp][iom, i, j]))
                            f.close()

        return DOS, DOSproj, DOSproj_orb
コード例 #10
0
                     target_shape=(4, 4))

    # -- The field is symmetric in (i1, i2)
    # -- only calculate upper triangle
    
    index_list = []
    for i1 in xrange(4):
        for i2 in xrange(i1, 4):
            index_list.append((i1, i2))

    #F = 0.0001 / m.beta
    F = 0.1 / m.beta
    F_vec = np.array([-F, F])
    
    work_list = np.array(index_list)
    work_list = mpi.slice_array(work_list)

    for i1, i2 in work_list:

        o1, o2 = m.op_imp[i1], m.op_imp[i2]
        O1 = dagger(o1) * o2
        O1 = O1 + dagger(O1)

        ed_p = TriqsExactDiagonalization(m.H + F * O1, m.op_full, m.beta)
        ed_m = TriqsExactDiagonalization(m.H - F * O1, m.op_full, m.beta)
        
        p.g_tau_field[(i1, i2)] = g_tau.copy()
        ed_p.set_g2_tau_matrix(p.g_tau_field[(i1, i2)], m.op_imp)

        for i3, i4 in itertools.product(range(4), repeat=2):
コード例 #11
0
ファイル: sumk_lda_tools.py プロジェクト: lwk205/dft_tools
    def dos_partial(self, broadening=0.01):
        """calculates the orbitally-resolved DOS"""

        assert hasattr(self, "Sigma_imp"), "Set Sigma First!!"

        #thingstoread = ['Dens_Mat_below','N_parproj','Proj_Mat_pc','rotmat_all']
        #retval = self.read_input_from_HDF(SubGrp=self.par_proj_data, thingstoread=thingstoread)
        retval = self.read_par_proj_input_from_hdf()
        if not retval: return retval
        if self.symm_op:
            self.Symm_par = Symmetry(self.hdf_file,
                                     subgroup=self.symm_par_data)

        mu = self.chemical_potential

        gf_struct_proj = [[(al, range(self.shells[i][3]))
                           for al in self.block_names[self.SO]]
                          for i in xrange(self.n_shells)]
        Gproj = [
            BlockGf(name_block_generator=[
                (a, GfReFreq(indices=al, mesh=self.Sigma_imp[0].mesh))
                for a, al in gf_struct_proj[ish]
            ],
                    make_copies=False) for ish in xrange(self.n_shells)
        ]
        for ish in range(self.n_shells):
            Gproj[ish].zero()

        Msh = [x for x in self.Sigma_imp[0].mesh]
        n_om = len(Msh)

        DOS = {}
        for bn in self.block_names[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.block_names[self.SO]:
                dl = self.shells[ish][3]
                DOSproj[ish][bn] = numpy.zeros([n_om], numpy.float_)
                DOSproj_orb[ish][bn] = numpy.zeros([n_om, dl, dl],
                                                   numpy.float_)

        ikarray = numpy.array(range(self.n_k))

        for ik in mpi.slice_array(ikarray):

            S = self.lattice_gf_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[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.symmetrize(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[
                        iom, :, :].imag.trace() / (-3.1415926535)
                DOSproj_orb[ish][sig][:, :, :] += gf.data[:, :, :].imag / (
                    -3.1415926535)

        if (mpi.is_master_node()):
            # output to files
            for bn in self.block_names[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][iom, i,
                                                                        j]))
                            f.close()
コード例 #12
0
ファイル: sumk_dft_tools.py プロジェクト: krivenko/dft_tools
    def spaghettis(self, broadening=None, plot_shift=0.0, plot_range=None, ishell=None, mu=None, save_to_file='Akw_'):
        """
        Calculates the correlated band structure using a real-frequency self energy.

        Parameters
        ----------
        mu : double, optional
             Chemical potential, overrides the one stored in the hdf5 archive.
        broadening : double, optional
                     Lorentzian broadening of the spectra. If not given, standard value of lattice_gf is used.
        plot_shift : double, optional
                     Offset for each A(k,w) for stacked plotting of spectra.
        plot_range : list of double, optional
                     Sets the energy window for plotting to (plot_range[0],plot_range[1]). If not provided, the energy mesh of the self energy is used.
        ishell : integer, optional
                 Contains the index of the shell on which the spectral function is projected. If ishell=None, the total spectrum without projection is calculated.
        save_to_file : string, optional
                       Filename where the spectra are stored.

        Returns
        -------
        Akw : Dict of numpy arrays
              Data as it is also written to the files.
        """

        assert hasattr(
            self, "Sigma_imp_w"), "spaghettis: Set Sigma_imp_w first."
        things_to_read = ['n_k', 'n_orbitals', 'proj_mat',
                          'hopping', 'n_parproj', 'proj_mat_all']
        value_read = self.read_input_from_hdf(
            subgrp=self.bands_data, things_to_read=things_to_read)
        if not value_read:
            return value_read
        things_to_read = ['rot_mat_all', 'rot_mat_all_time_inv']
        value_read = self.read_input_from_hdf(
            subgrp=self.parproj_data, things_to_read=things_to_read)
        if not value_read:
            return value_read

        if mu is None:
            mu = self.chemical_potential
        spn = self.spin_block_names[self.SO]
        mesh = [x.real for x in self.Sigma_imp_w[0].mesh]
        n_om = len(mesh)

        if plot_range is None:
            om_minplot = mesh[0] - 0.001
            om_maxplot = mesh[n_om - 1] + 0.001
        else:
            om_minplot = plot_range[0]
            om_maxplot = plot_range[1]

        if ishell is None:
            Akw = {sp: numpy.zeros([self.n_k, n_om], numpy.float_)
                   for sp in spn}
        else:
            Akw = {sp: numpy.zeros(
                [self.shells[ishell]['dim'], self.n_k, n_om], numpy.float_) for sp in spn}

        if not ishell is None:
            gf_struct_parproj = [
                (sp, range(self.shells[ishell]['dim'])) for sp in spn]
            G_loc = BlockGf(name_block_generator=[(block, GfReFreq(indices=inner, mesh=self.Sigma_imp_w[0].mesh))
                                                  for block, inner in gf_struct_parproj], make_copies=False)
            G_loc.zero()

        ikarray = numpy.array(range(self.n_k))
        for ik in mpi.slice_array(ikarray):

            G_latt_w = self.lattice_gf(
                ik=ik, mu=mu, iw_or_w="w", broadening=broadening)

            if ishell is None:
                # Non-projected A(k,w)
                for iom in range(n_om):
                    if (mesh[iom] > om_minplot) and (mesh[iom] < om_maxplot):
                        for bname, gf in G_latt_w:
                            Akw[bname][ik, iom] += gf.data[iom, :,
                                                           :].imag.trace() / (-1.0 * numpy.pi)
                        # shift Akw for plotting stacked k-resolved eps(k)
                        # curves
                        Akw[bname][ik, iom] += ik * plot_shift

            else:  # ishell not None
                # Projected A(k,w):
                G_loc.zero()
                tmp = G_loc.copy()
                for ir in range(self.n_parproj[ishell]):
                    for bname, gf in tmp:
                        tmp[bname] << self.downfold(ik, ishell, bname, G_latt_w[
                                                    bname], gf, shells='all', ir=ir)
                    G_loc += tmp

                # Rotate to local frame
                if self.use_rotations:
                    for bname, gf in G_loc:
                        G_loc[bname] << self.rotloc(
                            ishell, gf, direction='toLocal', shells='all')

                for iom in range(n_om):
                    if (mesh[iom] > om_minplot) and (mesh[iom] < om_maxplot):
                        for ish in range(self.shells[ishell]['dim']):
                            for sp in spn:
                                Akw[sp][ish, ik, iom] = G_loc[sp].data[
                                    iom, ish, ish].imag / (-1.0 * numpy.pi)

        # Collect data from mpi
        for sp in spn:
            Akw[sp] = mpi.all_reduce(mpi.world, Akw[sp], lambda x, y: x + y)
        mpi.barrier()

        if save_to_file and mpi.is_master_node():
            if ishell is None:
                for sp in spn:  # loop over GF blocs:
                    # Open file for storage:
                    f = open(save_to_file + sp + '.dat', 'w')
                    for ik in range(self.n_k):
                        for iom in range(n_om):
                            if (mesh[iom] > om_minplot) and (mesh[iom] < om_maxplot):
                                if plot_shift > 0.0001:
                                    f.write('%s      %s\n' %
                                            (mesh[iom], Akw[sp][ik, iom]))
                                else:
                                    f.write('%s     %s      %s\n' %
                                            (ik, mesh[iom], Akw[sp][ik, iom]))
                        f.write('\n')
                    f.close()

            else:  # ishell is not None
                for sp in spn:
                    for ish in range(self.shells[ishell]['dim']):
                        # Open file for storage:
                        f = open(save_to_file + str(ishell) + '_' +
                                 sp + '_proj' + str(ish) + '.dat', 'w')
                        for ik in range(self.n_k):
                            for iom in range(n_om):
                                if (mesh[iom] > om_minplot) and (mesh[iom] < om_maxplot):
                                    if plot_shift > 0.0001:
                                        f.write('%s      %s\n' % (
                                            mesh[iom], Akw[sp][ish, ik, iom]))
                                    else:
                                        f.write('%s     %s      %s\n' % (
                                            ik, mesh[iom], Akw[sp][ish, ik, iom]))
                            f.write('\n')
                        f.close()

        return Akw
コード例 #13
0
    def transport_distribution(self, beta, directions=['xx'], energy_window=None, Om_mesh=[0.0], with_Sigma=False, n_om=None, broadening=0.0):
        r"""
        Calculates the transport distribution 

        .. math::
           \Gamma_{\alpha\beta}\left(\omega+\Omega/2, \omega-\Omega/2\right) = \frac{1}{V} \sum_k Tr\left(v_{k,\alpha}A_{k}(\omega+\Omega/2)v_{k,\beta}A_{k}\left(\omega-\Omega/2\right)\right)

        in the direction :math:`\alpha\beta`. The velocities :math:`v_{k}` are read from the transport subgroup of the hdf5 archive. 

        Parameters
        ----------

        beta : double
            Inverse temperature :math:`\beta`.
        directions : list of double, optional
            :math:`\alpha\beta` e.g.: ['xx','yy','zz','xy','xz','yz'].
        energy_window : list of double, optional
            Specifies the upper and lower limit of the frequency integration for :math:`\Omega=0.0`. The window is automatically enlarged by the largest :math:`\Omega` value, 
            hence the integration is performed in the interval [energy_window[0]-max(Om_mesh), energy_window[1]+max(Om_mesh)].
        Om_mesh : list of double, optional
            :math:`\Omega` frequency mesh of the optical conductivity. For the conductivity and the Seebeck coefficient :math:`\Omega=0.0` has to be
            part of the mesh. In the current version Om_mesh is repined to the mesh provided by the self-energy! The actual mesh is printed on the screen and stored as
            member Om_mesh.
        with_Sigma : boolean, optional
            Determines whether the calculation is performed with or without self energy. If this parameter is set to False the self energy is set to zero (i.e. the DFT band 
            structure :math:`A(k,\omega)` is used). Note: For with_Sigma=False it is necessary to specify the parameters energy_window, n_om and broadening.
        n_om : integer, optional
            Number of equidistant frequency points in the interval [energy_window[0]-max(Om_mesh), energy_window[1]+max(Om_mesh)]. This parameters is only used if
            with_Sigma = False.
        broadening : double, optional
            Lorentzian broadening. It is necessary to specify the boradening if with_Sigma = False, otherwise this parameter can be set to 0.0.
        """

        # Check if wien converter was called and read transport subgroup form
        # hdf file
        if mpi.is_master_node():
            ar = HDFArchive(self.hdf_file, 'r')
            if not (self.transp_data in ar):
                raise IOError, "transport_distribution: No %s subgroup in hdf file found! Call convert_transp_input first." % self.transp_data
            # check if outputs file was converted
            if not ('n_symmetries' in ar['dft_misc_input']):
                raise IOError,  "transport_distribution: n_symmetries missing. Check if case.outputs file is present and call convert_misc_input() or convert_dft_input()."

        self.read_transport_input_from_hdf()

        if mpi.is_master_node():
            # k-dependent-projections.
            assert self.k_dep_projection == 1, "transport_distribution: k dependent projection is not implemented!"
            # positive Om_mesh
            assert all(
                Om >= 0.0 for Om in Om_mesh), "transport_distribution: Om_mesh should not contain negative values!"

        # Check if energy_window is sufficiently large and correct

        if (energy_window[0] >= energy_window[1] or energy_window[0] >= 0 or energy_window[1] <= 0):
            assert 0, "transport_distribution: energy_window wrong!"

        if (abs(self.fermi_dis(energy_window[0], beta) * self.fermi_dis(-energy_window[0], beta)) > 1e-5
                or abs(self.fermi_dis(energy_window[1], beta) * self.fermi_dis(-energy_window[1], beta)) > 1e-5):
            mpi.report(
                "\n####################################################################")
            mpi.report(
                "transport_distribution: WARNING - energy window might be too narrow!")
            mpi.report(
                "####################################################################\n")

        # up and down are equivalent if SP = 0
        n_inequiv_spin_blocks = self.SP + 1 - self.SO
        self.directions = directions
        dir_to_int = {'x': 0, 'y': 1, 'z': 2}

        # calculate A(k,w)
        #######################################

        # Define mesh for Green's function and in the specified energy window
        if (with_Sigma == True):
            self.omega = numpy.array([round(x.real, 12)
                                      for x in self.Sigma_imp_w[0].mesh])
            mesh = None
            mu = self.chemical_potential
            n_om = len(self.omega)
            mpi.report("Using omega mesh provided by Sigma!")

            if energy_window is not None:
                # Find according window in Sigma mesh
                ioffset = numpy.sum(
                    self.omega < energy_window[0] - max(Om_mesh))
                self.omega = self.omega[numpy.logical_and(self.omega >= energy_window[
                                                          0] - max(Om_mesh), self.omega <= energy_window[1] + max(Om_mesh))]
                n_om = len(self.omega)

                # Truncate Sigma to given omega window
                # In the future there should be an option in gf to manipulate the mesh (e.g. truncate) directly.
                # For now we stick with this:
                for icrsh in range(self.n_corr_shells):
                    Sigma_save = self.Sigma_imp_w[icrsh].copy()
                    spn = self.spin_block_names[self.corr_shells[icrsh]['SO']]
                    glist = lambda: [GfReFreq(indices=inner, window=(self.omega[
                                              0], self.omega[-1]), n_points=n_om) for block, inner in self.gf_struct_sumk[icrsh]]
                    self.Sigma_imp_w[icrsh] = BlockGf(
                        name_list=spn, block_list=glist(), make_copies=False)
                    for i, g in self.Sigma_imp_w[icrsh]:
                        for iL in g.indices:
                            for iR in g.indices:
                                for iom in xrange(n_om):
                                    g.data[iom, int(iL), int(iR)] = Sigma_save[
                                        i].data[ioffset + iom, int(iL), int(iR)]
        else:
            assert n_om is not None, "transport_distribution: Number of omega points (n_om) needed to calculate transport distribution!"
            assert energy_window is not None, "transport_distribution: Energy window needed to calculate transport distribution!"
            assert broadening != 0.0 and broadening is not None, "transport_distribution: Broadening necessary to calculate transport distribution!"
            self.omega = numpy.linspace(
                energy_window[0] - max(Om_mesh), energy_window[1] + max(Om_mesh), n_om)
            mesh = [energy_window[0] -
                    max(Om_mesh), energy_window[1] + max(Om_mesh), n_om]
            mu = 0.0

        # Define mesh for optic conductivity
        d_omega = round(numpy.abs(self.omega[0] - self.omega[1]), 12)
        iOm_mesh = numpy.array([round((Om / d_omega), 0) for Om in Om_mesh])
        self.Om_mesh = iOm_mesh * d_omega

        if mpi.is_master_node():
            print "Chemical potential: ", mu
            print "Using n_om = %s points in the energy_window [%s,%s]" % (n_om, self.omega[0], self.omega[-1]),
            print "where the omega vector is:"
            print self.omega
            print "Calculation requested for Omega mesh:   ", numpy.array(Om_mesh)
            print "Omega mesh automatically repined to:  ", self.Om_mesh

        self.Gamma_w = {direction: numpy.zeros(
            (len(self.Om_mesh), n_om), dtype=numpy.float_) for direction in self.directions}

        # Sum over all k-points
        ikarray = numpy.array(range(self.n_k))
        for ik in mpi.slice_array(ikarray):
            # Calculate G_w  for ik and initialize A_kw
            G_w = self.lattice_gf(ik, mu, iw_or_w="w", beta=beta,
                                  broadening=broadening, mesh=mesh, with_Sigma=with_Sigma)
            A_kw = [numpy.zeros((self.n_orbitals[ik][isp], self.n_orbitals[ik][isp], n_om), dtype=numpy.complex_)
                    for isp in range(n_inequiv_spin_blocks)]

            for isp in range(n_inequiv_spin_blocks):
                # copy data from G_w (swapaxes is used to have omega in the 3rd
                # dimension)
                A_kw[isp] = copy.deepcopy(G_w[self.spin_block_names[self.SO][
                                          isp]].data.swapaxes(0, 1).swapaxes(1, 2))
                # calculate A(k,w) for each frequency
                for iw in xrange(n_om):
                    A_kw[isp][:, :, iw] = -1.0 / (2.0 * numpy.pi * 1j) * (
                        A_kw[isp][:, :, iw] - numpy.conjugate(numpy.transpose(A_kw[isp][:, :, iw])))

                b_min = max(self.band_window[isp][
                            ik, 0], self.band_window_optics[isp][ik, 0])
                b_max = min(self.band_window[isp][
                            ik, 1], self.band_window_optics[isp][ik, 1])
                A_i = slice(
                    b_min - self.band_window[isp][ik, 0], b_max - self.band_window[isp][ik, 0] + 1)
                v_i = slice(b_min - self.band_window_optics[isp][
                            ik, 0], b_max - self.band_window_optics[isp][ik, 0] + 1)

                # loop over all symmetries
                for R in self.rot_symmetries:
                    # get transformed velocity under symmetry R
                    vel_R = copy.deepcopy(self.velocities_k[isp][ik])
                    for nu1 in range(self.band_window_optics[isp][ik, 1] - self.band_window_optics[isp][ik, 0] + 1):
                        for nu2 in range(self.band_window_optics[isp][ik, 1] - self.band_window_optics[isp][ik, 0] + 1):
                            vel_R[nu1][nu2][:] = numpy.dot(
                                R, vel_R[nu1][nu2][:])

                    # calculate Gamma_w for each direction from the velocities
                    # vel_R and the spectral function A_kw
                    for direction in self.directions:
                        for iw in xrange(n_om):
                            for iq in range(len(self.Om_mesh)):
                                if(iw + iOm_mesh[iq] >= n_om or self.omega[iw] < -self.Om_mesh[iq] + energy_window[0] or self.omega[iw] > self.Om_mesh[iq] + energy_window[1]):
                                    continue

                                self.Gamma_w[direction][iq, iw] += (numpy.dot(numpy.dot(numpy.dot(vel_R[v_i, v_i, dir_to_int[direction[0]]],
                                                                                                  A_kw[isp][A_i, A_i, int(iw + iOm_mesh[iq])]), vel_R[v_i, v_i, dir_to_int[direction[1]]]),
                                                                              A_kw[isp][A_i, A_i, iw]).trace().real * self.bz_weights[ik])

        for direction in self.directions:
            self.Gamma_w[direction] = (mpi.all_reduce(mpi.world, self.Gamma_w[direction], lambda x, y: x + y)
                                       / self.cellvolume(self.lattice_type, self.lattice_constants, self.lattice_angles)[1] / self.n_symmetries)
コード例 #14
0
    def partial_charges(self, beta=40, mu=None, with_Sigma=True, with_dc=True):
        """
        Calculates the orbitally-resolved density matrix for all the orbitals considered in the input, consistent with
        the definition of Wien2k. Hence, (possibly non-orthonormal) projectors have to be provided in the partial projectors subgroup of
        the hdf5 archive.

        Parameters
        ----------

        with_Sigma : boolean, optional
                     If True, the self energy is used for the calculation. If false, partial charges are calculated without self-energy correction.
        beta : double, optional
               In case the self-energy correction is not used, the inverse temperature where the calculation should be done has to be given here.
        mu : double, optional
             Chemical potential, overrides the one stored in the hdf5 archive.
        with_dc : boolean, optional
                  If True the double counting correction is used.

        Returns
        -------
        dens_mat : list of numpy array
                   A list of density matrices projected to all shells provided in the input.
        """

        things_to_read = ['dens_mat_below', 'n_parproj',
                          'proj_mat_all', 'rot_mat_all', 'rot_mat_all_time_inv']
        value_read = self.read_input_from_hdf(
            subgrp=self.parproj_data, things_to_read=things_to_read)
        if not value_read:
            return value_read
        if self.symm_op:
            self.symmpar = Symmetry(self.hdf_file, subgroup=self.symmpar_data)

        spn = self.spin_block_names[self.SO]
        ntoi = self.spin_names_to_ind[self.SO]
        # Density matrix in the window
        self.dens_mat_window = [[numpy.zeros([self.shells[ish]['dim'], self.shells[ish]['dim']], numpy.complex_)
                                 for ish in range(self.n_shells)]
                                for isp in range(len(spn))]
        # Set up G_loc
        gf_struct_parproj = [[(sp, range(self.shells[ish]['dim'])) for sp in spn]
                             for ish in range(self.n_shells)]
        if with_Sigma:
            G_loc = [BlockGf(name_block_generator=[(block, GfImFreq(indices=inner, mesh=self.Sigma_imp_iw[0].mesh))
                                                   for block, inner in gf_struct_parproj[ish]], make_copies=False)
                     for ish in range(self.n_shells)]
            beta = self.Sigma_imp_iw[0].mesh.beta
        else:
            G_loc = [BlockGf(name_block_generator=[(block, GfImFreq(indices=inner, beta=beta))
                                                   for block, inner in gf_struct_parproj[ish]], make_copies=False)
                     for ish in range(self.n_shells)]
        for ish in range(self.n_shells):
            G_loc[ish].zero()

        ikarray = numpy.array(range(self.n_k))
        for ik in mpi.slice_array(ikarray):

            G_latt_iw = self.lattice_gf(
                ik=ik, mu=mu, iw_or_w="iw", beta=beta, with_Sigma=with_Sigma, with_dc=with_dc)
            G_latt_iw *= self.bz_weights[ik]
            for ish in range(self.n_shells):
                tmp = G_loc[ish].copy()
                for ir in range(self.n_parproj[ish]):
                    for bname, gf in tmp:
                        tmp[bname] << self.downfold(ik, ish, bname, G_latt_iw[
                                                    bname], gf, shells='all', ir=ir)
                    G_loc[ish] += tmp

        # Collect data from mpi:
        for ish in range(self.n_shells):
            G_loc[ish] << mpi.all_reduce(
                mpi.world, G_loc[ish], lambda x, y: x + y)
        mpi.barrier()

        # Symmetrize and rotate to local coord. system if needed:
        if self.symm_op != 0:
            G_loc = self.symmpar.symmetrize(G_loc)
        if self.use_rotations:
            for ish in range(self.n_shells):
                for bname, gf in G_loc[ish]:
                    G_loc[ish][bname] << self.rotloc(
                        ish, gf, direction='toLocal', shells='all')

        for ish in range(self.n_shells):
            isp = 0
            for bname, gf in G_loc[ish]:
                self.dens_mat_window[isp][ish] = G_loc[ish].density()[bname]
                isp += 1

        # Add density matrices to get the total:
        dens_mat = [[self.dens_mat_below[ntoi[spn[isp]]][ish] + self.dens_mat_window[isp][ish]
                     for ish in range(self.n_shells)]
                    for isp in range(len(spn))]

        return dens_mat
コード例 #15
0
    def dos_wannier_basis(self, mu=None, broadening=None, mesh=None, with_Sigma=True, with_dc=True, save_to_file=True):
        """
        Calculates the density of states in the basis of the Wannier functions.

        Parameters
        ----------
        mu : double, optional
             Chemical potential, overrides the one stored in the hdf5 archive.
        broadening : double, optional
                     Lorentzian broadening of the spectra. If not given, standard value of lattice_gf is used.
        mesh : real frequency MeshType, optional
               Omega mesh for the real-frequency Green's function. Given as parameter to lattice_gf.
        with_Sigma : boolean, optional
                     If True, the self energy is used for the calculation. If false, the DOS is calculated without self energy.
        with_dc : boolean, optional
                  If True the double counting correction is used.
        save_to_file : boolean, optional
                       If True, text files with the calculated data will be created.

        Returns
        -------
        DOS : Dict of numpy arrays
              Contains the full density of states.
        DOSproj :  Dict of numpy arrays
                   DOS projected to atoms.
        DOSproj_orb : Dict of numpy arrays
                      DOS projected to atoms and resolved into orbital contributions.
        """

        if (mesh is None) and (not with_Sigma):
            raise ValueError, "lattice_gf: Give the mesh=(om_min,om_max,n_points) for the lattice GfReFreq."
        if mesh is None:
            om_mesh = [x.real for x in self.Sigma_imp_w[0].mesh]
            om_min = om_mesh[0]
            om_max = om_mesh[-1]
            n_om = len(om_mesh)
            mesh = (om_min, om_max, n_om)
        else:
            om_min, om_max, n_om = mesh
            om_mesh = numpy.linspace(om_min, om_max, n_om)

        G_loc = []
        for icrsh in range(self.n_corr_shells):
            spn = self.spin_block_names[self.corr_shells[icrsh]['SO']]
            glist = [GfReFreq(indices=inner, window=(om_min, om_max), n_points=n_om)
                     for block, inner in self.gf_struct_sumk[icrsh]]
            G_loc.append(
                BlockGf(name_list=spn, block_list=glist, make_copies=False))
        for icrsh in range(self.n_corr_shells):
            G_loc[icrsh].zero()

        DOS = {sp: numpy.zeros([n_om], numpy.float_)
               for sp in self.spin_block_names[self.SO]}
        DOSproj = [{} for ish in range(self.n_inequiv_shells)]
        DOSproj_orb = [{} for ish in range(self.n_inequiv_shells)]
        for ish in range(self.n_inequiv_shells):
            for sp in self.spin_block_names[self.corr_shells[self.inequiv_to_corr[ish]]['SO']]:
                dim = self.corr_shells[self.inequiv_to_corr[ish]]['dim']
                DOSproj[ish][sp] = numpy.zeros([n_om], numpy.float_)
                DOSproj_orb[ish][sp] = numpy.zeros(
                    [n_om, dim, dim], numpy.complex_)

        ikarray = numpy.array(range(self.n_k))
        for ik in mpi.slice_array(ikarray):

            G_latt_w = self.lattice_gf(
                ik=ik, mu=mu, iw_or_w="w", broadening=broadening, mesh=mesh, with_Sigma=with_Sigma, with_dc=with_dc)
            G_latt_w *= self.bz_weights[ik]

            # Non-projected DOS
            for iom in range(n_om):
                for bname, gf in G_latt_w:
                    DOS[bname][iom] -= gf.data[iom, :, :].imag.trace() / \
                        numpy.pi

            # Projected DOS:
            for icrsh in range(self.n_corr_shells):
                tmp = G_loc[icrsh].copy()
                for bname, gf in tmp:
                    tmp[bname] << self.downfold(ik, icrsh, bname, G_latt_w[
                                                bname], gf)  # downfolding G
                G_loc[icrsh] += tmp

        # Collect data from mpi:
        for bname in DOS:
            DOS[bname] = mpi.all_reduce(
                mpi.world, DOS[bname], lambda x, y: x + y)
        for icrsh in range(self.n_corr_shells):
            G_loc[icrsh] << mpi.all_reduce(
                mpi.world, G_loc[icrsh], lambda x, y: x + y)
        mpi.barrier()

        # Symmetrize and rotate to local coord. system if needed:
        if self.symm_op != 0:
            G_loc = self.symmcorr.symmetrize(G_loc)
        if self.use_rotations:
            for icrsh in range(self.n_corr_shells):
                for bname, gf in G_loc[icrsh]:
                    G_loc[icrsh][bname] << self.rotloc(
                        icrsh, gf, direction='toLocal')

        # G_loc can now also be used to look at orbitally-resolved quantities
        for ish in range(self.n_inequiv_shells):
            for bname, gf in G_loc[self.inequiv_to_corr[ish]]:  # loop over spins
                for iom in range(n_om):
                    DOSproj[ish][bname][iom] -= gf.data[iom,
                                                        :, :].imag.trace() / numpy.pi
                DOSproj_orb[ish][bname][
                    :, :, :] += (1.0j*(gf-gf.conjugate().transpose())/2.0/numpy.pi).data[:,:,:]

        # Write to files
        if save_to_file and mpi.is_master_node():
            for sp in self.spin_block_names[self.SO]:
                f = open('DOS_wann_%s.dat' % sp, 'w')
                for iom in range(n_om):
                    f.write("%s    %s\n" % (om_mesh[iom], DOS[sp][iom]))
                f.close()

                # Partial
                for ish in range(self.n_inequiv_shells):
                    f = open('DOS_wann_%s_proj%s.dat' % (sp, ish), 'w')
                    for iom in range(n_om):
                        f.write("%s    %s\n" %
                                (om_mesh[iom], DOSproj[ish][sp][iom]))
                    f.close()

                    # Orbitally-resolved
                    for i in range(self.corr_shells[self.inequiv_to_corr[ish]]['dim']):
                        for j in range(i, self.corr_shells[self.inequiv_to_corr[ish]]['dim']):
                            f = open('DOS_wann_' + sp + '_proj' + str(ish) +
                                     '_' + str(i) + '_' + str(j) + '.dat', 'w')
                            for iom in range(n_om):
                                f.write("%s    %s    %s\n" % (
                                    om_mesh[iom], DOSproj_orb[ish][sp][iom, i, j].real,DOSproj_orb[ish][sp][iom, i, j].imag))
                            f.close()

        return DOS, DOSproj, DOSproj_orb
コード例 #16
0
    def spaghettis(self, broadening=None, plot_shift=0.0, plot_range=None, ishell=None, mu=None, save_to_file='Akw_'):
        """
        Calculates the correlated band structure using a real-frequency self energy.

        Parameters
        ----------
        mu : double, optional
             Chemical potential, overrides the one stored in the hdf5 archive.
        broadening : double, optional
                     Lorentzian broadening of the spectra. If not given, standard value of lattice_gf is used.
        plot_shift : double, optional
                     Offset for each A(k,w) for stacked plotting of spectra.
        plot_range : list of double, optional
                     Sets the energy window for plotting to (plot_range[0],plot_range[1]). If not provided, the energy mesh of the self energy is used.
        ishell : integer, optional
                 Contains the index of the shell on which the spectral function is projected. If ishell=None, the total spectrum without projection is calculated.
        save_to_file : string, optional
                       Filename where the spectra are stored.

        Returns
        -------
        Akw : Dict of numpy arrays
              Data as it is also written to the files.
        """

        assert hasattr(
            self, "Sigma_imp_w"), "spaghettis: Set Sigma_imp_w first."
        things_to_read = ['n_k', 'n_orbitals', 'proj_mat',
                          'hopping', 'n_parproj', 'proj_mat_all']
        value_read = self.read_input_from_hdf(
            subgrp=self.bands_data, things_to_read=things_to_read)
        if not value_read:
            return value_read
        if ishell is not None:
            things_to_read = ['rot_mat_all', 'rot_mat_all_time_inv']
            value_read = self.read_input_from_hdf(
                subgrp=self.parproj_data, things_to_read=things_to_read)
            if not value_read:
                return value_read

        if mu is None:
            mu = self.chemical_potential
        spn = self.spin_block_names[self.SO]
        mesh = [x.real for x in self.Sigma_imp_w[0].mesh]
        n_om = len(mesh)

        if plot_range is None:
            om_minplot = mesh[0] - 0.001
            om_maxplot = mesh[n_om - 1] + 0.001
        else:
            om_minplot = plot_range[0]
            om_maxplot = plot_range[1]

        if ishell is None:
            Akw = {sp: numpy.zeros([self.n_k, n_om], numpy.float_)
                   for sp in spn}
        else:
            Akw = {sp: numpy.zeros(
                [self.shells[ishell]['dim'], self.n_k, n_om], numpy.float_) for sp in spn}

        if not ishell is None:
            gf_struct_parproj = [
                (sp, range(self.shells[ishell]['dim'])) for sp in spn]
            G_loc = BlockGf(name_block_generator=[(block, GfReFreq(indices=inner, mesh=self.Sigma_imp_w[0].mesh))
                                                  for block, inner in gf_struct_parproj], make_copies=False)
            G_loc.zero()

        ikarray = numpy.array(range(self.n_k))
        for ik in mpi.slice_array(ikarray):

            G_latt_w = self.lattice_gf(
                ik=ik, mu=mu, iw_or_w="w", broadening=broadening)

            if ishell is None:
                # Non-projected A(k,w)
                for iom in range(n_om):
                    if (mesh[iom] > om_minplot) and (mesh[iom] < om_maxplot):
                        for bname, gf in G_latt_w:
                            Akw[bname][ik, iom] += gf.data[iom, :,
                                                           :].imag.trace() / (-1.0 * numpy.pi)
                        # shift Akw for plotting stacked k-resolved eps(k)
                        # curves
                        Akw[bname][ik, iom] += ik * plot_shift

            else:  # ishell not None
                # Projected A(k,w):
                G_loc.zero()
                tmp = G_loc.copy()
                for ir in range(self.n_parproj[ishell]):
                    for bname, gf in tmp:
                        tmp[bname] << self.downfold(ik, ishell, bname, G_latt_w[
                                                    bname], gf, shells='all', ir=ir)
                    G_loc += tmp

                # Rotate to local frame
                if self.use_rotations:
                    for bname, gf in G_loc:
                        G_loc[bname] << self.rotloc(
                            ishell, gf, direction='toLocal', shells='all')

                for iom in range(n_om):
                    if (mesh[iom] > om_minplot) and (mesh[iom] < om_maxplot):
                        for ish in range(self.shells[ishell]['dim']):
                            for sp in spn:
                                Akw[sp][ish, ik, iom] = G_loc[sp].data[
                                    iom, ish, ish].imag / (-1.0 * numpy.pi)

        # Collect data from mpi
        for sp in spn:
            Akw[sp] = mpi.all_reduce(mpi.world, Akw[sp], lambda x, y: x + y)
        mpi.barrier()

        if save_to_file and mpi.is_master_node():
            if ishell is None:
                for sp in spn:  # loop over GF blocs:
                    # Open file for storage:
                    f = open(save_to_file + sp + '.dat', 'w')
                    for ik in range(self.n_k):
                        for iom in range(n_om):
                            if (mesh[iom] > om_minplot) and (mesh[iom] < om_maxplot):
                                if plot_shift > 0.0001:
                                    f.write('%s      %s\n' %
                                            (mesh[iom], Akw[sp][ik, iom]))
                                else:
                                    f.write('%s     %s      %s\n' %
                                            (ik, mesh[iom], Akw[sp][ik, iom]))
                        f.write('\n')
                    f.close()

            else:  # ishell is not None
                for sp in spn:
                    for ish in range(self.shells[ishell]['dim']):
                        # Open file for storage:
                        f = open(save_to_file + str(ishell) + '_' +
                                 sp + '_proj' + str(ish) + '.dat', 'w')
                        for ik in range(self.n_k):
                            for iom in range(n_om):
                                if (mesh[iom] > om_minplot) and (mesh[iom] < om_maxplot):
                                    if plot_shift > 0.0001:
                                        f.write('%s      %s\n' % (
                                            mesh[iom], Akw[sp][ish, ik, iom]))
                                    else:
                                        f.write('%s     %s      %s\n' % (
                                            ik, mesh[iom], Akw[sp][ish, ik, iom]))
                            f.write('\n')
                        f.close()

        return Akw
コード例 #17
0
ファイル: sumk_dft_tools.py プロジェクト: krivenko/dft_tools
    def transport_distribution(self, beta, directions=['xx'], energy_window=None, Om_mesh=[0.0], with_Sigma=False, n_om=None, broadening=0.0):
        r"""
        Calculates the transport distribution 

        .. math::
           \Gamma_{\alpha\beta}\left(\omega+\Omega/2, \omega-\Omega/2\right) = \frac{1}{V} \sum_k Tr\left(v_{k,\alpha}A_{k}(\omega+\Omega/2)v_{k,\beta}A_{k}\left(\omega-\Omega/2\right)\right)

        in the direction :math:`\alpha\beta`. The velocities :math:`v_{k}` are read from the transport subgroup of the hdf5 archive. 

        Parameters
        ----------

        beta : double
            Inverse temperature :math:`\beta`.
        directions : list of double, optional
            :math:`\alpha\beta` e.g.: ['xx','yy','zz','xy','xz','yz'].
        energy_window : list of double, optional
            Specifies the upper and lower limit of the frequency integration for :math:`\Omega=0.0`. The window is automatically enlarged by the largest :math:`\Omega` value, 
            hence the integration is performed in the interval [energy_window[0]-max(Om_mesh), energy_window[1]+max(Om_mesh)].
        Om_mesh : list of double, optional
            :math:`\Omega` frequency mesh of the optical conductivity. For the conductivity and the Seebeck coefficient :math:`\Omega=0.0` has to be
            part of the mesh. In the current version Om_mesh is repined to the mesh provided by the self-energy! The actual mesh is printed on the screen and stored as
            member Om_mesh.
        with_Sigma : boolean, optional
            Determines whether the calculation is performed with or without self energy. If this parameter is set to False the self energy is set to zero (i.e. the DFT band 
            structure :math:`A(k,\omega)` is used). Note: For with_Sigma=False it is necessary to specify the parameters energy_window, n_om and broadening.
        n_om : integer, optional
            Number of equidistant frequency points in the interval [energy_window[0]-max(Om_mesh), energy_window[1]+max(Om_mesh)]. This parameters is only used if
            with_Sigma = False.
        broadening : double, optional
            Lorentzian broadening. It is necessary to specify the boradening if with_Sigma = False, otherwise this parameter can be set to 0.0.
        """

        # Check if wien converter was called and read transport subgroup form
        # hdf file
        if mpi.is_master_node():
            ar = HDFArchive(self.hdf_file, 'r')
            if not (self.transp_data in ar):
                raise IOError, "transport_distribution: No %s subgroup in hdf file found! Call convert_transp_input first." % self.transp_data
            # check if outputs file was converted
            if not ('n_symmetries' in ar['dft_misc_input']):
                raise IOError,  "transport_distribution: n_symmetries missing. Check if case.outputs file is present and call convert_misc_input() or convert_dft_input()."

        self.read_transport_input_from_hdf()

        if mpi.is_master_node():
            # k-dependent-projections.
            assert self.k_dep_projection == 1, "transport_distribution: k dependent projection is not implemented!"
            # positive Om_mesh
            assert all(
                Om >= 0.0 for Om in Om_mesh), "transport_distribution: Om_mesh should not contain negative values!"

        # Check if energy_window is sufficiently large and correct

        if (energy_window[0] >= energy_window[1] or energy_window[0] >= 0 or energy_window[1] <= 0):
            assert 0, "transport_distribution: energy_window wrong!"

        if (abs(self.fermi_dis(energy_window[0], beta) * self.fermi_dis(-energy_window[0], beta)) > 1e-5
                or abs(self.fermi_dis(energy_window[1], beta) * self.fermi_dis(-energy_window[1], beta)) > 1e-5):
            mpi.report(
                "\n####################################################################")
            mpi.report(
                "transport_distribution: WARNING - energy window might be too narrow!")
            mpi.report(
                "####################################################################\n")

        # up and down are equivalent if SP = 0
        n_inequiv_spin_blocks = self.SP + 1 - self.SO
        self.directions = directions
        dir_to_int = {'x': 0, 'y': 1, 'z': 2}

        # calculate A(k,w)
        #######################################

        # Define mesh for Green's function and in the specified energy window
        if (with_Sigma == True):
            self.omega = numpy.array([round(x.real, 12)
                                      for x in self.Sigma_imp_w[0].mesh])
            mesh = None
            mu = self.chemical_potential
            n_om = len(self.omega)
            mpi.report("Using omega mesh provided by Sigma!")

            if energy_window is not None:
                # Find according window in Sigma mesh
                ioffset = numpy.sum(
                    self.omega < energy_window[0] - max(Om_mesh))
                self.omega = self.omega[numpy.logical_and(self.omega >= energy_window[
                                                          0] - max(Om_mesh), self.omega <= energy_window[1] + max(Om_mesh))]
                n_om = len(self.omega)

                # Truncate Sigma to given omega window
                # In the future there should be an option in gf to manipulate the mesh (e.g. truncate) directly.
                # For now we stick with this:
                for icrsh in range(self.n_corr_shells):
                    Sigma_save = self.Sigma_imp_w[icrsh].copy()
                    spn = self.spin_block_names[self.corr_shells[icrsh]['SO']]
                    glist = lambda: [GfReFreq(indices=inner, window=(self.omega[
                                              0], self.omega[-1]), n_points=n_om) for block, inner in self.gf_struct_sumk[icrsh]]
                    self.Sigma_imp_w[icrsh] = BlockGf(
                        name_list=spn, block_list=glist(), make_copies=False)
                    for i, g in self.Sigma_imp_w[icrsh]:
                        for iL in g.indices:
                            for iR in g.indices:
                                for iom in xrange(n_om):
                                    g.data[iom, iL, iR] = Sigma_save[
                                        i].data[ioffset + iom, iL, iR]
        else:
            assert n_om is not None, "transport_distribution: Number of omega points (n_om) needed to calculate transport distribution!"
            assert energy_window is not None, "transport_distribution: Energy window needed to calculate transport distribution!"
            assert broadening != 0.0 and broadening is not None, "transport_distribution: Broadening necessary to calculate transport distribution!"
            self.omega = numpy.linspace(
                energy_window[0] - max(Om_mesh), energy_window[1] + max(Om_mesh), n_om)
            mesh = [energy_window[0] -
                    max(Om_mesh), energy_window[1] + max(Om_mesh), n_om]
            mu = 0.0

        # Define mesh for optic conductivity
        d_omega = round(numpy.abs(self.omega[0] - self.omega[1]), 12)
        iOm_mesh = numpy.array([round((Om / d_omega), 0) for Om in Om_mesh])
        self.Om_mesh = iOm_mesh * d_omega

        if mpi.is_master_node():
            print "Chemical potential: ", mu
            print "Using n_om = %s points in the energy_window [%s,%s]" % (n_om, self.omega[0], self.omega[-1]),
            print "where the omega vector is:"
            print self.omega
            print "Calculation requested for Omega mesh:   ", numpy.array(Om_mesh)
            print "Omega mesh automatically repined to:  ", self.Om_mesh

        self.Gamma_w = {direction: numpy.zeros(
            (len(self.Om_mesh), n_om), dtype=numpy.float_) for direction in self.directions}

        # Sum over all k-points
        ikarray = numpy.array(range(self.n_k))
        for ik in mpi.slice_array(ikarray):
            # Calculate G_w  for ik and initialize A_kw
            G_w = self.lattice_gf(ik, mu, iw_or_w="w", beta=beta,
                                  broadening=broadening, mesh=mesh, with_Sigma=with_Sigma)
            A_kw = [numpy.zeros((self.n_orbitals[ik][isp], self.n_orbitals[ik][isp], n_om), dtype=numpy.complex_)
                    for isp in range(n_inequiv_spin_blocks)]

            for isp in range(n_inequiv_spin_blocks):
                # copy data from G_w (swapaxes is used to have omega in the 3rd
                # dimension)
                A_kw[isp] = copy.deepcopy(G_w[self.spin_block_names[self.SO][
                                          isp]].data.swapaxes(0, 1).swapaxes(1, 2))
                # calculate A(k,w) for each frequency
                for iw in xrange(n_om):
                    A_kw[isp][:, :, iw] = -1.0 / (2.0 * numpy.pi * 1j) * (
                        A_kw[isp][:, :, iw] - numpy.conjugate(numpy.transpose(A_kw[isp][:, :, iw])))

                b_min = max(self.band_window[isp][
                            ik, 0], self.band_window_optics[isp][ik, 0])
                b_max = min(self.band_window[isp][
                            ik, 1], self.band_window_optics[isp][ik, 1])
                A_i = slice(
                    b_min - self.band_window[isp][ik, 0], b_max - self.band_window[isp][ik, 0] + 1)
                v_i = slice(b_min - self.band_window_optics[isp][
                            ik, 0], b_max - self.band_window_optics[isp][ik, 0] + 1)

                # loop over all symmetries
                for R in self.rot_symmetries:
                    # get transformed velocity under symmetry R
                    vel_R = copy.deepcopy(self.velocities_k[isp][ik])
                    for nu1 in range(self.band_window_optics[isp][ik, 1] - self.band_window_optics[isp][ik, 0] + 1):
                        for nu2 in range(self.band_window_optics[isp][ik, 1] - self.band_window_optics[isp][ik, 0] + 1):
                            vel_R[nu1][nu2][:] = numpy.dot(
                                R, vel_R[nu1][nu2][:])

                    # calculate Gamma_w for each direction from the velocities
                    # vel_R and the spectral function A_kw
                    for direction in self.directions:
                        for iw in xrange(n_om):
                            for iq in range(len(self.Om_mesh)):
                                if(iw + iOm_mesh[iq] >= n_om or self.omega[iw] < -self.Om_mesh[iq] + energy_window[0] or self.omega[iw] > self.Om_mesh[iq] + energy_window[1]):
                                    continue

                                self.Gamma_w[direction][iq, iw] += (numpy.dot(numpy.dot(numpy.dot(vel_R[v_i, v_i, dir_to_int[direction[0]]],
                                                                                                  A_kw[isp][A_i, A_i, iw + iOm_mesh[iq]]), vel_R[v_i, v_i, dir_to_int[direction[1]]]),
                                                                              A_kw[isp][A_i, A_i, iw]).trace().real * self.bz_weights[ik])

        for direction in self.directions:
            self.Gamma_w[direction] = (mpi.all_reduce(mpi.world, self.Gamma_w[direction], lambda x, y: x + y)
                                       / self.cellvolume(self.lattice_type, self.lattice_constants, self.lattice_angles)[1] / self.n_symmetries)
コード例 #18
0
ファイル: sumk_lda.py プロジェクト: boujnah-mourad/dft_tools
    def extract_G_loc(self, mu=None, with_Sigma = 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 with_Sigma = False: Sigma is not included => non-interacting local GF
        """

        if (mu is None): mu = self.chemical_potential
            
        Gloc = [ self.Sigma_imp[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
        beta = Gloc[0].mesh.beta
        
        ikarray=numpy.array(range(self.n_k))
        
        for ik in mpi.slice_array(ikarray):
            
            S = self.lattice_gf_matsubara(ik=ik,mu=mu,with_Sigma = with_Sigma, beta = beta) 
            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.symmetrize(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 = [ BlockGf( name_block_generator = [ (a,GfImFreq(indices = al, mesh = Gloc[0].mesh)) for a,al in self.gf_struct_solver[i] ],
                        make_copies = False) for i in xrange(self.n_inequiv_corr_shells)  ]
        for ish in xrange(self.n_inequiv_corr_shells):

            # setting up the index map:
            map_ind={}
            cnt = {}
            for blname in self.map[ish]:
                cnt[blname] = 0
    
            for a,al in self.gf_struct_solver[ish]:
                blname = self.map_inv[ish][a]
                map_ind[a] = range(len(al))
                for i in al:
                    map_ind[a][i] = cnt[blname]
                    cnt[blname]+=1
            
            
            for ibl in range(len(self.gf_struct_solver[ish])):
                for i in range(len(self.gf_struct_solver[ish][ibl][1])):
                    for j in range(len(self.gf_struct_solver[ish][ibl][1])):
                        bl   = self.gf_struct_solver[ish][ibl][0]
                        ind1 = self.gf_struct_solver[ish][ibl][1][i]
                        ind2 = self.gf_struct_solver[ish][ibl][1][j]
                        ind1_imp = map_ind[bl][ind1]
                        ind2_imp = map_ind[bl][ind2]
                        Glocret[ish][bl][ind1,ind2] <<= Gloc[self.invshellmap[ish]][self.map_inv[ish][bl]][ind1_imp,ind2_imp]


        # return only the inequivalent shells:
        return Glocret
コード例 #19
0
def get_G_w_from_A_w(A_w,
                     w_points,
                     np_interp_A=None,
                     np_omega=2000,
                     w_min=-10,
                     w_max=10,
                     broadening_factor=1.0):
    r""" Use Kramers-Kronig to determine the retarded Green function :math:`G(\omega)`

    This calculates :math:`G(\omega)` from the spectral function :math:`A(\omega)`.
    A numerical broadening of :math:`bf * i\Delta\omega`
    is used, with the adjustable broadening factor bf (default is 1).
    This function normalizes :math:`A(\omega)`.
    Use mpi to save time.

    Parameters
    ----------
    A_w : array
        Real-frequency spectral function.
    w_points : array
        Real-frequency grid points.
    np_interp_A : int
        Number of grid points A_w should be interpolated on before
        G_w is calculated. The interpolation is performed on a linear
        grid with np_interp_A points from min(w_points) to max(w_points).
    np_omega : int
        Number of equidistant grid points of the output Green function.
    w_min : float
        Start point of output Green function.
    w_max : float
        End point of output Green function.
    broadening_factor : float
        Factor multiplying the broadening :math:`i\Delta\omega`

    Returns
    -------
    G_w : GfReFreq
        TRIQS retarded Green function.
    """

    shape_A = np.shape(A_w)

    if len(shape_A) == 1:
        indices = [0]
        matrix_valued = False
    elif (len(shape_A) == 3) and (shape_A[0] == shape_A[1]):
        indices = range(0, shape_A[0])
        matrix_valued = True
    else:
        raise Exception('A_w has wrong shape, must be n x n x n_w')

    if w_min > w_max:
        raise Exception('w_min must be smaller than w_max')

    if np_interp_A:
        w_points_interp = np.linspace(np.min(w_points),
                                      np.max(w_points), np_interp_A)
        if matrix_valued:
            for i in range(shape_A[0]):
                for j in range(shape_A[1]):
                    A_w[i, j, :] = np.interp(w_points_interp,
                                             w_points, A_w[i, j, :])
        else:
            A_w = np.interp(w_points_interp, w_points, A_w)
        w_points = w_points_interp

    G_w = GfReFreq(indices=indices, window=(w_min, w_max), n_points=np_omega)
    G_w.zero()

    iw_points = np.array(range(len(w_points)))

    for iw in mpi.slice_array(iw_points):
        domega = (w_points[min(len(w_points) - 1, iw + 1)] -
                  w_points[max(0, iw - 1)]) * 0.5
        if matrix_valued:
            for i in range(shape_A[0]):
                for j in range(shape_A[1]):
                    G_w[i, j] << G_w[i, j] + A_w[i, j, iw] * \
                        inverse(Omega - w_points[iw] + 1j * domega * broadening_factor) * domega
        else:
            G_w << G_w + A_w[iw] * \
                inverse(Omega - w_points[iw] + 1j * domega * broadening_factor) * domega

    G_w << mpi.all_reduce(mpi.world, G_w, lambda x, y: x + y)
    mpi.barrier()

    return G_w
コード例 #20
0
    def dos_partial(self,broadening=0.01):
        """calculates the orbitally-resolved DOS"""

        assert hasattr(self,"Sigma_imp"), "Set Sigma First!!"

        #thingstoread = ['Dens_Mat_below','N_parproj','Proj_Mat_pc','rotmat_all']
        #retval = self.read_input_from_HDF(SubGrp=self.par_proj_data, thingstoread=thingstoread)
        retval = self.read_par_proj_input_from_hdf()
        if not retval: return retval
        if self.symm_op: self.Symm_par = Symmetry(self.hdf_file,subgroup=self.symm_par_data)

        mu = self.chemical_potential

        gf_struct_proj = [ [ (al, range(self.shells[i][3])) for al in self.block_names[self.SO] ]  for i in xrange(self.n_shells) ]
        Gproj = [BlockGf(name_block_generator = [ (a,GfReFreq(indices = al, mesh = self.Sigma_imp[0].mesh)) for a,al in gf_struct_proj[ish] ], make_copies = False ) 
                 for ish in xrange(self.n_shells)]
        for ish in range(self.n_shells): Gproj[ish].zero()

        Msh = [x for x in self.Sigma_imp[0].mesh]
        n_om = len(Msh)

        DOS = {}
        for bn in self.block_names[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.block_names[self.SO]:
                dl = self.shells[ish][3]
                DOSproj[ish][bn] = numpy.zeros([n_om],numpy.float_)
                DOSproj_orb[ish][bn] = numpy.zeros([n_om,dl,dl],numpy.float_)

        ikarray=numpy.array(range(self.n_k))

        for ik in mpi.slice_array(ikarray):

            S = self.lattice_gf_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[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.symmetrize(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[iom,:,:].imag.trace()/(-3.1415926535)
                DOSproj_orb[ish][sig][:,:,:] += gf.data[:,:,:].imag / (-3.1415926535)
	    

        if (mpi.is_master_node()):
            # output to files
            for bn in self.block_names[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][iom,i,j]))
                            f.close()
コード例 #21
0
ファイル: sumk_lda_tools.py プロジェクト: lwk205/dft_tools
    def partial_charges(self, beta=40):
        """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.par_proj_data,thingstoread=thingstoread)
        retval = self.read_par_proj_input_from_hdf()
        if not retval: return retval
        if self.symm_op:
            self.Symm_par = Symmetry(self.hdf_file,
                                     subgroup=self.symm_par_data)

        # Density matrix in the window
        bln = self.block_names[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, "Sigma_imp"):
            Gproj = [
                BlockGf(name_block_generator=[
                    (a, GfImFreq(indices=al, mesh=self.Sigma_imp[0].mesh))
                    for a, al in GFStruct_proj[ish]
                ],
                        make_copies=False) for ish in xrange(self.n_shells)
            ]
            beta = self.Sigma_imp[0].mesh.beta
        else:
            Gproj = [
                BlockGf(name_block_generator=[(a,
                                               GfImFreq(indices=al, beta=beta))
                                              for a, al in GFStruct_proj[ish]],
                        make_copies=False) for ish in xrange(self.n_shells)
            ]

        for ish in xrange(self.n_shells):
            Gproj[ish].zero()

        ikarray = numpy.array(range(self.n_k))
        #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.lattice_gf_matsubara(ik=ik, mu=mu, beta=beta)
            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.symmetrize(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
コード例 #22
0
ファイル: sumk_discrete.py プロジェクト: TRIQS/triqs
    def __call__ (self, Sigma, mu=0, eta=0, field=None, epsilon_hat=None, result=None, selected_blocks=()):
	"""
	- Computes:
	   result <- \[ \sum_k (\omega + \mu - field - t(k) - Sigma(k,\omega)) \]
           if result is None, it returns a new GF with the results.
           otherwise, result must be a GF, in which the calculation is done, and which is then returned.
           (this allows chain calculation: SK(mu = mu,Sigma = Sigma, result = 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 selected_blocks.
	      e.g. X can be a BlockGf(with at least the selected_blocks), 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

        - selected_blocks: 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 selected_blocks ==None: 'up' and 'down' are calculated
	       if selected_blocks == ['up']: only 'up' is calculated. 'down' is 0.


        """

        assert selected_blocks == (), "selected_blocks not supported for now"
            #S = Sigma.view_selected_blocks(selected_blocks) if selected_blocks else Sigma
            #Gres = result if result else Sigma.copy()
            #G = Gres.view_selected_blocks(selected_blocks) if selected_blocks else Gres

        # check Sigma
        # case 1) Sigma is a BlockGf
        if isinstance(Sigma, BlockGf):
            model = Sigma
            Sigma_fnt = False
        # case 2) Sigma is a function returning a BlockGf
        else:
            assert callable(Sigma), "If Sigma is not a BlockGf it must be a function"
            Sigma_Nargs = len(inspect.getargspec(Sigma)[0])
            assert Sigma_Nargs <= 2, "Sigma must be a function of k or of k and epsilon"
            if Sigma_Nargs == 1:
                model = Sigma(self.bz_points[0])
            elif Sigma_Nargs == 2:
                model = Sigma(self.bz_points[0], self.hopping[0])
            Sigma_fnt = True

        G = result if result else model.copy()
        assert isinstance(G,BlockGf), "G must be a BlockGf"

        # check input
        assert self.orthogonal_basis, "Local_G: must be orthogonal. non ortho cases not checked."
        assert len(list(set([g.target_shape[0] for i,g in G]))) == 1
        assert self.bz_weights.shape[0] == self.n_kpts(), "Internal Error"
        no = list(set([g.target_shape[0] for i,g in G]))[0]

        # 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 not Sigma_fnt: 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.n_blocks * [eps_hat - mupat]

            if Sigma_fnt:
                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 G
コード例 #23
0
    def partial_charges(self,beta=40):
        """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.par_proj_data,thingstoread=thingstoread)
        retval = self.read_par_proj_input_from_hdf()
        if not retval: return retval
        if self.symm_op: self.Symm_par = Symmetry(self.hdf_file,subgroup=self.symm_par_data)
        
        # Density matrix in the window
        bln = self.block_names[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,"Sigma_imp"):
            Gproj = [BlockGf(name_block_generator = [ (a,GfImFreq(indices = al, mesh = self.Sigma_imp[0].mesh)) for a,al in GFStruct_proj[ish] ], make_copies = False)
                     for ish in xrange(self.n_shells)]
            beta = self.Sigma_imp[0].mesh.beta
        else:
            Gproj = [BlockGf(name_block_generator = [ (a,GfImFreq(indices = al, beta = beta)) for a,al in GFStruct_proj[ish] ], make_copies = False)
                     for ish in xrange(self.n_shells)]

        for ish in xrange(self.n_shells): Gproj[ish].zero()

        ikarray=numpy.array(range(self.n_k))
        #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.lattice_gf_matsubara(ik=ik,mu=mu,beta=beta)
            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.symmetrize(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
コード例 #24
0
ファイル: sumk_dft_tools.py プロジェクト: krivenko/dft_tools
    def partial_charges(self, beta=40, mu=None, with_Sigma=True, with_dc=True):
        """
        Calculates the orbitally-resolved density matrix for all the orbitals considered in the input, consistent with
        the definition of Wien2k. Hence, (possibly non-orthonormal) projectors have to be provided in the partial projectors subgroup of
        the hdf5 archive.

        Parameters
        ----------

        with_Sigma : boolean, optional
                     If True, the self energy is used for the calculation. If false, partial charges are calculated without self-energy correction.
        beta : double, optional
               In case the self-energy correction is not used, the inverse temperature where the calculation should be done has to be given here.
        mu : double, optional
             Chemical potential, overrides the one stored in the hdf5 archive.
        with_dc : boolean, optional
                  If True the double counting correction is used.

        Returns
        -------
        dens_mat : list of numpy array
                   A list of density matrices projected to all shells provided in the input.
        """

        things_to_read = ['dens_mat_below', 'n_parproj',
                          'proj_mat_all', 'rot_mat_all', 'rot_mat_all_time_inv']
        value_read = self.read_input_from_hdf(
            subgrp=self.parproj_data, things_to_read=things_to_read)
        if not value_read:
            return value_read
        if self.symm_op:
            self.symmpar = Symmetry(self.hdf_file, subgroup=self.symmpar_data)

        spn = self.spin_block_names[self.SO]
        ntoi = self.spin_names_to_ind[self.SO]
        # Density matrix in the window
        self.dens_mat_window = [[numpy.zeros([self.shells[ish]['dim'], self.shells[ish]['dim']], numpy.complex_)
                                 for ish in range(self.n_shells)]
                                for isp in range(len(spn))]
        # Set up G_loc
        gf_struct_parproj = [[(sp, range(self.shells[ish]['dim'])) for sp in spn]
                             for ish in range(self.n_shells)]
        if with_Sigma:
            G_loc = [BlockGf(name_block_generator=[(block, GfImFreq(indices=inner, mesh=self.Sigma_imp_iw[0].mesh))
                                                   for block, inner in gf_struct_parproj[ish]], make_copies=False)
                     for ish in range(self.n_shells)]
            beta = self.Sigma_imp_iw[0].mesh.beta
        else:
            G_loc = [BlockGf(name_block_generator=[(block, GfImFreq(indices=inner, beta=beta))
                                                   for block, inner in gf_struct_parproj[ish]], make_copies=False)
                     for ish in range(self.n_shells)]
        for ish in range(self.n_shells):
            G_loc[ish].zero()

        ikarray = numpy.array(range(self.n_k))
        for ik in mpi.slice_array(ikarray):

            G_latt_iw = self.lattice_gf(
                ik=ik, mu=mu, iw_or_w="iw", beta=beta, with_Sigma=with_Sigma, with_dc=with_dc)
            G_latt_iw *= self.bz_weights[ik]
            for ish in range(self.n_shells):
                tmp = G_loc[ish].copy()
                for ir in range(self.n_parproj[ish]):
                    for bname, gf in tmp:
                        tmp[bname] << self.downfold(ik, ish, bname, G_latt_iw[
                                                    bname], gf, shells='all', ir=ir)
                    G_loc[ish] += tmp

        # Collect data from mpi:
        for ish in range(self.n_shells):
            G_loc[ish] << mpi.all_reduce(
                mpi.world, G_loc[ish], lambda x, y: x + y)
        mpi.barrier()

        # Symmetrize and rotate to local coord. system if needed:
        if self.symm_op != 0:
            G_loc = self.symmpar.symmetrize(G_loc)
        if self.use_rotations:
            for ish in range(self.n_shells):
                for bname, gf in G_loc[ish]:
                    G_loc[ish][bname] << self.rotloc(
                        ish, gf, direction='toLocal', shells='all')

        for ish in range(self.n_shells):
            isp = 0
            for bname, gf in G_loc[ish]:
                self.dens_mat_window[isp][ish] = G_loc[ish].density()[bname]
                isp += 1

        # Add density matrices to get the total:
        dens_mat = [[self.dens_mat_below[ntoi[spn[isp]]][ish] + self.dens_mat_window[isp][ish]
                     for ish in range(self.n_shells)]
                    for isp in range(len(spn))]

        return dens_mat
コード例 #25
0
def mpi_op_comb(op_list, repeat=2):

    work_list = list(itertools.product(enumerate(op_list), repeat=repeat))
    work_list = mpi.slice_array(np.array(work_list))

    return work_list
    def __call__ (self, Sigma, mu=0, eta=0, field=None, epsilon_hat=None, result=None, selected_blocks=()):
	"""
	- Computes:
	   result <- \[ \sum_k (\omega + \mu - field - t(k) - Sigma(k,\omega)) \]
           if result is None, it returns a new GF with the results.
           otherwise, result must be a GF, in which the calculation is done, and which is then returned.
           (this allows chain calculation: SK(mu = mu,Sigma = Sigma, result = 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 selected_blocks.
	      e.g. X can be a BlockGf(with at least the selected_blocks), 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

        - selected_blocks: 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 selected_blocks ==None: 'up' and 'down' are calculated
	       if selected_blocks == ['up']: only 'up' is calculated. 'down' is 0.


        """

        assert selected_blocks == (), "selected_blocks not supported for now"
            #S = Sigma.view_selected_blocks(selected_blocks) if selected_blocks else Sigma
            #Gres = result if result else Sigma.copy()
            #G = Gres.view_selected_blocks(selected_blocks) if selected_blocks else Gres

        # check Sigma
        # case 1) Sigma is a BlockGf
        if isinstance(Sigma, BlockGf):
            model = Sigma
            Sigma_fnt = False
        # case 2) Sigma is a function returning a BlockGf
        else:
            assert callable(Sigma), "If Sigma is not a BlockGf it must be a function"
            Sigma_Nargs = len(inspect.getargspec(Sigma)[0])
            assert Sigma_Nargs <= 2, "Sigma must be a function of k or of k and epsilon"
            if Sigma_Nargs == 1:
                model = Sigma(self.bz_points[0])
            elif Sigma_Nargs == 2:
                model = Sigma(self.bz_points[0], self.hopping[0])
            Sigma_fnt = True

        G = result if result else model.copy()
        assert isinstance(G,BlockGf), "G must be a BlockGf"

        # check input
        assert self.orthogonal_basis, "Local_G: must be orthogonal. non ortho cases not checked."
        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]

        # 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 not Sigma_fnt: 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.n_blocks * [eps_hat - mupat]

            if Sigma_fnt:
                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 G