From eca8e38f8a3867eb64992ad2e2a95c7922e29573 Mon Sep 17 00:00:00 2001
From: Anton Akhmerov <anton.akhmerov@gmail.com>
Date: Sun, 28 Apr 2013 16:27:53 -0400
Subject: [PATCH] restore selfenergy to accept h, t, introduce
 selfenergy_from_modes

---
 doc/source/whatsnew/0.3.rst       |  3 ---
 kwant/builder.py                  |  2 +-
 kwant/physics/leads.py            | 38 +++++++++++++++++++++++++------
 kwant/physics/tests/test_leads.py |  2 +-
 kwant/system.py                   | 14 ++++++++----
 5 files changed, 43 insertions(+), 16 deletions(-)

diff --git a/doc/source/whatsnew/0.3.rst b/doc/source/whatsnew/0.3.rst
index 3ce75445..eaaf78ce 100644
--- a/doc/source/whatsnew/0.3.rst
+++ b/doc/source/whatsnew/0.3.rst
@@ -133,6 +133,3 @@ responsibility.
 The new class `~kwant.builder.ModesLead` allows to attach leads that have a
 custom way of calculating their modes (e.g. ideal leads) directly to a
 `~kwant.builder.Builder`.
-
-`~kwant.physics.selfenergy` now uses the output of `~kwant.physics.modes` as
-input instead of the slice Hamiltonian and inter-slice hopping.
diff --git a/kwant/builder.py b/kwant/builder.py
index 8dbc29a9..6869c547 100644
--- a/kwant/builder.py
+++ b/kwant/builder.py
@@ -481,7 +481,7 @@ class ModesLead(Lead):
 
     def selfenergy(self, energy, args=()):
         modes = self.modes(energy, args)
-        return physics.selfenergy(modes=modes)
+        return physics.selfenergy_from_modes(modes=modes)
 
 
 
diff --git a/kwant/physics/leads.py b/kwant/physics/leads.py
index a9a630e9..dec942ef 100644
--- a/kwant/physics/leads.py
+++ b/kwant/physics/leads.py
@@ -503,20 +503,15 @@ def modes(h_onslice, h_hop, tol=1e6):
     return Modes(vecs, vecslmbdainv, nmodes, v)
 
 
-def selfenergy(lead_modes, tol=1e6):
+def selfenergy_from_modes(lead_modes):
     """
-    Compute the self-energy generated by a lead.
-
-    The lead is described either by the unit-cell Hamiltonian h_onslice and the
-    hopping matrix h_hop, or by its modes.
+    Compute the self-energy generated by lead modes.
 
     Parameters
     ----------
     lead_modes : Modes(vecs, vecslmbdainv, nmodes, v) a named tuple
         The modes in the lead, as calculated by
         `kwant.physics.modes`.
-    tol : double
-        Numerical tolerance used in several places.
 
     Returns
     -------
@@ -539,6 +534,35 @@ def selfenergy(lead_modes, tol=1e6):
         return la.solve(vecslmbdainv.T, vecs.T).T
 
 
+def selfenergy(h_onslice, h_hop, tol=1e6):
+    """
+    Compute the self-energy generated by the lead.
+
+    Parameters
+    ----------
+    h_onslice : numpy array, real or complex, shape (N,N) The unit cell
+        Hamiltonian of the lead slice.
+    h_hop : numpy array, real or complex, shape (N,M)
+        The hopping matrix from a lead slice to the one on which self-energy
+        has to be calculated (and any other hopping in the same direction).
+    tol : float
+        Tolerance for numerical error.
+
+    Returns
+    -------
+    Sigma : numpy array, real or complex, shape (M,M)
+        The computed self-energy. Note that even if `h_onslice` and `h_hop`
+        are both real, `Sigma` will typically be complex. (More precisely, if
+        there is a propagating mode, `Sigma` will definitely be complex.)
+
+    Notes
+    -----
+    For simplicity this function internally calculates the modes first.
+    This may cause a small slowdown, and can be improved if necessary.
+    """
+    return selfenergy_from_modes(modes(h_onslice, h_hop, tol))
+
+
 def square_selfenergy(width, hopping, fermi_energy):
     """
     Calculate analytically the self energy for a square lattice.
diff --git a/kwant/physics/tests/test_leads.py b/kwant/physics/tests/test_leads.py
index e182fa8c..0ec651be 100644
--- a/kwant/physics/tests/test_leads.py
+++ b/kwant/physics/tests/test_leads.py
@@ -11,7 +11,7 @@ import numpy as np
 from numpy.testing import assert_almost_equal
 from kwant.physics import leads
 
-modes_se = lambda h, t: leads.selfenergy(leads.modes(h, t))
+modes_se = leads.selfenergy
 
 def h_slice(t, w, e):
     h = (4 * t - e) * np.identity(w)
diff --git a/kwant/system.py b/kwant/system.py
index fc5eb368..d07d54ed 100644
--- a/kwant/system.py
+++ b/kwant/system.py
@@ -148,10 +148,10 @@ class InfiniteSystem(System):
                                           sparse=sparse, args=args)
 
     def modes(self, energy, args=()):
-        """Return self-energy of a lead.
+        """Return mode decomposition of the lead
 
-        The returned matrix has the shape (n, n), where n is
-        ``sum(self.num_orbitals(i) for i in range(self.slice_size))``.
+        See documentation of `~kwant.physics.Modes` for the return
+        format details.
         """
         ham = self.slice_hamiltonian(args=args)
         shape = ham.shape
@@ -167,4 +167,10 @@ class InfiniteSystem(System):
         The returned matrix has the shape (n, n), where n is
         ``sum(self.num_orbitals(i) for i in range(self.slice_size))``.
         """
-        return physics.selfenergy(self.modes(energy, args=()))
+        ham = self.slice_hamiltonian(args=args)
+        shape = ham.shape
+        assert len(shape) == 2
+        assert shape[0] == shape[1]
+        # Subtract energy from the diagonal.
+        ham.flat[::ham.shape[0] + 1] -= energy
+        return physics.selfenergy(ham, self.inter_slice_hopping(args=args))
-- 
GitLab