Пример #1
0
def kdos_bands(h,
               use_kpm=True,
               kpath=None,
               scale=10.0,
               ewindow=4.0,
               ne=1000,
               delta=0.01,
               ntries=10):
    """Calculate the KDOS bands using the KPM"""
    if not use_kpm: raise  # nope
    hkgen = h.get_hk_gen()  # get generator
    if kpath is None: kpath = klist.default(h.geometry)  # default
    fo = open("KDOS_BANDS.OUT", "w")  # open file
    ik = 0
    tr = timing.Testimator("KDOS")  # generate object
    for k in kpath:  # loop over kpoints
        tr.remaining(ik, len(kpath))
        hk = hkgen(k)  # get Hamiltonian
        npol = int(scale / delta)  # number of polynomials
        (x, y) = kpm.tdos(hk,
                          scale=scale,
                          npol=npol,
                          ne=ne,
                          ewindow=ewindow,
                          ntries=ntries)  # compute
        for (ix, iy) in zip(x, y):  # loop
            fo.write(str(ik / len(kpath)) + "   ")
            fo.write(str(ix) + "   ")
            fo.write(str(iy) + "\n")
        fo.flush()
        ik += 1
    fo.close()
Пример #2
0
def density(h,
            e=0.0,
            nk=20,
            mode="arpack",
            random=True,
            num_wf=20,
            window=0.1,
            nrep=3,
            name="DENSITY_UP.OUT",
            window_mode="around",
            kpoints=None):
    """ Calculate the electronic density"""
    if h.intra.shape[0] < 100: mode = "full"
    if h.dimensionality == 0: nk = 1  # single kpoint
    hkgen = h.get_hk_gen()  # get generator
    d = np.zeros(h.intra.shape[0])  # initialize
    tr = timing.Testimator("DENSITY")
    if kpoints is None:
        kpoints = [np.random.random(3) for ik in range(nk)]
    else:
        nk = len(kpoints)  # given at input
    for ik in range(len(kpoints)):
        tr.remaining(ik, nk)
        k = kpoints[ik]  # random k-point
        hk = csc_matrix(hkgen(k))  # get Hamiltonian
        d = d + restricted_density(hk,
                                   n=num_wf,
                                   e=e,
                                   window=window,
                                   mode=mode,
                                   window_mode=window_mode)
    d /= nk  # normalize
    d = spatial_density(h, d)  # sum if necessary
    geometry.write_profile(h.geometry, d, name=name, nrep=nrep)
    return d  # return density
Пример #3
0
def dos_kpm(h,
            scale=10.0,
            ewindow=4.0,
            ne=1000,
            delta=0.01,
            ntries=10,
            nk=100):
    """Calculate the KDOS bands using the KPM"""
    hkgen = h.get_hk_gen()  # get generator
    tr = timing.Testimator("DOS")  # generate object
    if h.dimensionality == 0: nk = 0  # single kpoint
    ytot = np.zeros(ne)  # initialize
    for ik in range(nk):  # loop over kpoints
        tr.remaining(ik, nk)
        hk = hkgen(np.random.random(3))  # get Hamiltonian
        npol = int(scale / delta)  # number of polynomials
        (x, y) = kpm.tdos(hk,
                          scale=scale,
                          npol=npol,
                          ne=ne,
                          ewindow=ewindow,
                          ntries=ntries)  # compute
        ytot += y  # add contribution
    ytot /= nk  # normalize
    np.savetxt("DOS.OUT", np.matrix([x, ytot]).T)  # save in file
Пример #4
0
def calculate_dos_hkgen(hkgen,
                        ks,
                        ndos=100,
                        delta=None,
                        is_sparse=False,
                        numw=10):
    """Calculate density of states using the ks given on input"""
    es = np.zeros((len(ks), hkgen(ks[0]).shape[0]))  # empty list
    es = []  # empty list
    tr = timing.Testimator("DOS")
    for ik in range(len(ks)):
        tr.remaining(ik, len(ks))
        hk = hkgen(ks[ik])  # Hamiltonian
        t0 = time.clock()  # time
        if is_sparse:  # sparse Hamiltonian
            es += [smalleig(hk, numw=numw)]  # eigenvalues
        else:  # dense Hamiltonian
            es += [lg.eigvalsh(hk)]  # get eigenvalues


#  es = es.reshape(len(es)*len(es[0])) # 1d array
    es = np.array(es)  # convert to array
    nk = len(ks)  # number of kpoints
    if delta is None: delta = 5. / nk  # automatic delta
    xs = np.linspace(np.min(es) - .5, np.max(es) + .5, ndos)  # create x
    ys = calculate_dos(es, xs, delta)  # use the Fortran routine
    ys /= nk  # normalize
    write_dos(xs, ys)  # write in file
    print("\nDOS finished")
Пример #5
0
def write_berry(h,
                kpath=None,
                dk=0.01,
                window=None,
                max_waves=None,
                mode="Wilson",
                delta=0.001,
                reciprocal=False,
                operator=None):
    """Calculate and write in file the Berry curvature"""
    if kpath is None: kpath = klist.default(h.geometry)  # take default kpath
    fo = open("BERRY_CURVATURE.OUT", "w")  # open file
    tr = timing.Testimator("BERRY CURVATURE")
    ik = 0
    if operator is not None: mode = "Green"  # Green function mode
    for k in kpath:
        tr.remaining(ik, len(kpath))
        if reciprocal: k = h.geometry.get_k2K_generator()(k)  # convert
        ik += 1
        if mode == "Wilson":
            b = berry_curvature(h,
                                k,
                                dk=dk,
                                window=window,
                                max_waves=max_waves)
        if mode == "Green":
            f = h.get_gk_gen(delta=delta)  # get generator
            b = berry_green(f, k=k, operator=operator)
        fo.write(str(k[0]) + "   ")
        fo.write(str(k[1]) + "   ")
        fo.write(str(b) + "\n")
        fo.flush()
    fo.close()  # close file
Пример #6
0
def interface(h1,
              h2,
              energies=np.linspace(-1., 1., 100),
              operator=None,
              delta=0.01,
              kpath=None):
    """Get the surface DOS of an interface"""
    from scipy.sparse import csc_matrix, bmat
    if kpath is None:
        if h1.dimensionality == 3:
            g2d = h1.geometry.copy()  # copy Hamiltonian
            import sculpt
            g2d = sculpt.set_xy_plane(g2d)
            kpath = klist.default(g2d, nk=100)
        elif h1.dimensionality == 2:
            kpath = [[k, 0., 0.] for k in np.linspace(0., 1., 40)]
        else:
            raise
    fo = open("KDOS_INTERFACE.OUT", "w")
    fo.write("# k, E, Bulk1, Surf1, Bulk2, Surf2, interface\n")
    tr = timing.Testimator("KDOS")  # generate object
    ik = 0
    h1 = h1.get_multicell()  # multicell Hamiltonian
    h2 = h2.get_multicell()  # multicell Hamiltonian
    for k in kpath:
        tr.remaining(ik, len(kpath))  # generate object
        ik += 1
        #    for energy in energies:
        #  (b1,s1,b2,s2,b12) = green.interface(h1,h2,k=k,energy=energy,delta=delta)
        #      out = green.interface(h1,h2,k=k,energy=energy,delta=delta)
        outs = green.interface_multienergy(h1,
                                           h2,
                                           k=k,
                                           energies=energies,
                                           delta=delta)
        for (energy, out) in zip(energies, outs):
            if operator is None:
                op = np.identity(h1.intra.shape[0] * 2)  # normal cell
                ops = np.identity(h1.intra.shape[0])  # supercell


#      elif callable(operator): op = callable(op)
            else:
                op = operator  # normal cell
                ops = bmat([[csc_matrix(operator), None],
                            [None, csc_matrix(operator)]])
            # write everything
            fo.write(str(ik) + "   " + str(energy) + "   ")
            for g in out:  # loop
                if g.shape[0] == op.shape[0]:
                    d = -(g * op).trace()[0, 0].imag  # bulk
                else:
                    d = -(g * ops).trace()[0, 0].imag  # interface
                fo.write(str(d) + "   ")
            fo.write("\n")
            fo.flush()  # flush
    fo.close()
Пример #7
0
def get_bands_1d(h,
                 nkpoints=100,
                 operator=None,
                 num_bands=None,
                 callback=None):
    if num_bands is None:  # all the bands
        if operator is not None:
            diagf = lg.eigh  # all eigenvals and eigenfuncs
        else:
            diagf = lg.eigvalsh  # all eigenvals and eigenfuncs
    else:  # using arpack
        h = h.copy()
        h.turn_sparse()  # sparse Hamiltonian

        def diagf(m):
            eig, eigvec = slg.eigsh(m,
                                    k=num_bands,
                                    which="LM",
                                    sigma=0.0,
                                    tol=arpack_tol,
                                    maxiter=arpack_maxiter)
            if operator is None: return eig
            else: return (eig, eigvec)

    hkgen = h.get_hk_gen()  # generator hamiltonian
    ks = np.linspace(0., 1., nkpoints, endpoint=True)
    f = open("BANDS.OUT", "w")  # open bands file
    f.write("# system_dimension = 1\n")
    #  if operator is not None: operator=np.matrix(operator) # convert to matrix
    tr = timing.Testimator("BANDSTRUCTURE")  # generate object
    ik = 0
    for k in ks:  # loop over kpoints
        ik += 1
        tr.remaining(ik, ks.shape[0])
        hk = hkgen(k)  # get hamiltonian
        #    if h.is_sparse: hk = hk.todense() # turn the matrix dense
        if operator is None:
            es = diagf(hk)
            for e in es:  # loop over energies
                f.write(str(k) + "   " + str(e) + "\n")  # write in file
            if callback is not None: callback(k, es)  # call the function
        else:
            es, ws = diagf(hk)
            ws = ws.transpose()  # transpose eigenvectors
            for (e, w) in zip(es, ws):  # loop over waves
                if callable(operator):
                    waw = operator(w, k=k)
                else:
                    waw = braket_wAw(
                        w, operator).real  # calcualte expectation value
                f.write(str(k) + "   " + str(e) + "  " + str(waw) +
                        "\n")  # write in file
            if callback is not None: callback(k, es, ws)  # call the function
    f.close()
    return np.genfromtxt("BANDS.OUT").transpose()  # return data
Пример #8
0
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)
Пример #9
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
Пример #10
0
def surface(h1,
            energies=np.linspace(-1., 1., 100),
            operator=None,
            delta=0.01,
            kpath=None,
            hs=None):
    """Get the surface DOS of an interface"""
    from scipy.sparse import csc_matrix, bmat
    if kpath is None:
        if h1.dimensionality == 3:
            g2d = h1.geometry.copy()  # copy Hamiltonian
            import sculpt
            g2d = sculpt.set_xy_plane(g2d)
            kpath = klist.default(g2d, nk=100)
        elif h1.dimensionality == 2:
            kpath = [[k, 0., 0.] for k in np.linspace(0., 1., 40)]
        else:
            raise
    fo = open("KDOS.OUT", "w")
    fo.write("# k, E, Surface, Bulk\n")
    tr = timing.Testimator("KDOS")  # generate object
    ik = 0
    h1 = h1.get_multicell()  # multicell Hamiltonian
    for k in kpath:
        tr.remaining(ik, len(kpath))  # generate object
        ik += 1
        outs = green.surface_multienergy(h1,
                                         k=k,
                                         energies=energies,
                                         delta=delta,
                                         hs=hs)
        for (energy, out) in zip(energies, outs):
            # write everything
            fo.write(str(ik) + "   " + str(energy) + "   ")
            for g in out:  # loop
                if operator is None:
                    d = -g.trace()[0, 0].imag  # only the trace
                elif callable(operator):
                    d = operator(g, k=k)  # call the operator
                else:
                    d = -(g *
                          operator).trace()[0, 0].imag  # assume it is a matrix
                fo.write(str(d) + "   ")  # write in a file
            fo.write("\n")  # next line
            fo.flush()  # flush
    fo.close()
Пример #11
0
def dos1d(h,
          use_kpm=False,
          scale=10.,
          nk=100,
          npol=100,
          ntries=2,
          ndos=1000,
          delta=0.01,
          ewindow=None,
          frand=None):
    """ Calculate density of states of a 1d system"""
    if h.dimensionality != 1: raise  # only for 1d
    ks = np.linspace(0., 1., nk, endpoint=False)  # number of kpoints
    if not use_kpm:  # conventional method
        hkgen = h.get_hk_gen()  # get generator
        #    delta = 16./(nk*h.intra.shape[0]) # smoothing
        calculate_dos_hkgen(hkgen, ks, ndos=ndos,
                            delta=delta)  # conventiona algorithm
    else:
        h.turn_sparse()  # turn the hamiltonian sparse
        hkgen = h.get_hk_gen()  # get generator
        yt = np.zeros(ndos)  # number of dos
        import kpm
        ts = timing.Testimator("DOS")
        for i in range(nk):  # loop over kpoints
            k = np.random.random(3)  # random k-point
            hk = hkgen(k)  # hamiltonian
            (xs, yi) = kpm.tdos(hk,
                                scale=scale,
                                npol=npol,
                                frand=frand,
                                ewindow=ewindow,
                                ntries=ntries,
                                ne=ndos)
            yt += yi  # Add contribution
            ts.remaining(i, nk)
        yt /= nk  # normalize
        write_dos(xs, yt)  # write in file
        print()
        return xs, yt
Пример #12
0
def chern(h, dk=-1, nk=10, delta=0.0001, mode="Wilson", operator=None):
    """ Calculates the chern number of a 2d system """
    c = 0.0
    ks = []  # array for kpoints
    bs = []  # array for berrys
    if dk < 0: dk = 1. / float(2 * nk)  # automatic dk
    if operator is not None and mode == "Wilson":
        print("Swuitching to Green mode in topology")
        mode = "Green"
    # create the function
    def fberry(k):  # function to integrate
        if mode == "Wilson":
            return berry_curvature(h, k, dk=dk)
        if mode == "Green":
            f2 = h.get_gk_gen(delta=delta)  # get generator
            return berry_green(f2, k=[k[0], k[1], 0.], operator=operator)

    ##################
    for x in np.linspace(0., 1., nk, endpoint=False):
        for y in np.linspace(0., 1., nk, endpoint=False):
            ks.append([x, y])  # create kpoints
    tr = timing.Testimator("CHERN NUMBER")
    ik = 0
    for k in ks:  # loop
        tr.remaining(ik, len(ks))
        ik += 1  # increase
        b = fberry(k)  # get berry curvature
        bs.append(b)
    # write in file
    fo = open("BERRY_CURVATURE.OUT", "w")  # open file
    for (k, b) in zip(ks, bs):
        fo.write(str(k[0]) + "   ")
        fo.write(str(k[1]) + "   ")
        fo.write(str(b) + "\n")
    fo.close()  # close file
    ################
    c = sum(bs)  # sum berry curvatures
    c = c / (2. * np.pi * nk * nk)
    open("CHERN.OUT", "w").write(str(c) + "\n")
    return c
Пример #13
0
def bulkandsurface(h1,
                   energies=np.linspace(-1., 1., 100),
                   operator=None,
                   delta=0.01,
                   hs=None,
                   nk=30):
    """Compute the DOS of the bulk and the surface"""
    tr = timing.Testimator("KDOS")  # generate object
    ik = 0
    h1 = h1.get_multicell()  # multicell Hamiltonian
    kpath = [np.random.random(3) for i in range(nk)]  # loop
    dosout = np.zeros((2, len(energies)))  # output DOS
    for k in kpath:
        tr.remaining(ik, len(kpath))  # generate object
        ik += 1
        outs = green.surface_multienergy(h1,
                                         k=k,
                                         energies=energies,
                                         delta=delta,
                                         hs=hs)
        ie = 0
        for (energy, out) in zip(energies, outs):  # loop over energies
            # compute dos
            ig = 0
            for g in out:  # loop
                if operator is None:
                    d = -g.trace()[0, 0].imag  # only the trace
                elif callable(operator):
                    d = operator(g, k=k)  # call the operator
                else:
                    d = -(g *
                          operator).trace()[0, 0].imag  # assume it is a matrix
                dosout[ig, ie] += d  # store
                ig += 1  # increase site
            ie += 1  # increase energy
    # write in file
    dosout /= nk  # normalize
    np.savetxt("DOS_BULK_SURFACE.OUT",
               np.matrix([energies, dosout[0], dosout[1]]).T)
Пример #14
0
def berry_map(h,
              dk=-1,
              nk=40,
              reciprocal=True,
              nsuper=1,
              window=None,
              max_waves=None,
              mode="Wilson",
              delta=0.001,
              operator=None):
    """ Calculates the chern number of a 2d system """
    if operator is not None: mode = "Green"  # Green function mode
    c = 0.0
    ks = []  # array for kpoints
    if dk < 0: dk = 5. / float(2 * nk)  # automatic dk
    if reciprocal: R = h.geometry.get_k2K()
    else: R = np.matrix(np.identity(3))
    fo = open("BERRY_MAP.OUT", "w")  # open file
    nt = nk * nk  # total number of points
    tr = timing.Testimator("BERRY CURVATURE")
    ik = 0
    for x in np.linspace(-nsuper, nsuper, nk, endpoint=False):
        for y in np.linspace(-nsuper, nsuper, nk, endpoint=False):
            tr.remaining(ik, nt)
            ik += 1
            r = np.matrix([x, y, 0.]).T  # real space vectors
            k = np.array((R * r).T)[0]  # change of basis
            if mode == "Wilson":
                b = berry_curvature(h,
                                    k,
                                    dk=dk,
                                    window=window,
                                    max_waves=max_waves)
            if mode == "Green":
                f = h.get_gk_gen(delta=delta)  # get generator
                b = berry_green(f, k=k, operator=operator)
            fo.write(str(x) + "   " + str(y) + "     " + str(b) + "\n")
            fo.flush()
    fo.close()  # close file
Пример #15
0
def get_bands_2d(h,
                 kpath=None,
                 operator=None,
                 num_bands=None,
                 callback=None,
                 central_energy=0.0):
    """Get a 2d bandstructure"""
    if num_bands is None:  # all the bands
        if operator is not None:

            def diagf(m):  # diagonalization routine
                if h.is_sparse and h.intra.shape[0] < maxdim:
                    return lg.eigh(m.todense())  # all eigenvals and eigenfuncs
                else:
                    return lg.eigh(m)  # all eigenvals and eigenfuncs
        else:

            def diagf(m):  # diagonalization routine
                if h.is_sparse and h.intra.shape[0] < maxdim:
                    return lg.eigvalsh(
                        m.todense())  # all eigenvals and eigenfuncs
                else:
                    return lg.eigvalsh(m)  # all eigenvals and eigenfuncs
    else:  # using arpack
        h = h.copy()
        h.turn_sparse()  # sparse Hamiltonian

        def diagf(m):
            eig, eigvec = slg.eigsh(m,
                                    k=num_bands,
                                    which="LM",
                                    sigma=central_energy,
                                    tol=arpack_tol,
                                    maxiter=arpack_maxiter)
            if operator is None: return eig
            else: return (eig, eigvec)

    # open file and get generator
    f = open("BANDS.OUT", "w")  # open bands file
    hkgen = h.get_hk_gen()  # generator hamiltonian
    if kpath is None:
        import klist
        kpath = klist.default(h.geometry)  # generate default klist
    tr = timing.Testimator("BANDSTRUCTURE")  # generate object
    for k in range(len(kpath)):  # loop over kpoints
        #    print("Bands in kpoint",k,"of",len(kpath),end="\r")
        tr.remaining(k, len(kpath))
        hk = hkgen(kpath[k])  # get hamiltonian
        if operator is None:
            es = diagf(hk)
            for e in es:  # loop over energies
                f.write(str(k) + "   " + str(e) + "\n")  # write in file
            if callback is not None: callback(k, es)  # call the function
        else:
            es, ws = diagf(hk)
            ws = ws.transpose()  # transpose eigenvectors
            for (e, w) in zip(es, ws):  # loop over waves
                if callable(operator):
                    try:
                        waw = operator(w, k=kpath[k])  # call the operator
                    except:
                        print("Check out the k optional argument in operator")
                        waw = operator(w)  # call the operator
                else:
                    waw = braket_wAw(
                        w, operator).real  # calculate expectation value
                f.write(str(k) + "   " + str(e) + "  " + str(waw) +
                        "\n")  # write in file
            # callback function in each iteration
            if callback is not None: callback(k, es, ws)  # call the function
        f.flush()
    f.close()
    print("\nBANDS finished")
    return np.genfromtxt("BANDS.OUT").transpose()  # return data