示例#1
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'])
    # 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 = raw_input('   ... select file:')
        geom = MG.Geom(XVfiles[int(select)])
    else:
        print 'No XV file was found in folder %s:' % templateCGrun
        raw_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')
示例#2
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'])
    # 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 = raw_input('   ... select file:')
        geom = MG.Geom(XVfiles[int(select)])
    else:
        print 'No XV file was found in folder %s:' % CGrun
        raw_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(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')
示例#3
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)
示例#4
0
def SetupFCrun(CGrun,
               newFCrun,
               FCfirst,
               FClast,
               displacement=0.02,
               overwrite=False,
               PBStemplate=None,
               PBSsubs=None,
               submitJob=False):
    """
    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', '.TSDE'])
    # 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 = raw_input('   ... select file:')
        geom = MG.Geom(XVfiles[int(select)])
    else:
        print 'No XV file was found in folder %s:' % CGrun
        raw_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])
    # Prepend lines to RUN.fdf
    for elm in glob.glob(newFCrun + '/RUN.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)
            for line in lines:
                f.write(line)
            f.close()
    # PBS files
    MakePBS(PBStemplate, newFCrun + '/RUN.pbs', PBSsubs, submitJob, rtype='TS')
示例#5
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)