Performing a spin polarized calculation with DFTB

Table of Contents

Calculating the spin polarization of a graphene ribbon

In the following you will set up a graphene nanoribbon and perform a spin-polarized calculation using the DFTB [mio] model.

Open the Builder , and click Add>Add Custom>Nanoribbon.

Build a zigzag ribbon of width 8 atoms.

To set up a calculation of the band structure, send the structure to the Script Generator using the "Send To" icon in the lower right-hand corner of the builder window.

In the Script Generator, add the following blocks to the script:

  • New Calculator

  • Initial State

  • Analysis/Bandstructure

Finally, change the output filename to ribbon.nc

Open the New Calculator block.

  • Select the "ATK-SE: Slater-Koster" calculator.

  • Change the k-point sampling to (1,1,11).

  • Go to the "Slater-Koster basis set" and select the "DFTB [mio]" basis set.

  • Check the Use polarized spin box, to perform a spin polarized DFTB calculation.

    [Note] Note

    The DFTB parameter set does not include the spin polarization parameters. Instead, the spin polarization parameters are obtained from the ATK_W database.

To set up the initial spin state of the system, open the Initial State block.

Set the Initial state type to "User spin", and then under Spin, set the default spin of both carbon and hydrogen to 0.

Then, in the 3D view, click the upper carbon atom (index 0 in the list of atoms) and set its initial spin value to 1.0. Repeat this procedure for the lower carbon atom (number 1 in the list) setting its initial values to -1.0. The hydrogen atoms and the other carbon atoms can be left with spin values equal to 0.0. The dialog now look as (don't be confused by the fact that the carbon atoms are not ordered by Y coordinate)

Finally open the Bandstructure block and change Points pr. segment to 200. This implies, that each band will be calculated with a resolution of 200 points. Also notice that the default suggested route in the Brillouin zone (from the Γ point G=(0,0,0) to Z=(0,0,1/2) in units of the reciprocal lattice vectors) is the appropriate one.

Send the script to the Job Manager and run it.

Return to the main VNL window and select the file ribbon.nc and plot the bandstructure. By zooming in, into the plot, you should be able to obtain the following figure.

Calculate the properties of a series of configurations using scripting

If you want to calculate the bandstructure of a number of nanoribbons it is very convenient to use Python scripting. The script below performs a calculation of the bandstructure of nanoribbons with chiral index (n,n), where n runs from 1 to 10.

[Note] Note

The "chiral index" notation for nanoribbons in ATK is based on which linear combination of the planar graphene unit vectors that are used to form the unit cell. Thus, (n,n) have zigzag edges, and actually correspond to an unrolled armchair nanotube with the same chiral indices. For armchair edge nanoribbons, the chiral indices are (n,0).

# Setup the DFTB Calculator
basis_set = DFTBDirectory("dftb/mio/")
pair_potentials = DFTBDirectory("dftb/mio/")

numerical_accuracy_parameters = NumericalAccuracyParameters(
    k_point_sampling=(1, 1, 51),
    )

iteration_control_parameters = IterationControlParameters()

calculator = SlaterKosterCalculator(
    basis_set=basis_set,
    pair_potentials=pair_potentials,
    numerical_accuracy_parameters=numerical_accuracy_parameters,
    iteration_control_parameters=iteration_control_parameters,
    spin_polarization=True,
    )

#loop over different NanoRibbons
for n in range(1,10):
    #generate the nanoribbon
    bulk_configuration = NanoRibbon(n,n)

    #Determine the initial spin of the configuration
    elements = bulk_configuration.elements()
    coords = bulk_configuration.fractionalCoordinates()
    scaled_spins = numpy.zeros(len(elements))

    #find the index of the two edge Carbon atoms,
    ymin = 0.5
    ymax = 0.5
    imin=0
    imax=0
    for i in range(len(elements)):
        if coords[i][1] < ymin and elements[i] == Carbon:
            ymin = coords[i][1]
            imin = i
        if coords[i][1] > ymax and elements[i] == Carbon:
            ymax = coords[i][1]
            imax = i

    # set opposite spins on the edge Carbon atoms
    scaled_spins[imin] = 1
    scaled_spins[imax] = -1

    #attach calculator, and set the initial spin
    bulk_configuration.setCalculator(
        calculator(),
        initial_spin=InitialSpin(scaled_spins=scaled_spins),
        )
    bulk_configuration.update()

    # Calculate Bandstructure
    bandstructure = Bandstructure(
        configuration=bulk_configuration,
        route=['G', 'Z'],
        points_per_segment=200,
        bands_above_fermi_level=All
    )
    nlsave('bandgap.nc',bandstructure)

bandgap.py

Execute the script by downloading it and dropping it on the Job Manager. This will generate the file bandgap.nc.

To analyze the data, drop the following script on the Job Manager

w_list = []
gap0_list = []
gap1_list = []
# read a list with the bandstructure data
bandstructure = nlread('bandgap.nc', Bandstructure)

for i in range(len(bandstructure)):
    # get all the bandlines
    energies = bandstructure[i].evaluate().inUnitsOf(eV)
    #calculate the number of occupied bands
    occupied_bands = numpy.sum(numpy.array(energies[0]) < 0)
    #calculate the minimum direct band gap
    gap0 = numpy.min(energies[:,occupied_bands]- energies[:,occupied_bands-1])
    #calculate the band gap at the zone boundary
    gap1 = energies[-1,occupied_bands]- energies[-1,occupied_bands-1]
    #determine the coordinates in the y direction
    y_values = NanoRibbon(i+1,i+1).cartesianCoordinates().inUnitsOf(Ang)[:,1]
    # calculate the width, as distance between furthest carbon atoms
    # i.e. calculate the  H-H distance and subtracting the C-H distance
    w = numpy.max(y_values)-numpy.min(y_values)-2.2
    #append calculated values to the list
    w_list.append(w)
    gap0_list.append(gap0)
    gap1_list.append(gap1)

#print the data
import pylab
pylab.figure()
pylab.plot(w_list,gap0_list, 'k-o')
pylab.plot(w_list,gap1_list, 'k-o', markerfacecolor='white')
pylab.xlabel(r"$w_z$ ($\AA$)", size=16)
pylab.ylabel("$\Delta_z$ (eV)", size=16)
pylab.show()

analyze_bandgap.py

Direct band gap (solid circles) and the band gap at the zone boundary as function of the width of the nanoribbon.

Figure 1: Direct band gap (solid circles) and the band gap at the zone boundary as function of the width of the nanoribbon.


[Note] Note

Except for the smallest ribbon, the plot shows the same qualitative behavior as Fig. 4c in Ref. [3]. The discrepancy in the results are related to the accuracy of the DFTB method compared with a DFT-LDA calculation. To test this, you may modify the script and change the definition of the variable calculator:

calculator = LCAOCalculator(
    numerical_accuracy_parameters=numerical_accuracy_parameters,
    exchange_correlation = LSDA.PZ
    )

Remember to also modify the name of the output file to separate the new data from the old data set and then execute the script.