.. _onebody_advanced: Advanced onebody settings ========================= .. jupyter-execute:: :hide-code: from cmath import exp from math import cos, sqrt, pi import numpy as np import matplotlib from matplotlib import pyplot as plt import kwant import tkwant def onsite_potential(site, time): return 1 def create_system(L): # system building lat = kwant.lattice.square(a=1, norbs=1) syst = kwant.Builder() # central scattering region syst[(lat(x, 0) for x in range(L))] = 1 syst[lat.neighbors()] = -1 # time dependent onsite-potential V(t) at leftmost site syst[lat(0, 0)] = onsite_potential # add leads sym = kwant.TranslationalSymmetry((-1, 0)) lead_left = kwant.Builder(sym) lead_left[lat(0, 0)] = 1 lead_left[lat.neighbors()] = -1 syst.attach_lead(lead_left) syst.attach_lead(lead_left.reversed()) return syst syst = create_system(5).finalized() We show some advanced settings for solving the onebody Schrödinger equation which is based on :ref:`onebody`. In the following, ``syst`` is a finalized kwant system with leads and we import the onebody module from tkwant: .. jupyter-execute:: from tkwant import onebody Boundary conditions ~~~~~~~~~~~~~~~~~~~ Special boundary conditions have to be provided in order to solve the dynamic equations for an open quantum systems (with leads). For ``onebody.WaveFunction`` they must be precalculated: .. jupyter-execute:: boundaries = tkwant.leads.automatic_boundary(syst.leads, tmax=10000, refl_max=1E-10) scattering_states = kwant.wave_function(syst, energy=1, params={'time':0}) lead, mode = 0, 0 psi_st = scattering_states(lead)[mode] psi = onebody.WaveFunction.from_kwant(syst, psi_st, boundaries=boundaries, energy=1.) For the scattering state solver boundary conditions are calculated on the fly. One can provide different boundary conditions by the keyword ``boundary`` .. jupyter-execute:: boundaries = tkwant.leads.automatic_boundary(syst.leads, tmax=10000, refl_max=1E-10) psi = onebody.ScatteringStates(syst, energy=1, lead=0, boundaries=boundaries)[mode] For closed quantum systems (without leads), no boundary conditions are needed. .. seealso:: A tutorial on boundary conditions is given in :ref:`boundary`. An example script which shows alternative boundary conditions is given in :ref:`alternative_boundary_conditions`. Time integration ~~~~~~~~~~~~~~~~ The time integration can be changed by prebinding values with the module ``functool.partial`` to the onebody solver. In the current example, we change the relative tolerance ``rtol`` of the time-stepping algorithm: .. jupyter-execute:: import functools as ft solver_type = ft.partial(tkwant.onebody.solvers.default, rtol=1E-5) psi = onebody.WaveFunction.from_kwant(syst=syst, boundaries=boundaries, psi_init=psi_st, energy=1., solver_type=solver_type) Time-dependent perturbation ~~~~~~~~~~~~~~~~~~~~~~~~~~~ When the method ``onebody.WaveFunction.from_kwant()`` is used, the time-dependent perturbation :math:`W(t)` is extracted from the Hamiltonian of a Kwant system. By defaut, Tkwant uses cubic spline interpolation to interpolate :math:`W(t)` in time with with an adaptive stepsize. The interpolation is used for performance reasons, in order to minimize the number of calls to Kwant. One can switch off interpolation and always evaluate the exact :math:`W(t)` function with: .. jupyter-execute:: psi = onebody.WaveFunction.from_kwant(syst=syst, psi_init=psi_st, energy=1., boundaries=boundaries, perturbation_type=onebody.kernels.PerturbationExtractor) For the onebody scattering state solver ``onebody.ScatteringStates``, the :math:`W(t)` interpolation is switched off with: .. jupyter-execute:: import functools as ft wavefunction_type = ft.partial(tkwant.onebody.WaveFunction.from_kwant, perturbation_type=onebody.kernels.PerturbationExtractor) mode = 0 psi = onebody.ScatteringStates(syst, energy=1., lead=0, tmax=100, wavefunction_type=wavefunction_type)[mode] Saving and restarting states ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sometimes we might like to save a state in order to resume a calculation on a later stage. An easy way is to to use the ``pickle`` package: .. jupyter-execute:: import pickle psi = onebody.WaveFunction.from_kwant(syst=syst, psi_init=psi_st, energy=1., boundaries=boundaries, kernel_type=onebody.kernels.Scipy) saved = pickle.dumps(psi) Saving a state works currently only with the ``tkwant.onebody.kernels.Scipy`` kernel. The saved object ``saved`` can be stored. Recovering the state later on in order to continue the calculation is possible by using .. jupyter-execute:: new_psi = pickle.loads(saved) See :ref:`restarting` for the complete code. .. seealso:: An example script showing the restarting of states is given in :ref:`restarting`.