diff --git a/.gitignore b/.gitignore index 64f23822bf30e9700f24c185f626343d379dd239..7357693774aea277987ca67c03ecd729581debb1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ /build /dist /doc/build +/doc/source/tutorial/*.py /doc/source/reference/generated/ /doc/source/images/*.png /doc/source/images/*.pdf diff --git a/INSTALL.rst b/INSTALL.rst index 8fe4686dd04f742a21594ec6f885676af474769b..1b0a494f0927f1f781fb7bfa653caf02e24fb036 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -171,6 +171,24 @@ Because of some quirks of how Sphinx works, it might be necessary to execute done, Sphinx may mistakenly use PNG files for PDF output or other problems may appear. +When ``make html`` is run, modified tutorial example scripts are executed to +update any figures that might have changed. The machinery behind this works as +follows. The canonical source for a tutorial script, say ``graphene.py`` is +the file ``doc/source/images/graphene.py.diff``. This diff file contains the +information to recreate two versions of ``graphene.py``: a version that is +presented in the documentation (``doc/source/tutorial/graphene.py``), and a +version that is used to generate the figures for the documentation +(``doc/source/images/graphene.py``). Both versions are related but differ +e.g. in the details of the plotting. When ``make html`` is run, both versions +are extracted form the diff file. + +The diff file may be modified directly. Another possible way of working is to +directly modify either the tutorial script or the figure generation script. +Then ``make html`` will use the command line tool `wiggle +<http://neil.brown.name/wiggle/>`_ to propagate the modifications accordingly. +This will often just work, but may sometimes result in conflicts, in which case +a message will be printed. The conflicts then have to be resolved much like +with a version control system. **************************** Hints for specific platforms diff --git a/doc/Makefile b/doc/Makefile index 985a4ef95df64706afd9f2344c73f41fc4d99b88..8df4d59b00d3f81b876e8a3249cca7ddb5eab9c8 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -35,6 +35,7 @@ GENERATEDPDF = $(patsubst %.svg,%.pdf,$(IMAGESOURCES)) # deleting the corresponding flag file. SCRIPTS = $(patsubst source/images/%.diff,%,$(wildcard source/images/*.py.diff)) FLAGS = $(patsubst %.py,source/images/.%_flag,$(SCRIPTS)) +INCLUDES = $(patsubst %,source/tutorial/%,$(SCRIPTS)) .PHONY: help clean realclean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest @@ -59,37 +60,38 @@ clean: realclean: clean -rm -f $(FLAGS) + -rm -f $(INCLUDES) -rm -f $(patsubst %,source/images/%,$(SCRIPTS)) -rm -f $(patsubst %.py,source/images/%_*.png,$(SCRIPTS)) -rm -f $(patsubst %.py,source/images/%_*.pdf,$(SCRIPTS)) -html: $(FLAGS) +html: $(FLAGS) $(INCLUDES) $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." -dirhtml: $(FLAGS) +dirhtml: $(FLAGS) $(INCLUDES) $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." -pickle: $(FLAGS) +pickle: $(FLAGS) $(INCLUDES) $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." -json: $(FLAGS) +json: $(FLAGS) $(INCLUDES) $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." -htmlhelp: $(FLAGS) +htmlhelp: $(FLAGS) $(INCLUDES) $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." -qthelp: $(FLAGS) +qthelp: $(FLAGS) $(INCLUDES) $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ @@ -98,7 +100,7 @@ qthelp: $(FLAGS) @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/kwant.qhc" -latex: $(GENERATEDPDF) $(FLAGS) +latex: $(GENERATEDPDF) $(FLAGS) $(INCLUDES) $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @@ -124,19 +126,48 @@ doctest: %.pdf: %.svg rsvg-convert -f pdf -o $@ $< -# Make the image generation scripts by patching tutorial scipts. +# Make tutorial scripts by extracting the (complete!) context of the "patches". +# We make sure not to use 'wiggle' here. .SECONDARY: -%.py: %.py.diff - @grep -v '^#HIDDEN' source/tutorial/$(notdir $@) >$@ - @patch $@ $< - -# The image generation scripts depend on their unpatched originals +source/tutorial/%.py: source/images/%.py.diff + @sed -n '/^[- ]/ s/^.//p' <$< >$@ + @touch -r $< $@ + +# Make the image generation scripts by patching tutorial scripts. If the +# tutorial scripts haven't been modified, don't patch but directly extract the +# image generation scripts. This means that 'wiggle' is only needed when the +# tutorial scripts have been modified. +.SECONDARY: +source/images/%.py: source/tutorial/%.py + @if [ $< -nt $@.diff ]; then \ + cp $< $@; \ + rm -f $@.porig; \ + if ! wiggle --replace $@ $@.diff; then \ + command -v wiggle >/dev/null 2>&1 && \ + echo "Resolve conflicts by editing the files named below"; \ + touch -d@0 $@; \ + exit 1; \ + fi \ + else \ + sed -n '/^[+ ]/ s/^.//p' <$@.diff >$@; \ + touch -r $@.diff $@; \ + fi + +# Make the image generation scripts also depend on the diffs. define makedep -source/images/$(1): source/tutorial/$(1) +source/images/$(1): source/images/$(1).diff endef $(foreach name,$(SCRIPTS),$(eval $(call makedep,$(name)))) -# Generation of images -.%_flag: %.py +# Run an image generation script. When successful, and if the script is newer +# than the corresponding diff, recreate the latter. Note that the +# corresponding tutorial script cannot be newer, since if it is, the image +# generation script is generated from it by patching. +source/images/.%_flag: source/images/%.py cd $(dir $<) && python3 $(notdir $<) + @if [ ! -f $<.diff -o $< -nt $<.diff ]; then \ + wiggle --diff --lines source/tutorial/$(notdir $<) $< >$<.diff; \ + touch -r $< $<.diff; \ + fi + @rm -f $<.porig @touch $@ diff --git a/doc/source/images/ab_ring.py.diff b/doc/source/images/ab_ring.py.diff index ded6e1426f8aeba1694994b425b39ac9454bb541..50a10d1920c488552360b3bfc388d661da86d88f 100644 --- a/doc/source/images/ab_ring.py.diff +++ b/doc/source/images/ab_ring.py.diff @@ -1,6 +1,15 @@ ---- original -+++ modified -@@ -12,6 +12,7 @@ +@@ -1,127 +1,196 @@ + # Tutorial 2.3.3. Nontrivial shapes + # ================================= + # + # Physics background + # ------------------ + # Flux-dependent transmission through a quantum ring + # + # Kwant features highlighted + # -------------------------- + # - More complex shapes with lattices + # - Allows for discussion of subtleties of `attach_lead` (not in the # example, but in the tutorial main text) # - Modifcations of hoppings/sites after they have been added @@ -8,7 +17,79 @@ from cmath import exp from math import pi -@@ -81,6 +82,50 @@ + import kwant + + # For plotting + from matplotlib import pyplot + + + #HIDDEN_BEGIN_eusz + def make_system(a=1, t=1.0, W=10, r1=10, r2=20): + # Start with an empty tight-binding system and a single square lattice. + # `a` is the lattice constant (by default set to 1 for simplicity). + + lat = kwant.lattice.square(a) + + syst = kwant.Builder() + + #### Define the scattering region. #### + # Now, we aim for a more complex shape, namely a ring (or annulus) + def ring(pos): + (x, y) = pos + rsq = x ** 2 + y ** 2 + return (r1 ** 2 < rsq < r2 ** 2) + #HIDDEN_END_eusz + + # and add the corresponding lattice points using the `shape`-function + #HIDDEN_BEGIN_lcak + syst[lat.shape(ring, (0, r1 + 1))] = 4 * t + syst[lat.neighbors()] = -t + #HIDDEN_END_lcak + + # In order to introduce a flux through the ring, we introduce a phase on + # the hoppings on the line cut through one of the arms. Since we want to + # change the flux without modifying the Builder instance repeatedly, we + # define the modified hoppings as a function that takes the flux as its + # parameter phi. + #HIDDEN_BEGIN_lvkt + def hopping_phase(site1, site2, phi): + return -t * exp(1j * phi) + + def crosses_branchcut(hop): + ix0, iy0 = hop[0].tag + + # builder.HoppingKind with the argument (1, 0) below + # returns hoppings ordered as ((i+1, j), (i, j)) + return iy0 < 0 and ix0 == 1 # ix1 == 0 then implied + + # Modify only those hopings in x-direction that cross the branch cut + def hops_across_cut(syst): + for hop in kwant.builder.HoppingKind((1, 0), lat, lat)(syst): + if crosses_branchcut(hop): + yield hop + syst[hops_across_cut] = hopping_phase + #HIDDEN_END_lvkt + + #### Define the leads. #### + # left lead + #HIDDEN_BEGIN_qwgr + sym_lead = kwant.TranslationalSymmetry((-a, 0)) + lead = kwant.Builder(sym_lead) + + def lead_shape(pos): + (x, y) = pos + return (-W / 2 < y < W / 2) + + lead[lat.shape(lead_shape, (0, 0))] = 4 * t + lead[lat.neighbors()] = -t + #HIDDEN_END_qwgr + + #### Attach the leads and return the system. #### + #HIDDEN_BEGIN_skbz + syst.attach_lead(lead) + syst.attach_lead(lead.reversed()) + #HIDDEN_END_skbz + return syst @@ -59,7 +140,9 @@ def plot_conductance(syst, energy, fluxes): # compute conductance -@@ -90,18 +135,31 @@ + normalized_fluxes = [flux / (2 * pi) for flux in fluxes] + data = [] + for flux in fluxes: smatrix = kwant.smatrix(syst, energy, args=[flux]) data.append(smatrix.transmission(1, 0)) @@ -96,7 +179,9 @@ # Finalize the system. syst = syst.finalized() -@@ -111,6 +169,17 @@ + + # We should see a conductance that is periodic with the flux quantum + plot_conductance(syst, energy=0.15, fluxes=[0.01 * i * 3 * 2 * pi for i in range(100)]) @@ -114,3 +199,4 @@ # Call the main function if the script gets executed (as opposed to imported). # See <http://docs.python.org/library/__main__.html>. if __name__ == '__main__': + main() diff --git a/doc/source/images/band_structure.py.diff b/doc/source/images/band_structure.py.diff index 90d735445d34d33297a7a5532ff9b867892cb34b..8a2652072aea317f4a6e5090497c37b43afdef15 100644 --- a/doc/source/images/band_structure.py.diff +++ b/doc/source/images/band_structure.py.diff @@ -1,6 +1,12 @@ ---- original -+++ modified -@@ -9,6 +9,7 @@ +@@ -1,52 +1,62 @@ + # Tutorial 2.4.1. Band structure calculations + # =========================================== + # + # Physics background + # ------------------ + # band structure of a simple quantum wire in tight-binding approximation + # + # Kwant features highlighted # -------------------------- # - Computing the band structure of a finalized lead. @@ -8,8 +14,31 @@ import kwant # For plotting. -@@ -36,10 +37,19 @@ + from matplotlib import pyplot + #HIDDEN_BEGIN_zxip + def make_lead(a=1, t=1.0, W=10): + # Start with an empty lead with a single square lattice + lat = kwant.lattice.square(a) + + sym_lead = kwant.TranslationalSymmetry((-a, 0)) + lead = kwant.Builder(sym_lead) + + # build up one unit cell of the lead, and add the hoppings + # to the next unit cell + for j in range(W): + lead[lat(0, j)] = 4 * t + + if j > 0: + lead[lat(0, j), lat(0, j - 1)] = -t + + lead[lat(1, j), lat(0, j)] = -t + + return lead + #HIDDEN_END_zxip + + + #HIDDEN_BEGIN_pejz def main(): lead = make_lead().finalized() - kwant.plotter.bands(lead, show=False) @@ -29,6 +58,10 @@ + for extension in ('pdf', 'png'): + fig.savefig("band_structure_result." + extension, dpi=_defs.dpi) + + #HIDDEN_END_pejz # Call the main function if the script gets executed (as opposed to imported). + # See <http://docs.python.org/library/__main__.html>. + if __name__ == '__main__': + main() diff --git a/doc/source/images/closed_system.py.diff b/doc/source/images/closed_system.py.diff index e33c3c2c86340a909b0959b42fdece6138e86100..7f1de4715780c3c04f7ccf668301027617fff545 100644 --- a/doc/source/images/closed_system.py.diff +++ b/doc/source/images/closed_system.py.diff @@ -1,6 +1,14 @@ ---- original -+++ modified -@@ -11,6 +11,7 @@ +@@ -1,140 +1,157 @@ + # Tutorial 2.4.2. Closed systems + # ============================== + # + # Physics background + # ------------------ + # Fock-darwin spectrum of a quantum dot (energy spectrum in + # as a function of a magnetic field) + # + # Kwant features highlighted + # -------------------------- # - Use of `hamiltonian_submatrix` in order to obtain a Hamiltonian # matrix. @@ -8,7 +16,62 @@ from cmath import exp import numpy as np import kwant -@@ -68,24 +69,39 @@ + + # For eigenvalue computation + #HIDDEN_BEGIN_tibv + import scipy.sparse.linalg as sla + #HIDDEN_END_tibv + + # For plotting + from matplotlib import pyplot + + + def make_system(a=1, t=1.0, r=10): + # Start with an empty tight-binding system and a single square lattice. + # `a` is the lattice constant (by default set to 1 for simplicity). + + #HIDDEN_BEGIN_qlyd + lat = kwant.lattice.square(a, norbs=1) + + syst = kwant.Builder() + + # Define the quantum dot + def circle(pos): + (x, y) = pos + rsq = x ** 2 + y ** 2 + return rsq < r ** 2 + + def hopx(site1, site2, B=0): + # The magnetic field is controlled by the parameter B + y = site1.pos[1] + return -t * exp(-1j * B * y) + + syst[lat.shape(circle, (0, 0))] = 4 * t + # hoppings in x-direction + syst[kwant.builder.HoppingKind((1, 0), lat, lat)] = hopx + # hoppings in y-directions + syst[kwant.builder.HoppingKind((0, 1), lat, lat)] = -t + + # It's a closed system for a change, so no leads + return syst + #HIDDEN_END_qlyd + + + #HIDDEN_BEGIN_yvri + def plot_spectrum(syst, Bfields): + + # In the following, we compute the spectrum of the quantum dot + # using dense matrix methods. This works in this toy example, as + # the system is tiny. In a real example, one would want to use + # sparse matrix methods + + energies = [] + for B in Bfields: + # Obtain the Hamiltonian as a dense matrix + ham_mat = syst.hamiltonian_submatrix(args=[B], sparse=True) + + # we only calculate the 15 lowest eigenvalues + ev = sla.eigsh(ham_mat, k=15, which='SM', return_eigenvectors=False) energies.append(ev) @@ -29,8 +92,10 @@ + fig.subplots_adjust(left=0.15, right=0.95, top=0.95, bottom=0.15) + for extension in ('pdf', 'png'): + fig.savefig("closed_system_result." + extension, dpi=_defs.dpi) + #HIDDEN_END_yvri + #HIDDEN_BEGIN_wave def plot_wave_function(syst): + size = (_defs.figwidth_in, _defs.figwidth_in) + @@ -46,15 +111,17 @@ + syst, np.abs(evecs[:, 9])**2, colorbar=False, oversampling=1, + file="closed_system_eigenvector." + extension, + fig_size=size, dpi=_defs.dpi) + #HIDDEN_END_wave + #HIDDEN_BEGIN_current def plot_current(syst): + size = (_defs.figwidth_in, _defs.figwidth_in) + # Calculate the wave functions in the system. ham_mat = syst.hamiltonian_submatrix(sparse=True) evecs = sla.eigsh(ham_mat, k=20, which='SM')[1] -@@ -93,15 +109,16 @@ + # Calculate and plot the local current of the 10th eigenmode. J = kwant.operator.Current(syst) current = J(evecs[:, 9]) @@ -64,6 +131,7 @@ + syst, current, colorbar=False, + file="closed_system_current." + extension, + fig_size=size, dpi=_defs.dpi) + #HIDDEN_END_current def main(): @@ -75,3 +143,26 @@ # Finalize the system. syst = syst.finalized() + # The following try-clause can be removed once SciPy 0.9 becomes uncommon. + try: + # We should observe energy levels that flow towards Landau + # level energies with increasing magnetic field. + plot_spectrum(syst, [iB * 0.002 for iB in range(100)]) + + # Plot an eigenmode of a circular dot. Here we create a larger system for + # better spatial resolution. + syst = make_system(r=30).finalized() + plot_wave_function(syst) + plot_current(syst) + except ValueError as e: + if e.message == "Input matrix is not real-valued.": + print("The calculation of eigenvalues failed because of a bug in SciPy 0.9.") + print("Please upgrade to a newer version of SciPy.") + else: + raise + + + # Call the main function if the script gets executed (as opposed to imported). + # See <http://docs.python.org/library/__main__.html>. + if __name__ == '__main__': + main() diff --git a/doc/source/images/discretize.py.diff b/doc/source/images/discretize.py.diff index 7ac6dfe381a9289e7d0c1c7766222e0664e56a81..3d6c20249528f78846a946f1cd53d926f1db3c7c 100644 --- a/doc/source/images/discretize.py.diff +++ b/doc/source/images/discretize.py.diff @@ -1,6 +1,12 @@ ---- original -+++ modified -@@ -9,6 +9,7 @@ +@@ -1,222 +1,236 @@ + # Tutorial 2.9. Processing continuum Hamiltonians with discretize + # =============================================================== + # + # Physics background + # ------------------ + # - tight-binding approximation of continuous Hamiltonians + # + # Kwant features highlighted # -------------------------- # - kwant.continuum.discretize @@ -8,7 +14,11 @@ import kwant import scipy.sparse.linalg -@@ -20,10 +21,19 @@ + import scipy.linalg + import numpy as np + + # For plotting + import matplotlib as mpl from matplotlib import pyplot as plt @@ -21,34 +31,120 @@ + + def stadium_system(L=20, W=20): + #HIDDEN_BEGIN_template hamiltonian = "k_x**2 + k_y**2 + V(x, y)" template = kwant.continuum.discretize(hamiltonian) - print(template) + with open('discretizer_verbose.txt', 'w') as f: + print(template, file=f) + #HIDDEN_END_template + #HIDDEN_BEGIN_fill def stadium(site): (x, y) = site.pos -@@ -44,7 +54,7 @@ + x = max(abs(x) - 20, 0) + return x**2 + y**2 < 30**2 + + syst = kwant.Builder() + syst.fill(template, stadium, (0, 0)); + syst = syst.finalized() + #HIDDEN_END_fill + return syst + + + #HIDDEN_BEGIN_plot_eigenstate + def plot_eigenstate(syst, n=2, Vx=.0003, Vy=.0005): + + def potential(x, y): + return Vx * x + Vy * y + ham = syst.hamiltonian_submatrix(params=dict(V=potential), sparse=True) evecs = scipy.sparse.linalg.eigsh(ham, k=10, which='SM')[1] kwant.plotter.map(syst, abs(evecs[:, n])**2, show=False) + #HIDDEN_END_plot_eigenstate - plt.show() + save_figure('discretizer_gs') def qsh_system(a=20, L=2000, W=1000): -@@ -91,7 +101,8 @@ + #HIDDEN_BEGIN_define_qsh + hamiltonian = """ + + C * identity(4) + M * kron(sigma_0, sigma_z) + - B * (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) + """ + + template = kwant.continuum.discretize(hamiltonian, grid_spacing=a) + #HIDDEN_END_define_qsh + + #HIDDEN_BEGIN_define_qsh_build + def shape(site): + (x, y) = site.pos + return (0 <= y < W and 0 <= x < L) + + def lead_shape(site): + (x, y) = site.pos + return (0 <= y < W) + + syst = kwant.Builder() + syst.fill(template, shape, (0, 0)) + + lead = kwant.Builder(kwant.TranslationalSymmetry([-a, 0])) + lead.fill(template, lead_shape, (0, 0)) + + syst.attach_lead(lead) + syst.attach_lead(lead.reversed()) + + syst = syst.finalized() + #HIDDEN_END_define_qsh_build + return syst + + + def analyze_qsh(): + params = dict(A=3.65, B=-68.6, D=-51.1, M=-0.01, C=0) + syst = qsh_system() + + #HIDDEN_BEGIN_plot_qsh_band + kwant.plotter.bands(syst.leads[0], params=params, + momenta=np.linspace(-0.3, 0.3, 201), show=False) + #HIDDEN_END_plot_qsh_band + + plt.grid() + plt.xlim(-.3, 0.3) plt.ylim(-0.05, 0.05) plt.xlabel('momentum [1/A]') plt.ylabel('energy [eV]') - plt.show() + save_figure('discretizer_qsh_band') + #HIDDEN_BEGIN_plot_qsh_wf + # get scattering wave functions at E=0 wf = kwant.wave_function(syst, energy=0, params=params) -@@ -119,7 +130,7 @@ + # prepare density operators + sigma_z = np.array([[1, 0], [0, -1]]) + prob_density = kwant.operator.Density(syst, np.eye(4)) + spin_density = kwant.operator.Density(syst, np.kron(sigma_z, np.eye(2))) + + # calculate expectation values and plot them + wf_sqr = sum(prob_density(psi) for psi in wf(0)) # states from left lead + rho_sz = sum(spin_density(psi) for psi in wf(0)) # states from left lead + + fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(16, 4)) + kwant.plotter.map(syst, wf_sqr, ax=ax1) + kwant.plotter.map(syst, rho_sz, ax=ax2) + #HIDDEN_END_plot_qsh_wf + ax = ax1 + im = [obj for obj in ax.get_children() + if isinstance(obj, mpl.image.AxesImage)][0] + fig.colorbar(im, ax=ax) + + ax = ax2 + im = [obj for obj in ax.get_children() + if isinstance(obj, mpl.image.AxesImage)][0] + fig.colorbar(im, ax=ax) ax1.set_title('Probability density') ax2.set_title('Spin density') @@ -57,7 +153,46 @@ def lattice_spacing(): -@@ -160,7 +171,7 @@ + #HIDDEN_BEGIN_ls_def + hamiltonian = "k_x**2 * identity(2) + alpha * k_x * sigma_y" + params = dict(alpha=.5) + #HIDDEN_END_ls_def + + def plot(ax, a=1): + #HIDDEN_BEGIN_ls_hk_cont + h_k = kwant.continuum.lambdify(hamiltonian, locals=params) + k_cont = np.linspace(-4, 4, 201) + e_cont = [scipy.linalg.eigvalsh(h_k(k_x=ki)) for ki in k_cont] + #HIDDEN_END_ls_hk_cont + + #HIDDEN_BEGIN_ls_hk_tb + template = kwant.continuum.discretize(hamiltonian, grid_spacing=a) + syst = kwant.wraparound.wraparound(template).finalized() + + def h_k(k_x): + p = dict(k_x=k_x, **params) + return syst.hamiltonian_submatrix(params=p) + + k_tb = np.linspace(-np.pi/a, np.pi/a, 201) + e_tb = [scipy.linalg.eigvalsh(h_k(k_x=a*ki)) for ki in k_tb] + #HIDDEN_END_ls_hk_tb + + ax.plot(k_cont, e_cont, 'r-') + ax.plot(k_tb, e_tb, 'k-') + + ax.plot([], [], 'r-', label='continuum') + ax.plot([], [], 'k-', label='tight-binding') + + ax.set_xlim(-4, 4) + ax.set_ylim(-1, 14) + ax.set_title('a={}'.format(a)) + + ax.set_xlabel('momentum [a.u.]') + ax.set_ylabel('energy [a.u.]') + ax.grid() + ax.legend() + + _, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(12, 4)) plot(ax1, a=1) plot(ax2, a=.25) @@ -66,25 +201,45 @@ def substitutions(): -@@ -173,15 +184,18 @@ + #HIDDEN_BEGIN_subs_1 + sympify = kwant.continuum.sympify + subs = {'sx': [[0, 1], [1, 0]], 'sz': [[1, 0], [0, -1]]} + + e = ( + sympify('[[k_x**2, alpha * k_x], [k_x * alpha, -k_x**2]]'), + sympify('k_x**2 * sigma_z + alpha * k_x * sigma_x'), sympify('k_x**2 * sz + alpha * k_x * sx', locals=subs), ) - print(e[0] == e[1] == e[2]) + with open('discretizer_subs_1.txt', 'w') as f: + print(e[0] == e[1] == e[2], file=f) + #HIDDEN_END_subs_1 + #HIDDEN_BEGIN_subs_2 subs = {'A': 'A(x) + B', 'V': 'V(x) + V_0', 'C': 5} - print(sympify('k_x * A * k_x + V + C', locals=subs)) + with open('discretizer_subs_2.txt', 'w') as f: + print(sympify('k_x * A * k_x + V + C', locals=subs), file=f) + #HIDDEN_END_subs_2 def main(): + #HIDDEN_BEGIN_symbolic_discretization template = kwant.continuum.discretize('k_x * A(x) * k_x') - print(template) + with open('discretizer_intro_verbose.txt', 'w') as f: + print(template, file=f) + #HIDDEN_END_symbolic_discretization syst = stadium_system() plot_eigenstate(syst) + + analyze_qsh() + lattice_spacing() + substitutions() + + # Call the main function if the script gets executed (as opposed to imported). + # See <http://docs.python.org/library/__main__.html>. + if __name__ == '__main__': + main() diff --git a/doc/source/images/faq.py.diff b/doc/source/images/faq.py.diff index 4df4fd94bffa976cf028011428df2d4d1c19468d..7c8889dceec701572fde707e7c5aed3d5cf9f427 100644 --- a/doc/source/images/faq.py.diff +++ b/doc/source/images/faq.py.diff @@ -1,6 +1,6 @@ ---- original -+++ modified -@@ -3,6 +3,7 @@ +@@ -1,450 +1,479 @@ + # Frequently asked questions + # # This script is a disorganized collection of code snippets. As a whole, it is # not meant as an example of good programming practice. @@ -8,7 +8,8 @@ import kwant import numpy as np import tinyarray -@@ -11,6 +12,12 @@ + import matplotlib + from matplotlib import pyplot as plt matplotlib.rcParams['figure.figsize'] = (3.5, 3.5) @@ -20,32 +21,72 @@ + #### What is a Site? + #HIDDEN_BEGIN_site a = 1 -@@ -21,6 +28,7 @@ + lat = kwant.lattice.square(a) + syst = kwant.Builder() + + syst[lat(1, 0)] = 4 syst[lat(1, 1)] = 4 kwant.plot(syst) +save_figure("faq_site") + #HIDDEN_END_site #### What is a hopping? -@@ -34,6 +42,7 @@ + + a = 1 + lat = kwant.lattice.square(a) + syst = kwant.Builder() + + syst[lat(1, 0)] = 4 + syst[lat(1, 1)] = 4 + #HIDDEN_BEGIN_hopping syst[(lat(1, 0), lat(1, 1))] = 1j + #HIDDEN_END_hopping kwant.plot(syst) +save_figure("faq_hopping") #### What is a lattice? -@@ -50,6 +59,7 @@ + + #HIDDEN_BEGIN_lattice_monatomic + # Two monatomic lattices + primitive_vectors = [(1, 0), (0, 1)] + lat_a = kwant.lattice.Monatomic(primitive_vectors, offset=(0, 0)) + lat_b = kwant.lattice.Monatomic(primitive_vectors, offset=(0.5, 0.5)) + # lat1 is equivalent to kwant.lattice.square() + + syst = kwant.Builder() + + syst[lat_a(0, 0)] = 4 syst[lat_b(0, 0)] = 4 kwant.plot(syst) +save_figure("faq_lattice") + #HIDDEN_END_lattice_monatomic + #HIDDEN_BEGIN_lattice_polyatomic # One polyatomic lattice containing two sublattices lat = kwant.lattice.Polyatomic([(1, 0), (0, 1)], [(0, 0), (0.5, 0.5)]) -@@ -70,6 +80,7 @@ + sub_a, sub_b = lat.sublattices + #HIDDEN_END_lattice_polyatomic + + #### How to make a hole in a system? + + #HIDDEN_BEGIN_hole + # Define the lattice and the (empty) system + a = 2 + lat = kwant.lattice.cubic(a) + syst = kwant.Builder() + + L = 10 + W = 10 + H = 2 + + # Add sites to the system in a cuboid syst[(lat(i, j, k) for i in range(L) for j in range(W) for k in range(H))] = 4 kwant.plot(syst) @@ -53,47 +94,143 @@ # Delete sites to create a hole -@@ -81,6 +92,7 @@ + def in_hole(site): + x, y, z = site.pos / a - (L/2, W/2, H/2) # position relative to centre + return abs(x) < L / 4 and abs(y) < W / 4 + + for site in filter(in_hole, list(syst.sites())): del syst[site] kwant.plot(syst) +save_figure("faq_hole2") + #HIDDEN_END_hole #### How can we get access to the sites of our system? -@@ -127,7 +139,7 @@ + + builder = kwant.Builder() + lat = kwant.lattice.square() + builder[(lat(i, j) for i in range(3) for j in range(3))] = 4 + #HIDDEN_BEGIN_sites1 + # Before finalizing the system + + sites = list(builder.sites()) # sites() doe *not* return a list + #HIDDEN_END_sites1 + #HIDDEN_BEGIN_sites2 + # After finalizing the system + syst = builder.finalized() + sites = syst.sites # syst.sites is an actual list + #HIDDEN_END_sites2 + #HIDDEN_BEGIN_sites3 + i = syst.id_by_site[lat(0, 2)] # we want the id of the site lat(0, 2) + #HIDDEN_END_sites3 + + + #### How to plot a polyatomic lattice with different colors? + + #HIDDEN_BEGIN_colors1 + lat = kwant.lattice.kagome() + syst = kwant.Builder() + + a, b, c = lat.sublattices # The kagome lattice has 3 sublattices + #HIDDEN_END_colors1 + + #HIDDEN_BEGIN_colors2 + # Plot sites from different families in different colors + def family_color(site): + if site.family == a: + return 'red' + if site.family == b: + return 'green' + else: + return 'blue' + + def plot_system(syst): + kwant.plot(syst, site_lw=0.1, site_color=family_color) + + ## Add sites and hoppings. + for i in range(4): + for j in range (4): + syst[a(i, j)] = 4 + syst[b(i, j)] = 4 + syst[c(i, j)] = 4 + + syst[lat.neighbors()] = -1 ## Plot the system. plot_system(syst) -- +save_figure("faq_colors") + #HIDDEN_END_colors2 +- #### How to create all hoppings in a given direction using Hoppingkind? -@@ -141,6 +153,7 @@ + # Monatomic lattice + + #HIDDEN_BEGIN_direction1 + # Create hopping between neighbors with HoppingKind + a = 1 + syst = kwant.Builder() + lat = kwant.lattice.square(a) + syst[ (lat(i, j) for i in range(5) for j in range(5)) ] = 4 syst[kwant.builder.HoppingKind((1, 0), lat)] = -1 kwant.plot(syst) +save_figure("faq_direction1") + #HIDDEN_END_direction1 # Polyatomic lattice -@@ -171,12 +184,14 @@ + lat = kwant.lattice.kagome() + syst = kwant.Builder() + + a, b, c = lat.sublattices # The kagome lattice has 3 sublattices + + def family_color(site): + if site.family == a: + return 'red' + if site.family == b: + return 'green' + else: + return 'blue' + + def plot_system(syst): + kwant.plot(syst, site_size=0.15, site_lw=0.05, site_color=family_color) + + + for i in range(4): + for j in range (4): + syst[a(i, j)] = 4 + syst[b(i, j)] = 4 + syst[c(i, j)] = 4 + + + #HIDDEN_BEGIN_direction2 # equivalent to syst[kwant.builder.HoppingKind((0, 1), b)] = -1 syst[kwant.builder.HoppingKind((0, 1), b, b)] = -1 + #HIDDEN_END_direction2 plot_system(syst) +save_figure("faq_direction2") # Delete the hoppings previously created del syst[kwant.builder.HoppingKind((0, 1), b, b)] + #HIDDEN_BEGIN_direction3 syst[kwant.builder.HoppingKind((0, 0), a, b)] = -1 syst[kwant.builder.HoppingKind((0, 0), a, c)] = -1 syst[kwant.builder.HoppingKind((0, 0), c, b)] = -1 + #HIDDEN_END_direction3 plot_system(syst) +save_figure("faq_direction3") #### How to create the hoppings between adjacent sites? -@@ -190,11 +205,13 @@ + + # Monatomic lattice + + #HIDDEN_BEGIN_adjacent1 + # Create hoppings with lat.neighbors() + syst = kwant.Builder() + lat = kwant.lattice.square() + syst[(lat(i, j) for i in range(3) for j in range(3))] = 4 syst[lat.neighbors()] = -1 # Equivalent to lat.neighbors(1) kwant.plot(syst) @@ -104,66 +241,175 @@ kwant.plot(syst) +save_figure("faq_adjacent2") + #HIDDEN_END_adjacent1 # Polyatomic lattice -@@ -213,9 +230,11 @@ + #HIDDEN_BEGIN_FAQ6 + + # Hoppings using .neighbors() + #HIDDEN_BEGIN_adjacent2 + # Create the system + lat = kwant.lattice.kagome() + syst = kwant.Builder() + a, b, c = lat.sublattices # The kagome lattice has 3 sublattices + + for i in range(4): + for j in range (4): + syst[a(i, j)] = 4 # red + syst[b(i, j)] = 4 # green + syst[c(i, j)] = 4 # blue syst[lat.neighbors()] = -1 + #HIDDEN_END_adjacent2 plot_system(syst) +save_figure("faq_adjacent3") del syst[lat.neighbors()] # Delete the hoppings previously created + #HIDDEN_BEGIN_adjacent3 syst[a.neighbors()] = -1 + #HIDDEN_END_adjacent3 plot_system(syst) +save_figure("faq_adjacent4") del syst[a.neighbors()] # Delete the hoppings previously created -@@ -253,6 +272,7 @@ + syst[lat.neighbors(2)] = -1 + plot_system(syst) + del syst[lat.neighbors(2)] + + + #### How to create a lead with a lattice different from the scattering region? + + # Plot sites from different families in different colors + + def plot_system(syst): + + def family_color(site): + if site.family == subA: + return 'blue' + if site.family == subB: + return 'yellow' + else: + return 'green' + + kwant.plot(syst, site_lw=0.1, site_color=family_color) + + + #HIDDEN_BEGIN_different_lattice1 + # Define the scattering Region + L = 5 + W = 5 + + lat = kwant.lattice.honeycomb() + subA, subB = lat.sublattices + + syst = kwant.Builder() + syst[(subA(i, j) for i in range(L) for j in range(W))] = 4 syst[(subB(i, j) for i in range(L) for j in range(W))] = 4 syst[lat.neighbors()] = -1 + #HIDDEN_END_different_lattice1 plot_system(syst) +save_figure("faq_different_lattice1") + #HIDDEN_BEGIN_different_lattice2 # Create a lead lat_lead = kwant.lattice.square() -@@ -262,6 +282,7 @@ + sym_lead1 = kwant.TranslationalSymmetry((0, 1)) + + lead1 = kwant.Builder(sym_lead1) lead1[(lat_lead(i, 0) for i in range(2, 7))] = 4 lead1[lat_lead.neighbors()] = -1 + #HIDDEN_END_different_lattice2 plot_system(lead1) +save_figure("faq_different_lattice2") + #HIDDEN_BEGIN_different_lattice3 syst[(lat_lead(i, 5) for i in range(2, 7))] = 4 syst[lat_lead.neighbors()] = -1 -@@ -269,9 +290,11 @@ + # Manually attach sites from graphene to square lattice syst[((lat_lead(i+2, 5), subB(i, 4)) for i in range(5))] = -1 + #HIDDEN_END_different_lattice3 plot_system(syst) +save_figure("faq_different_lattice3") + #HIDDEN_BEGIN_different_lattice4 syst.attach_lead(lead1) + #HIDDEN_END_different_lattice4 plot_system(syst) +save_figure("faq_different_lattice4") #### How to cut a finite system out of a system with translationnal symmetries? -@@ -291,6 +314,7 @@ + + #HIDDEN_BEGIN_fill1 + # Create 3d model. + cubic = kwant.lattice.cubic() + sym_3d = kwant.TranslationalSymmetry([1, 0, 0], [0, 1, 0], [0, 0, 1]) + model = kwant.Builder(sym_3d) + model[cubic(0, 0, 0)] = 4 + model[cubic.neighbors()] = -1 + #HIDDEN_END_fill1 + + #HIDDEN_BEGIN_fill2 + # Build scattering region (white). + def cuboid_shape(site): + x, y, z = abs(site.pos) + return x < 4 and y < 10 and z < 3 + cuboid = kwant.Builder() cuboid.fill(model, cuboid_shape, (0, 0, 0)); + #HIDDEN_END_fill2 kwant.plot(cuboid); +save_figure("faq_fill2") + #HIDDEN_BEGIN_fill3 # Build electrode (black). def electrode_shape(site): -@@ -305,6 +329,7 @@ + x, y, z = site.pos - (0, 5, 2) + return y**2 + z**2 < 2.3**2 + + electrode = kwant.Builder(kwant.TranslationalSymmetry([1, 0, 0])) + electrode.fill(model, electrode_shape, (0, 5, 2)) # lead + + # Scattering region + cuboid.fill(electrode, lambda s: abs(s.pos[0]) < 7, (0, 5, 4)) cuboid.attach_lead(electrode) + #HIDDEN_END_fill3 kwant.plot(cuboid); +save_figure("faq_fill3") #### How does Kwant order the propagating modes of a lead? -@@ -337,6 +362,7 @@ + + #HIDDEN_BEGIN_pm + lat = kwant.lattice.square() + + lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0))) + lead[(lat(0, i) for i in range(3))] = 4 + lead[lat.neighbors()] = -1 + + flead = lead.finalized() + + E = 2.5 + prop_modes, _ = flead.modes(energy=E) + #HIDDEN_END_pm + + def plot_and_label_modes(lead, E): + # Plot the different modes + pmodes, _ = lead.modes(energy=E) + kwant.plotter.bands(lead, show=False) + for i, k in enumerate(pmodes.momenta): + plt.plot(k, E, 'ko') + plt.annotate(str(i), xy=(k, E), xytext=(-5, 8), + textcoords='offset points', + bbox=dict(boxstyle='round,pad=0.1',fc='white', alpha=0.7)) + plt.plot([-3, 3], [E, E], 'r--') + plt.ylim(E-1, E+1) + plt.xlim(-2, 2) + plt.xlabel("momentum") + plt.ylabel("energy") plt.show() plot_and_label_modes(flead, E) @@ -171,7 +417,14 @@ # More involved example -@@ -351,6 +377,7 @@ + s0 = np.eye(2) + sz = np.array([[1, 0], [0, -1]]) + + lead2 = kwant.Builder(kwant.TranslationalSymmetry((-1, 0))) + + lead2[(lat(0, i) for i in range(2))] = np.diag([1.8, -1]) + lead2[lat.neighbors()] = -1 * sz + flead2 = lead2.finalized() plot_and_label_modes(flead2, 1) @@ -179,20 +432,52 @@ #### How does Kwant order components of an individual wavefunction? -@@ -381,7 +408,8 @@ + def circle(R): + return lambda r: np.linalg.norm(r) < R + + + def make_system(lat): + norbs = lat.norbs + syst = kwant.Builder() + syst[lat.shape(circle(3), (0, 0))] = 4 * np.eye(norbs) + syst[lat.neighbors()] = -1 * np.eye(norbs) + + lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0))) + lead[(lat(0, i) for i in range(-1, 2))] = 4 * np.eye(norbs) + lead[lat.neighbors()] = -1 * np.eye(norbs) + + syst.attach_lead(lead) + syst.attach_lead(lead.reversed()) + + return syst.finalized() + + + #HIDDEN_BEGIN_ord1 + lat = kwant.lattice.square(norbs=1) + syst = make_system(lat) + scattering_states = kwant.wave_function(syst, energy=1) + wf = scattering_states(0)[0] # scattering state from lead 0 incoming in mode 0 idx = syst.id_by_site[lat(0, 0)] # look up index of site -print('wavefunction on lat(0, 0): ', wf[idx]) +with open('faq_ord1.txt', 'w') as f: + print('wavefunction on lat(0, 0): ', wf[idx], file=f) + #HIDDEN_END_ord1 + #HIDDEN_BEGIN_ord2 lat = kwant.lattice.square(norbs=2) syst = make_system(lat) -@@ -394,4 +422,5 @@ + scattering_states = kwant.wave_function(syst, energy=1) + wf = scattering_states(0)[0] # scattering state from lead 0 incoming in mode 0 + + idx = syst.id_by_site[lat(0, 0)] # look up index of site + + # Group consecutive degrees of freedom from 'wf' together; these correspond # to degrees of freedom on the same site. wf = wf.reshape(-1, 2) -print('wavefunction on lat(0, 0): ', wf[idx]) +with open('faq_ord2.txt', 'w') as f: + print('wavefunction on lat(0, 0): ', wf[idx], file=f) + #HIDDEN_END_ord2 diff --git a/doc/source/images/generate-diffs.sh b/doc/source/images/generate-diffs.sh deleted file mode 100755 index d78525ea67151e22aad3ef50ccbf20b0bf5f73e0..0000000000000000000000000000000000000000 --- a/doc/source/images/generate-diffs.sh +++ /dev/null @@ -1,16 +0,0 @@ -# !/bin/sh - -# This script regenerates the .diff files in this directory. It's these files -# that are kept under vesion control instead of the scripts themselves. - -for f in [a-zA-Z]*.py; do - # We use custom labels to suppress the time stamps which are unnecessary - # here and would only lead to noise in version control. - grep -v '#HIDDEN' ../tutorial/$f | - diff -u --label original --label modified - $f >$f.diff_ - if cmp $f.diff_ $f.diff >/dev/null 2>&1; then - rm $f.diff_ - else - mv $f.diff_ $f.diff - fi -done diff --git a/doc/source/images/graphene.py.diff b/doc/source/images/graphene.py.diff index 4871213278c445098a82cc72bd2c2cacc5cf8480..1352ed270df555a9cd1aa5c6ef51632590cd7337 100644 --- a/doc/source/images/graphene.py.diff +++ b/doc/source/images/graphene.py.diff @@ -1,6 +1,13 @@ ---- original -+++ modified -@@ -10,6 +10,7 @@ +@@ -1,179 +1,203 @@ + # Tutorial 2.5. Beyond square lattices: graphene + # ============================================== + # + # Physics background + # ------------------ + # Transport through a graphene quantum dot with a pn-junction + # + # Kwant features highlighted + # -------------------------- # - Application of all the aspects of tutorials 1-3 to a more complicated # lattice, namely graphene @@ -8,7 +15,102 @@ from math import pi, sqrt, tanh import kwant -@@ -96,22 +97,40 @@ + + # For computing eigenvalues + import scipy.sparse.linalg as sla + + # For plotting + from matplotlib import pyplot + + + # Define the graphene lattice + sin_30, cos_30 = (1 / 2, sqrt(3) / 2) + #HIDDEN_BEGIN_hnla + graphene = kwant.lattice.general([(1, 0), (sin_30, cos_30)], + [(0, 0), (0, 1 / sqrt(3))]) + a, b = graphene.sublattices + #HIDDEN_END_hnla + + + #HIDDEN_BEGIN_shzy + def make_system(r=10, w=2.0, pot=0.1): + + #### Define the scattering region. #### + # circular scattering region + def circle(pos): + x, y = pos + return x ** 2 + y ** 2 < r ** 2 + + syst = kwant.Builder() + + # w: width and pot: potential maximum of the p-n junction + def potential(site): + (x, y) = site.pos + d = y * cos_30 + x * sin_30 + return pot * tanh(d / w) + + syst[graphene.shape(circle, (0, 0))] = potential + #HIDDEN_END_shzy + + # specify the hoppings of the graphene lattice in the + # format expected by builder.HoppingKind + #HIDDEN_BEGIN_hsmc + hoppings = (((0, 0), a, b), ((0, 1), a, b), ((-1, 1), a, b)) + #HIDDEN_END_hsmc + #HIDDEN_BEGIN_bfwb + syst[[kwant.builder.HoppingKind(*hopping) for hopping in hoppings]] = -1 + #HIDDEN_END_bfwb + + # Modify the scattering region + #HIDDEN_BEGIN_efut + del syst[a(0, 0)] + syst[a(-2, 1), b(2, 2)] = -1 + #HIDDEN_END_efut + + #### Define the leads. #### + #HIDDEN_BEGIN_aakh + # left lead + sym0 = kwant.TranslationalSymmetry(graphene.vec((-1, 0))) + + def lead0_shape(pos): + x, y = pos + return (-0.4 * r < y < 0.4 * r) + + lead0 = kwant.Builder(sym0) + lead0[graphene.shape(lead0_shape, (0, 0))] = -pot + lead0[[kwant.builder.HoppingKind(*hopping) for hopping in hoppings]] = -1 + + # The second lead, going to the top right + sym1 = kwant.TranslationalSymmetry(graphene.vec((0, 1))) + + def lead1_shape(pos): + v = pos[1] * sin_30 - pos[0] * cos_30 + return (-0.4 * r < v < 0.4 * r) + + lead1 = kwant.Builder(sym1) + lead1[graphene.shape(lead1_shape, (0, 0))] = pot + lead1[[kwant.builder.HoppingKind(*hopping) for hopping in hoppings]] = -1 + #HIDDEN_END_aakh + + #HIDDEN_BEGIN_kmmw + return syst, [lead0, lead1] + #HIDDEN_END_kmmw + + + #HIDDEN_BEGIN_zydk + def compute_evs(syst): + # Compute some eigenvalues of the closed system + sparse_mat = syst.hamiltonian_submatrix(sparse=True) + + evs = sla.eigs(sparse_mat, 2)[0] + print(evs.real) + #HIDDEN_END_zydk + + + def plot_conductance(syst, energies): + # Compute transmission as a function of energy + data = [] + for energy in energies: smatrix = kwant.smatrix(syst, energy) data.append(smatrix.transmission(0, 1)) @@ -56,8 +158,17 @@ + fig.savefig("graphene_bs." + extension, dpi=_defs.dpi) + #HIDDEN The part of the following code block which begins with family_colors + #HIDDEN is included verbatim in the tutorial text because nested code examples + #HIDDEN are not supported. Remember to update the tutorial text when you + #HIDDEN modify this block. + #HIDDEN_BEGIN_itkk def main(): -@@ -123,8 +142,11 @@ + pot = 0.1 + syst, leads = make_system(pot=pot) + + # To highlight the two sublattices of graphene, we plot one with + # a filled, and the other one with an open circle: def family_colors(site): return 0 if site.family == a else 1 @@ -68,10 +179,14 @@ + kwant.plot(syst, site_color=family_colors, site_lw=0.1, colorbar=False, + file="graphene_syst1." + extension, + fig_size=size, dpi=_defs.dpi) + #HIDDEN_END_itkk # Compute some eigenvalues. + #HIDDEN_BEGIN_jmbi compute_evs(syst.finalized()) -@@ -133,9 +155,11 @@ + #HIDDEN_END_jmbi + + # Attach the leads to the system. for lead in leads: syst.attach_lead(lead) @@ -86,3 +201,17 @@ # Finalize the system. syst = syst.finalized() + + # Compute the band structure of lead 0. + momenta = [-pi + 0.02 * pi * i for i in range(101)] + plot_bandstructure(syst.leads[0], momenta) + + # Plot conductance. + energies = [-2 * pot + 4. / 50. * pot * i for i in range(51)] + plot_conductance(syst, energies) + + + # Call the main function if the script gets executed (as opposed to imported). + # See <http://docs.python.org/library/__main__.html>. + if __name__ == '__main__': + main() diff --git a/doc/source/images/kernel_polynomial_method.py.diff b/doc/source/images/kernel_polynomial_method.py.diff index d58b3836bd85bb6ec8fe06f930dfc41dedf6788a..9e778f10d77979805d3587eedf23d4447e49807c 100644 --- a/doc/source/images/kernel_polynomial_method.py.diff +++ b/doc/source/images/kernel_polynomial_method.py.diff @@ -1,6 +1,14 @@ ---- original -+++ modified -@@ -11,6 +11,9 @@ +@@ -1,219 +1,242 @@ + # Tutorial 2.8. Calculating spectral density with the Kernel Polynomial Method + # ============================================================================ + # + # Physics background + # ------------------ + # - Chebyshev polynomials, random trace approximation, spectral densities. + # + # Kwant features highlighted + # -------------------------- + # - kpm module,kwant operators. import scipy @@ -10,7 +18,27 @@ # For plotting from matplotlib import pyplot as plt -@@ -36,13 +39,13 @@ + #HIDDEN_BEGIN_sys1 + # necessary imports + import kwant + import numpy as np + + + # define the system + def make_syst(r=30, t=-1, a=1): + syst = kwant.Builder() + lat = kwant.lattice.honeycomb(a, norbs=1) + + def circle(pos): + x, y = pos + return x ** 2 + y ** 2 < r ** 2 + + syst[lat.shape(circle, (0, 0))] = 0. + syst[lat.neighbors()] = t + syst.eradicate_dangling() + + return syst + #HIDDEN_END_sys1 # Plot several density of states curves on the same axes. @@ -26,7 +54,14 @@ plt.clf() -@@ -57,10 +60,18 @@ + def site_size_conversion(densities): + return 3 * np.abs(densities) / max(densities) + + + # Plot several local density of states maps in different subplots + def plot_ldos(fsyst, axes, titles_to_data, file_name=None): + for ax, (title, ldos) in zip(axes, titles_to_data): + site_size = site_size_conversion(ldos) # convert LDoS to sizes kwant.plot(fsyst, site_size=site_size, site_color=(0, 0, 1, 0.3), ax=ax) ax.set_title(title) ax.set(adjustable='box-forced', aspect='equal') @@ -44,9 +79,21 @@ + + def simple_dos_example(): + #HIDDEN_BEGIN_kpm1 fsyst = make_syst().finalized() -@@ -74,18 +85,24 @@ + spectrum = kwant.kpm.SpectralDensity(fsyst) + #HIDDEN_END_kpm1 + + #HIDDEN_BEGIN_kpm2 + energies, densities = spectrum() + #HIDDEN_END_kpm2 + + #HIDDEN_BEGIN_kpm3 + energy_subset = np.linspace(0, 2) + density_subset = spectrum(energy_subset) + #HIDDEN_END_kpm3 + plot_dos([ ('densities', (energies, densities)), ('density subset', (energy_subset, density_subset)), @@ -59,11 +106,14 @@ def dos_integrating_example(fsyst): spectrum = kwant.kpm.SpectralDensity(fsyst) + #HIDDEN_BEGIN_int1 - print('identity resolution:', spectrum.integrate()) + with open('kpm_normalization.txt', 'w') as f: + with redirect_stdout(f): + print('identity resolution:', spectrum.integrate()) + #HIDDEN_END_int1 + #HIDDEN_BEGIN_int2 # Fermi energy 0.1 and temperature 0.2 fermi = lambda E: 1 / (np.exp((E - 0.1) / 0.2) + 1) @@ -71,10 +121,19 @@ + with open('kpm_total_states.txt', 'w') as f: + with redirect_stdout(f): + print('number of filled states:', spectrum.integrate(fermi)) + #HIDDEN_END_int2 def increasing_accuracy_example(fsyst): -@@ -99,7 +116,9 @@ + spectrum = kwant.kpm.SpectralDensity(fsyst) + original_dos = spectrum() # get unaltered DoS + + #HIDDEN_BEGIN_acc1 + spectrum.add_moments(energy_resolution=0.03) + #HIDDEN_END_acc1 + + increased_resolution_dos = spectrum() + plot_dos([ ('density', original_dos), ('higher energy resolution', increased_resolution_dos), @@ -83,9 +142,13 @@ + file_name='kpm_dos_acc' + ) + #HIDDEN_BEGIN_acc2 spectrum.add_moments(100) spectrum.add_vectors(5) -@@ -109,7 +128,9 @@ + #HIDDEN_END_acc2 + + increased_moments_dos = spectrum() + plot_dos([ ('density', original_dos), ('higher number of moments', increased_moments_dos), @@ -96,7 +159,36 @@ def operator_example(fsyst): -@@ -139,7 +160,9 @@ + #HIDDEN_BEGIN_op1 + # identity matrix + matrix_op = scipy.sparse.eye(len(fsyst.sites)) + matrix_spectrum = kwant.kpm.SpectralDensity(fsyst, operator=matrix_op) + #HIDDEN_END_op1 + + #HIDDEN_BEGIN_op2 + # 'sum=True' means we sum over all the sites + kwant_op = kwant.operator.Density(fsyst, sum=True) + operator_spectrum = kwant.kpm.SpectralDensity(fsyst, operator=kwant_op) + #HIDDEN_END_op2 + + plot_dos([ + ('identity matrix', matrix_spectrum()), + ('kwant.operator.Density', operator_spectrum()), + ]) + + + def ldos_example(fsyst): + #HIDDEN_BEGIN_op3 + # 'sum=False' is the default, but we include it explicitly here for clarity. + kwant_op = kwant.operator.Density(fsyst, sum=False) + local_dos = kwant.kpm.SpectralDensity(fsyst, operator=kwant_op) + #HIDDEN_END_op3 + + #HIDDEN_BEGIN_op4 + zero_energy_ldos = local_dos(energy=0) + finite_energy_ldos = local_dos(energy=1) + + _, axes = plt.subplots(1, 2, figsize=(12, 7)) plot_ldos(fsyst, axes,[ ('energy = 0', zero_energy_ldos), ('energy = 1', finite_energy_ldos), @@ -104,6 +196,57 @@ + ], + file_name='kpm_ldos' + ) + #HIDDEN_END_op4 def vector_factory_example(fsyst): + spectrum = kwant.kpm.SpectralDensity(fsyst) + #HIDDEN_BEGIN_fact1 + # construct vectors with n random elements -1 or +1. + def binary_vectors(n): + return np.rint(np.random.random_sample(n)) * 2 - 1 + + custom_factory = kwant.kpm.SpectralDensity(fsyst, + vector_factory=binary_vectors) + #HIDDEN_END_fact1 + plot_dos([ + ('default vector factory', spectrum()), + ('binary vector factory', custom_factory()), + ]) + + + def bilinear_map_operator_example(fsyst): + #HIDDEN_BEGIN_blm + rho = kwant.operator.Density(fsyst, sum=True) + + # sesquilinear map that does the same thing as `rho` + def rho_alt(bra, ket): + return np.vdot(bra, ket) + + rho_spectrum = kwant.kpm.SpectralDensity(fsyst, operator=rho) + rho_alt_spectrum = kwant.kpm.SpectralDensity(fsyst, operator=rho_alt) + #HIDDEN_END_blm + + plot_dos([ + ('kwant.operator.Density', rho_spectrum()), + ('bilinear operator', rho_alt_spectrum()), + ]) + + + def main(): + simple_dos_example() + + fsyst = make_syst().finalized() + + dos_integrating_example(fsyst) + increasing_accuracy_example(fsyst) + operator_example(fsyst) + ldos_example(fsyst) + vector_factory_example(fsyst) + bilinear_map_operator_example(fsyst) + + + # Call the main function if the script gets executed (as opposed to imported). + # See <http://docs.python.org/library/__main__.html>. + if __name__ == '__main__': + main() diff --git a/doc/source/images/magnetic_texture.py.diff b/doc/source/images/magnetic_texture.py.diff index bc7acb4dcf1b7bda417c3dc3458eb61655435e05..0b1f90cb6bd17d88a97b7e1924641fb640b15a63 100644 --- a/doc/source/images/magnetic_texture.py.diff +++ b/doc/source/images/magnetic_texture.py.diff @@ -1,6 +1,14 @@ ---- original -+++ modified -@@ -11,6 +11,9 @@ +@@ -1,245 +1,268 @@ + # Tutorial 2.7. Spin textures + # =========================== + # + # Physics background + # ------------------ + # - Spin textures + # - Skyrmions + # + # Kwant features highlighted + # -------------------------- # - operators # - plotting vector fields @@ -10,8 +18,73 @@ from math import sin, cos, tanh, pi import itertools import numpy as np -@@ -79,7 +82,13 @@ + import tinyarray as ta + import matplotlib.pyplot as plt + + import kwant + + sigma_0 = ta.array([[1, 0], [0, 1]]) + sigma_x = ta.array([[0, 1], [1, 0]]) + sigma_y = ta.array([[0, -1j], [1j, 0]]) + sigma_z = ta.array([[1, 0], [0, -1]]) + + # vector of Pauli matrices σ_αiβ where greek + # letters denote spinor indices + sigma = np.rollaxis(np.array([sigma_x, sigma_y, sigma_z]), 1) + + #HIDDEN_BEGIN_model + def field_direction(pos, r0, delta): + x, y = pos + r = np.linalg.norm(pos) + r_tilde = (r - r0) / delta + theta = (tanh(r_tilde) - 1) * (pi / 2) + + if r == 0: + m_i = [0, 0, 1] + else: + m_i = [ + (x / r) * sin(theta), + (y / r) * sin(theta), + cos(theta), + ] + + return np.array(m_i) + + + def scattering_onsite(site, r0, delta, J): + m_i = field_direction(site.pos, r0, delta) + return J * np.dot(m_i, sigma) + + + def lead_onsite(site, J): + return J * sigma_z + #HIDDEN_END_model + + + #HIDDEN_BEGIN_syst + lat = kwant.lattice.square(norbs=2) + + def make_system(L=80): + + syst = kwant.Builder() + + def square(pos): + return all(-L/2 < p < L/2 for p in pos) + + syst[lat.shape(square, (0, 0))] = scattering_onsite + syst[lat.neighbors()] = -sigma_0 + + lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)), + conservation_law=-sigma_z) + + lead[lat.shape(square, (0, 0))] = lead_onsite + lead[lat.neighbors()] = -sigma_0 + + syst.attach_lead(lead) + syst.attach_lead(lead.reversed()) + return syst + #HIDDEN_END_syst -def plot_vector_field(syst, params): @@ -25,7 +98,8 @@ xmin, ymin = min(s.tag for s in syst.sites) xmax, ymax = max(s.tag for s in syst.sites) x, y = np.meshgrid(np.arange(xmin, xmax+1), np.arange(ymin, ymax+1)) -@@ -88,28 +97,38 @@ + + m_i = [field_direction(p, **params) for p in zip(x.flat, y.flat)] m_i = np.reshape(m_i, x.shape + (3,)) m_i = np.rollaxis(m_i, 2, 0) @@ -52,11 +126,11 @@ + save_plot(fname) + else: + plt.show() -+ -def plot_currents(syst, currents): - fig, axes = plt.subplots(1, len(currents)) ++ +def plot_currents(syst, currents, fname=None): + fig, axes = plt.subplots(1, len(currents), figsize=(7*len(currents), 7)) if not hasattr(axes, '__len__'): @@ -72,34 +146,80 @@ def main(): -@@ -119,7 +138,7 @@ + syst = make_system().finalized() + + #HIDDEN_BEGIN_wavefunction + params = dict(r0=20, delta=10, J=1) wf = kwant.wave_function(syst, energy=-1, params=params) psi = wf(0)[0] + #HIDDEN_END_wavefunction - plot_vector_field(syst, dict(r0=20, delta=10)) + plot_vector_field(syst, dict(r0=20, delta=10), fname='mag_field_direction') + #HIDDEN_BEGIN_ldos # even (odd) indices correspond to spin up (down) up, down = psi[::2], psi[1::2] -@@ -144,7 +163,7 @@ + density = np.abs(up)**2 + np.abs(down)**2 + #HIDDEN_END_ldos + + #HIDDEN_BEGIN_lsdz + # spin down components have a minus sign + spin_z = np.abs(up)**2 - np.abs(down)**2 + #HIDDEN_END_lsdz + + #HIDDEN_BEGIN_lsdy + # spin down components have a minus sign + spin_y = 1j * (down.conjugate() * up - up.conjugate() * down) + #HIDDEN_END_lsdy + + #HIDDEN_BEGIN_lden + rho = kwant.operator.Density(syst) + rho_sz = kwant.operator.Density(syst, sigma_z) + rho_sy = kwant.operator.Density(syst, sigma_y) + + # calculate the expectation values of the operators with 'psi' + density = rho(psi) + spin_z = rho_sz(psi) + spin_y = rho_sy(psi) + #HIDDEN_END_lden + + plot_densities(syst, [ ('$σ_0$', density), ('$σ_z$', spin_z), ('$σ_y$', spin_y), - ]) + ], fname='spin_densities') + #HIDDEN_BEGIN_current J_0 = kwant.operator.Current(syst) J_z = kwant.operator.Current(syst, sigma_z) -@@ -159,7 +178,7 @@ + J_y = kwant.operator.Current(syst, sigma_y) + + # calculate the expectation values of the operators with 'psi' + current = J_0(psi) + spin_z_current = J_z(psi) + spin_y_current = J_y(psi) + #HIDDEN_END_current + + plot_currents(syst, [ ('$J_{σ_0}$', current), ('$J_{σ_z}$', spin_z_current), ('$J_{σ_y}$', spin_y_current), - ]) + ], fname='spin_currents') + #HIDDEN_BEGIN_following def following_m_i(site, r0, delta): m_i = field_direction(site.pos, r0, delta) -@@ -173,7 +192,7 @@ + return np.dot(m_i, sigma) + + J_m = kwant.operator.Current(syst, following_m_i) + + # evaluate the operator + m_current = J_m(psi, params=dict(r0=25, delta=10)) + #HIDDEN_END_following + plot_currents(syst, [ (r'$J_{\mathbf{m}_i}$', m_current), ('$J_{σ_z}$', spin_z_current), @@ -107,8 +227,11 @@ + ], fname='spin_current_comparison') + #HIDDEN_BEGIN_density_cut def circle(site): -@@ -183,7 +202,9 @@ + return np.linalg.norm(site.pos) < 20 + + rho_circle = kwant.operator.Density(syst, where=circle, sum=True) all_states = np.vstack((wf(0), wf(1))) dos_in_circle = sum(rho_circle(p) for p in all_states) / (2 * pi) @@ -116,10 +239,18 @@ + with open('circle_dos.txt', 'w') as f: + with redirect_stdout(f): + print('density of states in circle:', dos_in_circle) + #HIDDEN_END_density_cut + #HIDDEN_BEGIN_current_cut def left_cut(site_to, site_from): return site_from.pos[0] <= -39 and site_to.pos[0] > -39 -@@ -197,8 +218,10 @@ + + def right_cut(site_to, site_from): + return site_from.pos[0] < 39 and site_to.pos[0] >= 39 + + J_left = kwant.operator.Current(syst, where=left_cut, sum=True) + J_right = kwant.operator.Current(syst, where=right_cut, sum=True) + Jz_left = kwant.operator.Current(syst, sigma_z, where=left_cut, sum=True) Jz_right = kwant.operator.Current(syst, sigma_z, where=right_cut, sum=True) @@ -129,10 +260,21 @@ + with redirect_stdout(f): + print('J_left:', J_left(psi), ' J_right:', J_right(psi)) + print('Jz_left:', Jz_left(psi), ' Jz_right:', Jz_right(psi)) + #HIDDEN_END_current_cut + #HIDDEN_BEGIN_bind J_m = kwant.operator.Current(syst, following_m_i) J_z = kwant.operator.Current(syst, sigma_z) -@@ -214,7 +237,7 @@ + + J_m_bound = J_m.bind(params=dict(r0=25, delta=10, J=1)) + J_z_bound = J_z.bind(params=dict(r0=25, delta=10, J=1)) + + # Sum current local from all scattering states on the left at energy=-1 + wf_left = wf(0) + J_m_left = sum(J_m_bound(p) for p in wf_left) + J_z_left = sum(J_z_bound(p) for p in wf_left) + #HIDDEN_END_bind + plot_currents(syst, [ (r'$J_{\mathbf{m}_i}$ (from left)', J_m_left), (r'$J_{σ_z}$ (from left)', J_z_left), @@ -141,3 +283,4 @@ if __name__ == '__main__': + main() diff --git a/doc/source/images/plot_graphene.py.diff b/doc/source/images/plot_graphene.py.diff index 74263c4f1ce1f523ba6c4205b4a5f99c8e92de41..82c7555424f6a0206c68cbce0235da3e6fa7ef73 100644 --- a/doc/source/images/plot_graphene.py.diff +++ b/doc/source/images/plot_graphene.py.diff @@ -1,6 +1,12 @@ ---- original -+++ modified -@@ -9,6 +9,7 @@ +@@ -1,112 +1,130 @@ + # Tutorial 2.8.1. 2D example: graphene quantum dot + # ================================================ + # + # Physics background + # ------------------ + # - graphene edge states + # + # Kwant features highlighted # -------------------------- # - demonstrate different ways of plotting @@ -8,7 +14,14 @@ import kwant from matplotlib import pyplot -@@ -22,7 +23,7 @@ + #HIDDEN_BEGIN_makesyst + lat = kwant.lattice.honeycomb() + a, b = lat.sublattices + + def make_system(r=8, t=-1, tp=-0.1): + + def circle(pos): + x, y = pos return x**2 + y**2 < r**2 syst = kwant.Builder() @@ -17,11 +30,16 @@ syst[lat.neighbors()] = t syst.eradicate_dangling() if tp: -@@ -32,9 +33,11 @@ + syst[lat.neighbors(2)] = tp + return syst + #HIDDEN_END_makesyst + + #HIDDEN_BEGIN_plotsyst1 def plot_system(syst): - kwant.plot(syst) + #HIDDEN_END_plotsyst1 - # the standard plot is ok, but not very intelligible. One can do - # better by playing wioth colors and linewidths + # standard plot - not very intelligible for this particular situation @@ -31,8 +49,10 @@ + fig_size=size, dpi=_defs.dpi) # use color and linewidths to get a better plot + #HIDDEN_BEGIN_plotsyst2 def family_color(site): -@@ -43,7 +46,11 @@ + return 'black' if site.family == a else 'white' + def hopping_lw(site1, site2): return 0.04 if site1.family == site2.family else 0.1 @@ -42,23 +62,38 @@ + kwant.plot(syst, site_lw=0.1, site_color=family_color, + hop_lw=hopping_lw, file="plot_graphene_syst2." + extension, + fig_size=size, dpi=_defs.dpi) + #HIDDEN_END_plotsyst2 + #HIDDEN_BEGIN_plotdata1 def plot_data(syst, n): -@@ -58,7 +65,11 @@ + import scipy.linalg as la + + syst = syst.finalized() + ham = syst.hamiltonian_submatrix() + evecs = la.eigh(ham)[1] + + wf = abs(evecs[:, n])**2 + #HIDDEN_END_plotdata1 + # the usual - works great in general, looks just a bit crufty for # small systems + #HIDDEN_BEGIN_plotdata2 - kwant.plotter.map(syst, wf, oversampling=10, cmap='gist_heat_r') + size = (_defs.figwidth_in, _defs.figwidth_in) + for extension in ('pdf', 'png'): + kwant.plotter.map(syst, wf, oversampling=10, cmap='gist_heat_r', + file="plot_graphene_data1." + extension, + fig_size=size, dpi=_defs.dpi) + #HIDDEN_END_plotdata2 # use two different sort of triangles to cleanly fill the space + #HIDDEN_BEGIN_plotdata3 def family_shape(i): -@@ -68,15 +79,22 @@ + site = syst.sites[i] + return ('p', 3, 180) if site.family == a else ('p', 3, 0) + def family_color(i): return 'black' if syst.sites[i].family == a else 'white' @@ -70,8 +105,10 @@ + site_size=0.5, hop_lw=0, cmap='gist_heat_r', + file="plot_graphene_data2." + extension, + fig_size=size, dpi=_defs.dpi) + #HIDDEN_END_plotdata3 # plot by changing the symbols itself + #HIDDEN_BEGIN_plotdata4 def site_size(i): return 3 * wf[i] / wf.max() @@ -82,6 +119,23 @@ + kwant.plot(syst, site_size=site_size, site_color=(0,0,1,0.3), + hop_lw=0.1, file="plot_graphene_data3." + extension, + fig_size=size, dpi=_defs.dpi) + #HIDDEN_END_plotdata4 def main(): + # plot the graphene system in different styles + syst = make_system() + + plot_system(syst) + + # compute a wavefunction (number 225) and plot it in different + # styles + syst = make_system(tp=0) + + plot_data(syst, 225) + + + # Call the main function if the script gets executed (as opposed to imported). + # See <http://docs.python.org/library/__main__.html>. + if __name__ == '__main__': + main() diff --git a/doc/source/images/plot_qahe.py.diff b/doc/source/images/plot_qahe.py.diff index 8db900c966ddc680fd2bf0b5d0282830cc3b9695..0e0957092919800658a8ffae081cf47491ac4861 100644 --- a/doc/source/images/plot_qahe.py.diff +++ b/doc/source/images/plot_qahe.py.diff @@ -1,6 +1,14 @@ ---- original -+++ modified -@@ -11,6 +11,7 @@ +@@ -1,71 +1,75 @@ + # Comprehensive example: quantum anomalous Hall effect + # ==================================================== + # + # Physics background + # ------------------ + # + Quantum anomalous Hall effect + # + # Features highlighted + # -------------------- + # + Use of `kwant.continuum` to discretize a continuum Hamiltonian # + Use of `kwant.operator` to compute local current # + Use of `kwant.plotter.current` to plot local current @@ -8,8 +16,53 @@ import math import matplotlib.pyplot import kwant -@@ -60,7 +61,10 @@ + + + # 2 band model exhibiting quantum anomalous Hall effect + #HIDDEN_BEGIN_model + def make_model(a): + ham = ("alpha * (k_x * sigma_x - k_y * sigma_y)" + "+ (m + beta * kk) * sigma_z" + "+ (gamma * kk + U) * sigma_0") + subs = {"kk": "k_x**2 + k_y**2"} + return kwant.continuum.discretize(ham, locals=subs, grid_spacing=a) + #HIDDEN_END_model + + + def make_system(model, L): + def lead_shape(site): + x, y = site.pos / L + return abs(y) < 0.5 + + # QPC shape: a rectangle with 2 gaussians + # etched out of the top and bottom edge. + def central_shape(site): + x, y = site.pos / L + return abs(x) < 3/5 and abs(y) < 0.5 - 0.4 * math.exp(-40 * x**2) + + lead = kwant.Builder(kwant.TranslationalSymmetry( + model.lattice.vec((-1, 0)))) + lead.fill(model, lead_shape, (0, 0)) + + syst = kwant.Builder() + syst.fill(model, central_shape, (0, 0)) + syst.attach_lead(lead) + syst.attach_lead(lead.reversed()) + + return syst.finalized() + + + def main(): + # Set up our model and system, and define the model parameters. + params = dict(alpha=0.365, beta=0.686, gamma=0.512, m=-0.01, U=0) + model = make_model(1) + syst = make_system(model, 70) + kwant.plot(syst) + + # Calculate the scattering states at energy 'm' coming from the left + # lead, and the associated particle current. psi = kwant.wave_function(syst, energy=params['m'], params=params)(0) + #HIDDEN_BEGIN_current J = kwant.operator.Current(syst).bind(params=params) current = sum(J(p) for p in psi) - kwant.plotter.current(syst, current) @@ -17,6 +70,8 @@ + kwant.plotter.current(syst, current, + file="plot_qahe_current." + extension, + dpi=_defs.dpi) + #HIDDEN_END_current if __name__ == '__main__': + main() diff --git a/doc/source/images/plot_zincblende.py.diff b/doc/source/images/plot_zincblende.py.diff index 5a4bf03839c56c4732dd349e2fa628b76a99d02f..ad5007871331dd28bf8653ab5be63e102d58205b 100644 --- a/doc/source/images/plot_zincblende.py.diff +++ b/doc/source/images/plot_zincblende.py.diff @@ -1,6 +1,12 @@ ---- original -+++ modified -@@ -9,6 +9,7 @@ +@@ -1,59 +1,67 @@ + # Tutorial 2.8.2. 3D example: zincblende structure + # ================================================ + # + # Physical background + # ------------------- + # - 3D Bravais lattices + # + # Kwant features highlighted # -------------------------- # - demonstrate different ways of plotting in 3D @@ -8,8 +14,30 @@ import kwant from matplotlib import pyplot -@@ -33,7 +34,10 @@ + #HIDDEN_BEGIN_zincblende1 + lat = kwant.lattice.general([(0, 0.5, 0.5), (0.5, 0, 0.5), (0.5, 0.5, 0)], + [(0, 0, 0), (0.25, 0.25, 0.25)]) + a, b = lat.sublattices + #HIDDEN_END_zincblende1 + + #HIDDEN_BEGIN_zincblende2 + def make_cuboid(a=15, b=10, c=5): + def cuboid_shape(pos): + x, y, z = pos + return 0 <= x < a and 0 <= y < b and 0 <= z < c + + syst = kwant.Builder() + syst[lat.shape(cuboid_shape, (0, 0, 0))] = None + syst[lat.neighbors()] = None + + return syst + #HIDDEN_END_zincblende2 + + + def main(): + # the standard plotting style for 3D is mainly useful for # checking shapes: + #HIDDEN_BEGIN_plot1 syst = make_cuboid() - kwant.plot(syst) @@ -17,10 +45,12 @@ + for extension in ('pdf', 'png'): + kwant.plot(syst, file="plot_zincblende_syst1." + extension, + fig_size=size, dpi=_defs.dpi) + #HIDDEN_END_plot1 # visualize the crystal structure better for a very small system + #HIDDEN_BEGIN_plot2 syst = make_cuboid(a=1.5, b=1.5, c=1.5) -@@ -41,8 +45,12 @@ + def family_colors(site): return 'r' if site.family == a else 'g' @@ -32,6 +62,10 @@ + site_color=family_colors, + file="plot_zincblende_syst2." + extension, + fig_size=size, dpi=_defs.dpi) + #HIDDEN_END_plot2 # Call the main function if the script gets executed (as opposed to imported). + # See <http://docs.python.org/library/__main__.html>. + if __name__ == '__main__': + main() diff --git a/doc/source/images/quantum_well.py.diff b/doc/source/images/quantum_well.py.diff index eec8c54023f956381a24dc8cdbcd4795c7f7ac99..7b81c8668eadb48b0dbcceff7cfb0a04a7d78d64 100644 --- a/doc/source/images/quantum_well.py.diff +++ b/doc/source/images/quantum_well.py.diff @@ -1,6 +1,12 @@ ---- original -+++ modified -@@ -9,6 +9,7 @@ +@@ -1,88 +1,95 @@ + # Tutorial 2.3.2. Spatially dependent values through functions + # ============================================================ + # + # Physics background + # ------------------ + # transmission through a quantum well + # + # Kwant features highlighted # -------------------------- # - Functions as values in Builder @@ -8,7 +14,51 @@ import kwant # For plotting -@@ -55,19 +56,25 @@ + from matplotlib import pyplot + + + #HIDDEN_BEGIN_ehso + def make_system(a=1, t=1.0, W=10, L=30, L_well=10): + # Start with an empty tight-binding system and a single square lattice. + # `a` is the lattice constant (by default set to 1 for simplicity. + lat = kwant.lattice.square(a) + + syst = kwant.Builder() + + #### Define the scattering region. #### + # Potential profile + def potential(site, pot): + (x, y) = site.pos + if (L - L_well) / 2 < x < (L + L_well) / 2: + return pot + else: + return 0 + #HIDDEN_END_ehso + + #HIDDEN_BEGIN_coid + def onsite(site, pot=0): + return 4 * t + potential(site, pot) + + syst[(lat(x, y) for x in range(L) for y in range(W))] = onsite + syst[lat.neighbors()] = -t + #HIDDEN_END_coid + + #### Define and attach the leads. #### + lead = kwant.Builder(kwant.TranslationalSymmetry((-a, 0))) + lead[(lat(0, j) for j in range(W))] = 4 * t + lead[lat.neighbors()] = -t + syst.attach_lead(lead) + syst.attach_lead(lead.reversed()) + + return syst + + + def plot_conductance(syst, energy, welldepths): + #HIDDEN_BEGIN_sqvr + + # Compute conductance + data = [] + for welldepth in welldepths: smatrix = kwant.smatrix(syst, energy, args=[-welldepth]) data.append(smatrix.transmission(1, 0)) @@ -30,6 +80,7 @@ + fig.subplots_adjust(left=0.15, right=0.95, top=0.95, bottom=0.15) + for extension in ('pdf', 'png'): + fig.savefig("quantum_well_result." + extension, dpi=_defs.dpi) + #HIDDEN_END_sqvr def main(): @@ -41,3 +92,12 @@ # Finalize the system. syst = syst.finalized() + # We should see conductance steps. + plot_conductance(syst, energy=0.2, + welldepths=[0.01 * i for i in range(100)]) + + + # Call the main function if the script gets executed (as opposed to imported). + # See <http://docs.python.org/library/__main__.html>. + if __name__ == '__main__': + main() diff --git a/doc/source/images/quantum_wire.py.diff b/doc/source/images/quantum_wire.py.diff index 0b9aa16dfb1d1ed1765e516369899c862fb08578..396ab255359afa8c53f7790a1c53b7b9fe2de178 100644 --- a/doc/source/images/quantum_wire.py.diff +++ b/doc/source/images/quantum_wire.py.diff @@ -1,29 +1,124 @@ ---- original -+++ modified -@@ -11,6 +11,7 @@ +@@ -1,121 +1,130 @@ + # Tutorial 2.2.2. Transport through a quantum wire + # ================================================ + # + # Physics background + # ------------------ + # Conductance of a quantum wire; subbands + # + # Kwant features highlighted + # -------------------------- + # - Builder for setting up transport systems easily # - Making scattering region and leads # - Using the simple sparse solver for computing Landauer conductance +import _defs from matplotlib import pyplot + #HIDDEN_BEGIN_dwhx import kwant + #HIDDEN_END_dwhx + + # First, define the tight-binding system + + #HIDDEN_BEGIN_goiq + syst = kwant.Builder() + #HIDDEN_END_goiq + + # Here, we are only working with square lattices + #HIDDEN_BEGIN_suwo + a = 1 + lat = kwant.lattice.square(a) + #HIDDEN_END_suwo + + #HIDDEN_BEGIN_zfvr + t = 1.0 + W = 10 + L = 30 + + # Define the scattering region + + for i in range(L): + for j in range(W): + # On-site Hamiltonian + syst[lat(i, j)] = 4 * t + + # Hopping in y-direction + if j > 0: + syst[lat(i, j), lat(i, j - 1)] = -t + + # Hopping in x-direction + if i > 0: + syst[lat(i, j), lat(i - 1, j)] = -t + #HIDDEN_END_zfvr + + # Then, define and attach the leads: + + # First the lead to the left + # (Note: TranslationalSymmetry takes a real-space vector) + #HIDDEN_BEGIN_xcmc + sym_left_lead = kwant.TranslationalSymmetry((-a, 0)) + left_lead = kwant.Builder(sym_left_lead) + #HIDDEN_END_xcmc + + #HIDDEN_BEGIN_ndez + for j in range(W): + left_lead[lat(0, j)] = 4 * t + if j > 0: + left_lead[lat(0, j), lat(0, j - 1)] = -t + left_lead[lat(1, j), lat(0, j)] = -t + #HIDDEN_END_ndez + + #HIDDEN_BEGIN_fskr + syst.attach_lead(left_lead) + #HIDDEN_END_fskr + + # Then the lead to the right + #HIDDEN_BEGIN_xhqc + sym_right_lead = kwant.TranslationalSymmetry((a, 0)) + right_lead = kwant.Builder(sym_right_lead) + + for j in range(W): + right_lead[lat(0, j)] = 4 * t + if j > 0: + right_lead[lat(0, j), lat(0, j - 1)] = -t + right_lead[lat(1, j), lat(0, j)] = -t -@@ -69,7 +70,10 @@ syst.attach_lead(right_lead) + #HIDDEN_END_xhqc # Plot it, to make sure it's OK + #HIDDEN_BEGIN_wsgh -kwant.plot(syst) +size = (_defs.figwidth_in, 0.3 * _defs.figwidth_in) +for extension in ('pdf', 'png'): + kwant.plot(syst, file="quantum_wire_syst." + extension, + fig_size=size, dpi=_defs.dpi) + #HIDDEN_END_wsgh # Finalize the system + #HIDDEN_BEGIN_dngj syst = syst.finalized() -@@ -90,8 +94,13 @@ + #HIDDEN_END_dngj + + # Now that we have the system, we can compute conductance + #HIDDEN_BEGIN_buzn + energies = [] + data = [] + for ie in range(100): + energy = ie * 0.01 + + # compute the scattering matrix at a given energy + smatrix = kwant.smatrix(syst, energy) + + # compute the transmission probability from lead 0 to + # lead 1 + energies.append(energy) + data.append(smatrix.transmission(1, 0)) + #HIDDEN_END_buzn # Use matplotlib to write output # We should see conductance steps + #HIDDEN_BEGIN_lliv -pyplot.figure() +fig = pyplot.figure() pyplot.plot(energies, data) @@ -38,3 +133,4 @@ +fig.subplots_adjust(left=0.15, right=0.95, top=0.95, bottom=0.15) +for extension in ('pdf', 'png'): + fig.savefig("quantum_wire_result." + extension, dpi=_defs.dpi) + #HIDDEN_END_lliv diff --git a/doc/source/images/spin_orbit.py.diff b/doc/source/images/spin_orbit.py.diff index a044351f55751cd6b833b4ad6851ebdbbd2cb380..ba32e81221f498d1b7057502b566632fbdf202df 100644 --- a/doc/source/images/spin_orbit.py.diff +++ b/doc/source/images/spin_orbit.py.diff @@ -1,6 +1,16 @@ ---- original -+++ modified -@@ -13,6 +13,7 @@ +@@ -1,104 +1,110 @@ + # Tutorial 2.3.1. Matrix structure of on-site and hopping elements + # ================================================================ + # + # Physics background + # ------------------ + # Gaps in quantum wires with spin-orbit coupling and Zeeman splititng, + # as theoretically predicted in + # http://prl.aps.org/abstract/PRL/v90/i25/e256601 + # and (supposedly) experimentally oberved in + # http://www.nature.com/nphys/journal/v6/n5/abs/nphys1626.html + # + # Kwant features highlighted # -------------------------- # - Numpy matrices as values in Builder @@ -8,7 +18,65 @@ import kwant # For plotting -@@ -70,19 +71,24 @@ + from matplotlib import pyplot + + # For matrix support + #HIDDEN_BEGIN_xumz + import tinyarray + #HIDDEN_END_xumz + + # define Pauli-matrices for convenience + #HIDDEN_BEGIN_hwbt + sigma_0 = tinyarray.array([[1, 0], [0, 1]]) + sigma_x = tinyarray.array([[0, 1], [1, 0]]) + sigma_y = tinyarray.array([[0, -1j], [1j, 0]]) + sigma_z = tinyarray.array([[1, 0], [0, -1]]) + #HIDDEN_END_hwbt + + + def make_system(a=1, t=1.0, alpha=0.5, e_z=0.08, W=10, L=30): + # Start with an empty tight-binding system and a single square lattice. + # `a` is the lattice constant (by default set to 1 for simplicity). + lat = kwant.lattice.square(a) + + syst = kwant.Builder() + + #### Define the scattering region. #### + #HIDDEN_BEGIN_uxrm + syst[(lat(x, y) for x in range(L) for y in range(W))] = \ + 4 * t * sigma_0 + e_z * sigma_z + # hoppings in x-direction + syst[kwant.builder.HoppingKind((1, 0), lat, lat)] = \ + -t * sigma_0 - 1j * alpha * sigma_y + # hoppings in y-directions + syst[kwant.builder.HoppingKind((0, 1), lat, lat)] = \ + -t * sigma_0 + 1j * alpha * sigma_x + #HIDDEN_END_uxrm + + #### Define the left lead. #### + lead = kwant.Builder(kwant.TranslationalSymmetry((-a, 0))) + + #HIDDEN_BEGIN_yliu + lead[(lat(0, j) for j in range(W))] = 4 * t * sigma_0 + e_z * sigma_z + # hoppings in x-direction + lead[kwant.builder.HoppingKind((1, 0), lat, lat)] = \ + -t * sigma_0 - 1j * alpha * sigma_y + # hoppings in y-directions + lead[kwant.builder.HoppingKind((0, 1), lat, lat)] = \ + -t * sigma_0 + 1j * alpha * sigma_x + #HIDDEN_END_yliu + + #### Attach the leads and return the finalized system. #### + syst.attach_lead(lead) + syst.attach_lead(lead.reversed()) + + return syst + + + def plot_conductance(syst, energies): + # Compute conductance + data = [] + for energy in energies: smatrix = kwant.smatrix(syst, energy) data.append(smatrix.transmission(1, 0)) @@ -40,3 +108,11 @@ # Finalize the system. syst = syst.finalized() + # We should see non-monotonic conductance steps. + plot_conductance(syst, energies=[0.01 * i - 0.3 for i in range(100)]) + + + # Call the main function if the script gets executed (as opposed to imported). + # See <http://docs.python.org/library/__main__.html>. + if __name__ == '__main__': + main() diff --git a/doc/source/images/superconductor.py.diff b/doc/source/images/superconductor.py.diff index 06bf2198fb7a378d02170d9eff225c6bfcf4e0c5..156bdac66a114f713af8edc5d65d68da572df0bc 100644 --- a/doc/source/images/superconductor.py.diff +++ b/doc/source/images/superconductor.py.diff @@ -1,6 +1,14 @@ ---- original -+++ modified -@@ -11,6 +11,7 @@ +@@ -1,132 +1,141 @@ + # Tutorial 2.6. "Superconductors": orbitals, conservation laws and symmetries + # =========================================================================== + # + # Physics background + # ------------------ + # - conductance of a NS-junction (Andreev reflection, superconducting gap) + # + # Kwant features highlighted + # -------------------------- + # - Implementing electron and hole ("orbital") degrees of freedom # using conservation laws. # - Use of discrete symmetries to relate scattering states. @@ -8,7 +16,7 @@ import kwant import tinyarray -@@ -18,6 +19,7 @@ + import numpy as np # For plotting from matplotlib import pyplot @@ -16,10 +24,67 @@ tau_x = tinyarray.array([[0, 1], [1, 0]]) tau_y = tinyarray.array([[0, -1j], [1j, 0]]) -@@ -74,11 +76,19 @@ + tau_z = tinyarray.array([[1, 0], [0, -1]]) + + #HIDDEN_BEGIN_nbvn + def make_system(a=1, W=10, L=10, barrier=1.5, barrierpos=(3, 4), + mu=0.4, Delta=0.1, Deltapos=4, t=1.0, phs=True): + # Start with an empty tight-binding system. On each site, there + # are now electron and hole orbitals, so we must specify the + # number of orbitals per site. The orbital structure is the same + # as in the Hamiltonian. + lat = kwant.lattice.square(norbs=2) + syst = kwant.Builder() + + #### Define the scattering region. #### + # The superconducting order parameter couples electron and hole orbitals + # on each site, and hence enters as an onsite potential. + # The pairing is only included beyond the point 'Deltapos' in the scattering region. + syst[(lat(x, y) for x in range(Deltapos) for y in range(W))] = (4 * t - mu) * tau_z + syst[(lat(x, y) for x in range(Deltapos, L) for y in range(W))] = (4 * t - mu) * tau_z + Delta * tau_x + + # The tunnel barrier + syst[(lat(x, y) for x in range(barrierpos[0], barrierpos[1]) + for y in range(W))] = (4 * t + barrier - mu) * tau_z + + # Hoppings + syst[lat.neighbors()] = -t * tau_z + #HIDDEN_END_nbvn + #HIDDEN_BEGIN_ttth + #### Define the leads. #### + # Left lead - normal, so the order parameter is zero. + sym_left = kwant.TranslationalSymmetry((-a, 0)) + # Specify the conservation law used to treat electrons and holes separately. + # We only do this in the left lead, where the pairing is zero. + lead0 = kwant.Builder(sym_left, conservation_law=-tau_z, particle_hole=tau_y) + lead0[(lat(0, j) for j in range(W))] = (4 * t - mu) * tau_z + lead0[lat.neighbors()] = -t * tau_z + #HIDDEN_END_ttth + #HIDDEN_BEGIN_zuuw + # Right lead - superconducting, so the order parameter is included. + sym_right = kwant.TranslationalSymmetry((a, 0)) + lead1 = kwant.Builder(sym_right) + lead1[(lat(0, j) for j in range(W))] = (4 * t - mu) * tau_z + Delta * tau_x + lead1[lat.neighbors()] = -t * tau_z + + #### Attach the leads and return the system. #### + syst.attach_lead(lead0) + syst.attach_lead(lead1) + + return syst + #HIDDEN_END_zuuw + + #HIDDEN_BEGIN_jbjt + def plot_conductance(syst, energies): + # Compute conductance + data = [] + for energy in energies: + smatrix = kwant.smatrix(syst, energy) + # Conductance is N - R_ee + R_he data.append(smatrix.submatrix((0, 0), (0, 0)).shape[0] - smatrix.transmission((0, 0), (0, 0)) + smatrix.transmission((0, 1), (0, 0))) + #HIDDEN_END_jbjt - pyplot.figure() + fig = pyplot.figure() pyplot.plot(energies, data) @@ -36,9 +101,28 @@ + fig.savefig("superconductor_transport_result." + extension, + dpi=_defs.dpi) + #HIDDEN_BEGIN_pqmp def check_PHS(syst): # Scattering matrix -@@ -103,14 +113,13 @@ + s = kwant.smatrix(syst, energy=0) + # Electron to electron block + s_ee = s.submatrix((0,0), (0,0)) + # Hole to hole block + s_hh = s.submatrix((0,1), (0,1)) + print('s_ee: \n', np.round(s_ee, 3)) + print('s_hh: \n', np.round(s_hh[::-1, ::-1], 3)) + print('s_ee - s_hh^*: \n', + np.round(s_ee - s_hh[::-1, ::-1].conj(), 3), '\n') + # Electron to hole block + s_he = s.submatrix((0,1), (0,0)) + # Hole to electron block + s_eh = s.submatrix((0,0), (0,1)) + print('s_he: \n', np.round(s_he, 3)) + print('s_eh: \n', np.round(s_eh[::-1, ::-1], 3)) + print('s_he + s_eh^*: \n', + np.round(s_he + s_eh[::-1, ::-1].conj(), 3)) + #HIDDEN_END_pqmp + def main(): syst = make_system(W=10) @@ -56,3 +140,9 @@ # Compute and plot the conductance plot_conductance(syst, energies=[0.002 * i for i in range(-10, 100)]) + + + # Call the main function if the script gets executed (as opposed to imported). + # See <http://docs.python.org/library/__main__.html>. + if __name__ == '__main__': + main() diff --git a/doc/source/tutorial/README b/doc/source/tutorial/README deleted file mode 100644 index 974ae08b427a7f8e2974b88f6ff869a931aea40c..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/README +++ /dev/null @@ -1,11 +0,0 @@ -Note for Kwant developers -------------------------- - -Say you have modified SCRIPT.py in this directory. Make sure that the tutorial -image generation patches still apply by deleting doc/source/images/SCRIPT.py -and running ``make doc/source/images/SCRIPT.py`` in doc. Now examine the newly -created doc/source/images/SCRIPT.py. If you do not like the result or the -patch did not apply, edit doc/source/images/SCRIPT.py until you like it. You -can run `make html` during your edits to check things. Finally, even if you -did not edit the script, execute generate-diffs.sh in doc/source/images. If -the patches applied cleanly the diff files will usually stay unchanged. diff --git a/doc/source/tutorial/ab_ring.py b/doc/source/tutorial/ab_ring.py deleted file mode 100644 index 2af92ec9c659812649911ea4586b615525cede85..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/ab_ring.py +++ /dev/null @@ -1,127 +0,0 @@ -# Tutorial 2.3.3. Nontrivial shapes -# ================================= -# -# Physics background -# ------------------ -# Flux-dependent transmission through a quantum ring -# -# Kwant features highlighted -# -------------------------- -# - More complex shapes with lattices -# - Allows for discussion of subtleties of `attach_lead` (not in the -# example, but in the tutorial main text) -# - Modifcations of hoppings/sites after they have been added - -from cmath import exp -from math import pi - -import kwant - -# For plotting -from matplotlib import pyplot - - -#HIDDEN_BEGIN_eusz -def make_system(a=1, t=1.0, W=10, r1=10, r2=20): - # Start with an empty tight-binding system and a single square lattice. - # `a` is the lattice constant (by default set to 1 for simplicity). - - lat = kwant.lattice.square(a) - - syst = kwant.Builder() - - #### Define the scattering region. #### - # Now, we aim for a more complex shape, namely a ring (or annulus) - def ring(pos): - (x, y) = pos - rsq = x ** 2 + y ** 2 - return (r1 ** 2 < rsq < r2 ** 2) -#HIDDEN_END_eusz - - # and add the corresponding lattice points using the `shape`-function -#HIDDEN_BEGIN_lcak - syst[lat.shape(ring, (0, r1 + 1))] = 4 * t - syst[lat.neighbors()] = -t -#HIDDEN_END_lcak - - # In order to introduce a flux through the ring, we introduce a phase on - # the hoppings on the line cut through one of the arms. Since we want to - # change the flux without modifying the Builder instance repeatedly, we - # define the modified hoppings as a function that takes the flux as its - # parameter phi. -#HIDDEN_BEGIN_lvkt - def hopping_phase(site1, site2, phi): - return -t * exp(1j * phi) - - def crosses_branchcut(hop): - ix0, iy0 = hop[0].tag - - # builder.HoppingKind with the argument (1, 0) below - # returns hoppings ordered as ((i+1, j), (i, j)) - return iy0 < 0 and ix0 == 1 # ix1 == 0 then implied - - # Modify only those hopings in x-direction that cross the branch cut - def hops_across_cut(syst): - for hop in kwant.builder.HoppingKind((1, 0), lat, lat)(syst): - if crosses_branchcut(hop): - yield hop - syst[hops_across_cut] = hopping_phase -#HIDDEN_END_lvkt - - #### Define the leads. #### - # left lead -#HIDDEN_BEGIN_qwgr - sym_lead = kwant.TranslationalSymmetry((-a, 0)) - lead = kwant.Builder(sym_lead) - - def lead_shape(pos): - (x, y) = pos - return (-W / 2 < y < W / 2) - - lead[lat.shape(lead_shape, (0, 0))] = 4 * t - lead[lat.neighbors()] = -t -#HIDDEN_END_qwgr - - #### Attach the leads and return the system. #### -#HIDDEN_BEGIN_skbz - syst.attach_lead(lead) - syst.attach_lead(lead.reversed()) -#HIDDEN_END_skbz - - return syst - - -def plot_conductance(syst, energy, fluxes): - # compute conductance - - normalized_fluxes = [flux / (2 * pi) for flux in fluxes] - data = [] - for flux in fluxes: - smatrix = kwant.smatrix(syst, energy, args=[flux]) - data.append(smatrix.transmission(1, 0)) - - pyplot.figure() - pyplot.plot(normalized_fluxes, data) - pyplot.xlabel("flux [flux quantum]") - pyplot.ylabel("conductance [e^2/h]") - pyplot.show() - - -def main(): - syst = make_system() - - # Check that the system looks as intended. - kwant.plot(syst) - - # Finalize the system. - syst = syst.finalized() - - # We should see a conductance that is periodic with the flux quantum - plot_conductance(syst, energy=0.15, fluxes=[0.01 * i * 3 * 2 * pi - for i in range(100)]) - - -# Call the main function if the script gets executed (as opposed to imported). -# See <http://docs.python.org/library/__main__.html>. -if __name__ == '__main__': - main() diff --git a/doc/source/tutorial/band_structure.py b/doc/source/tutorial/band_structure.py deleted file mode 100644 index 5b223d3e96f0f474e7b684f2eae779c160698388..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/band_structure.py +++ /dev/null @@ -1,52 +0,0 @@ -# Tutorial 2.4.1. Band structure calculations -# =========================================== -# -# Physics background -# ------------------ -# band structure of a simple quantum wire in tight-binding approximation -# -# Kwant features highlighted -# -------------------------- -# - Computing the band structure of a finalized lead. - -import kwant - -# For plotting. -from matplotlib import pyplot - -#HIDDEN_BEGIN_zxip -def make_lead(a=1, t=1.0, W=10): - # Start with an empty lead with a single square lattice - lat = kwant.lattice.square(a) - - sym_lead = kwant.TranslationalSymmetry((-a, 0)) - lead = kwant.Builder(sym_lead) - - # build up one unit cell of the lead, and add the hoppings - # to the next unit cell - for j in range(W): - lead[lat(0, j)] = 4 * t - - if j > 0: - lead[lat(0, j), lat(0, j - 1)] = -t - - lead[lat(1, j), lat(0, j)] = -t - - return lead -#HIDDEN_END_zxip - - -#HIDDEN_BEGIN_pejz -def main(): - lead = make_lead().finalized() - kwant.plotter.bands(lead, show=False) - pyplot.xlabel("momentum [(lattice constant)^-1]") - pyplot.ylabel("energy [t]") - pyplot.show() -#HIDDEN_END_pejz - - -# Call the main function if the script gets executed (as opposed to imported). -# See <http://docs.python.org/library/__main__.html>. -if __name__ == '__main__': - main() diff --git a/doc/source/tutorial/closed_system.py b/doc/source/tutorial/closed_system.py deleted file mode 100644 index b192b18374981d45a3e98f23eeeb179fbe2c9295..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/closed_system.py +++ /dev/null @@ -1,140 +0,0 @@ -# Tutorial 2.4.2. Closed systems -# ============================== -# -# Physics background -# ------------------ -# Fock-darwin spectrum of a quantum dot (energy spectrum in -# as a function of a magnetic field) -# -# Kwant features highlighted -# -------------------------- -# - Use of `hamiltonian_submatrix` in order to obtain a Hamiltonian -# matrix. - -from cmath import exp -import numpy as np -import kwant - -# For eigenvalue computation -#HIDDEN_BEGIN_tibv -import scipy.sparse.linalg as sla -#HIDDEN_END_tibv - -# For plotting -from matplotlib import pyplot - - -def make_system(a=1, t=1.0, r=10): - # Start with an empty tight-binding system and a single square lattice. - # `a` is the lattice constant (by default set to 1 for simplicity). - -#HIDDEN_BEGIN_qlyd - lat = kwant.lattice.square(a, norbs=1) - - syst = kwant.Builder() - - # Define the quantum dot - def circle(pos): - (x, y) = pos - rsq = x ** 2 + y ** 2 - return rsq < r ** 2 - - def hopx(site1, site2, B=0): - # The magnetic field is controlled by the parameter B - y = site1.pos[1] - return -t * exp(-1j * B * y) - - syst[lat.shape(circle, (0, 0))] = 4 * t - # hoppings in x-direction - syst[kwant.builder.HoppingKind((1, 0), lat, lat)] = hopx - # hoppings in y-directions - syst[kwant.builder.HoppingKind((0, 1), lat, lat)] = -t - - # It's a closed system for a change, so no leads - return syst -#HIDDEN_END_qlyd - - -#HIDDEN_BEGIN_yvri -def plot_spectrum(syst, Bfields): - - # In the following, we compute the spectrum of the quantum dot - # using dense matrix methods. This works in this toy example, as - # the system is tiny. In a real example, one would want to use - # sparse matrix methods - - energies = [] - for B in Bfields: - # Obtain the Hamiltonian as a dense matrix - ham_mat = syst.hamiltonian_submatrix(args=[B], sparse=True) - - # we only calculate the 15 lowest eigenvalues - ev = sla.eigsh(ham_mat, k=15, which='SM', return_eigenvectors=False) - - energies.append(ev) - - pyplot.figure() - pyplot.plot(Bfields, energies) - pyplot.xlabel("magnetic field [arbitrary units]") - pyplot.ylabel("energy [t]") - pyplot.show() -#HIDDEN_END_yvri - - -#HIDDEN_BEGIN_wave -def plot_wave_function(syst): - # Calculate the wave functions in the system. - ham_mat = syst.hamiltonian_submatrix(sparse=True) - evecs = sla.eigsh(ham_mat, k=20, which='SM')[1] - - # Plot the probability density of the 10th eigenmode. - kwant.plotter.map(syst, np.abs(evecs[:, 9])**2, - colorbar=False, oversampling=1) -#HIDDEN_END_wave - - -#HIDDEN_BEGIN_current -def plot_current(syst): - # Calculate the wave functions in the system. - ham_mat = syst.hamiltonian_submatrix(sparse=True) - evecs = sla.eigsh(ham_mat, k=20, which='SM')[1] - - # Calculate and plot the local current of the 10th eigenmode. - J = kwant.operator.Current(syst) - current = J(evecs[:, 9]) - kwant.plotter.current(syst, current, colorbar=False) -#HIDDEN_END_current - - -def main(): - syst = make_system() - - # Check that the system looks as intended. - kwant.plot(syst) - - # Finalize the system. - syst = syst.finalized() - - # The following try-clause can be removed once SciPy 0.9 becomes uncommon. - try: - # We should observe energy levels that flow towards Landau - # level energies with increasing magnetic field. - plot_spectrum(syst, [iB * 0.002 for iB in range(100)]) - - # Plot an eigenmode of a circular dot. Here we create a larger system for - # better spatial resolution. - syst = make_system(r=30).finalized() - plot_wave_function(syst) - plot_current(syst) - except ValueError as e: - if e.message == "Input matrix is not real-valued.": - print("The calculation of eigenvalues failed because of a bug in SciPy 0.9.") - print("Please upgrade to a newer version of SciPy.") - else: - raise - - -# Call the main function if the script gets executed (as opposed to imported). -# See <http://docs.python.org/library/__main__.html>. -if __name__ == '__main__': - main() diff --git a/doc/source/tutorial/discretize.py b/doc/source/tutorial/discretize.py deleted file mode 100644 index 03c04db3ec3da9c1a4782ce8dac7c214179d1cdc..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/discretize.py +++ /dev/null @@ -1,222 +0,0 @@ -# Tutorial 2.9. Processing continuum Hamiltonians with discretize -# =============================================================== -# -# Physics background -# ------------------ -# - tight-binding approximation of continuous Hamiltonians -# -# Kwant features highlighted -# -------------------------- -# - kwant.continuum.discretize - - -import kwant -import scipy.sparse.linalg -import scipy.linalg -import numpy as np - -# For plotting -import matplotlib as mpl -from matplotlib import pyplot as plt - - -def stadium_system(L=20, W=20): -#HIDDEN_BEGIN_template - hamiltonian = "k_x**2 + k_y**2 + V(x, y)" - template = kwant.continuum.discretize(hamiltonian) - print(template) -#HIDDEN_END_template - -#HIDDEN_BEGIN_fill - def stadium(site): - (x, y) = site.pos - x = max(abs(x) - 20, 0) - return x**2 + y**2 < 30**2 - - syst = kwant.Builder() - syst.fill(template, stadium, (0, 0)); - syst = syst.finalized() -#HIDDEN_END_fill - return syst - - -#HIDDEN_BEGIN_plot_eigenstate -def plot_eigenstate(syst, n=2, Vx=.0003, Vy=.0005): - - def potential(x, y): - return Vx * x + Vy * y - - ham = syst.hamiltonian_submatrix(params=dict(V=potential), sparse=True) - evecs = scipy.sparse.linalg.eigsh(ham, k=10, which='SM')[1] - kwant.plotter.map(syst, abs(evecs[:, n])**2, show=False) -#HIDDEN_END_plot_eigenstate - plt.show() - - -def qsh_system(a=20, L=2000, W=1000): -#HIDDEN_BEGIN_define_qsh - hamiltonian = """ - + C * identity(4) + M * kron(sigma_0, sigma_z) - - B * (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) - """ - - template = kwant.continuum.discretize(hamiltonian, grid_spacing=a) -#HIDDEN_END_define_qsh - -#HIDDEN_BEGIN_define_qsh_build - def shape(site): - (x, y) = site.pos - return (0 <= y < W and 0 <= x < L) - - def lead_shape(site): - (x, y) = site.pos - return (0 <= y < W) - - syst = kwant.Builder() - syst.fill(template, shape, (0, 0)) - - lead = kwant.Builder(kwant.TranslationalSymmetry([-a, 0])) - lead.fill(template, lead_shape, (0, 0)) - - syst.attach_lead(lead) - syst.attach_lead(lead.reversed()) - - syst = syst.finalized() -#HIDDEN_END_define_qsh_build - return syst - - -def analyze_qsh(): - params = dict(A=3.65, B=-68.6, D=-51.1, M=-0.01, C=0) - syst = qsh_system() - -#HIDDEN_BEGIN_plot_qsh_band - kwant.plotter.bands(syst.leads[0], params=params, - momenta=np.linspace(-0.3, 0.3, 201), show=False) -#HIDDEN_END_plot_qsh_band - - plt.grid() - plt.xlim(-.3, 0.3) - plt.ylim(-0.05, 0.05) - plt.xlabel('momentum [1/A]') - plt.ylabel('energy [eV]') - plt.show() -#HIDDEN_BEGIN_plot_qsh_wf - # get scattering wave functions at E=0 - wf = kwant.wave_function(syst, energy=0, params=params) - - # prepare density operators - sigma_z = np.array([[1, 0], [0, -1]]) - prob_density = kwant.operator.Density(syst, np.eye(4)) - spin_density = kwant.operator.Density(syst, np.kron(sigma_z, np.eye(2))) - - # calculate expectation values and plot them - wf_sqr = sum(prob_density(psi) for psi in wf(0)) # states from left lead - rho_sz = sum(spin_density(psi) for psi in wf(0)) # states from left lead - - fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(16, 4)) - kwant.plotter.map(syst, wf_sqr, ax=ax1) - kwant.plotter.map(syst, rho_sz, ax=ax2) -#HIDDEN_END_plot_qsh_wf - ax = ax1 - im = [obj for obj in ax.get_children() - if isinstance(obj, mpl.image.AxesImage)][0] - fig.colorbar(im, ax=ax) - - ax = ax2 - im = [obj for obj in ax.get_children() - if isinstance(obj, mpl.image.AxesImage)][0] - fig.colorbar(im, ax=ax) - - ax1.set_title('Probability density') - ax2.set_title('Spin density') - plt.show() - - -def lattice_spacing(): -#HIDDEN_BEGIN_ls_def - hamiltonian = "k_x**2 * identity(2) + alpha * k_x * sigma_y" - params = dict(alpha=.5) -#HIDDEN_END_ls_def - - def plot(ax, a=1): -#HIDDEN_BEGIN_ls_hk_cont - h_k = kwant.continuum.lambdify(hamiltonian, locals=params) - k_cont = np.linspace(-4, 4, 201) - e_cont = [scipy.linalg.eigvalsh(h_k(k_x=ki)) for ki in k_cont] -#HIDDEN_END_ls_hk_cont - -#HIDDEN_BEGIN_ls_hk_tb - template = kwant.continuum.discretize(hamiltonian, grid_spacing=a) - syst = kwant.wraparound.wraparound(template).finalized() - - def h_k(k_x): - p = dict(k_x=k_x, **params) - return syst.hamiltonian_submatrix(params=p) - - k_tb = np.linspace(-np.pi/a, np.pi/a, 201) - e_tb = [scipy.linalg.eigvalsh(h_k(k_x=a*ki)) for ki in k_tb] -#HIDDEN_END_ls_hk_tb - - ax.plot(k_cont, e_cont, 'r-') - ax.plot(k_tb, e_tb, 'k-') - - ax.plot([], [], 'r-', label='continuum') - ax.plot([], [], 'k-', label='tight-binding') - - ax.set_xlim(-4, 4) - ax.set_ylim(-1, 14) - ax.set_title('a={}'.format(a)) - - ax.set_xlabel('momentum [a.u.]') - ax.set_ylabel('energy [a.u.]') - ax.grid() - ax.legend() - - _, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(12, 4)) - - plot(ax1, a=1) - plot(ax2, a=.25) - plt.show() - - -def substitutions(): -#HIDDEN_BEGIN_subs_1 - sympify = kwant.continuum.sympify - subs = {'sx': [[0, 1], [1, 0]], 'sz': [[1, 0], [0, -1]]} - - e = ( - sympify('[[k_x**2, alpha * k_x], [k_x * alpha, -k_x**2]]'), - sympify('k_x**2 * sigma_z + alpha * k_x * sigma_x'), - sympify('k_x**2 * sz + alpha * k_x * sx', locals=subs), - ) - - print(e[0] == e[1] == e[2]) -#HIDDEN_END_subs_1 - -#HIDDEN_BEGIN_subs_2 - subs = {'A': 'A(x) + B', 'V': 'V(x) + V_0', 'C': 5} - print(sympify('k_x * A * k_x + V + C', locals=subs)) -#HIDDEN_END_subs_2 - - -def main(): -#HIDDEN_BEGIN_symbolic_discretization - template = kwant.continuum.discretize('k_x * A(x) * k_x') - print(template) -#HIDDEN_END_symbolic_discretization - - syst = stadium_system() - plot_eigenstate(syst) - - analyze_qsh() - lattice_spacing() - substitutions() - -# Call the main function if the script gets executed (as opposed to imported). -# See <http://docs.python.org/library/__main__.html>. -if __name__ == '__main__': - main() diff --git a/doc/source/tutorial/faq.py b/doc/source/tutorial/faq.py deleted file mode 100644 index 3a00860b375fbdc558e141bfeae803c4fd19ccc7..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/faq.py +++ /dev/null @@ -1,450 +0,0 @@ -# Frequently asked questions -# -# This script is a disorganized collection of code snippets. As a whole, it is -# not meant as an example of good programming practice. - -import kwant -import numpy as np -import tinyarray -import matplotlib -from matplotlib import pyplot as plt -matplotlib.rcParams['figure.figsize'] = (3.5, 3.5) - - -#### What is a Site? - -#HIDDEN_BEGIN_site -a = 1 -lat = kwant.lattice.square(a) -syst = kwant.Builder() - -syst[lat(1, 0)] = 4 -syst[lat(1, 1)] = 4 - -kwant.plot(syst) -#HIDDEN_END_site - - -#### What is a hopping? - -a = 1 -lat = kwant.lattice.square(a) -syst = kwant.Builder() - -syst[lat(1, 0)] = 4 -syst[lat(1, 1)] = 4 -#HIDDEN_BEGIN_hopping -syst[(lat(1, 0), lat(1, 1))] = 1j -#HIDDEN_END_hopping - -kwant.plot(syst) - - -#### What is a lattice? - -#HIDDEN_BEGIN_lattice_monatomic -# Two monatomic lattices -primitive_vectors = [(1, 0), (0, 1)] -lat_a = kwant.lattice.Monatomic(primitive_vectors, offset=(0, 0)) -lat_b = kwant.lattice.Monatomic(primitive_vectors, offset=(0.5, 0.5)) -# lat1 is equivalent to kwant.lattice.square() - -syst = kwant.Builder() - -syst[lat_a(0, 0)] = 4 -syst[lat_b(0, 0)] = 4 - -kwant.plot(syst) -#HIDDEN_END_lattice_monatomic - -#HIDDEN_BEGIN_lattice_polyatomic -# One polyatomic lattice containing two sublattices -lat = kwant.lattice.Polyatomic([(1, 0), (0, 1)], [(0, 0), (0.5, 0.5)]) -sub_a, sub_b = lat.sublattices -#HIDDEN_END_lattice_polyatomic - -#### How to make a hole in a system? - -#HIDDEN_BEGIN_hole -# Define the lattice and the (empty) system -a = 2 -lat = kwant.lattice.cubic(a) -syst = kwant.Builder() - -L = 10 -W = 10 -H = 2 - -# Add sites to the system in a cuboid - -syst[(lat(i, j, k) for i in range(L) for j in range(W) for k in range(H))] = 4 -kwant.plot(syst) - -# Delete sites to create a hole - -def in_hole(site): - x, y, z = site.pos / a - (L/2, W/2, H/2) # position relative to centre - return abs(x) < L / 4 and abs(y) < W / 4 - -for site in filter(in_hole, list(syst.sites())): - del syst[site] - -kwant.plot(syst) -#HIDDEN_END_hole - - -#### How can we get access to the sites of our system? - -builder = kwant.Builder() -lat = kwant.lattice.square() -builder[(lat(i, j) for i in range(3) for j in range(3))] = 4 -#HIDDEN_BEGIN_sites1 -# Before finalizing the system - -sites = list(builder.sites()) # sites() doe *not* return a list -#HIDDEN_END_sites1 -#HIDDEN_BEGIN_sites2 -# After finalizing the system -syst = builder.finalized() -sites = syst.sites # syst.sites is an actual list -#HIDDEN_END_sites2 -#HIDDEN_BEGIN_sites3 -i = syst.id_by_site[lat(0, 2)] # we want the id of the site lat(0, 2) -#HIDDEN_END_sites3 - - -#### How to plot a polyatomic lattice with different colors? - -#HIDDEN_BEGIN_colors1 -lat = kwant.lattice.kagome() -syst = kwant.Builder() - -a, b, c = lat.sublattices # The kagome lattice has 3 sublattices -#HIDDEN_END_colors1 - -#HIDDEN_BEGIN_colors2 -# Plot sites from different families in different colors -def family_color(site): - if site.family == a: - return 'red' - if site.family == b: - return 'green' - else: - return 'blue' - -def plot_system(syst): - kwant.plot(syst, site_lw=0.1, site_color=family_color) - -## Add sites and hoppings. -for i in range(4): - for j in range (4): - syst[a(i, j)] = 4 - syst[b(i, j)] = 4 - syst[c(i, j)] = 4 - -syst[lat.neighbors()] = -1 - -## Plot the system. -plot_system(syst) -#HIDDEN_END_colors2 - - -#### How to create all hoppings in a given direction using Hoppingkind? - -# Monatomic lattice - -#HIDDEN_BEGIN_direction1 -# Create hopping between neighbors with HoppingKind -a = 1 -syst = kwant.Builder() -lat = kwant.lattice.square(a) -syst[ (lat(i, j) for i in range(5) for j in range(5)) ] = 4 - -syst[kwant.builder.HoppingKind((1, 0), lat)] = -1 -kwant.plot(syst) -#HIDDEN_END_direction1 - -# Polyatomic lattice - -lat = kwant.lattice.kagome() -syst = kwant.Builder() - -a, b, c = lat.sublattices # The kagome lattice has 3 sublattices - -def family_color(site): - if site.family == a: - return 'red' - if site.family == b: - return 'green' - else: - return 'blue' - -def plot_system(syst): - kwant.plot(syst, site_size=0.15, site_lw=0.05, site_color=family_color) - - -for i in range(4): - for j in range (4): - syst[a(i, j)] = 4 - syst[b(i, j)] = 4 - syst[c(i, j)] = 4 - - -#HIDDEN_BEGIN_direction2 -# equivalent to syst[kwant.builder.HoppingKind((0, 1), b)] = -1 -syst[kwant.builder.HoppingKind((0, 1), b, b)] = -1 -#HIDDEN_END_direction2 -plot_system(syst) -# Delete the hoppings previously created -del syst[kwant.builder.HoppingKind((0, 1), b, b)] -#HIDDEN_BEGIN_direction3 -syst[kwant.builder.HoppingKind((0, 0), a, b)] = -1 -syst[kwant.builder.HoppingKind((0, 0), a, c)] = -1 -syst[kwant.builder.HoppingKind((0, 0), c, b)] = -1 -#HIDDEN_END_direction3 -plot_system(syst) - - -#### How to create the hoppings between adjacent sites? - -# Monatomic lattice - -#HIDDEN_BEGIN_adjacent1 -# Create hoppings with lat.neighbors() -syst = kwant.Builder() -lat = kwant.lattice.square() -syst[(lat(i, j) for i in range(3) for j in range(3))] = 4 - -syst[lat.neighbors()] = -1 # Equivalent to lat.neighbors(1) -kwant.plot(syst) - -del syst[lat.neighbors()] # Delete all nearest-neighbor hoppings -syst[lat.neighbors(2)] = -1 - -kwant.plot(syst) -#HIDDEN_END_adjacent1 - -# Polyatomic lattice - -#HIDDEN_BEGIN_FAQ6 - -# Hoppings using .neighbors() -#HIDDEN_BEGIN_adjacent2 -# Create the system -lat = kwant.lattice.kagome() -syst = kwant.Builder() -a, b, c = lat.sublattices # The kagome lattice has 3 sublattices - -for i in range(4): - for j in range (4): - syst[a(i, j)] = 4 # red - syst[b(i, j)] = 4 # green - syst[c(i, j)] = 4 # blue - -syst[lat.neighbors()] = -1 -#HIDDEN_END_adjacent2 -plot_system(syst) -del syst[lat.neighbors()] # Delete the hoppings previously created -#HIDDEN_BEGIN_adjacent3 -syst[a.neighbors()] = -1 -#HIDDEN_END_adjacent3 -plot_system(syst) -del syst[a.neighbors()] # Delete the hoppings previously created - - -syst[lat.neighbors(2)] = -1 -plot_system(syst) -del syst[lat.neighbors(2)] - - -#### How to create a lead with a lattice different from the scattering region? - -# Plot sites from different families in different colors - -def plot_system(syst): - - def family_color(site): - if site.family == subA: - return 'blue' - if site.family == subB: - return 'yellow' - else: - return 'green' - - kwant.plot(syst, site_lw=0.1, site_color=family_color) - - -#HIDDEN_BEGIN_different_lattice1 -# Define the scattering Region -L = 5 -W = 5 - -lat = kwant.lattice.honeycomb() -subA, subB = lat.sublattices - -syst = kwant.Builder() -syst[(subA(i, j) for i in range(L) for j in range(W))] = 4 -syst[(subB(i, j) for i in range(L) for j in range(W))] = 4 -syst[lat.neighbors()] = -1 -#HIDDEN_END_different_lattice1 -plot_system(syst) - -#HIDDEN_BEGIN_different_lattice2 -# Create a lead -lat_lead = kwant.lattice.square() -sym_lead1 = kwant.TranslationalSymmetry((0, 1)) - -lead1 = kwant.Builder(sym_lead1) -lead1[(lat_lead(i, 0) for i in range(2, 7))] = 4 -lead1[lat_lead.neighbors()] = -1 -#HIDDEN_END_different_lattice2 -plot_system(lead1) - -#HIDDEN_BEGIN_different_lattice3 -syst[(lat_lead(i, 5) for i in range(2, 7))] = 4 -syst[lat_lead.neighbors()] = -1 - -# Manually attach sites from graphene to square lattice -syst[((lat_lead(i+2, 5), subB(i, 4)) for i in range(5))] = -1 -#HIDDEN_END_different_lattice3 -plot_system(syst) - -#HIDDEN_BEGIN_different_lattice4 -syst.attach_lead(lead1) -#HIDDEN_END_different_lattice4 -plot_system(syst) - - -#### How to cut a finite system out of a system with translationnal symmetries? - -#HIDDEN_BEGIN_fill1 -# Create 3d model. -cubic = kwant.lattice.cubic() -sym_3d = kwant.TranslationalSymmetry([1, 0, 0], [0, 1, 0], [0, 0, 1]) -model = kwant.Builder(sym_3d) -model[cubic(0, 0, 0)] = 4 -model[cubic.neighbors()] = -1 -#HIDDEN_END_fill1 - -#HIDDEN_BEGIN_fill2 -# Build scattering region (white). -def cuboid_shape(site): - x, y, z = abs(site.pos) - return x < 4 and y < 10 and z < 3 - -cuboid = kwant.Builder() -cuboid.fill(model, cuboid_shape, (0, 0, 0)); -#HIDDEN_END_fill2 -kwant.plot(cuboid); - -#HIDDEN_BEGIN_fill3 -# Build electrode (black). -def electrode_shape(site): - x, y, z = site.pos - (0, 5, 2) - return y**2 + z**2 < 2.3**2 - -electrode = kwant.Builder(kwant.TranslationalSymmetry([1, 0, 0])) -electrode.fill(model, electrode_shape, (0, 5, 2)) # lead - -# Scattering region -cuboid.fill(electrode, lambda s: abs(s.pos[0]) < 7, (0, 5, 4)) - -cuboid.attach_lead(electrode) -#HIDDEN_END_fill3 -kwant.plot(cuboid); - - -#### How does Kwant order the propagating modes of a lead? - -#HIDDEN_BEGIN_pm -lat = kwant.lattice.square() - -lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0))) -lead[(lat(0, i) for i in range(3))] = 4 -lead[lat.neighbors()] = -1 - -flead = lead.finalized() - -E = 2.5 -prop_modes, _ = flead.modes(energy=E) -#HIDDEN_END_pm - -def plot_and_label_modes(lead, E): - # Plot the different modes - pmodes, _ = lead.modes(energy=E) - kwant.plotter.bands(lead, show=False) - for i, k in enumerate(pmodes.momenta): - plt.plot(k, E, 'ko') - plt.annotate(str(i), xy=(k, E), xytext=(-5, 8), - textcoords='offset points', - bbox=dict(boxstyle='round,pad=0.1',fc='white', alpha=0.7)) - plt.plot([-3, 3], [E, E], 'r--') - plt.ylim(E-1, E+1) - plt.xlim(-2, 2) - plt.xlabel("momentum") - plt.ylabel("energy") - plt.show() - -plot_and_label_modes(flead, E) - -# More involved example - -s0 = np.eye(2) -sz = np.array([[1, 0], [0, -1]]) - -lead2 = kwant.Builder(kwant.TranslationalSymmetry((-1, 0))) - -lead2[(lat(0, i) for i in range(2))] = np.diag([1.8, -1]) -lead2[lat.neighbors()] = -1 * sz - -flead2 = lead2.finalized() - -plot_and_label_modes(flead2, 1) - - -#### How does Kwant order components of an individual wavefunction? -def circle(R): - return lambda r: np.linalg.norm(r) < R - - -def make_system(lat): - norbs = lat.norbs - syst = kwant.Builder() - syst[lat.shape(circle(3), (0, 0))] = 4 * np.eye(norbs) - syst[lat.neighbors()] = -1 * np.eye(norbs) - - lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0))) - lead[(lat(0, i) for i in range(-1, 2))] = 4 * np.eye(norbs) - lead[lat.neighbors()] = -1 * np.eye(norbs) - - syst.attach_lead(lead) - syst.attach_lead(lead.reversed()) - - return syst.finalized() - - -#HIDDEN_BEGIN_ord1 -lat = kwant.lattice.square(norbs=1) -syst = make_system(lat) -scattering_states = kwant.wave_function(syst, energy=1) -wf = scattering_states(0)[0] # scattering state from lead 0 incoming in mode 0 - -idx = syst.id_by_site[lat(0, 0)] # look up index of site - -print('wavefunction on lat(0, 0): ', wf[idx]) -#HIDDEN_END_ord1 - -#HIDDEN_BEGIN_ord2 -lat = kwant.lattice.square(norbs=2) -syst = make_system(lat) -scattering_states = kwant.wave_function(syst, energy=1) -wf = scattering_states(0)[0] # scattering state from lead 0 incoming in mode 0 - -idx = syst.id_by_site[lat(0, 0)] # look up index of site - -# Group consecutive degrees of freedom from 'wf' together; these correspond -# to degrees of freedom on the same site. -wf = wf.reshape(-1, 2) - -print('wavefunction on lat(0, 0): ', wf[idx]) -#HIDDEN_END_ord2 diff --git a/doc/source/tutorial/graphene.py b/doc/source/tutorial/graphene.py deleted file mode 100644 index 512ca7e8d68f2554299d48548769cb017427c1fd..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/graphene.py +++ /dev/null @@ -1,179 +0,0 @@ -# Tutorial 2.5. Beyond square lattices: graphene -# ============================================== -# -# Physics background -# ------------------ -# Transport through a graphene quantum dot with a pn-junction -# -# Kwant features highlighted -# -------------------------- -# - Application of all the aspects of tutorials 1-3 to a more complicated -# lattice, namely graphene - -from math import pi, sqrt, tanh - -import kwant - -# For computing eigenvalues -import scipy.sparse.linalg as sla - -# For plotting -from matplotlib import pyplot - - -# Define the graphene lattice -sin_30, cos_30 = (1 / 2, sqrt(3) / 2) -#HIDDEN_BEGIN_hnla -graphene = kwant.lattice.general([(1, 0), (sin_30, cos_30)], - [(0, 0), (0, 1 / sqrt(3))]) -a, b = graphene.sublattices -#HIDDEN_END_hnla - - -#HIDDEN_BEGIN_shzy -def make_system(r=10, w=2.0, pot=0.1): - - #### Define the scattering region. #### - # circular scattering region - def circle(pos): - x, y = pos - return x ** 2 + y ** 2 < r ** 2 - - syst = kwant.Builder() - - # w: width and pot: potential maximum of the p-n junction - def potential(site): - (x, y) = site.pos - d = y * cos_30 + x * sin_30 - return pot * tanh(d / w) - - syst[graphene.shape(circle, (0, 0))] = potential -#HIDDEN_END_shzy - - # specify the hoppings of the graphene lattice in the - # format expected by builder.HoppingKind -#HIDDEN_BEGIN_hsmc - hoppings = (((0, 0), a, b), ((0, 1), a, b), ((-1, 1), a, b)) -#HIDDEN_END_hsmc -#HIDDEN_BEGIN_bfwb - syst[[kwant.builder.HoppingKind(*hopping) for hopping in hoppings]] = -1 -#HIDDEN_END_bfwb - - # Modify the scattering region -#HIDDEN_BEGIN_efut - del syst[a(0, 0)] - syst[a(-2, 1), b(2, 2)] = -1 -#HIDDEN_END_efut - - #### Define the leads. #### -#HIDDEN_BEGIN_aakh - # left lead - sym0 = kwant.TranslationalSymmetry(graphene.vec((-1, 0))) - - def lead0_shape(pos): - x, y = pos - return (-0.4 * r < y < 0.4 * r) - - lead0 = kwant.Builder(sym0) - lead0[graphene.shape(lead0_shape, (0, 0))] = -pot - lead0[[kwant.builder.HoppingKind(*hopping) for hopping in hoppings]] = -1 - - # The second lead, going to the top right - sym1 = kwant.TranslationalSymmetry(graphene.vec((0, 1))) - - def lead1_shape(pos): - v = pos[1] * sin_30 - pos[0] * cos_30 - return (-0.4 * r < v < 0.4 * r) - - lead1 = kwant.Builder(sym1) - lead1[graphene.shape(lead1_shape, (0, 0))] = pot - lead1[[kwant.builder.HoppingKind(*hopping) for hopping in hoppings]] = -1 -#HIDDEN_END_aakh - -#HIDDEN_BEGIN_kmmw - return syst, [lead0, lead1] -#HIDDEN_END_kmmw - - -#HIDDEN_BEGIN_zydk -def compute_evs(syst): - # Compute some eigenvalues of the closed system - sparse_mat = syst.hamiltonian_submatrix(sparse=True) - - evs = sla.eigs(sparse_mat, 2)[0] - print(evs.real) -#HIDDEN_END_zydk - - -def plot_conductance(syst, energies): - # Compute transmission as a function of energy - data = [] - for energy in energies: - smatrix = kwant.smatrix(syst, energy) - data.append(smatrix.transmission(0, 1)) - - pyplot.figure() - pyplot.plot(energies, data) - pyplot.xlabel("energy [t]") - pyplot.ylabel("conductance [e^2/h]") - pyplot.show() - - -def plot_bandstructure(flead, momenta): - bands = kwant.physics.Bands(flead) - energies = [bands(k) for k in momenta] - - pyplot.figure() - pyplot.plot(momenta, energies) - pyplot.xlabel("momentum [(lattice constant)^-1]") - pyplot.ylabel("energy [t]") - pyplot.show() - - -#HIDDEN The part of the following code block which begins with family_colors -#HIDDEN is included verbatim in the tutorial text because nested code examples -#HIDDEN are not supported. Remember to update the tutorial text when you -#HIDDEN modify this block. -#HIDDEN_BEGIN_itkk -def main(): - pot = 0.1 - syst, leads = make_system(pot=pot) - - # To highlight the two sublattices of graphene, we plot one with - # a filled, and the other one with an open circle: - def family_colors(site): - return 0 if site.family == a else 1 - - # Plot the closed system without leads. - kwant.plot(syst, site_color=family_colors, site_lw=0.1, colorbar=False) -#HIDDEN_END_itkk - - # Compute some eigenvalues. -#HIDDEN_BEGIN_jmbi - compute_evs(syst.finalized()) -#HIDDEN_END_jmbi - - # Attach the leads to the system. - for lead in leads: - syst.attach_lead(lead) - - # Then, plot the system with leads. - kwant.plot(syst, site_color=family_colors, site_lw=0.1, - lead_site_lw=0, colorbar=False) - - # Finalize the system. - syst = syst.finalized() - - # Compute the band structure of lead 0. - momenta = [-pi + 0.02 * pi * i for i in range(101)] - plot_bandstructure(syst.leads[0], momenta) - - # Plot conductance. - energies = [-2 * pot + 4. / 50. * pot * i for i in range(51)] - plot_conductance(syst, energies) - - -# Call the main function if the script gets executed (as opposed to imported). -# See <http://docs.python.org/library/__main__.html>. -if __name__ == '__main__': - main() diff --git a/doc/source/tutorial/kernel_polynomial_method.py b/doc/source/tutorial/kernel_polynomial_method.py deleted file mode 100644 index 226893b45cd2f142992bbf262db7d172643628cb..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/kernel_polynomial_method.py +++ /dev/null @@ -1,219 +0,0 @@ -# Tutorial 2.8. Calculating spectral density with the Kernel Polynomial Method -# ============================================================================ -# -# Physics background -# ------------------ -# - Chebyshev polynomials, random trace approximation, spectral densities. -# -# Kwant features highlighted -# -------------------------- -# - kpm module,kwant operators. - -import scipy - -# For plotting -from matplotlib import pyplot as plt - -#HIDDEN_BEGIN_sys1 -# necessary imports -import kwant -import numpy as np - - -# define the system -def make_syst(r=30, t=-1, a=1): - syst = kwant.Builder() - lat = kwant.lattice.honeycomb(a, norbs=1) - - def circle(pos): - x, y = pos - return x ** 2 + y ** 2 < r ** 2 - - syst[lat.shape(circle, (0, 0))] = 0. - syst[lat.neighbors()] = t - syst.eradicate_dangling() - - return syst -#HIDDEN_END_sys1 - - -# Plot several density of states curves on the same axes. -def plot_dos(labels_to_data): - for label, (x, y) in labels_to_data: - plt.plot(x, y, label=label, linewidth=2) - plt.legend(loc=2, framealpha=0.5) - plt.xlabel("energy [t]") - plt.ylabel("DoS [a.u.]") - plt.show() - plt.clf() - - -def site_size_conversion(densities): - return 3 * np.abs(densities) / max(densities) - - -# Plot several local density of states maps in different subplots -def plot_ldos(fsyst, axes, titles_to_data, file_name=None): - for ax, (title, ldos) in zip(axes, titles_to_data): - site_size = site_size_conversion(ldos) # convert LDoS to sizes - kwant.plot(fsyst, site_size=site_size, site_color=(0, 0, 1, 0.3), ax=ax) - ax.set_title(title) - ax.set(adjustable='box-forced', aspect='equal') - plt.show() - plt.clf() - - -def simple_dos_example(): -#HIDDEN_BEGIN_kpm1 - fsyst = make_syst().finalized() - - spectrum = kwant.kpm.SpectralDensity(fsyst) -#HIDDEN_END_kpm1 - -#HIDDEN_BEGIN_kpm2 - energies, densities = spectrum() -#HIDDEN_END_kpm2 - -#HIDDEN_BEGIN_kpm3 - energy_subset = np.linspace(0, 2) - density_subset = spectrum(energy_subset) -#HIDDEN_END_kpm3 - - plot_dos([ - ('densities', (energies, densities)), - ('density subset', (energy_subset, density_subset)), - ]) - - -def dos_integrating_example(fsyst): - spectrum = kwant.kpm.SpectralDensity(fsyst) - -#HIDDEN_BEGIN_int1 - print('identity resolution:', spectrum.integrate()) -#HIDDEN_END_int1 - -#HIDDEN_BEGIN_int2 - # Fermi energy 0.1 and temperature 0.2 - fermi = lambda E: 1 / (np.exp((E - 0.1) / 0.2) + 1) - - print('number of filled states:', spectrum.integrate(fermi)) -#HIDDEN_END_int2 - - -def increasing_accuracy_example(fsyst): - spectrum = kwant.kpm.SpectralDensity(fsyst) - original_dos = spectrum() # get unaltered DoS - -#HIDDEN_BEGIN_acc1 - spectrum.add_moments(energy_resolution=0.03) -#HIDDEN_END_acc1 - - increased_resolution_dos = spectrum() - - plot_dos([ - ('density', original_dos), - ('higher energy resolution', increased_resolution_dos), - ]) - -#HIDDEN_BEGIN_acc2 - spectrum.add_moments(100) - spectrum.add_vectors(5) -#HIDDEN_END_acc2 - - increased_moments_dos = spectrum() - - plot_dos([ - ('density', original_dos), - ('higher number of moments', increased_moments_dos), - ]) - - -def operator_example(fsyst): -#HIDDEN_BEGIN_op1 - # identity matrix - matrix_op = scipy.sparse.eye(len(fsyst.sites)) - matrix_spectrum = kwant.kpm.SpectralDensity(fsyst, operator=matrix_op) -#HIDDEN_END_op1 - -#HIDDEN_BEGIN_op2 - # 'sum=True' means we sum over all the sites - kwant_op = kwant.operator.Density(fsyst, sum=True) - operator_spectrum = kwant.kpm.SpectralDensity(fsyst, operator=kwant_op) -#HIDDEN_END_op2 - - plot_dos([ - ('identity matrix', matrix_spectrum()), - ('kwant.operator.Density', operator_spectrum()), - ]) - - -def ldos_example(fsyst): -#HIDDEN_BEGIN_op3 - # 'sum=False' is the default, but we include it explicitly here for clarity. - kwant_op = kwant.operator.Density(fsyst, sum=False) - local_dos = kwant.kpm.SpectralDensity(fsyst, operator=kwant_op) -#HIDDEN_END_op3 - -#HIDDEN_BEGIN_op4 - zero_energy_ldos = local_dos(energy=0) - finite_energy_ldos = local_dos(energy=1) - - _, axes = plt.subplots(1, 2, figsize=(12, 7)) - plot_ldos(fsyst, axes,[ - ('energy = 0', zero_energy_ldos), - ('energy = 1', finite_energy_ldos), - ]) -#HIDDEN_END_op4 - - -def vector_factory_example(fsyst): - spectrum = kwant.kpm.SpectralDensity(fsyst) -#HIDDEN_BEGIN_fact1 - # construct vectors with n random elements -1 or +1. - def binary_vectors(n): - return np.rint(np.random.random_sample(n)) * 2 - 1 - - custom_factory = kwant.kpm.SpectralDensity(fsyst, - vector_factory=binary_vectors) -#HIDDEN_END_fact1 - plot_dos([ - ('default vector factory', spectrum()), - ('binary vector factory', custom_factory()), - ]) - - -def bilinear_map_operator_example(fsyst): -#HIDDEN_BEGIN_blm - rho = kwant.operator.Density(fsyst, sum=True) - - # sesquilinear map that does the same thing as `rho` - def rho_alt(bra, ket): - return np.vdot(bra, ket) - - rho_spectrum = kwant.kpm.SpectralDensity(fsyst, operator=rho) - rho_alt_spectrum = kwant.kpm.SpectralDensity(fsyst, operator=rho_alt) -#HIDDEN_END_blm - - plot_dos([ - ('kwant.operator.Density', rho_spectrum()), - ('bilinear operator', rho_alt_spectrum()), - ]) - - -def main(): - simple_dos_example() - - fsyst = make_syst().finalized() - - dos_integrating_example(fsyst) - increasing_accuracy_example(fsyst) - operator_example(fsyst) - ldos_example(fsyst) - vector_factory_example(fsyst) - bilinear_map_operator_example(fsyst) - - -# Call the main function if the script gets executed (as opposed to imported). -# See <http://docs.python.org/library/__main__.html>. -if __name__ == '__main__': - main() diff --git a/doc/source/tutorial/magnetic_texture.py b/doc/source/tutorial/magnetic_texture.py deleted file mode 100644 index 89c7acfb793aecce1126a50fa45f31b360c2e053..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/magnetic_texture.py +++ /dev/null @@ -1,245 +0,0 @@ -# Tutorial 2.7. Spin textures -# =========================== -# -# Physics background -# ------------------ -# - Spin textures -# - Skyrmions -# -# Kwant features highlighted -# -------------------------- -# - operators -# - plotting vector fields - -from math import sin, cos, tanh, pi -import itertools -import numpy as np -import tinyarray as ta -import matplotlib.pyplot as plt - -import kwant - -sigma_0 = ta.array([[1, 0], [0, 1]]) -sigma_x = ta.array([[0, 1], [1, 0]]) -sigma_y = ta.array([[0, -1j], [1j, 0]]) -sigma_z = ta.array([[1, 0], [0, -1]]) - -# vector of Pauli matrices σ_αiβ where greek -# letters denote spinor indices -sigma = np.rollaxis(np.array([sigma_x, sigma_y, sigma_z]), 1) - -#HIDDEN_BEGIN_model -def field_direction(pos, r0, delta): - x, y = pos - r = np.linalg.norm(pos) - r_tilde = (r - r0) / delta - theta = (tanh(r_tilde) - 1) * (pi / 2) - - if r == 0: - m_i = [0, 0, 1] - else: - m_i = [ - (x / r) * sin(theta), - (y / r) * sin(theta), - cos(theta), - ] - - return np.array(m_i) - - -def scattering_onsite(site, r0, delta, J): - m_i = field_direction(site.pos, r0, delta) - return J * np.dot(m_i, sigma) - - -def lead_onsite(site, J): - return J * sigma_z -#HIDDEN_END_model - - -#HIDDEN_BEGIN_syst -lat = kwant.lattice.square(norbs=2) - -def make_system(L=80): - - syst = kwant.Builder() - - def square(pos): - return all(-L/2 < p < L/2 for p in pos) - - syst[lat.shape(square, (0, 0))] = scattering_onsite - syst[lat.neighbors()] = -sigma_0 - - lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)), - conservation_law=-sigma_z) - - lead[lat.shape(square, (0, 0))] = lead_onsite - lead[lat.neighbors()] = -sigma_0 - - syst.attach_lead(lead) - syst.attach_lead(lead.reversed()) - - return syst -#HIDDEN_END_syst - - -def plot_vector_field(syst, params): - xmin, ymin = min(s.tag for s in syst.sites) - xmax, ymax = max(s.tag for s in syst.sites) - x, y = np.meshgrid(np.arange(xmin, xmax+1), np.arange(ymin, ymax+1)) - - m_i = [field_direction(p, **params) for p in zip(x.flat, y.flat)] - m_i = np.reshape(m_i, x.shape + (3,)) - m_i = np.rollaxis(m_i, 2, 0) - - fig, ax = plt.subplots(1, 1) - im = ax.quiver(x, y, *m_i, pivot='mid', scale=75) - fig.colorbar(im) - plt.show() - - -def plot_densities(syst, densities): - fig, axes = plt.subplots(1, len(densities)) - for ax, (title, rho) in zip(axes, densities): - kwant.plotter.map(syst, rho, ax=ax, a=4) - ax.set_title(title) - plt.show() - - -def plot_currents(syst, currents): - fig, axes = plt.subplots(1, len(currents)) - if not hasattr(axes, '__len__'): - axes = (axes,) - for ax, (title, current) in zip(axes, currents): - kwant.plotter.current(syst, current, ax=ax, colorbar=False) - ax.set_title(title) - plt.show() - - -def main(): - syst = make_system().finalized() - -#HIDDEN_BEGIN_wavefunction - params = dict(r0=20, delta=10, J=1) - wf = kwant.wave_function(syst, energy=-1, params=params) - psi = wf(0)[0] -#HIDDEN_END_wavefunction - - plot_vector_field(syst, dict(r0=20, delta=10)) - -#HIDDEN_BEGIN_ldos - # even (odd) indices correspond to spin up (down) - up, down = psi[::2], psi[1::2] - density = np.abs(up)**2 + np.abs(down)**2 -#HIDDEN_END_ldos - -#HIDDEN_BEGIN_lsdz - # spin down components have a minus sign - spin_z = np.abs(up)**2 - np.abs(down)**2 -#HIDDEN_END_lsdz - -#HIDDEN_BEGIN_lsdy - # spin down components have a minus sign - spin_y = 1j * (down.conjugate() * up - up.conjugate() * down) -#HIDDEN_END_lsdy - -#HIDDEN_BEGIN_lden - rho = kwant.operator.Density(syst) - rho_sz = kwant.operator.Density(syst, sigma_z) - rho_sy = kwant.operator.Density(syst, sigma_y) - - # calculate the expectation values of the operators with 'psi' - density = rho(psi) - spin_z = rho_sz(psi) - spin_y = rho_sy(psi) -#HIDDEN_END_lden - - plot_densities(syst, [ - ('$σ_0$', density), - ('$σ_z$', spin_z), - ('$σ_y$', spin_y), - ]) - -#HIDDEN_BEGIN_current - J_0 = kwant.operator.Current(syst) - J_z = kwant.operator.Current(syst, sigma_z) - J_y = kwant.operator.Current(syst, sigma_y) - - # calculate the expectation values of the operators with 'psi' - current = J_0(psi) - spin_z_current = J_z(psi) - spin_y_current = J_y(psi) -#HIDDEN_END_current - - plot_currents(syst, [ - ('$J_{σ_0}$', current), - ('$J_{σ_z}$', spin_z_current), - ('$J_{σ_y}$', spin_y_current), - ]) - -#HIDDEN_BEGIN_following - def following_m_i(site, r0, delta): - m_i = field_direction(site.pos, r0, delta) - return np.dot(m_i, sigma) - - J_m = kwant.operator.Current(syst, following_m_i) - - # evaluate the operator - m_current = J_m(psi, params=dict(r0=25, delta=10)) -#HIDDEN_END_following - - plot_currents(syst, [ - (r'$J_{\mathbf{m}_i}$', m_current), - ('$J_{σ_z}$', spin_z_current), - ]) - - -#HIDDEN_BEGIN_density_cut - def circle(site): - return np.linalg.norm(site.pos) < 20 - - rho_circle = kwant.operator.Density(syst, where=circle, sum=True) - - all_states = np.vstack((wf(0), wf(1))) - dos_in_circle = sum(rho_circle(p) for p in all_states) / (2 * pi) - print('density of states in circle:', dos_in_circle) -#HIDDEN_END_density_cut - -#HIDDEN_BEGIN_current_cut - def left_cut(site_to, site_from): - return site_from.pos[0] <= -39 and site_to.pos[0] > -39 - - def right_cut(site_to, site_from): - return site_from.pos[0] < 39 and site_to.pos[0] >= 39 - - J_left = kwant.operator.Current(syst, where=left_cut, sum=True) - J_right = kwant.operator.Current(syst, where=right_cut, sum=True) - - Jz_left = kwant.operator.Current(syst, sigma_z, where=left_cut, sum=True) - Jz_right = kwant.operator.Current(syst, sigma_z, where=right_cut, sum=True) - - print('J_left:', J_left(psi), ' J_right:', J_right(psi)) - print('Jz_left:', Jz_left(psi), ' Jz_right:', Jz_right(psi)) -#HIDDEN_END_current_cut - -#HIDDEN_BEGIN_bind - J_m = kwant.operator.Current(syst, following_m_i) - J_z = kwant.operator.Current(syst, sigma_z) - - J_m_bound = J_m.bind(params=dict(r0=25, delta=10, J=1)) - J_z_bound = J_z.bind(params=dict(r0=25, delta=10, J=1)) - - # Sum current local from all scattering states on the left at energy=-1 - wf_left = wf(0) - J_m_left = sum(J_m_bound(p) for p in wf_left) - J_z_left = sum(J_z_bound(p) for p in wf_left) -#HIDDEN_END_bind - - plot_currents(syst, [ - (r'$J_{\mathbf{m}_i}$ (from left)', J_m_left), - (r'$J_{σ_z}$ (from left)', J_z_left), - ]) - - -if __name__ == '__main__': - main() diff --git a/doc/source/tutorial/plot_graphene.py b/doc/source/tutorial/plot_graphene.py deleted file mode 100644 index e81e331b2bedf7de7241b857a50611a562d51316..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/plot_graphene.py +++ /dev/null @@ -1,112 +0,0 @@ -# Tutorial 2.8.1. 2D example: graphene quantum dot -# ================================================ -# -# Physics background -# ------------------ -# - graphene edge states -# -# Kwant features highlighted -# -------------------------- -# - demonstrate different ways of plotting - -import kwant -from matplotlib import pyplot - -#HIDDEN_BEGIN_makesyst -lat = kwant.lattice.honeycomb() -a, b = lat.sublattices - -def make_system(r=8, t=-1, tp=-0.1): - - def circle(pos): - x, y = pos - return x**2 + y**2 < r**2 - - syst = kwant.Builder() - syst[lat.shape(circle, (0, 0))] = 0 - syst[lat.neighbors()] = t - syst.eradicate_dangling() - if tp: - syst[lat.neighbors(2)] = tp - - return syst -#HIDDEN_END_makesyst - - -#HIDDEN_BEGIN_plotsyst1 -def plot_system(syst): - kwant.plot(syst) -#HIDDEN_END_plotsyst1 - # the standard plot is ok, but not very intelligible. One can do - # better by playing wioth colors and linewidths - - # use color and linewidths to get a better plot -#HIDDEN_BEGIN_plotsyst2 - def family_color(site): - return 'black' if site.family == a else 'white' - - def hopping_lw(site1, site2): - return 0.04 if site1.family == site2.family else 0.1 - - kwant.plot(syst, site_lw=0.1, site_color=family_color, hop_lw=hopping_lw) -#HIDDEN_END_plotsyst2 - - -#HIDDEN_BEGIN_plotdata1 -def plot_data(syst, n): - import scipy.linalg as la - - syst = syst.finalized() - ham = syst.hamiltonian_submatrix() - evecs = la.eigh(ham)[1] - - wf = abs(evecs[:, n])**2 -#HIDDEN_END_plotdata1 - - # the usual - works great in general, looks just a bit crufty for - # small systems - -#HIDDEN_BEGIN_plotdata2 - kwant.plotter.map(syst, wf, oversampling=10, cmap='gist_heat_r') -#HIDDEN_END_plotdata2 - - # use two different sort of triangles to cleanly fill the space -#HIDDEN_BEGIN_plotdata3 - def family_shape(i): - site = syst.sites[i] - return ('p', 3, 180) if site.family == a else ('p', 3, 0) - - def family_color(i): - return 'black' if syst.sites[i].family == a else 'white' - - kwant.plot(syst, site_color=wf, site_symbol=family_shape, - site_size=0.5, hop_lw=0, cmap='gist_heat_r') -#HIDDEN_END_plotdata3 - - # plot by changing the symbols itself -#HIDDEN_BEGIN_plotdata4 - def site_size(i): - return 3 * wf[i] / wf.max() - - kwant.plot(syst, site_size=site_size, site_color=(0, 0, 1, 0.3), - hop_lw=0.1) -#HIDDEN_END_plotdata4 - - -def main(): - # plot the graphene system in different styles - syst = make_system() - - plot_system(syst) - - # compute a wavefunction (number 225) and plot it in different - # styles - syst = make_system(tp=0) - - plot_data(syst, 225) - - -# Call the main function if the script gets executed (as opposed to imported). -# See <http://docs.python.org/library/__main__.html>. -if __name__ == '__main__': - main() diff --git a/doc/source/tutorial/plot_qahe.py b/doc/source/tutorial/plot_qahe.py deleted file mode 100644 index 65b2ee65115e9a7224886af3d632912eba972f6f..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/plot_qahe.py +++ /dev/null @@ -1,71 +0,0 @@ -# Comprehensive example: quantum anomalous Hall effect -# ==================================================== -# -# Physics background -# ------------------ -# + Quantum anomalous Hall effect -# -# Features highlighted -# -------------------- -# + Use of `kwant.continuum` to discretize a continuum Hamiltonian -# + Use of `kwant.operator` to compute local current -# + Use of `kwant.plotter.current` to plot local current - -import math -import matplotlib.pyplot -import kwant - - -# 2 band model exhibiting quantum anomalous Hall effect -#HIDDEN_BEGIN_model -def make_model(a): - ham = ("alpha * (k_x * sigma_x - k_y * sigma_y)" - "+ (m + beta * kk) * sigma_z" - "+ (gamma * kk + U) * sigma_0") - subs = {"kk": "k_x**2 + k_y**2"} - return kwant.continuum.discretize(ham, locals=subs, grid_spacing=a) -#HIDDEN_END_model - - -def make_system(model, L): - def lead_shape(site): - x, y = site.pos / L - return abs(y) < 0.5 - - # QPC shape: a rectangle with 2 gaussians - # etched out of the top and bottom edge. - def central_shape(site): - x, y = site.pos / L - return abs(x) < 3/5 and abs(y) < 0.5 - 0.4 * math.exp(-40 * x**2) - - lead = kwant.Builder(kwant.TranslationalSymmetry( - model.lattice.vec((-1, 0)))) - lead.fill(model, lead_shape, (0, 0)) - - syst = kwant.Builder() - syst.fill(model, central_shape, (0, 0)) - syst.attach_lead(lead) - syst.attach_lead(lead.reversed()) - - return syst.finalized() - - -def main(): - # Set up our model and system, and define the model parameters. - params = dict(alpha=0.365, beta=0.686, gamma=0.512, m=-0.01, U=0) - model = make_model(1) - syst = make_system(model, 70) - kwant.plot(syst) - - # Calculate the scattering states at energy 'm' coming from the left - # lead, and the associated particle current. - psi = kwant.wave_function(syst, energy=params['m'], params=params)(0) -#HIDDEN_BEGIN_current - J = kwant.operator.Current(syst).bind(params=params) - current = sum(J(p) for p in psi) - kwant.plotter.current(syst, current) -#HIDDEN_END_current - - -if __name__ == '__main__': - main() diff --git a/doc/source/tutorial/plot_zincblende.py b/doc/source/tutorial/plot_zincblende.py deleted file mode 100644 index 6b75a54e0df3d4b977ab1ec51a00960ef4f6f262..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/plot_zincblende.py +++ /dev/null @@ -1,59 +0,0 @@ -# Tutorial 2.8.2. 3D example: zincblende structure -# ================================================ -# -# Physical background -# ------------------- -# - 3D Bravais lattices -# -# Kwant features highlighted -# -------------------------- -# - demonstrate different ways of plotting in 3D - -import kwant -from matplotlib import pyplot - -#HIDDEN_BEGIN_zincblende1 -lat = kwant.lattice.general([(0, 0.5, 0.5), (0.5, 0, 0.5), (0.5, 0.5, 0)], - [(0, 0, 0), (0.25, 0.25, 0.25)]) -a, b = lat.sublattices -#HIDDEN_END_zincblende1 - -#HIDDEN_BEGIN_zincblende2 -def make_cuboid(a=15, b=10, c=5): - def cuboid_shape(pos): - x, y, z = pos - return 0 <= x < a and 0 <= y < b and 0 <= z < c - - syst = kwant.Builder() - syst[lat.shape(cuboid_shape, (0, 0, 0))] = None - syst[lat.neighbors()] = None - - return syst -#HIDDEN_END_zincblende2 - - -def main(): - # the standard plotting style for 3D is mainly useful for - # checking shapes: -#HIDDEN_BEGIN_plot1 - syst = make_cuboid() - - kwant.plot(syst) -#HIDDEN_END_plot1 - - # visualize the crystal structure better for a very small system -#HIDDEN_BEGIN_plot2 - syst = make_cuboid(a=1.5, b=1.5, c=1.5) - - def family_colors(site): - return 'r' if site.family == a else 'g' - - kwant.plot(syst, site_size=0.18, site_lw=0.01, hop_lw=0.05, - site_color=family_colors) -#HIDDEN_END_plot2 - - -# Call the main function if the script gets executed (as opposed to imported). -# See <http://docs.python.org/library/__main__.html>. -if __name__ == '__main__': - main() diff --git a/doc/source/tutorial/quantum_well.py b/doc/source/tutorial/quantum_well.py deleted file mode 100644 index 780052e9be77dbd6d2a52a9b6742a495d6481232..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/quantum_well.py +++ /dev/null @@ -1,88 +0,0 @@ -# Tutorial 2.3.2. Spatially dependent values through functions -# ============================================================ -# -# Physics background -# ------------------ -# transmission through a quantum well -# -# Kwant features highlighted -# -------------------------- -# - Functions as values in Builder - -import kwant - -# For plotting -from matplotlib import pyplot - - -#HIDDEN_BEGIN_ehso -def make_system(a=1, t=1.0, W=10, L=30, L_well=10): - # Start with an empty tight-binding system and a single square lattice. - # `a` is the lattice constant (by default set to 1 for simplicity. - lat = kwant.lattice.square(a) - - syst = kwant.Builder() - - #### Define the scattering region. #### - # Potential profile - def potential(site, pot): - (x, y) = site.pos - if (L - L_well) / 2 < x < (L + L_well) / 2: - return pot - else: - return 0 -#HIDDEN_END_ehso - -#HIDDEN_BEGIN_coid - def onsite(site, pot=0): - return 4 * t + potential(site, pot) - - syst[(lat(x, y) for x in range(L) for y in range(W))] = onsite - syst[lat.neighbors()] = -t -#HIDDEN_END_coid - - #### Define and attach the leads. #### - lead = kwant.Builder(kwant.TranslationalSymmetry((-a, 0))) - lead[(lat(0, j) for j in range(W))] = 4 * t - lead[lat.neighbors()] = -t - syst.attach_lead(lead) - syst.attach_lead(lead.reversed()) - - return syst - - -def plot_conductance(syst, energy, welldepths): -#HIDDEN_BEGIN_sqvr - - # Compute conductance - data = [] - for welldepth in welldepths: - smatrix = kwant.smatrix(syst, energy, args=[-welldepth]) - data.append(smatrix.transmission(1, 0)) - - pyplot.figure() - pyplot.plot(welldepths, data) - pyplot.xlabel("well depth [t]") - pyplot.ylabel("conductance [e^2/h]") - pyplot.show() -#HIDDEN_END_sqvr - - -def main(): - syst = make_system() - - # Check that the system looks as intended. - kwant.plot(syst) - - # Finalize the system. - syst = syst.finalized() - - # We should see conductance steps. - plot_conductance(syst, energy=0.2, - welldepths=[0.01 * i for i in range(100)]) - - -# Call the main function if the script gets executed (as opposed to imported). -# See <http://docs.python.org/library/__main__.html>. -if __name__ == '__main__': - main() diff --git a/doc/source/tutorial/quantum_wire.py b/doc/source/tutorial/quantum_wire.py deleted file mode 100644 index 992a7dc37fb17309da2f9c2f51d2c68bcc90371d..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/quantum_wire.py +++ /dev/null @@ -1,121 +0,0 @@ -# Tutorial 2.2.2. Transport through a quantum wire -# ================================================ -# -# Physics background -# ------------------ -# Conductance of a quantum wire; subbands -# -# Kwant features highlighted -# -------------------------- -# - Builder for setting up transport systems easily -# - Making scattering region and leads -# - Using the simple sparse solver for computing Landauer conductance - -from matplotlib import pyplot -#HIDDEN_BEGIN_dwhx -import kwant -#HIDDEN_END_dwhx - -# First, define the tight-binding system - -#HIDDEN_BEGIN_goiq -syst = kwant.Builder() -#HIDDEN_END_goiq - -# Here, we are only working with square lattices -#HIDDEN_BEGIN_suwo -a = 1 -lat = kwant.lattice.square(a) -#HIDDEN_END_suwo - -#HIDDEN_BEGIN_zfvr -t = 1.0 -W = 10 -L = 30 - -# Define the scattering region - -for i in range(L): - for j in range(W): - # On-site Hamiltonian - syst[lat(i, j)] = 4 * t - - # Hopping in y-direction - if j > 0: - syst[lat(i, j), lat(i, j - 1)] = -t - - # Hopping in x-direction - if i > 0: - syst[lat(i, j), lat(i - 1, j)] = -t -#HIDDEN_END_zfvr - -# Then, define and attach the leads: - -# First the lead to the left -# (Note: TranslationalSymmetry takes a real-space vector) -#HIDDEN_BEGIN_xcmc -sym_left_lead = kwant.TranslationalSymmetry((-a, 0)) -left_lead = kwant.Builder(sym_left_lead) -#HIDDEN_END_xcmc - -#HIDDEN_BEGIN_ndez -for j in range(W): - left_lead[lat(0, j)] = 4 * t - if j > 0: - left_lead[lat(0, j), lat(0, j - 1)] = -t - left_lead[lat(1, j), lat(0, j)] = -t -#HIDDEN_END_ndez - -#HIDDEN_BEGIN_fskr -syst.attach_lead(left_lead) -#HIDDEN_END_fskr - -# Then the lead to the right -#HIDDEN_BEGIN_xhqc -sym_right_lead = kwant.TranslationalSymmetry((a, 0)) -right_lead = kwant.Builder(sym_right_lead) - -for j in range(W): - right_lead[lat(0, j)] = 4 * t - if j > 0: - right_lead[lat(0, j), lat(0, j - 1)] = -t - right_lead[lat(1, j), lat(0, j)] = -t - -syst.attach_lead(right_lead) -#HIDDEN_END_xhqc - -# Plot it, to make sure it's OK -#HIDDEN_BEGIN_wsgh -kwant.plot(syst) -#HIDDEN_END_wsgh - -# Finalize the system -#HIDDEN_BEGIN_dngj -syst = syst.finalized() -#HIDDEN_END_dngj - -# Now that we have the system, we can compute conductance -#HIDDEN_BEGIN_buzn -energies = [] -data = [] -for ie in range(100): - energy = ie * 0.01 - - # compute the scattering matrix at a given energy - smatrix = kwant.smatrix(syst, energy) - - # compute the transmission probability from lead 0 to - # lead 1 - energies.append(energy) - data.append(smatrix.transmission(1, 0)) -#HIDDEN_END_buzn - -# Use matplotlib to write output -# We should see conductance steps -#HIDDEN_BEGIN_lliv -pyplot.figure() -pyplot.plot(energies, data) -pyplot.xlabel("energy [t]") -pyplot.ylabel("conductance [e^2/h]") -pyplot.show() -#HIDDEN_END_lliv diff --git a/doc/source/tutorial/spin_orbit.py b/doc/source/tutorial/spin_orbit.py deleted file mode 100644 index f4c84b6c8984062aeb155f25f258ddd0345434e1..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/spin_orbit.py +++ /dev/null @@ -1,104 +0,0 @@ -# Tutorial 2.3.1. Matrix structure of on-site and hopping elements -# ================================================================ -# -# Physics background -# ------------------ -# Gaps in quantum wires with spin-orbit coupling and Zeeman splititng, -# as theoretically predicted in -# http://prl.aps.org/abstract/PRL/v90/i25/e256601 -# and (supposedly) experimentally oberved in -# http://www.nature.com/nphys/journal/v6/n5/abs/nphys1626.html -# -# Kwant features highlighted -# -------------------------- -# - Numpy matrices as values in Builder - -import kwant - -# For plotting -from matplotlib import pyplot - -# For matrix support -#HIDDEN_BEGIN_xumz -import tinyarray -#HIDDEN_END_xumz - -# define Pauli-matrices for convenience -#HIDDEN_BEGIN_hwbt -sigma_0 = tinyarray.array([[1, 0], [0, 1]]) -sigma_x = tinyarray.array([[0, 1], [1, 0]]) -sigma_y = tinyarray.array([[0, -1j], [1j, 0]]) -sigma_z = tinyarray.array([[1, 0], [0, -1]]) -#HIDDEN_END_hwbt - - -def make_system(a=1, t=1.0, alpha=0.5, e_z=0.08, W=10, L=30): - # Start with an empty tight-binding system and a single square lattice. - # `a` is the lattice constant (by default set to 1 for simplicity). - lat = kwant.lattice.square(a) - - syst = kwant.Builder() - - #### Define the scattering region. #### -#HIDDEN_BEGIN_uxrm - syst[(lat(x, y) for x in range(L) for y in range(W))] = \ - 4 * t * sigma_0 + e_z * sigma_z - # hoppings in x-direction - syst[kwant.builder.HoppingKind((1, 0), lat, lat)] = \ - -t * sigma_0 - 1j * alpha * sigma_y - # hoppings in y-directions - syst[kwant.builder.HoppingKind((0, 1), lat, lat)] = \ - -t * sigma_0 + 1j * alpha * sigma_x -#HIDDEN_END_uxrm - - #### Define the left lead. #### - lead = kwant.Builder(kwant.TranslationalSymmetry((-a, 0))) - -#HIDDEN_BEGIN_yliu - lead[(lat(0, j) for j in range(W))] = 4 * t * sigma_0 + e_z * sigma_z - # hoppings in x-direction - lead[kwant.builder.HoppingKind((1, 0), lat, lat)] = \ - -t * sigma_0 - 1j * alpha * sigma_y - # hoppings in y-directions - lead[kwant.builder.HoppingKind((0, 1), lat, lat)] = \ - -t * sigma_0 + 1j * alpha * sigma_x -#HIDDEN_END_yliu - - #### Attach the leads and return the finalized system. #### - syst.attach_lead(lead) - syst.attach_lead(lead.reversed()) - - return syst - - -def plot_conductance(syst, energies): - # Compute conductance - data = [] - for energy in energies: - smatrix = kwant.smatrix(syst, energy) - data.append(smatrix.transmission(1, 0)) - - pyplot.figure() - pyplot.plot(energies, data) - pyplot.xlabel("energy [t]") - pyplot.ylabel("conductance [e^2/h]") - pyplot.show() - - -def main(): - syst = make_system() - - # Check that the system looks as intended. - kwant.plot(syst) - - # Finalize the system. - syst = syst.finalized() - - # We should see non-monotonic conductance steps. - plot_conductance(syst, energies=[0.01 * i - 0.3 for i in range(100)]) - - -# Call the main function if the script gets executed (as opposed to imported). -# See <http://docs.python.org/library/__main__.html>. -if __name__ == '__main__': - main() diff --git a/doc/source/tutorial/superconductor.py b/doc/source/tutorial/superconductor.py deleted file mode 100644 index 06caf0c4049280ceed1cc71aa7384730ff45e145..0000000000000000000000000000000000000000 --- a/doc/source/tutorial/superconductor.py +++ /dev/null @@ -1,132 +0,0 @@ -# Tutorial 2.6. "Superconductors": orbitals, conservation laws and symmetries -# =========================================================================== -# -# Physics background -# ------------------ -# - conductance of a NS-junction (Andreev reflection, superconducting gap) -# -# Kwant features highlighted -# -------------------------- -# - Implementing electron and hole ("orbital") degrees of freedom -# using conservation laws. -# - Use of discrete symmetries to relate scattering states. - -import kwant - -import tinyarray -import numpy as np - -# For plotting -from matplotlib import pyplot - -tau_x = tinyarray.array([[0, 1], [1, 0]]) -tau_y = tinyarray.array([[0, -1j], [1j, 0]]) -tau_z = tinyarray.array([[1, 0], [0, -1]]) - -#HIDDEN_BEGIN_nbvn -def make_system(a=1, W=10, L=10, barrier=1.5, barrierpos=(3, 4), - mu=0.4, Delta=0.1, Deltapos=4, t=1.0, phs=True): - # Start with an empty tight-binding system. On each site, there - # are now electron and hole orbitals, so we must specify the - # number of orbitals per site. The orbital structure is the same - # as in the Hamiltonian. - lat = kwant.lattice.square(norbs=2) - syst = kwant.Builder() - - #### Define the scattering region. #### - # The superconducting order parameter couples electron and hole orbitals - # on each site, and hence enters as an onsite potential. - # The pairing is only included beyond the point 'Deltapos' in the scattering region. - syst[(lat(x, y) for x in range(Deltapos) for y in range(W))] = (4 * t - mu) * tau_z - syst[(lat(x, y) for x in range(Deltapos, L) for y in range(W))] = (4 * t - mu) * tau_z + Delta * tau_x - - # The tunnel barrier - syst[(lat(x, y) for x in range(barrierpos[0], barrierpos[1]) - for y in range(W))] = (4 * t + barrier - mu) * tau_z - - # Hoppings - syst[lat.neighbors()] = -t * tau_z -#HIDDEN_END_nbvn -#HIDDEN_BEGIN_ttth - #### Define the leads. #### - # Left lead - normal, so the order parameter is zero. - sym_left = kwant.TranslationalSymmetry((-a, 0)) - # Specify the conservation law used to treat electrons and holes separately. - # We only do this in the left lead, where the pairing is zero. - lead0 = kwant.Builder(sym_left, conservation_law=-tau_z, particle_hole=tau_y) - lead0[(lat(0, j) for j in range(W))] = (4 * t - mu) * tau_z - lead0[lat.neighbors()] = -t * tau_z -#HIDDEN_END_ttth -#HIDDEN_BEGIN_zuuw - # Right lead - superconducting, so the order parameter is included. - sym_right = kwant.TranslationalSymmetry((a, 0)) - lead1 = kwant.Builder(sym_right) - lead1[(lat(0, j) for j in range(W))] = (4 * t - mu) * tau_z + Delta * tau_x - lead1[lat.neighbors()] = -t * tau_z - - #### Attach the leads and return the system. #### - syst.attach_lead(lead0) - syst.attach_lead(lead1) - - return syst -#HIDDEN_END_zuuw - -#HIDDEN_BEGIN_jbjt -def plot_conductance(syst, energies): - # Compute conductance - data = [] - for energy in energies: - smatrix = kwant.smatrix(syst, energy) - # Conductance is N - R_ee + R_he - data.append(smatrix.submatrix((0, 0), (0, 0)).shape[0] - - smatrix.transmission((0, 0), (0, 0)) + - smatrix.transmission((0, 1), (0, 0))) -#HIDDEN_END_jbjt - pyplot.figure() - pyplot.plot(energies, data) - pyplot.xlabel("energy [t]") - pyplot.ylabel("conductance [e^2/h]") - pyplot.show() - -#HIDDEN_BEGIN_pqmp -def check_PHS(syst): - # Scattering matrix - s = kwant.smatrix(syst, energy=0) - # Electron to electron block - s_ee = s.submatrix((0,0), (0,0)) - # Hole to hole block - s_hh = s.submatrix((0,1), (0,1)) - print('s_ee: \n', np.round(s_ee, 3)) - print('s_hh: \n', np.round(s_hh[::-1, ::-1], 3)) - print('s_ee - s_hh^*: \n', - np.round(s_ee - s_hh[::-1, ::-1].conj(), 3), '\n') - # Electron to hole block - s_he = s.submatrix((0,1), (0,0)) - # Hole to electron block - s_eh = s.submatrix((0,0), (0,1)) - print('s_he: \n', np.round(s_he, 3)) - print('s_eh: \n', np.round(s_eh[::-1, ::-1], 3)) - print('s_he + s_eh^*: \n', - np.round(s_he + s_eh[::-1, ::-1].conj(), 3)) -#HIDDEN_END_pqmp - -def main(): - syst = make_system(W=10) - - # Check that the system looks as intended. - kwant.plot(syst) - - # Finalize the system. - syst = syst.finalized() - - # Check particle-hole symmetry of the scattering matrix - check_PHS(syst) - - # Compute and plot the conductance - plot_conductance(syst, energies=[0.002 * i for i in range(-10, 100)]) - - -# Call the main function if the script gets executed (as opposed to imported). -# See <http://docs.python.org/library/__main__.html>. -if __name__ == '__main__': - main()