tbkit 0.2.0__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.2.0/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2014, Charles Poli
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
tbkit-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,260 @@
1
+ Metadata-Version: 2.4
2
+ Name: tbkit
3
+ Version: 0.2.0
4
+ Summary: A Python package to build and solve Tight-Binding models, for research and education.
5
+ Author-email: Charles Poli <cpoli374@gmail.com>
6
+ License-Expression: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/cpoli/tbkit
8
+ Classifier: Intended Audience :: Education
9
+ Classifier: Intended Audience :: Science/Research
10
+ Classifier: Topic :: Scientific/Engineering :: Physics
11
+ Classifier: Programming Language :: Python :: 3
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: numpy>=1.24
16
+ Requires-Dist: scipy>=1.10
17
+ Requires-Dist: matplotlib>=3.7
18
+ Provides-Extra: test
19
+ Requires-Dist: pytest>=7; extra == "test"
20
+ Requires-Dist: pytest-cov>=4; extra == "test"
21
+ Provides-Extra: docs
22
+ Requires-Dist: sphinx>=7; extra == "docs"
23
+ Requires-Dist: pydata-sphinx-theme>=0.15; extra == "docs"
24
+ Requires-Dist: sphinx-gallery>=0.15; extra == "docs"
25
+ Dynamic: license-file
26
+
27
+ # tbkit — a Tight-Binding package for research and education
28
+
29
+ [![tests](https://github.com/cpoli/tbkit/actions/workflows/tests.yml/badge.svg)](https://github.com/cpoli/tbkit/actions/workflows/tests.yml)
30
+ [![docs](https://img.shields.io/badge/docs-cpoli.github.io%2Ftbkit-blue.svg)](https://cpoli.github.io/tbkit/)
31
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](pyproject.toml)
32
+ [![License: BSD 3-Clause](https://img.shields.io/badge/License-BSD--3--Clause-blue.svg)](LICENSE)
33
+
34
+ ![tbkit logo](docs/source/_static/image/tbkit_logo.png)
35
+
36
+ **tbkit** is a Python package to build and solve Tight-Binding models, written
37
+ in vectorized NumPy/SciPy. It aims to make the mechanics of Tight-Binding
38
+ models — lattices, hoppings, Hamiltonians, spectra, band structures —
39
+ explicit and easy to inspect, so it works as well for teaching as for
40
+ research prototyping.
41
+
42
+ ## Features
43
+
44
+ * **Real space**: build arbitrarily complex finite lattices (flakes,
45
+ ribbons, disordered structures, defects) site by site or via boolean
46
+ selections (ellipses, half-planes, unions/differences of lattices), then
47
+ diagonalize the resulting Hamiltonian directly.
48
+ * **Reciprocal space**: build the Bloch Hamiltonian `H(k)` of the infinite
49
+ periodic lattice from a small set of intra-unit-cell hoppings, and compute
50
+ band structures along a k-path through high-symmetry points.
51
+ * **Topology**: Berry curvature and Chern numbers of a group of bands, by
52
+ the gauge-invariant Fukui-Hatsugai-Suzuki lattice method.
53
+ * **Spin**: optional spin-1/2 degree of freedom on every site, with 2x2
54
+ (Pauli-matrix) hoppings/onsite terms, for spin-orbit coupling (Rashba,
55
+ Kane-Mele) and Zeeman splitting.
56
+ * **Edge states**: cut a ribbon (periodic in one direction, finite in the
57
+ other) out of any periodic model, to see edge/surface physics.
58
+ * **Density of states**, Gaussian- or Lorentzian-broadened, from either a
59
+ real-space spectrum or a Brillouin-zone mesh.
60
+ * A small library of ready-made lattices (chain, square, triangular,
61
+ honeycomb, kagome, Lieb).
62
+ * Complex-valued onsite energies and hoppings; **Hermitian and non-Hermitian**
63
+ Tight-Binding Hamiltonians.
64
+ * Multiple sublattices, with hoppings addressed by neighbor order (1st,
65
+ 2nd, 3rd-nearest neighbor, ...), by angle, or by sublattice-pair tag.
66
+ * Built-in patterns for onsite disorder, hopping disorder, dimerization,
67
+ strain, and an orbital magnetic field (Peierls substitution).
68
+ * Time propagation of a wavepacket under the Tight-Binding Hamiltonian
69
+ (Crank-Nicolson).
70
+
71
+ **tbkit** is organized as a small set of composable classes and modules:
72
+
73
+ | Class / module | Purpose |
74
+ |----------------------------|---------------------------------------------------------|
75
+ | `tbkit.Lattice` | Define and manipulate site positions and sublattices. |
76
+ | `tbkit.System` | Build the real-space Hamiltonian from a `Lattice` and solve it. |
77
+ | `tbkit.KSpace` | Build and solve the Bloch Hamiltonian of a periodic `Lattice`; bands, Berry curvature/Chern numbers, ribbons, DOS. |
78
+ | `tbkit.Plot` | Plot lattices, spectra, eigenstates, and the density of states. |
79
+ | `tbkit.Propagation` | Time-evolve a wavepacket. |
80
+ | `tbkit.Save` | Save figures/animations to disk. |
81
+ | `tbkit.lattices` | Ready-made common lattices. |
82
+ | `tbkit.dos` | Broadened density of states from a set of eigenenergies. |
83
+
84
+ ## Install
85
+
86
+ Requires Python >= 3.10.
87
+
88
+ ```bash
89
+ git clone https://github.com/cpoli/tbkit
90
+ cd tbkit
91
+ pip install -e .
92
+ ```
93
+
94
+ or, to also install the tools needed to run the test suite:
95
+
96
+ ```bash
97
+ pip install -e ".[test]"
98
+ pytest tests/
99
+ ```
100
+
101
+ ## Quick start
102
+
103
+ Real-space flake, nearest-neighbor square lattice:
104
+
105
+ ```python
106
+ from tbkit.lattice import Lattice
107
+ from tbkit.system import System
108
+
109
+ lat = Lattice(unit_cell=[{'tag': 'a', 'r0': (0., 0.)}],
110
+ prim_vec=[(1., 0.), (0., 1.)])
111
+ lat.get_lattice(n1=10, n2=10)
112
+
113
+ sys = System(lat)
114
+ sys.set_hopping([{'n': 1, 't': 1.}])
115
+ sys.get_ham()
116
+ sys.get_eig()
117
+ print(sys.en)
118
+ ```
119
+
120
+ Graphene band structure (reciprocal space):
121
+
122
+ ```python
123
+ import numpy as np
124
+ from tbkit.lattice import Lattice
125
+ from tbkit.kspace import KSpace, reciprocal_vectors
126
+
127
+ DX, DY = 0.5 * 3 ** 0.5, 0.5
128
+ unit_cell = [{'tag': 'a', 'r0': (0., 0.)}, {'tag': 'b', 'r0': (DX, DY)}]
129
+ prim_vec = [(2 * DX, 0.), (DX, 1.5)]
130
+ lat = Lattice(unit_cell=unit_cell, prim_vec=prim_vec)
131
+
132
+ gra = KSpace(lat)
133
+ gra.set_hopping([{'i': 0, 'j': 1, 'R': (0, 0), 't': 1.},
134
+ {'i': 0, 'j': 1, 'R': (-1, 0), 't': 1.},
135
+ {'i': 0, 'j': 1, 'R': (0, -1), 't': 1.}])
136
+
137
+ b1, b2 = (np.array(v) for v in reciprocal_vectors(prim_vec))
138
+ Gamma, K, M = np.zeros(2), (b1 - b2) / 3, b1 / 2
139
+ gra.k_path([Gamma, K, M, Gamma], nk=60)
140
+ fig = gra.plot_bands(node_labels=[r'$\Gamma$', 'K', 'M', r'$\Gamma$'])
141
+ fig.savefig('graphene_bands.png')
142
+ ```
143
+
144
+ A magnetic field is added with `System.set_magnetic_field` (uniform field) or
145
+ `System.set_peierls_phase` (arbitrary vector potential), applied to the
146
+ hoppings *after* `set_hopping`/`set_hopping_manual`:
147
+
148
+ ```python
149
+ sys.set_hopping_manual(hop_dict)
150
+ sys.set_magnetic_field(alpha=0.01) # flux quanta per unit area
151
+ sys.get_ham()
152
+ ```
153
+
154
+ See [`examples/magnetic_field/plot_magnetic_field.py`](examples/magnetic_field/plot_magnetic_field.py) for a full
155
+ worked example (an Aharonov-Bohm ring, reproducing the textbook result that
156
+ the spectrum is periodic in the enclosed flux with period one flux quantum).
157
+
158
+ A Chern number is the Berry curvature of a group of bands, integrated over
159
+ the Brillouin zone:
160
+
161
+ ```python
162
+ chern = gra.chern_number(bands=[0], nk=40) # ~0 for plain graphene
163
+ ```
164
+
165
+ See [`examples/topology/plot_haldane_topology.py`](examples/topology/plot_haldane_topology.py) for the
166
+ Haldane model (the first Chern insulator), reproducing its topological
167
+ phase transition (Chern number 1 -> 0) and Berry-curvature map.
168
+
169
+ A spin-1/2 degree of freedom is added with `KSpace(lat, spin=True)`; onsite
170
+ values and hoppings then also accept 2x2 (Pauli) matrices:
171
+
172
+ ```python
173
+ from tbkit.kspace import KSpace, PAULI
174
+
175
+ kmele = KSpace(lat, spin=True)
176
+ kmele.set_hopping([{'i': 0, 'j': 0, 'R': (1, 0), 't': 1j*lam*PAULI['z']}]) # intrinsic SOC
177
+ ```
178
+
179
+ A ribbon -- periodic in one direction, finite in the other, the standard
180
+ way to see edge states -- is cut out of a periodic model with
181
+ `tbkit.kspace.ribbon`:
182
+
183
+ ```python
184
+ from tbkit.kspace import ribbon
185
+
186
+ rib = ribbon(lat, list_hop, width=30, direction=1) # 30 unit cells wide
187
+ fig = rib.plot_bands()
188
+ ```
189
+
190
+ See [`examples/topology/plot_edge_states.py`](examples/topology/plot_edge_states.py) for the zigzag
191
+ graphene ribbon's zero-energy edge band, and the Kane-Mele ribbon's helical
192
+ edge states crossing a spin-orbit gap.
193
+
194
+ ## Examples
195
+
196
+ `examples/` is organized as a [Sphinx-Gallery](https://sphinx-gallery.github.io/)
197
+ source tree, one topic per subfolder, each with a `README.rst` blurb. Every
198
+ `plot_*.py` script is self-contained and runnable directly
199
+ (`python examples/<section>/<script>.py`), and checks its own key numeric
200
+ claims with `assert` before plotting -- nothing is asserted in the docs
201
+ that isn't also verified in code. Building the docs (`pip install -e ".[docs]"`
202
+ then `cd docs && make html`) renders these same scripts into an executed,
203
+ thumbnailed example gallery under `docs/source/api/gallery/`.
204
+
205
+ | Script | What it shows |
206
+ |---------------------------------------------------------------------------|----------------|
207
+ | [`tight_binding/plot_graphene_bands.py`](examples/tight_binding/plot_graphene_bands.py) | Real-space flake + reciprocal-space band structure; graphene's Dirac point and Wallace's 1947 linear dispersion. |
208
+ | [`tight_binding/plot_visualizing_a_model.py`](examples/tight_binding/plot_visualizing_a_model.py) | `tbkit.plot.Plot`: lattice, spectrum with sublattice polarization, density of states, eigenstate intensity. |
209
+ | [`magnetic_field/plot_magnetic_field.py`](examples/magnetic_field/plot_magnetic_field.py) | Peierls substitution; an Aharonov-Bohm ring's flux-periodic spectrum. |
210
+ | [`magnetic_field/plot_hofstadter_butterfly.py`](examples/magnetic_field/plot_hofstadter_butterfly.py) | The fractal spectrum of a lattice threaded by a continuously swept flux. |
211
+ | [`magnetic_field/plot_landau_levels.py`](examples/magnetic_field/plot_landau_levels.py) | Landau levels: a square lattice's non-relativistic ladder vs. graphene's relativistic sqrt(n) ladder and zero mode. |
212
+ | [`topology/plot_ssh_model.py`](examples/topology/plot_ssh_model.py) | The SSH model: bulk gap closing and topologically protected edge states. |
213
+ | [`disorder/plot_anderson_localization.py`](examples/disorder/plot_anderson_localization.py) | Anderson localization: IPR vs. disorder strength, extended vs. localized states. |
214
+ | [`topology/plot_haldane_topology.py`](examples/topology/plot_haldane_topology.py) | The Haldane model: Berry curvature, Chern number, topological phase transition. |
215
+ | [`flat_bands/plot_flat_bands.py`](examples/flat_bands/plot_flat_bands.py) | Exactly flat bands on the kagome and Lieb lattices. |
216
+ | [`topology/plot_kagome_chern_band.py`](examples/topology/plot_kagome_chern_band.py) | Gapping the kagome flat band into a Chern insulator (C=-1) with complex nearest-neighbor hopping. |
217
+ | [`topology/plot_edge_states.py`](examples/topology/plot_edge_states.py) | Zigzag graphene ribbon edge band; Kane-Mele helical edge states. |
218
+ | [`dynamics/plot_bloch_oscillations.py`](examples/dynamics/plot_bloch_oscillations.py) | Wannier-Stark ladder, its localization, and Bloch oscillations under a uniform tilt. |
219
+ | [`topology/plot_thouless_pump.py`](examples/topology/plot_thouless_pump.py) | The Rice-Mele model as a Thouless quantum pump: quantized Chern number and polarization winding. |
220
+
221
+ The `examples/` directory also has five older Jupyter notebooks (graphene
222
+ flakes, kagome/Lieb/dumbbell lattices, disorder, strain, time propagation)
223
+ predating the 0.2 API refresh below.
224
+
225
+ ## Documentation
226
+
227
+ Rendered docs (tutorial, API reference, example gallery): https://cpoli.github.io/tbkit/
228
+
229
+ * [`docs/source/tutorial.rst`](docs/source/tutorial.rst) -- a narrative walkthrough of the
230
+ package, from building a lattice through topology, spin-orbit coupling,
231
+ and edge states.
232
+ * [`docs/source/history.rst`](docs/source/history.rst) -- a chronology of the breakthroughs
233
+ behind Tight-Binding theory (Bloch's theorem through the Kane-Mele model),
234
+ each one linked to the corresponding **tbkit** functionality and example
235
+ above.
236
+ * `docs/source/tbkit.rst` -- the API reference (auto-generated from docstrings).
237
+
238
+ Build the HTML docs with `cd docs && make html` (output in `docs/build/html`).
239
+
240
+ ## A note on the API
241
+
242
+ Version 0.2 modernized the package to run on current Python/NumPy/SciPy and
243
+ cleaned up the API:
244
+
245
+ * Sublattice tags are plain one-character **strings** (`'a'`) rather than
246
+ byte strings (`b'a'`).
247
+ * Classes are named in `PascalCase` (`Lattice`, `System`, ...) rather than
248
+ lowercase names identical to their module (`lattice.lattice`,
249
+ `system.system`, ...), which used to make `import tbkit.lattice as lattice`
250
+ silently bind the wrong object.
251
+
252
+ For continuity, the pre-0.2 lowercase class names (`lattice`, `system`,
253
+ `plot`, `propagation`, `save`) remain available as aliases of the new
254
+ classes, so `from tbkit.lattice import lattice` still works. Example
255
+ notebooks predating 0.2 still use byte-string tags (`b'a'`) and will need
256
+ that one mechanical change to run on the current version.
257
+
258
+ ## License
259
+
260
+ BSD 3-Clause, see [LICENSE](LICENSE).
tbkit-0.2.0/README.md ADDED
@@ -0,0 +1,234 @@
1
+ # tbkit — a Tight-Binding package for research and education
2
+
3
+ [![tests](https://github.com/cpoli/tbkit/actions/workflows/tests.yml/badge.svg)](https://github.com/cpoli/tbkit/actions/workflows/tests.yml)
4
+ [![docs](https://img.shields.io/badge/docs-cpoli.github.io%2Ftbkit-blue.svg)](https://cpoli.github.io/tbkit/)
5
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](pyproject.toml)
6
+ [![License: BSD 3-Clause](https://img.shields.io/badge/License-BSD--3--Clause-blue.svg)](LICENSE)
7
+
8
+ ![tbkit logo](docs/source/_static/image/tbkit_logo.png)
9
+
10
+ **tbkit** is a Python package to build and solve Tight-Binding models, written
11
+ in vectorized NumPy/SciPy. It aims to make the mechanics of Tight-Binding
12
+ models — lattices, hoppings, Hamiltonians, spectra, band structures —
13
+ explicit and easy to inspect, so it works as well for teaching as for
14
+ research prototyping.
15
+
16
+ ## Features
17
+
18
+ * **Real space**: build arbitrarily complex finite lattices (flakes,
19
+ ribbons, disordered structures, defects) site by site or via boolean
20
+ selections (ellipses, half-planes, unions/differences of lattices), then
21
+ diagonalize the resulting Hamiltonian directly.
22
+ * **Reciprocal space**: build the Bloch Hamiltonian `H(k)` of the infinite
23
+ periodic lattice from a small set of intra-unit-cell hoppings, and compute
24
+ band structures along a k-path through high-symmetry points.
25
+ * **Topology**: Berry curvature and Chern numbers of a group of bands, by
26
+ the gauge-invariant Fukui-Hatsugai-Suzuki lattice method.
27
+ * **Spin**: optional spin-1/2 degree of freedom on every site, with 2x2
28
+ (Pauli-matrix) hoppings/onsite terms, for spin-orbit coupling (Rashba,
29
+ Kane-Mele) and Zeeman splitting.
30
+ * **Edge states**: cut a ribbon (periodic in one direction, finite in the
31
+ other) out of any periodic model, to see edge/surface physics.
32
+ * **Density of states**, Gaussian- or Lorentzian-broadened, from either a
33
+ real-space spectrum or a Brillouin-zone mesh.
34
+ * A small library of ready-made lattices (chain, square, triangular,
35
+ honeycomb, kagome, Lieb).
36
+ * Complex-valued onsite energies and hoppings; **Hermitian and non-Hermitian**
37
+ Tight-Binding Hamiltonians.
38
+ * Multiple sublattices, with hoppings addressed by neighbor order (1st,
39
+ 2nd, 3rd-nearest neighbor, ...), by angle, or by sublattice-pair tag.
40
+ * Built-in patterns for onsite disorder, hopping disorder, dimerization,
41
+ strain, and an orbital magnetic field (Peierls substitution).
42
+ * Time propagation of a wavepacket under the Tight-Binding Hamiltonian
43
+ (Crank-Nicolson).
44
+
45
+ **tbkit** is organized as a small set of composable classes and modules:
46
+
47
+ | Class / module | Purpose |
48
+ |----------------------------|---------------------------------------------------------|
49
+ | `tbkit.Lattice` | Define and manipulate site positions and sublattices. |
50
+ | `tbkit.System` | Build the real-space Hamiltonian from a `Lattice` and solve it. |
51
+ | `tbkit.KSpace` | Build and solve the Bloch Hamiltonian of a periodic `Lattice`; bands, Berry curvature/Chern numbers, ribbons, DOS. |
52
+ | `tbkit.Plot` | Plot lattices, spectra, eigenstates, and the density of states. |
53
+ | `tbkit.Propagation` | Time-evolve a wavepacket. |
54
+ | `tbkit.Save` | Save figures/animations to disk. |
55
+ | `tbkit.lattices` | Ready-made common lattices. |
56
+ | `tbkit.dos` | Broadened density of states from a set of eigenenergies. |
57
+
58
+ ## Install
59
+
60
+ Requires Python >= 3.10.
61
+
62
+ ```bash
63
+ git clone https://github.com/cpoli/tbkit
64
+ cd tbkit
65
+ pip install -e .
66
+ ```
67
+
68
+ or, to also install the tools needed to run the test suite:
69
+
70
+ ```bash
71
+ pip install -e ".[test]"
72
+ pytest tests/
73
+ ```
74
+
75
+ ## Quick start
76
+
77
+ Real-space flake, nearest-neighbor square lattice:
78
+
79
+ ```python
80
+ from tbkit.lattice import Lattice
81
+ from tbkit.system import System
82
+
83
+ lat = Lattice(unit_cell=[{'tag': 'a', 'r0': (0., 0.)}],
84
+ prim_vec=[(1., 0.), (0., 1.)])
85
+ lat.get_lattice(n1=10, n2=10)
86
+
87
+ sys = System(lat)
88
+ sys.set_hopping([{'n': 1, 't': 1.}])
89
+ sys.get_ham()
90
+ sys.get_eig()
91
+ print(sys.en)
92
+ ```
93
+
94
+ Graphene band structure (reciprocal space):
95
+
96
+ ```python
97
+ import numpy as np
98
+ from tbkit.lattice import Lattice
99
+ from tbkit.kspace import KSpace, reciprocal_vectors
100
+
101
+ DX, DY = 0.5 * 3 ** 0.5, 0.5
102
+ unit_cell = [{'tag': 'a', 'r0': (0., 0.)}, {'tag': 'b', 'r0': (DX, DY)}]
103
+ prim_vec = [(2 * DX, 0.), (DX, 1.5)]
104
+ lat = Lattice(unit_cell=unit_cell, prim_vec=prim_vec)
105
+
106
+ gra = KSpace(lat)
107
+ gra.set_hopping([{'i': 0, 'j': 1, 'R': (0, 0), 't': 1.},
108
+ {'i': 0, 'j': 1, 'R': (-1, 0), 't': 1.},
109
+ {'i': 0, 'j': 1, 'R': (0, -1), 't': 1.}])
110
+
111
+ b1, b2 = (np.array(v) for v in reciprocal_vectors(prim_vec))
112
+ Gamma, K, M = np.zeros(2), (b1 - b2) / 3, b1 / 2
113
+ gra.k_path([Gamma, K, M, Gamma], nk=60)
114
+ fig = gra.plot_bands(node_labels=[r'$\Gamma$', 'K', 'M', r'$\Gamma$'])
115
+ fig.savefig('graphene_bands.png')
116
+ ```
117
+
118
+ A magnetic field is added with `System.set_magnetic_field` (uniform field) or
119
+ `System.set_peierls_phase` (arbitrary vector potential), applied to the
120
+ hoppings *after* `set_hopping`/`set_hopping_manual`:
121
+
122
+ ```python
123
+ sys.set_hopping_manual(hop_dict)
124
+ sys.set_magnetic_field(alpha=0.01) # flux quanta per unit area
125
+ sys.get_ham()
126
+ ```
127
+
128
+ See [`examples/magnetic_field/plot_magnetic_field.py`](examples/magnetic_field/plot_magnetic_field.py) for a full
129
+ worked example (an Aharonov-Bohm ring, reproducing the textbook result that
130
+ the spectrum is periodic in the enclosed flux with period one flux quantum).
131
+
132
+ A Chern number is the Berry curvature of a group of bands, integrated over
133
+ the Brillouin zone:
134
+
135
+ ```python
136
+ chern = gra.chern_number(bands=[0], nk=40) # ~0 for plain graphene
137
+ ```
138
+
139
+ See [`examples/topology/plot_haldane_topology.py`](examples/topology/plot_haldane_topology.py) for the
140
+ Haldane model (the first Chern insulator), reproducing its topological
141
+ phase transition (Chern number 1 -> 0) and Berry-curvature map.
142
+
143
+ A spin-1/2 degree of freedom is added with `KSpace(lat, spin=True)`; onsite
144
+ values and hoppings then also accept 2x2 (Pauli) matrices:
145
+
146
+ ```python
147
+ from tbkit.kspace import KSpace, PAULI
148
+
149
+ kmele = KSpace(lat, spin=True)
150
+ kmele.set_hopping([{'i': 0, 'j': 0, 'R': (1, 0), 't': 1j*lam*PAULI['z']}]) # intrinsic SOC
151
+ ```
152
+
153
+ A ribbon -- periodic in one direction, finite in the other, the standard
154
+ way to see edge states -- is cut out of a periodic model with
155
+ `tbkit.kspace.ribbon`:
156
+
157
+ ```python
158
+ from tbkit.kspace import ribbon
159
+
160
+ rib = ribbon(lat, list_hop, width=30, direction=1) # 30 unit cells wide
161
+ fig = rib.plot_bands()
162
+ ```
163
+
164
+ See [`examples/topology/plot_edge_states.py`](examples/topology/plot_edge_states.py) for the zigzag
165
+ graphene ribbon's zero-energy edge band, and the Kane-Mele ribbon's helical
166
+ edge states crossing a spin-orbit gap.
167
+
168
+ ## Examples
169
+
170
+ `examples/` is organized as a [Sphinx-Gallery](https://sphinx-gallery.github.io/)
171
+ source tree, one topic per subfolder, each with a `README.rst` blurb. Every
172
+ `plot_*.py` script is self-contained and runnable directly
173
+ (`python examples/<section>/<script>.py`), and checks its own key numeric
174
+ claims with `assert` before plotting -- nothing is asserted in the docs
175
+ that isn't also verified in code. Building the docs (`pip install -e ".[docs]"`
176
+ then `cd docs && make html`) renders these same scripts into an executed,
177
+ thumbnailed example gallery under `docs/source/api/gallery/`.
178
+
179
+ | Script | What it shows |
180
+ |---------------------------------------------------------------------------|----------------|
181
+ | [`tight_binding/plot_graphene_bands.py`](examples/tight_binding/plot_graphene_bands.py) | Real-space flake + reciprocal-space band structure; graphene's Dirac point and Wallace's 1947 linear dispersion. |
182
+ | [`tight_binding/plot_visualizing_a_model.py`](examples/tight_binding/plot_visualizing_a_model.py) | `tbkit.plot.Plot`: lattice, spectrum with sublattice polarization, density of states, eigenstate intensity. |
183
+ | [`magnetic_field/plot_magnetic_field.py`](examples/magnetic_field/plot_magnetic_field.py) | Peierls substitution; an Aharonov-Bohm ring's flux-periodic spectrum. |
184
+ | [`magnetic_field/plot_hofstadter_butterfly.py`](examples/magnetic_field/plot_hofstadter_butterfly.py) | The fractal spectrum of a lattice threaded by a continuously swept flux. |
185
+ | [`magnetic_field/plot_landau_levels.py`](examples/magnetic_field/plot_landau_levels.py) | Landau levels: a square lattice's non-relativistic ladder vs. graphene's relativistic sqrt(n) ladder and zero mode. |
186
+ | [`topology/plot_ssh_model.py`](examples/topology/plot_ssh_model.py) | The SSH model: bulk gap closing and topologically protected edge states. |
187
+ | [`disorder/plot_anderson_localization.py`](examples/disorder/plot_anderson_localization.py) | Anderson localization: IPR vs. disorder strength, extended vs. localized states. |
188
+ | [`topology/plot_haldane_topology.py`](examples/topology/plot_haldane_topology.py) | The Haldane model: Berry curvature, Chern number, topological phase transition. |
189
+ | [`flat_bands/plot_flat_bands.py`](examples/flat_bands/plot_flat_bands.py) | Exactly flat bands on the kagome and Lieb lattices. |
190
+ | [`topology/plot_kagome_chern_band.py`](examples/topology/plot_kagome_chern_band.py) | Gapping the kagome flat band into a Chern insulator (C=-1) with complex nearest-neighbor hopping. |
191
+ | [`topology/plot_edge_states.py`](examples/topology/plot_edge_states.py) | Zigzag graphene ribbon edge band; Kane-Mele helical edge states. |
192
+ | [`dynamics/plot_bloch_oscillations.py`](examples/dynamics/plot_bloch_oscillations.py) | Wannier-Stark ladder, its localization, and Bloch oscillations under a uniform tilt. |
193
+ | [`topology/plot_thouless_pump.py`](examples/topology/plot_thouless_pump.py) | The Rice-Mele model as a Thouless quantum pump: quantized Chern number and polarization winding. |
194
+
195
+ The `examples/` directory also has five older Jupyter notebooks (graphene
196
+ flakes, kagome/Lieb/dumbbell lattices, disorder, strain, time propagation)
197
+ predating the 0.2 API refresh below.
198
+
199
+ ## Documentation
200
+
201
+ Rendered docs (tutorial, API reference, example gallery): https://cpoli.github.io/tbkit/
202
+
203
+ * [`docs/source/tutorial.rst`](docs/source/tutorial.rst) -- a narrative walkthrough of the
204
+ package, from building a lattice through topology, spin-orbit coupling,
205
+ and edge states.
206
+ * [`docs/source/history.rst`](docs/source/history.rst) -- a chronology of the breakthroughs
207
+ behind Tight-Binding theory (Bloch's theorem through the Kane-Mele model),
208
+ each one linked to the corresponding **tbkit** functionality and example
209
+ above.
210
+ * `docs/source/tbkit.rst` -- the API reference (auto-generated from docstrings).
211
+
212
+ Build the HTML docs with `cd docs && make html` (output in `docs/build/html`).
213
+
214
+ ## A note on the API
215
+
216
+ Version 0.2 modernized the package to run on current Python/NumPy/SciPy and
217
+ cleaned up the API:
218
+
219
+ * Sublattice tags are plain one-character **strings** (`'a'`) rather than
220
+ byte strings (`b'a'`).
221
+ * Classes are named in `PascalCase` (`Lattice`, `System`, ...) rather than
222
+ lowercase names identical to their module (`lattice.lattice`,
223
+ `system.system`, ...), which used to make `import tbkit.lattice as lattice`
224
+ silently bind the wrong object.
225
+
226
+ For continuity, the pre-0.2 lowercase class names (`lattice`, `system`,
227
+ `plot`, `propagation`, `save`) remain available as aliases of the new
228
+ classes, so `from tbkit.lattice import lattice` still works. Example
229
+ notebooks predating 0.2 still use byte-string tags (`b'a'`) and will need
230
+ that one mechanical change to run on the current version.
231
+
232
+ ## License
233
+
234
+ BSD 3-Clause, see [LICENSE](LICENSE).
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "tbkit"
7
+ version = "0.2.0"
8
+ description = "A Python package to build and solve Tight-Binding models, for research and education."
9
+ readme = "README.md"
10
+ license = "BSD-3-Clause"
11
+ authors = [{ name = "Charles Poli", email = "cpoli374@gmail.com" }]
12
+ requires-python = ">=3.10"
13
+ dependencies = [
14
+ "numpy>=1.24",
15
+ "scipy>=1.10",
16
+ "matplotlib>=3.7",
17
+ ]
18
+ classifiers = [
19
+ "Intended Audience :: Education",
20
+ "Intended Audience :: Science/Research",
21
+ "Topic :: Scientific/Engineering :: Physics",
22
+ "Programming Language :: Python :: 3",
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/cpoli/tbkit"
27
+
28
+ [project.optional-dependencies]
29
+ test = ["pytest>=7", "pytest-cov>=4"]
30
+ docs = ["sphinx>=7", "pydata-sphinx-theme>=0.15", "sphinx-gallery>=0.15"]
31
+
32
+ [tool.setuptools.packages.find]
33
+ include = ["tbkit*"]
34
+
35
+ [tool.coverage.run]
36
+ source = ["tbkit"]
tbkit-0.2.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,27 @@
1
+ # Copyright 2014 Charles Poli.
2
+ #
3
+ # This file is part of TBKIT. It is subject to the license terms in the
4
+ # LICENSE file found in the top-level directory of this distribution and at
5
+ # https://github.com/cpoli/tbkit.
6
+
7
+ """tbkit: build and solve Tight-Binding models."""
8
+
9
+ __version__ = "0.2.0"
10
+
11
+ __all__ = [
12
+ "Lattice", "System", "Plot", "Propagation", "Save", "KSpace",
13
+ "reciprocal_vectors", "error_handling",
14
+ ]
15
+
16
+ # NOTE: these are explicit imports, not `from tbkit.<module> import *`.
17
+ # A wildcard import here would rebind the `tbkit.<module>` submodule
18
+ # attributes to the classes they define (since e.g. tbkit/lattice.py both
19
+ # *is* the submodule `tbkit.lattice` and defines a `lattice` alias of the
20
+ # same name), breaking `import tbkit.lattice as lattice`-style imports.
21
+ from tbkit.lattice import Lattice
22
+ from tbkit.system import System
23
+ from tbkit.plot import Plot
24
+ from tbkit.propagation import Propagation
25
+ from tbkit.save import Save
26
+ from tbkit.kspace import KSpace, reciprocal_vectors
27
+ import tbkit.error_handling
@@ -0,0 +1,65 @@
1
+ """
2
+ Density of states from a set of eigenenergies, real-space
3
+ (:class:`tbkit.system.System`) or reciprocal-space
4
+ (:class:`tbkit.kspace.KSpace`, sampled over a k-mesh).
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import numpy as np
9
+ from numpy.typing import ArrayLike, NDArray
10
+
11
+ import tbkit.error_handling as error_handling
12
+
13
+
14
+ def density_of_states(
15
+ energies: ArrayLike,
16
+ e_grid: ArrayLike | None = None,
17
+ broadening: float = 0.05,
18
+ kernel: str = 'gaussian',
19
+ ) -> tuple[NDArray[np.float64], NDArray[np.float64]]:
20
+ r'''
21
+ Get the density of states, broadened by a Gaussian or Lorentzian
22
+ kernel of width *broadening*:
23
+
24
+ .. math::
25
+
26
+ \rho(E) = \sum_n g(E-E_n)\, ,\quad
27
+ g(x) = \frac{1}{\sqrt{2\pi}\sigma}e^{-x^2/2\sigma^2}\ \text{(gaussian)}
28
+ \ \text{or}\
29
+ g(x) = \frac{1}{\pi}\frac{\sigma}{x^2+\sigma^2}\ \text{(lorentzian)}
30
+
31
+ Each level contributes a kernel of unit area, so
32
+ :math:`\int\rho(E)dE` equals the number of levels in *energies*,
33
+ for an *e_grid* wide enough to contain the tails.
34
+
35
+ :param energies: Array of (real) eigenenergies. Any shape (e.g. the
36
+ *en* attribute of **System**, or of **KSpace** after *get_bands*
37
+ over a k-mesh -- flattened automatically).
38
+ :param e_grid: Real ndarray. Default value None. Energies at which to
39
+ evaluate the density of states. If None, a grid of 401 points
40
+ spanning ``[min(energies)-3*broadening, max(energies)+3*broadening]``
41
+ is used.
42
+ :param broadening: Positive real number. Default value 0.05. Kernel width
43
+ :math:`\sigma`.
44
+ :param kernel: String. Default value 'gaussian'. 'gaussian' or 'lorentzian'.
45
+
46
+ :returns:
47
+ * **e_grid** -- Real ndarray. The energy grid used.
48
+ * **dos** -- Real ndarray, same shape as *e_grid*. Density of states.
49
+ '''
50
+ error_handling.ndarray_empty(np.asarray(energies), 'energies')
51
+ error_handling.positive_real(broadening, 'broadening')
52
+ error_handling.dos_kernel(kernel)
53
+ energies = np.asarray(energies).real.astype('f8').ravel()
54
+ if e_grid is None:
55
+ pad = 3 * broadening
56
+ e_grid = np.linspace(energies.min() - pad, energies.max() + pad, 401)
57
+ else:
58
+ error_handling.ndarray_empty(np.asarray(e_grid), 'e_grid')
59
+ e_grid = np.asarray(e_grid, dtype='f8')
60
+ diff = e_grid[:, None] - energies[None, :]
61
+ if kernel == 'gaussian':
62
+ weight = np.exp(-diff**2 / (2*broadening**2)) / (broadening*np.sqrt(2*np.pi))
63
+ else:
64
+ weight = (broadening/np.pi) / (diff**2 + broadening**2)
65
+ return e_grid, weight.sum(axis=1)