Пример #1
0
def test_regular_fully_degenerate():
    """Selfenergy with an invertible hopping matrix, and degenerate bands."""

    w = 6                       # width
    t = 0.5                     # hopping element
    e = 1.3                     # Fermi energy

    h_hop_s = -t * np.identity(w)
    h_cell_s = h_cell_s_func(t, w, e)

    h_hop = np.zeros((2*w, 2*w))
    h_hop[:w, :w] = h_hop_s
    h_hop[w:, w:] = h_hop_s

    h_cell = np.zeros((2*w, 2*w))
    h_cell[:w, :w] = h_cell_s
    h_cell[w:, w:] = h_cell_s

    g = np.zeros((2*w, 2*w), dtype=complex)
    g[:w, :w] = leads.square_selfenergy(w, t, e)
    g[w:, w:] = leads.square_selfenergy(w, t, e)

    assert_almost_equal(g, modes_se(h_cell, h_hop))
    # Now with conservation laws and symmetries.
    conserved = np.identity(2*w)
    projectors = [sparse.csr_matrix(i) for i in [conserved[:, :w],
                                                 conserved[:, w:]]]
    modes2 = leads.modes(h_cell, h_hop, projectors=projectors)
    current_conserving(modes2[1])
    assert_almost_equal(g, modes2[1].selfenergy())

    trs = sparse.identity(2*w)
    modes3 = leads.modes(h_cell, h_hop, projectors=projectors,
                         time_reversal=trs)
    current_conserving(modes3[1])
    assert_almost_equal(g, modes3[1].selfenergy())

    phs = np.eye(2*w, 2*w, w) + np.eye(2*w, 2*w, -w)

    modes4 = leads.modes(h_cell, h_hop, projectors=projectors,
                         time_reversal=trs, particle_hole=phs)
    current_conserving(modes4[1])
    assert_almost_equal(g, modes4[1].selfenergy())
Пример #2
0
def test_for_all_evs_equal():
    """Test an 'ideal lead' which has all eigenvalues e^ik equal."""

    onsite = np.array([[0., 1.], [1., 0.]], dtype=complex)
    hopping = np.array([[0.0], [-1.0]], dtype=complex)

    modes = leads.modes(onsite, hopping)[1]

    assert modes.vecs.shape == (1, 2)
    assert modes.vecslmbdainv.shape == (1, 2)
    assert modes.nmodes == 1
Пример #3
0
def test_modes_bearded_ribbon():
    # Check if bearded graphene ribbons work.
    lat = kwant.lattice.honeycomb()
    syst = kwant.Builder(kwant.TranslationalSymmetry((1, 0)))
    syst[lat.shape((lambda pos: -20 < pos[1] < 20),
                  (0, 0))] = 0.3
    syst[lat.neighbors()] = -1
    syst = syst.finalized()
    h, t = syst.cell_hamiltonian(), syst.inter_cell_hopping()
    # The number of expected modes is calculated by plotting the dispersion.
    assert leads.modes(h, t)[1].nmodes == 8
Пример #4
0
def test_modes_bearded_ribbon():
    # Check if bearded graphene ribbons work.
    lat = kwant.lattice.honeycomb(norbs=1)
    syst = kwant.Builder(kwant.TranslationalSymmetry((1, 0)))
    syst[lat.shape((lambda pos: -20 < pos[1] < 20),
                  (0, 0))] = 0.3
    syst[lat.neighbors()] = -1
    syst = syst.finalized()
    h, t = syst.cell_hamiltonian(), syst.inter_cell_hopping()
    # The number of expected modes is calculated by plotting the dispersion.
    assert leads.modes(h, t)[1].nmodes == 8
Пример #5
0
def test_for_all_evs_equal():
    """Test an 'ideal lead' which has all eigenvalues e^ik equal."""

    onsite = np.array([[0., 1.], [1., 0.]], dtype=complex)
    hopping = np.array([[0.0], [-1.0]], dtype=complex)

    modes = leads.modes(onsite, hopping)[1]
    current_conserving(modes)
    assert modes.vecs.shape == (1, 2)
    assert modes.vecslmbdainv.shape == (1, 2)
    assert modes.nmodes == 1
Пример #6
0
def test_modes():
    h, t = .3, .7
    k = np.arccos(-h / (2 * t))
    v = 2 * t * np.sin(k)
    prop, stab = leads.modes(np.array([[h]]), np.array([[t]]))
    assert stab.nmodes == 1
    assert stab.sqrt_hop[0] == np.sqrt(np.linalg.norm(t))
    np.testing.assert_almost_equal(prop.velocities, [-v, v])
    np.testing.assert_almost_equal(prop.momenta, [k, -k])
    # Test for normalization by current.
    np.testing.assert_almost_equal(
        2 * (stab.vecs[0] * stab.vecslmbdainv[0].conj()).imag, [1, -1])
Пример #7
0
def test_modes():
    h, t = .3, .7
    k = np.arccos(-h / (2 * t))
    v = 2 * t * np.sin(k)
    prop, stab = leads.modes(np.array([[h]]), np.array([[t]]))
    current_conserving(stab)
    assert stab.nmodes == 1
    assert stab.sqrt_hop[0] == np.sqrt(np.linalg.norm(t))
    np.testing.assert_almost_equal(prop.velocities, [-v, v])
    np.testing.assert_almost_equal(prop.momenta, [k, -k])
    # Test for normalization by current.
    np.testing.assert_almost_equal(
        2 * (stab.vecs[0] * stab.vecslmbdainv[0].conj()).imag, [1, -1])
Пример #8
0
def test_zero_hopping():
    h_cell = np.identity(2)
    h_hop = np.zeros((2, 1))
    expected = (leads.PropagatingModes(np.zeros((2, 0)), np.zeros((0,)),
                                       np.zeros((0,))),
                leads.StabilizedModes(np.zeros((0, 0)), np.zeros((0, 0)), 0,
                                      np.zeros((1, 0))))
    actual = leads.modes(h_cell, h_hop)
    assert all(np.alltrue(getattr(actual[1], attr) ==
                          getattr(expected[1], attr)) for attr
                   in ('vecs', 'vecslmbdainv', 'nmodes', 'sqrt_hop'))
    assert all(np.alltrue(getattr(actual[0], attr) ==
                          getattr(expected[0], attr)) for attr
                   in ('wave_functions', 'velocities', 'momenta'))
Пример #9
0
def test_zero_hopping():
    h_cell = np.identity(2)
    h_hop = np.zeros((2, 1))
    expected = (leads.PropagatingModes(np.zeros((2, 0)), np.zeros((0,)),
                                       np.zeros((0,))),
                leads.StabilizedModes(np.zeros((0, 0)), np.zeros((0, 0)), 0,
                                      np.zeros((1, 0))))
    actual = leads.modes(h_cell, h_hop)
    assert all(np.alltrue(getattr(actual[1], attr) ==
                          getattr(expected[1], attr)) for attr
                   in ('vecs', 'vecslmbdainv', 'nmodes', 'sqrt_hop'))
    assert all(np.alltrue(getattr(actual[0], attr) ==
                          getattr(expected[0], attr)) for attr
                   in ('wave_functions', 'velocities', 'momenta'))
Пример #10
0
def check_equivalence(h, t, n, sym='', particle_hole=None, chiral=None,
                      time_reversal=None):
    """Compare modes stabilization algorithms for a given Hamiltonian."""
    u, s, vh = la.svd(t)
    u, v = u * np.sqrt(s), vh.T.conj() * np.sqrt(s)
    prop_vecs = []
    evan_vecs = []
    algos = [None, (True, True), (True, False), (False, True), (False, False)]
    for algo in algos:
        result = leads.modes(h, t, stabilization=algo, chiral=chiral,
                             particle_hole=particle_hole,
                             time_reversal=time_reversal)[1]
        current_conserving(result, (sym, algo, n))
        vecs, vecslmbdainv = result.vecs, result.vecslmbdainv

        # Bring the calculated vectors to real space
        if algo is not None:
            vecs = np.dot(v, vecs)
            np.testing.assert_almost_equal(result.sqrt_hop, v)
        else:
            vecslmbdainv = (np.dot(v.T.conj(), vecslmbdainv) /
                            np.sqrt(np.linalg.norm(t)))
            vecs = vecs * np.sqrt(np.linalg.norm(t))
        full_vecs = np.r_[vecslmbdainv, vecs]

        prop_vecs.append(full_vecs[:, : 2 * result.nmodes])
        evan_vecs.append(full_vecs[:, 2 * result.nmodes :])

    msg = 'Stabilization {0} failed.in symmetry class {1}'
    for vecs, algo in zip(prop_vecs, algos):
        # Propagating modes should have identical ordering, and only vary
        # By a phase
        np.testing.assert_allclose(np.abs(np.sum(vecs/prop_vecs[0], axis=0)),
                                   vecs.shape[0],
                                   err_msg=msg.format(algo, sym))

    for vecs, algo in zip(evan_vecs, algos):
        # Evanescent modes must span the same linear space.
        mat = np.c_[vecs, evan_vecs[0]]
        # Scale largest singular value to 1 if the array is not empty
        mat = mat/np.linalg.norm(mat, ord=2)
        # As a tolerance, take the square root of machine precision times the
        # largest matrix dimension.
        tol = np.abs(np.sqrt(max(mat.shape)*np.finfo(mat.dtype).eps))
        assert (np.linalg.matrix_rank(mat, tol=tol) ==
                vecs.shape[1]), msg.format(algo)+' in symmetry class '+sym
Пример #11
0
def check_equivalence(h, t, n, sym='', particle_hole=None, chiral=None, time_reversal=None):
    """Compare modes stabilization algorithms for a given Hamiltonian."""
    u, s, vh = np.linalg.svd(t)
    u, v = u * np.sqrt(s), vh.T.conj() * np.sqrt(s)
    prop_vecs = []
    evan_vecs = []
    algos = [None, (True, True), (True, False), (False, True), (False, False)]
    for algo in algos:
        result = leads.modes(h, t, stabilization=algo, chiral=chiral,
                             particle_hole=particle_hole, time_reversal=time_reversal)[1]

        vecs, vecslmbdainv = result.vecs, result.vecslmbdainv

        # Bring the calculated vectors to real space
        if algo is not None:
            vecs = np.dot(v, vecs)
            np.testing.assert_almost_equal(result.sqrt_hop, v)
        else:
            vecslmbdainv = (np.dot(v.T.conj(), vecslmbdainv) /
                            np.sqrt(np.linalg.norm(t)))
            vecs = vecs * np.sqrt(np.linalg.norm(t))
        full_vecs = np.r_[vecslmbdainv, vecs]

        prop_vecs.append(full_vecs[:, : 2 * result.nmodes])
        evan_vecs.append(full_vecs[:, 2 * result.nmodes :])

    msg = 'Stabilization {0} failed.'
    for vecs, algo in zip(prop_vecs, algos):
        # Propagating modes should have identical ordering, and only vary
        # By a phase
        np.testing.assert_allclose(np.abs(np.sum(vecs/prop_vecs[0],
                                                 axis=0)), vecs.shape[0],
                                   err_msg=msg.format(algo)+' in symmetry class '+sym)

    for vecs, algo in zip(evan_vecs, algos):
        # Evanescent modes must span the same linear space.
        mat = np.c_[vecs, evan_vecs[0]]
        # Scale largest singular value to 1 if the array is not empty
        mat = mat/np.linalg.norm(mat, ord=2)
        # As a tolerance, take the square root of machine precision times the largest
        # matrix dimension.
        tol = np.abs(np.sqrt(max(mat.shape)*np.finfo(mat.dtype).eps))
        assert (np.linalg.matrix_rank(mat, tol=tol) ==
                vecs.shape[1]), msg.format(algo)+' in symmetry class '+sym
Пример #12
0
def test_algorithm_equivalence():
    np.random.seed(400)
    n = 12
    h = np.random.randn(n, n) + 1j * np.random.randn(n, n)
    h += h.T.conj()
    t = np.random.randn(n, n) + 1j * np.random.randn(n, n)
    u, s, vh = np.linalg.svd(t)
    u, v = u * np.sqrt(s), vh.T.conj() * np.sqrt(s)
    prop_vecs = []
    evan_vecs = []
    algos = [None, (True, True), (True, False), (False, True), (False, False)]
    for algo in algos:
        result = leads.modes(h, t, stabilization=algo)[1]

        vecs, vecslmbdainv = result.vecs, result.vecslmbdainv

        # Bring the calculated vectors to real space
        if algo is not None:
            vecs = np.dot(v, vecs)
            np.testing.assert_almost_equal(result.sqrt_hop, v)
        else:
            vecslmbdainv = (np.dot(v.T.conj(), vecslmbdainv) /
                            np.sqrt(np.linalg.norm(t)))
            vecs = vecs * np.sqrt(np.linalg.norm(t))
        full_vecs = np.r_[vecslmbdainv, vecs]

        prop_vecs.append(full_vecs[:, : 2 * result.nmodes])
        evan_vecs.append(full_vecs[:, 2 * result.nmodes :])

    msg = 'Stabilization {0} failed.'
    for vecs, algo in zip(prop_vecs, algos):
        # Propagating modes should have identical ordering, and only vary
        # By a phase
        np.testing.assert_allclose(np.abs(np.sum(vecs/prop_vecs[0],
                                                 axis=0)), vecs.shape[0],
                                   err_msg=msg.format(algo))

    for vecs, algo in zip(evan_vecs, algos):
        # Evanescent modes must span the same linear space.
        assert (np.linalg.matrix_rank(np.c_[vecs, evan_vecs[0]], tol=1e-12) ==
                vecs.shape[1]), msg.format(algo)
Пример #13
0
def test_modes_symmetries():
    rng = ensure_rng(10)
    for n in (4, 8, 40, 60):
        for sym in kwant.rmt.sym_list:
            # Random onsite and hopping matrices in symmetry class
            h_cell = kwant.rmt.gaussian(n, sym, rng=rng)
            # Hopping is an offdiagonal block of a Hamiltonian. We rescale it
            # to ensure that there are modes at the Fermi level.
            h_hop = 10 * kwant.rmt.gaussian(2*n, sym, rng=rng)[:n, n:]

            if kwant.rmt.p(sym):
                p_mat = np.array(kwant.rmt.h_p_matrix[sym])
                p_mat = np.kron(np.identity(n // len(p_mat)), p_mat)
            else:
                p_mat = None

            if kwant.rmt.t(sym):
                t_mat = np.array(kwant.rmt.h_t_matrix[sym])
                t_mat = np.kron(np.identity(n // len(t_mat)), t_mat)
            else:
                t_mat = None

            if kwant.rmt.c(sym):
                c_mat = np.kron(np.identity(n // 2), np.diag([1, -1]))
            else:
                c_mat = None

            prop_modes, stab_modes = leads.modes(h_cell, h_hop,
                                                 particle_hole=p_mat,
                                                 time_reversal=t_mat,
                                                 chiral=c_mat)
            current_conserving(stab_modes)
            wave_functions = prop_modes.wave_functions
            momenta = prop_modes.momenta
            nmodes = stab_modes.nmodes

            if t_mat is not None:
                assert_almost_equal(wave_functions[:, nmodes:],
                        t_mat.dot(wave_functions[:, :nmodes].conj()),
                        err_msg='TRS broken in ' + sym)

            if c_mat is not None:
                assert_almost_equal(wave_functions[:, nmodes:],
                        c_mat.dot(wave_functions[:, :nmodes][:, ::-1]),
                        err_msg='SLS broken in ' + sym)

            if p_mat is not None:
                # If P^2 = -1, then P psi(-k) = -psi(k) for k>0, so one must
                # look at positive and negative momenta separately.  Test
                # positive momenta.
                first, last = momenta[:nmodes], momenta[nmodes:]
                in_positive_k = (np.pi > first) * (first > 0)
                out_positive_k = (np.pi > last) * (last > 0)

                wf_first = wave_functions[:, :nmodes]
                wf_last = wave_functions[:, nmodes:]
                assert_almost_equal(wf_first[:, in_positive_k[::-1]],
                        p_mat.dot((wf_first[:, in_positive_k][:, ::-1]).conj()),
                        err_msg='PHS broken in ' + sym)
                assert_almost_equal(wf_last[:, out_positive_k[::-1]],
                        p_mat.dot((wf_last[:, out_positive_k][:, ::-1]).conj()),
                        err_msg='PHS broken in ' + sym)

                # Test negative momenta. Need the sign of P^2 here.
                p_squared_sign = np.sign(p_mat.dot(p_mat.conj())[0, 0].real)
                in_neg_k = (-np.pi < first) * (first < 0)
                out_neg_k = (-np.pi < last) * (last < 0)

                assert_almost_equal(p_squared_sign*wf_first[:, in_neg_k[::-1]],
                        p_mat.dot((wf_first[:, in_neg_k][:, ::-1]).conj()),
                        err_msg='PHS broken in ' + sym)
                assert_almost_equal(p_squared_sign*wf_last[:, out_neg_k[::-1]],
                        p_mat.dot((wf_last[:, out_neg_k][:, ::-1]).conj()),
                        err_msg='PHS broken in ' + sym)
Пример #14
0
def test_PHS_TRIM_degenerate_ordering():
    """ Test PHS at a TRIM, both when it squares to 1 and -1.

    Take a Hamiltonian with 3 degenerate bands, the degeneracy of each is given
    in the tuple dims. The bands have different velocities. All bands intersect
    zero energy only at k = 0 and at the edge of the BZ, so all momenta are 0
    or -pi. We thus have multiple TRIM modes, both with the same and different
    velocities.

    If P^2 = 1, all TRIM modes are eigenmodes of P.
    If P^2 = -1, TRIM modes come in pairs of particle-hole partners, ordered by
    a predefined convention."""
    sy = np.array([[0,-1j],[1j,0]])
    sz = np.array([[1,0],[0,-1]])

    # P squares to 1.
    rng = ensure_rng(42)
    dims = (4, 8, 12)
    ts = (1.0, 1.7, 13.8)
    rand_hop = 1j*(0.1+rng.random_sample())
    hop = la.block_diag(*[t*rand_hop*np.eye(dim) for t, dim in zip(ts, dims)])

    pmat = np.eye(sum(dims))
    onsite = np.zeros(hop.shape, dtype=complex)
    prop, stab = leads.modes(onsite, hop, particle_hole=pmat)
    current_conserving(stab)
    assert np.all([np.any(momentum - np.array([0, -np.pi])) for momentum in
                   prop.momenta])
    assert np.all([np.allclose(wf, pmat.dot(wf.conj())) for wf in
                   prop.wave_functions.T])

    # P squares to -1
    dims = (1, 4, 10)
    ts = (1.0, 17.2, 13.4)

    hop_mat = np.kron(sz, 1j * (0.1 + rng.random_sample()) * np.eye(2))
    blocks = []
    for t, dim in zip(ts, dims):
        blocks += dim*[t*hop_mat]
    hop = la.block_diag(*blocks)
    pmat = np.kron(np.eye(sum(dims)), 1j*np.kron(sz, sy))

    assert_almost_equal(pmat.dot(pmat.conj()), -np.eye(pmat.shape[0]))
    # The Hamiltonian anticommutes with P
    assert_almost_equal(pmat.dot(hop.conj()).dot(np.linalg.inv(pmat)), -hop)

    onsite = np.zeros(hop.shape, dtype=complex)
    prop, stab = leads.modes(onsite, hop, particle_hole=pmat)
    current_conserving(stab)
    # By design, all momenta are either 0 or -pi.
    assert np.all([np.any(momentum - np.array([0, -np.pi])) for momentum in
                   prop.momenta])

    wfs = prop.wave_functions
    momenta = prop.momenta
    velocities = prop.velocities
    nmodes = stab.nmodes

    # By design, all modes are at a TRIM here. Each must thus have a
    # particle-hole partner at the same TRIM and with the same velocity.
    # Incident modes
    check_PHS(0, momenta[:nmodes], velocities[:nmodes], wfs[:, :nmodes], pmat)
    check_PHS(-np.pi, momenta[:nmodes], velocities[:nmodes], wfs[:, :nmodes],
              pmat)
    # Outgoing modes
    check_PHS(0, momenta[nmodes:], velocities[nmodes:], wfs[:, nmodes:], pmat)
    check_PHS(-np.pi, momenta[nmodes:], velocities[nmodes:], wfs[:, nmodes:],
              pmat)
Пример #15
0
def test_PHS_TRIM_degenerate_ordering():
    """ Test PHS at a TRIM, both when it squares to 1 and -1.

    Take a Hamiltonian with 3 degenerate bands, the degeneracy of each is given
    in the tuple dims. The bands have different velocities. All bands intersect
    zero energy only at k = 0 and at the edge of the BZ, so all momenta are 0
    or -pi. We thus have multiple TRIM modes, both with the same and different
    velocities.

    If P^2 = 1, all TRIM modes are eigenmodes of P.
    If P^2 = -1, TRIM modes come in pairs of particle-hole partners, ordered by
    a predefined convention."""
    sy = np.array([[0,-1j],[1j,0]])
    sz = np.array([[1,0],[0,-1]])
    ### P squares to 1 ###
    np.random.seed(42)
    dims = (4, 10, 20)
    ts = (1.0, 1.7, 13.8)
    rand_hop = 1j*(0.1+np.random.rand())
    hop = la.block_diag(*[t*rand_hop*np.eye(dim) for t, dim in zip(ts, dims)])

    # Particle-hole operator
    pmat = np.eye(sum(dims))
    onsite = np.zeros(hop.shape, dtype=complex)
    prop, stab = leads.modes(onsite, hop, particle_hole=pmat)
    # All momenta are either 0 or -pi.
    assert np.all([np.any(ele - np.array([0, -np.pi])) for ele in prop.momenta])
    # All modes are eigenmodes of P.
    assert np.all([np.allclose(wf, pmat.dot(wf.conj())) for wf in prop.wave_functions.T])
    ###########

    ### P squares to -1 ###
    np.random.seed(1337)
    dims = (1, 4, 16)
    ts = (1.0, 17.2, 13.4)

    hop_mat = np.kron(sz, 1j*(0.1+np.random.rand())*np.eye(2))
    blocks = []
    for t, dim in zip(ts, dims):
        blocks += dim*[t*hop_mat]
    hop = la.block_diag(*blocks)
    # Particle-hole operator
    pmat = np.kron(np.eye(sum(dims)), 1j*np.kron(sz, sy))

    # P squares to -1
    assert np.allclose(pmat.dot(pmat.conj()), -np.eye(pmat.shape[0]))
    # The Hamiltonian anticommutes with P
    assert np.allclose(pmat.dot(hop.conj()).dot(npl.inv(pmat)), -hop)

    onsite = np.zeros(hop.shape, dtype=complex)
    prop, stab = leads.modes(onsite, hop, particle_hole=pmat)
    # By design, all momenta are either 0 or -pi.
    assert np.all([np.any(ele - np.array([0, -np.pi])) for ele in prop.momenta])

    wfs = prop.wave_functions
    momenta = prop.momenta
    velocities = prop.velocities
    nmodes = stab.nmodes

    # By design, all modes are at a TRIM here. Each must thus have a particle-hole
    # partner at the same TRIM and with the same velocity.
    # Incident modes
    check_PHS(0, momenta[:nmodes], velocities[:nmodes], wfs[:, :nmodes], pmat)
    check_PHS(-np.pi, momenta[:nmodes], velocities[:nmodes], wfs[:, :nmodes], pmat)
    # Outgoing modes
    check_PHS(0, momenta[nmodes:], velocities[nmodes:], wfs[:, nmodes:], pmat)
    check_PHS(-np.pi, momenta[nmodes:], velocities[nmodes:], wfs[:, nmodes:], pmat)
Пример #16
0
def test_modes_symmetries():
    np.random.seed(10)
    for n in (4, 8, 40, 60):
        for sym in kwant.rmt.sym_list:
            # Random onsite and hopping matrices in symmetry class
            h_cell = kwant.rmt.gaussian(n, sym)
            # Hopping is an offdiagonal block of a Hamiltonian. We rescale it
            # to ensure that there are modes at the Fermi level.
            h_hop = 10 * kwant.rmt.gaussian(2*n, sym)[:n, n:]

            if kwant.rmt.p(sym):
                p_mat = np.array(kwant.rmt.h_p_matrix[sym])
                p_mat = np.kron(np.identity(n // len(p_mat)), p_mat)
            else:
                p_mat = None

            if kwant.rmt.t(sym):
                t_mat = np.array(kwant.rmt.h_t_matrix[sym])
                t_mat = np.kron(np.identity(n // len(t_mat)), t_mat)
            else:
                t_mat = None

            if kwant.rmt.c(sym):
                c_mat = np.kron(np.identity(n // 2), np.diag([1, -1]))
            else:
                c_mat = None

            prop_modes, stab_modes = leads.modes(h_cell, h_hop, particle_hole=p_mat,
                                                 time_reversal=t_mat, chiral=c_mat)
            wave_functions = prop_modes.wave_functions
            momenta = prop_modes.momenta
            nmodes = stab_modes.nmodes

            if t_mat is not None:
                assert_almost_equal(wave_functions[:, nmodes:],
                        t_mat.dot(wave_functions[:, :nmodes].conj()),
                        err_msg='TRS broken in ' + sym)

            if c_mat is not None:
                assert_almost_equal(wave_functions[:, nmodes:],
                        c_mat.dot(wave_functions[:, :nmodes:-1]),
                        err_msg='SLS broken in ' + sym)

            if p_mat is not None:
                # If P^2 = -1, then P psi(-k) = -psi(k) for k>0, so one must look at
                # positive and negative momenta separately.
                # Test positive momenta.
                in_positive_k = (np.pi > momenta[:nmodes]) * (momenta[:nmodes] > 0)
                out_positive_k = (np.pi > momenta[nmodes:]) * (momenta[nmodes:] > 0)

                assert_almost_equal(wave_functions[:, :nmodes][:, in_positive_k[::-1]],
                        p_mat.dot((wave_functions[:, :nmodes][:, in_positive_k][:, ::-1]).conj()),
                        err_msg='PHS broken in ' + sym)
                assert_almost_equal(wave_functions[:, nmodes:][:, out_positive_k[::-1]],
                        p_mat.dot((wave_functions[:, nmodes:][:, out_positive_k][:, ::-1]).conj()),
                        err_msg='PHS broken in ' + sym)

                # Test negative momenta. Need the sign of P^2 here.
                p_squared_sign = np.sign(p_mat.dot(p_mat.conj())[0, 0].real)
                in_neg_k = (-np.pi < momenta[:nmodes]) * (momenta[:nmodes] < 0)
                out_neg_k = (-np.pi < momenta[nmodes:]) * (momenta[nmodes:] < 0)

                assert_almost_equal(p_squared_sign*wave_functions[:, :nmodes][:, in_neg_k[::-1]],
                        p_mat.dot((wave_functions[:, :nmodes][:, in_neg_k][:, ::-1]).conj()),
                        err_msg='PHS broken in ' + sym)
                assert_almost_equal(p_squared_sign*wave_functions[:, nmodes:][:, out_neg_k[::-1]],
                        p_mat.dot((wave_functions[:, nmodes:][:, out_neg_k][:, ::-1]).conj()),
                        err_msg='PHS broken in ' + sym)
Пример #17
0
def test_cons_blocks_sizes():
    # Hamiltonian with a conservation law consisting of three blocks of
    # different size.
    n = 8
    # Three blocks of different sizes.
    cs = np.diag(n*[-1] + 2*n*[1] + 3*n*[2])
    # Onsite and hopping
    hc, hh = random_onsite_hop(6*n)
    hc[:n, n:] = 0
    hc[n:, :n] = 0
    hc[n:3*n, 3*n:] = 0
    hc[3*n:, n:3*n] = 0
    assert_almost_equal(cs.dot(hc) - hc.dot(cs), 0)
    hh[:n, n:] = 0
    hh[n:, :n] = 0
    hh[n:3*n, 3*n:] = 0
    hh[3*n:, n:3*n] = 0
    assert_almost_equal(cs.dot(hh) - hh.dot(cs), 0)
    # Mix them with a random unitary
    U = kwant.rmt.circular(6*n, 'A', rng=23)
    cs_t = U.T.conj().dot(cs).dot(U)
    hc_t = U.T.conj().dot(hc).dot(U)
    hh_t = U.T.conj().dot(hh).dot(U)
    assert_almost_equal(cs_t.dot(hc_t) - hc_t.dot(cs_t), 0)
    assert_almost_equal(cs_t.dot(hh_t) - hh_t.dot(cs_t), 0)
    # Get the projectors. There are three of them, composed of
    # the eigenvectors of the conservation law.
    evals, evecs = np.linalg.eigh(cs_t)
    # Make sure the ordering is correct.
    assert_almost_equal(evals-np.array(n*[-1] + 2*n*[1] + 3*n*[2]), 0)
    # First projector projects onto block with
    # eigenvalue -1 of size n, second to eigenvalue 1 of
    # size 2n, third onto block with eigenvalue 2 of size 3n.
    projectors = [np.reshape(evecs[:,:n], (6*n, n)),
                  np.reshape(evecs[:,n:3*n], (6*n, 2*n)),
                  np.reshape(evecs[:,3*n:6*n], (6*n, 3*n))]
    # Check that projectors are correctly defined.
    assert_almost_equal(evecs, np.hstack(projectors))

    ########
    # Compute self energy with and without specifying projectors.
    # Make the projectors sparse.
    projectors = [sparse.csr_matrix(p) for p in projectors]
    # Modes without projectors
    modes1 = leads.modes(hc_t, hh_t)
    current_conserving(modes1[1])
    # With projectors
    modes2 = leads.modes(hc_t, hh_t, projectors=projectors)
    current_conserving(modes2[1])
    assert_almost_equal(modes1[1].selfenergy(), modes2[1].selfenergy())

    ########
    # Check that the number of modes per block with projectors matches the
    # total number of modes, with and without projectors.
    prop1, stab1 = modes1  # No projectors
    prop2, stab2 = modes2  # Projectors
    assert_almost_equal(stab1.nmodes, sum(prop1.block_nmodes))
    assert_almost_equal(stab2.nmodes, sum(prop2.block_nmodes))
    assert_almost_equal(stab1.nmodes, sum(prop2.block_nmodes))

    ########
    # Check that with projectors specified, in/out propagating modes and
    # evanescent modes in vecs and vecslmbdainv are block diagonal.
    # Do this by checking explicitly that the blocks are nonzero, and that
    # if all blocks are set to zero manually, the stabilized modes only contain
    # zeros (meaning that anything off the block diagonal is zero).
    nmodes = stab2.nmodes
    block_nmodes = prop2.block_nmodes
    vecs, vecslmbdainv = stab2.vecs, stab2.vecslmbdainv
    # Row indices for the blocks.
    # The first block is of size n, second of size 2n
    # and the third of size 3n.
    block_rows = [slice(0, n), slice(n, 3*n), slice(3*n, 6*n)]
    ### Check propagating modes ###
    # Column indices for the blocks.
    offsets = np.cumsum([0]+block_nmodes)
    block_cols = [slice(*i) for i in np.vstack([offsets[:-1], offsets[1:]]).T]
    prop_modes = (vecs[:, :nmodes], vecs[:, nmodes:2*nmodes],
                  vecslmbdainv[:, :nmodes], vecslmbdainv[:, nmodes:2*nmodes])
    check_bdiag_modes(prop_modes, block_rows, block_cols)
    ### Check evanescent modes ###
    # First figure out the number of evanescent modes per block.
    # The number of relevant evanescent modes (outward decaying) in a block is
    # N - nmodes, where N is the dimension of the block and nmodes the number
    # of incident or outgoing propagating modes.
    block_cols = [N - nmodes for nmodes, N in zip(block_nmodes, [n, 2*n, 3*n])]
    offsets = np.cumsum([0]+block_cols)
    block_cols = [slice(*i) for i in np.vstack([offsets[:-1], offsets[1:]]).T]
    ev_modes = (vecs[:, 2*nmodes:], vecslmbdainv[:, 2*nmodes:])
    check_bdiag_modes(ev_modes, block_rows, block_cols)