Commit 5ce0bfe7 authored by Anton Akhmerov's avatar Anton Akhmerov
Browse files

Merge branch 'fix/greens-function-reflection' into 'master'

Fix reflection calculation for kwant.greens_function

Closes #398

See merge request kwant/kwant!377
parents f5dc7c65 fd628fa9
...@@ -989,17 +989,20 @@ class GreensFunction(BlockResult): ...@@ -989,17 +989,20 @@ class GreensFunction(BlockResult):
result = np.trace(attdagainv).real result = np.trace(attdagainv).real
if lead_out == lead_in: if lead_out == lead_in:
# For reflection we have to be more careful # For reflection we have to be more careful
gamma = 1j * (self.lead_info[lead_in] - sigma = self.lead_info[lead_in]
self.lead_info[lead_in].conj().T) gamma = 1j * (sigma - sigma.conj().T)
gf = self.submatrix(lead_out, lead_in) gf = self.submatrix(lead_out, lead_in)
# The number of channels is given by the number of # The number of channels is given by the number of
# nonzero eigenvalues of Gamma # nonzero eigenvalues of Gamma
# rationale behind the threshold from # rationale behind the threshold from
# Golub; van Loan, chapter 5.5.8 # Golub; van Loan, chapter 5.5.8
eps = np.finfo(gamma.dtype).eps * 1000 # We use ‖Σ‖, not ‖Γ‖, for the tolerance as ‖Γ‖~0 when there
N = np.sum(np.linalg.eigvalsh(gamma) > # are no open modes.
eps * np.linalg.norm(gamma, np.inf)) eps = (
1e6 * np.finfo(gamma.dtype).eps * np.linalg.norm(sigma, np.inf)
)
N = np.sum(np.linalg.eigvalsh(gamma) > eps)
result += 2 * np.trace(np.dot(gamma, gf)).imag + N result += 2 * np.trace(np.dot(gamma, gf)).imag + N
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# the file AUTHORS.rst at the top-level directory of this distribution and at # the file AUTHORS.rst at the top-level directory of this distribution and at
# http://kwant-project.org/authors. # http://kwant-project.org/authors.
from itertools import chain import itertools
from math import cos, sin from math import cos, sin
import numpy as np import numpy as np
import pytest import pytest
...@@ -37,7 +37,7 @@ sparse_solver_options = [ ...@@ -37,7 +37,7 @@ sparse_solver_options = [
{}, {},
] ]
solvers = list(chain( solvers = list(itertools.chain(
[("mumps", opts) for opts in mumps_solver_options], [("mumps", opts) for opts in mumps_solver_options],
[("sparse", opts) for opts in sparse_solver_options], [("sparse", opts) for opts in sparse_solver_options],
)) ))
...@@ -272,6 +272,29 @@ def test_two_equal_leads(smatrix): ...@@ -272,6 +272,29 @@ def test_two_equal_leads(smatrix):
raises(ValueError, check_fsyst, fsyst.precalculate(what='selfenergy')) raises(ValueError, check_fsyst, fsyst.precalculate(what='selfenergy'))
# Regression test against
# https://gitlab.kwant-project.org/kwant/kwant/-/issues/398
# that the reflection calculation in 'greens_function' does not
# mis-count the number of open modes when there are none.
def test_reflection_no_open_modes(greens_function):
# Build system
syst = kwant.Builder()
lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))
syst[(square(i, j) for i in range(3) for j in range(3))] = 4
lead[(square(0, j) for j in range(3))] = 4
syst[square.neighbors()] = -1
lead[square.neighbors()] = -1
syst.attach_lead(lead)
syst.attach_lead(lead.reversed())
syst = syst.finalized()
# Sanity check; no open modes at 0 energy
_, m = syst.leads[0].modes(energy=0)
assert m.nmodes == 0
assert np.isclose(greens_function(syst).transmission(0, 0), 0)
# Test a more complicated graph with non-singular hopping. # Test a more complicated graph with non-singular hopping.
def test_graph_system(smatrix): def test_graph_system(smatrix):
rng = ensure_rng(11) rng = ensure_rng(11)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment