Source code for wannierberri.system.system_kp

#                                                            #
# This file is distributed as part of the WannierBerri code  #
# under the terms of the GNU General Public License. See the #
# file 'LICENSE' in the root directory of the WannierBerri   #
# distribution, or http://www.gnu.org/copyleft/gpl.txt       #
#                                                            #
# The WannierBerri code is hosted on GitHub:                 #
# https://github.com/stepan-tsirkin/wannier-berri            #
#                     written by                             #
#           Stepan Tsirkin, University of Zurich             #
#                                                            #
# ------------------------------------------------------------

import numpy as np

from .system import System_k
from .__finite_differences import find_shells, Derivative3D


[docs] class SystemKP(System_k): r""" A system to describe k.p Hamiltonians. Technically, it is concodered as a periodic system with k-vector limited to the box defined by the reciprocal lattice. a k-vector is always translated to have reduced coordinates between [-1/2,1/2) (In future : translate to the 1BZ for non-simple-cubic lattices) Parameters ----------- Ham : function The Hamiltonian - a function of 3D k-vector that returns a (num_waan x num_wann) Hermitean matrix derHam : function The cartesian k-derivative of the Hamiltonian - a function of 3D k-vector that returns a (num_waan x num_wann x 3) Hermitean (in mn) matrix. If not specified, it will be evaluated numerically from `Ham` with a finite-difference scheme using the `finite_diff_dk` parameter. der2Ham : function The cartesian second k-derivative of the Hamiltonian - a function of 3D k-vector that returns a (num_waan x num_wann x 3 x 3) Hermitean (in mn) matrix If not specified, it will be evaluated numerically from `derHam` with a finite-difference scheme using the `finite_diff_dk` parameter. der3Ham : function The cartesian second k-derivative of the Hamiltonian - a function of 3D k-vector that returns a (num_waan x num_wann x 3 x 3 x 3) Hermitean (in mn) matrix If not specified, it will be evaluated numerically from `der2Ham` with a finite-difference scheme using the `finite_diff_dk` parameter. kmax : float maximal k-vector (in :math:`\mathring{\rm A}^{-1}`) In this case the reciprocal lattice is cubic with size `2*kmax` real_lattice : array(3,3) the lattice vectors of the model (iif `kmax` is not set) recip_lattice : array(3,3) the reciprocal lattice vectors of the model (if 'kmax','real_lattice' are not set) k_vector_cartesian : bool if True, the k-vector in `Ham`, `derHar`, `der2Ham` is given in cartesian coordinates. if `False` - it is in reduced coordinates (Note : the derivatives are always assumed w.r.t. cartesian coordinates) finite_diff_dk : float defines the dk in taking derivatives (in fraction of the reciprocal lattice) Notes ----- * if derivatives of hamiltonian are not provided, they are computed with finite diifferences * internally, `self.Ham` and derivatives (`self.Ham_cart`, `self_derHam_cart` ...) accept k in reduced coordinated. * the derivatives are always assumed w.r.t. cartesian coordinates """ def __init__(self, Ham, derHam=None, der2Ham=None, der3Ham=None, kmax=1., real_lattice=None, recip_lattice=None, k_vector_cartesian=True, finite_diff_dk=1e-4, **parameters): if "name" not in parameters: parameters["name"] = "kp" super().__init__(force_internal_terms_only=True, **parameters) if kmax is not None: assert real_lattice is None, "kmax and real_lattice should not be set tigether" assert recip_lattice is None, "kmax and recip_lattice should not be set tigether" recip_lattice = np.eye(3) * 2 * kmax self.set_real_lattice(real_lattice=real_lattice, recip_lattice=recip_lattice) self.recip_lattice_inv = np.linalg.inv(self.recip_lattice) self.num_wann = Ham([0, 0, 0]).shape[0] self.k_to_1BZ = lambda k: (np.array(k) + 0.5) % 1 - 0.5 # in is not actually 1BZ, rather a box [-0.5:0.5), but for simple cubic its the same. # TODO : make a real 1BZ self.k_red2cart = lambda k: np.dot(k, self.recip_lattice) self.k_cart2red = lambda k: np.dot(k, self.recip_lattice_inv) if k_vector_cartesian: self.k_ham_from_red = lambda k: self.k_red2cart(self.k_to_1BZ(k)) else: self.k_ham_from_red = lambda k: np.array(self.k_to_1BZ(k)) self.Ham = lambda k: Ham(self.k_ham_from_red(k)) assert self.Ham([0, 0, 0]).shape == (self.num_wann, self.num_wann), f"the shape of Hamiltonian is {self.Ham([0, 0, 0]).shape} not a square ({self.num_wann})" self.wk, bki = find_shells(self.recip_lattice * finite_diff_dk) self.bk_red = bki * finite_diff_dk self.bk_cart = self.bk_red.dot(self.recip_lattice) if derHam is not None: self.derHam = lambda k: derHam(self.k_ham_from_red(k)) else: self.derHam = Derivative3D(self.Ham, bk_red=self.bk_red, bk_cart=self.bk_cart, wk=self.wk) assert self.derHam([0, 0, 0]).shape == (self.num_wann, self.num_wann, 3) if der2Ham is not None: self.der2Ham = lambda k: der2Ham(self.k_ham_from_red(k)) else: self.der2Ham = Derivative3D(self.derHam, bk_red=self.bk_red, bk_cart=self.bk_cart, wk=self.wk) assert self.der2Ham([0, 0, 0]).shape == (self.num_wann, self.num_wann, 3, 3) if der3Ham is not None: self.der3Ham = lambda k: der3Ham(self.k_ham_from_red(k)) else: self.der3Ham = Derivative3D(self.der2Ham, bk_red=self.bk_red, bk_cart=self.bk_cart, wk=self.wk) assert self.der3Ham([0, 0, 0]).shape == (self.num_wann, self.num_wann, 3, 3, 3) self.Ham_cart = lambda k: self.Ham(self.k_cart2red(k)) self.derHam_cart = lambda k: self.derHam(self.k_cart2red(k)) self.der2Ham_cart = lambda k: self.der2Ham(self.k_cart2red(k)) self.der3Ham_cart = lambda k: self.der3Ham(self.k_cart2red(k)) self.set_pointgroup() print("Number of wannier functions:", self.num_wann) @property def NKFFT_recommended(self): return np.array([1, 1, 1])