Esempio n. 1
0
def test_closest():
    rng = ensure_rng(10)
    for sym_dim in range(1, 4):
        for space_dim in range(sym_dim, 4):
            lat = kwant.lattice.general(ta.identity(space_dim))

            # Choose random periods.
            while True:
                periods = rng.randint(-10, 11, (sym_dim, space_dim))
                if np.linalg.det(np.dot(periods, periods.T)) > 0.1:
                    # Periods are reasonably linearly independent.
                    break
            syst = builder.Builder(kwant.TranslationalSymmetry(*periods))

            for tag in rng.randint(-30, 31, (4, space_dim)):
                # Add site and connect it to the others.
                old_sites = list(syst.sites())
                new_site = lat(*tag)
                syst[new_site] = None
                syst[((new_site, os) for os in old_sites)] = None

                # Test consistency with fill().
                for point in 200 * rng.random_sample((10, space_dim)) - 100:
                    closest = syst.closest(point)
                    dist = closest.pos - point
                    dist = ta.dot(dist, dist)
                    syst2 = builder.Builder()
                    syst2.fill(syst, inside_disc(point, 2 * dist), closest)
                    assert syst2.closest(point) == closest
                    for site in syst2.sites():
                        dd = site.pos - point
                        dd = ta.dot(dd, dd)
                        assert dd >= 0.999999 * dist
Esempio n. 2
0
def test_symm_algorithm_equivalence():
    """Test different stabilization methods in the computation of modes,
    in the presence and/or absence of the discrete symmetries."""
    rng = ensure_rng(400)
    n = 8
    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

        check_equivalence(h_cell, h_hop, n, sym=sym, particle_hole=p_mat,
                          chiral=c_mat, time_reversal=t_mat)
Esempio n. 3
0
def test_singular_graph_system(smatrix):
    rng = ensure_rng(11)

    system = kwant.Builder()
    lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))
    h = rng.random_sample((n, n)) + 1j * rng.random_sample((n, n))
    h += h.conjugate().transpose()
    h *= 0.8
    t = 4 * rng.random_sample((n, n)) + 4j * rng.random_sample((n, n))
    t1 = 4 * rng.random_sample((n, n)) + 4j * rng.random_sample((n, n))
    lead[sq(0, 0)] = system[[sq(0, 0), sq(1, 0)]] = h
    lead[sq(0, 1)] = system[[sq(0, 1), sq(1, 1)]] = 4 * h
    for builder in [system, lead]:
        builder[sq(0, 0), sq(1, 0)] = t
        builder[sq(0, 1), sq(1, 0)] = t1
    system.attach_lead(lead)
    system.attach_lead(lead.reversed())
    fsyst = system.finalized()

    result = smatrix(fsyst)
    s, leads = result.data, result.lead_info
    assert_almost_equal(np.dot(s.conjugate().transpose(), s),
                        np.identity(s.shape[0]))
    n_modes = len(leads[0].momenta) // 2
    assert len(leads[1].momenta) // 2 == n_modes
    assert_almost_equal(s[:n_modes, :n_modes], 0)
    t_elements = np.sort(abs(np.asarray(s[n_modes:, :n_modes])), axis=None)
    t_el_should_be = n_modes * (n_modes - 1) * [0] + n_modes * [1]
    assert_almost_equal(t_elements, t_el_should_be)
Esempio n. 4
0
def test_selfenergy_reflection(greens_function, smatrix):
    rng = ensure_rng(4)
    system = kwant.Builder()
    left_lead = kwant.Builder(kwant.TranslationalSymmetry((-1, )))
    for b, site in [(system, chain(0)), (system, chain(1)),
                    (left_lead, chain(0))]:
        h = rng.random_sample((n, n)) + 1j * rng.random_sample((n, n))
        h += h.conjugate().transpose()
        b[site] = h
    for b, hopp in [(system, (chain(0), chain(1))),
                    (left_lead, (chain(0), chain(1)))]:
        b[hopp] = (10 * rng.random_sample((n, n)) + 1j * rng.random_sample(
            (n, n)))
    system.attach_lead(left_lead)
    fsyst = system.finalized()

    t = smatrix(fsyst, 0, (), [0], [0])

    fsyst.leads[0] = LeadWithOnlySelfEnergy(fsyst.leads[0])
    sol = greens_function(fsyst, 0, (), [0], [0])
    assert_almost_equal(sol.transmission(0, 0), t.transmission(0, 0))

    fsyst = system.finalized()
    for syst in (fsyst.precalculate(what='selfenergy'),
                 fsyst.precalculate(what='all')):
        sol = greens_function(syst, 0, (), [0], [0])
        assert_almost_equal(sol.transmission(0, 0), t.transmission(0, 0))
    raises(ValueError, greens_function, fsyst.precalculate(what='modes'), 0,
           (), [0], [0])
Esempio n. 5
0
def test_density_interpolation():
    ## Passing a Builder will raise an error
    pytest.raises(TypeError, plotter.interpolate_density, syst_2d(), None)

    # Test that the density is always identically zero at the box boundaries
    # as the bump function has finite support and we add a padding
    _test_border_0(kwant.plotter.interpolate_density)

    def R(theta):
        return ta.array([[cos(theta), -sin(theta)], [sin(theta), cos(theta)]])

    # Make lattice with lattice vectors perturbed from x and y directions
    def make_lattice(a, salt='0'):
        theta_x = kwant.digest.uniform('x', salt=salt) * np.pi / 6
        theta_y = kwant.digest.uniform('y', salt=salt) * np.pi / 6
        x = ta.dot(R(theta_x), (a, 0))
        y = ta.dot(R(theta_y), (0, a))
        return kwant.lattice.general([x, y], norbs=1)

    # Check that integrating the interpolated density gives the same result
    # as summing the densities on all sites. We check this for several lattice
    # widths, lattice orientations and bump widths.
    for a, width in itertools.product((1, 2), (1, 0.5)):
        lat = make_lattice(a)
        syst = syst_rect(lat, salt='0').finalized()

        psi = kwant.wave_function(syst, energy=3)(0)[0]
        density = kwant.operator.Density(syst)(psi)
        exact_charge = sum(density)
        # We verify that the result is good by interpolating for
        # various numbers of points-per-bump and verifying that
        # the error falls of as 1/n.
        data = []
        for n in [4, 6, 8, 11, 16]:
            rho, box = plotter.interpolate_density(syst,
                                                   density,
                                                   n=n,
                                                   abswidth=width)
            (xmin, xmax), (ymin, ymax) = box
            area = xmax - xmin * (ymax - ymin)
            N = rho.shape[0] * rho.shape[1]
            charge = np.sum(rho) * area / N
            data.append((n, abs(charge - exact_charge)))
        _, _, rvalue, *_ = scipy.stats.linregress(np.log(data))
        # Gradient of -1 on log-log plot means error falls off as 1/n
        # TODO: review this value once #280 has been dealt with.
        assert rvalue < -0.7

    # Test that the interpolation is linear in the input.
    rng = ensure_rng(1)
    lat = make_lattice(1, '1')
    syst = syst_rect(lat, salt='1').finalized()
    rho_0 = rng.rand(len(syst.sites))
    rho_1 = rng.rand(len(syst.sites))

    irho_0, _ = plotter.interpolate_density(syst, rho_0)
    irho_1, _ = plotter.interpolate_density(syst, rho_1)

    rho_tot, _ = plotter.interpolate_density(syst, rho_0 + 2 * rho_1)
    assert np.allclose(rho_tot, irho_0 + 2 * irho_1)
Esempio n. 6
0
def test_gaussian_symmetries():
    rng = ensure_rng(10)
    for n in (5, 8, 100, 200):
        for sym in rmt.sym_list:
            if sym not in ('A', 'D', 'AI') and n % 2:
                raises(ValueError, rmt.gaussian, 5, sym)
                continue
            h = rmt.gaussian(n, sym, rng=rng)
            if rmt.t(sym):
                t_mat = np.array(rmt.h_t_matrix[sym])
                t_mat = np.kron(np.identity(n // len(t_mat)), t_mat)
                assert_allclose(h,
                                np.dot(t_mat, np.dot(h.conj(), t_mat)),
                                err_msg='TRS broken in ' + sym)
            if rmt.p(sym):
                p_mat = np.array(rmt.h_p_matrix[sym])
                p_mat = np.kron(np.identity(n // len(p_mat)), p_mat)
                assert_allclose(h,
                                -np.dot(p_mat, np.dot(h.conj(), p_mat)),
                                err_msg='PHS broken in ' + sym)
            if rmt.c(sym):
                sz = np.kron(np.identity(n // 2), np.diag([1, -1]))
                assert_allclose(h,
                                -np.dot(sz, np.dot(h, sz)),
                                err_msg='SLS broken in ' + sym)
Esempio n. 7
0
def test_gaussian_distributions():
    rng = ensure_rng(1)
    n = 8
    for sym in rmt.sym_list:
        matrices = np.array(
            [rmt.gaussian(n, sym, rng=rng)[-1, 0] for i in range(3000)])
        matrices = matrices.imag if sym in ('D', 'BDI') else matrices.real
        ks = stats.kstest(matrices, 'norm')
        assert (ks[1] > 0.1), (sym, ks)
Esempio n. 8
0
def test_lll():
    rng = ensure_rng(1)
    for i in range(50):
        x = rng.randint(4) + 1
        mat = rng.randn(x, x + rng.randint(2))
        c = 1.34 + .5 * rng.random_sample()
        reduced_mat, coefs = lll.lll(mat)
        assert lll.is_c_reduced(reduced_mat, c)
        assert np.allclose(np.dot(mat.T, coefs), reduced_mat.T)
def test_cvp():
    rng = ensure_rng(0)
    for i in range(1, 5):
        for j in range(i, 5):
            mat = rng.randn(i, j)
            mat = lll.lll(mat)[0]
            for k in range(4):
                point = 50 * rng.randn(j)
                assert np.array_equal(
                    lll.cvp(point, mat, 10)[:3], lll.cvp(point, mat, 3))
Esempio n. 10
0
def test_closest():
    rng = ensure_rng(4)
    lat = lattice.general(((1, 0), (0.5, sqrt(3) / 2)), norbs=1)
    for i in range(50):
        point = 20 * rng.random_sample(2)
        closest = lat(*lat.closest(point)).pos
        assert np.linalg.norm(point - closest) <= 1 / sqrt(3)
    lat = lattice.general(rng.randn(3, 3), norbs=1)
    for i in range(50):
        tag = rng.randint(10, size=(3, ))
        assert lat.closest(lat(*tag).pos) == tag
Esempio n. 11
0
def twoterminal_system():
    rng = ensure_rng(11)
    system = kwant.Builder()
    lead = kwant.Builder(kwant.TranslationalSymmetry((1, )))
    h = rng.random_sample((n, n)) + 1j * rng.random_sample((n, n))
    h += h.conjugate().transpose()
    h *= 0.8
    t = 4 * rng.random_sample((n, n)) + 4j * rng.random_sample((n, n))
    lead[chain(0)] = h
    system[chain(0)] = h * 1.2
    lead[chain(0), chain(1)] = t
    system.attach_lead(lead)
    system.attach_lead(lead.reversed())
    return system
Esempio n. 12
0
def test_circular():
    rng = ensure_rng(10)
    n = 6
    sy = np.kron(np.identity(n // 2), [[0, 1j], [-1j, 0]])
    for sym in rmt.sym_list:
        if rmt.t(sym) == -1 or rmt.p(sym) == -1:
            raises(ValueError, rmt.circular, 5, sym)
        s = rmt.circular(n, sym, rng=rng)
        assert_allclose(np.dot(s, s.T.conj()),
                        np.identity(n),
                        atol=1e-9,
                        err_msg='Unitarity broken in ' + sym)
        if rmt.t(sym):
            s1 = np.copy(
                s.T if rmt.p(sym) != -1 else np.dot(sy, np.dot(s.T, sy)))
            s1 *= rmt.t(sym) * (-1 if rmt.p(sym) == -1 else 1)
            assert_allclose(s, s1, atol=1e-9, err_msg='TRS broken in ' + sym)
        if rmt.p(sym):
            s1 = np.copy(s.conj() if rmt.p(sym) != -1 else np.
                         dot(sy, np.dot(s.conj(), sy)))
            if sym in ('DIII', 'CI'):
                s1 *= -1
            assert_allclose(s, s1, atol=1e-9, err_msg='PHS broken in ' + sym)
        if rmt.c(sym):
            assert_allclose(s,
                            s.T.conj(),
                            atol=1e-9,
                            err_msg='SLS broken in ' + sym)

    # Check for distribution properties if the ensemble is a symmetric group.
    f = lambda x: x[0] / np.linalg.norm(x)
    for sym in ('A', 'C'):
        sample_distr = np.apply_along_axis(f, 0, rng.randn(2 * n, 1000))
        s_sample = np.array(
            [rmt.circular(n, sym, rng=rng) for i in range(1000)])
        assert stats.ks_2samp(sample_distr, s_sample[:, 0, 0].real)[1] > 0.1, \
                'Noncircular distribution in ' + sym
        assert stats.ks_2samp(sample_distr, s_sample[:, 3, 2].real)[1] > 0.1, \
                'Noncircular distribution in ' + sym
        assert stats.ks_2samp(sample_distr, s_sample[:, 1, 1].imag)[1] > 0.1, \
                'Noncircular distribution in ' + sym
        assert stats.ks_2samp(sample_distr, s_sample[:, 2, 3].imag)[1] > 0.1, \
                'Noncircular distribution in ' + sym

    sample_distr = np.apply_along_axis(f, 0, rng.randn(n, 500))
    s_sample = np.array([rmt.circular(n, 'D', rng=rng) for i in range(500)])
    ks = stats.ks_2samp(sample_distr, s_sample[:, 0, 0])
    assert ks[1] > 0.1, 'Noncircular distribution in D ' + str(ks)
    ks = stats.ks_2samp(sample_distr, s_sample[:, 3, 2])
    assert ks[1] > 0.1, 'Noncircular distribution in D ' + str(ks)
Esempio n. 13
0
def test_wire():
    rng = ensure_rng(5)
    vecs = rng.randn(3, 3)
    vecs[0] = [1, 0, 0]
    center = rng.randn(3)
    lat = lattice.general(vecs, rng.randn(4, 3), norbs=1)
    syst = builder.Builder(lattice.TranslationalSymmetry((2, 0, 0)))
    def wire_shape(pos):
        pos = np.array(pos)
        return np.linalg.norm(pos[1:] - center[1:])**2 <= 8.6**2
    syst[lat.shape(wire_shape, center)] = 0
    sites2 = set(syst.sites())
    syst = builder.Builder(lattice.TranslationalSymmetry((2, 0, 0)))
    syst[lat.wire(center, 8.6)] = 1
    sites1 = set(syst.sites())
    assert sites1 == sites2
Esempio n. 14
0
def test_translational_symmetry_reversed():
    rng = ensure_rng(30)
    lat = lattice.general(np.identity(3), norbs=1)
    sites = [lat(i, j, k) for i in range(-2, 6) for j in range(-2, 6)
                          for k in range(-2, 6)]
    for i in range(4):
            periods = rng.randint(-5, 5, (3, 3))
            try:
                sym = lattice.TranslationalSymmetry(*periods)
                rsym = sym.reversed()
                for site in sites:
                    assert sym.to_fd(site) == rsym.to_fd(site)
                    assert sym.which(site) == -rsym.which(site)
                    vec = np.array([1, 1, 1])
                    assert sym.act(vec, site), rsym.act(-vec == site)
            except ValueError:
                pass
Esempio n. 15
0
def twolead_builder():
    rng = ensure_rng(4)
    system = kwant.Builder()
    left_lead = kwant.Builder(kwant.TranslationalSymmetry((-1,)))
    right_lead = kwant.Builder(kwant.TranslationalSymmetry((1,)))
    for b, site in [(system, chain(0)), (system, chain(1)),
                    (left_lead, chain(0)), (right_lead, chain(0))]:
        h = rng.random_sample((n, n)) + 1j * rng.random_sample((n, n))
        h += h.conjugate().transpose()
        b[site] = h
    for b, hopp in [(system, (chain(0), chain(1))),
                    (left_lead, (chain(0), chain(1))),
                    (right_lead, (chain(0), chain(1)))]:
        b[hopp] = (10 * rng.random_sample((n, n)) +
                   1j * rng.random_sample((n, n)))
    system.attach_lead(left_lead)
    system.attach_lead(right_lead)
    return system
Esempio n. 16
0
def test_selfenergy(greens_function, smatrix):
    rng = ensure_rng(4)
    system = kwant.Builder()
    left_lead = kwant.Builder(kwant.TranslationalSymmetry((-1, )))
    right_lead = kwant.Builder(kwant.TranslationalSymmetry((1, )))
    for b, site in [(system, chain(0)), (system, chain(1)),
                    (left_lead, chain(0)), (right_lead, chain(0))]:
        h = rng.random_sample((n, n)) + 1j * rng.random_sample((n, n))
        h += h.conjugate().transpose()
        b[site] = h
    for b, hopp in [(system, (chain(0), chain(1))),
                    (left_lead, (chain(0), chain(1))),
                    (right_lead, (chain(0), chain(1)))]:
        b[hopp] = (10 * rng.random_sample((n, n)) + 1j * rng.random_sample(
            (n, n)))
    system.attach_lead(left_lead)
    system.attach_lead(right_lead)
    fsyst = system.finalized()

    t = smatrix(fsyst, 0, (), [1], [0]).data
    eig_should_be = np.linalg.eigvals(t * t.conjugate().transpose())
    n_eig = len(eig_should_be)

    def check_fsyst(fsyst):
        sol = greens_function(fsyst, 0, (), [1], [0])
        ttdagnew = sol._a_ttdagger_a_inv(1, 0)
        eig_are = np.linalg.eigvals(ttdagnew)
        t_should_be = np.sum(eig_are)
        assert_almost_equal(eig_are.imag, 0)
        assert_almost_equal(
            np.sort(eig_are.real)[-n_eig:], np.sort(eig_should_be.real))
        assert_almost_equal(t_should_be, sol.transmission(1, 0))

    fsyst.leads[1] = LeadWithOnlySelfEnergy(fsyst.leads[1])
    check_fsyst(fsyst)

    fsyst.leads[0] = LeadWithOnlySelfEnergy(fsyst.leads[0])
    check_fsyst(fsyst)

    fsyst = system.finalized()
    for syst in (fsyst, fsyst.precalculate(what='selfenergy'),
                 fsyst.precalculate(what='all')):
        check_fsyst(syst)
    raises(ValueError, check_fsyst, fsyst.precalculate(what='modes'))
Esempio n. 17
0
def test_wavefunc_ldos_consistency(wave_function, ldos):
    L = 2
    W = 3

    rng = ensure_rng(31)
    syst = kwant.Builder()
    left_lead = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))
    top_lead = kwant.Builder(kwant.TranslationalSymmetry((1, 0)))
    for b, sites in [(syst, [square(x, y) for x in range(L)
                             for y in range(W)]),
                     (left_lead, [square(0, y) for y in range(W)]),
                     (top_lead, [square(x, 0) for x in range(L)])]:
        for site in sites:
            h = rng.random_sample((n, n)) + 1j * rng.random_sample((n, n))
            h += h.conjugate().transpose()
            b[site] = h
        for hopping_kind in square.neighbors():
            for hop in hopping_kind(b):
                b[hop] = (10 * rng.random_sample(
                    (n, n)) + 1j * rng.random_sample((n, n)))
    syst.attach_lead(left_lead)
    syst.attach_lead(top_lead)
    syst = syst.finalized()

    def check(syst):
        for energy in [0, 1000]:
            wf = wave_function(syst, energy)
            ldos2 = np.zeros(wf.num_orb, float)
            for lead in range(len(syst.leads)):
                temp = abs(wf(lead))
                temp **= 2
                ldos2 += temp.sum(axis=0)
            ldos2 *= (0.5 / np.pi)

            assert_almost_equal(ldos2, ldos(syst, energy))

    for fsyst in (syst, syst.precalculate(what='modes'),
                  syst.precalculate(what='all')):
        check(fsyst)
    raises(ValueError, check, syst.precalculate(what='selfenergy'))
    syst.leads[0] = LeadWithOnlySelfEnergy(syst.leads[0])
    raises(NotImplementedError, check, syst)
Esempio n. 18
0
def test_cvp():
    rng = ensure_rng(0)
    for i in range(1, 5):
        for j in range(i, 5):
            mat = rng.randn(i, j)
            mat = lll.lll(mat)[0]
            for k in range(4):
                point = 50 * rng.randn(j)
                assert np.array_equal(
                    lll.cvp(point, mat, 10)[:3], lll.cvp(point, mat, 3))

    # Test equidistant vectors
    # Cubic lattice
    basis = np.eye(3)
    vec = np.zeros((3))
    assert len(lll.cvp(vec, basis, n=2, group_by_length=True)) == 7
    assert len(lll.cvp(vec, basis, n=3, group_by_length=True)) == 19
    vec = 0.5 * np.array([1, 1, 1])
    assert len(lll.cvp(vec, basis, group_by_length=True)) == 8
    vec = 0.5 * np.array([1, 1, 0])
    assert len(lll.cvp(vec, basis, group_by_length=True)) == 4
    vec = 0.5 * np.array([1, 0, 0])
    assert len(lll.cvp(vec, basis, group_by_length=True)) == 2
    # Square lattice with offset
    offset = np.array([0, 0, 1])
    basis = np.eye(3)[:2]
    vec = np.zeros((3)) + rng.rand() * offset
    assert len(lll.cvp(vec, basis, n=2, group_by_length=True)) == 5
    assert len(lll.cvp(vec, basis, n=3, group_by_length=True)) == 9
    vec = 0.5 * np.array([1, 1, 0]) + rng.rand() * offset
    assert len(lll.cvp(vec, basis, group_by_length=True)) == 4
    vec = 0.5 * np.array([1, 0, 0]) + rng.rand() * offset
    assert len(lll.cvp(vec, basis, group_by_length=True)) == 2
    # Hexagonal lattice
    basis = np.array([[1, 0], [-0.5, 0.5 * np.sqrt(3)]])
    vec = np.zeros((2))
    assert len(lll.cvp(vec, basis, n=2, group_by_length=True)) == 7
    assert len(lll.cvp(vec, basis, n=3, group_by_length=True)) == 13
    vec = np.array([0.5, 0.5 / np.sqrt(3)])
    assert len(lll.cvp(vec, basis, group_by_length=True)) == 3
    assert len(lll.cvp(vec, basis, n=2, group_by_length=True)) == 6
    assert len(lll.cvp(vec, basis, n=3, group_by_length=True)) == 12
Esempio n. 19
0
def test_two_equal_leads(smatrix):
    def check_fsyst(fsyst):
        sol = smatrix(fsyst)
        s, leads = sol.data, sol.lead_info
        assert_almost_equal(np.dot(s.conjugate().transpose(), s),
                            np.identity(s.shape[0]))
        n_modes = len(leads[0].momenta) // 2
        assert len(leads[1].momenta) // 2 == n_modes
        assert_almost_equal(s[:n_modes, :n_modes], 0)
        t_elements = np.sort(abs(np.asarray(s[n_modes:, :n_modes])), axis=None)
        t_el_should_be = n_modes * (n_modes - 1) * [0] + n_modes * [1]
        assert_almost_equal(t_elements, t_el_should_be)
        assert_almost_equal(sol.transmission(1, 0), n_modes)

    rng = ensure_rng(11)
    system = kwant.Builder()
    lead = kwant.Builder(kwant.TranslationalSymmetry((1, )))
    h = rng.random_sample((n, n)) + 1j * rng.random_sample((n, n))
    h += h.conjugate().transpose()
    h *= 0.8
    t = 4 * rng.random_sample((n, n)) + 4j * rng.random_sample((n, n))
    lead[chain(0)] = system[chain(0)] = h
    lead[chain(0), chain(1)] = t
    system.attach_lead(lead)
    system.attach_lead(lead.reversed())
    fsyst = system.finalized()
    for syst in (fsyst, fsyst.precalculate(), fsyst.precalculate(what='all')):
        check_fsyst(syst)
    raises(ValueError, check_fsyst, fsyst.precalculate(what='selfenergy'))

    # Test the same, but with a larger scattering region.
    system = kwant.Builder()
    system[[chain(0), chain(1)]] = h
    system[chain(0), chain(1)] = t
    system.attach_lead(lead)
    system.attach_lead(lead.reversed())
    fsyst = system.finalized()
    for syst in (fsyst, fsyst.precalculate(), fsyst.precalculate(what='all')):
        check_fsyst(syst)
    raises(ValueError, check_fsyst, fsyst.precalculate(what='selfenergy'))
Esempio n. 20
0
def test_output(smatrix):
    rng = ensure_rng(3)
    system = kwant.Builder()
    left_lead = kwant.Builder(kwant.TranslationalSymmetry((-1, )))
    right_lead = kwant.Builder(kwant.TranslationalSymmetry((1, )))
    for b, site in [(system, chain(0)), (system, chain(1)),
                    (left_lead, chain(0)), (right_lead, chain(0))]:
        h = rng.random_sample((n, n)) + 1j * rng.random_sample((n, n))
        h += h.conjugate().transpose()
        b[site] = h
    for b, hopp in [(system, (chain(0), chain(1))),
                    (left_lead, (chain(0), chain(1))),
                    (right_lead, (chain(0), chain(1)))]:
        b[hopp] = (10 * rng.random_sample((n, n)) + 1j * rng.random_sample(
            (n, n)))
    system.attach_lead(left_lead)
    system.attach_lead(right_lead)
    fsyst = system.finalized()

    result1 = smatrix(fsyst)
    s, modes1 = result1.data, result1.lead_info
    assert s.shape == 2 * (sum(len(i.momenta) for i in modes1) // 2, )
    s1 = result1.submatrix(1, 0)
    result2 = smatrix(fsyst, 0, (), [1], [0])
    s2, modes2 = result2.data, result2.lead_info
    assert s2.shape == (len(modes2[1].momenta) // 2,
                        len(modes2[0].momenta) // 2)
    assert_almost_equal(abs(s1), abs(s2))
    assert_almost_equal(np.dot(s.T.conj(), s), np.identity(s.shape[0]))
    raises(ValueError, smatrix, fsyst, out_leads=[])
    modes = smatrix(fsyst).lead_info
    h = fsyst.leads[0].cell_hamiltonian()
    t = fsyst.leads[0].inter_cell_hopping()
    modes1 = kwant.physics.modes(h, t)[0]
    h = fsyst.leads[1].cell_hamiltonian()
    t = fsyst.leads[1].inter_cell_hopping()
    modes2 = kwant.physics.modes(h, t)[0]
    assert_modes_equal(modes1, modes[0])
    assert_modes_equal(modes2, modes[1])
Esempio n. 21
0
def test_one_lead(smatrix):
    rng = ensure_rng(3)
    system = kwant.Builder()
    lead = kwant.Builder(kwant.TranslationalSymmetry((-1, )))
    for b, site in [(system, chain(0)), (system, chain(1)), (system, chain(2)),
                    (lead, chain(0))]:
        h = rng.random_sample((n, n)) + 1j * rng.random_sample((n, n))
        h += h.conjugate().transpose()
        b[site] = h
    for b, hopp in [(system, (chain(0), chain(1))),
                    (system, (chain(1), chain(2))),
                    (lead, (chain(0), chain(1)))]:
        b[hopp] = (10 * rng.random_sample((n, n)) + 1j * rng.random_sample(
            (n, n)))
    system.attach_lead(lead)
    fsyst = system.finalized()

    for syst in (fsyst, fsyst.precalculate(), fsyst.precalculate(what='all')):
        s = smatrix(syst).data
        assert_almost_equal(np.dot(s.conjugate().transpose(), s),
                            np.identity(s.shape[0]))

    raises(ValueError, smatrix, fsyst.precalculate(what='selfenergy'))
Esempio n. 22
0
def test_current_interpolation():

    ## Passing a Builder will raise an error
    pytest.raises(TypeError, plotter.interpolate_current, syst_2d(), None)

    def R(theta):
        return ta.array([[cos(theta), -sin(theta)], [sin(theta), cos(theta)]])

    def make_lattice(a, theta):
        x = ta.dot(R(theta), (a, 0))
        y = ta.dot(R(theta), (0, a))
        return kwant.lattice.general([x, y], norbs=1)

    _test_border_0(plotter.interpolate_current)

    ## Check current through cross section is same for different lattice
    ## parameters and orientations of the system wrt. the discretization grid
    for a, theta, width in [(1, 0, 1), (1, 0, 0.5), (2, 0, 1), (1, 0.2, 1),
                            (2, 0.4, 1)]:
        lat = make_lattice(a, theta)
        syst = syst_rect(lat, salt='0').finalized()
        psi = kwant.wave_function(syst, energy=3)(0)

        def cut(a, b):
            return b.tag[0] < 0 and a.tag[0] >= 0

        J = kwant.operator.Current(syst).bind()
        J_cut = kwant.operator.Current(syst, where=cut, sum=True).bind()
        J_exact = J_cut(psi[0])

        data = []
        for n in [4, 6, 8, 11, 16]:
            j0, box = plotter.interpolate_current(syst,
                                                  J(psi[0]),
                                                  n=n,
                                                  abswidth=width)
            x, y = (np.linspace(mn, mx, shape)
                    for (mn, mx), shape in zip(box, j0.shape))
            # slice field perpendicular to a cut along the y axis
            y_axis = (np.argmin(np.abs(x)), slice(None), 0)
            J_interp = scipy.integrate.simps(j0[y_axis], y)
            data.append((n, abs(J_interp - J_exact)))
        # 3rd value returned from 'linregress' is 'rvalue'
        # TODO: review this value once #280 has been dealt with.
        assert scipy.stats.linregress(np.log(data))[2] < -0.7

    ### Tests on a divergence-free current (closed system)

    lat = kwant.lattice.general([(1, 0), (0.5, np.sqrt(3) / 2)], norbs=1)
    syst = kwant.Builder()
    sites = [lat(0, 0), lat(1, 0), lat(0, 1), lat(2, 2)]
    syst[sites] = None
    syst[((s, t) for s, t in itertools.product(sites, sites) if s != t)] = None
    del syst[lat(0, 0), lat(2, 2)]
    syst = syst.finalized()

    # generate random divergence-free currents
    Js = rotational_currents(syst.graph)
    rng = ensure_rng(3)
    J0 = sum(rng.rand(len(Js))[:, None] * Js)
    J1 = sum(rng.rand(len(Js))[:, None] * Js)

    # Sanity check that diverence on the graph is 0
    divergence = np.zeros(len(syst.sites))
    for (a, _), current in zip(syst.graph, J0):
        divergence[a] += current
    assert np.allclose(divergence, 0)

    j0, _ = plotter.interpolate_current(syst, J0)
    j1, _ = plotter.interpolate_current(syst, J1)

    ## Test linearity of interpolation.
    j_tot, _ = plotter.interpolate_current(syst, J0 + 2 * J1)
    assert np.allclose(j_tot, j0 + 2 * j1)

    ## Test that divergence of interpolated current approaches zero as we make
    ## the interpolation finer.
    data = []
    for n in [4, 6, 8, 11, 16]:
        j, box = plotter.interpolate_current(syst, J0, n=n)
        dx = [(mx - mn) / (shape - 1) for (mn, mx), shape in zip(box, j.shape)]
        div_j = np.max(np.abs(div(j, dx)))
        data.append((n, div_j))

    # 3rd value returned from 'linregress' is 'rvalue'
    # TODO: review this value once #280 has been dealt with.
    assert scipy.stats.linregress(np.log(data))[2] < -0.7
Esempio n. 23
0
def test_blocks_symm_complex_projectors():
    # Two blocks of equal size, related by any one of the discrete
    # symmetries. Each block by itself has no symmetry. The system is
    # transformed with a random unitary, such that the projectors onto the
    # blocks are complex.
    n = 8
    rng = ensure_rng(27)
    # Symmetry class, sign of H under symmetry transformation.
    sym_info = [('AI', 1), ('AII', 1), ('D', -1),
                ('C', -1), ('AIII', -1)]
    for (sym, trans_sign) in sym_info:
        # Conservation law values
        cs = n*[-1] + n*[1]
        # Random onsite and hopping blocks
        h_cell, h_hop = random_onsite_hop(n, rng)
        # Symmetry operator
        if sym in ['AI', 'AII']:
            sym_op = np.array(kwant.rmt.h_t_matrix[sym])
            sym_op = np.kron(np.identity(n // len(sym_op)), sym_op)
        elif sym in ['D', 'C']:
            sym_op = np.array(kwant.rmt.h_p_matrix[sym])
            sym_op = np.kron(np.identity(n // len(sym_op)), sym_op)
        elif sym in ['AIII']:
            sym_op = np.kron(np.identity(n // 2), np.diag([1, -1]))
        else:
            raise ValueError('Symmetry class not covered.')
        # Full onsite and hoppings
        if sym in ['AI', 'AII', 'C', 'D']:
            # Antiunitary symmetries
            H_cell = la.block_diag(h_cell, trans_sign*sym_op.dot(
                                   h_cell.conj()).dot(sym_op.T.conj()))
            H_hop = la.block_diag(h_hop, trans_sign*sym_op.dot(
                                  h_hop.conj()).dot(sym_op.T.conj()))
        elif sym in ['AIII']:
            # Unitary symmetries
            H_cell = la.block_diag(h_cell, trans_sign*sym_op.dot(
                                   h_cell).dot(sym_op.T.conj()))
            H_hop = la.block_diag(h_hop, trans_sign*sym_op.dot(
                                  h_hop).dot(sym_op.T.conj()))
        sx = np.array([[0,1],[1,0]])
        # Full symmetry operator relating the blocks
        S = np.kron(sx, sym_op)
        check_symm_ham(H_cell, H_hop, S, trans_sign, sym=sym)
        # Mix with a random unitary
        U = kwant.rmt.circular(2*n, 'A', rng=3)
        H_cell_t = U.T.conj().dot(H_cell).dot(U)
        H_hop_t = U.T.conj().dot(H_hop).dot(U)
        if sym in ['AI', 'AII', 'C', 'D']:
            S_t = U.T.conj().dot(S).dot(U.conj())
        elif sym in ['AIII']:
            S_t = U.T.conj().dot(S).dot(U)
        # Conservation law matrix in the new basis
        cs_t = U.T.conj().dot(np.diag(cs)).dot(U)
        check_symm_ham(H_cell_t, H_hop_t, S_t, trans_sign, sym=sym)

        # Get the projectors.
        evals, evecs = np.linalg.eigh(cs_t)
        # Make sure the ordering is correct.
        assert_almost_equal(evals-np.array(cs), 0)
        projectors = [np.reshape(evecs[:, :n], (2*n, n)),
                      np.reshape(evecs[:, n:2*n], (2*n, n))]
        # Ensure that the projectors sum to a unitary.
        assert_almost_equal(sum(projector.dot(projector.conj().T) for projector
                                in projectors), np.eye(2*n))
        projectors = [sparse.csr_matrix(p) for p in projectors]

        if sym in ['AI', 'AII']:
            prop, stab = kwant.physics.leads.modes(H_cell_t, H_hop_t,
                                                   time_reversal=S_t,
                                                   projectors=projectors)
        elif sym in ['C', 'D']:
            prop, stab = kwant.physics.leads.modes(H_cell_t, H_hop_t,
                                                   particle_hole=S_t,
                                                   projectors=projectors)
        elif sym in ['AIII']:
            prop, stab = kwant.physics.leads.modes(H_cell_t, H_hop_t,
                                                   chiral=S_t,
                                                   projectors=projectors)
        current_conserving(stab)

        nmodes = stab.nmodes
        block_nmodes = prop.block_nmodes
        vecs, vecslmbdainv = stab.vecs, stab.vecslmbdainv
        # Row indices for the blocks. Both are of size n.
        block_rows = [slice(0, n), slice(n, 2*n)]
        ######## Check that the two blocks are related by symmetry.

        # Compare the stabilized propagating modes of incident and outgoing
        # modes for the two blocks that are related by symmetry.  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]
        # Mode rearrangement for each symmetry
        bnmodes = block_nmodes[0] # Number of modes in the first block
        if sym in ['AI', 'AII']:
            perm = np.arange(2*bnmodes)[::-1]
        elif sym in ['C', 'D']:
            perm = ((-1-np.arange(2*bnmodes)) % bnmodes +
                    bnmodes * (np.arange(2*bnmodes) // bnmodes))
        elif sym in ['AIII']:
            perm = (np.arange(2*bnmodes) % bnmodes +
                    bnmodes * (np.arange(2*bnmodes) < bnmodes))

        # Need both incident and outgoing stabilized modes to make the
        # comparison between blocks
        prop_modes = [(vecs[:, :nmodes], vecs[:, nmodes:2*nmodes], 1),
                      (vecslmbdainv[:, :nmodes],
                       vecslmbdainv[:, nmodes:2*nmodes], trans_sign)]
        # Symmetries that flip the sign of energy change the sign of
        # vecslmbdainv when used to construct modes between blocks.
        for (in_modes, out_modes, vecs_sign) in prop_modes:
            rows0, cols0 = block_rows[0], block_cols[0]
            rows1, cols1 = block_rows[1], block_cols[1]
            # Make sure the blocks are not empty
            if in_modes[rows0, cols0].size:
                # Check the real space representations of the stabilized modes
                sqrt_hop = stab.sqrt_hop
                modes0 = sqrt_hop.dot(np.hstack([in_modes[:, cols0],
                                                 out_modes[:, cols0]]))
                modes1 = sqrt_hop.dot(np.hstack([in_modes[:, cols1],
                                                 out_modes[:, cols1]]))
                # In the algorithm, the blocks are compared in the same order
                # they are specified.  Block 0 is computed before block 1, so
                # block 1 is obtained by symmetry transforming the modes of
                # block 0. Check that it is so.
                if sym in ['AI', 'AII', 'C', 'D']:
                    assert_almost_equal(S_t.dot(modes0.conj())[:, perm], vecs_sign*modes1)
                elif sym in ['AIII']:
                    assert_almost_equal(S_t.dot(modes0)[:, perm], vecs_sign*modes1)
            # If first block is empty, so is the second one.
            else:
                assert not in_modes[rows1, cols1].size
Esempio n. 24
0
def test_PHS_TRIM():
    """Test the function that makes particle-hole symmetric modes at a TRIM. """
    rng = ensure_rng(10)
    for n in (4, 8, 16, 60):
        for sym in kwant.rmt.sym_list:
            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)
                P_squared = 1 if np.allclose(p_mat.conj().dot(p_mat),
                                             np.eye(*p_mat.shape)) else -1
                if P_squared == 1:
                    for nmodes in (1, 3, n//4, n//2, n):
                        # Random matrix of 'modes.' Take part of a unitary
                        # matrix to ensure that the modes form a basis.
                        modes = kwant.rmt.circular(n, 'A', rng=rng)[:, :nmodes]
                        # Ensure modes are particle-hole symmetric and
                        # orthonormal
                        modes = modes + p_mat.dot(modes.conj())
                        modes = la.qr(modes, mode='economic')[0]
                        # Mix the modes with a random unitary transformation
                        U = kwant.rmt.circular(nmodes, 'A', rng=rng)
                        modes = modes.dot(U)
                        # Make the modes PHS symmetric using the method for a
                        # TRIM.
                        phs_modes = leads.phs_symmetrization(modes, p_mat)[0]
                        assert_almost_equal(phs_modes,
                                            p_mat.dot(phs_modes.conj()),
                                            err_msg='PHS broken at a TRIM in '
                                                    + sym)
                        assert_almost_equal(phs_modes.T.conj().dot(phs_modes),
                                            np.eye(phs_modes.shape[1]),
                                            err_msg='Modes are not orthonormal,'
                                                    'TRIM PHS in ' + sym)
                elif P_squared == -1:
                    # Need even number of modes =< n
                    for nmodes in (2, 4, n//2, n):
                        # Random matrix of 'modes.' Take part of a unitary
                        # matrix to ensure that the modes form a basis.
                        modes = kwant.rmt.circular(n, 'A', rng=rng)[:, :nmodes]
                        # Ensure modes are particle-hole symmetric and
                        # orthonormal.
                        modes[:, nmodes//2:] = \
                                p_mat.dot(modes[:, :nmodes//2].conj())
                        modes = la.qr(modes, mode='economic')[0]
                        # Mix the modes with a random unitary transformation
                        U = kwant.rmt.circular(nmodes, 'A', rng=rng)
                        modes = modes.dot(U)
                        # Make the modes PHS symmetric using the method for a
                        # TRIM.
                        phs_modes = leads.phs_symmetrization(modes, p_mat)[0]
                        assert_almost_equal(phs_modes[:, 1::2],
                                            p_mat.dot(phs_modes[:, ::2].conj()),
                                            err_msg='PHS broken at a TRIM in '
                                                    + sym)
                        assert_almost_equal(phs_modes.T.conj().dot(phs_modes),
                                            np.eye(phs_modes.shape[1]),
                                            err_msg='Modes are not orthonormal,'
                                                    ' TRIM PHS in ' + sym)
        # Test the off-diagonal case when p_mat = sigma_x
        p_mat = np.array([[0, 1], [1, 0]])
        p_mat = np.kron(p_mat, np.identity(n // len(p_mat)))
        for nmodes in (1, 3, n//4, n//2):
            if nmodes > n//2:
                continue
            # Random matrix of 'modes.' Take part of a unitary
            # matrix to ensure that the modes form a basis, all modes
            # are only in half of the space
            modes = kwant.rmt.circular(n//2, 'A', rng=rng)[:, :nmodes]
            modes = np.vstack((modes, np.zeros((n//2, nmodes))))
            # Add an orthogonal set of vectors that are ph images
            modes = np.hstack((modes, p_mat.dot(modes.conj())))
            # Make the modes PHS symmetric using the method for a
            # TRIM.
            phs_modes = leads.phs_symmetrization(modes, p_mat)[0]
            assert_almost_equal(phs_modes,
                                p_mat.dot(phs_modes.conj()),
                                err_msg='PHS broken at a TRIM in '
                                        'off-diagonal test')
            assert_almost_equal(phs_modes.T.conj().dot(phs_modes),
                                np.eye(phs_modes.shape[1]),
                                err_msg='Modes are not orthonormal,'
                                        'off-diagonal test')
Esempio n. 25
0
def test_translational_symmetry():
    ts = lattice.TranslationalSymmetry
    f2 = lattice.general(np.identity(2), norbs=1)
    f3 = lattice.general(np.identity(3), norbs=1)
    shifted = lambda site, delta: site.family(*ta.add(site.tag, delta))

    raises(ValueError, ts, (0, 0, 4), (0, 5, 0), (0, 0, 2))
    sym = ts((3.3, 0))
    raises(ValueError, sym.add_site_family, f2)

    # Test lattices with dimension smaller than dimension of space.
    f2in3 = lattice.general([[4, 4, 0], [4, -4, 0]], norbs=1)
    sym = ts((8, 0, 0))
    sym.add_site_family(f2in3)
    sym = ts((8, 0, 1))
    raises(ValueError, sym.add_site_family, f2in3)

    # Test automatic fill-in of transverse vectors.
    sym = ts((1, 2))
    sym.add_site_family(f2)
    assert sym.site_family_data[f2][2] != 0
    sym = ts((1, 0, 2), (3, 0, 2))
    sym.add_site_family(f3)
    assert sym.site_family_data[f3][2] != 0

    transl_vecs = np.array([[10, 0], [7, 7]], dtype=int)
    sym = ts(*transl_vecs)
    assert sym.num_directions == 2
    sym2 = ts(*transl_vecs[:1, :])
    sym2.add_site_family(f2, transl_vecs[1:, :])
    for site in [f2(0, 0), f2(4, 0), f2(2, 1), f2(5, 5), f2(15, 6)]:
        assert sym.in_fd(site)
        assert sym2.in_fd(site)
        assert sym.which(site) == (0, 0)
        assert sym2.which(site) == (0, )
        for v in [(1, 0), (0, 1), (-1, 0), (0, -1), (5, 10), (-111, 573)]:
            site2 = shifted(site, np.dot(v, transl_vecs))
            assert not sym.in_fd(site2)
            assert (v[0] != 0) != sym2.in_fd(site2)
            assert sym.to_fd(site2) == site
            assert (v[1] == 0) == (sym2.to_fd(site2) == site)
            assert sym.which(site2) == v
            assert sym2.which(site2) == v[:1]

            for hop in [(0, 0), (100, 0), (0, 5), (-2134, 3213)]:
                assert (sym.to_fd(site2,
                                  shifted(site2,
                                          hop)) == (site, shifted(site, hop)))

    # Test act for hoppings belonging to different lattices.
    f2p = lattice.general(2 * np.identity(2), norbs=1)
    sym = ts(*(2 * np.identity(2)))
    assert sym.act((1, 1), f2(0, 0), f2p(0, 0)) == (f2(2, 2), f2p(1, 1))
    assert sym.act((1, 1), f2p(0, 0), f2(0, 0)) == (f2p(1, 1), f2(2, 2))

    # Test add_site_family on random lattices and symmetries by ensuring that
    # it's possible to add site groups that are compatible with a randomly
    # generated symmetry with proper vectors.
    rng = ensure_rng(30)
    vec = rng.randn(3, 5)
    lat = lattice.general(vec, norbs=1)
    total = 0
    for k in range(1, 4):
        for i in range(10):
            sym_vec = rng.randint(-10, 10, size=(k, 3))
            if np.linalg.matrix_rank(sym_vec) < k:
                continue
            total += 1
            sym_vec = np.dot(sym_vec, vec)
            sym = ts(*sym_vec)
            sym.add_site_family(lat)
    assert total > 20
Esempio n. 26
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)
Esempio n. 27
0
def test_hamiltonian_submatrix():
    syst = kwant.Builder()
    chain = kwant.lattice.chain()
    for i in range(3):
        syst[chain(i)] = 0.5 * i
    for i in range(2):
        syst[chain(i), chain(i + 1)] = 1j * (i + 1)

    syst2 = syst.finalized()
    mat = syst2.hamiltonian_submatrix()
    assert mat.shape == (3, 3)
    # Sorting is required due to unknown compression order of builder.
    perm = np.argsort(syst2.onsite_hamiltonians)
    mat_should_be = np.array([[0, 1j, 0], [-1j, 0.5, 2j], [0, -2j, 1]])

    mat = mat[perm, :]
    mat = mat[:, perm]
    np.testing.assert_array_equal(mat, mat_should_be)

    mat = syst2.hamiltonian_submatrix(sparse=True)
    assert sparse.isspmatrix_coo(mat)
    mat = mat.todense()
    mat = mat[perm, :]
    mat = mat[:, perm]
    np.testing.assert_array_equal(mat, mat_should_be)

    mat = syst2.hamiltonian_submatrix((), perm[[0, 1]], perm[[2]])
    np.testing.assert_array_equal(mat, mat_should_be[:2, 2:3])

    mat = syst2.hamiltonian_submatrix((), perm[[0, 1]], perm[[2]], sparse=True)
    mat = mat.todense()
    np.testing.assert_array_equal(mat, mat_should_be[:2, 2:3])

    # Test for correct treatment of matrix input.
    syst = kwant.Builder()
    syst[chain(0)] = np.array([[0, 1j], [-1j, 0]])
    syst[chain(1)] = np.array([[1]])
    syst[chain(2)] = np.array([[2]])
    syst[chain(1), chain(0)] = np.array([[1, 2j]])
    syst[chain(2), chain(1)] = np.array([[3j]])
    syst2 = syst.finalized()
    mat_dense = syst2.hamiltonian_submatrix()
    mat_sp = syst2.hamiltonian_submatrix(sparse=True).todense()
    np.testing.assert_array_equal(mat_sp, mat_dense)

    # Test precalculation of modes.
    rng = ensure_rng(5)
    lead = kwant.Builder(kwant.TranslationalSymmetry((-1,)))
    lead[chain(0)] = np.zeros((2, 2))
    lead[chain(0), chain(1)] = rng.randn(2, 2)
    syst.attach_lead(lead)
    syst2 = syst.finalized()
    smatrix = kwant.smatrix(syst2, .1).data
    syst3 = syst2.precalculate(.1, what='modes')
    smatrix2 = kwant.smatrix(syst3, .1).data
    np.testing.assert_almost_equal(smatrix, smatrix2)
    raises(ValueError, kwant.solvers.default.greens_function, syst3, 0.2)

    # Test for shape errors.
    syst[chain(0), chain(2)] = np.array([[1, 2]])
    syst2 = syst.finalized()
    raises(ValueError, syst2.hamiltonian_submatrix)
    raises(ValueError, syst2.hamiltonian_submatrix, sparse=True)
    syst[chain(0), chain(2)] = 1
    syst2 = syst.finalized()
    raises(ValueError, syst2.hamiltonian_submatrix)
    raises(ValueError, syst2.hamiltonian_submatrix, sparse=True)
Esempio n. 28
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)
Esempio n. 29
0
def random_onsite_hop(n, rng=0):
    rng = ensure_rng(rng)
    onsite = rng.randn(n, n) + 1j * rng.randn(n, n)
    onsite = onsite + onsite.T.conj()
    hop = rng.rand(n, n) + 1j * rng.rand(n, n)
    return onsite, hop
Esempio n. 30
0
def test_block_relations_cons_PHS():
    # Four blocks. Two identical blocks, each with particle-hole symmetry. Then
    # two blocks, related by particle-hole symmetry, but neither possessing it
    # on its own. These two blocks are not identical.  There is a conservation
    # law relating the first two, and a discrete symmetry relating the latter
    # two.  Also check the case when the latter two blocks have singular
    # hopping.
    n = 8
    rng = ensure_rng(99)
    sym = 'C'  # Particle-hole squares to -1
    # Onsite and hopping blocks with particle-hole symm
    hP_cell = kwant.rmt.gaussian(n, sym, rng=rng)
    hP_hop = 10 * kwant.rmt.gaussian(2*n, sym, rng=rng)[:n, n:]
    p_mat = np.array(kwant.rmt.h_p_matrix[sym])
    p_mat = np.kron(np.identity(n // len(p_mat)), p_mat)
    # Random onsite and hopping blocks
    h_cell, h_hop = random_onsite_hop(n)
    # Full onsite and hoppings
    H_cell = la.block_diag(hP_cell, hP_cell, h_cell,
                           -p_mat.dot(h_cell.conj()).dot(p_mat.T.conj()))
    H_hop = la.block_diag(hP_hop, hP_hop, h_hop,
                          -p_mat.dot(h_hop.conj()).dot(p_mat.T.conj()))
    # Also check the case when the hopping is singular (but square) in the
    # second two blocks.
    h_hop[:, ::2] = 0
    H_hop_s = la.block_diag(hP_hop, hP_hop, h_hop,
                            -p_mat.dot(h_hop.conj()).dot(p_mat.T.conj()))
    sx = np.array([[0,1],[1,0]])
    # Particle-hole symmetry operator
    P_mat = la.block_diag(p_mat, p_mat, np.kron(sx, p_mat))
    assert_almost_equal(P_mat.dot(H_cell.conj()) + H_cell.dot(P_mat), 0)
    assert_almost_equal(P_mat.dot(H_hop.conj()) + H_hop.dot(P_mat), 0)
    assert_almost_equal(P_mat.dot(H_hop_s.conj()) + H_hop_s.dot(P_mat), 0)
    assert_almost_equal(P_mat.dot(P_mat.conj()), -np.eye(P_mat.shape[0]))

    # Projectors
    projectors = np.split(np.eye(4*n), 4, 1)
    # Make the projectors sparse.
    projectors = [sparse.csr_matrix(p) for p in projectors]

    # Cover both singular and nonsingular hopping
    ham = [(H_cell, H_hop), (H_cell, H_hop_s)]
    for (H_cell, H_hop) in ham:
        prop, stab = kwant.physics.leads.modes(H_cell, H_hop,
                                               particle_hole=P_mat,
                                               projectors=projectors)
        current_conserving(stab)
        nmodes = stab.nmodes
        block_nmodes = prop.block_nmodes
        vecs, vecslmbdainv = stab.vecs, stab.vecslmbdainv
        # Row indices for the blocks.
        # All 4 blocks are of size n.
        block_rows = [slice(0, n), slice(n, 2*n),
                      slice(2*n, 3*n), slice(3*n, 4*n)]

        ######## Check that the first two blocks are identical.
        ### 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_identical_modes(prop_modes, block_rows, block_cols)
        ### 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, 4*[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_identical_modes(ev_modes, block_rows, block_cols)

        # Check that the second two blocks are related by PHS.

        # Here we only look at propagating modes. Compare the stabilized modes
        # of incident and outgoing modes for the two blocks that are related by
        # particle-hole symmetry, i.e. blocks 2 and 3.  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]
        # Need both incident and outgoing stabilized modes to make the
        # comparison between blocks
        prop_modes = [(vecs[:, :nmodes], vecs[:, nmodes:2*nmodes], 1),
                      (vecslmbdainv[:, :nmodes],
                       vecslmbdainv[:, nmodes:2*nmodes], -1)]
        # P is antiunitary, such that vecslmbdainv changes sign when
        # used between blocks to construct modes.
        for (in_modes, out_modes, vecs_sign) in prop_modes:
            # Coordinates of blocks 2 and 3
            rows2, cols2 = block_rows[2], block_cols[2]
            cols3 = block_cols[3]
            bnmodes = block_nmodes[2] # Number of modes in block 2
            # Mode rearrangement by particle-hole symmetry
            perm = ((-1-np.arange(2*bnmodes)) % bnmodes +
                    bnmodes * (np.arange(2*bnmodes) // bnmodes))
            # Make sure the blocks are not empty
            if in_modes[rows2, cols2].size:
                # Check that the real space representations of the stabilized
                # modes of blocks 2 and 3 are related by particle-hole
                # symmetry.
                sqrt_hop = stab.sqrt_hop
                modes2 = sqrt_hop.dot(np.hstack([in_modes[:, cols2],
                                                 out_modes[:, cols2]]))
                modes3 = sqrt_hop.dot(np.hstack([in_modes[:, cols3],
                                                 out_modes[:, cols3]]))
                # In the algorithm, the blocks are compared in the same order
                # they are specified.  Block 2 is computed before block 3, so
                # block 3 is obtained by particle-hole transforming the modes
                # of block 2. Check that it is so.
                assert_almost_equal(P_mat.dot(modes2.conj())[:, perm], vecs_sign*modes3)