Skip to content
Snippets Groups Projects
Commit 4035315d authored by Joseph Weston's avatar Joseph Weston
Browse files

add tutorial

parent 37f611b5
No related branches found
No related tags found
No related merge requests found
......@@ -217,6 +217,8 @@ In addition, the function passed as ``V`` expects two input parameters ``x``
and ``y``, the same as in the initial continuum Hamiltonian.
.. _discretize-bhz-model:
Models with more structure: Bernevig-Hughes-Zhang
.................................................
......
......@@ -12,4 +12,5 @@ Tutorial: learning Kwant through examples
plotting
kpm
discretize
magnetic_field
faq
Adding magnetic field
---------------------
Computing Landau levels in a harmonic oscillator basis
......................................................
When electrons move in an external magnetic field, their motion perpendicular
to the field direction is quantized into discrete Landau levels. Kwant implements
an efficient scheme for computing the Landau levels of arbitrary continuum
Hamiltonians. The general scheme revolves around rewriting the Hamiltonian in terms
of a basis of harmonic oscillator states [#]_, and is commonly illustrated in textbooks
for quadratic Hamiltonians.
To demonstrate the general scheme, let us consider a magnetic field oriented along
the :math:`z` direction :math:`\vec{B} = (0, 0, B)`, such that electron motion
in the :math:`xy` plane is Landau quantized. The magnetic field enters the Hamiltonian
through the kinetic momentum
.. math:: \hbar \vec{k} = - i \hbar \nabla + e\vec{A}(x, y).
In the symmetric gauge :math:`\vec{A}(x, y) = (B/2)[-y, x, 0]`, we introduce ladder
operators with the substitution
.. math::
k_x = \frac{1}{\sqrt{2} l_B} (a + a^\dagger), \quad \quad
k_y = \frac{1}{\sqrt{2} l_B} (a - a^\dagger),
with the magnetic length :math:`l_B = \sqrt{\hbar/eB}`. The ladder operators obey the
commutation relation
.. math:: [a, a^\dagger] = 1,
and define a quantum harmonic oscillator. We can thus write any electron continuum
Hamiltonian in terms of :math:`a` and :math:`a^\dagger`. Such a Hamiltonian has a
simple matrix representation in the eigenbasis of the number operator :math:`a^\dagger a`.
The eigenstates satisfy :math:`a^\dagger a | n \rangle = n | n \rangle` with the integer
Landau level index :math:`n \geq 0`, and in coordinate representation are proportional to
.. math::
\psi_n (x, y) = \left( \frac{\partial}{ \partial w} - \frac{w^*}{4 l_B^2} \right)
w^n e^{-|w|^2/4l_B^2},
with :math:`w = x + i y`. The matrix elements of the ladder operators are
.. math::
\langle n | a | m \rangle = \sqrt{m}~\delta_{n, m-1}, \quad \quad
\langle n | a^\dagger | m \rangle = \sqrt{m + 1}~\delta_{n, m+1}.
Truncating the basis to the first :math:`N` Landau levels allows us to approximate
the Hamiltonian as a discrete, finite matrix.
We can now formulate the algorithm that Kwant uses to compute Landau levels.
1. We take a generic continuum Hamiltonian, written in terms of the kinetic
momentum :math:`\vec{k}`. The Hamiltonian must be translationally
invariant along the directions perpendicular to the field direction.
2. We substitute the momenta perpendicular to the magnetic field with the ladder
operators :math:`a` and :math:`a^\dagger`.
3. We construct a `kwant.builder.Builder` using a special lattice which includes
the Landau level index :math:`n` as a degree of freedom on each site. The directions
normal to the field direction are not included in the builder, because they are
encoded in the Landau level index.
This procedure is automated with `kwant.continuum.discretize_landau`.
As an example, let us take the Bernevig-Hughes-Zhang model that we first considered in the
discretizer tutorial ":ref:`discretize-bhz-model`":
.. math::
C + M σ_0 \otimes σ_z + F(k_x^2 + k_y^2) σ_0 \otimes σ_z + D(k_x^2 + k_y^2) σ_0 \otimes σ_0
+ A k_x σ_z \otimes σ_x + A k_y σ_0 \otimes σ_y.
We can discretize this Hamiltonian in a basis of Landau levels as follows
.. jupyter-execute::
import numpy as np
import scipy.linalg
from matplotlib import pyplot
import kwant
import kwant.continuum
.. jupyter-execute:: boilerplate.py
:hide-code:
.. jupyter-execute::
hamiltonian = """
+ C * identity(4) + M * kron(sigma_0, sigma_z)
- F * (k_x**2 + k_y**2) * kron(sigma_0, sigma_z)
- D * (k_x**2 + k_y**2) * kron(sigma_0, sigma_0)
+ A * k_x * kron(sigma_z, sigma_x)
- A * k_y * kron(sigma_0, sigma_y)
"""
syst = kwant.continuum.discretize_landau(hamiltonian, N=10)
syst = syst.finalized()
We can then plot the spectrum of the system as a function of magnetic field, and
observe a crossing of Landau levels at finite magnetic field near zero energy,
characteristic of a quantum spin Hall insulator with band inversion.
.. jupyter-execute::
params = dict(A=3.645, F =-68.6, D=-51.2, M=-0.01, C=0)
b_values = np.linspace(0.0001, 0.0004, 200)
fig = kwant.plotter.spectrum(syst, ('B', b_values), params=params, show=False)
pyplot.ylim(-0.1, 0.2);
Comparing with tight-binding
============================
In the limit where fewer than one quantum of flux is threaded through a plaquette of
the discretization lattice we can compare the discretization in Landau levels with
a discretization in realspace.
.. jupyter-execute::
lat = kwant.lattice.square()
syst = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))
def peierls(to_site, from_site, B):
y = from_site.tag[1]
return -1 * np.exp(-1j * B * y)
syst[(lat(0, j) for j in range(-19, 20))] = 4
syst[lat.neighbors()] = -1
syst[kwant.HoppingKind((1, 0), lat)] = peierls
syst = syst.finalized()
landau_syst = kwant.continuum.discretize_landau("k_x**2 + k_y**2", N=5)
landau_syst = landau_syst.finalized()
Here we plot the dispersion relation for the discretized ribbon and compare it
with the Landau levels shown as dashed lines.
.. jupyter-execute::
fig, ax = pyplot.subplots(1, 1)
ax.set_xlabel("momentum")
ax.set_ylabel("energy")
ax.set_ylim(0, 1)
params = dict(B=0.1)
kwant.plotter.bands(syst, ax=ax, params=params)
h = landau_syst.hamiltonian_submatrix(params=params)
for ev in scipy.linalg.eigvals(h):
ax.axhline(ev, linestyle='--')
The dispersion and the Landau levels diverge with increasing energy, because the real space
discretization of the ribbon gives a worse approximation to the dispersion at higher energies.
Discretizing 3D models
======================
Although the preceding examples have only included the plane perpendicular to the
magnetic field, the Landau level quantization also works if the direction
parallel to the field is included. In fact, although the system must be
translationally invariant in the plane perpendicular to the field, the system may
be arbitrary along the parallel direction. For example, it is therefore possible to
model a heterostructure and/or set up a scattering problem along the field direction.
Let's say that we wish to to model a heterostructure with a varying potential
:math:`V` along the direction of a magnetic field, :math:`z`, that includes
Zeeman splitting and Rashba spin-orbit coupling:
.. math::
\frac{\hbar^2}{2m}\sigma_0(k_x^2 + k_y^2 + k_z^2)
+ V(z)\sigma_0
+ \frac{\mu_B B}{2}\sigma_z
+ \hbar\alpha(\sigma_x k_y - \sigma_y k_x).
We can discretize this Hamiltonian in a basis of Landau levels as before:
.. jupyter-execute::
continuum_hamiltonian = """
(k_x**2 + k_y**2 + k_z**2) * sigma_0
+ V(z) * sigma_0
+ mu * B * sigma_z / 2
+ alpha * (sigma_x * k_y - sigma_y * k_x)
"""
template = kwant.continuum.discretize_landau(continuum_hamiltonian, N=10)
This creates a system with a single translational symmetry, along
the :math:`z` direction, which we can use as a template
to construct our heterostructure:
.. jupyter-execute::
def hetero_structure(site):
z, = site.pos
return 0 <= z < 10
def hetero_potential(z):
if z < 2:
return 0
elif z < 7:
return 0.5
else:
return 0.7
syst = kwant.Builder()
syst.fill(template, hetero_structure, (0,))
syst = syst.finalized()
params = dict(
B=0.5,
mu=0.2,
alpha=0.4,
V=hetero_potential,
)
syst.hamiltonian_submatrix(params=params);
.. rubric:: Footnotes
.. [#] `Wikipedia <https://en.wikipedia.org/wiki/Landau_quantization>`_ has
a nice introduction to Landau quantization.
\ No newline at end of file
%% Cell type:code id: tags:
``` python
import numpy as np
import sympy
import operator
import inspect
import itertools
import functools
from copy import deepcopy
import kwant
import kwant.continuum
```
%% Output
/home/tinkerer/kwant/kwant/solvers/default.py:18: RuntimeWarning: MUMPS is not available, SciPy built-in solver will be used as a fallback. Performance can be very poor in this case.
"Performance can be very poor in this case.", RuntimeWarning)
%% Cell type:code id: tags:
``` python
%matplotlib inline
import sympy
import matplotlib.pyplot as plt
sympy.init_printing(print_builtin=True)
```
%% Cell type:code id: tags:
``` python
from kwant.continuum import landau_levels
```
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
builder = kwant.continuum.discretize('k_x**2 + k_y**2 + V(x, y) + sqrt(B)')
```
%% Cell type:code id: tags:
``` python
print(builder)
```
%% Output
# Discrete coordinates: x y
# Onsite element:
def onsite(site, B, V):
(x, y, ) = site.pos
_const_0 = (V(x, y))
return (B**(1/2) + _const_0 + 4.0)
# Hopping from (1, 0):
(-1+0j)
# Hopping from (0, 1):
(-1+0j)
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
a_dag = sympy.symbols('a^\dagger')
```
%% Cell type:code id: tags:
``` python
a_dag
```
%% Output
$$a^\dagger$$
a__\dagger
%% Cell type:code id: tags:
``` python
chain = kwant.lattice.chain()
```
%% Cell type:code id: tags:
``` python
type(chain(1))
```
%% Output
kwant.builder.Site
%% Cell type:code id: tags:
``` python
chain(2)
```
%% Output
Site(kwant.lattice.Monatomic([[1.0]], [0.0], '', None), array([2]))
%% Cell type:code id: tags:
``` python
kwant.builder.Site(chain, (1,))
```
%% Output
Site(kwant.lattice.Monatomic([[1.0]], [0.0], '', None), array([1]))
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
s = kwant.builder.Site(chain, (40,)) # Second argument is the tag, for the chain its the position.
```
%% Cell type:code id: tags:
``` python
s.pos
```
%% Output
array([40.0])
%% Cell type:code id: tags:
``` python
kwant.builder.Site?
```
%% Output
%% Cell type:code id: tags:
``` python
chain?
```
%% Output
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
H1 = "k_x**2 + 10*k_y**2"
H2 = "t_1*k_x**2 + t_2*k_y**2 + t_3*k_z**2"
H3 = "sigma_z*k_x**2 + 10*sigma_x*k_y**2"
```
%% Cell type:code id: tags:
``` python
ll = landau_levels.ll_hamiltonian(H3)
```
%% Cell type:code id: tags:
``` python
ll.monomials
```
%% Output
$$\left \{ k_{x}^{2} : \left[\begin{matrix}1 & 0\\0 & -1\end{matrix}\right], \quad k_{y}^{2} : \left[\begin{matrix}0 & 10\\10 & 0\end{matrix}\right]\right \}$$
⎧ 2 ⎡1 0 ⎤ 2 ⎡0 10⎤⎫
⎨kₓ : ⎢ ⎥, k_y : ⎢ ⎥⎬
⎩ ⎣0 -1⎦ ⎣10 0 ⎦⎭
%% Cell type:code id: tags:
``` python
ll.normal_coordinate == None
```
%% Output
True
%% Cell type:code id: tags:
``` python
ll.set_ll_momenta([1, 2])
```
%% Cell type:code id: tags:
``` python
ll.ll_momenta
```
%% Output
$$\left [ k_{y}, \quad k_{z}\right ]$$
[k_y, k_z]
%% Cell type:code id: tags:
``` python
ll.monomials
```
%% Output
$$\left \{ 1 : \left[\begin{matrix}k_{x}^{2} & 0\\0 & - k_{x}^{2}\end{matrix}\right], \quad k_{y}^{2} : \left[\begin{matrix}0 & 10\\10 & 0\end{matrix}\right]\right \}$$
⎧ ⎡ 2 ⎤ ⎫
⎪ ⎢kₓ 0 ⎥ 2 ⎡0 10⎤⎪
⎨1: ⎢ ⎥, k_y : ⎢ ⎥⎬
⎪ ⎢ 2⎥ ⎣10 0 ⎦⎪
⎩ ⎣ 0 -kₓ ⎦ ⎭
%% Cell type:code id: tags:
``` python
ll.normal_coordinate
```
%% Output
$$x$$
x
%% Cell type:code id: tags:
``` python
# ll.set_ll_momenta(['k_x', 'k_y'])
```
%% Cell type:code id: tags:
``` python
ll.normal_coordinate
```
%% Output
$$x$$
x
%% Cell type:code id: tags:
``` python
ll.monomials
```
%% Output
$$\left \{ 1 : \left[\begin{matrix}k_{x}^{2} & 0\\0 & - k_{x}^{2}\end{matrix}\right], \quad k_{y}^{2} : \left[\begin{matrix}0 & 10\\10 & 0\end{matrix}\right]\right \}$$
⎧ ⎡ 2 ⎤ ⎫
⎪ ⎢kₓ 0 ⎥ 2 ⎡0 10⎤⎪
⎨1: ⎢ ⎥, k_y : ⎢ ⎥⎬
⎪ ⎢ 2⎥ ⎣10 0 ⎦⎪
⎩ ⎣ 0 -kₓ ⎦ ⎭
%% Cell type:code id: tags:
``` python
ll.shape_func
```
%% Cell type:code id: tags:
``` python
N = 3
```
%% Cell type:code id: tags:
``` python
ham = ll.hamiltonian_matrix(N)
```
%% Cell type:code id: tags:
``` python
ll.monomials
```
%% Output
$$\left \{ 1 : \left[\begin{matrix}k_{x}^{2} & 0\\0 & - k_{x}^{2}\end{matrix}\right], \quad k_{y}^{2} : \left[\begin{matrix}0 & 10\\10 & 0\end{matrix}\right]\right \}$$
⎧ ⎡ 2 ⎤ ⎫
⎪ ⎢kₓ 0 ⎥ 2 ⎡0 10⎤⎪
⎨1: ⎢ ⎥, k_y : ⎢ ⎥⎬
⎪ ⎢ 2⎥ ⎣10 0 ⎦⎪
⎩ ⎣ 0 -kₓ ⎦ ⎭
%% Cell type:code id: tags:
``` python
params = dict(t_1 = 1, t_2 = 2, t_3 = 3, k_x=0)
```
%% Cell type:code id: tags:
``` python
ham(B=1, params=params).todense()
```
%% Output
matrix([[ 0. +0.j, 5. +0.j, 0. +0.j,
0. +0.j, 0. +0.j, 7.07106781+0.j],
[ 5. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 7.07106781+0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j,
15. +0.j, 0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 15. +0.j,
0. +0.j, 0. +0.j, 0. +0.j],
[ 0. +0.j, 7.07106781+0.j, 0. +0.j,
0. +0.j, 0. +0.j, 25. +0.j],
[ 7.07106781+0.j, 0. +0.j, 0. +0.j,
0. +0.j, 25. +0.j, 0. +0.j]])
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
H1 = "k_x**2 + 10*k_y**2"
H2 = "t_1*k_x**2 + t_2*k_y**2 + t_3*k_z**2"
H3 = "sigma_z*k_x**2 + 10*sigma_x*k_y**2"
```
%% Cell type:code id: tags:
``` python
N = 2
ham, monomials = ll_hamiltonian(H3, N, momenta=None)
```
%% Cell type:code id: tags:
``` python
ham
```
%% Output
<function kwant.continuum.landau_levels.combine.<locals>.final_wrapper(*, B, params=None)>
%% Cell type:code id: tags:
``` python
ham(B=1, params=dict(t_1=1, t_2=1, t_3=1)).todense()
```
%% Output
matrix([[ 0.5+0.j, 5. +0.j, 0. +0.j, 0. +0.j],
[ 5. +0.j, -0.5+0.j, 0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 1.5+0.j, 15. +0.j],
[ 0. +0.j, 0. +0.j, 15. +0.j, -1.5+0.j]])
%% Cell type:code id: tags:
``` python
monomials
```
%% Output
{k_x**2: <function __main__.ll_hamiltonian.<locals>.<lambda>.<locals>.<lambda>(params=None)>,
k_y**2: <function __main__.ll_hamiltonian.<locals>.<lambda>.<locals>.<lambda>(params=None)>}
%% Cell type:code id: tags:
``` python
funcs = list(monomials.values())
```
%% Cell type:code id: tags:
``` python
funcs[0]
```
%% Output
<function __main__.ll_hamiltonian.<locals>.<lambda>.<locals>.<lambda>(params=None)>
%% Cell type:code id: tags:
``` python
# funcs[0]().todense()
```
%% Cell type:code id: tags:
``` python
params = dict(t_1 = 1, t_2=1, t_3=1)
for key, value in monomials.items():
print(key, value(params=params).todense())
```
%% Output
k_x**2 [[ 1.+0.j 0.+0.j]
[ 0.+0.j -1.+0.j]]
k_y**2 [[ 0.+0.j 10.+0.j]
[10.+0.j 0.+0.j]]
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
f1 = lambda x, y=1, z=2: x*y + z
f2 = lambda l, y=1, z=2: l*y + z
```
%% Cell type:code id: tags:
``` python
funcs = [f1, f2]
```
%% Cell type:code id: tags:
``` python
combine(operator.add, funcs, args_names=None)
```
%% Output
<function __main__.combine.<locals>.final_wrapper(*, l, x, y=1, z=2)>
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
('N_1', None) == ('N_2', None)
```
%% Output
False
%% Cell type:code id: tags:
``` python
H = "k_x**2 + k_y**2 + k_z**2"
```
%% Cell type:code id: tags:
``` python
disc = kwant.continuum.discretize(H, coords=['y', 'z'])
```
%% Cell type:code id: tags:
``` python
disc
```
%% Output
<kwant.continuum.discretizer._DiscretizedBuilder at 0x7f8e4a178630>
%% Cell type:code id: tags:
``` python
for site in disc.sites():
print(site.pos)
```
%% Output
[0.0 0.0]
%% Cell type:code id: tags:
``` python
fsyst = disc.finalized()
```
%% Cell type:code id: tags:
``` python
fsyst.hamiltonian_submatrix()
```
%% Output
array([[ 2.+0.j, -1.-0.j],
[-1.+0.j, 2.+0.j]])
%% Cell type:code id: tags:
``` python
l = ['a', 'b', 'c', 'd']
inds = [0, 3]
```
%% Cell type:code id: tags:
``` python
```
%% Output
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-22-39657fc954cd> in <module>
----> 1 l[zip(*inds)]
TypeError: zip argument #1 must support iteration
%% Cell type:code id: tags:
``` python
```
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment