API#
tbkit.lattice module#
- tbkit.lattice.COOR_DTYPE_3D = [('x', 'f8'), ('y', 'f8'), ('z', 'f8'), ('tag', 'U1')]#
Site dtype of a lattice in 3D space (unit_cell and prim_vec given as 3-tuples).
- class tbkit.lattice.Lattice(unit_cell: list[dict], prim_vec: Sequence[tuple[float, ...]])[source]#
Bases:
objectBuild up 1D, 2D or 3D lattice. Lattice is defined by the discrete operation:
\[\mathbf{R} = n_1\mathbf{a}_1 + n_2\mathbf{a}_2 + n_3\mathbf{a}_3\]where \(\mathbf{a}_1\), \(\mathbf{a}_2\), \(\mathbf{a}_3\) are the primitive vectors and \(n_1\), \(n_2\), \(n_3\) are the number of unit cells along them.
- Parameters:
unit_cell (List of dictionaries) –
One dictionary per site within the unit cell. Each dictionary has two keys:
‘tag’, one-character string. Label of the associated sublattice.
‘r0’, Tuple. Position: \((x, y)\), or \((x, y, z)\) for a lattice in 3D space.
prim_vec (List of tuples) – Define the primitive vectors. List of one/two/three tuples for 1D/2D/3D lattices, each the cartesian coordinates of a primitive vector: 2-tuples in the plane, or 3-tuples in 3D space (then r0 must be 3-tuples too, and coor gains a ‘z’ field, see
COOR_DTYPE_3D).
Notes
In 3D space, the geometry methods acting in the plane (rotation, ellipse_in, boundary_line, …) act on \((x, y)\) only (rotation about the z axis, cylinders, vertical planes), and plot draws the projection on the \((x, y)\) plane.
Examples
Example usage:
# Line-Centered Square lattice unit_cell = [{'tag': 'a', 'r0': (0., 0.)}, {'tag': 'a', 'r0': (0., 1.)}] prim_vec = [(0, 2), (2, 0)] lat = lattice(unit_cell=unit_cell, prim_vec=prim_vec)
- get_lattice(n1: int, n2: int = 1, n3: int = 1) None[source]#
Get the lattice positions, sorted by (y, x) – by (z, y, x) in 3D space.
- Parameters:
n1 (Positive Integer) – Number of unit cells along \(\mathbf{a}_1\).
n2 (Positive Integer, default 1) – Number of unit cells along \(\mathbf{a}_2\).
n3 (Positive Integer, default 1) – Number of unit cells along \(\mathbf{a}_3\) (3D lattices only).
Examples
Example usage:
# Line-Centered Square lattice unit_cell = [{'tag': 'a', 'r0': (0., 0.)}, {'tag': 'a', 'r0': (0., 1.)}] prim_vec = [(0, 2), (2, 0)] lat = lattice(unit_cell=unit_cell, prim_vec=prim_vec) lat.get_lattice(n1=4, n2=5)
- sort_order() tuple[str, ...][source]#
Private method. Fields the sites are sorted by: (‘y’, ‘x’), or (‘z’, ‘y’, ‘x’) in 3D space.
- distances() tuple[NDArray, ...][source]#
Private method. Pairwise coordinate differences, d[i, j] from site i to site j: (dx, dy), or (dx, dy, dz) in 3D space.
- add_sites(coor: NDArray) None[source]#
Add sites.
- Parameters:
coor – Structured array with keys: {‘x’, ‘y’, ‘tag’} ({‘x’, ‘y’, ‘z’, ‘tag’} for a lattice in 3D space).
Examples
Example usage:
# Square lattice unit_cell = [{'tag': 'a', 'r0': (0., 0.)}] prim_vec = [(0, 1), (1, 0)] lat = lattice(unit_cell=unit_cell, prim_vec=prim_vec) lat.get_lattice(n1=2, n2=2) coor = np.array([(-1., -1, 'b'), (-2., -2, 'c')], dtype=[('x', 'f8'), ('y', 'f8'), ('tag', 'U1')]) lat.add_sites(coor)
- remove_sites(index: list[int]) None[source]#
Remove sites defined by their indices (use method lattice.plot(plt_index=True) to get access to the site indices).
- Parameters:
index (List) – Site indices to be removed.
Examples
Example usage:
# Square lattice unit_cell = [{'tag': 'a', 'r0': (0., 0.)}] prim_vec = [(0, 1), (1, 0)] lat = lattice(unit_cell=unit_cell, prim_vec=prim_vec) lat.get_lattice(n1=2, n2=2) lat.remove_sites([0, 2])
- shift_x(shift: float) None[source]#
Shift the x coordinates.
- Parameters:
shift (Real number) – Shift value.
- shift_y(shift: float) None[source]#
Shift the y coordinates.
- Parameters:
shift (Real number) – Shift value.
- shift_z(shift: float) None[source]#
Shift the z coordinates (3D lattices only).
- Parameters:
shift (Real number) – Shift value.
- slab(z_min: float, z_max: float) None[source]#
Keep only the sites with \(z_{min} < z < z_{max}\) (3D lattices only).
- Parameters:
z_min (Real number)
z_max (Real number, larger than *z_min*)
- boundary_line(cx: float, cy: float, co: float) None[source]#
Keep only the sites with \(c_yy+c_xx > c_0\).
- Parameters:
cx (Real number) – \(c_x\) value.
cy (Real number) – \(c_y\) value.
co (Real number) – \(c_0\) value.
- ellipse_in(rx: float, ry: float, x0: float, y0: float) None[source]#
Select sites according to
\[(x-x_0)^2/r_x^2+(y-y_0)^2/r_y^2 < 1\, .\]- Parameters:
rx (Positive Real number) – Radius along \(x\).
ry (Positive Real number) – Radius along \(y\).
x0 (Real number) – \(x\) center.
y0 (Real number) – \(y\) center.
- ellipse_out(rx: float, ry: float, x0: float, y0: float) None[source]#
Select sites according to
\[(x-x_0)^2/r_x^2+(y-y_0)^2/r_y^2 > 1\, .\]- Parameters:
rx (Positive Real number) – Radius along \(x\).
ry (Positive Real number) – Radius along \(y\).
x0 (Real number) – \(x\) center.
y0 (Real number) – \(y\) center.
- rotation(theta: float) None[source]#
Rotate the lattice structure about the origin (about the z axis, in 3D space) by the angle \(\theta\).
- Parameters:
theta – Rotation angle in degrees.
- overlaps(other: Lattice) NDArray[bool][source]#
Private method. Mask of the sites of self that coincide with a site of other.
- plot(ms: float = 20, fs: float = 20, plt_index: bool = False, axis: bool = False, figsize: tuple[float, float] | None = None) Figure[source]#
Plot the lattice in real space (its projection on the (x, y) plane, in 3D space).
- Parameters:
ms (Positive number, default 20) – Markersize.
fs (Positive number, default 20) – Fontsize.
plt_index (Boolean, default False) – Plot site labels.
axis (Boolean, default False) – Plot axis.
figsize (Tuple, default None) – Figsize.
- Returns:
fig (Figure)
tbkit.system module#
- class tbkit.system.System(lat: Lattice, periodic: bool | tuple[bool, ...] = False)[source]#
Bases:
objectSolve the Tight-Binding eigenvalue problem of a lattice defined by the class lattice.
- Parameters:
lat (*lattice class instance*)
periodic (Boolean, or tuple of booleans (one per primitive vector), default False) – Periodic boundary conditions along the primitive vectors \(\mathbf{a}_i\): the sample is then the \(n_1\mathbf{a}_1\times n_2\mathbf{a}_2\,(\times n_3\mathbf{a}_3)\) box of lat.get_lattice wrapped into a torus (True), or a cylinder (e.g.
(True, False), periodic along \(\mathbf{a}_1\) only). lat.get_lattice must have been called; sites may be removed afterwards (vacancies), but not moved. Every distance and bond angle is then that of the shortest image, so the neighbour orders of set_hopping include the bonds that wrap around, with their short bond vector; a bond order reaching half-way around the torus is refused (it would be ambiguous). A uniform magnetic field (set_magnetic_field) and the local Chern marker need open boundaries; get_bott_index is the Chern number of a torus.
Notes
Up to dense_max sites (default 5000), the distances between all pairs of sites are computed (and kept in vec_hop). Larger lattices only look for the neighbours they need, with a k-d tree, up to the largest neighbour order a call asks for: memory and time then grow linearly with the number of sites (vec_hop stays empty).
- dense_max = 5000#
Largest lattice (number of sites) whose pairwise distances are all computed.
- get_distances(n_orders: int = 1) None[source]#
Private method. Get distances and angles of the edges. The angle is that of the bond’s projection on the (x, y) plane; in 3D space, a vertical bond gets angle 0 pointing up (+z) and -180 pointing down.
- Parameters:
n_orders (Positive integer, default 1) – Beyond dense_max sites, the number of neighbour orders (distinct distances) needed.
- print_distances(n: int = 1) None[source]#
Print distances and positive angles (in degrees) \(\phi_+\in[0, 180)\) of the nth shortest edges. Negative angles are given by: \(\phi_-= \phi_+-180\) and \(\phi_-\in[-180, 0)\).
- Parameters:
n (Positive integer) – Number of shortest edges.
- set_onsite(dict_onsite: dict[str, complex]) None[source]#
Set onsite energies.
- Parameters:
dict_onsite (Dictionary) – key: sublattice tag, val: onsite energy, or a value function
onsite(site, **params), evaluated byget_ham(**params). site is a structured array of the sites of that tag (fields ‘x’, ‘y’, (‘z’), ‘tag’, ‘index’); the function returns one energy, or one per site. set_onsite_dis adds to it.
Examples
Example usage:
# Line-Centered Square lattice sys.set_onsite({'a': -1j, 'b': -2j}) # a gate voltage V across the sample, set by get_ham(V=...) sys.set_onsite({'a': lambda site, V: V * site['x'] / 10, 'b': 0.}) sys.get_ham(V=0.5)
- get_bonds(n: int) tuple[NDArray, NDArray, NDArray][source]#
Private method. Get every bond of the nth shortest length once, oriented from i to j so that its angle lies in \([0, 180)\).
The sign of hop[‘ang’] is what marks a hopping as belonging to the upper or the lower part of the Hamiltonian (see get_ham). Sites sorted by (y, x), as get_lattice leaves them, give that orientation for \(i < j\), but rotation, clean_coor, +=, … reorder the sites, so the orientation is taken from the angle itself.
- Returns:
i, j (Integer ndarrays) – Bond end points.
ang (Real ndarray) – Bond angles, in degrees, in \([0, 180)\).
- fill_store_hop(n: int) None[source]#
Private method.
Store in store_hop indices, positive angles, and tags of a given type of hopping (see get_bonds).
- set_hopping(list_hop: list[dict], upper_part: bool = True) None[source]#
Set lattice hoppings.
- Parameters:
list_hop (List of Dictionaries) –
Dictionary with keys (‘n’, ‘ang’, ‘tag’, ‘t’) where:
‘n’ Positive integer, type of hoppings:
‘n’: 1 for nearest neighbours.
‘n’: 2 for next-nearest neighbours.
‘n’: 3 for next-next-nearest neighbours.
etc…
‘ang’ value, float, angle, in deg, of the hoppings. (optional).
Hopping angles are given by the method print_distances.
If \(ang \in[0, 180)\), fill the Hamiltonian upper part.
If \(ang \in[-180, 0)\), fill the Hamiltonian lower part.
‘tag’ string of length 2 (optional).
Hopping tags.
‘t’ Complex number, or value function.
Hopping value. A value function
t(site_i, site_j, **params)is evaluated byget_ham(**params): site_i and site_j are structured arrays of the bonds’ end points (fields ‘x’, ‘y’, (‘z’), ‘tag’, ‘index’), and it returns one value, or one per bond (see the example below). Modifiers applied afterwards (set_peierls_phase, set_hopping_dis, …) multiply it.
upper_part (Boolean, default True) –
True, get the hoppings with angles in \([0, 180)\), i.e. fill the Hamiltonian upper part.
False, get the reversed hoppings, with angles in \([-180, 0)\), i.e. fill the Hamiltonian lower part.
Examples
Example usage:
# fill upper part: sys.set_hopping([{'n': 1, 't': 1.}]) # fill lower part: sys.set_hopping([{'n': 1, 't': 1.}], upper_part=False) # fill upper part: specifying the angles: sys.set_hopping([{'n': 1, 'ang': 0., 't': 1.}, {'n': 1, 'ang': 90., 't': 2.}]) # fill lower part: sys.set_hopping([{'n': 1, 'ang': -180., 't': 1.}, {'n': 1, 'ang': -90., 't': 2.}], upper_part=False) # fill upper part: specifying the tags: sys.set_hopping([{'n': 1, 'tag': 'ab', 't': 1.}, {'n': 1, 'tag': 'ba', 't': 2.}]) # fill lower part: sys.set_hopping([{'n': 1, 'tag': 'ab', 't': 1.}, {'n': 1, 'tag': 'ba', 't': 2.}], upper_part=False) # fill upper part: specifying the angles and tags: sys.set_hopping([{'n': 1, 'ang': 0., 'tag': 'ab', 't': 1.}, {'n': 1, 'ang': 0., 'tag': 'ba', 't': 2.}, {'n': 1, 'ang': 90., 'tag': 'ab', 't': 3.}, {'n': 1, 'ang': 90., 'tag': 'ba', 't': 4.}]) # fill lower part: sys.set_hopping([{'n': 1, 'ang': -180., 'tag': 'ab', 't': 1.}, {'n': 1, 'ang': -180., 'tag': 'ba', 't': 2.}, {'n': 1, 'ang': -90., 'tag': 'ab', 't': 3.}, {'n': 1, 'ang': -90., 'tag': 'ba', 't': 4.}], upper_part=False) # value function: a hopping that decays along x, swept without # rebuilding the model sys.set_hopping([{'n': 1, 't': lambda si, sj, t0, xi: t0 * np.exp(-si['x'] / xi)}]) for xi in (5., 10., 20.): sys.get_ham(t0=1., xi=xi)
Note
A Hermitian hopping matrix can be built using only its upper part OR only its lower part. The full matrix is then built automatically by Hermitian conjugation.
If both the upper AND the lower parts are used to build the hopping matrix, no Hermitian conjugation is performed, i.e. a non-Hermitian hopping matrix can be built.
- check_sites() None[source]#
Private method. Check if the number of sites was changed after calling the method system.set_hopping().
- set_given_hopping(n: int, size: int, dic: dict, mask: NDArray, upper_part: bool) NDArray[source]#
Private method. Fill self.hop.
- Parameters:
n (Integer) – Hopping type.
size (Integer) – Number of hoppings.
dic (Dictionary) – Hopping dictionary.
mask (np.ndarray) – Mask.
upper_part (Boolean) – If True, keep the orientation of store_hop (angles in [0, 180)), else reverse it.
- set_hopping_manual(dict_hop: dict[tuple[int, int], complex], upper_part: bool = True) None[source]#
Set hoppings manually.
- Parameters:
dict_hop (Dictionary of hoppings) – key: hopping indices, val: hopping values.
upper_part (Boolean, default True) –
True, fill the Hamiltonian upper part.
False, fill the Hamiltonian lower part.
Examples
Example usage:
sys.set_hopping_manual({(0, 1): 1., (1, 2): 2.})
- set_hopping_dis(alpha: complex) None[source]#
Set uniform hopping disorder.
- Parameters:
alpha (Complex or Real number) – Disorder strength.
Examples
Example usage:
sys.set_hopping_dis(alpha=0.1)
- set_peierls_phase(phase: Callable[[...], NDArray]) None[source]#
Apply the Peierls substitution to the existing hoppings, to capture the effect of an orbital magnetic field:
\[t_{ij} \to t_{ij}\, e^{i\phi_{ij}}\, ,\quad \phi_{ij} = \frac{2\pi}{\Phi_0}\int_{\mathbf{r}_i}^{\mathbf{r}_j} \mathbf{A}\cdot d\mathbf{l}\]where \(\mathbf{A}\) is the vector potential, integrated along the straight bond from site \(i\) to site \(j\).
Must be called after set_hopping / set_hopping_manual (it rescales the existing hoppings in place) and before get_ham. For a uniform perpendicular field, use the convenience method set_magnetic_field instead.
- Parameters:
phase (Callable) –
phase(xi, yi, xj, yj)returns \(\phi_{ij}\), the (real-valued) Peierls phase for the bond from \((x_i, y_i)\) to \((x_j, y_j)\). Called with Numpy arrays (one value per hopping in sys.hop). With periodic boundaries, \((x_j, y_j)\) is the end of the short bond, i.e. the image of site \(j\) next to site \(i\), which lies outside the sample for a bond that wraps around. The vector potential must then be consistent with the torus: periodic (a field of zero net flux), or uniform (a flux threading the holes of the torus, i.e. twisted boundary conditions).
Notes
Note
get_ham automatically assigns the reversed bond its complex conjugate, so the Hamiltonian stays Hermitian as long as phase is antisymmetric under swapping \(i\) and \(j\) – true for the line integral of any vector potential, since reversing the integration path negates it.
Examples
Example usage:
# Peierls phase from a uniform field via the Landau gauge # A = (0, B x): the same field as set_magnetic_field(alpha), # just in a different (equally valid) gauge. alpha = 0.01 sys.set_peierls_phase(lambda xi, yi, xj, yj: 2 * np.pi * alpha * (yj - yi) * (xi + xj) / 2)
- set_magnetic_field(alpha: float) None[source]#
Set a uniform perpendicular magnetic field via the Peierls substitution (see set_peierls_phase), using the symmetric gauge \(\mathbf{A} = \frac{B}{2}(-y, x)\):
\[\phi_{ij} = \pi\alpha\,(x_iy_j - x_jy_i)\]- Parameters:
alpha (Real number) – Flux density \(B/\Phi_0\), in flux quanta per unit area (in the lattice’s length units) – i.e. the flux through a region of area \(S\) is \(\alpha S\) flux quanta.
Examples
Example usage:
# one flux quantum per 100 unit cells of a lattice with # lattice constant 1: sys.set_magnetic_field(alpha=0.01)
Open boundaries only: on a torus the symmetric gauge is not periodic, and a uniform field needs a quantized total flux and magnetic boundary conditions.
- set_onsite_dis(alpha: complex) None[source]#
Set uniform onsite disorder.
- Parameters:
alpha (Complex or Real number) – Disorder strength.
Examples
Example usage:
sys.set_onsite_dis(alpha=0.1)
- set_onsite_def(onsite_def: dict[int, complex]) None[source]#
Set specific onsite energies.
- Parameters:
onsite_def (Dictionary) – key: site indices, val: onsite values.
Examples
Example usage:
sys.set_onsite_def({0: 1., 1: -1j})
- set_hopping_def(hopping_def: dict[tuple[int, int], complex]) None[source]#
Set specific hoppings.
- Parameters:
hopping_def (Dictionary of hoppings) – key: hopping indices \((i, j)\), val: hopping value \(t_{ij}\). If sys.hop stores the bond the other way round, as \((j, i)\) (only one direction is stored for a Hermitian Hamiltonian), that entry is set to \(t_{ij}^*\), so that \(H_{ij} = t_{ij}\). A pair that is not a hopping of sys.hop is ignored.
Examples
Example usage:
sys.set_hopping_def({(0, 1): 1., (1, 2): -1j})
- set_new_hopping(list_hop: list[dict], ind: NDArray) None[source]#
Private method. Set new hoppings.
- Parameters:
list_hop (List of Dictionary (see set_hopping definition))
ind (List) – List of indices.
- find_square(xlims: tuple[float, float], ylims: tuple[float, float]) NDArray[source]#
Private method. Find hoppings within the square.
- Parameters:
xlims (List or Tuple) – \(x\) interval.
ylims (List or Tuple) – \(y\) interval.
- find_ellipse(rx: float, ry: float, x0: float, y0: float) NDArray[source]#
Private method. Find hoppings within the ellipse.
- Parameters:
rx (Positive Float) – Radius along \(x\).
ry (Positive Float) – Radius along \(y\).
x0 (Float, default 0) – \(x\) center.
y0 (Float, default 0) – \(y\) center.
- change_hopping_square(list_hop: list[dict], xlims: tuple[float, float], ylims: tuple[float, float] = (-1.0, 1.0)) None[source]#
Change the values of the hoppings whose two sites both lie in the rectangle xlims x ylims.
- Parameters:
list_hop (List of Dictionary (see set_hopping definition))
xlims (List or Tuple) – \(x\) interval.
ylims (List or Tuple, default [-1, 1]) – \(y\) interval.
- change_hopping_ellipse(list_hop: list[dict], rx: float, ry: float, x0: float = 0.0, y0: float = 0.0) None[source]#
Change the values of the hoppings whose two sites both lie in the ellipse of radii rx, ry centered at (x0, y0).
- Parameters:
list_hop (List of Dictionary (see set_hopping definition))
rx (Positive Float) – Radius along \(x\).
ry (Positive Float) – Radius along \(y\).
x0 (Float, default 0) – \(x\) center.
y0 (Float, default 0) – \(y\) center.
- get_coor_hop() None[source]#
Get the site coordinates in hopping space only considering the nearest neighbours hoppings.
- get_ham(**params) None[source]#
Get the Tight-Binding Hamiltonian using sys.hop.
- Parameters:
params – Values of the parameters of the value functions given to set_hopping / set_onsite: each function gets the ones its signature names (all of them with
**kwargs); the others are ignored. Only the values are recomputed: sweeping a parameter costs one call per point, not a new model.
Examples
Example usage:
for B in np.linspace(0., 0.1, 50): sys.get_ham(B=B) sys.get_eig()
- get_eig(eigenvec: bool = False, left: bool = False) None[source]#
Get the eigenergies, eigenvectors and polarisation.
- Parameters:
eigenvec (Boolean, default False) – If True, get the eigenvectors.
left (Boolean, default False) – If True, get the left eigenvectors too. Relevant for non-Hermitian matrices.
- get_eig_sparse(n_eig: int = 10, sigma: complex = 0.0, eigenvec: bool = False) None[source]#
Get the n_eig eigenenergies closest to sigma, and optionally their eigenvectors, with the sparse shift-invert Lanczos (Hermitian) or Arnoldi (non-Hermitian) solver of ARPACK. Unlike get_eig, it never builds the dense matrix, so it reaches lattices of \(10^5\) sites and more – e.g. the states near a band centre, or the zero modes of a large flake. The results replace en (sorted by real part) and, with eigenvec, rn, intensity and pola, as for get_eig.
- Parameters:
n_eig (Positive integer, default 10) – Number of eigenpairs (at most sites - 2).
sigma (Real or complex number, default 0) – Target energy. The factorization uses sigma shifted by about 1e-9 (relative to the largest matrix element), so that it may be exactly an eigenvalue, e.g. zero modes at the default sigma = 0; the eigenvalues themselves are not shifted.
eigenvec (Boolean, default False)
- get_green(energy: complex, eta: float = 1e-06) NDArray[complex128][source]#
Get the retarded Green’s function (resolvent)
\[G(E) = \left[(E + i\eta) - H\right]^{-1}\, .\]- Parameters:
energy (Real (or complex) number) – Energy \(E\).
eta (Positive real or zero, default 1e-6) – Broadening \(\eta\).
- Returns:
G (Complex ndarray, shape (sites, sites))
- get_ldos(energies: ArrayLike, eta: float = 0.05) NDArray[float64][source]#
Get the local density of states
\[\rho_i(E) = -\frac{1}{\pi}\,\mathrm{Im}\,G_{ii}(E) = \sum_n |\psi_n(i)|^2\,\frac{\eta/\pi}{(E - E_n)^2 + \eta^2}\](the second form, from the eigenvectors, for a Hermitian Hamiltonian). Summed over sites it is the Lorentzian-broadened density of states.
- Parameters:
energies (Real array) – Energies.
eta (Positive real, default 0.05) – Broadening.
- Returns:
ldos (Real ndarray, shape (len(energies), sites))
- get_fermi_level(n_electrons: float, temperature: float = 0.0) float[source]#
Get the Fermi level holding n_electrons electrons in the spectrum en (one electron per state; see tbkit.occupation.fermi_level).
- Parameters:
n_electrons (Positive real or zero) – Number of electrons.
temperature (Positive real or zero, default 0)
- Returns:
e_fermi (Real number)
- get_occupations(e_fermi: float, temperature: float = 0.0) NDArray[float64][source]#
Get the Fermi-Dirac occupation of every eigenstate of en.
- Parameters:
e_fermi (Real number) – Fermi level (see get_fermi_level).
temperature (Positive real or zero, default 0)
- Returns:
f (Real ndarray, same length as *en*)
- get_charge_density(e_fermi: float, temperature: float = 0.0) NDArray[float64][source]#
Get the electron density on every site, \(n_i = \sum_n f(E_n)\,|\psi_n(i)|^2\).
- Parameters:
e_fermi (Real number) – Fermi level.
temperature (Positive real or zero, default 0)
- Returns:
density (Real ndarray, shape (sites,))
- get_total_energy(e_fermi: float, temperature: float = 0.0) float[source]#
Get the band energy \(E = \sum_n f(E_n)\,E_n\).
- Parameters:
e_fermi (Real number) – Fermi level.
temperature (Positive real or zero, default 0)
- Returns:
energy (Real number)
- get_petermann() None[source]#
Get the Petermann factor:
\[K_n = \frac{\langle\psi_L^{n}|\psi_L^{n}\rangle\langle\psi_R^{n}|\psi_R^{n}\rangle}{|\langle\psi_L^{n}|\psi_R^{n}\rangle|^2}\, .\]Note
LA.eig fixes the norm such that \(\langle\psi_L^{n}|\psi_L^{n}\rangle = 1\) and \(\langle\psi_R^{n}|\psi_R^{n}\rangle = 1\).
- get_intensity_pola_max(tag_pola: str) NDArray[float64][source]#
Get the state with largest polarization on one sublattice.
- Parameters:
tag_pola (One-character string) – Sublattice tag.
- Returns:
intensity – Intensity of max polarized state on tag.
- get_intensity_pola_min(tag_pola: str) NDArray[float64][source]#
Get the state with smallest polarization on one sublattice.
- Parameters:
tag_pola (One-character string) – Sublattice tag.
- Returns:
intensity – Intensity of min polarized state on tag.
- get_intensity_en(lims: tuple[float, float]) NDArray[float64][source]#
Get, if any, the intensity of the sum of the states whose energies (real part) lie between lims[0] and lims[1].
- Parameters:
lims (List) – lims[0] energy min, lims[1] energy max.
- Returns:
intensity – Sum of the intensities between (lims[0], lims[1]).
- get_local_chern_marker(e_fermi: float = 0.0, area: float | None = None) NDArray[float64][source]#
Get the local Chern marker of the states below e_fermi (Bianco and Resta, Phys. Rev. B 84, 241106 (2011)),
\[C(\mathbf{r}_i) = -\frac{4\pi}{a}\,\mathrm{Im}\, \langle i|\,P\,x\,Q\,y\,P\,|i\rangle\, ,\]with \(P\) the projector on the occupied states, \(Q = 1-P\), and \(a\) the area per site. Averaged over the bulk of a finite flake – even a disordered or amorphous one, where no Brillouin zone exists – it gives the Chern number, in the sign convention of KSpace.chern_number; it sums to zero over the whole flake, the edges carrying the opposite value.
- Parameters:
e_fermi (Real number, default 0) – Fermi energy: the states with energies below it are occupied.
area (Positive real number) – Default value None: the area of the unit cell of lat divided by its number of sites.
- Returns:
marker (Real ndarray, shape (sites,))
- get_bott_index(e_fermi: float = 0.0) float[source]#
Get the Bott index of the states below e_fermi of a 2D lattice with periodic boundaries along both primitive vectors (Loring and Hastings, EPL 92, 67004 (2010); see tbkit.topology.bott_index): the Chern number of a torus, in the sign convention of KSpace.chern_number, and an integer for any disordered sample whose occupied states are gapped or localized.
- Parameters:
e_fermi (Real number, default 0) – Fermi energy.
- Returns:
bott (Real number, close to an integer)
Examples
Example usage:
lat = lattices.honeycomb() lat.get_lattice(12, 12) sys = System(lat, periodic=True) sys.set_hopping([{'n': 1, 't': 1.}]) ... sys.get_ham() sys.get_bott_index()
tbkit.kspace module#
- tbkit.kspace.PAULI = {'0': array([[1.+0.j, 0.+0.j], [0.+0.j, 1.+0.j]]), 'x': array([[0.+0.j, 1.+0.j], [1.+0.j, 0.+0.j]]), 'y': array([[ 0.+0.j, -0.-1.j], [ 0.+1.j, 0.+0.j]]), 'z': array([[ 1.+0.j, 0.+0.j], [ 0.+0.j, -1.+0.j]])}#
Pauli matrices (plus the identity, key
'0'), for building spinful hoppings/onsite terms (spin-orbit coupling, Zeeman splitting, …) whenKSpaceis constructed withspin=True.
- tbkit.kspace.reciprocal_vectors(prim_vec: Sequence[tuple[float, ...]]) list[tuple[float, ...]][source]#
Get the reciprocal lattice vectors \(\mathbf{b}_i\) such that \(\mathbf{a}_i\cdot\mathbf{b}_j = 2\pi\delta_{ij}\), lying in the span of the \(\mathbf{a}_i\).
- Parameters:
prim_vec (List of one/two/three tuples) – Primitive vectors (see class lattice).
- Returns:
rec_vec (List of one/two/three tuples) – Reciprocal vectors, with as many components as the primitive vectors.
- class tbkit.kspace.KSpace(lat: Lattice, spin: bool = False)[source]#
Bases:
objectBuild and solve the Tight-Binding Bloch Hamiltonian \(H(\mathbf{k})\) of a periodic lattice defined by the class lattice.
Hoppings are defined between orbitals of the unit cell, separated by a lattice vector \(\mathbf{R} = n_1\mathbf{a}_1+n_2\mathbf{a}_2\):
\[H_{ij}(\mathbf{k}) = \sum_{\mathbf{R}} t_{ij}(\mathbf{R})\, e^{i\mathbf{k}\cdot\mathbf{R}}\]- Parameters:
lat (*lattice class instance*) – Only unit_cell and prim_vec are used (the instance need not call get_lattice).
spin (Boolean, default False) – If True, every site of unit_cell carries a spin-1/2 degree of freedom (norb doubles to
2*len(unit_cell), ordered site-major: orbitals2*i, 2*i+1are the up/down components of site i). set_onsite and set_hopping then accept 2x2 (spin) matrices in addition to plain numbers, to build spin-orbit coupling or Zeeman terms – seePAULIfor ready-made Pauli matrices.
Examples
Example usage:
# graphene, nearest-neighbor hopping t DX, DY = 0.5 * 3 ** 0.5, 0.5 unit_cell = [{'tag': 'a', 'r0': (0., 0.)}, {'tag': 'b', 'r0': (DX, DY)}] prim_vec = [(2*DX, 0.), (DX, 1.5)] lat = Lattice(unit_cell=unit_cell, prim_vec=prim_vec) gra = KSpace(lat) gra.set_hopping([{'i': 0, 'j': 1, 'R': (0, 0), 't': 1.}, {'i': 0, 'j': 1, 'R': (-1, 0), 't': 1.}, {'i': 0, 'j': 1, 'R': (0, -1), 't': 1.}])
- workers = 1#
- rec_vec_k#
Reciprocal vectors in the k coordinates used by get_ham (rows).
- set_params(**params) None[source]#
Set the parameters of the value functions of set_hopping: every method (get_bands, chern_number, finite_ham, …) then uses these values. get_ham also takes them per call.
- Parameters:
params – Parameter values, added to (or replacing those of) params.
Examples
Example usage:
ks.set_params(m=0.5) ks.chern_number()
- set_onsite(dict_onsite: dict[str, complex | Sequence[complex]]) None[source]#
Set the onsite energies, by sublattice tag.
- Parameters:
dict_onsite (Dictionary) – key: tag, val: onsite energy (a plain number), or, if
spin=True, a plain number (applied equally to both spins), a pair(E_up, E_down)of numbers (a spin splitting along z), or a 2x2 complex matrix (a general spin structure, e.g. an in-plane Zeeman field built fromPAULI). A complex onsite energy (gain/loss), or a non-Hermitian 2x2 block, makes \(H(\mathbf{k})\) non-Hermitian: get_bands then returns complex energies, sorted by their real part.
Examples
Example usage:
kag.set_onsite({'a': 1., 'b': -1.}) # spinful: same onsite energy for both spins on 'a', a Zeeman # splitting along z on 'b': kag_spin.set_onsite({'a': 1., 'b': (1., -1.)}) # spinful: an in-plane Zeeman field on 'a': kag_spin.set_onsite({'a': Bx*PAULI['x']})
- set_hopping(list_hop: list[dict], hermitian: bool = True) None[source]#
Set the hoppings between orbitals of the unit cell.
Only one representative of each hopping needs to be given: its Hermitian conjugate (\(j\to i\), \(\mathbf{R}\to-\mathbf{R}\)) is added automatically (unless
hermitian=False).- Parameters:
list_hop – List of dictionaries with keys (‘i’, ‘j’, ‘R’, ‘t’):
‘i’, ‘j’: Positive integers. Site indices within the unit cell (following the order of unit_cell).
‘R’: Tuple of one/two integers \((n_1, n_2)\). Lattice vector \(\mathbf{R}=n_1\mathbf{a}_1+n_2\mathbf{a}_2\) separating the two sites.
‘t’: Complex number, or, if
spin=True, either a complex number (spin-independent hopping) or a 2x2 complex matrix (a general, possibly spin-mixing, hopping – e.g. built fromPAULIfor Rashba or intrinsic spin-orbit coupling). Or a value functiont(site_i, site_j, **params), evaluated byget_ham(k, **params)(and by every other method, with the parameters of set_params): site_i and site_j are structured arrays of the bonds’ end points, site_i in the home cell and site_j in cell \(\mathbf{R}\) (fields ‘x’, ‘y’, (‘z’), ‘tag’, ‘index’ – the site index within unit_cell). It is called once with every bond of the dictionaries that share it, and returns one value, or one per bond (or, ifspin=True, a 2x2 matrix, or one per bond).
list_hop may instead use the neighbour-order form of System.set_hopping: dictionaries with keys (‘n’, ‘t’) and optionally ‘ang’ and/or ‘tag’ – ‘n’ the neighbour order (1st, 2nd, … shortest distance between orbitals of the infinite lattice), ‘ang’ a bond angle in degrees, ‘tag’ a sublattice pair such as
'ab'. The bonds are found from unit_cell and prim_vec (in 1D, 2D and 3D) and turned into the explicit form by tbkit.neighbours.neighbour_hoppings (see there for the bond orientations; a negative angle addresses the reversed bonds). A list uses one form or the other, not both.hermitian (Boolean, default True) – If False, the Hermitian conjugates are not added: each dictionary is one matrix element \(H_{ij}(\mathbf{R})\) only, so that non-reciprocal (non-Hermitian) hoppings can be built – give the reverse hopping explicitly, with its own amplitude.
Examples
Example usage:
# graphene, by neighbour order: nearest (t) and next-nearest # (t2) neighbours, as in System.set_hopping gra.set_hopping([{'n': 1, 't': t}, {'n': 2, 't': t2}]) # square lattice, anisotropic nearest neighbours sq.set_hopping([{'n': 1, 'ang': 0., 't': tx}, {'n': 1, 'ang': 90., 't': ty}]) # 1D chain, nearest-neighbor hopping t between the only orbital # and its right neighbor: chain.set_hopping([{'i': 0, 'j': 0, 'R': (1,), 't': 1.}]) # spinful: spin-independent hopping t, plus a Rashba-like # spin-flip term of strength alpha: chain_spin.set_hopping([{'i': 0, 'j': 0, 'R': (1,), 't': t*PAULI['0'] + 1j*alpha*PAULI['y']}]) # value function: a staggered hopping, swept without rebuilding chain.set_hopping([{'n': 1, 't': lambda si, sj, t, d: t + d * (-1) ** si['index']}]) ham = chain.get_ham((0.,), t=1., d=0.2)
- set_overlap(list_hop: list[dict]) None[source]#
Set the overlaps \(s_{ij}(\mathbf{R}) = \langle i,\mathbf{0}|j,\mathbf{R}\rangle\) of a non-orthogonal basis, in the format of set_hopping (key ‘t’ for the overlap; the Hermitian conjugates are added):
\[S(\mathbf{k}) = \mathbb{1} + \sum_{\mathbf{R}} s(\mathbf{R})\,e^{i\mathbf{k}\cdot\mathbf{R}}\, ,\]after which the bands solve \(H(\mathbf{k})v = E\,S(\mathbf{k})v\). (With graphene’s nearest-neighbour overlap \(s\), the \(\pi\) bands become \(E = (\epsilon \pm t|f|)/(1 \pm s|f|)\): no longer symmetric about \(\epsilon\).) The topological tools use the Lowdin-orthonormalized states \(S^{1/2}v\).
- Parameters:
list_hop – List of dictionaries (‘i’, ‘j’, ‘R’, ‘t’), or by neighbour order (‘n’, ‘t’, optionally ‘ang’, ‘tag’), see set_hopping (numbers only, no value functions).
- get_overlap(k: ArrayLike) NDArray[complex128][source]#
Get the overlap matrix \(S(\mathbf{k})\) (the identity for an orthogonal basis), see set_overlap.
- Parameters:
k (k point (see *get_ham)*)
- Returns:
S (Complex ndarray, shape (norb, norb))
- clear_hopping() None[source]#
Clear the hoppings set by set_hopping (and the overlaps of set_overlap).
- get_ham(k: ArrayLike, **params) NDArray[complex128][source]#
Get the dense Bloch Hamiltonian \(H(\mathbf{k})\).
- Parameters:
k (Tuple/list/ndarray of *dim real numbers*) – When the lattice fills its space (2D in the plane, 3D in space), the \(\mathbf{k}\) point in the same Cartesian frame as prim_vec. In 1D, the crystal momentum along the primitive vector (so the Brillouin zone spans \(2\pi/|\mathbf{a}_1|\)), which coincides with \(k_x\) for a chain aligned with \(x\). For a 2D lattice in 3D space (a slab), the components along the orthonormal basis k_basis of its plane (the first along \(\mathbf{a}_1\)). rec_vec_k holds the reciprocal vectors in these coordinates.
params – Values of the parameters of the value functions of set_hopping, for this call only: they override those of set_params. Each function gets the ones its signature names (all of them with
**kwargs); the others are ignored.
- Returns:
ham (Complex ndarray, shape (norb, norb))
Examples
Example usage:
hams = [ks.get_ham((0., 0.), m=m) for m in np.linspace(-1., 1., 21)]
- get_ham_peierls(k: ArrayLike, A: ArrayLike) NDArray[complex128][source]#
Get the Bloch Hamiltonian in a uniform vector potential \(\mathbf{A}\) (\(\hbar = e = 1\)): every hopping picks up the Peierls phase \(e^{i\mathbf{A}\cdot\mathbf{d}}\) of its bond vector \(\mathbf{d} = \mathbf{R} + \boldsymbol\tau_j - \boldsymbol\tau_i\) (see System.set_peierls_phase). A time-dependent \(\mathbf{A}(t)\) is a uniform electric field \(-\partial_t\mathbf{A}\), e.g. light (see tbkit.floquet).
- Parameters:
k (k point (see *get_ham)*)
A (Tuple/ndarray of space_dim real numbers) – Vector potential.
- Returns:
ham (Complex ndarray, shape (norb, norb))
- get_bands(ks: ArrayLike, eigenvec: bool = False) NDArray[float64] | tuple[NDArray[float64], NDArray[complex128]][source]#
Diagonalize \(H(\mathbf{k})\) over a set of k-points, and keep the result for plot_bands (plotted against the cumulative distance between consecutive k-points).
- Parameters:
ks (ndarray, shape (nk, dim)) – k-points.
eigenvec (Boolean, default False) – If True, also return the eigenvectors.
- Returns:
en (Real ndarray, shape (nk, norb)) – Band energies, sorted ascending. Complex, and sorted by real part, if \(H(\mathbf{k})\) is non-Hermitian (complex onsite energies, see set_onsite).
vn (Complex ndarray, shape (nk, norb, norb), only if *eigenvec is True*) – vn[k, :, n] is the nth (right) eigenvector at ks[k].
- set_workers(workers: int) None[source]#
Set the number of threads that diagonalize \(H(\mathbf{k})\) over many k-points (get_bands, mesh_bands, berry_curvature, the Wilson loops, …). The k-points are split into chunks, each diagonalized by one stacked LAPACK call, which releases the GIL, so the chunks run in parallel. The results depend on workers only up to rounding (and the phases of the eigenvectors).
- Parameters:
workers (Positive integer) – Number of threads (default 1, no threads).
Examples
Example usage:
ks.set_workers(4) curv = ks.berry_curvature(0, nk=400)
- is_hermitian() bool[source]#
Check whether \(H(\mathbf{k})\) is Hermitian: it is, unless an onsite term is not, or set_hopping was called with
hermitian=False(such a model is always treated as non-Hermitian, and diagonalized with the general solver).- Returns:
hermitian (Boolean)
- k_path(points: list[ArrayLike], nk: int) tuple[NDArray[float64], NDArray[float64]][source]#
Build a k-path through a list of high-symmetry points, and get the associated bands.
- Parameters:
points – List of at least two k-points (each a tuple/list of dim real numbers), e.g. from high_symmetry_path.
nk (Positive integer) – Number of k-points per path segment.
- Returns:
ks_dist (Real ndarray) – Cumulative distance along the path, to be used as the x-axis of a band-structure plot.
en (Real ndarray, shape (len(ks_dist), norb)) – Band energies.
- mesh_grid(nk: int | tuple[int, ...], monkhorst_pack: bool = False) tuple[list[NDArray[float64]], NDArray[float64]][source]#
Build a uniform grid of fractional coordinates spanning the Brillouin zone, and the corresponding Cartesian k-points. By default the grid contains \(\Gamma\): \(r/q\), \(r = 0, \dots, q-1\) (each in [0, 1)). With monkhorst_pack, it is the grid of Monkhorst and Pack (Phys. Rev. B 13, 5188 (1976)), \((2r - q - 1)/2q\), \(r = 1, \dots, q\) (each in (-1/2, 1/2)), symmetric about \(\Gamma\): the same points for odd \(q\), shifted by half a step (off \(\Gamma\) and the zone boundary) for even \(q\). Both integrate exactly every Fourier component \(e^{i\mathbf{k}\cdot\mathbf{R}}\) with \(|R_i| < q\).
- Parameters:
nk (Positive integer, or tuple of *dim positive integers*) – Number of k-points along each reciprocal lattice vector.
monkhorst_pack (Boolean, default False) – If True, the Monkhorst-Pack grid.
- Returns:
fracs – List of dim real ndarrays, shape (nk1, nk2) each (or (nk1,) in 1D): fractional coordinates of the grid.
ks (Real ndarray, shape (nk1*nk2, dim) (or (nk1, dim) in 1D))
- mesh_bands(nk: int | tuple[int, ...], monkhorst_pack: bool = False) NDArray[float64][source]#
Diagonalize \(H(\mathbf{k})\) over a uniform mesh spanning the Brillouin zone. Unlike get_bands, it leaves the band structure kept for plot_bands untouched.
- Parameters:
nk (Positive integer, or tuple of *dim positive integers*) – Number of k-points along each reciprocal lattice vector.
monkhorst_pack (Boolean, default False) – If True, the Monkhorst-Pack grid (see mesh_grid).
- Returns:
en (Real ndarray, shape (nk1*nk2, norb)) – Band energies over the mesh (flattened).
- get_fermi_level(n_electrons: float, nk: int | tuple[int, ...] = 30, temperature: float = 0.0) float[source]#
Get the Fermi level holding n_electrons electrons per unit cell (one electron per band and k-point), from the bands over a uniform Brillouin-zone mesh (see tbkit.occupation.fermi_level).
- Parameters:
n_electrons (Positive real or zero, at most norb) – Electrons per unit cell.
nk (Positive integer, or tuple, default 30) – k-mesh.
temperature (Positive real or zero, default 0)
- Returns:
e_fermi (Real number)
- berry_curvature(bands: int | list[int], nk: int | tuple[int, int] = 30, plane: tuple[int, int] = (0, 1), k_fixed: float = 0.0) NDArray[float64][source]#
Get the Berry curvature of a group of bands over a uniform Brillouin-zone mesh, using the gauge-invariant lattice method of Fukui, Hatsugai and Suzuki (J. Phys. Soc. Jpn. 74, 1674 (2005)): the flux through each mesh plaquette is minus the phase of the product of the (Slater-determinant) overlaps between the occupied subspaces at its four corners,
\[\Omega_{\square} = -\arg\prod_{\langle\mathbf{k}\mathbf{k}'\rangle\in\partial\square} \det\langle u(\mathbf{k})|u(\mathbf{k}')\rangle\, ,\]the corners being visited counterclockwise. This is the discrete version of \(\Omega = \partial_{k_x}A_y - \partial_{k_y}A_x\), \(\mathbf{A} = i\langle u|\nabla_{\mathbf{k}}u\rangle\), and does not depend on the orientation (handedness) of prim_vec. The local curvature is that of the periodic gauge of get_ham (orbitals on the cell origin), which differs point by point from the one with the orbital positions included (see quantum_geometric_tensor); their integral, the Chern number, is the same. For a non-Hermitian \(H(\mathbf{k})\) (see set_onsite), the bands are ordered by the real part of their energy and the overlaps are taken between right eigenvectors (the “RR” curvature of biorthogonal_berry_curvature). That ordering follows the bands continuously only if a real line gap separates bands from the others over the whole zone: without one (an imaginary line gap, or exceptional points), a ValueError is raised instead of a meaningless result – see biorthogonal_berry_curvature.
- Parameters:
bands (Positive integer, or list of positive integers) – Band index, or indices of a group of bands (e.g. all occupied bands below a gap).
nk (Positive integer, or tuple of 2 positive integers, default 30) – Number of k-points along each of the two reciprocal lattice vectors spanning the plane.
plane (Tuple of two distinct integers) – Default value (0, 1). 3D lattices only: the reciprocal vectors \(\mathbf{b}_i, \mathbf{b}_j\) spanning the plane of the Brillouin zone. The flux is oriented along the remaining primitive vector \(\mathbf{a}_l\) (along +z in 2D).
k_fixed (Real number, default 0) – 3D lattices only: the fractional coordinate of the plane along the remaining reciprocal vector \(\mathbf{b}_l\) (e.g. \(k_z\) in units of \(|\mathbf{b}_3|\) for
plane=(0, 1)).
- Returns:
curv (Real ndarray, shape (nk1, nk2)) – Berry curvature (flux through each plaquette, in radians). Summing curv and dividing by \(2\pi\) gives the Chern number, see chern_number.
- biorthogonal_berry_curvature(bands: int | list[int], nk: int | tuple[int, int] = 30, kind: str = 'LR', gap: str = 'real', plane: tuple[int, int] = (0, 1), k_fixed: float = 0.0) NDArray[float64][source]#
Get the Berry curvature of a group of bands of a (non-Hermitian) model from its right and left eigenvectors, \(H|R_n\rangle = E_n|R_n\rangle\) and \(H^\dagger|L_n\rangle = E_n^*|L_n\rangle\), normalized by \(\langle L_m|R_n\rangle = \delta_{mn}\) (Shen, Zhen and Fu, Phys. Rev. Lett. 120, 146402 (2018)). The four connections
\[\mathbf{A}^{\alpha\beta} = i\langle u^\alpha|\nabla_{\mathbf{k}}u^\beta\rangle\, , \qquad \alpha, \beta \in \{L, R\}\, ,\]have different curvatures point by point, but their integrals, the Chern numbers \(C^{LR} = C^{RL} = C^{RR} = C^{LL}\), are the same integer. The flux through each plaquette is computed as in berry_curvature (Fukui-Hatsugai-Suzuki), with the links \(\det\langle u^\alpha(\mathbf{k})|u^\beta(\mathbf{k}')\rangle\) (for RR and LL, the phase does not depend on the normalization). For a Hermitian model all four are the curvature of berry_curvature.
The bands are ordered at every k-point by the real part of their energy (gap = ‘real’) or by its imaginary part (‘imaginary’), and bands must be separated from the others by a line gap of that kind over the whole zone – a line \(\mathrm{Re}\,E = E_0\) (or \(\mathrm{Im}\,E = E_0\)) that no band crosses. Otherwise a ValueError is raised: the gap closes at exceptional points (see tbkit.exceptional.find_exceptional_points), where the Chern number can change.
- Parameters:
bands (Positive integer, or list of positive integers) – Band indices in the order set by gap.
nk (Positive integer, or tuple of 2 positive integers, default 30) – See berry_curvature.
kind (‘LR’, ‘RL’, ‘RR’ or ‘LL’, default ‘LR’) – \(\alpha\beta\) above.
gap (‘real’ or ‘imaginary’, default ‘real’) – Kind of line gap, and the order of the bands.
plane (Tuple of two integers) – Default value (0, 1). 3D only, see berry_curvature.
k_fixed (Real number, default 0) – 3D only, see berry_curvature.
- Returns:
curv (Real ndarray, shape (nk1, nk2)) – Flux through each plaquette, in radians (sign convention of berry_curvature).
- biorthogonal_chern_number(bands: int | list[int], nk: int | tuple[int, int] = 30, kind: str = 'LR', gap: str = 'real', plane: tuple[int, int] = (0, 1), k_fixed: float = 0.0) float[source]#
Get the Chern number of a line-gapped group of bands of a (non-Hermitian) model, \(C^{\alpha\beta} = \frac{1}{2\pi}\int_{BZ} \Omega^{\alpha\beta}\,d^2k\), the same integer for the four kinds LR, RL, RR, LL (see biorthogonal_berry_curvature). It equals the Hermitian Chern number of chern_number as long as the line gap stays open.
- Parameters:
bands – See biorthogonal_berry_curvature.
nk – See biorthogonal_berry_curvature.
kind (‘LR’, ‘RL’, ‘RR’ or ‘LL’, default ‘LR’)
gap (‘real’ or ‘imaginary’, default ‘real’)
plane – See berry_curvature.
k_fixed – See berry_curvature.
- Returns:
chern (Real number, close to an integer)
- chern_number(bands: int | list[int], nk: int | tuple[int, int] = 30, plane: tuple[int, int] = (0, 1), k_fixed: float = 0.0) float[source]#
Get the Chern number of a group of bands:
\[C = \frac{1}{2\pi}\int_{BZ} \Omega(\mathbf{k})\, d^2k\]an integer (up to the numerical precision set by nk) for a group of bands that is isolated from the rest of the spectrum by a gap everywhere in the Brillouin zone. See berry_curvature. For a non-Hermitian model, bands (ordered by Re E) must be isolated by a real line gap, or a ValueError is raised; biorthogonal_chern_number also handles imaginary line gaps and the left eigenvectors.
- Parameters:
bands (Positive integer, or list of positive integers) – Band index, or indices of a group of bands (e.g. all occupied bands below a gap).
nk (Positive integer, or tuple of 2 positive integers, default 30) – Number of k-points along each reciprocal lattice vector.
plane (Tuple of two integers) – Default value (0, 1). 3D lattices only, see berry_curvature.
k_fixed (Real number, default 0) – 3D lattices only, see berry_curvature: the Chern number of the plane at this fractional coordinate (it jumps across a Weyl point).
- Returns:
chern (Real number, close to an integer)
- sector_chern_numbers(op, bands: int | list[int], nk: int | tuple[int, int] = 30, plane: tuple[int, int] = (0, 1), k_fixed: float = 0.0) tuple[float, float][source]#
Get the Chern numbers of the two sectors into which a Hermitian operator \(O\) splits a group of bands: at every k-point, the projected operator \(P(\mathbf{k})\,O\,P(\mathbf{k})\) (\(P\) the projector on bands) is diagonalized within the bands, and its eigenvectors with positive and negative eigenvalues span the two sectors, whose Chern numbers \(C_\pm\) follow as in berry_curvature. They are well defined as long as the spectrum of \(POP\) keeps a gap around zero over the whole plane, even if \(O\) does not commute with \(H\) (Prodan, Phys. Rev. B 80, 125327 (2009)); otherwise a ValueError is raised. See spin_chern_number and mirror_chern_number.
- Parameters:
op – Complex ndarray, shape (norb, norb), or callable of k returning one: the Hermitian operator \(O\).
bands (Band index, or list of band indices)
nk (Positive integer, or tuple of 2 positive integers, default 30)
plane (Tuple of two integers) – Default value (0, 1). 3D only, see berry_curvature.
k_fixed (Real number, default 0) – 3D only, see berry_curvature.
- Returns:
c_plus – Real number, close to an integer: Chern number of the sector with \(POP > 0\).
c_minus (Real number: that of the sector with \(POP < 0\)) – \(C_+ + C_-\) is the Chern number of bands.
- spin_chern_number(bands: list[int], nk: int | tuple[int, int] = 30, s_z=None, plane: tuple[int, int] = (0, 1), k_fixed: float = 0.0) float[source]#
Get the spin Chern number of a group of bands (Prodan, Phys. Rev. B 80, 125327 (2009); Sheng, Weng, Sheng and Haldane, Phys. Rev. Lett. 97, 036808 (2006)),
\[C_s = \frac{C_+ - C_-}{2}\, ,\]with \(C_\pm\) the Chern numbers of the two sectors of the projected spin operator \(Ps_zP\) (see sector_chern_numbers). When \(s_z\) is conserved they are the Chern numbers of the two spins; Rashba coupling mixes the spins, but \(C_s\) stays quantized, and unchanged, as long as the spectrum of \(Ps_zP\) keeps a gap around zero. With time reversal, \(C_s\) modulo 2 is the \(\mathbb{Z}_2\) invariant of z2_invariant.
- Parameters:
bands (List of band indices (e.g. the occupied bands))
nk (Positive integer, or tuple of 2 positive integers, default 30)
s_z (Complex ndarray, shape (norb, norb), or callable of k) – Default value None: \(\sigma_z\) on every site of a model built with
spin=True. The spin operator.plane (Tuple of two integers) – Default value (0, 1). 3D only, see berry_curvature.
k_fixed (Real number, default 0) – 3D only, see berry_curvature.
- Returns:
c_s (Real number, close to an integer)
- mirror_chern_number(mirror, bands: list[int], nk: int | tuple[int, int] = 30, plane: tuple[int, int] = (0, 1), k_fixed: float = 0.0, tol: float = 1e-08) float[source]#
Get the mirror Chern number of a group of bands on a mirror-invariant plane of the Brillouin zone (Teo, Fu and Kane, Phys. Rev. B 78, 045426 (2008); Hsieh et al., Nat. Commun. 3, 982 (2012)),
\[n_M = \frac{C_{+} - C_{-}}{2}\, ,\]with \(C_\pm\) the Chern numbers of the bands of mirror eigenvalue \(+i\) and \(-i\) (\(M^2 = -1\), spinful electrons) or \(+1\) and \(-1\) (\(M^2 = +1\)). The mirror must commute with \(H(\mathbf{k})\) at every point of the plane: in 3D, the plane fixed by the reflection (e.g. \(k_z = 0\) or \(\pi\) for \(z\to-z\)); in 2D, the whole zone, for a reflection of the third axis. A topological crystalline insulator such as SnTe has \(n_M = 2\) and every \(\mathbb{Z}_2\) index zero (\(\nu = n_M\) modulo 2 on the plane).
- Parameters:
mirror – Complex ndarray, shape (norb, norb), or callable of k: the unitary mirror operator \(M\), with \(M^2 = \pm1\).
bands (List of band indices (e.g. the occupied bands))
nk (Positive integer, or tuple of 2 positive integers, default 30)
plane (Tuple of two integers) – Default value (0, 1). 3D only, see berry_curvature.
k_fixed (Real number, default 0) – 3D only: the mirror-invariant plane (0 or 0.5 for a reflection of the remaining axis).
tol (Positive real, default 1e-8) – Tolerance of the checks \(M^2 = \pm1\) and \([M, H(\mathbf{k})] = 0\).
- Returns:
n_m (Real number, close to an integer)
- hall_conductivity(e_fermi: float | ArrayLike, temperature: float = 0.0, nk: int | tuple[int, ...] = 60, plane: tuple[int, int] = (0, 1), k_fixed: float | None = None, positions: bool = True, refine: int = 1, refine_fraction: float = 0.05) float | NDArray[float64][source]#
Get the intrinsic anomalous Hall conductivity at any Fermi level – in a gap, in a band, or at a band crossing – from the Kubo formula over a uniform Brillouin-zone mesh,
\[\sigma_{xy} = \frac{e^2}{\hbar}\int_{BZ}\frac{d^dk}{(2\pi)^d}\, F(\mathbf{k})\, ,\qquad F = -\sum_{n\neq m}(f_n - f_m)\, \frac{\mathrm{Im}\left[\langle n|\partial_x H|m\rangle\langle m|\partial_y H|n\rangle\right]} {(E_n - E_m)^2} = \sum_n f_n\,\Omega_n\, ,\]with \(f_n = f(E_n)\) the Fermi-Dirac occupations and
\[\Omega_n = -2\,\mathrm{Im}\sum_{m\neq n} \frac{\langle n|\partial_x H|m\rangle\langle m|\partial_y H|n\rangle}{(E_n-E_m)^2} = -2\,\mathrm{Im}\langle\partial_x u_n|\partial_y u_n\rangle\]the Berry curvature of band n (\(\partial_\mu H = \partial H/\partial k_\mu\), the convention \(\Omega = \partial_xA_y - \partial_yA_x\), \(\mathbf{A} = i\langle u|\nabla_{\mathbf{k}}u\rangle\) of berry_curvature). The form with \(f_n - f_m\) stays finite where bands touch: degenerate pairs have equal occupations and drop out, instead of cancelling between two diverging \(\Omega_n\). \(\partial H/\partial\mathbf{k}\) is built analytically from the stored hoppings, \(\sum_{\mathbf{R}} i\mathbf{d}\,t\,e^{i\mathbf{k}\cdot\mathbf{d}}\) with the Cartesian bond vector \(\mathbf{d}\).
Sign. In a gap, \(\sigma_{xy} = C\,e^2/h\) with \(C\) the value chern_number returns for the occupied bands: this is the sign of TKNN (Phys. Rev. Lett. 49, 405 (1982)), whose \(\sigma_H = (e^2/h)\,\frac{i}{2\pi}\int d^2k\,(\langle\partial_1u|\partial_2u\rangle - \langle\partial_2u|\partial_1u\rangle)\) has the same integrand, \(\Omega/2\pi\). The adiabatic (semiclassical) response of a charge \(q\) of either sign, \(\dot{\mathbf{r}} = \partial_{\mathbf{k}}E - \dot{\mathbf{k}}\times\boldsymbol\Omega\) with \(\hbar\dot{\mathbf{k}} = q\mathbf{E}\), gives the opposite sign for the tensor of Ohm’s law \(j_x = \sigma^{\mathrm{Ohm}}_{xy}E_y\): \(\sigma^{\mathrm{Ohm}}_{xy} = -(q^2/\hbar)\int F\,d^dk/(2\pi)^d\), the convention of Wang, Yates, Souza and Vanderbilt (Phys. Rev. B 74, 195118 (2006)) and of the Kubo-Bastin formula (tbkit.kpm.hall_conductivity returns, likewise, minus it). So the value returned is \(\sigma^{\mathrm{Ohm}}_{yx} = -\sigma^{\mathrm{Ohm}}_{xy}\); e.g. a massive Dirac cone \(v(k_x\sigma_x + k_y\sigma_y) + m\sigma_z\) gives \(+\frac{e^2}{2h}\frac{m}{|E_F|}\) outside its gap (the literature’s \(\sigma_{xy} = -\frac{e^2}{2h}\frac{m}{|E_F|}\)), and \(\frac{e^2}{2h}\mathrm{sgn}(m)\) inside.
Orbital positions. The velocity is \(\partial H/\partial\mathbf{k}\) in the gauge of positions: with
positions=True(the default) the bond vector is \(\mathbf{d} = \mathbf{R} + \boldsymbol\tau_j - \boldsymbol\tau_i\), the matrix of the physical velocity \(i[H, \mathbf{r}]\) of a tight-binding model whose position operator is diagonal on its orbitals (the one kpm.hall_conductivity uses on a torus). Withpositions=False, every orbital sits on its cell origin (the periodic gauge of get_ham). The two differ by \(i(E_n-E_m)\langle n|\boldsymbol\tau|m\rangle\) in the velocity’s matrix elements, so the band curvatures differ by \(\nabla\times\langle n|\boldsymbol\tau|n\rangle\), a total derivative: the conductivities agree whenever the bands below \(E_F\) are all full (in a gap, at any temperature well below the gap) and differ in general at partial filling, by the circulation \(\frac{1}{2\pi}\oint_{FS}\langle n|\boldsymbol\tau|n\rangle\cdot d\mathbf{k}\) around the Fermi surface. The default is the physical one.Units and dimensions. In 2D, \(\sigma\) is in units of \(e^2/h\) (\(\frac{1}{2\pi}\int d^2k\,F\)). In 3D, with k_fixed given, the value of the plane (the conductance of that slice of the Brillouin zone, in \(e^2/h\), oriented like chern_number along \(\mathbf{a}_l\)); with
k_fixed=None, the full 3D conductivity as the Hall (pseudo)vector \((\sigma_{yz}, \sigma_{zx}, \sigma_{xy}) = \frac{1}{(2\pi)^2}\int d^3k\,\mathbf{F}\) in units of \(e^2/(h\cdot\mathrm{length})\) (length the unit of prim_vec): \(\frac{1}{2\pi}\sum_l\bar C_l\,\mathbf{b}_l\), e.g. \(C/c\) along \(z\) for a stack of Chern layers \(c\) apart.Convergence. The integrand peaks where bands nearly touch close to \(E_F\) (hot spots), and jumps across the Fermi surface. A temperature smooths the latter. refine resamples the fraction refine_fraction of mesh cells with the largest \(|F|\) on a finer submesh (refine points per direction), in the spirit of the adaptive mesh refinement of Wang, Yates, Souza and Vanderbilt (2006); the cells are ranked by the size of the curvature whatever the occupations. It is meant for metals: in a gap the plain uniform mesh already converges exponentially, and refining part of it costs a little accuracy (about \(4\cdot10^{-4}\) for the Haldane model on a 60 x 60 mesh). With an overlap (set_overlap), \(H\) is first Lowdin-orthogonalized, \(S^{-1/2}HS^{-1/2}\), as by the topology tools (exact derivatives of \(S^{-1/2}\) included).
- Parameters:
e_fermi (Real number, or array of real numbers) – Fermi energies (all of them are computed from one diagonalization of the mesh).
temperature (Positive real or zero, default 0) – In energy units (\(k_B = 1\)).
nk – Positive integer, or tuple (two integers for a plane, three for the full 3D conductivity). Default value 60. k-mesh.
plane (Tuple of two integers) – Default value (0, 1). 3D only: the reciprocal vectors spanning the plane (see berry_curvature).
k_fixed (Real number or None, default None) – 3D only: the fractional coordinate of the plane along the remaining reciprocal vector; None for the full 3D conductivity. Ignored in 2D.
positions (Boolean, default True) – Include the orbital positions in the bond vectors (see above).
refine (Positive integer) – Default value 1 (no refinement). Submesh points per direction in the refined cells.
refine_fraction (Real in (0, 1], default 0.05) – Fraction of the mesh cells that are refined.
- Returns:
sigma – Real number (or ndarray shaped like e_fermi); in 3D with
k_fixed=None, ndarray of shape (3,) (ore_fermi.shape + (3,)).
Examples
Example usage:
e_f = np.linspace(-3., 3., 301) sigma = hal.hall_conductivity(e_f, nk=120) # plateau at C in the gap
- spin_hall_conductivity(e_fermi: float | ArrayLike, temperature: float = 0.0, nk: int | tuple[int, int] = 60, plane: tuple[int, int] = (0, 1), k_fixed: float | None = None, positions: bool = True, spin_axis: str = 'z', refine: int = 1, refine_fraction: float = 0.05) float | NDArray[float64][source]#
Get the intrinsic spin Hall conductivity of a spinful model (
spin=True): the Kubo formula of hall_conductivity with the charge current along \(x\) replaced by the spin current (Sinova et al., Phys. Rev. Lett. 92, 126603 (2004))\[j^{s}_x = \tfrac12\{s, v_x\}\, ,\qquad s = \tfrac{\hbar}{2}\sigma_{a}\, ,\]i.e. \(\sigma^{s}_{xy} = \frac{e}{2\pi}\cdot\frac{1}{2\pi}\int d^2k\,F^s\), \(F^s = -\sum_{n\neq m}(f_n-f_m)\,\mathrm{Im}[\langle n|j^s_x|m\rangle\langle m|\partial_yH|n\rangle]/(E_n-E_m)^2\) (\(j^s_x\) with \(s = \sigma_a/2\), in units of \(\hbar\)). The unit is \(e/2\pi\): one \(e/\hbar\) from the electric field, one \(\hbar/2\) from the spin, and \(1/2\pi\) from the Brillouin-zone integral, as for \(e^2/h = (e^2/\hbar)/2\pi\). When \(s_z\) is conserved, the two spins decouple and \(j^s_x = \pm\frac{\hbar}{2}v_x\) in each, so in a gap \(\sigma^s_{xy} = \frac{e}{2\pi}\cdot\frac{C_\uparrow - C_\downarrow}{2}\), \(C_\sigma\) the Chern number of each spin sector (the sign of hall_conductivity and chern_number): \(\pm e/2\pi\) for the Kane-Mele quantum spin Hall insulator (Kane and Mele 2005). Rashba coupling breaks the conservation of \(s_z\), and the value is then no longer quantized (the \(\mathbb{Z}_2\) invariant, see z2_invariant, still is).
- Parameters:
e_fermi – See hall_conductivity.
temperature – See hall_conductivity.
nk (Positive integer, or tuple of 2 integers, default 60)
plane – See hall_conductivity.
k_fixed (Real number or None, default None) – 3D only: the plane (required in 3D, where only planes are computed).
positions (Boolean, default True) – See hall_conductivity.
spin_axis (‘x’, ‘y’ or ‘z’, default ‘z’) – Spin component \(a\) carried by the current.
refine – See hall_conductivity.
refine_fraction – See hall_conductivity.
- Returns:
sigma_s – Real number (or ndarray shaped like e_fermi), in units of \(e/2\pi\).
- orbital_magnetization(e_fermi: float | ArrayLike, temperature: float = 0.0, nk: int | tuple[int, ...] = 60, plane: tuple[int, int] = (0, 1), k_fixed: float | None = None, positions: bool = True, refine: int = 1, refine_fraction: float = 0.05) float | NDArray[float64][source]#
Get the orbital magnetization in the modern theory (Thonhauser, Ceresoli, Vanderbilt and Resta, Phys. Rev. Lett. 95, 137205 (2005); Xiao, Shi and Niu, Phys. Rev. Lett. 95, 137204 (2005); Ceresoli et al., Phys. Rev. B 74, 024408 (2006)), at any Fermi level and temperature:
\[M = \frac{e}{h}\,\frac{1}{2\pi}\int_{BZ} d^2k\sum_n\left[f_n\,m_n + g_n\,\Omega_n\right],\qquad m_n = \mathrm{Im}\langle\partial_xu_n|(H-E_n)|\partial_yu_n\rangle\, ,\]with \(g = k_BT\ln(1+e^{-(E-\mu)/k_BT})\) (\(\mu - E\) below \(\mu\) and 0 above, at \(T = 0\)). The first term is the self-rotation of the wavepackets, the second the circulation of the Berry-curvature currents at the edges. At \(T = 0\) both combine into \(\sum_nf_n\,\mathrm{Im}\langle\partial_xu_n|(H+E_n-2\mu)|\partial_yu_n\rangle\), the formula of Thonhauser et al. It is evaluated, like hall_conductivity, from \(\langle n|\partial H|m\rangle\) (no derivatives of the eigenstates), so it is finite where bands touch.
Sign and units. The sign is that of hall_conductivity, so that the Streda formula reads \(\partial M/\partial\mu = \sigma\): in a gap (\(T = 0\)), \(M\) is linear in \(\mu\) with slope the Chern number \(C\). In 2D, \(M\) (a magnetic moment per area, i.e. a current) is in units of \(e/h\) times the energy unit; with
k_fixed=Nonein 3D, the vector \((M_x, M_y, M_z)\) per length. positions matters as for hall_conductivity, and the physical choice is the default.- Parameters:
e_fermi – See hall_conductivity.
temperature – See hall_conductivity.
nk – See hall_conductivity.
plane – See hall_conductivity.
k_fixed – See hall_conductivity.
positions – See hall_conductivity.
refine – See hall_conductivity.
refine_fraction – See hall_conductivity.
- Returns:
M – Real number (or ndarray shaped like e_fermi); in 3D with
k_fixed=None, ndarray of shape (3,) (ore_fermi.shape + (3,)).
Examples
Example usage:
mu = np.linspace(-0.5, 0.5, 11) # in the gap of a Chern insulator M = hal.orbital_magnetization(mu) # slope C = hall_conductivity(mu)
- anomalous_nernst_conductivity(e_fermi: float | ArrayLike, temperature: float, nk: int | tuple[int, ...] = 60, plane: tuple[int, int] = (0, 1), k_fixed: float | None = None, positions: bool = True, refine: int = 1, refine_fraction: float = 0.05) float | NDArray[float64][source]#
Get the intrinsic anomalous Nernst (transverse thermoelectric) conductivity \(\alpha_{xy}\), \(j_x = \alpha_{xy}(-\partial_yT)\), from the Berry curvature weighted by the entropy of each state (Xiao, Yao, Fang and Niu, Phys. Rev. Lett. 97, 026603 (2006)):
\[\alpha_{xy} = \frac{ek_B}{h}\,\frac{1}{2\pi}\int_{BZ}d^2k\sum_n s_n\,\Omega_n\, , \qquad s = -f\ln f - (1-f)\ln(1-f)\, .\]Only the states within a few \(k_BT\) of \(\mu\) carry entropy, so it vanishes in a gap at low temperature. It obeys the Mott relation exactly, \(\alpha_{xy}(\mu, T) = \frac{1}{eT}\int dE\,(E-\mu)\left(-\frac{\partial f}{\partial E}\right)\sigma_{xy}(E)\), with \(\sigma_{xy}(E)\) the \(T = 0\) hall_conductivity at Fermi energy \(E\), which fixes the sign. The pair form of hall_conductivity keeps it finite where bands touch.
Units. \(ek_B/h\) in 2D (\(k_B = 1\), temperatures in energy units), per length for the 3D vector (
k_fixed=None).- Parameters:
e_fermi – See hall_conductivity.
temperature (Positive real number) – In energy units (\(k_B = 1\)).
nk – See hall_conductivity.
plane – See hall_conductivity.
k_fixed – See hall_conductivity.
positions – See hall_conductivity.
refine – See hall_conductivity.
refine_fraction – See hall_conductivity.
- Returns:
alpha (Real number (or ndarray, as *hall_conductivity)*)
Examples
Example usage:
alpha = hal.anomalous_nernst_conductivity(np.linspace(-3, 3, 301), 0.05)
- thermal_hall_conductivity(e_fermi: float | ArrayLike, temperature: float, nk: int | tuple[int, ...] = 60, plane: tuple[int, int] = (0, 1), k_fixed: float | None = None, positions: bool = True, refine: int = 1, refine_fraction: float = 0.05) float | NDArray[float64][source]#
Get the intrinsic thermal Hall conductivity of the electrons \(\kappa_{xy}\), \(j^Q_x = \kappa_{xy}(-\partial_yT)\) (Qin, Niu and Shi, Phys. Rev. Lett. 107, 236601 (2011)):
\[\kappa_{xy} = \frac{k_B^2T}{h}\,\frac{1}{2\pi}\int_{BZ}d^2k \sum_n c_2(x_n)\,\Omega_n\, ,\qquad c_2(x) = \int_x^\infty y^2\left(-\frac{\partial f}{\partial y}\right)dy\, ,\]\(x_n = (E_n-\mu)/k_BT\) (\(c_2 = \pi^2/3\) deep below \(\mu\), 0 far above). Equivalently, exactly, \(\kappa_{xy}(\mu, T) = \frac{1}{e^2T}\int dE\,(E-\mu)^2\left(-\frac{\partial f}{\partial E}\right)\sigma_{xy}(E)\) with the \(T = 0\) hall_conductivity. In a gap at low temperature it is the Wiedemann-Franz value \(\kappa_{xy} = \frac{\pi^2k_B^2}{3e^2}T\sigma_{xy}\): for a Chern insulator the quantized \(C\,\pi^2k_B^2T/3h\).
Units. \(k_B^2/h\) times the temperature (in energy units, \(k_B = 1\)) in 2D, so that \(\kappa/T = \pi^2C/3\) on a Chern plateau; per length for the 3D vector (
k_fixed=None). The sign is that of hall_conductivity.- Parameters:
e_fermi – See hall_conductivity.
temperature (Positive real number) – In energy units (\(k_B = 1\)).
nk – See hall_conductivity.
plane – See hall_conductivity.
k_fixed – See hall_conductivity.
positions – See hall_conductivity.
refine – See hall_conductivity.
refine_fraction – See hall_conductivity.
- Returns:
kappa (Real number (or ndarray, as *hall_conductivity)*)
Examples
Example usage:
kappa = hal.thermal_hall_conductivity(0., 0.01) # = pi^2/3 C T in the gap
- axion_angle(bands: list[int], param: str, values: ArrayLike, nk: int | tuple[int, int, int] = 16, theta0: float = 0.0, positions: bool = True) NDArray[float64][source]#
Get the axion angle \(\theta\) of a 3D insulator along a path of a parameter of its value functions (set_hopping), from the second Chern form (Qi, Hughes and Zhang, Phys. Rev. B 78, 195424 (2008); Essin, Moore and Vanderbilt, Phys. Rev. Lett. 102, 146805 (2009)):
\[\frac{d\theta}{d\lambda} = \frac{1}{2\pi}\int_{BZ}d^3k\; \mathrm{tr}\left[F_{\lambda x}F_{yz} + F_{\lambda y}F_{zx} + F_{\lambda z}F_{xy}\right],\]\(F_{\mu\nu}\) the non-Abelian Berry curvature of the bands bands in \((\lambda, k_x, k_y, k_z)\) space, so that \(\theta(\lambda) = \theta_0 + \int_{\lambda_0}^{\lambda}\frac{d\theta}{d\lambda'}d\lambda'\). This is the variation of the Chern-Simons axion coupling, computed from gauge-invariant quantities only (no smooth gauge is needed), and \(\theta_0\) is its value at
values[0]: e.g. 0 for a path starting from an atomic insulator. A closed path (a pumping cycle) changes \(\theta\) by \(2\pi C_2\), with \(C_2\) the second Chern number of the 4D family. At a point with time-reversal or inversion symmetry, \(\theta\) is 0 or \(\pi\) (mod \(2\pi\)): \(\pi\) for a strong topological insulator, cf. z2_indices_3d. The sign of \(\theta\) follows the orientation \((\lambda, k_x, k_y, k_z)\) above.The path must stay gapped: the bands bands must be separated from the others at every k-point and every value (a ValueError names the value where they touch). The integrand is smooth, so the uniform k-mesh converges exponentially; the \(\lambda\) integral is a trapezoid over values (error \(O(\Delta\lambda^2)\)). \(\partial H/\partial\lambda\) is a central difference, and \(\partial H/\partial\mathbf{k}\) is exact (see hall_conductivity, whose positions convention applies).
- Parameters:
bands (List of integers) – The occupied bands (e.g. the lower half of the spectrum).
param (String) – Name of the parameter of the value functions that the path varies (see set_params; the other parameters keep their values in params).
values (1D array of at least two real numbers, increasing or decreasing) – The parameter values along the path.
nk (Positive integer, or tuple of 3 positive integers, default 16) – k-mesh.
theta0 (Real number, default 0) – \(\theta\) at
values[0].positions (Boolean, default True) – See hall_conductivity.
- Returns:
theta – ndarray, shape
(len(values),): \(\theta\) at each value, not reduced modulo \(2\pi\).
Examples
Example usage:
phi = np.linspace(0., 2 * np.pi, 41) theta = ks.axion_angle([0, 1], 'phi', phi) # theta[-1] = 2 pi C2
- finite_ham(n_cells: int | tuple[int, ...], periodic: bool = False, sparse: bool = False) NDArray[complex128] | csr_matrix[source]#
Get the real-space Hamiltonian of a finite sample of \(N_1\times N_2\times\dots\) unit cells of the model – open boundaries (a flake, a finite chain), or periodic ones (a torus). Orbital o of cell \((n_1, n_2, n_3)\) is row \(((n_3 N_2 + n_2) N_1 + n_1)\,\mathrm{norb} + o\).
- Parameters:
n_cells (Positive integer, or tuple of *dim positive integers*)
periodic (Boolean, default False) – Periodic boundary conditions (the spectrum is then that of get_bands on the \(N_1\times N_2\times\dots\) k-mesh), else open ones.
sparse (Boolean, default False) – Return a sparse CSR matrix (for large samples, e.g. with tbkit.kpm) instead of a dense array.
- Returns:
ham – Complex ndarray (or CSR matrix), shape (N*norb, N*norb), N the number of cells.
- finite_velocity(n_cells: int | tuple[int, ...], periodic: bool = False, sparse: bool = False) list[NDArray[complex128] | csr_matrix][source]#
Get the velocity operators \(\mathbf{v} = i[H, \mathbf{r}]\) (\(\hbar = 1\)) of the finite sample of finite_ham, from the Cartesian bond vectors of the hoppings rather than from the site coordinates:
\[(v_\alpha)_{ab} = i\,H_{ab}\,d_\alpha\, ,\qquad \mathbf{d} = \mathbf{R} + \boldsymbol\tau_j - \boldsymbol\tau_i\, ,\]so that they are well defined on a torus (
periodic=True), where the position operator is not: a bond that wraps around the sample keeps its short displacement. They are the real-space counterpart of \(\partial H/\partial\mathbf{k}\) withpositions=True(hall_conductivity), and the input of tbkit.kpm.hall_conductivity.- Parameters:
n_cells – See finite_ham.
periodic (Boolean, default False) – See finite_ham.
sparse (Boolean, default False) – See finite_ham.
- Returns:
vel – List of space_dim complex ndarrays (or CSR matrices), shape (N*norb, N*norb): \(v_x, v_y, (v_z)\).
- get_ham_beta(beta: complex) NDArray[complex128][source]#
Get the non-Bloch Hamiltonian of a 1D model, \(H(\beta) = \sum_{n} t(n)\, \beta^{n}\): the Bloch Hamiltonian continued off the unit circle, \(\beta = e^{ik}\) with complex \(k\). On the generalized Brillouin zone (see gbz), its spectrum is the open-chain spectrum of a non-Hermitian chain.
- Parameters:
beta (Complex number, nonzero)
- Returns:
ham (Complex ndarray, shape (norb, norb))
- spectral_winding(e_ref: complex = 0.0, nk: int = 400) float[source]#
Get the spectral winding number of a 1D (non-Hermitian) model about the reference energy \(E_r\),
\[W(E_r) = \frac{1}{2\pi i}\oint_0^{2\pi} dk\, \partial_k \ln\det\left[H(k) - E_r\right]\, ,\]the number of times the periodic-chain spectrum winds around \(E_r\) in the complex plane. \(W \neq 0\) for some \(E_r\) is the criterion for the non-Hermitian skin effect: the open-chain eigenstates then pile up at one end (Okuma, Kawabata, Shiozaki and Sato, Phys. Rev. Lett. 124, 086801 (2020)).
- Parameters:
e_ref (Complex number, default 0) – Reference energy.
nk (Positive integer, default 400) – k-points.
- Returns:
W – Real number, close to an integer (it is ill defined if \(E_r\) lies on the periodic spectrum).
- gbz(energies: ArrayLike) NDArray[complex128][source]#
Get the generalized Brillouin zone of a 1D non-Hermitian model (Yao and Wang, Phys. Rev. Lett. 121, 086803 (2018); Yokomizo and Murakami, Phys. Rev. Lett. 123, 066404 (2019)): for each energy \(E\), the roots of \(\det[H(\beta)-E] = 0\) sorted by modulus, \(|\beta_1|\le\dots\le|\beta_{p+s}|\) (\(p\) the order of its pole at \(\beta = 0\)), and the middle pair \(\beta_p, \beta_{p+1}\). The open-chain spectrum, in the limit of a long chain, is where \(|\beta_p| = |\beta_{p+1}|\); those \(\beta\) trace the generalized Brillouin zone, on which the non-Bloch bands \(H(\beta)\) (see get_ham_beta) replace the Bloch ones. For a Hermitian model it is the unit circle.
- Parameters:
energies – Complex array of energies (e.g. open-chain eigenvalues from finite_ham).
- Returns:
beta (Complex ndarray, shape (len(energies), 2): \(\beta_p, \beta_{p+1}\))
- orbital_positions() NDArray[float64][source]#
Get the positions \(\boldsymbol\tau\) of the orbitals within the unit cell (each site twice, for its two spin components, if
spin=True).- Returns:
tau (Real ndarray, shape (norb, space_dim))
- berry_phase(bands: int | list[int], nk: int = 100, direction: int = 0, k_perp: float | tuple[float, float] | None = None, positions: bool = True) float[source]#
Get the Berry phase of a group of bands along a closed loop across the Brillouin zone, \(\mathbf{k}\to\mathbf{k}+\mathbf{b}_{direction}\),
\[\gamma = \oint \mathbf{A}\cdot d\mathbf{k} = -\arg\det W\, ,\qquad W = \prod_{m} \langle u(\mathbf{k}_m)|u(\mathbf{k}_{m+1})\rangle\, ,\]with \(\mathbf{A} = i\langle u|\nabla_{\mathbf{k}}u\rangle\) (the convention of berry_curvature). In 1D it is the Zak phase: its value \(\gamma/2\pi\), modulo 1, is the centre of the band’s Wannier functions in units of \(\mathbf{a}_{direction}\) (the polarization).
- Parameters:
bands (Band index, or list of band indices)
nk (Positive integer, default 100) – Number of k-points on the loop.
direction (Integer, default 0) – Reciprocal vector the loop follows.
k_perp (Real number (2D) or pair of real numbers (3D)) – Default value None (zero). Fractional coordinates of the loop along the other reciprocal vectors.
positions (Boolean, default True) – Include the orbital positions in the Bloch functions (the physical choice: the phase then locates the Wannier centres in the crystal). If False, all orbitals are placed on the cell origin (the periodic gauge of get_ham); the two differ by \(\sum_n\mathbf{b}\cdot\boldsymbol\tau\) weighted by the orbital content, and agree on quantized differences between phases.
- Returns:
gamma (Real number in \((-\pi, \pi]\))
- wannier_centers(bands: int | list[int], nk: int = 100, direction: int = 0, k_perp: float | tuple[float, float] | None = None, positions: bool = True) NDArray[float64][source]#
Get the (hybrid) Wannier centres of a group of bands: minus the phases of the eigenvalues of the Wilson loop (see berry_phase), divided by \(2\pi\). They are the positions, in units of \(\mathbf{a}_{direction}\) and modulo 1, of the maximally localized Wannier functions along that direction (hybrid: still Bloch waves along the others, at k_perp). Their sum is \(\gamma/2\pi\), modulo 1.
- Parameters:
bands (Band index, or list of band indices)
nk (Positive integer, default 100) – Number of k-points on the loop.
direction (Integer, default 0)
k_perp – See berry_phase.
positions (Boolean, default True) – See berry_phase.
- Returns:
centers (Real ndarray, sorted, in \([0, 1)\))
- wannier_flow(bands: int | list[int], nk: int = 100, nk_perp: int = 51, direction: int = 0, flow: int | None = None, k_fixed: float = 0.0, positions: bool = True, k_range: tuple[float, float] = (0.0, 1.0)) tuple[NDArray[float64], NDArray[float64]][source]#
Get the flow of the hybrid Wannier centres (see wannier_centers) along direction, as the loop is moved across the Brillouin zone along the reciprocal vector flow. In a Chern insulator the centres wind by \(C\) cells over a full period; in a \(\mathbb{Z}_2\) topological insulator, the Kramers pairs swap partners over half a period (see z2_invariant).
- Parameters:
bands (Band index, or list of band indices)
nk (Positive integer, default 100) – k-points on each loop.
nk_perp (Positive integer, default 51) – Number of loops.
direction (Integer, default 0) – Direction of the loops.
flow (Integer) – Default value None (the first other direction). Reciprocal vector along which the loops are moved.
k_fixed (Real number, default 0) – 3D only: fractional coordinate along the remaining reciprocal vector.
positions (Boolean, default True) – See berry_phase.
k_range (Pair of real numbers) – Default value (0, 1). Range of the fractional coordinate along flow (both ends included).
- Returns:
fracs (Real ndarray, shape (nk_perp,)) – Fractional coordinates along flow.
centers (Real ndarray, shape (nk_perp, len(bands))) – Sorted centres, in [0, 1).
- z2_invariant(bands: list[int], nk: int = 100, nk_perp: int = 51, direction: int = 0, flow: int | None = None, k_fixed: float = 0.0) int[source]#
Get the \(\mathbb{Z}_2\) invariant of a time-reversal-symmetric group of bands (an even number, e.g. all occupied bands of the Kane-Mele model) from the flow of its hybrid Wannier centres over half the Brillouin zone (Soluyanov and Vanderbilt, Phys. Rev. B 83, 235401 (2011); Yu, Qi, Bernevig, Fang and Dai, Phys. Rev. B 84, 075119 (2011)): follow the midpoint of the largest gap between the centres, and count, modulo 2, how many centres it jumps over. It is odd when the Kramers partners exchange along the flow – a topological insulator – and even otherwise.
Unlike the parity criterion (parity_z2), it needs no inversion symmetry, so it also works with Rashba coupling.
- Parameters:
bands (List of band indices (an even number of bands))
nk (Positive integer, default 100) – k-points on each loop.
nk_perp (Positive integer, default 51) – Number of loops over the half zone (the flow must be resolved finely enough that no two centres cross between neighbouring loops unnoticed).
direction (Integer, default 0) – See wannier_flow.
flow (Integer, default None) – See wannier_flow.
k_fixed (Real number, default 0) – 3D only: a time-reversal invariant plane has k_fixed 0 or 0.5 (the weak and strong indices follow from the six such planes).
- Returns:
nu (0 (trivial) or 1 (topological))
- z2_indices_3d(bands: list[int], nk: int = 100, nk_perp: int = 51) tuple[int, int, int, int][source]#
Get the four \(\mathbb{Z}_2\) indices \((\nu_0;\nu_1\nu_2\nu_3)\) of a 3D time-reversal-invariant insulator (Fu, Kane and Mele, Phys. Rev. Lett. 98, 106803 (2007); Moore and Balents, Phys. Rev. B 75, 121306(R) (2007)) from the \(\mathbb{Z}_2\) invariants of its six time-reversal-invariant planes \(k_i = 0\) and \(k_i = 1/2\) (fractional coordinates along \(\mathbf{b}_i\)), each computed by z2_invariant:
\[\nu_0 = \nu(k_i = 0) + \nu(k_i = 1/2) \bmod 2\, ,\qquad \nu_i = \nu(k_i = 1/2)\, .\]The strong index \(\nu_0\) comes out the same for the three \(i\), which is checked (a ValueError asks for a finer flow otherwise). \(\nu_0 = 1\) is a strong topological insulator; a weak one has \(\nu_0 = 0\) and some \(\nu_i = 1\), i.e. stacked quantum spin Hall layers normal to \(\nu_1\mathbf{b}_1 + \nu_2\mathbf{b}_2 + \nu_3\mathbf{b}_3\). No inversion symmetry is needed (compare parity_z2).
- Parameters:
bands (List of band indices (an even number of bands))
nk (Positive integer, default 100) – See z2_invariant.
nk_perp (Positive integer, default 51) – See z2_invariant.
- Returns:
indices (Tuple of four integers, 0 or 1: \((\nu_0, \nu_1, \nu_2, \nu_3)\))
- entanglement_spectrum(ks: ArrayLike, region: list[int], bands: int | list[int]) NDArray[float64][source]#
Get the k-resolved entanglement spectrum of a group of bands (Peschel, J. Phys. A 36, L205 (2003); Li and Haldane, Phys. Rev. Lett. 101, 010504 (2008); Fidkowski, Phys. Rev. Lett. 104, 130502 (2010)): the eigenvalues \(\xi_n(\mathbf{k})\) of the correlation matrix \(P(\mathbf{k})\) of the filled bands, restricted to the orbitals of region,
\[C_A(\mathbf{k}) = \left[P(\mathbf{k})\right]_{A}\, ,\qquad P(\mathbf{k}) = \sum_{n\in\mathrm{bands}}|u_n(\mathbf{k})\rangle\langle u_n(\mathbf{k})|\, ,\]between 0 and 1. For a ribbon or a supercell (tbkit.moire.supercell) cut in two halves across its width, the states of the whole are either inside the region (\(\xi \approx 1\)) or outside (\(\xi \approx 0\)), except for those localized at the cuts: a topological phase leaves entanglement modes inside \((0, 1)\) – a mode pinned at 1/2 in a chiral-symmetric chain, a branch that flows from 0 to 1 across the zone in a Chern insulator. The single-particle entanglement energies are \(\epsilon = \ln[(1-\xi)/\xi]\).
- Parameters:
ks (ndarray, shape (nk, dim)) – k-points (see get_bands).
region (List of orbital indices (the region \(A\)))
bands (Band index, or list of band indices (the filled bands))
- Returns:
xi (Real ndarray, shape (nk, len(region)), sorted ascending at every k)
- parity_z2(inversion, bands: list[int]) int[source]#
Get the \(\mathbb{Z}_2\) invariant of an inversion- and time-reversal-symmetric model from the parity eigenvalues of its occupied bands at the time-reversal-invariant momenta \(\Gamma_i\) (Fu and Kane, Phys. Rev. B 76, 045302 (2007)):
\[(-1)^\nu = \prod_i \delta_i\, ,\qquad \delta_i = \prod_{m=1}^{N} \xi_{2m}(\Gamma_i)\, ,\]one parity \(\xi = \pm1\) per Kramers pair. In 3D, \(\nu\) is the strong index.
- Parameters:
inversion – Complex ndarray, shape (norb, norb), or callable of k returning one: the inversion operator \(P\), with \(P H(\mathbf{k}) P^{-1} = H(-\mathbf{k})\) (e.g. swapping the two sublattices of graphene, and the identity on spin).
bands (List of band indices (the occupied Kramers pairs))
- Returns:
nu (0 (trivial) or 1 (topological))
- symmetry_error(op, k_map: str = 'minus', antiunitary: bool = False, anti: bool = False, nk: int = 5, seed: int = 0) float[source]#
Check a symmetry of the Bloch Hamiltonian,
\[H(g\mathbf{k}) = \pm\, U\, \mathcal{K}H(\mathbf{k})\mathcal{K}^{-1} U^\dagger\, ,\]with \(g\mathbf{k} = -\mathbf{k}\) or \(\mathbf{k}\), \(\mathcal{K}\) complex conjugation if antiunitary, and the minus sign if anti: time reversal is antiunitary with \(\mathbf{k}\to-\mathbf{k}\) and the plus sign, particle-hole antiunitary with \(\mathbf{k}\to-\mathbf{k}\) and the minus sign, chiral unitary with \(\mathbf{k}\to\mathbf{k}\) and the minus sign, inversion unitary with \(\mathbf{k}\to-\mathbf{k}\) and the plus sign.
- Parameters:
op (Complex ndarray, shape (norb, norb), or callable of k: \(U\))
k_map (‘minus’ or ‘identity’, default ‘minus’)
antiunitary (Boolean, default False)
anti (Boolean, default False)
nk (Positive integer, default 5) – Points per direction of the (randomly shifted) test mesh.
seed (Integer, default 0) – Seed of the random shift.
- Returns:
error (Real number) – Largest deviation over the mesh (0 for a symmetry).
- tenfold_class(time_reversal=None, particle_hole=None, chiral=None, nk: int = 5, tol: float = 1e-08) str[source]#
Get the Altland-Zirnbauer symmetry class (the “tenfold way”) of the model from its time-reversal \(T = U_T\mathcal{K}\), particle-hole \(C = U_C\mathcal{K}\) and chiral \(S = U_S\) symmetries. Each given operator is first checked (see symmetry_error) to be a symmetry; the class then follows from \(T^2 = U_TU_T^* = \pm1\), \(C^2 = \pm1\), and the presence of \(S\). Any two of the three imply the third (\(S = TC\)), which need not be given.
- Parameters:
time_reversal (Matrix \(U_T\), or None (absent))
particle_hole (Matrix \(U_C\), or None (absent))
chiral (Matrix \(U_S\), or None (absent))
nk (Positive integer, default 5) – See symmetry_error.
tol (Positive real, default 1e-8) – Tolerance of the checks.
- Returns:
name (String: ‘A’, ‘AIII’, ‘AI’, ‘BDI’, ‘D’, ‘DIII’, ‘AII’, ‘CII’, ‘C’ or ‘CI’)
- quantum_geometric_tensor(bands: int | list[int], k: ArrayLike, dk: float = 0.0001, positions: bool = True) NDArray[complex128][source]#
Get the quantum geometric tensor of a group of bands at \(\mathbf{k}\),
\[Q_{\mu\nu} = \mathrm{Tr}\left[P\,\partial_\mu P\,\partial_\nu P\right] = \sum_{n\in\mathrm{bands}}\langle\partial_\mu u_n|(1-P)|\partial_\nu u_n\rangle\, ,\]with \(P(\mathbf{k})\) the projector on the bands (gauge invariant, so degeneracies within the group are harmless). Its real part is the quantum metric \(g_{\mu\nu}\) (Provost and Vallee, 1980), minus twice its imaginary part the Berry curvature \(\Omega_{\mu\nu} = -2\,\mathrm{Im}\,Q_{\mu\nu}\) (the convention of berry_curvature, per unit k-area here). They obey \(\sqrt{\det g} \ge |\Omega_{xy}|/2\) in 2D.
- Parameters:
bands (Band index, or list of band indices)
k (k point (see *get_ham)*)
dk (Positive real, default 1e-4) – Finite-difference step.
positions (Boolean, default True) – Include the orbital positions in the Bloch functions. The local metric and curvature depend on this choice (the Berry curvature of berry_curvature is that of
positions=False); integrals such as the Chern number do not.
- Returns:
Q (Complex ndarray, shape (dim, dim), in the k coordinates of *get_ham*)
- surface_spectral_function(ks: ArrayLike, energies: ArrayLike, direction: int, side: int = 1, eta: float = 0.01, bulk: bool = False, max_iter: int = 10000) NDArray[float64][source]#
Get the spectral function of the surface of a semi-infinite crystal,
\[A_s(\mathbf{k}_\parallel, E) = -\frac{1}{\pi}\, \mathrm{Im}\,\mathrm{Tr}\, G_{00}(\mathbf{k}_\parallel, E + i\eta)\, ,\]with \(G_{00}\) the Green’s function of the outermost unit cell: the crystal fills the cells \(n\,\mathbf{a}_d\), \(n = 0, 1, 2, \dots\) along the primitive vector \(\mathbf{a}_d\) (
lat.prim_vec[direction]), times side, and is periodic along the others. It comes from the Lopez Sancho-Rubio decimation (see transport.surface_green) of the chain of principal layers (as many cells as the longest hopping along \(\mathbf{a}_d\) spans), so the crystal is truly semi-infinite: no finite slab, and no states of the opposite surface. It is the tight-binding picture of an ARPES map – surface states (edge states, in 2D; the end state of a 1D chain) show up as sharp lines inside the bulk gaps. With bulk, the same quantity for a unit cell deep inside the crystal: the bulk bands projected on the surface Brillouin zone.- Parameters:
ks (Real array, shape (nk, dim)) – k-points, in the coordinates of get_ham (e.g. from a k_path of the surface Brillouin zone). Only \(\mathbf{k}_\parallel\) matters: the result does not depend on the component along the reciprocal vector \(\mathbf{b}_d\).
energies (Real number or real array) – Energies \(E\).
direction (Integer, between 0 and dim-1) – The primitive vector normal to the surface (the one along which the crystal is semi-infinite).
side (+1 or -1, default 1) – The crystal extends along \(+\mathbf{a}_d\) (the surface faces \(-\mathbf{a}_d\)) or along \(-\mathbf{a}_d\) (the opposite surface).
eta (Positive real, default 1e-2) – Broadening: the width of the lines, and the decay length (about \(v/\eta\) cells) over which the bulk is resolved.
bulk (Boolean, default False) – If True, the spectral function of a bulk unit cell instead of the surface one.
max_iter (Positive integer, default 10000) – Maximum number of decimation steps.
- Returns:
A (Real ndarray, shape (nk, len(energies)))
Examples
Example usage:
# the (001) surface of a 3D model, along a path of the surface zone A = ks.surface_spectral_function(k_path, np.linspace(-1, 1, 201), direction=2)
- spin_operator(axis: str) NDArray[complex128][source]#
Get the Pauli matrix \(\sigma_{axis}\) acting on the spin of every site, \(\mathbb{1}_{sites}\otimes\sigma_{axis}\), for a model built with
spin=True(for band_weights and spin_texture).- Parameters:
axis (‘x’, ‘y’ or ‘z’)
- Returns:
op (Complex ndarray, shape (norb, norb))
- band_weights(projector, ks: ArrayLike | None = None) NDArray[float64][source]#
Get the weight of each band on a set of orbitals, or the expectation value of an operator, for “fat band” plots (see plot_bands):
\[w_n(\mathbf{k}) = \langle u_n(\mathbf{k})|P|u_n(\mathbf{k})\rangle\, ,\]with \(P\) the projector on the chosen orbitals (a weight between 0 and 1; the weights on all the sublattices add up to 1), or any Hermitian operator, e.g.
ks.spin_operator('z')for the spin polarization (between -1 and 1). Within a group of degenerate bands (e.g. Kramers pairs with inversion and time reversal), the weight of a single eigenvector depends on the choice of eigenvectors; each band of the group gets instead the average over the group, which does not (a Kramers pair has zero spin polarization). For a non-Hermitian model, the right eigenvectors are used; with an overlap (set_overlap), \(v^\dagger Pv/v^\dagger v\).- Parameters:
projector – Orbital index, list of orbital indices, sublattice tag (all the orbitals, both spins, of the sites with that tag), or a (norb, norb) Hermitian matrix.
ks (Real array, shape (nk, dim)) – Default value None: the k-points of the last get_bands or k_path.
- Returns:
weights (Real ndarray, shape (nk, norb), ordered as the bands)
Examples
Example usage:
ks.k_path(points, nk=100) ks.plot_bands(weights=ks.band_weights('a'))
- spin_texture(ks: ArrayLike, band: int) NDArray[float64][source]#
Get the spin expectation values \(\langle\boldsymbol\sigma\rangle_n(\mathbf{k}) = \langle u_n|\boldsymbol\sigma|u_n\rangle\) of a band, for a model built with
spin=True. Their length is 1 if the band is fully polarized, less if spin-orbit coupling entangles the spin with the orbitals. Within a group of degenerate bands, each band gets the average spin of the group (see band_weights): zero for a Kramers pair, with both inversion and time reversal.- Parameters:
ks (Real array, shape (nk, dim)) – k-points.
band (Integer) – Band index.
- Returns:
spin – Real ndarray, shape (nk, 3): \((\langle\sigma_x\rangle, \langle\sigma_y\rangle, \langle\sigma_z\rangle)\).
- fermi_surface(energy: float = 0.0, nk: int | tuple[int, ...] | None = None, bands: int | list[int] | None = None) list[NDArray[float64]][source]#
Get the constant-energy surfaces \(E_n(\mathbf{k}) = E\) (the Fermi surface at \(E = E_F\)): lines in a 2D Brillouin zone, surfaces in 3D. The bands are interpolated linearly in the triangles (tetrahedra in 3D) of a uniform mesh, the same decomposition as dos.tetrahedron_dos, and the level set of each simplex is a segment (a triangle or a quadrilateral, split in two, in 3D): marching triangles and tetrahedra, exact for the interpolated bands. Each piece is brought into the first Brillouin zone, the Wigner-Seitz cell around \(\Gamma\). For a non-Hermitian model, the real part of the energies is used.
- Parameters:
energy (Real number, default 0) – The energy \(E\).
nk (Positive integer, or tuple of *dim positive integers, default None: 100 in 2D, 40 in 3D*) – Number of k-points along each reciprocal lattice vector.
bands (Band index, or list of band indices) – Default value None: all bands.
- Returns:
surfaces – List, one entry per band of bands: a real ndarray of shape (n, 2, 2) in 2D (n segments, each two k-points) or (n, 3, 3) in 3D (n triangles, each three k-points), in the k coordinates of get_ham. Empty (n = 0) if the band does not cross energy.
Examples
Example usage:
# the Fermi surface of the half-filled square lattice segments = sq.fermi_surface(0.)[0]
- plot_fermi_surface(energy: float = 0.0, nk: int | tuple[int, ...] | None = None, bands: int | list[int] | None = None, lw: float = 2.0, alpha: float = 0.6, fs: float = 20, figsize: tuple[float, float] | None = None) Figure[source]#
Plot the constant-energy contours of fermi_surface (one color per band, with a legend if several bands cross the energy): lines inside the first Brillouin zone (drawn in black) in 2D, surfaces in 3D.
- Parameters:
energy (Real number, default 0) – The energy.
nk – See fermi_surface.
bands – See fermi_surface.
lw (Positive number, default 2) – Linewidth (2D).
alpha (Real number in (0, 1], default 0.6) – Opacity of the surfaces (3D).
fs (Positive number, default 20) – Fontsize.
figsize (Tuple, default None) – Figure size.
- Returns:
fig (Figure)
- plot_spin_texture(band: int, energy: float = 0.0, nk: int = 100, n_arrows: int = 40, cmap: str = 'RdBu_r', lw: float = 1.0, fs: float = 20, figsize: tuple[float, float] | None = None) Figure[source]#
Plot the spin texture of a band of a 2D spinful model on its constant-energy contour (see fermi_surface), zoomed on the contour: arrows of \((\langle\sigma_x\rangle, \langle\sigma_y\rangle)\) along the contour, colored by \(\langle\sigma_z\rangle\) (see spin_texture). Rashba coupling, for instance, locks the spin perpendicular to \(\mathbf{k}\), winding once around the contour.
- Parameters:
band (Integer) – Band index.
energy (Real number, default 0) – Energy of the contour.
nk (Positive integer, default 100) – Mesh of the contour.
n_arrows (Positive integer, default 40) – Approximate number of arrows, evenly spaced along the contour. A fully polarized in-plane spin is drawn 80% as long as their spacing.
cmap – Default value ‘RdBu_r’. Colormap of \(\langle\sigma_z\rangle\).
lw (Positive number, default 1) – Linewidth of the contour.
fs (Positive number, default 20) – Fontsize.
figsize (Tuple, default None) – Figure size.
- Returns:
fig (Figure)
- plot_berry_curvature(bands: int | list[int], nk: int | tuple[int, int] = 60, plane: tuple[int, int] = (0, 1), k_fixed: float = 0.0, cmap: str = 'RdBu_r', fs: float = 20, figsize: tuple[float, float] | None = None) Figure[source]#
Plot the Berry curvature of berry_curvature as a density, \(\Omega(\mathbf{k})\) = flux of each plaquette / its area. In 2D, the plaquettes are brought into the first Brillouin zone (drawn in black), in the k coordinates of get_ham. In 3D, they fill the parallelogram spanned by the two reciprocal vectors of plane, in orthonormal coordinates of the plane (\(k_1\) along \(\mathbf{b}_i\)). The title gives the Chern number, the total flux over \(2\pi\).
- Parameters:
bands – See berry_curvature.
nk – Default value 60. See berry_curvature.
plane – See berry_curvature.
k_fixed – See berry_curvature.
cmap – Default value ‘RdBu_r’. Colormap, centred on zero.
fs (Positive number, default 20) – Fontsize.
figsize (Tuple, default None) – Figure size.
- Returns:
fig (Figure)
- plot_wannier_flow(bands: int | list[int], nk: int = 100, nk_perp: int = 51, direction: int = 0, flow: int | None = None, k_fixed: float = 0.0, positions: bool = True, k_range: tuple[float, float] = (0.0, 1.0), ms: float = 4.0, c: str = 'b', fs: float = 20, figsize: tuple[float, float] | None = None) Figure[source]#
Plot the flow of the hybrid Wannier centres (the Wilson-loop spectrum) of wannier_flow: the centres along direction, in units of \(\mathbf{a}_{direction}\), as the loop moves along the reciprocal vector flow. They wind \(C\) times in a Chern insulator, and the Kramers pairs swap partners in a \(\mathbb{Z}_2\) topological insulator.
- Parameters:
bands – See wannier_flow.
nk – See wannier_flow.
nk_perp – See wannier_flow.
direction – See wannier_flow.
flow – See wannier_flow.
k_fixed – See wannier_flow.
positions – See wannier_flow.
k_range – See wannier_flow.
ms (Positive number, default 4) – Marker size.
c – Default value ‘b’. Marker color.
fs (Positive number, default 20) – Fontsize.
figsize (Tuple, default None) – Figure size.
- Returns:
fig (Figure)
- plot_surface_spectral_function(points: list[ArrayLike], energies: ArrayLike, direction: int, nk: int = 60, side: int = 1, eta: float = 0.01, bulk: bool = False, node_labels: list[str] | None = None, log: bool = True, cmap: str = 'magma', fs: float = 20, figsize: tuple[float, float] | None = None) Figure[source]#
Plot the surface spectral function of surface_spectral_function along a path through the surface Brillouin zone (built as in k_path), as an ARPES-like map of \(E\) against \(\mathbf{k}_\parallel\). Surface states are the sharp lines in the bulk gaps.
- Parameters:
points (List of at least two k-points, the nodes of the path (see *k_path)*)
energies (Real array) – Energies \(E\).
direction – See surface_spectral_function.
nk (Positive integer, default 60) – Number of k-points per path segment.
side – See surface_spectral_function.
eta – See surface_spectral_function.
bulk – See surface_spectral_function.
node_labels (List of strings, default None) – Labels of points.
log (Boolean, default True) – Logarithmic color scale, over four decades below the maximum (the surface states are much sharper than the bulk continuum).
cmap – Default value ‘magma’. Colormap.
fs (Positive number, default 20) – Fontsize.
figsize (Tuple, default None) – Figure size.
- Returns:
fig (Figure)
- plot_dos(nk: int | tuple[int, ...] = 30, broadening: float = 0.05, kernel: str = 'gaussian', e_grid: ArrayLike | None = None, fs: float = 20, lw: float = 2.0, figsize: tuple[float, float] | None = None) Figure[source]#
Plot the density of states, obtained by diagonalizing \(H(\mathbf{k})\) over a uniform Brillouin-zone mesh: broadened (see tbkit.dos.density_of_states), or by the linear tetrahedron method (
kernel='tetrahedron', see tbkit.dos.tetrahedron_dos), which needs no broadening and keeps band edges and van Hove singularities sharp.- Parameters:
nk (Positive integer, or tuple of *dim positive integers, default 30*) – Number of k-points along each reciprocal lattice vector.
broadening (Positive real number, default 0.05) – Kernel width (unused by the tetrahedron method).
kernel (String, default ‘gaussian’) – ‘gaussian’, ‘lorentzian’ or ‘tetrahedron’.
e_grid (Real ndarray, default None) – Energies at which to evaluate the density of states.
fs (Positive number, default 20) – Fontsize.
lw (Positive number, default 2) – Linewidth.
figsize (Tuple, default None) – Figure size.
- Returns:
fig (Figure)
- plot_bands(node_labels: list[str] | None = None, fs: float = 20, lw: float = 2.0, ms: float = 0.0, c: str = 'b', lims: tuple[float, float] | None = None, figsize: tuple[float, float] | None = None, weights: ArrayLike | None = None, style: str = 'color', cmap: str | None = None) Figure[source]#
Plot the band structure computed by k_path or get_bands, against the cumulative distance along the k-points (vertical lines mark the nodes of a k_path). For a non-Hermitian model, the real part of the energies is plotted. With weights (e.g. from band_weights: an orbital, sublattice or spin projection), a “fat band” plot: the bands are colored by the weights (with a colorbar), or drawn with dots sized by their absolute value.
- Parameters:
node_labels (List of strings, default None) – Labels of the high-symmetry points passed to k_path.
fs (Positive number, default 20) – Fontsize.
lw (Positive number, default 2) – Linewidth.
ms (Positive number, default 0) – Marker size.
c – Default value ‘b’. Line color.
lims (List, default None) – Energy plot limits.
figsize (Tuple, default None) – Figure size.
weights (Real array, shape (nk, norb), default None) – One weight per k-point and band, e.g. from band_weights.
style (String, default ‘color’) – ‘color’: the bands colored by weights; ‘size’: dots of size proportional to \(|w|\) (ms, or 8 if ms is 0, for the largest) on thin lines of color c.
cmap – Default value None (‘viridis’, or ‘RdBu_r’, centred on zero, if some weights are negative). Colormap of style ‘color’.
- Returns:
fig (Figure)
- tbkit.kspace.ribbon(lat: Lattice, list_hop: list[dict], width: int, direction: int = 1, onsite: dict | None = None, spin: bool = False) KSpace[source]#
Cut a ribbon out of a 2D periodic model: periodic along one primitive vector, finite (open boundary, width unit cells) along the other. This is the standard way to see edge states in a band structure (e.g. the zero-energy edge band of a zigzag graphene ribbon, or the helical edge states of a Kane-Mele ribbon). Cut out of a 3D model, it gives a slab: periodic along the two other primitive vectors, the way to see surface states (e.g. the Fermi arcs of a Weyl semimetal).
- Parameters:
lat – Lattice class instance (2D or 3D, i.e. two or three primitive vectors). Only unit_cell and prim_vec are used.
list_hop – List of dictionaries, in the same format passed to KSpace.set_hopping – the hoppings of the periodic (2D) model that the ribbon is cut from.
width (Positive integer) – Number of unit cells across the ribbon.
direction (0 or 1 (or 2, in 3D), default 1) – Which primitive vector (
lat.prim_vec[direction]) becomes finite; the others stay periodic.onsite (Dictionary, default None) – Onsite energies, in the same format passed to KSpace.set_onsite – applied identically on every row of the ribbon.
spin (Boolean, default False) – See KSpace.
- Returns:
rib – KSpace instance, 1D-periodic (2D-periodic for a slab), with
width * len(lat.unit_cell)sites (each site of lat, repeated once per row across the ribbon; row w’s copy of site i is orbitalw*len(lat.unit_cell) + i).
Examples
Example usage:
# zigzag graphene ribbon, 20 unit cells wide list_hop = [{'i': 0, 'j': 1, 'R': (0, 0), 't': 1.}, {'i': 0, 'j': 1, 'R': (-1, 0), 't': 1.}, {'i': 0, 'j': 1, 'R': (0, -1), 't': 1.}] rib = ribbon(lat, list_hop, width=20)
- tbkit.kspace.magnetic_supercell(lat: Lattice, list_hop: list[dict], p: int, q: int, onsite: dict | None = None, spin: bool = False) KSpace[source]#
Thread a uniform magnetic field through a 2D periodic model, with a rational flux \(\alpha = p/q\) flux quanta per unit cell, and return the Bloch Hamiltonian of its magnetic unit cell: q cells along \(\mathbf{a}_1\). Each hopping gets its Peierls phase (see System.set_peierls_phase)
\[\phi_{ij} = \frac{2\pi}{\Phi_0}\int_{\mathbf{r}_i}^{\mathbf{r}_j}\mathbf{A}\cdot d\mathbf{l} = 2\pi\alpha\,\frac{s_{1,i}+s_{1,j}}{2}\,(s_{2,j}-s_{2,i})\]in the gauge \(\mathbf{A} = \alpha\Phi_0\, s_1\nabla s_2\), with \((s_1, s_2)\) the fractional coordinates of a point along \((\mathbf{a}_1, \mathbf{a}_2)\), periodic along \(\mathbf{a}_2\). A translation by \(q\mathbf{a}_1\) is a symmetry only up to the gauge transformation \(e^{-2\pi i p s_2}\), which the hoppings crossing the magnetic cell boundary carry. The bands of the result are the Hofstadter subbands, and their chern_number the TKNN integers.
- Parameters:
lat (*Lattice class instance, 2D (two primitive vectors in the plane)*)
list_hop – List of dictionaries, the hoppings of the field-free model, in the format of KSpace.set_hopping.
p (Integer) – Numerator of the flux per unit cell.
q (Positive integer) – Denominator of the flux per unit cell: the magnetic cell has q unit cells.
onsite (Dictionary, default None) – Onsite energies, in the format of KSpace.set_onsite, applied to every copy.
spin (Boolean, default False) – See KSpace.
- Returns:
mag – KSpace instance, with
q * len(lat.unit_cell)sites: copy m of site i is sitem*len(lat.unit_cell) + i, displaced by \(m\mathbf{a}_1\).
Examples
Example usage:
# square lattice, flux 1/3 per plaquette: three Hofstadter bands mag = magnetic_supercell(lattices.square(), list_hop, p=1, q=3) chern = [mag.chern_number(bands=[n]) for n in range(3)]
- tbkit.kspace.cubic_path(points: dict[str, ArrayLike], names: list[str], a: float = 1.0, axes: ArrayLike | None = None) tuple[list[NDArray[float64]], list[str]][source]#
Build a path through k-points given in the conventional coordinates of a cubic crystal: in units of \(2\pi/a\) along the cubic axes, with \(a\) the side of the conventional cube, as tables of high-symmetry points list them (e.g. \(X = (0, 1, 0)\) and \(L = (\tfrac12, \tfrac12, \tfrac12)\) for fcc). high_symmetry_path builds the standard simple cubic, fcc and bcc paths with it; use it for another path, or other points, of the same lattices.
- Parameters:
points (Dictionary) – key: label, val: tuple of 3 real numbers, the point in units of \(2\pi/a\).
names – List of at least two labels (keys of points), the nodes of the path in order.
a (Positive real, default 1) – Side of the conventional cube.
axes (Real array, shape (3, 3)) – Default value None: the Cartesian axes. Rows: the three orthonormal cubic axes, in the coordinates of KSpace.get_ham (for a crystal whose cube is rotated).
- Returns:
points (List of real ndarrays, the k-points, for *KSpace.k_path*)
labels (List of strings, *names, for node_labels*)
Examples
Example usage:
# fcc, along Gamma - X - U and K - Gamma - L pts = {'G': (0, 0, 0), 'X': (0, 1, 0), 'U': (.25, 1, .25), 'K': (.75, .75, 0), 'L': (.5, .5, .5)} points, labels = cubic_path(pts, ['G', 'X', 'U'], a=3.6)
- tbkit.kspace.high_symmetry_path(lat: Lattice) tuple[list[NDArray[float64]], list[str]][source]#
Get a standard path through the high-symmetry points of the Brillouin zone of a lattice, for KSpace.k_path and the labels of KSpace.plot_bands. The Bravais lattice is recognized from lat.prim_vec, whatever the choice of primitive vectors and the orientation of the lattice:
1D: \(-X, \Gamma, X\) (the whole zone, \(X = \mathbf{b}/2\)).
2D (the five Bravais lattices): square \(\Gamma X M \Gamma\); rectangular \(\Gamma X S Y \Gamma\); hexagonal \(\Gamma M K \Gamma\); centred rectangular and oblique \(\Gamma X H C H_1 Y \Gamma\), along the edges of the zone: \(X, Y, C\) are the midpoints of the edges normal to the reciprocal vectors \(\mathbf{b}_1, \mathbf{b}_2, \mathbf{b}_1+\mathbf{b}_2\) of the reduced basis (with \(|\mathbf{b}_1| \le |\mathbf{b}_2|\)), \(H\) and \(H_1\) the corners between them.
3D: simple cubic \(\Gamma X M \Gamma R X\); fcc \(\Gamma X W K \Gamma L U W L K\); bcc \(\Gamma H N \Gamma P H\); simple tetragonal \(\Gamma X M \Gamma Z R A Z\); hexagonal \(\Gamma M K \Gamma A L H A\). These are the paths of Setyawan and Curtarolo (Comput. Mater. Sci. 49, 299 (2010)), up to their first discontinuity (a path here is one continuous line).
The other 3D lattices (orthorhombic, monoclinic, body-centred tetragonal, rhombohedral, …) raise a ValueError: give their points to k_path directly.
- Parameters:
lat (*lattice class instance (only prim_vec is used)*)
- Returns:
points – List of real ndarrays, the k-points, in the coordinates of KSpace.get_ham.
labels (List of strings (LaTeX), for *node_labels*)
Examples
Example usage:
points, labels = high_symmetry_path(lat) ks.k_path(points, nk=60) ks.plot_bands(node_labels=labels)
tbkit.lattices module#
A small library of common 2D Bravais lattices, ready to feed into
tbkit.lattice.Lattice, tbkit.system.System, or
tbkit.kspace.KSpace.
Each function returns a fresh Lattice instance with unit_cell and
prim_vec already set (call get_lattice yourself to build a finite
flake, or hand it straight to KSpace for a periodic/band-structure
calculation). Nearest-neighbor sites are a distance a apart.
Examples
Example usage:
import tbkit.lattices as lattices
lat = lattices.kagome()
lat.get_lattice(n1=6, n2=6)
- tbkit.lattices.chain(a: float = 1.0) Lattice[source]#
1D chain: one site per unit cell.
- Parameters:
a (Positive real number, default 1) – Lattice constant.
- tbkit.lattices.square(a: float = 1.0) Lattice[source]#
Square lattice: one site per unit cell.
- Parameters:
a (Positive real number, default 1) – Lattice constant.
- tbkit.lattices.triangular(a: float = 1.0) Lattice[source]#
Triangular lattice: one site per unit cell.
- Parameters:
a (Positive real number, default 1) – Lattice constant.
- tbkit.lattices.honeycomb(a: float = 1.0) Lattice[source]#
Honeycomb lattice (e.g. graphene): two sites per unit cell, nearest neighbors a distance a apart. See also
tbkit.graphene.GrapheneLatticefor ready-made finite flakes of various shapes.- Parameters:
a (Positive real number, default 1) – Nearest-neighbor distance.
- tbkit.lattices.kagome(a: float = 1.0) Lattice[source]#
Kagome lattice: three sites per unit cell (tags ‘a’, ‘b’, ‘c’), arranged as corner-sharing triangles on a triangular Bravais lattice. With uniform nearest-neighbor hopping, this lattice famously has an exactly flat band (at E = -2t for hopping amplitude t).
- Parameters:
a (Positive real number, default 1) – Nearest-neighbor distance.
Examples
Example usage (nearest-neighbor hopping, for
tbkit.kspace.KSpace):lat = lattices.kagome() kag = KSpace(lat) 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}])
- tbkit.lattices.lieb(a: float = 1.0) Lattice[source]#
Lieb lattice: three sites per unit cell (tag ‘a’: corner site; tags ‘b’, ‘c’: edge-center sites) on a square Bravais lattice. With uniform nearest-neighbor hopping, this lattice famously has an exactly flat band (at E = 0), squeezed between two dispersive bands.
- Parameters:
a (Positive real number, default 1) – Nearest-neighbor distance.
Examples
Example usage (nearest-neighbor hopping, for
tbkit.kspace.KSpace):lat = lattices.lieb() lb = KSpace(lat) lb.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}])
tbkit.dos module#
Density of states from a set of eigenenergies, real-space
(tbkit.system.System) or reciprocal-space
(tbkit.kspace.KSpace, sampled over a k-mesh).
- tbkit.dos.density_of_states(energies: ArrayLike, e_grid: ArrayLike | None = None, broadening: float = 0.05, kernel: str = 'gaussian') tuple[NDArray[float64], NDArray[float64]][source]#
Get the density of states, broadened by a Gaussian or Lorentzian kernel of width broadening:
\[\rho(E) = \sum_n g(E-E_n)\, ,\quad g(x) = \frac{1}{\sqrt{2\pi}\sigma}e^{-x^2/2\sigma^2}\ \text{(gaussian)} \ \text{or}\ g(x) = \frac{1}{\pi}\frac{\sigma}{x^2+\sigma^2}\ \text{(lorentzian)}\]Each level contributes a kernel of unit area, so \(\int\rho(E)dE\) equals the number of levels in energies, for an e_grid wide enough to contain the tails.
- Parameters:
energies (Array of (real) eigenenergies) – Any shape (e.g. the en attribute of System, or of KSpace after get_bands over a k-mesh – flattened automatically).
e_grid (Real ndarray, default None) – Energies at which to evaluate the density of states. If None, a grid of 401 points spanning
[min(energies)-3*broadening, max(energies)+3*broadening]is used.broadening (Positive real number, default 0.05) – Kernel width \(\sigma\).
kernel (String, default ‘gaussian’) – ‘gaussian’ or ‘lorentzian’.
- Returns:
e_grid (Real ndarray) – The energy grid used.
dos (Real ndarray, same shape as *e_grid*) – Density of states.
- tbkit.dos.tetrahedron_dos(energies: ArrayLike, e_grid: ArrayLike | None = None) tuple[NDArray[float64], NDArray[float64]][source]#
Get the density of states by the linear tetrahedron method (Jepsen and Andersen 1971, Lehmann and Taut 1972, Blochl et al. 1994): the bands are interpolated linearly inside the simplices (segments in 1D, triangles in 2D, tetrahedra in 3D) of a uniform mesh of the Brillouin zone, and the density of states of the interpolated bands is integrated exactly. There is no broadening: band edges and van Hove singularities (the logarithmic peak of the 2D square lattice, the \(\sqrt{E}\) edges of 3D bands) come out sharp, and converge with the mesh instead of with a kernel width.
The value at
e_grid[i]is the exact average of that density of states over the bin between the midpoints to the neighbouring grid points, so a flat band (a delta function) still carries its full weight, in one or two bins. The normalization is that of density_of_states on the same energies: \(\int\rho(E)dE\) equals the number of levels,energies.size, for an e_grid that spans them all. This is the linear method, without Blochl’s curvature correction. Complex energies (non-Hermitian bands) are replaced by their real part.- Parameters:
energies – Real array, shape (n1, n2, …, nbands): the bands on a periodic mesh of 1, 2 or 3 dimensions,
energies[i1, i2, ..., n]at the k-point \(\sum_d (i_d/n_d)\mathbf{b}_d\) (as given byKSpace.mesh_bands(nk).reshape(*nk, norb)).e_grid (Real ndarray, increasing, default None) – Energies at which to evaluate the density of states. If None, 401 points spanning the bands, with a 2% margin on each side.
- Returns:
e_grid (Real ndarray) – The energy grid used.
dos (Real ndarray, same shape as *e_grid*) – Density of states.
Examples
Example usage:
en = ks.mesh_bands((40, 40)).reshape(40, 40, ks.norb) e_grid, rho = dos.tetrahedron_dos(en)
tbkit.plot module#
- class tbkit.plot.Plot(sys: System, colors: list[str] | None = None)[source]#
Bases:
objectPlot the results of the classes lattice or system.
- Parameters:
sys (class instance **system**)
colors – Default value None. Color plot.
- plt_hopping(coor: NDArray, hop: NDArray, c: float, ax: Axes | None = None) None[source]#
Private method called by lattice_generic.
- lattice_generic(coor: NDArray, ms: float, lw: float, c: float, fs: float, axis: bool, plt_hop: bool, plt_hop_low: bool, plt_index: bool, figsize: tuple[float, float] | None, ax: Axes | None = None) Figure | SubFigure[source]#
Private method called by lattice and lattice_hop.
- lattice(ms: float = 20, lw: float = 5.0, c: float = 3.0, fs: float = 20, axis: bool = False, plt_hop: bool = False, plt_hop_low: bool = False, plt_index: bool = False, figsize: tuple[float, float] | None = None, ax: Axes | None = None) Figure | SubFigure[source]#
Plot lattice.
- Parameters:
ms (Positive number, default 20) – Markersize.
c (Positive number, default 3) – Coefficient. Hopping linewidths given by c*|hop[‘t’]|.
fs (Positive number, default 20) – Fontsize.
plt_hop (Boolean, default False) – Plot hoppings.
plt_hop_low (Boolean, default False) – Plot hoppings diagonal low.
plt_index (Boolean, default False) – Plot site labels.
axis (Boolean, default False) – Plot axis.
figsize (Tuple, default None) – Figure size.
ax (Axes, default None) – Draw on this axis instead of creating a figure of its own – to place several lattices side by side in one figure. figsize is then ignored.
- Returns:
fig (Figure)
- lattice_hop(ms: float = 20, lw: float = 5, c: float = 3.0, fs: float = 20, axis: bool = False, plt_hop: bool = False, plt_hop_low: bool = False, plt_index: bool = False, figsize: tuple[float, float] | None = None, ax: Axes | None = None) Figure | SubFigure[source]#
Plot lattice in hopping space.
- Parameters:
ms (Positive Float, default 20) – Markersize.
c (Positive Float, default 3) – Coefficient. Hopping linewidths given by c*|hop[‘t’]|.
fs (Positive Float, default 20) – Fontsize.
axis (Boolean, default False) – Plot axis.
plt_hop (Boolean, default False) – Plot hoppings.
plt_index (Boolean, default False) – Plot site labels.
figsize (Tuple, default None) – Figure size.
ax (Axes, default None) – Draw on this axis instead of creating a figure of its own – to place several lattices side by side in one figure. figsize is then ignored.
- Returns:
fig (Figure)
- spectrum_hist(nbr_bins: int = 61, fs: float = 20, lims: tuple[float, float] | None = None) Figure[source]#
Plot the spectrum (real part of the eigenenergies) as a histogram.
- Parameters:
nbr_bins (Positive integer, default 61) – Number of bins of the histogram.
fs (Positive number, default 20) – Fontsize.
lims (List, lims[0] energy min, lims[1] energy max)
- Returns:
fig (Figure)
- dos(broadening: float = 0.05, kernel: str = 'gaussian', e_grid: ArrayLike | None = None, fs: float = 20, lw: float = 2.0, figsize: tuple[float, float] | None = None) Figure[source]#
Plot the (broadened) density of states, see tbkit.dos.density_of_states.
- Parameters:
broadening (Positive real number, default 0.05) – Kernel width.
kernel (String, default ‘gaussian’) – ‘gaussian’ or ‘lorentzian’.
e_grid (Real ndarray, default None) – Energies at which to evaluate the density of states.
fs (Positive number, default 20) – Fontsize.
lw (Positive number, default 2) – Linewidth.
figsize (Tuple, default None) – Figure size.
- Returns:
fig (Figure)
- spectrum(ms: float = 10, fs: float = 20, lims: tuple[float, float] | None = None, tag_pola: str | None = None, ipr: bool | None = None, petermann: bool | None = None) Figure[source]#
Plot spectrum (eigenenergies real part (blue circles), and sublattice polarization if pola not empty (red circles).
- Parameters:
ms – Default value 10. Markersize.
fs – Default value 20. Fontsize.
lims (List, lims[0] energy min, lims[1] energy max)
tag_pola – Default value None. One-character string. Tag of the sublattice.
ipr – Default value None. If True plot the Inverse Participation Ratio.
petermann – Default value None. If True plot the Petermann factor.
- Returns:
fig (Figure)
- polarization(fig: Figure | None = None, ax1: Axes | None = None, ms: float = 10.0, fs: float = 20.0, lims: tuple[float, float] | None = None, tag_pola: str | None = None, ind: NDArray | None = None) tuple[Figure, Axes][source]#
Plot sublattice polarization.
- Parameters:
fig (Figure, default None) – (used by the method spectrum).
ax1 (Axis, default None) – (used by the method spectrum).
ms (Positive Float, default 10) – Markersize.
fs (Positive Float, default 20) – Fontsize.
lims (List, lims[0] energy min, lims[1] energy max)
tag_pola (One-character string, default None) – Tag of the sublattice.
ind (List, default None) – List of indices. (used in the method spectrum).
- Returns:
fig (Figure)
- ipr(fig: Figure | None = None, ax1: Axes | None = None, ms: float = 10, fs: float = 20, lims: tuple[float, float] | None = None, ind: NDArray | None = None) tuple[Figure, Axes][source]#
Plot the Inverse Participation Ratio.
- Parameters:
fig (Figure, default None) – (used by the method spectrum).
ax1 (Axis, default None) – (used by the method spectrum).
ms (Positive Float, default 10) – Markersize.
fs (Positive Float, default 20) – Fontsize.
lims (List) – lims[0] energy min, lims[1] energy max.
ind (List, default None) – List of indices. (used in the method spectrum).
- Returns:
fig (Figure)
- petermann(fig: Figure | None = None, ax1: Axes | None = None, ms: float = 10, fs: float = 20, lims: tuple[float, float] | None = None, ind: NDArray | None = None) tuple[Figure, Axes][source]#
Plot the Petermann factor.
- Parameters:
fig (Figure, default None) – (used by the method spectrum).
ax1 (Axis, default None) – (used by the method spectrum).
ms (Positive Float, default 10) – Markersize.
fs (Positive Float, default 20) – Fontsize.
lims (List) – lims[0] energy min, lims[1] energy max.
ind (List, default None) – List of indices. (used in the method spectrum).
- Returns:
fig (Figure)
- spectrum_complex(ms: float = 10.0, fs: float = 20.0, lims: tuple[float, float] | None = None) Figure[source]#
Plot complex value eigenenergies, real part (blue circles), and imaginary part (red circles).
- Parameters:
ms (Positive Float, default 10) – Markersize.
fs (Positive Float, default 20) – Font size.
lims (List) – lims[0] energy min, lims[1] energy max.
- Returns:
fig (Figure)
- intensity_1d(intensity: NDArray, ms: float = 20.0, lw: float = 2.0, fs: float = 20.0, title: str = '$|\\psi^{(j)}|^2$') Figure[source]#
Plot intensity for 1D lattices.
- Parameters:
intensity (np.array) – Field intensity.
ms (Positive Float, default 20) – Markersize.
lw (Positive Float, default 2) – Linewith, connect sublattice sites.
fs (Positive Float, default 20) – Font size.
title (String) – Default value ‘$|psi^{(j)}|^2$’. Figure title.
- Returns:
fig (Figure)
- intensity_disk(intensity: NDArray, s: float = 200.0, fs: float = 20.0, lims: tuple[float, float] | None = None, figsize: tuple[float, float] | None = None, title: str = '$|\\psi|^2$') Figure[source]#
Plot the intensity. Colormap with identical disk shape.
- Parameters:
intensity (np.array) – Field intensity.
s – Default value 200. Disk size.
fs – Default value 20. Font size.
lims (List, default None) – Colormap limits.
figsize (Tuple, default None) – Figure size.
title (String, default ‘$|psi|^2$’) – Title.
- Returns:
fig (Figure)
- intensity_area(intensity: NDArray, s: float = 1000.0, lw: float = 1.0, fs: float = 20.0, plt_hop: bool = False, figsize: tuple[float, float] | None = None, title: str = '$|\\psi|^2$') Figure[source]#
Plot the intensity. Intensity propotional to disk shape.
- Parameters:
intensity (np.array) – Intensity.
s (Positive Float, default 1000) – Circle size given by 100 * s * intensity.
lw (Positive Float, default 1) – Hopping linewidths.
fs (Positive Float, default 20) – Fontsize.
plt_hop (Boolean, default False) – Plot hoppings.
figsize (Tuple, default None) – Figure size.
title (String, default ‘$|psi|^2$’) – Figure title.
- Returns:
fig (Figure)
- butterfly(betas: NDArray, butterfly: NDArray, lw: float = 1.0, fs: float = 20.0, lims: tuple[float, float] | None = None, title: str = '') Figure[source]#
Plot energies depending on the strain (see GrapheneSystem.get_butterfly). The energy levels plotted are the ones lying in lims at the smallest strain.
- Parameters:
betas (np.array) – Strain values, shape (N,).
butterfly (np.array) – Eigenvalues, shape (N, sites).
lw (Positive Float, default 1) – Linewidths.
fs (Positive Float, default 20) – Fontsize.
lims (List, lims[0] energy min, lims[1] energy max)
title – Default value ‘’. Figure title. If empty, ‘Energies depending on strain’.
- Returns:
fig (Figure)
tbkit.propagation module#
- class tbkit.propagation.Propagation(lat: Lattice)[source]#
Bases:
objectGet lattice time evolution. The time-dependent Schrodinger equation \(i\,\partial_z\psi = H\psi\) is solved by the Crank-Nicolson method,
\[\psi(z+dz) = \left(1 + \tfrac{i}{2}H\,dz\right)^{-1} \left(1 - \tfrac{i}{2}H\,dz\right)\psi(z)\, ,\]unitary for a Hermitian \(H\).
- Parameters:
lat (*lattice class instance*)
- get_propagation(ham: spmatrix, psi_init: NDArray, steps: int, dz: float, norm: bool = False) None[source]#
Get the time evolution.
- Parameters:
ham (sparse.csr_matrix) – Tight-Binding Hamiltonian.
psi_init (np.ndarray) – Initial state.
steps (Positive Integer) – Number of steps.
dz (Positive number) – Step.
norm (Boolean, default False) – Renormalize the state to \(\sum_i|\psi_i|^2 = 1\) at each step. The Crank-Nicolson step is unitary, so this only matters for a non-Hermitian Hamiltonian (gain/loss), where the norm is not conserved.
- get_pumping(hams: list[spmatrix], psi_init: NDArray, steps: int, dz: float, norm: bool = True) None[source]#
Get the time evolution with adiabatic pumpings.
- Parameters:
hams (List of sparse.csr_matrices) – Tight-Binding Hamiltonians.
psi_init (np.ndarray) – Initial state.
steps (Positive integer) – Number of steps.
dz (Positive number) – Step.
norm (Boolean, default True) – Renormalize the state to \(\sum_i|\psi_i|^2 = 1\) at each step.
Notes
The steps are split into
len(hams) + 1equal stages: evolution underhams[0], thenlen(hams) - 1stages each interpolating linearly fromhams[j]tohams[j+1], then evolution underhams[-1]for the remaining steps. With fewer thanlen(hams) + 1steps the stages are empty: the state evolves underhams[-1]from the first step on.
- plt_propagation_1d(prop_type: str = 'real', fs: float = 20, figsize: tuple[float, float] | None = None) Figure[source]#
Plot time evolution for 1D systems.
- Parameters:
prop_type (String, default ‘real’) – Plot the real part (‘real’), the imaginary part (‘imag’), or the intensity (‘norm’).
fs (Positive number, default 20) – Fontsize.
figsize (Tuple, default None) – Figure size.
- Returns:
fig (Figure)
- prop_smooth_1d(prop: NDArray, a: float = 10, no: int = 40) NDArray[source]#
Private function. Used in plt_propagation_1d. Smooth propagation for 1D systems. Perform Gaussian interpolation \(e^{-a(x-x_i)^2}\),
- Parameters:
prop – Propagation.
a – Default value 10. Gaussian Parameter.
no – Default value 40. Number of points of each Gaussian.
- Returns:
smooth – Smoothed propagation.
- get_animation(s: float = 300.0, fs: float = 20.0, prop_type: str = 'real', figsize: tuple[float, float] | None = None) FuncAnimation[source]#
Get time evolution animation.
- Parameters:
s – Default value 300. Circle size.
fs – Default value 20. Fontsize.
prop_type (String, default ‘real’) – Plot the real part (‘real’), the imaginary part (‘imag’), or the intensity (‘norm’).
figsize (Tuple, default None) – Figsize.
- Returns:
ani – Animation.
- get_animation_nb(s: float = 300.0, fs: float = 20.0, prop_type: str = 'real', figsize: tuple[float, float] | None = None) FuncAnimation[source]#
Get time evolution animation for iPython notebooks.
- Parameters:
s – Default value 300. Circle size.
fs – Default value 20. Fontsize.
prop_type (String, default ‘real’) – Plot the real part (‘real’), the imaginary part (‘imag’), or the intensity (‘norm’).
figsize (Tuple, default None) – Figsize.
- Returns:
ani – Animation.
- tbkit.propagation.propagation#
alias of
Propagation
tbkit.save module#
- class tbkit.save.Save(dir_name: str, dir_main: str | None = None, params: dict | None = None, file_format: str = 'png')[source]#
Bases:
objectCreate folder and save figures / animations obtained via plot or propagation.
- Parameters:
dir_name (String) – Name of the sub-directory the figures are stored in.
dir_main (String, default None) – Path of the main directory. If None, figures are stored under
'figs/'.params (Dictionary, default None) – Parameters appended to file names.
file_format – Default value ‘png’. Figure format.
- fig(fig: Figure, name: str) None[source]#
Save the figure in the directory dir_name.
- Parameters:
fig (Matplotlib fig)
name (String) – First part of the file name.
tbkit.graphene module#
- class tbkit.graphene.GrapheneLattice[source]#
Bases:
LatticeHoneycomb lattice of graphene, with flake shapes.
Two sublattices, ‘a’ at \((0, 0)\) and ‘b’ at \((\sqrt3/2, 1/2)\), and primitive vectors \(\mathbf{a}_1 = (\sqrt3, 0)\) and \(\mathbf{a}_2 = (\sqrt3/2, 3/2)\), so the nearest-neighbour distance is 1. It is a
Latticewith methods that cut flakes of the usual shapes: triangle_zigzag, hexagon_zigzag, triangle_armchair, hexagon_armchair, square and circle.butterfly and betas are empty here; GrapheneSystem.get_butterfly fills the ones of the system.
Examples
Example usage:
from tbkit.graphene import GrapheneLattice, GrapheneSystem lat = GrapheneLattice() lat.hexagon_zigzag(n=4) sys = GrapheneSystem(lat) sys.set_hopping([{'n': 1, 't': 1.}])
- triangle_zigzag(n: int) None[source]#
Triangular flake with zigzag terminations.
- Parameters:
n (Int) – Number of plaquettes along the edges.
- hexagon_zigzag(n: int) None[source]#
Hexagonal flake with zigzag terminations.
- Parameters:
n (Int) – Number of plaquettes along the edges.
- triangle_armchair(n: int) None[source]#
Triangular flake with armchair terminations.
- Parameters:
n (Int) – Number of plaquettes along the edges.
- class tbkit.graphene.GrapheneSystem(lat: Lattice)[source]#
Bases:
SystemGraphene
System, with triaxial strain.Adds to System the nearest-neighbour hoppings of a linear triaxial strain (set_hop_linear_strain), which acts as a uniform pseudo-magnetic field, the range of strains that keeps every hopping positive (get_beta_lims), and the spectrum as a function of the strain (get_butterfly).
- Parameters:
lat (Lattice, usually a
GrapheneLatticeflake)
Examples
Example usage:
from tbkit.graphene import GrapheneLattice, GrapheneSystem lat = GrapheneLattice() lat.hexagon_zigzag(n=10) lat.center() sys = GrapheneSystem(lat) sys.set_hop_linear_strain(t=1., beta=0.1) sys.get_ham()
- set_hop_linear_strain(t: complex, beta: float) None[source]#
Set nearest-neighbor hoppings according to a linear triaxial strain:
\[t_{ij} = t\left(1 + \tfrac14\beta\, \hat{\boldsymbol\delta}_{ij}\cdot\mathbf{r}_{ij}\right)\]with \(\hat{\boldsymbol\delta}_{ij}\) the bond direction (from its ‘b’ site to its ‘a’ site) and \(\mathbf{r}_{ij}\) its midpoint. The strain is measured from the coordinate origin, so centre the flake on it (see lattice.center) before calling this.
- Parameters:
t – Hopping value without strain.
beta – Strength of the strain. See get_beta_lims for the range that keeps every hopping positive.
- get_butterfly(t: complex, N: int) None[source]#
Get the spectrum as a function of the strain beta (see set_hop_linear_strain), stored in sys.butterfly, shape (N, sites), with the strain values in sys.betas.
- Parameters:
t – Unstrained hopping value.
N (Positive integer) – Number of strain values between the minimal and maximal strains given by get_beta_lims.
- get_beta_lims() NDArray[float64][source]#
Get the extremal strain values keeping every hopping positive.
Under set_hop_linear_strain a bond’s amplitude is \(t(1+\tfrac14\beta s_{ij})\), so it stays positive for every bond iff \(-4/\max_{ij} s_{ij} < \beta < -4/\min_{ij} s_{ij}\).
- Returns:
beta_lims (Real ndarray of length 2,
[beta_min, beta_max](ascending)) – A bound is infinite if the corresponding \(s_{ij}\) never takes that sign.
- tbkit.graphene.grapheneLat#
alias of
GrapheneLattice
- tbkit.graphene.grapheneSys#
alias of
GrapheneSystem
tbkit.occupation module#
Occupation of single-particle states: the Fermi-Dirac distribution and the
Fermi level that holds a given number of electrons, at zero or finite
temperature. Used by tbkit.system.System (a finite spectrum) and
tbkit.kspace.KSpace (a Brillouin-zone mesh, with weights).
Energies and temperatures are in the same units (\(k_B = 1\)). Each state holds one electron: for spin-degenerate levels of a spinless model, count two electrons per level.
- tbkit.occupation.fermi_dirac(energies: ArrayLike, mu: float, temperature: float = 0.0) NDArray[float64][source]#
Get the Fermi-Dirac occupations
\[f(E) = \frac{1}{e^{(E-\mu)/T} + 1}\, ,\]the step \(\Theta(\mu - E)\) at \(T = 0\) (with \(f = 1/2\) exactly at \(E = \mu\)).
- Parameters:
energies (Array of real energies (for complex ones, the real part is used))
mu (Real number) – Chemical potential.
temperature (Positive real number or zero, default 0)
- Returns:
f (Real ndarray, same shape as *energies*)
- tbkit.occupation.fermi_level(energies: ArrayLike, n_electrons: float, temperature: float = 0.0, weights: ArrayLike | None = None) float[source]#
Get the Fermi level \(\mu\) at which \(\sum_n w_n f(E_n) = N_e\).
At \(T = 0\) with a gap above the last occupied level, \(\mu\) is placed midway in that gap (one unit above the top level if every level is filled); if the last electrons only partly fill a (degenerate) level, \(\mu\) is that level’s energy, where fermi_dirac gives each state \(f = 1/2\) – the electron count is then exact only for a half-filled shell. For partly filled degenerate shells, use a small temperature.
- Parameters:
energies – Array of real energies, any shape (e.g. System.en, or the bands of KSpace.mesh_bands).
n_electrons (Positive real number or zero) – Number of electrons \(N_e\) (per unit cell, with the weights of a k-mesh).
temperature (Positive real number or zero, default 0)
weights (Array of positive reals, same shape as *energies*) – Default value None (all 1). Weight of each level (e.g. 1/nk on a k-mesh).
- Returns:
mu (Real number)
tbkit.transport module#
Quantum transport through a finite Tight-Binding device attached to semi-infinite leads: the Landauer-Buttiker picture, in which the (linear, zero-temperature) conductance between two leads is the transmission probability at the Fermi energy,
(the Caroli formula) with \(G^r = [E + i\eta - H - \sum_l\Sigma_l]^{-1}\) the device’s retarded Green’s function, \(\Sigma_l\) the self-energy of lead \(l\) and \(\Gamma_l = i(\Sigma_l - \Sigma_l^\dagger)\).
A lead is a semi-infinite repetition of a unit cell with Hamiltonian \(h_0\), each cell coupled to the next one (away from the device) by \(v\); its surface cell is coupled to some device sites by \(\tau\). Its surface Green’s function comes from the decimation algorithm of Lopez Sancho, Lopez Sancho and Rubio (J. Phys. F 15, 851 (1985)), and \(\Sigma = \tau\, g_s\,\tau^\dagger\).
Examples
Example usage:
# a perfect chain of 10 sites between two chain leads: T = 1 in the band
tr = Transport(sys.ham)
h0, v = np.zeros((1, 1)), np.ones((1, 1))
tr.add_lead(h0, v, coupling=np.ones((1, 1)), sites=[0])
tr.add_lead(h0, v, coupling=np.ones((1, 1)), sites=[9])
T = tr.transmission(np.linspace(-1.9, 1.9, 50))
Transport.attach_lead builds the coupling and finds the device sites
itself, from a lead given as a 1D KSpace model placed in the device’s
coordinates (e.g. tr.attach_lead(sys, strip, 1)).
Transport.smatrix gives the scattering matrix itself. It uses the exact propagating and evanescent modes of the leads (lead_modes, with no broadening) and one sparse factorization of the device per energy (the formulation of Groth et al. 2014, as in Kwant). Transport.wave_function and Transport.ldos give the scattering states and the local density of states they carry. Transport.transmission uses the scattering matrix by default.
With more leads, Transport.conductance_matrix and four_terminal_resistance solve the Landauer-Buttiker equations (Hall bars); bond_currents and local_currents map the current; transmission_eigenvalues, shot_noise and fano_factor give the shot noise. RecursiveTransport computes the two-terminal transmission of long quasi-1D devices slice by slice (recursive Green’s function), without inverting the whole device.
- tbkit.transport.surface_green(h0: ArrayLike, v: ArrayLike, energy: float, eta: float = 1e-09, tol: float = 1e-12, max_iter: int = 10000) NDArray[complex128][source]#
Get the surface Green’s function of a semi-infinite lead: cells \(0, 1, 2, \dots\), with \(H_{nn} = h_0\) and \(H_{n,n+1} = v\), \(H_{n+1,n} = v^\dagger\), by the Lopez Sancho-Rubio decimation (each iteration doubles the number of cells accounted for, so it converges in a few tens of steps inside the bands, as \(\eta\to0^+\)).
- Parameters:
h0 (Square complex array) – Cell Hamiltonian.
v (Square complex array, same shape) – Coupling of a cell to the next one.
energy (Real number) – Energy.
eta (Positive real, default 1e-9) – Broadening.
tol (Positive real, default 1e-12) – Convergence threshold on the norm of the renormalized couplings.
max_iter (Positive integer, default 10000)
- Returns:
gs – Complex ndarray, same shape as h0: \(g_s = [E+i\eta - h_0 - \Sigma_{bulk}]^{-1}\).
- tbkit.transport.lead_from_kspace(ks, direction: int = 1) tuple[NDArray[complex128], NDArray[complex128]][source]#
Get the cell Hamiltonian \(h_0\) and coupling \(v\) of a lead from a 1D periodic model (e.g. a ribbon, see kspace.ribbon), whose hoppings reach at most the neighbouring cells.
- Parameters:
ks (*KSpace instance, 1D*)
direction (+1 or -1, default 1) – Direction, along the model’s primitive vector, in which the lead extends away from the device: \(v\) gathers the hoppings to the cell at \(\mathbf{R} = \pm\mathbf{a}_1\).
- Returns:
h0 (Complex ndarray, shape (norb, norb))
v (Complex ndarray, shape (norb, norb))
- class tbkit.transport.LeadModes(wave_functions: NDArray[np.complex128], momenta: NDArray[np.float64], velocities: NDArray[np.float64], blocks: NDArray[np.int64])[source]#
Bases:
NamedTupleThe propagating modes of a lead at one energy (see lead_modes): the incoming ones first (moving towards the device, velocity < 0), then the outgoing ones, each group by block of the conservation law, then in increasing momentum.
wave_functions – Complex ndarray, shape (m, n_modes). Mode \(\phi\) on the lead’s surface cell: cell \(n\) carries \(\lambda^n\phi\), with \(\lambda = e^{ik}\). Normalized to unit current.
momenta – Real ndarray, shape (n_modes,). \(k\) in \((-\pi, \pi]\).
velocities – Real ndarray, shape (n_modes,). \(dE/dk\), positive away from the device.
blocks – Integer ndarray, shape (n_modes,). The block of the conservation law each mode belongs to: the index of its eigenvalue, in increasing order (all 0 without a conservation law).
- wave_functions: NDArray[complex128]#
Alias for field number 0
- momenta: NDArray[float64]#
Alias for field number 1
- velocities: NDArray[float64]#
Alias for field number 2
- blocks: NDArray[int64]#
Alias for field number 3
- tbkit.transport.lead_modes(h0: ArrayLike, v: ArrayLike, energy: float, conservation_law: ArrayLike | None = None) LeadModes[source]#
Get the propagating modes of a semi-infinite lead (cells \(0, 1, 2, \dots\) away from the device, \(H_{nn} = h_0\), \(H_{n,n+1} = v\)) at one energy. A mode \(\psi_n = \lambda^n\phi\) solves \((E - h_0 - \lambda v - \lambda^{-1}v^\dagger)\phi = 0\), the generalized eigenproblem of the transfer matrix
\[\begin{split}\begin{pmatrix} 0 & 1\\ -v^\dagger & E - h_0\end{pmatrix} \begin{pmatrix}\phi\\ \lambda\phi\end{pmatrix} = \lambda \begin{pmatrix} 1 & 0\\ 0 & v\end{pmatrix} \begin{pmatrix}\phi\\ \lambda\phi\end{pmatrix}\, ,\end{split}\]solved as an ordinary eigenproblem when \(v\) is well conditioned, and by the QZ algorithm otherwise, so that a singular \(v\) is allowed (in real arithmetic for a real lead). The modes with \(|\lambda| = 1\) propagate with the velocity \(dE/dk = -2\,\mathrm{Im}(\lambda\phi^\dagger v\phi)\) (diagonalized within degenerate modes). There is no broadening \(\eta\), so the modes are exact up to the band edges.
A conservation_law \(Q\) (spin \(\sigma_z\), the electron-hole \(\tau_z\) of a normal lead, a valley) commutes with \(h_0\) and \(v\). The modes are then found in each eigenspace of \(Q\) separately, so that every mode carries one of its eigenvalues, even when modes of different blocks are degenerate.
- Parameters:
h0 (Square complex array, Hermitian) – Cell Hamiltonian.
v (Square complex array, same shape) – Coupling of a cell to the next one, away from the device.
energy (Real number) – Energy, not at a band edge of the lead.
conservation_law (Hermitian complex array, shape of *h0, or None, default None*)
- Returns:
modes (*LeadModes: the wave functions, momenta, velocities and blocks*)
- class tbkit.transport.SMatrix(data: NDArray[complex128], lead_info: list[LeadModes], n_blocks: list[int] | None = None)[source]#
Bases:
objectThe scattering matrix of a device at one energy (see Transport.smatrix):
data[a, b]is the amplitude of outgoing mode a for an incoming mode b of unit current. The rows are the outgoing modes of lead 0, then lead 1, …; the columns the incoming ones, in the order of lead_info. It is unitary for a Hermitian device.A lead is an integer, or a tuple
(lead, block)that keeps only the modes in one block of the lead’s conservation law (Transport.add_lead), for example(0, 1)for the electrons and(0, 0)for the holes of a normal lead with \(Q = \tau_z\).- data#
- Type:
Complex ndarray, shape (n_out, n_in)
- lead_info#
- Type:
List of LeadModes, one per lead
- num_propagating(lead: int | tuple[int, int]) int[source]#
Get the number of propagating modes (incoming, as many as outgoing) of a lead, or of one block of it.
- Parameters:
lead (Integer or tuple (lead, block))
- Returns:
n (Integer)
- submatrix(lead_out: int | tuple[int, int], lead_in: int | tuple[int, int]) NDArray[complex128][source]#
Get the block of the scattering matrix from lead lead_in to lead lead_out: the transmission amplitudes \(t\), or the reflection amplitudes \(r\) if the two are equal.
- Parameters:
lead_out (Integer or tuple (lead, block))
lead_in (Integer or tuple (lead, block))
- Returns:
s – Complex ndarray, shape (num_propagating(lead_out), num_propagating(lead_in)).
- transmission(lead_out: int | tuple[int, int], lead_in: int | tuple[int, int]) float[source]#
Get the transmission \(\sum_{ab}|S_{ab}|^2\) from lead lead_in to lead lead_out (the reflection if they are equal). With blocks,
transmission((0, 0), (0, 1))is, for example, the Andreev reflection of electrons into holes.- Parameters:
lead_out (Integer or tuple (lead, block))
lead_in (Integer or tuple (lead, block))
- Returns:
T (Real number)
- class tbkit.transport.Transport(ham)[source]#
Bases:
objectA finite device, of Hamiltonian ham (e.g. System.ham), to which semi-infinite leads are attached with add_lead; transmission then gives the Landauer transmission between two of them.
The device is stored sparse. smatrix, wave_function, ldos and transmission (by default) only factorize the sparse matrix. The methods with a broadening eta use the dense Green’s function, and the dense matrix ham is built once, the first time it is needed.
- Parameters:
ham (Square matrix (sparse or dense)) – Device Hamiltonian.
- property ham: NDArray[complex128]#
The device Hamiltonian, as a dense complex ndarray.
- add_lead(h0: ArrayLike, v: ArrayLike, coupling: ArrayLike, sites: list[int], conservation_law: ArrayLike | None = None) None[source]#
Attach a semi-infinite lead (see surface_green).
A conservation_law \(Q\), Hermitian and commuting with \(h_0\) and \(v\), sorts the lead’s modes into the eigenspaces of \(Q\) (lead_modes), and smatrix then resolves its blocks: \(\sigma_z\) for spin-resolved transport, the electron-hole \(\tau_z\) of a normal lead for Andreev reflection. The device itself need not conserve \(Q\).
- Parameters:
h0 (Square complex array, shape (m, m)) – Lead cell Hamiltonian.
v (Square complex array, shape (m, m)) – Coupling of a lead cell to the next one, away from the device.
coupling (Complex array, shape (len(sites), m)) – Hoppings \(\tau\) between the device sites and the lead’s surface cell.
sites (List of device site (row) indices the lead touches)
conservation_law (Hermitian complex array, shape (m, m), or None, default None) – Its blocks are numbered in increasing eigenvalue.
- attach_lead(sys, ks, direction: int = 1, conservation_law: ArrayLike | None = None, extend: bool = False) tuple[csr_matrix, NDArray[float64]] | None[source]#
Attach a semi-infinite lead given as a 1D KSpace model (e.g. a ribbon, see kspace.ribbon) to the device built from sys, without writing the coupling by hand. Returns, with extend, the enlarged device (None otherwise).
The lead’s sites sit at \(\boldsymbol\tau_o + n\mathbf{a}_1\) (its unit_cell positions, in the coordinates of sys, and its primitive vector). The device sites found at these positions, with the same tag, are copies of lead orbitals; the outermost cell along direction that holds some of them is the interface. The lead starts at the next cell, and couples to the interface sites through its own hoppings: \(\tau = v\) restricted to their orbitals (see lead_from_kspace, which also gives \(h_0\) and \(v\)). Every lead orbital with a hopping into the next cell must be present in the interface cell.
With extend, a device whose edge is ragged relative to the lead (a disc under a strip, a flake under a zigzag lead) is completed first, as Kwant’s attach_lead does: starting from the lead’s first cell, every lead site reached through the lead’s hoppings and absent from the device is added to it, cell by cell towards the device, until the sites reached are all present. The added sites take the lead’s onsite energies and its hoppings to their neighbours (device or added sites at lead positions). They come after the device sites, so the sites of the leads already attached keep their indices, and a later attach_lead with the same sys knows of them.
- Parameters:
sys – System instance (one orbital per site) whose Hamiltonian, in the same site order, is the device of this Transport (followed by the sites added by earlier extend calls).
ks – KSpace instance, 1D and spinless, with hoppings between neighbouring cells only.
direction (+1 or -1, default 1) – Direction, along the lead’s primitive vector, in which the lead extends away from the device.
conservation_law (Hermitian complex array, shape (norb, norb), or None, default None) – See add_lead.
extend (Boolean, default False) – Add the missing lead sites to the device instead of refusing an incomplete interface.
- Returns:
ham (Sparse CSR complex matrix) – The device Hamiltonian, the added sites last.
positions (Real ndarray, shape (n_sites, space_dim)) – The positions of its sites, those of sys first.
Examples
Example usage:
strip = ribbon(lattices.square(), hoppings, width=5, direction=1) tr = Transport(sys.ham) tr.attach_lead(sys, strip, -1) # at the left end of the device tr.attach_lead(sys, strip, 1) # at the right end ham, pos = tr.attach_lead(disc, strip, 1, extend=True) # ragged edge
- self_energy(lead: int, energy: float, eta: float = 1e-09) NDArray[complex128][source]#
Get the self-energy \(\Sigma = \tau g_s \tau^\dagger\) of a lead, embedded in the device space.
- Parameters:
lead (Integer) – Lead index (in the order of add_lead).
energy (Real number)
eta (Positive real, default 1e-9)
- Returns:
sigma (Complex ndarray, shape of *ham*)
- get_green(energy: float, eta: float = 1e-09) NDArray[complex128][source]#
Get the retarded Green’s function of the device with all its leads, \(G^r = [E + i\eta - H - \sum_l \Sigma_l]^{-1}\).
- Parameters:
energy (Real number)
eta (Positive real, default 1e-9)
- Returns:
G (Complex ndarray, shape of *ham*)
- transmission(energies: ArrayLike, lead_in: int = 0, lead_out: int = 1, eta: float | None = None) NDArray[float64][source]#
Get the transmission from lead lead_in to lead lead_out: the two-terminal conductance in units of \(e^2/h\) (per spin, for a spinless model).
By default (eta None) it is \(\sum_{ab}|S_{ab}|^2\) over the block of the scattering matrix (smatrix), exact up to the band edges of the leads. With a broadening eta (and, as a fallback, for non-Hermitian leads or lead_in = lead_out, with eta = 1e-9) it is the Caroli formula \(T(E) = \mathrm{Tr}[\Gamma_{out} G^r \Gamma_{in} G^a]\). The two agree to \(O(\eta)\).
- Parameters:
energies (Real array) – Energies.
lead_in (Integer, default 0)
lead_out (Integer, default 1)
eta (Positive real or None, default None)
- Returns:
T (Real ndarray, same length as *energies*)
- smatrix(energy: float) SMatrix[source]#
Get the scattering matrix at one energy: the amplitudes of the outgoing modes of every lead for each incoming mode of unit current, from the exact lead modes (lead_modes, no broadening) and one sparse factorization of the device. It is unitary for a Hermitian device. Every lead must be Hermitian. The blocks of the leads’ conservation laws (add_lead) are addressed as
(lead, block)in SMatrix.submatrix and SMatrix.transmission.- Parameters:
energy (Real number) – Energy, not at a band edge of a lead.
- Returns:
S (*SMatrix: data, lead_info, submatrix, transmission*)
Examples
Example usage:
s = tr.smatrix(0.3) t = s.submatrix(1, 0) # transmission amplitudes, lead 0 to lead 1 T = s.transmission(1, 0) # = tr.transmission(0.3, 0, 1)
- wave_function(energy: float, lead: int) NDArray[complex128][source]#
Get the scattering states injected from a lead: the wave function on the device of each incoming mode of unit current (lead_modes), with the scattered part leaving through every lead.
- Parameters:
energy (Real number) – Energy, not at a band edge of a lead.
lead (Integer) – Injecting lead.
- Returns:
psi – Complex ndarray, shape (n_modes, n_sites): one row per incoming mode of the lead.
- ldos(energy: float) NDArray[float64][source]#
Get the local density of states carried by the scattering states, \(\rho_i(E) = \frac{1}{2\pi}\sum_{l,a}|\psi_{la}(i)|^2\) over every incoming mode \(a\) of every lead \(l\) (unit current normalization). The bound states of the device, which no lead feeds, are left out.
- Parameters:
energy (Real number) – Energy, not at a band edge of a lead.
- Returns:
rho (Real ndarray, shape (n_sites,))
- conductance(mu: float, temperature: float = 0.0, lead_in: int = 0, lead_out: int = 1, eta: float | None = None, n_points: int = 101) float[source]#
Get the two-terminal linear conductance at a finite temperature, in units of \(e^2/h\),
\[G = \int dE\,\left(-\frac{\partial f}{\partial E}\right)T(E)\, ,\]with the Fermi-Dirac \(f\) at chemical potential \(\mu\). The integral runs over \(|E - \mu| \le 36k_BT\) on n_points equally spaced energies (the trapezoidal rule, spectrally accurate for a smooth \(T(E)\)). Resolving features of \(T(E)\) narrower than \(k_BT\) needs more points. At zero temperature it is \(T(\mu)\).
- Parameters:
mu (Real number) – Chemical potential.
temperature (Positive real or zero) – Default value 0 (\(k_B = 1\)).
lead_in (Integer, default 0)
lead_out (Integer, default 1)
eta (Positive real or None) – Default value None (see transmission).
n_points (Positive integer, default 101)
- Returns:
G (Real number)
- thermoelectric(mu: float, temperature: float, lead_in: int = 0, lead_out: int = 1, eta: float | None = None, n_points: int = 101) tuple[float, float, float][source]#
Get the two-terminal thermoelectric coefficients in linear response (Sivan and Imry 1986), from \(L_n = \int dE\,(E - \mu)^n\,T(E) (-\partial f/\partial E)\):
\[G = L_0\, ,\qquad S = -\frac{L_1}{T L_0}\, ,\qquad \kappa = \frac{1}{T}\left(L_2 - \frac{L_1^2}{L_0}\right)\, ,\]the conductance (\(e^2/h\)), the thermopower (\(k_B/e\), for electrons of charge \(-e\)) and the electronic thermal conductance at zero current (\(k_B/h\) times the energy unit). At low temperature they obey the Mott formula \(S = -\frac{\pi^2}{3}T\,\frac{d\ln T(E)}{dE}\) and the Wiedemann-Franz law \(\kappa = \frac{\pi^2}{3}TG\). The integrals are those of conductance.
- Parameters:
mu (Real number) – Chemical potential.
temperature (Positive real (\(k_B = 1\)))
lead_in (Integer, default 0)
lead_out (Integer, default 1)
eta (Positive real or None) – Default value None (see transmission).
n_points (Positive integer, default 101)
- Returns:
G (Real number)
S (Real number (NaN when nothing is transmitted))
kappa (Real number)
- transmission_matrix(energy: float, eta: float = 1e-09) NDArray[float64][source]#
Get the transmissions between every pair of leads at one energy, \(T_{pq} = \mathrm{Tr}[\Gamma_pG^r\Gamma_qG^a]\) from lead \(q\) to lead \(p\) (the diagonal, a reflection, is set to 0).
- Parameters:
energy (Real number)
eta (Positive real, default 1e-9)
- Returns:
T (Real ndarray, shape (n_leads, n_leads))
- conductance_matrix(energy: float, eta: float = 1e-09, temperature: float = 0.0, n_points: int = 101) NDArray[float64][source]#
Get the Landauer-Buttiker conductance matrix (Buttiker 1986), in units of \(e^2/h\): the linear-response currents flowing into the device from each lead, \(I_p = \sum_q G_{pq}V_q\), with
\[G_{pq} = -T_{pq}\ (p\neq q)\, ,\qquad G_{pp} = \sum_{q\neq p}T_{qp}\, .\]Its rows and columns add up to zero (current conservation, and no current at equal voltages). At a finite temperature it is averaged over the Fermi window, \(\int dE\,(-\partial f/\partial E)\,G(E)\) (see conductance).
- Parameters:
energy (Real number) – Fermi energy (chemical potential).
eta (Positive real, default 1e-9)
temperature (Positive real or zero) – Default value 0 (\(k_B = 1\)).
n_points (Positive integer, default 101) – Energies in the Fermi window, at a finite temperature.
- Returns:
G (Real ndarray, shape (n_leads, n_leads))
- four_terminal_resistance(energy: float, current: tuple[int, int], voltage: tuple[int, int], eta: float = 1e-09, temperature: float = 0.0, n_points: int = 101) float[source]#
Get a four-terminal (or two-terminal) resistance from the Landauer-Buttiker equations: a current \(I\) enters through lead
current[0]and leaves throughcurrent[1], every other lead is an ideal voltage probe (no net current), and the result is \(R = (V_a - V_b)/I\) withvoltage = (a, b), in units of \(h/e^2\). On a Hall bar, a longitudinal pair gives \(R_{xx}\) and a transverse pair \(R_{xy}\); in the quantum Hall regime with \(\nu\) edge channels, \(|R_{xy}| = 1/\nu\) and \(R_{xx} = 0\) (Buttiker 1988).- Parameters:
energy (Real number) – Fermi energy.
current (Tuple of two distinct lead indices (source, drain))
voltage (Tuple of two lead indices (a, b))
eta (Positive real, default 1e-9)
temperature (Positive real or zero) – Default value 0 (see conductance_matrix).
n_points (Positive integer, default 101)
- Returns:
R (Real number)
- bond_currents(energy: float, lead: int, eta: float = 1e-09) NDArray[float64][source]#
Get the bond currents carried, per unit energy, by the electrons injected from one lead (the non-equilibrium current when that lead’s electrochemical potential is raised),
\[J_{i\to j} = -2\,\mathrm{Im}\left[H_{ij}\,A^{(q)}_{ji}\right]\, ,\qquad A^{(q)} = G^r\Gamma_qG^a\, ,\]in units of \(e/h\) per unit energy: summed over a cross-section of a two-terminal device, it is the transmission \(T(E)\). The matrix is antisymmetric, and the currents are conserved at every site not touched by a lead.
- Parameters:
energy (Real number)
lead (Integer) – Injecting lead.
eta (Positive real, default 1e-9)
- Returns:
J – Real ndarray, shape of ham: J[i, j] is the current from site i to site j.
- local_currents(energy: float, lead: int, positions: ArrayLike, eta: float = 1e-09) NDArray[float64][source]#
Get the current density vector on every site from the bond currents (bond_currents): half of the currents of the bonds leaving the site, along their bond vectors, \(\mathbf{j}_i = \frac12\sum_jJ_{i\to j}(\mathbf{r}_j - \mathbf{r}_i)\).
- Parameters:
energy (Real number)
lead (Integer) – Injecting lead.
positions (Real array, shape (n_sites, d)) – Site positions (e.g.
np.column_stack([lat.coor['x'], lat.coor['y']])).eta (Positive real, default 1e-9)
- Returns:
j (Real ndarray, shape (n_sites, d))
- transmission_eigenvalues(energy: float, lead_in: int = 0, lead_out: int = 1, eta: float = 1e-09) NDArray[float64][source]#
Get the transmission eigenvalues \(T_n\), eigenvalues of \(t^\dagger t\) with \(t = \Gamma_{out}^{1/2}G^r\Gamma_{in}^{1/2}\): their sum is the transmission.
- Parameters:
energy (Real number)
lead_in (Integer, default 0)
lead_out (Integer, default 1)
eta (Positive real, default 1e-9)
- Returns:
T_n – Real ndarray, in decreasing order, of length min(len(sites_in), len(sites_out)).
- shot_noise(energies: ArrayLike, lead_in: int = 0, lead_out: int = 1, eta: float = 1e-09) NDArray[float64][source]#
Get the zero-temperature shot-noise factor \(\sum_nT_n(1-T_n)\) (Lesovik 1989; Buttiker 1990): the noise power at bias \(V\) is \(S = 2\frac{e^3|V|}{h}\sum_nT_n(1-T_n)\) (per spin).
- Parameters:
energies (Real array) – Energies.
lead_in (Integer, default 0)
lead_out (Integer, default 1)
eta (Positive real, default 1e-9)
- Returns:
noise (Real ndarray, same length as *energies*)
- fano_factor(energies: ArrayLike, lead_in: int = 0, lead_out: int = 1, eta: float = 1e-09) NDArray[float64][source]#
Get the Fano factor of the zero-temperature shot noise,
\[F = \frac{\sum_nT_n(1-T_n)}{\sum_nT_n}\, ,\]the noise in units of the Poisson value \(2e|I|\): 0 for a ballistic conductor (every \(T_n\) is 0 or 1), close to 1 for a tunnel barrier, 1/3 for a diffusive wire (Beenakker and Buttiker 1992).
- Parameters:
energies (Real array) – Energies.
lead_in (Integer, default 0)
lead_out (Integer, default 1)
eta (Positive real, default 1e-9)
- Returns:
F – Real ndarray, same length as energies (NaN where nothing is transmitted).
- tbkit.transport.slices_from_positions(x: ArrayLike, tol: float = 1e-06) list[list[int]][source]#
Group the sites of a device into slices of equal coordinate x (e.g. the columns of a strip along \(x\)), ordered by increasing x, for RecursiveTransport.
- Parameters:
x (Real array) – One coordinate per site (e.g.
lat.coor['x']).tol (Positive real, default 1e-6) – Coordinates closer than tol belong to the same slice.
- Returns:
slices (List of lists of site indices)
- class tbkit.transport.RecursiveTransport(ham, slices: list[list[int]], left: tuple, right: tuple)[source]#
Bases:
objectTwo-terminal transport through a long quasi-1D device by the recursive Green’s function method (Thouless and Kirkpatrick 1981; Lee and Fisher 1981; MacKinnon 1985). The device is cut into slices \(1\dots N\), each coupled only to its neighbours, with the left lead on slice 1 and the right lead on slice \(N\). The left-connected Green’s functions
\[g_1 = [z - H_{11} - \Sigma_L]^{-1}\, ,\qquad g_{i} = [z - H_{ii} - H_{i,i-1}\,g_{i-1}H_{i-1,i}]^{-1}\, ,\](\(\Sigma_R\) added in the last one, \(z = E + i\eta\)) and the propagator \(G_{i1} = g_iH_{i,i-1}G_{i-1,1}\) give \(T = \mathrm{Tr}[\Gamma_RG_{N1}\Gamma_LG_{N1}^\dagger]\). The cost grows linearly with the length, and only slice-sized matrices are inverted, never the whole device (compare Transport, which inverts the dense device matrix).
- Parameters:
ham (Square matrix, sparse (preferred for long devices) or dense) – Device Hamiltonian.
slices – List of lists of site indices: a partition of the device into slices, ordered from the left lead to the right one, with hoppings between neighbouring slices only (see slices_from_positions).
left – Tuple (h0, v, coupling): the left lead (see Transport.add_lead), with a coupling of shape (len(slices[0]), len(h0)), its rows in the order of
slices[0].right (Tuple (h0, v, coupling): the right lead, coupled to
slices[-1])
Examples
Example usage:
slices = slices_from_positions(lat.coor['x']) rgf = RecursiveTransport(sys.ham, slices, (h0, v_left, tau), (h0, v_right, tau)) T = rgf.transmission(energies)
- transmission(energies: ArrayLike, eta: float = 1e-09) NDArray[float64][source]#
Get the transmission from the left lead to the right one: the same as Transport.transmission for the same device and leads.
- Parameters:
energies (Real array) – Energies.
eta (Positive real, default 1e-9)
- Returns:
T (Real ndarray, same length as *energies*)
tbkit.kpm module#
The kernel polynomial method (KPM; Silver and Roder 1994, Weisse, Wellein, Alvermann and Fehske, Rev. Mod. Phys. 78, 275 (2006)): spectral quantities of a large sparse Hamiltonian from its Chebyshev moments, without diagonalizing it. The spectrum is first mapped into \((-1, 1)\), \(\tilde H = (H - b)/a\); then
with \(\epsilon = (E-b)/a\), \(T_m\) the Chebyshev polynomials (computed by the recursion \(T_{m+1}(\tilde H)|r\rangle = 2\tilde H\,T_m(\tilde H)|r\rangle - T_{m-1}(\tilde H)|r\rangle\), one sparse matrix-vector product each), and \(g_m\) a kernel that damps the Gibbs oscillations of the truncated series (Jackson: an almost Gaussian broadening of width about \(\pi a/M\)). Traces are estimated with a few random-phase vectors, \(\mathrm{Tr}\,A \approx \frac1R\sum_r\langle r|A|r\rangle\), whose error falls as \(1/\sqrt{RN}\): the cost is \(O(MRN)\) for \(N\) sites, so millions of sites are within reach.
The Hamiltonian must be Hermitian (System.ham, a sparse matrix).
- tbkit.kpm.spectral_bounds(ham) tuple[float, float][source]#
Get bounds on the spectrum of a Hermitian matrix from Gershgorin’s circle theorem: every eigenvalue lies within \(H_{ii} \pm \sum_{j\neq i}|H_{ij}|\) for some \(i\).
- Parameters:
ham (Square sparse (or dense) Hermitian matrix)
- Returns:
e_min, e_max (Real numbers)
- tbkit.kpm.jackson_kernel(n_moments: int) NDArray[float64][source]#
Get the Jackson kernel
\[g_m = \frac{(M-m+1)\cos\frac{\pi m}{M+1} + \sin\frac{\pi m}{M+1}\cot\frac{\pi}{M+1}}{M+1}\, ,\]the optimal choice for spectral densities (positive, and resolution about \(\pi/M\) in the scaled energy).
- Parameters:
n_moments (Positive integer \(M\))
- Returns:
g (Real ndarray, shape (n_moments,))
- tbkit.kpm.lorentz_kernel(n_moments: int, lam: float = 4.0) NDArray[float64][source]#
Get the Lorentz kernel \(g_m = \sinh[\lambda(1 - m/M)]/\sinh\lambda\), which gives Lorentzian broadening (the better choice for Green’s functions).
- Parameters:
n_moments (Positive integer \(M\))
lam (Positive real, default 4)
- Returns:
g (Real ndarray, shape (n_moments,))
- tbkit.kpm.dos(ham, n_moments: int = 256, n_random: int | None = 10, e_grid: ArrayLike | None = None, kernel: str = 'jackson', seed=None, bounds: tuple[float, float] | None = None) tuple[NDArray[float64], NDArray[float64]][source]#
Get the density of states \(\rho(E) = \mathrm{Tr}\,\delta(E - H)\) (normalized, like tbkit.dos.density_of_states, to integrate to the number of states).
- Parameters:
ham (Square sparse Hermitian matrix (e.g. *System.ham)*)
n_moments (Positive integer, default 256) – Number of Chebyshev moments (the energy resolution is about \(\pi a/M\), \(2a\) the spectral width).
n_random (Positive integer, or None, default 10) – Number of random vectors for the trace; None for the exact trace (N vectors: small systems only).
e_grid (Real array) – Default value None: 1001 Chebyshev nodes over the spectrum. Energies, inside the spectral bounds.
kernel (String, default ‘jackson’) – ‘jackson’ or ‘lorentz’.
seed – Default value None. Seed of the random vectors.
bounds (Pair of reals) – Default value None (Gershgorin bounds, see spectral_bounds). Bounds enclosing the whole spectrum.
- Returns:
e_grid (Real ndarray)
rho (Real ndarray, same shape)
- tbkit.kpm.dos_from_levels(levels: ArrayLike, n_moments: int, bounds: tuple[float, float], e_grid: ArrayLike, kernel: str = 'jackson') NDArray[float64][source]#
Get the KPM density of states of a known spectrum: every level broadened by exactly the truncated, kernel-damped Chebyshev series that dos uses. It is the reference dos converges to (up to the random trace), e.g. for the bands of a periodic model on a k-mesh.
- Parameters:
levels (Real array) – Energy levels.
n_moments (Positive integer) – Number of Chebyshev moments.
bounds (Pair of reals) – Spectral bounds (those of dos, e.g. spectral_bounds of the Hamiltonian it is compared with).
e_grid (Real array) – Energies.
kernel (String, default ‘jackson’)
- Returns:
rho – Real ndarray, same shape as e_grid (integrating to the number of levels).
- tbkit.kpm.ldos(ham, site: int, n_moments: int = 256, e_grid: ArrayLike | None = None, kernel: str = 'jackson', bounds: tuple[float, float] | None = None) tuple[NDArray[float64], NDArray[float64]][source]#
Get the local density of states on one site (or orbital), \(\rho_i(E) = \langle i|\delta(E-H)|i\rangle\), exactly (no random vectors).
- Parameters:
ham (Square sparse Hermitian matrix)
site (Integer) – Site (row) index.
n_moments (Positive integer, default 256)
e_grid – See dos.
kernel – See dos.
bounds – See dos.
- Returns:
e_grid (Real ndarray)
rho (Real ndarray, same shape)
- tbkit.kpm.conductivity(ham, x: ArrayLike, n_moments: int = 128, n_random: int | None = 10, e_grid: ArrayLike | None = None, kernel: str = 'jackson', seed=None, bounds: tuple[float, float] | None = None, area: float | None = None) tuple[NDArray[float64], NDArray[float64]][source]#
Get the zero-temperature DC conductivity along \(x\) from the Kubo-Greenwood formula,
\[\sigma_{xx}(E) = \frac{\pi}{\Omega}\, \mathrm{Tr}\left[v_x\,\delta(E-H)\,v_x\,\delta(E-H)\right]\, ,\qquad v_x = i[H, x]\, ,\]in units of \(e^2/\hbar\) (\(\hbar = e = 1\)), by the two-dimensional Chebyshev expansion of Weisse et al. (the moments \(\mu_{mn} = \mathrm{Tr}[v_x T_m(\tilde H) v_x T_n(\tilde H)]\), \(O(M N)\) memory, the DOS needing only \(O(N)\)).
- Parameters:
ham (Square sparse Hermitian matrix)
x (Real array, one coordinate per site (e.g. *lat.coor[‘x’])*)
n_moments (Positive integer, default 128)
n_random (Positive integer, or None, default 10) – See dos.
e_grid – See dos.
kernel – See dos.
seed – See dos.
bounds – See dos.
area (Positive real) – Default value None (the number of sites): the area (volume) \(\Omega\) of the sample.
- Returns:
e_grid (Real ndarray)
sigma (Real ndarray, same shape)
- tbkit.kpm.hall_conductivity(ham, vx, vy, n_moments: int = 256, n_random: int | None = 10, e_grid: ArrayLike | None = None, kernel: str = 'jackson', seed=None, bounds: tuple[float, float] | None = None, area: float | None = None, temperature: float = 0.0) tuple[NDArray[float64], NDArray[float64]][source]#
Get the Hall conductivity \(\sigma_{xy}(\mu)\) of a large sample, at any Fermi level and temperature, from the Kubo-Bastin formula expanded in Chebyshev polynomials (Garcia, Covaci and Rappoport, Phys. Rev. Lett. 114, 116602 (2015), Eqs. (1)-(5)). Bastin’s formula,
\[\sigma^{B}_{\alpha\beta}(\mu) = \frac{ie^2\hbar}{\Omega}\int d\varepsilon\,f(\varepsilon)\, \mathrm{Tr}\left[v_\alpha\,\delta(\varepsilon-H)\,v_\beta\,\frac{dG^+}{d\varepsilon} - v_\alpha\,\frac{dG^-}{d\varepsilon}\,v_\beta\,\delta(\varepsilon-H)\right]\, ,\]\(G^\pm = (\varepsilon - H \pm i0)^{-1}\), becomes, with the spectrum rescaled into \((-1, 1)\), \(\tilde H = (H-b)/a\),
\[\sigma^{B}_{\alpha\beta}(\mu) = \frac{4e^2\hbar}{\pi\Omega a^2}\int_{-1}^{1} d\tilde\varepsilon\,\frac{f(\tilde\varepsilon)}{(1-\tilde\varepsilon^2)^2} \sum_{m,n}\Gamma_{nm}(\tilde\varepsilon)\,\mu^{\alpha\beta}_{nm}\, ,\]\[\mu^{\alpha\beta}_{mn} = \frac{g_mg_n}{(1+\delta_{m0})(1+\delta_{n0})} \mathrm{Tr}\left[v_\alpha T_m(\tilde H)\,v_\beta T_n(\tilde H)\right]\, ,\]\[\Gamma_{mn}(\tilde\varepsilon) = (\tilde\varepsilon - in\sqrt{1-\tilde\varepsilon^2})\, e^{in\theta}\,T_m(\tilde\varepsilon) + (\tilde\varepsilon + im\sqrt{1-\tilde\varepsilon^2})\,e^{-im\theta}\,T_n(\tilde\varepsilon)\, ,\]\(\theta = \arccos\tilde\varepsilon\), \(g_m\) the kernel. The moments \(\mu_{mn}\) (the expensive part: \(5MR\) sparse products, \(O(MN)\) memory) serve every Fermi level and temperature. The energy integral runs over \(|\tilde\varepsilon|\le 0.995\) (the spectrum lies within \(\pm0.99\)): at the ends, \((1-\tilde\varepsilon^2)^{-2}\) would only amplify rounding errors.
Hall part. The value is computed from the antisymmetric moments \((\mu^{xy}_{mn} - \mu^{yx}_{mn})/2\), i.e. it is the Hall conductivity proper, \((\sigma^B_{xy} - \sigma^B_{yx})/2\), the part that the Berry curvature gives (KSpace.hall_conductivity). The symmetric part \((\sigma^B_{xy} + \sigma^B_{yx})/2\) is a Fermi-surface term, like \(\sigma_{xx}\) (see conductivity): it vanishes by symmetry in many lattices (e.g. with a \(C_3\) axis), but in a clean metal of lower symmetry it grows as the kernel’s broadening \(\pi a/M\) shrinks (the Drude weight), and with random vectors it is the main source of noise. Leaving it out removes that noise too. In a clean metal the random-vector estimate is still noisy inside the bands (increase n_random, or the size of the sample); disorder, which makes the Fermi-surface terms finite, and gaps, where they vanish, are much quieter.
Sign and units. The value returned is \(-(\sigma^B_{xy}-\sigma^B_{yx})/2\) in units of \(e^2/h\) (\(\hbar = e = 1\)), the sign of KSpace.hall_conductivity: \(C\) in the gap of a Chern insulator of Chern number \(C\) (KSpace.chern_number). Bastin’s \(\sigma^B_{xy}\) is the Ohm’s-law tensor, \(j_x = \sigma^B_{xy}E_y\) (see KSpace.hall_conductivity).
Sample. The trace must run over a sample without edges – a torus (KSpace.finite_ham and KSpace.finite_velocity with
periodic=True): over a whole open flake, the edge currents cancel the bulk and the trace vanishes in a gap.- Parameters:
ham (Square sparse Hermitian matrix)
vx (Square sparse (or dense) Hermitian matrix, like *ham*) – Velocity \(v_x = i[H, x]\) (see KSpace.finite_velocity). For a spin Hall conductivity, pass the spin current \(\{s, v_x\}/2\) instead (units \(e/2\pi\), see KSpace.spin_hall_conductivity).
vy (Square sparse (or dense) Hermitian matrix) – Velocity \(v_y\).
n_moments (Positive integer, default 256) – Number of Chebyshev moments \(M\) (energy resolution about \(\pi a/M\)).
n_random (Positive integer, or None, default 10) – See dos.
e_grid (Real array) – Default value None: 1001 Chebyshev nodes over the spectrum. Fermi energies \(\mu\).
kernel (String, default ‘jackson’) – See dos.
seed – See dos.
bounds – See dos.
area (Positive real) – Default value None (the number of orbitals). Area \(\Omega\) of the sample (e.g. number of cells times the cell area).
temperature (Positive real or zero, default 0) – In energy units.
- Returns:
e_grid (Real ndarray)
sigma (Real ndarray, same shape, in units of \(e^2/h\))
tbkit.slater_koster module#
Slater-Koster two-centre integrals (J. C. Slater and G. F. Koster, Phys. Rev. 94, 1498 (1954)) between s, p and d orbitals.
The matrix element between orbital \(\alpha\) on one atom and orbital \(\beta\) on a neighbour at \(\mathbf{d} = d\,(l, m, n)\) depends only on a handful of bond integrals \(V_{ll'\mu}\) (\(\mu = \sigma, \pi, \delta\): the angular momentum about the bond), through the direction cosines \((l, m, n)\) – e.g.
Rather than tabulating all 81 such formulas, they are generated: in a frame whose z axis lies along the bond, the matrix is diagonal in the angular momentum about the bond, with entries \(V_{ll'\mu}\); rotating the frame onto \(\hat{\mathbf{d}}\) gives every entry, \(E(\hat{\mathbf{d}}) = D_{l}(R)\,E(\hat z)\,D_{l'}(R)^T\), with \(D_1 = R\) for the p orbitals and \(D_2\) its action on the quadratic forms of the d orbitals. This is exactly the Slater-Koster table (checked against it in the tests), in the usual real-orbital basis:
's', 'px', 'py', 'pz', 'dxy', 'dyz', 'dzx',
'dx2-y2', 'dz2'.
Bond integrals are given as a dictionary, with keys 'ss_sigma',
'sp_sigma', 'pp_sigma', 'pp_pi', 'sd_sigma',
'pd_sigma', 'pd_pi', 'dd_sigma', 'dd_pi', 'dd_delta'
(missing keys are zero). Between different atoms, \(V_{sp\sigma}\)
(s on the first atom, p on the second) and \(V_{ps\sigma}\) (p on the
first, s on the second) differ: give 'ps_sigma', 'ds_sigma',
'dp_sigma', 'dp_pi' for the latter (they default to their
homonuclear counterparts).
- tbkit.slater_koster.ORBITALS = {'dx2-y2': 2, 'dxy': 2, 'dyz': 2, 'dz2': 2, 'dzx': 2, 'px': 1, 'py': 1, 'pz': 1, 's': 0}#
Real orbitals, with their angular momentum l.
- tbkit.slater_koster.PARAMS = ('ss_sigma', 'sp_sigma', 'ps_sigma', 'pp_sigma', 'pp_pi', 'sd_sigma', 'ds_sigma', 'pd_sigma', 'pd_pi', 'dp_sigma', 'dp_pi', 'dd_sigma', 'dd_pi', 'dd_delta')#
Bond-integral keys (the heteronuclear ps/ds/dp keys are optional).
- tbkit.slater_koster.sk_block(orbs1: list[str], orbs2: list[str], d: ArrayLike, params: dict) NDArray[float64][source]#
Get the Slater-Koster hopping matrix between the orbitals orbs1 of an atom and the orbitals orbs2 of a neighbour at displacement \(\mathbf{d}\).
- Parameters:
orbs1 (List of orbital names (see
ORBITALS))orbs2 (List of orbital names)
d (Tuple of 2 or 3 reals) – Displacement from the first atom to the second (a 2D vector lies in the (x, y) plane).
params (Dictionary of bond integrals (see the module docstring))
- Returns:
block (Real ndarray, shape (len(orbs1), len(orbs2)))
- tbkit.slater_koster.orbital_angular_momentum() list[NDArray[complex128]][source]#
Get the orbital angular momentum \((L_x, L_y, L_z)\) (\(\hbar = 1\)) on the real p orbitals
(px, py, pz): \((L_k)_{ij} = -i\epsilon_{kij}\).- Returns:
L (List of three complex ndarrays, shape (3, 3))
- tbkit.slater_koster.sk_kspace(lat, orbitals: dict[str, list[str]], bonds: dict[int, dict], onsite: dict | None = None, overlap: dict[int, dict] | None = None)[source]#
Get the Slater-Koster Bloch Hamiltonian of a periodic lattice: a KSpace with one orbital per (site, orbital) of the unit cell, and the hoppings of sk_block between the n-th neighbours listed in bonds – the reciprocal-space twin of
tbkit.orbital.OrbitalSystem.set_slater_koster().- Parameters:
lat (*Lattice instance (unit cell and primitive vectors)*)
orbitals (Dictionary {tag: list of orbital names})
bonds – Dictionary {n: bond integrals}: the neighbour orders to connect (1 for nearest neighbours), each with its Slater-Koster parameters (see the module docstring).
onsite (Dictionary, default None) – {tag: energy} (every orbital of the site) or {tag: {orbital: energy}}.
overlap (Dictionary, default None) – {n: bond integrals} of the overlap matrix (see KSpace.set_overlap).
- Returns:
ks – KSpace instance; ks.sk_orbitals lists the (site, orbital) of each of its orbitals.
tbkit.orbital module#
Real-space Tight-Binding models with several orbitals per site and an
optional spin: OrbitalSystem extends tbkit.system.System
with Slater-Koster hoppings between s, p and d orbitals (see
tbkit.slater_koster), non-orthogonal bases (an overlap matrix),
and spin-dependent terms – Kane-Mele intrinsic spin-orbit coupling,
Rashba coupling, Zeeman fields and atomic \(\lambda\mathbf{L}\cdot\mathbf{S}\).
Rows of the Hamiltonian are ordered site by site, then orbital by orbital (in the order given for the site’s tag), then spin (up, down): the row of orbital o with spin s on site i is sys.row(i, o, s).
- class tbkit.orbital.OrbitalSystem(lat: Lattice, orbitals: dict[str, list[str]] | None = None, spin: bool = False, periodic: bool | tuple[bool, ...] = False)[source]#
Bases:
SystemSolve a real-space Tight-Binding model with several orbitals per site and, optionally, spin.
- Parameters:
lat (*Lattice class instance*)
orbitals (Dictionary) – Default value None (one ‘s’ orbital per site). key: sublattice tag, val: list of orbital names (see
tbkit.slater_koster.ORBITALS), e.g.{'a': ['s', 'px', 'py', 'pz']}.spin (Boolean, default False) – Give every orbital a spin-1/2 degree of freedom.
periodic (Boolean, or tuple of booleans, default False) – Periodic boundaries (see System); the bond vectors of the Slater-Koster, spin-orbit and Rashba blocks are then those of the shortest image.
Notes
Everything of System still applies: set_hopping (and the disorder, defect and Peierls methods) sets hoppings \(t\) that connect equal orbitals and equal spins of the two sites (\(t\,\mathbb{1}\)), and set_onsite with plain numbers shifts every orbital of a site. Onsite energies can also be given orbital by orbital, and full hopping blocks come from set_slater_koster, set_spin_orbit, set_rashba or set_hopping_block. Call set_peierls_phase / set_magnetic_field last: they multiply every hopping (and block) set so far.
Examples
Example usage:
# graphene's sp3 bands: four orbitals per carbon sys = OrbitalSystem(lat, orbitals={'a': ['s', 'px', 'py', 'pz'], 'b': ['s', 'px', 'py', 'pz']}) sys.set_onsite({'a': {'s': -8.87}, 'b': {'s': -8.87}}) sys.set_slater_koster(1, {'ss_sigma': -6.77, 'sp_sigma': 5.58, 'pp_sigma': 5.04, 'pp_pi': -3.03}) sys.get_ham()
- row(site: int, orbital: str, spin: int = 0) int[source]#
Get the row of an orbital.
- Parameters:
site (Integer) – Site index.
orbital (String) – Orbital name (one of the site’s).
spin (0 (up) or 1 (down), default 0)
- Returns:
row (Integer)
- set_onsite(dict_onsite: dict) None[source]#
Set onsite energies.
- Parameters:
dict_onsite (Dictionary) – key: sublattice tag, val: onsite energy (a number, applied to every orbital of the sites), or a dictionary {orbital: energy} (orbitals not given get 0).
Examples
Example usage:
sys.set_onsite({'a': 0.5, 'b': {'s': -8.87, 'pz': 0.}})
- set_zeeman(b: tuple[float, float, float]) None[source]#
Set a Zeeman field \(\mathbf{b}\cdot\boldsymbol\sigma\) on every orbital (
spin=Trueonly).- Parameters:
b (Tuple of three real numbers \((b_x, b_y, b_z)\))
- set_atomic_soc(lam: float, tags: list[str] | None = None) None[source]#
Set the atomic spin-orbit coupling \(\lambda\,\mathbf{L}\cdot\mathbf{S} = \frac{\lambda}{2}\sum_k L_k\sigma_k\) on the p orbitals (
spin=Trueonly; the sites must carry all three of px, py, pz). It splits them into \(j = 3/2\) (at \(+\lambda/2\)) and \(j = 1/2\) (at \(-\lambda\)) levels.- Parameters:
lam (Real number) – \(\lambda\).
tags (List of tags) – Default value None (every tag with p orbitals).
- set_slater_koster(n: int, params: dict, overlap: dict | None = None) None[source]#
Set the hoppings between the orbitals of every pair of n-th neighbours from Slater-Koster bond integrals (see
tbkit.slater_koster.sk_block()), replacing those set before for the same n. The blocks are spin independent.- Parameters:
n (Positive integer) – Neighbour order (1 for nearest neighbours).
params – Dictionary of bond integrals (e.g.
{'pp_sigma': 5.04, 'pp_pi': -3.03}), or dictionary {tag pair: bond integrals} (e.g.{'ab': {...}, 'ba': {...}}, for bonds from an ‘a’ to a ‘b’ site).overlap (Dictionary, default None) – Bond integrals of the overlap matrix \(S_{ij} = \langle i|j\rangle\), in the same format: the basis is then non-orthogonal, and get_eig solves \(H\psi = ES\psi\).
- set_spin_orbit(lam: float, n: int = 2) None[source]#
Set the Kane-Mele intrinsic spin-orbit coupling on the n-th neighbours (
spin=Trueonly),\[H_{SO} = i\lambda\sum_{\langle\langle ij\rangle\rangle}\nu_{ij}\, c_i^\dagger\sigma_z c_j\, ,\qquad \nu_{ij} = \sum_k \mathrm{sign}\left[(\mathbf{d}_{ik}\times\mathbf{d}_{kj})_z\right]\, ,\]the sum running over the nearest neighbours \(k\) shared by \(i\) and \(j\) (one on the honeycomb lattice, where \(\nu_{ij} = \pm1\) says whether the path turns left or right). It connects equal orbitals of the two sites.
- Parameters:
lam (Real number) – \(\lambda\).
n (Positive integer, default 2) – Neighbour order.
- set_rashba(lam: float, n: int = 1) None[source]#
Set a Rashba spin-orbit coupling on the n-th neighbours (
spin=Trueonly), \(H_R = i\lambda\sum_{\langle ij\rangle} c_i^\dagger (\boldsymbol\sigma\times\hat{\mathbf{d}}_{ij})_z\, c_j\), \(\hat{\mathbf{d}}_{ij}\) the bond direction. It connects equal orbitals of the two sites.- Parameters:
lam (Real number) – \(\lambda\).
n (Positive integer, default 1)
- set_hopping_block(dict_block: dict[tuple[int, int], NDArray]) None[source]#
Set hopping blocks by hand, added to the others: key: site pair \((i, j)\), val: matrix of shape (rows of i, rows of j) – orbitals, then spin, as row orders them. Their Hermitian conjugates are added.
- Parameters:
dict_block (Dictionary)
- set_peierls_phase(phase: Callable[[...], NDArray]) None[source]#
Apply the Peierls substitution (see System.set_peierls_phase) to the hoppings hop and to every hopping block set so far.
- Parameters:
phase (Callable
phase(xi, yi, xj, yj))
- get_ham(**params) None[source]#
Get the Hamiltonian (and, for a non-orthogonal basis, the overlap matrix overlap).
- Parameters:
params – Values of the parameters of the value functions of hop (see System.get_ham).
- get_eig(eigenvec: bool = False, left: bool = False) None[source]#
Get the eigenenergies (and eigenvectors), as System.get_eig. With a non-orthogonal basis (see set_slater_koster), solve the generalized problem \(H\psi = ES\psi\) (eigenvectors normalized as \(\psi^\dagger S\psi = 1\) for a Hermitian \(H\)).
- Parameters:
eigenvec (Boolean, default False)
left (Boolean) – Default value False (orthogonal basis only).
- get_eig_sparse(n_eig: int = 10, sigma: complex = 0.0, eigenvec: bool = False) None[source]#
Get the eigenpairs closest to sigma (see System.get_eig_sparse; orthogonal basis only).
- get_local_chern_marker(e_fermi: float = 0.0, area: float | None = None) NDArray[float64][source]#
Get the local Chern marker (see System.get_local_chern_marker), summed over the orbitals and spin of each site (orthogonal basis only).
- Parameters:
e_fermi (Real number, default 0)
area (Positive real number, default None)
- Returns:
marker (Real ndarray, shape (sites,))
tbkit.meanfield module#
The Hubbard model in the (collinear, unrestricted Hartree-Fock) mean-field approximation:
Each spin moves in the density of the other; the densities are iterated (with linear mixing) until self-consistent. With \(U > 0\) on a bipartite lattice at half filling it reproduces Lieb’s theorem (the total moment \(S = ||A| - |B||/2\)) and the edge magnetism of zigzag graphene.
- class tbkit.meanfield.MeanFieldResult(n_up, n_dn, en_up, en_dn, e_fermi, energy, iterations)[source]#
Bases:
objectSelf-consistent solution of hubbard_mean_field.
- n_up#
Spin-up density on every site.
- Type:
Real ndarray
- n_dn#
Spin-down density on every site.
- Type:
Real ndarray
- magnetization#
\(m_i = (n_{i\uparrow} - n_{i\downarrow})/2\).
- Type:
Real ndarray
- en_up#
Spin-up mean-field energies.
- Type:
Real ndarray
- en_dn#
Spin-down mean-field energies.
- Type:
Real ndarray
- e_fermi#
Fermi level.
- Type:
Real number
- energy#
Mean-field ground-state (free, at T > 0) energy \(\sum f E - U\sum_i n_{i\uparrow}n_{i\downarrow}\).
- Type:
Real number
- iterations#
Number of iterations.
- Type:
Integer
- tbkit.meanfield.hubbard_mean_field(ham, U: float | ArrayLike, n_electrons: float, temperature: float = 0.0, n_up: ArrayLike | None = None, n_dn: ArrayLike | None = None, mixing: float = 0.5, tol: float = 1e-08, max_iter: int = 20000, seed=None) MeanFieldResult[source]#
Solve the Hubbard model in mean field, self-consistently.
The iteration converges to a self-consistent solution, not necessarily the one of lowest energy: compare the energy of the solutions reached from several starts (random seeds, or a staggered magnetization on the two sublattices of a bipartite lattice).
- Parameters:
ham – Square Hermitian matrix (sparse or dense), the spin-independent single-particle Hamiltonian (e.g. System.ham).
U (Real number, or array of one per site) – Onsite repulsion.
n_electrons (Positive real, at most 2N) – Number of electrons (both spins; N for half filling). An integer at T = 0.
temperature (Positive real or zero, default 0)
n_up (Real array, default None) – Initial spin-up density.
n_dn (Real array, default None) – Initial spin-down density. By default, a small random magnetization on top of the uniform density (to break the spin symmetry).
mixing (Real in (0, 1], default 0.5) – Fraction of the new density mixed in at each iteration. (Plain linear mixing converges only to stable solutions, but slowly near a magnetic transition: raise max_iter there.)
tol (Positive real, default 1e-8) – Convergence threshold on the largest density change.
max_iter (Positive integer, default 20000)
seed – Default value None. Seed of the random initial magnetization.
- Returns:
result (
MeanFieldResult)
- class tbkit.meanfield.NonCollinearResult(rho, energies, states, e_fermi, energy, iterations)[source]#
Bases:
objectSelf-consistent solution of hubbard_mean_field_noncollinear.
- rho#
Onsite spin density matrices \(\rho_{i,\alpha\beta} = \langle c^\dagger_{i\beta}c_{i\alpha}\rangle\).
- Type:
Complex ndarray, shape (N, 2, 2)
- density#
\(n_i = \mathrm{Tr}\,\rho_i\).
- Type:
Real ndarray
- magnetization#
\(\mathbf{m}_i = \mathrm{Tr}(\rho_i\boldsymbol\sigma)/2\).
- Type:
Real ndarray, shape (N, 3)
- energies#
Mean-field energies (2N).
- Type:
Real ndarray
- states#
Eigenvectors (columns), rows site-major (spin up, down).
- Type:
Complex ndarray, shape (2N, 2N)
- e_fermi#
Fermi level.
- Type:
Real number
- energy#
Mean-field ground-state energy \(\sum f E - U\sum_i(\rho_{i\uparrow\uparrow}\rho_{i\downarrow\downarrow} - |\rho_{i\uparrow\downarrow}|^2)\).
- Type:
Real number
- iterations#
Number of iterations.
- Type:
Integer
- property total_spin: NDArray[float64]#
Total spin \(\sum_i\mathbf{m}_i\), shape (3,).
- tbkit.meanfield.hubbard_mean_field_noncollinear(ham, U: float | ArrayLike, n_electrons: float, temperature: float = 0.0, magnetization: ArrayLike | None = None, spinful: bool = False, mixing: float = 0.5, tol: float = 1e-08, max_iter: int = 20000, seed=None) NonCollinearResult[source]#
Solve the Hubbard model in the non-collinear (spin-rotation invariant) Hartree-Fock approximation: the onsite spin density matrix \(\rho_i\) is kept whole, so the moments may point in any direction (spirals, the 120-degree order of frustrated lattices, moments canted by spin-orbit coupling). The Hartree and Fock terms of \(Un_{i\uparrow}n_{i\downarrow}\) add, on every site,
\[\begin{split}V_i = U\,(n_i\mathbb{1} - \rho_i) = U\begin{pmatrix}\rho_{\downarrow\downarrow} & -\rho_{\uparrow\downarrow}\\ -\rho_{\downarrow\uparrow} & \rho_{\uparrow\uparrow}\end{pmatrix} = U\Big(\frac{n_i}{2}\mathbb{1} - \mathbf{m}_i\cdot\boldsymbol\sigma\Big)\, ,\end{split}\]iterated with linear mixing until \(\rho\) is self-consistent. With \(\rho_{\uparrow\downarrow} = 0\) it is hubbard_mean_field (collinear moments along \(z\) stay collinear, and give the same solution). As there, several starts should be compared by energy.
- Parameters:
ham – Square Hermitian matrix: the single-particle Hamiltonian, (N, N) spin independent, or, with
spinful=True, (2N, 2N) with rows site-major (spin up, down) – e.g. with spin-orbit coupling.U (Real number, or array of one per site) – Onsite repulsion.
n_electrons (Positive real, at most 2N) – An integer at T = 0.
temperature (Positive real or zero, default 0)
magnetization (Real array, shape (N, 3)) – Default value None (random directions of length 0.1). Initial moments, on top of a uniform density.
spinful (Boolean, default False) – See ham.
mixing (Real in (0, 1], default 0.5)
tol (Positive real, default 1e-8) – Convergence threshold on the largest change of \(\rho\).
max_iter (Positive integer, default 20000)
seed – Default value None. Seed of the random initial moments.
- Returns:
result (
NonCollinearResult)
tbkit.exceptional module#
Band touchings of two-dimensional (non-Hermitian) Bloch bands: diabolical points (DPs), Hermitian degeneracies such as graphene’s Dirac points, where two eigenvalues meet but their eigenvectors stay distinct; and exceptional points (EPs), where the eigenvalues and the eigenvectors coalesce, so that \(H(\mathbf{k})\) stops being diagonalizable (a Jordan block).
The tools below tell them apart and compute their invariants. Each takes a
model: a 2D KSpace (the plane is the Brillouin zone, in the k
coordinates of get_ham), or any callable model(p) returning a square
matrix for a point p of a two-parameter plane.
Eigenvalue vorticity of a pair of bands around a closed loop \(\Gamma\) (Shen, Zhen and Fu, Phys. Rev. Lett. 120, 146402 (2018)),
\[\nu_{mn}(\Gamma) = -\frac{1}{2\pi}\oint_\Gamma \nabla_{\mathbf{k}}\arg\left[E_m(\mathbf{k}) - E_n(\mathbf{k})\right]\cdot d\mathbf{k}\, .\]Band labels are not single-valued around an EP (the two eigenvalues swap after one loop), so vorticity follows the eigenvalues by continuation along the loop (track_eigenvalues), never by sorting. A second-order EP has \(\nu = \pm1/2\), a DP \(\nu = 0\).
Discriminant winding (Yang, Schnyder, Hu and Chiu, Phys. Rev. Lett. 126, 086401 (2021)): the discriminant \(\Delta(\mathbf{k}) = \prod_{m<n}(E_m - E_n)^2\) is a polynomial in the matrix elements, computed from the characteristic polynomial without any eigenvalue, and its winding \(W(\Gamma) = \frac{1}{2\pi}\oint_\Gamma \nabla_{\mathbf{k}}\arg\Delta\cdot d\mathbf{k}\) counts the EPs inside \(\Gamma\) with their charges. With the two sign conventions above, \(W = -2\sum_{m<n}\nu_{mn}\): \(W = -2\nu = \mp1\) for a second-order EP of a two-band model.
EP finder (find_exceptional_points): zeros of \(\Delta\) with \(W \neq 0\) on a plaquette mesh of the Brillouin zone, refined by Newton’s method, with their charge and their order (the size of the Jordan block, from the Petermann factors, which diverge at an EP). Since \(\Delta\) is periodic, the charges sum to zero over the zone: EPs come in pairs of opposite charge (the doubling theorem). When a symmetry makes \(\Delta\) real, EPs form lines instead (exceptional rings, Zhen et al., Nature 525, 354 (2015)), which the finder also returns; fermi_arcs draws the bulk Fermi arcs \(\mathrm{Re}(E_m - E_n) = 0\) that join a pair of EPs (Kozii and Fu, arXiv:1708.05841 (2017); Zhou et al., Science 359, 1009 (2018)).
Encircling (encircle): parallel transport of an eigenvector around a loop. Around a DP one loop returns the state with a Berry phase \(\pi\); around a second-order EP one loop swaps the two eigenstates, two loops return the state with a sign flip, and four loops restore it (Heiss, Phys. Rev. E 61, 929 (2000); Dembowski et al., Phys. Rev. Lett. 86, 787 (2001)).
- tbkit.exceptional.circle(center: ArrayLike, radius: float) Callable[[float], NDArray[float64]][source]#
Get a circular loop, run counterclockwise: \(\mathbf{k}(s) = \mathbf{k}_0 + r(\cos 2\pi s, \sin 2\pi s)\), \(s\in[0, 1]\).
- Parameters:
center (Tuple/list/ndarray of 2 real numbers) – \(\mathbf{k}_0\).
radius (Positive real) – \(r\).
- Returns:
loop (Callable of s, returning a real ndarray of shape (2,))
- tbkit.exceptional.track_eigenvalues(model, loop, n_loops: int = 1, nk: int = 100) tuple[NDArray[float64], NDArray[float64], NDArray[complex128]][source]#
Follow the (complex) eigenvalues of \(H(\mathbf{k})\) continuously around a closed loop, n_loops times. Each step (at most 1/nk of the loop) matches the new eigenvalues to a linear prediction from the previous ones, and is halved while that matching is ambiguous; nothing depends on how the eigensolver orders its output. Label \(m\) is the \(m\)-th eigenvalue at the start of the loop, sorted by real part. After one loop around a second-order exceptional point the labels come back swapped:
en[-1]is then a permutation ofen[0].- Parameters:
model – 2D KSpace, or callable of a point of a plane returning a square matrix.
loop – Closed loop: a callable of \(s\in[0, 1]\) returning a point (e.g. circle), or an array of polygon vertices, shape (m, 2). For a KSpace, points are k in the coordinates of get_ham, and a loop may close up to a reciprocal lattice vector.
n_loops (Positive integer, default 1) – Number of turns.
nk (Positive integer, default 100) – Steps per turn before refinement.
- Returns:
s (Real ndarray, shape (n,)) – Loop parameter, from 0 to n_loops.
k (Real ndarray, shape (n, 2)) – Points of the loop.
en (Complex ndarray, shape (n, norb)) – Eigenvalues, en[:, m] continuous in s.
- tbkit.exceptional.vorticity(model, loop, bands: tuple[int, int] = (0, 1), nk: int = 100) float[source]#
Get the eigenvalue vorticity of a pair of bands around a closed loop \(\Gamma\) (Shen, Zhen and Fu, Phys. Rev. Lett. 120, 146402 (2018)),
\[\nu_{mn}(\Gamma) = -\frac{1}{2\pi}\oint_\Gamma \nabla_{\mathbf{k}}\arg\left[E_m(\mathbf{k}) - E_n(\mathbf{k})\right] \cdot d\mathbf{k}\, ,\]with the eigenvalues followed by continuation (see track_eigenvalues). \(\nu_{mn} = \pm1/2\) around a second-order exceptional point, where \(E_m - E_n \propto \sqrt{\mathbf{k}-\mathbf{k}_{EP}}\) changes sign after one loop; \(\pm1/3\) for each pair of a third-order one; 0 around a diabolical point, or a loop enclosing no degeneracy. \(\nu_{mn} = \nu_{nm}\).
- Parameters:
model – See track_eigenvalues.
loop – See track_eigenvalues. Counterclockwise for the sign above.
bands (Pair of distinct integers) – Default value (0, 1). Band labels \((m, n)\) at the start of the loop, sorted by real part.
nk (Positive integer, default 100) – See track_eigenvalues.
- Returns:
nu (Real number, a multiple of 1/2 around second-order EPs)
- tbkit.exceptional.discriminant(model, k: ArrayLike) complex[source]#
Get the discriminant of \(H(\mathbf{k})\),
\[\Delta(\mathbf{k}) = \prod_{m<n}\left[E_m(\mathbf{k}) - E_n(\mathbf{k})\right]^2 = (-1)^{N(N-1)/2}\,\mathrm{Res}(p, p')\, ,\]computed as the resultant of the characteristic polynomial \(p(E) = \det[E - H(\mathbf{k})]\) and its derivative (the determinant of their Sylvester matrix), without the eigenvalues. It is a polynomial in the matrix elements, hence smooth and single-valued, and it vanishes exactly where two eigenvalues meet. For a two-band model \(H = d_0 + \mathbf{d}\cdot\boldsymbol\sigma\), \(\Delta = 4\,\mathbf{d}\cdot\mathbf{d}\).
- Parameters:
model – See track_eigenvalues.
k (Tuple/list/ndarray of 2 real numbers) – Point of the plane.
- Returns:
delta (Complex number, in units of energy^(N(N-1)) (1 if N = 1))
- tbkit.exceptional.discriminant_winding(model, loop, nk: int = 100) float[source]#
Get the winding number of the discriminant (see discriminant) around a closed loop \(\Gamma\) (Yang, Schnyder, Hu and Chiu, Phys. Rev. Lett. 126, 086401 (2021)),
\[W(\Gamma) = \frac{1}{2\pi}\oint_\Gamma \nabla_{\mathbf{k}}\arg\Delta(\mathbf{k}) \cdot d\mathbf{k} = -2\sum_{m<n}\nu_{mn}(\Gamma)\, ,\]the total charge of the exceptional points inside \(\Gamma\) (\(\pm1\) for a second-order EP, where \(\Delta\) vanishes linearly). It needs no eigenvalue tracking. A diabolical point has \(W = 0\): \(\Delta \geq 0\) for a Hermitian model. The relation to the vorticities vorticity holds with the signs as written, the minus sign coming from Shen, Zhen and Fu’s definition of \(\nu\).
- Parameters:
model – See track_eigenvalues.
loop – See track_eigenvalues. Counterclockwise for the sign above.
nk (Positive integer, default 100) – Points on the loop; a step along which \(\arg\Delta\) turns by more than \(\pi/4\) is bisected.
- Returns:
W (Real number, close to an integer)
- tbkit.exceptional.petermann_factors(model, k: ArrayLike) tuple[NDArray[complex128], NDArray[float64]][source]#
Get the eigenvalues of \(H(\mathbf{k})\) and their Petermann factors
\[K_n = \frac{\langle L_n|L_n\rangle\langle R_n|R_n\rangle}{|\langle L_n|R_n\rangle|^2} \geq 1\, ,\]with \(|R_n\rangle\), \(|L_n\rangle\) the right and left eigenvectors: 1 for a normal (e.g. Hermitian) matrix, diverging at an exceptional point, where \(\langle L_n|R_n\rangle \to 0\) (as \(|\mathbf{k}-\mathbf{k}_{EP}|^{-1}\) near a second-order one).
- Parameters:
model – See track_eigenvalues.
k (Tuple/list/ndarray of 2 real numbers)
- Returns:
en (Complex ndarray, shape (norb,)) – Eigenvalues, sorted by real part.
K (Real ndarray, shape (norb,)) – Petermann factors.
- class tbkit.exceptional.ExceptionalPoints(k, charge, order, petermann, energy, lines)[source]#
Bases:
objectExceptional points of a 2D model, see find_exceptional_points.
- k#
Isolated exceptional points.
- Type:
Real ndarray, shape (n, 2)
- charge#
Discriminant winding around each one (see discriminant_winding): \(\pm1\) for a second-order EP.
- Type:
Integer ndarray, shape (n,)
- order#
Number of coalescing eigenvalues (the size of the Jordan block): 2, 3, …
- Type:
Integer ndarray, shape (n,)
- petermann#
Largest Petermann factor at each point (divergent at an EP: about \(10^{8}\) or more once refined).
- Type:
Real ndarray, shape (n,)
- energy#
The coalescing eigenvalue.
- Type:
Complex ndarray, shape (n,)
- lines#
Points on exceptional lines (rings), when a symmetry makes the discriminant real; empty otherwise.
- Type:
Real ndarray, shape (m, 2)
- tbkit.exceptional.find_exceptional_points(ks: KSpace, nk: int = 40, tol: float = 1e-12, max_iter: int = 50) ExceptionalPoints[source]#
Locate the exceptional points of a 2D model over its Brillouin zone.
The discriminant \(\Delta(\mathbf{k})\) (see discriminant) is computed on an \(nk\times nk\) mesh of the zone (shifted off the high-symmetry lines), and its winding around every plaquette from the phase changes along the mesh edges (bisected where \(\arg\Delta\) turns by more than \(\pi/4\)). A plaquette with a nonzero winding \(w\) holds an EP.
Each one is refined by Newton’s method on \((\mathrm{Re}\,\Delta, \mathrm{Im}\,\Delta) = 0\) from the plaquette centre (the step multiplied by \(|w|\), the multiplicity of the zero).
Its charge is the winding of \(\Delta\) around a small circle (a quarter of a plaquette), and its order the number of eigenvalues whose Petermann factor diverges there (see petermann_factors).
If a symmetry makes \(\Delta\) real everywhere (up to a constant phase), EPs are not isolated: they form lines, exceptional rings, where \(\Delta\) changes sign. The lines are then sampled where they cross the mesh edges (bisection to machine precision), and no isolated point is returned. A Hermitian model has \(\Delta \geq 0\), and no EP.
Since \(\Delta\) is periodic, the charges add up to zero (total_charge): EPs come in pairs of opposite charge. The mesh must be fine enough that no plaquette holds two EPs of opposite charge.
- Parameters:
ks (*KSpace instance with two primitive vectors*)
nk (Positive integer, default 40) – Mesh points along each reciprocal vector.
tol (Positive real, default 1e-12) – Newton’s method stops when a step is shorter than tol (units of k).
max_iter (Positive integer, default 50) – Newton iterations.
- Returns:
eps – ExceptionalPoints instance (positions k, charge, order, petermann, energy, and the exceptional lines).
- tbkit.exceptional.fermi_arcs(ks: KSpace, nk: int = 60) NDArray[float64][source]#
Get the bulk Fermi arcs of a 2D non-Hermitian model: the curves where two eigenvalues have equal real parts but different imaginary parts, \(\mathrm{Re}(E_m - E_n) = 0\), \(\mathrm{Im}(E_m - E_n) \neq 0\). Such an arc joins two exceptional points of opposite charge (for a two-band model it is where \(\Delta\) is real and negative, see discriminant); it is what a Hermitian Dirac point turns into when a non-Hermitian term splits it into an EP pair (Kozii and Fu 2017; Zhou et al., Science 359, 1009 (2018)).
Along every edge of an \(nk\times nk\) mesh of the zone the eigenvalues are followed by continuation (see track_eigenvalues), and where \(\mathrm{Re}(E_m - E_n)\) changes sign, the crossing is found by bisection. Regions where the real parts coincide over an area (inside an exceptional ring) show no sign change and are not reported, and neither are edges that cross an exceptional point or line, along which the eigenvalues cannot be followed.
- Parameters:
ks (*KSpace instance with two primitive vectors*)
nk (Positive integer, default 60) – Mesh points along each reciprocal vector.
- Returns:
points (Real ndarray, shape (m, 2)) – Points on the arcs.
- class tbkit.exceptional.Encircling(s, k, en, vector, band, final_band, overlap)[source]#
Bases:
objectAn eigenstate carried around a loop by parallel transport, see encircle.
- s#
Loop parameter, from 0 to n_loops.
- Type:
Real ndarray, shape (n,)
- k#
Points of the loop.
- Type:
Real ndarray, shape (n, 2)
- en#
All eigenvalues, followed by continuation (see track_eigenvalues).
- Type:
Complex ndarray, shape (n, norb)
- vector#
The transported right eigenvector \(|R(s)\rangle\) of the followed state.
- Type:
Complex ndarray, shape (n, norb)
- band#
Label of the state at the start.
- Type:
Integer
- final_band#
Label, at the start, of the eigenvalue the state ends on (different from band after an odd number of loops around a second-order EP: the states swap).
- Type:
Integer
- overlap#
\(c = \langle L_{f}(0)|R(\mathrm{end})\rangle\), with \(f\) = final_band and \(\langle L_f(0)|R_f(0)\rangle = 1\): the transported state is \(c\,|R_f(0)\rangle\). If final_band is band, \(c = e^{i\gamma}\) (times a modulus that is 1 for a Hermitian model), \(\gamma\) the geometric phase; otherwise its phase depends on the (arbitrary) phase of \(|R_f(0)\rangle\).
- Type:
Complex number
- tbkit.exceptional.encircle(model, loop, band: int = 0, n_loops: int = 1, nk: int = 100) Encircling[source]#
Carry an eigenstate around a closed loop n_loops times, by parallel transport of its right eigenvector \(|R\rangle\), with the left one \(\langle L|\) normalized by \(\langle L|R\rangle = 1\):
\[\langle L(\mathbf{k})|\partial_s R(\mathbf{k})\rangle = 0\, ,\]discretized symmetrically between successive points, \(\langle L_j + L_{j+1}|R_{j+1} - R_j\rangle = 0\) (second order in the step; the eigenvalue is followed by continuation, see track_eigenvalues). For a Hermitian model \(L = R\), the norm is kept exactly, and this is the usual parallel transport: the state comes back as \(e^{i\gamma}|R\rangle\), \(\gamma = \oint i\langle u|\nabla_{\mathbf{k}}u\rangle\cdot d\mathbf{k}\) the Berry phase (the convention of KSpace.berry_phase), \(\pi\) around a diabolical point. Around a second-order exceptional point:
one loop swaps the two eigenstates (final_band differs from band);
two loops bring the state back with a sign flip, \(\gamma = \pi\);
four loops restore it.
- Parameters:
model – See track_eigenvalues.
loop – See track_eigenvalues.
band (Integer, default 0) – Label of the state at the start of the loop (by real part of the eigenvalue).
n_loops (Positive integer, default 1) – Number of turns.
nk (Positive integer, default 100) – Steps per turn before refinement.
- Returns:
result – Encircling instance (en, the transported vector, final_band, overlap and phase).
tbkit.bdg module#
Superconductivity in the Bogoliubov-de Gennes (BdG) formalism. With a pairing term \(\sum_{ij}\Delta_{ij}c^\dagger_ic^\dagger_j + h.c.\), the Hamiltonian is \(\frac12\Psi^\dagger H_{BdG}\Psi\) in the Nambu basis \(\Psi = (c_1, \dots, c_N, c_1^\dagger, \dots, c_N^\dagger)^T\),
with \(\Delta^T = -\Delta\) (Fermi statistics). Its spectrum is
symmetric, \(\pm E_n\), by the particle-hole symmetry
\(\tau_x H_{BdG}^*\tau_x = -H_{BdG}\); the quasiparticle energies are
the \(E_n \ge 0\), and a zero mode is a Majorana mode. Real-space
models come from bdg_ham, periodic ones from bdg_kspace (a
tbkit.kspace.KSpace with the holes as extra orbitals, so its bands,
Berry phases, finite_ham, … all apply).
- tbkit.bdg.bdg_ham(ham, pairing, mu: float = 0.0) csr_matrix[source]#
Get the real-space BdG Hamiltonian (see the module docstring).
- Parameters:
ham (Square Hermitian matrix, shape (N, N) (e.g. *System.ham)*)
pairing – Square antisymmetric matrix, shape (N, N): \(\Delta\) (see pairing_bonds, pairing_s_wave).
mu (Real number, default 0) – Chemical potential.
- Returns:
ham_bdg (Sparse CSR matrix, shape (2N, 2N))
- tbkit.bdg.pairing_bonds(sys, delta: complex) csr_matrix[source]#
Get a p-wave (odd) pairing on the bonds of sys.hop: \(\Delta_{ij} = \Delta\), \(\Delta_{ji} = -\Delta\) for every stored hopping \(i\to j\) (oriented as System.set_hopping stores them: angle in \([0, 180)\)). On a chain it is Kitaev’s \(\Delta\,c^\dagger_jc^\dagger_{j+1}\).
- Parameters:
sys (*System instance, with hoppings*)
delta (Complex number) – \(\Delta\).
- Returns:
pairing (Sparse CSR matrix, shape (sites, sites))
- tbkit.bdg.pairing_s_wave(n_sites: int, delta: complex) csr_matrix[source]#
Get an onsite singlet (s-wave) pairing \(\Delta\sum_i c^\dagger_{i\uparrow}c^\dagger_{i\downarrow} + h.c.\) for a spinful model with rows ordered site by site, spin up then down (as KSpace with
spin=Trueand OrbitalSystem with one orbital).- Parameters:
n_sites (Positive integer) – Number of sites.
delta (Complex number) – \(\Delta\).
- Returns:
pairing (Sparse CSR matrix, shape (2 n_sites, 2 n_sites))
- tbkit.bdg.bdg_kspace(ks, pairing: list[dict], mu: float = 0.0)[source]#
Get the BdG Bloch Hamiltonian of a periodic model,
\[\begin{split}H_{BdG}(\mathbf{k}) = \begin{pmatrix} h(\mathbf{k})-\mu & \Delta(\mathbf{k}) \\ \Delta(\mathbf{k})^\dagger & -[h(-\mathbf{k})-\mu]^T\end{pmatrix}\, ,\qquad \Delta(\mathbf{k}) = \sum_{\mathbf{R}}\Delta_{ij}(\mathbf{R})\,e^{i\mathbf{k}\cdot\mathbf{R}}\, ,\end{split}\]as a new KSpace whose orbitals are those of ks (particles,
0 ... norb-1) followed by their holes (norb ... 2 norb-1, at the same positions). Each pairing \(\Delta\,c^\dagger_{i,\mathbf{0}}c^\dagger_{j,\mathbf{R}} + h.c.\) enters antisymmetrized, \(\Delta_{ij}(\mathbf{R}) = -\Delta_{ji}(-\mathbf{R})\).- Parameters:
ks (*KSpace instance (Hermitian, orthogonal basis)*)
pairing – List of dictionaries with keys (‘i’, ‘j’, ‘R’, ‘delta’): orbital indices of ks (
0 ... norb-1; withspin=True,2*site + spin), lattice vector, amplitude.mu (Real number, default 0) – Chemical potential.
- Returns:
ks_bdg (*KSpace instance, 2 norb orbitals*)
Examples
Example usage:
# Kitaev chain: E(k) = +-sqrt((2t cos k - mu)^2 + 4 Delta^2 sin^2 k) chain = KSpace(lattices.chain()) chain.set_hopping([{'i': 0, 'j': 0, 'R': (1,), 't': t}]) kit = bdg_kspace(chain, [{'i': 0, 'j': 0, 'R': (1,), 'delta': delta}], mu=mu)
- tbkit.bdg.particle_hole(n: int) NDArray[float64][source]#
Get the unitary part \(\tau_x\) of the BdG particle-hole symmetry \(C = \tau_x\mathcal{K}\) (\(C^2 = +1\)), for n particle orbitals: pass it to KSpace.symmetry_error (
antiunitary=True,anti=True) or KSpace.tenfold_class (particle_hole=).- Parameters:
n (Positive integer) – Number of particle orbitals.
- Returns:
tau_x (Real ndarray, shape (2n, 2n))
- tbkit.bdg.pfaffian(a) complex[source]#
Get the Pfaffian of an antisymmetric matrix, \(\mathrm{Pf}(A)^2 = \det A\), by the Parlett-Reid reduction to tridiagonal form with pivoting (Wimmer, ACM Trans. Math. Softw. 38, 30 (2012)). For a 2x2 block \(\begin{pmatrix}0 & a\\ -a & 0\end{pmatrix}\) it is \(a\); it is 0 for an odd dimension.
- Parameters:
a (Square antisymmetric matrix, shape (n, n))
- Returns:
pf (Complex number (a float for a real matrix))
- tbkit.bdg.majorana_number(ks) int[source]#
Get Kitaev’s Majorana number of a BdG model (Kitaev, Physics-Uspekhi 44, 131 (2001)): the product, over the time-reversal-invariant momenta \(\Gamma_i\), of the signs of the Pfaffians of the Hamiltonian in the Majorana basis,
\[\begin{split}\mathcal{M} = \prod_i \mathrm{sign}\,\mathrm{Pf}\,A(\Gamma_i)\, ,\qquad A = -i\,U H_{BdG} U^\dagger\, ,\qquad U = \frac{1}{\sqrt2}\begin{pmatrix}1 & 1\\ -i & i\end{pmatrix}\, ,\end{split}\]\(U\) taking the Nambu spinor \((c, c^\dagger)\) to the Majorana operators \((c + c^\dagger, -i(c - c^\dagger))\). Particle-hole symmetry makes \(A(\Gamma_i)\) real and antisymmetric. In 1D, \(\mathcal{M} = \mathrm{sign}\,\mathrm{Pf}A(0)\,\mathrm{Pf}A(\pi) = -1\) in the topological phase (a Majorana zero mode at each end of an open chain), +1 in the trivial one: the \(\mathbb{Z}_2\) invariant of class D. In 2D the product over the four momenta is \((-1)^C\), the parity of the Chern number (Ghosh et al., Phys. Rev. B 82, 184525 (2010)). The invariant changes only where the gap closes at one of the \(\Gamma_i\).
- Parameters:
ks – KSpace instance of a BdG model, 2n orbitals: n particles then their n holes (see bdg_kspace).
- Returns:
m (Integer, -1 (topological) or +1 (trivial))
- class tbkit.bdg.GapResult(delta, energies, states, iterations)[source]#
Bases:
objectSelf-consistent s-wave pairing of s_wave_gap.
- delta#
Gap \(\Delta_i\) on every site.
- Type:
Complex ndarray
- energies#
Spectrum of the reduced BdG Hamiltonian (symmetric, \(\pm E_n\)).
- Type:
Real ndarray, shape (2N,)
- states#
Its eigenvectors \((u_n, v_n)\) (columns).
- Type:
Complex ndarray, shape (2N, 2N)
- iterations#
Number of iterations.
- Type:
Integer
- tbkit.bdg.s_wave_gap(ham, V: float | NDArray, mu: float = 0.0, temperature: float = 0.0, delta0: complex | NDArray = 0.1, mixing: float = 1.0, tol: float = 1e-08, max_iter: int = 10000) GapResult[source]#
Solve the real-space gap equation of an s-wave superconductor self-consistently (the attractive Hubbard model \(-\sum_iV_in_{i\uparrow}n_{i\downarrow}\) in the BCS mean-field approximation, de Gennes 1966). For a spin-independent ham the singlet BdG Hamiltonian reduces to the Nambu basis \((c_{i\uparrow}, c^\dagger_{i\downarrow})\),
\[\begin{split}H = \begin{pmatrix} h-\mu & \Delta\\ \Delta^* & -(h-\mu)^*\end{pmatrix}\, , \qquad \Delta = \mathrm{diag}(\Delta_i)\, ,\end{split}\]whose eigenvectors \((u_n, v_n)\), \(E_n > 0\), give the gap equation
\[\Delta_i = V_i\,\langle c_{i\downarrow}c_{i\uparrow}\rangle = V_i\sum_{E_n>0}u_n(i)\,v_n^*(i)\tanh\frac{E_n}{2T}\, ,\]iterated (with linear mixing) until self-consistent. On a clean lattice it is the BCS gap equation \(1 = \frac{V}{N}\sum_{\mathbf{k}} \tanh(E_{\mathbf{k}}/2T)/2E_{\mathbf{k}}\), with \(\Delta(T_c) = 0\) at \(T_c \approx \Delta(0)/1.764\) at weak coupling. The chemical potential is fixed (the Hartree shift \(-V_in_i/2\) is left out, i.e. absorbed in \(\mu\)). Near \(T_c\) the iteration slows down (the linearized map has an eigenvalue close to 1): raise max_iter there.
- Parameters:
ham (Square Hermitian matrix, (N, N), spin independent (e.g. *System.ham)*)
V (Positive real, or array of N non-negative reals) – Attraction.
mu (Real number, default 0) – Chemical potential.
temperature (Positive real or zero, default 0)
delta0 (Number, or array of N numbers, default 0.1) – Initial gap.
mixing (Real in (0, 1]) – Default value 1 (plain iteration).
tol (Positive real, default 1e-8) – Convergence threshold on the largest change of \(\Delta_i\).
max_iter (Positive integer, default 10000)
- Returns:
result (
GapResult)
tbkit.floquet module#
Floquet theory of periodically driven Tight-Binding models, \(H(t + T) = H(t)\), \(\omega = 2\pi/T\) (\(\hbar = 1\)).
The evolution over one period, \(U(T) = \mathcal{T}e^{-i\int_0^TH(t)dt} = e^{-iH_FT}\), defines the Floquet Hamiltonian \(H_F\), whose eigenvalues – the quasienergies \(\epsilon\), defined modulo \(\omega\) – replace the energies of a static model: the driven system, observed once per period, behaves as if it were static with Hamiltonian \(H_F\). Driving can therefore engineer band structures and their topology: circularly polarized light turns graphene into a Chern insulator (Oka and Aoki, Phys. Rev. B 79, 081406 (2009); Kitagawa, Oka, Brataas, Fu and Demler, Phys. Rev. B 84, 235108 (2011)).
Two routes give the quasienergies, checked against each other in the tests:
the time-ordered product of short-time propagators (evolution_operator, quasienergies, effective_hamiltonian);
the Sambe (extended) space of the harmonics \(H(t) = \sum_m H_m e^{-im\omega t}\), a static eigenvalue problem (harmonics, sambe_hamiltonian).
FloquetKSpace makes a driven KSpace model: its get_ham is
the Floquet Hamiltonian \(H_F(\mathbf{k})\), so its bands, Berry
curvature and Chern numbers are the driven ones.
Anomalous Floquet phases. The quasienergies are defined modulo \(\omega\), so \(H_F\) depends on where the branch cut of the logarithm is put (the epsilon arguments). The Chern numbers of the Floquet bands no longer count the edge states: every band can have \(C = 0\) while chiral edge states cross every gap (Kitagawa, Berg, Rudner and Demler, Phys. Rev. B 82, 235114 (2010)). The winding number of Rudner, Lindner, Berg and Levin (Phys. Rev. X 3, 031005 (2013)), which uses the evolution at all times of the period, does (DrivenKSpace.winding_number):
DrivenKSpacemakes a driven Bloch model out of any time-dependent \(H(\mathbf{k}, t)\);step_drive builds a piecewise-constant drive from a list of models (KSpace models, ribbons made by kspace.ribbon, real-space System instances, or matrices), evolved exactly as a product of step exponentials (
StepDrivein real space);DrivenKSpace.edge_state_count counts the chiral edge states of a driven ribbon, independently of the bulk winding number.
- tbkit.floquet.evolution_operator(ham_t: Callable, period: float, n_steps: int = 100) NDArray[complex128][source]#
Get the one-period evolution operator \(U(T) = \prod_m e^{-iH(t_m)\,\delta t}\) (later times on the left, midpoints \(t_m = (m + 1/2)\delta t\), error \(O(\delta t^2)\)).
- Parameters:
ham_t (Callable) –
ham_t(t)returns the Hamiltonian at time t (a square matrix).period (Positive real) – \(T\).
n_steps (Positive integer, default 100) – Time steps per period.
- Returns:
U (Complex ndarray, the shape of the Hamiltonian)
- tbkit.floquet.quasienergies(ham_t: Callable, period: float, n_steps: int = 100, epsilon: float | None = None) NDArray[float64][source]#
Get the quasienergies \(\epsilon\), eigenvalues of the Floquet Hamiltonian, in the first Floquet zone \([-\omega/2, \omega/2)\), or in \([\epsilon_{cut} - \omega, \epsilon_{cut})\).
- Parameters:
ham_t (Callable) – See evolution_operator.
period (Positive real)
n_steps (Positive integer, default 100)
epsilon (Real number) – Default value None (the zone \([-\omega/2, \omega/2)\)). Branch cut, see effective_hamiltonian.
- Returns:
eps (Real ndarray, sorted)
- tbkit.floquet.effective_hamiltonian(ham_t: Callable, period: float, n_steps: int = 100, epsilon: float | None = None) NDArray[complex128][source]#
Get the Floquet Hamiltonian \(H_F = \frac{i}{T}\ln U(T)\), with its quasienergies in the first Floquet zone (Hermitian for a Hermitian drive).
The logarithm is defined up to multiples of \(\omega\) on each eigenvalue: epsilon puts its branch cut at the quasienergy \(\epsilon_{cut}\) (the phase \(e^{-i\epsilon_{cut}T}\) of \(U\)), so that the quasienergies lie in \([\epsilon_{cut} - \omega, \epsilon_{cut})\). The default, the zone \([-\omega/2, \omega/2)\), is the cut \(\epsilon_{cut} = \omega/2\). Rudner et al. (2013) take \((\epsilon_{cut}, \epsilon_{cut} + \omega]\) instead: \(H_F\) shifted by \(\omega\) (the same projectors, so the same Chern numbers and winding numbers).
- Parameters:
ham_t (Callable) – See evolution_operator.
period (Positive real)
n_steps (Positive integer, default 100)
epsilon (Real number) – Default value None (\(\epsilon_{cut} = \omega/2\), computed exactly as before this option existed). Branch cut, best placed in a quasienergy gap.
- Returns:
H_F (Complex ndarray)
- tbkit.floquet.harmonics(ham_t: Callable, period: float, n_harmonics: int, n_samples: int | None = None) dict[source]#
Get the Fourier components \(H_m = \frac1T\int_0^T H(t)\,e^{im\omega t}\,dt\) of the drive, \(H(t) = \sum_m H_m e^{-im\omega t}\), for \(|m| \le\) n_harmonics (exact for a drive with no higher harmonics).
- Parameters:
ham_t (Callable) – See evolution_operator.
period (Positive real)
n_harmonics (Positive integer or zero)
n_samples (Positive integer) – Default value None (4 n_harmonics + 16). Time samples per period.
- Returns:
H_m (Dictionary {m: complex ndarray})
- tbkit.floquet.sambe_hamiltonian(harm: dict, omega: float, n_max: int) NDArray[complex128][source]#
Get the Sambe-space Floquet Hamiltonian, truncated to the photon sectors \(n = -n_{max}, \dots, n_{max}\):
\[(\mathcal{H})_{nn'} = H_{n-n'} + n\omega\,\delta_{nn'}\, .\]Its eigenvalues are the quasienergies, repeated in every Floquet zone (shifted by multiples of \(\omega\)); those of the central zone converge fastest as n_max grows.
- Parameters:
harm (Dictionary {m: square complex array}, see *harmonics*)
omega (Positive real) – Driving frequency.
n_max (Positive integer or zero)
- Returns:
H (Complex ndarray, shape ((2 n_max + 1) d, (2 n_max + 1) d))
- class tbkit.floquet.StepDrive(hams: list, durations: ArrayLike, epsilon: float | None = None)[source]#
Bases:
objectA finite (real-space) system driven by a piecewise-constant Hamiltonian: \(H(t) = H_n\) for \(t_{n-1} \le t < t_n = \delta t_1 + \dots + \delta t_n\), repeated with period \(T = \sum_n \delta t_n\). The evolution is exact, a product of step exponentials,
\[U(t) = e^{-iH_n(t - t_{n-1})}\,e^{-iH_{n-1}\delta t_{n-1}}\cdots e^{-iH_1\delta t_1}\, ,\]with no time grid. Built by step_drive from System instances or matrices (see DrivenKSpace for Bloch models and ribbons).
- Parameters:
hams – List of square complex ndarrays, one Hermitian matrix per step (all of one shape).
durations (List of positive reals, the step durations \(\delta t_n\))
epsilon (Real number, default None) – Default branch cut of quasienergies and effective_hamiltonian.
- get_ham(t: float) NDArray[complex128][source]#
Get the Hamiltonian \(H(t)\) (periodic in \(T\)).
- Parameters:
t (Real number) – Time.
- Returns:
H (Complex ndarray)
- evolution_operator(t: float | None = None) NDArray[complex128][source]#
Get the exact evolution operator \(U(t)\) from time 0.
- Parameters:
t (Real number in \([0, T]\)) – Default value None (one period, \(U(T)\)).
- Returns:
U (Complex ndarray)
- quasienergies(epsilon: float | None = None) NDArray[float64][source]#
Get the quasienergies, sorted, in \([-\omega/2, \omega/2)\) or \([\epsilon_{cut} - \omega, \epsilon_{cut})\) (see effective_hamiltonian).
- Parameters:
epsilon (Real number) – Default value None (the epsilon of the drive).
- Returns:
eps (Real ndarray)
- effective_hamiltonian(epsilon: float | None = None) NDArray[complex128][source]#
Get the Floquet Hamiltonian \(H_F = \frac{i}{T}\ln U(T)\), branch cut at epsilon (see tbkit.floquet.effective_hamiltonian).
- Parameters:
epsilon (Real number) – Default value None (the epsilon of the drive).
- Returns:
H_F (Complex ndarray)
- evolve(psi: NDArray, n_periods: int) NDArray[complex128][source]#
Evolve a state stroboscopically, \(\psi(nT) = U(T)^n\psi(0)\).
- Parameters:
psi (Complex ndarray, the initial state (one amplitude per site))
n_periods (Positive integer or zero)
- Returns:
psi_n – Complex ndarray, shape (n_periods + 1, n_sites): the state after 0, 1, …, n_periods periods.
- tbkit.floquet.step_drive(models: list, durations: ArrayLike, epsilon: float | None = None)[source]#
Build a piecewise-constant drive: the Hamiltonian of
models[n]acts fordurations[n], in order, and the cycle repeats with period \(T = \sum_n \delta t_n\). The evolution is exact (a product of step exponentials, no time grid, see StepDrive).- Parameters:
models – List of models of one size, all of one kind:
KSpace instances (including ribbons made by kspace.ribbon) – returns a DrivenKSpace, whose get_ham is the Floquet Hamiltonian \(H_F(\mathbf{k})\);
System instances (their get_ham is called) or square matrices (dense or scipy.sparse) – returns a StepDrive.
Each must be Hermitian; KSpace models need an orthogonal basis.
durations (List of positive reals) – \(\delta t_n\), one per model.
epsilon (Real number, default None) – Branch cut of the Floquet Hamiltonian (see effective_hamiltonian).
- Returns:
drive – DrivenKSpace or StepDrive.
Examples
Example usage:
# Rudner et al. (2013): hopping along one bond direction per step drive = step_drive([ks1, ks2, ks3, ks4, ks5], [T/5] * 5) w = drive.winding_number(epsilon=np.pi / T)
- class tbkit.floquet.DrivenKSpace(ks, ham_kt: Callable, period: float, n_steps: int = 100, epsilon: float | None = None)[source]#
Bases:
objectA periodic model driven by any time-periodic Bloch Hamiltonian \(H(\mathbf{k}, t + T) = H(\mathbf{k}, t)\).
It is a copy of the KSpace model whose get_ham returns the Floquet Hamiltonian \(H_F(\mathbf{k}) = \frac{i}{T}\ln U(\mathbf{k}, T)\) (branch cut at epsilon, see effective_hamiltonian), so get_bands, k_path, berry_curvature, chern_number, … describe the driven system, and winding_number gives its anomalous topology. The evolution \(U(\mathbf{k}, T)\) is the product of n_steps midpoint propagators (see evolution_operator); drives built by step_drive are evolved exactly. Real-space methods that need static hoppings (finite_ham, get_ham_beta, gbz) are not available.
- Parameters:
ks (*KSpace instance*) – The model driven: its lattice, orbitals and k-space conventions (periodic gauge) are those of the driven model.
ham_kt (Callable) –
ham_kt(k, t)returns the Hermitian Bloch Hamiltonian \(H(\mathbf{k}, t)\), shape (norb, norb), in the periodic gauge of ks (\(H(\mathbf{k} + \mathbf{G}, t) = H(\mathbf{k}, t)\)).period (Positive real) – \(T\).
n_steps (Positive integer, default 100) – Time steps per period.
epsilon (Real number) – Default value None (quasienergies in \([-\omega/2, \omega/2)\)). Branch cut of get_ham.
Examples
Example usage:
# a sublattice mass switched on and off drive = DrivenKSpace(ks, lambda k, t: ks.get_ham(k) + m * np.cos(w * t) * sz, 2 * np.pi / w)
- durations: NDArray[np.float64]#
- ham_kt: Callable#
- rec_vec_k: NDArray[np.float64]#
- get_evolution(k: ArrayLike, t: float | None = None) NDArray[complex128][source]#
Get the evolution operator \(U(\mathbf{k}, t) = \mathcal{T}e^{-i\int_0^tH(\mathbf{k},t')dt'}\).
- Parameters:
k (k point (see *KSpace.get_ham)*)
t (Real number in \([0, T]\)) – Default value None (one period: the Floquet operator \(U(\mathbf{k}, T)\)).
- Returns:
U (Complex ndarray, shape (norb, norb))
- get_ham(k: ArrayLike) NDArray[complex128][source]#
Get the Floquet Hamiltonian \(H_F(\mathbf{k})\), quasienergies in \([\epsilon_{cut} - \omega, \epsilon_{cut})\) (default \([-\omega/2, \omega/2)\)).
- Parameters:
k (k point (see *KSpace.get_ham)*)
- Returns:
H_F (Complex ndarray, shape (norb, norb))
- winding_number(epsilon: float, nk: int | tuple[int, int] = 48, n_t: int = 40) float[source]#
Get the winding number of Rudner, Lindner, Berg and Levin (Phys. Rev. X 3, 031005 (2013)), the number of chiral edge states in the quasienergy gap at epsilon:
\[W[U_\epsilon] = \frac{1}{8\pi^2}\int_0^T dt\int_{BZ} dk_x dk_y\, \mathrm{Tr}\left(U_\epsilon^{-1}\partial_tU_\epsilon \left[U_\epsilon^{-1}\partial_{k_x}U_\epsilon, U_\epsilon^{-1}\partial_{k_y}U_\epsilon\right]\right),\]of the loop \(U_\epsilon(\mathbf{k}, t) = U(\mathbf{k}, 2t)\) for \(t \le T/2\), then \(V_\epsilon(\mathbf{k}, 2T - 2t)\), with the return map \(V_\epsilon(\mathbf{k}, t) = e^{-iH_F^\epsilon(\mathbf{k})t}\) and \(H_F^\epsilon\) the Floquet Hamiltonian with its branch cut at epsilon (see effective_hamiltonian). As the integrand is a 3-form, this is the winding of \(U\) over \([0, T]\) minus that of \(V_\epsilon\) over \([0, T]\).
Signs. \(W\) counts the chiral edge states in the gap: \(W = n_{lower} = -n_{upper}\) of edge_state_count, so \(W > 0\) means states moving along \(+\mathbf{a}_1\) on the edge of a ribbon on the side of \(-\hat{z}\times\mathbf{a}_1\) (the bottom edge of a ribbon along x). Across a group of Floquet bands, \(W[U_{\epsilon'}] - W[U_\epsilon] = -\sum_n C_n\) for \(\epsilon < \epsilon'\), the sum over the bands between the two gaps, with the Chern numbers \(C_n\) of chern_number (the paper’s \(\mathcal{C}_n = -\frac{1}{2\pi}\int\nabla\times\mathcal{A}_n\) is minus ours, so there \(W' - W = +\sum\mathcal{C}\)). A static model (whose bands fit in the zone below the cut) has \(W = 0\) at the zone edge, and \(W = -\sum C\) of the bands below any other gap. The anomalous phases are those with \(W \ne 0\) in every gap while all the \(C_n = 0\).
Discretization: \(U(\mathbf{k}, t)\) on a uniform \(n_1\times n_2\) Brillouin-zone grid, differentiated spectrally in \(\mathbf{k}\) (exponentially accurate: both \(U\) and, while the gap at epsilon is open, \(V_\epsilon\) are analytic and periodic in \(\mathbf{k}\)), and \(\partial_tU = -iHU\) exactly, integrated by Gauss-Legendre quadrature on each time step (n_t nodes per period in total, at least 2 per step) and over \([0, T]\) for the return map. Step drives are exact; a continuous drive is replaced by its n_steps midpoint steps, whose loop has the same \(W\) as long as the gap stays open.
Tolerance. The result is returned raw. Its error falls off exponentially with nk, at a rate set by the k-width of the region where \(V_\epsilon\) varies fast, gap / band velocity near the smallest gap at epsilon (the Berry curvature is concentrated there). For the five-step model (\(\delta_{AB} = 0.5\pi/T\)) the error is below \(10^{-12}\) at perfect transfer; with a gap of \(0.067\omega\) it is \(2\times10^{-5}\) at the default nk = 48; with a gap of \(0.021\omega\) it is \(10^{-2}\) at nk = 48 and \(4\times10^{-4}\) at nk = 96. Circularly driven graphene (gap \(0.01\omega\) at K) needs nk = 96 for \(3\times10^{-3}\). Rounding to the nearest integer is trustworthy when \(|W - \mathrm{round}(W)| < 0.01\) and the value is unchanged within that tolerance when nk is doubled; a value far from an integer means the gap is too small for the grid (or closed).
- Parameters:
epsilon (Real number) – Quasienergy of the gap (branch cut).
nk (Positive integer (at least 4), or tuple of 2) – Default value 48. k-points along each reciprocal vector.
n_t (Positive integer, default 40) – Gauss-Legendre nodes per period (at least 2 per step; 2 n_t, and at least 24, for the return map).
- Returns:
W (Real number, close to an integer)
- edge_state_count(epsilon: float, nk: int = 200, window: float | None = None) tuple[float, float][source]#
Count the chiral edge states of a driven ribbon (a 1D model, e.g. made by step_drive from kspace.ribbon models) crossing the quasienergy gap at epsilon, on each of its two edges.
Following the quasienergies \(\epsilon_n(k)\) over the Brillouin zone (\(k\) along \(\mathbf{a}_1\), nk points), a state crossing epsilon upwards (\(d\epsilon/dk > 0\)) counts +1, downwards -1, weighted by its probability on each half of the ribbon (the halves below and above its middle line, along \(\hat{z}\times\mathbf{a}_1\)). States are followed from one k to the next by their largest overlap. Only states within window of epsilon are followed; bulk states do not cross a gap, so only edge states contribute. The counts are integers, \(\pm1\) per chiral mode, up to the tail of the edge states on the other half (exponentially small in the width) and the two edges sum to zero. With the conventions of winding_number,
n_upper = -n_lower = W(checked in the tests and examples).- Parameters:
epsilon (Real number) – Quasienergy of the gap.
nk (Positive integer (at least 4), default 200) – k-points, fine enough that a state moves by less than window between two.
window (Positive real) – Default value None (\(\omega/8\)).
- Returns:
n_lower (Real number) – Signed count on the lower edge.
n_upper (Real number) – Signed count on the upper edge.
- class tbkit.floquet.FloquetKSpace(ks, vector_potential: Callable, period: float, n_steps: int = 100, epsilon: float | None = None)[source]#
Bases:
DrivenKSpaceA periodic model driven by a uniform, time-periodic vector potential \(\mathbf{A}(t)\) (e.g. circularly polarized light, \(\mathbf{A}(t) = A_0(\cos\omega t, \sin\omega t)\)), coupled through the Peierls phases of its bonds (see KSpace.get_ham_peierls).
It is a copy of the KSpace model whose get_ham returns the Floquet Hamiltonian \(H_F(\mathbf{k})\) (see effective_hamiltonian), so get_bands, k_path, berry_curvature, chern_number, wannier_centers, … describe the driven system (quasienergies in the first Floquet zone: for Chern numbers, pick bands separated by gaps that do not wrap around the zone edge, or move the zone edge with epsilon). It is a DrivenKSpace, with \(H(\mathbf{k}, t)\) =
ks.get_ham_peierls(k, vector_potential(t)), so winding_number applies. Real-space methods that need static hoppings (finite_ham, get_ham_beta, gbz) are not available.- Parameters:
ks (*KSpace instance (the static model)*)
vector_potential (Callable) –
vector_potential(t)returns \(\mathbf{A}(t)\) (space_dim components).period (Positive real) – \(T\).
n_steps (Positive integer, default 100) – Time steps per period.
epsilon (Real number) – Default value None (quasienergies in \([-\omega/2, \omega/2)\), as before this option existed). Branch cut of get_ham, see effective_hamiltonian.
- vector_potential: Callable#
tbkit.neighbours module#
Neighbour shells of a periodic lattice, and the neighbour-order hoppings of KSpace.set_hopping.
System.set_hopping addresses the bonds of a finite lattice by neighbour
order 'n' (1st, 2nd, … shortest distance), optionally narrowed by
bond angle 'ang' and sublattice-pair tag 'tag'. This module finds
the same bonds in a periodic lattice, from unit_cell and prim_vec
only: each bond is an intra-cell orbital pair \((i, j)\) plus a lattice
vector \(\mathbf{R} = n_1\mathbf{a}_1+\dots\), with bond vector
\(\mathbf{d} = \mathbf{R} + \boldsymbol\tau_j - \boldsymbol\tau_i\),
and turns a neighbour-order hopping list into the explicit
{'i', 'j', 'R', 't'} list of KSpace.set_hopping.
The conventions are those of System: distances are grouped after rounding
to 4 decimals and matched within ATOL = 1e-3; every bond is kept once,
oriented from i to j so that its angle (that of the projection of
\(\mathbf{d}\) on the \((x, y)\) plane, in degrees; a vertical bond
has angle 0 pointing up, -180 pointing down) lies in \([0, 180)\); its
tag is tag_i + tag_j.
- tbkit.neighbours.neighbour_shells(lat: Lattice, n_max: int) NDArray[float64][source]#
Get the distances of the first n_max neighbour shells of the infinite periodic lattice (the
dist_uni[1:]of System, without its edges).- Parameters:
lat (*Lattice instance*) – Only unit_cell and prim_vec are used.
n_max (Positive integer) – Number of shells.
- Returns:
shells (Real ndarray, shape (n_max,)) – Distances, ascending (rounded to 4 decimals, as in System).
- tbkit.neighbours.shell_index(lat: Lattice, dist: NDArray[float64]) NDArray[int64][source]#
Private function. Neighbour order of bond lengths dist (0 for a length below ATOL, as System’s
dist_uni[0]).
- tbkit.neighbours.neighbour_bonds(lat: Lattice, n_max: int) NDArray[source]#
Get every bond of the first n_max neighbour shells of the infinite periodic lattice, once each, oriented so that its angle lies in \([0, 180)\) (see the module docstring).
- Parameters:
lat (*Lattice instance*) – Only unit_cell and prim_vec are used.
n_max (Positive integer) – Number of shells.
- Returns:
bonds – Structured ndarray with fields ‘n’ (shell), ‘i’, ‘j’ (orbitals), ‘R’ (lattice vector, dim integers), ‘ang’ (degrees, in [0, 180)), ‘tag’ (
tag_i + tag_j) and ‘dis’ (length), sorted by (n, i, j, R).
Examples
Example usage:
bonds = neighbour_bonds(lattices.honeycomb(), 1) # three 'ab'/'ba' bonds of length 1, at angles 30, 90 and 150
- tbkit.neighbours.neighbour_hoppings(lat: Lattice, list_hop: list[dict], spin: bool = False, hermitian: bool = True) list[dict][source]#
Turn hoppings given by neighbour order, as in System.set_hopping, into the explicit
{'i', 'j', 'R', 't'}list of KSpace.set_hopping.- Parameters:
lat (*Lattice instance*) – Only unit_cell and prim_vec are used.
list_hop – List of dictionaries with keys (‘n’, ‘t’) and optionally ‘ang’ and/or ‘tag’ (see System.set_hopping):
‘n’: Positive integer. Neighbour order (1 for nearest neighbours).
‘ang’: Real number, in degrees. Only the bonds along this angle. An angle in \([0, 180)\) selects the bonds oriented as they are stored (see neighbour_bonds), an angle in \([-180, 0)\) the same bonds oriented the other way (from j to i).
‘tag’: String of length 2. Only the bonds from a site of the first sublattice to one of the second, in the orientation above.
‘t’: Complex number (or, if spin, a 2x2 matrix): the matrix element \(\langle i|H|j\rangle\) along the oriented bond. Or a value function (see KSpace.set_hopping), passed on as it is (as
t(j, i)^\daggerfor a reversed bond of a Hermitian model).
When several dictionaries select the same bond, the last one wins, as in System.set_hopping.
spin (Boolean, default False) – See KSpace.
hermitian (Boolean, default True) – If True, each bond is returned once, in its stored orientation (a hopping given along a negative angle becomes its conjugate transpose); if False, the two orientations are independent hoppings (non-reciprocal models).
- Returns:
list_hop (List of dictionaries (‘i’, ‘j’, ‘R’, ‘t’))
Examples
Example usage:
# graphene: nearest (t) and next-nearest (t2) neighbours explicit = neighbour_hoppings(lattices.honeycomb(), [{'n': 1, 't': -1.}, {'n': 2, 't': 0.1}])
tbkit.topology module#
Topological diagnostics beyond the Brillouin-zone integrals of
tbkit.kspace.KSpace:
Bott index (bott_index): the Chern number of a finite sample on a torus, from its projector on the occupied states and the exponentiated position operators (Loring and Hastings, EPL 92, 67004 (2010)). It needs no Brillouin zone, so it applies to disordered samples and quasicrystals, and complements the local Chern marker of
tbkit.system.System.get_local_chern_marker().Entanglement spectrum (entanglement_spectrum): the eigenvalues of the correlation matrix of the occupied states restricted to a region of a finite sample (Peschel 2003; Li and Haldane 2008). Its k-resolved version for ribbons and supercells is
tbkit.kspace.KSpace.entanglement_spectrum().Weyl points (find_weyl_points): the band touchings of a 3D model and their chiralities, the Berry flux through a small sphere around each one (Wan, Turner, Vishwanath and Savrasov, Phys. Rev. B 83, 205101 (2011)) – the Hermitian counterpart of
tbkit.exceptional.find_exceptional_points().
- tbkit.topology.bott_index(ham, positions: ArrayLike, cell: ArrayLike, e_fermi: float = 0.0) float[source]#
Get the Bott index of the states below e_fermi of a finite sample with periodic boundary conditions (a torus spanned by \(\mathbf{L}_1, \mathbf{L}_2\); Loring and Hastings, EPL 92, 67004 (2010)):
\[B = \frac{1}{2\pi}\,\mathrm{Im}\,\mathrm{Tr}\log\left( \tilde V\tilde U\tilde V^\dagger\tilde U^\dagger\right)\, ,\qquad \tilde U = P e^{2\pi i X_1} P\, ,\quad \tilde V = P e^{2\pi i X_2} P\, ,\]with \(P\) the projector on the occupied states and \(X_{1,2}\) the fractional coordinates of the orbitals along \(\mathbf{L}_{1,2}\). The exponentials are well defined on the torus, where the position operator is not. \(B\) is an integer whenever the occupied states are localized or gapped, equals the Chern number of a clean sample (in the sign convention of KSpace.chern_number), and keeps working with disorder until the mobility gap closes. The torus comes from KSpace.finite_ham with
periodic=Trueand the positions from tbkit.higher_order.flake_positions.- Parameters:
ham (Square Hermitian matrix (dense or sparse), shape (N, N))
positions (Real array, shape (N, d)) – Position of the orbital of each row.
cell (Real array, shape (2, d)) – The two vectors \(\mathbf{L}_1, \mathbf{L}_2\) spanning the torus (e.g. \(N_1\mathbf{a}_1\) and \(N_2\mathbf{a}_2\)).
e_fermi (Real number, default 0) – Fermi energy.
- Returns:
bott (Real number, close to an integer)
Examples
Example usage:
n = 12 ham = ks.finite_ham((n, n), periodic=True) pos = flake_positions(ks, (n, n)) cell = [n * np.array(a) for a in ks.lat.prim_vec] bott = bott_index(ham, pos, cell)
- tbkit.topology.entanglement_spectrum(ham, region: list[int], e_fermi: float = 0.0) NDArray[float64][source]#
Get the entanglement spectrum of the states below e_fermi of a finite sample: the eigenvalues \(\xi_n \in [0, 1]\) of the correlation matrix \(C_{ij} = \langle c_i^\dagger c_j\rangle\) restricted to the orbitals \(i, j\) of region (Peschel, J. Phys. A 36, L205 (2003)). The entanglement Hamiltonian of the region is quadratic, with single-particle energies \(\epsilon_n = \ln[(1-\xi_n)/\xi_n]\), and the entanglement entropy is \(S = -\sum_n[\xi_n\ln\xi_n + (1-\xi_n)\ln(1-\xi_n)]\). Its low-lying part mirrors the edge spectrum at the cut (Li and Haldane, Phys. Rev. Lett. 101, 010504 (2008)): a topological phase leaves entanglement modes inside (0, 1), e.g. a mode at exactly 1/2 at each cut of a chiral-symmetric chain – without any physical edge, so it is a property of the ground state alone. See KSpace.entanglement_spectrum for the k-resolved version.
- Parameters:
ham (Square Hermitian matrix (dense or sparse), shape (N, N))
region (List of row indices (the region \(A\)))
e_fermi (Real number, default 0) – Fermi energy.
- Returns:
xi (Real ndarray, shape (len(region),), sorted ascending)
- class tbkit.topology.WeylPoints(k, chirality, energy, gap)[source]#
Bases:
objectWeyl points of a 3D model, see find_weyl_points.
- k#
Positions, in the k coordinates of KSpace.get_ham, folded to fractional coordinates in [-1/2, 1/2).
- Type:
Real ndarray, shape (n, 3)
- chirality#
Berry flux of the bands below the touching out of a small sphere around each point, over \(2\pi\): \(\pm1\) for a simple Weyl point.
- Type:
Integer ndarray, shape (n,)
- energy#
Energy of the touching.
- Type:
Real ndarray, shape (n,)
- gap#
Remaining gap at the refined point (zero up to the tolerance).
- Type:
Real ndarray, shape (n,)
- tbkit.topology.find_weyl_points(ks: KSpace, bands: int | list[int], nk: int = 20, radius: float | None = None, tol: float = 1e-10, max_iter: int = 50) WeylPoints[source]#
Locate the Weyl points of a 3D model: the points where the highest band of bands (band \(n\)) touches the next one, and their chirality.
The gap \(E_{n+1} - E_n\) is computed on an \(nk^3\) mesh of the Brillouin zone (shifted off the high-symmetry planes); its local minima (over the 26 neighbours, periodically) are the candidates.
Each candidate is refined by Newton’s method on the two-band Hamiltonian \(\mathbf{d}(\mathbf{k})\cdot\boldsymbol\sigma\) of bands \(n, n+1\), whose zeros are the touchings; candidates whose gap does not close (avoided crossings) are dropped, and points equal up to a reciprocal lattice vector merged.
The chirality of each point is the Berry flux of bands out of a small sphere around it, divided by \(2\pi\) – the monopole charge, \(\pm1\) for a linear Weyl point. With the sign convention of KSpace.berry_curvature, the Chern number of the planes \(k_l = \mathrm{const}\) (KSpace.chern_number) jumps by the chirality as the plane crosses the point along \(+\mathbf{b}_l\).
The chiralities add up to zero (total_chirality): Weyl points come in pairs of opposite chirality (Nielsen-Ninomiya). The mesh must resolve the gap minima: on too coarse a mesh, two candidates may refine to the same point and miss another one, which a nonzero total_chirality reveals (increase nk). Nodal lines (degeneracies along curves) are not isolated points and are outside the scope of this finder.
- Parameters:
ks (*KSpace instance with three primitive vectors (Hermitian)*)
bands – Band index, or list of band indices (e.g. the occupied bands): the touching is between
max(bands)andmax(bands) + 1.nk (Positive integer, default 20) – Mesh points along each reciprocal vector.
radius (Positive real) – Default value None: a fifth of the mesh step. Radius of the sphere for the chirality (in units of k); it must enclose no other Weyl point.
tol (Positive real, default 1e-10) – Newton’s method stops when a step is shorter than tol; a point is kept if its gap is below \(10^4\) tol times the bandwidth.
max_iter (Positive integer, default 50) – Newton iterations.
- Returns:
weyl (*WeylPoints instance (k, chirality, energy, gap)*)
tbkit.wannier module#
Wannier functions of a group of bands of a tbkit.kspace.KSpace
model, built in two steps (three for entangled bands):
Disentanglement (when there are more bands than Wannier functions): at each k, the \(n_W\)-dimensional subspace of the states in an outer energy window that is smoothest across the mesh, i.e. that minimizes \(\Omega_I\), keeping the states of an optional frozen window exactly (Souza, Marzari and Vanderbilt, Phys. Rev. B 65, 035109 (2001)).
Projection onto trial orbitals \(|g_n\rangle\) localized in the home cell: \(A_{mn}(\mathbf{k}) = \langle u_{m\mathbf{k}}|g_n\rangle\), made unitary by Lowdin orthogonalization, \(U(\mathbf{k}) = A(A^\dagger A)^{-1/2}\) (Marzari, Mostofi, Yates, Souza and Vanderbilt, Rev. Mod. Phys. 84, 1419 (2012), Sec. III.A).
Maximal localization: conjugate-gradient descent of the spread \(\Omega = \sum_n \langle r^2\rangle_n - |\bar{\mathbf{r}}_n|^2\) over the gauge \(U(\mathbf{k})\), from the overlaps \(M^{(\mathbf{k},\mathbf{b})}_{mn} = \langle u_{m\mathbf{k}}|u_{n\mathbf{k}+\mathbf{b}}\rangle\) between neighbouring points of the k-mesh (Marzari and Vanderbilt, Phys. Rev. B 56, 12847 (1997)).
The Wannier functions are the Fourier transforms of the rotated Bloch states, on the \(N_1\times N_2\times\dots\) cells of the k-mesh (the supercell on which they are periodic). Their Hamiltonian \(H_{mn}(\mathbf{R}) = \langle W_{m\mathbf{0}}|H|W_{n\mathbf{R}}\rangle\) is a tight-binding model of its own (WannierFunctions.kspace), which interpolates the bands between the mesh points (Wannier interpolation).
A band group with a nonzero Chern number has no exponentially localized Wannier functions (Thouless, J. Phys. C 17, L325 (1984); Brouder et al., Phys. Rev. Lett. 98, 046402 (2007)): any projection vanishes somewhere in the Brillouin zone, and the spread grows with the mesh instead of converging.
- class tbkit.wannier.WannierFunctions(ks, n_cells, functions, positions, centers, spreads, omega_i, omega_d, omega_od, gauge, history, converged, min_singular_value, dis_history=None, dis_converged=True, ham_k=None, shift=None)[source]#
Bases:
objectWannier functions of a group of bands, see wannierize.
- functions#
Amplitudes of each Wannier function on the orbitals of the \(N = N_1N_2\dots\) cells of the k-mesh, indexed as the rows of KSpace.finite_ham(nk) (and the sites of system). Each one is a lattice translate chosen to sit in the middle of the sample.
- Type:
Complex ndarray, shape (n_wann, N*norb)
- positions#
Position of each row.
- Type:
Real ndarray, shape (N*norb, space_dim)
- centers#
Centres \(\bar{\mathbf{r}}_n\) of functions (Cartesian).
- Type:
Real ndarray, shape (n_wann, space_dim)
- spreads#
Spreads \(\langle r^2\rangle_n - |\bar{\mathbf{r}}_n|^2\) (squared length), along the primitive vectors only for a chain or a 2D lattice in 3D.
- Type:
Real ndarray, shape (n_wann,)
- omega_i#
Gauge-invariant part \(\Omega_I\) of the total spread.
- Type:
Real number
- omega_d#
Diagonal part \(\tilde\Omega_D\).
- Type:
Real number
- omega_od#
Off-diagonal part \(\tilde\Omega_{OD}\).
- Type:
Real number
- gauge#
\(U(\mathbf{k})\) over the k-mesh (flattened as KSpace.mesh_grid), acting on the eigenvectors of bands: unitary for an isolated group, otherwise the disentangled subspace (orthonormal columns, zero on the states outside the window) times the unitary gauge.
- Type:
Complex ndarray, shape (N, len(bands), n_wann)
- history#
Total spread after the projection and after each step.
- Type:
Real ndarray
- converged#
Whether the spread changed by less than tol.
- Type:
Boolean
- min_singular_value#
Smallest singular value of the projection \(A(\mathbf{k})\) over the mesh: close to zero when the trial orbitals miss the bands somewhere (as they must for a Chern band).
- Type:
Real number
- dis_history#
\(\Omega_I\) after the projection and after each disentanglement step (empty for an isolated group).
- Type:
Real ndarray
- dis_converged#
Whether \(\Omega_I\) changed by less than dis_tol (True for an isolated group).
- Type:
Boolean
- ham_k#
Hamiltonian \(U^\dagger(\mathbf{k})\,\mathrm{diag}(E)\,U(\mathbf{k})\) in the gauge of the Wannier functions, over the k-mesh.
- Type:
Complex ndarray, shape (N, n_wann, n_wann)
- property omega: float#
Total spread \(\Omega = \Omega_I + \tilde\Omega_D + \tilde\Omega_{OD}\), the sum of spreads.
- property system#
The finite System (open boundaries) whose sites carry functions: bridges.finite_system(ks, nk), built on first access. Spinless models only (for a spinful one, use positions).
- kspace(cutoff: float = 1e-10) KSpace[source]#
The tight-binding model of the Wannier functions (Wannier interpolation): one orbital per function, at its centre (folded into the home cell), and the matrix elements
\[H_{mn}(\mathbf{R}) = \langle W_{m\mathbf{0}}|H|W_{n\mathbf{R}}\rangle = \frac{1}{N}\sum_{\mathbf{k}} e^{-i\mathbf{k}\cdot\mathbf{R}}\, [U^\dagger(\mathbf{k})\,\mathrm{diag}(E)\,U(\mathbf{k})]_{mn}\]as onsite energies and hoppings. Each \(\mathbf{R}\) is the image on the \(N_1\times N_2\times\dots\) supercell closest to the bond, \(|\mathbf{R} + \boldsymbol\tau_n - \boldsymbol\tau_m|\) minimal (equidistant images share the element, as Wannier90’s
use_ws_distance). Its bands equal the Wannierized ones on the k-mesh: all of them for an isolated group, those in the frozen window after disentanglement. Between the mesh points they converge exponentially with the mesh, as the functions decay. The model is the one io.read_wannier90 would read from Wannier90’sseedname_hr.dat.- Parameters:
cutoff (Positive real number or zero, default 1e-10) – Drop the hoppings with \(|t| \le\) cutoff.
- Returns:
ks (*KSpace instance, Hermitian, with n_wann orbitals*)
Examples
Example usage:
wf = wannierize(ks, list(range(ks.norb)), trial=[0, 1], frozen=(-3., 0.)) wk = wf.kspace() dist, en = wk.k_path(high_symmetry_path(ks.lat)[0], 50)
- tbkit.wannier.wannierize(ks: KSpace, bands: int | list[int], trial: list[int] | ArrayLike, nk: int | tuple[int, ...] = 12, max_iter: int = 500, tol: float = 1e-10, step: float = 0.5, window: tuple[float, float] | None = None, frozen: tuple[float, float] | None = None, dis_iter: int = 2000, dis_tol: float = 1e-10, mixing: float = 0.5) WannierFunctions[source]#
Build the maximally localized Wannier functions of a group of bands: project the Bloch states onto trial orbitals (Lowdin orthogonalized), then minimize the spread
\[\Omega = \sum_n \left[\langle r^2\rangle_n - |\bar{\mathbf{r}}_n|^2\right] = \Omega_I + \tilde\Omega_D + \tilde\Omega_{OD}\]by conjugate gradients over the gauge \(U(\mathbf{k})\) (Marzari and Vanderbilt, Phys. Rev. B 56, 12847 (1997); as in Wannier90, with a parabolic line search). The finite-difference formulas use the overlaps of the Bloch states at neighbouring mesh points, with the orbital positions included (as in the Wilson loops of KSpace.wannier_centers, so the centres agree with them). Only \(\tilde\Omega_D + \tilde\Omega_{OD}\) depends on the gauge; \(\Omega_I\) is fixed by the band group.
In 1D, the minimum has \(\tilde\Omega_D = \tilde\Omega_{OD} = 0\) for one band, and the centre is the Berry phase over \(2\pi\). For a Chern band, every projection fails somewhere (min_singular_value tends to zero), and the spread diverges as the mesh is refined. The descent finds the local minimum nearest the projected gauge: trial orbitals that miss the bands at isolated k-points (a small min_singular_value) leave phase vortices that it does not remove, even in a trivial band, so choose orbitals the bands actually live on.
Entangled bands. With fewer trial orbitals \(n_W\) than bands (or with a window), the bands need not be isolated: the Wannier functions span, at each k, the \(n_W\)-dimensional subspace of the states of bands inside the outer window that minimizes \(\Omega_I\) (Souza, Marzari and Vanderbilt, Phys. Rev. B 65, 035109 (2001)), found by iterating from the projection of the trial orbitals, with linear mixing. The states inside the frozen window are kept exactly, so the Wannier bands (WannierFunctions.kspace) reproduce them. The maximal localization then runs within that subspace. Pass every band (
list(range(ks.norb))) and select the states with the windows.- Parameters:
ks (*KSpace instance, Hermitian*)
bands (Band index, or list of band indices) – With one trial orbital per band and no window, the group, which must be separated in energy from the other bands over the whole mesh; otherwise the candidate bands of the disentanglement.
trial – Trial orbitals, one per Wannier function (at most one per band): a list of orbital indices (each a single orbital of the home cell), or a complex array of shape (norb, n_wann) whose columns are combinations of the orbitals of the home cell (e.g. a bond orbital).
nk (Positive integer, or tuple of *dim integers*) – Default value 12. k-mesh, at least 3 along each direction; the Wannier functions live on the same number of cells.
max_iter (Positive integer or zero, default 500) – Maximal number of descent steps (0 keeps the projected gauge).
tol (Positive real number, default 1e-10) – Convergence threshold on the change of \(\Omega\) between steps.
step (Positive real number, default 0.5) – Trial step \(\alpha\) of the line search, \(dW = \alpha D/4\sum_b w_b\) along the search direction \(D\); it is halved whenever the spread would grow.
window (Tuple of two real numbers) – Default value None (every state of bands). Outer energy window \((E_{min}, E_{max})\): the states of bands inside it are the candidates, at least n_wann at every k-point.
frozen (Tuple of two real numbers) – Default value None (no frozen states). Inner energy window, inside window: its states, at most n_wann at every k-point, are kept in the subspace.
dis_iter (Positive integer or zero, default 2000) – Maximal number of disentanglement steps (0 keeps the projected subspace).
dis_tol (Positive real number, default 1e-10) – Convergence threshold on the change of \(\Omega_I\) between steps.
mixing (Real in (0, 1], default 0.5) – Fraction of the new \(Z(\mathbf{k})\) mixed in at each disentanglement step.
- Returns:
wf (*WannierFunctions instance*)
Examples
Example usage:
wf = wannierize(ssh, 0, trial=[0], nk=20) wf.centers, wf.spreads, wf.functions # two Wannier functions out of four bands, the lowest two kept exactly wf = wannierize(ks, [0, 1, 2, 3], trial=[0, 1], window=(-4., 3.), frozen=(-4., 0.)) wf.kspace() # the Wannier-interpolated model
tbkit.higher_order module#
Higher-order topology: nested Wilson loops, Wannier-sector polarizations, the quadrupole moment and corner charges (Benalcazar, Bernevig and Hughes, Science 357, 61 (2017); Phys. Rev. B 96, 245115 (2017)).
A two-dimensional insulator can have no dipole moment (no Chern number, no bulk polarization) and still be topological: its hybrid Wannier functions split into two gapped Wannier sectors, each carrying a quantized polarization of its own, and the bulk quadrupole moment
(1/2 or 0 with reflection symmetries) shows up as a fractional charge \(\pm e/2\) bound to each corner of a finite flake, with zero-energy corner states at the corners in the chiral-symmetric limit.
The recipe of the nested Wilson loop, for occupied bands \(|u^n_{\mathbf{k}}\rangle\):
The Wilson loop along \(x\) from every base point \(\mathbf{k}\), \(W_{x,\mathbf{k}}|\nu^j_{x,\mathbf{k}}\rangle = e^{-2\pi i\nu_x^j(k_y)}|\nu^j_{x,\mathbf{k}}\rangle\); its phases \(\nu_x^j(k_y)\) are the Wannier bands (see
tbkit.kspace.KSpace.wannier_flow()).The Wannier-sector states \(|w^j_{x,\mathbf{k}}\rangle = \sum_n|u^n_{\mathbf{k}}\rangle[\nu^j_{x,\mathbf{k}}]^n\) of the sector \(\nu_x^-\) (the Wannier bands below the Wannier gap).
The Wilson loop of those states along \(y\) (the nested Wilson loop), whose phase, averaged over \(k_x\), is the Wannier-sector polarization \(p_y^{\nu_x^-}\).
The Bloch matrices of the whole mesh come at once from
KSpace._bloch_ham; the links carry the orbital
positions (positions=True), as in KSpace.berry_phase.
- tbkit.higher_order.bbh_model(gamma: float = 0.5, lam: float = 1.0, delta: float = 0.0) KSpace[source]#
Get the Benalcazar-Bernevig-Hughes (BBH) quadrupole insulator: four orbitals per square cell, intra-cell hoppings \(\gamma\), inter-cell hoppings \(\lambda\), and a \(\pi\) flux through every plaquette,
\[H(\mathbf{k}) = [\gamma+\lambda\cos k_x]\Gamma_4 + \lambda\sin k_x\,\Gamma_3 + [\gamma+\lambda\cos k_y]\Gamma_2 + \lambda\sin k_y\,\Gamma_1 + \delta\,\Gamma_0\, ,\]with \(\Gamma_0 = \tau_3\sigma_0\), \(\Gamma_k = -\tau_2\sigma_k\) (\(k = 1, 2, 3\)), \(\Gamma_4 = \tau_1\sigma_0\) (orbital \(2\tau + \sigma\)). The hoppings are read off \(H(\mathbf{k})\), and the four orbitals sit at the corners of a square of side 1/2 centred on the cell origin, each next to the orbitals it is bonded to by \(\gamma\). For \(|\gamma| < |\lambda|\) (and \(\delta = 0\)) the model is a quadrupole insulator, \(q_{xy} = 1/2\); for \(|\gamma| > |\lambda|\) it is trivial. \(\delta\) breaks the chiral symmetry and splits the corner states to \(\pm\delta\).
- Parameters:
gamma (Real number, default 0.5) – Intra-cell hopping.
lam (Real number, default 1) – Inter-cell hopping.
delta (Real number, default 0) – Onsite \(\pm\delta\).
- Returns:
bbh (*KSpace instance, 4 orbitals, lattice constant 1*)
- tbkit.higher_order.wannier_bands(ks: KSpace, bands: int | list[int], nk: int | tuple[int, int] = 40, direction: int = 0, positions: bool = True) tuple[NDArray[float64], NDArray[complex128]][source]#
Get the Wannier bands \(\nu_{d}^j(\mathbf{k})\) of a group of bands of a 2D model, and the Wannier-sector states, from the Wilson loop \(W_{d,\mathbf{k}}\) along \(\mathbf{b}_d\) starting from every point \(\mathbf{k}\) of the mesh. The Wannier bands do not depend on the base point along \(d\) (only the eigenvectors do); they are the hybrid Wannier centres of KSpace.wannier_centers, in units of \(\mathbf{a}_d\), here in \((-1/2, 1/2]\) and sorted.
- Parameters:
ks (*KSpace instance, 2D, Hermitian, without overlap*)
bands (Band index or list of band indices (e.g. the occupied bands))
nk (Positive integer, or tuple of two, default 40) – Mesh along \(\mathbf{b}_1, \mathbf{b}_2\).
direction (0 or 1, default 0) – Direction \(d\) of the Wilson loop.
positions (Boolean, default True) – Include the orbital positions in the links (see KSpace.berry_phase).
- Returns:
nu (Real ndarray, shape (n1, n2, len(bands))) – Wannier bands at every base point, sorted, in \((-1/2, 1/2]\).
w (Complex ndarray, shape (n1, n2, norb, len(bands))) – The Wannier-sector states \(|w^j_{d,\mathbf{k}}\rangle\), column j for
nu[..., j].
- tbkit.higher_order.wannier_sector_polarization(ks: KSpace, bands: int | list[int], sector: int | list[int] | None = None, nk: int | tuple[int, int] = 40, direction: int = 0, positions: bool = True) float[source]#
Get the polarization of a Wannier sector, \(p_{d'}^{\nu_d}\), by the nested Wilson loop of Benalcazar, Bernevig and Hughes (see the module docstring): the Wannier-sector states of sector (from wannier_bands along direction \(d\)) are carried around the Brillouin zone along the other direction \(d'\),
\[p_{d'}^{\nu_d} = -\frac{1}{N_d}\sum_{k_d}\frac{1}{2\pi}\arg\det \prod_{k_{d'}}\langle w_{d,\mathbf{k}}|e^{-i\delta\mathbf{k}\cdot\boldsymbol\tau}|w_{d,\mathbf{k}+\delta\mathbf{k}_{d'}}\rangle \pmod 1\, ,\]in units of \(\mathbf{a}_{d'}\). The sector must be separated from the other Wannier bands by a Wannier gap at every \(\mathbf{k}\) (a ValueError is raised otherwise). For the BBH model it is 1/2 in the quadrupole phase and 0 in the trivial one.
- Parameters:
ks (*KSpace instance, 2D, Hermitian, without overlap*)
bands (Band index or list of band indices (the occupied bands))
sector (Integer or list of integers) – Default value None (the lower half, \(\nu_d^-\)). Indices of the Wannier bands (sorted in \((-1/2, 1/2]\), see wannier_bands) forming the sector.
nk (Positive integer, or tuple of two, default 40) – Mesh.
direction (0 or 1, default 0) – Direction \(d\) of the first Wilson loop; the polarization is along the other one.
positions (Boolean, default True) – See wannier_bands.
- Returns:
p (Real number in \([0, 1)\))
- tbkit.higher_order.quadrupole_moment(ks: KSpace, bands: int | list[int], nk: int | tuple[int, int] = 40, positions: bool = True) float[source]#
Get the bulk quadrupole moment of a 2D insulator with reflection symmetries, from its Wannier-sector polarizations (Benalcazar, Bernevig and Hughes 2017):
\[q_{xy} = 2\,p_y^{\nu_x^-}\,p_x^{\nu_y^-} \pmod 1\, ,\]in units of \(e\) per unit cell area. With the reflections \(M_x, M_y\) (and \(C_4\), or the chiral symmetry, of the BBH model) both polarizations are quantized to 0 or 1/2, and so is \(q_{xy}\). The occupied bands must have a Wannier gap in both directions (a ValueError is raised otherwise, see wannier_sector_polarization).
- Parameters:
ks (*KSpace instance, 2D, Hermitian, without overlap*)
bands (List of band indices (the occupied bands, at least two))
nk (Positive integer, or tuple of two, default 40) – Mesh.
positions (Boolean, default True) – See wannier_bands.
- Returns:
q_xy (Real number in \([0, 1)\))
- tbkit.higher_order.flake_positions(ks: KSpace, n_cells: int | tuple[int, ...]) NDArray[float64][source]#
Get the positions of the orbitals of the finite sample of KSpace.finite_ham, in its order: orbital o of cell \((n_1, n_2, \dots)\) at \(\sum_i n_i\mathbf{a}_i + \boldsymbol\tau_o\).
- Parameters:
ks (*KSpace instance*)
n_cells (Positive integer, or tuple of *dim positive integers*)
- Returns:
positions (Real ndarray, shape (N*norb, space_dim))
- class tbkit.higher_order.CornerCharges(energies, density, positions, background, e_fermi, charges)[source]#
Bases:
objectCharges of the four corners of a finite 2D flake, see corner_charges.
- energies#
Spectrum of the flake.
- Type:
Real ndarray
- density#
Electron density \(\rho_i\) on every orbital.
- Type:
Real ndarray
- positions#
Orbital positions.
- Type:
Real ndarray, shape (N*norb, 2)
- background#
Uniform background \(\bar\rho\) (electrons per orbital) that neutralizes the flake.
- Type:
Real number
- e_fermi#
Fermi level.
- Type:
Real number
- charges#
Excess electron number \(\sum_{i\in Q}(\rho_i - \bar\rho)\) in each quadrant Q:
charges[a, b]for the half \(a\) (0: low, 1: high) along \(\mathbf{a}_1\) and \(b\) along \(\mathbf{a}_2\).- Type:
Real ndarray, shape (2, 2)
- tbkit.higher_order.corner_charges(ks: KSpace, n_cells: int | tuple[int, int], n_electrons: float | None = None, temperature: float = 0.0) CornerCharges[source]#
Get the corner charges of a finite flake of \(N_1\times N_2\) cells of a 2D model (KSpace.finite_ham, open boundaries): the electron density \(\rho_i = \sum_n f_n|\psi_n(i)|^2\) of the lowest states, minus a uniform neutralizing background \(\bar\rho = N_e/(N\,\mathrm{norb})\), summed over each quadrant of the flake (the halves being split at the middle of the sample along \(\mathbf{a}_1\) and \(\mathbf{a}_2\)). A quadrant charge is the corner charge of Benalcazar, Bernevig and Hughes, \(Q^{\mathrm{corner}} = p^{\mathrm{edge}}_x + p^{\mathrm{edge}}_y - q_{xy}\): \(\pm 1/2\) for the BBH quadrupole insulator (with \(\delta \ne 0\) to fill two of its four corner states), 0 for a trivial insulator. The sign is that of the electron number (charge in units of \(-e\)).
At \(T = 0\), the electrons left for a degenerate level at the Fermi energy are shared equally among its states (e.g. the four exact zero modes of the BBH model at \(\delta = 0\), which then gives zero corner charges): split the degeneracy, or use a temperature.
- Parameters:
ks (*KSpace instance, 2D, Hermitian, without overlap*)
n_cells (Positive integer, or tuple of two) – Cells along \(\mathbf{a}_1, \mathbf{a}_2\).
n_electrons (Positive real) – Default value None (half filling). Number of electrons in the flake. An integer at T = 0.
temperature (Positive real or zero, default 0)
- Returns:
result (
CornerCharges)
tbkit.bridges module#
Bridges between the two pipelines of tbkit: the real-space System (a finite lattice, its sparse Hamiltonian) and the reciprocal-space KSpace (the Bloch Hamiltonian \(H(\mathbf{k})\) of the infinite lattice).
kspace_from_system reads the Bloch model off a translation-invariant System built the real-space way (get_lattice, set_hopping by neighbour order, set_onsite, …).
finite_model and finite_system cut a finite sample (open boundaries, or a torus) out of a KSpace model: its sparse Hamiltonian with the site positions, or a ready-to-use System.
Both use the convention of KSpace.finite_ham: the hopping \(t_{ij}(\mathbf{R}) = \langle i,\mathbf{0}|H|j,\mathbf{R}\rangle\) joins orbital i of every cell to orbital j of the cell \(\mathbf{R}\) further. So, for the same model, the spectrum of a System on an \(N_1\times N_2\) torus is the set of KSpace bands on the \(N_1\times N_2\) Brillouin-zone mesh.
- tbkit.bridges.cell_orbitals(lat: Lattice) tuple[NDArray[int64], NDArray[int64]][source]#
Get, for every site of a finite lattice (lat.coor), the unit-cell orbital it is a copy of and its cell: site s sits at \(\boldsymbol\tau_{o_s} + \sum_k n_{s,k}\mathbf{a}_k\), with the tag of orbital \(o_s\) (within
ATOL).- Parameters:
lat – Lattice instance, after get_lattice (sites may have been removed, but not moved).
- Returns:
cells (Integer ndarray, shape (sites, dim)) – \(n_{s,k}\).
orbitals (Integer ndarray, shape (sites,)) – \(o_s\).
- tbkit.bridges.kspace_from_system(sys: System, periodic: bool | None = None, tol: float = 1e-09) KSpace[source]#
Get the Bloch Hamiltonian of a periodic model defined the real-space way: every matrix element \(H_{ab}\) of the finite System (built by get_ham) joins orbital \(o_a\) of cell \(\mathbf{n}_a\) to orbital \(o_b\) of cell \(\mathbf{n}_b\) (see cell_orbitals), i.e. is the hopping \(t_{o_ao_b}(\mathbf{n}_b-\mathbf{n}_a)\) of the infinite lattice. Each such hopping must take the same value in every cell where it appears (bonds cut by the boundary are simply missing). The lattice must be large enough to hold every bond of the model.
A System on a torus (periodic, e.g. from finite_system) has bonds that wrap around: their lattice vectors are then taken modulo the \(N_1\times N_2\times\dots\) cells of get_lattice, as the shortest image (so the model’s range must stay below half the torus).
A Hermitian hopping matrix gives a Hermitian model (one representative per bond, set_hopping adding the conjugate); otherwise every matrix element is kept, with
hermitian=False. Onsite energies are taken orbital by orbital.- Parameters:
sys (*System instance with its hoppings set (one orbital per site)*)
periodic (Boolean) – Default value None: True if sys has periodic boundaries along some primitive vector (
System(lat, periodic=...), or finite_system withperiodic=True). The System is a torus of the lat.n1 x lat.n2 (x lat.n3) cells of get_lattice.tol (Positive real number, default 1e-9) – Largest allowed difference between equivalent matrix elements.
- Returns:
ks – KSpace instance (spinless), on a new Lattice with the unit_cell and prim_vec of sys.lat.
Examples
Example usage:
lat = lattices.honeycomb() lat.get_lattice(6, 6) sys = System(lat) sys.set_hopping([{'n': 1, 't': -1.}, {'n': 2, 't': 0.1}]) gra = kspace_from_system(sys) # the Bloch model of the same graphene
- tbkit.bridges.finite_model(ks: KSpace, n_cells: int | tuple[int, ...], periodic: bool = False) tuple[csr_matrix, NDArray[float64], NDArray][source]#
Get a finite sample of a KSpace model: its sparse Hamiltonian (that of KSpace.finite_ham, open or periodic boundaries), with the position and tag of every row. Spinful models are supported (the two spin components of a site share its position).
- Parameters:
ks (*KSpace instance*)
n_cells (Positive integer, or tuple of *dim positive integers*) – Number of unit cells along each primitive vector.
periodic (Boolean, default False) – Periodic boundaries (a torus).
- Returns:
ham (Complex CSR matrix, shape (N*norb, N*norb))
positions (Real ndarray, shape (N*norb, space_dim)) – Row \(c\,\mathrm{norb}+o\) sits at \(\boldsymbol\tau_o + \sum_k n_k\mathbf{a}_k\) (cell c has \(c = n_1 + N_1 n_2 + N_1N_2 n_3\)).
tags (String ndarray, shape (N*norb,)) – Sublattice tags.
- tbkit.bridges.finite_system(ks: KSpace, n_cells: int | tuple[int, ...], periodic: bool = False) System[source]#
Build a finite System out of a (spinless) KSpace model: lat.coor holds the sites of \(N_1\times N_2\times\dots\) unit cells (in the order of finite_model), and sys.hop / sys.onsite the model’s hoppings and onsite energies, so that sys.get_ham() gives ks.finite_ham(n_cells, periodic). Every real-space tool (get_eig, get_ldos, Plot, disorder, …) then applies.
In sys.hop, each bond is stored with the conventions of System.set_hopping: a Hermitian model keeps one orientation per bond (angle in [0, 180), get_ham adds the conjugate); a non-reciprocal one keeps both, the missing direction with a zero amplitude. ‘n’ is the neighbour order of the bond (0 for coinciding orbitals), ‘tag’ the sublattice pair. On a torus, a bond that wraps around keeps its short bond vector for its angle, and a hopping that wraps onto its own site is added to the onsite energy; the System has periodic boundaries (
sys.periodic), so that further set_hopping calls, Plot and get_bott_index treat it as a torus.- Parameters:
ks (KSpace instance, with
spin=False)n_cells (Positive integer, or tuple of *dim positive integers*)
periodic (Boolean, default False) – Periodic boundaries (a torus).
- Returns:
sys (*System instance, with its hoppings set*)
Examples
Example usage:
sys = finite_system(gra, (30, 30), periodic=True) sys.get_ham() sys.get_eig() # = gra.mesh_bands((30, 30)), sorted
tbkit.continuum module#
Continuum discretization: turn a k·p (continuum) Hamiltonian, a polynomial in the momenta \(k_x, k_y, k_z\) with constant (possibly symbolic) matrix coefficients, into a Tight-Binding model on a square or cubic grid of spacing a.
Each momentum is the derivative \(k_x = -i\partial_x\), and a power
\(k_x^n\) is replaced by the half-step finite difference
\(D_hf(x) = [f(x+h/2) - f(x-h/2)]/h\) applied n times, with
\(h = a\) for an even n and \(h = 2a\) for an odd one, so that
every shift is a whole number of sites (the scheme of Kwant’s
kwant.continuum). In k-space this replaces
which agrees with \(k^n\) up to \(O(a^2)\) and keeps a Hermitian Hamiltonian Hermitian: \(k_x\to-i(\psi_{n+1}-\psi_{n-1})/2a\), \(k_x^2\to-(\psi_{n+1}-2\psi_n+\psi_{n-1})/a^2\). Products of momenta along different axes multiply their stencils. The coefficients do not depend on the position, so the order of the factors does not matter.
discretize_symbolic returns the hopping matrices \(T(\mathbf{R})\) as sympy matrices in the grid spacing a, to inspect.
discretize builds the KSpace model with \(H(\mathbf{k}) = \sum_\mathbf{R} T(\mathbf{R})e^{i\mathbf{k}\cdot\mathbf{R}}\). Its free symbols (M, B, …) become parameters of value functions, set by
get_ham(k, M=...)or KSpace.set_params. bridges.finite_system then gives the matching real-space System.
sympy is an optional dependency: pip install tbkit[continuum].
- tbkit.continuum.MOMENTA = ('k_x', 'k_y', 'k_z')#
Names of the momenta, along x, y and z.
- tbkit.continuum.discretize_symbolic(hamiltonian, dim: int | None = None) dict[source]#
Discretize a continuum Hamiltonian on a square or cubic grid, keeping everything symbolic: the hopping matrices \(T(\mathbf{R}) = \langle\mathbf{0}|H|\mathbf{R}\rangle\) between a grid site and the one \(\mathbf{R}\) sites further, in terms of the grid spacing a and the parameters of the Hamiltonian (see the module docstring for the scheme).
- Parameters:
hamiltonian – sympy expression or Matrix, or a string, in the momenta
k_x,k_y,k_z: a polynomial in them with constant coefficients. Any other symbol is a parameter, taken real (the symbolsx,y,zandaare not allowed). A string may use the Pauli matricessigma_0,sigma_x,sigma_y,sigma_zandkron(Kronecker product);Iis the imaginary unit.dim (1, 2 or 3) – Default value None: the last axis whose momentum appears (1 if none).
- Returns:
hoppings (Dictionary) – key: tuple of dim integers \(\mathbf{R}\), val: sympy Matrix \(T(\mathbf{R})\), in the symbol
aand those of hamiltonian.
Examples
Example usage:
discretize_symbolic('k_x**2') # {(-1,): Matrix([[-1/a**2]]), (0,): Matrix([[2/a**2]]), (1,): Matrix([[-1/a**2]])}
- tbkit.continuum.discretize(hamiltonian, a: float = 1.0, dim: int | None = None, tags: str | list[str] | None = None) KSpace[source]#
Discretize a continuum (k·p) Hamiltonian into a Tight-Binding KSpace model on a square (2D) or cubic (3D) grid, or a chain (1D), of spacing a. The grid has one site per unit cell carrying the norb orbitals of the Hamiltonian’s matrix, all at the origin of the cell, so that \(H(\mathbf{k}) = \sum_\mathbf{R} T(\mathbf{R})e^{i\mathbf{k}\cdot\mathbf{R}}\) with the hoppings of discretize_symbolic. It agrees with the continuum Hamiltonian up to \(O(a^2)\) near \(\mathbf{k}=\mathbf{0}\).
A matrix element with no free symbol becomes a number. One with parameters becomes a value function (see KSpace.set_hopping): pass the parameters to
get_ham(k, M=...), or to KSpace.set_params for the other methods. A Hamiltonian that is Hermitian for real parameters is stored withhermitian=True(one representative per bond); otherwise every matrix element is stored, withhermitian=False. Constant onsite terms are in ks.onsite.- Parameters:
hamiltonian (sympy expression or Matrix, or a string (see *discretize_symbolic)*)
a – Real number, at least \(\sqrt{0.1}\approx 0.316\) (the shortest primitive vector of a Lattice). Default value 1. Grid spacing: to refine the grid, measure lengths in a smaller unit.
dim (1, 2 or 3) – Default value None: the last axis whose momentum appears (1 if none).
tags (String or list of one-character strings) – Default value None: ‘a’, ‘b’, ‘c’, … Tag of each orbital.
- Returns:
ks (*KSpace instance (spinless, norb orbitals)*) – Its lattice has prim_vec \(a\hat{\mathbf{x}}, a\hat{\mathbf{y}}, (a\hat{\mathbf{z}})\).
Examples
Example usage:
# the BHZ model of HgTe quantum wells, one spin block bhz = discretize('A*(k_x*sigma_x - k_y*sigma_y)' '+ (M - B*(k_x**2 + k_y**2))*sigma_z', a=0.5) bhz.set_params(A=1., B=1., M=1.) bhz.chern_number([0]) sys = finite_system(bhz, (40, 40)) # a real-space flake
tbkit.io module#
Save and load models, and import models from other codes.
save_model / load_model store a Lattice, System or KSpace
in a versioned NumPy .npz archive (no pickle, readable with NumPy
alone): the lattice (unit_cell, prim_vec, and the sites of
get_lattice if any), and for a System its onsite energies and hopping
array sys.hop, for a KSpace its onsite terms (with the spin-off-diagonal
block), hoppings, overlaps and spin. Every number is stored in binary,
so a loaded model reproduces the Hamiltonians exactly.
Archive layout (format 'tbkit-model', version VERSION):
format,version,kind('Lattice','System'or'KSpace'),tbkit_version;uc_tag(n_sites,),uc_r0(n_sites, space_dim),prim_vec(dim, space_dim),coor(the structured site array),n_cells(3,);System:
onsite(sites,),hop(the structured sys.hop), and, from version 2,periodic(one boolean per primitive vector) for a System with periodic boundaries (every other model is still written as version 1, which older tbkit versions read);KSpace:
spin,onsite(norb,),onsite_offdiag(norb, norb),nonreciprocal, andhop_i,hop_j,hop_R(Cartesian lattice vectors),hop_tfor the hoppings,ovl_i,ovl_j,ovl_R,ovl_tfor the overlaps.
read_wannier90 imports a tight-binding model from Wannier90’s
seedname_hr.dat (see there).
- tbkit.io.FORMAT = 'tbkit-model'#
Name of the archive format written by save_model.
- tbkit.io.VERSION = 2#
Version of the archive format written by save_model; load_model reads this version and every earlier one.
- tbkit.io.save_model(model: Lattice | System | KSpace, path: str | PathLike) str[source]#
Save a Lattice, System or KSpace to a
.npzarchive (see the module docstring for its layout). Subclasses are saved as their base class (e.g. a GrapheneSystem as a System); an OrbitalSystem or a driven (Floquet) model cannot be saved.- Parameters:
model (*Lattice, System or KSpace instance*)
path (String or path) – File name;
.npzis appended if missing.
- Returns:
path (String) – The file written.
Examples
Example usage:
save_model(gra, 'graphene.npz') gra2 = load_model('graphene.npz')
- tbkit.io.load_model(path: str | PathLike) Lattice | System | KSpace[source]#
Load a model saved by save_model.
- Parameters:
path (String or path) – File name.
- Returns:
model – Lattice, System or KSpace instance, whose Hamiltonians (get_ham) are exactly those of the saved model.
- tbkit.io.BOHR = 0.529177210903#
Bohr radius in Angstrom (CODATA 2018), for
unit_cell_cartgiven in bohr.
- tbkit.io.read_hr(path: str | PathLike) tuple[int, NDArray[int64], NDArray[int64], NDArray[complex128]][source]#
Read a Wannier90
seedname_hr.datfile: a header line, the number of Wannier functions, the number of lattice vectors \(\mathbf{R}\), their degeneracy weights (15 per line), then one lineR1 R2 R3 m n Re Imper matrix element \(H_{mn}(\mathbf{R}) = \langle m\mathbf{0}|H|n\mathbf{R}\rangle\) (m, n counted from 1).- Parameters:
path (String or path) – The
_hr.datfile.- Returns:
num_wann (Integer) – Number of Wannier functions.
R (Integer ndarray, shape (nrpts, 3)) – Lattice vectors (in units of the primitive vectors).
ndegen (Integer ndarray, shape (nrpts,)) – Degeneracy weights.
ham (Complex ndarray, shape (nrpts, num_wann, num_wann)) – \(H_{mn}(\mathbf{R})\) as written in the file (not divided by the weights).
- tbkit.io.read_win_cell(path: str | PathLike) NDArray[float64][source]#
Read the lattice vectors of a Wannier90
seedname.winfile (blockunit_cell_cart, in Angstrom, or in bohr if its first line saysbohr). Comments (!,#) are ignored.- Parameters:
path (String or path) – The
.winfile.- Returns:
cell (Real ndarray, shape (3, 3)) – The rows are \(\mathbf{a}_1, \mathbf{a}_2, \mathbf{a}_3\), in Angstrom.
- tbkit.io.read_centres(path: str | PathLike, num_wann: int) NDArray[float64][source]#
Read the Wannier centres of a Wannier90
seedname_centres.xyzfile (the first num_wann atoms labelledX, in Angstrom).- Parameters:
path (String or path) – The
_centres.xyzfile.num_wann (Positive integer) – Number of Wannier functions.
- Returns:
centres (Real ndarray, shape (num_wann, 3))
- tbkit.io.read_wannier90(hr: str | PathLike, prim_vec: list[tuple[float, ...]] | None = None, win: str | PathLike | None = None, centres: str | PathLike | None = None, positions: ArrayLike | None = None, tags: list[str] | None = None, dim: int = 3, cutoff: float = 0.0, tol: float = 1e-06) KSpace[source]#
Import a tight-binding model from Wannier90’s
seedname_hr.dat, the Hamiltonian in a basis of (maximally localized) Wannier functions:\[H_{mn}(\mathbf{k}) = \sum_{\mathbf{R}} \frac{H_{mn}(\mathbf{R})}{N_{\mathbf{R}}}\, e^{i\mathbf{k}\cdot\mathbf{R}}\, ,\]\(N_{\mathbf{R}}\) being the degeneracy weight of \(\mathbf{R}\) (lattice vectors on the boundary of the Wigner-Seitz supercell appear several times). The Wannier functions become the orbitals of a KSpace, in the file’s order: \(H_{mm}(\mathbf{0})\) the onsite energies, the other elements the hoppings \(t_{mn}(\mathbf{R})\) of KSpace.set_hopping. If the file is Hermitian (within tol), one element of each conjugate pair is kept and the model is Hermitian (with real onsite energies); otherwise every element is kept, with
hermitian=False.- Parameters:
hr (String or path) – The
seedname_hr.datfile.prim_vec (List of *dim tuples of dim real numbers*) – Default value None. Primitive vectors, in the units of the positions (Angstrom for Wannier90). If None, read from win.
win (String or path, default None) – The
seedname.winfile, for itsunit_cell_cartblock (if prim_vec is None).centres (String or path, default None) – The
seedname_centres.xyzfile: the Wannier centres become the orbital positions (used by the Wilson-loop tools, the Peierls phases, bridges.finite_system, …).positions (Array, shape (num_wann, dim) or (num_wann, 3), default None) – Orbital positions, instead of centres. With neither, every orbital sits at the origin of the cell.
tags (List of num_wann one-character strings) – Default value None (every orbital tagged
'a'). Sublattice tags.dim (2 or 3, default 3) – A 2D model (a layer) keeps only \((R_1, R_2)\): every element with \(R_3\neq 0\) must vanish (within tol), and the lattice lies in the \((x, y)\) plane (the z components of the vectors read from win must vanish; those of the positions are dropped).
cutoff (Positive real number or zero, default 0) – Drop the hoppings with \(|t| \le\) cutoff (the exact zeros by default).
tol (Positive real number, default 1e-6) – Tolerance of the Hermiticity and 2D checks (the file has 6 decimals).
- Returns:
ks (*KSpace instance, with num_wann orbitals*)
Examples
Example usage:
ks = read_wannier90('graphene_hr.dat', win='graphene.win', centres='graphene_centres.xyz', dim=2)
tbkit.moire module#
Supercells, band unfolding and moiré bilayers.
supercell()repeats a periodic model (tbkit.kspace.KSpace) in a larger cell spanned by integer combinations of its primitive vectors, \(\mathbf{A}_i = \sum_j M_{ij}\mathbf{a}_j\): the natural home of disorder, defects and superstructures that the primitive cell cannot hold.unfold()andspectral_function()project the supercell eigenstates back onto the primitive Brillouin zone (Ku, Berlijn and Lee, Phys. Rev. Lett. 104, 216401 (2010); Popescu and Zunger, Phys. Rev. B 85, 085201 (2012)): the weight of state \(|\mathbf{K}J\rangle\) at the primitive \(\mathbf{k}\) (folding onto \(\mathbf{K}\)) is\[W_J(\mathbf{k}) = \frac{1}{N}\sum_o\Big|\sum_{m=1}^{N} e^{-i\mathbf{k}\cdot\mathbf{r}_m}\,\psi_J(m, o)\Big|^2\, ,\]\(\mathbf{r}_m\) the origins of the \(N\) primitive cells in the supercell and \(o\) the primitive orbitals, so that \(A(\mathbf{k},\omega) = \sum_J W_J(\mathbf{k})\,\delta(\omega - E_J)\). A pristine supercell unfolds exactly onto the primitive bands (\(W = 1\) on them, 0 elsewhere); disorder smears them.
twisted_bilayer()builds the commensurate supercells of two honeycomb (twisted bilayer graphene) or square layers twisted by \(\theta\), with every hopping a function of the distance (pz_hopping(), the Slater-Koster \(p_z\) form of Moon and Koshino, Phys. Rev. B 85, 195458 (2012), by default).magic_angle_parameter()gives the Bistritzer-MacDonald \(\alpha = w/\hbar v k_\theta\) and Fermi velocity \(v^*/v = (1-3\alpha^2)/(1+6\alpha^2)\) of the same model.
Every Bloch matrix comes from KSpace._bloch_ham
(the supercells are ordinary KSpace models: k_path, mesh_bands,
finite_ham, the topology tools all apply).
- class tbkit.moire.SupercellKSpace(lat: Lattice, spin: bool, prim: KSpace, matrix: NDArray, cells: NDArray)[source]#
Bases:
KSpaceA KSpace made of \(N\) copies of a primitive model (see supercell). Orbital o of primitive cell m is orbital
m*prim.norb + o.- prim#
The primitive model.
- Type:
KSpace instance
- cells#
Origins \(\mathbf{r}_m\) of the primitive cells in the supercell.
- Type:
Real ndarray, shape (N, space_dim)
- n_cells#
\(N = |\det M|\).
- Type:
Integer
- class tbkit.moire.MoireKSpace(lat: Lattice, theta: float, layer: NDArray, z: NDArray, n_layer_cells: int)[source]#
Bases:
KSpaceA KSpace of a twisted bilayer (see twisted_bilayer): the orbitals of layer 0 (tags ‘a’, ‘b’, rotated by \(-\theta/2\)) then those of layer 1 (tags ‘c’, ‘d’, rotated by \(+\theta/2\), a height d above).
- theta#
Twist angle, in radians.
- Type:
Real number
- layer#
Layer (0 or 1) of every orbital.
- Type:
Integer ndarray
- z#
Height of every orbital.
- Type:
Real ndarray
- n_layer_cells#
Primitive cells per layer in the supercell.
- Type:
Integer
- tbkit.moire.supercell(ks: KSpace, matrix: ArrayLike) SupercellKSpace[source]#
Get the supercell of a periodic model spanned by \(\mathbf{A}_i = \sum_j M_{ij}\mathbf{a}_j\), a KSpace whose unit cell holds the \(N = |\det M|\) primitive cells inside it. The bands of the supercell are those of the primitive model folded into the smaller Brillouin zone; unfold undoes the folding. Break the translation symmetry afterwards by changing the supercell’s
onsitearray (one entry per orbital), e.g. with random energies.- Parameters:
ks (*KSpace instance (any dimension; spinful or not)*)
matrix – Integer array, shape (dim, dim), nonzero determinant (an integer n in 1D is also accepted).
- Returns:
sc –
SupercellKSpaceinstance,N*ks.norborbitals: orbital o of cell m (originsc.cells[m]) ism*ks.norb + o.
Examples
Example usage:
# a 3 x 3 supercell of graphene, 18 orbitals sc = supercell(gra, [[3, 0], [0, 3]])
- tbkit.moire.unfold(sc: SupercellKSpace, ks: ArrayLike) tuple[NDArray[float64], NDArray[float64]][source]#
Unfold the bands of a supercell onto k-points of the primitive Brillouin zone (see the module docstring): diagonalize the supercell Hamiltonian at each primitive \(\mathbf{k}\) (which folds onto itself modulo the supercell reciprocal lattice), and weigh each eigenstate by its overlap with the primitive Bloch states at \(\mathbf{k}\). The weights at one \(\mathbf{k}\) add up to the number of primitive orbitals; for a pristine supercell they are 1 on the primitive bands \(E_n(\mathbf{k})\) and 0 on the others.
- Parameters:
sc (
SupercellKSpaceinstance (Hermitian, without overlap))ks (Real array, shape (nk, dim)) – Primitive k-points, in the coordinates of
sc.prim.get_ham.
- Returns:
en (Real ndarray, shape (nk, sc.norb)) – Supercell energies at each k.
weights (Real ndarray, shape (nk, sc.norb)) – Spectral weights \(W_J(\mathbf{k})\).
- tbkit.moire.spectral_function(sc: SupercellKSpace, ks: ArrayLike, energies: ArrayLike, broadening: float = 0.05, kernel: str = 'lorentzian') NDArray[float64][source]#
Get the unfolded spectral function of a supercell,
\[A(\mathbf{k}, \omega) = \sum_J W_J(\mathbf{k})\, g(\omega - E_J)\, ,\]with the weights of unfold and a normalized kernel g (Lorentzian or Gaussian of width broadening), so that \(\int A\,d\omega\) is the number of primitive orbitals. For a disordered supercell, average it over disorder configurations.
- Parameters:
sc (
SupercellKSpaceinstance)ks (Real array, shape (nk, dim)) – Primitive k-points.
energies (Real array) – Energies \(\omega\).
broadening (Positive real, default 0.05) – Kernel width.
kernel (‘lorentzian’ or ‘gaussian’, default ‘lorentzian’)
- Returns:
A (Real ndarray, shape (nk, len(energies)))
- tbkit.moire.pz_hopping(d: ArrayLike, t_pi: float = -2.7, t_sigma: float = 0.48, a0: float = 0.142, d0: float = 0.335, delta: float = 0.0453) NDArray[float64][source]#
Get the hopping between two \(p_z\) orbitals a vector \(\mathbf{d}\) apart, in the Slater-Koster form of Moon and Koshino (Phys. Rev. B 85, 195458 (2012)), used for twisted bilayer graphene:
\[t(\mathbf{d}) = V_{pp\pi}(d)\Big[1-\Big(\frac{d_z}{d}\Big)^2\Big] + V_{pp\sigma}(d)\Big(\frac{d_z}{d}\Big)^2\, ,\quad V_{pp\pi} = t_\pi e^{-(d-a_0)/\delta}\, ,\quad V_{pp\sigma} = t_\sigma e^{-(d-d_0)/\delta}\, .\]In-plane it is \(t_\pi\) between nearest neighbours and decays with distance; between the layers of AA-stacked graphene it is \(t_\sigma\). Defaults: graphene, in eV and nm (\(\delta = 0.184\,a\), \(a = 0.246\) nm).
- Parameters:
d (Real array, shape (n, 3)) – Bond vectors.
t_pi (Real number, default -2.7)
t_sigma (Real number, default 0.48)
a0 (Positive real, default 0.142) – In-plane nearest-neighbour distance.
d0 (Positive real, default 0.335) – Interlayer distance.
delta (Positive real, default 0.0453) – Decay length.
- Returns:
t (Real ndarray, shape (n,))
- tbkit.moire.commensurate_angle(m: int, lattice: str = 'honeycomb') float[source]#
Get the commensurate twist angle \(\theta_m\) of two layers: the rotation that maps the lattice vector \((m+1)\mathbf{a}_1 + m\mathbf{a}_2\) onto \(m\mathbf{a}_1 + (m+1)\mathbf{a}_2\),
\[\cos\theta_m = \frac{3m^2+3m+1/2}{3m^2+3m+1}\ \text{(honeycomb)},\qquad \cos\theta_m = \frac{2m(m+1)}{2m^2+2m+1}\ \text{(square)}\](Lopes dos Santos, Peres and Castro Neto, Phys. Rev. B 86, 155449 (2012)). The moiré cell holds \(3m^2+3m+1\) (honeycomb) or \(2m^2+2m+1\) (square) primitive cells per layer; \(m = 31\) gives graphene’s first magic angle, \(\theta \approx 1.05°\).
- Parameters:
m (Positive integer)
lattice (‘honeycomb’ or ‘square’, default ‘honeycomb’)
- Returns:
theta (Real number, in radians)
- tbkit.moire.twisted_bilayer(m: int, lattice: str = 'honeycomb', a: float = 0.142, d: float = 0.335, hopping: Callable[[NDArray], NDArray] | None = None, cutoff: float | None = None, interlayer_scale: float = 1.0) MoireKSpace[source]#
Get the commensurate twisted bilayer of two honeycomb or square layers, twisted by \(\theta_m\) (see commensurate_angle) about a common site (AA stacking at the origin): a KSpace with the moiré cell as unit cell, and every hopping, within a layer and between the layers, given by the function hopping of the bond vector \(\mathbf{d} = (d_x, d_y, d_z)\), for all bonds shorter than cutoff (periodic images included).
Near the first magic angle (\(\theta \approx 1.05°\) for graphene, \(m = 31\), 11908 orbitals) the two bands at charge neutrality become almost flat (Bistritzer and MacDonald, PNAS 108, 12233 (2011); Cao et al., Nature 556, 43 (2018)). The physics depends on the ratio \(\alpha = w/\hbar v k_\theta\) only (see magic_angle_parameter), so interlayer_scale (which multiplies every interlayer hopping) moves the magic angle to larger angles and smaller cells.
- Parameters:
m (Positive integer) – See commensurate_angle.
lattice (‘honeycomb’ or ‘square’, default ‘honeycomb’)
a (Positive real) – Default value 0.142 (graphene, nm). Nearest-neighbour distance.
d (Positive real) – Default value 0.335 (nm). Interlayer distance.
hopping (Callable) – Default value None (pz_hopping). Maps bond vectors, shape (n, 3), to hoppings, shape (n,).
cutoff (Positive real) – Default value None (3.8 a, between the honeycomb neighbour shells at \(\sqrt{13}a\) and \(4a\), so that no shell is cut by rounding). Longest bond.
interlayer_scale (Positive real, default 1) – Factor on the interlayer hoppings.
- Returns:
tbl (
MoireKSpaceinstance)
- tbkit.moire.magic_angle_parameter(theta: float, a: float = 0.142, d: float = 0.335, t: float = -2.7, interlayer: Callable[[NDArray], NDArray] | None = None, interlayer_scale: float = 1.0) tuple[float, float, float][source]#
Get the Bistritzer-MacDonald parameters of twisted bilayer graphene for a tight-binding model with nearest-neighbour hopping t and the interlayer hopping interlayer (a function of the bond vector): the interlayer tunnelling \(w = \frac{1}{\Omega}\int d^2r\, t_\perp(\mathbf{r}, d)\,e^{-i\mathbf{K}\cdot\mathbf{r}}\) (\(\Omega = \sqrt3a_{\mathrm{lat}}^2/2\) the cell area, \(|\mathbf{K}| = 4\pi/3a_{\mathrm{lat}}\), \(a_{\mathrm{lat}} = \sqrt3 a\)), the Dirac velocity \(\hbar v = \frac32|t|a\), the ratio \(\alpha = w/\hbar vk_\theta\) (\(k_\theta = 2|\mathbf{K}|\sin\frac\theta2\)), and the renormalized velocity at the Dirac points of the moiré bands (Bistritzer and MacDonald, PNAS 108, 12233 (2011)),
\[\frac{v^*}{v} = \frac{1-3\alpha^2}{1+6\alpha^2}\, ,\]which vanishes at the first magic angle, \(\alpha = 1/\sqrt3\).
- Parameters:
theta (Positive real) – Twist angle, in radians.
a (Positive real, default 0.142) – Nearest-neighbour distance.
d (Positive real, default 0.335) – Interlayer distance.
t (Real number, default -2.7) – Nearest-neighbour hopping.
interlayer (Callable) – Default value None (pz_hopping). Interlayer hopping.
interlayer_scale (Positive real, default 1) – See twisted_bilayer.
- Returns:
w (Real number) – Interlayer tunnelling.
alpha (Real number)
v_ratio (Real number) – \(v^*/v\).
tbkit.error_handling module#
- tbkit.error_handling.boolean(var, var_name)[source]#
Check if var is a boolean.
- Raises:
TypeError – Parameter var must be a bool.
- tbkit.error_handling.positive_int(var, var_name)[source]#
Check if var is a positive integer.
- Raises:
TypeError – Parameter var must be an integer.
ValueError – Parameter var must be a positive integer.
- tbkit.error_handling.positive_int_lim(var, var_name, nmax)[source]#
Check if var is a positive integer smaller than nmax.
- Raises:
TypeError – Parameter var must be an integer.
ValueError – Parameter var must be a positive integer.
ValueError – Parameter var must be a positive integer smaller than nmax.
- tbkit.error_handling.real_number(var, var_name)[source]#
Check if parameter var is a real number.
- Raises:
TypeError – Parameter var must be a real number.
- tbkit.error_handling.positive_real(var, var_name)[source]#
Check if parameter var is a positive number.
- Raises:
TypeError – Parameter var must be a real number.
ValueError – Parameter var must be a positive number.
- tbkit.error_handling.positive_real_zero(var, var_name)[source]#
Check if parameter var is a positive number or zero.
- Raises:
TypeError – Parameter var must be a real number.
ValueError – Parameter var must be a positive number or zero.
- tbkit.error_handling.negative_real(var, var_name)[source]#
Check if parameter var is a negative number.
- Raises:
TypeError – Parameter var must be a real number.
ValueError – Parameter var must be a negative number.
- tbkit.error_handling.number(var, var_name)[source]#
Check if parameter var is a number.
- Raises:
TypeError – Parameter var must be a real or complex number.
- tbkit.error_handling.value_params(required, params, func)[source]#
Check that params holds every parameter that the value function func needs (see tbkit.values).
- Raises:
TypeError – The value function needs parameters missing from get_ham.
- tbkit.error_handling.value_shape(val, size, spin, func)[source]#
Check the values returned by the value function func for size bonds or sites: a number or one per entry (or, if spin, also a 2x2 matrix or one per entry).
- Raises:
ValueError – The value function must return a number or an array of one value per bond/site.
- tbkit.error_handling.no_value_functions(model, method)[source]#
Check that model has no value functions (callable hoppings or onsite energies), which method cannot represent.
- Raises:
ValueError – method does not support value functions.
- tbkit.error_handling.is_callable(var, var_name)[source]#
Check if parameter var is callable.
- Raises:
TypeError – Parameter var must be callable.
- tbkit.error_handling.larger(var1, var_name1, var2, var_name2)[source]#
Check if var1 larger than val.
- Raises:
ValueError – Parameter var1 larger than var2.
- tbkit.error_handling.smaller(var1, var_name1, var2, var_name2)[source]#
Check if var1 smaller than var2.
- Raises:
ValueError – Parameter var1 must be smaller than var2.
- tbkit.error_handling.string(var, var_name)[source]#
Check if parameter var is a string.
- Raises:
TypeError – Parameter var must be a string.
- tbkit.error_handling.ndarray(var, var_name, length)[source]#
Check if parameter var is a numpy array.
- Raises:
TypeError – Parameter var must be a numpy ndarray.
ValueError – length array must be equal to length.
- tbkit.error_handling.ndarray_null(var, var_name)[source]#
Check if parameter var is not a null numpy array.
- Raises:
ValueError – Parameter var must not be a null numpy ndarray.
- tbkit.error_handling.ndarray_empty(var, var_name)[source]#
Check if parameter var is not an empty numpy array.
- Raises:
ValueError – Parameter var must not be an emptynumpy ndarray.
- tbkit.error_handling.list_tuple_2elem(var, var_name)[source]#
Check if parameter var is a list/tuple with 2 elements.
- Raises:
TypeError – Parameter var must be a list/tuple.
ValueError – Parameter var must contain 2 elements.
- tbkit.error_handling.tuple_2elem(var, var_name)[source]#
Check if parameter var is a tuple with 2 elements.
- Raises:
TypeError – Parameter var must be a tuple.
ValueError – Parameter var must contain 2 elements.
- tbkit.error_handling.lat(lat)[source]#
Check if parameter is an instance of the lattice.
- Raises:
TypeError – Parameter must be an instance of the class lattice.
- tbkit.error_handling.unit_cell(unit_cell)[source]#
Check parameter unit_cell.
- Raises:
TypeError – Parameter unit_cell must be a list.
KeyError – Dictionaries must contain the key “tag”.
KeyError – Dictionaries must contain the key “r0”.
TypeError – Key “tags” must contain a one-character string.
ValueError – Key “tags” must contain a one-character string.
ValueError – Key “r0” must contain be a list.
TypeError – Key “r0” must contain be a tuple.
ValueError – Key “r0” must contain a tuple of length two.
ValueError – Key “r0” must contain a tuple of two real numbers.
- tbkit.error_handling.prim_vec(prim_vec)[source]#
Check parameter prim_vec.
- Raises:
TypeError – Parameter prim_vec must be a list.
ValueError – Parameter prim_vec must be a list of length 1 for 1D lattices or length 2 fro 2D lattices.
TypeError – List elements must be tuples.
ValueError – List elements must be 1 or 2 tuples.
ValueError – Tuples must be of length 2.
ValueError – Tuples must containt real numbers.
ValueError – Norm of coor should be larger than 0.1.
- tbkit.error_handling.independent(prim_vec)[source]#
Check that the primitive vectors are linearly independent (needed for the reciprocal lattice).
- Raises:
ValueError – The primitive vectors must be linearly independent.
- tbkit.error_handling.space_dim(unit_cell, prim_vec)[source]#
Check that the unit cell positions and the primitive vectors live in the same space (2D or 3D).
- Raises:
ValueError – “r0” and prim_vec tuples must have the same length.
- tbkit.error_handling.get_lattice(prim_vec, n1, n2, n3=1)[source]#
Check method get_lattice.
- Raises:
TypeError – Parameters n1, n2, n3 must be integers.
ValueError – Parameters n1, n2, n3 must be positive integers.
ValueError – n2 (n3) must be 1 with fewer than 2 (3) primitive vectors.
- tbkit.error_handling.coor(coor, dtype=None)[source]#
Check if coor is a structured array with dtype=[(‘x’, ‘f8’), (‘y’, ‘f8’), (‘tag’, ‘U1’)], or, for a lattice in 3D space, dtype=[(‘x’, ‘f8’), (‘y’, ‘f8’), (‘z’, ‘f8’), (‘tag’, ‘U1’)]. If dtype is given, coor must have exactly that dtype.
- tbkit.error_handling.coor_1d(coor)[source]#
Check if coor is 1d (coor[‘y’] = cst).
- Raises:
ValueError – coor must be 1d( coor[‘y’] = cst)..
- tbkit.error_handling.remove_sites(index, sites)[source]#
Check method remove_sites.
- Raises:
TypeError – Parameter index must be a list.
ValueError – Parameter index must be a list of integers.
ValueError – Indices must be between 0 and sites -1. of integers between 0 and sites
- tbkit.error_handling.shift(shift)[source]#
Check shift_x and shift_y.
- Raises:
TypeError – Parameter delta must be a real number.
- tbkit.error_handling.space_3d(space_dim)[source]#
Check that the lattice lives in 3D space.
- Raises:
ValueError – This method requires a lattice in 3D space.
- tbkit.error_handling.sites(sites)[source]#
Check if get_lattice has been called (coor not empty).
- Raises:
RuntimeError – Run method lat.get_lattice first.
- tbkit.error_handling.sys(sys)[source]#
Check if parameter is an instance of the system.
- Raises:
TypeError – Parameter must be an instance of the class system.
- tbkit.error_handling.print_hopping(n, nmax)[source]#
Check method print_vec_hopping.
- Raises:
TypeError – Parameter nmax must be an integer.
ValueError – Parameter nmax must be a positive integer. between 1 and n_max-1.
- tbkit.error_handling.set_onsite(onsite, tags)[source]#
Check method set_onsite.
- Raises:
TypeError – Parameter onsite must be a dictionary.
ValueError – Parameter onsite keys must be a tag.
ValueError – Parameter onsite values must be real and/or complex numbers, or value functions.
- tbkit.error_handling.set_hopping(list_hop, n_max)[source]#
Check method set_hopping.
- Raises:
TypeError – Parameter list_hop must be a list.
TypeError – Parameter list_hop must be a list of dictionary.
KeyError – “n” and “t” must be dictionary keys.
KeyError – “tag” or “ang” must be a key.
KeyError – “tag” and “ang” must be keys.
ValueError – Dictionaries must be of length 2, 3, or 4.
ValueError – “n” must be between 1 and nmax”
- tbkit.error_handling.set_hopping_def(hop, hopping_def, sites, var_name='hopping_def', same_site=False)[source]#
Check methods set_hopping_def and set_hopping_manual.
hop is not used (kept for backward compatibility). Indices may be Python or NumPy integers, values Python or NumPy numbers. If same_site is True, keys \((i, i)\) are accepted.
- Raises:
TypeError – Parameter hopping_def must be a dictionary
TypeError – hopping_def keys must be tuples.
TypeError – hopping_def keys must be tuples of length 2.
ValueError – hopping_def keys must be tuples of integers.
ValueError – hopping_def keys must be integers between 0 and sites-1.
ValueError – hopping_def keys must be different integers between 0 and sites-1.
TypeError – hopping_def values must be numbers.
- tbkit.error_handling.set_onsite_def(onsite_def, sites)[source]#
Check method set_ons_def.
- Raises:
TypeError – Parameter onsite_def must be a dictionary.
TypeError – onsite_def keys must be integers.
TypeError – onsite_def values must be numbers.
ValueError – onsite_def keys must be integers between \([0, sites)\).
- tbkit.error_handling.hop_n1(hop)[source]#
Check method if self.hop contains nearest neighbours hoppings.
- Raises:
ValueError – self.hop must contain nearest neighbours hoppings.
- tbkit.error_handling.empty_onsite(onsite)[source]#
Check if onsite not empty.
- Raises:
RuntimeError – Run method set_onsite first.
- tbkit.error_handling.empty_hop(hop)[source]#
Check if hop not empty.
- Raises:
RuntimeError – Run method set_hopping first.
- tbkit.error_handling.hop_sites(hop, sites)[source]#
Check if hop indices are smaller than sites.
- Raises:
ValueError – Run method sys.clear_hopping and redefine the hoppings.
- tbkit.error_handling.empty_coor(coor)[source]#
Check if coor not empty.
- Raises:
RuntimeError – Run method lattice.get_lattice first.
- tbkit.error_handling.empty_coor_hop(coor_hop)[source]#
Check if coor_hop not empty.
- Raises:
RuntimeError – Run method system.get_coor_hop first.
- tbkit.error_handling.empty_ham(ham)[source]#
Check if Hamiltonian not empty.
- Raises:
RuntimeError – Run method system.get_ham first.
- tbkit.error_handling.empty_en(en)[source]#
Check if en not empty.
- Raises:
RuntimeError – Run method get_ham first.
- tbkit.error_handling.empty_pola(pola)[source]#
Check if pola not empty.
- Raises:
RuntimeError – Run method get_eig(eigenvec=True) first.
- tbkit.error_handling.empty_vn(vn)[source]#
Check if vn not empty.
- Raises:
RuntimeError – Run method get_eig(eigenvec=True) first.
- tbkit.error_handling.tag(tag, tags)[source]#
Check tag.
- Raises:
TypeError – Parameter tag must be a string.
ValueError – Parameter tag is not in tags.
- tbkit.error_handling.angle(angle, angles, upper_part)[source]#
Check angle.
- Raises:
TypeError – Parameter angle must be * a positive number if upper_part is True * a negative real if upper_part is False.
ValueError – Parameter angle is not in hop[‘ang’].
- tbkit.error_handling.lims(lims)[source]#
Check parameter lims.
- Raises:
TypeError – Parameter lims must be a list.
TypeError – Parameter lims[0] must be a real number.
TypeError – Parameter lims[1] must be a real number.
ValueError – lims must be a list of length 2.
ValueError – lims[0] must be smaller than lims[1].
- tbkit.error_handling.lims_positive(lims)[source]#
Check parameter lims.
- Raises:
TypeError – Parameter lims must be a list.
TypeError – Parameter lims[0] must be a positive real number.
TypeError – Parameter lims[1] must be a positive real number.
ValueError – lims must be a list of length 2.
ValueError – lims[0] must be smaller than lims[1].
- tbkit.error_handling.fig(fig)[source]#
Check if fig is an instance of Figure.
- Raises:
TypeError – fig must be an instance of Figure.
- tbkit.error_handling.ani(ani)[source]#
Check if ani is an instance of FuncAnimation.
- Raises:
TypeError – ani must be an instance of FuncAnimation.
- tbkit.error_handling.file_format(file_format)[source]#
Check if file_format is a string ‘png’, ‘pdf’, ‘ps’, ‘eps’, or ‘svg’.
- Raises:
TypeError – file_format must be a string.
ValueError – file_format must be a string given by ‘png’, ‘pdf’, ‘ps’, ‘eps’, or ‘svg’.
- tbkit.error_handling.get_pump(hams)[source]#
Check method propagation.get_pumping.
- Raises:
TypeError – hams must be a non-empty list.
RuntimeError – Run method system.get_ham first.
- tbkit.error_handling.k_vector(vec, var_name, ndim)[source]#
Check that vec is a tuple/list of ndim real numbers.
- Raises:
TypeError – Parameter var_name must be a tuple/list.
ValueError – Parameter var_name must be of length ndim.
TypeError – Parameter var_name must contain real numbers.
- tbkit.error_handling.ks(ks, ndim)[source]#
Check the k-points passed to kspace.get_bands: a 2D array of shape (nk, ndim).
- Raises:
ValueError – Parameter ks must be of shape (nk, ndim).
- tbkit.error_handling.spin_matrix(t, var_name)[source]#
Check a spinful “t” or onsite value: either a plain number, or a 2x2 complex matrix.
- Raises:
TypeError – Parameter var_name must be a number or a 2x2 matrix.
- tbkit.error_handling.set_hopping_kspace(list_hop, n_sites, ndim, spin=False, values=False)[source]#
Check method kspace.set_hopping. With values, “t” may also be a value function (a callable).
- Raises:
TypeError – Parameter list_hop must be a list of dictionaries.
KeyError – “i”, “j”, “R”, and “t” must be dictionary keys.
ValueError – “i” and “j” must be site indices between 0 and n_sites-1.
ValueError – “R” must be a tuple of ndim integers.
TypeError – “t” must be a real or complex number (or, if spin, a 2x2 matrix).
- tbkit.error_handling.set_onsite_kspace(dict_onsite, tags, spin=False)[source]#
Check method kspace.set_onsite.
- Raises:
TypeError – Parameter dict_onsite must be a dictionary.
ValueError – keys must be tags.
TypeError – values must be real or complex numbers (or, if spin, a pair of real/complex numbers, or a 2x2 matrix).
- tbkit.error_handling.k_path_points(points, ndim)[source]#
Check parameter points used by kspace.k_path.
- Raises:
TypeError – Parameter points must be a list.
ValueError – Parameter points must contain at least two k-points.
- tbkit.error_handling.dos_kernel(kernel)[source]#
Check parameter kernel used by dos.density_of_states.
- Raises:
TypeError – Parameter kernel must be a string.
ValueError – Parameter kernel must be “gaussian” or “lorentzian”.
- tbkit.error_handling.kspace_dos_kernel(kernel)[source]#
Check parameter kernel used by kspace.plot_dos.
- Raises:
TypeError – Parameter kernel must be a string.
ValueError – Parameter kernel must be “gaussian”, “lorentzian” or “tetrahedron”.
- tbkit.error_handling.mesh_energies(energies)[source]#
Check parameter energies used by dos.tetrahedron_dos: a non-empty array of bands on a mesh of 1, 2 or 3 dimensions.
- Raises:
ValueError – Parameter energies must be of shape (n1, …, nbands), on a mesh of 1 to 3 dimensions.
- tbkit.error_handling.increasing_grid(grid, var_name)[source]#
Check that grid is a 1D real array of at least two increasing values.
- Raises:
ValueError – Parameter var_name must be a 1D array of at least two increasing real values.
- tbkit.error_handling.nk(nk, ndim)[source]#
Check parameter nk used by kspace.mesh_bands / kspace.berry_curvature.
- Raises:
TypeError – Parameter nk must be an integer or a tuple of integers.
ValueError – Parameter nk (or each of its elements) must be a positive integer.
ValueError – Parameter nk must be a tuple of length ndim.
- tbkit.error_handling.dim_2(dim)[source]#
Check that the model is 2D. Berry curvature / Chern number are only defined for a 2D Brillouin zone.
- Raises:
ValueError – This calculation requires a 2D lattice.
- tbkit.error_handling.dim_min(dim, dmin)[source]#
Check that the model has at least dmin periodic dimensions.
- Raises:
ValueError – This calculation requires a lattice with at least dmin primitive vectors.
- tbkit.error_handling.plane(plane, dim)[source]#
Check parameter plane of kspace.berry_curvature: two distinct reciprocal-vector indices below dim.
- Raises:
TypeError – Parameter plane must be a tuple of two integers.
ValueError – Parameter plane must contain two distinct indices below dim.
- tbkit.error_handling.direction(direction, dim=2)[source]#
Check parameter direction used by kspace.ribbon (and the Wilson-loop methods): a primitive-vector index below dim.
- Raises:
TypeError – Parameter direction must be an integer.
ValueError – Parameter direction must be between 0 and dim-1.
- tbkit.error_handling.band_indices(bands, norb)[source]#
Check parameter bands used by kspace.berry_curvature.
- Raises:
TypeError – Parameter bands must be a non-empty list of integers.
ValueError – Parameter bands must be a list of distinct band indices between 0 and norb-1.
- tbkit.error_handling.k_perp(k_perp, n)[source]#
Check parameter k_perp of the Wilson-loop methods: a tuple of n real numbers (fractional coordinates along the other reciprocal vectors).
- Raises:
ValueError – Parameter k_perp must contain n real numbers.
- tbkit.error_handling.flow(flow, direction, dim)[source]#
Check parameter flow of kspace.wannier_flow.
- Raises:
TypeError – Parameter flow must be an integer.
ValueError – Parameter flow must be a direction other than direction.
- tbkit.error_handling.even_bands(bands)[source]#
Check that bands is a list of an even number of band indices (Kramers pairs).
- Raises:
TypeError – Parameter bands must be a list.
ValueError – Parameter bands must contain an even number of bands.
- tbkit.error_handling.operator(mat, norb)[source]#
Check a symmetry operator: a (norb, norb) matrix.
- Raises:
ValueError – The operator must be a (norb, norb) matrix.
- tbkit.error_handling.parities(xi, tol=1e-06)[source]#
Check that inversion eigenvalues are +-1.
- Raises:
ValueError – The bands are not an inversion-invariant subspace.
- tbkit.error_handling.k_map(k_map)[source]#
Check parameter k_map of kspace.symmetry_error.
- Raises:
ValueError – Parameter k_map must be ‘minus’ or ‘identity’.
- tbkit.error_handling.is_symmetry(err, tol)[source]#
Check that a symmetry error is below tol.
- Raises:
ValueError – The operator is not a symmetry of the model.
- tbkit.error_handling.square(sq, tol)[source]#
Check that the square of an antiunitary operator is +-1.
- Raises:
ValueError – The square of the operator must be +1 or -1.
- tbkit.error_handling.hermitian(ham)[source]#
Check that a (sparse) Hamiltonian is Hermitian.
- Raises:
ValueError – This calculation requires a Hermitian Hamiltonian.
- tbkit.error_handling.planar_cell(prim_vec)[source]#
Check that the lattice has two in-plane primitive vectors (a unit-cell area).
- Raises:
ValueError – Give the area per site explicitly.
- tbkit.error_handling.integer(var, var_name)[source]#
Check if var is an integer.
- Raises:
TypeError – Parameter var must be an integer.
- tbkit.error_handling.dim_exact(dim, d)[source]#
Check that the model has exactly d periodic dimensions.
- Raises:
ValueError – This calculation requires a lattice with d primitive vectors.
- tbkit.error_handling.nonzero_number(var, var_name)[source]#
Check if var is a nonzero number.
- Raises:
TypeError – Parameter var must be a number.
ValueError – Parameter var must be nonzero.
- tbkit.error_handling.gbz_roots(n_roots, p)[source]#
Check that det[H(beta) - E] has roots on both sides of the GBZ.
- Raises:
ValueError – The model has no hoppings in both directions.
- tbkit.error_handling.ham_model(model, cls)[source]#
Check the model of tbkit.exceptional: a 2D KSpace instance, or a callable of a point of a 2D parameter plane.
- Raises:
TypeError – Parameter model must be a KSpace instance or a callable.
ValueError – A KSpace model must have two primitive vectors.
- tbkit.error_handling.ham_matrix(ham)[source]#
Check the matrix returned by the callable model of tbkit.exceptional: square and finite.
- Raises:
ValueError – The model must return a finite square matrix.
- tbkit.error_handling.loop(loop)[source]#
Check a closed loop of tbkit.exceptional: a callable of s in [0, 1] returning a point of the plane, or the vertices of a polygon.
- Raises:
TypeError – Parameter loop must be a callable or an array of vertices.
ValueError – A polygon needs at least 3 vertices with 2 real coordinates.
- tbkit.error_handling.loop_point(point)[source]#
Check a point returned by a loop callable: 2 finite real numbers.
- Raises:
ValueError – The loop must return points of 2 real coordinates.
- tbkit.error_handling.closed_loop(ham_start, ham_end)[source]#
Check that a loop is closed: the Hamiltonian at its end is the one at its start.
- Raises:
ValueError – The loop is not closed.
- tbkit.error_handling.band_pair(bands, norb)[source]#
Check a pair of band labels: two distinct integers between 0 and norb-1.
- Raises:
TypeError – Parameter bands must be a pair of integers.
ValueError – Parameter bands must be two distinct band indices.
- tbkit.error_handling.band_index(band, norb)[source]#
Check a band label: an integer between 0 and norb-1.
- Raises:
TypeError – Parameter band must be an integer.
ValueError – Parameter band must be between 0 and norb-1.
- tbkit.error_handling.tracking(k)[source]#
Eigenvalue continuation failed: the path meets a degeneracy.
- Raises:
ValueError – Cannot follow the eigenvalues continuously near k.
- tbkit.error_handling.winding_path(k)[source]#
The discriminant vanishes on the path of a winding number.
- Raises:
ValueError – The loop passes through a zero of the discriminant.
- tbkit.error_handling.discriminant_nonzero(scale)[source]#
Check that the discriminant does not vanish identically.
- Raises:
ValueError – The bands are degenerate everywhere.
- tbkit.error_handling.gap_kind(gap)[source]#
Check the kind of line gap: ‘real’ (Re E) or ‘imaginary’ (Im E).
- Raises:
ValueError – Parameter gap must be “real” or “imaginary”.
- tbkit.error_handling.biorthogonal_kind(kind)[source]#
Check the kind of Berry connection: ‘LR’, ‘RL’, ‘RR’ or ‘LL’.
- Raises:
ValueError – Parameter kind must be “LR”, “RL”, “RR” or “LL”.
- tbkit.error_handling.line_gap(keys, bands, gap)[source]#
Check that bands are separated from the other bands by a line gap: with the bands ordered by keys (Re E or Im E, shape (nk, norb)) at every k-point, a band inside the group and its neighbour outside it never overlap over the whole mesh.
- Raises:
ValueError – The bands have no line gap.
- tbkit.error_handling.band_continuity(en, bands)[source]#
Check that a group of bands, labelled at every point of a periodic k mesh (en, complex, shape (n1, n2, norb)), is continuous: matching the eigenvalues of neighbouring points by distance maps the group onto itself. A line gap measured on the mesh alone can miss a narrow crossing between mesh points; this catches the jump of the labels.
- Raises:
ValueError – The band labels jump between neighbouring k-points.
- tbkit.error_handling.no_overlap(overlap)[source]#
Check that no overlap matrix is set (non-orthogonal bases are not supported by the biorthogonal tools).
- Raises:
ValueError – Not available with an overlap matrix.
- tbkit.error_handling.weights(weights, n)[source]#
Check the weights of occupation.fermi_level: n positive numbers.
- Raises:
ValueError – Parameter weights must contain n positive numbers.
- tbkit.error_handling.electrons(n_electrons, capacity)[source]#
Check a number of electrons: between 0 and the total weight of the levels.
- Raises:
TypeError – Parameter n_electrons must be a real number.
ValueError – Parameter n_electrons must be between 0 and capacity.
- tbkit.error_handling.n_eig(n_eig, sites)[source]#
Check the number of eigenpairs of system.get_eig_sparse.
- Raises:
TypeError – Parameter n_eig must be an integer.
ValueError – Parameter n_eig must be between 1 and sites-2.
- tbkit.error_handling.square_matrix(mat, var_name)[source]#
Check that mat is a square 2D array.
- Raises:
ValueError – Parameter must be a square matrix.
- tbkit.error_handling.lead(h0, v)[source]#
Check a lead: square cell Hamiltonian h0 and coupling v of the same shape.
- Raises:
ValueError – h0 and v must be square matrices of the same shape.
- tbkit.error_handling.converged(flag, name)[source]#
Check that an iteration converged.
- Raises:
RuntimeError – The iteration did not converge.
- tbkit.error_handling.lead_direction(direction)[source]#
Check the direction of a lead: +1 or -1.
- Raises:
ValueError – Parameter direction must be +1 or -1.
- tbkit.error_handling.surface_side(side)[source]#
Check parameter side of KSpace.surface_spectral_function: +1 or -1.
- Raises:
ValueError – Parameter side must be +1 or -1.
- tbkit.error_handling.nearest_cells(n)[source]#
Check that a lead hopping reaches at most the neighbouring cells.
- Raises:
ValueError – Lead hoppings must connect neighbouring cells only.
- tbkit.error_handling.lead_coupling(coupling, sites, m, n_device)[source]#
Check the coupling of a lead to the device.
- Raises:
TypeError – Parameter sites must be a list of integers.
ValueError – sites must be distinct device indices, coupling of shape (len(sites), m).
- tbkit.error_handling.lead_device_size(sites, n_device)[source]#
Check that a System has one site per row of the device Hamiltonian.
- Raises:
ValueError – The System must have as many sites as the device Hamiltonian has rows.
- tbkit.error_handling.lead_space_dim(lead_dim, device_dim)[source]#
Check that a lead and the device have positions of the same dimension.
- Raises:
ValueError – The lead and the device must have the same space dimension.
- tbkit.error_handling.lead_overlap(found)[source]#
Check that some device site lies on the lattice of a lead.
- Raises:
ValueError – No device site matches a lead orbital.
- tbkit.error_handling.lead_interface(missing)[source]#
Check that the interface cell of a lead is complete (missing: the lead orbitals coupled to the next cell but absent from the device).
- Raises:
ValueError – The interface between the device and the lead is incomplete.
- tbkit.error_handling.lead_extension(inside)[source]#
Check that the lead sites added to complete an interface stay within the device’s extent along the lead (inside False when they would pass the innermost lead cell holding a device site).
- Raises:
ValueError – The lead cannot be closed against the device.
- tbkit.error_handling.lead_index(lead, n_leads)[source]#
Check a lead index.
- Raises:
TypeError – The lead index must be an integer.
ValueError – No such lead.
- tbkit.error_handling.lead_band_edge(flag, energy)[source]#
Check that the modes of a lead are well defined: the energy is not at a band edge, where a propagating mode has zero velocity.
- Raises:
ValueError – Energy at a band edge of a lead.
- tbkit.error_handling.conservation_law(law, h0, v, tol=1e-10)[source]#
Check the conservation law of a lead: a Hermitian matrix of the shape of h0 that commutes with h0 and v.
- Raises:
ValueError – Wrong shape, not Hermitian, or not conserved by the lead.
- tbkit.error_handling.lead_block(lead, n_blocks)[source]#
Check a lead of a scattering matrix: a lead index, or a tuple (lead, block) with a block of that lead’s conservation law.
- Raises:
TypeError – Not an integer or a tuple of two integers.
ValueError – No such lead or block.
- tbkit.error_handling.kpm_kernel(kernel)[source]#
Check the KPM kernel name.
- Raises:
ValueError – Parameter kernel must be “jackson” or “lorentz”.
- tbkit.error_handling.kpm_grid(eps)[source]#
Check that the KPM energies lie inside the (scaled) spectral bounds.
- Raises:
ValueError – e_grid must lie inside the spectral bounds.
- tbkit.error_handling.site_index(site, n)[source]#
Check a site (row) index.
- Raises:
TypeError – Parameter site must be an integer.
ValueError – Parameter site must be between 0 and n-1.
- tbkit.error_handling.max_order(list_hop)[source]#
Largest neighbour order ‘n’ requested by a (possibly malformed) list of hoppings; 1 if there is none (the list is validated afterwards).
- tbkit.error_handling.orbitals(orbs)[source]#
Check a list of orbital names.
- Raises:
TypeError – The orbitals must be a list of names.
ValueError – Unknown or repeated orbital.
- tbkit.error_handling.orbital_dict(orbital_dict, tags)[source]#
Check the orbitals of OrbitalSystem: a list of orbitals for every tag.
- Raises:
TypeError – Parameter orbitals must be a dictionary.
ValueError – Every tag needs its orbitals.
- tbkit.error_handling.sk_params(params)[source]#
Check a dictionary of Slater-Koster bond integrals.
- Raises:
TypeError – Parameter params must be a dictionary of numbers.
ValueError – Unknown bond integral.
- tbkit.error_handling.sk_pair_params(params, tags_i, tags_j)[source]#
Check the bond integrals of set_slater_koster: one dictionary, or one per tag pair of the bonds.
- Returns:
bool – True if keyed by tag pair.
- Raises:
ValueError – A tag pair of the bonds has no bond integrals.
- tbkit.error_handling.bond_vector(d)[source]#
Check a bond vector: 2 or 3 reals, nonzero.
- Raises:
ValueError – The bond vector must have 2 or 3 components and be nonzero.
- tbkit.error_handling.orbital_of_site(orbital, orbs)[source]#
Check that a site carries an orbital.
- Raises:
ValueError – The site has no such orbital.
- tbkit.error_handling.spin_index(spin, ns)[source]#
Check a spin index: 0, or 0/1 with spin.
- Raises:
ValueError – Parameter spin must be 0 (or 1 with spin).
- tbkit.error_handling.set_onsite_orb(dict_onsite, tags, orbital_dict)[source]#
Check OrbitalSystem.set_onsite: numbers, or {orbital: number} dictionaries.
- Raises:
TypeError – Onsite energies must be numbers or dictionaries.
ValueError – Unknown tag or orbital.
- tbkit.error_handling.spinful(spin)[source]#
Check that the model has spin.
- Raises:
ValueError – This term needs spin=True.
- tbkit.error_handling.vector3(vec, var_name)[source]#
Check a tuple of three real numbers.
- Raises:
ValueError – Parameter must be a tuple of three real numbers.
- tbkit.error_handling.p_shell(tags, orbital_dict)[source]#
Check that the tags carry the three p orbitals.
- Raises:
ValueError – The tags must carry px, py and pz.
- tbkit.error_handling.block_shape(mat, shape)[source]#
Check the shape of a hopping block.
- Raises:
ValueError – The block must have the given shape.
- tbkit.error_handling.orbital_terms(hop, blocks)[source]#
Check that an OrbitalSystem has hoppings.
- Raises:
RuntimeError – Run set_hopping or set_slater_koster first.
- tbkit.error_handling.no_left(left)[source]#
Check that left eigenvectors are not asked for with an overlap matrix.
- Raises:
ValueError – left=True needs an orthogonal basis.
- tbkit.error_handling.orthogonal(overlap)[source]#
Check that the basis is orthogonal.
- Raises:
ValueError – This calculation needs an orthogonal basis.
- tbkit.error_handling.hermitian_dense(ham)[source]#
Check that a dense matrix is Hermitian.
- Raises:
ValueError – This calculation requires a Hermitian Hamiltonian.
- tbkit.error_handling.integer_electrons(n_electrons)[source]#
Check that the number of electrons is an integer (zero temperature).
- Raises:
ValueError – At zero temperature, n_electrons must be an integer.
- tbkit.error_handling.mixing(mixing)[source]#
Check the density mixing: a real in (0, 1].
- Raises:
ValueError – Parameter mixing must be in (0, 1].
- tbkit.error_handling.pairing(delta, n)[source]#
Check a BdG pairing matrix: (n, n), antisymmetric.
- Raises:
ValueError – The pairing matrix must be (n, n) and antisymmetric.
- tbkit.error_handling.hermitian_kspace(hermitian, overlap)[source]#
Check that a KSpace model is Hermitian, with an orthogonal basis.
- Raises:
ValueError – The model must be Hermitian, without overlap.
- tbkit.error_handling.pairing_kspace(pairing, norb, ndim)[source]#
Check the pairings of bdg.bdg_kspace.
- Raises:
TypeError – Parameter pairing must be a list of dictionaries.
KeyError – “i”, “j”, “R” and “delta” must be keys.
ValueError – Orbital indices below norb; R a tuple of ndim integers.
- tbkit.error_handling.positive_int_zero(var, var_name)[source]#
Check if var is a positive integer or zero.
- Raises:
TypeError – Parameter var must be an integer.
ValueError – Parameter var must be a positive integer or zero.
- tbkit.error_handling.harmonics(harm)[source]#
Check the harmonics of floquet.sambe_hamiltonian: a dictionary with (at least) m = 0.
- Raises:
TypeError – The harmonics must be a dictionary {m: matrix}.
ValueError – The harmonics must contain m = 0 and square matrices of one shape.
- tbkit.error_handling.kspace(ks, cls)[source]#
Check that ks is a KSpace instance.
- Raises:
TypeError – Parameter ks must be a KSpace instance.
- tbkit.error_handling.not_floquet()[source]#
- Raises:
ValueError – Not available for a Floquet (driven) model.
- tbkit.error_handling.sk_bonds(bonds)[source]#
Check the bonds of slater_koster.sk_kspace: {n: bond integrals}.
- Raises:
TypeError – Parameter bonds must be a dictionary {n: bond integrals}.
- tbkit.error_handling.fermi_energies(e_fermi)[source]#
Check the Fermi energies of the Hall conductivities: a real number, or a non-empty array of finite real numbers.
- Raises:
TypeError – Parameter e_fermi must be a real number or an array of real numbers.
ValueError – Parameter e_fermi must be non-empty and finite.
- tbkit.error_handling.hermitian_model(hermitian)[source]#
Check that a KSpace model is Hermitian (a Kubo conductivity needs real bands and orthonormal eigenstates).
- Raises:
ValueError – This calculation requires a Hermitian model.
- tbkit.error_handling.k_fixed_hall(k_fixed, dim, full_allowed=True)[source]#
Check parameter k_fixed of the Hall conductivities: None (the whole Brillouin zone) or a real number (a plane of a 3D model).
- Raises:
TypeError – Parameter k_fixed must be None or a real number.
ValueError – A 3D spin Hall conductivity needs a plane (k_fixed).
- tbkit.error_handling.spin_axis(axis)[source]#
Check the spin quantization axis: ‘x’, ‘y’ or ‘z’.
- Raises:
ValueError – Parameter spin_axis must be “x”, “y” or “z”.
- tbkit.error_handling.refine_fraction(fraction)[source]#
Check the fraction of mesh points refined by the adaptive mesh: a real in (0, 1].
- Raises:
TypeError – Parameter refine_fraction must be a real number.
ValueError – Parameter refine_fraction must be in (0, 1].
- tbkit.error_handling.path_parameter(param)[source]#
Check the parameter that a path varies (KSpace.axion_angle): a string.
- Raises:
TypeError – Parameter param must be a string (the name of a value-function parameter).
- tbkit.error_handling.path_values(values)[source]#
Check the parameter values of a path: a 1D array of at least two finite real numbers, strictly increasing or strictly decreasing.
- Raises:
TypeError – Parameter values must be a 1D array of real numbers.
ValueError – Parameter values must hold at least two finite, strictly monotonic values.
- tbkit.error_handling.path_gap(gap, param, value, tol=1e-06)[source]#
Check that the bands stay separated from the others along a path.
- Raises:
ValueError – The bands touch the others at param = value.
- tbkit.error_handling.velocity(vel, n, var_name)[source]#
Check a velocity operator: a square (sparse or dense) matrix of the Hamiltonian’s shape.
- Raises:
ValueError – The velocity must be a (n, n) matrix.
- tbkit.error_handling.positive_overlap(s_min)[source]#
Check that the overlap matrix S(k) is positive definite.
- Raises:
ValueError – The overlap matrix must be positive definite.
- tbkit.error_handling.branch_cut(epsilon)[source]#
Check the branch cut of a Floquet Hamiltonian: None or a real number.
- Raises:
TypeError – Parameter epsilon must be None or a real number.
- tbkit.error_handling.durations(durations, n)[source]#
Check the step durations of a step drive: n positive reals.
- Raises:
TypeError – Parameter durations must be a list of real numbers.
ValueError – Parameter durations must hold one positive number per step.
- tbkit.error_handling.step_models(models, kspace_cls, system_cls)[source]#
Check the models of a step drive: a non-empty list, either of KSpace instances (Hermitian, orthogonal basis, one lattice size) or of System instances and square matrices. Returns ‘kspace’ or ‘matrix’.
- Raises:
TypeError – Parameter models must be a non-empty list of KSpace, System or matrices.
ValueError – The KSpace models must be Hermitian, with no overlap, of one size.
- tbkit.error_handling.step_matrices(hams)[source]#
Check the Hamiltonians of a real-space step drive: Hermitian square matrices of one shape.
- Raises:
TypeError – Parameter hams must be a non-empty list of matrices.
ValueError – The matrices must be square, Hermitian and of one shape.
- tbkit.error_handling.drive_matrix(ham, norb)[source]#
Check the output of a Bloch drive ham_kt(k, t): a Hermitian (norb, norb) matrix.
- Raises:
ValueError – ham_kt(k, t) must return a Hermitian (norb, norb) matrix.
- tbkit.error_handling.time_in_period(t, period)[source]#
Check a time within the period: None or a real in [0, period].
- Raises:
TypeError – Parameter t must be None or a real number.
ValueError – Parameter t must be in [0, period].
- tbkit.error_handling.nk_min(nk, n_min)[source]#
Check that every k-mesh size is at least n_min.
- Raises:
ValueError – Parameter nk must be at least n_min.
- tbkit.error_handling.hopping_form(list_hop)[source]#
Tell the two forms of KSpace.set_hopping apart: the explicit one (keys ‘i’, ‘j’, ‘R’, ‘t’) and the neighbour-order one of System.set_hopping (keys ‘n’, ‘t’, and optionally ‘ang’, ‘tag’).
- Returns:
neighbour (Boolean) – True for the neighbour-order form.
- Raises:
TypeError – Parameter list_hop must be a list of dictionaries.
ValueError – list_hop mixes the two forms.
- tbkit.error_handling.set_hopping_neighbours(list_hop, spin=False)[source]#
Check the neighbour-order form of KSpace.set_hopping.
- Raises:
KeyError – “n” and “t” must be keys, and only “ang” and “tag” may be added.
TypeError – “n” must be an integer, “t” a number (or, if spin, a 2x2 matrix) or a value function, “ang” a real number and “tag” a string.
ValueError – “n” must be positive, “ang” in [-180, 180), “tag” of length 2.
- tbkit.error_handling.shell_angle(ang, angles)[source]#
Check that a neighbour shell has bonds along the angle ang (in degrees, either orientation: angles are those in [0, 180)).
- Raises:
ValueError – No bond of the shell points along ang.
- tbkit.error_handling.not_orbital_system(sys, orbital_cls)[source]#
Check that a System is not an OrbitalSystem (several rows per site).
- Raises:
TypeError – An OrbitalSystem is not supported.
- tbkit.error_handling.lattice_sites(matches)[source]#
Check that every site of a finite lattice is a copy of exactly one orbital of unit_cell, translated by a lattice vector (matches: the number of such orbitals, per site).
- Raises:
ValueError – A site is not on the periodic lattice.
- tbkit.error_handling.translation_invariant(dev, tol)[source]#
Check that equivalent matrix elements (same orbitals, same lattice vector) are equal in every cell, within tol.
- Raises:
ValueError – The model is not translation invariant.
- tbkit.error_handling.torus_range(R, sizes)[source]#
Check that the lattice vectors of a torus’s bonds (shortest images, in [-N/2, N/2)) are unambiguous: at least 3 cells along every direction, and no bond reaching half-way around.
- Raises:
ValueError – The torus is too small for the range of the model.
- tbkit.error_handling.saveable_model(model, lattice_cls, system_cls, kspace_cls, orbital_cls)[source]#
Check that tbkit.io.save_model can store model.
- Raises:
TypeError – model must be a Lattice, System or KSpace instance (not an OrbitalSystem).
- tbkit.error_handling.file_path(path, var_name)[source]#
Check a file name.
- Raises:
TypeError – Parameter var_name must be a string or a path.
- tbkit.error_handling.model_archive(data, fmt, version)[source]#
Check an archive read by tbkit.io.load_model.
- Raises:
ValueError – Not a tbkit model archive, or a newer version.
- tbkit.error_handling.hr_header(tokens)[source]#
Check the header of a Wannier90
_hr.datfile: num_wann, nrpts and the nrpts degeneracy weights, as positive integers.- Raises:
ValueError – Not a Wannier90 _hr.dat file.
- tbkit.error_handling.hr_body(n_tokens, nrpts, num_wann)[source]#
Check the number of entries of a Wannier90
_hr.datfile.- Raises:
ValueError – The file must have nrpts * num_wann**2 lines of 7 numbers.
- tbkit.error_handling.hr_blocks(ok)[source]#
Check that the lines of a
_hr.datfile come in blocks of num_wann**2 with the same lattice vector.- Raises:
ValueError – Lines of a lattice vector must be consecutive.
- tbkit.error_handling.win_block(found)[source]#
Check that a
.winfile has aunit_cell_cartblock.- Raises:
ValueError – No unit_cell_cart block.
- tbkit.error_handling.win_cell(cell)[source]#
Check the
unit_cell_cartblock of a.winfile: three lines of three real numbers.- Raises:
ValueError – unit_cell_cart must hold three vectors of three numbers.
- tbkit.error_handling.centres_count(n, num_wann)[source]#
Check that a
_centres.xyzfile lists num_wann Wannier centres (X).- Raises:
ValueError – Too few Wannier centres.
- tbkit.error_handling.wannier_dim(dim)[source]#
Check the dimension of a Wannier90 model.
- Raises:
ValueError – dim must be 2 or 3.
- tbkit.error_handling.win_given(win)[source]#
Check that the lattice vectors can be found.
- Raises:
ValueError – Give prim_vec or win.
- tbkit.error_handling.layer_cell(cell, dim)[source]#
Check that, for a 2D model, a1 and a2 lie in the (x, y) plane.
- Raises:
ValueError – a1 and a2 must have no z component.
- tbkit.error_handling.wannier_prim_vec(prim_vec, dim)[source]#
Check that the primitive vectors are dim vectors of dim components.
- Raises:
ValueError – prim_vec must hold dim vectors of dim components.
- tbkit.error_handling.wannier_positions(shape, num_wann, dim)[source]#
Check the orbital positions of a Wannier90 model.
- Raises:
ValueError – positions must have shape (num_wann, dim) or (num_wann, 3).
- tbkit.error_handling.wannier_tags(tags, num_wann)[source]#
Check the sublattice tags of a Wannier90 model.
- Raises:
TypeError – tags must be a list of one-character strings.
ValueError – tags must have num_wann elements.
- tbkit.error_handling.layer_hoppings(h_max, tol)[source]#
Check that a 2D model has no hopping between layers (R3 != 0).
- Raises:
ValueError – Hoppings with R3 != 0 must vanish for dim=2.
- tbkit.error_handling.spinless(spin)[source]#
Check that a KSpace model has no spin.
- Raises:
ValueError – This needs a spinless model.
- tbkit.error_handling.wannier_gap(nu, sector, tol=0.0001)[source]#
Check that a Wannier sector is separated from the other Wannier bands over the mesh (nu, shape (n1, n2, nb), sorted at each k): at every k, the smallest distance on the circle between a Wannier band of the sector and one outside it (the Wannier gap) exceeds tol, and the Wannier bands of the sector change between neighbouring k-points by less than the smallest gap (otherwise two Wannier bands crossed between them, or the sector wrapped around the circle).
- Raises:
ValueError – The Wannier sector is not separated by a Wannier gap.
- tbkit.error_handling.supercell_matrix(mat, dim)[source]#
Check a supercell matrix: integers, shape (dim, dim), nonzero determinant.
- Raises:
TypeError – The supercell matrix must contain integers.
ValueError – The supercell matrix must be (dim, dim), with a nonzero determinant.
- tbkit.error_handling.supercell_model(sc, cls)[source]#
Check that sc is a supercell (made by moire.supercell).
- Raises:
TypeError – Parameter sc must be a SupercellKSpace instance.
- tbkit.error_handling.bond_vectors(d)[source]#
Check bond vectors: shape (n, 3), none of zero length.
- Raises:
ValueError – Bond vectors must have the shape (n, 3) and a nonzero length.
- tbkit.error_handling.twist_lattice(lattice)[source]#
Check the layer lattice of a twisted bilayer.
- Raises:
ValueError – Parameter lattice must be “honeycomb” or “square”.
- tbkit.error_handling.commensurate(moire_1, moire_2)[source]#
Check that the moire vectors of the two layers coincide.
- Raises:
ValueError – The two layers do not share the moire cell.
- tbkit.error_handling.hopping_values(t, n)[source]#
Check the output of a hopping function: n values.
- Raises:
ValueError – The hopping function must return one value per bond vector.
- tbkit.error_handling.even_dimension(n)[source]#
Check that a spinful matrix has an even dimension (two spins per site).
- Raises:
ValueError – A spinful Hamiltonian must have an even dimension.
- tbkit.error_handling.magnetization(mag, n)[source]#
Check initial moments: a real array of shape (n, 3).
- Raises:
ValueError – Parameter magnetization must have the shape (n, 3).
- tbkit.error_handling.interaction(V, n)[source]#
Check an attractive interaction: a positive number, or n non-negative numbers.
- Raises:
ValueError – The interaction must be positive (or n non-negative values).
- tbkit.error_handling.pairing_amplitudes(delta, n)[source]#
Check initial pairing amplitudes: a number, or n numbers.
- Raises:
ValueError – Parameter delta0 must be a number or n numbers.
- tbkit.error_handling.frequencies(omega, var_name)[source]#
Check photon energies (or energies): a real number, or a non-empty array of finite real numbers.
- Raises:
TypeError – Parameter must be a real number or an array of real numbers.
ValueError – Parameter must contain at least one finite number.
- tbkit.error_handling.tensor_component(component, order)[source]#
Check a Cartesian tensor component of a 2D response: a string of order letters among ‘x’ and ‘y’. Returns the axis indices.
- Raises:
TypeError – Parameter component must be a string.
ValueError – Parameter component must have order letters among x, y.
- tbkit.error_handling.band_derivatives(en, vel, w)[source]#
Check the band energies (nk, n), velocities (2, nk, n, n) and second derivatives (2, 2, nk, n, n) of optics.generalized_derivative.
- Raises:
ValueError – Inconsistent shapes.
- tbkit.error_handling.lead_pair(pair, n_leads, var_name, distinct)[source]#
Check a pair of lead indices (and, with distinct, that they differ).
- Raises:
TypeError – Parameter must be a tuple/list of two lead indices.
ValueError – No such lead, or the two leads must differ.
- tbkit.error_handling.site_positions(positions, n_sites)[source]#
Check site positions: a real array of shape (n_sites, d).
- Raises:
ValueError – Parameter positions must have shape (n_sites, d).
- tbkit.error_handling.slices(slices, n_sites)[source]#
Check a partition of the device sites into non-empty slices.
- Raises:
TypeError – Parameter slices must be a list of lists of integers.
ValueError – The slices must contain every site exactly once.
- tbkit.error_handling.block_tridiagonal(max_distance)[source]#
Check that hoppings only couple a slice to itself or to its neighbours.
- Raises:
ValueError – Hoppings must connect neighbouring slices only.
- tbkit.error_handling.lead_tuple(lead)[source]#
Check a lead given as a tuple (h0, v, coupling).
- Raises:
TypeError – A lead must be a tuple (h0, v, coupling).
- tbkit.error_handling.hermitian_operator(ops, tol=1e-10)[source]#
Check that an operator (shape (…, norb, norb)) is Hermitian.
- Raises:
ValueError – The operator must be Hermitian.
- tbkit.error_handling.projected_gap(w, tol=1e-06)[source]#
Check that the projected operator POP (eigenvalues w, shape (nk, n), sorted) has no eigenvalue near zero, and the same number of negative eigenvalues at every k-point; return that number.
- Raises:
ValueError – The spectrum of POP must have a gap around zero.
- tbkit.error_handling.mirror_square(squares, tol)[source]#
Check that a mirror operator squares to +1 or -1 (squares, shape (…, norb, norb)); return the sign.
- Raises:
ValueError – The mirror operator must square to +1 or -1.
- tbkit.error_handling.commutes(err, tol)[source]#
Check that an operator commutes with H(k) on the plane (err: largest entry of the commutator).
- Raises:
ValueError – The operator does not commute with H(k) on this plane.
- tbkit.error_handling.strong_index(strong)[source]#
Check that the strong Z2 index comes out the same from the three pairs of time-reversal-invariant planes.
- Raises:
ValueError – The six Z2 invariants are inconsistent.
- tbkit.error_handling.region(region, n)[source]#
Check a region: a non-empty list of distinct indices between 0 and n-1.
- Raises:
TypeError – Parameter region must be a non-empty list of integers.
ValueError – Parameter region must hold distinct indices between 0 and n-1.
- tbkit.error_handling.torus_cell(cell, d)[source]#
Check the two vectors spanning a torus: shape (2, d), linearly independent.
- Raises:
ValueError – Parameter cell must hold two independent vectors of d components.
- tbkit.error_handling.band_below_top(n, norb)[source]#
Check that a band has a band above it.
- Raises:
ValueError – The highest band of bands must not be the top band.
- tbkit.error_handling.antisymmetric(a, tol=1e-10)[source]#
Check that a matrix is antisymmetric.
- Raises:
ValueError – The matrix must be antisymmetric.
- tbkit.error_handling.bdg_orbitals(norb)[source]#
Check that a BdG model has an even number of orbitals (particles, then holes).
- Raises:
ValueError – A BdG model must have an even number of orbitals.
- tbkit.error_handling.majorana_form(a, tol=1e-08)[source]#
Check that the Majorana form -i U H U^dagger of a BdG Hamiltonian at a time-reversal-invariant momentum is real (particle-hole symmetry).
- Raises:
ValueError – The model is not particle-hole symmetric.
- tbkit.error_handling.gapped_trim(pf, tol=1e-12)[source]#
Check that a Pfaffian is nonzero (the BdG gap is open at the momentum).
- Raises:
ValueError – The gap closes at a time-reversal-invariant momentum.
- tbkit.error_handling.periodic(periodic, dim)[source]#
Check parameter periodic of System: a boolean, or a tuple of dim booleans (one per primitive vector); return the tuple.
- Raises:
TypeError – Parameter periodic must be a bool or a tuple of bools.
ValueError – Parameter periodic must have one entry per primitive vector.
- tbkit.error_handling.torus_lattice(n1)[source]#
Check that the lattice of a periodic System comes from get_lattice.
- Raises:
ValueError – Periodic boundaries need lat.get_lattice first.
- tbkit.error_handling.torus_size(dist, period, n)[source]#
Check that bonds of length dist (order n) reach less than half-way around the torus (shortest period period), so that each one has a single shortest image.
- Raises:
ValueError – The torus is too small for this neighbour order.
- tbkit.error_handling.not_periodic(periodic, method)[source]#
Check that a System has open boundaries.
- Raises:
ValueError – The method needs open boundaries.
- tbkit.error_handling.torus_2d(periodic)[source]#
Check that a System is a 2D torus (periodic along two primitive vectors).
- Raises:
ValueError – This calculation needs a 2D lattice periodic along both vectors.
- tbkit.error_handling.projector(proj, norb, tags)[source]#
Check parameter projector of kspace.band_weights: an orbital index, a non-empty list of distinct orbital indices, a sublattice tag, or a (norb, norb) Hermitian matrix.
- Raises:
TypeError – Parameter projector must be an orbital index, a list of them, a tag or a matrix.
ValueError – Orbital indices must be distinct and between 0 and norb-1.
ValueError – Parameter projector must be a tag of the unit cell.
ValueError – The operator must be a (norb, norb) Hermitian matrix.
- tbkit.error_handling.band_weights(weights, shape)[source]#
Check parameter weights of kspace.plot_bands: real values, one per band and k-point of the stored band structure.
- Raises:
ValueError – Parameter weights must be a real array of the shape of the bands.
- tbkit.error_handling.weight_style(style)[source]#
Check parameter style of kspace.plot_bands.
- Raises:
ValueError – Parameter style must be “color” or “size”.
- tbkit.error_handling.contour_found(n_elements, energy)[source]#
Check that a band crosses the energy of a constant-energy contour.
- Raises:
ValueError – The band does not cross the energy.
- tbkit.error_handling.cubic_path(points, names, axes)[source]#
Check the parameters of kspace.cubic_path.
- Raises:
TypeError – Parameter points must be a dictionary.
ValueError – Each point must have 3 real coordinates.
ValueError – Parameter names must list at least two keys of points.
ValueError – Parameter axes must be 3 orthonormal rows.
- tbkit.error_handling.bravais_lattice(kind, dim)[source]#
Check that kspace.high_symmetry_path recognized the Bravais lattice.
- Raises:
ValueError – No standard path for this lattice.
- tbkit.error_handling.sympy_module(module)[source]#
Check that sympy, the optional dependency of tbkit.continuum, is installed.
- Raises:
ImportError – sympy is not installed.
- tbkit.error_handling.continuum_type(ham, types)[source]#
Check the type of the Hamiltonian of continuum.discretize.
- Raises:
TypeError – The Hamiltonian must be a string, a sympy expression or a sympy Matrix.
- tbkit.error_handling.continuum_parsed(error, string)[source]#
Check that the string Hamiltonian of continuum.discretize was parsed.
- Raises:
ValueError – The string is not a valid expression.
- tbkit.error_handling.continuum_square(shape)[source]#
Check that the Hamiltonian of continuum.discretize is a square matrix.
- Raises:
ValueError – The Hamiltonian must be a square matrix.
- tbkit.error_handling.continuum_symbols(names)[source]#
Check the free symbols of the Hamiltonian of continuum.discretize: no position (the model is translation invariant), no symbol named like the grid spacing a, and parameter names that can be passed as keyword arguments.
- Raises:
ValueError – x, y, z are not supported.
ValueError – a is reserved for the grid spacing.
ValueError – Parameter names must be Python identifiers.
- tbkit.error_handling.continuum_dim(dim, used)[source]#
Check the dimension of continuum.discretize, given the momenta k_x, k_y, k_z (axes 0, 1, 2) used by the Hamiltonian.
- Raises:
TypeError – Parameter dim must be an integer.
ValueError – Parameter dim must be 1, 2 or 3.
ValueError – The Hamiltonian uses a momentum beyond dim.
- tbkit.error_handling.continuum_polynomial(entry, is_polynomial)[source]#
Check that a matrix element of continuum.discretize is a polynomial in the momenta.
- Raises:
ValueError – The Hamiltonian must be a polynomial in k_x, k_y, k_z.
- tbkit.error_handling.continuum_tags(tags, norb)[source]#
Check the orbital tags of continuum.discretize.
- Raises:
ValueError – More than 52 orbitals need explicit tags.
TypeError – Parameter tags must be a string or a list of strings.
ValueError – Parameter tags must hold one one-character tag per orbital.
- tbkit.error_handling.continuum_spacing(a)[source]#
Check the grid spacing of continuum.discretize: a Lattice refuses primitive vectors whose squared norm is below 0.1.
- Raises:
ValueError – Parameter a must be at least sqrt(0.1).
- tbkit.error_handling.trial_orbitals(trial, norb, n_bands)[source]#
Check the trial orbitals of wannier.wannierize: a list of orbital indices, or an array of shape (norb, n_wann), with at most n_bands trial orbitals (one per Wannier function; fewer than the bands disentangles them).
- Raises:
TypeError – Parameter trial must be a list of orbital indices or an array.
ValueError – Parameter trial must hold between 1 and n_bands trial orbitals.
- tbkit.error_handling.energy_window(window, var_name)[source]#
Check an energy window of wannier.wannierize: a tuple of two increasing real numbers.
- Raises:
TypeError – Parameter var_name must be a tuple of two real numbers.
ValueError – Parameter var_name must be increasing.
- tbkit.error_handling.frozen_window(frozen, window)[source]#
Check that the frozen (inner) window of wannier.wannierize lies inside the outer window.
- Raises:
ValueError – The frozen window must lie inside the outer window.
- tbkit.error_handling.window_states(n_inside, n_frozen, n_wann)[source]#
Check the number of states of the disentanglement windows at every k-point: at least n_wann in the outer window, at most n_wann in the frozen window.
- Raises:
ValueError – The outer window holds fewer than n_wann states at some k-point.
ValueError – The frozen window holds more than n_wann states at some k-point.
- tbkit.error_handling.isolated_bands(en, bands, tol=1e-08)[source]#
Check that a group of bands is separated in energy from the other bands at every point of the mesh (en, shape (nk, norb), sorted).
- Raises:
ValueError – The bands are not isolated.
- tbkit.error_handling.projection(s_min, tol=1e-10)[source]#
Check that the projection of the bands onto the trial orbitals has full rank at every k-point.
- Raises:
ValueError – The trial orbitals miss the bands at some k-point.
tbkit.optics module#
Linear and nonlinear optical response of 2D Bloch models (KSpace)
over a uniform Brillouin-zone mesh.
optical_conductivity()– the Kubo-Greenwood conductivity \(\sigma_{ab}(\omega)\), interband and intraband (Drude), with a broadening \(\eta\).joint_dos()– the joint density of states of vertical transitions.berry_curvature_dipole()– the Berry curvature dipole of the nonlinear Hall effect (Sodemann and Fu 2015).shift_current()– the shift-current conductivity \(\sigma^{abc}(0;\omega,-\omega)\) (Sipe and Shkrebtii 2000).
Every function works in units \(\hbar = e = 1\), energies (and \(\hbar\omega\)) in the units of the hoppings, lengths in those of prim_vec, and counts each orbital once: a spinless model gives the response per spin.
The velocities are the exact \(\partial H/\partial k_a\) of
KSpace._bloch_derivatives along the Cartesian axes \(x, y\) (for a 2D
lattice embedded in 3D space, the axes of KSpace.k_basis). With
positions=True (the default) the bond vectors include the orbital
positions, \(\mathbf{d} = \mathbf{R} + \boldsymbol\tau_j -
\boldsymbol\tau_i\), so that the velocity is the physical \(i[H,
\mathbf{r}]\) (see KSpace.hall_conductivity).
Examples
Example usage:
from tbkit.optics import optical_conductivity
omega = np.linspace(0.05, 3., 60)
sigma = optical_conductivity(graphene, omega, e_fermi=0., nk=300)
# Re sigma ~ pi/4 e^2/h per spin for hbar omega << t
- tbkit.optics.cell_area(ks: KSpace) float[source]#
Get the area \(A_c = |\mathbf{a}_1\times\mathbf{a}_2|\) of the unit cell of a 2D model (in the units of prim_vec), which turns a Brillouin-zone average into an integral: \(\int\frac{d^2k}{(2\pi)^2}g = \frac{1}{N_kA_c}\sum_{\mathbf{k}}g\).
- Parameters:
ks (*KSpace instance, 2D*)
- Returns:
area (Positive real)
- tbkit.optics.optical_conductivity(ks: KSpace, omega: float | ArrayLike, e_fermi: float = 0.0, temperature: float = 0.0, eta: float = 0.05, nk: int | tuple[int, int] = 100, component: str = 'xx', positions: bool = True) complex | NDArray[complex128][source]#
Get the optical conductivity \(\sigma_{ab}(\omega)\) of a 2D model from the Kubo-Greenwood formula over a uniform Brillouin-zone mesh,
\[\sigma_{ab}(\omega) = \frac{i e^2}{\hbar}\int\frac{d^2k}{(2\pi)^2} \sum_{n,m}\frac{f_n - f_m}{E_m - E_n}\, \frac{v^a_{nm}\,v^b_{mn}}{\hbar\omega + E_n - E_m + i\eta}\, ,\]with \(v^a_{nm} = \langle n|\partial H/\partial k_a|m\rangle\), \(f_n\) the Fermi-Dirac occupations at e_fermi and temperature, and \(\eta\) a phenomenological broadening (the inverse lifetime). Pairs of degenerate states, \(n = m\) included, enter through the limit \((f_n-f_m)/(E_m-E_n)\to-\partial f/\partial E\): the intraband (Drude) term \(\frac{i}{\hbar\omega+i\eta}\sum_n (-f'_n)v^a_{nn}v^b_{nn}\). It samples the Fermi surface only through the thermal window, so it needs a temperature larger than the level spacing of the mesh; at
temperature=0only the interband part is computed.It is the Ohm’s-law tensor, \(j_a = \sigma_{ab}E_b\). In a gap its static Hall part is the TKNN conductance: \(\sigma_{yx}(0) = -\sigma_{xy}(0)\) equals KSpace.hall_conductivity (which returns \(\sigma^{\mathrm{Ohm}}_{yx}\), see its docstring). The absorptive part obeys the f-sum rule \(\int_0^\infty\mathrm{Re}\,\sigma_{aa}\,d\omega = \frac{\pi e^2}{2\hbar^2}\int\frac{d^2k}{(2\pi)^2}\sum_n f_n\langle n|\partial_a^2H|n\rangle\). For graphene at neutrality, \(\mathrm{Re}\,\sigma_{xx} \to \frac{e^2}{16\hbar}\) per spin and valley for \(\eta \ll \hbar\omega \ll t\): the universal \(\sigma_0 = e^2/4\hbar\) once spin and valleys are counted, \(\pi/4\) in units of \(e^2/h\) for a spinless model.
- Parameters:
ks (*KSpace instance, 2D, Hermitian*)
omega (Real number or array of real numbers) – Photon energies \(\hbar\omega\).
e_fermi (Real number, default 0) – Fermi energy.
temperature (Positive real or zero) – Default value 0 (\(k_B = 1\)).
eta (Positive real, default 0.05) – Broadening, larger than the spacing of the transition energies on the mesh.
nk (Positive integer, or tuple of 2, default 100) – k-mesh.
component (‘xx’, ‘xy’, ‘yx’ or ‘yy’, default ‘xx’)
positions (Boolean, default True) – Orbital positions in the bond vectors (see KSpace.hall_conductivity).
- Returns:
sigma – Complex number (or ndarray shaped like omega), in units of \(e^2/h\).
- tbkit.optics.joint_dos(ks: KSpace, omega: float | ArrayLike, e_fermi: float = 0.0, temperature: float = 0.0, eta: float = 0.05, nk: int | tuple[int, int] = 100) float | NDArray[float64][source]#
Get the joint density of states of the vertical (interband) transitions, per unit cell,
\[J(\omega) = \frac{1}{N_k}\sum_{\mathbf{k}}\sum_{n\neq m} f_n\,(1 - f_m)\,\delta(\hbar\omega - E_m + E_n)\, ,\]with the delta function a Gaussian of standard deviation \(\eta\). Its integral over \(\omega\) is the number of (occupied, empty) pairs per k-point. For graphene at neutrality, \(J = A_c\,\hbar\omega/(4\pi\hbar^2 v_F^2)\) near the Dirac points (both valleys, per spin).
- Parameters:
ks (*KSpace instance, 2D, Hermitian*)
omega (Real number or array of real numbers) – Photon energies.
e_fermi (Real number, default 0)
temperature (Positive real or zero, default 0)
eta (Positive real, default 0.05) – Gaussian width.
nk (Positive integer, or tuple of 2, default 100)
- Returns:
jdos – Real number (or ndarray shaped like omega), in states per unit cell and per unit energy.
- tbkit.optics.berry_curvature_dipole(ks: KSpace, e_fermi: float | ArrayLike, temperature: float, nk: int | tuple[int, int] = 100, positions: bool = True) NDArray[float64][source]#
Get the Berry curvature dipole of a 2D model (Sodemann and Fu, Phys. Rev. Lett. 115, 216806 (2015)),
\[D_a = \int\frac{d^2k}{(2\pi)^2}\sum_n f_n\,\partial_a\Omega_n = \int\frac{d^2k}{(2\pi)^2}\sum_n \left(-\frac{\partial f}{\partial E}\right)_{E_n} v^a_{nn}\,\Omega_n\, ,\]the first moment of the Berry curvature \(\Omega_n\) (the convention of KSpace.berry_curvature and hall_conductivity, \(\Omega_n = -2\,\mathrm{Im}\sum_{m\neq n}v^x_{nm}v^y_{mn}/(E_n-E_m)^2\)) over the occupied states. It is a Fermi-surface property: the second form, used here, samples it through the thermal window \(-\partial f/\partial E\), so temperature must be positive and larger than the level spacing of the mesh near \(E_F\). A finite dipole needs broken inversion symmetry and a single mirror line at most. In a DC field it drives the nonlinear Hall current \(j_a = \chi_{abc}E_bE_c\), \(\chi_{abc} = -\varepsilon_{adc}\frac{e^3\tau}{2\hbar^2(1+i\omega\tau)}D_{bd}\), with \(D_{bd} = D_b\) along \(d = z\) in 2D.
For the tilted massive Dirac cone \(H = t k_x + v(k_x\sigma_x + k_y\sigma_y) + m\sigma_z\) doped into the conduction band (\(\mu > |m|\)), the first order in the tilt is \(D_x = -\frac{3\,t\,m\,(\mu^2 - m^2)}{8\pi\mu^4}\), \(D_y = 0\), from \(\Omega_c = -mv^2/2\varepsilon^3\) (Sodemann and Fu’s model, in these conventions).
- Parameters:
ks (*KSpace instance, 2D, Hermitian*)
e_fermi (Real number, or array of real numbers) – Fermi energies.
temperature (Positive real) – Temperature (\(k_B = 1\)).
nk (Positive integer, or tuple of 2, default 100)
positions (Boolean, default True) – See KSpace.hall_conductivity.
- Returns:
dipole – Real ndarray of shape (2,): \((D_x, D_y)\) (or
e_fermi.shape + (2,)), in units of length (of prim_vec).
- tbkit.optics.generalized_derivative(en: NDArray[float64], vel: NDArray[complex128], w: NDArray[complex128]) tuple[NDArray[complex128], NDArray[complex128]][source]#
Get the interband position matrix elements and their generalized derivatives from the band energies and the first and second derivatives of \(H\) in the eigenbasis (a sum over states, Sipe and Shkrebtii 2000; Cook et al. 2017; \(\hbar = 1\), \(\omega_{nm} = E_n - E_m\), \(\Delta^a_{nm} = v^a_{nn} - v^a_{mm}\)):
\[r^b_{nm} = \frac{v^b_{nm}}{i\omega_{nm}}\, ,\qquad r^b_{nm;a} = \frac{i}{\omega_{nm}}\left[ \frac{v^b_{nm}\Delta^a_{nm} + v^a_{nm}\Delta^b_{nm}}{\omega_{nm}} - w^{ba}_{nm} + \sum_{p\neq n,m}\left( \frac{v^b_{np}v^a_{pm}}{\omega_{pm}} - \frac{v^a_{np}v^b_{pm}}{\omega_{np}} \right)\right]\, ,\]\(r^b_{nm;a} = \partial_ar^b_{nm} - i(A^a_{nn} - A^a_{mm})r^b_{nm}\), gauge covariant. Degenerate pairs (\(|\omega_{nm}| < 10^{-9}\)) are set to zero, and dropped from the sum over \(p\).
- Parameters:
en (Real ndarray, shape (nk, n)) – Band energies.
vel (Complex ndarray, shape (2, nk, n, n)) – \(v^a_{nm}\).
w (Complex ndarray, shape (2, 2, nk, n, n)) – \(w^{ab}_{nm} = \langle n|\partial_a\partial_bH|m\rangle\).
- Returns:
r (Complex ndarray, shape (2, nk, n, n): r[b] is \(r^b_{nm}\))
r_der – Complex ndarray, shape (2, 2, nk, n, n): r_der[b, a] is \(r^b_{nm;a}\).
- tbkit.optics.shift_current(ks: KSpace, omega: float | ArrayLike, e_fermi: float = 0.0, temperature: float = 0.0, eta: float = 0.05, nk: int | tuple[int, int] = 100, component: str = 'xxx', positions: bool = True) float | NDArray[float64][source]#
Get the shift-current conductivity of a 2D model under linearly polarized light (Sipe and Shkrebtii, Phys. Rev. B 61, 5337 (2000)), \(j^a = 2\sigma^{abc}(0;\omega,-\omega)E^b(\omega)E^c(-\omega)\),
\[\sigma^{abc}(\omega) = -\frac{\pi e^3}{2\hbar^2}\int\frac{d^2k}{(2\pi)^2} \sum_{n,m}f_{nm}\,\mathrm{Im}\left[r^b_{mn}r^c_{nm;a} + r^c_{mn}r^b_{nm;a}\right]\delta(\omega_{mn} - \omega)\, ,\]\(f_{nm} = f_n - f_m\), with the position matrix elements \(r\) and their generalized derivatives from
generalized_derivative()(a sum over states, with the exact second derivatives of \(H\)). The delta function is a Gaussian of standard deviation \(\eta\). For \(b = c\), \(\mathrm{Im}[r^b_{mn}r^b_{nm;a}] = |r^b_{nm}|^2R^{a,b}_{nm}\) with \(R^{a,b}_{nm}\) the shift vector, the real-space displacement of the electron in the transition. It vanishes with inversion symmetry. Unlike the Hall conductance of full bands, it depends on where the orbitals sit in the cell (Ibanez-Azpiroz, Tsirkin and Souza, Phys. Rev. B 97, 245143 (2018)):positions=False, which puts them all at the cell origin, describes a different crystal.- Parameters:
ks (*KSpace instance, 2D, Hermitian, without overlap*)
omega (Real number or array of real numbers) – Photon energies \(\hbar\omega\).
e_fermi (Real number, default 0)
temperature (Positive real or zero, default 0)
eta (Positive real, default 0.05) – Gaussian width.
nk (Positive integer, or tuple of 2, default 100)
component – Three letters among ‘x’, ‘y’ (current direction, then the two field directions). Default value ‘xxx’.
positions (Boolean, default True) – See KSpace.hall_conductivity.
- Returns:
sigma – Real number (or ndarray shaped like omega), in units of \(e^3/\hbar\times\) length / energy (\(\hbar = e = 1\)), counting each orbital once.