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:

../../_images/dyn_pol.png

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).

../../_images/epsilon.png

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:

../../_images/ac_cond.png

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:

\[\Pi(\textbf{q},\omega)=\frac{g_s}{(2\pi)^n}\int_{\mathrm{BZ}}\mathrm{d}^n\textbf{k}\sum_{l,l^\prime}\frac{n_\mathrm{F}(E_{\textbf{k}l})-n_\mathrm{F}(E_{\textbf{k}^{\prime}l^{\prime}})}{E_{\textbf{k}l}-E_{\textbf{k}^{\prime}l^{\prime}}+\hbar\omega+\mathrm{i}\eta^+}|\langle\textbf{k}^{\prime}l^{\prime}|\mathrm{e^{\mathrm{i}\textbf{q}\cdot\textbf{r}}|\textbf{k}l\rangle}|^2\]
\[\epsilon(\textbf{q},\omega)=1-V(\textbf{q})\Pi(\textbf{q},\omega)\]
\[\sigma_{\alpha\beta}(\omega)=\frac{\mathrm{i} e^2 \hbar}{N_k \Omega_c}\sum_{\textbf k}\sum_{n,m} \frac{f_{m\textbf{k}} - f_{n\textbf{k}}}{\epsilon_{m\textbf{k}} - \epsilon_{n\textbf{k}}} \frac{\langle\psi_{n\textbf k}|v_\alpha|\psi_{m\textbf k}\rangle \langle\psi_{m\textbf k}|v_\beta|\psi_{n\textbf k}\rangle}{\epsilon_{m\textbf{k}} - \epsilon_{n\textbf{k}}-(\hbar\omega+\mathrm i\eta^+)}\]

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.