Wavefunction tutorial

Requirements

Software components

  • nanotools

  • RESCU+

Pseudopotentials

I will need the following pseudopotentials.

  • C_AtomicData.mat

Let’s copy them from the pseudo database to the current working directory and export RESCUPLUS_PSEUDO=$PWD.

Briefing

In this tutorial, I show how to calculate the real space wavefunctions of graphene at a few k-points.

Setup

Create the Python script etot.py with the following content (see the tutorial on TotalEnergy)

from nanotools import Atoms, Cell, System, TotalEnergy
import numpy as np
a = 2.46 # lattice constant (ang)
avec = [
[.5*a, np.sqrt(3)/2*a, 0.],
[.5*a,-np.sqrt(3)/2*a, 0.],
[0.,0.,10.583544213400000],
]
cell = Cell(avec=avec, resolution=0.12)
fxyz = [[2/3, 1/3, 0.5],[1/3, 2/3, 0.5]]
atoms = Atoms(fractional_positions=fxyz, formula="CC")
sys = System(cell=cell, atoms=atoms)
sys.kpoint.set_grid([15,15,1])
calc = TotalEnergy(sys)
calc.solve()

and wvf.py

from nanotools import Wavefunction as WF
import numpy as np
calc = WF.from_totalenergy("nano_scf_out.json")
calc.system.kpoint.set_grid([4,4,1], shift = [.5, .5, 0.])
calc.solve()

Explanations

Here is a high level view of the calculation workflow:

  1. Initialize the Wavefunction calculator from a ground state calculation (TotalEnergy).

  2. Perform a wavefunction calculation (non-self-consistently) for a given set of k-points and compute the wavefunction.

Initialize the Wavefunction calculator

Upon completing the total energy calculation, the results are saved in nano_scf_out.json. I will initialize a Wavefunction calculator using the class method from_totalenergy.

calc = WF.from_totalenergy("nano_scf_out.json")
calc.system.kpoint.set_grid([4,4,1], shift = [.5, .5, 0.])
calc.solve()

The method from_totalenergy will copy the system information and initialize the Wavefunction calculator. I then set the k-point to a \(4\times 4\times 1\) grid. Alternatively, I can directly set the k-point coordinates for which I want the real space wavefunctions calling set_fractional_coordinates from the Kpoint class.

Wavefunction calculation

RESCU+’s solvers are invoked calling the solve method

calc.solve()

The method writes all parameters to a JSON file, then calls the relevant (Fortran) program, then loads the data back into the calculator. The output of rescuplus goes to nano_wvf_out.h5 and nano_wvf_out.json. As other real space data, the local DOSes are stored in nano_wvf_out.h5 similarly with density, i.e. under /wavefunctions/#/field where # is an index running over all k-points. If spin is accounted for, then the paths to the spin-up and spin-down wavefunctions are /wavefunctions/spin-up/#/field and /wavefunctions/spin-down/#/field respectively. Besides, the k-point fractional coordinates and grid information are found in /wavefunctions/#/kpoint and /wavefunctions/#/cell.

Target specific eigenstates

It is sometimes useful to target specific states in the band structure. In large scale calculations, for example, where one might be interested in a few states, it is not necessary to compute the real space representation of thousands of eigenstates. Taking the above system as example, we can compute the wavefunctions of the 4th and 5th band at k-point [.1,.2,.3] as follows

from nanotools import Wavefunction as WF
import numpy as np
calc = WF.from_totalenergy("nano_scf_out.json")
calc.system.kpoint.set_fractional_coordinates([[.1,.2,.3]])
calc.solver.eig.target_irange = [3,4]
calc.solve()

We invoke the Kpoint object’s method set_fractional_coordinates to directly set the k-points to [.1,.2,.3]. We also set the eigensolver parameter target_irange to [3,4]. Note that target_irange is an index range, and hence all states between target_irange[0] and target_irange[1] will be computed.