Пример #1
0
 def GetGradient(self, Atom, Axis):
     print('\nPhonons.GetGradient: Computing dH[%i,%i]' % (Atom, Axis))
     # Read TSHS files
     TSHSm = SIO.HS(self.TSHS[Atom, Axis, -1])
     TSHSm.setkpoint(self.kpoint, atype=self.atype)
     TSHSp = SIO.HS(self.TSHS[Atom, Axis, 1])
     TSHSp.setkpoint(self.kpoint, atype=self.atype)
     # Use Fermi energy of equilibrium calculation as energy reference?
     if self.AbsEref:
         print('Computing gradient with absolute energy reference')
         for iSpin in range(self.nspin):
             TSHSm.H[iSpin, :, :] += (TSHSm.ef - self.TSHS0.ef) * TSHSm.S
             TSHSp.H[iSpin, :, :] += (TSHSp.ef - self.TSHS0.ef) * TSHSp.S
     # Compute direct gradient
     dH = (TSHSp.H - TSHSm.H) / (2 * self.Displ[Atom])
     del TSHSm, TSHSp
     # Orbital range for the displaced atom:
     f, l = self.OrbIndx[Atom - 1]
     self.dSdij[:, f:l + 1] = self.dS[Axis, :, f:l + 1]
     # Apply Pulay-type corrections
     for iSpin in range(self.nspin):
         dH[iSpin, :, :] -= MM.mm(MM.dagger(self.dSdij), self.invS0H0[0, iSpin, :, :]) \
                          + MM.mm(self.invS0H0[1, iSpin, :, :], self.dSdij)
     self.dSdij[:, f:l + 1] = 0.  # reset
     return dH
Пример #2
0
def readHS():
    # Setup H, S and self-energies
    global HS
    fn = glob.glob('*.TSHS')
    if len(fn) > 1:
        print "ERROR: BandStruct: More than one .TSHS file ... which to choose???"
        sys.exit(1)
    if len(fn) < 1:
        print "ERROR: BandStruct: No .TSHS file ???"
        sys.exit(1)
    HS = SIO.HS(fn=fn[0])
Пример #3
0
 def __init__(self, fn, NA1, NA2, voltage=0.0, UseF90helpers=True):
     self.path = os.path.split(os.path.abspath(fn))[0]
     self.HS = SIO.HS(fn, UseF90helpers=UseF90helpers) # An electrode HS
     self.hash = myHash([self.HS, NA1, NA2, voltage])
     SavedSig.add_hsfile(self.path)
     if self.HS.gamma:
         raise IOError("Are you trying to sneak a Gamma point electrode calculation past me?")
     self.NA1 = NA1
     self.NA2 = NA2
     self.kpoint = N.array([1e10, 1e10], N.float)
     self.voltage = voltage
     self.scaling = 1.0 # Default scale factor for coupling to device
Пример #4
0
 def __init__(self, onlySdir, kpoint, atype=N.complex):
     print('Phonons.GetOnlyS: Reading from: ' + onlySdir)
     onlySfiles = glob.glob(onlySdir + '/*.onlyS*')
     onlySfiles.sort()
     if len(onlySfiles) < 1:
         sys.exit('Phonons.GetOnlyS: No .onlyS file found!')
     if len(onlySfiles) != 6:
         sys.exit('Phonons.GetOnlyS: Wrong number of onlyS files found!')
     else:
         onlyS = {}
         Displ = {}
         for file in onlySfiles:
             thisHS = SIO.HS(file)
             thisHS.setkpoint(kpoint, atype=atype)
             S = thisHS.S
             del thisHS
             nao = len(S) // 2
             S0 = S[0:nao, 0:nao].copy()
             dmat = S[0:nao, nao:nao * 2].copy()
             if file.endswith('_1.onlyS'):
                 onlyS[0, -1] = dmat
             elif file.endswith('_2.onlyS'):
                 onlyS[0, 1] = dmat
             elif file.endswith('_3.onlyS'):
                 onlyS[1, -1] = dmat
             elif file.endswith('_4.onlyS'):
                 onlyS[1, 1] = dmat
             elif file.endswith('_5.onlyS'):
                 onlyS[2, -1] = dmat
             elif file.endswith('_6.onlyS'):
                 onlyS[2, 1] = dmat
         # Loop over the 6 doubled geometries and determine the displacement
         for i in range(1, 7):
             thisd = 1e10
             xyz = N.array(SIO.Getxyz(onlySdir + '/RUN_%i.fdf' % i))
             #for j in range(1, len(xyz)):
             #    thisd = min(thisd, (N.dot(xyz[0]-xyz[j], xyz[0]-xyz[j]))**.5)
             j = len(xyz) // 2
             v = xyz[0] - xyz[j]
             thisd = N.dot(v, v)**.5
             Displ[(i - 1) // 2, 1 - 2 * (i % 2)] = thisd
             print('Phonons.GetOnlyS: OnlyS-displacement (min) = %.5f Ang' %
                   thisd)
         # Construct dS array
         self.S0 = S0
         self.dS = N.empty((3, ) + dmat.shape, dtype=dmat.dtype)
         for j in range(3):
             self.dS[j] = (onlyS[j, 1] - onlyS[j, -1]) / (Displ[j, -1] +
                                                          Displ[j, 1])
         self.Displ = Displ
Пример #5
0
    def PrepareGradients(self,
                         onlySdir,
                         kpoint,
                         DeviceFirst,
                         DeviceLast,
                         AbsEref,
                         atype,
                         TSrun=False):
        print('\nPhonons.PrepareGradients: Setting up various arrays')
        self.atype = atype
        self.kpoint = kpoint
        self.OrbIndx, nao = self.FCRs[0].GetOrbitalIndices()
        self.TSHS0 = SIO.HS(self.TSHS[0])
        self.TSHS0.setkpoint(kpoint, atype=atype)
        if not TSrun:
            OS = OSrun(onlySdir, kpoint, atype=atype)
            self.dS = OS.dS
            # OS.S0 and TSHS0.S should be identical, but with some versions/compilations
            # of TranSIESTA this is NOT always the case away from k=0 (GammaPoint is OK).
            # It appears to be a bug in TranSIESTA 3.2 and 4.0b affecting runs
            # with TS.onlyS=True, i.e., the quick evaluations in the OSrun folder
            if not N.allclose(OS.S0, self.TSHS0.S):
                sys.exit(
                    'Inconsistency detected with your .onlyS files. Perhaps a bug in your TranSIESTA version/compilation or overlaps beyond first neighbor cells.'
                )
        self.invS0H0 = N.empty((2, ) + self.TSHS0.H.shape,
                               dtype=self.TSHS0.H.dtype)
        #invS0 = LA.inv(OS.S0) # <--- This choice was used in rev. 324-397
        invS0 = LA.inv(
            self.TSHS0.S)  # Reverting to the matrix used up to rev. 323
        self.nspin = len(self.TSHS0.H)
        for iSpin in range(self.nspin):
            self.invS0H0[0, iSpin, :, :] = MM.mm(invS0,
                                                 self.TSHS0.H[iSpin, :, :])
            self.invS0H0[1, iSpin, :, :] = MM.mm(self.TSHS0.H[iSpin, :, :],
                                                 invS0)
        del invS0
        # don't re-create the array every time... too expensive
        self.dSdij = N.zeros((nao, nao), atype)

        # Take Device region
        self.DeviceAtoms = list(range(DeviceFirst, DeviceLast + 1))
        first, last = self.OrbIndx[DeviceFirst -
                                   1][0], self.OrbIndx[DeviceLast - 1][1]
        self.h0 = self.TSHS0.H[:, first:last + 1, first:last + 1]
        self.s0 = self.TSHS0.S[first:last + 1, first:last + 1]
        self.DeviceFirst = DeviceFirst
        self.DeviceLast = DeviceLast
        self.AbsEref = AbsEref
Пример #6
0
def main():
    if not SIO.F90imported:
        print "To test the F90 routines you better compile them first"
        kuk

    print 'TESTING reading routines:\n'

    # Test readTSHS routines
    for file in ['Self-energy-FCC111/ELEC-1x1/Au3D_BCA.TSHS', 'sample.onlyS']:
        HS1 = SIO.HS('../TestCalculations/' + file, UseF90helpers=False)
        HS2 = SIO.HS('../TestCalculations/' + file, UseF90helpers=True)
        compare_H(HS1, HS2)

    # Test readTSHS routines new vs. old
    for file in [
            'Self-energy-FCC100/ELEC-1x1/ABAB.TSHS',
            'Self-energy-FCC111/ELEC-1x1/Au3D_BCA.TSHS'
    ]:
        HS1 = SIO.HS('../TestCalculations/' + file, UseF90helpers=True)
        HS2 = SIO.HS('../TestCalculations/' +
                     file.replace('.TSHS', '_NEW.TSHS'),
                     UseF90helpers=True)
        compare_H(HS1, HS2, not_checks={'xij': False})

    # Test removeUnitCellXij
    print 'TESTING removeUnitCellXij method'
    elec1 = NEGF.ElectrodeSelfEnergy(
        '../TestCalculations/Self-energy-FCC111/ELEC-1x1/Au3D_BCA.TSHS',
        1,
        1,
        UseF90helpers=True)
    elec2 = NEGF.ElectrodeSelfEnergy(
        '../TestCalculations/Self-energy-FCC111/ELEC-1x1/Au3D_BCA.TSHS',
        1,
        1,
        UseF90helpers=False)
    maxerr = N.max(abs(elec1.HS.xij - elec2.HS.xij))
    print "Maximum difference between Xij :", maxerr

    for ii in range(10):
        k = N.array(RA.random(3), N.float)
        print " Checking k-point: %f,%f,%f" % (k[0], k[1], k[2])
        elec1.HS.kpoint = N.zeros((3, ),
                                  N.float)  # To ensure it is calculated!
        elec1.HS.setkpoint(k, UseF90helpers=True)
        H1, S1 = elec1.HS.H.copy(), elec1.HS.S.copy()
        elec2.HS.kpoint = N.zeros((3, ),
                                  N.float)  # To ensure it is calculated!
        elec2.HS.setkpoint(k, UseF90helpers=False)
        H2, S2 = elec2.HS.H.copy(), elec2.HS.S.copy()
        tmp1 = N.max(abs(H1 - H2))
        tmp2 = N.max(abs(S1 - S2))
        print "Max difference kpointhelper: ", max(tmp1, tmp2)
        if maxerr > 1e-9:
            print "ERROR!"
            kuk

        ee = RA.random(1) + 0.0001j
        elec1.semiinf = 2
        elec2.semiinf = 2
        SGF1 = elec1.getSig(ee, k[0:2].copy(), UseF90helpers=True)
        SGF2 = elec2.getSig(ee, k[0:2].copy(), UseF90helpers=False)
        SGFerr = N.max(abs(SGF1 - SGF2))
        print "Max difference for self-energy: ", SGFerr
        maxerr = max(tmp1, tmp2, SGFerr, maxerr)
        if maxerr > 1e-9:
            print "ERROR!"
            kuk

    # SurfaceGF
    print '\nTESTING pyTBT.surfaceGF method (1x1 vs 3x3)'
    elecF90 = NEGF.ElectrodeSelfEnergy(
        '../TestCalculations/Self-energy-FCC111/ELEC-1x1/Au3D_BCA.TSHS',
        3,
        3,
        UseF90helpers=True)
    elecNoF90 = NEGF.ElectrodeSelfEnergy(
        '../TestCalculations/Self-energy-FCC111/ELEC-1x1/Au3D_BCA.TSHS',
        3,
        3,
        UseF90helpers=False)

    for ii in range(10):
        k = N.array(RA.random(3), N.float)
        print " Checking k-point: %f,%f,%f" % (k[0], k[1], k[2])
        elecF90.HS.kpoint = N.zeros((3, ),
                                    N.float)  # To ensure it is calculated!
        elecF90.HS.setkpoint(k, UseF90helpers=True)
        H1, S1 = elecF90.HS.H.copy(), elecF90.HS.S.copy()
        elecNoF90.HS.kpoint = N.zeros((3, ),
                                      N.float)  # To ensure it is calculated!
        elecNoF90.HS.setkpoint(k, UseF90helpers=False)
        H2, S2 = elecNoF90.HS.H.copy(), elecNoF90.HS.S.copy()
        tmp1 = N.max(abs(H1 - H2))
        tmp2 = N.max(abs(S1 - S2))
        print "Max difference kpointhelper: ", max(tmp1, tmp2)
        if maxerr > 1e-9:
            print "ERROR!"
            kuk

        ee = RA.random(1) + 0.0001j
        elecF90.semiinf = 2
        elecNoF90.semiinf = 2
        SGFf90 = elecF90.getSig(ee, k[0:2].copy(), UseF90helpers=True)
        SGF = elecNoF90.getSig(ee, k[0:2].copy(), UseF90helpers=False)
        SGFerr = N.max(abs(SGFf90 - SGF))
        print "Max difference for self-energy: ", SGFerr
        maxerr = max(tmp1, tmp2, SGFerr, maxerr)
        if maxerr > 1e-9:
            print "ERROR!"
            kuk

    print "Maximum error : ", maxerr
    print
    print "###############################################################"
    print "###############################################################"
    if maxerr > 1e-9:
        print "ERROR!"
        kuk
    else:
        print "Tests passed for remove Xij, expansion_SE, readTSHS, and setkpoint!"
    print "###############################################################"
    print "###############################################################"
    print
Пример #7
0
    def __init__(self, TSHSfile, elecL, elecR, Bulk=True, DeviceAtoms=[0, 0], BufferAtoms=N.empty((0,))):
        """
        Calculate Green's functions etc for TSHSfile connected to left/right
        electrode (class ElectrodeSelfEnergy).
        To speed up calculations folding to smaller device region suggested
        For spin-polarized calcGF has to be called for each ispin
        Variables:
        Gr     : Retarded Green's function, folded
        H,S    : Hamiltonian, overlap, folded
        H0,S0  : Hamiltonian, overlap, not folded
        nuo    : Size of Gr
        SigL, SigR, GamL, GamR : Self energy, Gamma NOTE, not same size as Gr!
        nuoL, nuoR : Size of Sig, Gam
        nuo0, nuoL0, nuoR0 : Non-folded sizes
        FoldedL, FoldedR : True/False
        DeviceAtoms : start/end Siesta numbering of atoms included in device
        DeviceOrbs : Start/end of orbitals. Siesta ordering.
        BufferAtoms: A list of buffer atoms
        """
        self.elecL, self.elecR, self.Bulk = elecL, elecR, Bulk
        self.HS = SIO.HS(TSHSfile, BufferAtoms=BufferAtoms)
        print('GF: UseBulk=', Bulk)
        self.DeviceAtoms = DeviceAtoms
        if DeviceAtoms[0] <= 1:
            self.DeviceAtoms[0] = 1
            self.FoldedL = False
        else:
            self.FoldedL = True
        if DeviceAtoms[1] == 0 or DeviceAtoms[1] >= self.HS.nua:
            self.DeviceAtoms[1] = self.HS.nua
            self.FoldedR = False
        else:
            self.FoldedR = True
        self.DeviceOrbs = [self.HS.lasto[DeviceAtoms[0]-1]+1, self.HS.lasto[DeviceAtoms[1]]]

        self.nuo0, self.nuoL0, self.nuoR0 = self.HS.nuo, elecL.NA1*elecL.NA2*elecL.HS.nuo, elecR.NA1*elecR.NA2*elecR.HS.nuo
        self.nuo = self.DeviceOrbs[1]-self.DeviceOrbs[0]+1
        self.nuoL, self.nuoR = self.nuoL0, self.nuoR0 # Not folded, for folded case changed below

        print("GF:", TSHSfile)
        print("Device atoms %i-%i, orbitals %i-%i"%(tuple(self.DeviceAtoms+self.DeviceOrbs)))
        if not self.FoldedL:
            print("Suggest left folding to atom : ", self.elecL.HS.nua*self.elecL.NA1*self.elecL.NA2+1)
        if not self.FoldedR:
            print("Suggest right folding to atom : ", self.HS.nua-self.elecR.HS.nua*self.elecR.NA1*self.elecR.NA2)

        if self.FoldedL or self.FoldedR:
            # Check that device region is large enough!
            kpoint = N.zeros((2,), N.float)
            self.setkpoint(kpoint, ispin=0) # At least for one spin

            devSt, devEnd = self.DeviceOrbs[0], self.DeviceOrbs[1]
            VC.Check("Device-Elec-overlap", N.abs(self.S0[0:devSt, devEnd:self.nuo0]),
                     "Too much overlap directly from left-top right",
                     "Make device region larger")
            VC.Check("Device-Elec-overlap", N.abs(self.H0[0:devSt, devEnd:self.nuo0]),
                     "Too large Hamiltonian directly from left-top right.",
                     "Make device region larger")
        if self.FoldedL:
            # Find orbitals in device region coupling to left and right.
            tau = abs(self.S0[0:devSt-1, 0:devEnd])
            coupling = N.sum(tau, axis=0)
            ii = devEnd-1
            while coupling[ii] < 1e-10: ii = ii-1
            self.devEndL = max(ii+1, self.nuoL0)
            self.nuoL = self.devEndL-devSt+1
            print("Left self energy on orbitals %i-%i"%(devSt, self.devEndL))
        if self.FoldedR:
            tau = abs(self.S0[devEnd-1:self.nuo0, 0:self.nuo0])
            coupling = N.sum(tau, axis=0)
            ii = devSt-1
            while coupling[ii] < 1e-10: ii = ii+1
            self.devStR = min(ii+1, self.nuo0-self.nuoR0+1)
            self.nuoR = devEnd-self.devStR+1
            print("Right self energy on orbitals %i-%i"%(self.devStR, devEnd))
        # Quantities expressed in nonorthogonal basis:
        self.OrthogonalDeviceRegion = False
Пример #8
0
def main(options, kpoint, ikpoint):
    Ef = SIO.HS(options.systemlabel + '.TSHS').ef / PC.Rydberg2eV
    kpt = ikpoint
    pathkpt = './' + options.DestDir + '/' + str(kpt) + '/'
    print 'k-point: ' + str(ikpoint) + '/'
    print '(k1,k2): (' + str(kpoint[0]) + ',' + str(kpoint[1]) + ')'
    print 'Fermi energy (' + str(options.systemlabel) + '.TSHS):', N.round(
        Ef, 4), 'Ry =', N.round(Ef * PC.Rydberg2eV, 4), 'eV'

    #Determine substrate layers and tip height
    posZMol, posZTip = LayersAndTipheight(options, kpoint, ikpoint)

    #Read total potential, loc-basis states, lattice constants etc.
    tmp = readDFT(options, kpoint, pathkpt, posZMol, posZTip)
    Subwfs, Tipwfs, Vsub, Vtip = tmp[0], tmp[1], tmp[2], tmp[3]
    scSize, ucSize, Max, dS, theta = tmp[4], tmp[5], tmp[6], tmp[7], tmp[8]
    SubChans, TipChans, SubPot, TipPot, SubRho, TipRho, MeshCutoff = tmp[
        9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14], tmp[15]

    Nx, Ny, Nz = scSize[0], scSize[1], scSize[2]
    NN = Nx * Ny * Nz
    a1, a2, a3 = ucSize[0], ucSize[1], ucSize[2]
    if options.samplingscale != 1:
        print '\nReal-space sampling in xy plane coarser by factor', options.samplingscale, '...'
        tmp = sampling(options, Nx, Ny, Nz, Subwfs, Tipwfs, SubChans, TipChans,
                       SubPot, TipPot, SubRho, TipRho)
        Nx, Ny, Nz = tmp[0], tmp[1], tmp[2]
        NN = Nx * Ny * Nz
        a1, a2 = a1 * options.samplingscale, a2 * options.samplingscale
        ucSize = [a1, a2, a3]
        Subwfs, Tipwfs, Vsub, Vtip, SubRho, TipRho = tmp[3], tmp[4], tmp[
            5], tmp[6], tmp[7], tmp[8]
        print 'New lattice in xy plane obtained (corresponding to ' + str(
            MeshCutoff / options.samplingscale**2) + ' Ry):'
        print '          [Nx Ny Nz] = [' + str(Nx), str(Ny), str(Nz) + ']'
        print '          [a1 a2 a3] = [' + str(N.round(
            a1 * PC.Bohr2Ang, 4)), str(
                N.round(a2 * PC.Bohr2Ang,
                        4)), str(N.round(a3 * PC.Bohr2Ang, 4)) + '] Ang'
    else:
        print '\nReal-space sampling omitted (same grid as TranSiesta).\n'

    #Substrate part
    print '\nCalculation from substrate side:'
    WFs, Chans, rho = Subwfs, SubChans, SubRho
    inda, indb = reindexing(options, Nx, Ny, Nz, NN, WFs, Chans, rho, ucSize,
                            theta)
    Pot = Vsub
    Ham = Hamiltonian(options, a1, a2, a3, Nx, Ny, Nz, NN, Pot, theta, kpoint)
    Tau, Hb = SplitHam(Ham, inda, indb)
    ChansL = Chans
    propSubModes = LinearSolve(options, WFs, inda, indb, Ef, Tau, Hb, NN, Nx,
                               Ny, Nz, Chans)

    #Tip part
    print '\nCalculation from tip side:'
    WFs, Chans, rho = Tipwfs, TipChans, TipRho
    inda, indb = reindexing(options, Nx, Ny, Nz, NN, WFs, Chans, rho, ucSize,
                            theta)
    Pot = Vtip
    Ham = Hamiltonian(options, a1, a2, a3, Nx, Ny, Nz, NN, Pot, theta, kpoint)
    Tau, Hb = SplitHam(Ham, inda, indb)
    ChansR = Chans
    propTipModes = LinearSolve(options, WFs, inda, indb, Ef, Tau, Hb, NN, Nx,
                               Ny, Nz, Chans)

    #Combine sub and tip to find conductance
    STMimage, Currmat = Current(options, propSubModes, propTipModes, Nx, Ny, Nz, Max,\
                               ucSize, ChansL, ChansR, dS, kpoint, pathkpt, ikpoint)
    STMimage = STMimage[:Nx, :Ny]