Note
Go to the end to download the full example code.
The Fu-Kane Parity Criterion: Z2 from Inversion Eigenvalues#
L. Fu and C. Kane showed in 2007 that for a crystal with inversion symmetry the \(\mathbb{Z}_2\) invariant needs no Wilson loop at all: it is fixed by the parities \(\xi = \pm1\) of the occupied Kramers pairs at the four time-reversal-invariant momenta \(\Gamma_i\),
A band inversion at one \(\Gamma_i\) flips \(\delta_i\) and makes the insulator topological. The criterion led directly to the prediction of the 3D topological insulators (Bi1-xSbx, then Bi2Se3).
Here it is applied to the Bernevig-Hughes-Zhang (BHZ) model of HgTe
quantum wells: s-like and p-like orbitals of opposite parity on a square
lattice, with the mass term
\(d_z(\mathbf{k}) = m - 2(2 - \cos k_x - \cos k_y)\). The parity
product is compared, across the phase diagram, with the invariant from
the Wannier-centre flow (z2_invariant()),
which knows nothing about inversion: they agree everywhere.
import numpy as np
import matplotlib.pyplot as plt
from tbkit.lattice import Lattice
from tbkit.kspace import KSpace, PAULI
from tbkit.plot import Plot
from tbkit.system import System
# orbitals: (s, up), (s, down), (p, up), (p, down) -> two "sites" with spin
lat = Lattice(unit_cell=[{'tag': 's', 'r0': (0., 0.)}, {'tag': 'p', 'r0': (0., 0.)}],
prim_vec=[(1., 0.), (0., 1.)])
SZ = PAULI['z']
INVERSION = np.kron(np.diag([1., -1.]), np.eye(2)) # s even, p odd
TIME_REVERSAL = np.kron(np.eye(2), 1j * PAULI['y'])
def bhz(m, a=1.):
r'''
H(k) = sin kx tau_x s_z + sin ky tau_y + d_z(k) tau_z (tau: orbital, s: spin),
i.e. two time-reversed Chern insulators, one per spin.
'''
model = KSpace(lat, spin=True)
model.set_onsite({'s': (m - 4.) * PAULI['0'], 'p': -(m - 4.) * PAULI['0']})
for R in [(1, 0), (0, 1)]:
model.set_hopping([{'i': 0, 'j': 0, 'R': R, 't': PAULI['0']},
{'i': 1, 'j': 1, 'R': R, 't': -PAULI['0']}])
# tau_x s_z sin kx + tau_y sin ky between s and p
model.set_hopping([{'i': 0, 'j': 1, 'R': (1, 0), 't': -0.5j * a * SZ},
{'i': 0, 'j': 1, 'R': (-1, 0), 't': 0.5j * a * SZ},
{'i': 0, 'j': 1, 'R': (0, 1), 't': -0.5 * a * PAULI['0']},
{'i': 0, 'j': 1, 'R': (0, -1), 't': 0.5 * a * PAULI['0']}])
return model
The lattice#
The square lattice with its nearest-neighbour bonds. Each site holds an s and a p orbital, each with spin, and every bond carries a \(4\times4\) hopping matrix that couples them (not drawn).
patch = Lattice(unit_cell=[{'tag': 'a', 'r0': (0., 0.)}], prim_vec=lat.prim_vec)
patch.get_lattice(n1=6, n2=6)
vis = System(patch)
vis.set_hopping([{'n': 1, 't': 1.}])
fig_lat = Plot(vis).lattice(plt_hop=True, ms=10, figsize=(4, 4))

Both symmetries hold#
model = bhz(1.)
assert model.symmetry_error(INVERSION) < 1e-12
assert model.symmetry_error(TIME_REVERSAL, antiunitary=True) < 1e-12
print('Inversion and time reversal (T^2 = -1): class', model.tenfold_class(time_reversal=TIME_REVERSAL))
Inversion and time reversal (T^2 = -1): class AII
Parities at the TRIMs, and the phase diagram#
The occupied pair has the parity of the lower of the two orbitals, set by the sign of \(d_z\) at each TRIM: \(m\) at \(\Gamma\), \(m - 4\) at X and Y, \(m - 8\) at M. So \(\nu = 1\) for \(0 < m < 4\) and \(4 < m < 8\), and 0 otherwise.
masses = np.array([-1., 1., 3., 5., 7., 9.])
nu_parity = [bhz(m).parity_z2(INVERSION, [0, 1]) for m in masses]
nu_flow = [bhz(m).z2_invariant([0, 1], nk=40, nk_perp=31) for m in masses]
expected = [int(0 < m < 4 or 4 < m < 8) for m in masses]
print('m:', masses, '\n Fu-Kane parity:', nu_parity, '\n Wannier flow: ', nu_flow)
assert nu_parity == expected and nu_flow == expected
fig, ax = plt.subplots(figsize=(6, 3.4))
ax.plot(masses, nu_parity, 'ob', ms=9, label='Fu-Kane parity')
ax.plot(masses, nu_flow, 'xr', ms=9, mew=2, label='Wannier-centre flow')
ax.set_xlabel('$m$')
ax.set_ylabel(r'$\nu$')
ax.set_yticks([0, 1])
ax.legend()
ax.set_title('BHZ model: two routes to the same Z2 invariant')
fig.set_layout_engine('tight')

m: [-1. 1. 3. 5. 7. 9.]
Fu-Kane parity: [0, 1, 1, 1, 1, 0]
Wannier flow: [0, 1, 1, 1, 1, 0]
Total running time of the script: (0 minutes 0.097 seconds)