.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/topology/plot_mirror_chern_number.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_api_gallery_topology_plot_mirror_chern_number.py: Mirror Chern Numbers: a Topological Crystalline Insulator ================================================================ Two copies of a strong topological insulator make a trivial one, as far as time reversal can tell: the :math:`\mathbb{Z}_2` indices add modulo 2, so all four vanish, and the two surface Dirac cones can in principle annihilate. Teo, Fu and Kane (2008) pointed out that a crystal symmetry can still protect them. On a plane of the Brillouin zone left invariant by a mirror :math:`M` (here :math:`z\to-z`, the plane :math:`k_z = 0`), :math:`M` commutes with :math:`H(\mathbf{k})`, the bands split into the mirror sectors :math:`M = \pm i`, and each sector has its own Chern number. Their half-difference is the *mirror Chern number* .. math:: n_M = \frac{C_{+i} - C_{-i}}{2}\, , an integer, of which the :math:`\mathbb{Z}_2` index of the plane is only the parity. Hsieh, Lin, Liu, Duan, Lin and Fu (2012) predicted that SnTe is such a *topological crystalline insulator*, with :math:`n_M = 2` and trivial :math:`\mathbb{Z}_2` indices, and photoemission found its surface Dirac cones the same year (Tanaka et al.; Dziawa et al.; Xu et al.). The model: two copies of the cubic topological insulator of ``plot_3d_topological_insulator.py`` (:math:`H = m(\mathbf{k})\tau_z + \sum_i\sin k_i\,\tau_x\sigma_i`), coupled by a hopping :math:`\delta` between the copies that respects time reversal and the mirror :math:`M = i\tau_z\sigma_z`. :meth:`~tbkit.kspace.KSpace.mirror_chern_number` computes :math:`n_M`. .. GENERATED FROM PYTHON SOURCE LINES 32-84 .. code-block:: Python import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d.art3d import Line3DCollection from tbkit.lattice import Lattice from tbkit.kspace import KSpace, PAULI from tbkit.system import System cubic = [(1., 0., 0.), (0., 1., 0.), (0., 0., 1.)] SIGMA = [PAULI['x'], PAULI['y'], PAULI['z']] MIRROR = 1j * np.kron(np.diag([1., -1.]), PAULI['z']) # z -> -z: s even, p_z odd, i sigma_z on spin TIME_REVERSAL = np.kron(np.eye(2), 1j * PAULI['y']) def cubic_ti_hoppings(s, p): '''The topological insulator on orbitals s, p (each with spin).''' hops = [] for d in range(3): R = tuple(int(x) for x in np.eye(3, dtype=int)[d]) hops += [{'i': s, 'j': s, 'R': R, 't': PAULI['0']}, {'i': p, 'j': p, 'R': R, 't': -PAULI['0']}, {'i': s, 'j': p, 'R': R, 't': -0.5j * SIGMA[d]}, {'i': p, 'j': s, 'R': R, 't': -0.5j * SIGMA[d]}] return hops def single(M): lat = Lattice(unit_cell=[{'tag': t, 'r0': (0., 0., 0.)} for t in 'sp'], prim_vec=cubic) ti = KSpace(lat, spin=True) ti.set_hopping(cubic_ti_hoppings(0, 1)) ti.set_onsite({'s': (M - 6) * PAULI['0'], 'p': -(M - 6) * PAULI['0']}) return ti def doubled(M, delta=0.3): lat = Lattice(unit_cell=[{'tag': t, 'r0': (0., 0., 0.)} for t in 'spSP'], prim_vec=cubic) tci = KSpace(lat, spin=True) tci.set_hopping(cubic_ti_hoppings(0, 1) + cubic_ti_hoppings(2, 3) + [{'i': 0, 'j': 2, 'R': (0, 0, 0), 't': delta * PAULI['0']}, {'i': 1, 'j': 3, 'R': (0, 0, 0), 't': delta * PAULI['0']}]) tci.set_onsite({tag: sign * (M - 6) * PAULI['0'] for tag, sign in zip('spSP', (1, -1, 1, -1))}) return tci mirror_2 = np.kron(np.eye(2), MIRROR) tci = doubled(2.) assert tci.symmetry_error(np.kron(np.eye(2), TIME_REVERSAL), antiunitary=True) < 1e-12 for kz in (0., np.pi): ham = tci.get_ham([0.4, -1.1, kz]) assert np.allclose(mirror_2 @ ham, ham @ mirror_2) # M commutes with H on k_z = 0, pi ham = tci.get_ham([0.4, -1.1, 0.7]) assert not np.allclose(mirror_2 @ ham, ham @ mirror_2) # but not elsewhere .. GENERATED FROM PYTHON SOURCE LINES 85-91 The lattice ----------- The simple cubic lattice, here :math:`4\times4\times4` sites, with its nearest-neighbour bonds. Each site holds an s and a p orbital with spin (two such pairs in the doubled model), and every bond carries a hopping matrix that couples them (not drawn). .. GENERATED FROM PYTHON SOURCE LINES 91-105 .. code-block:: Python lat_vis = Lattice(unit_cell=[{'tag': 'a', 'r0': (0., 0., 0.)}], prim_vec=[(1., 0., 0.), (0., 1., 0.), (0., 0., 1.)]) lat_vis.get_lattice(4, 4, 4) vis = System(lat_vis) vis.set_hopping([{'n': 1, 't': 1.}]) pos = np.column_stack([lat_vis.coor[f] for f in 'xyz']) bonds = np.stack([pos[vis.hop['i'].astype(int)], pos[vis.hop['j'].astype(int)]], axis=1) fig_lat = plt.figure(figsize=(4.5, 4.5)) ax_lat = fig_lat.add_subplot(projection='3d') ax_lat.add_collection3d(Line3DCollection(bonds, colors='k', linewidths=1)) ax_lat.scatter(*pos.T, s=30, c='b', depthshade=False) ax_lat.set_aspect('equal') ax_lat.set_axis_off() .. image-sg:: /api/gallery/topology/images/sphx_glr_plot_mirror_chern_number_001.png :alt: plot mirror chern number :srcset: /api/gallery/topology/images/sphx_glr_plot_mirror_chern_number_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 106-111 A single topological insulator: nu is the parity of n_M ------------------------------------------------------------- On each mirror plane, :math:`\nu = n_M` modulo 2. For :math:`0 < M < 4` the band inversion at :math:`\Gamma` gives :math:`n_M = 1` on :math:`k_z = 0`, and nothing on :math:`k_z = \pi`. .. GENERATED FROM PYTHON SOURCE LINES 111-122 .. code-block:: Python for M in (-2., 2., 6.): ti = single(M) nu0, nu1, nu2, nu3 = ti.z2_indices_3d([0, 1], nk=60, nk_perp=31) planes = {0.: (nu0 + nu3) % 2, 0.5: nu3} # nu(k_z = 0), nu(k_z = pi) for k_fixed, nu in planes.items(): n_m = ti.mirror_chern_number(MIRROR, [0, 1], k_fixed=k_fixed) assert np.isclose(n_m, np.round(n_m)) and int(np.round(n_m)) % 2 == nu print('M = {:4.1f}: indices ({}; {}{}{}), n_M(k_z = 0) = {:+d}'.format( M, nu0, nu1, nu2, nu3, int(np.round(ti.mirror_chern_number(MIRROR, [0, 1]))))) .. rst-class:: sphx-glr-script-out .. code-block:: none M = -2.0: indices (0; 000), n_M(k_z = 0) = +0 M = 2.0: indices (1; 000), n_M(k_z = 0) = +1 M = 6.0: indices (0; 111), n_M(k_z = 0) = -1 .. GENERATED FROM PYTHON SOURCE LINES 123-125 Two copies: Z2 says trivial, the mirror Chern number does not ------------------------------------------------------------------ .. GENERATED FROM PYTHON SOURCE LINES 125-136 .. code-block:: Python occupied = [0, 1, 2, 3] indices = tci.z2_indices_3d(occupied, nk=60, nk_perp=31) n_m = tci.mirror_chern_number(mirror_2, occupied) n_m_pi = tci.mirror_chern_number(mirror_2, occupied, k_fixed=0.5) print('Two coupled copies: Z2 indices {}, n_M = {:.3f} on k_z = 0, {:.3f} on k_z = pi.' .format(indices, n_m, n_m_pi)) assert indices == (0, 0, 0, 0) assert np.isclose(n_m, 2.) and np.isclose(n_m_pi, 0., atol=1e-8) assert np.isclose(doubled(-2.).mirror_chern_number(mirror_2, occupied), 0., atol=1e-8) .. rst-class:: sphx-glr-script-out .. code-block:: none Two coupled copies: Z2 indices (0, 0, 0, 0), n_M = 2.000 on k_z = 0, 0.000 on k_z = pi. .. GENERATED FROM PYTHON SOURCE LINES 137-145 The surface states protected by the mirror --------------------------------------------- The (100) surface keeps the mirror :math:`z\to-z`, and its mirror line :math:`k_z = 0` carries :math:`|n_M| = 2` pairs of surface states across the bulk gap: two Dirac cones at :math:`\bar\Gamma`, at the energies :math:`\pm\delta` set by the coupling, whose branches cross at :math:`E = 0` at :math:`k_y = \pm\delta`. The bulk gap, :math:`|E| < 0.7`, is empty, and the doubled trivial insulator has no surface state. .. GENERATED FROM PYTHON SOURCE LINES 145-170 .. code-block:: Python kys = np.linspace(-np.pi, np.pi, 121) path = np.array([[0., ky, 0.] for ky in kys]) energies = np.linspace(-2.5, 2.5, 201) eta = 0.02 in_gap = np.abs(energies) < 0.5 surface = tci.surface_spectral_function(path, energies, direction=0, eta=eta) bulk = tci.surface_spectral_function(path, energies, direction=0, eta=eta, bulk=True) surface_triv = doubled(-2.).surface_spectral_function(path, energies, direction=0, eta=eta) assert bulk[:, in_gap].max() < 0.1 and surface_triv[:, in_gap].max() < 0.1 col = surface[:, np.argmin(np.abs(energies))] peaks = [i for i in range(1, len(col) - 1) if col[i] > max(col[i - 1], col[i + 1]) and col[i] > 1.] print('E = 0 on the (100) surface: surface states at k_y =', np.round(kys[peaks], 3)) assert len(peaks) == 2 and np.allclose(np.abs(kys[peaks]), 0.3, atol=0.03) fig, axes = plt.subplots(1, 2, figsize=(10, 4.2), sharey=True) for ax, spec, title in zip(axes, (surface, surface_triv), (r'$M = 2$: $n_M = 2$, $\mathbb{Z}_2$ trivial', r'$M = -2$: $n_M = 0$')): ax.pcolormesh(kys, energies, np.log10(spec.T + 1e-3), cmap='magma', vmin=-2, vmax=1.5, shading='auto') ax.set_xlabel(r'$k_y$ (mirror line $k_z = 0$)') ax.set_title(title) axes[0].set_ylabel('$E$') fig.suptitle(r'(100) surface spectral function of two coupled topological insulators') fig.set_layout_engine('tight') .. image-sg:: /api/gallery/topology/images/sphx_glr_plot_mirror_chern_number_002.png :alt: (100) surface spectral function of two coupled topological insulators, $M = 2$: $n_M = 2$, $\mathbb{Z}_2$ trivial, $M = -2$: $n_M = 0$ :srcset: /api/gallery/topology/images/sphx_glr_plot_mirror_chern_number_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none E = 0 on the (100) surface: surface states at k_y = [-0.314 0.314] .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 6.519 seconds) .. _sphx_glr_download_api_gallery_topology_plot_mirror_chern_number.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_mirror_chern_number.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_mirror_chern_number.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_mirror_chern_number.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_