Two-probe systems

Table of Contents

The major strength of ATK is its unique capability of supporting the analysis and design of two-probe systems. Using NanoLanguage, the investigation of the following two-probe specific key features will be at your disposal:

In the following, we will present you with the basic NanoLanguage script elements that are required for defining the geometry and the subsequent analysis of two-probe systems

Building two-probe geometries

A two-probe system consists of two key components:

  • Two semi-infinite bulk regions called the left and the right electrodes

  • The region between the two electrodes called the scattering or central region

Consider, for example, a two-probe system consisting of a hydrogen molecule positioned in-between two identical one-dimensional lithium electrodes. Using NanoLanguage and basic Python constructions, the following script sets up the geometry for you

from ATK.TwoProbe import *

# Li chain lattice constant
a = 2.90
# Construct the electrode unit cell
unit_cell = [ [3*a, 0.0, 0.0 ],
              [0.0, 3*a, 0.0 ],
              [0.0, 0.0, 4*a ] ] * Angstrom

# Define the electrode
electrode_Li = PeriodicAtomConfiguration(
    super_cell_vectors=unit_cell,
    elements=4*[Lithium],
    fractional_coordinates=[(0.5, 0.5, float(i)/4.0) for i in range(0,4)]
    )

# Setup the two-probe scattering region

# Distances between Li-H and H-H (found from relaxing a Li4H2 cluster)
dist_HH = 0.804
dist_LiH = 2.366

# The atoms in the central region
elements = 3*[Lithium] + 2*[Hydrogen] + 3*[Lithium]

positions = [
    (0.0, 0.0, 0*a),
    (0.0, 0.0, 1*a),
    (0.0, 0.0, 2*a),
    (0.0, 0.0, 2*a + dist_LiH),
    (0.0, 0.0, 2*a + dist_LiH + dist_HH),
    (0.0, 0.0, 2*a + dist_LiH + dist_HH + dist_LiH + 0*a),
    (0.0, 0.0, 2*a + dist_LiH + dist_HH + dist_LiH + 1*a),
    (0.0, 0.0, 2*a + dist_LiH + dist_HH + dist_LiH + 2*a)
    ] * Angstrom
    
# Combine electrode and scattering region
# into a two-probe system
two_probe = TwoProbeConfiguration(
    electrodes = (electrode_Li,electrode_Li),
    scattering_region_elements              = elements,
    scattering_region_cartesian_coordinates = positions
    )

# Export the two-probe system to VNL file.
vnl_file = VNLFile("lih2li.vnl")
vnl_file.addToSample(two_probe, "lih2li")

lih2li-setup.py

The script performs the following actions:

  1. Define the electrode unit cells.

  2. Use the class TwoProbeConfiguration for storing the left and right electrodes.

  3. Set up the geometry and atomic constituents of scattering region.

  4. Define a list of lithium atoms that make up the interface between the bulk electrodes and the scattering region.

  5. Store the finished two-probe system in a TwoProbeConfiguration object.

  6. Store the configuration in a VNLFile making it available for import into other NanoLanguage scripts.

Run the script by issuing the following command from the command line

atk lih2li-setup.py

Preparing a two-probe calculation

Once you have defined the basic geometry of a two-probe system, the next is to specify the details of the actual DFT calculation. The following script example illustrates the many parameters that can be controlled by making use of the advanced named parameter handling available in NanoLanguage

from ATK.TwoProbe import *

# Restore old two-probe configuration
vnl_file = VNLFile("lih2li.vnl")
configurations = vnl_file.readAtomicConfigurations()
two_probe_conf = configurations["lih2li"]

# Reduce basis set size for Li
basis_set_params = basisSetParameters(
    type = SingleZeta,
    element = Lithium
    )

# Set k-points for electrodes
bz_int_param = brillouinZoneIntegrationParameters( (1,1,100) )

# Create parameters for electrodes
electrode_params = ElectrodeParameters(
    brillouin_zone_integration_parameters = bz_int_param
    )

# Tolerance for convergence (default)
iteration_control_params = iterationControlParameters(
    tolerance = 1e-5
    )

# Collect parameters into a two-probe calculation method
method = TwoProbeMethod(
    (electrode_params,electrode_params),
    basis_set_parameters = basis_set_params,
    iteration_control_parameters = iteration_control_params
    )

# Specify verbosity and checkpoint file
runtime_params = runtimeParameters(
    verbosity_level = 10,
    checkpoint_filename = 'lih2li-scf.nc' 
    )

# Perform SCF calculation with chosen parameters
scf = executeSelfConsistentCalculation(
    atomic_configuration = two_probe_conf,
    method = method,
    runtime_parameters = runtime_params
    )

lih2li-scf.py

In this case, the following actions are performed:

  1. Load the two-probe configuration from a previously stored VNLFile.

  2. Specify the basis set that should be used in the DFT calculation.

  3. Invoke the function brillouinZoneIntegrationParameters() to define the number of user requested k-points. In this case, a high resolution is only required along the C-axis, since the electrodes are one-dimensional.In the specific case of three dimensional systems, it's necessary to have more than one k-point along A and B-axis. The number of k-points is affecting the accuracy of the calculation of the Fermi energy. For this reason, in case of poor or slow convergence of the self-consistent field, it's highly suggested to increase the number of k-points according to the symmetry of the system.

  4. Add the requested number of k-points to the definition of the electrodes.

  5. Set the convergence tolerance for the self-consistent field (SCF) calculation.

  6. All parameters for defining the entire two-probe system are now in place. We collect them using a TwoProbeMethod object.

  7. Specify a high-level of verbosity during the SCF-calculation. Setting this quantity enables you track errors and debug any anomalies during the development and testing phase of novel two-probe systems.

  8. Set the file name of a checkpoint file. In this way, the results of the DFT run is stored on disk, and may then be reused in other scripts and calculations.

  9. Finally, call the function executeSelfConsistentCalculation() with the user-defined input parameters to perform the actual DFT calculation of the two-probe system.

Run the script by issuing the following command from the command line

atk lih2li-scf.py

Analyzing the calculation

Once you have set up and run a DFT calculation of a two-probe system, the task is to extract the relevant system characteristics. After a calculation has finished, you may restore the state of the calculation using the restoreSelfConsistentCalculation() function. Here is how to do it

from ATK.TwoProbe import *

# Restore initial density from old calculation
zero_bias = restoreSelfConsistentCalculation("lih2li-scf.nc")

This enables you to analyze your two-probe system without having to redo the time-consuming calculation once again. Below, we shall use this to calculate the current-voltage curve.

Current as a function of bias

One of the most interesting properties of a two-probe system is the variation of its electrical properties as a function of an applied system bias. Even though this is a relative demanding task, a structured NanoLanguage script will provide a logical walk-through the challenge. Here is an example using the Li-H2-Li two-probe as the test system

from ATK.TwoProbe import *
import numpy 
import ATK

# Restore two-probe geometry
vnlfile = VNLFile('lih2li.vnl')
lih2li = vnlfile.readAtomicConfigurations()['lih2li']

# Use the same parameters for final bias as for zero bias
bz_int_param = brillouinZoneIntegrationParameters(
    monkhorst_pack_parameters=(1,1,100)
    )
electrode_params = ElectrodeParameters(
    brillouin_zone_integration_parameters = bz_int_param
    )
basis_set_params = basisSetParameters(
    type = SingleZeta,
    element = Lithium
    )
iteration_control_params = iterationControlParameters(
    tolerance = 1e-5
    )

ATK.setVerbosityLevel(0)

# Restore initial density from old calculation
scf = restoreSelfConsistentCalculation("lih2li-scf.nc")

print '# Bias (Volt)\tCurrent (Ampere)'

# Run bias from 0.0 and 1.0 in steps of 0.1
for voltage in numpy.arange(0.0, 1.01, 0.1):

    dft_method = TwoProbeMethod(
        electrode_parameters=(electrode_params,electrode_params),
        basis_set_parameters = basis_set_params,
        iteration_control_parameters = iteration_control_params,
        electrode_voltages = (voltage/2.0, -voltage/2.0)*Volt    
        )

    # Store each calculation in a separate NetCDF file    
    ATK.setCheckpointFilename ('lih2li-bias-%.1f.nc' % voltage)
    
    scf = executeSelfConsistentCalculation(
        atomic_configuration=lih2li,
        method = dft_method,
        initial_calculation = scf
        )

    current = calculateCurrent(scf)

    print "%.1f\t\t%.2e" %(voltage, current.inUnitsOf(Ampere))

lih2li-bias.py

In summary, the script performs the following actions:

  1. Load the geometry from the saved VNLFile.

  2. Define the parameters for the finite bias calculation, in the same way we did for zero bias above.

  3. Restore the converged density from a previous DFT performed at zero bias. We will use this density as the initial guess for the SCF-calculations for finite bias.

  4. Loop over the bias. For each value perform the following:

    1. Define the TwoProbeMethod DFT method.

    2. Perform a self-consistent calculation using the converged result of the previous bias as initial guess. This reduces the calculation time substantially, especially for finite bias.

    3. Calculate and print the current.

Run the script by issuing the following command from the command line

atk lih2li-bias.py

The current-voltage relation for the lithium-hydrogen two-probe system is shown in Figure 8.

The current-voltage characteristics for the lithium-hydrogen two-probe system.

Figure 8: The current-voltage characteristics for the lithium-hydrogen two-probe system.