예제 #1
0
class TestGeometryPlot(GeometryPlotTester):

    run_for = {
        "sisl_geom": {
            "init_func": sisl.geom.graphene(orthogonal=True).plot
        },
        "ghost_atoms": {
            "init_func":
            sisl.Geometry([[0, 0, 1], [1, 0, 0]],
                          atoms=[sisl.Atom(6), sisl.Atom(-6)]).plot
        }
    }
예제 #2
0
    def init_func_and_attrs(self, request):
        name = request.param

        if name == "sisl_geom":
            init_func = sisl.geom.graphene(orthogonal=True).plot
        elif name == "ghost_atoms":
            init_func = sisl.Geometry([[0, 0, 1], [1, 0, 0]],
                                      atoms=[sisl.Atom(6),
                                             sisl.Atom(-6)]).plot

        attrs = {}

        return init_func, attrs
예제 #3
0
def pre_prepare_ase_after_relax(initial_XV,final_XV,Ghost):
    """
    """
    import sisl
    if Ghost ==True:
        print ('Finding Ghosts in XV')
        #Ghost_initial = sisl.Geometry(initial_XV.xyz[-2],
        #                              atoms =  initial_XV.atoms.Z[-2])
        #Ghost_final = sisl.Geometry(initial_XV.xyz[-1],
        #                            atoms = initial_XV.atoms.Z[-1])

        Ghost_initial_Info = sisl.Atom(-1 * initial_XV.atoms[-2].Z)
        Ghost_initial = sisl.Geometry( initial_XV.xyz[-2],
                                          atoms= sisl.Atom( -1* Ghost_initial_Info.Z , tag=Ghost_initial_Info.symbol+"_ghost"))
            
        Ghost_final_Info = sisl.Atom(-1 * initial_XV.atoms[-1].Z)
        Ghost_final = sisl.Geometry( initial_XV.xyz[-1],
                                        atoms=sisl.Atom( -1* Ghost_final_Info.Z,tag = Ghost_final_Info.symbol+"_ghost" ))


        trace_atom_initial = sisl.Geometry(initial_XV.xyz[-3],
                                           atoms = initial_XV.atoms.Z[-3])
        trace_atom_final =  sisl.Geometry(final_XV.xyz[-3],
                                          atoms = final_XV.atoms.Z[-3])
        initial_XV = initial_XV.remove([-1])
        initial_XV = initial_XV.remove([-1])
        final_XV = final_XV.remove([-1])
        final_XV = final_XV.remove([-1])
       
        info_sisl = {'initial' : initial_XV,
                 'final' : final_XV,
                 'trace_atom_initial' : trace_atom_initial,
                 'trace_atom_final' : trace_atom_final,
                 'Ghost_initial' : Ghost_initial,
                 'Ghost_final' : Ghost_final,
                 }

    else:
        trace_atom_initial = initial_XV[-1]
        trace_atom_final = final_XV[-1]

        info_sisl ={'initial' : initial_XV,
                    'final' : final_XV,
                    'trace_atom_initial' : trace_atom_initial,
                    'trace_atom_final' : trace_atom_final,
                    }

    return info_sisl
예제 #4
0
    def from_yaml(cls, file, nodes=()):
        """ Parse the yaml file """
        from sisl_toolbox.siesta.minimizer._yaml_reader import read_yaml, parse_variable
        dic = read_yaml(file, nodes)

        element = dic["element"]
        tag = dic.get("tag")
        mass = dic.get("mass", None)

        # get default options for pseudo
        opts = NotNonePropertyDict()
        pseudo = dic["pseudo"]
        opts["logr"] = parse_variable(pseudo.get("log-radii"), unit="Ang").value
        opts["rcore"] = parse_variable(pseudo.get("core-correction"), unit="Ang").value
        opts["xc"] = pseudo.get("xc")
        opts["equation"] = pseudo.get("equation")
        opts["flavor"] = pseudo.get("flavor")
        define = pseudo.get("define", ('NEW_CC', 'FREE_FORMAT_RC_INPUT', 'NO_PS_CUTOFFS'))

        # Now on to parsing the valence shells
        orbs = []
        for key in dic:
            if key not in _shell_order:
                continue

            # Now we know the occupation is a shell
            pseudo = dic[key].get("pseudo", {})
            cutoff = parse_variable(pseudo.get("cutoff"), 2.1, "Ang").value
            charge = parse_variable(pseudo.get("charge"), 0.).value
            orbs.append(si.AtomicOrbital(key, m=0, R=cutoff, q0=charge))

        atom = si.Atom(element, orbs, mass=mass, tag=tag)
        return cls(atom, define, **opts)
예제 #5
0
def test_tshs_warn(sisl_files, sisl_tmp):
    si = sisl.get_sile(sisl_files(_dir, 'si_pdos_kgrid.TSHS'))

    # check number of orbitals
    geom = si.read_geometry()
    geom._atoms = sisl.Atoms([sisl.Atom(i + 1) for i in range(geom.na)])
    with pytest.warns(sisl.SislWarning, match='number of orbitals'):
        si.read_hamiltonian(geometry=geom)

    # check cell
    geom = si.read_geometry()
    geom.sc.cell[:, :] = 1.
    with pytest.warns(sisl.SislWarning, match='lattice vectors'):
        si.read_hamiltonian(geometry=geom)

    # check atomic coordinates
    geom = si.read_geometry()
    geom.xyz[0, :] += 10.
    with pytest.warns(sisl.SislWarning, match='atomic coordinates'):
        si.read_hamiltonian(geometry=geom)

    # check supercell
    geom = si.read_geometry()
    geom.set_nsc([1, 1, 1])
    with pytest.warns(sisl.SislWarning, match='supercell'):
        si.read_hamiltonian(geometry=geom)
예제 #6
0
파일: _hamiltonian.py 프로젝트: juijan/sisl
    def dispatch(self,
                 t=(-2.414, -0.168),
                 beta=(-1.847, -3.077),
                 a=1.42,
                 orthogonal=False):
        distance = self._obj.distance
        da = 0.0005

        R = (distance(0, a) + da, distance(1, a) + da, distance(2, a) + da)

        def construct(H, ia, atoms, atoms_xyz=None):
            idx_t012, rij_t012 = H.geometry.close(ia,
                                                  R=R,
                                                  atoms=atoms,
                                                  atoms_xyz=atoms_xyz,
                                                  ret_rij=True)
            H[ia, idx_t012[0]] = 0.
            H[ia, idx_t012[1]] = t[0] * np.exp(beta[0] * (rij_t012[1] - R[1]))
            H[ia, idx_t012[2]] = t[1] * np.exp(beta[1] * (rij_t012[2] - R[2]))

        # Define the graphene lattice
        C = si.Atom(6, si.AtomicOrbital(n=2, l=1, m=0, R=R[-1]))
        graphene = si.geom.graphene(a, C, orthogonal=orthogonal)
        # Define the Hamiltonian
        H = si.Hamiltonian(graphene)
        H.construct(construct)
        return H
예제 #7
0
def Ghost_block(sisl_images):
    """
    """
    import sisl
    import numpy as np
    Ghost_Species = np.array([])
    Ghost_Species_name = np.array([])
    count = 0
    n_ghost = 0
    for i in range(sisl_images[0].atoms.nspecie):
        count = int(count + 1)
        print(count, sisl_images[0].atoms.atom[i].Z)
        #print (count)
        if sisl_images[0].atoms.atom[i].Z < 0:
            n_ghost = n_ghost + 1
            a = sisl.Atom(abs(sisl_images[0].atoms.atom[i].Z))
            Ghost_Species = np.append(Ghost_Species, int(count))
            Ghost_Species = np.append(Ghost_Species,
                                      int(sisl_images[0].atoms.atom[i].Z))
            Ghost_Species_name = np.append(Ghost_Species_name,
                                           a.symbol + '_ghost')

    Ghost_Species = Ghost_Species.reshape(n_ghost, 2)
    Ghost_Species_name = Ghost_Species_name.reshape(n_ghost, 1)

    F = open('ghost_block_temp', 'w')
    F.writelines('\n')
    F.writelines('%block Geometry-Constraints\n')
    for i in range(Ghost_Species.shape[0]):
        F.writelines("species-i  {:}  \n".format(int(Ghost_Species[i][0])))
    F.writelines('%endblock Geometry-Constraints\n')
    F.writelines('\n')
    F.writelines('%include parameters.fdf \n')
    F.close()
예제 #8
0
파일: _hamiltonian.py 프로젝트: juijan/sisl
 def dispatch(self, t=-2.7, a=1.42, orthogonal=False):
     # Define the graphene lattice
     da = 0.0005
     C = si.Atom(6, si.AtomicOrbital(n=2, l=1, m=0, R=a + da))
     graphene = si.geom.graphene(a, C, orthogonal=orthogonal)
     # Define the Hamiltonian
     H = si.Hamiltonian(graphene)
     H.construct([(da, a + da), (0, t)])
     return H
예제 #9
0
파일: sview.py 프로젝트: jonaslb/siutil
def sview(g, ghosts_z=None, **kwargs):
    if ghosts_z is not None:
        g = g.copy()
        cw = warnings.catch_warnings()
        cw.__enter__()
        warnings.simplefilter("ignore")
        replacement = si.Atom(ghosts_z)
        for a in g.atoms._atom:
            if a.Z < 1:
                g.atoms.replace(a, replacement)
        g.atoms.reduce(in_place=True)
        cw.__exit__()
    aview(g.toASE(), **kwargs)
예제 #10
0
파일: _hamiltonian.py 프로젝트: juijan/sisl
    def dispatch(self, a=1.42, orthogonal=False):
        distance = self._obj.distance
        da = 0.0005

        R = (distance(0, a) + da, distance(1, a) + da, distance(2, a) + da,
             distance(3, a) + da)
        # Define the graphene lattice
        C = si.Atom(6, si.AtomicOrbital(n=2, l=1, m=0, R=R[-1]))
        graphene = si.geom.graphene(a, C, orthogonal=orthogonal)
        # Define the Hamiltonian
        H = si.Hamiltonian(graphene, orthogonal=False)
        t = [(-0.45, 1), (-2.78, 0.117), (-0.15, 0.004), (-0.095, 0.002)]
        H.construct([R, t])
        return H
예제 #11
0
파일: _hamiltonian.py 프로젝트: juijan/sisl
    def dispatch(self, set='A', a=1.42, orthogonal=False):
        distance = self._obj.distance
        da = 0.0005
        H_orthogonal = True
        #U = 2.0

        R = tuple(distance(i, a) + da for i in range(4))
        if set == 'A':
            # same as simple
            t = (0, -2.7)
            #U = 0.
        elif set == 'B':
            # same as simple
            t = (0, -2.7)
        elif set == 'C':
            t = (0, -2.7, -0.2)
        elif set == 'D':
            t = (0, -2.7, -0.2, -0.18)
        elif set == 'E':
            # same as D, but specific for GNR
            t = (0, -2.7, -0.2, -0.18)
        elif set == 'F':
            # same as D, but specific for GNR
            t = [(0, 1), (-2.7, 0.11), (-0.09, 0.045), (-0.27, 0.065)]
            H_orthogonal = False
        elif set == 'G':
            # same as D, but specific for GNR
            t = [(0, 1), (-2.97, 0.073), (-0.073, 0.018), (-0.33, 0.026)]
            #U = 0.
            H_orthogonal = False
        else:
            raise ValueError(
                f"Set specification for {self.doi} does not exist, should be one of [A-G]"
            )

        # Reduce size of R
        R = R[:len(t)]

        # Currently we do not carry over U, since it is not specified for the
        # sisl objects....

        # Define the graphene lattice
        C = si.Atom(6, si.AtomicOrbital(n=2, l=1, m=0, R=R[-1]))
        graphene = si.geom.graphene(a, C, orthogonal=orthogonal)
        graphene.optimize_nsc([0, 1])
        # Define the Hamiltonian
        H = si.Hamiltonian(graphene, orthogonal=H_orthogonal)
        H.construct([R, t])
        return H
예제 #12
0
파일: _hamiltonian.py 프로젝트: juijan/sisl
    def dispatch(self, t=-2.7, a=1.42, orthogonal=False):
        distance = self._obj.distance
        da = 0.0005

        R = (distance(0, a) + da, distance(1, a) + da)

        def construct(H, ia, atoms, atoms_xyz=None):
            idx_t01, rij_t01 = H.geometry.close(ia,
                                                R=R,
                                                atoms=atoms,
                                                atoms_xyz=atoms_xyz,
                                                ret_rij=True)
            H[ia, idx_t01[0]] = 0.
            H[ia, idx_t01[1]] = t * (a / rij_t01[1])**2

        # Define the graphene lattice
        C = si.Atom(6, si.AtomicOrbital(n=2, l=1, m=0, R=R[-1]))
        graphene = si.geom.graphene(a, C, orthogonal=orthogonal)
        # Define the Hamiltonian
        H = si.Hamiltonian(graphene)
        H.construct(construct)
        return H
예제 #13
0
def pre_prepare_sisl (frac_or_cart_or_index,Initial_Geom,InitialAtomPosition,FinalAtomPosition,KickedAtomPosition,rtol=1e-2,atol=1e-2):

    """
    
    """
    import sisl
    from sisl import Atom
    if frac_or_cart_or_index == 'cartesian':
        print ("Cartesian ...")
        #Initial_Geom = Fdf.read_geometry()
        XYZ = Initial_Geom.xyz
        InitialASEXYZ = Initial_Geom
        FinalASEXYZ = Initial_Geom
        print ("Removing Vacancies Ang/Bohr")
        print ("Removing Index for Initial Atom:{}".format(AtomIndex(XYZ,InitialAtomPosition,rtol,atol)))
        print ("Removing Index for Final Atom:{}".format(AtomIndex(XYZ,FinalAtomPosition,rtol,atol)))
        

        # Fixing tags
        TraceAtom_Initial_Info = sisl.Atom(Initial_Geom.atoms.Z[AtomIndex(XYZ,InitialAtomPosition,rtol,atol)])
        TraceAtom_Initial = sisl.Geometry(xyz=Initial_Geom.xyz[AtomIndex(XYZ,InitialAtomPosition,rtol,atol)],
                                           atoms= sisl.Atom(TraceAtom_Initial_Info.Z,tag=TraceAtom_Initial_Info.symbol+'_i' ))
        Ghost_initial = sisl.Geometry(xyz=Initial_Geom.xyz[AtomIndex(XYZ,InitialAtomPosition,rtol,atol)],
                                           atoms= sisl.Atom(TraceAtom_Initial_Info.Z,tag=TraceAtom_Initial_Info.symbol+'_ghost' ))
        TraceAtom_Final_Info  = sisl.Atom(Initial_Geom.atoms.Z[AtomIndex(XYZ,InitialAtomPosition,rtol,atol)])
        TraceAtom_Final = sisl.Geometry(xyz = FinalAtomPosition ,
                                    atoms= sisl.Atom(TraceAtom_Final_Info.Z,tag=TraceAtom_Final_Info.symbol+'_i'))       
        Ghost_final = sisl.Geometry(xyz = FinalAtomPosition ,
                                    atoms= sisl.Atom(TraceAtom_Final_Info.Z,tag=TraceAtom_Final_Info.symbol+'_ghost'))
        
        InitialASEXYZ = InitialASEXYZ.remove(AtomIndex(XYZ,InitialAtomPosition,rtol,atol))
        FinalASEXYZ =  InitialASEXYZ  
        
    elif frac_or_cart_or_index  == 'frac':
        #print ("Removing Vacancies Fractional NOT Implemented")
        print ("Fractional ...")
        Frac = Initial_Geom.fxyz
        InitialASEXYZ = Initial_Geom
        FinalASEXYZ = Initial_Geom
        print ("Removing Vacancies Ang/Bohr")
        print ("Removing Index for Initial Atom:{}".format(AtomIndex(Frac,InitialAtomPosition,rtol,atol)))
        print ("Removing Index for Final Atom:{}".format(AtomIndex(Frac,FinalAtomPosition,rtol,atol)))
        trace_atom_initial = sisl.Geometry(Initial_Geom.xyz[AtomIndex(Frac,InitialAtomPosition,rtol,atol)],
                                      atoms= Initial_Geom.atoms.Z[AtomIndex(Frac,InitialAtomPosition,rtol,atol)])
        trace_atom_final = sisl.Geometry(Initial_Geom.xyz[AtomIndex(Frac,FinalAtomPosition,rtol,atol)],
                                        atoms= Initial_Geom.atoms.Z[AtomIndex(Frac,FinalAtomPosition,rtol,atol)])    

        InitialASEXYZ = InitialASEXYZ.remove(AtomIndex(Frac,InitialAtomPosition,rtol,atol))
        FinalASEXYZ = FinalASEXYZ.remove(AtomIndex(Frac,FinalAtomPosition,rtol,atol))
        if AtomIndex(Frac,FinalAtomPosition,rtol,atol) > AtomIndex(Frac,InitialAtomPosition,rtol,atol):
            print ("Order : Final Atom Position > Initial Atom Position")
            InitialASEXYZ = InitialASEXYZ.remove(AtomIndex(Frac,FinalAtomPosition,rtol,atol)-1)
            FinalASEXYZ = FinalASEXYZ.remove(AtomIndex(Frac,InitialAtomPosition,rtol,atol))
        if AtomIndex(Frac,FinalAtomPosition,rtol,atol) < AtomIndex(Frac,InitialAtomPosition,rtol,atol):
            print ("Order : Initial Atom Position > Final Atom Position")
            InitialASEXYZ = InitialASEXYZ.remove(AtomIndex(Frac,FinalAtomPosition,rtol,atol))
            FinalASEXYZ = FinalASEXYZ.remove(AtomIndex(Frac,InitialAtomPosition,rtol,atol)-1)
    else:
        print('index')
        #Frac = Initial_Geom.fxyz
        InitialASEXYZ = Initial_Geom
        FinalASEXYZ = Initial_Geom
        print ("Removing Vacancies Ang/Bohr")
        print ("Removing Index for Initial Atom:{}".format(InitialAtomPosition-1))
        print ("Removing Index for Final Atom:{}".format(FinalAtomPosition-1))
        
        #trace_atom_A_initial = sisl.Geometry(Initial_Geom.xyz[InitialAtomPosition-1],
        #                                   atoms= Initial_Geom.atoms.Z[InitialAtomPosition-1])
        #trace_atom_B_final = sisl.Geometry(Initial_Geom.xyz[FinalAtomPosition-1],
        #                                 atoms=  Initial_Geom.atoms.Z[FinalAtomPosition-1])       
        trace_atom_A_initial = sisl.Geometry(Initial_Geom.xyz[InitialAtomPosition-1],
                                      atoms= Initial_Geom.atoms.Z[InitialAtomPosition-1])
        trace_atom_A_final = sisl.Geometry(Initial_Geom.xyz[FinalAtomPosition-1],
                                      atoms= Initial_Geom.atoms.Z[InitialAtomPosition-1])
        trace_atom_B_initial = sisl.Geometry(Initial_Geom.xyz[FinalAtomPosition-1],
                                      atoms= Initial_Geom.atoms.Z[FinalAtomPosition-1])
        trace_atom_B_final = sisl.Geometry(Initial_Geom.xyz[InitialAtomPosition-1],
                                      atoms= Initial_Geom.atoms.Z[FinalAtomPosition-1])


        InitialASEXYZ = InitialASEXYZ.remove(InitialAtomPosition-1)
        FinalASEXYZ = FinalASEXYZ.remove(FinalAtomPosition-1)
        if (FinalAtomPosition-1) > (InitialAtomPosition-1):
            print ("Order : Final Atom Position > Initial Atom Position")
            InitialASEXYZ = InitialASEXYZ.remove(FinalAtomPosition-2)
            FinalASEXYZ = FinalASEXYZ.remove(InitialAtomPosition-1)
        if (FinalAtomPosition-1) < (InitialAtomPosition-1):
            print ("Order : Initial Atom Position > Final Atom Position")
            InitialASEXYZ = InitialASEXYZ.remove(FinalAtomPosition-1)
            FinalASEXYZ = FinalASEXYZ.remove(InitialAtomPosition-2)   

    
    

    InitialASEXYZ = InitialASEXYZ.add(TraceAtom_Initial)
    FinalASEXYZ = FinalASEXYZ.add(TraceAtom_Final)

    info_sisl = {'initial' : InitialASEXYZ,
                 'final' : FinalASEXYZ,
                 'trace_atom_initial' : TraceAtom_Initial,
                 'trace_atom_final' : TraceAtom_Final,
                 'Ghost_initial' : Ghost_initial,
                 'Ghost_final' : Ghost_final,
                 }


    return info_sisl
예제 #14
0
def si_pdos_kgrid_geom():
    return sisl.Geometry([[0, 0, 0], [1, 1, 1]],
                         sisl.Atom('Si', R=np.arange(13) + 1))
예제 #15
0
def CAP(geometry, side, dz_CAP=30, write_xyz=True, zaxis=2):
    # Determine orientation
    if zaxis == 2:
        xaxis, yaxis = 0, 1
    elif zaxis == 0:
        xaxis, yaxis = 1, 2
    elif zaxis == 1:
        xaxis, yaxis = 0, 2
    # Natural units (see "http://superstringtheory.com/unitsa.html")
    hbar = 1
    m = 0.511e6  # eV
    c = 2.62
    print('\nSetting up CAP regions: {}'.format(side))
    print('Width of absorbing walls = {} Angstrom'.format(dz_CAP))
    Wmax = 100
    dH_CAP = si.Hamiltonian(geometry, dtype='complex128')
    CAP_list = []
    ### EDGES
    if 'right' in side:
        print('Setting at right')
        z, y = geometry.xyz[:, xaxis], geometry.xyz[:, yaxis]
        z2 = np.max(geometry.xyz[:, xaxis]) + 1.
        z1 = z2 - dz_CAP
        idx = np.where(np.logical_and(z1 <= z, z < z2))[0]
        fz = (4 / (c**2)) * ((dz_CAP / (z2 - 2 * z1 + z[idx]))**2 +
                             (dz_CAP / (z2 - z[idx]))**2 - 2)
        Wz = ((hbar**2) / (2 * m)) * (2 * np.pi / (dz_CAP / 2000))**2 * fz
        orbs = dH_CAP.geom.a2o(
            idx)  # if you have just 1 orb per atom, then orb = ia
        for orb, wz in zip(orbs, Wz):
            dH_CAP[orb, orb] = complex(0, -wz)
        CAP_list.append(idx)
        #print(list2range_TBTblock(idx))

    if 'left' in side:
        print('Setting at left')
        z, y = geometry.xyz[:, xaxis], geometry.xyz[:, yaxis]
        z2 = np.min(geometry.xyz[:, xaxis]) - 1.
        z1 = z2 + dz_CAP
        idx = np.where(np.logical_and(z2 < z, z <= z1))[0]
        fz = (4 / (c**2)) * ((dz_CAP / (z2 - 2 * z1 + z[idx]))**2 +
                             (dz_CAP / (z2 - z[idx]))**2 - 2)
        Wz = ((hbar**2) / (2 * m)) * (2 * np.pi / (dz_CAP / 2000))**2 * fz
        orbs = dH_CAP.geom.a2o(
            idx)  # if you have just 1 orb per atom, then orb = ia
        for orb, wz in zip(orbs, Wz):
            dH_CAP[orb, orb] = complex(0, -wz)
        CAP_list.append(idx)
        #print(list2range_TBTblock(idx))

    if 'top' in side:
        print('Setting at top')
        z, y = geometry.xyz[:, xaxis], geometry.xyz[:, yaxis]
        y2 = np.max(geometry.xyz[:, yaxis]) + 1.
        y1 = y2 - dz_CAP
        idx = np.where(np.logical_and(y1 <= y, y < y2))[0]
        fz = (4 / (c**2)) * ((dz_CAP / (y2 - 2 * y1 + y[idx]))**2 +
                             (dz_CAP / (y2 - y[idx]))**2 - 2)
        Wz = ((hbar**2) / (2 * m)) * (2 * np.pi / (dz_CAP / 2000))**2 * fz
        orbs = dH_CAP.geom.a2o(
            idx)  # if you have just 1 orb per atom, then orb = ia
        for orb, wz in zip(orbs, Wz):
            dH_CAP[orb, orb] = complex(0, -wz)
        CAP_list.append(idx)
        #print(list2range_TBTblock(idx))

    if 'bottom' in side:
        print('Setting at bottom')
        z, y = geometry.xyz[:, xaxis], geometry.xyz[:, yaxis]
        y2 = np.min(geometry.xyz[:, yaxis]) - 1.
        y1 = y2 + dz_CAP
        idx = np.where(np.logical_and(y2 < y, y <= y1))[0]
        fz = (4 / (c**2)) * ((dz_CAP / (y2 - 2 * y1 + y[idx]))**2 +
                             (dz_CAP / (y2 - y[idx]))**2 - 2)
        Wz = ((hbar**2) / (2 * m)) * (2 * np.pi / (dz_CAP / 2000))**2 * fz
        orbs = dH_CAP.geom.a2o(
            idx)  # if you have just 1 orb per atom, then orb = ia
        for orb, wz in zip(orbs, Wz):
            dH_CAP[orb, orb] = complex(0, -wz)
        CAP_list.append(idx)
        #print(list2range_TBTblock(idx))

    CAP_list = np.concatenate(CAP_list).ravel().tolist()
    if write_xyz:
        # visualize CAP regions
        visualize = geometry.copy()
        visualize.atom[CAP_list] = si.Atom(8, R=[1.44])
        visualize.write('CAP.xyz')

    return dH_CAP
예제 #16
0
H.write('inside_HS_DEV.nc')

# Create CAP
from lib_dft2tb import CAP
dH_CAP = CAP(H.geom, 'left+right', dz_CAP=50, write_xyz=True, zaxis=2)
dH_CAP_sile = si.get_sile('CAP.delta.nc', 'w')
dH_CAP_sile.write_delta(dH_CAP)

############################
############################
############################
# Define atoms where Gamma exists
a_tip = [3704]
# Check
tmp = H.geom.copy()
tmp.atom[a_tip] = si.Atom(16, R=[1.44])
tmp.write('a_tip.xyz')
# Setup TBTGF for tip injection
# It is vital that you also write an electrode Hamiltonian,
# i.e. the Hamiltonian object passed as "Htip", has to be written:
# Build HS for tip
HStip = H.sub(a_tip)

HStip.write('TBTGF_H.nc')
# Now generate a TBTGF file
GF = si.io.TBTGFSileTBtrans('Gamma.TBTGF')

# Below we load whatever TBT file from which we can take the energies and kpoints
# In the next TBTrans run we MUST use the same energy points and kpoints we load here
#TBT = si.get_sile("elist.TBT.nc")
# Energy contour
예제 #17
0
def construct_modular(H0, TSHS, modules, positions):
    """
    H0:         Host TB model to be rearranged. Modules will be progressively appended
                at the end of atomic list
    TSHS:       list of DFT Hamiltonians for each module; needed to recover the input coordinates to map
    modules:    list of tuples (a_Delta, Delta, area_ext, area_R2) as those obtained 
                from tbtncTools.Delta provide one tuple for each module
    positions:  list of xyz object (ndarray with shape=(1,3)) in H0 corresponding to
                the center of mass of each module provide one xyz for each module

    EXAMPLE OF USAGE:
        from tbtncTools import Delta
        a_Delta, _, Delta, area_ext, area_R2 = Delta(TSHS, shape='Cuboid', z_area=TSHS.xyz[0, 2], 
            thickness=10., ext_offset=tshs_0.cell[1,:].copy(), zaxis=2, atoms=C_list)
        frame_tip = (a_Delta, Delta, area_ext, area_R2)
        xyz_tsource = H0.center(what='xyz') +(0.4*H0.cell[1,:]-[0,5.31,0])
        xyz_tdrain = H0.center(what='xyz') -(0.4*H0.cell[1,:]-[0,5.31,0]) -0.5*TSHS.cell[0,:]

        Hfinal, l_al, l_buf = construct_modular(H0=H0,
            TSHS=[TSHS, TSHS] 
            modules=[frame_tip, frame_tip], 
            positions=[xyz_tsource, xyz_tdrain])

    WARNING: maybe in some situations it might overlap some buffer and module atoms.
        So, ALWAYS CHECK THAT FINAL XYZ IS WHAT YOU ACTUALLY EXPECT!!! 
    """
    Htmp = H0.copy()
    l_nal = []

    for i, hs, mod, xyz in zip(range(len(TSHS)), TSHS, modules, positions):
        print('\nciaoooooooooo\n')
        H, al = rearrange_H(hs, mod[0], Htmp, pos_dSE=xyz, area=mod[1])
        nal = len(al)
        print(nal)
        l_nal.insert(0, nal)
        Htmp = H.copy()

    l_nal = np.asarray(l_nal)

    # Find atoms in each frame, write xyz and info about modules
    l_al = []
    for i in range(len(l_nal)):
        first = len(H) - l_nal[:len(l_nal) - i].sum()
        last = len(H) - l_nal[:len(l_nal) - (i + 1)].sum()

        al = np.arange(first, last)
        l_al.append(al)

        from tbtncTools import list2range_TBTblock
        print('After reordering: \n{}'.format(list2range_TBTblock(al)))

        v = H.geom.copy()
        v.atom[al] = si.Atom(8, R=[1.44])
        #v.atom[l_buf[i]] = si.Atom(10, R=[1.44])
        v.write('module_{}.xyz'.format(i + 1))
        # Print elec-pos end for use in tbtrans
        print("< module_{}.xyz > \n   elec-pos end {} (or {})".format(
            i + 1, al[-1] + 1, -1 - (l_nal[:len(l_nal) - (i + 1)].sum())))

    l_al = np.asarray(l_al)

    # Find buffer
    # NB: that cuboids are always independent from the sorting in the host geometry
    l_buf = []
    for mod, xyz, al in zip(modules, positions, l_al):
        area_B = mod[2].copy()
        area_B.set_center(xyz)
        almostbuffer = area_B.within_index(H.xyz)
        buffer_i = np.in1d(almostbuffer, al, assume_unique=True, invert=True)
        buf = almostbuffer[buffer_i]
        l_buf.append(buf)

    # Check final frames and buffers
    all_al = np.concatenate(l_al[:])
    all_buf = np.concatenate(l_buf[:])
    v = H.geom.copy()
    v.atom[all_al] = si.Atom(8, R=[1.44])
    v.atom[all_buf] = si.Atom(10, R=[1.44])
    v.write('framesbuffer.xyz')

    # Write buffer xyz and fdf block
    from tbtncTools import list2range_TBTblock
    with open('block_buffer.fdf', 'w') as fb:
        fb.write("%block TBT.Atoms.Buffer\n")
        fb.write(list2range_TBTblock(all_buf))
        fb.write("\n%endblock\n")

    return H, l_al, l_buf
예제 #18
0
    def from_block(cls, block):
        """ Return an `Atom` for a specified basis block

        Parameters
        ----------
        block : list or str
           the PAO.basis block (as read from an fdf file).
           Should be a list of lines.
        """
        if isinstance(block, str):
            block = block.splitlines()
        else:
            # store local list
            block = list(block)

        def blockline():
            nonlocal block
            out = ""
            while len(out) == 0:
                out = block.pop(0).split('#')[0].strip()
            return out

        # define global opts
        opts = {}

        specie = blockline()
        specie = specie.split()
        if len(specie) == 4:
            # we have Symbol, nl, type, ionic_charge
            symbol, nl, opts["type"], opts["ion_charge"] = specie
        elif len(specie) == 3:
            # we have Symbol, nl, type
            # or
            # we have Symbol, nl, ionic_charge
            symbol, nl, opt = specie
            try:
                opts["ion_charge"] = float(opt)
            except:
                opts["type"] = opt
        elif len(specie) == 2:
            # we have Symbol, nl
            symbol, nl = specie
            type = None

        # now loop orbitals
        orbs = []
        for _ in range(int(nl)):
            # we have 2 or 3 lines
            nl_line = blockline()
            rc_line = blockline()
            # check if we have contraction in the line
            # This is not perfect, but should grab
            # contration lines rather than next orbital line.
            # This is because the first n=<integer> should never
            # contain a ".", whereas the contraction *should*.
            if len(block) > 0:
                if '.' in block[0].split()[0]:
                    contract_line = blockline()

            # remove n=
            nl_line = nl_line.replace("n=", "").split()

            # first 3 are n, l, Nzeta
            n = int(nl_line.pop(0))
            l = int(nl_line.pop(0))
            nzeta = int(nl_line.pop(0))
            # assign defaults
            nlopts = {}

            while len(nl_line) > 0:
                opt = nl_line.pop(0)
                if opt == "P":
                    try:
                        npol = int(nl_line[0])
                        nl_line.pop(0)
                        nlopts["pol"] = npol
                    except:
                        nlopts["pol"] = 1
                elif opt == "S":
                    nlopts["split"] = float(nl_line.pop(0))
                elif opt == "F":
                    nlopts["filter"] = float(nl_line.pop(0)) / _eV2Ry
                elif opt == "E":
                    # 1 or 2 values
                    V0 = float(nl_line.pop(0)) / _eV2Ry
                    try:
                        ri = float(nl_line[0]) / _Ang2Bohr
                        nl_line.pop(0)
                    except:
                        # default to None (uses siesta default)
                        ri = None
                    nlopts["soft"] = [V0, ri]
                elif opt == "Q":
                    # 1, 2 or 3 values
                    charge = float(nl_line.pop(0))
                    try:
                        # this is in Bohr-1
                        yukawa = float(nl_line[0]) * _Ang2Bohr
                        nl_line.pop(0)
                    except:
                        # default to None (uses siesta default)
                        yukawa = None
                    try:
                        width = float(nl_line[0]) / _Ang2Bohr
                        nl_line.pop(0)
                    except:
                        # default to None (uses siesta default)
                        width = None
                    nlopts["charge"] = [charge, yukawa, width]

            # now we have everything to build the orbitals etc.
            for izeta, rc in enumerate(map(float, rc_line.split()), 1):
                if rc > 0:
                    rc /= _Ang2Bohr
                elif rc < 0 and izeta > 1:
                    rc *= -orbs[-1].R
                elif rc == 0 and izeta > 1:
                    # this is ok, the split-norm will be used to
                    # calculate the radius
                    pass
                else:
                    raise ValueError(
                        f"Could not parse the PAO.Basis block for the zeta ranges {rc_line}."
                    )
                orb = si.AtomicOrbital(n=n, l=l, m=0, zeta=izeta, R=rc)
                nzeta -= 1
                orbs.append(orb)

            # In case the final orbitals hasn't been defined.
            # They really should be defined in this one, but sometimes it may be
            # useful to leave the rc's definitions out.
            rc = orbs[-1].R
            for izeta in range(nzeta):
                orb = si.AtomicOrbital(n=n,
                                       l=l,
                                       m=0,
                                       zeta=orbs[-1].zeta + 1,
                                       R=rc)
                orbs.append(orb)
            opts[(n, l)] = nlopts

        # Now create the atom
        atom = si.Atom(symbol, orbs)
        return cls(atom, opts)
예제 #19
0
파일: _atom.py 프로젝트: tfrederiksen/sisl
    def from_input(cls, inp):
        """ Return atom object respecting the input

        Parameters
        ----------
        inp : list or str
           create `AtomInput` from the content of `inp`
        """
        def _get_content(f):
            if f.is_file():
                return open(f, 'r').readlines()
            return None

        if isinstance(inp, (tuple, list)):
            # it is already in correct format
            pass
        elif isinstance(inp, (str, Path)):
            # convert to path
            inp = Path(inp)

            # Check if it is a path or an input
            content = _get_content(inp)
            if content is None:
                content = _get_content(inp / "INP")
            if content is None:
                raise ValueError(
                    f"Could not find any input file in {str(inp)} or {str(inp / 'INP')}"
                )
            inp = content

        else:
            raise ValueError(f"Unknown input format inp={inp}?")

        # Now read lines
        defines = []
        opts = PropertyDict()

        def bypass_comments(inp):
            if inp[0].startswith("#"):
                inp.pop(0)
                bypass_comments(inp)

        def bypass(inp, defines):
            bypass_comments(inp)
            if inp[0].startswith("%define"):
                line = inp.pop(0)
                defines.append(line.split()[1].strip())
                bypass(inp, defines)

        bypass(inp, defines)

        # Now prepare reading
        # First line has to contain the *type* of calculation
        # pg|pe|ae|pt <comment>
        line = inp.pop(0).strip()
        if line.startswith("pg"):
            opts.cc = False
        elif line.startswith("pe"):
            opts.cc = True

        # <flavor> logr?
        line = inp.pop(0).strip().split()
        opts.flavor = line[0]
        if len(line) >= 2:
            opts.logr = float(line[1]) / _Ang2Bohr

        # <element> <xc>' rs'?
        line = inp.pop(0)
        symbol = line.split()[0]
        # now get xc equation
        if len(line) >= 11:
            opts.equation = line[10:10]
        opts.xc = line[:10].split()[1]
        line = line.split()
        if len(line) >= 3:
            opts.libxc = int(line[2])

        # currently not used line
        inp.pop(0)

        # core, valence
        core, valence = inp.pop(0).split()
        opts.core = int(core)
        valence = int(valence)

        orbs = []
        for _ in range(valence):
            n, l, *occ = inp.pop(0).split()
            orb = PropertyDict()
            orb.n = int(n)
            orb.l = int(l)
            # currently we don't distinguish between up/down
            orb.q0 = sum(map(float, occ))
            orbs.append(orb)

        # now we read the line with rc's and core-correction
        rcs = inp.pop(0).split()
        if len(rcs) >= 6:
            # core-correction
            opts.rcore = float(rcs[5]) / _Ang2Bohr

        for orb in orbs:
            orb.R = float(rcs[orb.l]) / _Ang2Bohr

        # Now create orbitals
        orbs = [si.AtomicOrbital(**orb, m=0, zeta=1) for orb in orbs]
        # now re-arrange ensuring we have correct order of l shells
        orbs = sorted(orbs, key=lambda orb: orb.l)
        atom = si.Atom(symbol, orbs)
        return cls(atom, defines, **opts)
예제 #20
0
def map_xyz(A,
            B,
            area_R_A,
            a_R_A=None,
            center_B=None,
            pos_B=None,
            area_for_buffer=None,
            tol=None):
    ### FRAME
    print('\nMapping from geometry A to geometry B')
    if a_R_A is None:
        # Recover atoms in R_A region of model A
        a_R_A = area_R_A.within_index(A.xyz)

    # Find the set R_B of unique corresponding atoms in model B
    area_R_B = area_R_A.copy()

    if pos_B is not None:
        vector = pos_B
        B_translated = B.translate(-vector)
    else:
        if center_B is None:
            center_B = B.center(what='xyz')
        vector = center_B - area_R_B.center
        B_translated = B.translate(-vector)
    a_R_B = area_R_B.within_index(B_translated.xyz)

    R_A = A.sub(a_R_A)
    R_B = B.sub(a_R_B)
    v1, v2 = np.amin(R_A.xyz, axis=0), np.amin(R_B.xyz, axis=0)
    xyz_B_shifted = R_B.xyz - v2[None, :]
    xyz_A_shifted = R_A.xyz - v1[None, :]

    if tol is None:
        tol = [0.01, 0.01, 0.01]
    tol = np.asarray(tol)
    print('Tolerance along x,y,z is set to {}'.format(tol))

    # Check if a_R_A is included in a_R_B and if yes, try to solve the problem
    # Following `https://stackoverflow.com/questions/33513204/finding-intersection-of-two-matrices-in-python-within-a-tolerance`
    # Get absolute differences between xyz_B_shifted and xyz_A_shifted keeping their columns aligned
    diffs = np.abs(
        xyz_B_shifted.reshape(-1, 1, 3) - xyz_A_shifted.reshape(1, -1, 3))
    # Compare each row with the triplet from `tol`.
    # Get mask of all matching rows and finally get the matching indices
    x1, x2 = np.nonzero((diffs < tol.reshape(1, 1, -1)).all(2))
    idx_swap = np.argsort(x2[:len(x1)])
    x1_reorder = x1[idx_swap]

    # CHECK
    if len(x1) == len(a_R_A):
        if len(a_R_B) > len(a_R_A):
            print('\nWARNING: len(a_R_A) = {} is not equal to len(a_R_B) = {}'.
                  format(len(a_R_A), len(a_R_B)))
            print(
                'But since a_R_A is entirely contained in a_R_B, I will fix it by removing the extra atoms'
            )
        print(
            '\n OK! The coordinates of the mapped atoms in the two geometries match \
within the desired tolerance! ;)')
    else:
        print('\nWARNING: len(a_R_A) = {} is not equal to len(a_R_B) = {}'.
              format(len(a_R_A), len(a_R_B)))
        print('\n STOOOOOP: not all elements of a_R_A are in a_R_B')
        print('   Check `a_R_B_not_matching.xyz` vs `a_R_A.xyz` and \
try to set `pos_B` to `B.center(what=\'xyz\') + [dx,dy,dz]`. Or increase the tolerance'
              )
        v = B.geom.copy()
        v.atom[a_R_B] = si.Atom(8, R=[1.44])
        v.write('a_R_B_not_matching.xyz')
        exit(1)

    a_R_B, a_R_A = a_R_B[x1_reorder], a_R_A[x2]

    # Further CHECK, just to be sure
    if not np.allclose(xyz_B_shifted[x1],
                       xyz_A_shifted[x2],
                       rtol=np.amax(tol),
                       atol=np.amax(tol)):
        print(
            '\n STOOOOOP: The coordinates of the mapped atoms in the two geometries don\'t match \
within the tolerance!!!!')
        print('   Check `a_R_B_not_matching.xyz` vs `a_R_A.xyz` and \
try to set `pos_B` to `B.center(what=\'xyz\') + [dx,dy,dz]`. Or increase the tolerance'
              )
        v = B.geom.copy()
        v.atom[a_R_B] = si.Atom(8, R=[1.44])
        v.write('a_R_B_not_matching.xyz')
        exit(1)

    print(' Max deviation (Ang) =',
          np.amax(xyz_A_shifted[x2] - xyz_B_shifted[x1]))

    # WARNING: we are about to rearrange the atoms in the host geometry!!!
    a_R_B_rearranged, new_B = rearrange(B, a_R_B, where='end')
    print("\nSelected atoms mapped into host geometry, after rearrangement\n\
at the end of the coordinates list (1-based): {}\n{}".format(
        len(a_R_B_rearranged), list2range_TBTblock(a_R_B_rearranged)))

    # Find and print buffer atoms
    if area_for_buffer is not None:
        # NB: that cuboids are always independent from the sorting in the host geometry
        area_B = area_for_buffer.copy()
        if center_B is not None:
            area_B.set_center(center_B)
        almostbuffer = area_B.within_index(new_B.xyz)
        buffer_i = np.in1d(almostbuffer,
                           a_R_B_rearranged,
                           assume_unique=True,
                           invert=True)
        buffer = almostbuffer[buffer_i]
        return a_R_B_rearranged, new_B, buffer
    else:
        return a_R_B_rearranged, new_B
예제 #21
0
def makearea(TSHS,
             shape='Cuboid',
             z_area=None,
             ext_offset=None,
             center=None,
             thickness=None,
             zaxis=2,
             atoms=None,
             segment_dir=None):
    """
    In frame cases, we are going to define an outer area 'area_ext' 
    and an inner area 'area_R2', and we are going to subtract them.
    The resulting area is called 'Delta'
    TSHS:           Hamiltonian or geometry object
    shape:          shape (check sisl doc)
                    ['Cube', 'Cuboid', 'Ellipsoid', 'Sphere', 'Segment']
    z_area:         coordinate at which the area should be defined [Angstrom] 
                    Default is along direction 2. Otherwise, change z_axis
    ext_offset:     [3x1 array] Use this to set an offset along any direction in area_ext
    center:         center of area plane in TSHS
    thickness:      thickness of area [Angstrom]
    zaxis:          [0,1,2] direction perpendicular to area plane
    atoms:          list of atomic indices to filter the atoms inside Delta
    segment_dir:    [0,1,2] direction along the smallest side of the segment 
    
    Note:
    - it works for orthogonal cells! Needs some adjustments to be general... 
    """
    # z coordinate of area plane
    if z_area is None:
        print('\n\nPlease provide a value for z_area in makearea routine')
        exit(1)
    # Center of area plane in TSHS
    cellcenter = TSHS.center(atom=(TSHS.xyz[:, zaxis] == z_area).nonzero()[0])
    if center is None:
        center = cellcenter
    center = np.asarray(center)  # make sure it's an array
    # Thickness in Ang
    if thickness is None:
        thickness = 6.  # Ang
    thickness = np.asarray(thickness, np.float64)

    # Cuboid or Ellissoid?
    if zaxis == 2:
        size = .5 * np.diagonal(TSHS.cell) + [
            0, 0, 300
        ]  # default radius is half the cell size
    elif zaxis == 0:
        size = .5 * np.diagonal(TSHS.cell) + [
            300, 0, 0
        ]  # default radius is half the cell size
    elif zaxis == 1:
        size = .5 * np.diagonal(TSHS.cell) + [
            0, 300, 0
        ]  # default radius is half the cell size

    if shape == 'Ellipsoid' or shape == 'Sphere':
        mkshape = si.shape.Ellipsoid
    elif shape == 'Cuboid' or shape == 'Cube':
        mkshape = si.shape.Cuboid
        # In this case it's the full perimeter so we double
        size *= 2
        thickness *= 2
        if ext_offset is not None:
            ext_offset = np.asarray(ext_offset, np.float64).copy()
            ext_offset *= 2
    elif shape == 'Segment':
        mkshape = si.shape.Cuboid
        # In this case it's the full perimeter so we double
        size *= 2
        size[segment_dir] = thickness
        if ext_offset is not None:
            ext_offset = np.asarray(ext_offset, np.float64).copy()
    else:
        print('\n shape = "{}" is not implemented...'.format(shape))
        exit(1)

    if shape == 'Segment':  # ADD COMPLEMENTARY AREA...
        # Areas
        Delta = mkshape(size, center=center)
        # Atoms within Delta and complementary area
        a_Delta = Delta.within_index(TSHS.xyz)
        if atoms is not None:
            a_Delta = a_Delta[np.in1d(a_Delta, atoms)]
        # Check
        v = TSHS.geom.copy()
        v.atom[a_Delta] = si.Atom(8, R=[1.43])
        v.write('a_Delta.xyz')
        return a_Delta, Delta
    else:
        # External boundary
        area_ext = mkshape(size, center=center)
        # Adjust with ext_offset if necessary
        if ext_offset is not None:
            ext_offset = np.asarray(ext_offset, np.float64)
            area_ext = area_ext.expand(-ext_offset)
            # Force it to be Cube or Sphere (side = ext_offset) if necessary
            if shape == 'Sphere' or shape == 'Cube':
                if len(ext_offset.nonzero()[0]) > 1:
                    print(
                        'Offset is in both axes. Please set "shape" to Cuboid or Ellipsoid'
                    )
                    exit(1)
                axis = ext_offset.nonzero()[0][0]
                print(
                    'Offset is non-zero along axis: {}...complementary is {}'.
                    format(axis, int(axis < 1)))
                new_ext_offset = np.zeros(3)
                new_ext_offset[int(axis < 1)] = ext_offset[axis]
                area_ext = area_ext.expand(-new_ext_offset)

        # Internal boundary
        area_R2 = area_ext.expand(-thickness)
        # Disjuction composite shape
        Delta = area_ext - area_R2
        # Atoms within Delta and internal boundary
        a_Delta = Delta.within_index(TSHS.xyz)
        a_int = area_R2.within_index(TSHS.xyz)
        if atoms is not None:
            a_Delta = a_Delta[np.in1d(a_Delta, atoms)]
        # Check
        v = TSHS.geom.copy()
        v.atom[a_Delta] = si.Atom(8, R=[1.43])
        v.write('a_Delta.xyz')
        return a_Delta, a_int, Delta, area_ext, area_R2
예제 #22
0
파일: test-zak.py 프로젝트: dipc-cc/hubbard
from hubbard import HubbardHamiltonian, sp2
import numpy as np
import sisl

for w in range(1, 25, 2):
    g = sisl.geom.agnr(w)
    H0 = sp2(g)
    H = HubbardHamiltonian(H0, U=0)
    zak = H.get_Zak_phase()
    print(f'width={w:3}, zak={zak:7.3f}')

# SSH model, topological cell
g = sisl.Geometry([[0, 0, 0], [0, 1.65, 0]],
                  sisl.Atom(6, 1.001),
                  sc=[10, 3, 10])
g.set_nsc([1, 3, 1])
H0 = sp2(g)
H = HubbardHamiltonian(H0, U=0)
zak = H.get_Zak_phase(axis=1)
print(f'SSH topo : zak={zak:7.3f}')

# SSH model, trivial cell
g = sisl.Geometry([[0, 0, 0], [0, 1.42, 0]],
                  sisl.Atom(6, 1.001),
                  sc=[10, 3, 10])
g.set_nsc([1, 3, 1])
H0 = sp2(g)
H = HubbardHamiltonian(H0, U=0)
zak = H.get_Zak_phase(axis=1)
print(f'SSH triv : zak={zak:7.3f}')
예제 #23
0
def pre_prepare_sisl (frac_or_cart_or_index,Initial_Geom,InitialAtomPosition,FinalAtomPosition,rtol,atol,Ghost):

    """
    
    """
    import sisl

    if frac_or_cart_or_index == 'cartesian':
        print ("Cartesian ...(BUGGGGGGGG! SHOULD FIX)")
        #Initial_Geom = Fdf.read_geometry()
        XYZ = Initial_Geom.xyz
        InitialASEXYZ = Initial_Geom
        FinalASEXYZ = Initial_Geom
        print ("Removing Vacancies Ang/Bohr")
        print ("Removing Index for Initial Atom:{}".format(AtomIndex(XYZ,InitialAtomPosition,rtol,atol)))
        print ("Removing Index for Final Atom:{}".format(AtomIndex(XYZ,FinalAtomPosition,rtol,atol)))
        if Ghost == True:
            Ghost_initial = sisl.Geometry(Initial_Geom.xyz[AtomIndex(XYZ,InitialAtomPosition,rtol,atol)],
                                          atoms= -1* Initial_Geom.atoms.Z[AtomIndex(XYZ,InitialAtomPosition,rtol,atol)]
                                          )
            Ghost_final = sisl.Geometry(Initial_Geom.xyz[AtomIndex(XYZ,FinalAtomPosition,rtol,atol)],
                                        atoms= -1* Initial_Geom.atoms.Z[AtomIndex(XYZ,FinalAtomPosition,rtol,atol)]
                                         )       
        trace_atom_initial = sisl.Geometry(Initial_Geom.xyz[AtomIndex(XYZ,InitialAtomPosition,rtol,atol)],
                                      atoms= Initial_Geom.atoms.Z[AtomIndex(XYZ,InitialAtomPosition,rtol,atol)]
                                     )
        trace_atom_final = sisl.Geometry(Initial_Geom.xyz[AtomIndex(XYZ,FinalAtomPosition,rtol,atol)],
                                    atoms=  Initial_Geom.atoms.Z[AtomIndex(XYZ,FinalAtomPosition,rtol,atol)]
                                     )       
        InitialASEXYZ = InitialASEXYZ.remove(AtomIndex(XYZ,InitialAtomPosition,rtol,atol))
        FinalASEXYZ = FinalASEXYZ.remove(AtomIndex(XYZ,FinalAtomPosition,rtol,atol))
        if AtomIndex(XYZ,FinalAtomPosition,rtol,atol) > AtomIndex(XYZ,InitialAtomPosition,rtol,atol):
            print ("Order : Final Atom Position > Initial Atom Position")
            InitialASEXYZ = InitialASEXYZ.remove(AtomIndex(XYZ,FinalAtomPosition,rtol,atol)-1)
            FinalASEXYZ = FinalASEXYZ.remove(AtomIndex(XYZ,InitialAtomPosition,rtol,atol))
        if AtomIndex(XYZ,FinalAtomPosition,rtol,atol) < AtomIndex(XYZ,InitialAtomPosition,rtol,atol):
            print ("Order : Initial Atom Position > Final Atom Position")
            InitialASEXYZ = InitialASEXYZ.remove(AtomIndex(XYZ,FinalAtomPosition,rtol,atol))
            FinalASEXYZ = FinalASEXYZ.remove(AtomIndex(XYZ,InitialAtomPosition,rtol,atol)-1)   
    elif frac_or_cart_or_index  == 'frac':
        #print ("Removing Vacancies Fractional NOT Implemented")
        print ("Fractional ... (BUGGGGGGGG SHOULD FIX)")
        Frac = Initial_Geom.fxyz
        InitialASEXYZ = Initial_Geom
        FinalASEXYZ = Initial_Geom
        print ("Removing Vacancies Ang/Bohr")
        print ("Removing Index for Initial Atom:{}".format(AtomIndex(Frac,InitialAtomPosition,rtol,atol)))
        print ("Removing Index for Final Atom:{}".format(AtomIndex(Frac,FinalAtomPosition,rtol,atol)))
        if Ghost == True:
            Ghost_initial = sisl.Geometry(Initial_Geom.xyz[AtomIndex(Frac,InitialAtomPosition,rtol,atol)],
                                          atoms= -1* Initial_Geom.atoms.Z[AtomIndex(Frac,InitialAtomPosition,rtol,atol)]
                                          )
            Ghost_final = sisl.Geometry(Initial_Geom.xyz[AtomIndex(Frac,FinalAtomPosition,rtol,atol)],
                                        atoms= -1* Initial_Geom.atoms.Z[AtomIndex(Frac,FinalAtomPosition,rtol,atol)]
                                       )    
        trace_atom_initial = sisl.Geometry(Initial_Geom.xyz[AtomIndex(Frac,InitialAtomPosition,rtol,atol)],
                                      atoms= Initial_Geom.atoms.Z[AtomIndex(Frac,InitialAtomPosition,rtol,atol)]
                                      )
        trace_atom_final = sisl.Geometry(Initial_Geom.xyz[AtomIndex(Frac,FinalAtomPosition,rtol,atol)],
                                        atoms= Initial_Geom.atoms.Z[AtomIndex(Frac,FinalAtomPosition,rtol,atol)]
                                       )    

        InitialASEXYZ = InitialASEXYZ.remove(AtomIndex(Frac,InitialAtomPosition,rtol,atol))
        FinalASEXYZ = FinalASEXYZ.remove(AtomIndex(Frac,FinalAtomPosition,rtol,atol))
        if AtomIndex(Frac,FinalAtomPosition,rtol,atol) > AtomIndex(Frac,InitialAtomPosition,rtol,atol):
            print ("Order : Final Atom Position > Initial Atom Position")
            InitialASEXYZ = InitialASEXYZ.remove(AtomIndex(Frac,FinalAtomPosition,rtol,atol)-1)
            FinalASEXYZ = FinalASEXYZ.remove(AtomIndex(Frac,InitialAtomPosition,rtol,atol))
        if AtomIndex(Frac,FinalAtomPosition,rtol,atol) < AtomIndex(Frac,InitialAtomPosition,rtol,atol):
            print ("Order : Initial Atom Position > Final Atom Position")
            InitialASEXYZ = InitialASEXYZ.remove(AtomIndex(Frac,FinalAtomPosition,rtol,atol))
            FinalASEXYZ = FinalASEXYZ.remove(AtomIndex(Frac,InitialAtomPosition,rtol,atol)-1)
    else:
        print('index')
        #Frac = Initial_Geom.fxyz
        InitialASEXYZ = Initial_Geom
        FinalASEXYZ = Initial_Geom
        print ("Removing Vacancies Ang/Bohr")
        print ("Removing Index for Initial Atom:{}".format(InitialAtomPosition-1))
        print ("Removing Index for Final Atom:{}".format(FinalAtomPosition-1))
        if Ghost == True:
            #Ghost_initial = sisl.Geometry(Initial_Geom.xyz[InitialAtomPosition-1],
            #                              atoms= -1* Initial_Geom.atoms.Z[InitialAtomPosition-1]
            #                              )
            #Ghost_final = sisl.Geometry(Initial_Geom.xyz[FinalAtomPosition-1],
            #                            atoms= -1* Initial_Geom.atoms.Z[FinalAtomPosition-1]
            #                             )       

            Ghost_initial_Info = sisl.Atom(Initial_Geom.atoms.Z[InitialAtomPosition-1])
            Ghost_initial = sisl.Geometry(Initial_Geom.xyz[InitialAtomPosition-1],
                                          atoms= sisl.Atom( -1* Ghost_initial_Info.Z , tag=Ghost_initial_Info.symbol+"_ghost"))
            
            Ghost_final_Info = sisl.Atom(Initial_Geom.atoms.Z[FinalAtomPosition-1])
            Ghost_final = sisl.Geometry(Initial_Geom.xyz[ FinalAtomPosition-1 ],
                                        atoms=sisl.Atom( -1* Ghost_final_Info.Z,tag = Ghost_final_Info.symbol+"_ghost" ))
        trace_atom_initial = sisl.Geometry(Initial_Geom.xyz[InitialAtomPosition-1],
                                      atoms= Initial_Geom.atoms.Z[InitialAtomPosition-1]
                                     )
        trace_atom_final = sisl.Geometry(Initial_Geom.xyz[FinalAtomPosition-1],
                                    atoms=  Initial_Geom.atoms.Z[FinalAtomPosition-1]
                                     )       
        InitialASEXYZ = InitialASEXYZ.remove(InitialAtomPosition-1)
        FinalASEXYZ = FinalASEXYZ.remove(FinalAtomPosition-1)
        if (FinalAtomPosition-1) > (InitialAtomPosition-1):
            print ("Order : Final Atom Position > Initial Atom Position")
            InitialASEXYZ = InitialASEXYZ.remove(FinalAtomPosition-2)
            FinalASEXYZ = FinalASEXYZ.remove(InitialAtomPosition-1)
        if (FinalAtomPosition-1) < (InitialAtomPosition-1):
            print ("Order : Initial Atom Position > Final Atom Position")
            InitialASEXYZ = InitialASEXYZ.remove(FinalAtomPosition-1)
            FinalASEXYZ = FinalASEXYZ.remove(InitialAtomPosition-2)   

    
    InitialASEXYZ = InitialASEXYZ.add(trace_atom_final)
    FinalASEXYZ = FinalASEXYZ.add(trace_atom_initial)

    if Ghost == True:
        info_sisl = {'initial' : InitialASEXYZ, 
                 'final' : FinalASEXYZ,
                 'trace_atom_initial' : trace_atom_initial,
                 'trace_atom_final' : trace_atom_final,
                 'Ghost_initial' : Ghost_initial,
                 'Ghost_final' : Ghost_final,
                 }
    else:
        info_sisl = {'initial' : InitialASEXYZ,
                    'final' : FinalASEXYZ,
                    'trace_atom_initial' : trace_atom_initial,
                    'trace_atom_final' : trace_atom_final,
                    }


    return info_sisl
예제 #24
0
import plotly.graph_objs as go
import numpy as np

import sisl

r = np.linspace(0, 3.5, 50)
f = np.exp(-r)

orb = sisl.AtomicOrbital('2pzZ', (r, f))
geom = sisl.geom.graphene(orthogonal=True, atoms=sisl.Atom(6, orb))
geom = geom.move([0, 0, 5])
H = sisl.Hamiltonian(geom)
H.construct([(0.1, 1.44), (0, -2.7)], )


def test_eigenstate_wf():

    plot = H.eigenstate()[0].plot.wavefunction(geometry=H.geometry)

    assert len(plot.data) > 0
    assert isinstance(plot.data[0], go.Isosurface)


def test_hamiltonian_wf():

    # Check if it works for 3D plots
    plot = H.plot.wavefunction(2)
    assert isinstance(plot.data[0], go.Isosurface)

    # Check that setting plot geom to True adds data traces
    plot.update_settings(plot_geom=False)
예제 #25
0
파일: test_tbt.py 프로젝트: freude/sisl
def test_1_graphene_all_content(sisl_files):
    """ This tests manifolds itself as:

    sisl.geom.graphene(orthogonal=True).tile(3, 0).tile(5, 1)

    All output is enabled:

    ### FDF ###
    # Transmission related quantities
    TBT.T.All T
    TBT.T.Out T
    TBT.T.Eig 2

    # Density of states
    TBT.DOS.Elecs T
    TBT.DOS.Gf T
    TBT.DOS.A T
    TBT.DOS.A.All T

    # Orbital currents and Crystal-Orbital investigations.
    TBT.Symmetry.TimeReversal F
    TBT.Current.Orb T
    TBT.COOP.Gf T
    TBT.COOP.A T
    TBT.COHP.Gf T
    TBT.COHP.A T

    TBT.k [100 1 1]
    ### FDF ###
    """
    tbt = sisl.get_sile(sisl_files(_dir, '1_graphene_all.TBT.nc'))
    assert tbt.E.min() > -2.
    assert tbt.E.max() < 2.
    # We have 400 energy-points
    ne = len(tbt.E)
    assert ne == 400
    assert tbt.ne == ne

    # We have 100 k-points
    nk = len(tbt.kpt)
    assert nk == 100
    assert tbt.nk == nk
    assert tbt.wk.sum() == pytest.approx(1.)

    for i in range(ne):
        assert tbt.Eindex(i) == i
        assert tbt.Eindex(tbt.E[i]) == i

    # Check raises
    with pytest.warns(sisl.SislWarning):
        tbt.Eindex(tbt.E.min() - 1.)
    with pytest.warns(sisl.SislInfo):
        tbt.Eindex(tbt.E.min() - 2e-3)
    with pytest.warns(sisl.SislWarning):
        tbt.kindex([0, 0, 0.5])
    # Can't hit it
    #with pytest.warns(sisl.SislInfo):
    #    tbt.kindex([0.0106, 0, 0])

    for i in range(nk):
        assert tbt.kindex(i) == i
        assert tbt.kindex(tbt.kpt[i]) == i

    # Get geometry
    geom = tbt.geometry
    geom_c1 = tbt.read_geometry(atom=sisl.Atoms(sisl.Atom[6], geom.na))
    geom_c2 = tbt.read_geometry(atom=sisl.Atoms(sisl.Atom(6, orbs=2), geom.na))
    assert geom_c1 == geom_c2

    # Check read is the same as the direct query
    assert tbt.na == geom.na
    assert tbt.no == geom.no
    assert tbt.no == geom.na
    assert tbt.na == 3 * 5 * 4
    assert np.allclose(tbt.cell, geom.cell)

    # Check device atoms (1-orbital system)
    assert tbt.na_d == tbt.no_d
    assert tbt.na_d == 36  # 3 * 5 * 4 (and device is without electrodes, so 3 * 3 * 4)
    assert len(
        tbt.pivot()
    ) == 3 * 3 * 4  # 3 * 5 * 4 (and device is without electrodes, so 3 * 3 * 4)
    assert len(tbt.pivot(True)) == len(tbt.pivot())
    assert np.all(tbt.pivot(True, True) == np.arange(tbt.no_d))
    assert np.all(tbt.pivot(sort=True) == np.sort(tbt.pivot()))

    # Just check they are there
    assert tbt.n_btd() == len(tbt.btd())

    # Check electrodes
    assert len(tbt.elecs) == 2
    elecs = tbt.elecs[:]
    assert elecs == ['Left', 'Right']
    for i, elec in enumerate(elecs):
        assert tbt._elec(i) == elec

    # Check the chemical potentials
    for elec in elecs:
        assert tbt.n_btd(elec) == len(tbt.btd(elec))
        assert tbt.chemical_potential(elec) == pytest.approx(0.)
        assert tbt.electronic_temperature(elec) == pytest.approx(300., abs=1)
        assert tbt.eta(elec) == pytest.approx(1e-4, abs=1e-6)

    # Check electrode relevant stuff
    left = elecs[0]
    right = elecs[1]

    # Assert we have transmission symmetry
    assert np.allclose(tbt.transmission(left, right),
                       tbt.transmission(right, left))
    assert np.allclose(tbt.transmission_eig(left, right),
                       tbt.transmission_eig(right, left))
    # Check that the total transmission is larger than the sum of transmission eigenvalues
    assert np.all(
        tbt.transmission(left, right) +
        1e-7 >= tbt.transmission_eig(left, right).sum(-1))
    assert np.all(
        tbt.transmission(right, left) +
        1e-7 >= tbt.transmission_eig(right, left).sum(-1))

    # Check that we can't retrieve from same to same electrode
    with pytest.raises(ValueError):
        tbt.transmission(left, left)
    with pytest.raises(ValueError):
        tbt.transmission_eig(left, left)

    assert np.allclose(tbt.transmission(left, right, kavg=False),
                       tbt.transmission(right, left, kavg=False))

    # Also check for each k
    for ik in range(nk):
        assert np.allclose(tbt.transmission(left, right, ik),
                           tbt.transmission(right, left, ik))
        assert np.allclose(tbt.transmission_eig(left, right, ik),
                           tbt.transmission_eig(right, left, ik))
        assert np.all(
            tbt.transmission(left, right, ik) +
            1e-7 >= tbt.transmission_eig(left, right, ik).sum(-1))
        assert np.all(
            tbt.transmission(right, left, ik) +
            1e-7 >= tbt.transmission_eig(right, left, ik).sum(-1))
        assert np.allclose(tbt.DOS(kavg=ik),
                           tbt.ADOS(left, kavg=ik) + tbt.ADOS(right, kavg=ik))
        assert np.allclose(
            tbt.DOS(E=0.195, kavg=ik),
            tbt.ADOS(left, E=0.195, kavg=ik) +
            tbt.ADOS(right, E=0.195, kavg=ik))

    kavg = list(range(10))
    assert np.allclose(tbt.DOS(kavg=kavg),
                       tbt.ADOS(left, kavg=kavg) + tbt.ADOS(right, kavg=kavg))
    assert np.allclose(
        tbt.DOS(E=0.195, kavg=kavg),
        tbt.ADOS(left, E=0.195, kavg=kavg) +
        tbt.ADOS(right, E=0.195, kavg=kavg))

    # Check that norm returns correct values
    assert tbt.norm() == 1
    assert tbt.norm(norm='all') == tbt.no_d
    assert tbt.norm(norm='atom') == tbt.norm(norm='orbital')

    # Check atom is equivalent to orbital
    for norm in ['atom', 'orbital']:
        assert tbt.norm(0, norm=norm) == 0.
        assert tbt.norm(3 * 4, norm=norm) == 1
        assert tbt.norm(range(3 * 4, 3 * 5), norm=norm) == 3

    # Assert sum(ADOS) == DOS
    assert np.allclose(tbt.DOS(), tbt.ADOS(left) + tbt.ADOS(right))
    assert np.allclose(tbt.DOS(sum=False),
                       tbt.ADOS(left, sum=False) + tbt.ADOS(right, sum=False))

    # Now check orbital resolved DOS
    assert np.allclose(tbt.DOS(sum=False),
                       tbt.ADOS(left, sum=False) + tbt.ADOS(right, sum=False))

    # Current must be 0 when the chemical potentials are equal
    assert tbt.current(left, right) == pytest.approx(0.)
    assert tbt.current(right, left) == pytest.approx(0.)

    high_low = tbt.current_parameter(left, 0.5, 0.0025, right, -0.5, 0.0025)
    low_high = tbt.current_parameter(left, -0.5, 0.0025, right, 0.5, 0.0025)
    assert high_low > 0.
    assert low_high < 0.
    assert -high_low == pytest.approx(low_high)
    with pytest.warns(sisl.SislWarning):
        tbt.current_parameter(left, -10., 0.0025, right, 10., 0.0025)

    # Since this is a perfect system there should be *no* QM shot-noise
    # Also, the shot-noise is related to the applied bias, so NO shot-noise
    assert np.allclose(tbt.shot_noise(left, right), 0.)
    assert np.allclose(tbt.shot_noise(right, left), 0.)
    # Since the data-file does not contain all T-eigs (only the first two)
    # we can't correctly calculate the fano factors
    assert np.all(tbt.fano(left, right) > 0.)
    assert np.all(tbt.fano(right, left) > 0.)

    # Check specific DOS queries
    DOS = tbt.DOS
    ADOS = tbt.ADOS

    atom = range(8, 40)  # some in device, some not in device
    for o in ['atom', 'orbital']:
        opt = {o: atom}

        for E in [None, 2, 4]:
            assert np.allclose(DOS(E), ADOS(left, E) + ADOS(right, E))
            assert np.allclose(DOS(E, **opt),
                               ADOS(left, E, **opt) + ADOS(right, E, **opt))

        opt['sum'] = False
        for E in [None, 2, 4]:
            assert np.allclose(DOS(E), ADOS(left, E) + ADOS(right, E))
            assert np.allclose(DOS(E, **opt),
                               ADOS(left, E, **opt) + ADOS(right, E, **opt))

        opt['sum'] = True
        opt['norm'] = o
        for E in [None, 2, 4]:
            assert np.allclose(DOS(E), ADOS(left, E) + ADOS(right, E))
            assert np.allclose(DOS(E, **opt),
                               ADOS(left, E, **opt) + ADOS(right, E, **opt))

        opt['sum'] = False
        for E in [None, 2, 4]:
            assert np.allclose(DOS(E), ADOS(left, E) + ADOS(right, E))
            assert np.allclose(DOS(E, **opt),
                               ADOS(left, E, **opt) + ADOS(right, E, **opt))

    # Check orbital currents
    E = 201
    # Sum of orbital current should be 0 (in == out)
    orb_left = tbt.orbital_current(left, E)
    orb_right = tbt.orbital_current(right, E)
    assert orb_left.sum() == pytest.approx(0., abs=1e-7)
    assert orb_right.sum() == pytest.approx(0., abs=1e-7)

    d1 = np.arange(12, 24).reshape(-1, 1)
    d2 = np.arange(24, 36).reshape(-1, 1)
    assert orb_left[d1, d2.T].sum() == pytest.approx(
        tbt.transmission(left, right)[E])
    assert orb_left[d1, d2.T].sum() == pytest.approx(-orb_left[d2, d1.T].sum())
    assert orb_right[d2, d1.T].sum() == pytest.approx(
        tbt.transmission(right, left)[E])
    assert orb_right[d2,
                     d1.T].sum() == pytest.approx(-orb_right[d1, d2.T].sum())

    orb_left.sort_indices()
    atom_left = tbt.bond_current(left, E, only='all')
    atom_left.sort_indices()
    assert np.allclose(orb_left.data, atom_left.data)
    assert np.allclose(
        orb_left.data,
        tbt.bond_current_from_orbital(orb_left, only='all').data)
    orb_right.sort_indices()
    atom_right = tbt.bond_current(right, E, only='all')
    atom_right.sort_indices()
    assert np.allclose(orb_right.data, atom_right.data)
    assert np.allclose(
        orb_right.data,
        tbt.bond_current_from_orbital(orb_right, only='all').data)

    # Calculate the atom current
    # For 1-orbital systems the activity and non-activity are equivalent
    assert np.allclose(tbt.atom_current(left, E),
                       tbt.atom_current(left, E, activity=False))
    tbt.vector_current(left, E)
    assert np.allclose(
        tbt.vector_current_from_bond(atom_left) / 2,
        tbt.vector_current(left, E, only='all'))

    # Check COOP curves
    coop = tbt.orbital_COOP(E)
    coop_l = tbt.orbital_ACOOP(left, E)
    coop_r = tbt.orbital_ACOOP(right, E)
    assert np.allclose(coop.data, (coop_l + coop_r).data)

    coop = tbt.orbital_COOP(E, isc=[0, 0, 0])
    coop_l = tbt.orbital_ACOOP(left, E, isc=[0, 0, 0])
    coop_r = tbt.orbital_ACOOP(right, E, isc=[0, 0, 0])
    assert np.allclose(coop.data, (coop_l + coop_r).data)

    coop = tbt.atom_COOP(E)
    coop_l = tbt.atom_ACOOP(left, E)
    coop_r = tbt.atom_ACOOP(right, E)
    assert np.allclose(coop.data, (coop_l + coop_r).data)

    coop = tbt.atom_COOP(E, isc=[0, 0, 0])
    coop_l = tbt.atom_ACOOP(left, E, isc=[0, 0, 0])
    coop_r = tbt.atom_ACOOP(right, E, isc=[0, 0, 0])
    assert np.allclose(coop.data, (coop_l + coop_r).data)

    # Check COHP curves
    coop = tbt.orbital_COHP(E)
    coop_l = tbt.orbital_ACOHP(left, E)
    coop_r = tbt.orbital_ACOHP(right, E)
    assert np.allclose(coop.data, (coop_l + coop_r).data)

    coop = tbt.atom_COHP(E)
    coop_l = tbt.atom_ACOHP(left, E)
    coop_r = tbt.atom_ACOHP(right, E)
    assert np.allclose(coop.data, (coop_l + coop_r).data)

    # Simply print out information
    tbt.info()
    for elec in elecs:
        tbt.info(elec)
예제 #26
0
def si_pdos_kgrid_geom(with_orbs=True):
    if with_orbs:
        return sisl.geom.diamond(5.43, sisl.Atom('Si', R=np.arange(13) + 1))
    return sisl.geom.diamond(5.43, sisl.Atom('Si'))
예제 #27
0
    __slots__ = ('U', )

    def __init__(self, *args, U=0., **kwargs):
        super().__init__(*args, **kwargs)
        self.U = U

    def copy(self, *args, **kwargs):
        copy = super().copy(*args, **kwargs)
        copy.U = self.U
        return copy


# Multi-orbital tight-binding Hamiltonian, set U in the geometry
pz = OrbitalU(1.42, q0=1.0, U=3.)
s = OrbitalU(1.42, q0=0, U=0.)
C = sisl.Atom(6, orbitals=[pz, s])
g = geom.zgnr(W, atoms=C)

# Add another atom to have heterogeneous number of orbitals per atoms
C2 = sisl.Atom(6, orbitals=[pz])
G_C2 = sisl.Geometry(g.xyz[0], atoms=C2)
g = g.replace(0, G_C2)

# Identify index for atoms
idx = g.a2o(range(len(g)))

# Build U for each orbital in each atom
#U = np.zeros(g.no)
#U[idx] = 3.

# Build TB Hamiltonian, zeroes for non-pz orbitals
예제 #28
0
파일: ex_01.py 프로젝트: sofiasanz/sisl
#!/usr/bin/env python
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

# This example creates the tight-binding Hamiltonian
# for graphene with on-site energy 0, and hopping energy
# -2.7 eV.

import sisl

bond = 1.42
# Construct the atom with the appropriate orbital range
# Note the 0.01 which is for numerical accuracy.
C = sisl.Atom(6, R=bond + 0.01)
# Create graphene unit-cell
gr = sisl.geom.graphene(bond, C)

# Create the tight-binding Hamiltonian
H = sisl.Hamiltonian(gr)
R = [0.1 * bond, bond + 0.01]

for ia in gr:
    idx_a = gr.close(ia, R)
    # On-site
    H[ia, idx_a[0]] = 0.
    # Nearest neighbour hopping
    H[ia, idx_a[1]] = -2.7

# Calculate eigenvalues at K-point
print(H.eigh([2. / 3, 1. / 3, 0.]))
예제 #29
0
    def from_dict(cls, dic):
        """ Return an `AtomBasis` from a dictionary

        Parameters
        ----------
        dic : dict
        """
        from sisl_toolbox.siesta.atom._atom import _shell_order
        element = dic["element"]
        tag = dic.get("tag")
        mass = dic.get("mass", None)

        # get default options for pseudo
        opts = NotNonePropertyDict()

        basis = dic.get("basis", {})
        opts["ion_charge"] = parse_variable(basis.get("ion-charge")).value
        opts["type"] = basis.get("type")

        def get_radius(orbs, zeta):
            for orb in orbs:
                if orb.zeta == zeta:
                    return orb.R
            raise ValueError("Could parse the negative R value")

        orbs = []
        for nl in dic:
            if nl not in _shell_order:
                continue

            n, l = int(nl[0]), 'spdfg'.index(nl[1])
            # Now we are sure we are dealing with valence shells
            basis = dic[nl].get("basis", {})

            opt_nl = NotNonePropertyDict()
            orbs_nl = []

            # Now read through the entries
            for key, entry in basis.items():
                if key in ("charge-confinement", "charge-conf"):
                    opt_nl["charge"] = [
                        parse_variable(entry.get("charge")).value,
                        parse_variable(entry.get("yukawa"),
                                       unit='1/Ang').value,
                        parse_variable(entry.get("width"), unit='Ang').value
                    ]
                elif key in ("soft-confinement", "soft-conf"):
                    opt_nl["soft"] = [
                        parse_variable(entry.get("V0"), unit='eV').value,
                        parse_variable(entry.get("ri"), unit='Ang').value
                    ]
                elif key in ("filter", ):
                    opt_nl["filter"] = parse_variable(entry, unit='eV').value
                elif key in ("split-norm", "split"):
                    opt_nl["split"] = parse_variable(entry).value
                elif key in ("polarization", "pol"):
                    opt_nl["pol"] = parse_variable(entry).value
                elif key.startswith("zeta"):
                    # cutoff of zeta
                    zeta = int(key[4:])
                    R = parse_variable(entry, unit='Ang').value
                    if R < 0:
                        R *= -get_radius(orbs_nl, zeta - 1)
                    orbs_nl.append(
                        si.AtomicOrbital(n=n, l=l, m=0, zeta=zeta, R=R))

            if len(orbs_nl) > 0:
                opts[(n, l)] = opt_nl
                orbs.extend(orbs_nl)

        atom = si.Atom(element, orbs, mass=mass, tag=tag)
        return cls(atom, opts)
예제 #30
0
def in2out_frame_PBCoff(TSHS,
                        a_R1,
                        eta_value,
                        energies,
                        TBT,
                        HS_host,
                        orb_idx=None,
                        pos_dSE=None,
                        area_R1=None,
                        area_R2=None,
                        area_for_buffer=None,
                        TBTSE=None,
                        useCAP=None,
                        spin=0,
                        tol=None,
                        EfromTBT=True):
    """
    TSHS:                   TSHS from perturbed DFT system
    a_R1:                idx atoms in sub-region A of perturbed DFT system (e.g. frame)
                            \Sigma will live on these atoms
    eta_value:              imaginary part in Green's function
    energies:               energy in eV for which \Sigma should be computed (closest E in TBT will be used )
    TBT:                    *.TBT.nc (or *.TBT.SE.nc) from a TBtrans calc. where TBT.HS = TSHS 
    HS_host:                host (H, S) model (e.g. a large TB model of unperturbed system). 
                            Coordinates of atoms "a_R1" in TSHS will be mapped into this new model.
                            Atomic order will be adjusted so that mapped atoms will be consecutive and at the end of the list   
    orb_idx (=None):          idx of orbital per atom to be extracted from TSHS, in case HS_host has a reduced basis size
    pos_dSE (=0):           center of region where \Sigma atoms should be placed in HS_host 
    area_R1 (=None):     si.shape.Cuboid object used to select "a_R1" atoms in TSHS
    area_R2 (=None):              internal si.shape.Cuboid object used to construct area_R1 in TSHS
    area_for_buffer (=None):       external si.shape.Cuboid object used to used to construct area_R1 in TSHS
    TBTSE (=None):          *TBT.SE.nc file of self-energy enclosed by the atoms "a_R1" in TSHS (e.g., tip) 
    useCAP (=None):         use 'left+right+top+bottom' to set complex absorbing potential in all in-plane directions
    
    Important output files:
    "HS_DEV.nc":        HS file for TBtrans (to be used with "TBT.HS" flag)
                        this Hamiltonian is identical to HS_host, but it has no PBC 
                        and \Sigma projected atoms are moved to the end of the atom list   
    "SE_i.delta.nc":    \Delta \Sigma file for TBtrans (to be used as "TBT.dSE" flag)
                        it will contain \Sigma from k-averaged Green's function from TSHS,
                        projected on the atoms "a_R1" equivalent atoms of HS_host
    "SE_i.TBTGF":       Green's function file for usage as electrode in TBtrans 
                        (to be used with "GF" flag in the electrode block for \Sigma)
                        it will contain S^{noPBC}*e - H^{noPBC} - \Sigma from TSHS k-averaged Green's function,
                        projected on the atoms "a_R1" equivalent atoms of HS_host    
    "HS_SE_i.nc":       electrode HS file for usage of TBTGF as electrode in TBtrans
                        (to be used with "HS" flag in the electrode block for \Sigma)
    
    NOTES:
    - works for 2D carbon systems (as of now)
    """
    """ 
    Let's first find the orbitals inside R1 and R2
    """

    # Indices of atoms in device region
    a_dev = TBT.a_dev
    # a_dev from *TBT.nc and *TBT.SE.nc is not sorted correctly in older versions of tbtrans!!!
    # a_dev = np.sort(TBT.a_dev)

    # Indices of orbitals in device region
    o_dev = TSHS.a2o(a_dev, all=True)

    # Check it's only carbon in R1
    for ia in a_R1:
        if TSHS.atom[ia].Z != 6:
            print('\nERROR: please select C atoms in region R1.')
            print('Atoms {} are not carbon \n'.format(
                (TSHS.atoms.Z != 6).nonzero()[0]))
            exit(1)

    # Define R1 region (indices are w.r.t. device device region! )
    if orb_idx is not None:
        # Selected 'orb_idx' orbitals inside R1 region
        print(
            'WARNING: you are selecting only orbital index \'{}\' in R1 region'
            .format(orb_idx))
        o_R1 = TSHS.a2o(
            a_R1
        ) + orb_idx  # IMPORTANT: these are pz indices in the full L+D+R geometry
    else:
        # If no particular orbital is specified, then consider ALL orbitals inside R1 region
        o_R1 = TSHS.a2o(
            a_R1, all=True
        )  # With this  we will basically calculate a Sigma DFT-->DFT instead of DFT-->TB
    # Now we find their indeces with respect to the device region
    o_R1 = np.in1d(o_dev, o_R1).nonzero(
    )[0]  # np.in1d returns true/false. Nonzero turns it into the actual indices

    # In region 2 we will consider ALL orbitals of ALL atoms
    vv = TSHS.geom.sub(a_dev)
    o_R2_tmp = area_R2.within_index(vv.xyz)
    o_R2 = vv.a2o(o_R2_tmp,
                  all=True)  # these are ALL orbitals indices in region 2

    # Check
    v = TSHS.geom.copy()
    v.atom[v.o2a(o_dev, unique=True)] = si.Atom(8, R=[1.44])
    v.write('o_dev.xyz')
    # Check
    vv = TSHS.geom.sub(a_dev)
    vv.atom[vv.o2a(o_R1, unique=True)] = si.Atom(8, R=[1.44])
    vv.write('o_R1.xyz')
    # Check
    vv = TSHS.geom.sub(a_dev)
    vv.atom[vv.o2a(o_R2, unique=True)] = si.Atom(8, R=[1.44])
    vv.write('o_R2.xyz')
    """ 
    ### Map a_R1 into host geometry (which includes electrodes!)
    We will now rearrange the atoms in the host geometry
    putting the mapped ones at the end of the coordinates list
    """

    # sometimes this is useful to fix the mapping
    if area_for_buffer is None:
        area_for_buffer = area_R2.copy()
        print(
            "WARNING: You didn't provide 'area_for_buffer'. \n We are setting it to 'area_R2'. Please check that it is completely correct by comparing 'a_dSE_host.xyz' and 'buffer.xyz'"
        )
    a_dSE_host, new_HS_host, a_buffer_host = map_xyz(
        A=TSHS,
        B=HS_host,
        center_B=pos_dSE,
        area_R_A=area_R1,
        a_R_A=a_R1,
        area_for_buffer=area_for_buffer,
        tol=tol)

    # Write dSE xyz
    v = new_HS_host.geom.copy()
    v.atom[a_dSE_host] = si.Atom(8, R=[1.44])
    v.write('a_dSE_host.xyz')

    # Write buffer atoms fdf block
    v = new_HS_host.geom.copy()
    v.atom[a_buffer_host] = si.Atom(8, R=[1.44])
    v.write('buffer.xyz')
    with open('block_buffer.fdf', 'w') as fb:
        fb.write("%block TBT.Atoms.Buffer\n")
        fb.write(list2range_TBTblock(a_buffer_host))
        fb.write("\n%endblock\n")

    # Write final host large model, ready to be served to tbtrans
    new_HS_host.geom.write('HS_DEV.xyz')
    new_HS_host.geom.write('HS_DEV.fdf')
    new_HS_host.write('HS_DEV.nc')

    # Set CAP (optional)
    if useCAP:
        # Create dH | CAP
        dH_CAP = CAP(new_HS_host.geom, useCAP, dz_CAP=50, write_xyz=True)
        dH_CAP_sile = si.get_sile('CAP.delta.nc', 'w')
        dH_CAP_sile.write_delta(dH_CAP)  # TBT.dH

    #############################
    """
    # Now we calculate and store the self-energy
    """

    ### Initialize dSE  (flag for tbtrans is --> TBT.dSE)
    print('Initializing dSE file...')
    o_dSE_host = new_HS_host.a2o(a_dSE_host, all=True).reshape(
        -1, 1)  # this has to be wrt L+D+R host geometry
    dSE = si.get_sile('SE_i.delta.nc', 'w')

    ### Initialize TBTGF (flag for tbtrans is --> GF inside an electrode block)
    # For this we need a complex energy contour + the sub H, S and geom of R1 in the new_HS_host (large TB)

    # Energy grid
    if EfromTBT:
        Eindices = [TBT.Eindex(en) for en in energies]
        E = TBT.E[Eindices] + 1j * eta_value
    else:
        print(
            'WARNING: energies will not be taken from TBT. Make sure you know what you are doing.'
        )
        E = np.asarray(energies) + 1j * eta_value
    tbl = si.io.table.tableSile('contour.IN', 'w')
    tbl.write_data(E.real, np.zeros(len(E)), np.ones(len(E)), fmt='.8f')

    # Remove periodic boundary conditions from TSHS!!!
    TSHS_n = TSHS.copy()
    print('Removing periodic boundary conditions')
    TSHS_n.set_nsc(
        [1] * 3
    )  # this is how you do it in sisl. Super easy. Removes all phase factors

    # Now we extract submatrices of this, pruning into o_R1
    print('Initializing TBTGF files...')
    if TSHS_n.spin.is_polarized:
        H_tbtgf = TSHS_n.Hk(dtype=np.float64, spin=spin)
    else:
        H_tbtgf = TSHS_n.Hk(dtype=np.float64)
    S_tbtgf = TSHS_n.Sk(dtype=np.float64)
    print(' Hk and Sk: DONE')

    # Prune to dev region  (again, this is because o_R1 is w.r.t. device)
    H_tbtgf_d = pruneMat(H_tbtgf, o_dev)
    S_tbtgf_d = pruneMat(S_tbtgf, o_dev)
    # Prune now these to o_R1
    H_tbtgf_R1 = pruneMat(H_tbtgf_d, o_R1)
    S_tbtgf_R1 = pruneMat(S_tbtgf_d, o_R1)

    # Finally we need the geometry of R1 in new_HS_host
    geom_R1 = new_HS_host.geom.sub(a_dSE_host)

    # It is vital that you also write an electrode Hamiltonian
    Semi = si.Hamiltonian.fromsp(geom_R1, H_tbtgf_R1, S_tbtgf_R1)
    Semi.write('HS_SE_i.nc'
               )  # this is used as HS flag inside the TBTGF electrode block

    # We also need a formal Brillouin zone.
    # "Formal" because we will always use a Gamma-only TBTGF
    # (there is no periodicity once we plug DFT into TB!)
    BZ = si.BrillouinZone(TSHS_n)
    BZ._k = np.array([[0., 0., 0.]])
    BZ._w = np.array([1.0])

    # Now finally we initialize a TBTGF file. We
    # We will fill it further below with the matrix for the DFT-TB self-energy
    GF = si.io.TBTGFSileTBtrans('SE_i.TBTGF')
    GF.write_header(
        BZ, E, obj=Semi
    )  # Semi HAS to be a Hamiltonian object, E has to be complex (WITH eta)
    ###############

    # If there is a self energy enclosed by the frame (e.g. a semi-infinite tip),
    # we will need to add it later to H_R2 and S_R2 to generate G_R2
    # For that we will need to know the indices of the orbitals of the device region (in_device=True)
    # on which the self-energy has been down-folded during the tbtrans BTD process (see tbtrans manual).
    # - When read with BTTSE.pivot, they will be sorted as after the BTD process
    # we can sort them back to the original indices by using sort=True
    if TBTSE:
        pv = TBTSE.pivot('tip', in_device=True, sort=True).reshape(-1, 1)
        pv_R2 = np.in1d(o_R2, pv.reshape(-1, )).nonzero()[0].reshape(-1, 1)
    """
    Now we loop over requested energies and create the DFT-TB self-energy matrices 
    at those energies. FINALLY some physics ;-)
    """
    print('Computing and storing Sigma in TBTGF and dSE format...')
    for i, (ispin, HS4GF, _, e) in enumerate(
            GF
    ):  # sisl specific. THe _ would be k. But we just have Gamma, so who cares
        print('Doing E # {} of {}  ({} eV)'.format(i + 1, len(E), e.real))
        print('Doing E # {} of {}  ({} eV)'.format(i + 1, len(E), e.real),
              file=open('log', 'a+'))  # Also log while running
        """ 
        Calculate G_R2
        """
        # Read H and S from full TSHS (L+D+R) - no self-energies here!
        if TSHS_n.spin.is_polarized:
            Hfullk = TSHS_n.Hk(format='array', spin=spin)
        else:
            Hfullk = TSHS_n.Hk(format='array')
        Sfullk = TSHS_n.Sk(format='array')

        # Prune H, S to device region
        H_d = pruneMat(Hfullk, o_dev)
        S_d = pruneMat(Sfullk, o_dev)

        # Prune H, S matrices from device region to region 2
        H_R2 = pruneMat(H_d, o_R2)
        S_R2 = pruneMat(S_d, o_R2)

        # Build inverse of G_R2 (no self-energies such as tip yet!)
        invG_R2 = S_R2 * e - H_R2

        # if there's a self energy enclosed by the frame
        if TBTSE:
            # Read in the correct format
            SE_ext = TBTSE.self_energy('tip',
                                       E=e.real,
                                       k=[0., 0., 0.],
                                       sort=True)
            # Subtract from invG_R2 at the correct rows and columns (given by pv_R2)
            invG_R2[pv_R2, pv_R2.T] -= SE_ext

        # Now invert
        G_R2 = np.linalg.inv(invG_R2)
        """ 
        Extract V_21 elements from H_d
        """
        # Coupling matrix from R1 to R2 (len(o_R2) x len(o_R1))
        V_21 = couplingMat(H_d, o_R2, o_R1)
        # CHECK: V_21 OR V_21 - z*S_21
        S_21 = couplingMat(S_d, o_R2, o_R1)
        """ 
        Compute the final self-energy
        """
        # Self-energy is projected (lives) in R1, connecting R1 to R2 (len(o_R1) x len(o_R1))
        SE_R1 = np.dot(np.dot(dagger(V_21), G_R2), V_21)
        #SE_R1 = np.dot(np.dot(dagger(V_21-e*S_21), G_R2), V_21-e*S_21)
        """
        Now that we have it, we save it!
        """
        # Write Sigma as a dSE file
        Sigma_in_HS_host = sp.sparse.csr_matrix(
            (len(new_HS_host), len(new_HS_host)), dtype=np.complex128)
        Sigma_in_HS_host[o_dSE_host, o_dSE_host.T] = SE_R1
        delta_Sigma = si.Hamiltonian.fromsp(new_HS_host.geom, Sigma_in_HS_host)
        dSE.write_delta(delta_Sigma, E=e.real)

        # Write Sigma as TBTGF
        # tbtrans wants you to write the quantity S_R1*e - H_R1 - SE_R1
        # So, prune H, S matrices from device region to region 1
        H_R1 = pruneMat(H_d, o_R1)
        S_R1 = pruneMat(S_d, o_R1)
        if HS4GF:
            GF.write_hamiltonian(H_R1, S_R1)
        GF.write_self_energy(S_R1 * e - H_R1 - SE_R1)