Example #1
0
def BuildOSstruct(infile,
                  outfile,
                  axes=[0, 1, 2],
                  direction=[-1, 1],
                  displacement=0.04 * PC.Bohr2Ang):
    print('BuildOSstruct: displacement = %.6f Ang' % displacement)
    geom = MG.Geom(infile)
    for i in axes:
        for displdir in direction:
            new = MG.Geom(infile)
            displ = [0., 0., 0.]
            displ[i] = displdir * displacement
            new.move(displ)
            geom.addGeom(new)
    geom.writeFDF(outfile)
Example #2
0
def FindElectrodeSep(directory, AtomsPerLayer):
    for xvfile in glob.glob(directory + '/*.XV*'):
        print(xvfile)
        g = MG.Geom(xvfile)
        g.findContactsAndDevice(AtomsPerLayer)
        DeviceFirst, DeviceLast = g.deviceList[0], g.deviceList[-1]
    return g.ContactSeparation, DeviceFirst, DeviceLast
Example #3
0
 def __init__(self, runfdf):
     self.fdf = runfdf
     self.directory, self.tail = os.path.split(runfdf)
     self.systemlabel = SIO.GetFDFlineWithDefault(runfdf, 'SystemLabel',
                                                  str, 'siesta', 'Phonons')
     # Read geometry
     self.geom = MG.Geom(runfdf)
     # Compare with XV file corrected for last displacement
     XV = self.directory + '/%s.XV' % self.systemlabel
     geomXV = MG.Geom(XV)
     natoms = self.geom.natoms
     # Determine TSHS files
     files = glob.glob(self.directory + '/%s*.TSHS' % self.systemlabel)
     # Build dictionary over TSHS files and corresponding displacement amplitudes
     self.TSHS = {}
     try:
         self.TSHS[0] = files[0]  # Equilibrium TSHS
     except:
         sys.exit('Phonons.GetFileLists: No TSHS file found in %s' %
                  self.directory)
Example #4
0
 def checkDone(self):
     if self.fixed==True:
         self.FDFgeom = MG.Geom(self.dir+"/RUN.fdf")
         self.XVgeom  = readxv(self.dir)
         self.forces  = SIO.ReadForces(self.dir+"/RUN.out")
         self.forces  = self.forces[-len(self.XVgeom.xyz):]
         self.Ftot    = self.forces
         self.converged = True
         return True
     else:
         SIO.CheckTermination(self.dir+"/RUN.out")
         self.FDFgeom = MG.Geom(self.dir+"/RUN.fdf")
         done = False
         try:
             self.XVgeom  = readxv(self.dir)
             self.forces  = SIO.ReadForces(self.dir+"/RUN.out")
             print len(self.forces[0])
             if N.allclose(self.XVgeom.xyz, self.FDFgeom.xyz, 1e-6):
                 done=True
         except:
             done=False
         return done
Example #5
0
 def checkDone(self):
     if self.fixed == True:
         self.FDFgeom = MG.Geom(self.dirr + "/" + opts.fn)
         self.XVgeom = readxv(self.dirr)
         self.forces = SIO.ReadForces(self.dirr + "/RUN.out")
         self.forces = self.forces[-len(self.XVgeom.xyz):]
         self.F = N.array(self.forces) * 0
         self.v = N.array(self.forces) * 0
         self.converged = True
         return True
     else:
         done = SIO.CheckTermination(self.dirr + "/RUN.out")
         if done:
             try:
                 self.FDFgeom = MG.Geom(self.dirr + "/" + opts.fn)
                 self.XVgeom = readxv(self.dirr)
                 self.forces = SIO.ReadForces(self.dirr + "/RUN.out")
                 if N.allclose(self.XVgeom.xyz, self.FDFgeom.xyz, 1e-6):
                     done = True
             except:
                 done = False
         return done
Example #6
0
def readxv(dirpath):
    global geom
    # Read geometry from first .XV file found in dirpath
    fns=glob.glob(dirpath+'/*.XV')

    if len(fns)>1:
        print "ERROR: NEB: More than one .XV file in dir:%s"%dirpath
        sys.exit(1)
    elif len(fns)<1:
        return None

    print('Reading geometry from "%s" file' % fns[0])
    geom = MG.Geom(fns[0])
    return geom
Example #7
0
def cutlayers(infile, nalayer, nl, nr, outfile, ord=None):
    """
    cut down some layers for md simulation
    infile  input STRUCT.fdf file
    nalayer number of atoms per layer
    nl      nl layers from left
    nr      nr layers from left
    ord     atom lists in new order
    """
    print "reading ", infile
    geom = MG.Geom(infile)
    xyz = geom.xyz
    snr = geom.snr
    anr = geom.anr
    pbc = geom.pbc

    if ord is not None:
        anr, xyz = reordxyz(anr, xyz, ord)

    zs = [a[2] for a in xyz]
    olen = max(zs) - min(zs)

    na = len(xyz)
    nal = nl * nalayer
    nar = nr * nalayer
    if (nal + nar >= na):
        print "Cuting too many atoms"
        sys.exit(0)

    nna = int(na - nal - nar)
    nxyz = [xyz[nal + i] for i in range(nna)]
    nsnr = [snr[nal + i] for i in range(nna)]
    nanr = [anr[nal + i] for i in range(nna)]

    nzs = [a[2] for a in nxyz]
    nlen = max(nzs) - min(nzs)

    pbc[2][2] = pbc[2][2] - (olen - nlen)

    geom.xyz = nxyz
    geom.pbc = pbc
    geom.snr = nsnr
    geom.anr = nanr
    geom.natoms = nna

    geom.writeFDF(outfile)
    geom.writeXYZ(os.path.splitext(outfile)[0] + ".xyz")

    return geom
Example #8
0
    def __init__(self, dirr, restart, iistep, initial=None, final=None):
        self.dirr = dirr
        self.converged, self.Fmax = False, 0.0
        self.ii = iistep
        self.fixed = (iistep == 0) or (iistep == opts.NNEB + 1)

        if restart or self.fixed:
            self.FDFgeom = MG.Geom(self.dirr + "/" + opts.fn)
            self.XVgeom = readxv(self.dirr)
            self.v = N.array(self.FDFgeom.xyz) * 0

        if not restart and not self.fixed:
            os.makedirs(dirr)
            SUR.CopyInputFiles(opts.initial+"/CGrun/", dirr,\
                                   ['.fdf', '.vps', '.psf'])
            # Interpolate
            ixyz, fxyz = N.array(initial.XVgeom.xyz), N.array(final.XVgeom.xyz)
            mix = float(iistep) / (opts.NNEB + 1.0)
            xyz = (1 - mix) * ixyz + mix * fxyz
            self.FDFgeom = copy.copy(initial.XVgeom)
            self.FDFgeom.xyz = [xyz[ii, :] for ii in range(len(xyz))]
            self.FDFgeom.writeFDF(self.dirr + "/STRUCT.fdf")
            self.v = N.array(self.FDFgeom.xyz) * 0

            # Append lines to RUN.fdf
            elm = dirr + "/" + opts.fn
            f = open(elm, 'r')
            lines = f.readlines()
            f.close()
            f = open(elm, 'w')
            f.write('### Lines appended %s \n' % time.ctime())
            f.write("MD.TypeOfRun         CG\n")
            f.write("MD.NumCGsteps        0\n")
            f.write("MD.UseSaveXV         False\n")
            f.write("MD.UseSaveCG         False\n")
            f.write('# end of lines appended %s \n' % time.ctime())
            for line in lines:
                f.write(line)
            f.close()

        self.done = self.checkDone()
        const = SIO.GetFDFblock(dirr + "/" + opts.fn, "GeometryConstraints")
        if opts.const2 != None:
            self.const = [[opts.const2[0], opts.const2[0]]]
        else:
            self.const = []
        for ii in const:
            self.const += [[int(ii[2]) - 1, int(ii[4]) - 1]]
Example #9
0
def readxv():
    global geom
    # Read geometry from first .XV file found in dir
    fns = glob.glob('*.XV')

    if len(fns) > 1:
        print "ERROR: BandStruct: More than one .XV file ... which geometry to choose???"
        sys.exit(1)
    elif len(fns) < 1:
        print "ERROR: BandStruct: Error ... No .XV file found!"
        sys.exit(1)

    print('Reading geometry from "%s" file' % fns[0])
    geom = MG.Geom(fns[0])
    geom.sym = SYM.Symmetry(fns[0], onlyLatticeSym=True)
    if geom.sym.NNbasis != geom.natoms:
        print "ERROR: Siesta cell does not contain one unit cell"
        sys.exit(1)
Example #10
0
def RunTBT(TSrun,
           Emin,
           Emax,
           NPoints,
           NumKxy_A1=1,
           NumKxy_A2=1,
           AtomsPerLayer=0,
           DeviceLayerInclLeft=0,
           DeviceLayerInclRight=0,
           PBStemplate=None,
           PBSsubs=None,
           submitJob=False):
    """
    PBStemplate          : Path+foldername to a template RUN.pbs file for PBS queueing
    PBSsubs              : A list of string substitutions to be applied to the template
                              PBS script in order to generate a new PBS script
                              (e.g., PBSsubs=[['JOBNAME','newjobname'],...] will replace
                              any JOBNAME string with newjobname)
    submitJob            : (True/False) Submit to batch queue via qsub command?
    """
    # Remove old Green's functions
    for elm in glob.glob(TSrun + '/*GF'):
        print('SetupRuns.RunTBT: Removing *.GF')
        if os.path.isfile(elm):
            print('   Deleting %s' % elm)
            os.remove(elm)
    # Determine Device PDOS?
    if AtomsPerLayer > 0:
        for elm in glob.glob(TSrun + '/*XV'):
            if os.path.isfile(elm):
                geom = MG.Geom(elm)
                geom.findContactsAndDevice(AtomsPerLayer)
                PDOSfirst = min(
                    geom.deviceList) - DeviceLayerInclLeft * AtomsPerLayer
                PDOSlast = max(
                    geom.deviceList) + DeviceLayerInclRight * AtomsPerLayer
    else:
        PDOSfirst, PDOSlast = 0, 0
    # Prepend lines to TBTRANS.fdf
    tbtfile = TSrun + '/TBTRANS.fdf'
    f = open(tbtfile, 'r')
    lines = f.readlines()
    f.close()
    f = open(tbtfile, 'w')
    f.write('### Lines appended %s \n' % time.ctime())
    if PDOSfirst > 0 and PDOSlast > 0:
        print('SetupRuns.RunTBT: Prepending PDOS = [%i,%i] to %s' \
            %(PDOSfirst, PDOSlast, tbtfile))
        f.write('TS.TBT.PDOSFrom   %i\n' % PDOSfirst)
        f.write('TS.TBT.PDOSTo     %i\n' % PDOSlast)
    print('SetupRuns.RunTBT: Writing Emin=%f, Emax=%f, NPoints=%i to %s' \
        %(Emin, Emax, NPoints, tbtfile))
    f.write('TS.TBT.Emin       %f  eV\n' % Emin)
    f.write('TS.TBT.Emax       %f  eV\n' % Emax)
    f.write('TS.TBT.NPoints    %i\n' % NPoints)
    f.write('TS.NumKxy_A1      %i\n' % NumKxy_A1)
    f.write('TS.NumKxy_A2      %i\n' % NumKxy_A2)
    f.write('pyTBT.K_A1        %i\n' % NumKxy_A1)
    f.write('pyTBT.K_A2        %i\n\n' % NumKxy_A2)
    for line in lines:
        f.write(line)
    f.close()
    # PBS files
    MakePBS(PBStemplate,
            newTSrun + '/RUN.pyTBT.pbs',
            PBSsubs,
            submitJob,
            rtype='PY')
Example #11
0
def SetupCGrun(templateCGrun,
               newCGrun,
               NewContactSeparation,
               AtomsPerLayer,
               IndexShift=0,
               ListL=None,
               ListR=None,
               ZmatRanges=None,
               RotationAngle=None,
               RotationCenter=None,
               RotationAxis=None,
               RotationSubset=None,
               overwrite=False,
               PBStemplate=None,
               PBSsubs=None,
               submitJob=False):
    """
    templateCGrun        : Path+foldername to a template CGrun folder which contain
                              the necessary SIESTA files and a structure which is to
                              be modified for a new electrode separation
                              (this function writes a new STRUCT.fdf file)
    newCGrun             : Path+foldername for the CGrun to be created
    NewContactSeparation : The new electrode separation in Ang (defined as the z-distance
                              over the device between two electrode layers which has not
                              been relaxed)
    AtomsPerLayer        : Number of atoms in one electrode layer in a cross-section wrt.
                              the transport direction
    IndexShift           : Number of atoms which is periodically translated from left to
                              right during the formation of the new STRUCT.fdf from the
                              template *.XV file
    ListL/ListR          : These atom indices (SIESTA numbering) are forced to be a part of
                              the electrodes and hence not affected by stretching
    RotationAngle/       : Rotate whole CG geometry (or only RotationSubset if specified)
    RotationCenter/           an angle RotationAngle (in degrees) around RotationAxis vector through
    RotationAxis/             atom index RotationCenter (SIESTA numbering). These manipulations
    RotationSubset            are implemented BEFORE electrode separation is adjusted.
    overwrite            : (True/False) Specifies if one is allowed to write in existing
                              directories
    PBStemplate          : Path+foldername to a template RUN.pbs file for PBS queueing
    PBSsubs              : A list of string substitutions to be applied to the template
                              PBS script in order to generate a new PBS script
                              (e.g., PBSsubs=[['JOBNAME','newjobname'],...]' will replace
                              any JOBNAME string with newjobname)
    submitJob            : (True/False) Submit to batch queue via qsub command?
    """

    # Make new directories
    head = os.path.split(newCGrun)[0]
    if not os.path.isdir(head):
        print('\nSetupRuns.SetupCGrun: Creating folder %s' % head)
        os.mkdir(head)
    if not os.path.isdir(newCGrun):
        print('\nSetupRuns.SetupCGrun: Creating folder %s' % newCGrun)
        os.mkdir(newCGrun)
    elif not overwrite:
        print('\nSetupRuns.SetupCGrun: %s already exists. No further actions taken.'\
              %newCGrun)
        return ''  # Quit script
    else:
        print('\nSetupRuns.SetupCGrun: %s already exists. OVERWRITING FILES!!!'\
              %newCGrun)
    # Copy template files
    CopyInputFiles(templateCGrun, newCGrun,
                   ['.fdf', '.vps', '.psf', '.pbs', '.slurm', '.TSHS'])
    # Read relaxed geometry
    XVfiles = glob.glob(templateCGrun + '/*.XV*')
    if len(XVfiles) == 1:
        geom = MG.Geom(XVfiles[0])
    elif len(XVfiles) > 1:
        print('More than one XV file was found in folder %s:' % templateCGrun)
        for i, xvfile in enumerate(XVfiles):
            print('   No. %i :' % i, xvfile)
        select = input('   ... select file:')
        geom = MG.Geom(XVfiles[int(select)])
    else:
        print('No XV file was found in folder %s:' % templateCGrun)
        input('   ... Continue reading geometry from RUN.fdf?')
        geom = MG.Geom(templateCGrun + '/RUN.fdf')
    # Rotate via indexshift?
    if IndexShift > 0:
        print('SetupRuns.SetupCGrun: Applying IndexShift =', IndexShift)
        for ii in range(IndexShift):
            geom.xyz[0][2] += geom.pbc[2][2]
            geom.addAtom(geom.xyz[0], geom.snr[0], geom.anr[0])
            geom.rmAtom(0)
    # Rotation?
    if RotationAngle and RotationCenter and RotationAxis:
        print('SetupRuns.SetupCGrun: Rotation applied:')
        print('   ... Rotation angle  =', RotationAngle, ' deg')
        print('   ... Rotation center = atom %i (SIESTA numbering)' %
              RotationCenter)
        print('   ... Rotation axis   =', RotationAxis)
        if RotationSubset:
            print('   ... RotationSubset  =', RotationSubset,
                  ' (SIESTA numbering)')
            # Change from SIESTA numbering to Python indices
            RotationSubset = [x - 1 for x in RotationSubset]
        center = N.array(geom.xyz[RotationCenter - 1])
        geom.rotate(RotationAxis,
                    RotationAngle,
                    center,
                    RotateSubset=RotationSubset)
    # Adjust electrode separation
    if NewContactSeparation:
        geom.stretch2NewContactSeparation(NewContactSeparation,
                                          AtomsPerLayer,
                                          ListL=ListL,
                                          ListR=ListR)
    if not ZmatRanges:
        geom.writeFDF(newCGrun + '/STRUCT.fdf')
    else:
        geom.writeFDFZmat(newCGrun + '/STRUCT.fdf', ZmatRanges)
    geom.writeXYZ(newCGrun + '/STRUCT.xyz')
    geom.writeXYZ(newCGrun + '/STRUCT2.xyz', rep=[2, 2, 2])
    # PBS files
    MakePBS(PBStemplate, newCGrun + '/RUN.pbs', PBSsubs, submitJob, rtype='TS')
Example #12
0
def SetupFCrun(CGrun,
               newFCrun,
               FCfirst,
               FClast,
               displacement=0.02,
               overwrite=False,
               PBStemplate=None,
               PBSsubs=None,
               submitJob=False,
               main_fdf="RUN.fdf"):
    """
    CGrun                : Path+foldername to a relaxed structure CGrun folder on
                              which to perform a FCrun calculation. This folder must
                              contain an *.XV file
    newFCrun             : Path+foldername for the FCrun to be created
    FCfirst              : Number of the first atom to displace (SIESTA numbering)
    FClast               : Number of the last atom to displace (SIESTA numbering)
    displacement         : Displacement
    overwrite            : (True/False) Specifies if one is allowed to write in existing
                              directories
    PBStemplate          : Path+foldername to a template RUN.pbs file for PBS queueing
    PBSsubs              : A list of string substitutions to be applied to the template
                              PBS script in order to generate a new PBS script
                              (e.g., PBSsubs=[['JOBNAME','newjobname'],...]' will replace
                              any JOBNAME string with newjobname)
    submitJob            : (True/False) Submit to batch queue via qsub command?
    """
    # Make new directory
    if not os.path.isdir(newFCrun):
        print('\nSetupRuns.SetupFCrun: Creating folder %s' % newFCrun)
        os.mkdir(newFCrun)
    elif not overwrite:
        print('\nSetupRuns.SetupFCrun: %s already exists. No further actions taken.'\
              %newFCrun)
        return ''  # Quit script
    else:
        print('\nSetupRuns.SetupFCrun: %s already exists. OVERWRITING FILES!!!'\
              %newFCrun)
    # Copy template files
    CopyInputFiles(CGrun, newFCrun, [
        '.fdf', '.vps', '.psf', '.DM', '.XV', '.pbs', '.slurm', '.TSDE',
        '.TSHS'
    ])
    # Read relaxed geometry and overwrite STRUCT files
    XVfiles = glob.glob(CGrun + '/*.XV*')
    if len(XVfiles) == 1:
        geom = MG.Geom(XVfiles[0])
    elif len(XVfiles) > 1:
        print('More than one XV file was found in folder %s:' % CGrun)
        for i, xvfile in enumerate(XVfiles):
            print('   No. %i :' % i, xvfile)
        select = input('   ... select file:')
        geom = MG.Geom(XVfiles[int(select)])
    else:
        print('No XV file was found in folder %s:' % CGrun)
        input('   ... Continue reading geometry from RUN.fdf?')
        geom = MG.Geom(CGrun + '/RUN.fdf')
    geom.writeFDF(newFCrun + '/STRUCT.fdf')
    geom.writeXYZ(newFCrun + '/STRUCT.xyz')
    geom.writeXYZ(newFCrun + '/STRUCT2.xyz', rep=[2, 2, 2])
    if os.path.isfile(CGrun + "/STRUCT.fdf"):
        copy_chemical_info(CGrun + "/STRUCT.fdf", newFCrun + "/STRUCT.fdf")

    # Prepend lines to RUN.fdf
    elm = newFCrun + '/' + main_fdf
    if os.path.isfile(elm):
        print('SetupRuns.SetupFCrun: Modifying %s' % elm)
        f = open(elm, 'r')
        lines = f.readlines()
        f.close()
        f = open(elm, 'w')
        f.write('### Lines appended %s \n' % time.ctime())
        f.write('MD.TypeOfRun  FC\n')
        f.write('MD.FCfirst   %i\n' % FCfirst)
        f.write('MD.FClast    %i\n' % FClast)
        f.write('TS.HS.Save True\n')
        f.write('TS.SaveHS    True\n')
        f.write('MD.FCDispl   %.8f Ang\n' % displacement)
        f.write('%include STRUCT.fdf\n')
        f.writelines(lines)
        f.close()
    else:
        print("{} was not found, so it cannot be edited."
              "Rerun with main_fdf set correctly.".format(elm))
    # PBS files
    MakePBS(PBStemplate, newFCrun + '/RUN.pbs', PBSsubs, submitJob, rtype='TS')
Example #13
0
    def __init__(self, runfdf):
        self.fdf = runfdf
        self.directory, self.tail = os.path.split(runfdf)
        self.systemlabel = SIO.GetFDFlineWithDefault(runfdf, 'SystemLabel',
                                                     str, 'siesta', 'Phonons')
        FCfirst = SIO.GetFDFlineWithDefault(runfdf, 'MD.FCfirst', int, 0,
                                            'Phonons')
        FClast = SIO.GetFDFlineWithDefault(runfdf, 'MD.FClast', int, 0,
                                           'Phonons')
        # Finite-displacement amplitude
        ampl, unit = SIO.GetFDFline(runfdf, KeyWord='MD.FCDispl')
        if unit.upper() == 'ANG':
            self.Displ = float(ampl)
        elif unit.upper() == 'BOHR':
            self.Displ = float(ampl) * PC.Bohr2Ang
        print('Displacement = %.6f Ang' % self.Displ)
        # Read geometry
        self.geom = MG.Geom(runfdf)
        # Compare with XV file corrected for last displacement
        XV = self.directory + '/%s.XV' % self.systemlabel
        geomXV = MG.Geom(XV)
        geomXV.xyz[FClast - 1, 2] -= self.Displ
        if not N.allclose(geomXV.xyz, self.geom.xyz):
            sys.exit('Error: Geometries %s and %s should differ ONLY by displacement of atom %s in z'\
                     %(runfdf, XV, FClast))
        # Set up FC[i,a,j,b]: Force constant (eV/A^2) from moved atom i, axis a to atom j, axis b
        natoms = self.geom.natoms
        self.m = N.zeros((FClast - FCfirst + 1, 3, natoms, 3), N.float)
        self.p = N.zeros((FClast - FCfirst + 1, 3, natoms, 3), N.float)
        fc = N.array(
            SIO.ReadFCFile(self.directory + '/%s.FC' % self.systemlabel))
        for i in range(FClast - FCfirst + 1):
            for j in range(3):
                self.m[i, j] = fc[2 * (3 * i + j) *
                                  natoms:(2 * (3 * i + j) + 1) * natoms]
                self.p[i, j] = fc[(2 * (3 * i + j) + 1) *
                                  natoms:(2 * (3 * i + j) + 2) * natoms]
        # Correct force constants for the moved atom
        # Cf. Eq. (13) in Frederiksen et al. PRB 75, 205413 (2007)
        for i in range(FClast - FCfirst + 1):
            for j in range(3):
                self.m[i, j, FCfirst - 1 + i, :] = 0.0
                self.m[i, j, FCfirst - 1 + i, :] = -N.sum(self.m[i, j], axis=0)
                self.p[i, j, FCfirst - 1 + i, :] = 0.0
                self.p[i, j, FCfirst - 1 + i, :] = -N.sum(self.p[i, j], axis=0)
        self.DynamicAtoms = list(range(FCfirst, FClast + 1))

        # Determine TSHS files
        files = glob.glob(self.directory + '/%s*.TSHS' % self.systemlabel)
        files.sort()
        if self.directory + '/%s.TSHS' % self.systemlabel in files:
            # If present, ignore this file which does not origninate from the FCrun
            files.remove(self.directory + '/%s.TSHS' % self.systemlabel)
        if (FClast - FCfirst + 1) * 6 + 1 != len(files):
            warnings.warn(
                'Phonons.GetFileLists: WARNING - Inconsistent number of *.TSHS files in %s'
                % self.directory)
            return

        # Build dictionary over TSHS files and corresponding displacement amplitudes
        self.TSHS = {}
        self.TSHS[0] = files[0]  # Equilibrium TSHS
        for i, v in enumerate(self.DynamicAtoms):
            for j in range(3):
                # Shifted TSHS files (atom,axis,direction)
                self.TSHS[v, j, -1] = files[1 + 6 * i + 2 * j]
                self.TSHS[v, j, 1] = files[1 + 6 * i + 2 * j + 1]
Example #14
0
def main(options):
    """
    Main routine to compute eigenchannel scattering states

    Parameters
    ----------
    options : an ``options`` instance
    """

    Log.CreatePipeOutput(options)
    VC.OptionsCheck(options)
    Log.PrintMainHeader(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')

    Log.PrintMainFooter(options)
    return DevGF
Example #15
0
from __future__ import print_function

import glob
import os
import Inelastica.MakeGeom as MG
import numpy as N
import numpy.linalg as LA

# Find geometries
fns = glob.glob('NEB*/CGrun/RUN.fdf')

# Fix order
indx = [int(ii.split('_')[1].split('/')[0]) for ii in fns]
fns = [fns[ii] for ii in N.argsort(indx)]

geoms = [MG.Geom(ii) for ii in fns]
xyz = [N.array(ii.xyz) for ii in geoms]

# Find bond length
d = LA.norm(xyz[0][37] - xyz[0][36])

# Move in z to keep bond length
for ii in xyz:
    ii[37, 2] = ii[36, 2] + N.sqrt(d**2 - (ii[36, 0] - ii[37, 0])**2 -
                                   (ii[36, 1] - ii[37, 1])**2)

# Redistribute points

xyz, nxyz = N.array(xyz), N.array(xyz)  # Two copies

Example #16
0
def SetupTSrun(CGrun,
               templateTSrun,
               newTSrun,
               AtomsPerLayer,
               BlockSize,
               LayersLeft,
               LayersRight,
               DeviceLayerInclLeft=0,
               DeviceLayerInclRight=0,
               IndexShift=0,
               AddLeftList=[],
               AddRightList=[],
               ListL=None,
               ListR=None,
               NewContactSeparation=None,
               RotationAngle=None,
               RotationCenter=None,
               RotationAxis=None,
               RotationSubset=None,
               overwrite=False,
               PBStemplate=None,
               PBSsubs=None,
               submitJob=False):
    """

    CGrun                : Path+foldername to a relaxed structure CGrun folder on
                              which to run a TranSIESTA calculation. This folder must
                              contain an *.XV file
    templateTSrun        : Path+foldername to an existing TSrun folder which contains
                              all relevant electrode calculations and *.fdf files
                              except for STRUCT.fdf
    newTSrun             : Path+foldername for the TSrun folder to be created
    AtomsPerLayer        : Number of atoms in the electrodes in a cross section along
                              the transport direction
    BlockSize            : Number of atoms in the electrode block from CGrun/*.XV file
    LayersLeft/Right     : Number of blocks to be pasted to the new enlarged STRUCT.fdf.
    DeviceLayerInclLeft  : As default TBTRANS takes all relaxed atoms to be the device
                              If DeviceLayerInclLeft is larger than 0 then TBTRANS
                              includes the specified number of electode atomic planes into
                              the device region.
    DeviceLayerInclRight : See DeviceLayerInclLeft
    IndexShift           : Number of atoms which is periodically translated from left to
                              right contact BEFORE eventual electrode layers are pasted.
    AddLeftList          : Add list of atoms to the left side
    AddRightList         : Add list of atoms to the right side
    ListL/ListR          : These atom indices (SIESTA numbering) are forced to be a part of
                              the electrodes and hence not affected by stretching
    NewContactSeparation : (Optional) value to set a different electrode separation
                              than in the CG geometry
    RotationAngle/       : Rotate whole CG geometry (or only RotationSubset if specified)
    RotationCenter/           an angle RotationAngle (in degrees) around RotationAxis vector through
    RotationAxis/             atom index RotationCenter (SIESTA numbering). These manipulations
    RotationSubset            are implemented BEFORE electrode separation is adjusted.
    overwrite            : (True/False) Specifies if one is allowed to write in existing
                              directories
    PBStemplate          : Path+foldername to a template RUN.pbs file for PBS queueing
    PBSsubs              : A list of string substitutions to be applied to the template
                              PBS script in order to generate a new PBS script
                              (e.g., PBSsubs=[['JOBNAME','newjobname'],...]' will replace
                              any JOBNAME string with newjobname)
    submitJob            : (True/False) Submit to batch queue via qsub command?
    """
    # Make new directory
    if not os.path.isdir(newTSrun):
        print('\nSetupRuns.SetupTSrun: Creating folder %s' % newTSrun)
        os.mkdir(newTSrun)
    elif not overwrite:
        print('\nSetupRuns.SetupTSrun: %s already exists. No further actions taken.'\
              %newTSrun)
        return ''  # Quit script
    else:
        print('\nSetupRuns.SetupTSrun: %s already exists. OVERWRITING FILES!!!'\
              %newTSrun)
    # Copy all sub-directories
    for elm in glob.glob(templateTSrun + '/*'):
        tail = os.path.split(elm)[1]
        if os.path.isdir(elm):
            CopyTree(elm, newTSrun + '/' + tail, overwrite=overwrite)
    # Copy template files
    CopyInputFiles(templateTSrun, newTSrun,
                   ['.fdf', '.vps', '.psf', '.pbs', '.slurm'])
    # Read relaxed geometry
    XVfiles = glob.glob(CGrun + '/*.XV*')
    if len(XVfiles) == 1:
        geom = MG.Geom(XVfiles[0])
    elif len(XVfiles) > 1:
        print('More than one XV file was found in folder %s:' % CGrun)
        for i, xvfile in enumerate(XVfiles):
            print('   No. %i :' % i, xvfile)
        select = input('   ... select file:')
        geom = MG.Geom(XVfiles[int(select)])
    else:
        print('No XV file was found in folder %s:' % CGrun)
        input('   ... Continue reading geometry from RUN.fdf?')
        geom = MG.Geom(CGrun + '/RUN.fdf')
    # Rotate via indexshift?
    if IndexShift > 0:
        print('SetupRuns.SetupTSrun: Applying IndexShift =', IndexShift)
        for ii in range(IndexShift):
            geom.xyz[0][2] += geom.pbc[2][2]
            geom.addAtom(geom.xyz[0], geom.snr[0], geom.anr[0])
            geom.rmAtom(0)
    # Overwrite STRUCT files
    if RotationAngle and RotationCenter and RotationAxis:
        print('SetupRuns.SetupTSrun: Rotation applied:')
        print('   ... Rotation angle  =', RotationAngle, ' deg')
        print('   ... Rotation center = atom %i (SIESTA numbering)' %
              RotationCenter)
        print('   ... Rotation axis   =', RotationAxis)
        if RotationSubset:
            print('   ... RotationSubset  =', RotationSubset,
                  ' (SIESTA numbering)')
            # Change from SIESTA numbering to Python indices
            RotationSubset = [x - 1 for x in RotationSubset]
        center = N.array(geom.xyz[RotationCenter - 1])
        geom.rotate(RotationAxis,
                    RotationAngle,
                    center,
                    RotateSubset=RotationSubset)
    # Paste electrode layers via BlockSize specifications
    geom.PasteElectrodeLayers(BlockSize, AtomsPerLayer, LayersLeft,
                              LayersRight)
    # Change contact separation?
    if NewContactSeparation:
        geom.stretch2NewContactSeparation(NewContactSeparation,
                                          AtomsPerLayer,
                                          ListL=ListL,
                                          ListR=ListR)
    # Add electrode atoms to the left
    if len(AddLeftList) > 0:
        dz = AddLeftList[AtomsPerLayer, 2] - AddLeftList[0, 2]
        tmp = N.array(geom.xyz)
        minz = min(tmp[:, 2])
        maxz = max(AddLeftList[:, 2])
        for ii in reversed(list(range(len(AddLeftList)))):
            tmp = list(AddLeftList[ii, :] +
                       (-maxz + minz - dz) * N.array([0.0, 0.0, 1.0], N.float))
            geom.prependAtom(tmp, geom.snr[0], geom.anr[0])
        geom.pbc[2][2] += len(AddLeftList) / AtomsPerLayer * dz
    # Add electrode atoms to the right
    if len(AddRightList) > 0:
        dz = AddRightList[AtomsPerLayer, 2] - AddRightList[0, 2]
        tmp = N.array(geom.xyz)
        maxz = tmp[0, 2] - dz + geom.pbc[2][2]
        minz = min(AddRightList[:, 2])
        for ii in range(len(AddRightList)):
            geom.addAtom(
                list(AddRightList[ii, :] +
                     (maxz - minz + dz) * N.array([0, 0, 1], N.float)),
                geom.snr[0], geom.anr[0])
        geom.pbc[2][2] += len(AddRightList) / AtomsPerLayer * dz
    # Write structure to files
    geom.writeFDF(newTSrun + '/STRUCT.fdf')
    geom.writeXYZ(newTSrun + '/STRUCT.xyz')
    geom.writeXYZ(newTSrun + '/STRUCT2.xyz', rep=[2, 2, 2])
    # Find device atoms
    geom.findContactsAndDevice(AtomsPerLayer)
    PDOSfirst = min(geom.deviceList) - DeviceLayerInclLeft * AtomsPerLayer
    PDOSlast = max(geom.deviceList) + DeviceLayerInclRight * AtomsPerLayer
    # Prepend lines to TBTRANS.fdf
    for elm in glob.glob(newTSrun + '/TBTRANS.fdf'):
        if os.path.isfile(elm):
            print('SetupRuns.SetupTSrun: Prepending PDOS = [%i,%i] to %s' \
                  %(PDOSfirst, PDOSlast, elm))
            f = open(elm, 'r')
            lines = f.readlines()
            f.close()
            f = open(elm, 'w')
            f.write('### Lines appended %s \n' % time.ctime())
            f.write('TS.TBT.PDOSFrom   %i\n' % PDOSfirst)
            f.write('TS.TBT.PDOSTo     %i\n\n' % PDOSlast)
            for line in lines:
                f.write(line)
            f.close()
    # PBS files
    MakePBS(PBStemplate, newTSrun + '/RUN.pbs', PBSsubs, submitJob, rtype='TS')
Example #17
0
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
Example #18
0
def calcTSWF(options, ikpoint):
    kpoint = options.kpoints.k[ikpoint]
    def calcandwrite(A, txt, kpoint, ikpoint):
        if isinstance(A, MM.SpectralMatrix):
            A=A.full()
        A=A*PC.Rydberg2eV # Change to 1/Ryd
        ev, U = LA.eigh(A)
        Utilde = N.empty(U.shape, U.dtype)
        for jj, val in enumerate(ev): # Problems with negative numbers
            if val<0: val=0
            Utilde[:, jj]=N.sqrt(val/(2*N.pi))*U[:, jj]
        indx2 = N.where(abs(abs(ev)>1e-4))[0] # Pick non-zero states

        ev=ev[indx2]
        Utilde=Utilde[:, indx2]
        indx=ev.real.argsort()[::-1]
        fn=options.DestDir+'/%i/'%(ikpoint)+options.systemlabel+'.%s'%(txt)

        path = './'+options.DestDir+'/'
        #FermiEnergy = SIO.HS(options.systemlabel+'.TSHS').ef

        def noWfs(side):
            tmp = len(glob.glob(path+str(ikpoint)+'/'+options.systemlabel+'.A'+side+'*'))
            return tmp
        if noWfs('L')==0 or noWfs('R')==0 and len(glob.glob(path+str(ikpoint)+'/FD*'))==0:
            print('Calculating localized-basis states from spectral function %s ...'%(txt))
            tlb = time.clock()
            calcWF2(options, geom, options.DeviceAtoms, basis, Utilde[:, indx], [N1, N2, N3, minN3, maxN3], Fold=True, k=kpoint, fn=fn)
            times = N.round(time.clock()-tlb, 2); timem = N.round(times/60, 2)
            print('Finished in '+str(times)+' s = '+str(timem)+' min')

        if noWfs('L')>0 and noWfs('R')>0 and len(glob.glob(path+str(ikpoint)+'/FD*'))==0 and str('%s'%(txt))==str('AR'):
            print('\nLocalized-basis states are calculated in k point '+str(ikpoint)+'/.')
            print('------------------------------------------------------')
            print('Finite-difference calculation of vacuum states starts!')
            timeFD = time.clock()
            STMFD.main(options, kpoint, ikpoint)
            print('FD calculation in k-point folder '+str(ikpoint)+'/ done in '+str(N.round((time.clock()-timeFD)/60, 2))+' min.')
            print('------------------------------------------------------')
            if options.savelocwfs == False:
                os.system('rm -f '+path+str(ikpoint)+'/'+options.systemlabel+'*')

    #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, 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

    file = NC.Dataset('TotalPotential.grid.nc', 'r')
    N1, N2, N3 = len(file.dimensions['n1']), len(file.dimensions['n2']), len(file.dimensions['n3'])
    cell = file.variables['cell'][:]
    file.close()

    #Find device region in a3 axis
    U = LA.inv(N.array([cell[0]/N1, cell[1]/N2, cell[2]/N3]).transpose())
    gridindx = N.dot(geom.xyz[options.DeviceAtoms[0]-1:options.DeviceAtoms[1]]/PC.Bohr2Ang, U)
    minN3, maxN3 = N.floor(N.min(gridindx[:, 2])).astype(N.int), N.ceil(N.max(gridindx[:, 2])).astype(N.int)
    if not N.allclose(geom.pbc, cell*PC.Bohr2Ang):
        print('Error: TotalPotential.grid.nc has different cell compared to geometry')
        sys.exit(1)

    print('\nk-point folder '+str(ikpoint)+'/')
    print('Checking/calculating localized-basis states ...')
    calcandwrite(DevGF.AL, 'AL', kpoint, ikpoint)
    calcandwrite(DevGF.AR, 'AR', kpoint, ikpoint)