tbkit 0.4.1__tar.gz → 0.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tbkit-0.4.1/tbkit.egg-info → tbkit-0.4.2}/PKG-INFO +8 -2
- {tbkit-0.4.1 → tbkit-0.4.2}/README.md +7 -1
- {tbkit-0.4.1 → tbkit-0.4.2}/pyproject.toml +1 -1
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/__init__.py +1 -1
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/error_handling.py +10 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/kspace.py +96 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/transport.py +80 -19
- {tbkit-0.4.1 → tbkit-0.4.2/tbkit.egg-info}/PKG-INFO +8 -2
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit.egg-info/SOURCES.txt +1 -0
- tbkit-0.4.2/tests/test_surface_spectral.py +182 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/LICENSE +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/setup.cfg +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/bdg.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/bridges.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/dos.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/exceptional.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/floquet.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/graphene.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/higher_order.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/io.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/kpm.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/lattice.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/lattices.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/meanfield.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/moire.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/neighbours.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/occupation.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/optics.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/orbital.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/plot.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/propagation.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/save.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/slater_koster.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit/system.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit.egg-info/dependency_links.txt +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit.egg-info/requires.txt +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tbkit.egg-info/top_level.txt +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_bridges.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_correlations.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_dos.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_error_handling.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_error_handling_structures.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_exceptional.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_floquet.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_graphene.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_green_occupation.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_hall.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_higher_order.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_interactions.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_io.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_kpm.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_kspace.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_large_lattices.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_lattice.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_lattices.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_magnetic.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_moire.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_neighbours.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_non_hermitian_bands.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_optics.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_orbitals.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_plot.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_propagation.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_regressions.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_save.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_system.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_three_d.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_topology.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_transport.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_transport_response.py +0 -0
- {tbkit-0.4.1 → tbkit-0.4.2}/tests/test_wannier90.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tbkit
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: A Python package to build and solve Tight-Binding models.
|
|
5
5
|
Author-email: Charles Poli <cpoli374@gmail.com>
|
|
6
6
|
Maintainer-email: cpoli <cpoli374@gmail.com>
|
|
@@ -97,6 +97,9 @@ topology alongside superconductivity.
|
|
|
97
97
|
Kane-Mele) and Zeeman splitting.
|
|
98
98
|
* **Edge states**: cut a ribbon (periodic in one direction, finite in the
|
|
99
99
|
other) out of any periodic model, to see edge/surface physics.
|
|
100
|
+
* **Surface spectral functions** of semi-infinite crystals (iterative
|
|
101
|
+
surface Green's function): edge and surface states, e.g. the surface
|
|
102
|
+
Dirac cone of a 3D topological insulator, without a finite slab.
|
|
100
103
|
* **Density of states**, Gaussian- or Lorentzian-broadened, from either a
|
|
101
104
|
real-space spectrum or a Brillouin-zone mesh.
|
|
102
105
|
* A small library of ready-made lattices (chain, square, triangular,
|
|
@@ -116,7 +119,7 @@ topology alongside superconductivity.
|
|
|
116
119
|
|----------------------------|---------------------------------------------------------|
|
|
117
120
|
| `tbkit.Lattice` | Define and manipulate site positions and sublattices. |
|
|
118
121
|
| `tbkit.System` | Build the real-space Hamiltonian from a `Lattice` and solve it. |
|
|
119
|
-
| `tbkit.KSpace` | Build and solve the Bloch Hamiltonian of a periodic `Lattice`; bands, Berry curvature/Chern numbers, anomalous and spin Hall conductivities, ribbons, DOS. |
|
|
122
|
+
| `tbkit.KSpace` | Build and solve the Bloch Hamiltonian of a periodic `Lattice`; bands, Berry curvature/Chern numbers, anomalous and spin Hall conductivities, ribbons, surface spectral functions, DOS. |
|
|
120
123
|
| `tbkit.Plot` | Plot lattices, spectra, eigenstates, and the density of states. |
|
|
121
124
|
| `tbkit.Propagation` | Time-evolve a wavepacket. |
|
|
122
125
|
| `tbkit.Save` | Save figures/animations to disk. |
|
|
@@ -292,6 +295,7 @@ thumbnailed example gallery under `docs/source/api/gallery/`.
|
|
|
292
295
|
| [`topology/plot_tknn_hofstadter.py`](examples/topology/plot_tknn_hofstadter.py) | TKNN: Chern numbers of the Hofstadter bands from magnetic supercells, and the Diophantine equation. |
|
|
293
296
|
| [`topology/plot_kane_mele_z2.py`](examples/topology/plot_kane_mele_z2.py) | The Kane-Mele Z2 invariant from Wannier-centre flow. |
|
|
294
297
|
| [`topology/plot_fu_kane_parity.py`](examples/topology/plot_fu_kane_parity.py) | The Fu-Kane parity criterion on the BHZ model, checked against the Wannier flow. |
|
|
298
|
+
| [`topology/plot_3d_topological_insulator.py`](examples/topology/plot_3d_topological_insulator.py) | 3D topological insulators: the strong index and the surface Dirac cone, from the surface spectral function of a semi-infinite crystal. |
|
|
295
299
|
| [`topology/plot_quantum_geometry.py`](examples/topology/plot_quantum_geometry.py) | The quantum metric and Berry curvature of a Bloch band. |
|
|
296
300
|
| [`topology/plot_tenfold_way.py`](examples/topology/plot_tenfold_way.py) | Symmetry classes of tight-binding models: the tenfold way. |
|
|
297
301
|
| [`topology/plot_local_chern_marker.py`](examples/topology/plot_local_chern_marker.py) | The local Chern marker of a finite, disordered Haldane flake. |
|
|
@@ -345,6 +349,8 @@ Rendered docs (tutorial, API reference, example gallery): https://cpoli.github.i
|
|
|
345
349
|
each one linked to the corresponding **tbkit** functionality and example
|
|
346
350
|
above.
|
|
347
351
|
* `docs/source/tbkit.rst` -- the API reference (auto-generated from docstrings).
|
|
352
|
+
* [`ROADMAP.md`](ROADMAP.md) -- what is planned next, and what tbkit
|
|
353
|
+
does not do yet (compared with Kwant and PythTB).
|
|
348
354
|
|
|
349
355
|
Build the HTML docs with `cd docs && make html` (output in `docs/build/html`).
|
|
350
356
|
|
|
@@ -69,6 +69,9 @@ topology alongside superconductivity.
|
|
|
69
69
|
Kane-Mele) and Zeeman splitting.
|
|
70
70
|
* **Edge states**: cut a ribbon (periodic in one direction, finite in the
|
|
71
71
|
other) out of any periodic model, to see edge/surface physics.
|
|
72
|
+
* **Surface spectral functions** of semi-infinite crystals (iterative
|
|
73
|
+
surface Green's function): edge and surface states, e.g. the surface
|
|
74
|
+
Dirac cone of a 3D topological insulator, without a finite slab.
|
|
72
75
|
* **Density of states**, Gaussian- or Lorentzian-broadened, from either a
|
|
73
76
|
real-space spectrum or a Brillouin-zone mesh.
|
|
74
77
|
* A small library of ready-made lattices (chain, square, triangular,
|
|
@@ -88,7 +91,7 @@ topology alongside superconductivity.
|
|
|
88
91
|
|----------------------------|---------------------------------------------------------|
|
|
89
92
|
| `tbkit.Lattice` | Define and manipulate site positions and sublattices. |
|
|
90
93
|
| `tbkit.System` | Build the real-space Hamiltonian from a `Lattice` and solve it. |
|
|
91
|
-
| `tbkit.KSpace` | Build and solve the Bloch Hamiltonian of a periodic `Lattice`; bands, Berry curvature/Chern numbers, anomalous and spin Hall conductivities, ribbons, DOS. |
|
|
94
|
+
| `tbkit.KSpace` | Build and solve the Bloch Hamiltonian of a periodic `Lattice`; bands, Berry curvature/Chern numbers, anomalous and spin Hall conductivities, ribbons, surface spectral functions, DOS. |
|
|
92
95
|
| `tbkit.Plot` | Plot lattices, spectra, eigenstates, and the density of states. |
|
|
93
96
|
| `tbkit.Propagation` | Time-evolve a wavepacket. |
|
|
94
97
|
| `tbkit.Save` | Save figures/animations to disk. |
|
|
@@ -264,6 +267,7 @@ thumbnailed example gallery under `docs/source/api/gallery/`.
|
|
|
264
267
|
| [`topology/plot_tknn_hofstadter.py`](examples/topology/plot_tknn_hofstadter.py) | TKNN: Chern numbers of the Hofstadter bands from magnetic supercells, and the Diophantine equation. |
|
|
265
268
|
| [`topology/plot_kane_mele_z2.py`](examples/topology/plot_kane_mele_z2.py) | The Kane-Mele Z2 invariant from Wannier-centre flow. |
|
|
266
269
|
| [`topology/plot_fu_kane_parity.py`](examples/topology/plot_fu_kane_parity.py) | The Fu-Kane parity criterion on the BHZ model, checked against the Wannier flow. |
|
|
270
|
+
| [`topology/plot_3d_topological_insulator.py`](examples/topology/plot_3d_topological_insulator.py) | 3D topological insulators: the strong index and the surface Dirac cone, from the surface spectral function of a semi-infinite crystal. |
|
|
267
271
|
| [`topology/plot_quantum_geometry.py`](examples/topology/plot_quantum_geometry.py) | The quantum metric and Berry curvature of a Bloch band. |
|
|
268
272
|
| [`topology/plot_tenfold_way.py`](examples/topology/plot_tenfold_way.py) | Symmetry classes of tight-binding models: the tenfold way. |
|
|
269
273
|
| [`topology/plot_local_chern_marker.py`](examples/topology/plot_local_chern_marker.py) | The local Chern marker of a finite, disordered Haldane flake. |
|
|
@@ -317,6 +321,8 @@ Rendered docs (tutorial, API reference, example gallery): https://cpoli.github.i
|
|
|
317
321
|
each one linked to the corresponding **tbkit** functionality and example
|
|
318
322
|
above.
|
|
319
323
|
* `docs/source/tbkit.rst` -- the API reference (auto-generated from docstrings).
|
|
324
|
+
* [`ROADMAP.md`](ROADMAP.md) -- what is planned next, and what tbkit
|
|
325
|
+
does not do yet (compared with Kwant and PythTB).
|
|
320
326
|
|
|
321
327
|
Build the HTML docs with `cd docs && make html` (output in `docs/build/html`).
|
|
322
328
|
|
|
@@ -1546,6 +1546,16 @@ def lead_direction(direction):
|
|
|
1546
1546
|
raise ValueError('\n\nParameter direction must be +1 or -1.\n')
|
|
1547
1547
|
|
|
1548
1548
|
|
|
1549
|
+
def surface_side(side):
|
|
1550
|
+
'''
|
|
1551
|
+
Check parameter *side* of *KSpace.surface_spectral_function*: +1 or -1.
|
|
1552
|
+
|
|
1553
|
+
:raises ValueError: Parameter side must be +1 or -1.
|
|
1554
|
+
'''
|
|
1555
|
+
if isinstance(side, bool) or side not in (1, -1):
|
|
1556
|
+
raise ValueError('\n\nParameter side must be +1 or -1.\n')
|
|
1557
|
+
|
|
1558
|
+
|
|
1549
1559
|
def nearest_cells(n):
|
|
1550
1560
|
'''
|
|
1551
1561
|
Check that a lead hopping reaches at most the neighbouring cells.
|
|
@@ -13,6 +13,7 @@ import tbkit.dos as dos
|
|
|
13
13
|
import tbkit.occupation as occupation
|
|
14
14
|
import tbkit.neighbours as neighbours
|
|
15
15
|
from tbkit.lattice import Lattice
|
|
16
|
+
from tbkit.transport import _green_surface_bulk
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
PI = np.pi
|
|
@@ -1881,6 +1882,101 @@ class KSpace():
|
|
|
1881
1882
|
return np.array([[np.trace(p0 @ dp[mu] @ dp[nu]) for nu in range(self.dim)]
|
|
1882
1883
|
for mu in range(self.dim)])
|
|
1883
1884
|
|
|
1885
|
+
def surface_spectral_function(
|
|
1886
|
+
self, ks: ArrayLike, energies: ArrayLike, direction: int, side: int = 1,
|
|
1887
|
+
eta: float = 1e-2, bulk: bool = False, max_iter: int = 10000,
|
|
1888
|
+
) -> NDArray[np.float64]:
|
|
1889
|
+
r'''
|
|
1890
|
+
Get the spectral function of the surface of a semi-infinite crystal,
|
|
1891
|
+
|
|
1892
|
+
.. math::
|
|
1893
|
+
|
|
1894
|
+
A_s(\mathbf{k}_\parallel, E) = -\frac{1}{\pi}\,
|
|
1895
|
+
\mathrm{Im}\,\mathrm{Tr}\, G_{00}(\mathbf{k}_\parallel, E + i\eta)\, ,
|
|
1896
|
+
|
|
1897
|
+
with :math:`G_{00}` the Green's function of the outermost unit cell:
|
|
1898
|
+
the crystal fills the cells :math:`n\,\mathbf{a}_d`,
|
|
1899
|
+
:math:`n = 0, 1, 2, \dots` along the primitive vector
|
|
1900
|
+
:math:`\mathbf{a}_d` (``lat.prim_vec[direction]``), times *side*, and
|
|
1901
|
+
is periodic along the others. It comes from the Lopez Sancho-Rubio
|
|
1902
|
+
decimation (see *transport.surface_green*) of the chain of principal
|
|
1903
|
+
layers (as many cells as the longest hopping along
|
|
1904
|
+
:math:`\mathbf{a}_d` spans), so the crystal is truly semi-infinite: no
|
|
1905
|
+
finite slab, and no states of the opposite surface. It is the
|
|
1906
|
+
tight-binding picture of an ARPES map -- surface states (edge states,
|
|
1907
|
+
in 2D; the end state of a 1D chain) show up as sharp lines inside the
|
|
1908
|
+
bulk gaps. With *bulk*, the same quantity for a unit cell deep inside
|
|
1909
|
+
the crystal: the bulk bands projected on the surface Brillouin zone.
|
|
1910
|
+
|
|
1911
|
+
:param ks: Real array, shape (nk, dim). k-points, in the coordinates
|
|
1912
|
+
of *get_ham* (e.g. from a *k_path* of the surface Brillouin zone).
|
|
1913
|
+
Only :math:`\mathbf{k}_\parallel` matters: the result does not
|
|
1914
|
+
depend on the component along the reciprocal vector
|
|
1915
|
+
:math:`\mathbf{b}_d`.
|
|
1916
|
+
:param energies: Real number or real array. Energies :math:`E`.
|
|
1917
|
+
:param direction: Integer, between 0 and dim-1. The primitive vector
|
|
1918
|
+
normal to the surface (the one along which the crystal is
|
|
1919
|
+
semi-infinite).
|
|
1920
|
+
:param side: +1 or -1. Default value 1. The crystal extends along
|
|
1921
|
+
:math:`+\mathbf{a}_d` (the surface faces :math:`-\mathbf{a}_d`) or
|
|
1922
|
+
along :math:`-\mathbf{a}_d` (the opposite surface).
|
|
1923
|
+
:param eta: Positive real. Default value 1e-2. Broadening: the
|
|
1924
|
+
width of the lines, and the decay length (about :math:`v/\eta`
|
|
1925
|
+
cells) over which the bulk is resolved.
|
|
1926
|
+
:param bulk: Boolean. Default value False. If True, the spectral
|
|
1927
|
+
function of a bulk unit cell instead of the surface one.
|
|
1928
|
+
:param max_iter: Positive integer. Default value 10000. Maximum
|
|
1929
|
+
number of decimation steps.
|
|
1930
|
+
|
|
1931
|
+
:returns:
|
|
1932
|
+
* **A** -- Real ndarray, shape (nk, len(energies)).
|
|
1933
|
+
|
|
1934
|
+
Example usage::
|
|
1935
|
+
|
|
1936
|
+
# the (001) surface of a 3D model, along a path of the surface zone
|
|
1937
|
+
A = ks.surface_spectral_function(k_path, np.linspace(-1, 1, 201), direction=2)
|
|
1938
|
+
'''
|
|
1939
|
+
error_handling.no_overlap(self._overlap_hop)
|
|
1940
|
+
ks = np.atleast_2d(np.asarray(ks, dtype='f8'))
|
|
1941
|
+
error_handling.ks(ks, self.dim)
|
|
1942
|
+
error_handling.frequencies(energies, 'energies')
|
|
1943
|
+
energies = np.atleast_1d(np.asarray(energies, dtype='f8'))
|
|
1944
|
+
error_handling.direction(direction, self.dim)
|
|
1945
|
+
error_handling.surface_side(side)
|
|
1946
|
+
error_handling.positive_real(eta, 'eta')
|
|
1947
|
+
error_handling.boolean(bulk, 'bulk')
|
|
1948
|
+
error_handling.positive_int(max_iter, 'max_iter')
|
|
1949
|
+
# H_m(k): the hoppings from a cell to the cell m a_d away, with the
|
|
1950
|
+
# phase of their in-plane part only (independent of k along b_d)
|
|
1951
|
+
a_dir = np.array(self.lat.prim_vec[direction], dtype='f8')
|
|
1952
|
+
layers = {}
|
|
1953
|
+
for (i, j, n, t), (_, _, R, _) in zip(self._hop_cells(), self._hop):
|
|
1954
|
+
layers.setdefault(n[direction], []).append((i, j, R - n[direction] * a_dir, t))
|
|
1955
|
+
k_cart = ks @ self.k_basis.T
|
|
1956
|
+
blocks = {m: self._bloch_sum(hops, k_cart)[0] for m, hops in layers.items()}
|
|
1957
|
+
blocks[0] = blocks.get(0, 0.) + (np.diag(self.onsite) + self._onsite_offdiag)[None]
|
|
1958
|
+
width = max([abs(m) for m in layers] + [1])
|
|
1959
|
+
norb, nk = self.norb, len(ks)
|
|
1960
|
+
|
|
1961
|
+
def layer(shift):
|
|
1962
|
+
# block (p, q) couples cell p of a principal layer to cell q of
|
|
1963
|
+
# the layer *shift* cells further into the crystal
|
|
1964
|
+
out = np.zeros((nk, width, norb, width, norb), 'c16')
|
|
1965
|
+
for p in range(width):
|
|
1966
|
+
for q in range(width):
|
|
1967
|
+
m = side * (q - p + shift)
|
|
1968
|
+
if m in blocks:
|
|
1969
|
+
out[:, p, :, q, :] = blocks[m]
|
|
1970
|
+
return out.reshape(nk, width * norb, width * norb)
|
|
1971
|
+
h0, alpha, beta = layer(0), layer(width), layer(-width)
|
|
1972
|
+
spec = np.empty((nk, len(energies)))
|
|
1973
|
+
for n in range(nk):
|
|
1974
|
+
gs, gb = _green_surface_bulk(energies + 1j * eta, h0[n], alpha[n], beta[n], 1e-12,
|
|
1975
|
+
max_iter, 'surface_spectral_function')
|
|
1976
|
+
g = gb if bulk else gs
|
|
1977
|
+
spec[n] = -np.trace(g[:, :norb, :norb], axis1=1, axis2=2).imag / PI
|
|
1978
|
+
return spec
|
|
1979
|
+
|
|
1884
1980
|
def plot_dos(
|
|
1885
1981
|
self,
|
|
1886
1982
|
nk: int | tuple[int, int] = 30,
|
|
@@ -77,33 +77,94 @@ def surface_green(
|
|
|
77
77
|
error_handling.positive_real(eta, 'eta')
|
|
78
78
|
error_handling.positive_real(tol, 'tol')
|
|
79
79
|
error_handling.positive_int(max_iter, 'max_iter')
|
|
80
|
+
gs, _ = _green_surface_bulk(np.array([energy + 1j * eta]), h0, v, v.conj().T, tol, max_iter,
|
|
81
|
+
'surface_green')
|
|
82
|
+
return gs[0]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _green_surface_bulk(
|
|
86
|
+
z: NDArray[np.complex128], h0: NDArray[np.complex128], alpha: NDArray[np.complex128],
|
|
87
|
+
beta: NDArray[np.complex128], tol: float, max_iter: int, name: str,
|
|
88
|
+
) -> tuple[NDArray[np.complex128], NDArray[np.complex128]]:
|
|
89
|
+
r'''
|
|
90
|
+
Private function. The surface and bulk Green's functions of one cell
|
|
91
|
+
of the semi-infinite chain of *_decimation* (*h0*, *alpha*, *beta* of
|
|
92
|
+
shape (m, m)) at the complex energies *z*, shapes (nz, m, m).
|
|
93
|
+
|
|
94
|
+
The first decimation step inverts :math:`z - h_0`: at an energy equal to
|
|
95
|
+
an eigenvalue of :math:`h_0` (E = 0 for a plain chain) that is
|
|
96
|
+
:math:`\sim1/\eta`, and the precision is lost. Regrouping n = 1, 2 or 3
|
|
97
|
+
cells into one (the same chain) moves those energies: at each energy,
|
|
98
|
+
the best-conditioned grouping is used.
|
|
99
|
+
'''
|
|
80
100
|
m = len(h0)
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
# Scaling cell n by r**n is a similarity transform that leaves the
|
|
102
|
+
# Green's function of every cell unchanged: balancing the couplings of a
|
|
103
|
+
# non-reciprocal chain keeps the renormalized ones from overflowing
|
|
104
|
+
# (r = 1 when beta = alpha^dagger).
|
|
105
|
+
n_a, n_b = np.linalg.norm(alpha), np.linalg.norm(beta)
|
|
106
|
+
if n_a > 0 and n_b > 0:
|
|
107
|
+
r = np.sqrt(n_b / n_a)
|
|
108
|
+
alpha, beta = alpha * r, beta / r
|
|
109
|
+
groups, best, choice = [], None, np.zeros(len(z), int)
|
|
110
|
+
for c, n in enumerate((1, 2, 3)):
|
|
111
|
+
hn = (np.kron(np.eye(n), h0) + np.kron(np.eye(n, k=1), alpha)
|
|
112
|
+
+ np.kron(np.eye(n, k=-1), beta))
|
|
113
|
+
an = np.kron(np.eye(n, k=1 - n), alpha)
|
|
114
|
+
bn = np.kron(np.eye(n, k=n - 1), beta)
|
|
115
|
+
groups.append((hn, an, bn))
|
|
116
|
+
smin = np.linalg.svd(z[:, None, None] * np.eye(n * m)[None] - hn, compute_uv=False)[:, -1]
|
|
117
|
+
if best is None:
|
|
118
|
+
best = smin
|
|
119
|
+
else:
|
|
120
|
+
better = smin > best * (1. + 1e-12)
|
|
121
|
+
choice[better], best = c, np.where(better, smin, best)
|
|
122
|
+
gs, gb = np.empty((len(z), m, m), 'c16'), np.empty((len(z), m, m), 'c16')
|
|
123
|
+
for c, (hn, an, bn) in enumerate(groups):
|
|
124
|
+
sel = choice == c
|
|
125
|
+
if np.any(sel):
|
|
126
|
+
s_, b_ = _decimation(z[sel], hn, an, bn, tol, max_iter, name)
|
|
127
|
+
gs[sel], gb[sel] = s_[:, :m, :m], b_[:, :m, :m]
|
|
128
|
+
return gs, gb
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _decimation(
|
|
132
|
+
z: NDArray[np.complex128], h0: NDArray[np.complex128], alpha: NDArray[np.complex128],
|
|
133
|
+
beta: NDArray[np.complex128], tol: float, max_iter: int, name: str,
|
|
134
|
+
) -> tuple[NDArray[np.complex128], NDArray[np.complex128]]:
|
|
135
|
+
r'''
|
|
136
|
+
Private function. The Lopez Sancho-Rubio decimation of a semi-infinite
|
|
137
|
+
chain of cells :math:`0, 1, 2, \dots` (:math:`H_{nn} = h_0`,
|
|
138
|
+
:math:`H_{n,n+1} = \alpha`, :math:`H_{n+1,n} = \beta`, with
|
|
139
|
+
:math:`\beta = \alpha^\dagger` unless the chain is non-reciprocal) at
|
|
140
|
+
many complex energies *z* (shape (nz,)) at once; *h0*, *alpha* and *beta*
|
|
141
|
+
have shape (m, m) or (nz, m, m). Used by *surface_green* and
|
|
142
|
+
*KSpace.surface_spectral_function*, which validate the arguments. It
|
|
143
|
+
stops when the renormalized couplings are below *tol* at every energy
|
|
144
|
+
(a RuntimeError naming *name* after *max_iter* iterations).
|
|
145
|
+
|
|
146
|
+
:returns:
|
|
147
|
+
* **gs** -- Complex ndarray, shape (nz, m, m). Surface Green's function (cell 0).
|
|
148
|
+
* **gb** -- Complex ndarray, shape (nz, m, m). Bulk Green's function
|
|
149
|
+
(one cell of the infinite chain).
|
|
150
|
+
'''
|
|
151
|
+
m = h0.shape[-1]
|
|
152
|
+
zi = np.asarray(z, dtype='c16')[:, None, None] * np.eye(m)[None]
|
|
153
|
+
eps_s = np.broadcast_to(h0, zi.shape).astype('c16')
|
|
154
|
+
eps = eps_s.copy()
|
|
155
|
+
alpha = np.broadcast_to(alpha, zi.shape).astype('c16')
|
|
156
|
+
beta = np.broadcast_to(beta, zi.shape).astype('c16')
|
|
96
157
|
for _ in range(max_iter):
|
|
97
|
-
g =
|
|
158
|
+
g = np.linalg.inv(zi - eps)
|
|
98
159
|
ag, bg = alpha @ g, beta @ g
|
|
99
160
|
eps_s = eps_s + ag @ beta
|
|
100
161
|
eps = eps + ag @ beta + bg @ alpha
|
|
101
162
|
alpha, beta = ag @ alpha, bg @ beta
|
|
102
|
-
if np.linalg.norm(alpha) + np.linalg.norm(beta) < tol:
|
|
163
|
+
if np.all(np.linalg.norm(alpha, axis=(1, 2)) + np.linalg.norm(beta, axis=(1, 2)) < tol):
|
|
103
164
|
break
|
|
104
165
|
else:
|
|
105
|
-
error_handling.converged(False,
|
|
106
|
-
return
|
|
166
|
+
error_handling.converged(False, name)
|
|
167
|
+
return np.linalg.inv(zi - eps_s), np.linalg.inv(zi - eps)
|
|
107
168
|
|
|
108
169
|
|
|
109
170
|
def lead_from_kspace(ks, direction: int = 1) -> tuple[NDArray[np.complex128], NDArray[np.complex128]]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tbkit
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: A Python package to build and solve Tight-Binding models.
|
|
5
5
|
Author-email: Charles Poli <cpoli374@gmail.com>
|
|
6
6
|
Maintainer-email: cpoli <cpoli374@gmail.com>
|
|
@@ -97,6 +97,9 @@ topology alongside superconductivity.
|
|
|
97
97
|
Kane-Mele) and Zeeman splitting.
|
|
98
98
|
* **Edge states**: cut a ribbon (periodic in one direction, finite in the
|
|
99
99
|
other) out of any periodic model, to see edge/surface physics.
|
|
100
|
+
* **Surface spectral functions** of semi-infinite crystals (iterative
|
|
101
|
+
surface Green's function): edge and surface states, e.g. the surface
|
|
102
|
+
Dirac cone of a 3D topological insulator, without a finite slab.
|
|
100
103
|
* **Density of states**, Gaussian- or Lorentzian-broadened, from either a
|
|
101
104
|
real-space spectrum or a Brillouin-zone mesh.
|
|
102
105
|
* A small library of ready-made lattices (chain, square, triangular,
|
|
@@ -116,7 +119,7 @@ topology alongside superconductivity.
|
|
|
116
119
|
|----------------------------|---------------------------------------------------------|
|
|
117
120
|
| `tbkit.Lattice` | Define and manipulate site positions and sublattices. |
|
|
118
121
|
| `tbkit.System` | Build the real-space Hamiltonian from a `Lattice` and solve it. |
|
|
119
|
-
| `tbkit.KSpace` | Build and solve the Bloch Hamiltonian of a periodic `Lattice`; bands, Berry curvature/Chern numbers, anomalous and spin Hall conductivities, ribbons, DOS. |
|
|
122
|
+
| `tbkit.KSpace` | Build and solve the Bloch Hamiltonian of a periodic `Lattice`; bands, Berry curvature/Chern numbers, anomalous and spin Hall conductivities, ribbons, surface spectral functions, DOS. |
|
|
120
123
|
| `tbkit.Plot` | Plot lattices, spectra, eigenstates, and the density of states. |
|
|
121
124
|
| `tbkit.Propagation` | Time-evolve a wavepacket. |
|
|
122
125
|
| `tbkit.Save` | Save figures/animations to disk. |
|
|
@@ -292,6 +295,7 @@ thumbnailed example gallery under `docs/source/api/gallery/`.
|
|
|
292
295
|
| [`topology/plot_tknn_hofstadter.py`](examples/topology/plot_tknn_hofstadter.py) | TKNN: Chern numbers of the Hofstadter bands from magnetic supercells, and the Diophantine equation. |
|
|
293
296
|
| [`topology/plot_kane_mele_z2.py`](examples/topology/plot_kane_mele_z2.py) | The Kane-Mele Z2 invariant from Wannier-centre flow. |
|
|
294
297
|
| [`topology/plot_fu_kane_parity.py`](examples/topology/plot_fu_kane_parity.py) | The Fu-Kane parity criterion on the BHZ model, checked against the Wannier flow. |
|
|
298
|
+
| [`topology/plot_3d_topological_insulator.py`](examples/topology/plot_3d_topological_insulator.py) | 3D topological insulators: the strong index and the surface Dirac cone, from the surface spectral function of a semi-infinite crystal. |
|
|
295
299
|
| [`topology/plot_quantum_geometry.py`](examples/topology/plot_quantum_geometry.py) | The quantum metric and Berry curvature of a Bloch band. |
|
|
296
300
|
| [`topology/plot_tenfold_way.py`](examples/topology/plot_tenfold_way.py) | Symmetry classes of tight-binding models: the tenfold way. |
|
|
297
301
|
| [`topology/plot_local_chern_marker.py`](examples/topology/plot_local_chern_marker.py) | The local Chern marker of a finite, disordered Haldane flake. |
|
|
@@ -345,6 +349,8 @@ Rendered docs (tutorial, API reference, example gallery): https://cpoli.github.i
|
|
|
345
349
|
each one linked to the corresponding **tbkit** functionality and example
|
|
346
350
|
above.
|
|
347
351
|
* `docs/source/tbkit.rst` -- the API reference (auto-generated from docstrings).
|
|
352
|
+
* [`ROADMAP.md`](ROADMAP.md) -- what is planned next, and what tbkit
|
|
353
|
+
does not do yet (compared with Kwant and PythTB).
|
|
348
354
|
|
|
349
355
|
Build the HTML docs with `cd docs && make html` (output in `docs/build/html`).
|
|
350
356
|
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Surface spectral functions of semi-infinite crystals (KSpace.surface_spectral_function).
|
|
3
|
+
"""
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
import tbkit.lattices as lattices
|
|
9
|
+
from tbkit.lattice import Lattice
|
|
10
|
+
from tbkit.kspace import KSpace, PAULI, ribbon
|
|
11
|
+
|
|
12
|
+
CUBIC = [(1., 0., 0.), (0., 1., 0.), (0., 0., 1.)]
|
|
13
|
+
SIGMA = [PAULI['x'], PAULI['y'], PAULI['z']]
|
|
14
|
+
# Haldane-like model with a third-neighbour-cell bond along a1, so the
|
|
15
|
+
# principal layer normal to a2 is one cell and normal to a1 two cells
|
|
16
|
+
T2 = 0.2j
|
|
17
|
+
HONEY_HOPS = [{'i': 0, 'j': 1, 'R': (0, 0), 't': 1.}, {'i': 0, 'j': 1, 'R': (-1, 0), 't': 1.},
|
|
18
|
+
{'i': 0, 'j': 1, 'R': (0, -1), 't': 1.},
|
|
19
|
+
{'i': 0, 'j': 0, 'R': (1, 0), 't': T2}, {'i': 0, 'j': 0, 'R': (0, -1), 't': T2},
|
|
20
|
+
{'i': 0, 'j': 0, 'R': (-1, 1), 't': T2},
|
|
21
|
+
{'i': 1, 'j': 1, 'R': (1, 0), 't': -T2}, {'i': 1, 'j': 1, 'R': (0, -1), 't': -T2},
|
|
22
|
+
{'i': 1, 'j': 1, 'R': (-1, 1), 't': -T2},
|
|
23
|
+
{'i': 0, 'j': 0, 'R': (2, 0), 't': 0.1}]
|
|
24
|
+
HONEY_ONSITE = {'a': 0.3, 'b': -0.3}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def chain(t=1.):
|
|
28
|
+
ks = KSpace(lattices.chain())
|
|
29
|
+
ks.set_hopping([{'i': 0, 'j': 0, 'R': (1,), 't': t}])
|
|
30
|
+
return ks
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def ti_hops():
|
|
34
|
+
'''Hoppings of the cubic 3D topological insulator m(k) tau_z + sum_i sin k_i tau_x sigma_i.'''
|
|
35
|
+
hops = []
|
|
36
|
+
for d in range(3):
|
|
37
|
+
R = tuple(int(x) for x in np.eye(3, dtype=int)[d])
|
|
38
|
+
hops += [{'i': 0, 'j': 0, 'R': R, 't': PAULI['0']}, {'i': 1, 'j': 1, 'R': R, 't': -PAULI['0']},
|
|
39
|
+
{'i': 0, 'j': 1, 'R': R, 't': -0.5j * SIGMA[d]},
|
|
40
|
+
{'i': 1, 'j': 0, 'R': R, 't': -0.5j * SIGMA[d]}]
|
|
41
|
+
return hops
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def ti_onsite(M):
|
|
45
|
+
return {'s': (M - 6) * PAULI['0'], 'p': -(M - 6) * PAULI['0']}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
TI_LAT = Lattice(unit_cell=[{'tag': 's', 'r0': (0., 0., 0.)}, {'tag': 'p', 'r0': (0., 0., 0.)}],
|
|
49
|
+
prim_vec=CUBIC)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def topological_insulator(M):
|
|
53
|
+
ks = KSpace(TI_LAT, spin=True)
|
|
54
|
+
ks.set_hopping(ti_hops())
|
|
55
|
+
ks.set_onsite(ti_onsite(M))
|
|
56
|
+
return ks
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def slab_spectral(H, rows, energies, eta):
|
|
60
|
+
'''-Im Tr G / pi over the orbitals *rows* of a finite slab Hamiltonian.'''
|
|
61
|
+
n = len(H)
|
|
62
|
+
return np.array([-np.trace(np.linalg.inv((e + 1j * eta) * np.eye(n) - H)[np.ix_(rows, rows)]).imag
|
|
63
|
+
for e in energies]) / np.pi
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class TestSurfaceSpectralFunction(unittest.TestCase):
|
|
67
|
+
|
|
68
|
+
def test_chain_end_and_bulk(self):
|
|
69
|
+
# semi-infinite chain: A_s = sqrt(4 - E^2)/(2 pi), A_b = 1/(pi sqrt(4 - E^2)),
|
|
70
|
+
# including E = 0, where the cell Hamiltonian is singular
|
|
71
|
+
ch = chain()
|
|
72
|
+
E = np.linspace(-1.9, 1.9, 9)
|
|
73
|
+
for eta in (1e-6, 1e-9):
|
|
74
|
+
A = ch.surface_spectral_function([[0.]], E, 0, eta=eta)[0]
|
|
75
|
+
self.assertTrue(np.allclose(A, np.sqrt(4 - E ** 2) / (2 * np.pi), atol=1e-6))
|
|
76
|
+
B = ch.surface_spectral_function([[0.]], E, 0, eta=eta, bulk=True)[0]
|
|
77
|
+
self.assertTrue(np.allclose(B, 1 / (np.pi * np.sqrt(4 - E ** 2)), atol=1e-5))
|
|
78
|
+
# both ends alike; nothing outside the band; one number for a scalar energy
|
|
79
|
+
self.assertTrue(np.allclose(ch.surface_spectral_function([[0.]], E, 0, side=-1, eta=1e-6)[0],
|
|
80
|
+
np.sqrt(4 - E ** 2) / (2 * np.pi), atol=1e-6))
|
|
81
|
+
self.assertLess(ch.surface_spectral_function([[0.]], 2.5, 0, eta=1e-6)[0, 0], 1e-5)
|
|
82
|
+
self.assertEqual(ch.surface_spectral_function([0.], 0.5, 0).shape, (1, 1))
|
|
83
|
+
|
|
84
|
+
def test_spectral_sum_rule(self):
|
|
85
|
+
# int A_s dE = number of orbitals of the surface cell
|
|
86
|
+
ch = chain()
|
|
87
|
+
E = np.linspace(-60., 60., 24001)
|
|
88
|
+
A = ch.surface_spectral_function([[0.]], E, 0, eta=0.05)[0]
|
|
89
|
+
self.assertAlmostEqual(np.sum(A) * (E[1] - E[0]), 1., delta=2e-3)
|
|
90
|
+
|
|
91
|
+
def test_matches_thick_ribbon(self):
|
|
92
|
+
# the outer cell of a wide ribbon (eta resolves ~ 1/eta cells) is the
|
|
93
|
+
# semi-infinite surface, on both edges, normal to either primitive vector
|
|
94
|
+
lat = lattices.honeycomb()
|
|
95
|
+
ks = KSpace(lat)
|
|
96
|
+
ks.set_hopping(HONEY_HOPS)
|
|
97
|
+
ks.set_onsite(HONEY_ONSITE)
|
|
98
|
+
E = np.linspace(-3., 3., 13)
|
|
99
|
+
eta, width = 0.05, 200
|
|
100
|
+
k = np.array([0.37, 0.61]) @ ks.rec_vec_k
|
|
101
|
+
for direction in (0, 1):
|
|
102
|
+
rib = ribbon(lat, HONEY_HOPS, width, direction=direction, onsite=HONEY_ONSITE)
|
|
103
|
+
a_par = np.array(lat.prim_vec[1 - direction])
|
|
104
|
+
H = rib.get_ham([k @ a_par / np.linalg.norm(a_par)])
|
|
105
|
+
for side, rows in ((1, [0, 1]), (-1, [len(H) - 2, len(H) - 1])):
|
|
106
|
+
A = ks.surface_spectral_function([k], E, direction, side, eta=eta)[0]
|
|
107
|
+
self.assertTrue(np.allclose(A, slab_spectral(H, rows, E, eta), atol=1e-10))
|
|
108
|
+
# only k along the surface matters
|
|
109
|
+
A2 = ks.surface_spectral_function([k + 0.3 * ks.rec_vec_k[direction]], E, direction,
|
|
110
|
+
side, eta=eta)[0]
|
|
111
|
+
self.assertTrue(np.allclose(A, A2, atol=1e-12))
|
|
112
|
+
|
|
113
|
+
def test_matches_thick_slab_3d(self):
|
|
114
|
+
# a spinful 3D model against slabs cut normal to a2 (slab k = (k_x, k_z))
|
|
115
|
+
# and to a3 (slab k = (k_x, k_y)): the four orbitals of the outer cell
|
|
116
|
+
ti = topological_insulator(2.)
|
|
117
|
+
E, eta = np.linspace(-3., 3., 13), 0.1
|
|
118
|
+
for direction, k_slab, k in ((1, [0.4, -0.3], [0.4, 1.3, -0.3]), (2, [0.2, -0.1], [0.2, -0.1, 0.])):
|
|
119
|
+
slab = ribbon(TI_LAT, ti_hops(), 120, direction=direction, onsite=ti_onsite(2.), spin=True)
|
|
120
|
+
A = ti.surface_spectral_function([k], E, direction, eta=eta)[0]
|
|
121
|
+
ref = slab_spectral(slab.get_ham(k_slab), [0, 1, 2, 3], E, eta)
|
|
122
|
+
self.assertTrue(np.allclose(A, ref, atol=1e-10))
|
|
123
|
+
|
|
124
|
+
def test_topological_insulator_surface_dirac_cone(self):
|
|
125
|
+
kx = np.linspace(-0.6, 0.6, 121)
|
|
126
|
+
ks = np.column_stack([kx, 0 * kx, 0 * kx])
|
|
127
|
+
E = np.array([-0.4, 0., 0.2, 0.4])
|
|
128
|
+
ti = topological_insulator(2.)
|
|
129
|
+
A = ti.surface_spectral_function(ks, E, 2, eta=0.02)
|
|
130
|
+
bulk = ti.surface_spectral_function(ks, E, 2, eta=0.02, bulk=True)
|
|
131
|
+
self.assertLess(bulk.max(), 0.05) # all four energies in the bulk gap
|
|
132
|
+
self.assertGreater(A[60, 1], 10.) # the Dirac point at the zone centre
|
|
133
|
+
for n, e in ((2, 0.2), (3, 0.4), (0, -0.4)):
|
|
134
|
+
# exactly two peaks, at k = +-|E| (velocity 1)
|
|
135
|
+
col = A[:, n]
|
|
136
|
+
peaks = [i for i in range(1, len(kx) - 1)
|
|
137
|
+
if col[i] > col[i - 1] and col[i] > col[i + 1] and col[i] > 1.]
|
|
138
|
+
self.assertEqual(len(peaks), 2)
|
|
139
|
+
self.assertTrue(np.allclose(np.abs(kx[peaks]), abs(e), atol=0.02))
|
|
140
|
+
# no surface states in the gap of the trivial insulator
|
|
141
|
+
trivial = topological_insulator(-2.)
|
|
142
|
+
self.assertLess(trivial.surface_spectral_function(ks, E, 2, eta=0.02).max(), 0.05)
|
|
143
|
+
|
|
144
|
+
def test_non_reciprocal_chain(self):
|
|
145
|
+
# Hatano-Nelson: the surface Green's function obeys g = 1/(z - tR tL g),
|
|
146
|
+
# that of a Hermitian chain with t = sqrt(tR tL)
|
|
147
|
+
hn = KSpace(lattices.chain())
|
|
148
|
+
hn.set_hopping([{'i': 0, 'j': 0, 'R': (1,), 't': 2.}, {'i': 0, 'j': 0, 'R': (-1,), 't': 0.5}],
|
|
149
|
+
hermitian=False)
|
|
150
|
+
E = np.linspace(-1.5, 1.5, 7)
|
|
151
|
+
self.assertTrue(np.allclose(hn.surface_spectral_function([[0.]], E, 0, eta=1e-3),
|
|
152
|
+
chain().surface_spectral_function([[0.]], E, 0, eta=1e-3)))
|
|
153
|
+
|
|
154
|
+
def test_decoupled_layers(self):
|
|
155
|
+
# no hopping along the surface normal: each layer is an isolated chain
|
|
156
|
+
lat = lattices.square()
|
|
157
|
+
ks = KSpace(lat)
|
|
158
|
+
ks.set_hopping([{'i': 0, 'j': 0, 'R': (1, 0), 't': 1.}])
|
|
159
|
+
kx, E = 0.7, np.linspace(-3., 3., 7)
|
|
160
|
+
A = ks.surface_spectral_function([[kx, 0.]], E, 1, eta=0.1)[0]
|
|
161
|
+
e0 = 2 * np.cos(kx)
|
|
162
|
+
self.assertTrue(np.allclose(A, 0.1 / np.pi / ((E - e0) ** 2 + 0.01)))
|
|
163
|
+
|
|
164
|
+
def test_errors(self):
|
|
165
|
+
ch = chain()
|
|
166
|
+
f = ch.surface_spectral_function
|
|
167
|
+
self.assertRaises(ValueError, f, [[0., 0.]], 0., 0)
|
|
168
|
+
self.assertRaises(TypeError, f, [[0.]], [0.1j], 0)
|
|
169
|
+
self.assertRaises(ValueError, f, [[0.]], [], 0)
|
|
170
|
+
self.assertRaises(ValueError, f, [[0.]], 0., 1)
|
|
171
|
+
self.assertRaises(TypeError, f, [[0.]], 0., 0.)
|
|
172
|
+
self.assertRaises(ValueError, f, [[0.]], 0., 0, 0)
|
|
173
|
+
self.assertRaises(ValueError, f, [[0.]], 0., 0, True)
|
|
174
|
+
self.assertRaises(ValueError, f, [[0.]], 0., 0, 1, -1.)
|
|
175
|
+
self.assertRaises(TypeError, f, [[0.]], 0., 0, 1, 0.1, 1)
|
|
176
|
+
self.assertRaises(RuntimeError, f, [[0.]], 0.5, 0, 1, 1e-9, False, 2)
|
|
177
|
+
ch.set_overlap([{'i': 0, 'j': 0, 'R': (1,), 't': 0.1}])
|
|
178
|
+
self.assertRaises(ValueError, f, [[0.]], 0., 0)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
if __name__ == '__main__':
|
|
182
|
+
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|