Response functions
In this tutorial, we show how to calculate the response functions of primitive cell, namely dynamic
polarization, dielectric function and optical (AC) conductivity, using the Lindhard
class.
The corresponding script is examples/prim_cell/lindhard.py
. Lindhard
requires the
energies and wave functions from exact diagonalization, so its application is limited to primitive
cells of small or moderate size. For large models, the tight-binding propagation method (TBPM) is
recommended, which will be discussed in Properties from TBPM. Before beginning the tutorial, we import
all necessary packages:
import math
import numpy as np
import matplotlib.pyplot as plt
import tbplas as tb
Dynamic polarization and dielectric function
We define the following function to calculate and visualize the dynamic polarization and dielectric function of monolayer graphene:
1def calc_dyn_pol_epsilon() -> None:
2 """
3 Calculate dynamic polarizability and dielectric function of monolayer graphene.
4 """
5 # Model parameters
6 # t: hopping integral in eV
7 # a: C-C bond length in NM, NOT lattice constant (0.246 NM in make_graphene_diamond)
8 t = 3.0
9 a = 0.142
10
11 # q-points:
12 # q0: |q| = 1 / a and theta = 30 degrees
13 # q1: |q| = 4.76 nm^-1 and theta = 30 degrees
14 theta = 30.0 / 180.0 * math.pi
15 unit_vec = np.array([math.cos(theta), math.sin(theta), 0.0])
16 q0 = 1.0 / a * unit_vec
17 q1 = 4.76 * unit_vec
18
19 # Create model, solver and set parameters
20 cell = tb.make_graphene_diamond(t=t)
21 lind = tb.Lindhard(cell)
22 lind.config.prefix = "dyn_pol_epsilon"
23 lind.config.e_min = 0.0
24 lind.config.e_max = 18.0
25 lind.config.e_step = 0.005
26 lind.config.dimension = 2
27 lind.config.k_grid_size = (1200, 1200, 1)
28 lind.config.q_points = np.array([q0, q1], dtype=np.float64)
29
30 # Calculate dyn_pol and epsilon
31 omegas, dyn_pol = lind.calc_dyn_pol()
32 epsilon = lind.calc_epsilon(dyn_pol)
33
34 # Plot
35 plot_dyn_pol(omegas, dyn_pol, iq=0, t=t, a=a)
36 plot_epsilon(omegas, epsilon, iq=1)
Firstly, we define the model and calculation parameters. For consistency with Phys. Rev. B 84, 035439 (2011), we define the hopping parameter \(t=3.0eV\), and consider the following two q-points:
\(|q| = 1/a = 7.04\ nm ^{-1}\) and \(\theta = 30^\circ\)
\(|q| = 4.76\ nm^{-1}\) and \(\theta = 30^\circ\)
Then we create the model using the hopping parameter and a solver from Lindhard
taking the
model as argument. After that, we set up the calculation parameters, including the prefix of data
files (prefix
), the lower and upper bounds and resolution of energy range (e_min
, e_max
and e_step
, the dimension of the model (dimension
), the size k-grid in first Brillouin zone
(k_grid_size
), and the Cartesian coordinates of q-points (q_points
). Note that q-points must
have the shape of \(N_q \times 3\). Other parameters not shown in the example include the chemical
potential (mu
), the temperature (temperature
) and the background dielectric constant
(back_epsilon
). The dynamic polarization can be obtained by calling the calc_dyn_pol
method,
while the dielectric function can be evaluated from dynamic polarization with the calc_epsilon
method.
The functions for visualizing the results are defined as:
1def plot_dyn_pol(omegas: np.ndarray,
2 dyn_pol: np.ndarray,
3 iq: int = 0,
4 t: float = 3.0,
5 a: float = 0.142) -> None:
6 """
7 Plot dynamic polarizability.
8 :param omegas: (num_eng,) float64 array, energy grid in eV
9 :param dyn_pol: (num_qpt, num_eng) complex128 array, dynamic polarizability
10 :param iq: index of q-point of dyn_pol to plot
11 :param t: hopping integral in eV
12 :param a: C-C bond length in NM
13 :return: None
14 """
15 # Reference: fig. 3(e) of [1] for |q| = 1 / a and theta = 30 degrees
16 plt.plot(omegas / t, -dyn_pol[iq].imag * t * a ** 2, color="red")
17 plt.xticks(np.linspace(0.0, 6.0, 7))
18 plt.yticks(np.linspace(0.0, 1.4, 8))
19 plt.xlim(0.0, 6.0)
20 plt.ylim(0.0, 1.4)
21 plt.minorticks_on()
22 plt.tick_params(which="major", direction="in", length=8, width=0.6)
23 plt.tick_params(which="minor", direction="in", length=4, width=0.6)
24 plt.xlabel(r"$\omega\ (t)$")
25 plt.ylabel(r"-Im$\Pi\ (t^{-1}a^{-2})$")
26 plt.tight_layout()
27 plt.savefig("dyn_pol.pdf")
28 plt.close()
29
30
31def plot_epsilon(omegas: np.ndarray,
32 epsilon: np.ndarray,
33 iq: int = 0) -> None:
34 """
35 Plot dynamic polarization.
36 :param omegas: (num_eng,) float64 array, energy grid in eV
37 :param epsilon: (num_qpt, num_eng) complex128 array, dielectric function
38 :param iq: index of q-point of epsilon to plot
39 :return: None
40 """
41 # Reference: fig. 7(c) of [1] for |q| = 4.76 nm^-1 and theta = 30 degrees
42 plt.plot(omegas, epsilon[iq].real, color="red")
43 plt.xticks(np.linspace(0.0, 18.0, 10))
44 plt.yticks(np.linspace(0.0, 15.0, 4))
45 plt.xlim(0.0, 18.0)
46 plt.ylim(-1.5, 15)
47 plt.minorticks_on()
48 plt.tick_params(which="major", direction="in", length=8, width=0.6)
49 plt.tick_params(which="minor", direction="in", length=4, width=0.6)
50 plt.axhline(y=0.0, xmin=0.0, xmax=18.0, linestyle="--", color="k", linewidth=1.0)
51 plt.xlabel(r"$\omega\ (eV)$")
52 plt.ylabel(r"Re $\epsilon$")
53 plt.tight_layout()
54 plt.savefig("epsilon.pdf")
55 plt.close()
The results are shown in Fig. 1 and Fig.2:

Dynamic polarization of monolayer graphene for \(|q| = 1/a\) and \(\theta = 30^\circ\). (a) Output of this tutorial. (b) Fig. 3(e) of Phys. Rev. B 84, 035439 (2011).

Dielectric function of \(|q|=4.76 nm^{-1}\) and \(\theta = 30^\circ\). (a) Output of this tutorial. (b) Fig. 7(c) of Phys. Rev. B 84, 035439 (2011).
AC conductivity
AC conductivity can be evaluate in a similar approach to dynamic polarization:
1def calc_ac_cond() -> None:
2 """
3 Calculate ac conductivity of monolayer graphene.
4 """
5 # Model parameters
6 # t: hopping integral in eV
7 t = 3.0
8
9 # Create model, solver and set parameters
10 cell = tb.make_graphene_diamond(t=t)
11 lind = tb.Lindhard(cell)
12 lind.config.prefix = "ac_cond"
13 lind.config.e_min = 0.0
14 lind.config.e_max = 18.0
15 lind.config.e_step = 0.005
16 lind.config.dimension = 2
17 lind.config.num_spin = 2
18 lind.config.k_grid_size = (2048, 2048, 1)
19 omegas, ac_cond = lind.calc_ac_cond()
20
21 # Plot
22 plot_ac_cond(omegas, ac_cond, t=t)
We also need to create the model, the solver and set up parameters. Most of the parameters are
the same to dynamic polarization. To be consistent with
Phys. Rev. B 82, 115448 (2010),
we use a k-grid of \(2048 \times 2048 \times 1\), and set the spin-degeneracy to 2 via the num_spin
parameter. Other parameters not shown in the example include ac_cond_component
which defines the
component of ac conductivity to evaluate. The AC conductivity can be obtained by calling the calc_ac_cond
method. The function to visualize the results is defined as:
1def plot_ac_cond(omegas: np.ndarray,
2 ac_cond: np.ndarray,
3 t: float = 3.0) -> None:
4 """
5 Plot ac conductivity.
6 :param omegas: (num_eng,) float64 array, energy grid in eV
7 :param ac_cond: (num_eng,) complex128 array, ac conductivity
8 :param t: hopping integral in eV
9 :return: None
10 """
11 # Reference: fig. 13 of [2]
12 plt.plot(omegas / t, ac_cond.real * 4, color="red")
13 plt.xticks(np.linspace(0.0, 6.0, 7))
14 plt.yticks(np.linspace(0.0, 4.0, 9))
15 plt.xlim(0.0, 6.0)
16 plt.ylim(0.0, 4.0)
17 plt.minorticks_on()
18 plt.tick_params(which="major", direction="out", length=8, width=0.6)
19 plt.tick_params(which="minor", direction="out", length=4, width=0.6)
20 plt.xlabel(r"$\omega\ (t)$")
21 plt.ylabel(r"$\sigma_{xx}\ (\sigma_0)$")
22 plt.tight_layout()
23 plt.savefig("ac_cond.pdf")
24 plt.close()
The result is shown in Fig.3:

AC conductivity of monolayer graphene. (a) Output of this tutorial. (b) Fig. 3(e) of Phys. Rev. B 82, 115448 (2010).
Notes on system dimension
The formulae for calculating dynamic polarization, dielectric function and AC conductivity are defines as:
Lindhard
class deals with system dimension in two approaches. The first approach is to treat all systems as
3-dimensional. In this approach, supercell technique is required, with vacuum layers added on non-periodic
directions. Also, the component(s) of k_grid_size
should be set to 1 accordingly on that direction. The
seond approach utilizes dimension-specific formula whenever possible. For now, only 2-dimensional case has
been implemented. This approach requires that the system should be periodic in \(xOy`\) plane, i.e. the
non-periodic direction should be along \(c\) axis.
Regarding the accuracy of results, the first approach suffers from the issue that dynamic polarization and AC conductivity scale inversely proportional to the product of supercell lengths, i.e., \(|c|\) in 2d case and \(|a|*|b|\) in 1d case. This is caused by elementary volume in reciprocal space (\(\mathrm{d}^{3}k\)) in Lindhard function. On the contrary, the second approach has no such issue. If the supercell lengths of non-periodic directions are set to 1 nm, then the first approach yields the same results as the second approach.
For the dielectric function, the situation is more complicated. From the equation for epsilon we can see that it is also affected by the Coulomb potential \(V(q)\), which is \(V(q)=\frac{1}{\epsilon_0\epsilon_r}\cdot\frac{4\pi e^2}{q^2}\) in 3-d case and \(V(q)=\frac{1}{\epsilon_0\epsilon_r}\cdot\frac{2\pi e^2}{q}\) in 2-d case, respectively. So the influence of system dimension is q-dependent. Setting supercell length to 1 nm will NOT reproduce the same result as the second approach.