@@ -1,245 +1,268 @@ # Tutorial 2.7. Spin textures # =========================== # # Physics background # ------------------ # - Spin textures # - Skyrmions # # Kwant features highlighted # -------------------------- # - operators # - plotting vector fields +import _defs +from contextlib import redirect_stdout + 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): +def save_plot(fname): + for extension in ('.pdf', '.png'): + plt.savefig(fname + extension, + dpi=_defs.dpi, bbox_inches='tight') + + +def plot_vector_field(syst, params, fname=None): 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) + fig, ax = plt.subplots(1, 1, figsize=(9, 7)) im = ax.quiver(x, y, *m_i, pivot='mid', scale=75) fig.colorbar(im) - plt.show() + if fname: + save_plot(fname) + else: + plt.show() -def plot_densities(syst, densities): - fig, axes = plt.subplots(1, len(densities)) +def plot_densities(syst, densities, fname=None): + fig, axes = plt.subplots(1, len(densities), figsize=(7*len(densities), 7)) for ax, (title, rho) in zip(axes, densities): kwant.plotter.map(syst, rho, ax=ax, a=4) ax.set_title(title) - plt.show() + if fname: + 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__'): 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() + if fname: + save_plot(fname) + else: + 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)) + 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] 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) 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) 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), - ]) + ], fname='spin_current_comparison') #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) + 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 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)) + with open('current_cut.txt', 'w') as f: + 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) 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), - ]) + ], fname='bound_current') if __name__ == '__main__': main()