The Lattice class#
In version 2.0.0 of pythtb, we introduced the Lattice class to encapsulate all information about the lattice geometry, including lattice vectors, orbital positions, and periodicity. This modular approach allows for a separation of concerns, where the Lattice class handles geometric details, while the TBModel class focuses on the tight-binding model itself. This design enhances code readability, maintainability, and reusability.
from pythtb import Lattice
import numpy as np
Below, we demonstrate how to use the Lattice class to define a lattice and then use it to create a tight-binding model.
We start by defining the lattice vectors and orbital positions for a honeycomb lattice with two orbitals per unit cell. The lattice vectors are given by:
where \(a\) is the lattice constant, which we set to 1 for simplicity. The orbital positions are given in reduced coordinates as:
giving us a graphene-like structure.
lat_vecs = [[1, 0], [1 / 2, np.sqrt(3) / 2]]
orb_vecs = [[1 / 3, 1 / 3], [2 / 3, 2 / 3]]
We pass this information to the Lattice class to create a lattice object. Additionally, we specify which directions are periodic. In our case, both directions are periodic.
lat = Lattice(orb_vecs=orb_vecs, lat_vecs=lat_vecs, periodic_dirs=[0, 1])
We can see a report of the lattice object to verify its properties by printing it.
print(lat)
----------------------------------------
Lattice structure report
----------------------------------------
r-space dimension = 2
k-space dimension = 2
periodic directions = [0, 1]
number of orbitals = 2
Lattice vectors (Cartesian):
# 0 ===> [ 1.000, 0.000]
# 1 ===> [ 0.500, 0.866]
Volume of unit cell (Cartesian) = 0.866 [A^d]
Reciprocal lattice vectors (Cartesian):
# 0 ===> [ 6.283, -3.628]
# 1 ===> [ 0.000, 7.255]
Volume of reciprocal unit cell = 45.586 [A^-d]
Orbital vectors (Cartesian):
# 0 ===> [ 0.500, 0.289]
# 1 ===> [ 1.000, 0.577]
Orbital vectors (fractional):
# 0 ===> [ 0.333, 0.333]
# 1 ===> [ 0.667, 0.667]
----------------------------------------
If we want to get the positions of the orbitals in Cartesian coordinates, we can use the get_orb_vecs method of the Lattice class and set the cartesian argument to True.
lat.get_orb_vecs(cartesian=True)
array([[0.5 , 0.28867513],
[1. , 0.57735027]])
The Lattice class internally generates the reciprocal lattice vectors based on the provided lattice vectors and periodicity. We can access these reciprocal lattice vectors using the get_recip_lat_vecs method or the recip_lat_vecs attribute.
print(lat.get_recip_lat_vecs())
print(lat.recip_lat_vecs)
[[ 6.28318531 -3.62759873]
[ 0. 7.25519746]]
[[ 6.28318531 -3.62759873]
[ 0. 7.25519746]]
Let’s verigy that the reciprocal lattice vectors satisfy the orthogonality condition with the real-space lattice vectors.
overlap_mat = lat.lat_vecs @ lat.recip_lat_vecs.T
print(overlap_mat / (2 * np.pi))
[[ 1.00000000e+00 0.00000000e+00]
[-4.79476621e-17 1.00000000e+00]]
If we like, we can also get the volume of the unit cell in both real and reciprocal space. These are stored as attributes of the Lattice class.
print(lat.recip_volume, lat.cell_volume)
45.58575006211245 0.8660254037844386