コード例 #1
0
def total_energy(h, nk=10, nbands=None, use_kpm=False, random=True, kp=None):
    """Return the total energy"""
    if h.is_sparse and not use_kpm:
        print("Sparse Hamiltonian but no bands given, taking 20")
        nbands = 20
    from klist import kmesh
    if kp is None:  # no kpoints given
        kp = kmesh(h.dimensionality, nk=nk)
        if random == True:  # random k-mesh
            kp = [np.random.random(3) for k in kp]
    f = h.get_hk_gen()  # get generator
    etot = 0.0  # initialize
    iv = 0
    for k in kp:  # loop over kpoints
        hk = f(k)  # kdependent hamiltonian
        if use_kpm:  # Kernel polynomial method
            etot += kpm.total_energy(hk, scale=10., ntries=20,
                                     npol=100)  # using KPM
        else:  # conventional diagonalization
            if nbands is None:
                vv = lg.eigvalsh(hk)  # diagonalize k hamiltonian
            else:
                vv, aa = slg.eigsh(hk, k=nbands, which="LM", sigma=0.0)
            etot += np.sum(vv[vv < 0.0])  # sum energies below fermi energy
    etot = etot / len(kp)  # normalize
    return etot
コード例 #2
0
def ldos2d(h,
           e=0.0,
           delta=0.001,
           nrep=3,
           nk=None,
           mode="green",
           random=True,
           num_wf=20):
    """ Calculate DOS for a 2d system"""
    if mode == "green":
        import green
        if h.dimensionality != 2: raise  # only for 1d
        if nk is not None:
            print("LDOS using normal integration with nkpoints", nk)
            gb, gs = green.bloch_selfenergy(h,
                                            energy=e,
                                            delta=delta,
                                            mode="full",
                                            nk=nk)
            d = [-(gb[i, i]).imag
                 for i in range(len(gb))]  # get imaginary part
        else:
            print("LDOS using renormalization adaptative Green function")
            gb, gs = green.bloch_selfenergy(h,
                                            energy=e,
                                            delta=delta,
                                            mode="adaptive")
            d = [-(gb[i, i]).imag
                 for i in range(len(gb))]  # get imaginary part
    elif mode == "arpack":  # arpack diagonalization
        import klist
        if nk is None: nk = 10
        hkgen = h.get_hk_gen()  # get generator
        ds = []  # empty list
        for k in klist.kmesh(h.dimensionality, nk=nk):  # loop over kpoints
            print("Doing", k)
            if random:
                print("Random k-point")
                k = np.random.random(3)  # random k-point
            hk = csc_matrix(hkgen(k))  # get Hamiltonian
            ds += [
                ldos_arpack(hk,
                            num_wf=num_wf,
                            robust=False,
                            tol=0,
                            e=e,
                            delta=delta)
            ]
        d = ds[0] * 0.0  # inititlize
        for di in ds:
            d += di  # add
        d /= len(ds)  # normalize
    d = spatial_dos(h, d)  # convert to spatial resolved DOS
    g = h.geometry  # store geometry
    x, y = g.x, g.y  # get the coordinates
    go = h.geometry.copy()  # copy geometry
    go = go.supercell(nrep)  # create supercell
    write_ldos(go.x, go.y, d.tolist() * (nrep**2), z=go.z)  # write in file
コード例 #3
0
def multi_ldos(h, es=[0.0], delta=0.001, nrep=3, nk=2, numw=3, random=False):
    """Calculate many LDOS, by diagonalizing the Hamiltonian"""
    print("Calculating eigenvectors in LDOS")
    if h.is_sparse:  # sparse Hamiltonian
        from bandstructure import smalleig
        print("SPARSE Matrix")
        evals, ws = [], []  # empty list
        ks = klist.kmesh(h.dimensionality, nk=nk)  # get grid
        hk = h.get_hk_gen()  # get generator
        for k in ks:  # loop
            print("Diagonalizing in LDOS, SPARSE mode")
            if random:
                k = np.random.random(3)  # random vector
                print("RANDOM vector in LDOS")
            e, w = smalleig(hk(k), numw=numw, evecs=True)
            evals += [ie for ie in e]
            ws += [iw for iw in w]


#      evals = np.concatenate([evals,e]) # store
#      ws = np.concatenate([ws,w]) # store
#    raise
#    (evals,ws) = h.eigenvectors(nk) # get the different eigenvectors
    else:
        print("DENSE Matrix")
        (evals, ws) = h.eigenvectors(nk)  # get the different eigenvectors
    ds = [(np.conjugate(v) * v).real for v in ws]  # calculate densities
    del ws  # remove the wavefunctions
    os.system("rm -rf MULTILDOS")  # remove folder
    os.system("mkdir MULTILDOS")  # create folder
    go = h.geometry.copy()  # copy geometry
    go = go.supercell(nrep)  # create supercell
    fo = open("MULTILDOS/MULTILDOS.TXT", "w")  # files with the names
    for e in es:  # loop over energies
        print("MULTILDOS for energy", e)
        out = np.array([0.0 for i in range(h.intra.shape[0])])  # initialize
        for (d, ie) in zip(ds, evals):  # loop over wavefunctions
            fac = delta / ((e - ie)**2 + delta**2)  # factor to create a delta
            out += fac * d  # add contribution
        out /= np.pi  # normalize
        out = spatial_dos(h, out)  # resum if necessary
        name0 = "LDOS_" + str(e) + "_.OUT"  # name of the output
        name = "MULTILDOS/" + name0
        write_ldos(go.x,
                   go.y,
                   out.tolist() * (nrep**h.dimensionality),
                   output_file=name)  # write in file
        fo.write(name0 + "\n")  # name of the file
        fo.flush()  # flush
    fo.close()  # close file
    # Now calculate the DOS
    from dos import calculate_dos
    es2 = np.linspace(min(es), max(es), len(es) * 10)
    ys = calculate_dos(evals, es2, delta)  # use the Fortran routine
    from dos import write_dos
    write_dos(es2, ys, output_file="MULTILDOS/DOS.OUT")
コード例 #4
0
ファイル: dos.py プロジェクト: zx-sdu/pygra
def dos2d(h,
          use_kpm=False,
          scale=10.,
          nk=100,
          ntries=1,
          delta=None,
          ndos=500,
          numw=20,
          random=True,
          kpm_window=1.0):
    """ Calculate density of states of a 2d system"""
    if h.dimensionality != 2: raise  # only for 2d
    ks = []
    from klist import kmesh
    ks = kmesh(h.dimensionality, nk=nk)
    if random:
        ks = [np.random.random(2) for ik in ks]
        print("Random k-mesh")
    if not use_kpm:  # conventional method
        hkgen = h.get_hk_gen()  # get generator
        if delta is None: delta = 6. / nk
        # conventiona algorithm
        calculate_dos_hkgen(hkgen,
                            ks,
                            ndos=ndos,
                            delta=delta,
                            is_sparse=h.is_sparse,
                            numw=numw)
    else:  # use the kpm
        npol = ndos // 10
        h.turn_sparse()  # turn the hamiltonian sparse
        hkgen = h.get_hk_gen()  # get generator
        mus = np.array([0.0j
                        for i in range(2 * npol)])  # initialize polynomials
        import kpm
        tr = timing.Testimator("DOS")
        ik = 0
        for k in ks:  # loop over kpoints
            #      print("KPM DOS at k-point",k)
            ik += 1
            tr.remaining(ik, len(ks))
            if random:
                kr = np.random.random(2)
                print("Random sampling in DOS")
                hk = hkgen(kr)  # hamiltonian
            else:
                hk = hkgen(k)  # hamiltonian
            mus += kpm.random_trace(hk / scale, ntries=ntries, n=npol)
        mus /= len(ks)  # normalize by the number of kpoints
        xs = np.linspace(-0.9, 0.9, ndos) * kpm_window  # x points
        ys = kpm.generate_profile(mus, xs)  # generate the profile
        write_dos(xs * scale, ys)  # write in file
        return (xs, ys)
コード例 #5
0
ファイル: gsenergy.py プロジェクト: joselado/pygra
def eigenvalues(h,nk):
    """Return all the eigenvalues of a Hamiltonian"""
    import klist
    h.turn_dense()
    ks = klist.kmesh(h.dimensionality,nk=nk) # get grid
    hkgen = h.get_hk_gen() # get generator
    e0 = 0.0
    import timing
    est = timing.Testimator(maxite=len(ks))
    for k in ks: # loop
      est.iterate()
      es = eigvalsh(hkgen(k)).tolist() # add
      e0 += np.sum(es[es<0.]) # add contribution
    return e0/len(ks) # return the ground state energy
コード例 #6
0
def eigenvalues(h, nk):
    """Return all the eigenvalues of a Hamiltonian"""
    import klist
    h.turn_dense()
    ks = klist.kmesh(h.dimensionality, nk=nk)  # get grid
    hkgen = h.get_hk_gen()  # get generator
    e0 = 0.0
    import timing
    est = timing.Testimator(maxite=len(ks))
    for k in ks:  # loop
        est.iterate()
        es = eigvalsh(hkgen(k)).tolist()  # add
        e0 += np.sum(es[es < 0.])  # add contribution
    return e0 / len(ks)  # return the ground state energy
コード例 #7
0
ファイル: scftypes.py プロジェクト: zx-sdu/pygra
    def update_occupied_states(self, fermi_shift=0.0):
        """Get the eigenvectors for a mesh of kpoints"""
        mine = None  # minimum energy
        if self.scfmode == "fermi" and self.is_sparse:
            self.hamiltonian.turn_sparse()
            print("WARNING!!! using sparse mode")
            print("Use this mode only if you know what you are doing!!!!\n\n")
            es, ws, ks = self.hamiltonian.eigenvectors(self.nkgrid,
                                                       kpoints=True,
                                                       sparse=True,
                                                       numw=self.num_waves)
            if np.max(np.abs(es)) * 0.9 < self.energy_cutoff:
                print("NOT ENOUGH STATES, recalling with", self.num_waves * 2)
                self.num_waves += 5
                self.update_occupied_states()  # call again
#  raise
        else:  # any other, use brute force
            es, ws, ks = self.hamiltonian.eigenvectors(self.nkgrid,
                                                       kpoints=True)


#    self.kfac = float(len(ks))/self.hamiltonian.intra.shape[0]
# number of kpoints of the calculation
#    mine = min(es)*0.9 # minimum energy retained
        self.kfac = len(
            klist.kmesh(self.hamiltonian.dimensionality, nk=self.nkgrid))
        if self.scfmode == "filling":  # get the fermi energy if the mode requires it
            self.fermi = get_fermi_energy(es,
                                          self.filling,
                                          fermi_shift=fermi_shift)
        elif self.scfmode == "fermi":
            pass  # do nothing
        self.gap = get_gap(es, self.fermi)  # store the gap
        if self.energy_cutoff is not None:
            if self.gap > self.energy_cutoff / 2:
                print("\nEnergy cutoff is to small, halting", self.gap, "\n\n")
                raise
            print("Warning!!!! Performing calculation with an energy cutoff")
        eoccs, voccs, koccs = get_occupied_states(es,
                                                  ws,
                                                  ks,
                                                  self.fermi,
                                                  mine=self.energy_cutoff,
                                                  smearing=self.smearing)
        self.wavefunctions = voccs  # store wavefunctions
        #    print(len(voccs),voccs.shape,len(voccs[0]))
        self.energies = eoccs  # store energies
        self.kvectors = koccs  # store kvectors
コード例 #8
0
ファイル: hamiltonians.py プロジェクト: zx-sdu/pygra
def eigenvectors(h, nk=10, kpoints=False, k=None, sparse=False, numw=None):
    import scipy.linalg as lg
    from scipy.sparse import csc_matrix as csc
    shape = h.intra.shape
    if h.dimensionality == 0:
        vv = lg.eigh(h.intra)
        vecs = [v for v in vv[1].transpose()]
        if kpoints: return vv[0], vecs, [[0., 0., 0.] for e in vv[0]]
        else: return vv[0], vecs
    elif h.dimensionality > 0:
        f = h.get_hk_gen()
        if k is None:
            from klist import kmesh
            kp = kmesh(h.dimensionality, nk=nk)  # generate a mesh
        else:
            kp = np.array([k])  # kpoint given on input
        #    vvs = [lg.eigh(f(k)) for k in kp] # diagonalize k hamiltonian
        nkp = len(kp)  # total number of k-points
        if sparse:  # sparse Hamiltonians
            vvs = [
                slg.eigsh(csc(f(k)), k=numw, which="LM", sigma=0.0, tol=1e-10)
                for k in kp
            ]  #

        else:  # dense Hamiltonians
            import parallel
            if parallel.cores > 1:  # in parallel
                vvs = parallel.multieigh([f(k)
                                          for k in kp])  # multidiagonalization
            else:
                vvs = [lg.eigh(f(k)) for k in kp]  #
        nume = sum([len(v[0])
                    for v in vvs])  # number of eigenvalues calculated
        eigvecs = np.zeros((nume, h.intra.shape[0]),
                           dtype=np.complex)  # eigenvectors
        eigvals = np.zeros(nume)  # eigenvalues

        #### New way ####
        #    eigvals = np.array([iv[0] for iv in vvs]).reshape(nkp*shape[0],order="F")
        #    eigvecs = np.array([iv[1].transpose() for iv in vvs]).reshape((nkp*shape[0],shape[1]),order="F")
        #    if kpoints: # return also the kpoints
        #      kvectors = [] # empty list
        #      for ik in kp:
        #        for i in range(h.intra.shape[0]): kvectors.append(ik) # store
        #      return eigvals,eigvecs,kvectors
        #    else:
        #      return eigvals,eigvecs

        #### Old way, slightly slower but clearer ####
        iv = 0
        kvectors = []  # empty list
        for ik in range(len(kp)):  # loop over kpoints
            vv = vvs[ik]  # get eigenvalues and eigenvectors
            for (e, v) in zip(vv[0], vv[1].transpose()):
                eigvecs[iv] = v.copy()
                eigvals[iv] = e.copy()
                kvectors.append(kp[ik])
                iv += 1
        if kpoints:  # return also the kpoints
            #      for iik in range(len(kp)):
            #        ik = kp[iik] # store kpoint
            #        for e in vvs[iik][0]: kvectors.append(ik) # store
            return eigvals, eigvecs, kvectors
        else:
            return eigvals, eigvecs
    else:
        raise