Siesta 1: Basis Sets

This exercise is intended to illustrate the definition of basis sets with different numbers of orbitals and localization radii in SIESTA. It is based on the H2O molecule. You will first use standard basis sets generated by SIESTA, and then a basis set specifically optimized for the H2O molecule. The tips at the end of this page will help you in analyzing the results of the calculations.

We are going to use the ASE interface to the siesta calculator, for the official SIESTA documentation see here.

Part 1: Standard basis sets

In the following script you will relax the structure of the H2O molecule to find its equilibrium structure.

import time
import numpy as np

from ase import Atoms, units
from ase.optimize import QuasiNewton
from ase.calculators.siesta import Siesta

# Set up a H2O molecule by specifying atomic positions
h2o = Atoms(symbols='H2O',
            positions=[( 0.776070, 0.590459, 0.00000),
                       (-0.776070, 0.590459, 0.00000),
                       (0.000000,  -0.007702,  -0.000001)],
            pbc=(1,1,1))

# Center the molecule in the cell with some vacuum around
h2o.center(vacuum=6.0)

# Select some energy-shifts for the basis orbitals
e_shifts = [0.01,0.1,0.2,0.3,0.4,0.5]

# Run the relaxation for each energy shift, and print out the
# corresponding total energy, bond length and angle


for e_s in e_shifts:
    starttime = time.time()
    calc = Siesta('h2o',meshcutoff=200.0 * units.Ry, mix=0.5, pulay=4)
    calc.set_fdf('PAO.EnergyShift', e_s * units.eV)    
    calc.set_fdf('PAO.SplitNorm', 0.15)
    calc.set_fdf('PAO.BasisSize', 'SZ')
    h2o.set_calculator(calc)
    # Make a -traj file named h2o_current_shift.traj:      
    dyn = QuasiNewton(h2o, trajectory='h2o_%s.traj' % e_s)
    dyn.run(fmax=0.02)      # Perform the relaxation      
    E = h2o.get_potential_energy()
    print()                                # Make the output more readable      
    print("E_shift: %.2f" %e_s)       
    print("----------------")
    print("Total Energy: %.4f" % E)       # Print total energy      
    d = h2o.get_distance(0,2)
    print("Bond length: %.4f" % d)        # Print bond length      
    p = h2o.positions
    d1 = p[0] - p[2]
    d2 = p[1] - p[2]
    r = np.dot(d1, d2) / (np.linalg.norm(d1) * np.linalg.norm(d2))
    angle = np.arccos(r) / pi * 180
    print("Bond angle: %.4f" % angle)      # Print bond angle
    endtime = time.time()
    walltime = endtime - starttime
    print('Wall time: %.5f' % walltime)
    print()                                # Make the output more readable      

Run the script using three different basis sets: single-Z (SZ), double-Z (DZ) and double-Z plus polarization (DZP). Run it in different directories for each basis set, since the run will produce a large amount of output files. The bases are defined in the script through these three lines:

calc.set_fdf('PAO.BasisSize','SZ')
calc.set_fdf('PAO.EnergyShift',e_s * eV)
calc.set_fdf('PAO.SplitNorm',0.15)

For each of the basis sets the script will run the relaxation for different EnergyShift parameters. Look at the results as a function of basis size and localization radius (or energy shift).

In particular, you should look at:

  • Total energy
  • Bond lenghts at the relaxed structure
  • Bond angles at the relaxed structure
  • Execution time
  • Radius of each of the orbitals
  • Shape of the orbitals

The script will print bond lengths and angles, total energy plus the wall time for each energy shift. The radii of the orbitals from the last run can be found in the file h2o.txt along with miscellaneous other informations. Orbital shapes from the last run are stored in the ORB.* files, which contain the value of the orbitals versus radius. (Note that the standard way to plot the orbitals is to multiply the orbital by \(r^l\)).

You can visualize both the static atoms and the relaxation trajectory using the the ASE gui. For example you can visualize the relaxation trajectory from the command line by doing:

$ ase-gui h2o_0.1.traj

Note that you will get a trajectory file .traj for each energy shift in the loop.

Try to get plots like the following, obtained for a SZ basis:

en dist ang

Try to answer these questions:

  1. What is the best basis set that you have found? Why?
  2. How do the results compare with experiment?
  3. What do you consider a reasonable basis for the molecule, if you need an accuracy in the geometry of about 1%?
  4. In order to assess convergence with respect to basis set size, should you compare the results with the experimental ones, or with those of a converged basis set calculation?

Part 2: Optimized basis sets

You will now do the same calculations as in Part 1, but now using a basis set specifically optimized for the H2O molecule. Use the following optimized block instead of the basis-definition lines in Part1:

calc.set_fdf('PAO.Basis',
                ["""H     2      0.22
                n=1    0    2   E      2.07      0.00
                4.971   1.771
                1.000   1.000
                n=2    1    1   E      0.89      0.01
                4.988
                1.000
                O     3     -0.20
                n=2    0    2   E      0.00      1.31
                5.000   2.581
                1.000   1.000
                n=2    1    2   E      0.00      5.28
                6.500   2.487
                1.000   1.000
                n=3    2    1   E    104.31      0.00
                3.923
                1.000"""])

Compare the parameters with those of the calculations in Part 1.

Do the runs with this basis set, and compare the results with the previous ones.

Tips

Tip 1: You can see the radii of the orbitals in the output file, just after the line reading:

printput: Basis input ----------------------------------------------

Tip 2: You can look at the shape of the orbitals by plotting the contents of the ORB* files generated by SIESTA.

Tip 3: You will find a lot of information on the run in the .txt output file

Tip 4: In ag you can select View ‣ VMD to start the VMD viewer. There you can change the atom representation to what you feel is more convenient. Do that by selecting Graphics ‣ Representations in the top bar.

Tip 5: SIESTA will store basis functions in ORB.* files. These files can be plotted using the xmgrace command on the GBAR like this:

$ xmgrace ORB.S1.1.O ORB.S2.1.O