In [ ]:
from __future__ import print_function
import sisl
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
First TranSiesta bias example.
In this example we will take the system from TS 1 and perform bias calculations on it. Note, however, that applying a bias to a pristine bulk system is non-physical and should thus NEVER be done. TranSiesta will not warn you about this and will happily calculate the non-equilibrium density for any bulk system with an applied bias. This is an extremely important point and once complete with this example you should carefully think through why this is the case.
Bias calculations are very heavy because of a full DFT+NEGF calculation per bias-point.
We will begin with creating the structures.
In [ ]:
graphene = sisl.geom.graphene(1.44, orthogonal=True)
In [ ]:
elec = graphene.tile(2, axis=0)
elec.write('STRUCT_ELEC.fdf')
device = elec.tile(3, axis=0)
device.write('STRUCT_DEVICE.fdf')
In this exercise you will be familiarized with the input options that define a bias calculation. The input options are extremely elaborate, yet they require little intervention when using default parameters.
As this is your first example of running TranSiesta with applied bias there are a few things you should know:
dQ
(see TS 1).TS_<V>
.Any bias calculation should be a restart by using the closests bias calculations TranSiesta density matrix. This can be ensured by copying the siesta.TSDE
file from the closests bias calculation to the current simulation directory. I.e.
TS_0
, ensure convergence etc.TS_0.25
, copy TS_0/siesta.TSDE
to TS_0.25/
and start run.TS_0.5
, copy TS_0.25/siesta.TSDE
to TS_0.5/
and start run.TS_-0.25
, copy TS_0/siesta.TSDE
to TS_-0.25/
and start run (note negative bias' can be performed in parallel to positive bias)All the commands required for this example can be executed like this:
siesta --electrode RUN_ELEC.fdf > ELEC.out
cd TS_0
cp ../C.psf .
siesta ../RUN.fdf > TS.out
# Check that the charge is converged etc.
cp siesta.TSDE ../TS_0.5/
cd ../TS_0.5
cp ../C.psf .
siesta -V 0.5:eV ../RUN.fdf > TS.out
# Check that it has converged...
cp siesta.TSDE ../TS_1.0/
cd ../TS_1.0
cp ../C.psf .
siesta -V 1:eV ../RUN.fdf > TS.out
# Check that it has converged...
After every calculation go through the output to ensure everything is well behaved. Note that the output of a bias calculation is different from a non-bias calculation, they are more detailed.
v0 = sisl.Grid.read('TS_0/ElectrostaticPotential.grid.nc')
vd = (sisl.Grid.read('TS_0.5/ElectrostaticPotential.grid.nc') - v0)
vd
then contains the potential profile (in eV). To save it as a linear average bias file (remember transport is along first lattice vector) you can execute the following:
vd = vd.average(1).average(2)
dv = (vd.dcell[0, :] ** 2).sum() ** .5
sisl.io.tableSile('potential_0.5.dat', 'w').write_data(dv * np.arange(vd.shape[0]), vd.grid[:, 0, 0])
This completes all non-equilibrium calculations for this example. However, we have only calculated the non-equilibrium density and thus, the non-equilibrium Hamiltonian. We still need to calculate the transport properties for all bias'. Basically we can only calculate the transport properties at the calculated bias values, but generally we are interested in a full $I(V)$ curve.
As a user, one has three options:
The first option is by far the fastests and easiest with a sometimes poor accuracy; the second option is relatively fast, and drastically improves the accuracy; while the last option is the most accurate but may sometimes be non-feasible due to insufficient computational resources.
In the following we will calculate all transmissions using option 2. Look in the manual for the options regarding the interpolation (there are two interpolation methods).
Go through RUN.fdf
and find the respective block that tells TBtrans to interpolate the Hamiltonian, also notice how the energy-grid is defined in TBtrans. You will notice that this is the fastest way to calculate the $I(V)$ curve for any bias, it however, will not calculate any physical quantities outside the bias window.
Now complete the exercise by running TBtrans for $V\in\{0, 0.1, \dots, 1\}$ eV. Note that instead of changing the applied bias in the fdf-file, one can do:
tbtrans -V 0.4:eV RUN.fdf
to apply $V=0.4\,\mathrm{eV}$, any fdf-flag specified on the command line has precedence! The :
is to denote an effective space, otherwise you will have to encapsulate in quotation marks tbtrans -V "0.4 eV" RUN.fdf
.
If you do not want to run the commands manually, you may use this loop command:
for V in $(seq 0 0.1 1) ; do
d=TBT_${V//,/.}
mkdir $d
cd $d
tbtrans -V "${V//,/.}:eV" ../RUN.fdf > TBT.out
cd ../
done
TIME: A remark on this exercise. Think why applying a bias to a bulk system is wrong. If you can't immediately figure this out, try and create a longer system by replacing device = elec.tile(3, axis=0)
with, say: device = elec.tile(6, axis=0)
and redo the calculation for a given bias. Then compare the potential profiles.
In [ ]:
V = np.arange(0, 1.05, 0.1)
I = np.empty([len(V)])
for i, v in enumerate(V):
I[i] = sisl.get_sile('TBT_{:.1f}/siesta.TBT.nc'.format(v)).current()
plt.plot(V, I * 1e6);
plt.xlabel('Bias [V]'); plt.ylabel(r'Current [$\mu\mathrm{A}$]');
Why is the current $0$ for $V<0.8$?
Hint: see TB 1.
In [ ]: