In [ ]:
from __future__ import print_function
import sisl
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
This example will setup the required electronic structures for usage in TBtrans.
You will also learn the importance of perform $k$-point convergence tests for systems using TBtrans.
We will continue with the graphene nearest neighbour tight-binding model and perform simple transport calculations using TBtrans.
Our example will again concentrate on graphene:
In [ ]:
graphene = sisl.geom.graphene(orthogonal=True)
H = sisl.Hamiltonian(graphene)
H.construct([[0.1, 1.43], [0., -2.7]])
Note that the above call of the graphene lattice is different from TB 1. In this example we will create an orthogonal graphene lattice, i.e. the lattice vectors are orthogonal to each other, unlike the minimal graphene lattice.
The minimal orthogonal graphene lattice consists of 4 Carbon atoms.
Assert that we have 16 non zero elements:
In [ ]:
print(H)
The Hamiltonian we have thus far created will be our electrode. Lets write it to a TBtrans readable file:
In [ ]:
H.write('ELEC.nc')
Now a file ELEC.nc
file exists in the folder and it contains all the information (and more) that TBtrans requires to construct the self-energies for the electrode.
All that is required is now the device region.
An important aspect of any transport setup is that the electrodes must not have matrix elements crossing the device region. I.e. there must not be matrix elements between any of the electrodes. This restriction is easily accommodated in tight-binding setups, but for DFT systems it is less transparent.
In this tight-binding setup it simlpy means a repetition of the electrode 3 times; 1) left electrode, 2) scattering region, 3) right electrode.
Here we tile the orthogonal graphene lattice 3 times along the second lattice vector (Python is 0-based) and subsequently construct it using the same parameters.
This method of specifying all matrix elements is the most usable and easy scheme that is available in sisl
.
In [ ]:
device = graphene.tile(3, axis=1)
H_device = sisl.Hamiltonian(device)
H_device.construct([[0.1, 1.43], [0, -2.7]])
print(H_device)
The Geometry.tile
function is an explicit method to create bigger lattices from a smaller reference latice. Howewer, the tile
routine is also available to the Hamiltonian
object. Not only is it much easier to use, it also presents these advantages:
Hamiltonian
, i.e. you need not specify the parameters to construct
twice,
In [ ]:
H_device = H.tile(3, axis=1)
print(H_device)
For more information you may execute the following lines to view the :
help(Geometry.tile)
help(Hamiltonian.tile)
Now we have created the device electronic structure. The final step is to store it in a TBtrans readable format:
In [ ]:
H_device.write('DEVICE.nc')
Sometimes it may be convenient to plot the entries of the matrix to assert the symmetry and structure. The second line asserts that it is indeed a Hermitian matrix:
In [ ]:
plt.spy(H_device.Hk());
print('Hermitian deviation: ',np.amax(np.abs(H.Hk() - H.Hk().T.conj())))
You should first run tbtrans
like this (the RUN.fdf
file is already prepared with enough input options for a successfull run):
tbtrans RUN.fdf
After TBtrans is complete a number of files will be present:
siesta.TBT.nc
The main data-file of TBtrans, this contains all calculated quantities, and everything that can be orbital resolved is orbital resolved, such as density of states.
siesta.TBT.CC
The energy points at which TBtrans has calculated physical quantities.
siesta.TBT.KP
Used $k$-points and their corresponding weights for integrating the Brillouin zone.
siesta.TBT.TRANS_Left-Right
The $k$-resolved transmission from Left
to the Right
electrode. This is a consecutive list of transmissions for all energy points. Each $k$-point transmission is separated with a description of the $k$-point and its weight.
siesta.TBT.AVTRANS_Left-Right
The $k$-averaged transmission from Left
to the Right
electrode. This is the $k$-averaged equivalent of siesta.TBT.TRANS_Left-Right
.
In [ ]:
tbt = sisl.get_sile('siesta.TBT.nc')
After calculating the transport properties of the transport problem you may also use sisl
to interact with the TBtrans output (in the *.TBT.nc
file):
In [ ]:
plt.plot(tbt.E, tbt.transmission(), label='k-averaged');
plt.plot(tbt.E, tbt.transmission(kavg=tbt.kindex([0, 0, 0])), label=r'$\Gamma$');
plt.xlabel('Energy [eV]'); plt.ylabel('Transmission'); plt.ylim([0, None]); plt.legend();
There are several function calls present in the above code:
get_sile
sisl
function to read and parse any file that is enabled through sisl
. You can check the documentation to find the available files. Here we use it to make tbt
be an object with all the information that is present in the siesta.TBT.nc
file.tbt.transmission
tbt.transmission
True
, or not specified, it returns the k averaged transmission, else one may provide an array of integers that represent the internal k-points. I.e. the code above searches for the k-index of the $\Gamma$ point, and requests only that sampled transmission function.You will see a very crude step-like transmission function.
The siesta.TBT.nc
file also contains two different density-of-states quantities. How do they differ?
In [ ]:
plt.plot(tbt.E, tbt.DOS(), label='DOS');
plt.plot(tbt.E, tbt.ADOS(), label='ADOS');
plt.xlabel('Energy [eV]'); plt.ylabel('DOS [1/eV]'); plt.ylim([0, None]); plt.legend();
sisl
is capable of interacting much more with TBtrans output in various ways. We will return to this in later examples.
In [4]
and change H.write('ELEC.nc')
to H.write('ELEC.TSHS')
, then adapt RUN.fdf
file to let the left electrode read the electronic structure from the TSHS
file instead. Redo the calculation and check if the output is the same.tile
or repeat
to expand to the big system. If you try to run transport on this device it will take forever, and may even crash. To handle such big systems you may use the fdf-flag TBT.Atoms.Device
to limit the calculation region (advice is to not do the calculation).