def calcTEIG(self, channels=10): # Transmission matrix (complex array) TT = self.TT Trans = N.trace(TT) VC.Check("trans-imaginary-part", Trans.imag, "Transmission has large imaginary part") # Calculate eigenchannel transmissions too tval, tvec = LA.eig(TT) idx = (tval.real).argsort()[::-1] # sort from largest to smallest tval = tval[idx] tvec = tvec[:, idx] # Compute shot noise Smat = MM.mm(TT, N.identity(len(TT)) - TT) sval = N.diag(MM.mm(MM.dagger(tvec), Smat, tvec)) # set up arrays T = N.zeros(channels + 1) SN = N.zeros(channels + 1) T[0] = Trans.real SN[0] = N.trace(Smat).real for i in range(min(channels, len(TT))): T[i + 1] = tval[i].real SN[i + 1] = sval[i].real return T, SN
def AssertReal(x, label): VC.Check("zero-imaginary-part", abs(x.imag), "Imaginary part too large in quantity %s" % label) return x.real
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
def calcg0_old(self, ee, ispin=0, left=True): """ Only used if SciPy is not installed! For the left surface Green's function (1 is surface layer, 0 is all the other atoms): (E S00-H00 E S01-H01) (g00 g01) ( I 0 ) (E S10-H10 E S11-H11) * (g01 g11) = ( 0 I ) -> call E S - H for t ... t00 g01 + t01 g11 = 0 -> g01 = - t00^-1 t01 g11 t10 g01 + t11 g11 = I -> - t10 t00^-1 t01 g11 + t11 g11 = I -> And we get the surface Green's function: g11 = (t11 - t10 t00^-1 t01)^-1 with the right size of unitcell t00^-1 = g11! g11 = (E S11 - H11 - (E S10 - H10) g11 (E S01 - H01))^-1 In the calculations H01^+ and S01^+ are used instead of S10 and H10. (For complex energies (E S01 -H01)^+ is not (E S10 -H10) because the conjugate of the energy!!!!) For the right surface greens function same but different order on the MM.daggers! i.e., (E S - H - (E S01 - H01) gs (E S01^+ -H01^+) Algorith: Lopez Sancho*2 J Phys F:Met Phys 15 (1985) 851 I'm still very suspicios of this algorithm ... but it works and is really quick! The convergence is always checked against gs (E S - H - (E S01^+ - H01^+) gs (E S01 -H01) ) = I! """ H, S, H01, S01 = self.H[ispin, :, :], self.S, self.H01[ ispin, :, :], self.S01 alpha, beta = MM.dagger(H01) - ee * MM.dagger(S01), H01 - ee * S01 eps, epss = H.copy(), H.copy() converged = False iteration = 0 while not converged: iteration += 1 oldeps, oldepss = eps.copy(), epss.copy() oldalpha, oldbeta = alpha.copy(), beta.copy() tmpa = LA.solve(ee * S - oldeps, oldalpha) tmpb = LA.solve(ee * S - oldeps, oldbeta) alpha, beta = MM.mm(oldalpha, tmpa), MM.mm(oldbeta, tmpb) eps = oldeps + MM.mm(oldalpha, tmpb) + MM.mm(oldbeta, tmpa) if left: epss = oldepss + MM.mm(oldalpha, tmpb) else: epss = oldepss + MM.mm(oldbeta, tmpa) LopezConvTest = N.max(abs(alpha) + abs(beta)) if LopezConvTest < 1.0e-40: gs = LA.inv(ee * S - epss) if left: test = ee * S - H - MM.mm( ee * MM.dagger(S01) - MM.dagger(H01), gs, ee * S01 - H01) else: test = ee * S - H - MM.mm( ee * S01 - H01, gs, ee * MM.dagger(S01) - MM.dagger(H01)) myConvTest = N.max( abs( MM.mm(test, gs) - N.identity((self.HS.nuo), N.complex))) if myConvTest < VC.GetCheck("Lopez-Sancho"): converged = True if myConvTest > VC.GetCheck("Lopez-Sancho-warning"): v = "RIGHT" if left: v = "LEFT" print "WARNING: Lopez-scheme not-so-well converged for " + v + " electrode at E = %.4f eV:" % ee, myConvTest else: VC.Check("Lopez-Sancho", myConvTest, "Error: gs iteration {0}".format(iteration)) return gs