def main(options): """ Main routine to compute inelastic transport characteristics (dI/dV, d2I/dV2, IETS etc) Parameters ---------- options : an ``options`` instance """ CF.CreatePipeOutput(options.DestDir + '/' + options.Logfile) VC.OptionsCheck(options, 'Inelastica') CF.PrintMainHeader('Inelastica', options) options.XV = '%s/%s.XV' % (options.head, options.systemlabel) options.geom = MG.Geom(options.XV, BufferAtoms=options.buffer) # Voltage fraction over left-center interface VfracL = options.VfracL # default is 0.5 print 'Inelastica: Voltage fraction over left-center interface: VfracL =', VfracL # Set up electrodes and device Greens function elecL = NEGF.ElectrodeSelfEnergy(options.fnL, options.NA1L, options.NA2L, options.voltage * VfracL) elecL.scaling = options.scaleSigL elecL.semiinf = options.semiinfL elecR = NEGF.ElectrodeSelfEnergy(options.fnR, options.NA1R, options.NA2R, options.voltage * (VfracL - 1.)) elecR.scaling = options.scaleSigR elecR.semiinf = options.semiinfR # Read phonons NCfile = NC4.Dataset(options.PhononNetCDF, 'r') print 'Inelastica: Reading ', options.PhononNetCDF hw = NCfile.variables['hw'][:] # Work with GFs etc for positive (V>0: \mu_L>\mu_R) and negative (V<0: \mu_L<\mu_R) bias voltages GFp = NEGF.GF(options.TSHS, elecL, elecR, Bulk=options.UseBulk, DeviceAtoms=options.DeviceAtoms, BufferAtoms=options.buffer) # Prepare lists for various trace factors #GF.dGnout = [] #GF.dGnin = [] GFp.P1T = N.zeros(len(hw), N.float) # M.A.M.A (total e-h damping) GFp.P2T = N.zeros(len(hw), N.float) # M.AL.M.AR (emission) GFp.ehDampL = N.zeros(len(hw), N.float) # M.AL.M.AL (L e-h damping) GFp.ehDampR = N.zeros(len(hw), N.float) # M.AR.M.AR (R e-h damping) GFp.nHT = N.zeros(len(hw), N.float) # non-Hilbert/Isym factor GFp.HT = N.zeros(len(hw), N.float) # Hilbert/Iasym factor GFp.dIel = N.zeros(len(hw), N.float) GFp.dIinel = N.zeros(len(hw), N.float) GFp.dSel = N.zeros(len(hw), N.float) GFp.dSinel = N.zeros(len(hw), N.float) # GFm = NEGF.GF(options.TSHS, elecL, elecR, Bulk=options.UseBulk, DeviceAtoms=options.DeviceAtoms, BufferAtoms=options.buffer) GFm.P1T = N.zeros(len(hw), N.float) # M.A.M.A (total e-h damping) GFm.P2T = N.zeros(len(hw), N.float) # M.AL.M.AR (emission) GFm.ehDampL = N.zeros(len(hw), N.float) # M.AL.M.AL (L e-h damping) GFm.ehDampR = N.zeros(len(hw), N.float) # M.AR.M.AR (R e-h damping) GFm.nHT = N.zeros(len(hw), N.float) # non-Hilbert/Isym factor GFm.HT = N.zeros(len(hw), N.float) # Hilbert/Iasym factor GFm.dIel = N.zeros(len(hw), N.float) GFm.dIinel = N.zeros(len(hw), N.float) GFm.dSel = N.zeros(len(hw), N.float) GFm.dSinel = N.zeros(len(hw), N.float) # Calculate transmission at Fermi level GFp.calcGF(options.energy + options.eta * 1.0j, options.kpoint[0:2], ispin=options.iSpin, etaLead=options.etaLead, useSigNCfiles=options.signc, SpectralCutoff=options.SpectralCutoff) L = options.bufferL # Pad lasto with zeroes to enable basis generation... lasto = N.zeros((GFp.HS.nua + L + 1, ), N.int) lasto[L:] = GFp.HS.lasto basis = SIO.BuildBasis(options.fn, options.DeviceAtoms[0] + L, options.DeviceAtoms[1] + L, lasto) basis.ii -= L TeF = MM.trace(GFp.TT).real GFp.TeF = TeF GFm.TeF = TeF # Check consistency of PHrun vs TSrun inputs IntegrityCheck(options, GFp, basis, NCfile) # Calculate trace factors one mode at a time print 'Inelastica: LOEscale =', options.LOEscale if options.LOEscale == 0.0: # LOEscale=0.0 => Original LOE-WBA method, PRB 72, 201101(R) (2005) [cond-mat/0505473]. GFp.calcGF(options.energy + options.eta * 1.0j, options.kpoint[0:2], ispin=options.iSpin, etaLead=options.etaLead, useSigNCfiles=options.signc, SpectralCutoff=options.SpectralCutoff) GFm.calcGF(options.energy + options.eta * 1.0j, options.kpoint[0:2], ispin=options.iSpin, etaLead=options.etaLead, useSigNCfiles=options.signc, SpectralCutoff=options.SpectralCutoff) for ihw in (hw > options.modeCutoff).nonzero()[0]: calcTraces(options, GFp, GFm, basis, NCfile, ihw) calcTraces(options, GFm, GFp, basis, NCfile, ihw) writeFGRrates(options, GFp, hw, NCfile) else: # LOEscale=1.0 => Generalized LOE, PRB 89, 081405(R) (2014) [arXiv:1312.7625] for ihw in (hw > options.modeCutoff).nonzero()[0]: GFp.calcGF(options.energy + hw[ihw] * options.LOEscale * VfracL + options.eta * 1.0j, options.kpoint[0:2], ispin=options.iSpin, etaLead=options.etaLead, useSigNCfiles=options.signc, SpectralCutoff=options.SpectralCutoff) GFm.calcGF(options.energy + hw[ihw] * options.LOEscale * (VfracL - 1.) + options.eta * 1.0j, options.kpoint[0:2], ispin=options.iSpin, etaLead=options.etaLead, useSigNCfiles=options.signc, SpectralCutoff=options.SpectralCutoff) calcTraces(options, GFp, GFm, basis, NCfile, ihw) if VfracL != 0.5: GFp.calcGF(options.energy - hw[ihw] * options.LOEscale * (VfracL - 1.) + options.eta * 1.0j, options.kpoint[0:2], ispin=options.iSpin, etaLead=options.etaLead, useSigNCfiles=options.signc, SpectralCutoff=options.SpectralCutoff) GFm.calcGF(options.energy - hw[ihw] * options.LOEscale * VfracL + options.eta * 1.0j, options.kpoint[0:2], ispin=options.iSpin, etaLead=options.etaLead, useSigNCfiles=options.signc, SpectralCutoff=options.SpectralCutoff) calcTraces(options, GFm, GFp, basis, NCfile, ihw) # Multiply traces with voltage-dependent functions data = calcIETS(options, GFp, GFm, basis, hw) NCfile.close() NEGF.SavedSig.close() CF.PrintMainFooter('Inelastica') return data
def GetOptions(argv, **kwargs): """ Returns an instance of ``options`` for the ``iets`` module Parameters ---------- argv : string For example `-n 10 test_dir`, which instructs to compute 10 eigenchannels and place the results in the output directory `test_dir`. """ CF.PrintMainHeader('GetOptions', None) # if text string is specified, convert to list if isinstance(argv, VC.string_types): argv = argv.split() import argparse p = argparse.ArgumentParser( description= 'Inelastica script calculates and writes LOE quantities in ascii (Systemlabel.IN) and NetCDF (Systemlabel.IN.nc)' ) p.add_argument('DestDir', help='Destination directory') p.add_argument('-n', '--NumChan', dest='numchan', type=int, default=4, help='Number of eigenchannels [default: %(default)s]') p.add_argument( '-F', '--DeviceFirst', dest='DeviceFirst', default=0, type=int, help='First device atom (SIESTA numbering) [TS.TBT.PDOSFrom]') p.add_argument('-L', '--DeviceLast', dest='DeviceLast', default=0, type=int, help='Last device atom (SIESTA numbering) [TS.TBT.PDOSTo]') p.add_argument( '-e', '--Energy', dest='energy', default=0.0, type=float, help= 'Energy reference where Greens functions etc are evaluated [default: %(default)s eV]' ) p.add_argument( '--eta', dest='eta', default=0.000001, type=float, help= 'Tiny imag. part in Greens functions etc. [default: %(default)s eV]') p.add_argument( '-f', '--fdf', dest='fn', default='./RUN.fdf', type=str, help='Input fdf-file for TranSIESTA calculations [default: %(default)s]' ) p.add_argument('-s', '--iSpin', dest='iSpin', default=0, type=int, help='Spin channel [default: %(default)s]') p.add_argument('-x', '--k1', dest='k1', default=0.0, type=float, help='k-point along a1 [default: %(default)s]') p.add_argument('-y', '--k2', dest='k2', default=0.0, type=float, help='k-point along a2 [default: %(default)s]') p.add_argument( '-p', '--PhononNetCDF', dest='PhononNetCDF', default='Output.nc', type=str, help='Electron-phonon coupling NetCDF [default: %(default)s]') p.add_argument('-t', '--Temp', dest='Temp', default=4.2, type=float, help='Temperature [default: %(default)s K]') p.add_argument('-b', '--BiasPoints', dest='biasPoints', default=801, type=int, help='Number of bias points [default: %(default)s]') p.add_argument( '-v', '--MaxBias', dest='maxBias', default=0.4, type=float, help= 'Sets the IETS bias range (-MaxBias to MaxBias) [default: %(default)s V]' ) p.add_argument( '-c', '--ModeCutoff', dest='modeCutoff', default='0.0025', type=float, help='Ignore phonon modes with lower hw [default: %(default)s eV]') p.add_argument( '-V', '--Vrms', dest='Vrms', default='0.005', type=float, help='Lock in amplifier broadening [default: %(default)s V]') p.add_argument( '-H', '--Heating', dest='PhHeating', default=False, action='store_true', help='Include heating of vibrational modes [default: %(default)s]') p.add_argument( '-d', '--PhExtDamp', dest='PhExtDamp', default=1e-15, type=float, help='External damping [default: %(default)s (?) TODO check unit!]') p.add_argument('-u', '--useSigNC', dest='signc', default=False, action='store_true', help='Use SigNCfiles [default: %(default)s]') p.add_argument( '-l', '--etaLead', dest='etaLead', type=float, default=0.0, help= 'Additional imaginary part added ONLY in the leads (surface GF) [default: %(default)s eV]' ) p.add_argument( '--SpectralCutoff', dest='SpectralCutoff', type=float, default=1e-8, help= 'Cutoff value for SpectralMatrix functions (for ordinary matrix representation set cutoff<=0.0) [default: %(default)s]' ) # Electrode stuff p.add_argument( '--bulk', dest='UseBulk', default=-1, action='store_true', help= 'Use bulk in electrodes. The Hamiltonian from the electrode calculation is inserted into the electrode region in the TranSIESTA cell [TS.UseBulkInElectrodes]' ) p.add_argument( '--nobulk', dest='UseBulk', default=-1, action='store_false', help= 'Use only self-energies in the electrodes. The full Hamiltonian of the TranSIESTA cell is used in combination with self-energies for the electrodes [TS.UseBulkInElectrodes]' ) # Scale (artificially) the coupling to the electrodes p.add_argument( '--scaleSigL', dest='scaleSigL', type=float, default=1.0, help='Scale factor applied to Sigma_L [default: %(default)s]') p.add_argument( '--scaleSigR', dest='scaleSigR', type=float, default=1.0, help='Scale factor applied to Sigma_R [default: %(default)s]') # Which LOE method? p.add_argument( '--LOEscale', dest='LOEscale', type=float, default=1.0, help= 'Scale factor to interpolate between LOE-WBA (0.0) and generalized LOE (1.0), see PRB 89, 081405(R) (2014) [default: %(default)s]' ) p.add_argument( '--VfracL', dest='VfracL', type=float, default=0.5, help= 'Voltage fraction over the left-center interface [default: %(default)s]' ) # Parse the options options = p.parse_args(argv) # With this one can overwrite the logging information if "log" in kwargs: options.Logfile = kwargs['log'] else: options.Logfile = 'Inelastica.log' # k-point options.kpoint = N.array([options.k1, options.k2, 0.0], N.float) del options.k1, options.k2 return options
def main(options): """ Main routine to compute elastic transmission probabilities etc. Parameters ---------- options : an ``options`` instance """ CF.CreatePipeOutput(options.DestDir + '/' + options.Logfile) VC.OptionsCheck(options, 'pyTBT') CF.PrintMainHeader('pyTBT', options) # K-points if options.Gk1 > 1: Nk1, t1 = options.Gk1, 'GK' else: Nk1, t1 = options.Nk1, 'LIN' if options.Gk2 > 1: Nk2, t2 = options.Gk2, 'GK' else: Nk2, t2 = options.Nk2, 'LIN' # Generate full k-mesh: mesh = Kmesh.kmesh(Nk1, Nk2, Nk3=1, meshtype=[t1, t2, 'LIN'], invsymmetry=not options.skipsymmetry) mesh.mesh2file( '%s/%s.%ix%i.mesh' % (options.DestDir, options.systemlabel, mesh.Nk[0], mesh.Nk[1])) # Setup self-energies and device GF elecL = NEGF.ElectrodeSelfEnergy(options.fnL, options.NA1L, options.NA2L, options.voltage / 2.) elecL.scaling = options.scaleSigL elecL.semiinf = options.semiinfL elecR = NEGF.ElectrodeSelfEnergy(options.fnR, options.NA1R, options.NA2R, -options.voltage / 2.) elecR.scaling = options.scaleSigR elecR.semiinf = options.semiinfR DevGF = NEGF.GF(options.TSHS, elecL, elecR, Bulk=options.UseBulk, DeviceAtoms=options.DeviceAtoms, BufferAtoms=options.buffer) nspin = DevGF.HS.nspin # k-sample only self-energies? if options.singlejunction: elecL.mesh = mesh mesh = Kmesh.kmesh(3, 3, 1) if options.dos: DOSL = N.zeros((nspin, len(options.Elist), DevGF.nuo), N.float) DOSR = N.zeros((nspin, len(options.Elist), DevGF.nuo), N.float) # MPSH projections? MPSHL = N.zeros((nspin, len(options.Elist), DevGF.nuo), N.float) MPSHR = N.zeros((nspin, len(options.Elist), DevGF.nuo), N.float) # evaluate eigenstates at Gamma import scipy.linalg as SLA DevGF.setkpoint(N.zeros(2)) ev0, es0 = SLA.eigh(DevGF.H, DevGF.S) print 'MPSH eigenvalues:', ev0 #print 'MPSH eigenvector normalizations:',N.diag(MM.mm(MM.dagger(es0),DevGF.S,es0)).real # right # Loop over spin for iSpin in range(nspin): # initialize transmission and shot noise arrays Tkpt = N.zeros((len(options.Elist), mesh.NNk, options.numchan + 1), N.float) SNkpt = N.zeros((len(options.Elist), mesh.NNk, options.numchan + 1), N.float) # prepare output files outFile = options.DestDir + '/%s.%ix%i' % (options.systemlabel, mesh.Nk[0], mesh.Nk[1]) if nspin < 2: thisspinlabel = outFile else: thisspinlabel = outFile + ['.UP', '.DOWN'][iSpin] fo = open(thisspinlabel + '.AVTRANS', 'write') fo.write('# Nk1(%s)=%i Nk2(%s)=%i eta=%.2e etaLead=%.2e\n' % (mesh.type[0], mesh.Nk[0], mesh.type[1], mesh.Nk[1], options.eta, options.etaLead)) fo.write('# E Ttot(E) Ti(E)(i=1-%i) RelErrorTtot(E)\n' % options.numchan) foSN = open(thisspinlabel + '.AVNOISE', 'write') foSN.write('# Nk1(%s)=%i Nk2(%s)=%i eta=%.2e etaLead=%.2e\n' % (mesh.type[0], mesh.Nk[0], mesh.type[1], mesh.Nk[1], options.eta, options.etaLead)) foSN.write('# E SNtot(E) SNi(E)(i=1-%i)\n' % options.numchan) foFF = open(thisspinlabel + '.FANO', 'write') foFF.write('# Nk1(%s)=%i Nk2(%s)=%i eta=%.2e etaLead=%.2e\n' % (mesh.type[0], mesh.Nk[0], mesh.type[1], mesh.Nk[1], options.eta, options.etaLead)) foFF.write('# E Fano factor \n') # Loop over energy for ie, ee in enumerate(options.Elist): Tavg = N.zeros((options.numchan + 1, len(mesh.w)), N.float) SNavg = N.zeros((options.numchan + 1, len(mesh.w)), N.float) AavL = N.zeros((DevGF.nuo, DevGF.nuo), N.complex) AavR = N.zeros((DevGF.nuo, DevGF.nuo), N.complex) # Loops over k-points for ik in range(mesh.NNk): DevGF.calcGF(ee + options.eta * 1.0j, mesh.k[ik, :2], ispin=iSpin, etaLead=options.etaLead, useSigNCfiles=options.signc, SpectralCutoff=options.SpectralCutoff) # Transmission and shot noise T, SN = DevGF.calcTEIG(options.numchan) for iw in range(len(mesh.w)): Tavg[:, iw] += T * mesh.w[iw, ik] SNavg[:, iw] += SN * mesh.w[iw, ik] Tkpt[ie, ik] = T SNkpt[ie, ik] = SN # DOS calculation: if options.dos: if options.SpectralCutoff > 0.0: AavL += mesh.w[0, ik] * MM.mm(DevGF.AL.L, DevGF.AL.R, DevGF.S) AavR += mesh.w[0, ik] * MM.mm(DevGF.AR.L, DevGF.AR.R, DevGF.S) else: AavL += mesh.w[0, ik] * MM.mm(DevGF.AL, DevGF.S) AavR += mesh.w[0, ik] * MM.mm(DevGF.AR, DevGF.S) # Print calculated quantities err = (N.abs(Tavg[0, 0] - Tavg[0, 1]) + N.abs(Tavg[0, 0] - Tavg[0, 2])) / 2 relerr = err / Tavg[0, 0] print 'ispin= %i, e= %.4f, Tavg= %.8f, RelErr= %.1e' % ( iSpin, ee, Tavg[0, 0], relerr) transline = '\n%.10f ' % ee noiseline = '\n%.10f ' % ee for ichan in range(options.numchan + 1): if ichan == 0: transline += '%.8e ' % Tavg[ichan, 0] noiseline += '%.8e ' % SNavg[ichan, 0] else: transline += '%.4e ' % Tavg[ichan, 0] noiseline += '%.4e ' % SNavg[ichan, 0] transline += '%.2e ' % relerr fo.write(transline) foSN.write(noiseline) foFF.write('\n%.10f %.8e' % (ee, SNavg[0, 0] / Tavg[0, 0])) # Partial density of states: if options.dos: DOSL[iSpin, ie, :] += N.diag(AavL).real / (2 * N.pi) DOSR[iSpin, ie, :] += N.diag(AavR).real / (2 * N.pi) MPSHL[iSpin, ie, :] += N.diag(MM.mm(MM.dagger(es0), AavL, es0)).real / (2 * N.pi) MPSHR[iSpin, ie, :] += N.diag(MM.mm(MM.dagger(es0), AavR, es0)).real / (2 * N.pi) print 'ispin= %i, e= %.4f, DOSL= %.4f, DOSR= %.4f' % ( iSpin, ee, N.sum(DOSL[iSpin, ie, :]), N.sum(DOSR[iSpin, ie, :])) fo.write('\n') fo.close() foSN.write('\n') foSN.close() foFF.write('\n') foFF.close() # Write k-point-resolved transmission fo = open(thisspinlabel + '.TRANS', 'write') for ik in range(mesh.NNk): w = mesh.w[:, ik] fo.write('\n\n# k = %f, %f w = %f %f %f %f' % (mesh.k[ik, 0], mesh.k[ik, 1], w[0], w[1], w[2], w[3])) for ie, ee in enumerate(options.Elist): transline = '\n%.10f ' % ee for ichan in range(options.numchan + 1): if ichan == 0: transline += '%.8e ' % Tkpt[ie, ik, ichan] else: transline += '%.4e ' % Tkpt[ie, ik, ichan] fo.write(transline) fo.write('\n') fo.close() # Write k-point-resolved shot noise fo = open(thisspinlabel + '.NOISE', 'write') for ik in range(mesh.NNk): w = mesh.w[:, ik] fo.write('\n\n# k = %f, %f w = %f %f %f %f' % (mesh.k[ik, 0], mesh.k[ik, 1], w[0], w[1], w[2], w[3])) for ie, ee in enumerate(options.Elist): noiseline = '\n%.10f ' % ee for ichan in range(options.numchan + 1): if ichan == 0: noiseline += '%.8e ' % SNkpt[ie, ik, ichan] else: noiseline += '%.4e ' % SNkpt[ie, ik, ichan] fo.write(noiseline) fo.write('\n') fo.close() # End loop over spin NEGF.SavedSig.close() # Make sure saved Sigma is written to file if options.dos: # Read basis L = options.bufferL # Pad lasto with zeroes to enable basis generation... lasto = N.zeros((DevGF.HS.nua + L + 1, ), N.int) lasto[L:] = DevGF.HS.lasto basis = SIO.BuildBasis(options.fn, 1 + L, DevGF.HS.nua + L, lasto) basis.ii -= L WritePDOS(outFile + '.PDOS.gz', options, DevGF, DOSL + DOSR, basis) WritePDOS(outFile + '.PDOSL.gz', options, DevGF, DOSL, basis) WritePDOS(outFile + '.PDOSR.gz', options, DevGF, DOSR, basis) WriteMPSH(outFile + '.MPSH.gz', options, DevGF, MPSHL + MPSHR, ev0) WriteMPSH(outFile + '.MPSHL.gz', options, DevGF, MPSHL, ev0) WriteMPSH(outFile + '.MPSHR.gz', options, DevGF, MPSHR, ev0) CF.PrintMainFooter('pyTBT')
def GetOptions(argv, **kwargs): """ Returns an instance of ``options`` for the ``pyTBT`` module Parameters ---------- argv : string For example `-N 5 test_dir`, which instructs to compute transmission on 5 energy points and place the results in the output directory `test_dir`. """ CF.PrintMainHeader('GetOptions', None) # if text string is specified, convert to list if isinstance(argv, VC.string_types): argv = argv.split() import argparse p = argparse.ArgumentParser( description= 'pyTBT is a Python version of TBtrans originally developed by Mads Brandbyge.' ) p.add_argument('DestDir', help='Destination directory') # keywords with defaults from fdf-file: p.add_argument( '-f', '--fdf', dest='fn', default='./RUN.fdf', type=str, help='Input fdf-file for TranSIESTA calculation [%(default)s]') p.add_argument( '-F', '--DeviceFirst', dest='DeviceFirst', default=0, type=int, help='First device atom (SIESTA numbering) [TS.TBT.PDOSFrom]') p.add_argument('-L', '--DeviceLast', dest='DeviceLast', default=0, type=int, help='Last device atom (SIESTA numbering) [TS.TBT.PDOSTo]') p.add_argument('-N', '--NPoints', dest='NPoints', default=0, type=int, help='Energy points [TS.TBT.NPoints]') p.add_argument('--Emin', dest='Emin', default=1e10, type=float, help='First energy point [TS.TBT.Emin]') p.add_argument('--Emax', dest='Emax', default=1e10, type=float, help='Last energy point [TS.TBT.Emax]') # k-points related p.add_argument('-x', '--Nk1', dest='Nk1', default=1, type=int, help='k-points Nk1 along a1 [%(default)s]') p.add_argument('-y', '--Nk2', dest='Nk2', default=1, type=int, help='k-points Nk2 along a2 [%(default)s]') p.add_argument( '-a', '--Gk1', dest='Gk1', default=0, type=int, help= 'Gaussian quadrature k-point sampling for a1 direction (2*GK1+1 points) [%(default)s]' ) p.add_argument( '-b', '--Gk2', dest='Gk2', default=0, type=int, help= 'Gaussian quadrature k-point sampling for a2 direction (2*GK2+1 points) [%(default)s]' ) p.add_argument( '-s', '--skipsym', dest='skipsymmetry', default=False, action='store_true', help= 'Skip inversion (time-reversal) symmetry (i.e., k=-k) that reduces the number of k-point evaluations' ) p.add_argument('-j', '--singlejunction', dest='singlejunction', default=False, action='store_true', help='k-point sample only electrode self-energies') # Imaginary part to Greens functions p.add_argument( '-e', '--eta', dest='eta', type=float, default=1e-6, help= 'Imaginary part added to all energies (device and leads) [%(default)s eV]' ) p.add_argument( '-l', '--etaLead', dest='etaLead', type=float, default=0.0, help= 'Additional imaginary part added ONLY in the leads (surface GF) [%(default)s eV]' ) # Other options p.add_argument('-d', '--skipDOS', dest='dos', default=True, action='store_false', help='Skip calculation of PDOS') p.add_argument('--useSigNC', dest='signc', default=False, action='store_true', help='Use SigNCfiles') p.add_argument('--NumChan', dest='numchan', type=int, default=10, help='Number of eigenchannels [%(default)s]') # Electrode stuff p.add_argument( '--bulk', dest='UseBulk', default=-1, action='store_true', help= 'Use bulk in electrodes. The Hamiltonian from the electrode calculation is inserted into the electrode region in the TranSIESTA cell [TS.UseBulkInElectrodes]' ) p.add_argument( '--nobulk', dest='UseBulk', default=-1, action='store_false', help= 'Use only self-energies in the electrodes. The full Hamiltonian of the TranSIESTA cell is used in combination with self-energies for the electrodes [TS.UseBulkInElectrodes]' ) # Scale (artificially) coupling to electrodes p.add_argument( '--scaleSigL', dest='scaleSigL', type=float, default=1.0, help='Scale factor applied to Sigma_L [default=%(default)s]') p.add_argument( '--scaleSigR', dest='scaleSigR', type=float, default=1.0, help='Scale factor applied to Sigma_R [default=%(default)s]') # Use spectral matrices? p.add_argument( '--SpectralCutoff', dest='SpectralCutoff', type=float, default=0.0, help= 'Cutoff value for SpectralMatrix functions (for ordinary matrix representation set cutoff<=0.0) [default=%(default)s]' ) # Parse the options options = p.parse_args(argv) # With this one can overwrite the logging information if "log" in kwargs: options.Logfile = kwargs['log'] else: options.Logfile = 'pyTBT.log' return options
def GetOptions(argv, **kwargs): """ Returns an instance of ``options`` for the ``EigenChannels`` module Parameters ---------- argv : string For example `-n 2 test_dir`, which instructs to compute only the two most transmitting eigenchannel scattering states and place the results in the output directory `test_dir`. """ CF.PrintMainHeader('GetOptions', None) # if text string is specified, convert to list if isinstance(argv, VC.string_types): argv = argv.split() import argparse p = argparse.ArgumentParser(description='Eigenchannels, see Paulsson et al. PRB 76, 115117 (2007)') p.add_argument('DestDir', help='Destination directory') p.add_argument('-F', '--DeviceFirst', dest='DeviceFirst', default=0, type=int, help='First device atom (SIESTA numbering) [default: TS.TBT.PDOSFrom]') p.add_argument('-L', '--DeviceLast', dest='DeviceLast', default=0, type=int, help='Last device atom (SIESTA numbering) [default: TS.TBT.PDOSTo]') p.add_argument('-n', '--NumChan', dest='numchan', type=int, default=4, help='Number of eigenchannels [default: %(default)s]') p.add_argument('-B', '--BothSides', dest='bothsides', default=False, action='store_true', help='Calculate eigenchannels from both sides [default: %(default)s]') p.add_argument('-M', '--MPSH', dest='MolStates', default=0.0, type=float, help='Calculate eigenstates of the device region Hamiltonian (Molecular Projected Selfconsistent Hamiltonian, MPSH) within [default: +/- %(default)s] eV from Ef') p.add_argument('-r', '--Res', dest='res', default=0.4, type=float, help='Resolution [default: %(default)s Ang]') p.add_argument('-w', '--format', dest='format', default='XSF', type=str, help='Wavefunction format (macu, cube, XSF, or nc) [default: %(default)s]') p.add_argument('-e', '--Energy', dest='energy', default=0.0, type=float, help='Energy where eigenchannel scattering states are evaluated [default: %(default)s eV]') p.add_argument('--eta', dest='eta', type=float, default=0.000001, help='Imaginary part added to all energies (device and leads) [default: %(default)s eV]') p.add_argument('-l', '--etaLead', dest='etaLead', type=float, default=0.0, help='Additional imaginary part added ONLY in the leads (surface GF) [default: %(default)s eV]') p.add_argument('-f', '--fdf', dest='fn', default='./RUN.fdf', type=str, help='Input fdf-file for TranSIESTA calculations [default: %(default)s]') p.add_argument('-s', '--iSpin', dest='iSpin', default=0, type=int, help='Spin channel [default: %(default)s]') p.add_argument('-x', '--k1', dest='k1', default=0.0, type=float, help='k-point along a1 [default: %(default)s]') p.add_argument('-y', '--k2', dest='k2', default=0.0, type=float, help='k-point along a2 [default: %(default)s]') p.add_argument('-u', '--useSigNC', dest='signc', default=False, action='store_true', help='Use SigNCfiles [default: %(default)s]') # Electrode stuff p.add_argument('--bulk', dest='UseBulk', default=-1, action='store_true', help='Use bulk in electrodes. The Hamiltonian from the electrode calculation is inserted into the electrode region in the TranSIESTA cell [default: TS.UseBulkInElectrodes]') p.add_argument('--nobulk', dest='UseBulk', default=-1, action='store_false', help='Use only self-energies in the electrodes. The full Hamiltonian of the TranSIESTA cell is used in combination with self-energies for the electrodes [default: TS.UseBulkInElectrodes]') # Scale (artificially) the coupling to the electrodes p.add_argument('--scaleSigL', dest='scaleSigL', type=float, default=1.0, help='Scale factor applied to Sigma_L [default=%(default)s]') p.add_argument('--scaleSigR', dest='scaleSigR', type=float, default=1.0, help='Scale factor applied to Sigma_R [default=%(default)s]') # Use spectral matrices? p.add_argument('--SpectralCutoff', dest='SpectralCutoff', type=float, default=0.0, help='Cutoff value for SpectralMatrix functions (for ordinary matrix representation set cutoff<=0.0) [default=%(default)s]') options = p.parse_args(argv) # With this one can overwrite the logging information if "log" in kwargs: options.Logfile = kwargs["log"] else: options.Logfile = 'EigenChannels.log' # k-point options.kpoint = N.array([options.k1, options.k2, 0.0], N.float) del options.k1, options.k2 return options
def main(options): """ Main routine to compute eigenchannel scattering states Parameters ---------- options : an ``options`` instance """ CF.CreatePipeOutput(options.DestDir+'/'+options.Logfile) VC.OptionsCheck(options, 'EigenChannels') CF.PrintMainHeader('EigenChannels', options) # Read geometry XV = '%s/%s.XV'%(options.head, options.systemlabel) geom = MG.Geom(XV, BufferAtoms=options.buffer) # Set up device Greens function elecL = NEGF.ElectrodeSelfEnergy(options.fnL, options.NA1L, options.NA2L, options.voltage/2.) elecL.scaling = options.scaleSigL elecL.semiinf = options.semiinfL elecR = NEGF.ElectrodeSelfEnergy(options.fnR, options.NA1R, options.NA2R, -options.voltage/2.) elecR.scaling = options.scaleSigR elecR.semiinf = options.semiinfR DevGF = NEGF.GF(options.TSHS, elecL, elecR, Bulk=options.UseBulk, DeviceAtoms=options.DeviceAtoms, BufferAtoms=options.buffer) DevGF.calcGF(options.energy+options.eta*1.0j, options.kpoint[0:2], ispin=options.iSpin, etaLead=options.etaLead, useSigNCfiles=options.signc, SpectralCutoff=options.SpectralCutoff) NEGF.SavedSig.close() # Make sure saved Sigma is written to file # Transmission print 'Transmission Ttot(%.4feV) = %.16f'%(options.energy, N.trace(DevGF.TT).real) # Build basis options.nspin = DevGF.HS.nspin L = options.bufferL # Pad lasto with zeroes to enable basis generation... lasto = N.zeros((DevGF.HS.nua+L+1,), N.int) lasto[L:] = DevGF.HS.lasto basis = SIO.BuildBasis(options.fn, options.DeviceAtoms[0]+L, options.DeviceAtoms[1]+L, lasto) basis.ii -= L # Calculate Eigenchannels DevGF.calcEigChan(options.numchan) # Compute bond currents? if options.kpoint[0]!=0.0 or options.kpoint[1]!=0.0: print 'Warning: The current implementation of bond currents is only valid for the Gamma point (should be easy to fix)' BC = False else: BC = True # Eigenchannels from left ECleft = DevGF.ECleft for jj in range(options.numchan): options.iSide, options.iChan = 0, jj+1 writeWavefunction(options, geom, basis, ECleft[jj]) if BC: Curr=calcCurrent(options, basis, DevGF.H, ECleft[jj]) writeCurrent(options, geom, Curr) # Calculate eigenchannels from right if options.bothsides: ECright = DevGF.ECright for jj in range(options.numchan): options.iSide, options.iChan = 1, jj+1 writeWavefunction(options, geom, basis, ECright[jj]) if BC: Curr=calcCurrent(options, basis, DevGF.H, ECright[jj]) writeCurrent(options, geom, Curr) # Calculate total "bond currents" if BC: Curr=-calcCurrent(options, basis, DevGF.H, DevGF.AL) options.iChan, options.iSide = 0, 0 writeCurrent(options, geom, Curr) Curr=-calcCurrent(options, basis, DevGF.H, DevGF.AR) options.iSide = 1 writeCurrent(options, geom, Curr) # Calculate eigenstates of device Hamiltonian (MPSH) if options.MolStates>0.0: try: import scipy.linalg as SLA ev, es = SLA.eigh(DevGF.H, DevGF.S) print 'EigenChannels: Eigenvalues (in eV) of computed molecular eigenstates:' print ev # Write eigenvalues to file fn = options.DestDir+'/'+options.systemlabel+'.EIGVAL' print 'EigenChannels: Writing', fn fnfile = open(fn, 'w') fnfile.write('# Device region = [%i,%i], units in eV\n'%(options.DeviceFirst, options.DeviceLast)) for i, val in enumerate(ev): fnfile.write('%i %.8f\n'%(i, val)) fnfile.close() # Compute selected eigenstates for ii, val in enumerate(ev): if N.abs(val)<options.MolStates: fn=options.DestDir+'/'+options.systemlabel+'.S%.3i.E%.3f'%(ii, val) writeWavefunction(options, geom, basis, es[:, ii], fn=fn) except: print 'You need to install scipy to solve the generalized eigenvalue problem' print 'for the molecular eigenstates in the nonorthogonal basis' CF.PrintMainFooter('EigenChannels')
def main(options): CF.CreatePipeOutput(options.DestDir + '/' + options.Logfile) #VC.OptionsCheck(options,'Phonons') CF.PrintMainHeader('Bandstructures', options) try: fdf = glob.glob(options.onlyTSdir + '/RUN.fdf') TSrun = True except: fdf = glob.glob(options.FCwildcard + '/RUN.fdf') # This should be made an input flag TSrun = False SCDM = Supercell_DynamicalMatrix(fdf, TSrun) # Write high-symmetry path WritePath(options.DestDir + '/symmetry-path', SCDM.Sym.path, options.steps) # Write mesh k1, k2, k3 = ast.literal_eval(options.mesh) rvec = 2 * N.pi * N.array([SCDM.Sym.b1, SCDM.Sym.b2, SCDM.Sym.b3]) import Inelastica.physics.mesh as Kmesh # Full mesh kmesh = Kmesh.kmesh(2**k1, 2**k2, 2**k3, meshtype=['LIN', 'LIN', 'LIN'], invsymmetry=False) WriteKpoints(options.DestDir + '/mesh_%ix%ix%i' % tuple(kmesh.Nk), N.dot(kmesh.k, rvec)) # Mesh reduced by inversion symmetry kmesh = Kmesh.kmesh(2**k1, 2**k2, 2**k3, meshtype=['LIN', 'LIN', 'LIN'], invsymmetry=True) WriteKpoints(options.DestDir + '/mesh_%ix%ix%i_invsym' % tuple(kmesh.Nk), N.dot(kmesh.k, rvec)) # Evaluate electron k-points if options.kfile: # Prepare Hamiltonian etc in Gamma for whole supercell natoms = SIO.GetFDFlineWithDefault(fdf[0], 'NumberOfAtoms', int, -1, 'Error') SCDM.PrepareGradients(options.onlySdir, N.array([0., 0., 0.]), 1, natoms, AbsEref=False, atype=N.complex, TSrun=TSrun) SCDM.nao = SCDM.h0.shape[-1] SCDM.FirstOrb = SCDM.OrbIndx[0][0] # First atom = 1 SCDM.LastOrb = SCDM.OrbIndx[SCDM.Sym.basis.NN - 1][1] # Last atom = Sym.NN SCDM.rednao = SCDM.LastOrb + 1 - SCDM.FirstOrb # Read kpoints kpts, dk, klabels, kticks = ReadKpoints(options.kfile) if klabels: # Only write ascii if labels exist WriteKpoints(options.DestDir + '/kpoints', kpts, klabels) # Prepare netcdf ncfn = options.DestDir + '/Electrons.nc' ncf = NC4.Dataset(ncfn, 'w') # Grid ncf.createDimension('gridpts', len(kpts)) ncf.createDimension('vector', 3) grid = ncf.createVariable('grid', 'd', ('gridpts', 'vector')) grid[:] = kpts grid.units = '1/Angstrom' # Geometry ncf.createDimension('atoms', SCDM.Sym.basis.NN) xyz = ncf.createVariable('xyz', 'd', ('atoms', 'vector')) xyz[:] = SCDM.Sym.basis.xyz xyz.units = 'Angstrom' pbc = ncf.createVariable('pbc', 'd', ('vector', 'vector')) pbc.units = 'Angstrom' pbc[:] = [SCDM.Sym.a1, SCDM.Sym.a2, SCDM.Sym.a3] rvec1 = ncf.createVariable('rvec', 'd', ('vector', 'vector')) rvec1.units = '1/Angstrom (incl. factor 2pi)' rvec1[:] = rvec ncf.sync() # Loop over kpoints for i, k in enumerate(kpts): if i < 100: # Print only for the first 100 points ev, evec = SCDM.ComputeElectronStates(k, verbose=True, TSrun=TSrun) else: ev, evec = SCDM.ComputeElectronStates(k, verbose=False, TSrun=TSrun) # otherwise something simple if i % 100 == 0: print '%i out of %i k-points computed' % (i, len(kpts)) if i == 0: ncf.createDimension('nspin', SCDM.nspin) ncf.createDimension('orbs', SCDM.rednao) if options.nbands and options.nbands < SCDM.rednao: nbands = options.nbands else: nbands = SCDM.rednao ncf.createDimension('bands', nbands) evals = ncf.createVariable('eigenvalues', 'd', ('gridpts', 'nspin', 'bands')) evals.units = 'eV' evecsRe = ncf.createVariable( 'eigenvectors.re', 'd', ('gridpts', 'nspin', 'orbs', 'bands')) evecsIm = ncf.createVariable( 'eigenvectors.im', 'd', ('gridpts', 'nspin', 'orbs', 'bands')) # Check eigenvectors print 'SupercellPhonons: Checking eigenvectors at', k for j in range(SCDM.nspin): ev2 = N.diagonal( MM.mm(MM.dagger(evec[j]), SCDM.h0_k[j], evec[j])) print ' ... spin %i: Allclose=' % j, N.allclose(ev[j], ev2, atol=1e-5, rtol=1e-3) ncf.sync() # Write to NetCDF evals[i, :] = ev[:, :nbands] evecsRe[i, :] = evec[:, :, :nbands].real evecsIm[i, :] = evec[:, :, :nbands].imag ncf.sync() # Include basis orbitals in netcdf file if SCDM.Sym.basis.NN == len(SCDM.OrbIndx): lasto = N.zeros(SCDM.Sym.basis.NN + 1, N.float) lasto[:SCDM.Sym.basis.NN] = SCDM.OrbIndx[:SCDM.Sym.basis.NN, 0] lasto[SCDM.Sym.basis.NN] = SCDM.OrbIndx[SCDM.Sym.basis.NN - 1, 1] + 1 else: lasto = SCDM.OrbIndx[:SCDM.Sym.basis.NN + 1, 0] orbbasis = SIO.BuildBasis(fdf[0], 1, SCDM.Sym.basis.NN, lasto) # Note that the above basis is for the geometry with an atom FC-moved in z. #print dir(orbbasis) #print orbbasis.xyz # Hence, this is not the correct geometry of the basis atoms! center = ncf.createVariable('orbcenter', 'i', ('orbs', )) center[:] = N.array(orbbasis.ii - 1, dtype='int32') center.description = 'Atom index (counting from 0) of the orbital center' nn = ncf.createVariable('N', 'i', ('orbs', )) nn[:] = N.array(orbbasis.N, dtype='int32') ll = ncf.createVariable('L', 'i', ('orbs', )) ll[:] = N.array(orbbasis.L, dtype='int32') mm = ncf.createVariable('M', 'i', ('orbs', )) mm[:] = N.array(orbbasis.M, dtype='int32') # Cutoff radius and delta Rc = ncf.createVariable('Rc', 'd', ('orbs', )) Rc[:] = orbbasis.coff Rc.units = 'Angstrom' delta = ncf.createVariable('delta', 'd', ('orbs', )) delta[:] = orbbasis.delta delta.units = 'Angstrom' # Radial components of the orbitals ntb = len(orbbasis.orb[0]) ncf.createDimension('ntb', ntb) rii = ncf.createVariable('rii', 'd', ('orbs', 'ntb')) rii[:] = N.outer(orbbasis.delta, N.arange(ntb)) rii.units = 'Angstrom' radialfct = ncf.createVariable('radialfct', 'd', ('orbs', 'ntb')) radialfct[:] = orbbasis.orb # Sort eigenvalues to connect crossing bands? if options.sorting: for i in range(SCDM.nspin): evals[:, i, :] = SortBands(evals[:, i, :]) # Produce nice plots if labels exist if klabels: if SCDM.nspin == 1: PlotElectronBands(options.DestDir + '/Electrons.agr', dk, evals[:, 0, :], kticks) elif SCDM.nspin == 2: PlotElectronBands(options.DestDir + '/Electrons.UP.agr', dk, evals[:, 0, :], kticks) PlotElectronBands(options.DestDir + '/Electrons.DOWN.agr', dk, evals[:, 1, :], kticks) ncf.close() if TSrun: # only electronic calculation return SCDM.Sym.path # Compute phonon eigenvalues if options.qfile: SCDM.SymmetrizeFC(options.radius) SCDM.SetMasses() qpts, dq, qlabels, qticks = ReadKpoints(options.qfile) if qlabels: # Only write ascii if labels exist WriteKpoints(options.DestDir + '/qpoints', qpts, qlabels) # Prepare netcdf ncfn = options.DestDir + '/Phonons.nc' ncf = NC4.Dataset(ncfn, 'w') # Grid ncf.createDimension('gridpts', len(qpts)) ncf.createDimension('vector', 3) grid = ncf.createVariable('grid', 'd', ('gridpts', 'vector')) grid[:] = qpts grid.units = '1/Angstrom' # Geometry ncf.createDimension('atoms', SCDM.Sym.basis.NN) xyz = ncf.createVariable('xyz', 'd', ('atoms', 'vector')) xyz[:] = SCDM.Sym.basis.xyz xyz.units = 'Angstrom' pbc = ncf.createVariable('pbc', 'd', ('vector', 'vector')) pbc.units = 'Angstrom' pbc[:] = [SCDM.Sym.a1, SCDM.Sym.a2, SCDM.Sym.a3] rvec1 = ncf.createVariable('rvec', 'd', ('vector', 'vector')) rvec1.units = '1/Angstrom (incl. factor 2pi)' rvec1[:] = rvec ncf.sync() # Loop over q for i, q in enumerate(qpts): if i < 100: # Print only for the first 100 points hw, U = SCDM.ComputePhononModes_q(q, verbose=True) else: hw, U = SCDM.ComputePhononModes_q(q, verbose=False) # otherwise something simple if i % 100 == 0: print '%i out of %i q-points computed' % (i, len(qpts)) if i == 0: ncf.createDimension('bands', len(hw)) ncf.createDimension('displ', len(hw)) evals = ncf.createVariable('eigenvalues', 'd', ('gridpts', 'bands')) evals.units = 'eV' evecsRe = ncf.createVariable('eigenvectors.re', 'd', ('gridpts', 'bands', 'displ')) evecsIm = ncf.createVariable('eigenvectors.im', 'd', ('gridpts', 'bands', 'displ')) # Check eigenvectors print 'SupercellPhonons.Checking eigenvectors at', q tmp = MM.mm(N.conjugate(U), SCDM.FCtilde, N.transpose(U)) const = PC.hbar2SI * (1e20 / (PC.eV2Joule * PC.amu2kg))**0.5 hw2 = const * N.diagonal(tmp)**0.5 # Units in eV print ' ... Allclose=', N.allclose(hw, N.absolute(hw2), atol=1e-5, rtol=1e-3) ncf.sync() evals[i] = hw evecsRe[i] = U.real evecsIm[i] = U.imag ncf.sync() # Sort eigenvalues to connect crossing bands? if options.sorting: evals = SortBands(evals) # Produce nice plots if labels exist if qlabels: PlotPhononBands(options.DestDir + '/Phonons.agr', dq, N.array(evals[:]), qticks) ncf.close() # Compute e-ph couplings if options.kfile and options.qfile: SCDM.ReadGradients(AbsEref=False) ncf = NC4.Dataset(options.DestDir + '/EPH.nc', 'w') ncf.createDimension('kpts', len(kpts)) ncf.createDimension('qpts', len(qpts)) ncf.createDimension('modes', len(hw)) ncf.createDimension('nspin', SCDM.nspin) ncf.createDimension('bands', SCDM.rednao) ncf.createDimension('vector', 3) kgrid = ncf.createVariable('kpts', 'd', ('kpts', 'vector')) kgrid[:] = kpts qgrid = ncf.createVariable('qpts', 'd', ('qpts', 'vector')) qgrid[:] = qpts evalfkq = ncf.createVariable('evalfkq', 'd', ('kpts', 'qpts', 'nspin', 'bands')) # First (second) band index n (n') is the initial (final) state, i.e., # Mkq(k,q,mode,spin,n,n') := < n',k+q | dV_q(mode) | n,k > MkqAbs = ncf.createVariable( 'Mkqabs', 'd', ('kpts', 'qpts', 'modes', 'nspin', 'bands', 'bands')) GkqAbs = ncf.createVariable( 'Gkqabs', 'd', ('kpts', 'qpts', 'modes', 'nspin', 'bands', 'bands')) ncf.sync() # Loop over k-points for i, k in enumerate(kpts): kpts[i] = k # Compute initial electronic states evi, eveci = SCDM.ComputeElectronStates(k, verbose=True) # Loop over q-points for j, q in enumerate(qpts): # Compute phonon modes hw, U = SCDM.ComputePhononModes_q(q, verbose=True) # Compute final electronic states evf, evecf = SCDM.ComputeElectronStates(k + q, verbose=True) evalfkq[i, j, :] = evf # Compute electron-phonon couplings m, g = SCDM.ComputeEPHcouplings_kq( k, q) # (modes,nspin,bands,bands) # Data to file # M (modes,spin,i,l) = m(modes,k,j) init(i,j) final(k,l) # 0 1 2 0,1 0 1 # ^-------^ # ^----------------------^ for ispin in range(SCDM.nspin): evecfd = MM.dagger(evecf[ispin]) # (bands,bands) M = N.tensordot(N.tensordot(m[:, ispin], eveci[ispin], axes=[2, 0]), evecfd, axes=[1, 1]) G = N.tensordot(N.tensordot(g[:, ispin], eveci[ispin], axes=[2, 0]), evecfd, axes=[1, 1]) MkqAbs[i, j, :, ispin] = N.absolute(M) GkqAbs[i, j, :, ispin] = N.absolute(G) ncf.sync() ncf.close() return SCDM.Sym.path
def main(options): dd = len(glob.glob(options.DestDir)) if len(glob.glob('TotalPotential.grid.nc'))==0 and len(glob.glob('Rho.grid.nc'))==0: sys.exit('TotalPotential.nc and Rho.grid.nc not found! Add "SaveTotalPotential true" and "SaveRho true" to RUN.fdf') if len(glob.glob('TotalPotential.grid.nc'))==0: sys.exit('TotalPotential.nc not found! Add "SaveTotalPotential true" to RUN.fdf') if len(glob.glob('Rho.grid.nc'))==0: sys.exit('Rho.grid.nc not found! Add "SaveRho true" to RUN.fdf') CF.CreatePipeOutput(options.DestDir+'/'+options.Logfile) VC.OptionsCheck(options, 'STM') CF.PrintMainHeader('STM', options) ## Step 1: Calculate scattering states from L/R on TranSiesta real space grid. if glob.glob(options.DestDir+'/kpoints')!=[]: # Check previous k-points f, oldk = open(options.DestDir+'/kpoints', 'r'), [] f.readline() for ii in f.readlines(): oldk += [N.array(string.split(ii), N.float)] oldk = N.array(oldk) options.kpoints.mesh2file(options.DestDir+'/kpoints') doK = [] for ikpoint in range(len(options.kpoints.k)): ikdir = options.DestDir+'/%i'%(ikpoint) if not os.path.isdir(ikdir): os.mkdir(ikdir) doK += [ikpoint] #Check if some k points are already done doK = [] nokpts = len(options.kpoints.k) noFDcalcs = len(glob.glob('./'+options.DestDir+'/*/FDcurr*.nc')) for ii in range(nokpts): if len(glob.glob('./'+options.DestDir+'/'+str(ii)+'/FDcurr'+str(ii)+'.nc'))==1: pass else: doK += [ii] if noFDcalcs>nokpts-1: print('\nAll ('+str(nokpts)+') k points are already finished!\n') elif noFDcalcs>0 and noFDcalcs<nokpts: print(str(nokpts-len(doK))+' ('+str(N.round(100.*((1.*nokpts-len(doK))/nokpts), 1))+'%) k points already done. Will proceed with the rest.') print('You should perhaps remove the loc-basis states in the most recent k folder ') print('since some of these may not have been calculated before interuption.\n') else: if dd==1: print('No STM calculations found in existing directory '+str(options.DestDir)+'/. Starting from scratch.') print('(...by possibly using saved localized-basis states)\n') else: print('STM calculation starts.') args=[(options, ik) for ik in doK] tmp = CF.runParallel(calcTSWFPar, args, nCPU=options.nCPU) print('Calculating k-point averaged STM image') def ShiftOrigin(mat, x, y): Nx = N.shape(mat)[0]; Ny = N.shape(mat)[1] NewMat = N.zeros((Nx, Ny)) for ii in range(Nx): for jj in range(Ny): NewMat[N.mod(ii+x, Nx), N.mod(jj+y, Ny)] = mat[ii, jj] return NewMat file = NC.Dataset('TotalPotential.grid.nc', 'r') steps = N.array(file.variables['cell'][:], N.float) theta = N.arccos(N.dot(steps[0], steps[1])/(LA.norm(steps[0])*LA.norm(steps[1]))) currtmp = NC.Dataset('./'+options.DestDir+'/0/FDcurr0.nc', 'r') dimSTMimage = N.shape(currtmp.variables['Curr'][:, :]) dim1 = dimSTMimage[0] dim2 = dimSTMimage[1] STMimage = N.zeros((dim1, dim2)) tmpSTM = N.zeros((dim1*nokpts, dim2)) for ii in range(nokpts): file = NC.Dataset('./'+options.DestDir+'/'+str(ii)+'/FDcurr'+str(ii)+'.nc', 'r') ikSTMimage = file.variables['Curr'][:, :]/(nokpts) STMimage += ShiftOrigin(ikSTMimage, dim1/2, dim2/2) tmpSTM[ii*dim1:(ii+1)*dim1, :] = ShiftOrigin(ikSTMimage, dim1/2, dim2/2) STMimagekpt = N.zeros((dim1*options.Nk1, dim2*options.Nk2)) for ii in range(options.Nk1): for jj in range(options.Nk2): N1 = ii+1; N2 = options.Nk2-jj; kk = (ii+1)*options.Nk2-jj-1 STMimagekpt[(N1-1)*dim1:N1*dim1, (N2-1)*dim2:N2*dim2]=tmpSTM[kk*dim1:(kk+1)*dim1, ::-1] tmp = open(options.systemlabel+'.XV').readlines()[4+options.DeviceFirst-1:4+options.DeviceLast] xyz = N.zeros((len(tmp), 4)) for ii in range(len(tmp)): for jj in range(1, 5): tmp2 = tmp[ii].split() xyz[ii, jj-1] = ast.literal_eval(tmp2[jj]) if jj>1: xyz[ii, jj-1] = xyz[ii, jj-1]*PC.Bohr2Ang drAtoms = N.zeros(len(xyz)) for atomIdx in range(len(xyz)-1): drAtoms[atomIdx] = N.round((xyz[atomIdx+1][3]-xyz[atomIdx][3]), 3) TipHeight = N.max(drAtoms) n=writeNC.NCfile('./'+options.DestDir+'/STMimage.nc') n.write(STMimage, 'STMimage') n.write(theta, 'theta') n.write(options.kpoints.k, 'kpoints') n.write(options.Nk1, 'Nk1') n.write(options.Nk2, 'Nk2') n.write(STMimagekpt, 'STMkpoint') n.write(xyz, 'Geometry') n.write(TipHeight, 'TipHeight') n.close() CF.PrintMainFooter('STM')
varIm[:] = YY.imag*(PC.Bohr2Ang**(3.0/2.0)) varIm.units = '1/[Ryd^(1/2) Bohr^(3/2)]' varcell = file.createVariable('cell', 'd', ('naxes', 'naxes')) varcell[:] = pbc/PC.Bohr2Ang varcell.units = 'Bohr' vardsteps = file.createVariable('steps', 'd', ('naxes', 'naxes')) steps = N.array([pbc[0]/nx, pbc[1]/ny, pbc[2]/nz])/PC.Bohr2Ang vardsteps[:] = steps vardsteps.units = 'Bohr' varorig = file.createVariable('origin', 'd', ('naxes',)) varorig[:] = pbc[2]/nz*minnz/PC.Bohr2Ang varorig.units = 'Bohr' vargeom = file.createVariable('xyz', 'd', ('natoms', 'naxes')) vargeom[:] = geom.xyz[list(range(DeviceAtoms[0]-1, DeviceAtoms[1]))]/PC.Bohr2Ang vargeom.units = 'Bohr' varanr = file.createVariable('anr', 'i', ('natoms',)) varanr[:] = N.array(geom.anr[DeviceAtoms[0]-1:DeviceAtoms[1]], N.int32) file.close() ##################### Start main routine ##################### if __name__ == '__main__': from datetime import datetime start = datetime.now() options = GetOptions(sys.argv[1:]) print(dir(options)) #profile.run('main(options)') main(options) dT = datetime.now()-start CF.PrintScriptSummary(sys.argv, dT)