예제 #1
0
def test_neighbors_not_in_single_domain():
    sr = builder.Builder()
    lead = builder.Builder(VerySimpleSymmetry(-1))
    fam = builder.SimpleSiteFamily()
    sr[(fam(x, y) for x in range(3) for y in range(3) if x >= y)] = 0
    sr[builder.HoppingKind((1, 0), fam)] = 1
    sr[builder.HoppingKind((0, 1), fam)] = 1
    lead[(fam(0, y) for y in range(3))] = 0
    lead[((fam(0, y), fam(1, y)) for y in range(3))] = 1
    lead[((fam(0, y), fam(0, y + 1)) for y in range(2))] = 1
    sr.leads.append(builder.BuilderLead(lead, [fam(i, i) for i in range(3)]))
    raises(ValueError, sr.finalized)
예제 #2
0
def test_invalid_HoppingKind():
    g = kwant.lattice.general(ta.identity(3))
    h = kwant.lattice.general(np.identity(3)[:-1])  # 2D lattice in 3D

    delta = (1, 0, 0)

    # families have incompatible tags
    with raises(ValueError):
        builder.HoppingKind(delta, g, h)

    # delta is incompatible with tags
    with raises(ValueError):
        builder.HoppingKind(delta, h)
예제 #3
0
 def term_hopping(hopping_dict, hop_mat, atoms,
                  sublattices, coords_dict):
     """Find Kwant hoppings in a qsymm.BlochModel term that has a lattice
     translation in the Bloch factor.
     """
     # Iterate over combinations of atoms, set hoppings between each
     for atom1, atom2 in it.product(atoms, atoms):
         # Take the block from atom1 to atom2
         hop = hop_mat[ranges[atom1], ranges[atom2]]
         # Only include nonzero hoppings
         if allclose(hop, 0):
             continue
         # Adjust hopping vector to Bloch form basis
         r_lattice = (
             r_vec
             + np.array(coords_dict[atom1])
             - np.array(coords_dict[atom2])
         )
         # Bring vector to basis of lattice vectors
         lat_basis = np.linalg.solve(np.vstack(lat_vecs).T, r_lattice)
         lat_basis = make_int(lat_basis)
         # Should only have hoppings that are integer multiples of
         # lattice vectors
         if lat_basis is not None:
             hop_dir = builder.HoppingKind(-lat_basis,
                                           sublattices[atom1],
                                           sublattices[atom2])
             # Set the hopping as the matrix times the hopping amplitude
             hopping_dict[hop_dir] += Model({coeff: hop}, momenta=momenta)
         else:
             raise RuntimeError('A nonzero hopping not matching a '
                                'lattice vector was found.')
     return hopping_dict
예제 #4
0
def test_HoppingKind():
    g = kwant.lattice.general(ta.identity(3), name='some_lattice')
    h = kwant.lattice.general(ta.identity(3), name='another_lattice')
    sym = kwant.TranslationalSymmetry((0, 2, 0))
    syst = builder.Builder(sym)
    syst[((h if max(x, y, z) % 2 else g)(x, y, z)
         for x in range(4) for y in range(2) for z in range(4))] = None
    for delta, ga, gb, n in [((1, 0, 0), g, h, 4),
                             ((1, 0, 0), h, g, 7),
                             ((0, 1, 0), g, h, 1),
                             ((0, 4, 0), h, h, 21),
                             ((0, 0, 1), g, h, 4)]:
        ph = list(builder.HoppingKind(delta, ga, gb)(syst))
        assert len(ph) == n
        ph = set(ph)
        assert len(ph) == n

        ph2 = list((
                sym.to_fd(b, a) for a, b in
                builder.HoppingKind(ta.negative(delta), gb, ga)(syst)))
        assert len(ph2) == n
        ph2 = set(ph2)
        assert ph2 == ph

        for a, b in ph:
            assert a.family == ga
            assert b.family == gb
            assert sym.to_fd(a) == a
            assert a.tag - b.tag == delta

        # test hashability and equality
        hk = builder.HoppingKind((1, 0, 0), g)
        hk2 = builder.HoppingKind((1, 0, 0), g)
        hk3 = builder.HoppingKind((1, 0, 0), g, h)
        assert hk == hk2
        assert hash(hk) == hash(hk2)
        assert hk != hk3
        assert hash(hk) != hash(hk3)
        assert len({hk: 0, hk2:1, hk3: 2}) == 2
예제 #5
0
 def term_onsite(onsites_dict, hopping_dict, hop_mat, atoms,
                 sublattices, coords_dict):
     """Find the Kwant onsites and hoppings in a qsymm.BlochModel term
     that has no lattice translation in the Bloch factor.
     """
     for atom1, atom2 in it.product(atoms, atoms):
         # Subblock within the same sublattice is onsite
         hop = hop_mat[ranges[atom1], ranges[atom2]]
         if sublattices[atom1] == sublattices[atom2]:
             onsites_dict[atom1] += Model({coeff: hop}, momenta=momenta)
         # Blocks between sublattices are hoppings between sublattices
         # at the same position.
         # Only include nonzero hoppings
         elif not allclose(hop, 0):
             if not allclose(np.array(coords_dict[atom1]),
                             np.array(coords_dict[atom2])):
                 raise ValueError(
                     "Position of sites not compatible with qsymm model.")
             lat_basis = np.array(zer)
             hop = Model({coeff: hop}, momenta=momenta)
             hop_dir = builder.HoppingKind(-lat_basis, sublattices[atom1],
                                           sublattices[atom2])
             hopping_dict[hop_dir] += hop
     return onsites_dict, hopping_dict
예제 #6
0
def test_fill():
    g = kwant.lattice.square()
    sym_x = kwant.TranslationalSymmetry((-1, 0))
    sym_xy = kwant.TranslationalSymmetry((-1, 0), (0, 1))

    template_1d = builder.Builder(sym_x)
    template_1d[g(0, 0)] = None
    template_1d[g.neighbors()] = None

    def line_200(site):
        return -100 <= site.pos[0] < 100

    ## Test that copying a builder by "fill" preserves everything.
    for sym, func in [
        (kwant.TranslationalSymmetry(*np.diag([3, 4, 5])), lambda pos: True),
        (builder.NoSymmetry(), lambda pos: ta.dot(pos, pos) < 17)
    ]:
        cubic = kwant.lattice.general(ta.identity(3))

        # Make a weird system.
        orig = kwant.Builder(sym)
        sites = cubic.shape(func, (0, 0, 0))
        for i, site in enumerate(orig.expand(sites)):
            if i % 7 == 0:
                continue
            orig[site] = i
        for i, hopp in enumerate(orig.expand(cubic.neighbors(1))):
            if i % 11 == 0:
                continue
            orig[hopp] = i * 1.2345
        for i, hopp in enumerate(orig.expand(cubic.neighbors(2))):
            if i % 13 == 0:
                continue
            orig[hopp] = i * 1j

        # Clone the original using fill.
        clone = kwant.Builder(sym)
        clone.fill(orig, lambda s: True, (0, 0, 0))

        # Verify that both are identical.
        assert set(clone.site_value_pairs()) == set(orig.site_value_pairs())
        assert (set(clone.hopping_value_pairs()) == set(
            orig.hopping_value_pairs()))

    ## Test for warning when "start" is out.
    target = builder.Builder()
    for start in [(-101, 0), (101, 0)]:
        with warns(RuntimeWarning):
            target.fill(template_1d, line_200, start)

    ## Test filling of infinite builder.
    for n in [1, 2, 4]:
        sym_n = kwant.TranslationalSymmetry((n, 0))
        for start in [g(0, 0), g(20, 0)]:
            target = builder.Builder(sym_n)
            sites = target.fill(template_1d,
                                lambda s: True,
                                start,
                                max_sites=10)
            assert len(sites) == n
            assert len(list(target.hoppings())) == n
            assert set(sym_n.to_fd(s) for s in sites) == set(target.sites())

    ## test max_sites
    target = builder.Builder()
    for max_sites in (-1, 0):
        with raises(ValueError):
            target.fill(template_1d,
                        lambda site: True,
                        g(0, 0),
                        max_sites=max_sites)
        assert len(list(target.sites())) == 0
    target = builder.Builder()
    with raises(RuntimeError):
        target.fill(template_1d, line_200, g(0, 0), max_sites=10)
    ## test filling
    target = builder.Builder()
    added_sites = target.fill(template_1d, line_200, g(0, 0))
    assert len(added_sites) == 200
    # raise warning if target already contains all starting sites
    with warns(RuntimeWarning):
        target.fill(template_1d, line_200, g(0, 0))

    ## test multiplying unit cell size in 1D
    n_cells = 10
    sym_nx = kwant.TranslationalSymmetry(*(sym_x.periods * n_cells))
    target = builder.Builder(sym_nx)
    target.fill(template_1d, lambda site: True, g(0, 0))

    should_be_syst = builder.Builder(sym_nx)
    should_be_syst[(g(i, 0) for i in range(n_cells))] = None
    should_be_syst[g.neighbors()] = None

    assert sorted(target.sites()) == sorted(should_be_syst.sites())
    assert sorted(target.hoppings()) == sorted(should_be_syst.hoppings())

    ## test multiplying unit cell size in 2D
    template_2d = builder.Builder(sym_xy)
    template_2d[g(0, 0)] = None
    template_2d[g.neighbors()] = None
    template_2d[builder.HoppingKind((2, 2), g)] = None

    nm_cells = (3, 5)
    sym_nmxy = kwant.TranslationalSymmetry(*(sym_xy.periods * nm_cells))
    target = builder.Builder(sym_nmxy)
    target.fill(template_2d, lambda site: True, g(0, 0))

    should_be_syst = builder.Builder(sym_nmxy)
    should_be_syst[(g(i, j) for i in range(10) for j in range(10))] = None
    should_be_syst[g.neighbors()] = None
    should_be_syst[builder.HoppingKind((2, 2), g)] = None

    assert sorted(target.sites()) == sorted(should_be_syst.sites())
    assert sorted(target.hoppings()) == sorted(should_be_syst.hoppings())

    ## test filling 0D builder with 2D builder
    def square_shape(site):
        x, y = site.tag
        return 0 <= x < 10 and 0 <= y < 10

    target = builder.Builder()
    target.fill(template_2d, square_shape, g(0, 0))

    should_be_syst = builder.Builder()
    should_be_syst[(g(i, j) for i in range(10) for j in range(10))] = None
    should_be_syst[g.neighbors()] = None
    should_be_syst[builder.HoppingKind((2, 2), g)] = None

    assert sorted(target.sites()) == sorted(should_be_syst.sites())
    assert sorted(target.hoppings()) == sorted(should_be_syst.hoppings())

    ## test that 'fill' respects the symmetry of the target builder
    lat = kwant.lattice.chain(a=1)
    template = builder.Builder(kwant.TranslationalSymmetry((-1, )))
    template[lat(0)] = 2
    template[lat.neighbors()] = -1

    target = builder.Builder(kwant.TranslationalSymmetry((-2, )))
    target[lat(0)] = None
    to_target_fd = target.symmetry.to_fd
    # Refuses to fill the target because target already contains the starting
    # site.
    with warns(RuntimeWarning):
        target.fill(template, lambda x: True, lat(0))

    # should only add a single site (and hopping)
    new_sites = target.fill(template, lambda x: True, lat(1))
    assert target[lat(0)] is None  # should not be overwritten by template
    assert target[lat(-1)] == template[lat(0)]
    assert len(new_sites) == 1
    assert to_target_fd(new_sites[0]) == to_target_fd(lat(-1))
예제 #7
0
def test_ModesLead_and_SelfEnergyLead():
    lat = builder.SimpleSiteFamily()
    hoppings = [
        builder.HoppingKind((1, 0), lat),
        builder.HoppingKind((0, 1), lat)
    ]
    rng = Random(123)
    L = 5
    t = 1
    energies = [0.9, 1.7]

    syst = builder.Builder()
    for x in range(L):
        for y in range(L):
            syst[lat(x, y)] = 4 * t + rng.random() - 0.5
    syst[hoppings] = -t

    # Attach a lead from the left.
    lead = builder.Builder(VerySimpleSymmetry(-1))
    for y in range(L):
        lead[lat(0, y)] = 4 * t
    lead[hoppings] = -t
    syst.attach_lead(lead)

    # Make the right lead and attach it.
    lead = builder.Builder(VerySimpleSymmetry(1))
    for y in range(L):
        lead[lat(0, y)] = 4 * t
    lead[hoppings] = -t
    syst.attach_lead(lead)

    fsyst = syst.finalized()
    ts = [kwant.smatrix(fsyst, e).transmission(1, 0) for e in energies]

    # Replace lead with it's finalized copy.
    lead = fsyst.leads[1]
    interface = [lat(L - 1, lead.sites[i].tag[1]) for i in range(L)]

    # Re-attach right lead as ModesLead.
    syst.leads[1] = builder.ModesLead(lead.modes, interface)
    fsyst = syst.finalized()
    ts2 = [kwant.smatrix(fsyst, e).transmission(1, 0) for e in energies]
    assert_almost_equal(ts2, ts)

    # Re-attach right lead as ModesLead with old-style modes API
    # that does not take a 'params' keyword parameter.
    syst.leads[1] = builder.ModesLead(
        lambda energy, args: lead.modes(energy, args), interface)
    fsyst = syst.finalized()
    ts2 = [kwant.smatrix(fsyst, e).transmission(1, 0) for e in energies]
    assert_almost_equal(ts2, ts)

    # Re-attach right lead as SelfEnergyLead.
    syst.leads[1] = builder.SelfEnergyLead(lead.selfenergy, interface)
    fsyst = syst.finalized()
    ts2 = [
        kwant.greens_function(fsyst, e).transmission(1, 0) for e in energies
    ]
    assert_almost_equal(ts2, ts)

    # Re-attach right lead as SelfEnergyLead with old-style selfenergy API
    # that does not take a 'params' keyword parameter.
    syst.leads[1] = builder.SelfEnergyLead(
        lambda energy, args: lead.selfenergy(energy, args), interface)
    fsyst = syst.finalized()
    ts2 = [
        kwant.greens_function(fsyst, e).transmission(1, 0) for e in energies
    ]
    assert_almost_equal(ts2, ts)

    # Append a virtual (=zero self energy) lead.  This should have no effect.
    # Also verifies that the selfenergy callback function can return exotic
    # arraylikes.
    syst.leads.append(
        builder.SelfEnergyLead(lambda *args: list(ta.zeros((L, L))),
                               interface))
    fsyst = syst.finalized()
    ts2 = [
        kwant.greens_function(fsyst, e).transmission(1, 0) for e in energies
    ]
    assert_almost_equal(ts2, ts)