Note
Go to the end to download the full example code.
A Topological Flat Band on the Kagome Lattice#
The kagome lattice’s flat band (see Flat-Band Lattices: Kagome and Lieb) isn’t isolated: at zero field it touches the middle dispersive band exactly at \(\Gamma\) (a symmetry-protected degeneracy, both at \(E=-2t\)). Making the nearest-neighbor hopping complex – the same phase \(t e^{i\phi}\) on every bond, regardless of which of the lattice’s two triangle orientations it belongs to – breaks the mirror symmetries protecting that degeneracy (while leaving the threefold rotation intact) and opens a genuine gap across the whole Brillouin zone. The resulting lower band is no longer exactly flat, but it stays topologically nontrivial: a Chern insulator with no net magnetic field, built entirely from a real, physically motivated mechanism – the scalar spin chirality of a canted magnetic texture on the kagome lattice acts, for the itinerant electrons, exactly like this complex hopping (Ohgushi, Murakami, and Nagaosa, 2000).
import numpy as np
import matplotlib.pyplot as plt
import tbkit.lattices as lattices
from tbkit.kspace import KSpace, reciprocal_vectors
from tbkit.system import System
from tbkit.plot import Plot
lat = lattices.kagome()
t1 = 1.
b1, b2 = (np.array(v) for v in reciprocal_vectors(lat.prim_vec))
Gamma, K, M_pt = np.zeros(2), (b1 - b2) / 3, b1 / 2
def kagome_chiral(phi):
'''Kagome lattice, nearest-neighbor hopping t1*exp(i*phi) on every bond.'''
kag = KSpace(lat)
t = t1 * np.exp(1j * phi)
kag.set_hopping([{'i': 0, 'j': 1, 'R': (0, 0), 't': t},
{'i': 0, 'j': 1, 'R': (-1, 0), 't': t},
{'i': 0, 'j': 2, 'R': (0, 0), 't': t},
{'i': 0, 'j': 2, 'R': (0, -1), 't': t},
{'i': 1, 'j': 2, 'R': (0, 0), 't': t},
{'i': 1, 'j': 2, 'R': (1, -1), 't': t}])
return kag
The kagome lattice#
Corner-sharing triangles: three sites per unit cell (‘a’, ‘b’ and ‘c’, one per colour). The complex phase below is put on every one of the nearest-neighbor bonds drawn here.
patch = lattices.kagome()
patch.get_lattice(n1=4, n2=3)
vis = System(patch)
vis.set_hopping([{'n': 1, 't': 1.}])
fig_lat = Plot(vis).lattice(plt_hop=True, ms=12, figsize=(5.5, 4.5))

phi=0: the flat band touches the middle band at Gamma#
kag0 = kagome_chiral(phi=0.)
en_gamma_0 = np.sort(np.linalg.eigvalsh(kag0.get_ham(Gamma)))
print('phi=0, E(Gamma) = {} (bottom two exactly degenerate at -2t).'.format(np.round(en_gamma_0, 6)))
assert np.isclose(en_gamma_0[0], en_gamma_0[1], atol=1e-10)
phi=0, E(Gamma) = [-2. -2. 4.] (bottom two exactly degenerate at -2t).
phi != 0: a real gap opens across the whole Brillouin zone#
phi = 0.3
kag = kagome_chiral(phi)
nk = 60
ks = [(i / nk) * b1 + (j / nk) * b2 for i in range(nk) for j in range(nk)]
en_mesh = np.sort(np.array([np.linalg.eigvalsh(kag.get_ham(k)) for k in ks]), axis=1)
gap01 = en_mesh[:, 1].min() - en_mesh[:, 0].max()
gap12 = en_mesh[:, 2].min() - en_mesh[:, 1].max()
bandwidth0 = en_mesh[:, 0].max() - en_mesh[:, 0].min()
print('phi={}: gap below band 0 -> band 1 = {:.4f}, band 1 -> band 2 = {:.4f}, '
'band 0 bandwidth = {:.4f}.'.format(phi, gap01, gap12, bandwidth0))
assert gap01 > 0.3
assert gap12 > 0.3
phi=0.3: gap below band 0 -> band 1 = 0.3458, band 1 -> band 2 = 0.3458, band 0 bandwidth = 0.3458.
Chern numbers: -1, 0, +1#
Exact flatness and a nonzero Chern number cannot coexist without further fine-tuning (this band’s flatness ratio, gap/bandwidth, is only about 1 here – the 2011 papers that proposed nearly-flat Chern bands as a lattice route to fractional Chern insulators pushed this ratio far higher via additional further-neighbor terms). What does survive intact is the topology.
chern = [kag.chern_number(bands=[n], nk=60) for n in range(3)]
print('Chern numbers (bottom, middle, top): {}'.format(np.round(chern, 4)))
assert np.isclose(chern[0], -1., atol=1e-2)
assert np.isclose(chern[1], 0., atol=1e-2)
assert np.isclose(chern[2], 1., atol=1e-2)
assert np.isclose(sum(chern), 0., atol=1e-2)
print('Bottom band is a C=-1 Chern insulator; the three bands sum to C=0. OK')
Chern numbers (bottom, middle, top): [-1. 0. 1.]
Bottom band is a C=-1 Chern insulator; the three bands sum to C=0. OK
Berry curvature of the isolated lower band#
curv = kag.berry_curvature(bands=[0], nk=60)
fig, ax = plt.subplots()
im = ax.imshow(curv.T, origin='lower', extent=[0, 1, 0, 1], aspect='auto', cmap='RdBu')
ax.set_xlabel('$k_1$ (fractional)')
ax.set_ylabel('$k_2$ (fractional)')
ax.set_title('Berry curvature of the lower (Chern) band')
fig.colorbar(im, ax=ax)

<matplotlib.colorbar.Colorbar object at 0x1162b34d0>
Band structure: flat-and-touching vs. gapped-and-topological#
fig2, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5), sharey=True)
for axis, model, title in [(ax1, kag0, r'$\phi=0$: flat band touches band 1'),
(ax2, kag, r'$\phi={:.1f}$: gapped, $C=-1$'.format(phi))]:
ks_dist, en = model.k_path([Gamma, K, M_pt, Gamma], nk=60)
for n in range(3):
axis.plot(ks_dist, en[:, n], 'b')
axis.set_title(title)
axis.set_xlabel('$k$')
ax1.set_ylabel('$E$')
fig2.tight_layout()

Total running time of the script: (0 minutes 0.498 seconds)