Table of Contents
This tutorial analyzes the Li-H2-Li two-probe system introduced in tutorial Li-H2-Li two-probe system using additional analysis functions implemented in NanoLanguage. By doing this we will be able to explain some of the intricate features of our two-probe system. We will discuss calculating:
A voltage drop and perform a potential analysis.
Projected eigenstates.
Local density of states.
To perform the steps in this tutorial, you must have completed the previous tutorial Li-H2-Li two-probe system, as we will use the converged self-consistent calculations for both zero and finite bias produced there, as well as the VNLFile containing the atomic configuration of the Li-H2-Li two-probe system. We will also use Virtual NanoLab (VNL) to visualize our results, but all calculation are performed solely using ATK.
The function calculateProjectedHamiltonianEnergySpectrum() calculates the energy spectrum of the molecular projected self-consistent Hamiltonian (MPSH). By this, we mean that the self-consistent Hamiltonian is projected onto specified atoms in the central region, and then diagonalized to produce an energy spectrum. This can be used to show how the molecular levels for a molecule (e.g. hydrogen) are affected when placed between between the two electrodes.
The code sample below shows how the energy spectrum, projected onto the hydrogen atoms, is calculated. We export the calculated spectrum to a VNLFile, which can be imported and visualized in VNL.
from ATK.TwoProbe import * # Restore calculation scf = restoreSelfConsistentCalculation('lih2li-scf.nc') # Calculate energy spectrum for the two H atoms mpsh_spectrum = calculateProjectedHamiltonianEnergySpectrum( scf, projection_atoms = [3,4] ) # Store energy spectrum in a VNL file vnl_file = VNLFile("lih2li-mpsh.vnl") vnl_file.addToSample(mpsh_spectrum,'lih2li-mpsh')
The projection_atoms specify which atoms we want to calculate the
eigenstates for. The numbers refer to the order of the elements in the central
region, as they were specified in the TwoProbeConfiguration used in the self-consistent field calculation. In the above
script, we have specified atom 3 and 4
corresponding to the two hydrogen atoms.
If you cannot remember or do not know which atoms that are in the central region, the following script will display all elements in the central region along with their Cartesian coordinates.
def displayCentralRegionAtoms(atomic_configuration): ''' This function will print information about the atoms located in the central region of a two-probe system. This information involves: * Internal order (number) * Element type * Cartesian coordinates of the atom ''' print 'Central region atomic configuration:' print '='*50 print 'Number\tElement\tCartesian coordinates (Ang)' for i in range(len(atomic_configuration.elements())): print i,'\t',atomic_configuration.elements()[i].symbol(),'\t', for x in atomic_configuration.cartesianCoordinates()[i]: print x.inUnitsOf(Angstrom),'\t', print print '='*50
You can use this function in the following way:
from ATK.TwoProbe import * from displayCentralRegion import displayCentralRegionAtoms vnl_file=VNLFile("lih2li.vnl") atomic_configuration_dict = vnl_file.readAtomicConfigurations() atomic_configuration = atomic_configuration_dict["lih2li"] displayCentralRegionAtoms(atomic_configuration)
which should print the following to your screen provided you have been using the
file lih2li.vnl for storing the atomic configuration used
throughout these examples.
Atoms located in the scattering region: ================================================== Number Element Cartesian coordinates 0 Li [0.0 Ang 0.0 Ang -8.568 Ang] 1 Li [0.0 Ang 0.0 Ang -5.668 Ang] 2 Li [0.0 Ang 0.0 Ang -2.768 Ang] 3 H [0.0 Ang 0.0 Ang -0.402 Ang] 4 H [0.0 Ang 0.0 Ang 0.402 Ang] 5 Li [0.0 Ang 0.0 Ang 2.768 Ang] 6 Li [0.0 Ang 0.0 Ang 5.668 Ang] 7 Li [0.0 Ang 0.0 Ang 8.568 Ang] ==================================================
This confirms that the atoms chosen as projection_atoms indeed
were our hydrogen atoms.
Figure 40: Energy spectrum for hydrogen atoms in a hydrogen molecule and for the hydrogen atoms in the two-probe system. The HOMO/LUMO gap is smaller for the hydrogen atoms in the two-probe system.
By comparing the molecular projected energy spectrum for the hydrogen atoms in the two-probe system with that of molecular hydrogen, we can see that the energy gap between the HOMO and the LUMO is smaller for the hydrogen atoms in the two-probe system. This reduction of the HOMO–LUMO gap is directly responsible for the large value of the transmission coefficient of the hydrogen molecule observed experimentally.
Figure 41: Transmission spectrum for the Li-H2-Li system along with the molecular projected energy spectrum for the hydrogen atoms. Actually, this figure was produced using a DoubleZetaPolarized basis set also for the lithium atoms for a more accurate description.
Figure 41 shows the energy spectrum of the hydrogen atoms in the two-probe system along with the transmission spectrum for the entire Li-H2-Li two-probe system. Here, we see that only the LUMO of the hydrogen atoms take part in conducting electrons from one electrode to the other, as that is the only orbital which is located at energies where transmission is noticeable.
The calculateProjectedHamiltonianEigenstates() function calculates wave-functions (i.e. eigenstates) of the projected molecular Hamiltonian discussed just above. This way, one can study how the molecular orbitals for a molecule are changed when the molecule is placed between between the two electrodes.
The script below shows how to calculate the eigenstates of a molecule in a two-probe scattering region using the calculateProjectedHamiltonianEigenstates() method. We want to analyze the HOMO and LUMO eigenstates, corresponding to the first and second eigenstate for a hydrogen molecule. The complete script for doing this is shown below.
from ATK.TwoProbe import * # Restore calculation scf = restoreSelfConsistentCalculation('lih2li-scf.nc') # Reopen old two-probe configuration vnl_file=VNLFile("lih2li.vnl") atomic_configuration = vnl_file.readAtomicConfigurations()["lih2li"] # Calculate HOMO and LUMO eigenstates for the H atoms in the two-probe system eigenstates = calculateProjectedHamiltonianEigenstates( scf, projection_atoms = [3,4], quantum_numbers = [0,1] ) # Store results in VNL files vnl_file = VNLFile("lih2li-mpsh.vnl") vnl_file.addToSample(atomic_configuration,'lih2li_mpsh') for eigenstate in eigenstates: vnl_file.addToSample(eigenstate, 'lih2li_mpsh')
Remember, that in Python the first element in a list has the index zero. So when we specify the quantum states as
quantum_numbers = [0,1]
we mean the first and the second eigenstate, which in a hydrogen molecule correspond to the HOMO and LUMO states.
The produced file can now be loaded into VNL where the orbitals can be visualized.
In this section we will analyze how the effective potential of the two-probe system changes when we apply a bias between the lithium electrodes.
First, we import the necessary modules, restore the TwoProbeConfiguration and the previously performed calculations, for zero and finite bias (1 Volt).
from ATK.TwoProbe import * # Reopen old two-probe configuration vnl_file = VNLFile("lih2li.vnl") atomic_configuration = vnl_file.readAtomicConfigurations()["lih2li"] # Restore results from previous calculations bias0V = restoreSelfConsistentCalculation('lih2li-bias-0.0.nc') bias1V = restoreSelfConsistentCalculation('lih2li-bias-1.0.nc')
The effective potential of the two-probe system is calculated using the calculateEffectivePotential() method in NanoLanguage. To visualize the voltage drop over the two-probe system we need to calculate the effective potential with zero bias and the desired finite bias (1 Volt) across the electrodes. Using the executeSelfConsistentCalculation() we can start from the previously performed SCF-calculation which will save us some time. The difference between the two potentials (i.e. the voltage drop) is then calculated by subtracting the calculated effective potentials from each other. These steps are shown in the script below.
# Calculate effective potentials ... pot_0V = calculateEffectivePotential(bias0V) pot_1V = calculateEffectivePotential(bias1V) # ... and find the difference = the voltage drop potential_drop = pot_1V - pot_0V
Finally, we store our results in a VNLFile in order to visualize them using VNL. This involves storing the atomic configuration along with the effective potentials in order to visualize the position of the atoms in the two-probe systems; an examples is shown in Figure 42.
# Store result in a new VNL file vnl_file = VNLFile("lih2li-voltdrop.vnl") vnl_file.addToSample(atomic_configuration,'lih2li-voltdrop') vnl_file.addToSample(potential_drop,'lih2li-voltdrop')
Figure 42: Contour plot of the effective potential with an applied bias of 1 Volt over the two-probe system. The abrupt change in the potential at the right electrode shows that our calculation should include additional surface atoms in order to properly screen the induced electric field.
The complete script which accomplishes all of the above steps is provided below for easy reference.
from ATK.TwoProbe import * # Reopen old two-probe configuration vnl_file = VNLFile("lih2li.vnl") atomic_configuration = vnl_file.readAtomicConfigurations()["lih2li"] # Restore results from previous calculations bias0V = restoreSelfConsistentCalculation('lih2li-bias-0.0.nc') bias1V = restoreSelfConsistentCalculation('lih2li-bias-1.0.nc') # Calculate effective potentials ... pot_0V = calculateEffectivePotential(bias0V) pot_1V = calculateEffectivePotential(bias1V) # ... and find the difference = the voltage drop potential_drop = pot_1V - pot_0V # Store result in a new VNL file vnl_file = VNLFile("lih2li-voltdrop.vnl") vnl_file.addToSample(atomic_configuration,'lih2li-voltdrop') vnl_file.addToSample(potential_drop,'lih2li-voltdrop')
The local, or spatially resolved, density of states (DOS) are calculated using the calculateLocalDensityOfStates() function available in the ATK.TwoProbe module. An example script calculating the LDOS for our two-probe system is shown below.
from ATK.TwoProbe import * # Restore calculation lih2li_scf = restoreSelfConsistentCalculation('lih2li-scf.nc') # Read old atomic configuration vnl_file = VNLFile("lih2li.vnl") atomic_configuration = vnl_file.readAtomicConfigurations()["lih2li"] # Calculate electron density from old NetCDF data electron_density = calculateElectronDensity(lih2li_scf) # Calculate local DOS for non-electrode atoms ldos = calculateLocalDensityOfStates( lih2li_scf, energy = 0.0*eV, quantum_number = (0.0,0.0) ) # Store obtained results in vnl file using # different IDs vnl_file = VNLFile("lih2li-ldos.vnl") vnl_file.addToSample(atomic_configuration,'lih2li-ldos') vnl_file.addToSample(electron_density, 'lih2li-ldos') vnl_file.addToSample(ldos, 'lih2li-ldos')
We calculate the LDOS at the Fermi level. The variable quantum_numbers
corresponds to the k-point; for our one-dimensional system we naturally use the
two-dimensional Γ point, i.e. k=(0.0,0.0).
We see a substantial density of states located at the hydrogen atoms (and little or none elsewhere) which shows that for a moderate bias, the LUMO of the hydrogen molecule is the origin of the eigenchannel that carries most of the current.
Figure 43: Isosurface showing the local DOS of the two-probe system. The isosurface shown corresponds to 0.01216 states/(Å3 eV). A considerable density of states is located at the hydrogen atoms.